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