1#ifndef GAME_CLIENT_SKIN_H
2#define GAME_CLIENT_SKIN_H
3#include <base/color.h>
4#include <base/system.h>
5#include <base/vmath.h>
6#include <engine/graphics.h>
7#include <limits>
8
9// do this better and nicer
10struct CSkin
11{
12private:
13 char m_aName[24];
14
15public:
16 struct SSkinTextures
17 {
18 IGraphics::CTextureHandle m_Body;
19 IGraphics::CTextureHandle m_BodyOutline;
20
21 IGraphics::CTextureHandle m_Feet;
22 IGraphics::CTextureHandle m_FeetOutline;
23
24 IGraphics::CTextureHandle m_Hands;
25 IGraphics::CTextureHandle m_HandsOutline;
26
27 IGraphics::CTextureHandle m_aEyes[6];
28
29 void Reset()
30 {
31 m_Body = IGraphics::CTextureHandle();
32 m_BodyOutline = IGraphics::CTextureHandle();
33 m_Feet = IGraphics::CTextureHandle();
34 m_FeetOutline = IGraphics::CTextureHandle();
35 m_Hands = IGraphics::CTextureHandle();
36 m_HandsOutline = IGraphics::CTextureHandle();
37 for(auto &Eye : m_aEyes)
38 Eye = IGraphics::CTextureHandle();
39 }
40
41 void Unload(IGraphics *pGraphics)
42 {
43 pGraphics->UnloadTexture(pIndex: &m_Body);
44 pGraphics->UnloadTexture(pIndex: &m_BodyOutline);
45 pGraphics->UnloadTexture(pIndex: &m_Feet);
46 pGraphics->UnloadTexture(pIndex: &m_FeetOutline);
47 pGraphics->UnloadTexture(pIndex: &m_Hands);
48 pGraphics->UnloadTexture(pIndex: &m_HandsOutline);
49 for(auto &Eye : m_aEyes)
50 pGraphics->UnloadTexture(pIndex: &Eye);
51 }
52 };
53
54 SSkinTextures m_OriginalSkin;
55 SSkinTextures m_ColorableSkin;
56 ColorRGBA m_BloodColor;
57
58 template<bool IsSizeType>
59 struct SSkinMetricVariableInt
60 {
61 int m_Value;
62 operator int() const { return m_Value; }
63 SSkinMetricVariableInt &operator=(int NewVal)
64 {
65 if(IsSizeType)
66 m_Value = maximum(a: m_Value, b: NewVal);
67 else
68 m_Value = minimum(a: m_Value, b: NewVal);
69 return *this;
70 }
71
72 SSkinMetricVariableInt()
73 {
74 Reset();
75 }
76
77 void Reset()
78 {
79 if(IsSizeType)
80 m_Value = std::numeric_limits<int>::lowest();
81 else
82 m_Value = std::numeric_limits<int>::max();
83 }
84 };
85
86 struct SSkinMetricVariable
87 {
88 SSkinMetricVariableInt<true> m_Width;
89 SSkinMetricVariableInt<true> m_Height;
90 SSkinMetricVariableInt<false> m_OffsetX;
91 SSkinMetricVariableInt<false> m_OffsetY;
92
93 // these can be used to normalize the metrics
94 SSkinMetricVariableInt<true> m_MaxWidth;
95 SSkinMetricVariableInt<true> m_MaxHeight;
96
97 float WidthNormalized() const
98 {
99 return (float)m_Width / (float)m_MaxWidth;
100 }
101
102 float HeightNormalized() const
103 {
104 return (float)m_Height / (float)m_MaxHeight;
105 }
106
107 float OffsetXNormalized() const
108 {
109 return (float)m_OffsetX / (float)m_MaxWidth;
110 }
111
112 float OffsetYNormalized() const
113 {
114 return (float)m_OffsetY / (float)m_MaxHeight;
115 }
116
117 void Reset()
118 {
119 m_Width.Reset();
120 m_Height.Reset();
121 m_OffsetX.Reset();
122 m_OffsetY.Reset();
123 m_MaxWidth.Reset();
124 m_MaxHeight.Reset();
125 }
126 };
127
128 struct SSkinMetrics
129 {
130 SSkinMetricVariable m_Body;
131 SSkinMetricVariable m_Feet;
132
133 void Reset()
134 {
135 m_Body.Reset();
136 m_Feet.Reset();
137 }
138
139 SSkinMetrics()
140 {
141 Reset();
142 }
143 };
144 SSkinMetrics m_Metrics;
145
146 bool operator<(const CSkin &Other) const { return str_comp(a: m_aName, b: Other.m_aName) < 0; }
147 bool operator==(const CSkin &Other) const { return !str_comp(a: m_aName, b: Other.m_aName); }
148
149 CSkin(const char *pName)
150 {
151 str_copy(dst&: m_aName, src: pName);
152 }
153 CSkin(CSkin &&) = default;
154 CSkin &operator=(CSkin &&) = default;
155
156 const char *GetName() const { return m_aName; }
157
158 // has to be kept in sync with m_aSkinNameRestrictions
159 static bool IsValidName(const char *pName)
160 {
161 if(pName[0] == '\0' || str_length(str: pName) >= (int)sizeof(CSkin("").m_aName))
162 {
163 return false;
164 }
165
166 for(int i = 0; pName[i] != '\0'; ++i)
167 {
168 if(pName[i] == '"' || pName[i] == '/' || pName[i] == '\\')
169 {
170 return false;
171 }
172 }
173 return true;
174 }
175 static constexpr char m_aSkinNameRestrictions[] = "Skin names must be valid filenames shorter than 24 characters.";
176};
177
178#endif
179