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 |
10 | struct CSkin |
11 | { |
12 | private: |
13 | char m_aName[24]; |
14 | |
15 | public: |
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 |