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