1#include "backend_opengl.h"
2
3#include <base/dbg.h>
4#include <base/detect.h>
5#include <base/log.h>
6#include <base/mem.h>
7#include <base/str.h>
8
9#include <engine/client/backend_sdl.h>
10#include <engine/graphics.h>
11
12#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
13
14#include <engine/client/backend/glsl_shader_compiler.h>
15#include <engine/client/backend/opengl/opengl_sl.h>
16#include <engine/client/backend/opengl/opengl_sl_program.h>
17#include <engine/client/blocklist_driver.h>
18#include <engine/gfx/image_manipulation.h>
19
20#ifndef BACKEND_AS_OPENGL_ES
21#include <GL/glew.h>
22#else
23#include <GLES3/gl3.h>
24#define GL_TEXTURE_2D_ARRAY_EXT GL_TEXTURE_2D_ARRAY
25// GLES doesn't support GL_QUADS, but the code is also never executed
26#define GL_QUADS GL_TRIANGLES
27#ifndef CONF_BACKEND_OPENGL_ES3
28#include <GLES/gl.h>
29#define glOrtho glOrthof
30#else
31#define BACKEND_GL_MODERN_API 1
32#endif
33#endif
34
35// ------------ CCommandProcessorFragment_OpenGL
36void CCommandProcessorFragment_OpenGL::Cmd_Update_Viewport(const CCommandBuffer::SCommand_Update_Viewport *pCommand)
37{
38 if(pCommand->m_ByResize)
39 {
40 m_CanvasWidth = (uint32_t)pCommand->m_Width;
41 m_CanvasHeight = (uint32_t)pCommand->m_Height;
42 }
43 glViewport(x: pCommand->m_X, y: pCommand->m_Y, width: pCommand->m_Width, height: pCommand->m_Height);
44}
45
46size_t CCommandProcessorFragment_OpenGL::GLFormatToPixelSize(int GLFormat)
47{
48 switch(GLFormat)
49 {
50 case GL_RGBA: return 4;
51 case GL_RGB: return 3;
52 case GL_RED: return 1;
53 case GL_ALPHA: return 1;
54 default: return 4;
55 }
56}
57
58bool CCommandProcessorFragment_OpenGL::IsTexturedState(const CCommandBuffer::SState &State)
59{
60 return State.m_Texture >= 0 && State.m_Texture < (int)m_vTextures.size();
61}
62
63void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State, bool Use2DArrayTextures)
64{
65#ifndef BACKEND_GL_MODERN_API
66 // blend
67 switch(State.m_BlendMode)
68 {
69 case EBlendMode::NONE:
70 glDisable(GL_BLEND);
71 break;
72 case EBlendMode::ALPHA:
73 glEnable(GL_BLEND);
74 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
75 break;
76 case EBlendMode::ADDITIVE:
77 glEnable(GL_BLEND);
78 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
79 break;
80 default:
81 dbg_assert_failed("Invalid blend mode: %d", (int)State.m_BlendMode);
82 };
83 m_LastBlendMode = State.m_BlendMode;
84
85 // clip
86 if(State.m_ClipEnable)
87 {
88 glScissor(x: State.m_ClipX, y: State.m_ClipY, width: State.m_ClipW, height: State.m_ClipH);
89 glEnable(GL_SCISSOR_TEST);
90 m_LastClipEnable = true;
91 }
92 else if(m_LastClipEnable)
93 {
94 // Don't disable it always
95 glDisable(GL_SCISSOR_TEST);
96 m_LastClipEnable = false;
97 }
98
99 glDisable(GL_TEXTURE_2D);
100 if(!m_HasShaders)
101 {
102 if(m_Has3DTextures)
103 glDisable(GL_TEXTURE_3D);
104 if(m_Has2DArrayTextures)
105 {
106 glDisable(cap: m_2DArrayTarget);
107 }
108 }
109
110 if(m_HasShaders && IsNewApi())
111 {
112 glBindSampler(0, 0);
113 }
114
115 // texture
116 if(IsTexturedState(State))
117 {
118 if(!Use2DArrayTextures)
119 {
120 glEnable(GL_TEXTURE_2D);
121 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[State.m_Texture].m_Tex);
122
123 if(m_vTextures[State.m_Texture].m_LastWrapMode != State.m_WrapMode)
124 {
125 switch(State.m_WrapMode)
126 {
127 case EWrapMode::REPEAT:
128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
130 break;
131 case EWrapMode::CLAMP:
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
134 break;
135 default:
136 dbg_assert_failed("Invalid wrap mode: %d", (int)State.m_WrapMode);
137 };
138 m_vTextures[State.m_Texture].m_LastWrapMode = State.m_WrapMode;
139 }
140 }
141 else if(m_Has2DArrayTextures)
142 {
143 if(!m_HasShaders)
144 glEnable(cap: m_2DArrayTarget);
145 glBindTexture(target: m_2DArrayTarget, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
146 }
147 else if(m_Has3DTextures)
148 {
149 if(!m_HasShaders)
150 glEnable(GL_TEXTURE_3D);
151 glBindTexture(GL_TEXTURE_3D, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
152 }
153 else
154 {
155 dbg_assert_failed("Should have either 2D, 3D or no texture array support");
156 }
157 }
158
159 // screen mapping
160 glMatrixMode(GL_PROJECTION);
161 glLoadIdentity();
162 glOrtho(left: State.m_ScreenTL.x, right: State.m_ScreenBR.x, bottom: State.m_ScreenBR.y, top: State.m_ScreenTL.y, zNear: -10.0f, zFar: 10.f);
163#endif
164}
165
166static void ParseVersionString(EBackendType BackendType, const char *pStr, int &VersionMajor, int &VersionMinor, int &VersionPatch)
167{
168 if(pStr)
169 {
170 // if backend is GLES, it starts with "OpenGL ES " or OpenGL ES-CM for older contexts, rest is the same
171 if(BackendType == BACKEND_TYPE_OPENGL_ES)
172 {
173 int StrLenGLES = str_length(str: "OpenGL ES ");
174 int StrLenGLESCM = str_length(str: "OpenGL ES-CM ");
175 if(str_comp_num(a: pStr, b: "OpenGL ES ", num: StrLenGLES) == 0)
176 pStr += StrLenGLES;
177 else if(str_comp_num(a: pStr, b: "OpenGL ES-CM ", num: StrLenGLESCM) == 0)
178 pStr += StrLenGLESCM;
179 }
180
181 char aCurNumberStr[32];
182 size_t CurNumberStrLen = 0;
183 size_t TotalNumbersPassed = 0;
184 int aNumbers[3] = {0};
185 bool LastWasNumber = false;
186 while(*pStr && TotalNumbersPassed < 3)
187 {
188 if(str_isnum(c: *pStr))
189 {
190 aCurNumberStr[CurNumberStrLen++] = (char)*pStr;
191 LastWasNumber = true;
192 }
193 else if(LastWasNumber && (*pStr == '.' || *pStr == ' '))
194 {
195 if(CurNumberStrLen > 0)
196 {
197 aCurNumberStr[CurNumberStrLen] = 0;
198 aNumbers[TotalNumbersPassed++] = str_toint(str: aCurNumberStr);
199 CurNumberStrLen = 0;
200 }
201
202 LastWasNumber = false;
203
204 if(*pStr != '.')
205 break;
206 }
207 else
208 {
209 break;
210 }
211
212 ++pStr;
213 }
214
215 VersionMajor = aNumbers[0];
216 VersionMinor = aNumbers[1];
217 VersionPatch = aNumbers[2];
218 }
219}
220
221#ifndef BACKEND_AS_OPENGL_ES
222static LEVEL GetLogSeverity(GLenum Severity)
223{
224 switch(Severity)
225 {
226 case GL_DEBUG_SEVERITY_HIGH: return LEVEL_ERROR;
227 case GL_DEBUG_SEVERITY_MEDIUM: return LEVEL_WARN;
228 case GL_DEBUG_SEVERITY_LOW: return LEVEL_INFO;
229 case GL_DEBUG_SEVERITY_NOTIFICATION: return LEVEL_DEBUG;
230 default: dbg_assert_failed("Severity invalid: %d", (int)Severity);
231 }
232}
233
234static const char *GetErrorName(GLenum Type)
235{
236 switch(Type)
237 {
238 case GL_DEBUG_TYPE_ERROR: return "ERROR";
239 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "DEPRECATED BEHAVIOR";
240 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "UNDEFINED BEHAVIOR";
241 case GL_DEBUG_TYPE_PORTABILITY: return "PORTABILITY";
242 case GL_DEBUG_TYPE_PERFORMANCE: return "PERFORMANCE";
243 case GL_DEBUG_TYPE_OTHER: return "OTHER";
244 case GL_DEBUG_TYPE_MARKER: return "MARKER";
245 case GL_DEBUG_TYPE_PUSH_GROUP: return "PUSH_GROUP";
246 case GL_DEBUG_TYPE_POP_GROUP: return "POP_GROUP";
247 default: return "UNKNOWN";
248 }
249}
250
251static const char *GetSeverityString(GLenum Severity)
252{
253 switch(Severity)
254 {
255 // All OpenGL Errors, shader compilation/linking errors, or highly-dangerous undefined behavior
256 case GL_DEBUG_SEVERITY_HIGH: return "high";
257 // Major performance warnings, shader compilation/linking warnings, or the use of deprecated functionality
258 case GL_DEBUG_SEVERITY_MEDIUM: return "medium";
259 // Redundant state change performance warning, or unimportant undefined behavior
260 case GL_DEBUG_SEVERITY_LOW: return "low";
261 // Anything that isn't an error or performance issue.
262 case GL_DEBUG_SEVERITY_NOTIFICATION: return "notification";
263 default: dbg_assert_failed("Severity invalid: %d", (int)Severity);
264 }
265}
266
267static void GLAPIENTRY
268GfxOpenGLMessageCallback(GLenum Source,
269 GLenum Type,
270 GLuint Id,
271 GLenum Severity,
272 GLsizei Length,
273 const GLchar *pMsg,
274 const void *pUserParam)
275{
276 log_log(level: GetLogSeverity(Severity), sys: "gfx/opengl", fmt: "[%s] (importance: %s) %s", GetErrorName(Type), GetSeverityString(Severity), pMsg);
277}
278#endif
279
280bool CCommandProcessorFragment_OpenGL::GetPresentedImageData(uint32_t &Width, uint32_t &Height, CImageInfo::EImageFormat &Format, std::vector<uint8_t> &vDstData)
281{
282 if(m_CanvasWidth == 0 || m_CanvasHeight == 0)
283 {
284 return false;
285 }
286 else
287 {
288 Width = m_CanvasWidth;
289 Height = m_CanvasHeight;
290 Format = CImageInfo::FORMAT_RGBA;
291 vDstData.resize(new_size: (size_t)Width * (Height + 1) * 4); // +1 for flipping image
292 glReadBuffer(GL_FRONT);
293 GLint Alignment;
294 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
295 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
296 glReadPixels(x: 0, y: 0, width: m_CanvasWidth, height: m_CanvasHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels: vDstData.data());
297 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
298
299 uint8_t *pTempRow = vDstData.data() + Width * Height * 4;
300 for(uint32_t Y = 0; Y < Height / 2; ++Y)
301 {
302 mem_copy(dest: pTempRow, source: vDstData.data() + Y * Width * 4, size: Width * 4);
303 mem_copy(dest: vDstData.data() + Y * Width * 4, source: vDstData.data() + ((Height - Y) - 1) * Width * 4, size: Width * 4);
304 mem_copy(dest: vDstData.data() + ((Height - Y) - 1) * Width * 4, source: pTempRow, size: Width * 4);
305 }
306
307 return true;
308 }
309}
310
311bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
312{
313 m_IsOpenGLES = pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL_ES;
314
315 *pCommand->m_pReadPresentedImageDataFunc = [this](uint32_t &Width, uint32_t &Height, CImageInfo::EImageFormat &Format, std::vector<uint8_t> &vDstData) {
316 return GetPresentedImageData(Width, Height, Format, vDstData);
317 };
318
319 const char *pVendorString = (const char *)glGetString(GL_VENDOR);
320 log_info("gfx/opengl", "Vendor string: %s", pVendorString);
321
322 // check what this context can do
323 const char *pVersionString = (const char *)glGetString(GL_VERSION);
324 log_info("gfx/opengl", "Version string: %s", pVersionString);
325
326 const char *pRendererString = (const char *)glGetString(GL_RENDERER);
327
328 str_copy(dst: pCommand->m_pVendorString, src: pVendorString, dst_size: GPU_INFO_STRING_SIZE);
329 str_copy(dst: pCommand->m_pVersionString, src: pVersionString, dst_size: GPU_INFO_STRING_SIZE);
330 str_copy(dst: pCommand->m_pRendererString, src: pRendererString, dst_size: GPU_INFO_STRING_SIZE);
331
332 // parse version string
333 ParseVersionString(BackendType: pCommand->m_RequestedBackend, pStr: pVersionString, VersionMajor&: pCommand->m_pCapabilities->m_ContextMajor, VersionMinor&: pCommand->m_pCapabilities->m_ContextMinor, VersionPatch&: pCommand->m_pCapabilities->m_ContextPatch);
334
335 *pCommand->m_pInitError = 0;
336
337 int BlocklistMajor = -1, BlocklistMinor = -1, BlocklistPatch = -1;
338 bool RequiresWarning = false;
339 const char *pErrString = ParseBlocklistDriverVersions(pVendorStr: pVendorString, pVersionStr: pVersionString, BlocklistMajor, BlocklistMinor, BlocklistPatch, RequiresWarning);
340 // if the driver is buggy, and the requested GL version is the default, fallback
341 if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0)
342 {
343 // if not already in the error state, set the GL version
344 if(g_Config.m_GfxDriverIsBlocked == 0)
345 {
346 // fallback to known good GL version
347 pCommand->m_pCapabilities->m_ContextMajor = BlocklistMajor;
348 pCommand->m_pCapabilities->m_ContextMinor = BlocklistMinor;
349 pCommand->m_pCapabilities->m_ContextPatch = BlocklistPatch;
350
351 // set backend error string
352 if(RequiresWarning)
353 *pCommand->m_pErrStringPtr = pErrString;
354 *pCommand->m_pInitError = -2;
355
356 g_Config.m_GfxDriverIsBlocked = 1;
357 }
358 }
359 // if the driver was in a blocked error state, but is not anymore, reset all config variables
360 else if(pErrString == NULL && g_Config.m_GfxDriverIsBlocked == 1)
361 {
362 pCommand->m_pCapabilities->m_ContextMajor = 3;
363 pCommand->m_pCapabilities->m_ContextMinor = 0;
364 pCommand->m_pCapabilities->m_ContextPatch = 0;
365
366 // tell the caller to reinitialize the context
367 *pCommand->m_pInitError = -2;
368
369 g_Config.m_GfxDriverIsBlocked = 0;
370 }
371
372 int MajorV = pCommand->m_pCapabilities->m_ContextMajor;
373
374 if(pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL)
375 {
376#ifndef BACKEND_AS_OPENGL_ES
377 int MinorV = pCommand->m_pCapabilities->m_ContextMinor;
378 if(*pCommand->m_pInitError == 0)
379 {
380 if(MajorV < pCommand->m_RequestedMajor)
381 {
382 *pCommand->m_pInitError = -2;
383 }
384 else if(MajorV == pCommand->m_RequestedMajor)
385 {
386 if(MinorV < pCommand->m_RequestedMinor)
387 {
388 *pCommand->m_pInitError = -2;
389 }
390 else if(MinorV == pCommand->m_RequestedMinor)
391 {
392 int PatchV = pCommand->m_pCapabilities->m_ContextPatch;
393 if(PatchV < pCommand->m_RequestedPatch)
394 {
395 *pCommand->m_pInitError = -2;
396 }
397 }
398 }
399 }
400
401 if(*pCommand->m_pInitError == 0)
402 {
403 MajorV = pCommand->m_RequestedMajor;
404 MinorV = pCommand->m_RequestedMinor;
405
406 pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = false;
407 pCommand->m_pCapabilities->m_NPOTTextures = true;
408 pCommand->m_pCapabilities->m_TrianglesAsQuads = false;
409
410 if(MajorV >= 4 || (MajorV == 3 && MinorV == 3))
411 {
412 pCommand->m_pCapabilities->m_TileBuffering = true;
413 pCommand->m_pCapabilities->m_QuadBuffering = true;
414 pCommand->m_pCapabilities->m_TextBuffering = true;
415 pCommand->m_pCapabilities->m_QuadContainerBuffering = true;
416 pCommand->m_pCapabilities->m_ShaderSupport = true;
417
418 pCommand->m_pCapabilities->m_MipMapping = true;
419 pCommand->m_pCapabilities->m_3DTextures = true;
420 pCommand->m_pCapabilities->m_2DArrayTextures = true;
421
422 pCommand->m_pCapabilities->m_TrianglesAsQuads = true;
423 }
424 else if(MajorV == 3)
425 {
426 pCommand->m_pCapabilities->m_MipMapping = true;
427 // check for context native 2D array texture size
428 pCommand->m_pCapabilities->m_3DTextures = false;
429 pCommand->m_pCapabilities->m_2DArrayTextures = false;
430 pCommand->m_pCapabilities->m_ShaderSupport = true;
431
432 int TextureLayers = 0;
433 glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, params: &TextureLayers);
434 if(TextureLayers >= 256)
435 {
436 pCommand->m_pCapabilities->m_2DArrayTextures = true;
437 }
438
439 int Texture3DSize = 0;
440 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, params: &Texture3DSize);
441 if(Texture3DSize >= 256)
442 {
443 pCommand->m_pCapabilities->m_3DTextures = true;
444 }
445
446 if(!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures)
447 {
448 *pCommand->m_pInitError = -2;
449 pCommand->m_pCapabilities->m_ContextMajor = 1;
450 pCommand->m_pCapabilities->m_ContextMinor = 5;
451 pCommand->m_pCapabilities->m_ContextPatch = 0;
452 }
453
454 pCommand->m_pCapabilities->m_TileBuffering = pCommand->m_pCapabilities->m_2DArrayTextures;
455 pCommand->m_pCapabilities->m_QuadBuffering = false;
456 pCommand->m_pCapabilities->m_TextBuffering = false;
457 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
458 }
459 else if(MajorV == 2)
460 {
461 pCommand->m_pCapabilities->m_MipMapping = true;
462 // check for context extension: 2D array texture and its max size
463 pCommand->m_pCapabilities->m_3DTextures = false;
464 pCommand->m_pCapabilities->m_2DArrayTextures = false;
465
466 pCommand->m_pCapabilities->m_ShaderSupport = false;
467
468 int Texture3DSize = 0;
469 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, params: &Texture3DSize);
470 if(Texture3DSize >= 256)
471 {
472 pCommand->m_pCapabilities->m_3DTextures = true;
473 }
474
475 pCommand->m_pCapabilities->m_TileBuffering = false;
476 pCommand->m_pCapabilities->m_QuadBuffering = false;
477 pCommand->m_pCapabilities->m_TextBuffering = false;
478 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
479
480 pCommand->m_pCapabilities->m_NPOTTextures = GLEW_ARB_texture_non_power_of_two || pCommand->m_GlewMajor > 2;
481
482 if(!pCommand->m_pCapabilities->m_NPOTTextures || (!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures))
483 {
484 *pCommand->m_pInitError = -2;
485 pCommand->m_pCapabilities->m_ContextMajor = 1;
486 pCommand->m_pCapabilities->m_ContextMinor = 5;
487 pCommand->m_pCapabilities->m_ContextPatch = 0;
488 }
489 }
490 else if(MajorV < 2)
491 {
492 pCommand->m_pCapabilities->m_TileBuffering = false;
493 pCommand->m_pCapabilities->m_QuadBuffering = false;
494 pCommand->m_pCapabilities->m_TextBuffering = false;
495 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
496 pCommand->m_pCapabilities->m_ShaderSupport = false;
497
498 pCommand->m_pCapabilities->m_MipMapping = false;
499 pCommand->m_pCapabilities->m_3DTextures = false;
500 pCommand->m_pCapabilities->m_2DArrayTextures = false;
501 pCommand->m_pCapabilities->m_NPOTTextures = false;
502 }
503 }
504#endif
505 }
506 else if(pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL_ES)
507 {
508 if(MajorV < 3)
509 {
510 pCommand->m_pCapabilities->m_TileBuffering = false;
511 pCommand->m_pCapabilities->m_QuadBuffering = false;
512 pCommand->m_pCapabilities->m_TextBuffering = false;
513 pCommand->m_pCapabilities->m_QuadContainerBuffering = false;
514 pCommand->m_pCapabilities->m_ShaderSupport = false;
515
516 pCommand->m_pCapabilities->m_MipMapping = false;
517 pCommand->m_pCapabilities->m_3DTextures = false;
518 pCommand->m_pCapabilities->m_2DArrayTextures = false;
519 pCommand->m_pCapabilities->m_NPOTTextures = false;
520
521 pCommand->m_pCapabilities->m_TrianglesAsQuads = false;
522 }
523 else
524 {
525 pCommand->m_pCapabilities->m_TileBuffering = true;
526 pCommand->m_pCapabilities->m_QuadBuffering = true;
527 pCommand->m_pCapabilities->m_TextBuffering = true;
528 pCommand->m_pCapabilities->m_QuadContainerBuffering = true;
529 pCommand->m_pCapabilities->m_ShaderSupport = true;
530
531 pCommand->m_pCapabilities->m_MipMapping = true;
532 pCommand->m_pCapabilities->m_3DTextures = true;
533 pCommand->m_pCapabilities->m_2DArrayTextures = true;
534 pCommand->m_pCapabilities->m_NPOTTextures = true;
535
536 pCommand->m_pCapabilities->m_TrianglesAsQuads = true;
537 }
538 }
539
540 if(*pCommand->m_pInitError != -2)
541 {
542 // set some default settings
543 glEnable(GL_BLEND);
544 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
545 glDisable(GL_CULL_FACE);
546 glDisable(GL_DEPTH_TEST);
547
548#ifndef BACKEND_GL_MODERN_API
549 if(!IsNewApi())
550 {
551 glAlphaFunc(GL_GREATER, ref: 0);
552 glEnable(GL_ALPHA_TEST);
553 }
554#endif
555
556 glDepthMask(flag: 0);
557
558#ifndef BACKEND_AS_OPENGL_ES
559 if(g_Config.m_DbgGfx != DEBUG_GFX_MODE_NONE)
560 {
561 if(GLEW_KHR_debug || GLEW_ARB_debug_output)
562 {
563 // During init, enable debug output
564 if(GLEW_KHR_debug)
565 {
566 glEnable(GL_DEBUG_OUTPUT);
567 glDebugMessageCallback((GLDEBUGPROC)GfxOpenGLMessageCallback, 0);
568 }
569 else if(GLEW_ARB_debug_output)
570 {
571 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
572 glDebugMessageCallbackARB((GLDEBUGPROC)GfxOpenGLMessageCallback, 0);
573 }
574 log_info("gfx/opengl", "Enabled OpenGL debug mode");
575 }
576 else
577 {
578 log_warn("gfx/opengl", "Requested OpenGL debug mode, but the driver does not support the required extension");
579 }
580 }
581#endif
582
583 return true;
584 }
585 else
586 return false;
587}
588
589bool CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand)
590{
591 if(!InitOpenGL(pCommand))
592 return false;
593
594 m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
595 m_pTextureMemoryUsage->store(i: 0, m: std::memory_order_relaxed);
596 m_MaxTexSize = -1;
597
598 m_OpenGLTextureLodBIAS = 0;
599
600 m_Has2DArrayTextures = pCommand->m_pCapabilities->m_2DArrayTextures;
601 if(pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension)
602 {
603 m_Has2DArrayTexturesAsExtension = true;
604 m_2DArrayTarget = GL_TEXTURE_2D_ARRAY_EXT;
605 }
606 else
607 {
608 m_Has2DArrayTexturesAsExtension = false;
609 m_2DArrayTarget = GL_TEXTURE_2D_ARRAY;
610 }
611
612 m_Has3DTextures = pCommand->m_pCapabilities->m_3DTextures;
613 m_HasMipMaps = pCommand->m_pCapabilities->m_MipMapping;
614 m_HasNPOTTextures = pCommand->m_pCapabilities->m_NPOTTextures;
615
616 m_LastBlendMode = EBlendMode::ALPHA;
617 m_LastClipEnable = false;
618
619 return true;
620}
621
622void CCommandProcessorFragment_OpenGL::TextureUpdate(int Slot, int X, int Y, int Width, int Height, int GLFormat, uint8_t *pTexData)
623{
624 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[Slot].m_Tex);
625
626 if(!m_HasNPOTTextures)
627 {
628 float ResizeW = m_vTextures[Slot].m_ResizeWidth;
629 float ResizeH = m_vTextures[Slot].m_ResizeHeight;
630 if(ResizeW > 0 && ResizeH > 0)
631 {
632 int ResizedW = (int)(Width * ResizeW);
633 int ResizedH = (int)(Height * ResizeH);
634
635 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width, Height, NewWidth: ResizedW, NewHeight: ResizedH, BPP: GLFormatToPixelSize(GLFormat));
636 free(ptr: pTexData);
637 pTexData = pTmpData;
638
639 Width = ResizedW;
640 Height = ResizedH;
641 }
642 }
643
644 if(m_vTextures[Slot].m_RescaleCount > 0)
645 {
646 int OldWidth = Width;
647 int OldHeight = Height;
648 for(int i = 0; i < m_vTextures[Slot].m_RescaleCount; ++i)
649 {
650 Width >>= 1;
651 Height >>= 1;
652
653 X /= 2;
654 Y /= 2;
655 }
656
657 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width: OldWidth, Height: OldHeight, NewWidth: Width, NewHeight: Height, BPP: GLFormatToPixelSize(GLFormat));
658 free(ptr: pTexData);
659 pTexData = pTmpData;
660 }
661
662 glTexSubImage2D(GL_TEXTURE_2D, level: 0, xoffset: X, yoffset: Y, width: Width, height: Height, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
663 free(ptr: pTexData);
664}
665
666void CCommandProcessorFragment_OpenGL::DestroyTexture(int Slot)
667{
668 m_pTextureMemoryUsage->store(i: m_pTextureMemoryUsage->load(m: std::memory_order_relaxed) - m_vTextures[Slot].m_MemSize, m: std::memory_order_relaxed);
669
670 if(m_vTextures[Slot].m_Tex != 0)
671 {
672 glDeleteTextures(n: 1, textures: &m_vTextures[Slot].m_Tex);
673 }
674
675 if(m_vTextures[Slot].m_Tex2DArray != 0)
676 {
677 glDeleteTextures(n: 1, textures: &m_vTextures[Slot].m_Tex2DArray);
678 }
679
680 if(IsNewApi())
681 {
682 if(m_vTextures[Slot].m_Sampler != 0)
683 {
684 glDeleteSamplers(1, &m_vTextures[Slot].m_Sampler);
685 }
686 if(m_vTextures[Slot].m_Sampler2DArray != 0)
687 {
688 glDeleteSamplers(1, &m_vTextures[Slot].m_Sampler2DArray);
689 }
690 }
691
692 m_vTextures[Slot].m_Tex = 0;
693 m_vTextures[Slot].m_Sampler = 0;
694 m_vTextures[Slot].m_Tex2DArray = 0;
695 m_vTextures[Slot].m_Sampler2DArray = 0;
696 m_vTextures[Slot].m_LastWrapMode = EWrapMode::REPEAT;
697}
698
699void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand)
700{
701 DestroyTexture(Slot: pCommand->m_Slot);
702}
703
704void CCommandProcessorFragment_OpenGL::TextureCreate(int Slot, int Width, int Height, int GLFormat, int GLStoreFormat, int Flags, uint8_t *pTexData)
705{
706#ifndef BACKEND_GL_MODERN_API
707
708 if(m_MaxTexSize == -1)
709 {
710 // fix the alignment to allow even 1byte changes, e.g. for alpha components
711 glPixelStorei(GL_UNPACK_ALIGNMENT, param: 1);
712 glGetIntegerv(GL_MAX_TEXTURE_SIZE, params: &m_MaxTexSize);
713 }
714
715 while(Slot >= (int)m_vTextures.size())
716 m_vTextures.resize(new_size: m_vTextures.size() * 2);
717
718 m_vTextures[Slot].m_ResizeWidth = -1.f;
719 m_vTextures[Slot].m_ResizeHeight = -1.f;
720
721 if(!m_HasNPOTTextures)
722 {
723 int PowerOfTwoWidth = HighestBit(OfVar: Width);
724 int PowerOfTwoHeight = HighestBit(OfVar: Height);
725 if(Width != PowerOfTwoWidth || Height != PowerOfTwoHeight)
726 {
727 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width, Height, NewWidth: PowerOfTwoWidth, NewHeight: PowerOfTwoHeight, BPP: GLFormatToPixelSize(GLFormat));
728 free(ptr: pTexData);
729 pTexData = pTmpData;
730
731 m_vTextures[Slot].m_ResizeWidth = (float)PowerOfTwoWidth / (float)Width;
732 m_vTextures[Slot].m_ResizeHeight = (float)PowerOfTwoHeight / (float)Height;
733
734 Width = PowerOfTwoWidth;
735 Height = PowerOfTwoHeight;
736 }
737 }
738
739 int RescaleCount = 0;
740 if(GLFormat == GL_RGBA)
741 {
742 int OldWidth = Width;
743 int OldHeight = Height;
744 bool NeedsResize = false;
745
746 if(Width > m_MaxTexSize || Height > m_MaxTexSize)
747 {
748 do
749 {
750 Width >>= 1;
751 Height >>= 1;
752 ++RescaleCount;
753 } while(Width > m_MaxTexSize || Height > m_MaxTexSize);
754 NeedsResize = true;
755 }
756
757 if(NeedsResize)
758 {
759 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width: OldWidth, Height: OldHeight, NewWidth: Width, NewHeight: Height, BPP: GLFormatToPixelSize(GLFormat));
760 free(ptr: pTexData);
761 pTexData = pTmpData;
762 }
763 }
764 m_vTextures[Slot].m_Width = Width;
765 m_vTextures[Slot].m_Height = Height;
766 m_vTextures[Slot].m_RescaleCount = RescaleCount;
767
768 const size_t PixelSize = GLFormatToPixelSize(GLFormat);
769
770 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
771 {
772 glGenTextures(n: 1, textures: &m_vTextures[Slot].m_Tex);
773 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[Slot].m_Tex);
774 }
775
776 if(Flags & TextureFlag::NO_MIPMAPS || !m_HasMipMaps)
777 {
778 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
779 {
780 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
781 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
782 glTexImage2D(GL_TEXTURE_2D, level: 0, internalformat: GLStoreFormat, width: Width, height: Height, border: 0, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
783 }
784 }
785 else
786 {
787 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
788 {
789 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
790 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
791 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
792
793#ifndef BACKEND_AS_OPENGL_ES
794 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
795 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, param: ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
796#endif
797
798 glTexImage2D(GL_TEXTURE_2D, level: 0, internalformat: GLStoreFormat, width: Width, height: Height, border: 0, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
799 }
800
801 int Flag2DArrayTexture = TextureFlag::TO_2D_ARRAY_TEXTURE;
802 int Flag3DTexture = TextureFlag::TO_3D_TEXTURE;
803 if((Flags & (Flag2DArrayTexture | Flag3DTexture)) != 0)
804 {
805 bool Is3DTexture = (Flags & Flag3DTexture) != 0;
806
807 glGenTextures(n: 1, textures: &m_vTextures[Slot].m_Tex2DArray);
808
809 GLenum Target = GL_TEXTURE_3D;
810
811 if(Is3DTexture)
812 {
813 Target = GL_TEXTURE_3D;
814 }
815 else
816 {
817 Target = m_2DArrayTarget;
818 }
819
820 glBindTexture(target: Target, texture: m_vTextures[Slot].m_Tex2DArray);
821
822 if(IsNewApi())
823 {
824 glGenSamplers(1, &m_vTextures[Slot].m_Sampler2DArray);
825 glBindSampler(0, m_vTextures[Slot].m_Sampler2DArray);
826 }
827
828 glTexParameteri(target: Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
829 if(Is3DTexture)
830 {
831 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
832 if(IsNewApi())
833 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
834 }
835 else
836 {
837 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
838 glTexParameteri(target: Target, GL_GENERATE_MIPMAP, GL_TRUE);
839 if(IsNewApi())
840 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
841 }
842
843 glTexParameteri(target: Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
844 glTexParameteri(target: Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
845 glTexParameteri(target: Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
846
847#ifndef BACKEND_AS_OPENGL_ES
848 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
849 glTexParameterf(target: Target, GL_TEXTURE_LOD_BIAS, param: ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
850#endif
851
852 if(IsNewApi())
853 {
854 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
855 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
856 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
857
858#ifndef BACKEND_AS_OPENGL_ES
859 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
860 glSamplerParameterf(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
861#endif
862
863 glBindSampler(0, 0);
864 }
865
866 uint8_t *pImageData3D = static_cast<uint8_t *>(malloc(size: (size_t)Width * Height * PixelSize));
867 int Image3DWidth, Image3DHeight;
868
869 int ConvertWidth = Width;
870 int ConvertHeight = Height;
871
872 if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0)
873 {
874 int NewWidth = maximum<int>(a: HighestBit(OfVar: ConvertWidth), b: 16);
875 int NewHeight = maximum<int>(a: HighestBit(OfVar: ConvertHeight), b: 16);
876 uint8_t *pNewTexData = ResizeImage(pImageData: pTexData, Width: ConvertWidth, Height: ConvertHeight, NewWidth, NewHeight, BPP: GLFormatToPixelSize(GLFormat));
877 log_debug("gfx/opengl", "3D/2D array texture was resized");
878
879 ConvertWidth = NewWidth;
880 ConvertHeight = NewHeight;
881
882 free(ptr: pTexData);
883 pTexData = pNewTexData;
884 }
885
886 if(Texture2DTo3D(pImageBuffer: pTexData, ImageWidth: ConvertWidth, ImageHeight: ConvertHeight, PixelSize, SplitCountWidth: 16, SplitCountHeight: 16, pTarget3DImageData: pImageData3D, Target3DImageWidth&: Image3DWidth, Target3DImageHeight&: Image3DHeight))
887 {
888 glTexImage3D(Target, 0, GLStoreFormat, Image3DWidth, Image3DHeight, 256, 0, GLFormat, GL_UNSIGNED_BYTE, pImageData3D);
889 }
890
891 free(ptr: pImageData3D);
892 }
893 }
894
895 // This is the initial value for the wrap modes
896 m_vTextures[Slot].m_LastWrapMode = EWrapMode::REPEAT;
897
898 // calculate memory usage
899 m_vTextures[Slot].m_MemSize = (size_t)Width * Height * PixelSize;
900 while(Width > 2 && Height > 2)
901 {
902 Width >>= 1;
903 Height >>= 1;
904 m_vTextures[Slot].m_MemSize += (size_t)Width * Height * PixelSize;
905 }
906 m_pTextureMemoryUsage->store(i: m_pTextureMemoryUsage->load(m: std::memory_order_relaxed) + m_vTextures[Slot].m_MemSize, m: std::memory_order_relaxed);
907
908 free(ptr: pTexData);
909#endif
910}
911
912void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
913{
914 TextureCreate(Slot: pCommand->m_Slot, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_RGBA, GL_RGBA, Flags: pCommand->m_Flags, pTexData: pCommand->m_pData);
915}
916
917void CCommandProcessorFragment_OpenGL::Cmd_TextTexture_Update(const CCommandBuffer::SCommand_TextTexture_Update *pCommand)
918{
919 TextureUpdate(Slot: pCommand->m_Slot, X: pCommand->m_X, Y: pCommand->m_Y, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_ALPHA, pTexData: pCommand->m_pData);
920}
921
922void CCommandProcessorFragment_OpenGL::Cmd_TextTextures_Destroy(const CCommandBuffer::SCommand_TextTextures_Destroy *pCommand)
923{
924 DestroyTexture(Slot: pCommand->m_Slot);
925 DestroyTexture(Slot: pCommand->m_SlotOutline);
926}
927
928void CCommandProcessorFragment_OpenGL::Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand)
929{
930 TextureCreate(Slot: pCommand->m_Slot, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_ALPHA, GL_ALPHA, Flags: TextureFlag::NO_MIPMAPS, pTexData: pCommand->m_pTextData);
931 TextureCreate(Slot: pCommand->m_SlotOutline, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_ALPHA, GL_ALPHA, Flags: TextureFlag::NO_MIPMAPS, pTexData: pCommand->m_pTextOutlineData);
932}
933
934void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand)
935{
936 // if clip is still active, force disable it for clearing, enable it again afterwards
937 bool ClipWasEnabled = m_LastClipEnable;
938 if(ClipWasEnabled)
939 {
940 glDisable(GL_SCISSOR_TEST);
941 }
942 glClearColor(red: pCommand->m_Color.r, green: pCommand->m_Color.g, blue: pCommand->m_Color.b, alpha: 0.0f);
943 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
944 if(ClipWasEnabled)
945 {
946 glEnable(GL_SCISSOR_TEST);
947 }
948}
949
950void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand)
951{
952#ifndef BACKEND_GL_MODERN_API
953 SetState(State: pCommand->m_State);
954
955 glVertexPointer(size: 2, GL_FLOAT, stride: sizeof(CCommandBuffer::SVertex), pointer: (char *)pCommand->m_pVertices);
956 glTexCoordPointer(size: 2, GL_FLOAT, stride: sizeof(CCommandBuffer::SVertex), pointer: (char *)pCommand->m_pVertices + sizeof(float) * 2);
957 glColorPointer(size: 4, GL_UNSIGNED_BYTE, stride: sizeof(CCommandBuffer::SVertex), pointer: (char *)pCommand->m_pVertices + sizeof(float) * 4);
958 glEnableClientState(GL_VERTEX_ARRAY);
959 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
960 glEnableClientState(GL_COLOR_ARRAY);
961
962 switch(pCommand->m_PrimType)
963 {
964 case EPrimitiveType::QUADS:
965#ifndef BACKEND_AS_OPENGL_ES
966 glDrawArrays(GL_QUADS, first: 0, count: pCommand->m_PrimCount * 4);
967#endif
968 break;
969 case EPrimitiveType::LINES:
970 glDrawArrays(GL_LINES, first: 0, count: pCommand->m_PrimCount * 2);
971 break;
972 case EPrimitiveType::TRIANGLES:
973 glDrawArrays(GL_TRIANGLES, first: 0, count: pCommand->m_PrimCount * 3);
974 break;
975 default:
976 dbg_assert_failed("Invalid primitive type: %d", (int)pCommand->m_PrimType);
977 };
978#endif
979}
980
981void CCommandProcessorFragment_OpenGL::Cmd_ReadPixel(const CCommandBuffer::SCommand_TrySwapAndReadPixel *pCommand)
982{
983 // get size of viewport
984 GLint aViewport[4] = {0, 0, 0, 0};
985 glGetIntegerv(GL_VIEWPORT, params: aViewport);
986 const int h = aViewport[3];
987
988 // fetch the pixel
989 uint8_t aPixelData[3];
990 GLint Alignment;
991 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
992 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
993 glReadPixels(x: pCommand->m_Position.x, y: h - 1 - pCommand->m_Position.y, width: 1, height: 1, GL_RGB, GL_UNSIGNED_BYTE, pixels: aPixelData);
994 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
995
996 // fill in the information
997 *pCommand->m_pColor = ColorRGBA(aPixelData[0] / 255.0f, aPixelData[1] / 255.0f, aPixelData[2] / 255.0f, 1.0f);
998}
999
1000void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCommand_TrySwapAndScreenshot *pCommand)
1001{
1002 // fetch image data
1003 GLint aViewport[4] = {0, 0, 0, 0};
1004 glGetIntegerv(GL_VIEWPORT, params: aViewport);
1005
1006 int w = aViewport[2];
1007 int h = aViewport[3];
1008
1009 // we allocate one more row to use when we are flipping the texture
1010 unsigned char *pPixelData = (unsigned char *)malloc(size: (size_t)w * (h + 1) * 4);
1011 unsigned char *pTempRow = pPixelData + w * h * 4;
1012
1013 // fetch the pixels
1014 GLint Alignment;
1015 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
1016 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
1017 glReadPixels(x: 0, y: 0, width: w, height: h, GL_RGBA, GL_UNSIGNED_BYTE, pixels: pPixelData);
1018 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
1019
1020 // flip the pixel because opengl works from bottom left corner
1021 for(int y = 0; y < h / 2; y++)
1022 {
1023 mem_copy(dest: pTempRow, source: pPixelData + y * w * 4, size: w * 4);
1024 mem_copy(dest: pPixelData + y * w * 4, source: pPixelData + (h - y - 1) * w * 4, size: w * 4);
1025 mem_copy(dest: pPixelData + (h - y - 1) * w * 4, source: pTempRow, size: w * 4);
1026 for(int x = 0; x < w; x++)
1027 {
1028 pPixelData[y * w * 4 + x * 4 + 3] = 255;
1029 pPixelData[(h - y - 1) * w * 4 + x * 4 + 3] = 255;
1030 }
1031 }
1032
1033 // fill in the information
1034 pCommand->m_pImage->m_Width = w;
1035 pCommand->m_pImage->m_Height = h;
1036 pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGBA;
1037 pCommand->m_pImage->m_pData = pPixelData;
1038}
1039
1040CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL()
1041{
1042 m_vTextures.resize(new_size: CCommandBuffer::MAX_TEXTURES);
1043 m_HasShaders = false;
1044}
1045
1046ERunCommandReturnTypes CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand)
1047{
1048 switch(pBaseCommand->m_Cmd)
1049 {
1050 case CCommandProcessorFragment_OpenGL::CMD_INIT:
1051 Cmd_Init(pCommand: static_cast<const SCommand_Init *>(pBaseCommand));
1052 break;
1053 case CCommandProcessorFragment_OpenGL::CMD_SHUTDOWN:
1054 Cmd_Shutdown(pCommand: static_cast<const SCommand_Shutdown *>(pBaseCommand));
1055 break;
1056 case CCommandBuffer::CMD_TEXTURE_CREATE:
1057 Cmd_Texture_Create(pCommand: static_cast<const CCommandBuffer::SCommand_Texture_Create *>(pBaseCommand));
1058 break;
1059 case CCommandBuffer::CMD_TEXTURE_DESTROY:
1060 Cmd_Texture_Destroy(pCommand: static_cast<const CCommandBuffer::SCommand_Texture_Destroy *>(pBaseCommand));
1061 break;
1062 case CCommandBuffer::CMD_TEXT_TEXTURES_CREATE:
1063 Cmd_TextTextures_Create(pCommand: static_cast<const CCommandBuffer::SCommand_TextTextures_Create *>(pBaseCommand));
1064 break;
1065 case CCommandBuffer::CMD_TEXT_TEXTURES_DESTROY:
1066 Cmd_TextTextures_Destroy(pCommand: static_cast<const CCommandBuffer::SCommand_TextTextures_Destroy *>(pBaseCommand));
1067 break;
1068 case CCommandBuffer::CMD_TEXT_TEXTURE_UPDATE:
1069 Cmd_TextTexture_Update(pCommand: static_cast<const CCommandBuffer::SCommand_TextTexture_Update *>(pBaseCommand));
1070 break;
1071 case CCommandBuffer::CMD_CLEAR:
1072 Cmd_Clear(pCommand: static_cast<const CCommandBuffer::SCommand_Clear *>(pBaseCommand));
1073 break;
1074 case CCommandBuffer::CMD_RENDER:
1075 Cmd_Render(pCommand: static_cast<const CCommandBuffer::SCommand_Render *>(pBaseCommand));
1076 break;
1077 case CCommandBuffer::CMD_RENDER_TEX3D:
1078 Cmd_RenderTex3D(pCommand: static_cast<const CCommandBuffer::SCommand_RenderTex3D *>(pBaseCommand));
1079 break;
1080 case CCommandBuffer::CMD_TRY_SWAP_AND_READ_PIXEL:
1081 Cmd_ReadPixel(pCommand: static_cast<const CCommandBuffer::SCommand_TrySwapAndReadPixel *>(pBaseCommand));
1082 break;
1083 case CCommandBuffer::CMD_TRY_SWAP_AND_SCREENSHOT:
1084 Cmd_Screenshot(pCommand: static_cast<const CCommandBuffer::SCommand_TrySwapAndScreenshot *>(pBaseCommand));
1085 break;
1086 case CCommandBuffer::CMD_UPDATE_VIEWPORT:
1087 Cmd_Update_Viewport(pCommand: static_cast<const CCommandBuffer::SCommand_Update_Viewport *>(pBaseCommand));
1088 break;
1089
1090 case CCommandBuffer::CMD_CREATE_BUFFER_OBJECT: Cmd_CreateBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_CreateBufferObject *>(pBaseCommand)); break;
1091 case CCommandBuffer::CMD_UPDATE_BUFFER_OBJECT: Cmd_UpdateBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_UpdateBufferObject *>(pBaseCommand)); break;
1092 case CCommandBuffer::CMD_RECREATE_BUFFER_OBJECT: Cmd_RecreateBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_RecreateBufferObject *>(pBaseCommand)); break;
1093 case CCommandBuffer::CMD_COPY_BUFFER_OBJECT: Cmd_CopyBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_CopyBufferObject *>(pBaseCommand)); break;
1094 case CCommandBuffer::CMD_DELETE_BUFFER_OBJECT: Cmd_DeleteBufferObject(pCommand: static_cast<const CCommandBuffer::SCommand_DeleteBufferObject *>(pBaseCommand)); break;
1095
1096 case CCommandBuffer::CMD_CREATE_BUFFER_CONTAINER: Cmd_CreateBufferContainer(pCommand: static_cast<const CCommandBuffer::SCommand_CreateBufferContainer *>(pBaseCommand)); break;
1097 case CCommandBuffer::CMD_UPDATE_BUFFER_CONTAINER: Cmd_UpdateBufferContainer(pCommand: static_cast<const CCommandBuffer::SCommand_UpdateBufferContainer *>(pBaseCommand)); break;
1098 case CCommandBuffer::CMD_DELETE_BUFFER_CONTAINER: Cmd_DeleteBufferContainer(pCommand: static_cast<const CCommandBuffer::SCommand_DeleteBufferContainer *>(pBaseCommand)); break;
1099 case CCommandBuffer::CMD_INDICES_REQUIRED_NUM_NOTIFY: Cmd_IndicesRequiredNumNotify(pCommand: static_cast<const CCommandBuffer::SCommand_IndicesRequiredNumNotify *>(pBaseCommand)); break;
1100
1101 case CCommandBuffer::CMD_RENDER_TILE_LAYER: Cmd_RenderTileLayer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderTileLayer *>(pBaseCommand)); break;
1102 case CCommandBuffer::CMD_RENDER_BORDER_TILE: Cmd_RenderBorderTile(pCommand: static_cast<const CCommandBuffer::SCommand_RenderBorderTile *>(pBaseCommand)); break;
1103 case CCommandBuffer::CMD_RENDER_QUAD_LAYER: Cmd_RenderQuadLayer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadLayer *>(pBaseCommand), Grouped: false); break;
1104 case CCommandBuffer::CMD_RENDER_QUAD_LAYER_GROUPED: Cmd_RenderQuadLayer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadLayer *>(pBaseCommand), Grouped: true); break;
1105 case CCommandBuffer::CMD_RENDER_TEXT: Cmd_RenderText(pCommand: static_cast<const CCommandBuffer::SCommand_RenderText *>(pBaseCommand)); break;
1106 case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER: Cmd_RenderQuadContainer(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadContainer *>(pBaseCommand)); break;
1107 case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_EX: Cmd_RenderQuadContainerEx(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadContainerEx *>(pBaseCommand)); break;
1108 case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(pCommand: static_cast<const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *>(pBaseCommand)); break;
1109 default: return ERunCommandReturnTypes::RUN_COMMAND_COMMAND_UNHANDLED;
1110 }
1111
1112 return ERunCommandReturnTypes::RUN_COMMAND_COMMAND_HANDLED;
1113}
1114
1115// ------------ CCommandProcessorFragment_OpenGL2
1116
1117void CCommandProcessorFragment_OpenGL2::UseProgram(CGLSLTWProgram *pProgram)
1118{
1119 pProgram->UseProgram();
1120}
1121
1122void CCommandProcessorFragment_OpenGL2::SetState(const CCommandBuffer::SState &State, CGLSLTWProgram *pProgram, bool Use2DArrayTextures)
1123{
1124 if(m_LastBlendMode == EBlendMode::NONE)
1125 {
1126 m_LastBlendMode = EBlendMode::ALPHA;
1127 glEnable(GL_BLEND);
1128 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1129 }
1130 if(State.m_BlendMode != m_LastBlendMode && State.m_BlendMode != EBlendMode::NONE)
1131 {
1132 // blend
1133 switch(State.m_BlendMode)
1134 {
1135 case EBlendMode::NONE:
1136 // We don't really need this anymore
1137 // glDisable(GL_BLEND);
1138 break;
1139 case EBlendMode::ALPHA:
1140 // glEnable(GL_BLEND);
1141 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1142 break;
1143 case EBlendMode::ADDITIVE:
1144 // glEnable(GL_BLEND);
1145 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1146 break;
1147 default:
1148 dbg_assert_failed("Invalid blend mode: %d", (int)State.m_BlendMode);
1149 };
1150
1151 m_LastBlendMode = State.m_BlendMode;
1152 }
1153
1154 // clip
1155 if(State.m_ClipEnable)
1156 {
1157 glScissor(x: State.m_ClipX, y: State.m_ClipY, width: State.m_ClipW, height: State.m_ClipH);
1158 glEnable(GL_SCISSOR_TEST);
1159 m_LastClipEnable = true;
1160 }
1161 else if(m_LastClipEnable)
1162 {
1163 // Don't disable it always
1164 glDisable(GL_SCISSOR_TEST);
1165 m_LastClipEnable = false;
1166 }
1167
1168 if(!IsNewApi())
1169 {
1170 glDisable(GL_TEXTURE_2D);
1171 if(!m_HasShaders)
1172 {
1173 if(m_Has3DTextures)
1174 glDisable(GL_TEXTURE_3D);
1175 if(m_Has2DArrayTextures)
1176 {
1177 glDisable(cap: m_2DArrayTarget);
1178 }
1179 }
1180 }
1181
1182 // texture
1183 if(IsTexturedState(State))
1184 {
1185 int Slot = 0;
1186 if(!Use2DArrayTextures)
1187 {
1188 if(!IsNewApi() && !m_HasShaders)
1189 glEnable(GL_TEXTURE_2D);
1190 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[State.m_Texture].m_Tex);
1191 if(IsNewApi())
1192 glBindSampler(Slot, m_vTextures[State.m_Texture].m_Sampler);
1193 }
1194 else
1195 {
1196 if(!m_Has2DArrayTextures)
1197 {
1198 if(!IsNewApi() && !m_HasShaders)
1199 glEnable(GL_TEXTURE_3D);
1200 glBindTexture(GL_TEXTURE_3D, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
1201 if(IsNewApi())
1202 glBindSampler(Slot, m_vTextures[State.m_Texture].m_Sampler2DArray);
1203 }
1204 else
1205 {
1206 if(!IsNewApi() && !m_HasShaders)
1207 glEnable(cap: m_2DArrayTarget);
1208 glBindTexture(target: m_2DArrayTarget, texture: m_vTextures[State.m_Texture].m_Tex2DArray);
1209 if(IsNewApi())
1210 glBindSampler(Slot, m_vTextures[State.m_Texture].m_Sampler2DArray);
1211 }
1212 }
1213
1214 if(pProgram->m_LastTextureSampler != Slot)
1215 {
1216 pProgram->SetUniform(Loc: pProgram->m_LocTextureSampler, Value: Slot);
1217 pProgram->m_LastTextureSampler = Slot;
1218 }
1219
1220 if(m_vTextures[State.m_Texture].m_LastWrapMode != State.m_WrapMode && !Use2DArrayTextures)
1221 {
1222 switch(State.m_WrapMode)
1223 {
1224 case EWrapMode::REPEAT:
1225 if(IsNewApi())
1226 {
1227 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_REPEAT);
1228 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_REPEAT);
1229 }
1230 break;
1231 case EWrapMode::CLAMP:
1232 if(IsNewApi())
1233 {
1234 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1235 glSamplerParameteri(m_vTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1236 }
1237 break;
1238 default:
1239 dbg_assert_failed("Invalid wrap mode: %d", (int)State.m_WrapMode);
1240 };
1241 m_vTextures[State.m_Texture].m_LastWrapMode = State.m_WrapMode;
1242 }
1243 }
1244
1245 if(pProgram->m_LastScreenTL != State.m_ScreenTL || pProgram->m_LastScreenBR != State.m_ScreenBR)
1246 {
1247 pProgram->m_LastScreenTL = State.m_ScreenTL;
1248 pProgram->m_LastScreenBR = State.m_ScreenBR;
1249
1250 // screen mapping
1251 // orthographic projection matrix
1252 // the z coordinate is the same for every vertex, so just ignore the z coordinate and set it in the shaders
1253 float m[2 * 4] = {
1254 2.f / (State.m_ScreenBR.x - State.m_ScreenTL.x),
1255 0,
1256 0,
1257 -((State.m_ScreenBR.x + State.m_ScreenTL.x) / (State.m_ScreenBR.x - State.m_ScreenTL.x)),
1258 0,
1259 (2.f / (State.m_ScreenTL.y - State.m_ScreenBR.y)),
1260 0,
1261 -((State.m_ScreenTL.y + State.m_ScreenBR.y) / (State.m_ScreenTL.y - State.m_ScreenBR.y)),
1262 };
1263
1264 // transpose bcs of column-major order of opengl
1265 glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m);
1266 }
1267}
1268
1269#ifndef BACKEND_GL_MODERN_API
1270bool CCommandProcessorFragment_OpenGL2::DoAnalyzeStep(size_t CheckCount, size_t VerticesCount, uint8_t aFakeTexture[], size_t SingleImageSize)
1271{
1272 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1273
1274 int Slot = 0;
1275 if(m_HasShaders)
1276 {
1277 CGLSLTWProgram *pProgram = m_pPrimitive3DProgramTextured;
1278 UseProgram(pProgram);
1279
1280 pProgram->SetUniform(Loc: pProgram->m_LocTextureSampler, Value: Slot);
1281
1282 float m[2 * 4] = {
1283 1, 0, 0, 0,
1284 0, 1, 0, 0};
1285
1286 // transpose bcs of column-major order of opengl
1287 glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m);
1288 }
1289 else
1290 {
1291 glMatrixMode(GL_PROJECTION);
1292 glLoadIdentity();
1293 glOrtho(left: -1, right: 1, bottom: -1, top: 1, zNear: -10.0f, zFar: 10.f);
1294 }
1295
1296 glEnableClientState(GL_VERTEX_ARRAY);
1297 glEnableClientState(GL_COLOR_ARRAY);
1298 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1299
1300 glVertexPointer(size: 2, GL_FLOAT, stride: sizeof(m_aStreamVertices[0]), pointer: m_aStreamVertices);
1301 glColorPointer(size: 4, GL_FLOAT, stride: sizeof(m_aStreamVertices[0]), pointer: (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2)));
1302 glTexCoordPointer(size: 3, GL_FLOAT, stride: sizeof(m_aStreamVertices[0]), pointer: (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4)));
1303
1304 glDrawArrays(GL_QUADS, first: 0, count: VerticesCount);
1305
1306 glDisableClientState(GL_VERTEX_ARRAY);
1307 glDisableClientState(GL_COLOR_ARRAY);
1308 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1309
1310 if(m_HasShaders)
1311 {
1312 glUseProgram(0);
1313 }
1314
1315 glFinish();
1316
1317 GLint aViewport[4] = {0, 0, 0, 0};
1318 glGetIntegerv(GL_VIEWPORT, params: aViewport);
1319
1320 int w = aViewport[2];
1321 int h = aViewport[3];
1322
1323 size_t PixelDataSize = (size_t)w * h * 3;
1324 if(PixelDataSize == 0)
1325 return false;
1326 uint8_t *pPixelData = (uint8_t *)malloc(size: PixelDataSize);
1327
1328 // fetch the pixels
1329 GLint Alignment;
1330 glGetIntegerv(GL_PACK_ALIGNMENT, params: &Alignment);
1331 glPixelStorei(GL_PACK_ALIGNMENT, param: 1);
1332 glReadPixels(x: 0, y: 0, width: w, height: h, GL_RGB, GL_UNSIGNED_BYTE, pixels: pPixelData);
1333 glPixelStorei(GL_PACK_ALIGNMENT, param: Alignment);
1334
1335 // now analyse the image data
1336 bool CheckFailed = false;
1337 int WidthTile = w / 16;
1338 int HeightTile = h / 16;
1339 int StartX = WidthTile / 2;
1340 int StartY = HeightTile / 2;
1341 for(size_t d = 0; d < CheckCount; ++d)
1342 {
1343 int CurX = (int)d % 16;
1344 int CurY = (int)d / 16;
1345
1346 int CheckX = StartX + CurX * WidthTile;
1347 int CheckY = StartY + CurY * HeightTile;
1348
1349 ptrdiff_t OffsetPixelData = (CheckY * (w * 3)) + (CheckX * 3);
1350 ptrdiff_t OffsetFakeTexture = SingleImageSize * d;
1351 OffsetPixelData = std::clamp<ptrdiff_t>(val: OffsetPixelData, lo: 0, hi: (ptrdiff_t)PixelDataSize);
1352 OffsetFakeTexture = std::clamp<ptrdiff_t>(val: OffsetFakeTexture, lo: 0, hi: (ptrdiff_t)(SingleImageSize * CheckCount));
1353 uint8_t *pPixel = pPixelData + OffsetPixelData;
1354 uint8_t *pPixelTex = aFakeTexture + OffsetFakeTexture;
1355 for(size_t i = 0; i < 3; ++i)
1356 {
1357 if((pPixel[i] < pPixelTex[i] - 25) || (pPixel[i] > pPixelTex[i] + 25))
1358 {
1359 CheckFailed = true;
1360 break;
1361 }
1362 }
1363 }
1364
1365 free(ptr: pPixelData);
1366 return !CheckFailed;
1367}
1368
1369bool CCommandProcessorFragment_OpenGL2::IsTileMapAnalysisSucceeded()
1370{
1371 glClearColor(red: 0, green: 0, blue: 0, alpha: 1);
1372
1373 // create fake texture 1024x1024
1374 const size_t ImageWidth = 1024;
1375 const size_t ImageHeight = 1024;
1376 uint8_t *pFakeTexture = (uint8_t *)malloc(size: sizeof(uint8_t) * ImageWidth * ImageHeight * 4);
1377 // fill by colors stepping by 50 => (255 / 50 ~ 5) => 5 times 3(color channels) = 5 ^ 3 = 125 possibilities to check
1378 size_t CheckCount = 5 * 5 * 5;
1379 // always fill 4 pixels of the texture, so the sampling is accurate
1380 int aCurColor[4] = {25, 25, 25, 255};
1381 const size_t SingleImageWidth = 64;
1382 const size_t SingleImageHeight = 64;
1383 size_t SingleImageSize = SingleImageWidth * SingleImageHeight * 4;
1384 for(size_t d = 0; d < CheckCount; ++d)
1385 {
1386 uint8_t *pCurFakeTexture = pFakeTexture + (ptrdiff_t)(SingleImageSize * d);
1387
1388 uint8_t aCurColorUint8[SingleImageWidth * SingleImageHeight * 4];
1389 for(size_t y = 0; y < SingleImageHeight; ++y)
1390 {
1391 for(size_t x = 0; x < SingleImageWidth; ++x)
1392 {
1393 for(size_t i = 0; i < 4; ++i)
1394 {
1395 aCurColorUint8[(y * SingleImageWidth * 4) + (x * 4) + i] = (uint8_t)aCurColor[i];
1396 }
1397 }
1398 }
1399 mem_copy(dest: pCurFakeTexture, source: aCurColorUint8, size: sizeof(aCurColorUint8));
1400
1401 aCurColor[2] += 50;
1402 if(aCurColor[2] > 225)
1403 {
1404 aCurColor[2] -= 250;
1405 aCurColor[1] += 50;
1406 }
1407 if(aCurColor[1] > 225)
1408 {
1409 aCurColor[1] -= 250;
1410 aCurColor[0] += 50;
1411 }
1412 if(aCurColor[0] > 225)
1413 {
1414 break;
1415 }
1416 }
1417
1418 // upload the texture
1419 GLuint FakeTexture;
1420 glGenTextures(n: 1, textures: &FakeTexture);
1421
1422 GLenum Target = GL_TEXTURE_3D;
1423 if(m_Has2DArrayTextures)
1424 {
1425 Target = m_2DArrayTarget;
1426 }
1427
1428 glBindTexture(target: Target, texture: FakeTexture);
1429 glTexParameteri(target: Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1430 if(!m_Has2DArrayTextures)
1431 {
1432 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1433 }
1434 else
1435 {
1436 glTexParameteri(target: Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1437 glTexParameteri(target: Target, GL_GENERATE_MIPMAP, GL_TRUE);
1438 }
1439
1440 glTexParameteri(target: Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1441 glTexParameteri(target: Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1442 glTexParameteri(target: Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
1443
1444 glTexImage3D(Target, 0, GL_RGBA, ImageWidth / 16, ImageHeight / 16, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pFakeTexture);
1445
1446 glEnable(GL_BLEND);
1447 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1448 glDisable(GL_SCISSOR_TEST);
1449
1450 if(!m_HasShaders)
1451 {
1452 glDisable(GL_TEXTURE_2D);
1453 if(m_Has3DTextures)
1454 glDisable(GL_TEXTURE_3D);
1455 if(m_Has2DArrayTextures)
1456 {
1457 glDisable(cap: m_2DArrayTarget);
1458 }
1459
1460 if(!m_Has2DArrayTextures)
1461 {
1462 glEnable(GL_TEXTURE_3D);
1463 glBindTexture(GL_TEXTURE_3D, texture: FakeTexture);
1464 }
1465 else
1466 {
1467 glEnable(cap: m_2DArrayTarget);
1468 glBindTexture(target: m_2DArrayTarget, texture: FakeTexture);
1469 }
1470 }
1471
1472 static_assert(sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0]) >= 256 * 4, "Keep the number of stream vertices >= 256 * 4.");
1473
1474 size_t VertexCount = 0;
1475 for(size_t i = 0; i < CheckCount; ++i)
1476 {
1477 float XPos = (float)(i % 16);
1478 float YPos = (float)(i / 16);
1479
1480 GL_SVertexTex3D *pVertex = &m_aStreamVertices[VertexCount++];
1481 GL_SVertexTex3D *pVertexBefore = pVertex;
1482 pVertex->m_Pos.x = XPos / 16.f;
1483 pVertex->m_Pos.y = YPos / 16.f;
1484 pVertex->m_Color.r = 1;
1485 pVertex->m_Color.g = 1;
1486 pVertex->m_Color.b = 1;
1487 pVertex->m_Color.a = 1;
1488 pVertex->m_Tex.u = 0;
1489 pVertex->m_Tex.v = 0;
1490
1491 pVertex = &m_aStreamVertices[VertexCount++];
1492 pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f;
1493 pVertex->m_Pos.y = YPos / 16.f;
1494 pVertex->m_Color.r = 1;
1495 pVertex->m_Color.g = 1;
1496 pVertex->m_Color.b = 1;
1497 pVertex->m_Color.a = 1;
1498 pVertex->m_Tex.u = 1;
1499 pVertex->m_Tex.v = 0;
1500
1501 pVertex = &m_aStreamVertices[VertexCount++];
1502 pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f;
1503 pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f;
1504 pVertex->m_Color.r = 1;
1505 pVertex->m_Color.g = 1;
1506 pVertex->m_Color.b = 1;
1507 pVertex->m_Color.a = 1;
1508 pVertex->m_Tex.u = 1;
1509 pVertex->m_Tex.v = 1;
1510
1511 pVertex = &m_aStreamVertices[VertexCount++];
1512 pVertex->m_Pos.x = XPos / 16.f;
1513 pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f;
1514 pVertex->m_Color.r = 1;
1515 pVertex->m_Color.g = 1;
1516 pVertex->m_Color.b = 1;
1517 pVertex->m_Color.a = 1;
1518 pVertex->m_Tex.u = 0;
1519 pVertex->m_Tex.v = 1;
1520
1521 for(size_t n = 0; n < 4; ++n)
1522 {
1523 pVertexBefore[n].m_Pos.x *= 2;
1524 pVertexBefore[n].m_Pos.x -= 1;
1525 pVertexBefore[n].m_Pos.y *= 2;
1526 pVertexBefore[n].m_Pos.y -= 1;
1527 if(m_Has2DArrayTextures)
1528 {
1529 pVertexBefore[n].m_Tex.w = i;
1530 }
1531 else
1532 {
1533 pVertexBefore[n].m_Tex.w = (i + 0.5f) / 256.f;
1534 }
1535 }
1536 }
1537
1538 // everything build up, now do the analyze steps
1539 bool NoError = DoAnalyzeStep(CheckCount, VerticesCount: VertexCount, aFakeTexture: pFakeTexture, SingleImageSize);
1540
1541 glDeleteTextures(n: 1, textures: &FakeTexture);
1542 free(ptr: pFakeTexture);
1543
1544 return NoError;
1545}
1546
1547bool CCommandProcessorFragment_OpenGL2::Cmd_Init(const SCommand_Init *pCommand)
1548{
1549 if(!CCommandProcessorFragment_OpenGL::Cmd_Init(pCommand))
1550 return false;
1551
1552 m_pTileProgram = nullptr;
1553 m_pTileProgramTextured = nullptr;
1554 m_pPrimitive3DProgram = nullptr;
1555 m_pPrimitive3DProgramTextured = nullptr;
1556
1557 m_OpenGLTextureLodBIAS = g_Config.m_GfxGLTextureLODBIAS;
1558
1559 m_HasShaders = pCommand->m_pCapabilities->m_ShaderSupport;
1560
1561 bool HasAllFunc = true;
1562#ifndef BACKEND_AS_OPENGL_ES
1563 if(m_HasShaders)
1564 {
1565 HasAllFunc &= (glUniformMatrix4x2fv != NULL) && (glGenBuffers != NULL);
1566 HasAllFunc &= (glBindBuffer != NULL) && (glBufferData != NULL);
1567 HasAllFunc &= (glEnableVertexAttribArray != NULL) && (glVertexAttribPointer != NULL) && (glVertexAttribIPointer != NULL);
1568 HasAllFunc &= (glDisableVertexAttribArray != NULL) && (glDeleteBuffers != NULL);
1569 HasAllFunc &= (glUseProgram != NULL) && (glTexImage3D != NULL);
1570 HasAllFunc &= (glBindAttribLocation != NULL) && (glTexImage3D != NULL);
1571 HasAllFunc &= (glBufferSubData != NULL) && (glGetUniformLocation != NULL);
1572 HasAllFunc &= (glUniform1i != NULL) && (glUniform1f != NULL);
1573 HasAllFunc &= (glUniform1ui != NULL) && (glUniform1i != NULL);
1574 HasAllFunc &= (glUniform1fv != NULL) && (glUniform2fv != NULL);
1575 HasAllFunc &= (glUniform4fv != NULL) && (glGetAttachedShaders != NULL);
1576 HasAllFunc &= (glGetProgramInfoLog != NULL) && (glGetProgramiv != NULL);
1577 HasAllFunc &= (glLinkProgram != NULL) && (glDetachShader != NULL);
1578 HasAllFunc &= (glAttachShader != NULL) && (glDeleteProgram != NULL);
1579 HasAllFunc &= (glCreateProgram != NULL) && (glShaderSource != NULL);
1580 HasAllFunc &= (glCompileShader != NULL) && (glGetShaderiv != NULL);
1581 HasAllFunc &= (glGetShaderInfoLog != NULL) && (glDeleteShader != NULL);
1582 HasAllFunc &= (glCreateShader != NULL);
1583 }
1584#endif
1585
1586 bool AnalysisCorrect = true;
1587 if(HasAllFunc)
1588 {
1589 if(m_HasShaders)
1590 {
1591 m_pTileProgram = new CGLSLTileProgram;
1592 m_pTileProgramTextured = new CGLSLTileProgram;
1593 m_pBorderTileProgram = new CGLSLTileProgram;
1594 m_pBorderTileProgramTextured = new CGLSLTileProgram;
1595 m_pPrimitive3DProgram = new CGLSLPrimitiveProgram;
1596 m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram;
1597
1598 CGLSLCompiler ShaderCompiler(g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f);
1599 ShaderCompiler.SetHasTextureArray(pCommand->m_pCapabilities->m_2DArrayTextures);
1600
1601 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1602 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1603 else
1604 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1605 {
1606 CGLSL PrimitiveVertexShader;
1607 CGLSL PrimitiveFragmentShader;
1608 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.vert", GL_VERTEX_SHADER);
1609 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.frag", GL_FRAGMENT_SHADER);
1610
1611 m_pPrimitive3DProgram->CreateProgram();
1612 m_pPrimitive3DProgram->AddShader(pShader: &PrimitiveVertexShader);
1613 m_pPrimitive3DProgram->AddShader(pShader: &PrimitiveFragmentShader);
1614 m_pPrimitive3DProgram->LinkProgram();
1615
1616 UseProgram(pProgram: m_pPrimitive3DProgram);
1617
1618 m_pPrimitive3DProgram->m_LocPos = m_pPrimitive3DProgram->GetUniformLoc(pName: "gPos");
1619 }
1620
1621 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1622 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1623 else
1624 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1625 {
1626 CGLSL PrimitiveVertexShader;
1627 CGLSL PrimitiveFragmentShader;
1628 ShaderCompiler.AddDefine(pDefineName: "TW_TEXTURED", pDefineValue: "");
1629 if(!pCommand->m_pCapabilities->m_2DArrayTextures)
1630 ShaderCompiler.AddDefine(pDefineName: "TW_3D_TEXTURED", pDefineValue: "");
1631 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.vert", GL_VERTEX_SHADER);
1632 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.frag", GL_FRAGMENT_SHADER);
1633 ShaderCompiler.ClearDefines();
1634
1635 m_pPrimitive3DProgramTextured->CreateProgram();
1636 m_pPrimitive3DProgramTextured->AddShader(pShader: &PrimitiveVertexShader);
1637 m_pPrimitive3DProgramTextured->AddShader(pShader: &PrimitiveFragmentShader);
1638 m_pPrimitive3DProgramTextured->LinkProgram();
1639
1640 UseProgram(pProgram: m_pPrimitive3DProgramTextured);
1641
1642 m_pPrimitive3DProgramTextured->m_LocPos = m_pPrimitive3DProgramTextured->GetUniformLoc(pName: "gPos");
1643 m_pPrimitive3DProgramTextured->m_LocTextureSampler = m_pPrimitive3DProgramTextured->GetUniformLoc(pName: "gTextureSampler");
1644 }
1645 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1646 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1647 else
1648 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1649 {
1650 CGLSL VertexShader;
1651 CGLSL FragmentShader;
1652 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.vert", GL_VERTEX_SHADER);
1653 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.frag", GL_FRAGMENT_SHADER);
1654
1655 m_pTileProgram->CreateProgram();
1656 m_pTileProgram->AddShader(pShader: &VertexShader);
1657 m_pTileProgram->AddShader(pShader: &FragmentShader);
1658
1659 glBindAttribLocation(m_pTileProgram->GetProgramId(), 0, "inVertex");
1660
1661 m_pTileProgram->LinkProgram();
1662
1663 UseProgram(pProgram: m_pTileProgram);
1664
1665 m_pTileProgram->m_LocPos = m_pTileProgram->GetUniformLoc(pName: "gPos");
1666 m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc(pName: "gVertColor");
1667 }
1668 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1669 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1670 else
1671 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1672 {
1673 CGLSL VertexShader;
1674 CGLSL FragmentShader;
1675 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_TEXTURED", pDefineValue: "");
1676 if(!pCommand->m_pCapabilities->m_2DArrayTextures)
1677 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_3D_TEXTURED", pDefineValue: "");
1678 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.vert", GL_VERTEX_SHADER);
1679 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.frag", GL_FRAGMENT_SHADER);
1680 ShaderCompiler.ClearDefines();
1681
1682 m_pTileProgramTextured->CreateProgram();
1683 m_pTileProgramTextured->AddShader(pShader: &VertexShader);
1684 m_pTileProgramTextured->AddShader(pShader: &FragmentShader);
1685
1686 glBindAttribLocation(m_pTileProgram->GetProgramId(), 0, "inVertex");
1687 glBindAttribLocation(m_pTileProgram->GetProgramId(), 1, "inVertexTexCoord");
1688
1689 m_pTileProgramTextured->LinkProgram();
1690
1691 UseProgram(pProgram: m_pTileProgramTextured);
1692
1693 m_pTileProgramTextured->m_LocPos = m_pTileProgramTextured->GetUniformLoc(pName: "gPos");
1694 m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc(pName: "gTextureSampler");
1695 m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc(pName: "gVertColor");
1696 }
1697 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1698 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1699 else
1700 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1701 {
1702 CGLSL VertexShader;
1703 CGLSL FragmentShader;
1704 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.vert", GL_VERTEX_SHADER);
1705 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.frag", GL_FRAGMENT_SHADER);
1706 ShaderCompiler.ClearDefines();
1707
1708 m_pBorderTileProgram->CreateProgram();
1709 m_pBorderTileProgram->AddShader(pShader: &VertexShader);
1710 m_pBorderTileProgram->AddShader(pShader: &FragmentShader);
1711
1712 glBindAttribLocation(m_pBorderTileProgram->GetProgramId(), 0, "inVertex");
1713
1714 m_pBorderTileProgram->LinkProgram();
1715
1716 UseProgram(pProgram: m_pBorderTileProgram);
1717
1718 m_pBorderTileProgram->m_LocPos = m_pBorderTileProgram->GetUniformLoc(pName: "gPos");
1719 m_pBorderTileProgram->m_LocColor = m_pBorderTileProgram->GetUniformLoc(pName: "gVertColor");
1720 m_pBorderTileProgram->m_LocOffset = m_pBorderTileProgram->GetUniformLoc(pName: "gOffset");
1721 m_pBorderTileProgram->m_LocScale = m_pBorderTileProgram->GetUniformLoc(pName: "gScale");
1722 }
1723 if(pCommand->m_pCapabilities->m_2DArrayTextures)
1724 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY);
1725 else
1726 ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D);
1727 {
1728 CGLSL VertexShader;
1729 CGLSL FragmentShader;
1730 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_TEXTURED", pDefineValue: "");
1731 if(!pCommand->m_pCapabilities->m_2DArrayTextures)
1732 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_3D_TEXTURED", pDefineValue: "");
1733 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.vert", GL_VERTEX_SHADER);
1734 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.frag", GL_FRAGMENT_SHADER);
1735 ShaderCompiler.ClearDefines();
1736
1737 m_pBorderTileProgramTextured->CreateProgram();
1738 m_pBorderTileProgramTextured->AddShader(pShader: &VertexShader);
1739 m_pBorderTileProgramTextured->AddShader(pShader: &FragmentShader);
1740
1741 glBindAttribLocation(m_pBorderTileProgramTextured->GetProgramId(), 0, "inVertex");
1742 glBindAttribLocation(m_pBorderTileProgramTextured->GetProgramId(), 1, "inVertexTexCoord");
1743
1744 m_pBorderTileProgramTextured->LinkProgram();
1745
1746 UseProgram(pProgram: m_pBorderTileProgramTextured);
1747
1748 m_pBorderTileProgramTextured->m_LocPos = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gPos");
1749 m_pBorderTileProgramTextured->m_LocTextureSampler = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gTextureSampler");
1750 m_pBorderTileProgramTextured->m_LocColor = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gVertColor");
1751 m_pBorderTileProgramTextured->m_LocOffset = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gOffset");
1752 m_pBorderTileProgramTextured->m_LocScale = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gScale");
1753 }
1754
1755 glUseProgram(0);
1756 }
1757
1758 if(g_Config.m_Gfx3DTextureAnalysisRan == 0 || str_comp(a: g_Config.m_Gfx3DTextureAnalysisRenderer, b: pCommand->m_pRendererString) != 0 || str_comp(a: g_Config.m_Gfx3DTextureAnalysisVersion, b: pCommand->m_pVersionString) != 0)
1759 {
1760 AnalysisCorrect = IsTileMapAnalysisSucceeded();
1761 if(AnalysisCorrect)
1762 {
1763 g_Config.m_Gfx3DTextureAnalysisRan = 1;
1764 str_copy(dst&: g_Config.m_Gfx3DTextureAnalysisRenderer, src: pCommand->m_pRendererString);
1765 str_copy(dst&: g_Config.m_Gfx3DTextureAnalysisVersion, src: pCommand->m_pVersionString);
1766 }
1767 }
1768 }
1769
1770 if(!AnalysisCorrect || !HasAllFunc)
1771 {
1772 // downgrade to opengl 1.5
1773 *pCommand->m_pInitError = -2;
1774 pCommand->m_pCapabilities->m_ContextMajor = 1;
1775 pCommand->m_pCapabilities->m_ContextMinor = 5;
1776 pCommand->m_pCapabilities->m_ContextPatch = 0;
1777
1778 return false;
1779 }
1780
1781 return true;
1782}
1783
1784void CCommandProcessorFragment_OpenGL2::Cmd_Shutdown(const SCommand_Shutdown *pCommand)
1785{
1786 // TODO: cleanup the OpenGL context too
1787 delete m_pTileProgram;
1788 delete m_pTileProgramTextured;
1789 delete m_pPrimitive3DProgram;
1790 delete m_pPrimitive3DProgramTextured;
1791 for(auto &BufferObject : m_vBufferObjectIndices)
1792 free(ptr: BufferObject.m_pData);
1793}
1794
1795void CCommandProcessorFragment_OpenGL2::Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand)
1796{
1797 if(m_HasShaders)
1798 {
1799 CGLSLPrimitiveProgram *pProgram = NULL;
1800 if(IsTexturedState(State: pCommand->m_State))
1801 {
1802 pProgram = m_pPrimitive3DProgramTextured;
1803 }
1804 else
1805 pProgram = m_pPrimitive3DProgram;
1806
1807 UseProgram(pProgram);
1808
1809 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
1810 }
1811 else
1812 {
1813 CCommandProcessorFragment_OpenGL::SetState(State: pCommand->m_State, Use2DArrayTextures: true);
1814 }
1815
1816 glEnableClientState(GL_VERTEX_ARRAY);
1817 glEnableClientState(GL_COLOR_ARRAY);
1818 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1819
1820 glVertexPointer(size: 2, GL_FLOAT, stride: sizeof(pCommand->m_pVertices[0]), pointer: pCommand->m_pVertices);
1821 glColorPointer(size: 4, GL_UNSIGNED_BYTE, stride: sizeof(pCommand->m_pVertices[0]), pointer: (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2)));
1822 glTexCoordPointer(size: 3, GL_FLOAT, stride: sizeof(pCommand->m_pVertices[0]), pointer: (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(unsigned char) * 4));
1823
1824 switch(pCommand->m_PrimType)
1825 {
1826 case EPrimitiveType::QUADS:
1827 glDrawArrays(GL_QUADS, first: 0, count: pCommand->m_PrimCount * 4);
1828 break;
1829 case EPrimitiveType::TRIANGLES:
1830 glDrawArrays(GL_TRIANGLES, first: 0, count: pCommand->m_PrimCount * 3);
1831 break;
1832 default:
1833 dbg_assert_failed("Invalid primitive type: %d", (int)pCommand->m_PrimType);
1834 };
1835
1836 glDisableClientState(GL_VERTEX_ARRAY);
1837 glDisableClientState(GL_COLOR_ARRAY);
1838 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1839
1840 if(m_HasShaders)
1841 {
1842 glUseProgram(0);
1843 }
1844}
1845
1846void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand)
1847{
1848 void *pUploadData = pCommand->m_pUploadData;
1849 const int Index = pCommand->m_BufferIndex;
1850 // create necessary space
1851 if((size_t)Index >= m_vBufferObjectIndices.size())
1852 {
1853 m_vBufferObjectIndices.resize(new_size: Index + 1, x: 0);
1854 }
1855
1856 GLuint VertBufferId = 0;
1857
1858 glGenBuffers(1, &VertBufferId);
1859 glBindBuffer(GL_ARRAY_BUFFER, VertBufferId);
1860 glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW);
1861 glBindBuffer(GL_ARRAY_BUFFER, 0);
1862
1863 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1864 BufferObject.m_BufferObjectId = VertBufferId;
1865 BufferObject.m_DataSize = pCommand->m_DataSize;
1866 BufferObject.m_pData = static_cast<uint8_t *>(malloc(size: pCommand->m_DataSize));
1867 if(pUploadData)
1868 mem_copy(dest: BufferObject.m_pData, source: pUploadData, size: pCommand->m_DataSize);
1869
1870 if(pCommand->m_DeletePointer)
1871 free(ptr: pUploadData);
1872}
1873
1874void CCommandProcessorFragment_OpenGL2::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand)
1875{
1876 void *pUploadData = pCommand->m_pUploadData;
1877 int Index = pCommand->m_BufferIndex;
1878 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1879
1880 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
1881 glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW);
1882 glBindBuffer(GL_ARRAY_BUFFER, 0);
1883
1884 BufferObject.m_DataSize = pCommand->m_DataSize;
1885 free(ptr: BufferObject.m_pData);
1886 BufferObject.m_pData = static_cast<uint8_t *>(malloc(size: pCommand->m_DataSize));
1887 if(pUploadData)
1888 mem_copy(dest: BufferObject.m_pData, source: pUploadData, size: pCommand->m_DataSize);
1889
1890 if(pCommand->m_DeletePointer)
1891 free(ptr: pUploadData);
1892}
1893
1894void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand)
1895{
1896 void *pUploadData = pCommand->m_pUploadData;
1897 int Index = pCommand->m_BufferIndex;
1898 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1899
1900 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
1901 glBufferSubData(GL_ARRAY_BUFFER, (GLintptr)(pCommand->m_pOffset), (GLsizeiptr)(pCommand->m_DataSize), pUploadData);
1902 glBindBuffer(GL_ARRAY_BUFFER, 0);
1903
1904 if(pUploadData)
1905 mem_copy(dest: BufferObject.m_pData + (ptrdiff_t)pCommand->m_pOffset, source: pUploadData, size: pCommand->m_DataSize);
1906
1907 if(pCommand->m_DeletePointer)
1908 free(ptr: pUploadData);
1909}
1910
1911void CCommandProcessorFragment_OpenGL2::Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand)
1912{
1913 int WriteIndex = pCommand->m_WriteBufferIndex;
1914 int ReadIndex = pCommand->m_ReadBufferIndex;
1915
1916 SBufferObject &ReadBufferObject = m_vBufferObjectIndices[ReadIndex];
1917 SBufferObject &WriteBufferObject = m_vBufferObjectIndices[WriteIndex];
1918
1919 mem_copy(dest: WriteBufferObject.m_pData + (ptrdiff_t)pCommand->m_WriteOffset, source: ReadBufferObject.m_pData + (ptrdiff_t)pCommand->m_ReadOffset, size: pCommand->m_CopySize);
1920
1921 glBindBuffer(GL_ARRAY_BUFFER, WriteBufferObject.m_BufferObjectId);
1922 glBufferSubData(GL_ARRAY_BUFFER, (GLintptr)(pCommand->m_WriteOffset), (GLsizeiptr)(pCommand->m_CopySize), WriteBufferObject.m_pData + (ptrdiff_t)pCommand->m_WriteOffset);
1923 glBindBuffer(GL_ARRAY_BUFFER, 0);
1924}
1925
1926void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand)
1927{
1928 int Index = pCommand->m_BufferIndex;
1929 SBufferObject &BufferObject = m_vBufferObjectIndices[Index];
1930
1931 glDeleteBuffers(1, &BufferObject.m_BufferObjectId);
1932
1933 free(ptr: BufferObject.m_pData);
1934 BufferObject.m_pData = NULL;
1935}
1936
1937void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand)
1938{
1939 const int Index = pCommand->m_BufferContainerIndex;
1940 // create necessary space
1941 if((size_t)Index >= m_vBufferContainers.size())
1942 {
1943 SBufferContainer Container;
1944 Container.m_ContainerInfo.m_Stride = 0;
1945 Container.m_ContainerInfo.m_VertBufferBindingIndex = -1;
1946 m_vBufferContainers.resize(new_size: Index + 1, x: Container);
1947 }
1948
1949 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1950
1951 for(size_t i = 0; i < pCommand->m_AttrCount; ++i)
1952 {
1953 BufferContainer.m_ContainerInfo.m_vAttributes.push_back(x: pCommand->m_pAttributes[i]);
1954 }
1955
1956 BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
1957 BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
1958}
1959
1960void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand)
1961{
1962 SBufferContainer &BufferContainer = m_vBufferContainers[pCommand->m_BufferContainerIndex];
1963
1964 BufferContainer.m_ContainerInfo.m_vAttributes.clear();
1965
1966 for(size_t i = 0; i < pCommand->m_AttrCount; ++i)
1967 {
1968 BufferContainer.m_ContainerInfo.m_vAttributes.push_back(x: pCommand->m_pAttributes[i]);
1969 }
1970
1971 BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
1972 BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
1973}
1974
1975void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand)
1976{
1977 SBufferContainer &BufferContainer = m_vBufferContainers[pCommand->m_BufferContainerIndex];
1978
1979 if(pCommand->m_DestroyAllBO)
1980 {
1981 int VertBufferId = BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex;
1982 if(VertBufferId != -1)
1983 {
1984 glDeleteBuffers(1, &m_vBufferObjectIndices[VertBufferId].m_BufferObjectId);
1985
1986 free(ptr: m_vBufferObjectIndices[VertBufferId].m_pData);
1987 m_vBufferObjectIndices[VertBufferId].m_pData = NULL;
1988 }
1989 }
1990
1991 BufferContainer.m_ContainerInfo.m_vAttributes.clear();
1992}
1993
1994void CCommandProcessorFragment_OpenGL2::Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand)
1995{
1996}
1997
1998void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand)
1999{
2000 int Index = pCommand->m_BufferContainerIndex;
2001 // if space not there return
2002 if((size_t)Index >= m_vBufferContainers.size())
2003 return;
2004
2005 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
2006
2007 CGLSLTileProgram *pProgram = NULL;
2008 if(IsTexturedState(State: pCommand->m_State))
2009 pProgram = m_pBorderTileProgramTextured;
2010 else
2011 pProgram = m_pBorderTileProgram;
2012 UseProgram(pProgram);
2013
2014 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
2015 pProgram->SetUniformVec4(Loc: pProgram->m_LocColor, Count: 1, pValue: (float *)&pCommand->m_Color);
2016
2017 pProgram->SetUniformVec2(Loc: pProgram->m_LocOffset, Count: 1, pValue: (float *)&pCommand->m_Offset);
2018 pProgram->SetUniformVec2(Loc: pProgram->m_LocScale, Count: 1, pValue: (float *)&pCommand->m_Scale);
2019
2020 bool IsTextured = BufferContainer.m_ContainerInfo.m_vAttributes.size() == 2;
2021
2022 SBufferObject &BufferObject = m_vBufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex];
2023
2024 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
2025
2026 glEnableVertexAttribArray(0);
2027 glVertexAttribPointer(0, 2, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[0].m_pOffset);
2028 if(IsTextured)
2029 {
2030 glEnableVertexAttribArray(1);
2031 glVertexAttribIPointer(1, 4, GL_UNSIGNED_BYTE, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[1].m_pOffset);
2032 }
2033
2034 size_t RealDrawCount = pCommand->m_DrawNum * 4;
2035 GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffset)) / (6 * sizeof(unsigned int))) * 4);
2036 glDrawArrays(GL_QUADS, first: RealOffset, count: RealDrawCount);
2037
2038 glDisableVertexAttribArray(0);
2039 if(IsTextured)
2040 glDisableVertexAttribArray(1);
2041 glBindBuffer(GL_ARRAY_BUFFER, 0);
2042 glUseProgram(0);
2043}
2044
2045void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand)
2046{
2047 int Index = pCommand->m_BufferContainerIndex;
2048 // if space not there return
2049 if((size_t)Index >= m_vBufferContainers.size())
2050 return;
2051
2052 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
2053
2054 if(pCommand->m_IndicesDrawNum == 0)
2055 {
2056 return; // nothing to draw
2057 }
2058
2059 CGLSLTileProgram *pProgram = NULL;
2060 if(IsTexturedState(State: pCommand->m_State))
2061 {
2062 pProgram = m_pTileProgramTextured;
2063 }
2064 else
2065 pProgram = m_pTileProgram;
2066
2067 UseProgram(pProgram);
2068
2069 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
2070 pProgram->SetUniformVec4(Loc: pProgram->m_LocColor, Count: 1, pValue: (float *)&pCommand->m_Color);
2071
2072 bool IsTextured = BufferContainer.m_ContainerInfo.m_vAttributes.size() == 2;
2073
2074 SBufferObject &BufferObject = m_vBufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex];
2075
2076 glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectId);
2077
2078 glEnableVertexAttribArray(0);
2079 glVertexAttribPointer(0, 2, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[0].m_pOffset);
2080 if(IsTextured)
2081 {
2082 glEnableVertexAttribArray(1);
2083 glVertexAttribIPointer(1, 4, GL_UNSIGNED_BYTE, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_vAttributes[1].m_pOffset);
2084 }
2085
2086 for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i)
2087 {
2088 size_t RealDrawCount = (pCommand->m_pDrawCount[i] / 6) * 4;
2089 GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffsets[i])) / (6 * sizeof(unsigned int))) * 4);
2090 glDrawArrays(GL_QUADS, first: RealOffset, count: RealDrawCount);
2091 }
2092
2093 glDisableVertexAttribArray(0);
2094 if(IsTextured)
2095 glDisableVertexAttribArray(1);
2096 glBindBuffer(GL_ARRAY_BUFFER, 0);
2097 glUseProgram(0);
2098}
2099
2100#undef BACKEND_GL_MODERN_API
2101
2102#endif
2103
2104#endif
2105