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