1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef GAME_CLIENT_RENDER_H
4#define GAME_CLIENT_RENDER_H
5
6#include <base/color.h>
7#include <base/vmath.h>
8
9#include <engine/client/enums.h>
10
11#include <generated/protocol.h>
12#include <generated/protocol7.h>
13
14#include <game/client/skin.h>
15#include <game/client/ui_rect.h>
16
17#include <functional>
18#include <memory>
19
20class CAnimState;
21class CSpeedupTile;
22class CSwitchTile;
23class CTeleTile;
24class CTile;
25class CTuneTile;
26class CEnvPoint;
27class CEnvPointBezier;
28class CEnvPointBezier_upstream;
29class CMapItemGroup;
30class CQuad;
31
32class CSkinDescriptor
33{
34public:
35 enum
36 {
37 FLAG_SIX = 1,
38 FLAG_SEVEN = 2,
39 };
40 unsigned m_Flags;
41
42 char m_aSkinName[MAX_SKIN_LENGTH];
43
44 class CSixup
45 {
46 public:
47 char m_aaSkinPartNames[protocol7::NUM_SKINPARTS][protocol7::MAX_SKIN_LENGTH];
48 bool m_BotDecoration;
49 bool m_XmasHat;
50
51 void Reset();
52 bool operator==(const CSixup &Other) const;
53 bool operator!=(const CSixup &Other) const { return !(*this == Other); }
54 };
55 CSixup m_aSixup[NUM_DUMMIES];
56
57 CSkinDescriptor();
58 void Reset();
59 bool IsValid() const;
60 bool operator==(const CSkinDescriptor &Other) const;
61 bool operator!=(const CSkinDescriptor &Other) const { return !(*this == Other); }
62};
63
64class CTeeRenderInfo
65{
66public:
67 CTeeRenderInfo()
68 {
69 Reset();
70 }
71
72 void Reset()
73 {
74 m_OriginalRenderSkin.Reset();
75 m_ColorableRenderSkin.Reset();
76 m_SkinMetrics.Reset();
77 m_CustomColoredSkin = false;
78 m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
79 m_ColorBody = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
80 m_ColorFeet = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
81 m_Size = 1.0f;
82 m_GotAirJump = true;
83 m_TeeRenderFlags = 0;
84 m_FeetFlipped = false;
85
86 for(auto &Sixup : m_aSixup)
87 Sixup.Reset();
88 }
89
90 void Apply(const CSkin *pSkin)
91 {
92 m_OriginalRenderSkin = pSkin->m_OriginalSkin;
93 m_ColorableRenderSkin = pSkin->m_ColorableSkin;
94 m_BloodColor = pSkin->m_BloodColor;
95 m_SkinMetrics = pSkin->m_Metrics;
96 }
97
98 void ApplySkin(const CTeeRenderInfo &TeeRenderInfo)
99 {
100 m_OriginalRenderSkin = TeeRenderInfo.m_OriginalRenderSkin;
101 m_ColorableRenderSkin = TeeRenderInfo.m_ColorableRenderSkin;
102 m_BloodColor = TeeRenderInfo.m_BloodColor;
103 m_SkinMetrics = TeeRenderInfo.m_SkinMetrics;
104 }
105
106 void ApplyColors(bool CustomColoredSkin, int ColorBody, int ColorFeet)
107 {
108 m_CustomColoredSkin = CustomColoredSkin;
109 if(CustomColoredSkin)
110 {
111 m_ColorBody = color_cast<ColorRGBA>(hsl: ColorHSLA(ColorBody).UnclampLighting(Darkest: ColorHSLA::DARKEST_LGT));
112 m_ColorFeet = color_cast<ColorRGBA>(hsl: ColorHSLA(ColorFeet).UnclampLighting(Darkest: ColorHSLA::DARKEST_LGT));
113 }
114 else
115 {
116 m_ColorBody = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
117 m_ColorFeet = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
118 }
119 }
120
121 CSkin::CSkinTextures m_OriginalRenderSkin;
122 CSkin::CSkinTextures m_ColorableRenderSkin;
123
124 CSkin::CSkinMetrics m_SkinMetrics;
125
126 bool m_CustomColoredSkin;
127 ColorRGBA m_BloodColor;
128
129 ColorRGBA m_ColorBody;
130 ColorRGBA m_ColorFeet;
131 float m_Size;
132 bool m_GotAirJump;
133 int m_TeeRenderFlags;
134 bool m_FeetFlipped;
135
136 bool Valid() const
137 {
138 return m_CustomColoredSkin ? m_ColorableRenderSkin.m_Body.IsValid() : m_OriginalRenderSkin.m_Body.IsValid();
139 }
140
141 class CSixup
142 {
143 public:
144 void Reset()
145 {
146 for(auto &Texture : m_aOriginalTextures)
147 {
148 Texture.Invalidate();
149 }
150 for(auto &Texture : m_aColorableTextures)
151 {
152 Texture.Invalidate();
153 }
154 std::fill(first: std::begin(arr&: m_aUseCustomColors), last: std::end(arr&: m_aUseCustomColors), value: false);
155 std::fill(first: std::begin(arr&: m_aColors), last: std::end(arr&: m_aColors), value: ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
156 m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
157 m_HatTexture.Invalidate();
158 m_BotTexture.Invalidate();
159 m_HatSpriteIndex = 0;
160 m_BotColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
161 }
162
163 IGraphics::CTextureHandle m_aOriginalTextures[protocol7::NUM_SKINPARTS];
164 IGraphics::CTextureHandle m_aColorableTextures[protocol7::NUM_SKINPARTS];
165 bool m_aUseCustomColors[protocol7::NUM_SKINPARTS];
166 ColorRGBA m_aColors[protocol7::NUM_SKINPARTS];
167 ColorRGBA m_BloodColor;
168 IGraphics::CTextureHandle m_HatTexture;
169 IGraphics::CTextureHandle m_BotTexture;
170 int m_HatSpriteIndex;
171 ColorRGBA m_BotColor;
172
173 const IGraphics::CTextureHandle &PartTexture(int Part) const
174 {
175 return (m_aUseCustomColors[Part] ? m_aColorableTextures : m_aOriginalTextures)[Part];
176 }
177 };
178
179 CSixup m_aSixup[NUM_DUMMIES];
180};
181
182class CManagedTeeRenderInfo
183{
184 friend class CGameClient;
185 CTeeRenderInfo m_TeeRenderInfo;
186 CSkinDescriptor m_SkinDescriptor;
187 std::function<void()> m_RefreshCallback = nullptr;
188
189public:
190 CManagedTeeRenderInfo(const CTeeRenderInfo &TeeRenderInfo, const CSkinDescriptor &SkinDescriptor) :
191 m_TeeRenderInfo(TeeRenderInfo),
192 m_SkinDescriptor(SkinDescriptor)
193 {
194 }
195
196 CTeeRenderInfo &TeeRenderInfo() { return m_TeeRenderInfo; }
197 const CTeeRenderInfo &TeeRenderInfo() const { return m_TeeRenderInfo; }
198 const CSkinDescriptor &SkinDescriptor() const { return m_SkinDescriptor; }
199 void SetRefreshCallback(const std::function<void()> &RefreshCallback) { m_RefreshCallback = RefreshCallback; }
200};
201
202// Tee Render Flags
203enum
204{
205 TEE_EFFECT_FROZEN = 1,
206 TEE_NO_WEAPON = 2,
207 TEE_EFFECT_SPARKLE = 4,
208};
209
210class CRenderTools
211{
212 class IGraphics *m_pGraphics;
213 class ITextRender *m_pTextRender;
214
215 int m_TeeQuadContainerIndex;
216
217 static void GetRenderTeeBodyScale(float BaseSize, float &BodyScale);
218 static void GetRenderTeeFeetScale(float BaseSize, float &FeetScaleWidth, float &FeetScaleHeight);
219
220 void RenderTee6(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha = 1.0f) const;
221 void RenderTee7(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha = 1.0f) const;
222
223public:
224 class IGraphics *Graphics() const { return m_pGraphics; }
225 class ITextRender *TextRender() const { return m_pTextRender; }
226
227 void Init(class IGraphics *pGraphics, class ITextRender *pTextRender);
228
229 void RenderCursor(vec2 Center, float Size) const;
230 void RenderIcon(int ImageId, int SpriteId, const CUIRect *pRect, const ColorRGBA *pColor = nullptr) const;
231
232 // larger rendering methods
233 static void GetRenderTeeBodySize(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, vec2 &BodyOffset, float &Width, float &Height);
234 static void GetRenderTeeFeetSize(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, vec2 &FeetOffset, float &Width, float &Height);
235 static void GetRenderTeeAnimScaleAndBaseSize(const CTeeRenderInfo *pInfo, float &AnimScale, float &BaseSize);
236
237 // returns the offset to use, to render the tee with @see RenderTee exactly in the mid
238 static void GetRenderTeeOffsetToRenderedTee(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, vec2 &TeeOffsetToMid);
239 // object render methods
240 void RenderTee(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha = 1.0f) const;
241};
242
243#endif
244