1 | #ifndef ENGINE_CLIENT_GRAPHICS_THREADED_H |
2 | #define ENGINE_CLIENT_GRAPHICS_THREADED_H |
3 | |
4 | #include <base/system.h> |
5 | #include <engine/graphics.h> |
6 | #include <engine/shared/config.h> |
7 | |
8 | #include <cstddef> |
9 | #include <string> |
10 | #include <vector> |
11 | |
12 | constexpr int CMD_BUFFER_DATA_BUFFER_SIZE = 1024 * 1024 * 2; |
13 | constexpr int CMD_BUFFER_CMD_BUFFER_SIZE = 1024 * 256; |
14 | |
15 | class CCommandBuffer |
16 | { |
17 | class CBuffer |
18 | { |
19 | unsigned char *m_pData; |
20 | unsigned m_Size; |
21 | unsigned m_Used; |
22 | |
23 | public: |
24 | CBuffer(unsigned BufferSize) |
25 | { |
26 | m_Size = BufferSize; |
27 | m_pData = new unsigned char[m_Size]; |
28 | m_Used = 0; |
29 | } |
30 | |
31 | ~CBuffer() |
32 | { |
33 | delete[] m_pData; |
34 | m_pData = 0x0; |
35 | m_Used = 0; |
36 | m_Size = 0; |
37 | } |
38 | |
39 | void Reset() |
40 | { |
41 | m_Used = 0; |
42 | } |
43 | |
44 | void *Alloc(unsigned Requested, unsigned Alignment = alignof(std::max_align_t)) |
45 | { |
46 | size_t Offset = reinterpret_cast<uintptr_t>(m_pData + m_Used) % Alignment; |
47 | if(Offset) |
48 | Offset = Alignment - Offset; |
49 | |
50 | if(Requested + Offset + m_Used > m_Size) |
51 | return 0; |
52 | |
53 | void *pPtr = &m_pData[m_Used + Offset]; |
54 | m_Used += Requested + Offset; |
55 | return pPtr; |
56 | } |
57 | |
58 | unsigned char *DataPtr() { return m_pData; } |
59 | unsigned DataSize() const { return m_Size; } |
60 | unsigned DataUsed() const { return m_Used; } |
61 | }; |
62 | |
63 | public: |
64 | CBuffer m_CmdBuffer; |
65 | size_t m_CommandCount = 0; |
66 | size_t m_RenderCallCount = 0; |
67 | |
68 | CBuffer m_DataBuffer; |
69 | |
70 | enum |
71 | { |
72 | MAX_TEXTURES = 1024 * 8, |
73 | MAX_VERTICES = 32 * 1024, |
74 | }; |
75 | |
76 | enum ECommandBufferCMD |
77 | { |
78 | // command groups |
79 | CMDGROUP_CORE = 0, // commands that everyone has to implement |
80 | CMDGROUP_PLATFORM_GL = 10000, // commands specific to a platform |
81 | CMDGROUP_PLATFORM_SDL = 20000, |
82 | |
83 | // |
84 | CMD_FIRST = CMDGROUP_CORE, |
85 | CMD_NOP = CMD_FIRST, |
86 | |
87 | // |
88 | CMD_RUNBUFFER, |
89 | |
90 | // synchronization |
91 | CMD_SIGNAL, |
92 | |
93 | // texture commands |
94 | CMD_TEXTURE_CREATE, |
95 | CMD_TEXTURE_DESTROY, |
96 | CMD_TEXTURE_UPDATE, |
97 | CMD_TEXT_TEXTURES_CREATE, |
98 | CMD_TEXT_TEXTURES_DESTROY, |
99 | CMD_TEXT_TEXTURE_UPDATE, |
100 | |
101 | // rendering |
102 | CMD_CLEAR, |
103 | CMD_RENDER, |
104 | CMD_RENDER_TEX3D, |
105 | |
106 | // opengl 2.0+ commands (some are just emulated and only exist in opengl 3.3+) |
107 | CMD_CREATE_BUFFER_OBJECT, // create vbo |
108 | CMD_RECREATE_BUFFER_OBJECT, // recreate vbo |
109 | CMD_UPDATE_BUFFER_OBJECT, // update vbo |
110 | CMD_COPY_BUFFER_OBJECT, // copy vbo to another |
111 | CMD_DELETE_BUFFER_OBJECT, // delete vbo |
112 | |
113 | CMD_CREATE_BUFFER_CONTAINER, // create vao |
114 | CMD_DELETE_BUFFER_CONTAINER, // delete vao |
115 | CMD_UPDATE_BUFFER_CONTAINER, // update vao |
116 | |
117 | CMD_INDICES_REQUIRED_NUM_NOTIFY, // create indices that are required |
118 | |
119 | CMD_RENDER_TILE_LAYER, // render a tilelayer |
120 | CMD_RENDER_BORDER_TILE, // render one tile multiple times |
121 | CMD_RENDER_QUAD_LAYER, // render a quad layer |
122 | CMD_RENDER_TEXT, // render text |
123 | CMD_RENDER_QUAD_CONTAINER, // render a quad buffer container |
124 | CMD_RENDER_QUAD_CONTAINER_EX, // render a quad buffer container with extended parameters |
125 | CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE, // render a quad buffer container as sprite multiple times |
126 | |
127 | // swap |
128 | CMD_SWAP, |
129 | |
130 | // misc |
131 | CMD_MULTISAMPLING, |
132 | CMD_VSYNC, |
133 | CMD_TRY_SWAP_AND_READ_PIXEL, |
134 | CMD_TRY_SWAP_AND_SCREENSHOT, |
135 | CMD_UPDATE_VIEWPORT, |
136 | |
137 | // in Android a window that minimizes gets destroyed |
138 | CMD_WINDOW_CREATE_NTF, |
139 | CMD_WINDOW_DESTROY_NTF, |
140 | |
141 | CMD_COUNT, |
142 | }; |
143 | |
144 | enum |
145 | { |
146 | TEXFORMAT_INVALID = 0, |
147 | TEXFORMAT_RGBA, |
148 | |
149 | TEXFLAG_NOMIPMAPS = 1, |
150 | TEXFLAG_TO_3D_TEXTURE = (1 << 3), |
151 | TEXFLAG_TO_2D_ARRAY_TEXTURE = (1 << 4), |
152 | TEXFLAG_NO_2D_TEXTURE = (1 << 5), |
153 | }; |
154 | |
155 | enum |
156 | { |
157 | // |
158 | PRIMTYPE_INVALID = 0, |
159 | PRIMTYPE_LINES, |
160 | PRIMTYPE_QUADS, |
161 | PRIMTYPE_TRIANGLES, |
162 | }; |
163 | |
164 | enum |
165 | { |
166 | BLEND_NONE = 0, |
167 | BLEND_ALPHA, |
168 | BLEND_ADDITIVE, |
169 | }; |
170 | |
171 | enum |
172 | { |
173 | WRAP_REPEAT = 0, |
174 | WRAP_CLAMP, |
175 | }; |
176 | |
177 | typedef vec2 SPoint; |
178 | typedef vec2 STexCoord; |
179 | typedef GL_SColorf SColorf; |
180 | typedef GL_SColor SColor; |
181 | typedef GL_SVertex SVertex; |
182 | typedef GL_SVertexTex3D SVertexTex3D; |
183 | typedef GL_SVertexTex3DStream SVertexTex3DStream; |
184 | |
185 | struct SCommand |
186 | { |
187 | public: |
188 | SCommand(unsigned Cmd) : |
189 | m_Cmd(Cmd), m_pNext(nullptr) {} |
190 | unsigned m_Cmd; |
191 | SCommand *m_pNext; |
192 | }; |
193 | SCommand *m_pCmdBufferHead; |
194 | SCommand *m_pCmdBufferTail; |
195 | |
196 | struct SState |
197 | { |
198 | int m_BlendMode; |
199 | int m_WrapMode; |
200 | int m_Texture; |
201 | SPoint m_ScreenTL; |
202 | SPoint m_ScreenBR; |
203 | |
204 | // clip |
205 | bool m_ClipEnable; |
206 | int m_ClipX; |
207 | int m_ClipY; |
208 | int m_ClipW; |
209 | int m_ClipH; |
210 | }; |
211 | |
212 | struct SCommand_Clear : public SCommand |
213 | { |
214 | SCommand_Clear() : |
215 | SCommand(CMD_CLEAR) {} |
216 | SColorf m_Color; |
217 | bool m_ForceClear; |
218 | }; |
219 | |
220 | struct SCommand_Signal : public SCommand |
221 | { |
222 | SCommand_Signal() : |
223 | SCommand(CMD_SIGNAL) {} |
224 | CSemaphore *m_pSemaphore; |
225 | }; |
226 | |
227 | struct SCommand_RunBuffer : public SCommand |
228 | { |
229 | SCommand_RunBuffer() : |
230 | SCommand(CMD_RUNBUFFER) {} |
231 | CCommandBuffer *m_pOtherBuffer; |
232 | }; |
233 | |
234 | struct SCommand_Render : public SCommand |
235 | { |
236 | SCommand_Render() : |
237 | SCommand(CMD_RENDER) {} |
238 | SState m_State; |
239 | unsigned m_PrimType; |
240 | unsigned m_PrimCount; |
241 | SVertex *m_pVertices; // you should use the command buffer data to allocate vertices for this command |
242 | }; |
243 | |
244 | struct SCommand_RenderTex3D : public SCommand |
245 | { |
246 | SCommand_RenderTex3D() : |
247 | SCommand(CMD_RENDER_TEX3D) {} |
248 | SState m_State; |
249 | unsigned m_PrimType; |
250 | unsigned m_PrimCount; |
251 | SVertexTex3DStream *m_pVertices; // you should use the command buffer data to allocate vertices for this command |
252 | }; |
253 | |
254 | struct SCommand_CreateBufferObject : public SCommand |
255 | { |
256 | SCommand_CreateBufferObject() : |
257 | SCommand(CMD_CREATE_BUFFER_OBJECT) {} |
258 | |
259 | int m_BufferIndex; |
260 | |
261 | bool m_DeletePointer; |
262 | void *m_pUploadData; |
263 | size_t m_DataSize; |
264 | |
265 | int m_Flags; // @see EBufferObjectCreateFlags |
266 | }; |
267 | |
268 | struct SCommand_RecreateBufferObject : public SCommand |
269 | { |
270 | SCommand_RecreateBufferObject() : |
271 | SCommand(CMD_RECREATE_BUFFER_OBJECT) {} |
272 | |
273 | int m_BufferIndex; |
274 | |
275 | bool m_DeletePointer; |
276 | void *m_pUploadData; |
277 | size_t m_DataSize; |
278 | |
279 | int m_Flags; // @see EBufferObjectCreateFlags |
280 | }; |
281 | |
282 | struct SCommand_UpdateBufferObject : public SCommand |
283 | { |
284 | SCommand_UpdateBufferObject() : |
285 | SCommand(CMD_UPDATE_BUFFER_OBJECT) {} |
286 | |
287 | int m_BufferIndex; |
288 | |
289 | bool m_DeletePointer; |
290 | void *m_pOffset; |
291 | void *m_pUploadData; |
292 | size_t m_DataSize; |
293 | }; |
294 | |
295 | struct SCommand_CopyBufferObject : public SCommand |
296 | { |
297 | SCommand_CopyBufferObject() : |
298 | SCommand(CMD_COPY_BUFFER_OBJECT) {} |
299 | |
300 | int m_WriteBufferIndex; |
301 | int m_ReadBufferIndex; |
302 | |
303 | size_t m_ReadOffset; |
304 | size_t m_WriteOffset; |
305 | size_t m_CopySize; |
306 | }; |
307 | |
308 | struct SCommand_DeleteBufferObject : public SCommand |
309 | { |
310 | SCommand_DeleteBufferObject() : |
311 | SCommand(CMD_DELETE_BUFFER_OBJECT) {} |
312 | |
313 | int m_BufferIndex; |
314 | }; |
315 | |
316 | struct SCommand_CreateBufferContainer : public SCommand |
317 | { |
318 | SCommand_CreateBufferContainer() : |
319 | SCommand(CMD_CREATE_BUFFER_CONTAINER) {} |
320 | |
321 | int m_BufferContainerIndex; |
322 | |
323 | int m_Stride; |
324 | int m_VertBufferBindingIndex; |
325 | |
326 | size_t m_AttrCount; |
327 | SBufferContainerInfo::SAttribute *m_pAttributes; |
328 | }; |
329 | |
330 | struct SCommand_UpdateBufferContainer : public SCommand |
331 | { |
332 | SCommand_UpdateBufferContainer() : |
333 | SCommand(CMD_UPDATE_BUFFER_CONTAINER) {} |
334 | |
335 | int m_BufferContainerIndex; |
336 | |
337 | int m_Stride; |
338 | int m_VertBufferBindingIndex; |
339 | |
340 | size_t m_AttrCount; |
341 | SBufferContainerInfo::SAttribute *m_pAttributes; |
342 | }; |
343 | |
344 | struct SCommand_DeleteBufferContainer : public SCommand |
345 | { |
346 | SCommand_DeleteBufferContainer() : |
347 | SCommand(CMD_DELETE_BUFFER_CONTAINER) {} |
348 | |
349 | int m_BufferContainerIndex; |
350 | bool m_DestroyAllBO; |
351 | }; |
352 | |
353 | struct SCommand_IndicesRequiredNumNotify : public SCommand |
354 | { |
355 | SCommand_IndicesRequiredNumNotify() : |
356 | SCommand(CMD_INDICES_REQUIRED_NUM_NOTIFY) {} |
357 | |
358 | unsigned int m_RequiredIndicesNum; |
359 | }; |
360 | |
361 | struct SCommand_RenderTileLayer : public SCommand |
362 | { |
363 | SCommand_RenderTileLayer() : |
364 | SCommand(CMD_RENDER_TILE_LAYER) {} |
365 | SState m_State; |
366 | SColorf m_Color; // the color of the whole tilelayer -- already enveloped |
367 | |
368 | // the char offset of all indices that should be rendered, and the amount of renders |
369 | char **m_pIndicesOffsets; |
370 | unsigned int *m_pDrawCount; |
371 | |
372 | int m_IndicesDrawNum; |
373 | int m_BufferContainerIndex; |
374 | }; |
375 | |
376 | struct SCommand_RenderBorderTile : public SCommand |
377 | { |
378 | SCommand_RenderBorderTile() : |
379 | SCommand(CMD_RENDER_BORDER_TILE) {} |
380 | SState m_State; |
381 | SColorf m_Color; // the color of the whole tilelayer -- already enveloped |
382 | char *m_pIndicesOffset; |
383 | uint32_t m_DrawNum; |
384 | int m_BufferContainerIndex; |
385 | |
386 | vec2 m_Offset; |
387 | vec2 m_Scale; |
388 | }; |
389 | |
390 | struct SCommand_RenderQuadLayer : public SCommand |
391 | { |
392 | SCommand_RenderQuadLayer() : |
393 | SCommand(CMD_RENDER_QUAD_LAYER) {} |
394 | SState m_State; |
395 | |
396 | int m_BufferContainerIndex; |
397 | SQuadRenderInfo *m_pQuadInfo; |
398 | size_t m_QuadNum; |
399 | int m_QuadOffset; |
400 | }; |
401 | |
402 | struct SCommand_RenderText : public SCommand |
403 | { |
404 | SCommand_RenderText() : |
405 | SCommand(CMD_RENDER_TEXT) {} |
406 | SState m_State; |
407 | |
408 | int m_BufferContainerIndex; |
409 | int m_TextureSize; |
410 | |
411 | int m_TextTextureIndex; |
412 | int m_TextOutlineTextureIndex; |
413 | |
414 | int m_DrawNum; |
415 | ColorRGBA m_TextColor; |
416 | ColorRGBA m_TextOutlineColor; |
417 | }; |
418 | |
419 | struct SCommand_RenderQuadContainer : public SCommand |
420 | { |
421 | SCommand_RenderQuadContainer() : |
422 | SCommand(CMD_RENDER_QUAD_CONTAINER) {} |
423 | SState m_State; |
424 | |
425 | int m_BufferContainerIndex; |
426 | |
427 | unsigned int m_DrawNum; |
428 | void *m_pOffset; |
429 | }; |
430 | |
431 | struct SCommand_RenderQuadContainerEx : public SCommand |
432 | { |
433 | SCommand_RenderQuadContainerEx() : |
434 | SCommand(CMD_RENDER_QUAD_CONTAINER_EX) {} |
435 | SState m_State; |
436 | |
437 | int m_BufferContainerIndex; |
438 | |
439 | float m_Rotation; |
440 | SPoint m_Center; |
441 | |
442 | SColorf m_VertexColor; |
443 | |
444 | unsigned int m_DrawNum; |
445 | void *m_pOffset; |
446 | }; |
447 | |
448 | struct SCommand_RenderQuadContainerAsSpriteMultiple : public SCommand |
449 | { |
450 | SCommand_RenderQuadContainerAsSpriteMultiple() : |
451 | SCommand(CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE) {} |
452 | SState m_State; |
453 | |
454 | int m_BufferContainerIndex; |
455 | |
456 | IGraphics::SRenderSpriteInfo *m_pRenderInfo; |
457 | |
458 | SPoint m_Center; |
459 | SColorf m_VertexColor; |
460 | |
461 | unsigned int m_DrawNum; |
462 | unsigned int m_DrawCount; |
463 | void *m_pOffset; |
464 | }; |
465 | |
466 | struct SCommand_TrySwapAndReadPixel : public SCommand |
467 | { |
468 | SCommand_TrySwapAndReadPixel() : |
469 | SCommand(CMD_TRY_SWAP_AND_READ_PIXEL) {} |
470 | ivec2 m_Position; |
471 | SColorf *m_pColor; // processor will fill this out |
472 | bool *m_pSwapped; // processor may set this to true, must be initialized to false by the caller |
473 | }; |
474 | |
475 | struct SCommand_TrySwapAndScreenshot : public SCommand |
476 | { |
477 | SCommand_TrySwapAndScreenshot() : |
478 | SCommand(CMD_TRY_SWAP_AND_SCREENSHOT) {} |
479 | CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well |
480 | bool *m_pSwapped; // processor may set this to true, must be initialized to false by the caller |
481 | }; |
482 | |
483 | struct SCommand_Swap : public SCommand |
484 | { |
485 | SCommand_Swap() : |
486 | SCommand(CMD_SWAP) {} |
487 | }; |
488 | |
489 | struct SCommand_VSync : public SCommand |
490 | { |
491 | SCommand_VSync() : |
492 | SCommand(CMD_VSYNC) {} |
493 | |
494 | int m_VSync; |
495 | bool *m_pRetOk; |
496 | }; |
497 | |
498 | struct SCommand_MultiSampling : public SCommand |
499 | { |
500 | SCommand_MultiSampling() : |
501 | SCommand(CMD_MULTISAMPLING) {} |
502 | |
503 | uint32_t m_RequestedMultiSamplingCount; |
504 | uint32_t *m_pRetMultiSamplingCount; |
505 | bool *m_pRetOk; |
506 | }; |
507 | |
508 | struct SCommand_Update_Viewport : public SCommand |
509 | { |
510 | SCommand_Update_Viewport() : |
511 | SCommand(CMD_UPDATE_VIEWPORT) {} |
512 | |
513 | int m_X; |
514 | int m_Y; |
515 | int m_Width; |
516 | int m_Height; |
517 | bool m_ByResize; // resized by an resize event.. a hint to make clear that the viewport update can be deferred if wanted |
518 | }; |
519 | |
520 | struct SCommand_Texture_Create : public SCommand |
521 | { |
522 | SCommand_Texture_Create() : |
523 | SCommand(CMD_TEXTURE_CREATE) {} |
524 | |
525 | // texture information |
526 | int m_Slot; |
527 | |
528 | size_t m_Width; |
529 | size_t m_Height; |
530 | int m_Format; |
531 | int m_StoreFormat; |
532 | int m_Flags; |
533 | uint8_t *m_pData; // will be freed by the command processor |
534 | }; |
535 | |
536 | struct SCommand_Texture_Update : public SCommand |
537 | { |
538 | SCommand_Texture_Update() : |
539 | SCommand(CMD_TEXTURE_UPDATE) {} |
540 | |
541 | // texture information |
542 | int m_Slot; |
543 | |
544 | int m_X; |
545 | int m_Y; |
546 | size_t m_Width; |
547 | size_t m_Height; |
548 | int m_Format; |
549 | uint8_t *m_pData; // will be freed by the command processor |
550 | }; |
551 | |
552 | struct SCommand_Texture_Destroy : public SCommand |
553 | { |
554 | SCommand_Texture_Destroy() : |
555 | SCommand(CMD_TEXTURE_DESTROY) {} |
556 | |
557 | // texture information |
558 | int m_Slot; |
559 | }; |
560 | |
561 | struct SCommand_TextTextures_Create : public SCommand |
562 | { |
563 | SCommand_TextTextures_Create() : |
564 | SCommand(CMD_TEXT_TEXTURES_CREATE) {} |
565 | |
566 | // texture information |
567 | int m_Slot; |
568 | int m_SlotOutline; |
569 | |
570 | size_t m_Width; |
571 | size_t m_Height; |
572 | |
573 | uint8_t *m_pTextData; // will be freed by the command processor |
574 | uint8_t *m_pTextOutlineData; // will be freed by the command processor |
575 | }; |
576 | |
577 | struct SCommand_TextTextures_Destroy : public SCommand |
578 | { |
579 | SCommand_TextTextures_Destroy() : |
580 | SCommand(CMD_TEXT_TEXTURES_DESTROY) {} |
581 | |
582 | // texture information |
583 | int m_Slot; |
584 | int m_SlotOutline; |
585 | }; |
586 | |
587 | struct SCommand_TextTexture_Update : public SCommand |
588 | { |
589 | SCommand_TextTexture_Update() : |
590 | SCommand(CMD_TEXT_TEXTURE_UPDATE) {} |
591 | |
592 | // texture information |
593 | int m_Slot; |
594 | |
595 | int m_X; |
596 | int m_Y; |
597 | size_t m_Width; |
598 | size_t m_Height; |
599 | uint8_t *m_pData; // will be freed by the command processor |
600 | }; |
601 | |
602 | struct SCommand_WindowCreateNtf : public CCommandBuffer::SCommand |
603 | { |
604 | SCommand_WindowCreateNtf() : |
605 | SCommand(CMD_WINDOW_CREATE_NTF) {} |
606 | |
607 | uint32_t m_WindowId; |
608 | }; |
609 | |
610 | struct SCommand_WindowDestroyNtf : public CCommandBuffer::SCommand |
611 | { |
612 | SCommand_WindowDestroyNtf() : |
613 | SCommand(CMD_WINDOW_DESTROY_NTF) {} |
614 | |
615 | uint32_t m_WindowId; |
616 | }; |
617 | |
618 | // |
619 | CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) : |
620 | m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize), m_pCmdBufferHead(nullptr), m_pCmdBufferTail(nullptr) |
621 | { |
622 | } |
623 | |
624 | void *AllocData(unsigned WantedSize) |
625 | { |
626 | return m_DataBuffer.Alloc(Requested: WantedSize); |
627 | } |
628 | |
629 | template<class T> |
630 | bool AddCommandUnsafe(const T &Command) |
631 | { |
632 | // make sure that we don't do something stupid like ->AddCommand(&Cmd); |
633 | (void)static_cast<const SCommand *>(&Command); |
634 | |
635 | // allocate and copy the command into the buffer |
636 | T *pCmd = (T *)m_CmdBuffer.Alloc(Requested: sizeof(*pCmd), Alignment: alignof(T)); |
637 | if(!pCmd) |
638 | return false; |
639 | *pCmd = Command; |
640 | pCmd->m_pNext = nullptr; |
641 | |
642 | if(m_pCmdBufferTail) |
643 | m_pCmdBufferTail->m_pNext = pCmd; |
644 | if(!m_pCmdBufferHead) |
645 | m_pCmdBufferHead = pCmd; |
646 | m_pCmdBufferTail = pCmd; |
647 | |
648 | ++m_CommandCount; |
649 | |
650 | return true; |
651 | } |
652 | |
653 | SCommand *Head() |
654 | { |
655 | return m_pCmdBufferHead; |
656 | } |
657 | |
658 | void Reset() |
659 | { |
660 | m_pCmdBufferHead = m_pCmdBufferTail = nullptr; |
661 | m_CmdBuffer.Reset(); |
662 | m_DataBuffer.Reset(); |
663 | |
664 | m_CommandCount = 0; |
665 | m_RenderCallCount = 0; |
666 | } |
667 | |
668 | void AddRenderCalls(size_t RenderCallCountToAdd) |
669 | { |
670 | m_RenderCallCount += RenderCallCountToAdd; |
671 | } |
672 | }; |
673 | |
674 | enum EGraphicsBackendErrorCodes |
675 | { |
676 | GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN = -1, |
677 | GRAPHICS_BACKEND_ERROR_CODE_NONE = 0, |
678 | GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED, |
679 | GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED, |
680 | GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED, |
681 | GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_REQUEST_FAILED, |
682 | GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_INFO_REQUEST_FAILED, |
683 | GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_RESOLUTION_REQUEST_FAILED, |
684 | GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED, |
685 | }; |
686 | |
687 | // interface for the graphics backend |
688 | // all these functions are called on the main thread |
689 | class IGraphicsBackend |
690 | { |
691 | public: |
692 | enum |
693 | { |
694 | INITFLAG_FULLSCREEN = 1 << 0, |
695 | INITFLAG_VSYNC = 1 << 1, |
696 | INITFLAG_RESIZABLE = 1 << 2, |
697 | INITFLAG_BORDERLESS = 1 << 3, |
698 | INITFLAG_HIGHDPI = 1 << 4, |
699 | INITFLAG_DESKTOP_FULLSCREEN = 1 << 5, |
700 | }; |
701 | |
702 | virtual ~IGraphicsBackend() = default; |
703 | |
704 | virtual int Init(const char *pName, int *pScreen, int *pWidth, int *pHeight, int *pRefreshRate, int *pFsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage) = 0; |
705 | virtual int Shutdown() = 0; |
706 | |
707 | virtual uint64_t TextureMemoryUsage() const = 0; |
708 | virtual uint64_t BufferMemoryUsage() const = 0; |
709 | virtual uint64_t StreamedMemoryUsage() const = 0; |
710 | virtual uint64_t StagingMemoryUsage() const = 0; |
711 | |
712 | virtual const TTwGraphicsGpuList &GetGpus() const = 0; |
713 | |
714 | virtual void GetVideoModes(CVideoMode *pModes, int MaxModes, int *pNumModes, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0; |
715 | virtual void GetCurrentVideoMode(CVideoMode &CurMode, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0; |
716 | |
717 | virtual int GetNumScreens() const = 0; |
718 | virtual const char *GetScreenName(int Screen) const = 0; |
719 | |
720 | virtual void Minimize() = 0; |
721 | virtual void Maximize() = 0; |
722 | virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0; |
723 | virtual bool SetWindowScreen(int Index) = 0; |
724 | virtual bool UpdateDisplayMode(int Index) = 0; |
725 | virtual int GetWindowScreen() = 0; |
726 | virtual int WindowActive() = 0; |
727 | virtual int WindowOpen() = 0; |
728 | virtual void SetWindowGrab(bool Grab) = 0; |
729 | // returns true, if the video mode changed |
730 | virtual bool ResizeWindow(int w, int h, int RefreshRate) = 0; |
731 | virtual void GetViewportSize(int &w, int &h) = 0; |
732 | virtual void NotifyWindow() = 0; |
733 | |
734 | virtual void WindowDestroyNtf(uint32_t WindowId) = 0; |
735 | virtual void WindowCreateNtf(uint32_t WindowId) = 0; |
736 | |
737 | virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; |
738 | virtual void RunBufferSingleThreadedUnsafe(CCommandBuffer *pBuffer) = 0; |
739 | virtual bool IsIdle() const = 0; |
740 | virtual void WaitForIdle() = 0; |
741 | |
742 | virtual bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) = 0; |
743 | // checks if the current values of the config are a graphics modern API |
744 | virtual bool IsConfigModernAPI() { return false; } |
745 | virtual bool UseTrianglesAsQuad() { return false; } |
746 | virtual bool HasTileBuffering() { return false; } |
747 | virtual bool HasQuadBuffering() { return false; } |
748 | virtual bool HasTextBuffering() { return false; } |
749 | virtual bool HasQuadContainerBuffering() { return false; } |
750 | virtual bool Uses2DTextureArrays() { return false; } |
751 | virtual bool HasTextureArraysSupport() { return false; } |
752 | virtual const char *GetErrorString() { return NULL; } |
753 | |
754 | virtual const char *GetVendorString() = 0; |
755 | virtual const char *GetVersionString() = 0; |
756 | virtual const char *GetRendererString() = 0; |
757 | |
758 | // be aware that this function should only be called from the graphics thread, and even then you should really know what you are doing |
759 | virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() = 0; |
760 | |
761 | virtual bool GetWarning(std::vector<std::string> &WarningStrings) = 0; |
762 | |
763 | // returns true if the error msg was shown |
764 | virtual bool ShowMessageBox(unsigned Type, const char *pTitle, const char *pMsg) = 0; |
765 | }; |
766 | |
767 | class CGraphics_Threaded : public IEngineGraphics |
768 | { |
769 | enum |
770 | { |
771 | NUM_CMDBUFFERS = 2, |
772 | |
773 | DRAWING_QUADS = 1, |
774 | DRAWING_LINES = 2, |
775 | DRAWING_TRIANGLES = 3 |
776 | }; |
777 | |
778 | CCommandBuffer::SState m_State; |
779 | IGraphicsBackend *m_pBackend; |
780 | bool m_GLTileBufferingEnabled; |
781 | bool m_GLQuadBufferingEnabled; |
782 | bool m_GLTextBufferingEnabled; |
783 | bool m_GLQuadContainerBufferingEnabled; |
784 | bool m_GLUses2DTextureArrays; |
785 | bool m_GLHasTextureArraysSupport; |
786 | bool m_GLUseTrianglesAsQuad; |
787 | |
788 | CCommandBuffer *m_apCommandBuffers[NUM_CMDBUFFERS]; |
789 | CCommandBuffer *m_pCommandBuffer; |
790 | unsigned m_CurrentCommandBuffer; |
791 | |
792 | // |
793 | class IStorage *m_pStorage; |
794 | class IConsole *m_pConsole; |
795 | class IEngine *m_pEngine; |
796 | |
797 | int m_CurIndex; |
798 | |
799 | CCommandBuffer::SVertex m_aVertices[CCommandBuffer::MAX_VERTICES]; |
800 | CCommandBuffer::SVertexTex3DStream m_aVerticesTex3D[CCommandBuffer::MAX_VERTICES]; |
801 | int m_NumVertices; |
802 | |
803 | CCommandBuffer::SColor m_aColor[4]; |
804 | CCommandBuffer::STexCoord m_aTexture[4]; |
805 | |
806 | bool m_RenderEnable; |
807 | |
808 | float m_Rotation; |
809 | int m_Drawing; |
810 | bool m_DoScreenshot; |
811 | char m_aScreenshotName[IO_MAX_PATH_LENGTH]; |
812 | |
813 | CTextureHandle m_NullTexture; |
814 | |
815 | std::vector<int> m_vTextureIndices; |
816 | size_t m_FirstFreeTexture; |
817 | int m_TextureMemoryUsage; |
818 | |
819 | std::vector<uint8_t> m_vSpriteHelper; |
820 | |
821 | bool m_WarnPngliteIncompatibleImages = false; |
822 | |
823 | std::vector<SWarning> m_vWarnings; |
824 | |
825 | // is a non full windowed (in a sense that the viewport won't include the whole window), |
826 | // forced viewport, so that it justifies our UI ratio needs |
827 | bool m_IsForcedViewport = false; |
828 | |
829 | struct SVertexArrayInfo |
830 | { |
831 | SVertexArrayInfo() : |
832 | m_FreeIndex(-1) {} |
833 | // keep a reference to it, so we can free the ID |
834 | int m_AssociatedBufferObjectIndex; |
835 | |
836 | int m_FreeIndex; |
837 | }; |
838 | std::vector<SVertexArrayInfo> m_vVertexArrayInfo; |
839 | int m_FirstFreeVertexArrayInfo; |
840 | |
841 | std::vector<int> m_vBufferObjectIndices; |
842 | int m_FirstFreeBufferObjectIndex; |
843 | |
844 | struct SQuadContainer |
845 | { |
846 | SQuadContainer(bool AutomaticUpload = true) |
847 | { |
848 | m_vQuads.clear(); |
849 | m_QuadBufferObjectIndex = m_QuadBufferContainerIndex = -1; |
850 | m_FreeIndex = -1; |
851 | |
852 | m_AutomaticUpload = AutomaticUpload; |
853 | } |
854 | |
855 | struct SQuad |
856 | { |
857 | CCommandBuffer::SVertex m_aVertices[4]; |
858 | }; |
859 | |
860 | std::vector<SQuad> m_vQuads; |
861 | |
862 | int m_QuadBufferObjectIndex; |
863 | int m_QuadBufferContainerIndex; |
864 | |
865 | int m_FreeIndex; |
866 | |
867 | bool m_AutomaticUpload; |
868 | }; |
869 | std::vector<SQuadContainer> m_vQuadContainers; |
870 | int m_FirstFreeQuadContainer; |
871 | |
872 | std::vector<WINDOW_RESIZE_FUNC> m_vResizeListeners; |
873 | std::vector<WINDOW_PROPS_CHANGED_FUNC> m_vPropChangeListeners; |
874 | |
875 | void *AllocCommandBufferData(size_t AllocSize); |
876 | |
877 | void AddVertices(int Count); |
878 | void AddVertices(int Count, CCommandBuffer::SVertex *pVertices); |
879 | void AddVertices(int Count, CCommandBuffer::SVertexTex3DStream *pVertices); |
880 | |
881 | template<typename TName> |
882 | void Rotate(const CCommandBuffer::SPoint &rCenter, TName *pPoints, int NumPoints) |
883 | { |
884 | float c = std::cos(x: m_Rotation); |
885 | float s = std::sin(x: m_Rotation); |
886 | float x, y; |
887 | int i; |
888 | |
889 | TName *pVertices = pPoints; |
890 | for(i = 0; i < NumPoints; i++) |
891 | { |
892 | x = pVertices[i].m_Pos.x - rCenter.x; |
893 | y = pVertices[i].m_Pos.y - rCenter.y; |
894 | pVertices[i].m_Pos.x = x * c - y * s + rCenter.x; |
895 | pVertices[i].m_Pos.y = x * s + y * c + rCenter.y; |
896 | } |
897 | } |
898 | |
899 | template<typename TName> |
900 | void AddCmd( |
901 | TName &Cmd, std::function<bool()> FailFunc = [] { return true; }) |
902 | { |
903 | if(m_pCommandBuffer->AddCommandUnsafe(Cmd)) |
904 | return; |
905 | |
906 | // kick command buffer and try again |
907 | KickCommandBuffer(); |
908 | |
909 | if(!FailFunc()) |
910 | { |
911 | char aError[256]; |
912 | str_format(buffer: aError, buffer_size: sizeof(aError), format: "graphics: failed to run fail handler for command '%s'" , typeid(TName).name()); |
913 | dbg_assert(false, aError); |
914 | } |
915 | |
916 | if(!m_pCommandBuffer->AddCommandUnsafe(Cmd)) |
917 | { |
918 | char aError[256]; |
919 | str_format(buffer: aError, buffer_size: sizeof(aError), format: "graphics: failed to add command '%s' to command buffer" , typeid(TName).name()); |
920 | dbg_assert(false, aError); |
921 | } |
922 | } |
923 | |
924 | void KickCommandBuffer(); |
925 | |
926 | void AddBackEndWarningIfExists(); |
927 | |
928 | void AdjustViewport(bool SendViewportChangeToBackend); |
929 | |
930 | ivec2 m_ReadPixelPosition = ivec2(0, 0); |
931 | ColorRGBA *m_pReadPixelColor = nullptr; |
932 | void ReadPixelDirect(bool *pSwapped); |
933 | void ScreenshotDirect(bool *pSwapped); |
934 | |
935 | int IssueInit(); |
936 | int InitWindow(); |
937 | |
938 | public: |
939 | CGraphics_Threaded(); |
940 | |
941 | void ClipEnable(int x, int y, int w, int h) override; |
942 | void ClipDisable() override; |
943 | |
944 | void BlendNone() override; |
945 | void BlendNormal() override; |
946 | void BlendAdditive() override; |
947 | |
948 | void WrapNormal() override; |
949 | void WrapClamp() override; |
950 | |
951 | uint64_t TextureMemoryUsage() const override; |
952 | uint64_t BufferMemoryUsage() const override; |
953 | uint64_t StreamedMemoryUsage() const override; |
954 | uint64_t StagingMemoryUsage() const override; |
955 | |
956 | const TTwGraphicsGpuList &GetGpus() const override; |
957 | |
958 | void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) override; |
959 | void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY) override; |
960 | |
961 | void LinesBegin() override; |
962 | void LinesEnd() override; |
963 | void LinesDraw(const CLineItem *pArray, int Num) override; |
964 | |
965 | IGraphics::CTextureHandle FindFreeTextureIndex(); |
966 | void FreeTextureIndex(CTextureHandle *pIndex); |
967 | int UnloadTexture(IGraphics::CTextureHandle *pIndex) override; |
968 | IGraphics::CTextureHandle LoadTextureRaw(const CImageInfo &Image, int Flags, const char *pTexName = nullptr) override; |
969 | IGraphics::CTextureHandle LoadTextureRawMove(CImageInfo &Image, int Flags, const char *pTexName = nullptr) override; |
970 | int LoadTextureRawSub(IGraphics::CTextureHandle TextureId, int x, int y, const CImageInfo &Image) override; |
971 | IGraphics::CTextureHandle NullTexture() const override; |
972 | |
973 | bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) override; |
974 | bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override; |
975 | bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData) override; |
976 | |
977 | CTextureHandle LoadSpriteTextureImpl(const CImageInfo &FromImageInfo, int x, int y, size_t w, size_t h, const char *pName); |
978 | CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override; |
979 | |
980 | bool IsImageSubFullyTransparent(const CImageInfo &FromImageInfo, int x, int y, int w, int h) override; |
981 | bool IsSpriteTextureFullyTransparent(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override; |
982 | |
983 | // simple uncompressed RGBA loaders |
984 | IGraphics::CTextureHandle LoadTexture(const char *pFilename, int StorageType, int Flags = 0) override; |
985 | bool LoadPng(CImageInfo &Image, const char *pFilename, int StorageType) override; |
986 | |
987 | bool CheckImageDivisibility(const char *pFileName, CImageInfo &Img, int DivX, int DivY, bool AllowResize) override; |
988 | bool IsImageFormatRGBA(const char *pFileName, CImageInfo &Img) override; |
989 | |
990 | void CopyTextureBufferSub(uint8_t *pDestBuffer, const CImageInfo &SourceImage, size_t SubOffsetX, size_t SubOffsetY, size_t SubCopyWidth, size_t SubCopyHeight) override; |
991 | void CopyTextureFromTextureBufferSub(uint8_t *pDestBuffer, size_t DestWidth, size_t DestHeight, const CImageInfo &SourceImage, size_t SrcSubOffsetX, size_t SrcSubOffsetY, size_t SrcSubCopyWidth, size_t SrcSubCopyHeight) override; |
992 | |
993 | void TextureSet(CTextureHandle TextureId) override; |
994 | |
995 | void Clear(float r, float g, float b, bool ForceClearNow = false) override; |
996 | |
997 | void QuadsBegin() override; |
998 | void QuadsEnd() override; |
999 | void QuadsTex3DBegin() override; |
1000 | void QuadsTex3DEnd() override; |
1001 | void TrianglesBegin() override; |
1002 | void TrianglesEnd() override; |
1003 | void QuadsEndKeepVertices() override; |
1004 | void QuadsDrawCurrentVertices(bool KeepVertices = true) override; |
1005 | void QuadsSetRotation(float Angle) override; |
1006 | |
1007 | template<typename TName> |
1008 | void SetColor(TName *pVertex, int ColorIndex) |
1009 | { |
1010 | TName *pVert = pVertex; |
1011 | pVert->m_Color = m_aColor[ColorIndex]; |
1012 | } |
1013 | |
1014 | void SetColorVertex(const CColorVertex *pArray, size_t Num) override; |
1015 | void SetColor(float r, float g, float b, float a) override; |
1016 | void SetColor(ColorRGBA Color) override; |
1017 | void SetColor4(ColorRGBA TopLeft, ColorRGBA TopRight, ColorRGBA BottomLeft, ColorRGBA BottomRight) override; |
1018 | |
1019 | // go through all vertices and change their color (only works for quads) |
1020 | void ChangeColorOfCurrentQuadVertices(float r, float g, float b, float a) override; |
1021 | void ChangeColorOfQuadVertices(size_t QuadOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a) override; |
1022 | |
1023 | void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV) override; |
1024 | void QuadsSetSubsetFree( |
1025 | float x0, float y0, float x1, float y1, |
1026 | float x2, float y2, float x3, float y3, int Index = -1) override; |
1027 | |
1028 | void QuadsDraw(CQuadItem *pArray, int Num) override; |
1029 | |
1030 | template<typename TName> |
1031 | void QuadsDrawTLImpl(TName *pVertices, const CQuadItem *pArray, int Num) |
1032 | { |
1033 | CCommandBuffer::SPoint Center; |
1034 | |
1035 | dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsDrawTL without begin" ); |
1036 | |
1037 | if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad) |
1038 | { |
1039 | for(int i = 0; i < Num; ++i) |
1040 | { |
1041 | // first triangle |
1042 | pVertices[m_NumVertices + 6 * i].m_Pos.x = pArray[i].m_X; |
1043 | pVertices[m_NumVertices + 6 * i].m_Pos.y = pArray[i].m_Y; |
1044 | pVertices[m_NumVertices + 6 * i].m_Tex = m_aTexture[0]; |
1045 | SetColor(&pVertices[m_NumVertices + 6 * i], 0); |
1046 | |
1047 | pVertices[m_NumVertices + 6 * i + 1].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1048 | pVertices[m_NumVertices + 6 * i + 1].m_Pos.y = pArray[i].m_Y; |
1049 | pVertices[m_NumVertices + 6 * i + 1].m_Tex = m_aTexture[1]; |
1050 | SetColor(&pVertices[m_NumVertices + 6 * i + 1], 1); |
1051 | |
1052 | pVertices[m_NumVertices + 6 * i + 2].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1053 | pVertices[m_NumVertices + 6 * i + 2].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1054 | pVertices[m_NumVertices + 6 * i + 2].m_Tex = m_aTexture[2]; |
1055 | SetColor(&pVertices[m_NumVertices + 6 * i + 2], 2); |
1056 | |
1057 | // second triangle |
1058 | pVertices[m_NumVertices + 6 * i + 3].m_Pos.x = pArray[i].m_X; |
1059 | pVertices[m_NumVertices + 6 * i + 3].m_Pos.y = pArray[i].m_Y; |
1060 | pVertices[m_NumVertices + 6 * i + 3].m_Tex = m_aTexture[0]; |
1061 | SetColor(&pVertices[m_NumVertices + 6 * i + 3], 0); |
1062 | |
1063 | pVertices[m_NumVertices + 6 * i + 4].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1064 | pVertices[m_NumVertices + 6 * i + 4].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1065 | pVertices[m_NumVertices + 6 * i + 4].m_Tex = m_aTexture[2]; |
1066 | SetColor(&pVertices[m_NumVertices + 6 * i + 4], 2); |
1067 | |
1068 | pVertices[m_NumVertices + 6 * i + 5].m_Pos.x = pArray[i].m_X; |
1069 | pVertices[m_NumVertices + 6 * i + 5].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1070 | pVertices[m_NumVertices + 6 * i + 5].m_Tex = m_aTexture[3]; |
1071 | SetColor(&pVertices[m_NumVertices + 6 * i + 5], 3); |
1072 | |
1073 | if(m_Rotation != 0) |
1074 | { |
1075 | Center.x = pArray[i].m_X + pArray[i].m_Width / 2; |
1076 | Center.y = pArray[i].m_Y + pArray[i].m_Height / 2; |
1077 | |
1078 | Rotate(Center, &pVertices[m_NumVertices + 6 * i], 6); |
1079 | } |
1080 | } |
1081 | |
1082 | AddVertices(3 * 2 * Num, pVertices); |
1083 | } |
1084 | else |
1085 | { |
1086 | for(int i = 0; i < Num; ++i) |
1087 | { |
1088 | pVertices[m_NumVertices + 4 * i].m_Pos.x = pArray[i].m_X; |
1089 | pVertices[m_NumVertices + 4 * i].m_Pos.y = pArray[i].m_Y; |
1090 | pVertices[m_NumVertices + 4 * i].m_Tex = m_aTexture[0]; |
1091 | SetColor(&pVertices[m_NumVertices + 4 * i], 0); |
1092 | |
1093 | pVertices[m_NumVertices + 4 * i + 1].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1094 | pVertices[m_NumVertices + 4 * i + 1].m_Pos.y = pArray[i].m_Y; |
1095 | pVertices[m_NumVertices + 4 * i + 1].m_Tex = m_aTexture[1]; |
1096 | SetColor(&pVertices[m_NumVertices + 4 * i + 1], 1); |
1097 | |
1098 | pVertices[m_NumVertices + 4 * i + 2].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1099 | pVertices[m_NumVertices + 4 * i + 2].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1100 | pVertices[m_NumVertices + 4 * i + 2].m_Tex = m_aTexture[2]; |
1101 | SetColor(&pVertices[m_NumVertices + 4 * i + 2], 2); |
1102 | |
1103 | pVertices[m_NumVertices + 4 * i + 3].m_Pos.x = pArray[i].m_X; |
1104 | pVertices[m_NumVertices + 4 * i + 3].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1105 | pVertices[m_NumVertices + 4 * i + 3].m_Tex = m_aTexture[3]; |
1106 | SetColor(&pVertices[m_NumVertices + 4 * i + 3], 3); |
1107 | |
1108 | if(m_Rotation != 0) |
1109 | { |
1110 | Center.x = pArray[i].m_X + pArray[i].m_Width / 2; |
1111 | Center.y = pArray[i].m_Y + pArray[i].m_Height / 2; |
1112 | |
1113 | Rotate(Center, &pVertices[m_NumVertices + 4 * i], 4); |
1114 | } |
1115 | } |
1116 | |
1117 | AddVertices(4 * Num, pVertices); |
1118 | } |
1119 | } |
1120 | |
1121 | void QuadsDrawTL(const CQuadItem *pArray, int Num) override; |
1122 | |
1123 | void QuadsTex3DDrawTL(const CQuadItem *pArray, int Num) override; |
1124 | |
1125 | void QuadsDrawFreeform(const CFreeformItem *pArray, int Num) override; |
1126 | void QuadsText(float x, float y, float Size, const char *pText) override; |
1127 | |
1128 | void DrawRectExt(float x, float y, float w, float h, float r, int Corners) override; |
1129 | void DrawRectExt4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, float r, int Corners) override; |
1130 | int CreateRectQuadContainer(float x, float y, float w, float h, float r, int Corners) override; |
1131 | void DrawRect(float x, float y, float w, float h, ColorRGBA Color, int Corners, float Rounding) override; |
1132 | void DrawRect4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, int Corners, float Rounding) override; |
1133 | void DrawCircle(float CenterX, float CenterY, float Radius, int Segments) override; |
1134 | |
1135 | const GL_STexCoord *GetCurTextureCoordinates() override |
1136 | { |
1137 | return m_aTexture; |
1138 | } |
1139 | |
1140 | const GL_SColor *GetCurColor() override |
1141 | { |
1142 | return m_aColor; |
1143 | } |
1144 | |
1145 | int CreateQuadContainer(bool AutomaticUpload = true) override; |
1146 | void QuadContainerChangeAutomaticUpload(int ContainerIndex, bool AutomaticUpload) override; |
1147 | void QuadContainerUpload(int ContainerIndex) override; |
1148 | int QuadContainerAddQuads(int ContainerIndex, CQuadItem *pArray, int Num) override; |
1149 | int QuadContainerAddQuads(int ContainerIndex, CFreeformItem *pArray, int Num) override; |
1150 | void QuadContainerReset(int ContainerIndex) override; |
1151 | void DeleteQuadContainer(int &ContainerIndex) override; |
1152 | void RenderQuadContainer(int ContainerIndex, int QuadDrawNum) override; |
1153 | void RenderQuadContainer(int ContainerIndex, int QuadOffset, int QuadDrawNum, bool ChangeWrapMode = true) override; |
1154 | void RenderQuadContainerEx(int ContainerIndex, int QuadOffset, int QuadDrawNum, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override; |
1155 | void RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override; |
1156 | void RenderQuadContainerAsSpriteMultiple(int ContainerIndex, int QuadOffset, int DrawCount, SRenderSpriteInfo *pRenderInfo) override; |
1157 | |
1158 | template<typename TName> |
1159 | void FlushVerticesImpl(bool KeepVertices, int &PrimType, size_t &PrimCount, size_t &NumVerts, TName &Command, size_t VertSize) |
1160 | { |
1161 | Command.m_pVertices = nullptr; |
1162 | if(m_NumVertices == 0) |
1163 | return; |
1164 | |
1165 | NumVerts = m_NumVertices; |
1166 | |
1167 | if(!KeepVertices) |
1168 | m_NumVertices = 0; |
1169 | |
1170 | if(m_Drawing == DRAWING_QUADS) |
1171 | { |
1172 | if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad) |
1173 | { |
1174 | PrimType = CCommandBuffer::PRIMTYPE_TRIANGLES; |
1175 | PrimCount = NumVerts / 3; |
1176 | } |
1177 | else |
1178 | { |
1179 | PrimType = CCommandBuffer::PRIMTYPE_QUADS; |
1180 | PrimCount = NumVerts / 4; |
1181 | } |
1182 | } |
1183 | else if(m_Drawing == DRAWING_LINES) |
1184 | { |
1185 | PrimType = CCommandBuffer::PRIMTYPE_LINES; |
1186 | PrimCount = NumVerts / 2; |
1187 | } |
1188 | else if(m_Drawing == DRAWING_TRIANGLES) |
1189 | { |
1190 | PrimType = CCommandBuffer::PRIMTYPE_TRIANGLES; |
1191 | PrimCount = NumVerts / 3; |
1192 | } |
1193 | else |
1194 | return; |
1195 | |
1196 | Command.m_pVertices = (decltype(Command.m_pVertices))AllocCommandBufferData(AllocSize: VertSize * NumVerts); |
1197 | Command.m_State = m_State; |
1198 | |
1199 | Command.m_PrimType = PrimType; |
1200 | Command.m_PrimCount = PrimCount; |
1201 | |
1202 | AddCmd(Command, [&] { |
1203 | Command.m_pVertices = (decltype(Command.m_pVertices))m_pCommandBuffer->AllocData(WantedSize: VertSize * NumVerts); |
1204 | return Command.m_pVertices != nullptr; |
1205 | }); |
1206 | |
1207 | m_pCommandBuffer->AddRenderCalls(RenderCallCountToAdd: 1); |
1208 | } |
1209 | |
1210 | void FlushVertices(bool KeepVertices = false) override; |
1211 | void FlushVerticesTex3D() override; |
1212 | |
1213 | void RenderTileLayer(int BufferContainerIndex, const ColorRGBA &Color, char **pOffsets, unsigned int *pIndicedVertexDrawNum, size_t NumIndicesOffset) override; |
1214 | virtual void RenderBorderTiles(int BufferContainerIndex, const ColorRGBA &Color, char *pIndexBufferOffset, const vec2 &Offset, const vec2 &Scale, uint32_t DrawNum) override; |
1215 | void RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, size_t QuadNum, int QuadOffset) override; |
1216 | void RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor) override; |
1217 | |
1218 | // modern GL functions |
1219 | int CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override; |
1220 | void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override; |
1221 | void UpdateBufferObjectInternal(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer = false); |
1222 | void CopyBufferObjectInternal(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize); |
1223 | void DeleteBufferObject(int BufferIndex) override; |
1224 | |
1225 | int CreateBufferContainer(SBufferContainerInfo *pContainerInfo) override; |
1226 | // destroying all buffer objects means, that all referenced VBOs are destroyed automatically, so the user does not need to save references to them |
1227 | void DeleteBufferContainer(int &ContainerIndex, bool DestroyAllBO = true) override; |
1228 | void UpdateBufferContainerInternal(int ContainerIndex, SBufferContainerInfo *pContainerInfo); |
1229 | void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) override; |
1230 | |
1231 | int GetNumScreens() const override; |
1232 | const char *GetScreenName(int Screen) const override; |
1233 | |
1234 | void Minimize() override; |
1235 | void Maximize() override; |
1236 | void WarnPngliteIncompatibleImages(bool Warn) override; |
1237 | void SetWindowParams(int FullscreenMode, bool IsBorderless) override; |
1238 | bool SetWindowScreen(int Index) override; |
1239 | void Move(int x, int y) override; |
1240 | bool Resize(int w, int h, int RefreshRate) override; |
1241 | void ResizeToScreen() override; |
1242 | void GotResized(int w, int h, int RefreshRate) override; |
1243 | void UpdateViewport(int X, int Y, int W, int H, bool ByResize) override; |
1244 | void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc) override; |
1245 | void AddWindowPropChangeListener(WINDOW_PROPS_CHANGED_FUNC pFunc) override; |
1246 | int GetWindowScreen() override; |
1247 | |
1248 | void WindowDestroyNtf(uint32_t WindowId) override; |
1249 | void WindowCreateNtf(uint32_t WindowId) override; |
1250 | |
1251 | int WindowActive() override; |
1252 | int WindowOpen() override; |
1253 | |
1254 | void SetWindowGrab(bool Grab) override; |
1255 | void NotifyWindow() override; |
1256 | |
1257 | int Init() override; |
1258 | void Shutdown() override; |
1259 | |
1260 | void ReadPixel(ivec2 Position, ColorRGBA *pColor) override; |
1261 | void TakeScreenshot(const char *pFilename) override; |
1262 | void TakeCustomScreenshot(const char *pFilename) override; |
1263 | void Swap() override; |
1264 | bool SetVSync(bool State) override; |
1265 | bool SetMultiSampling(uint32_t ReqMultiSamplingCount, uint32_t &MultiSamplingCountBackend) override; |
1266 | |
1267 | int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen) override; |
1268 | void GetCurrentVideoMode(CVideoMode &CurMode, int Screen) override; |
1269 | |
1270 | virtual int GetDesktopScreenWidth() const { return g_Config.m_GfxDesktopWidth; } |
1271 | virtual int GetDesktopScreenHeight() const { return g_Config.m_GfxDesktopHeight; } |
1272 | |
1273 | // synchronization |
1274 | void InsertSignal(CSemaphore *pSemaphore) override; |
1275 | bool IsIdle() const override; |
1276 | void WaitForIdle() override; |
1277 | |
1278 | SWarning *GetCurWarning() override; |
1279 | bool ShowMessageBox(unsigned Type, const char *pTitle, const char *pMsg) override; |
1280 | bool IsBackendInitialized() override; |
1281 | |
1282 | bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) override { return m_pBackend->GetDriverVersion(DriverAgeType, Major, Minor, Patch, pName, BackendType); } |
1283 | bool IsConfigModernAPI() override { return m_pBackend->IsConfigModernAPI(); } |
1284 | bool IsTileBufferingEnabled() override { return m_GLTileBufferingEnabled; } |
1285 | bool IsQuadBufferingEnabled() override { return m_GLQuadBufferingEnabled; } |
1286 | bool IsTextBufferingEnabled() override { return m_GLTextBufferingEnabled; } |
1287 | bool IsQuadContainerBufferingEnabled() override { return m_GLQuadContainerBufferingEnabled; } |
1288 | bool Uses2DTextureArrays() override { return m_GLUses2DTextureArrays; } |
1289 | bool HasTextureArraysSupport() override { return m_GLHasTextureArraysSupport; } |
1290 | |
1291 | const char *GetVendorString() override; |
1292 | const char *GetVersionString() override; |
1293 | const char *GetRendererString() override; |
1294 | |
1295 | TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() override; |
1296 | }; |
1297 | |
1298 | typedef std::function<const char *(const char *, const char *)> TTranslateFunc; |
1299 | extern IGraphicsBackend *CreateGraphicsBackend(TTranslateFunc &&TranslateFunc); |
1300 | |
1301 | #endif // ENGINE_CLIENT_GRAPHICS_THREADED_H |
1302 | |