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