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 ENGINE_TEXTRENDER_H |
4 | #define ENGINE_TEXTRENDER_H |
5 | #include "kernel.h" |
6 | |
7 | #include <base/color.h> |
8 | |
9 | #include <engine/graphics.h> |
10 | |
11 | #include <cstdint> |
12 | #include <memory> |
13 | |
14 | enum |
15 | { |
16 | TEXTFLAG_RENDER = 1 << 0, |
17 | TEXTFLAG_DISALLOW_NEWLINE = 1 << 1, |
18 | TEXTFLAG_STOP_AT_END = 1 << 2, |
19 | TEXTFLAG_ELLIPSIS_AT_END = 1 << 3, |
20 | }; |
21 | |
22 | enum ETextAlignment |
23 | { |
24 | TEXTALIGN_LEFT = 0, |
25 | TEXTALIGN_CENTER = 1 << 1, |
26 | TEXTALIGN_RIGHT = 1 << 2, |
27 | TEXTALIGN_TOP = 0, // this is also 0, so the default alignment is top-left |
28 | TEXTALIGN_MIDDLE = 1 << 3, |
29 | TEXTALIGN_BOTTOM = 1 << 4, |
30 | |
31 | TEXTALIGN_TL = TEXTALIGN_TOP | TEXTALIGN_LEFT, |
32 | TEXTALIGN_TC = TEXTALIGN_TOP | TEXTALIGN_CENTER, |
33 | TEXTALIGN_TR = TEXTALIGN_TOP | TEXTALIGN_RIGHT, |
34 | TEXTALIGN_ML = TEXTALIGN_MIDDLE | TEXTALIGN_LEFT, |
35 | TEXTALIGN_MC = TEXTALIGN_MIDDLE | TEXTALIGN_CENTER, |
36 | TEXTALIGN_MR = TEXTALIGN_MIDDLE | TEXTALIGN_RIGHT, |
37 | TEXTALIGN_BL = TEXTALIGN_BOTTOM | TEXTALIGN_LEFT, |
38 | TEXTALIGN_BC = TEXTALIGN_BOTTOM | TEXTALIGN_CENTER, |
39 | TEXTALIGN_BR = TEXTALIGN_BOTTOM | TEXTALIGN_RIGHT, |
40 | |
41 | TEXTALIGN_MASK_HORIZONTAL = TEXTALIGN_LEFT | TEXTALIGN_CENTER | TEXTALIGN_RIGHT, |
42 | TEXTALIGN_MASK_VERTICAL = TEXTALIGN_TOP | TEXTALIGN_MIDDLE | TEXTALIGN_BOTTOM, |
43 | }; |
44 | |
45 | enum ETextRenderFlags |
46 | { |
47 | TEXT_RENDER_FLAG_NO_X_BEARING = 1 << 0, |
48 | TEXT_RENDER_FLAG_NO_Y_BEARING = 1 << 1, |
49 | TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH = 1 << 2, |
50 | TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT = 1 << 3, |
51 | TEXT_RENDER_FLAG_KERNING = 1 << 4, |
52 | TEXT_RENDER_FLAG_NO_OVERSIZE = 1 << 5, |
53 | TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING = 1 << 6, |
54 | TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE = 1 << 7, |
55 | TEXT_RENDER_FLAG_NO_AUTOMATIC_QUAD_UPLOAD = 1 << 8, |
56 | // text is only rendered once and then discarded (a hint for buffer creation) |
57 | TEXT_RENDER_FLAG_ONE_TIME_USE = 1 << 9, |
58 | }; |
59 | |
60 | enum class EFontPreset |
61 | { |
62 | DEFAULT_FONT, |
63 | ICON_FONT, |
64 | }; |
65 | |
66 | namespace FontIcons { |
67 | // Each font icon is named according to its official name in Font Awesome |
68 | MAYBE_UNUSED static const char *FONT_ICON_PLUS = "+" ; |
69 | MAYBE_UNUSED static const char *FONT_ICON_MINUS = "-" ; |
70 | MAYBE_UNUSED static const char *FONT_ICON_LOCK = "\xEF\x80\xA3" ; |
71 | MAYBE_UNUSED static const char *FONT_ICON_MAGNIFYING_GLASS = "\xEF\x80\x82" ; |
72 | MAYBE_UNUSED static const char *FONT_ICON_HEART = "\xEF\x80\x84" ; |
73 | MAYBE_UNUSED static const char *FONT_ICON_STAR = "\xEF\x80\x85" ; |
74 | MAYBE_UNUSED static const char *FONT_ICON_XMARK = "\xEF\x80\x8D" ; |
75 | MAYBE_UNUSED static const char *FONT_ICON_CIRCLE = "\xEF\x84\x91" ; |
76 | MAYBE_UNUSED static const char *FONT_ICON_ARROW_ROTATE_LEFT = "\xEF\x83\xA2" ; |
77 | MAYBE_UNUSED static const char *FONT_ICON_ARROW_ROTATE_RIGHT = "\xEF\x80\x9E" ; |
78 | MAYBE_UNUSED static const char *FONT_ICON_FLAG_CHECKERED = "\xEF\x84\x9E" ; |
79 | MAYBE_UNUSED static const char *FONT_ICON_BAN = "\xEF\x81\x9E" ; |
80 | MAYBE_UNUSED static const char *FONT_ICON_CIRCLE_CHEVRON_DOWN = "\xEF\x84\xBA" ; |
81 | MAYBE_UNUSED static const char *FONT_ICON_SQUARE_MINUS = "\xEF\x85\x86" ; |
82 | MAYBE_UNUSED static const char *FONT_ICON_SQUARE_PLUS = "\xEF\x83\xBE" ; |
83 | MAYBE_UNUSED static const char *FONT_ICON_SORT_UP = "\xEF\x83\x9E" ; |
84 | MAYBE_UNUSED static const char *FONT_ICON_SORT_DOWN = "\xEF\x83\x9D" ; |
85 | |
86 | MAYBE_UNUSED static const char *FONT_ICON_HOUSE = "\xEF\x80\x95" ; |
87 | MAYBE_UNUSED static const char *FONT_ICON_NEWSPAPER = "\xEF\x87\xAA" ; |
88 | MAYBE_UNUSED static const char *FONT_ICON_POWER_OFF = "\xEF\x80\x91" ; |
89 | MAYBE_UNUSED static const char *FONT_ICON_GEAR = "\xEF\x80\x93" ; |
90 | MAYBE_UNUSED static const char *FONT_ICON_PEN_TO_SQUARE = "\xEF\x81\x84" ; |
91 | MAYBE_UNUSED static const char *FONT_ICON_CLAPPERBOARD = "\xEE\x84\xB1" ; |
92 | MAYBE_UNUSED static const char *FONT_ICON_EARTH_AMERICAS = "\xEF\x95\xBD" ; |
93 | MAYBE_UNUSED static const char *FONT_ICON_NETWORK_WIRED = "\xEF\x9B\xBF" ; |
94 | MAYBE_UNUSED static const char *FONT_ICON_LIST_UL = "\xEF\x83\x8A" ; |
95 | MAYBE_UNUSED static const char *FONT_ICON_INFO = "\xEF\x84\xA9" ; |
96 | |
97 | MAYBE_UNUSED static const char *FONT_ICON_SLASH = "\xEF\x9C\x95" ; |
98 | MAYBE_UNUSED static const char *FONT_ICON_PLAY = "\xEF\x81\x8B" ; |
99 | MAYBE_UNUSED static const char *FONT_ICON_PAUSE = "\xEF\x81\x8C" ; |
100 | MAYBE_UNUSED static const char *FONT_ICON_STOP = "\xEF\x81\x8D" ; |
101 | MAYBE_UNUSED static const char *FONT_ICON_CHEVRON_LEFT = "\xEF\x81\x93" ; |
102 | MAYBE_UNUSED static const char *FONT_ICON_CHEVRON_RIGHT = "\xEF\x81\x94" ; |
103 | MAYBE_UNUSED static const char *FONT_ICON_CHEVRON_UP = "\xEF\x81\xB7" ; |
104 | MAYBE_UNUSED static const char *FONT_ICON_CHEVRON_DOWN = "\xEF\x81\xB8" ; |
105 | MAYBE_UNUSED static const char *FONT_ICON_BACKWARD = "\xEF\x81\x8A" ; |
106 | MAYBE_UNUSED static const char *FONT_ICON_FORWARD = "\xEF\x81\x8E" ; |
107 | MAYBE_UNUSED static const char *FONT_ICON_RIGHT_FROM_BRACKET = "\xEF\x8B\xB5" ; |
108 | MAYBE_UNUSED static const char *FONT_ICON_RIGHT_TO_BRACKET = "\xEF\x8B\xB6" ; |
109 | MAYBE_UNUSED static const char *FONT_ICON_ARROW_UP_RIGHT_FROM_SQUARE = "\xEF\x82\x8E" ; |
110 | MAYBE_UNUSED static const char *FONT_ICON_BACKWARD_STEP = "\xEF\x81\x88" ; |
111 | MAYBE_UNUSED static const char *FONT_ICON_FORWARD_STEP = "\xEF\x81\x91" ; |
112 | MAYBE_UNUSED static const char *FONT_ICON_BACKWARD_FAST = "\xEF\x81\x89" ; |
113 | MAYBE_UNUSED static const char *FONT_ICON_FORWARD_FAST = "\xEF\x81\x90" ; |
114 | MAYBE_UNUSED static const char *FONT_ICON_KEYBOARD = "\xE2\x8C\xA8" ; |
115 | MAYBE_UNUSED static const char *FONT_ICON_ELLIPSIS = "\xEF\x85\x81" ; |
116 | |
117 | MAYBE_UNUSED static const char *FONT_ICON_FOLDER = "\xEF\x81\xBB" ; |
118 | MAYBE_UNUSED static const char *FONT_ICON_FOLDER_OPEN = "\xEF\x81\xBC" ; |
119 | MAYBE_UNUSED static const char *FONT_ICON_FOLDER_TREE = "\xEF\xA0\x82" ; |
120 | MAYBE_UNUSED static const char *FONT_ICON_FILM = "\xEF\x80\x88" ; |
121 | MAYBE_UNUSED static const char *FONT_ICON_VIDEO = "\xEF\x80\xBD" ; |
122 | MAYBE_UNUSED static const char *FONT_ICON_MAP = "\xEF\x89\xB9" ; |
123 | MAYBE_UNUSED static const char *FONT_ICON_IMAGE = "\xEF\x80\xBE" ; |
124 | MAYBE_UNUSED static const char *FONT_ICON_MUSIC = "\xEF\x80\x81" ; |
125 | MAYBE_UNUSED static const char *FONT_ICON_FILE = "\xEF\x85\x9B" ; |
126 | |
127 | MAYBE_UNUSED static const char *FONT_ICON_PENCIL = "\xEF\x8C\x83" ; |
128 | MAYBE_UNUSED static const char *FONT_ICON_TRASH = "\xEF\x87\xB8" ; |
129 | |
130 | MAYBE_UNUSED static const char *FONT_ICON_ARROWS_LEFT_RIGHT = "\xEF\x8C\xB7" ; |
131 | MAYBE_UNUSED static const char *FONT_ICON_ARROWS_UP_DOWN = "\xEF\x81\xBD" ; |
132 | MAYBE_UNUSED static const char *FONT_ICON_CIRCLE_PLAY = "\xEF\x85\x84" ; |
133 | MAYBE_UNUSED static const char *FONT_ICON_BORDER_ALL = "\xEF\xA1\x8C" ; |
134 | MAYBE_UNUSED static const char *FONT_ICON_EYE = "\xEF\x81\xAE" ; |
135 | MAYBE_UNUSED static const char *FONT_ICON_EYE_SLASH = "\xEF\x81\xB0" ; |
136 | MAYBE_UNUSED static const char *FONT_ICON_EYE_DROPPER = "\xEF\x87\xBB" ; |
137 | |
138 | MAYBE_UNUSED static const char *FONT_ICON_DICE_ONE = "\xEF\x94\xA5" ; |
139 | MAYBE_UNUSED static const char *FONT_ICON_DICE_TWO = "\xEF\x94\xA8" ; |
140 | MAYBE_UNUSED static const char *FONT_ICON_DICE_THREE = "\xEF\x94\xA7" ; |
141 | MAYBE_UNUSED static const char *FONT_ICON_DICE_FOUR = "\xEF\x94\xA4" ; |
142 | MAYBE_UNUSED static const char *FONT_ICON_DICE_FIVE = "\xEF\x94\xA3" ; |
143 | MAYBE_UNUSED static const char *FONT_ICON_DICE_SIX = "\xEF\x94\xA6" ; |
144 | |
145 | MAYBE_UNUSED static const char *FONT_ICON_LAYER_GROUP = "\xEF\x97\xBD" ; |
146 | MAYBE_UNUSED static const char *FONT_ICON_UNDO = "\xEF\x8B\xAA" ; |
147 | MAYBE_UNUSED static const char *FONT_ICON_REDO = "\xEF\x8B\xB9" ; |
148 | |
149 | MAYBE_UNUSED static const char *FONT_ICON_ARROWS_ROTATE = "\xEF\x80\xA1" ; |
150 | MAYBE_UNUSED static const char *FONT_ICON_QUESTION = "?" ; |
151 | } // end namespace FontIcons |
152 | |
153 | enum ETextCursorSelectionMode |
154 | { |
155 | // ignore any kind of selection |
156 | TEXT_CURSOR_SELECTION_MODE_NONE = 0, |
157 | // calculates the selection based on the mouse press and release cursor position |
158 | TEXT_CURSOR_SELECTION_MODE_CALCULATE, |
159 | // sets the selection based on the character start and end count(these values have to be decoded character offsets) |
160 | TEXT_CURSOR_SELECTION_MODE_SET, |
161 | }; |
162 | |
163 | enum ETextCursorCursorMode |
164 | { |
165 | // ignore any kind of cursor |
166 | TEXT_CURSOR_CURSOR_MODE_NONE = 0, |
167 | // calculates the cursor based on the mouse release cursor position |
168 | TEXT_CURSOR_CURSOR_MODE_CALCULATE, |
169 | // sets the cursor based on the current character (this value has to be decoded character offset) |
170 | TEXT_CURSOR_CURSOR_MODE_SET, |
171 | }; |
172 | |
173 | struct STextBoundingBox |
174 | { |
175 | float m_X; |
176 | float m_Y; |
177 | float m_W; |
178 | float m_H; |
179 | |
180 | float Right() const { return m_X + m_W; } |
181 | float Bottom() const { return m_Y + m_H; } |
182 | vec2 Size() const { return vec2(m_W, m_H); } |
183 | void MoveBy(vec2 Offset) |
184 | { |
185 | m_X += Offset.x; |
186 | m_Y += Offset.y; |
187 | } |
188 | }; |
189 | |
190 | // Allow to render multi colored text in one go without having to call TextEx() multiple times. |
191 | // Needed to allow multi colored multi line texts |
192 | struct STextColorSplit |
193 | { |
194 | int m_CharIndex; // Which index within the text should the split occur |
195 | int m_Length; // How long is the split |
196 | ColorRGBA m_Color; // The color the text should be starting from m_CharIndex |
197 | |
198 | STextColorSplit(int CharIndex, int Length, const ColorRGBA &Color) : |
199 | m_CharIndex(CharIndex), m_Length(Length), m_Color(Color) {} |
200 | }; |
201 | |
202 | class CTextCursor |
203 | { |
204 | public: |
205 | int m_Flags; |
206 | int m_LineCount; |
207 | int m_GlyphCount; |
208 | int m_CharCount; |
209 | int m_MaxLines; |
210 | |
211 | float m_StartX; |
212 | float m_StartY; |
213 | float m_LineWidth; |
214 | float m_X, m_Y; |
215 | float m_MaxCharacterHeight; |
216 | float m_LongestLineWidth; |
217 | |
218 | float m_FontSize; |
219 | float m_AlignedFontSize; |
220 | float m_LineSpacing; |
221 | float m_AlignedLineSpacing; |
222 | |
223 | ETextCursorSelectionMode m_CalculateSelectionMode; |
224 | float m_SelectionHeightFactor; |
225 | |
226 | // these coordinates are respected if selection mode is set to calculate @see ETextCursorSelectionMode |
227 | vec2 m_PressMouse; |
228 | // these coordinates are respected if selection/cursor mode is set to calculate @see ETextCursorSelectionMode / @see ETextCursorCursorMode |
229 | vec2 m_ReleaseMouse; |
230 | |
231 | // note m_SelectionStart can be bigger than m_SelectionEnd, depending on how the mouse cursor was dragged |
232 | // also note, that these are the character offsets decoded |
233 | int m_SelectionStart; |
234 | int m_SelectionEnd; |
235 | |
236 | ETextCursorCursorMode m_CursorMode; |
237 | bool m_ForceCursorRendering; |
238 | // note this is the decoded character offset |
239 | int m_CursorCharacter; |
240 | vec2 m_CursorRenderedPosition; |
241 | |
242 | // Color splits of the cursor to allow multicolored text |
243 | std::vector<STextColorSplit> m_vColorSplits; |
244 | |
245 | float Height() const |
246 | { |
247 | return m_LineCount * (m_AlignedFontSize + m_AlignedLineSpacing); |
248 | } |
249 | |
250 | STextBoundingBox BoundingBox() const |
251 | { |
252 | return {.m_X: m_StartX, .m_Y: m_StartY, .m_W: m_LongestLineWidth, .m_H: Height()}; |
253 | } |
254 | |
255 | void Reset() |
256 | { |
257 | m_Flags = 0; |
258 | m_LineCount = 0; |
259 | m_GlyphCount = 0; |
260 | m_CharCount = 0; |
261 | m_MaxLines = 0; |
262 | m_StartX = 0; |
263 | m_StartY = 0; |
264 | m_LineWidth = 0; |
265 | m_X = 0; |
266 | m_Y = 0; |
267 | m_MaxCharacterHeight = 0; |
268 | m_LongestLineWidth = 0; |
269 | m_FontSize = 0; |
270 | m_AlignedFontSize = 0; |
271 | m_LineSpacing = 0; |
272 | m_CalculateSelectionMode = TEXT_CURSOR_SELECTION_MODE_NONE; |
273 | m_SelectionHeightFactor = 0; |
274 | m_PressMouse = vec2(); |
275 | m_ReleaseMouse = vec2(); |
276 | m_SelectionStart = 0; |
277 | m_SelectionEnd = 0; |
278 | m_CursorMode = TEXT_CURSOR_CURSOR_MODE_NONE; |
279 | m_ForceCursorRendering = false; |
280 | m_CursorCharacter = 0; |
281 | m_CursorRenderedPosition = vec2(); |
282 | m_vColorSplits.clear(); |
283 | } |
284 | }; |
285 | |
286 | struct STextContainerUsages |
287 | { |
288 | int m_Dummy = 0; |
289 | }; |
290 | |
291 | struct STextContainerIndex |
292 | { |
293 | int m_Index; |
294 | std::shared_ptr<STextContainerUsages> m_UseCount = |
295 | std::make_shared<STextContainerUsages>(args: STextContainerUsages()); |
296 | |
297 | STextContainerIndex() { Reset(); } |
298 | bool Valid() const { return m_Index >= 0; } |
299 | void Reset() { m_Index = -1; } |
300 | }; |
301 | |
302 | struct STextSizeProperties |
303 | { |
304 | float *m_pHeight = nullptr; |
305 | float *m_pAlignedFontSize = nullptr; |
306 | float *m_pMaxCharacterHeightInLine = nullptr; |
307 | int *m_pLineCount = nullptr; |
308 | }; |
309 | |
310 | class ITextRender : public IInterface |
311 | { |
312 | MACRO_INTERFACE("textrender" ) |
313 | public: |
314 | virtual void SetCursor(CTextCursor *pCursor, float x, float y, float FontSize, int Flags) const = 0; |
315 | virtual void MoveCursor(CTextCursor *pCursor, float x, float y) const = 0; |
316 | virtual void SetCursorPosition(CTextCursor *pCursor, float x, float y) const = 0; |
317 | |
318 | virtual void LoadFonts() = 0; |
319 | virtual void SetFontPreset(EFontPreset FontPreset) = 0; |
320 | virtual void SetFontLanguageVariant(const char *pLanguageFile) = 0; |
321 | |
322 | virtual void SetRenderFlags(unsigned Flags) = 0; |
323 | virtual unsigned GetRenderFlags() const = 0; |
324 | |
325 | ColorRGBA DefaultTextColor() const { return ColorRGBA(1, 1, 1, 1); } |
326 | ColorRGBA DefaultTextOutlineColor() const { return ColorRGBA(0, 0, 0, 0.3f); } |
327 | ColorRGBA DefaultTextSelectionColor() const { return ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f); } |
328 | |
329 | // |
330 | virtual void TextEx(CTextCursor *pCursor, const char *pText, int Length = -1) = 0; |
331 | virtual bool CreateTextContainer(STextContainerIndex &TextContainerIndex, CTextCursor *pCursor, const char *pText, int Length = -1) = 0; |
332 | virtual void AppendTextContainer(STextContainerIndex TextContainerIndex, CTextCursor *pCursor, const char *pText, int Length = -1) = 0; |
333 | // either creates a new text container or appends to a existing one |
334 | virtual bool CreateOrAppendTextContainer(STextContainerIndex &TextContainerIndex, CTextCursor *pCursor, const char *pText, int Length = -1) = 0; |
335 | // just deletes and creates text container |
336 | virtual void RecreateTextContainer(STextContainerIndex &TextContainerIndex, CTextCursor *pCursor, const char *pText, int Length = -1) = 0; |
337 | virtual void RecreateTextContainerSoft(STextContainerIndex &TextContainerIndex, CTextCursor *pCursor, const char *pText, int Length = -1) = 0; |
338 | virtual void DeleteTextContainer(STextContainerIndex &TextContainerIndex) = 0; |
339 | |
340 | virtual void UploadTextContainer(STextContainerIndex TextContainerIndex) = 0; |
341 | |
342 | virtual void RenderTextContainer(STextContainerIndex TextContainerIndex, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor) = 0; |
343 | virtual void RenderTextContainer(STextContainerIndex TextContainerIndex, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor, float X, float Y) = 0; |
344 | |
345 | virtual STextBoundingBox GetBoundingBoxTextContainer(STextContainerIndex TextContainerIndex) = 0; |
346 | |
347 | virtual void UploadEntityLayerText(const CImageInfo &TextImage, int TexSubWidth, int TexSubHeight, const char *pText, int Length, float x, float y, int FontSize) = 0; |
348 | virtual int AdjustFontSize(const char *pText, int TextLength, int MaxSize, int MaxWidth) const = 0; |
349 | virtual float GetGlyphOffsetX(int FontSize, char TextCharacter) const = 0; |
350 | virtual int CalculateTextWidth(const char *pText, int TextLength, int FontWidth, int FontSize) const = 0; |
351 | |
352 | // old foolish interface |
353 | virtual void TextColor(float r, float g, float b, float a) = 0; |
354 | virtual void TextColor(ColorRGBA rgb) = 0; |
355 | virtual void TextOutlineColor(float r, float g, float b, float a) = 0; |
356 | virtual void TextOutlineColor(ColorRGBA rgb) = 0; |
357 | virtual void TextSelectionColor(float r, float g, float b, float a) = 0; |
358 | virtual void TextSelectionColor(ColorRGBA rgb) = 0; |
359 | virtual void Text(float x, float y, float Size, const char *pText, float LineWidth = -1.0f) = 0; |
360 | virtual float TextWidth(float Size, const char *pText, int StrLength = -1, float LineWidth = -1.0f, int Flags = 0, const STextSizeProperties &TextSizeProps = {}) = 0; |
361 | virtual STextBoundingBox TextBoundingBox(float Size, const char *pText, int StrLength = -1, float LineWidth = -1.0f, float LineSpacing = 0.0f, int Flags = 0) = 0; |
362 | |
363 | virtual ColorRGBA GetTextColor() const = 0; |
364 | virtual ColorRGBA GetTextOutlineColor() const = 0; |
365 | virtual ColorRGBA GetTextSelectionColor() const = 0; |
366 | |
367 | virtual void OnPreWindowResize() = 0; |
368 | virtual void OnWindowResize() = 0; |
369 | }; |
370 | |
371 | class IEngineTextRender : public ITextRender |
372 | { |
373 | MACRO_INTERFACE("enginetextrender" ) |
374 | public: |
375 | virtual void Init() = 0; |
376 | virtual void Shutdown() override = 0; |
377 | }; |
378 | |
379 | extern IEngineTextRender *CreateEngineTextRender(); |
380 | |
381 | #endif |
382 | |