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_Flags; |
531 | // data must be in RGBA format |
532 | uint8_t *m_pData; // will be freed by the command processor |
533 | }; |
534 | |
535 | struct SCommand_Texture_Update : public SCommand |
536 | { |
537 | SCommand_Texture_Update() : |
538 | SCommand(CMD_TEXTURE_UPDATE) {} |
539 | |
540 | // texture information |
541 | int m_Slot; |
542 | |
543 | int m_X; |
544 | int m_Y; |
545 | size_t m_Width; |
546 | size_t m_Height; |
547 | // data must be in RGBA format |
548 | uint8_t *m_pData; // will be freed by the command processor |
549 | }; |
550 | |
551 | struct SCommand_Texture_Destroy : public SCommand |
552 | { |
553 | SCommand_Texture_Destroy() : |
554 | SCommand(CMD_TEXTURE_DESTROY) {} |
555 | |
556 | // texture information |
557 | int m_Slot; |
558 | }; |
559 | |
560 | struct SCommand_TextTextures_Create : public SCommand |
561 | { |
562 | SCommand_TextTextures_Create() : |
563 | SCommand(CMD_TEXT_TEXTURES_CREATE) {} |
564 | |
565 | // texture information |
566 | int m_Slot; |
567 | int m_SlotOutline; |
568 | |
569 | size_t m_Width; |
570 | size_t m_Height; |
571 | |
572 | uint8_t *m_pTextData; // will be freed by the command processor |
573 | uint8_t *m_pTextOutlineData; // will be freed by the command processor |
574 | }; |
575 | |
576 | struct SCommand_TextTextures_Destroy : public SCommand |
577 | { |
578 | SCommand_TextTextures_Destroy() : |
579 | SCommand(CMD_TEXT_TEXTURES_DESTROY) {} |
580 | |
581 | // texture information |
582 | int m_Slot; |
583 | int m_SlotOutline; |
584 | }; |
585 | |
586 | struct SCommand_TextTexture_Update : public SCommand |
587 | { |
588 | SCommand_TextTexture_Update() : |
589 | SCommand(CMD_TEXT_TEXTURE_UPDATE) {} |
590 | |
591 | // texture information |
592 | int m_Slot; |
593 | |
594 | int m_X; |
595 | int m_Y; |
596 | size_t m_Width; |
597 | size_t m_Height; |
598 | uint8_t *m_pData; // will be freed by the command processor |
599 | }; |
600 | |
601 | struct SCommand_WindowCreateNtf : public CCommandBuffer::SCommand |
602 | { |
603 | SCommand_WindowCreateNtf() : |
604 | SCommand(CMD_WINDOW_CREATE_NTF) {} |
605 | |
606 | uint32_t m_WindowId; |
607 | }; |
608 | |
609 | struct SCommand_WindowDestroyNtf : public CCommandBuffer::SCommand |
610 | { |
611 | SCommand_WindowDestroyNtf() : |
612 | SCommand(CMD_WINDOW_DESTROY_NTF) {} |
613 | |
614 | uint32_t m_WindowId; |
615 | }; |
616 | |
617 | // |
618 | CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) : |
619 | m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize), m_pCmdBufferHead(nullptr), m_pCmdBufferTail(nullptr) |
620 | { |
621 | } |
622 | |
623 | void *AllocData(unsigned WantedSize) |
624 | { |
625 | return m_DataBuffer.Alloc(Requested: WantedSize); |
626 | } |
627 | |
628 | template<class T> |
629 | bool AddCommandUnsafe(const T &Command) |
630 | { |
631 | // make sure that we don't do something stupid like ->AddCommand(&Cmd); |
632 | (void)static_cast<const SCommand *>(&Command); |
633 | |
634 | // allocate and copy the command into the buffer |
635 | T *pCmd = (T *)m_CmdBuffer.Alloc(Requested: sizeof(*pCmd), Alignment: alignof(T)); |
636 | if(!pCmd) |
637 | return false; |
638 | *pCmd = Command; |
639 | pCmd->m_pNext = nullptr; |
640 | |
641 | if(m_pCmdBufferTail) |
642 | m_pCmdBufferTail->m_pNext = pCmd; |
643 | if(!m_pCmdBufferHead) |
644 | m_pCmdBufferHead = pCmd; |
645 | m_pCmdBufferTail = pCmd; |
646 | |
647 | ++m_CommandCount; |
648 | |
649 | return true; |
650 | } |
651 | |
652 | SCommand *Head() |
653 | { |
654 | return m_pCmdBufferHead; |
655 | } |
656 | |
657 | void Reset() |
658 | { |
659 | m_pCmdBufferHead = m_pCmdBufferTail = nullptr; |
660 | m_CmdBuffer.Reset(); |
661 | m_DataBuffer.Reset(); |
662 | |
663 | m_CommandCount = 0; |
664 | m_RenderCallCount = 0; |
665 | } |
666 | |
667 | void AddRenderCalls(size_t RenderCallCountToAdd) |
668 | { |
669 | m_RenderCallCount += RenderCallCountToAdd; |
670 | } |
671 | }; |
672 | |
673 | enum EGraphicsBackendErrorCodes |
674 | { |
675 | GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN = -1, |
676 | GRAPHICS_BACKEND_ERROR_CODE_NONE = 0, |
677 | GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED, |
678 | GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED, |
679 | GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED, |
680 | GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_REQUEST_FAILED, |
681 | GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_INFO_REQUEST_FAILED, |
682 | GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_RESOLUTION_REQUEST_FAILED, |
683 | GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED, |
684 | }; |
685 | |
686 | // interface for the graphics backend |
687 | // all these functions are called on the main thread |
688 | class IGraphicsBackend |
689 | { |
690 | public: |
691 | enum |
692 | { |
693 | INITFLAG_FULLSCREEN = 1 << 0, |
694 | INITFLAG_VSYNC = 1 << 1, |
695 | INITFLAG_RESIZABLE = 1 << 2, |
696 | INITFLAG_BORDERLESS = 1 << 3, |
697 | INITFLAG_HIGHDPI = 1 << 4, |
698 | INITFLAG_DESKTOP_FULLSCREEN = 1 << 5, |
699 | }; |
700 | |
701 | virtual ~IGraphicsBackend() = default; |
702 | |
703 | 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; |
704 | virtual int Shutdown() = 0; |
705 | |
706 | virtual uint64_t TextureMemoryUsage() const = 0; |
707 | virtual uint64_t BufferMemoryUsage() const = 0; |
708 | virtual uint64_t StreamedMemoryUsage() const = 0; |
709 | virtual uint64_t StagingMemoryUsage() const = 0; |
710 | |
711 | virtual const TTwGraphicsGpuList &GetGpus() const = 0; |
712 | |
713 | virtual void GetVideoModes(CVideoMode *pModes, int MaxModes, int *pNumModes, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0; |
714 | virtual void GetCurrentVideoMode(CVideoMode &CurMode, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0; |
715 | |
716 | virtual int GetNumScreens() const = 0; |
717 | virtual const char *GetScreenName(int Screen) const = 0; |
718 | |
719 | virtual void Minimize() = 0; |
720 | virtual void Maximize() = 0; |
721 | virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0; |
722 | virtual bool SetWindowScreen(int Index) = 0; |
723 | virtual bool UpdateDisplayMode(int Index) = 0; |
724 | virtual int GetWindowScreen() = 0; |
725 | virtual int WindowActive() = 0; |
726 | virtual int WindowOpen() = 0; |
727 | virtual void SetWindowGrab(bool Grab) = 0; |
728 | // returns true, if the video mode changed |
729 | virtual bool ResizeWindow(int w, int h, int RefreshRate) = 0; |
730 | virtual void GetViewportSize(int &w, int &h) = 0; |
731 | virtual void NotifyWindow() = 0; |
732 | |
733 | virtual void WindowDestroyNtf(uint32_t WindowId) = 0; |
734 | virtual void WindowCreateNtf(uint32_t WindowId) = 0; |
735 | |
736 | virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; |
737 | virtual void RunBufferSingleThreadedUnsafe(CCommandBuffer *pBuffer) = 0; |
738 | virtual bool IsIdle() const = 0; |
739 | virtual void WaitForIdle() = 0; |
740 | |
741 | virtual bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) = 0; |
742 | // checks if the current values of the config are a graphics modern API |
743 | virtual bool IsConfigModernAPI() { return false; } |
744 | virtual bool UseTrianglesAsQuad() { return false; } |
745 | virtual bool HasTileBuffering() { return false; } |
746 | virtual bool HasQuadBuffering() { return false; } |
747 | virtual bool HasTextBuffering() { return false; } |
748 | virtual bool HasQuadContainerBuffering() { return false; } |
749 | virtual bool Uses2DTextureArrays() { return false; } |
750 | virtual bool HasTextureArraysSupport() { return false; } |
751 | virtual const char *GetErrorString() { return NULL; } |
752 | |
753 | virtual const char *GetVendorString() = 0; |
754 | virtual const char *GetVersionString() = 0; |
755 | virtual const char *GetRendererString() = 0; |
756 | |
757 | // be aware that this function should only be called from the graphics thread, and even then you should really know what you are doing |
758 | virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() = 0; |
759 | |
760 | virtual bool GetWarning(std::vector<std::string> &WarningStrings) = 0; |
761 | |
762 | // returns true if the error msg was shown |
763 | virtual bool ShowMessageBox(unsigned Type, const char *pTitle, const char *pMsg) = 0; |
764 | }; |
765 | |
766 | class CGraphics_Threaded : public IEngineGraphics |
767 | { |
768 | enum |
769 | { |
770 | NUM_CMDBUFFERS = 2, |
771 | |
772 | DRAWING_QUADS = 1, |
773 | DRAWING_LINES = 2, |
774 | DRAWING_TRIANGLES = 3 |
775 | }; |
776 | |
777 | CCommandBuffer::SState m_State; |
778 | IGraphicsBackend *m_pBackend; |
779 | bool m_GLTileBufferingEnabled; |
780 | bool m_GLQuadBufferingEnabled; |
781 | bool m_GLTextBufferingEnabled; |
782 | bool m_GLQuadContainerBufferingEnabled; |
783 | bool m_GLUses2DTextureArrays; |
784 | bool m_GLHasTextureArraysSupport; |
785 | bool m_GLUseTrianglesAsQuad; |
786 | |
787 | CCommandBuffer *m_apCommandBuffers[NUM_CMDBUFFERS]; |
788 | CCommandBuffer *m_pCommandBuffer; |
789 | unsigned m_CurrentCommandBuffer; |
790 | |
791 | // |
792 | class IStorage *m_pStorage; |
793 | class IConsole *m_pConsole; |
794 | class IEngine *m_pEngine; |
795 | |
796 | int m_CurIndex; |
797 | |
798 | CCommandBuffer::SVertex m_aVertices[CCommandBuffer::MAX_VERTICES]; |
799 | CCommandBuffer::SVertexTex3DStream m_aVerticesTex3D[CCommandBuffer::MAX_VERTICES]; |
800 | int m_NumVertices; |
801 | |
802 | CCommandBuffer::SColor m_aColor[4]; |
803 | CCommandBuffer::STexCoord m_aTexture[4]; |
804 | |
805 | bool m_RenderEnable; |
806 | |
807 | float m_Rotation; |
808 | int m_Drawing; |
809 | bool m_DoScreenshot; |
810 | char m_aScreenshotName[IO_MAX_PATH_LENGTH]; |
811 | |
812 | CTextureHandle m_NullTexture; |
813 | |
814 | std::vector<int> m_vTextureIndices; |
815 | size_t m_FirstFreeTexture; |
816 | int m_TextureMemoryUsage; |
817 | |
818 | std::vector<uint8_t> m_vSpriteHelper; |
819 | |
820 | bool m_WarnPngliteIncompatibleImages = false; |
821 | |
822 | std::vector<SWarning> m_vWarnings; |
823 | |
824 | // is a non full windowed (in a sense that the viewport won't include the whole window), |
825 | // forced viewport, so that it justifies our UI ratio needs |
826 | bool m_IsForcedViewport = false; |
827 | |
828 | struct SVertexArrayInfo |
829 | { |
830 | SVertexArrayInfo() : |
831 | m_FreeIndex(-1) {} |
832 | // keep a reference to it, so we can free the ID |
833 | int m_AssociatedBufferObjectIndex; |
834 | |
835 | int m_FreeIndex; |
836 | }; |
837 | std::vector<SVertexArrayInfo> m_vVertexArrayInfo; |
838 | int m_FirstFreeVertexArrayInfo; |
839 | |
840 | std::vector<int> m_vBufferObjectIndices; |
841 | int m_FirstFreeBufferObjectIndex; |
842 | |
843 | struct SQuadContainer |
844 | { |
845 | SQuadContainer(bool AutomaticUpload = true) |
846 | { |
847 | m_vQuads.clear(); |
848 | m_QuadBufferObjectIndex = m_QuadBufferContainerIndex = -1; |
849 | m_FreeIndex = -1; |
850 | |
851 | m_AutomaticUpload = AutomaticUpload; |
852 | } |
853 | |
854 | struct SQuad |
855 | { |
856 | CCommandBuffer::SVertex m_aVertices[4]; |
857 | }; |
858 | |
859 | std::vector<SQuad> m_vQuads; |
860 | |
861 | int m_QuadBufferObjectIndex; |
862 | int m_QuadBufferContainerIndex; |
863 | |
864 | int m_FreeIndex; |
865 | |
866 | bool m_AutomaticUpload; |
867 | }; |
868 | std::vector<SQuadContainer> m_vQuadContainers; |
869 | int m_FirstFreeQuadContainer; |
870 | |
871 | std::vector<WINDOW_RESIZE_FUNC> m_vResizeListeners; |
872 | std::vector<WINDOW_PROPS_CHANGED_FUNC> m_vPropChangeListeners; |
873 | |
874 | void *AllocCommandBufferData(size_t AllocSize); |
875 | |
876 | void AddVertices(int Count); |
877 | void AddVertices(int Count, CCommandBuffer::SVertex *pVertices); |
878 | void AddVertices(int Count, CCommandBuffer::SVertexTex3DStream *pVertices); |
879 | |
880 | template<typename TName> |
881 | void Rotate(const CCommandBuffer::SPoint &rCenter, TName *pPoints, int NumPoints) |
882 | { |
883 | float c = std::cos(x: m_Rotation); |
884 | float s = std::sin(x: m_Rotation); |
885 | float x, y; |
886 | int i; |
887 | |
888 | TName *pVertices = pPoints; |
889 | for(i = 0; i < NumPoints; i++) |
890 | { |
891 | x = pVertices[i].m_Pos.x - rCenter.x; |
892 | y = pVertices[i].m_Pos.y - rCenter.y; |
893 | pVertices[i].m_Pos.x = x * c - y * s + rCenter.x; |
894 | pVertices[i].m_Pos.y = x * s + y * c + rCenter.y; |
895 | } |
896 | } |
897 | |
898 | template<typename TName> |
899 | void AddCmd( |
900 | TName &Cmd, std::function<bool()> FailFunc = [] { return true; }) |
901 | { |
902 | if(m_pCommandBuffer->AddCommandUnsafe(Cmd)) |
903 | return; |
904 | |
905 | // kick command buffer and try again |
906 | KickCommandBuffer(); |
907 | |
908 | if(!FailFunc()) |
909 | { |
910 | char aError[256]; |
911 | str_format(buffer: aError, buffer_size: sizeof(aError), format: "graphics: failed to run fail handler for command '%s'" , typeid(TName).name()); |
912 | dbg_assert(false, aError); |
913 | } |
914 | |
915 | if(!m_pCommandBuffer->AddCommandUnsafe(Cmd)) |
916 | { |
917 | char aError[256]; |
918 | str_format(buffer: aError, buffer_size: sizeof(aError), format: "graphics: failed to add command '%s' to command buffer" , typeid(TName).name()); |
919 | dbg_assert(false, aError); |
920 | } |
921 | } |
922 | |
923 | void KickCommandBuffer(); |
924 | |
925 | void AddBackEndWarningIfExists(); |
926 | |
927 | void AdjustViewport(bool SendViewportChangeToBackend); |
928 | |
929 | ivec2 m_ReadPixelPosition = ivec2(0, 0); |
930 | ColorRGBA *m_pReadPixelColor = nullptr; |
931 | void ReadPixelDirect(bool *pSwapped); |
932 | void ScreenshotDirect(bool *pSwapped); |
933 | |
934 | int IssueInit(); |
935 | int InitWindow(); |
936 | |
937 | public: |
938 | CGraphics_Threaded(); |
939 | |
940 | void ClipEnable(int x, int y, int w, int h) override; |
941 | void ClipDisable() override; |
942 | |
943 | void BlendNone() override; |
944 | void BlendNormal() override; |
945 | void BlendAdditive() override; |
946 | |
947 | void WrapNormal() override; |
948 | void WrapClamp() override; |
949 | |
950 | uint64_t TextureMemoryUsage() const override; |
951 | uint64_t BufferMemoryUsage() const override; |
952 | uint64_t StreamedMemoryUsage() const override; |
953 | uint64_t StagingMemoryUsage() const override; |
954 | |
955 | const TTwGraphicsGpuList &GetGpus() const override; |
956 | |
957 | void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) override; |
958 | void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY) override; |
959 | |
960 | void LinesBegin() override; |
961 | void LinesEnd() override; |
962 | void LinesDraw(const CLineItem *pArray, int Num) override; |
963 | |
964 | IGraphics::CTextureHandle FindFreeTextureIndex(); |
965 | void FreeTextureIndex(CTextureHandle *pIndex); |
966 | int UnloadTexture(IGraphics::CTextureHandle *pIndex) override; |
967 | IGraphics::CTextureHandle LoadTextureRaw(const CImageInfo &Image, int Flags, const char *pTexName = nullptr) override; |
968 | IGraphics::CTextureHandle LoadTextureRawMove(CImageInfo &Image, int Flags, const char *pTexName = nullptr) override; |
969 | int LoadTextureRawSub(IGraphics::CTextureHandle TextureId, int x, int y, const CImageInfo &Image) override; |
970 | IGraphics::CTextureHandle NullTexture() const override; |
971 | |
972 | bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) override; |
973 | bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override; |
974 | bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData) override; |
975 | |
976 | CTextureHandle LoadSpriteTextureImpl(const CImageInfo &FromImageInfo, int x, int y, size_t w, size_t h, const char *pName); |
977 | CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override; |
978 | |
979 | bool IsImageSubFullyTransparent(const CImageInfo &FromImageInfo, int x, int y, int w, int h) override; |
980 | bool IsSpriteTextureFullyTransparent(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override; |
981 | |
982 | // simple uncompressed RGBA loaders |
983 | IGraphics::CTextureHandle LoadTexture(const char *pFilename, int StorageType, int Flags = 0) override; |
984 | bool LoadPng(CImageInfo &Image, const char *pFilename, int StorageType) override; |
985 | |
986 | bool CheckImageDivisibility(const char *pFileName, CImageInfo &Img, int DivX, int DivY, bool AllowResize) override; |
987 | bool IsImageFormatRGBA(const char *pFileName, CImageInfo &Img) override; |
988 | |
989 | void CopyTextureBufferSub(uint8_t *pDestBuffer, const CImageInfo &SourceImage, size_t SubOffsetX, size_t SubOffsetY, size_t SubCopyWidth, size_t SubCopyHeight) override; |
990 | 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; |
991 | |
992 | void TextureSet(CTextureHandle TextureId) override; |
993 | |
994 | void Clear(float r, float g, float b, bool ForceClearNow = false) override; |
995 | |
996 | void QuadsBegin() override; |
997 | void QuadsEnd() override; |
998 | void QuadsTex3DBegin() override; |
999 | void QuadsTex3DEnd() override; |
1000 | void TrianglesBegin() override; |
1001 | void TrianglesEnd() override; |
1002 | void QuadsEndKeepVertices() override; |
1003 | void QuadsDrawCurrentVertices(bool KeepVertices = true) override; |
1004 | void QuadsSetRotation(float Angle) override; |
1005 | |
1006 | template<typename TName> |
1007 | void SetColor(TName *pVertex, int ColorIndex) |
1008 | { |
1009 | TName *pVert = pVertex; |
1010 | pVert->m_Color = m_aColor[ColorIndex]; |
1011 | } |
1012 | |
1013 | void SetColorVertex(const CColorVertex *pArray, size_t Num) override; |
1014 | void SetColor(float r, float g, float b, float a) override; |
1015 | void SetColor(ColorRGBA Color) override; |
1016 | void SetColor4(ColorRGBA TopLeft, ColorRGBA TopRight, ColorRGBA BottomLeft, ColorRGBA BottomRight) override; |
1017 | |
1018 | // go through all vertices and change their color (only works for quads) |
1019 | void ChangeColorOfCurrentQuadVertices(float r, float g, float b, float a) override; |
1020 | void ChangeColorOfQuadVertices(size_t QuadOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a) override; |
1021 | |
1022 | void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV) override; |
1023 | void QuadsSetSubsetFree( |
1024 | float x0, float y0, float x1, float y1, |
1025 | float x2, float y2, float x3, float y3, int Index = -1) override; |
1026 | |
1027 | void QuadsDraw(CQuadItem *pArray, int Num) override; |
1028 | |
1029 | template<typename TName> |
1030 | void QuadsDrawTLImpl(TName *pVertices, const CQuadItem *pArray, int Num) |
1031 | { |
1032 | CCommandBuffer::SPoint Center; |
1033 | |
1034 | dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsDrawTL without begin" ); |
1035 | |
1036 | if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad) |
1037 | { |
1038 | for(int i = 0; i < Num; ++i) |
1039 | { |
1040 | // first triangle |
1041 | pVertices[m_NumVertices + 6 * i].m_Pos.x = pArray[i].m_X; |
1042 | pVertices[m_NumVertices + 6 * i].m_Pos.y = pArray[i].m_Y; |
1043 | pVertices[m_NumVertices + 6 * i].m_Tex = m_aTexture[0]; |
1044 | SetColor(&pVertices[m_NumVertices + 6 * i], 0); |
1045 | |
1046 | pVertices[m_NumVertices + 6 * i + 1].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1047 | pVertices[m_NumVertices + 6 * i + 1].m_Pos.y = pArray[i].m_Y; |
1048 | pVertices[m_NumVertices + 6 * i + 1].m_Tex = m_aTexture[1]; |
1049 | SetColor(&pVertices[m_NumVertices + 6 * i + 1], 1); |
1050 | |
1051 | pVertices[m_NumVertices + 6 * i + 2].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1052 | pVertices[m_NumVertices + 6 * i + 2].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1053 | pVertices[m_NumVertices + 6 * i + 2].m_Tex = m_aTexture[2]; |
1054 | SetColor(&pVertices[m_NumVertices + 6 * i + 2], 2); |
1055 | |
1056 | // second triangle |
1057 | pVertices[m_NumVertices + 6 * i + 3].m_Pos.x = pArray[i].m_X; |
1058 | pVertices[m_NumVertices + 6 * i + 3].m_Pos.y = pArray[i].m_Y; |
1059 | pVertices[m_NumVertices + 6 * i + 3].m_Tex = m_aTexture[0]; |
1060 | SetColor(&pVertices[m_NumVertices + 6 * i + 3], 0); |
1061 | |
1062 | pVertices[m_NumVertices + 6 * i + 4].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1063 | pVertices[m_NumVertices + 6 * i + 4].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1064 | pVertices[m_NumVertices + 6 * i + 4].m_Tex = m_aTexture[2]; |
1065 | SetColor(&pVertices[m_NumVertices + 6 * i + 4], 2); |
1066 | |
1067 | pVertices[m_NumVertices + 6 * i + 5].m_Pos.x = pArray[i].m_X; |
1068 | pVertices[m_NumVertices + 6 * i + 5].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1069 | pVertices[m_NumVertices + 6 * i + 5].m_Tex = m_aTexture[3]; |
1070 | SetColor(&pVertices[m_NumVertices + 6 * i + 5], 3); |
1071 | |
1072 | if(m_Rotation != 0) |
1073 | { |
1074 | Center.x = pArray[i].m_X + pArray[i].m_Width / 2; |
1075 | Center.y = pArray[i].m_Y + pArray[i].m_Height / 2; |
1076 | |
1077 | Rotate(Center, &pVertices[m_NumVertices + 6 * i], 6); |
1078 | } |
1079 | } |
1080 | |
1081 | AddVertices(3 * 2 * Num, pVertices); |
1082 | } |
1083 | else |
1084 | { |
1085 | for(int i = 0; i < Num; ++i) |
1086 | { |
1087 | pVertices[m_NumVertices + 4 * i].m_Pos.x = pArray[i].m_X; |
1088 | pVertices[m_NumVertices + 4 * i].m_Pos.y = pArray[i].m_Y; |
1089 | pVertices[m_NumVertices + 4 * i].m_Tex = m_aTexture[0]; |
1090 | SetColor(&pVertices[m_NumVertices + 4 * i], 0); |
1091 | |
1092 | pVertices[m_NumVertices + 4 * i + 1].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1093 | pVertices[m_NumVertices + 4 * i + 1].m_Pos.y = pArray[i].m_Y; |
1094 | pVertices[m_NumVertices + 4 * i + 1].m_Tex = m_aTexture[1]; |
1095 | SetColor(&pVertices[m_NumVertices + 4 * i + 1], 1); |
1096 | |
1097 | pVertices[m_NumVertices + 4 * i + 2].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; |
1098 | pVertices[m_NumVertices + 4 * i + 2].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1099 | pVertices[m_NumVertices + 4 * i + 2].m_Tex = m_aTexture[2]; |
1100 | SetColor(&pVertices[m_NumVertices + 4 * i + 2], 2); |
1101 | |
1102 | pVertices[m_NumVertices + 4 * i + 3].m_Pos.x = pArray[i].m_X; |
1103 | pVertices[m_NumVertices + 4 * i + 3].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; |
1104 | pVertices[m_NumVertices + 4 * i + 3].m_Tex = m_aTexture[3]; |
1105 | SetColor(&pVertices[m_NumVertices + 4 * i + 3], 3); |
1106 | |
1107 | if(m_Rotation != 0) |
1108 | { |
1109 | Center.x = pArray[i].m_X + pArray[i].m_Width / 2; |
1110 | Center.y = pArray[i].m_Y + pArray[i].m_Height / 2; |
1111 | |
1112 | Rotate(Center, &pVertices[m_NumVertices + 4 * i], 4); |
1113 | } |
1114 | } |
1115 | |
1116 | AddVertices(4 * Num, pVertices); |
1117 | } |
1118 | } |
1119 | |
1120 | void QuadsDrawTL(const CQuadItem *pArray, int Num) override; |
1121 | |
1122 | void QuadsTex3DDrawTL(const CQuadItem *pArray, int Num) override; |
1123 | |
1124 | void QuadsDrawFreeform(const CFreeformItem *pArray, int Num) override; |
1125 | void QuadsText(float x, float y, float Size, const char *pText) override; |
1126 | |
1127 | void DrawRectExt(float x, float y, float w, float h, float r, int Corners) override; |
1128 | void DrawRectExt4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, float r, int Corners) override; |
1129 | int CreateRectQuadContainer(float x, float y, float w, float h, float r, int Corners) override; |
1130 | void DrawRect(float x, float y, float w, float h, ColorRGBA Color, int Corners, float Rounding) override; |
1131 | void DrawRect4(float x, float y, float w, float h, ColorRGBA ColorTopLeft, ColorRGBA ColorTopRight, ColorRGBA ColorBottomLeft, ColorRGBA ColorBottomRight, int Corners, float Rounding) override; |
1132 | void DrawCircle(float CenterX, float CenterY, float Radius, int Segments) override; |
1133 | |
1134 | const GL_STexCoord *GetCurTextureCoordinates() override |
1135 | { |
1136 | return m_aTexture; |
1137 | } |
1138 | |
1139 | const GL_SColor *GetCurColor() override |
1140 | { |
1141 | return m_aColor; |
1142 | } |
1143 | |
1144 | int CreateQuadContainer(bool AutomaticUpload = true) override; |
1145 | void QuadContainerChangeAutomaticUpload(int ContainerIndex, bool AutomaticUpload) override; |
1146 | void QuadContainerUpload(int ContainerIndex) override; |
1147 | int QuadContainerAddQuads(int ContainerIndex, CQuadItem *pArray, int Num) override; |
1148 | int QuadContainerAddQuads(int ContainerIndex, CFreeformItem *pArray, int Num) override; |
1149 | void QuadContainerReset(int ContainerIndex) override; |
1150 | void DeleteQuadContainer(int &ContainerIndex) override; |
1151 | void RenderQuadContainer(int ContainerIndex, int QuadDrawNum) override; |
1152 | void RenderQuadContainer(int ContainerIndex, int QuadOffset, int QuadDrawNum, bool ChangeWrapMode = true) override; |
1153 | void RenderQuadContainerEx(int ContainerIndex, int QuadOffset, int QuadDrawNum, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override; |
1154 | void RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override; |
1155 | void RenderQuadContainerAsSpriteMultiple(int ContainerIndex, int QuadOffset, int DrawCount, SRenderSpriteInfo *pRenderInfo) override; |
1156 | |
1157 | template<typename TName> |
1158 | void FlushVerticesImpl(bool KeepVertices, int &PrimType, size_t &PrimCount, size_t &NumVerts, TName &Command, size_t VertSize) |
1159 | { |
1160 | Command.m_pVertices = nullptr; |
1161 | if(m_NumVertices == 0) |
1162 | return; |
1163 | |
1164 | NumVerts = m_NumVertices; |
1165 | |
1166 | if(!KeepVertices) |
1167 | m_NumVertices = 0; |
1168 | |
1169 | if(m_Drawing == DRAWING_QUADS) |
1170 | { |
1171 | if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad) |
1172 | { |
1173 | PrimType = CCommandBuffer::PRIMTYPE_TRIANGLES; |
1174 | PrimCount = NumVerts / 3; |
1175 | } |
1176 | else |
1177 | { |
1178 | PrimType = CCommandBuffer::PRIMTYPE_QUADS; |
1179 | PrimCount = NumVerts / 4; |
1180 | } |
1181 | } |
1182 | else if(m_Drawing == DRAWING_LINES) |
1183 | { |
1184 | PrimType = CCommandBuffer::PRIMTYPE_LINES; |
1185 | PrimCount = NumVerts / 2; |
1186 | } |
1187 | else if(m_Drawing == DRAWING_TRIANGLES) |
1188 | { |
1189 | PrimType = CCommandBuffer::PRIMTYPE_TRIANGLES; |
1190 | PrimCount = NumVerts / 3; |
1191 | } |
1192 | else |
1193 | return; |
1194 | |
1195 | Command.m_pVertices = (decltype(Command.m_pVertices))AllocCommandBufferData(AllocSize: VertSize * NumVerts); |
1196 | Command.m_State = m_State; |
1197 | |
1198 | Command.m_PrimType = PrimType; |
1199 | Command.m_PrimCount = PrimCount; |
1200 | |
1201 | AddCmd(Command, [&] { |
1202 | Command.m_pVertices = (decltype(Command.m_pVertices))m_pCommandBuffer->AllocData(WantedSize: VertSize * NumVerts); |
1203 | return Command.m_pVertices != nullptr; |
1204 | }); |
1205 | |
1206 | m_pCommandBuffer->AddRenderCalls(RenderCallCountToAdd: 1); |
1207 | } |
1208 | |
1209 | void FlushVertices(bool KeepVertices = false) override; |
1210 | void FlushVerticesTex3D() override; |
1211 | |
1212 | void RenderTileLayer(int BufferContainerIndex, const ColorRGBA &Color, char **pOffsets, unsigned int *pIndicedVertexDrawNum, size_t NumIndicesOffset) override; |
1213 | virtual void RenderBorderTiles(int BufferContainerIndex, const ColorRGBA &Color, char *pIndexBufferOffset, const vec2 &Offset, const vec2 &Scale, uint32_t DrawNum) override; |
1214 | void RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, size_t QuadNum, int QuadOffset) override; |
1215 | void RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor) override; |
1216 | |
1217 | // modern GL functions |
1218 | int CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override; |
1219 | void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override; |
1220 | void UpdateBufferObjectInternal(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer = false); |
1221 | void CopyBufferObjectInternal(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize); |
1222 | void DeleteBufferObject(int BufferIndex) override; |
1223 | |
1224 | int CreateBufferContainer(SBufferContainerInfo *pContainerInfo) override; |
1225 | // destroying all buffer objects means, that all referenced VBOs are destroyed automatically, so the user does not need to save references to them |
1226 | void DeleteBufferContainer(int &ContainerIndex, bool DestroyAllBO = true) override; |
1227 | void UpdateBufferContainerInternal(int ContainerIndex, SBufferContainerInfo *pContainerInfo); |
1228 | void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) override; |
1229 | |
1230 | int GetNumScreens() const override; |
1231 | const char *GetScreenName(int Screen) const override; |
1232 | |
1233 | void Minimize() override; |
1234 | void Maximize() override; |
1235 | void WarnPngliteIncompatibleImages(bool Warn) override; |
1236 | void SetWindowParams(int FullscreenMode, bool IsBorderless) override; |
1237 | bool SetWindowScreen(int Index) override; |
1238 | void Move(int x, int y) override; |
1239 | bool Resize(int w, int h, int RefreshRate) override; |
1240 | void ResizeToScreen() override; |
1241 | void GotResized(int w, int h, int RefreshRate) override; |
1242 | void UpdateViewport(int X, int Y, int W, int H, bool ByResize) override; |
1243 | void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc) override; |
1244 | void AddWindowPropChangeListener(WINDOW_PROPS_CHANGED_FUNC pFunc) override; |
1245 | int GetWindowScreen() override; |
1246 | |
1247 | void WindowDestroyNtf(uint32_t WindowId) override; |
1248 | void WindowCreateNtf(uint32_t WindowId) override; |
1249 | |
1250 | int WindowActive() override; |
1251 | int WindowOpen() override; |
1252 | |
1253 | void SetWindowGrab(bool Grab) override; |
1254 | void NotifyWindow() override; |
1255 | |
1256 | int Init() override; |
1257 | void Shutdown() override; |
1258 | |
1259 | void ReadPixel(ivec2 Position, ColorRGBA *pColor) override; |
1260 | void TakeScreenshot(const char *pFilename) override; |
1261 | void TakeCustomScreenshot(const char *pFilename) override; |
1262 | void Swap() override; |
1263 | bool SetVSync(bool State) override; |
1264 | bool SetMultiSampling(uint32_t ReqMultiSamplingCount, uint32_t &MultiSamplingCountBackend) override; |
1265 | |
1266 | int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen) override; |
1267 | void GetCurrentVideoMode(CVideoMode &CurMode, int Screen) override; |
1268 | |
1269 | virtual int GetDesktopScreenWidth() const { return g_Config.m_GfxDesktopWidth; } |
1270 | virtual int GetDesktopScreenHeight() const { return g_Config.m_GfxDesktopHeight; } |
1271 | |
1272 | // synchronization |
1273 | void InsertSignal(CSemaphore *pSemaphore) override; |
1274 | bool IsIdle() const override; |
1275 | void WaitForIdle() override; |
1276 | |
1277 | SWarning *GetCurWarning() override; |
1278 | bool ShowMessageBox(unsigned Type, const char *pTitle, const char *pMsg) override; |
1279 | bool IsBackendInitialized() override; |
1280 | |
1281 | 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); } |
1282 | bool IsConfigModernAPI() override { return m_pBackend->IsConfigModernAPI(); } |
1283 | bool IsTileBufferingEnabled() override { return m_GLTileBufferingEnabled; } |
1284 | bool IsQuadBufferingEnabled() override { return m_GLQuadBufferingEnabled; } |
1285 | bool IsTextBufferingEnabled() override { return m_GLTextBufferingEnabled; } |
1286 | bool IsQuadContainerBufferingEnabled() override { return m_GLQuadContainerBufferingEnabled; } |
1287 | bool Uses2DTextureArrays() override { return m_GLUses2DTextureArrays; } |
1288 | bool HasTextureArraysSupport() override { return m_GLHasTextureArraysSupport; } |
1289 | |
1290 | const char *GetVendorString() override; |
1291 | const char *GetVersionString() override; |
1292 | const char *GetRendererString() override; |
1293 | |
1294 | TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() override; |
1295 | }; |
1296 | |
1297 | typedef std::function<const char *(const char *, const char *)> TTranslateFunc; |
1298 | extern IGraphicsBackend *CreateGraphicsBackend(TTranslateFunc &&TranslateFunc); |
1299 | |
1300 | #endif // ENGINE_CLIENT_GRAPHICS_THREADED_H |
1301 | |