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_GRAPHICS_H
4#define ENGINE_GRAPHICS_H
5
6#include "image.h"
7#include "kernel.h"
8#include "warning.h"
9
10#include <base/color.h>
11#include <base/vmath.h>
12
13#include <cstddef>
14#include <cstdint>
15#include <functional>
16#include <optional>
17#include <vector>
18
19#define GRAPHICS_TYPE_UNSIGNED_BYTE 0x1401
20#define GRAPHICS_TYPE_UNSIGNED_SHORT 0x1403
21#define GRAPHICS_TYPE_INT 0x1404
22#define GRAPHICS_TYPE_UNSIGNED_INT 0x1405
23#define GRAPHICS_TYPE_FLOAT 0x1406
24
25struct SBufferContainerInfo
26{
27 int m_Stride;
28 int m_VertBufferBindingIndex;
29
30 // the attributes of the container
31 struct SAttribute
32 {
33 int m_DataTypeCount;
34 unsigned int m_Type;
35 bool m_Normalized;
36 void *m_pOffset;
37
38 //0: float, 1:integer
39 unsigned int m_FuncType;
40 };
41 std::vector<SAttribute> m_vAttributes;
42};
43
44struct SQuadRenderInfo
45{
46 ColorRGBA m_Color;
47 vec2 m_Offsets;
48 float m_Rotation;
49 // allows easier upload for uniform buffers because of the alignment requirements
50 float m_Padding;
51};
52
53class CGraphicTile
54{
55public:
56 vec2 m_TopLeft;
57 vec2 m_TopRight;
58 vec2 m_BottomRight;
59 vec2 m_BottomLeft;
60};
61
62class CGraphicTileTextureCoords
63{
64public:
65 ubvec4 m_TexCoordTopLeft;
66 ubvec4 m_TexCoordTopRight;
67 ubvec4 m_TexCoordBottomRight;
68 ubvec4 m_TexCoordBottomLeft;
69};
70
71/*
72 Structure: CVideoMode
73*/
74class CVideoMode
75{
76public:
77 int m_CanvasWidth, m_CanvasHeight;
78 int m_WindowWidth, m_WindowHeight;
79 int m_RefreshRate;
80};
81
82typedef vec2 GL_SPoint;
83typedef vec2 GL_STexCoord;
84
85struct GL_STexCoord3D
86{
87 GL_STexCoord3D &operator=(const GL_STexCoord &TexCoord)
88 {
89 u = TexCoord.u;
90 v = TexCoord.v;
91 return *this;
92 }
93
94 GL_STexCoord3D &operator=(const vec3 &TexCoord)
95 {
96 u = TexCoord.u;
97 v = TexCoord.v;
98 w = TexCoord.w;
99 return *this;
100 }
101
102 float u, v, w;
103};
104
105typedef ColorRGBA GL_SColorf;
106//use normalized color values
107typedef vector4_base<unsigned char> GL_SColor;
108
109struct GL_SVertex
110{
111 GL_SPoint m_Pos;
112 GL_STexCoord m_Tex;
113 GL_SColor m_Color;
114};
115
116struct GL_SVertexTex3D
117{
118 GL_SPoint m_Pos;
119 GL_SColorf m_Color;
120 GL_STexCoord3D m_Tex;
121};
122
123struct GL_SVertexTex3DStream
124{
125 GL_SPoint m_Pos;
126 GL_SColor m_Color;
127 GL_STexCoord3D m_Tex;
128};
129
130static constexpr size_t GRAPHICS_MAX_QUADS_RENDER_COUNT = 256;
131static constexpr size_t GRAPHICS_MAX_PARTICLES_RENDER_COUNT = 512;
132
133enum EGraphicsDriverAgeType
134{
135 GRAPHICS_DRIVER_AGE_TYPE_LEGACY = 0,
136 GRAPHICS_DRIVER_AGE_TYPE_DEFAULT,
137 GRAPHICS_DRIVER_AGE_TYPE_MODERN,
138
139 GRAPHICS_DRIVER_AGE_TYPE_COUNT,
140};
141
142enum EBackendType
143{
144 BACKEND_TYPE_OPENGL = 0,
145 BACKEND_TYPE_OPENGL_ES,
146 BACKEND_TYPE_VULKAN,
147
148 // special value to tell the backend to identify the current backend
149 BACKEND_TYPE_AUTO,
150
151 BACKEND_TYPE_COUNT,
152};
153
154struct STWGraphicGpu
155{
156 enum ETWGraphicsGpuType
157 {
158 GRAPHICS_GPU_TYPE_DISCRETE = 0,
159 GRAPHICS_GPU_TYPE_INTEGRATED,
160 GRAPHICS_GPU_TYPE_VIRTUAL,
161 GRAPHICS_GPU_TYPE_CPU,
162
163 // should stay at last position in this enum
164 GRAPHICS_GPU_TYPE_INVALID,
165 };
166
167 struct STWGraphicGpuItem
168 {
169 char m_aName[256];
170 ETWGraphicsGpuType m_GpuType;
171 };
172 std::vector<STWGraphicGpuItem> m_vGpus;
173 STWGraphicGpuItem m_AutoGpu;
174};
175
176typedef STWGraphicGpu TTwGraphicsGpuList;
177
178typedef std::function<void()> WINDOW_RESIZE_FUNC;
179typedef std::function<void()> WINDOW_PROPS_CHANGED_FUNC;
180
181typedef std::function<bool(uint32_t &Width, uint32_t &Height, CImageInfo::EImageFormat &Format, std::vector<uint8_t> &vDstData)> TGLBackendReadPresentedImageData;
182
183struct CDataSprite;
184
185class CScreenRect
186{
187public:
188 CScreenRect(float Left, float Top, float Width, float Height) :
189 m_TopLeft(Left, Top), m_BottomRight(Left + Width, Top + Height) {}
190
191 CScreenRect(const vec2 &TopLeft, const vec2 &BottomRight) :
192 m_TopLeft(TopLeft), m_BottomRight(BottomRight) {}
193
194 CScreenRect Move(const vec2 &Position) const
195 {
196 CScreenRect Rect(*this);
197 Rect.m_TopLeft += Position;
198 Rect.m_BottomRight += Position;
199 return Rect;
200 }
201
202 constexpr vec2 Size() const
203 {
204 return m_BottomRight - m_TopLeft;
205 }
206
207 constexpr float Width() const
208 {
209 return m_BottomRight.x - m_TopLeft.x;
210 }
211
212 constexpr float Height() const
213 {
214 return m_BottomRight.y - m_TopLeft.y;
215 }
216
217 constexpr bool Inside(const vec2 &Position) const
218 {
219 return !(!in_range(a: Position.x, lower: m_TopLeft.x, upper: m_BottomRight.x) || !in_range(a: Position.y, lower: m_TopLeft.y, upper: m_BottomRight.y));
220 }
221
222 void Expand(float Width, float Height)
223 {
224 m_TopLeft.x -= Width;
225 m_BottomRight.x += Width;
226 m_TopLeft.y -= Height;
227 m_BottomRight.y += Height;
228 }
229
230 void Expand(float Size)
231 {
232 Expand(Width: Size, Height: Size);
233 }
234
235 vec2 m_TopLeft;
236 vec2 m_BottomRight;
237};
238
239class IGraphics : public IInterface
240{
241 MACRO_INTERFACE("graphics")
242protected:
243 int m_ScreenWidth;
244 int m_ScreenHeight;
245 int m_ScreenRefreshRate;
246 float m_ScreenHiDPIScale;
247 ivec2 m_DesktopSize;
248
249public:
250 enum
251 {
252 TEXLOAD_TO_3D_TEXTURE = 1 << 0,
253 TEXLOAD_TO_2D_ARRAY_TEXTURE = 1 << 1,
254 TEXLOAD_NO_2D_TEXTURE = 1 << 2,
255 };
256
257 class CTextureHandle
258 {
259 friend class IGraphics;
260 int m_Id;
261
262 public:
263 CTextureHandle() :
264 m_Id(-1)
265 {
266 }
267
268 bool IsValid() const { return Id() >= 0; }
269 bool IsNullTexture() const { return Id() == 0; }
270 int Id() const { return m_Id; }
271 void Invalidate() { m_Id = -1; }
272 };
273
274 int ScreenWidth() const { return m_ScreenWidth; }
275 int ScreenHeight() const { return m_ScreenHeight; }
276 vec2 ScreenSize() const { return vec2(m_ScreenWidth, m_ScreenHeight); }
277 float ScreenAspect() const { return (float)ScreenWidth() / (float)ScreenHeight(); }
278 float ScreenHiDPIScale() const { return m_ScreenHiDPIScale; }
279 int WindowWidth() const { return m_ScreenWidth / m_ScreenHiDPIScale; }
280 int WindowHeight() const { return m_ScreenHeight / m_ScreenHiDPIScale; }
281
282 virtual void WarnPngliteIncompatibleImages(bool Warn) = 0;
283 virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0;
284 virtual bool SetWindowScreen(int Index, bool MoveToCenter) = 0;
285 virtual bool SwitchWindowScreen(int Index, bool MoveToCenter) = 0;
286 virtual bool SetVSync(bool State) = 0;
287 virtual bool SetMultiSampling(uint32_t ReqMultiSamplingCount, uint32_t &MultiSamplingCountBackend) = 0;
288 virtual int GetWindowScreen() = 0;
289 virtual void Move(int x, int y) = 0;
290 virtual bool Resize(int w, int h, int RefreshRate) = 0;
291 virtual void ResizeToScreen() = 0;
292 virtual void GotResized(int w, int h, int RefreshRate) = 0;
293 virtual void UpdateViewport(int X, int Y, int W, int H, bool ByResize) = 0;
294 virtual bool IsScreenKeyboardShown() = 0;
295
296 /**
297 * Listens to a resize event of the canvas, which is usually caused by a window resize.
298 * Will only be triggered if the actual size changed.
299 */
300 virtual void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc) = 0;
301 /**
302 * Listens to various window property changes, such as minimize, maximize, move, fullscreen mode
303 */
304 virtual void AddWindowPropChangeListener(WINDOW_PROPS_CHANGED_FUNC pFunc) = 0;
305
306 virtual void WindowDestroyNtf(uint32_t WindowId) = 0;
307 virtual void WindowCreateNtf(uint32_t WindowId) = 0;
308
309 // ForceClearNow forces the backend to trigger a clear, even at performance cost, else it might be delayed by one frame
310 virtual void Clear(float r, float g, float b, bool ForceClearNow = false) = 0;
311
312 virtual void ClipEnable(int x, int y, int w, int h) = 0;
313 virtual void ClipDisable() = 0;
314
315 virtual void MapScreen(const CScreenRect &ScreenRect) = 0;
316
317 // helper functions
318 void CalcScreenParams(float Aspect, float Zoom, float *pWidth, float *pHeight) const;
319 CScreenRect MapScreenToWorld(float CenterX, float CenterY, float ParallaxX, float ParallaxY,
320 float ParallaxZoom, float OffsetX, float OffsetY, float Aspect, float Zoom) const;
321 void MapScreenToInterface(float CenterX, float CenterY, float Zoom = 1.0f);
322 void MapScreenToSize(float Width, float Height);
323
324 virtual CScreenRect GetScreen() const = 0;
325
326 // TODO: These should perhaps not be virtuals
327 virtual void BlendNone() = 0;
328 virtual void BlendNormal() = 0;
329 virtual void BlendAdditive() = 0;
330 virtual void WrapNormal() = 0;
331 virtual void WrapClamp() = 0;
332
333 virtual uint64_t TextureMemoryUsage() const = 0;
334 virtual uint64_t BufferMemoryUsage() const = 0;
335 virtual uint64_t StreamedMemoryUsage() const = 0;
336 virtual uint64_t StagingMemoryUsage() const = 0;
337
338 virtual const TTwGraphicsGpuList &GetGpus() const = 0;
339
340 virtual bool LoadPng(CImageInfo &Image, const char *pFilename, int StorageType) = 0;
341 virtual bool LoadPng(CImageInfo &Image, const uint8_t *pData, size_t DataSize, const char *pContextName) = 0;
342
343 virtual bool CheckImageDivisibility(const char *pContextName, CImageInfo &Image, int DivX, int DivY, bool AllowResize) = 0;
344 virtual bool IsImageFormatRgba(const char *pContextName, const CImageInfo &Image) = 0;
345
346 virtual void UnloadTexture(CTextureHandle *pIndex) = 0;
347 virtual CTextureHandle LoadTextureRaw(const CImageInfo &Image, int Flags, const char *pTexName = nullptr) = 0;
348 virtual CTextureHandle LoadTextureRawMove(CImageInfo &Image, int Flags, const char *pTexName = nullptr) = 0;
349 virtual CTextureHandle LoadTexture(const char *pFilename, int StorageType, int Flags = 0) = 0;
350 virtual void TextureSet(CTextureHandle Texture) = 0;
351 void TextureClear() { TextureSet(Texture: CTextureHandle()); }
352
353 // pTextData & pTextOutlineData are automatically free'd
354 virtual bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) = 0;
355 virtual bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) = 0;
356 virtual bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer) = 0;
357
358 virtual CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const std::optional<CImageInfo> &FallbackImageInfo, const struct CDataSprite *pSprite) = 0;
359
360 virtual bool IsImageSubFullyTransparent(const CImageInfo &FromImageInfo, int x, int y, int w, int h) = 0;
361 virtual bool IsSpriteTextureFullyTransparent(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) = 0;
362
363 virtual void FlushVertices(bool KeepVertices = false) = 0;
364 virtual void FlushVerticesTex3D() = 0;
365
366 // specific render functions
367 virtual void RenderTileLayer(int BufferContainerIndex, const ColorRGBA &Color, char **pOffsets, unsigned int *pIndicedVertexDrawNum, size_t NumIndicesOffset) = 0;
368 virtual void RenderBorderTiles(int BufferContainerIndex, const ColorRGBA &Color, char *pIndexBufferOffset, const vec2 &Offset, const vec2 &Scale, uint32_t DrawNum) = 0;
369 virtual void RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, size_t QuadNum, int QuadOffset, bool Grouped = false) = 0;
370 virtual void RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor) = 0;
371
372 // opengl 3.3 functions
373
374 enum EBufferObjectCreateFlags
375 {
376 // tell the backend that the buffer only needs to be valid for the span of one frame. Buffer size is not allowed to be bigger than GL_SVertex * MAX_VERTICES
377 BUFFER_OBJECT_CREATE_FLAGS_ONE_TIME_USE_BIT = 1 << 0,
378 };
379
380 // if a pointer is passed as moved pointer, it requires to be allocated with malloc()
381 virtual int CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) = 0;
382 virtual void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) = 0;
383 virtual void DeleteBufferObject(int BufferIndex) = 0;
384
385 virtual int CreateBufferContainer(struct SBufferContainerInfo *pContainerInfo) = 0;
386 // destroying all buffer objects means, that all referenced VBOs are destroyed automatically, so the user does not need to save references to them
387 virtual void DeleteBufferContainer(int &ContainerIndex, bool DestroyAllBO = true) = 0;
388 virtual void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) = 0;
389
390 // returns true if the driver age type is supported, passing BACKEND_TYPE_AUTO for BackendType will query the values for the currently used backend
391 virtual bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) = 0;
392 virtual bool IsConfigModernAPI() = 0;
393 virtual bool IsTileBufferingEnabled() = 0;
394 virtual bool IsQuadBufferingEnabled() = 0;
395 virtual bool IsTextBufferingEnabled() = 0;
396 virtual bool IsQuadContainerBufferingEnabled() = 0;
397 virtual bool Uses2DTextureArrays() = 0;
398 virtual int TextureLoadFlags() = 0;
399 virtual bool HasTextureArraysSupport() = 0;
400
401 virtual const char *GetVendorString() = 0;
402 virtual const char *GetVersionString() = 0;
403 virtual const char *GetRendererString() = 0;
404 virtual const char *GetFatalError() const = 0;
405
406 class CLineItem
407 {
408 public:
409 float m_X0, m_Y0, m_X1, m_Y1;
410 CLineItem() = default;
411 CLineItem(float x0, float y0, float x1, float y1) :
412 m_X0(x0), m_Y0(y0), m_X1(x1), m_Y1(y1) {}
413 CLineItem(vec2 From, vec2 To)
414 {
415 m_X0 = From.x;
416 m_Y0 = From.y;
417 m_X1 = To.x;
418 m_Y1 = To.y;
419 }
420 };
421 virtual void LinesBegin() = 0;
422 virtual void LinesEnd() = 0;
423 virtual void LinesDraw(const CLineItem *pArray, size_t Num) = 0;
424
425 class CLineItemBatch
426 {
427 public:
428 IGraphics::CLineItem m_aItems[256];
429 size_t m_NumItems = 0;
430 };
431 virtual void LinesBatchBegin(CLineItemBatch *pBatch) = 0;
432 virtual void LinesBatchEnd(CLineItemBatch *pBatch) = 0;
433 virtual void LinesBatchDraw(CLineItemBatch *pBatch, const CLineItem *pArray, size_t Num) = 0;
434
435 virtual void QuadsBegin() = 0;
436 virtual void QuadsEnd() = 0;
437 virtual void QuadsTex3DBegin() = 0;
438 virtual void QuadsTex3DEnd() = 0;
439 virtual void TrianglesBegin() = 0;
440 virtual void TrianglesEnd() = 0;
441 virtual void QuadsEndKeepVertices() = 0;
442 virtual void QuadsDrawCurrentVertices(bool KeepVertices = true) = 0;
443 virtual void QuadsSetRotation(float Angle) = 0;
444 virtual void QuadsSetSubset(float TopLeftU, float TopLeftV, float BottomRightU, float BottomRightV) = 0;
445 virtual void QuadsSetSubsetFree(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, int Index = -1) = 0;
446
447 struct CFreeformItem
448 {
449 float m_X0, m_Y0, m_X1, m_Y1, m_X2, m_Y2, m_X3, m_Y3;
450 CFreeformItem() = default;
451 CFreeformItem(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) :
452 m_X0(x0), m_Y0(y0), m_X1(x1), m_Y1(y1), m_X2(x2), m_Y2(y2), m_X3(x3), m_Y3(y3) {}
453 CFreeformItem(vec2 Point1, vec2 Point2, vec2 Point3, vec2 Point4) :
454 m_X0(Point1.x), m_Y0(Point1.y), m_X1(Point2.x), m_Y1(Point2.y), m_X2(Point3.x), m_Y2(Point3.y), m_X3(Point4.x), m_Y3(Point4.y) {}
455 };
456
457 struct CQuadItem
458 {
459 float m_X, m_Y, m_Width, m_Height;
460 CQuadItem() = default;
461 CQuadItem(float x, float y, float w, float h) :
462 m_X(x), m_Y(y), m_Width(w), m_Height(h) {}
463 CQuadItem(vec2 Position, vec2 Size) :
464 m_X(Position.x), m_Y(Position.y), m_Width(Size.x), m_Height(Size.y) {}
465 };
466 virtual void QuadsDraw(CQuadItem *pArray, int Num) = 0;
467 virtual void QuadsDrawTL(const CQuadItem *pArray, int Num) = 0;
468
469 virtual void QuadsTex3DDrawTL(const CQuadItem *pArray, int Num) = 0;
470
471 virtual int CreateQuadContainer(bool AutomaticUpload = true) = 0;
472 virtual void QuadContainerChangeAutomaticUpload(int ContainerIndex, bool AutomaticUpload) = 0;
473 virtual void QuadContainerUpload(int ContainerIndex) = 0;
474 virtual int QuadContainerAddQuads(int ContainerIndex, CQuadItem *pArray, int Num) = 0;
475 virtual int QuadContainerAddQuads(int ContainerIndex, CFreeformItem *pArray, int Num) = 0;
476 virtual void QuadContainerReset(int ContainerIndex) = 0;
477 virtual void DeleteQuadContainer(int &ContainerIndex) = 0;
478 virtual void RenderQuadContainer(int ContainerIndex, int QuadDrawNum) = 0;
479 virtual void RenderQuadContainer(int ContainerIndex, int QuadOffset, int QuadDrawNum, bool ChangeWrapMode = true) = 0;
480 virtual void RenderQuadContainerEx(int ContainerIndex, int QuadOffset, int QuadDrawNum, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) = 0;
481 virtual void RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) = 0;
482
483 struct SRenderSpriteInfo
484 {
485 vec2 m_Pos;
486 float m_Scale;
487 float m_Rotation;
488 };
489
490 virtual void RenderQuadContainerAsSpriteMultiple(int ContainerIndex, int QuadOffset, int DrawCount, SRenderSpriteInfo *pRenderInfo) = 0;
491
492 virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num) = 0;
493 virtual void QuadsText(float x, float y, float Size, const char *pText) = 0;
494
495 // sprites
496 enum
497 {
498 SPRITE_FLAG_FLIP_Y = 1,
499 SPRITE_FLAG_FLIP_X = 2,
500 };
501 virtual void SelectSprite(int Id, int Flags = 0) = 0;
502 virtual void SelectSprite7(int Id, int Flags = 0) = 0;
503
504 virtual void GetSpriteScale(const CDataSprite *pSprite, float &ScaleX, float &ScaleY) const = 0;
505 virtual void GetSpriteScale(int Id, float &ScaleX, float &ScaleY) const = 0;
506 virtual void GetSpriteScaleImpl(int Width, int Height, float &ScaleX, float &ScaleY) const = 0;
507
508 virtual void DrawSprite(float x, float y, float Size) = 0;
509 virtual void DrawSprite(float x, float y, float ScaledWidth, float ScaledHeight) = 0;
510
511 virtual int QuadContainerAddSprite(int QuadContainerIndex, float x, float y, float Size) = 0;
512 virtual int QuadContainerAddSprite(int QuadContainerIndex, float Size) = 0;
513 virtual int QuadContainerAddSprite(int QuadContainerIndex, float Width, float Height) = 0;
514 virtual int QuadContainerAddSprite(int QuadContainerIndex, float X, float Y, float Width, float Height) = 0;
515
516 enum
517 {
518 CORNER_NONE = 0,
519 CORNER_TL = 1,
520 CORNER_TR = 2,
521 CORNER_BL = 4,
522 CORNER_BR = 8,
523
524 CORNER_T = CORNER_TL | CORNER_TR,
525 CORNER_B = CORNER_BL | CORNER_BR,
526 CORNER_R = CORNER_TR | CORNER_BR,
527 CORNER_L = CORNER_TL | CORNER_BL,
528
529 CORNER_ALL = CORNER_T | CORNER_B,
530 };
531 virtual void DrawRectExt(float x, float y, float w, float h, float r, int Corners) = 0;
532 virtual void DrawRectExt4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, float r, int Corners) = 0;
533 virtual int CreateRectQuadContainer(float x, float y, float w, float h, float r, int Corners) = 0;
534 virtual void DrawRect(float x, float y, float w, float h, ColorRGBA Color, int Corners, float Rounding) = 0;
535 virtual void DrawRect4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, int Corners, float Rounding) = 0;
536 virtual void DrawCircle(float CenterX, float CenterY, float Radius, int Segments) = 0;
537
538 struct CColorVertex
539 {
540 int m_Index;
541 float m_R, m_G, m_B, m_A;
542 CColorVertex() = default;
543 CColorVertex(int i, float r, float g, float b, float a) :
544 m_Index(i), m_R(r), m_G(g), m_B(b), m_A(a) {}
545 CColorVertex(int i, ColorRGBA Color) :
546 m_Index(i), m_R(Color.r), m_G(Color.g), m_B(Color.b), m_A(Color.a) {}
547 };
548 virtual void SetColorVertex(const CColorVertex *pArray, size_t Num) = 0;
549 virtual void SetColor(float r, float g, float b, float a) = 0;
550 virtual void SetColor(ColorRGBA Color) = 0;
551 virtual void SetColor4(ColorRGBA TopLeft, ColorRGBA TopRight, ColorRGBA BottomLeft, ColorRGBA BottomRight) = 0;
552 virtual void ChangeColorOfCurrentQuadVertices(float r, float g, float b, float a) = 0;
553 virtual void ChangeColorOfQuadVertices(size_t QuadOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a) = 0;
554
555 /**
556 * Reads the color at the specified position from the backbuffer once,
557 * after the next swap operation.
558 *
559 * @param Position The pixel position to read.
560 * @param pColor Pointer that will receive the read pixel color.
561 * The pointer must be valid until the next swap operation.
562 */
563 virtual void ReadPixel(ivec2 Position, ColorRGBA *pColor) = 0;
564 virtual void TakeScreenshot(const char *pFilename) = 0;
565 virtual void TakeCustomScreenshot(const char *pFilename) = 0;
566 virtual int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen) = 0;
567 virtual void GetCurrentVideoMode(CVideoMode &CurMode, int Screen) = 0;
568 virtual void Swap() = 0;
569 virtual int GetNumScreens() const = 0;
570 virtual const char *GetScreenName(int Screen) const = 0;
571
572 // synchronization
573 virtual void InsertSignal(class CSemaphore *pSemaphore) = 0;
574 virtual bool IsIdle() const = 0;
575 virtual void WaitForIdle() = 0;
576
577 virtual void SetWindowGrab(bool Grab) = 0;
578 virtual void NotifyWindow() = 0;
579
580 // be aware that this function should only be called from the graphics thread, and even then you should really know what you are doing
581 // this function always returns the pixels in RGB
582 virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() = 0;
583
584 virtual std::optional<SWarning> CurrentWarning() = 0;
585
586 /**
587 * Type of a message box popup.
588 *
589 * @see CMessageBox
590 */
591 enum class EMessageBoxType
592 {
593 ERROR,
594 WARNING,
595 INFO,
596 };
597 /**
598 * Description of a message box popup button.
599 *
600 * @see CMessageBox
601 */
602 class CMessageBoxButton
603 {
604 public:
605 /**
606 * The label of this button.
607 *
608 * @remark This needs to be short because some systems do not increase the button sizes.
609 */
610 const char *m_pLabel = nullptr;
611 /**
612 * Whether the enter key activates this button.
613 */
614 bool m_Confirm = false;
615 /**
616 * Whether the escape key activates this button.
617 *
618 * @remark Closing the popup with the window manager will also cause this button to be activated.
619 */
620 bool m_Cancel = false;
621 };
622 /**
623 * Description of a message box popup.
624 *
625 * @see ShowMessageBox
626 */
627 class CMessageBox
628 {
629 public:
630 /**
631 * Title of the message box.
632 */
633 const char *m_pTitle = nullptr;
634 /**
635 * Main message of the message box.
636 */
637 const char *m_pMessage = nullptr;
638 /**
639 * Type of the message box.
640 */
641 EMessageBoxType m_Type = EMessageBoxType::ERROR;
642 /**
643 * Buttons shown in the message box. At least one button is required.
644 * The buttons are laid out from left to right.
645 */
646 std::vector<CMessageBoxButton> m_vButtons = {{.m_pLabel = "OK", .m_Confirm = true, .m_Cancel = true}};
647 };
648 /**
649 * Shows a modal message box with configuration title, message and buttons.
650 *
651 * @param MessageBox Description of the message box.
652 *
653 * @return Optional containing the index of the pressed button if the popup was shown successfully.
654 * @return Empty optional if the message box was not shown successfully.
655 *
656 * @remark Note that calling this function will destroy the current window,
657 * so it only makes sense for fatal errors at the moment.
658 */
659 virtual std::optional<int> ShowMessageBox(const CMessageBox &MessageBox) = 0;
660
661 virtual bool IsBackendInitialized() = 0;
662
663protected:
664 CTextureHandle CreateTextureHandle(int Index)
665 {
666 CTextureHandle Tex;
667 Tex.m_Id = Index;
668 return Tex;
669 }
670};
671
672class IEngineGraphics : public IGraphics
673{
674 MACRO_INTERFACE("enginegraphics")
675public:
676 virtual int Init() = 0;
677 void Shutdown() override = 0;
678
679 virtual void Minimize() = 0;
680
681 virtual int WindowActive() = 0;
682 virtual int WindowOpen() = 0;
683};
684
685extern IEngineGraphics *CreateEngineGraphicsThreaded();
686
687/**
688 * This function should only be used when the graphics are not initialized or when @link IGraphics::ShowMessageBox @endlink failed.
689 *
690 * @see IGraphics::ShowMessageBox
691 */
692extern std::optional<int> ShowMessageBoxWithoutGraphics(const IGraphics::CMessageBox &MessageBox);
693
694#endif
695