1#include "backend_opengl3.h"
2
3#include <base/detect.h>
4#include <base/log.h>
5
6#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
7
8#ifndef BACKEND_AS_OPENGL_ES
9#include <GL/glew.h>
10#else
11#include <GLES3/gl3.h>
12#endif
13
14#include <engine/client/backend/glsl_shader_compiler.h>
15#include <engine/client/backend/opengl/opengl_sl.h>
16#include <engine/client/backend/opengl/opengl_sl_program.h>
17#include <engine/client/backend_sdl.h>
18#include <engine/gfx/image_manipulation.h>
19
20#if defined(CONF_PLATFORM_EMSCRIPTEN)
21// WebGL2 defines the type of a buffer at the first bind to a buffer target
22// this is different to GLES 3 (https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1)
23static constexpr GLenum BUFFER_INIT_INDEX_TARGET = GL_ELEMENT_ARRAY_BUFFER;
24static constexpr GLenum BUFFER_INIT_VERTEX_TARGET = GL_ARRAY_BUFFER;
25#else
26static constexpr GLenum BUFFER_INIT_INDEX_TARGET = GL_COPY_WRITE_BUFFER;
27static constexpr GLenum BUFFER_INIT_VERTEX_TARGET = GL_COPY_WRITE_BUFFER;
28#endif
29
30// ------------ CCommandProcessorFragment_OpenGL3_3
31void CCommandProcessorFragment_OpenGL3_3::UseProgram(CGLSLTWProgram *pProgram)
32{
33 if(m_LastProgramId != pProgram->GetProgramId())
34 {
35 pProgram->UseProgram();
36 m_LastProgramId = pProgram->GetProgramId();
37 }
38}
39
40void CCommandProcessorFragment_OpenGL3_3::InitPrimExProgram(CGLSLPrimitiveExProgram *pProgram, CGLSLCompiler *pCompiler, IStorage *pStorage, bool Textured, bool Rotationless)
41{
42 CGLSL PrimitiveVertexShader;
43 CGLSL PrimitiveFragmentShader;
44 if(Textured)
45 pCompiler->AddDefine(pDefineName: "TW_TEXTURED", pDefineValue: "");
46 if(Rotationless)
47 pCompiler->AddDefine(pDefineName: "TW_ROTATIONLESS", pDefineValue: "");
48 PrimitiveVertexShader.LoadShader(pCompiler, pStorage, pFile: "shader/primex.vert", GL_VERTEX_SHADER);
49 PrimitiveFragmentShader.LoadShader(pCompiler, pStorage, pFile: "shader/primex.frag", GL_FRAGMENT_SHADER);
50 if(Textured || Rotationless)
51 pCompiler->ClearDefines();
52
53 pProgram->CreateProgram();
54 pProgram->AddShader(pShader: &PrimitiveVertexShader);
55 pProgram->AddShader(pShader: &PrimitiveFragmentShader);
56 pProgram->LinkProgram();
57
58 UseProgram(pProgram);
59
60 pProgram->m_LocPos = pProgram->GetUniformLoc(pName: "gPos");
61 pProgram->m_LocTextureSampler = pProgram->GetUniformLoc(pName: "gTextureSampler");
62 pProgram->m_LocRotation = pProgram->GetUniformLoc(pName: "gRotation");
63 pProgram->m_LocCenter = pProgram->GetUniformLoc(pName: "gCenter");
64 pProgram->m_LocVertciesColor = pProgram->GetUniformLoc(pName: "gVerticesColor");
65
66 if(!Rotationless)
67 {
68 pProgram->SetUniform(Loc: pProgram->m_LocRotation, Value: 0.0f);
69 float aCenter[2] = {0.f, 0.f};
70 pProgram->SetUniformVec2(Loc: pProgram->m_LocCenter, Count: 1, pValue: aCenter);
71 }
72}
73
74bool CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand)
75{
76 if(!InitOpenGL(pCommand))
77 return false;
78
79 m_OpenGLTextureLodBIAS = g_Config.m_GfxGLTextureLODBIAS;
80
81 glActiveTexture(GL_TEXTURE0);
82
83 m_Has2DArrayTextures = true;
84 m_Has2DArrayTexturesAsExtension = false;
85 m_2DArrayTarget = GL_TEXTURE_2D_ARRAY;
86 m_Has3DTextures = false;
87 m_HasMipMaps = true;
88 m_HasNPOTTextures = true;
89 m_HasShaders = true;
90
91 m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
92 m_pTextureMemoryUsage->store(i: 0, m: std::memory_order_relaxed);
93 m_LastBlendMode = EBlendMode::ALPHA;
94 m_LastClipEnable = false;
95 m_pPrimitiveProgram = new CGLSLPrimitiveProgram;
96 m_pPrimitiveProgramTextured = new CGLSLPrimitiveProgram;
97 m_pTileProgram = new CGLSLTileProgram;
98 m_pTileProgramTextured = new CGLSLTileProgram;
99 m_pPrimitive3DProgram = new CGLSLPrimitiveProgram;
100 m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram;
101 m_pBorderTileProgram = new CGLSLTileProgram;
102 m_pBorderTileProgramTextured = new CGLSLTileProgram;
103 m_pQuadProgram = new CGLSLQuadProgram;
104 m_pQuadProgramTextured = new CGLSLQuadProgram;
105 m_pQuadProgramGrouped = new CGLSLQuadProgram;
106 m_pQuadProgramTexturedGrouped = new CGLSLQuadProgram;
107 m_pTextProgram = new CGLSLTextProgram;
108 m_pPrimitiveExProgram = new CGLSLPrimitiveExProgram;
109 m_pPrimitiveExProgramTextured = new CGLSLPrimitiveExProgram;
110 m_pPrimitiveExProgramRotationless = new CGLSLPrimitiveExProgram;
111 m_pPrimitiveExProgramTexturedRotationless = new CGLSLPrimitiveExProgram;
112 m_pSpriteProgramMultiple = new CGLSLSpriteMultipleProgram;
113 m_LastProgramId = 0;
114
115 CGLSLCompiler ShaderCompiler(g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f);
116
117 GLint CapVal;
118 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, params: &CapVal);
119
120 m_MaxQuadsAtOnce = minimum<int>(a: ((CapVal - 20) / (3 * 4)), b: ms_MaxQuadsPossible);
121
122 {
123 CGLSL PrimitiveVertexShader;
124 CGLSL PrimitiveFragmentShader;
125 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/prim.vert", GL_VERTEX_SHADER);
126 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/prim.frag", GL_FRAGMENT_SHADER);
127
128 m_pPrimitiveProgram->CreateProgram();
129 m_pPrimitiveProgram->AddShader(pShader: &PrimitiveVertexShader);
130 m_pPrimitiveProgram->AddShader(pShader: &PrimitiveFragmentShader);
131 m_pPrimitiveProgram->LinkProgram();
132
133 UseProgram(pProgram: m_pPrimitiveProgram);
134
135 m_pPrimitiveProgram->m_LocPos = m_pPrimitiveProgram->GetUniformLoc(pName: "gPos");
136 m_pPrimitiveProgram->m_LocTextureSampler = m_pPrimitiveProgram->GetUniformLoc(pName: "gTextureSampler");
137 }
138 {
139 CGLSL PrimitiveVertexShader;
140 CGLSL PrimitiveFragmentShader;
141 ShaderCompiler.AddDefine(pDefineName: "TW_TEXTURED", pDefineValue: "");
142 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/prim.vert", GL_VERTEX_SHADER);
143 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/prim.frag", GL_FRAGMENT_SHADER);
144 ShaderCompiler.ClearDefines();
145
146 m_pPrimitiveProgramTextured->CreateProgram();
147 m_pPrimitiveProgramTextured->AddShader(pShader: &PrimitiveVertexShader);
148 m_pPrimitiveProgramTextured->AddShader(pShader: &PrimitiveFragmentShader);
149 m_pPrimitiveProgramTextured->LinkProgram();
150
151 UseProgram(pProgram: m_pPrimitiveProgramTextured);
152
153 m_pPrimitiveProgramTextured->m_LocPos = m_pPrimitiveProgramTextured->GetUniformLoc(pName: "gPos");
154 m_pPrimitiveProgramTextured->m_LocTextureSampler = m_pPrimitiveProgramTextured->GetUniformLoc(pName: "gTextureSampler");
155 }
156
157 {
158 CGLSL PrimitiveVertexShader;
159 CGLSL PrimitiveFragmentShader;
160 ShaderCompiler.AddDefine(pDefineName: "TW_MODERN_GL", pDefineValue: "");
161 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.vert", GL_VERTEX_SHADER);
162 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.frag", GL_FRAGMENT_SHADER);
163 ShaderCompiler.ClearDefines();
164
165 m_pPrimitive3DProgram->CreateProgram();
166 m_pPrimitive3DProgram->AddShader(pShader: &PrimitiveVertexShader);
167 m_pPrimitive3DProgram->AddShader(pShader: &PrimitiveFragmentShader);
168 m_pPrimitive3DProgram->LinkProgram();
169
170 UseProgram(pProgram: m_pPrimitive3DProgram);
171
172 m_pPrimitive3DProgram->m_LocPos = m_pPrimitive3DProgram->GetUniformLoc(pName: "gPos");
173 }
174 {
175 CGLSL PrimitiveVertexShader;
176 CGLSL PrimitiveFragmentShader;
177 ShaderCompiler.AddDefine(pDefineName: "TW_MODERN_GL", pDefineValue: "");
178 ShaderCompiler.AddDefine(pDefineName: "TW_TEXTURED", pDefineValue: "");
179 if(!pCommand->m_pCapabilities->m_2DArrayTextures)
180 ShaderCompiler.AddDefine(pDefineName: "TW_3D_TEXTURED", pDefineValue: "");
181 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.vert", GL_VERTEX_SHADER);
182 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/pipeline.frag", GL_FRAGMENT_SHADER);
183 ShaderCompiler.ClearDefines();
184
185 m_pPrimitive3DProgramTextured->CreateProgram();
186 m_pPrimitive3DProgramTextured->AddShader(pShader: &PrimitiveVertexShader);
187 m_pPrimitive3DProgramTextured->AddShader(pShader: &PrimitiveFragmentShader);
188 m_pPrimitive3DProgramTextured->LinkProgram();
189
190 UseProgram(pProgram: m_pPrimitive3DProgramTextured);
191
192 m_pPrimitive3DProgramTextured->m_LocPos = m_pPrimitive3DProgramTextured->GetUniformLoc(pName: "gPos");
193 m_pPrimitive3DProgramTextured->m_LocTextureSampler = m_pPrimitive3DProgramTextured->GetUniformLoc(pName: "gTextureSampler");
194 }
195
196 {
197 CGLSL VertexShader;
198 CGLSL FragmentShader;
199 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.vert", GL_VERTEX_SHADER);
200 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.frag", GL_FRAGMENT_SHADER);
201
202 m_pTileProgram->CreateProgram();
203 m_pTileProgram->AddShader(pShader: &VertexShader);
204 m_pTileProgram->AddShader(pShader: &FragmentShader);
205 m_pTileProgram->LinkProgram();
206
207 UseProgram(pProgram: m_pTileProgram);
208
209 m_pTileProgram->m_LocPos = m_pTileProgram->GetUniformLoc(pName: "gPos");
210 m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc(pName: "gVertColor");
211 }
212 {
213 CGLSL VertexShader;
214 CGLSL FragmentShader;
215 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_TEXTURED", pDefineValue: "");
216 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.vert", GL_VERTEX_SHADER);
217 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile.frag", GL_FRAGMENT_SHADER);
218 ShaderCompiler.ClearDefines();
219
220 m_pTileProgramTextured->CreateProgram();
221 m_pTileProgramTextured->AddShader(pShader: &VertexShader);
222 m_pTileProgramTextured->AddShader(pShader: &FragmentShader);
223 m_pTileProgramTextured->LinkProgram();
224
225 UseProgram(pProgram: m_pTileProgramTextured);
226
227 m_pTileProgramTextured->m_LocPos = m_pTileProgramTextured->GetUniformLoc(pName: "gPos");
228 m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc(pName: "gTextureSampler");
229 m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc(pName: "gVertColor");
230 }
231 {
232 CGLSL VertexShader;
233 CGLSL FragmentShader;
234 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.vert", GL_VERTEX_SHADER);
235 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.frag", GL_FRAGMENT_SHADER);
236 ShaderCompiler.ClearDefines();
237
238 m_pBorderTileProgram->CreateProgram();
239 m_pBorderTileProgram->AddShader(pShader: &VertexShader);
240 m_pBorderTileProgram->AddShader(pShader: &FragmentShader);
241 m_pBorderTileProgram->LinkProgram();
242
243 UseProgram(pProgram: m_pBorderTileProgram);
244
245 m_pBorderTileProgram->m_LocPos = m_pBorderTileProgram->GetUniformLoc(pName: "gPos");
246 m_pBorderTileProgram->m_LocColor = m_pBorderTileProgram->GetUniformLoc(pName: "gVertColor");
247 m_pBorderTileProgram->m_LocOffset = m_pBorderTileProgram->GetUniformLoc(pName: "gOffset");
248 m_pBorderTileProgram->m_LocScale = m_pBorderTileProgram->GetUniformLoc(pName: "gScale");
249 }
250 {
251 CGLSL VertexShader;
252 CGLSL FragmentShader;
253 ShaderCompiler.AddDefine(pDefineName: "TW_TILE_TEXTURED", pDefineValue: "");
254 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.vert", GL_VERTEX_SHADER);
255 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/tile_border.frag", GL_FRAGMENT_SHADER);
256 ShaderCompiler.ClearDefines();
257
258 m_pBorderTileProgramTextured->CreateProgram();
259 m_pBorderTileProgramTextured->AddShader(pShader: &VertexShader);
260 m_pBorderTileProgramTextured->AddShader(pShader: &FragmentShader);
261 m_pBorderTileProgramTextured->LinkProgram();
262
263 UseProgram(pProgram: m_pBorderTileProgramTextured);
264
265 m_pBorderTileProgramTextured->m_LocPos = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gPos");
266 m_pBorderTileProgramTextured->m_LocTextureSampler = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gTextureSampler");
267 m_pBorderTileProgramTextured->m_LocColor = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gVertColor");
268 m_pBorderTileProgramTextured->m_LocOffset = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gOffset");
269 m_pBorderTileProgramTextured->m_LocScale = m_pBorderTileProgramTextured->GetUniformLoc(pName: "gScale");
270 }
271 {
272 CGLSL VertexShader;
273 CGLSL FragmentShader;
274 ShaderCompiler.AddDefine(pDefineName: "TW_MAX_QUADS", pDefineValue: std::to_string(val: m_MaxQuadsAtOnce).c_str());
275 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.vert", GL_VERTEX_SHADER);
276 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.frag", GL_FRAGMENT_SHADER);
277 ShaderCompiler.ClearDefines();
278
279 m_pQuadProgram->CreateProgram();
280 m_pQuadProgram->AddShader(pShader: &VertexShader);
281 m_pQuadProgram->AddShader(pShader: &FragmentShader);
282 m_pQuadProgram->LinkProgram();
283
284 UseProgram(pProgram: m_pQuadProgram);
285
286 m_pQuadProgram->m_LocPos = m_pQuadProgram->GetUniformLoc(pName: "gPos");
287 m_pQuadProgram->m_LocColors = m_pQuadProgram->GetUniformLoc(pName: "gVertColors");
288 m_pQuadProgram->m_LocRotations = m_pQuadProgram->GetUniformLoc(pName: "gRotations");
289 m_pQuadProgram->m_LocOffsets = m_pQuadProgram->GetUniformLoc(pName: "gOffsets");
290 m_pQuadProgram->m_LocQuadOffset = m_pQuadProgram->GetUniformLoc(pName: "gQuadOffset");
291 }
292 {
293 CGLSL VertexShader;
294 CGLSL FragmentShader;
295 ShaderCompiler.AddDefine(pDefineName: "TW_QUAD_TEXTURED", pDefineValue: "");
296 ShaderCompiler.AddDefine(pDefineName: "TW_MAX_QUADS", pDefineValue: std::to_string(val: m_MaxQuadsAtOnce).c_str());
297 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.vert", GL_VERTEX_SHADER);
298 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.frag", GL_FRAGMENT_SHADER);
299 ShaderCompiler.ClearDefines();
300
301 m_pQuadProgramTextured->CreateProgram();
302 m_pQuadProgramTextured->AddShader(pShader: &VertexShader);
303 m_pQuadProgramTextured->AddShader(pShader: &FragmentShader);
304 m_pQuadProgramTextured->LinkProgram();
305
306 UseProgram(pProgram: m_pQuadProgramTextured);
307
308 m_pQuadProgramTextured->m_LocPos = m_pQuadProgramTextured->GetUniformLoc(pName: "gPos");
309 m_pQuadProgramTextured->m_LocTextureSampler = m_pQuadProgramTextured->GetUniformLoc(pName: "gTextureSampler");
310 m_pQuadProgramTextured->m_LocColors = m_pQuadProgramTextured->GetUniformLoc(pName: "gVertColors");
311 m_pQuadProgramTextured->m_LocRotations = m_pQuadProgramTextured->GetUniformLoc(pName: "gRotations");
312 m_pQuadProgramTextured->m_LocOffsets = m_pQuadProgramTextured->GetUniformLoc(pName: "gOffsets");
313 m_pQuadProgramTextured->m_LocQuadOffset = m_pQuadProgramTextured->GetUniformLoc(pName: "gQuadOffset");
314 }
315 {
316 CGLSL VertexShader;
317 CGLSL FragmentShader;
318 ShaderCompiler.AddDefine(pDefineName: "TW_QUAD_GROUPED", pDefineValue: "");
319 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.vert", GL_VERTEX_SHADER);
320 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.frag", GL_FRAGMENT_SHADER);
321 ShaderCompiler.ClearDefines();
322
323 m_pQuadProgramGrouped->CreateProgram();
324 m_pQuadProgramGrouped->AddShader(pShader: &VertexShader);
325 m_pQuadProgramGrouped->AddShader(pShader: &FragmentShader);
326 m_pQuadProgramGrouped->LinkProgram();
327
328 UseProgram(pProgram: m_pQuadProgramGrouped);
329
330 m_pQuadProgramGrouped->m_LocPos = m_pQuadProgramGrouped->GetUniformLoc(pName: "gPos");
331 m_pQuadProgramGrouped->m_LocColors = m_pQuadProgramGrouped->GetUniformLoc(pName: "gVertColors");
332 m_pQuadProgramGrouped->m_LocRotations = m_pQuadProgramGrouped->GetUniformLoc(pName: "gRotations");
333 m_pQuadProgramGrouped->m_LocOffsets = m_pQuadProgramGrouped->GetUniformLoc(pName: "gOffsets");
334 }
335 {
336 CGLSL VertexShader;
337 CGLSL FragmentShader;
338 ShaderCompiler.AddDefine(pDefineName: "TW_QUAD_TEXTURED", pDefineValue: "");
339 ShaderCompiler.AddDefine(pDefineName: "TW_QUAD_GROUPED", pDefineValue: "");
340 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.vert", GL_VERTEX_SHADER);
341 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/quad.frag", GL_FRAGMENT_SHADER);
342 ShaderCompiler.ClearDefines();
343
344 m_pQuadProgramTexturedGrouped->CreateProgram();
345 m_pQuadProgramTexturedGrouped->AddShader(pShader: &VertexShader);
346 m_pQuadProgramTexturedGrouped->AddShader(pShader: &FragmentShader);
347 m_pQuadProgramTexturedGrouped->LinkProgram();
348
349 UseProgram(pProgram: m_pQuadProgramTexturedGrouped);
350
351 m_pQuadProgramTexturedGrouped->m_LocPos = m_pQuadProgramTexturedGrouped->GetUniformLoc(pName: "gPos");
352 m_pQuadProgramTexturedGrouped->m_LocTextureSampler = m_pQuadProgramTexturedGrouped->GetUniformLoc(pName: "gTextureSampler");
353 m_pQuadProgramTexturedGrouped->m_LocColors = m_pQuadProgramTexturedGrouped->GetUniformLoc(pName: "gVertColors");
354 m_pQuadProgramTexturedGrouped->m_LocRotations = m_pQuadProgramTexturedGrouped->GetUniformLoc(pName: "gRotations");
355 m_pQuadProgramTexturedGrouped->m_LocOffsets = m_pQuadProgramTexturedGrouped->GetUniformLoc(pName: "gOffsets");
356 }
357 {
358 CGLSL VertexShader;
359 CGLSL FragmentShader;
360 VertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/text.vert", GL_VERTEX_SHADER);
361 FragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/text.frag", GL_FRAGMENT_SHADER);
362
363 m_pTextProgram->CreateProgram();
364 m_pTextProgram->AddShader(pShader: &VertexShader);
365 m_pTextProgram->AddShader(pShader: &FragmentShader);
366 m_pTextProgram->LinkProgram();
367
368 UseProgram(pProgram: m_pTextProgram);
369
370 m_pTextProgram->m_LocPos = m_pTextProgram->GetUniformLoc(pName: "gPos");
371 m_pTextProgram->m_LocTextureSampler = -1;
372 m_pTextProgram->m_LocTextSampler = m_pTextProgram->GetUniformLoc(pName: "gTextSampler");
373 m_pTextProgram->m_LocTextOutlineSampler = m_pTextProgram->GetUniformLoc(pName: "gTextOutlineSampler");
374 m_pTextProgram->m_LocColor = m_pTextProgram->GetUniformLoc(pName: "gVertColor");
375 m_pTextProgram->m_LocOutlineColor = m_pTextProgram->GetUniformLoc(pName: "gVertOutlineColor");
376 m_pTextProgram->m_LocTextureSize = m_pTextProgram->GetUniformLoc(pName: "gTextureSize");
377 }
378 InitPrimExProgram(pProgram: m_pPrimitiveExProgram, pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, Textured: false, Rotationless: false);
379 InitPrimExProgram(pProgram: m_pPrimitiveExProgramTextured, pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, Textured: true, Rotationless: false);
380 InitPrimExProgram(pProgram: m_pPrimitiveExProgramRotationless, pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, Textured: false, Rotationless: true);
381 InitPrimExProgram(pProgram: m_pPrimitiveExProgramTexturedRotationless, pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, Textured: true, Rotationless: true);
382 {
383 CGLSL PrimitiveVertexShader;
384 CGLSL PrimitiveFragmentShader;
385 PrimitiveVertexShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/spritemulti.vert", GL_VERTEX_SHADER);
386 PrimitiveFragmentShader.LoadShader(pCompiler: &ShaderCompiler, pStorage: pCommand->m_pStorage, pFile: "shader/spritemulti.frag", GL_FRAGMENT_SHADER);
387
388 m_pSpriteProgramMultiple->CreateProgram();
389 m_pSpriteProgramMultiple->AddShader(pShader: &PrimitiveVertexShader);
390 m_pSpriteProgramMultiple->AddShader(pShader: &PrimitiveFragmentShader);
391 m_pSpriteProgramMultiple->LinkProgram();
392
393 UseProgram(pProgram: m_pSpriteProgramMultiple);
394
395 m_pSpriteProgramMultiple->m_LocPos = m_pSpriteProgramMultiple->GetUniformLoc(pName: "gPos");
396 m_pSpriteProgramMultiple->m_LocTextureSampler = m_pSpriteProgramMultiple->GetUniformLoc(pName: "gTextureSampler");
397 m_pSpriteProgramMultiple->m_LocRSP = m_pSpriteProgramMultiple->GetUniformLoc(pName: "gRSP[0]");
398 m_pSpriteProgramMultiple->m_LocCenter = m_pSpriteProgramMultiple->GetUniformLoc(pName: "gCenter");
399 m_pSpriteProgramMultiple->m_LocVertciesColor = m_pSpriteProgramMultiple->GetUniformLoc(pName: "gVerticesColor");
400
401 float aCenter[2] = {0.f, 0.f};
402 m_pSpriteProgramMultiple->SetUniformVec2(Loc: m_pSpriteProgramMultiple->m_LocCenter, Count: 1, pValue: aCenter);
403 }
404
405 m_LastStreamBuffer = 0;
406
407 glGenBuffers(MAX_STREAM_BUFFER_COUNT, m_aPrimitiveDrawBufferId);
408 glGenVertexArrays(MAX_STREAM_BUFFER_COUNT, m_aPrimitiveDrawVertexId);
409 glGenBuffers(1, &m_PrimitiveDrawBufferIdTex3D);
410 glGenVertexArrays(1, &m_PrimitiveDrawVertexIdTex3D);
411
412 for(int i = 0; i < MAX_STREAM_BUFFER_COUNT; ++i)
413 {
414 glBindBuffer(GL_ARRAY_BUFFER, m_aPrimitiveDrawBufferId[i]);
415 glBindVertexArray(m_aPrimitiveDrawVertexId[i]);
416 glEnableVertexAttribArray(0);
417 glEnableVertexAttribArray(1);
418 glEnableVertexAttribArray(2);
419
420 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), 0);
421 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), (void *)(sizeof(float) * 2));
422 glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(CCommandBuffer::SVertex), (void *)(sizeof(float) * 4));
423
424 m_aLastIndexBufferBound[i] = 0;
425 }
426
427 glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferIdTex3D);
428 glBindVertexArray(m_PrimitiveDrawVertexIdTex3D);
429 glEnableVertexAttribArray(0);
430 glEnableVertexAttribArray(1);
431 glEnableVertexAttribArray(2);
432
433 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertexTex3DStream), 0);
434 glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(CCommandBuffer::SVertexTex3DStream), (void *)(sizeof(float) * 2));
435 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertexTex3DStream), (void *)(sizeof(float) * 2 + sizeof(unsigned char) * 4));
436
437 // query the image max size only once
438 glGetIntegerv(GL_MAX_TEXTURE_SIZE, params: &m_MaxTexSize);
439
440 glBindVertexArray(0);
441 glGenBuffers(1, &m_QuadDrawIndexBufferId);
442 glBindBuffer(BUFFER_INIT_INDEX_TARGET, m_QuadDrawIndexBufferId);
443
444 unsigned int aIndices[CCommandBuffer::MAX_VERTICES / 4 * 6];
445 int Primq = 0;
446 for(int i = 0; i < CCommandBuffer::MAX_VERTICES / 4 * 6; i += 6)
447 {
448 aIndices[i] = Primq;
449 aIndices[i + 1] = Primq + 1;
450 aIndices[i + 2] = Primq + 2;
451 aIndices[i + 3] = Primq;
452 aIndices[i + 4] = Primq + 2;
453 aIndices[i + 5] = Primq + 3;
454 Primq += 4;
455 }
456 glBufferData(BUFFER_INIT_INDEX_TARGET, sizeof(unsigned int) * CCommandBuffer::MAX_VERTICES / 4 * 6, aIndices, GL_STATIC_DRAW);
457
458 m_CurrentIndicesInBuffer = CCommandBuffer::MAX_VERTICES / 4 * 6;
459
460 m_vTextures.resize(sz: CCommandBuffer::MAX_TEXTURES);
461
462 m_ClearColor.r = m_ClearColor.g = m_ClearColor.b = -1.f;
463
464 // fix the alignment to allow even 1byte changes, e.g. for alpha components
465 glPixelStorei(GL_UNPACK_ALIGNMENT, param: 1);
466
467 return true;
468}
469
470void CCommandProcessorFragment_OpenGL3_3::Cmd_Shutdown(const SCommand_Shutdown *pCommand)
471{
472 glUseProgram(0);
473
474 m_pPrimitiveProgram->DeleteProgram();
475 m_pPrimitiveProgramTextured->DeleteProgram();
476 m_pBorderTileProgram->DeleteProgram();
477 m_pBorderTileProgramTextured->DeleteProgram();
478 m_pQuadProgram->DeleteProgram();
479 m_pQuadProgramTextured->DeleteProgram();
480 m_pQuadProgramGrouped->DeleteProgram();
481 m_pQuadProgramTexturedGrouped->DeleteProgram();
482 m_pTileProgram->DeleteProgram();
483 m_pTileProgramTextured->DeleteProgram();
484 m_pPrimitive3DProgram->DeleteProgram();
485 m_pPrimitive3DProgramTextured->DeleteProgram();
486 m_pTextProgram->DeleteProgram();
487 m_pPrimitiveExProgram->DeleteProgram();
488 m_pPrimitiveExProgramTextured->DeleteProgram();
489 m_pPrimitiveExProgramRotationless->DeleteProgram();
490 m_pPrimitiveExProgramTexturedRotationless->DeleteProgram();
491 m_pSpriteProgramMultiple->DeleteProgram();
492
493 // clean up everything
494 delete m_pPrimitiveProgram;
495 delete m_pPrimitiveProgramTextured;
496 delete m_pBorderTileProgram;
497 delete m_pBorderTileProgramTextured;
498 delete m_pQuadProgram;
499 delete m_pQuadProgramTextured;
500 delete m_pQuadProgramGrouped;
501 delete m_pQuadProgramTexturedGrouped;
502 delete m_pTileProgram;
503 delete m_pTileProgramTextured;
504 delete m_pPrimitive3DProgram;
505 delete m_pPrimitive3DProgramTextured;
506 delete m_pTextProgram;
507 delete m_pPrimitiveExProgram;
508 delete m_pPrimitiveExProgramTextured;
509 delete m_pPrimitiveExProgramRotationless;
510 delete m_pPrimitiveExProgramTexturedRotationless;
511 delete m_pSpriteProgramMultiple;
512
513 glBindVertexArray(0);
514 glDeleteBuffers(MAX_STREAM_BUFFER_COUNT, m_aPrimitiveDrawBufferId);
515 glDeleteBuffers(1, &m_QuadDrawIndexBufferId);
516 glDeleteVertexArrays(MAX_STREAM_BUFFER_COUNT, m_aPrimitiveDrawVertexId);
517 glDeleteBuffers(1, &m_PrimitiveDrawBufferIdTex3D);
518 glDeleteVertexArrays(1, &m_PrimitiveDrawVertexIdTex3D);
519
520 for(int i = 0; i < (int)m_vTextures.size(); ++i)
521 {
522 DestroyTexture(Slot: i);
523 }
524
525 for(size_t i = 0; i < m_vBufferContainers.size(); ++i)
526 {
527 DestroyBufferContainer(Index: i);
528 }
529
530 m_vBufferContainers.clear();
531}
532
533void CCommandProcessorFragment_OpenGL3_3::TextureUpdate(int Slot, int X, int Y, int Width, int Height, int GLFormat, uint8_t *pTexData)
534{
535 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[Slot].m_Tex);
536
537 if(m_vTextures[Slot].m_RescaleCount > 0)
538 {
539 for(int i = 0; i < m_vTextures[Slot].m_RescaleCount; ++i)
540 {
541 Width >>= 1;
542 Height >>= 1;
543
544 X /= 2;
545 Y /= 2;
546 }
547
548 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width, Height, NewWidth: Width, NewHeight: Height, BPP: GLFormatToPixelSize(GLFormat));
549 free(ptr: pTexData);
550 pTexData = pTmpData;
551 }
552
553 glTexSubImage2D(GL_TEXTURE_2D, level: 0, xoffset: X, yoffset: Y, width: Width, height: Height, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
554 free(ptr: pTexData);
555}
556
557void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand)
558{
559 int Slot = 0;
560 glBindTexture(GL_TEXTURE_2D, texture: 0);
561 glBindSampler(Slot, 0);
562 DestroyTexture(Slot: pCommand->m_Slot);
563}
564
565void CCommandProcessorFragment_OpenGL3_3::TextureCreate(int Slot, int Width, int Height, int GLFormat, int GLStoreFormat, int Flags, uint8_t *pTexData)
566{
567 while(Slot >= (int)m_vTextures.size())
568 m_vTextures.resize(sz: m_vTextures.size() * 2);
569
570 // resample if needed
571 int RescaleCount = 0;
572 if(GLFormat == GL_RGBA)
573 {
574 if(Width > m_MaxTexSize || Height > m_MaxTexSize)
575 {
576 do
577 {
578 Width >>= 1;
579 Height >>= 1;
580 ++RescaleCount;
581 } while(Width > m_MaxTexSize || Height > m_MaxTexSize);
582
583 uint8_t *pTmpData = ResizeImage(pImageData: pTexData, Width, Height, NewWidth: Width, NewHeight: Height, BPP: GLFormatToPixelSize(GLFormat));
584 free(ptr: pTexData);
585 pTexData = pTmpData;
586 }
587 }
588 m_vTextures[Slot].m_Width = Width;
589 m_vTextures[Slot].m_Height = Height;
590 m_vTextures[Slot].m_RescaleCount = RescaleCount;
591
592 if(GLStoreFormat == GL_RED)
593 GLStoreFormat = GL_R8;
594 const size_t PixelSize = GLFormatToPixelSize(GLFormat);
595
596 int SamplerSlot = 0;
597
598 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
599 {
600 glGenTextures(n: 1, textures: &m_vTextures[Slot].m_Tex);
601 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[Slot].m_Tex);
602
603 glGenSamplers(1, &m_vTextures[Slot].m_Sampler);
604 glBindSampler(SamplerSlot, m_vTextures[Slot].m_Sampler);
605 }
606
607 if(Flags & TextureFlag::NO_MIPMAPS)
608 {
609 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
610 {
611 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
612 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
613 glSamplerParameteri(m_vTextures[Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
614 glSamplerParameteri(m_vTextures[Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
615 glTexImage2D(GL_TEXTURE_2D, level: 0, internalformat: GLStoreFormat, width: Width, height: Height, border: 0, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
616 }
617 }
618 else
619 {
620 if((Flags & TextureFlag::NO_2D_TEXTURE) == 0)
621 {
622 glSamplerParameteri(m_vTextures[Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
623 glSamplerParameteri(m_vTextures[Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
624
625#ifndef BACKEND_AS_OPENGL_ES
626 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
627 glSamplerParameterf(m_vTextures[Slot].m_Sampler, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
628#endif
629
630 // prevent mipmap display bugs, when zooming out far
631 if(Width >= 1024 && Height >= 1024)
632 {
633 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, param: 5.f);
634 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, param: 5);
635 }
636 glTexImage2D(GL_TEXTURE_2D, level: 0, internalformat: GLStoreFormat, width: Width, height: Height, border: 0, format: GLFormat, GL_UNSIGNED_BYTE, pixels: pTexData);
637 glGenerateMipmap(GL_TEXTURE_2D);
638 }
639
640 if((Flags & TextureFlag::TO_2D_ARRAY_TEXTURE) != 0)
641 {
642 glGenTextures(n: 1, textures: &m_vTextures[Slot].m_Tex2DArray);
643 glBindTexture(GL_TEXTURE_2D_ARRAY, texture: m_vTextures[Slot].m_Tex2DArray);
644
645 glGenSamplers(1, &m_vTextures[Slot].m_Sampler2DArray);
646 glBindSampler(SamplerSlot, m_vTextures[Slot].m_Sampler2DArray);
647 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
648 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
649 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
650 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
651 glSamplerParameteri(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
652
653#ifndef BACKEND_AS_OPENGL_ES
654 if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
655 glSamplerParameterf(m_vTextures[Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
656#endif
657
658 int ConvertWidth = Width;
659 int ConvertHeight = Height;
660
661 if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0)
662 {
663 int NewWidth = maximum<int>(a: HighestBit(OfVar: ConvertWidth), b: 16);
664 int NewHeight = maximum<int>(a: HighestBit(OfVar: ConvertHeight), b: 16);
665 uint8_t *pNewTexData = ResizeImage(pImageData: pTexData, Width: ConvertWidth, Height: ConvertHeight, NewWidth, NewHeight, BPP: GLFormatToPixelSize(GLFormat));
666 log_debug("gfx/opengl", "3D/2D array texture was resized. Slot=%d Size=(%d, %d) Resized=(%d, %d)", Slot, ConvertWidth, ConvertHeight, NewWidth, NewHeight);
667
668 ConvertWidth = NewWidth;
669 ConvertHeight = NewHeight;
670
671 free(ptr: pTexData);
672 pTexData = pNewTexData;
673 }
674
675 int Image3DWidth, Image3DHeight;
676 uint8_t *pImageData3D = static_cast<uint8_t *>(malloc(size: (size_t)PixelSize * ConvertWidth * ConvertHeight));
677 Texture2DTo3D(pImageBuffer: pTexData, ImageWidth: ConvertWidth, ImageHeight: ConvertHeight, PixelSize, SplitCountWidth: 16, SplitCountHeight: 16, pTarget3DImageData: pImageData3D, Target3DImageWidth&: Image3DWidth, Target3DImageHeight&: Image3DHeight);
678 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GLStoreFormat, Image3DWidth, Image3DHeight, 256, 0, GLFormat, GL_UNSIGNED_BYTE, pImageData3D);
679 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
680 free(ptr: pImageData3D);
681 }
682 }
683
684 // This is the initial value for the wrap modes
685 m_vTextures[Slot].m_LastWrapMode = EWrapMode::REPEAT;
686
687 // calculate memory usage
688 m_vTextures[Slot].m_MemSize = (size_t)Width * Height * PixelSize;
689 while(Width > 2 && Height > 2)
690 {
691 Width >>= 1;
692 Height >>= 1;
693 m_vTextures[Slot].m_MemSize += (size_t)Width * Height * PixelSize;
694 }
695 m_pTextureMemoryUsage->store(i: m_pTextureMemoryUsage->load(m: std::memory_order_relaxed) + m_vTextures[Slot].m_MemSize, m: std::memory_order_relaxed);
696
697 free(ptr: pTexData);
698}
699
700void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
701{
702 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);
703}
704
705void CCommandProcessorFragment_OpenGL3_3::Cmd_TextTexture_Update(const CCommandBuffer::SCommand_TextTexture_Update *pCommand)
706{
707 TextureUpdate(Slot: pCommand->m_Slot, X: pCommand->m_X, Y: pCommand->m_Y, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_RED, pTexData: pCommand->m_pData);
708}
709
710void CCommandProcessorFragment_OpenGL3_3::Cmd_TextTextures_Destroy(const CCommandBuffer::SCommand_TextTextures_Destroy *pCommand)
711{
712 DestroyTexture(Slot: pCommand->m_Slot);
713 DestroyTexture(Slot: pCommand->m_SlotOutline);
714}
715
716void CCommandProcessorFragment_OpenGL3_3::Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand)
717{
718 TextureCreate(Slot: pCommand->m_Slot, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_RED, GL_RED, Flags: TextureFlag::NO_MIPMAPS, pTexData: pCommand->m_pTextData);
719 TextureCreate(Slot: pCommand->m_SlotOutline, Width: pCommand->m_Width, Height: pCommand->m_Height, GL_RED, GL_RED, Flags: TextureFlag::NO_MIPMAPS, pTexData: pCommand->m_pTextOutlineData);
720}
721
722void CCommandProcessorFragment_OpenGL3_3::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand)
723{
724 // if clip is still active, force disable it for clearing, enable it again afterwards
725 bool ClipWasEnabled = m_LastClipEnable;
726 if(ClipWasEnabled)
727 {
728 glDisable(GL_SCISSOR_TEST);
729 }
730 if(pCommand->m_Color.r != m_ClearColor.r || pCommand->m_Color.g != m_ClearColor.g || pCommand->m_Color.b != m_ClearColor.b)
731 {
732 glClearColor(red: pCommand->m_Color.r, green: pCommand->m_Color.g, blue: pCommand->m_Color.b, alpha: 0.0f);
733 m_ClearColor = pCommand->m_Color;
734 }
735 glClear(GL_COLOR_BUFFER_BIT);
736 if(ClipWasEnabled)
737 {
738 glEnable(GL_SCISSOR_TEST);
739 }
740}
741
742void CCommandProcessorFragment_OpenGL3_3::UploadStreamBufferData(EPrimitiveType PrimitiveType, const void *pVertices, size_t VertSize, unsigned int PrimitiveCount, bool AsTex3D)
743{
744 int Count = 0;
745 switch(PrimitiveType)
746 {
747 case EPrimitiveType::LINES:
748 Count = PrimitiveCount * 2;
749 break;
750 case EPrimitiveType::TRIANGLES:
751 Count = PrimitiveCount * 3;
752 break;
753 case EPrimitiveType::QUADS:
754 Count = PrimitiveCount * 4;
755 break;
756 default:
757 return;
758 };
759
760 if(AsTex3D)
761 glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferIdTex3D);
762 else
763 glBindBuffer(GL_ARRAY_BUFFER, m_aPrimitiveDrawBufferId[m_LastStreamBuffer]);
764
765 glBufferData(GL_ARRAY_BUFFER, VertSize * Count, pVertices, GL_STREAM_DRAW);
766}
767
768void CCommandProcessorFragment_OpenGL3_3::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand)
769{
770 CGLSLTWProgram *pProgram = m_pPrimitiveProgram;
771 if(IsTexturedState(State: pCommand->m_State))
772 pProgram = m_pPrimitiveProgramTextured;
773 UseProgram(pProgram);
774 SetState(State: pCommand->m_State, pProgram);
775
776 UploadStreamBufferData(PrimitiveType: pCommand->m_PrimType, pVertices: pCommand->m_pVertices, VertSize: sizeof(CCommandBuffer::SVertex), PrimitiveCount: pCommand->m_PrimCount);
777
778 glBindVertexArray(m_aPrimitiveDrawVertexId[m_LastStreamBuffer]);
779
780 switch(pCommand->m_PrimType)
781 {
782 // We don't support GL_QUADS due to core profile
783 case EPrimitiveType::LINES:
784 glDrawArrays(GL_LINES, first: 0, count: pCommand->m_PrimCount * 2);
785 break;
786 case EPrimitiveType::TRIANGLES:
787 glDrawArrays(GL_TRIANGLES, first: 0, count: pCommand->m_PrimCount * 3);
788 break;
789 case EPrimitiveType::QUADS:
790 if(m_aLastIndexBufferBound[m_LastStreamBuffer] != m_QuadDrawIndexBufferId)
791 {
792 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
793 m_aLastIndexBufferBound[m_LastStreamBuffer] = m_QuadDrawIndexBufferId;
794 }
795 glDrawElements(GL_TRIANGLES, count: pCommand->m_PrimCount * 6, GL_UNSIGNED_INT, indices: 0);
796 break;
797 default:
798 dbg_assert_failed("Invalid primitive type: %d", (int)pCommand->m_PrimType);
799 };
800
801 m_LastStreamBuffer = (m_LastStreamBuffer + 1 >= MAX_STREAM_BUFFER_COUNT ? 0 : m_LastStreamBuffer + 1);
802}
803
804void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand)
805{
806 CGLSLPrimitiveProgram *pProg = m_pPrimitive3DProgram;
807 if(IsTexturedState(State: pCommand->m_State))
808 pProg = m_pPrimitive3DProgramTextured;
809 UseProgram(pProgram: pProg);
810 SetState(State: pCommand->m_State, pProgram: pProg, Use2DArrayTextures: true);
811
812 UploadStreamBufferData(PrimitiveType: pCommand->m_PrimType, pVertices: pCommand->m_pVertices, VertSize: sizeof(CCommandBuffer::SVertexTex3DStream), PrimitiveCount: pCommand->m_PrimCount, AsTex3D: true);
813
814 glBindVertexArray(m_PrimitiveDrawVertexIdTex3D);
815
816 switch(pCommand->m_PrimType)
817 {
818 // We don't support GL_QUADS due to core profile
819 case EPrimitiveType::LINES:
820 glDrawArrays(GL_LINES, first: 0, count: pCommand->m_PrimCount * 2);
821 break;
822 case EPrimitiveType::QUADS:
823 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
824 glDrawElements(GL_TRIANGLES, count: pCommand->m_PrimCount * 6, GL_UNSIGNED_INT, indices: 0);
825 break;
826 default:
827 dbg_assert_failed("Invalid primitive type: %d", (int)pCommand->m_PrimType);
828 };
829}
830
831void CCommandProcessorFragment_OpenGL3_3::DestroyBufferContainer(int Index, bool DeleteBOs)
832{
833 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
834 if(BufferContainer.m_VertArrayId != 0)
835 glDeleteVertexArrays(1, &BufferContainer.m_VertArrayId);
836
837 // all buffer objects can deleted automatically, so the program doesn't need to deal with them (e.g. causing crashes because of driver bugs)
838 if(DeleteBOs)
839 {
840 int VertBufferId = BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex;
841 if(VertBufferId != -1)
842 {
843 glDeleteBuffers(1, &m_vBufferObjectIndices[VertBufferId]);
844 }
845 }
846
847 BufferContainer.m_LastIndexBufferBound = 0;
848 BufferContainer.m_ContainerInfo.m_vAttributes.clear();
849}
850
851void CCommandProcessorFragment_OpenGL3_3::AppendIndices(unsigned int NewIndicesCount)
852{
853 if(NewIndicesCount <= m_CurrentIndicesInBuffer)
854 return;
855 unsigned int AddCount = NewIndicesCount - m_CurrentIndicesInBuffer;
856 unsigned int *pIndices = new unsigned int[AddCount];
857 int Primq = (m_CurrentIndicesInBuffer / 6) * 4;
858 for(unsigned int i = 0; i < AddCount; i += 6)
859 {
860 pIndices[i] = Primq;
861 pIndices[i + 1] = Primq + 1;
862 pIndices[i + 2] = Primq + 2;
863 pIndices[i + 3] = Primq;
864 pIndices[i + 4] = Primq + 2;
865 pIndices[i + 5] = Primq + 3;
866 Primq += 4;
867 }
868
869 glBindBuffer(GL_COPY_READ_BUFFER, m_QuadDrawIndexBufferId);
870 GLuint NewIndexBufferId;
871 glGenBuffers(1, &NewIndexBufferId);
872 glBindBuffer(BUFFER_INIT_INDEX_TARGET, NewIndexBufferId);
873 constexpr GLsizeiptr Size = sizeof(unsigned int);
874 glBufferData(BUFFER_INIT_INDEX_TARGET, (GLsizeiptr)NewIndicesCount * Size, NULL, GL_STATIC_DRAW);
875 glCopyBufferSubData(GL_COPY_READ_BUFFER, BUFFER_INIT_INDEX_TARGET, 0, 0, (GLsizeiptr)m_CurrentIndicesInBuffer * Size);
876 glBufferSubData(BUFFER_INIT_INDEX_TARGET, (GLsizeiptr)m_CurrentIndicesInBuffer * Size, (GLsizeiptr)AddCount * Size, pIndices);
877 glBindBuffer(BUFFER_INIT_INDEX_TARGET, 0);
878 glBindBuffer(GL_COPY_READ_BUFFER, 0);
879
880 glDeleteBuffers(1, &m_QuadDrawIndexBufferId);
881 m_QuadDrawIndexBufferId = NewIndexBufferId;
882
883 std::fill(first: std::begin(arr&: m_aLastIndexBufferBound), last: std::end(arr&: m_aLastIndexBufferBound), value: 0);
884 for(auto &BufferContainer : m_vBufferContainers)
885 {
886 BufferContainer.m_LastIndexBufferBound = 0;
887 }
888
889 m_CurrentIndicesInBuffer = NewIndicesCount;
890 delete[] pIndices;
891}
892
893void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand)
894{
895 void *pUploadData = pCommand->m_pUploadData;
896 const int Index = pCommand->m_BufferIndex;
897 // create necessary space
898 if((size_t)Index >= m_vBufferObjectIndices.size())
899 {
900 m_vBufferObjectIndices.resize(sz: Index + 1, c: 0);
901 }
902
903 GLuint VertBufferId = 0;
904
905 glGenBuffers(1, &VertBufferId);
906 glBindBuffer(BUFFER_INIT_VERTEX_TARGET, VertBufferId);
907 glBufferData(BUFFER_INIT_VERTEX_TARGET, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW);
908
909 m_vBufferObjectIndices[Index] = VertBufferId;
910
911 if(pCommand->m_DeletePointer)
912 free(ptr: pUploadData);
913}
914
915void CCommandProcessorFragment_OpenGL3_3::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand)
916{
917 void *pUploadData = pCommand->m_pUploadData;
918 int Index = pCommand->m_BufferIndex;
919
920 glBindBuffer(BUFFER_INIT_VERTEX_TARGET, m_vBufferObjectIndices[Index]);
921 glBufferData(BUFFER_INIT_VERTEX_TARGET, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW);
922
923 if(pCommand->m_DeletePointer)
924 free(ptr: pUploadData);
925}
926
927void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand)
928{
929 void *pUploadData = pCommand->m_pUploadData;
930 int Index = pCommand->m_BufferIndex;
931
932 glBindBuffer(BUFFER_INIT_VERTEX_TARGET, m_vBufferObjectIndices[Index]);
933 glBufferSubData(BUFFER_INIT_VERTEX_TARGET, (GLintptr)(pCommand->m_pOffset), (GLsizeiptr)(pCommand->m_DataSize), pUploadData);
934
935 if(pCommand->m_DeletePointer)
936 free(ptr: pUploadData);
937}
938
939void CCommandProcessorFragment_OpenGL3_3::Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand)
940{
941 int WriteIndex = pCommand->m_WriteBufferIndex;
942 int ReadIndex = pCommand->m_ReadBufferIndex;
943
944 glBindBuffer(GL_COPY_WRITE_BUFFER, m_vBufferObjectIndices[WriteIndex]);
945 glBindBuffer(GL_COPY_READ_BUFFER, m_vBufferObjectIndices[ReadIndex]);
946 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_ReadOffset), (GLsizeiptr)(pCommand->m_WriteOffset), (GLsizeiptr)pCommand->m_CopySize);
947}
948
949void CCommandProcessorFragment_OpenGL3_3::Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand)
950{
951 int Index = pCommand->m_BufferIndex;
952
953 glDeleteBuffers(1, &m_vBufferObjectIndices[Index]);
954}
955
956void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand)
957{
958 const int Index = pCommand->m_BufferContainerIndex;
959 // create necessary space
960 if((size_t)Index >= m_vBufferContainers.size())
961 {
962 SBufferContainer Container;
963 Container.m_ContainerInfo.m_Stride = 0;
964 Container.m_ContainerInfo.m_VertBufferBindingIndex = -1;
965 m_vBufferContainers.resize(sz: Index + 1, c: Container);
966 }
967
968 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
969 glGenVertexArrays(1, &BufferContainer.m_VertArrayId);
970 glBindVertexArray(BufferContainer.m_VertArrayId);
971
972 BufferContainer.m_LastIndexBufferBound = 0;
973
974 for(size_t i = 0; i < pCommand->m_AttrCount; ++i)
975 {
976 glEnableVertexAttribArray((GLuint)i);
977
978 glBindBuffer(GL_ARRAY_BUFFER, m_vBufferObjectIndices[pCommand->m_VertBufferBindingIndex]);
979
980 SBufferContainerInfo::SAttribute &Attr = pCommand->m_pAttributes[i];
981
982 if(Attr.m_FuncType == 0)
983 glVertexAttribPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, (GLboolean)Attr.m_Normalized, pCommand->m_Stride, Attr.m_pOffset);
984 else if(Attr.m_FuncType == 1)
985 glVertexAttribIPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, pCommand->m_Stride, Attr.m_pOffset);
986
987 BufferContainer.m_ContainerInfo.m_vAttributes.push_back(x: Attr);
988 }
989
990 BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
991 BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
992}
993
994void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand)
995{
996 SBufferContainer &BufferContainer = m_vBufferContainers[pCommand->m_BufferContainerIndex];
997
998 glBindVertexArray(BufferContainer.m_VertArrayId);
999
1000 // disable all old attributes
1001 for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_vAttributes.size(); ++i)
1002 {
1003 glDisableVertexAttribArray((GLuint)i);
1004 }
1005 BufferContainer.m_ContainerInfo.m_vAttributes.clear();
1006
1007 for(size_t i = 0; i < pCommand->m_AttrCount; ++i)
1008 {
1009 glEnableVertexAttribArray((GLuint)i);
1010
1011 glBindBuffer(GL_ARRAY_BUFFER, m_vBufferObjectIndices[pCommand->m_VertBufferBindingIndex]);
1012 SBufferContainerInfo::SAttribute &Attr = pCommand->m_pAttributes[i];
1013 if(Attr.m_FuncType == 0)
1014 glVertexAttribPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, Attr.m_Normalized, pCommand->m_Stride, Attr.m_pOffset);
1015 else if(Attr.m_FuncType == 1)
1016 glVertexAttribIPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, pCommand->m_Stride, Attr.m_pOffset);
1017
1018 BufferContainer.m_ContainerInfo.m_vAttributes.push_back(x: Attr);
1019 }
1020
1021 BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
1022 BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
1023}
1024
1025void CCommandProcessorFragment_OpenGL3_3::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand)
1026{
1027 DestroyBufferContainer(Index: pCommand->m_BufferContainerIndex, DeleteBOs: pCommand->m_DestroyAllBO);
1028}
1029
1030void CCommandProcessorFragment_OpenGL3_3::Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand)
1031{
1032 if(pCommand->m_RequiredIndicesNum > m_CurrentIndicesInBuffer)
1033 AppendIndices(NewIndicesCount: pCommand->m_RequiredIndicesNum);
1034}
1035
1036void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand)
1037{
1038 int Index = pCommand->m_BufferContainerIndex;
1039 // if space not there return
1040 if((size_t)Index >= m_vBufferContainers.size())
1041 return;
1042
1043 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1044 if(BufferContainer.m_VertArrayId == 0)
1045 return;
1046
1047 CGLSLTileProgram *pProgram = NULL;
1048 if(IsTexturedState(State: pCommand->m_State))
1049 pProgram = m_pBorderTileProgramTextured;
1050 else
1051 pProgram = m_pBorderTileProgram;
1052 UseProgram(pProgram);
1053
1054 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
1055 pProgram->SetUniformVec4(Loc: pProgram->m_LocColor, Count: 1, pValue: (float *)&pCommand->m_Color);
1056
1057 pProgram->SetUniformVec2(Loc: pProgram->m_LocOffset, Count: 1, pValue: (float *)&pCommand->m_Offset);
1058 pProgram->SetUniformVec2(Loc: pProgram->m_LocScale, Count: 1, pValue: (float *)&pCommand->m_Scale);
1059
1060 glBindVertexArray(BufferContainer.m_VertArrayId);
1061 if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferId)
1062 {
1063 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
1064 BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferId;
1065 }
1066 glDrawElements(GL_TRIANGLES, count: pCommand->m_DrawNum * 6, GL_UNSIGNED_INT, indices: pCommand->m_pIndicesOffset);
1067}
1068
1069void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand)
1070{
1071 int Index = pCommand->m_BufferContainerIndex;
1072 // if space not there return
1073 if((size_t)Index >= m_vBufferContainers.size())
1074 return;
1075
1076 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1077 if(BufferContainer.m_VertArrayId == 0)
1078 return;
1079
1080 if(pCommand->m_IndicesDrawNum == 0)
1081 {
1082 return; // nothing to draw
1083 }
1084
1085 CGLSLTileProgram *pProgram = NULL;
1086 if(IsTexturedState(State: pCommand->m_State))
1087 {
1088 pProgram = m_pTileProgramTextured;
1089 }
1090 else
1091 pProgram = m_pTileProgram;
1092
1093 UseProgram(pProgram);
1094
1095 SetState(State: pCommand->m_State, pProgram, Use2DArrayTextures: true);
1096 pProgram->SetUniformVec4(Loc: pProgram->m_LocColor, Count: 1, pValue: (float *)&pCommand->m_Color);
1097
1098 glBindVertexArray(BufferContainer.m_VertArrayId);
1099 if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferId)
1100 {
1101 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
1102 BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferId;
1103 }
1104 for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i)
1105 {
1106 glDrawElements(GL_TRIANGLES, count: pCommand->m_pDrawCount[i], GL_UNSIGNED_INT, indices: pCommand->m_pIndicesOffsets[i]);
1107 }
1108}
1109
1110void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand, bool Grouped)
1111{
1112 int Index = pCommand->m_BufferContainerIndex;
1113 // if space not there return
1114 if((size_t)Index >= m_vBufferContainers.size())
1115 return;
1116
1117 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1118 if(BufferContainer.m_VertArrayId == 0)
1119 return;
1120
1121 if(pCommand->m_QuadNum == 0)
1122 {
1123 return; // nothing to draw
1124 }
1125
1126 CGLSLQuadProgram *pProgram = NULL;
1127 if(Grouped)
1128 {
1129 if(IsTexturedState(State: pCommand->m_State))
1130 {
1131 pProgram = m_pQuadProgramTexturedGrouped;
1132 }
1133 else
1134 pProgram = m_pQuadProgramGrouped;
1135 }
1136 else
1137 {
1138 if(IsTexturedState(State: pCommand->m_State))
1139 {
1140 pProgram = m_pQuadProgramTextured;
1141 }
1142 else
1143 pProgram = m_pQuadProgram;
1144 }
1145
1146 UseProgram(pProgram);
1147 SetState(State: pCommand->m_State, pProgram);
1148
1149 glBindVertexArray(BufferContainer.m_VertArrayId);
1150 if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferId)
1151 {
1152 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
1153 BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferId;
1154 }
1155
1156 int QuadsLeft = pCommand->m_QuadNum;
1157 size_t QuadOffset = 0;
1158 // the extra offset is not related to the information from the command, but an actual offset in the buffer
1159 size_t QuadOffsetExtra = pCommand->m_QuadOffset;
1160
1161 if(!Grouped)
1162 {
1163 ColorRGBA aColors[ms_MaxQuadsPossible];
1164 vec2 aOffsets[ms_MaxQuadsPossible];
1165 float aRotations[ms_MaxQuadsPossible];
1166
1167 while(QuadsLeft > 0)
1168 {
1169 int ActualQuadCount = minimum<int>(a: QuadsLeft, b: m_MaxQuadsAtOnce);
1170 for(size_t i = 0; i < (size_t)ActualQuadCount; ++i)
1171 {
1172 aColors[i] = pCommand->m_pQuadInfo[i + QuadOffset].m_Color;
1173 aOffsets[i] = pCommand->m_pQuadInfo[i + QuadOffset].m_Offsets;
1174 aRotations[i] = pCommand->m_pQuadInfo[i + QuadOffset].m_Rotation;
1175 }
1176
1177 pProgram->SetUniformVec4(Loc: pProgram->m_LocColors, Count: ActualQuadCount, pValue: (float *)aColors);
1178 pProgram->SetUniformVec2(Loc: pProgram->m_LocOffsets, Count: ActualQuadCount, pValue: (float *)aOffsets);
1179 pProgram->SetUniform(Loc: pProgram->m_LocRotations, Count: ActualQuadCount, pValues: (float *)aRotations);
1180 pProgram->SetUniform(Loc: pProgram->m_LocQuadOffset, Value: (int)(QuadOffset + QuadOffsetExtra));
1181 glDrawElements(GL_TRIANGLES, count: ActualQuadCount * 6, GL_UNSIGNED_INT, indices: (void *)((QuadOffset + QuadOffsetExtra) * 6 * sizeof(unsigned int)));
1182
1183 QuadsLeft -= ActualQuadCount;
1184 QuadOffset += (size_t)ActualQuadCount;
1185 }
1186 }
1187 else
1188 {
1189 ColorRGBA Colors = pCommand->m_pQuadInfo[0].m_Color;
1190 vec2 Offsets = pCommand->m_pQuadInfo[0].m_Offsets;
1191 float Rotations = pCommand->m_pQuadInfo[0].m_Rotation;
1192
1193 pProgram->SetUniformVec4(Loc: pProgram->m_LocColors, Count: 1, pValue: (float *)(&Colors));
1194 pProgram->SetUniformVec2(Loc: pProgram->m_LocOffsets, Count: 1, pValue: (float *)(&Offsets));
1195 pProgram->SetUniform(Loc: pProgram->m_LocRotations, Count: 1, pValues: &Rotations);
1196 glDrawElements(GL_TRIANGLES, count: QuadsLeft * 6, GL_UNSIGNED_INT, indices: (void *)((QuadOffset + QuadOffsetExtra) * 6 * sizeof(unsigned int)));
1197 }
1198}
1199
1200void CCommandProcessorFragment_OpenGL3_3::RenderText(const CCommandBuffer::SState &State, int DrawNum, int TextTextureIndex, int TextOutlineTextureIndex, int TextureSize, const ColorRGBA &TextColor, const ColorRGBA &TextOutlineColor)
1201{
1202 if(DrawNum == 0)
1203 {
1204 return; // nothing to draw
1205 }
1206
1207 UseProgram(pProgram: m_pTextProgram);
1208
1209 int SlotText = 0;
1210 int SlotTextOutline = 1;
1211 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[TextTextureIndex].m_Tex);
1212 glBindSampler(SlotText, m_vTextures[TextTextureIndex].m_Sampler);
1213 glActiveTexture(GL_TEXTURE1);
1214 glBindTexture(GL_TEXTURE_2D, texture: m_vTextures[TextOutlineTextureIndex].m_Tex);
1215 glBindSampler(SlotTextOutline, m_vTextures[TextOutlineTextureIndex].m_Sampler);
1216 glActiveTexture(GL_TEXTURE0);
1217
1218 if(m_pTextProgram->m_LastTextSampler != SlotText)
1219 {
1220 m_pTextProgram->SetUniform(Loc: m_pTextProgram->m_LocTextSampler, Value: SlotText);
1221 m_pTextProgram->m_LastTextSampler = SlotText;
1222 }
1223
1224 if(m_pTextProgram->m_LastTextOutlineSampler != SlotTextOutline)
1225 {
1226 m_pTextProgram->SetUniform(Loc: m_pTextProgram->m_LocTextOutlineSampler, Value: SlotTextOutline);
1227 m_pTextProgram->m_LastTextOutlineSampler = SlotTextOutline;
1228 }
1229
1230 SetState(State, pProgram: m_pTextProgram);
1231
1232 if(m_pTextProgram->m_LastTextureSize != TextureSize)
1233 {
1234 m_pTextProgram->SetUniform(Loc: m_pTextProgram->m_LocTextureSize, Value: (float)TextureSize);
1235 m_pTextProgram->m_LastTextureSize = TextureSize;
1236 }
1237
1238 if(m_pTextProgram->m_LastOutlineColor != TextOutlineColor)
1239 {
1240 m_pTextProgram->SetUniformVec4(Loc: m_pTextProgram->m_LocOutlineColor, Count: 1, pValue: (float *)&TextOutlineColor);
1241 m_pTextProgram->m_LastOutlineColor = TextOutlineColor;
1242 }
1243
1244 if(m_pTextProgram->m_LastColor != TextColor)
1245 {
1246 m_pTextProgram->SetUniformVec4(Loc: m_pTextProgram->m_LocColor, Count: 1, pValue: (float *)&TextColor);
1247 m_pTextProgram->m_LastColor = TextColor;
1248 }
1249
1250 glDrawElements(GL_TRIANGLES, count: DrawNum, GL_UNSIGNED_INT, indices: (void *)(0));
1251}
1252
1253void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand)
1254{
1255 int Index = pCommand->m_BufferContainerIndex;
1256 // if space not there return
1257 if((size_t)Index >= m_vBufferContainers.size())
1258 return;
1259
1260 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1261 if(BufferContainer.m_VertArrayId == 0)
1262 return;
1263
1264 glBindVertexArray(BufferContainer.m_VertArrayId);
1265 if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferId)
1266 {
1267 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
1268 BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferId;
1269 }
1270
1271 RenderText(State: pCommand->m_State, DrawNum: pCommand->m_DrawNum, TextTextureIndex: pCommand->m_TextTextureIndex, TextOutlineTextureIndex: pCommand->m_TextOutlineTextureIndex, TextureSize: pCommand->m_TextureSize, TextColor: pCommand->m_TextColor, TextOutlineColor: pCommand->m_TextOutlineColor);
1272}
1273
1274void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand)
1275{
1276 if(pCommand->m_DrawNum == 0)
1277 {
1278 return; // nothing to draw
1279 }
1280
1281 int Index = pCommand->m_BufferContainerIndex;
1282 // if space not there return
1283 if((size_t)Index >= m_vBufferContainers.size())
1284 return;
1285
1286 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1287 if(BufferContainer.m_VertArrayId == 0)
1288 return;
1289
1290 glBindVertexArray(BufferContainer.m_VertArrayId);
1291 if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferId)
1292 {
1293 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
1294 BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferId;
1295 }
1296
1297 CGLSLTWProgram *pProgram = m_pPrimitiveProgram;
1298 if(IsTexturedState(State: pCommand->m_State))
1299 pProgram = m_pPrimitiveProgramTextured;
1300 UseProgram(pProgram);
1301 SetState(State: pCommand->m_State, pProgram);
1302
1303 glDrawElements(GL_TRIANGLES, count: pCommand->m_DrawNum, GL_UNSIGNED_INT, indices: pCommand->m_pOffset);
1304}
1305
1306void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerEx(const CCommandBuffer::SCommand_RenderQuadContainerEx *pCommand)
1307{
1308 if(pCommand->m_DrawNum == 0)
1309 {
1310 return; // nothing to draw
1311 }
1312
1313 int Index = pCommand->m_BufferContainerIndex;
1314 // if space not there return
1315 if((size_t)Index >= m_vBufferContainers.size())
1316 return;
1317
1318 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1319 if(BufferContainer.m_VertArrayId == 0)
1320 return;
1321
1322 glBindVertexArray(BufferContainer.m_VertArrayId);
1323 if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferId)
1324 {
1325 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
1326 BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferId;
1327 }
1328
1329 CGLSLPrimitiveExProgram *pProgram = m_pPrimitiveExProgramRotationless;
1330 if(IsTexturedState(State: pCommand->m_State))
1331 {
1332 if(pCommand->m_Rotation != 0.0f)
1333 pProgram = m_pPrimitiveExProgramTextured;
1334 else
1335 pProgram = m_pPrimitiveExProgramTexturedRotationless;
1336 }
1337 else
1338 {
1339 if(pCommand->m_Rotation != 0.0f)
1340 pProgram = m_pPrimitiveExProgram;
1341 }
1342
1343 UseProgram(pProgram);
1344 SetState(State: pCommand->m_State, pProgram);
1345
1346 if(pCommand->m_Rotation != 0.0f && pProgram->m_LastCenter != pCommand->m_Center)
1347 {
1348 pProgram->SetUniformVec2(Loc: pProgram->m_LocCenter, Count: 1, pValue: (float *)&pCommand->m_Center);
1349 pProgram->m_LastCenter = pCommand->m_Center;
1350 }
1351
1352 if(pProgram->m_LastRotation != pCommand->m_Rotation)
1353 {
1354 pProgram->SetUniform(Loc: pProgram->m_LocRotation, Value: pCommand->m_Rotation);
1355 pProgram->m_LastRotation = pCommand->m_Rotation;
1356 }
1357
1358 if(pProgram->m_LastVerticesColor != pCommand->m_VertexColor)
1359 {
1360 pProgram->SetUniformVec4(Loc: pProgram->m_LocVertciesColor, Count: 1, pValue: (float *)&pCommand->m_VertexColor);
1361 pProgram->m_LastVerticesColor = pCommand->m_VertexColor;
1362 }
1363
1364 glDrawElements(GL_TRIANGLES, count: pCommand->m_DrawNum, GL_UNSIGNED_INT, indices: pCommand->m_pOffset);
1365}
1366
1367void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand)
1368{
1369 if(pCommand->m_DrawNum == 0 || pCommand->m_DrawCount == 0)
1370 {
1371 return; // nothing to draw
1372 }
1373
1374 int Index = pCommand->m_BufferContainerIndex;
1375 // if space not there return
1376 if((size_t)Index >= m_vBufferContainers.size())
1377 return;
1378
1379 SBufferContainer &BufferContainer = m_vBufferContainers[Index];
1380 if(BufferContainer.m_VertArrayId == 0)
1381 return;
1382
1383 glBindVertexArray(BufferContainer.m_VertArrayId);
1384 if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferId)
1385 {
1386 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferId);
1387 BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferId;
1388 }
1389
1390 UseProgram(pProgram: m_pSpriteProgramMultiple);
1391 SetState(State: pCommand->m_State, pProgram: m_pSpriteProgramMultiple);
1392
1393 if(m_pSpriteProgramMultiple->m_LastCenter != pCommand->m_Center)
1394 {
1395 m_pSpriteProgramMultiple->SetUniformVec2(Loc: m_pSpriteProgramMultiple->m_LocCenter, Count: 1, pValue: (float *)&pCommand->m_Center);
1396 m_pSpriteProgramMultiple->m_LastCenter = pCommand->m_Center;
1397 }
1398
1399 if(m_pSpriteProgramMultiple->m_LastVerticesColor != pCommand->m_VertexColor)
1400 {
1401 m_pSpriteProgramMultiple->SetUniformVec4(Loc: m_pSpriteProgramMultiple->m_LocVertciesColor, Count: 1, pValue: (float *)&pCommand->m_VertexColor);
1402 m_pSpriteProgramMultiple->m_LastVerticesColor = pCommand->m_VertexColor;
1403 }
1404
1405 int DrawCount = pCommand->m_DrawCount;
1406 size_t RenderOffset = 0;
1407
1408 // 4 for the center (always use vec4) and 16 for the matrix(just to be sure), 4 for the sampler and vertex color
1409 const int RSPCount = 256 - 4 - 16 - 8;
1410
1411 while(DrawCount > 0)
1412 {
1413 int UniformCount = (DrawCount > RSPCount ? RSPCount : DrawCount);
1414
1415 m_pSpriteProgramMultiple->SetUniformVec4(Loc: m_pSpriteProgramMultiple->m_LocRSP, Count: UniformCount, pValue: (float *)(pCommand->m_pRenderInfo + RenderOffset));
1416
1417 glDrawElementsInstanced(GL_TRIANGLES, pCommand->m_DrawNum, GL_UNSIGNED_INT, pCommand->m_pOffset, UniformCount);
1418
1419 RenderOffset += RSPCount;
1420 DrawCount -= RSPCount;
1421 }
1422}
1423
1424#endif
1425