OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4DrawGL.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 
17 /* OpenGL implementation of NewGfx */
18 
19 #include "C4Include.h"
21 #include "graphics/C4DrawGL.h"
22 
23 #include "game/C4Application.h"
24 #include "graphics/C4Surface.h"
26 #include "lib/C4Rect.h"
27 #include "lib/StdColors.h"
28 #include "platform/C4Window.h"
29 
30 #ifndef USE_CONSOLE
31 
32 namespace
33 {
34  const char *MsgSourceToStr(GLenum source)
35  {
36  switch (source)
37  {
38  case GL_DEBUG_SOURCE_API_ARB: return "API";
39  case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: return "window system";
40  case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: return "shader compiler";
41  case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: return "third party";
42  case GL_DEBUG_SOURCE_APPLICATION_ARB: return "application";
43  case GL_DEBUG_SOURCE_OTHER_ARB: return "other";
44  default: return "<unknown>";
45  }
46  }
47 
48  const char *MsgTypeToStr(GLenum type)
49  {
50  switch (type)
51  {
52  case GL_DEBUG_TYPE_ERROR_ARB: return "error";
53  case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: return "deprecation warning";
54  case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: return "undefined behavior warning";
55  case GL_DEBUG_TYPE_PORTABILITY_ARB: return "portability warning";
56  case GL_DEBUG_TYPE_PERFORMANCE_ARB: return "performance warning";
57  case GL_DEBUG_TYPE_OTHER_ARB: return "other message";
58  default: return "unknown message";
59  }
60  }
61 
62  const char *MsgSeverityToStr(GLenum severity)
63  {
64  switch (severity)
65  {
66  case GL_DEBUG_SEVERITY_HIGH_ARB: return "high";
67  case GL_DEBUG_SEVERITY_MEDIUM_ARB: return "medium";
68  case GL_DEBUG_SEVERITY_LOW_ARB: return "low";
69 #ifdef GL_DEBUG_SEVERITY_NOTIFICATION
70  case GL_DEBUG_SEVERITY_NOTIFICATION: return "notification";
71 #endif
72  default: return "<unknown>";
73  }
74  }
75 
76 #ifdef GLDEBUGPROCARB_USERPARAM_IS_CONST
77 #define USERPARAM_CONST const
78 #else
79 #define USERPARAM_CONST
80 #endif
81 
82  void GLAPIENTRY OpenGLDebugProc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, USERPARAM_CONST void* userParam)
83  {
84  const char *msg_source = MsgSourceToStr(source);
85  const char *msg_type = MsgTypeToStr(type);
86  const char *msg_severity = MsgSeverityToStr(severity);
87 
88  LogSilentF(" gl: %s severity %s %s: %s", msg_severity, msg_source, msg_type, message);
89 #ifdef USE_WIN32_WINDOWS
90  if (IsDebuggerPresent() && severity == GL_DEBUG_SEVERITY_HIGH_ARB)
92 #endif
93  }
94 }
95 
96 #undef USERPARAM_CONST
97 
99  NextVAOID(VAOIDs.end())
100 {
101  GenericVBOs[0] = 0;
102  Default();
103  // global ptr
104  pGL = this;
105  lines_tex = 0;
106 }
107 
109 {
110  Clear();
111  pGL=nullptr;
112 }
113 
115 {
117  // cannot unlock TexMgr here or we can't preserve textures across GL reinitialization as required when changing multisampling
120  RenderTarget = nullptr;
121  // Clear all shaders
138  // clear context
139  if (pCurrCtx) pCurrCtx->Deselect();
140  pMainCtx=nullptr;
141  C4Draw::Clear();
142 }
143 
145 {
146  if (!pCurrCtx) return;
147  glClearColor((float)GetRedValue(dwClr)/255.0f, (float)GetGreenValue(dwClr)/255.0f, (float)GetBlueValue(dwClr)/255.0f, 0.0f);
148  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
149 }
150 
152 {
153  // no render target? do nothing
154  if (!RenderTarget || !Active) return true;
155  // negative/zero?
156  C4Rect clipRect = GetClipRect();
157  if (clipRect.Wdt<=0 || clipRect.Hgt<=0)
158  {
159  ClipAll=true;
160  return true;
161  }
162  ClipAll=false;
163  // set it
164  glViewport(clipRect.x, RenderTarget->Hgt-clipRect.y-clipRect.Hgt, clipRect.Wdt, clipRect.Hgt);
165  ProjectionMatrix = StdProjectionMatrix::Orthographic(clipRect.x, clipRect.x + clipRect.Wdt, clipRect.y + clipRect.Hgt, clipRect.y);
166  return true;
167 }
168 
170 {
171  // call from gfx thread only!
172  if (!pApp || !pApp->AssertMainThread()) return false;
173  // not ready?
174  if (!Active)
175  return false;
176  // target?
177  if (!sfcToSurface) return false;
178  // target locked?
179  if (sfcToSurface->Locked) return false;
180  // target is already set as render target?
181  if (sfcToSurface != RenderTarget)
182  {
183  // target is a render-target?
184  if (!sfcToSurface->IsRenderTarget()) return false;
185  // context
186  if (sfcToSurface->pCtx && sfcToSurface->pCtx != pCurrCtx)
187  if (!sfcToSurface->pCtx->Select()) return false;
188  // set target
189  RenderTarget=sfcToSurface;
190  // new target has different size; needs other clipping rect
191  UpdateClipper();
192  }
193  // done
194  return true;
195 }
196 
197 
198 bool CStdGL::PrepareSpriteShader(C4Shader& shader, const char* name, int ssc, C4GroupSet* pGroups, const char* const* additionalDefines, const char* const* additionalSlices)
199 {
200  const char* uniformNames[C4SSU_Count + 1];
201  uniformNames[C4SSU_ProjectionMatrix] = "projectionMatrix";
202  uniformNames[C4SSU_ModelViewMatrix] = "modelviewMatrix";
203  uniformNames[C4SSU_NormalMatrix] = "normalMatrix";
204  uniformNames[C4SSU_ClrMod] = "clrMod";
205  uniformNames[C4SSU_Gamma] = "gamma";
206  uniformNames[C4SSU_BaseTex] = "baseTex";
207  uniformNames[C4SSU_OverlayTex] = "overlayTex";
208  uniformNames[C4SSU_OverlayClr] = "overlayClr";
209  uniformNames[C4SSU_LightTex] = "lightTex";
210  uniformNames[C4SSU_LightTransform] = "lightTransform";
211  uniformNames[C4SSU_NormalTex] = "normalTex";
212  uniformNames[C4SSU_AmbientTex] = "ambientTex";
213  uniformNames[C4SSU_AmbientTransform] = "ambientTransform";
214  uniformNames[C4SSU_AmbientBrightness] = "ambientBrightness";
215  uniformNames[C4SSU_MaterialAmbient] = "materialAmbient"; // unused
216  uniformNames[C4SSU_MaterialDiffuse] = "materialDiffuse"; // unused
217  uniformNames[C4SSU_MaterialSpecular] = "materialSpecular"; // unused
218  uniformNames[C4SSU_MaterialEmission] = "materialEmission"; // unused
219  uniformNames[C4SSU_MaterialShininess] = "materialShininess"; // unused
220  uniformNames[C4SSU_Bones] = "bones"; // unused
221  uniformNames[C4SSU_CullMode] = "cullMode"; // unused
222  uniformNames[C4SSU_FrameCounter] = "frameCounter";
223  uniformNames[C4SSU_Count] = nullptr;
224 
225  const char* attributeNames[C4SSA_Count + 1];
226  attributeNames[C4SSA_Position] = "oc_Position";
227  attributeNames[C4SSA_Normal] = "oc_Normal"; // unused
228  attributeNames[C4SSA_TexCoord] = "oc_TexCoord"; // only used if C4SSC_Base is set
229  attributeNames[C4SSA_Color] = "oc_Color";
230  attributeNames[C4SSA_BoneIndices0] = "oc_BoneIndices0"; // unused
231  attributeNames[C4SSA_BoneIndices1] = "oc_BoneIndices1"; // unused
232  attributeNames[C4SSA_BoneWeights0] = "oc_BoneWeights0"; // unused
233  attributeNames[C4SSA_BoneWeights1] = "oc_BoneWeights1"; // unused
234  attributeNames[C4SSA_Count] = nullptr;
235 
236  // Clear previous content
237  shader.Clear();
238  shader.ClearSlices();
239 
240  // Start with #defines
241  shader.AddDefine("OPENCLONK");
242  shader.AddDefine("OC_SPRITE");
243  if (ssc & C4SSC_MOD2) shader.AddDefine("OC_CLRMOD_MOD2");
244  if (ssc & C4SSC_NORMAL) shader.AddDefine("OC_WITH_NORMALMAP");
245  if (ssc & C4SSC_LIGHT) shader.AddDefine("OC_DYNAMIC_LIGHT");
246  if (ssc & C4SSC_BASE) shader.AddDefine("OC_HAVE_BASE");
247  if (ssc & C4SSC_OVERLAY) shader.AddDefine("OC_HAVE_OVERLAY");
248 
249  if (additionalDefines)
250  for (const char* const* define = additionalDefines; *define != nullptr; ++define)
251  shader.AddDefine(*define);
252 
253  // Then load slices for fragment and vertex shader
254  shader.LoadVertexSlices(pGroups, "SpriteVertexShader.glsl");
255  shader.LoadFragmentSlices(pGroups, "CommonShader.glsl");
256  shader.LoadFragmentSlices(pGroups, "ObjectShader.glsl");
257 
258  // Categories for script shaders.
259  shader.SetScriptCategories({"Common", "Object"});
260 
261  if (additionalSlices)
262  for (const char* const* slice = additionalSlices; *slice != nullptr; ++slice)
263  shader.LoadFragmentSlices(pGroups, *slice);
264 
265  if (!shader.Init(name, uniformNames, attributeNames))
266  {
267  shader.ClearSlices();
268  return false;
269  }
270 
271  return true;
272 }
273 
274 void CStdGL::ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char * label)
275 {
276 #ifdef GL_KHR_debug
277  if (glObjectLabel)
278  glObjectLabel(identifier, name, length, label);
279 #endif
280 }
281 
283 {
284  // safety
285  if (!pWindow) return nullptr;
286 
287  // create it
288  CStdGLCtx *pCtx;
289 #ifdef WITH_QT_EDITOR
290  auto app = dynamic_cast<C4Application*>(pApp);
291  if (app->isEditor)
292  pCtx = new CStdGLCtxQt();
293  else
294 #endif
295  pCtx = new CStdGLCtx();
296  bool first_ctx = !pMainCtx;
297  if (first_ctx)
298  {
299  pMainCtx = pCtx;
300  LogF(" gl: Create first %scontext...", Config.Graphics.DebugOpenGL ? "debug " : "");
301  }
302  bool success = pCtx->Init(pWindow, pApp);
303  if (Config.Graphics.DebugOpenGL && glDebugMessageCallbackARB)
304  {
305  if (first_ctx) Log(" gl: Setting OpenGLDebugProc callback");
306  glDebugMessageCallbackARB(&OpenGLDebugProc, nullptr);
307  glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
308 #ifdef GL_KHR_debug
309  if (GLEW_KHR_debug)
310  glEnable(GL_DEBUG_OUTPUT);
311 #endif
312  }
313  // First context: Log some information about hardware/drivers
314  // Must log after context creation to get valid results
315  if (first_ctx)
316  {
317  const auto *gl_vendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
318  const auto *gl_renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
319  const auto *gl_version = reinterpret_cast<const char *>(glGetString(GL_VERSION));
320  LogF("GL %s on %s (%s)", gl_version ? gl_version : "", gl_renderer ? gl_renderer : "", gl_vendor ? gl_vendor : "");
321 
323  {
324  // Dump extension list
325  if (glGetStringi)
326  {
327  GLint gl_extension_count = 0;
328  glGetIntegerv(GL_NUM_EXTENSIONS, &gl_extension_count);
329  if (gl_extension_count == 0)
330  {
331  LogSilentF("No available extensions.");
332  }
333  else
334  {
335  LogSilentF("%d available extensions:", gl_extension_count);
336  for (GLint i = 0; i < gl_extension_count; ++i)
337  {
338  const char *gl_extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
339  LogSilentF(" %4d: %s", i, gl_extension);
340  }
341  }
342  }
343  else
344  {
345  const char *gl_extensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
346  LogSilentF("GLExt: %s", gl_extensions ? gl_extensions : "");
347  }
348  }
349  }
350  if (!success)
351  {
352  delete pCtx; Error(" gl: Error creating secondary context!"); return nullptr;
353  }
354  // creation selected the new context - switch back to previous context
355  RenderTarget = nullptr;
356  pCurrCtx = nullptr;
357  // done
358  return pCtx;
359 }
360 
361 void CStdGL::SetupMultiBlt(C4ShaderCall& call, const C4BltTransform* pTransform, GLuint baseTex, GLuint overlayTex, GLuint normalTex, DWORD dwOverlayModClr, StdProjectionMatrix* out_modelview)
362 {
363  // Initialize multi blit shader.
364  int iAdditive = dwBlitMode & C4GFXBLIT_ADDITIVE;
365  glBlendFunc(GL_SRC_ALPHA, iAdditive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
366 
367  call.Start();
368 
369  // Upload uniforms
370  const DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff;
371  const float fMod[4] = {
372  ((dwModClr >> 16) & 0xff) / 255.0f,
373  ((dwModClr >> 8) & 0xff) / 255.0f,
374  ((dwModClr ) & 0xff) / 255.0f,
375  ((dwModClr >> 24) & 0xff) / 255.0f
376  };
377 
378  call.SetUniform4fv(C4SSU_ClrMod, 1, fMod);
380 
381  if(baseTex != 0)
382  {
384  glBindTexture(GL_TEXTURE_2D, baseTex);
385  }
386 
387  if(overlayTex != 0)
388  {
390  glBindTexture(GL_TEXTURE_2D, overlayTex);
391 
392  const float fOverlayModClr[4] = {
393  ((dwOverlayModClr >> 16) & 0xff) / 255.0f,
394  ((dwOverlayModClr >> 8) & 0xff) / 255.0f,
395  ((dwOverlayModClr ) & 0xff) / 255.0f,
396  ((dwOverlayModClr >> 24) & 0xff) / 255.0f
397  };
398 
399  call.SetUniform4fv(C4SSU_OverlayClr, 1, fOverlayModClr);
400  }
401 
402  if(pFoW != nullptr && normalTex != 0)
403  {
405  glBindTexture(GL_TEXTURE_2D, normalTex);
406  }
407 
408  if(pFoW != nullptr)
409  {
410  const C4Rect OutRect = GetOutRect();
411  const C4Rect ClipRect = GetClipRect();
412  const FLOAT_RECT vpRect = pFoW->getViewportRegion();
413 
414  // Dynamic Light
416  glBindTexture(GL_TEXTURE_2D, pFoW->getSurfaceName());
417 
418  float lightTransform[6];
419  pFoW->GetFragTransform(ClipRect, OutRect, lightTransform);
420  call.SetUniformMatrix2x3fv(C4SSU_LightTransform, 1, lightTransform);
421 
422  // Ambient Light
424  glBindTexture(GL_TEXTURE_2D, pFoW->getFoW()->Ambient.Tex);
426 
427  float ambientTransform[6];
428  pFoW->getFoW()->Ambient.GetFragTransform(vpRect, ClipRect, OutRect, ambientTransform);
429  call.SetUniformMatrix2x3fv(C4SSU_AmbientTransform, 1, ambientTransform);
430  }
431 
432  call.SetUniform1f(C4SSU_CullMode, 0.0f);
433 
434  // The primary reason we use a 4x4 matrix for the modelview matrix is that
435  // that the C4BltTransform pTransform parameter can have projection components
436  // (see SetObjDrawTransform2). Still, for sprites the situation is a bit
437  // unsatisfactory because there's no distinction between modelview and projection
438  // components in the BltTransform. Object rotation is part of the BltTransform
439  // for sprites, which should be part of the modelview matrix, so that lighting
440  // is correct for rotated sprites. This is much more common than projection
441  // components in the BltTransform, and therefore we turn the BltTransform into
442  // the modelview matrix and not the projection matrix.
443  StdProjectionMatrix default_modelview = StdProjectionMatrix::Identity();
444  StdProjectionMatrix& modelview = out_modelview ? *out_modelview : default_modelview;
445 
446  // Apply zoom and transform
447  Translate(modelview, ZoomX, ZoomY, 0.0f);
448  // Scale Z as well so that we don't distort normals.
449  Scale(modelview, Zoom, Zoom, Zoom);
450  Translate(modelview, -ZoomX, -ZoomY, 0.0f);
451 
452  if(pTransform)
453  {
454  float sz = 1.0f;
455  if (pFoW != nullptr && normalTex != 0)
456  {
457  // Decompose scale factors and scale Z accordingly to X and Y, again to avoid distorting normals
458  // We could instead work around this by using the projection matrix, but then for object rotations (SetR)
459  // the normals would not be correct.
460  const float sx = sqrt(pTransform->mat[0]*pTransform->mat[0] + pTransform->mat[1]*pTransform->mat[1]);
461  const float sy = sqrt(pTransform->mat[3]*pTransform->mat[3] + pTransform->mat[4]*pTransform->mat[4]);
462  sz = sqrt(sx * sy);
463  }
464 
465  // Multiply modelview matrix with transform
466  StdProjectionMatrix transform;
467  transform(0, 0) = pTransform->mat[0];
468  transform(0, 1) = pTransform->mat[1];
469  transform(0, 2) = 0.0f;
470  transform(0, 3) = pTransform->mat[2];
471  transform(1, 0) = pTransform->mat[3];
472  transform(1, 1) = pTransform->mat[4];
473  transform(1, 2) = 0.0f;
474  transform(1, 3) = pTransform->mat[5];
475  transform(2, 0) = 0.0f;
476  transform(2, 1) = 0.0f;
477  transform(2, 2) = sz;
478  transform(2, 3) = 0.0f;
479  transform(3, 0) = pTransform->mat[6];
480  transform(3, 1) = pTransform->mat[7];
481  transform(3, 2) = 0.0f;
482  transform(3, 3) = pTransform->mat[8];
483  modelview *= transform;
484  }
485 
488 
489  if (pFoW != nullptr && normalTex != 0)
490  call.SetUniformMatrix3x3Transpose(C4SSU_NormalMatrix, StdMeshMatrix::Inverse(StdProjectionMatrix::Upper3x4(modelview)));
491 
492  scriptUniform.Apply(call);
493 }
494 
495 void CStdGL::PerformMultiPix(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, C4ShaderCall* shader_call)
496 {
497  // Draw on pixel center:
498  StdProjectionMatrix transform = StdProjectionMatrix::Translate(0.5f, 0.5f, 0.0f);
499 
500  // This is a workaround. Instead of submitting the whole vertex array to the GL, we do it
501  // in batches of 256 vertices. The intel graphics driver on Linux crashes with
502  // significantly larger arrays, such as 400. It's not clear to me why, maybe POINT drawing
503  // is just not very well tested.
504  const unsigned int BATCH_SIZE = 256;
505 
506  // Feed the vertices to the GL
507  if (!shader_call)
508  {
509  C4ShaderCall call(GetSpriteShader(false, false, false));
510  SetupMultiBlt(call, nullptr, 0, 0, 0, 0, &transform);
511  for(unsigned int i = 0; i < n_vertices; i += BATCH_SIZE)
512  PerformMultiBlt(sfcTarget, OP_POINTS, &vertices[i], std::min(n_vertices - i, BATCH_SIZE), false, &call);
513  }
514  else
515  {
516  SetupMultiBlt(*shader_call, nullptr, 0, 0, 0, 0, &transform);
517  for(unsigned int i = 0; i < n_vertices; i += BATCH_SIZE)
518  PerformMultiBlt(sfcTarget, OP_POINTS, &vertices[i], std::min(n_vertices - i, BATCH_SIZE), false, shader_call);
519  }
520 }
521 
522 void CStdGL::PerformMultiLines(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, float width, C4ShaderCall* shader_call)
523 {
524  // In a first step, we transform the lines array to a triangle array, so that we can draw
525  // the lines with some thickness.
526  // In principle, this step could be easily (and probably much more efficiently) performed
527  // by a geometry shader as well, however that would require OpenGL 3.2.
528  C4BltVertex* tri_vertices = new C4BltVertex[n_vertices * 3];
529  for(unsigned int i = 0; i < n_vertices; i += 2)
530  {
531  const float x1 = vertices[i].ftx;
532  const float y1 = vertices[i].fty;
533  const float x2 = vertices[i+1].ftx;
534  const float y2 = vertices[i+1].fty;
535 
536  float offx = y1 - y2;
537  float offy = x2 - x1;
538  float l = sqrtf(offx * offx + offy * offy);
539  // avoid division by zero
540  l += 0.000000005f;
541  offx *= width/l;
542  offy *= width/l;
543 
544  tri_vertices[3*i + 0].ftx = x1 + offx; tri_vertices[3*i + 0].fty = y1 + offy;
545  tri_vertices[3*i + 1].ftx = x1 - offx; tri_vertices[3*i + 1].fty = y1 - offy;
546  tri_vertices[3*i + 2].ftx = x2 - offx; tri_vertices[3*i + 2].fty = y2 - offy;
547  tri_vertices[3*i + 3].ftx = x2 + offx; tri_vertices[3*i + 3].fty = y2 + offy;
548 
549  for(int j = 0; j < 4; ++j)
550  {
551  tri_vertices[3*i + 0].color[j] = vertices[i].color[j];
552  tri_vertices[3*i + 1].color[j] = vertices[i].color[j];
553  tri_vertices[3*i + 2].color[j] = vertices[i + 1].color[j];
554  tri_vertices[3*i + 3].color[j] = vertices[i + 1].color[j];
555  }
556 
557  tri_vertices[3*i + 0].tx = 0.f; tri_vertices[3*i + 0].ty = 0.f;
558  tri_vertices[3*i + 1].tx = 0.f; tri_vertices[3*i + 1].ty = 2.f;
559  tri_vertices[3*i + 2].tx = 1.f; tri_vertices[3*i + 2].ty = 2.f;
560  tri_vertices[3*i + 3].tx = 1.f; tri_vertices[3*i + 3].ty = 0.f;
561 
562  tri_vertices[3*i + 4] = tri_vertices[3*i + 2]; // duplicate vertex
563  tri_vertices[3*i + 5] = tri_vertices[3*i + 0]; // duplicate vertex
564  }
565 
566  // Then, feed the vertices to the GL
567  if (!shader_call)
568  {
569  C4ShaderCall call(GetSpriteShader(true, false, false));
570  SetupMultiBlt(call, nullptr, lines_tex, 0, 0, 0, nullptr);
571  PerformMultiBlt(sfcTarget, OP_TRIANGLES, tri_vertices, n_vertices * 3, true, &call);
572  }
573  else
574  {
575  SetupMultiBlt(*shader_call, nullptr, lines_tex, 0, 0, 0, nullptr);
576  PerformMultiBlt(sfcTarget, OP_TRIANGLES, tri_vertices, n_vertices * 3, true, shader_call);
577  }
578 
579  delete[] tri_vertices;
580 }
581 
582 void CStdGL::PerformMultiTris(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, const C4BltTransform* pTransform, C4TexRef* pTex, C4TexRef* pOverlay, C4TexRef* pNormal, DWORD dwOverlayModClr, C4ShaderCall* shader_call)
583 {
584  // Feed the vertices to the GL
585  if (!shader_call)
586  {
587  C4ShaderCall call(GetSpriteShader(pTex != nullptr, pOverlay != nullptr, pNormal != nullptr));
588  SetupMultiBlt(call, pTransform, pTex ? pTex->texName : 0, pOverlay ? pOverlay->texName : 0, pNormal ? pNormal->texName : 0, dwOverlayModClr, nullptr);
589  PerformMultiBlt(sfcTarget, OP_TRIANGLES, vertices, n_vertices, pTex != nullptr, &call);
590  }
591  else
592  {
593  SetupMultiBlt(*shader_call, pTransform, pTex ? pTex->texName : 0, pOverlay ? pOverlay->texName : 0, pNormal ? pNormal->texName : 0, dwOverlayModClr, nullptr);
594  PerformMultiBlt(sfcTarget, OP_TRIANGLES, vertices, n_vertices, pTex != nullptr, shader_call);
595  }
596 }
597 
598 void CStdGL::PerformMultiBlt(C4Surface* sfcTarget, DrawOperation op, const C4BltVertex* vertices, unsigned int n_vertices, bool has_tex, C4ShaderCall* shader_call)
599 {
600  // Only direct rendering
601  assert(sfcTarget->IsRenderTarget());
602  if(!PrepareRendering(sfcTarget)) return;
603 
604  // Select a buffer
605  const unsigned int vbo_index = CurrentVBO;
607 
608  // Upload data into the buffer, resize buffer if necessary
609  glBindBuffer(GL_ARRAY_BUFFER, GenericVBOs[vbo_index]);
610  if (GenericVBOSizes[vbo_index] < n_vertices)
611  {
612  GenericVBOSizes[vbo_index] = n_vertices;
613  glBufferData(GL_ARRAY_BUFFER, n_vertices * sizeof(C4BltVertex), vertices, GL_STREAM_DRAW);
614  }
615  else
616  {
617  glBufferSubData(GL_ARRAY_BUFFER, 0, n_vertices * sizeof(C4BltVertex), vertices);
618  }
619 
620  // Choose the VAO that corresponds to the chosen VBO. Also, use one
621  // that supplies texture coordinates if we have texturing enabled.
622  GLuint vao;
623  const unsigned int vao_index = vbo_index + (has_tex ? N_GENERIC_VBOS : 0);
624  const unsigned int vao_id = GenericVAOs[vao_index];
625  const bool has_vao = GetVAO(vao_id, vao);
626  glBindVertexArray(vao);
627  if (!has_vao)
628  {
629  // Initialize VAO for this context
630  const GLuint position = shader_call->GetAttribute(C4SSA_Position);
631  const GLuint color = shader_call->GetAttribute(C4SSA_Color);
632  const GLuint texcoord = has_tex ? shader_call->GetAttribute(C4SSA_TexCoord) : 0;
633 
634  glEnableVertexAttribArray(position);
635  glEnableVertexAttribArray(color);
636  if (has_tex)
637  glEnableVertexAttribArray(texcoord);
638 
639 
640  glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, ftx)));
641  glVertexAttribPointer(color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, color)));
642  if (has_tex)
643  glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, tx)));
644  }
645 
646  switch (op)
647  {
648  case OP_POINTS:
649  glDrawArrays(GL_POINTS, 0, n_vertices);
650  break;
651  case OP_TRIANGLES:
652  glDrawArrays(GL_TRIANGLES, 0, n_vertices);
653  break;
654  default:
655  assert(false);
656  break;
657  }
658 
659  glBindVertexArray(0);
660  glBindBuffer(GL_ARRAY_BUFFER, 0);
661 }
662 
663 C4Shader* CStdGL::GetSpriteShader(bool haveBase, bool haveOverlay, bool haveNormal)
664 {
665  int ssc = 0;
666  if(dwBlitMode & C4GFXBLIT_MOD2) ssc |= C4SSC_MOD2;
667  if(haveBase) ssc |= C4SSC_BASE;
668  if(haveBase && haveOverlay) ssc |= C4SSC_OVERLAY;
669  if(pFoW != nullptr) ssc |= C4SSC_LIGHT;
670  if(pFoW != nullptr && haveBase && haveNormal) ssc |= C4SSC_NORMAL;
671  return GetSpriteShader(ssc);
672 }
673 
675 {
676  C4Shader* shaders[16] = {
677  &SpriteShader,
683 
694  };
695 
696  int index = 0;
697  if(ssc & C4SSC_LIGHT) index += 6;
698 
699  if(ssc & C4SSC_BASE)
700  {
701  index += 2;
702  if(ssc & C4SSC_OVERLAY)
703  index += 2;
704  if( (ssc & C4SSC_NORMAL) && (ssc & C4SSC_LIGHT))
705  index += 4;
706  }
707 
708  if(ssc & C4SSC_MOD2)
709  index += 1;
710 
711  assert(index < 16);
712  return shaders[index];
713 }
714 
716 {
717  // Create sprite blitting shaders
718  if(!PrepareSpriteShader(SpriteShader, "sprite", 0, pGroups, nullptr, nullptr))
719  return false;
720  if(!PrepareSpriteShader(SpriteShaderMod2, "spriteMod2", C4SSC_MOD2, pGroups, nullptr, nullptr))
721  return false;
722  if(!PrepareSpriteShader(SpriteShaderBase, "spriteBase", C4SSC_BASE, pGroups, nullptr, nullptr))
723  return false;
724  if(!PrepareSpriteShader(SpriteShaderBaseMod2, "spriteBaseMod2", C4SSC_MOD2 | C4SSC_BASE, pGroups, nullptr, nullptr))
725  return false;
726  if(!PrepareSpriteShader(SpriteShaderBaseOverlay, "spriteBaseOverlay", C4SSC_BASE | C4SSC_OVERLAY, pGroups, nullptr, nullptr))
727  return false;
728  if(!PrepareSpriteShader(SpriteShaderBaseOverlayMod2, "spriteBaseOverlayMod2", C4SSC_MOD2 | C4SSC_BASE | C4SSC_OVERLAY, pGroups, nullptr, nullptr))
729  return false;
730 
731  if(!PrepareSpriteShader(SpriteShaderLight, "spriteLight", C4SSC_LIGHT, pGroups, nullptr, nullptr))
732  return false;
733  if(!PrepareSpriteShader(SpriteShaderLightMod2, "spriteLightMod2", C4SSC_LIGHT | C4SSC_MOD2, pGroups, nullptr, nullptr))
734  return false;
735  if(!PrepareSpriteShader(SpriteShaderLightBase, "spriteLightBase", C4SSC_LIGHT | C4SSC_BASE, pGroups, nullptr, nullptr))
736  return false;
737  if(!PrepareSpriteShader(SpriteShaderLightBaseMod2, "spriteLightBaseMod2", C4SSC_LIGHT | C4SSC_BASE | C4SSC_MOD2, pGroups, nullptr, nullptr))
738  return false;
739  if(!PrepareSpriteShader(SpriteShaderLightBaseOverlay, "spriteLightBaseOverlay", C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY, pGroups, nullptr, nullptr))
740  return false;
741  if(!PrepareSpriteShader(SpriteShaderLightBaseOverlayMod2, "spriteLightBaseOverlayMod2", C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY | C4SSC_MOD2, pGroups, nullptr, nullptr))
742  return false;
743  if(!PrepareSpriteShader(SpriteShaderLightBaseNormal, "spriteLightBaseNormal", C4SSC_LIGHT | C4SSC_BASE | C4SSC_NORMAL, pGroups, nullptr, nullptr))
744  return false;
745  if(!PrepareSpriteShader(SpriteShaderLightBaseNormalMod2, "spriteLightBaseNormalMod2", C4SSC_LIGHT | C4SSC_BASE | C4SSC_NORMAL | C4SSC_MOD2, pGroups, nullptr, nullptr))
746  return false;
747  if(!PrepareSpriteShader(SpriteShaderLightBaseNormalOverlay, "spriteLightBaseNormalOverlay", C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY | C4SSC_NORMAL, pGroups, nullptr, nullptr))
748  return false;
749  if(!PrepareSpriteShader(SpriteShaderLightBaseNormalOverlayMod2, "spriteLightBaseNormalOverlayMod2", C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY | C4SSC_NORMAL | C4SSC_MOD2, pGroups, nullptr, nullptr))
750  return false;
751 
752  return true;
753 }
754 
756 {
757  return pMainCtx->Select();
758 }
759 
761 {
762  assert(pMainCtx);
763  // delete any previous objects
765 
766  // set states
767  Active = pMainCtx->Select();
769 
770  // lines texture
771  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
772  glGenTextures(1, &lines_tex);
773  glBindTexture(GL_TEXTURE_2D, lines_tex);
774  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
775  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
776  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
777  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
778  static const char * linedata = "\xff\xff\xff\x00\xff\xff\xff\xff";
779  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, linedata);
780 
781  MaxTexSize = 64;
782  GLint s = 0;
783  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s);
784  if (s>0) MaxTexSize = s;
785 
786  // Generic VBOs
787  glGenBuffers(N_GENERIC_VBOS, GenericVBOs);
788  for (unsigned int i = 0; i < N_GENERIC_VBOS; ++i)
789  {
791  glBindBuffer(GL_ARRAY_BUFFER, GenericVBOs[i]);
792  glBufferData(GL_ARRAY_BUFFER, GenericVBOSizes[i] * sizeof(C4BltVertex), nullptr, GL_STREAM_DRAW);
793  GenericVAOs[i] = GenVAOID();
795  }
796 
797  glBindBuffer(GL_ARRAY_BUFFER, 0);
798 
799  // reset blit states
800  dwBlitMode = 0;
801 
802  // done
803  return Active;
804 }
805 
807 {
808  bool fSuccess=true;
809  // deactivate
810  Active=false;
811  // invalidate font objects
812  // invalidate primary surfaces
813  if (lines_tex)
814  {
815  glDeleteTextures(1, &lines_tex);
816  lines_tex = 0;
817  }
818 
819  // invalidate generic VBOs
820  if (GenericVBOs[0] != 0)
821  {
822  glDeleteBuffers(N_GENERIC_VBOS, GenericVBOs);
823  GenericVBOs[0] = 0;
824  CurrentVBO = 0;
825  for (unsigned int GenericVAO : GenericVAOs)
826  FreeVAOID(GenericVAO);
827  }
828 
829  // invalidate shaders
830 
831  // TODO: We don't do this here because we cannot re-validate them in
832  // RestoreDeviceObjects. This should be refactored.
833 
834  /*SpriteShader.Clear();
835  SpriteShaderMod2.Clear();
836  SpriteShaderBase.Clear();
837  SpriteShaderBaseMod2.Clear();
838  SpriteShaderBaseOverlay.Clear();
839  SpriteShaderBaseOverlayMod2.Clear();
840  SpriteShaderLight.Clear();
841  SpriteShaderLightMod2.Clear();
842  SpriteShaderLightBase.Clear();
843  SpriteShaderLightBaseMod2.Clear();
844  SpriteShaderLightBaseOverlay.Clear();
845  SpriteShaderLightBaseOverlayMod2.Clear();
846  SpriteShaderLightBaseNormal.Clear();
847  SpriteShaderLightBaseNormalMod2.Clear();
848  SpriteShaderLightBaseNormalOverlay.Clear();
849  SpriteShaderLightBaseNormalOverlayMod2.Clear();*/
850  return fSuccess;
851 }
852 
853 bool CStdGL::Error(const char *szMsg)
854 {
855 #ifdef USE_WIN32_WINDOWS
856  DWORD err = GetLastError();
857 #endif
858  bool r = C4Draw::Error(szMsg);
859 #ifdef USE_WIN32_WINDOWS
860  wchar_t * lpMsgBuf;
861  FormatMessage(
862  FORMAT_MESSAGE_ALLOCATE_BUFFER |
863  FORMAT_MESSAGE_FROM_SYSTEM |
864  FORMAT_MESSAGE_IGNORE_INSERTS,
865  nullptr,
866  err,
867  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
868  (LPTSTR) &lpMsgBuf,
869  0, nullptr );
870  LogF(" gl: GetLastError() = %d - %s", err, StdStrBuf(lpMsgBuf).getData());
871  LocalFree(lpMsgBuf);
872 #endif
873  LogF(" gl: %s", glGetString(GL_VENDOR));
874  LogF(" gl: %s", glGetString(GL_RENDERER));
875  LogF(" gl: %s", glGetString(GL_VERSION));
876  LogF(" gl: %s", glGetString(GL_EXTENSIONS));
877  return r;
878 }
879 
880 const char* CStdGL::GLErrorString(GLenum code)
881 {
882  switch (code)
883  {
884  case GL_NO_ERROR: return "No error";
885  case GL_INVALID_ENUM: return "An unacceptable value is specified for an enumerated argument";
886  case GL_INVALID_VALUE: return "A numeric argument is out of range";
887  case GL_INVALID_OPERATION: return "The specified operation is not allowed in the current state";
888  case GL_INVALID_FRAMEBUFFER_OPERATION: return "The framebuffer object is not complete";
889  case GL_OUT_OF_MEMORY: return "There is not enough memory left to execute the command";
890  case GL_STACK_UNDERFLOW: return "An attempt has been made to perform an operation that would cause an internal stack to underflow";
891  case GL_STACK_OVERFLOW: return "An attempt has been made to perform an operation that would cause an internal stack to overflow";
892  default: assert(false); return "";
893  }
894 }
895 
896 bool CStdGL::CheckGLError(const char *szAtOp)
897 {
898  GLenum err = glGetError();
899  if (!err) return true;
900 
901  LogF("GL error with %s: %d - %s", szAtOp, err, GLErrorString(err));
902  return false;
903 }
904 
905 CStdGL *pGL=nullptr;
906 
907 bool CStdGL::OnResolutionChanged(unsigned int iXRes, unsigned int iYRes)
908 {
909  // Re-create primary clipper to adapt to new size.
910  CreatePrimaryClipper(iXRes, iYRes);
912  return true;
913 }
914 
916 {
917  C4Draw::Default();
918  pCurrCtx = nullptr;
919  iPixelFormat=0;
920  sfcFmt=0;
921  Workarounds.LowMaxVertexUniformCount = false;
922  Workarounds.ForceSoftwareTransform = false;
923 }
924 
925 unsigned int CStdGL::GenVAOID()
926 {
927  // Generate a new VAO ID. Make them sequential so that the actual
928  // VAOs in the context can be simply maintained with a lookup table.
929  unsigned int id;
930  if (NextVAOID == VAOIDs.begin())
931  {
932  // Insert at the beginning
933  id = 1;
934  }
935  else
936  {
937  // Insert at the end, or somewhere in the middle
938  std::set<unsigned int>::iterator iter = NextVAOID;
939  --iter;
940 
941  id = *iter + 1;
942  }
943 
944  // Actually insert the ID
945 #ifdef NDEBUG
946  std::set<unsigned int>::iterator inserted_iter = VAOIDs.insert(NextVAOID, id);
947 #else
948  std::pair<std::set<unsigned int>::iterator, bool> inserted = VAOIDs.insert(id);
949  assert(inserted.second == true);
950  std::set<unsigned int>::iterator inserted_iter = inserted.first;
951 #endif
952 
953  // Update next VAO ID: increment iterator until we find a gap
954  // in the sequence.
955  NextVAOID = inserted_iter;
956  unsigned int prev_id = id;
957  ++NextVAOID;
958  while(NextVAOID != VAOIDs.end() && prev_id + 1 == *NextVAOID)
959  {
960  prev_id = *NextVAOID;
961  ++NextVAOID;
962  }
963 
964  return id;
965 }
966 
967 void CStdGL::FreeVAOID(unsigned int vaoid)
968 {
969  std::set<unsigned int>::iterator iter = VAOIDs.find(vaoid);
970  assert(iter != VAOIDs.end());
971 
972  // Delete this VAO in the current context
973  if (pCurrCtx)
974  {
975  if (vaoid < pCurrCtx->hVAOs.size() && pCurrCtx->hVAOs[vaoid] != 0)
976  {
977  glDeleteVertexArrays(1, &pCurrCtx->hVAOs[vaoid]);
978  pCurrCtx->hVAOs[vaoid] = 0;
979  }
980  }
981 
982  // For all other contexts, mark it to be deleted as soon as we select
983  // that context. Otherwise we would need to do a lot of context
984  // switching at this point.
985  for (auto ctx : CStdGLCtx::contexts)
986  {
987  if (ctx != pCurrCtx && vaoid < ctx->hVAOs.size() && ctx->hVAOs[vaoid] != 0)
988  if (std::find(ctx->VAOsToBeDeleted.begin(), ctx->VAOsToBeDeleted.end(), vaoid) == ctx->VAOsToBeDeleted.end())
989  ctx->VAOsToBeDeleted.push_back(vaoid);
990  }
991 
992  // Delete the VAO ID from our list of VAO IDs in use
993  // If the Next VAO ID is 1, then no matter what we delete we don't need
994  // to update anything. If it is not at the beginning, then move it to the
995  // gap we just created if it was at a higher place, to make sure we keep
996  // the numbers as sequential as possible.
997  unsigned int nextVaoID = 1;
998  if (NextVAOID != VAOIDs.begin())
999  {
1000  std::set<unsigned int>::iterator next_vao_iter = NextVAOID;
1001  --next_vao_iter;
1002  nextVaoID = *next_vao_iter + 1;
1003  }
1004 
1005  assert(vaoid != nextVaoID);
1006 
1007  if (vaoid < nextVaoID || iter == NextVAOID)
1008  NextVAOID = VAOIDs.erase(iter);
1009  else
1010  VAOIDs.erase(iter);
1011 }
1012 
1013 bool CStdGL::GetVAO(unsigned int vaoid, GLuint& vao)
1014 {
1015  assert(pCurrCtx != nullptr);
1016 
1017  if (vaoid >= pCurrCtx->hVAOs.size())
1018  {
1019  // Resize the VAO array so that all generated VAO IDs fit
1020  // in it, and not only the one requested in this call.
1021  // We hope to get away with fewer reallocations this way.
1022  assert(VAOIDs.find(vaoid) != VAOIDs.end());
1023  std::set<unsigned int>::iterator iter = VAOIDs.end();
1024  --iter;
1025 
1026  pCurrCtx->hVAOs.resize(*iter + 1);
1027  }
1028 
1029  if (pCurrCtx->hVAOs[vaoid] == 0)
1030  {
1031  glGenVertexArrays(1, &pCurrCtx->hVAOs[vaoid]);
1032  vao = pCurrCtx->hVAOs[vaoid];
1033  return false;
1034  }
1035 
1036  vao = pCurrCtx->hVAOs[vaoid];
1037  return true;
1038 }
1039 
1040 #endif // USE_CONSOLE
bool AssertMainThread()
Definition: C4App.h:123
float fty
Definition: C4Draw.h:64
int32_t DebugOpenGL
Definition: C4Config.h:117
C4Shader SpriteShaderLightBaseNormalOverlay
Definition: C4DrawGL.h:205
int MaxTexSize
Definition: C4Draw.h:99
C4Config Config
Definition: C4Config.cpp:833
virtual bool Select(bool verbose=false)
static std::list< CStdGLCtx * > contexts
Definition: C4DrawGL.h:135
#define C4GFXBLIT_MOD2
Definition: C4Surface.h:27
static const unsigned int N_GENERIC_VBOS
Definition: C4DrawGL.h:215
bool Active
Definition: C4Draw.h:96
unsigned int CurrentVBO
Definition: C4DrawGL.h:219
CStdGLCtx * pCurrCtx
Definition: C4DrawGL.h:179
void SetScriptCategories(const std::vector< std::string > &categories)
Definition: C4Shader.cpp:100
float ZoomY
Definition: C4Draw.h:112
float tx
Definition: C4Draw.h:62
C4ScriptUniform scriptUniform
Definition: C4Draw.h:100
#define GetGreenValue(rgb)
Definition: StdColors.h:28
virtual void Deselect()
unsigned char color[4]
Definition: C4Draw.h:63
const FLOAT_RECT & getViewportRegion() const
Definition: C4FoWRegion.h:52
C4Shader SpriteShaderBase
Definition: C4DrawGL.h:192
CStdGLCtx * pCtx
Definition: C4Surface.h:76
std::set< unsigned int >::iterator NextVAOID
Definition: C4DrawGL.h:227
C4Surface * pSurface
Definition: C4Window.h:274
C4Shader SpriteShaderLightBaseNormalMod2
Definition: C4DrawGL.h:204
GLint GetAttribute(int iAttribute) const
Definition: C4Shader.h:194
float gammaOut[3]
Definition: C4Draw.h:98
CStdGLCtx * pMainCtx
Definition: C4DrawGL.h:178
double GetBrightness() const
Definition: C4FoWAmbient.h:56
#define C4GFXBLIT_ADDITIVE
Definition: C4Surface.h:26
bool LoadFragmentSlices(C4GroupSet *pGroupSet, const char *szFile)
Definition: C4Shader.cpp:90
void FreeVAOID(unsigned int vaoid)
Definition: C4DrawGL.cpp:967
bool EnsureMainContextSelected() override
Definition: C4DrawGL.cpp:755
void Apply(C4ShaderCall &call)
Definition: C4Shader.cpp:826
void AddDefine(const char *name)
Definition: C4Shader.cpp:63
Definition: C4Rect.h:27
C4Shader SpriteShaderBaseOverlay
Definition: C4DrawGL.h:194
void PerformMultiTris(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, const C4BltTransform *pTransform, C4TexRef *pTex, C4TexRef *pOverlay, C4TexRef *pNormal, DWORD dwOverlayClrMod, C4ShaderCall *shader_call) override
Definition: C4DrawGL.cpp:582
void FillBG(DWORD dwClr=0) override
Definition: C4DrawGL.cpp:144
const C4FoW * getFoW() const
Definition: C4FoWRegion.h:50
void ClearSlices()
Definition: C4Shader.cpp:322
C4Shader SpriteShaderLightBaseOverlay
Definition: C4DrawGL.h:201
CStdGLCtx * CreateContext(C4Window *pWindow, C4AbstractApp *pApp) override
Definition: C4DrawGL.cpp:282
#define GetRedValue(rgb)
Definition: StdColors.h:29
CStdGL()
Definition: C4DrawGL.cpp:98
float ty
Definition: C4Draw.h:62
GLuint GenericVBOs[N_GENERIC_VBOS]
Definition: C4DrawGL.h:217
int Hgt
Definition: C4Surface.h:65
C4Shader SpriteShaderLightBaseMod2
Definition: C4DrawGL.h:200
#define USERPARAM_CONST
Definition: C4DrawGL.cpp:79
const C4FoWRegion * pFoW
Definition: C4Draw.h:111
C4Shader SpriteShaderBaseMod2
Definition: C4DrawGL.h:193
bool CreatePrimaryClipper(unsigned int iXRes, unsigned int iYRes)
Definition: C4Draw.cpp:507
GLenum sfcFmt
Definition: C4DrawGL.h:177
C4ConfigGraphics Graphics
Definition: C4Config.h:253
int32_t Wdt
Definition: C4Rect.h:30
bool UpdateClipper() override
Definition: C4DrawGL.cpp:151
C4Shader SpriteShaderBaseOverlayMod2
Definition: C4DrawGL.h:195
void SetupMultiBlt(C4ShaderCall &call, const C4BltTransform *pTransform, GLuint baseTex, GLuint overlayTex, GLuint normalTex, DWORD dwOverlayModClr, StdProjectionMatrix *out_modelview)
Definition: C4DrawGL.cpp:361
void Default() override
Definition: C4DrawGL.cpp:915
void Clear() override
Definition: C4DrawGL.cpp:114
bool LogSilentF(const char *strMessage,...)
Definition: C4Log.cpp:270
int iPixelFormat
Definition: C4DrawGL.h:175
bool PrepareSpriteShader(C4Shader &shader, const char *name, int ssc, C4GroupSet *pGroups, const char *const *additionalDefines, const char *const *additionalSlices) override
Definition: C4DrawGL.cpp:198
void PerformMultiLines(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, float width, C4ShaderCall *shader_call) override
Definition: C4DrawGL.cpp:522
int32_t y
Definition: C4Rect.h:30
#define GetBlueValue(rgb)
Definition: StdColors.h:27
~CStdGL() override
Definition: C4DrawGL.cpp:108
void Clear()
Definition: C4Shader.cpp:333
C4Shader SpriteShaderLightBaseNormalOverlayMod2
Definition: C4DrawGL.h:206
void SetUniformMatrix3x3Transpose(int iUniform, const StdMeshMatrix &matrix)
Definition: C4Shader.h:336
friend class CStdGLCtx
Definition: C4DrawGL.h:291
GLuint getSurfaceName() const
C4Shader SpriteShader
Definition: C4DrawGL.h:190
bool LoadVertexSlices(C4GroupSet *pGroupSet, const char *szFile)
Definition: C4Shader.cpp:95
bool GetVAO(unsigned int vaoid, GLuint &vao)
Definition: C4DrawGL.cpp:1013
GLuint lines_tex
Definition: C4DrawGL.h:181
#define BREAKPOINT_HERE
void SetUniformMatrix2x3fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:307
C4FoWAmbient Ambient
Definition: C4FoW.h:115
virtual bool Error(const char *szMsg)
Definition: C4Draw.cpp:500
C4Shader SpriteShaderMod2
Definition: C4DrawGL.h:191
unsigned int GenericVBOSizes[N_GENERIC_VBOS]
Definition: C4DrawGL.h:218
float ZoomX
Definition: C4Draw.h:112
unsigned int GenericVAOs[N_GENERIC_VBOS *2]
Definition: C4DrawGL.h:223
C4Shader SpriteShaderLightBaseOverlayMod2
Definition: C4DrawGL.h:202
DWORD BlitModulateClr
Definition: C4Draw.h:109
unsigned int texName
Definition: C4Surface.h:155
int32_t x
Definition: C4Rect.h:30
float Zoom
Definition: C4Draw.h:116
void SetUniform3fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:297
struct CStdGL::@10 Workarounds
const char * GLErrorString(GLenum code)
Definition: C4DrawGL.cpp:880
bool OnResolutionChanged(unsigned int iXRes, unsigned int iYRes) override
Definition: C4DrawGL.cpp:907
bool Init(const char *szWhat, const char **szUniforms, const char **szAttributes)
Definition: C4Shader.cpp:346
void SetUniform1f(int iUniform, float gX) const
Definition: C4Shader.h:241
unsigned int GenVAOID()
Definition: C4DrawGL.cpp:925
static const unsigned int GENERIC_VBO_SIZE
Definition: C4DrawGL.h:216
virtual void Default()
Definition: C4Draw.cpp:169
bool PrepareRendering(C4Surface *sfcToSurface) override
Definition: C4DrawGL.cpp:169
virtual bool Init(C4Window *pWindow, C4AbstractApp *pApp)
C4Shader SpriteShaderLightBaseNormal
Definition: C4DrawGL.h:203
bool RestoreDeviceObjects() override
Definition: C4DrawGL.cpp:760
C4Surface * RenderTarget
Definition: C4Draw.h:107
bool InitShaders(C4GroupSet *pGroups)
Definition: C4DrawGL.cpp:715
bool Log(const char *szMessage)
Definition: C4Log.cpp:202
float ftx
Definition: C4Draw.h:64
void GetFragTransform(const C4Rect &clipRect, const C4Rect &outRect, float lightTransform[6]) const
GLint AllocTexUnit(int iUniform)
Definition: C4Shader.cpp:666
C4Rect GetOutRect() const
Definition: C4Draw.cpp:739
void ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char *label)
Definition: C4DrawGL.cpp:274
virtual void Clear()
Definition: C4Draw.cpp:184
DWORD dwBlitMode
Definition: C4Draw.h:110
bool Error(const char *szMsg) override
Definition: C4DrawGL.cpp:853
void PerformMultiBlt(C4Surface *sfcTarget, DrawOperation op, const C4BltVertex *vertices, unsigned int n_vertices, bool has_tex, C4ShaderCall *shader_call)
Definition: C4DrawGL.cpp:598
void SetUniformMatrix4x4(int iUniform, const StdMeshMatrix &matrix)
Definition: C4Shader.h:351
bool ClipAll
Definition: C4Draw.h:105
bool IsRenderTarget()
Definition: C4Surface.cpp:144
void PerformMultiPix(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, C4ShaderCall *shader_call) override
Definition: C4DrawGL.cpp:495
std::set< unsigned int > VAOIDs
Definition: C4DrawGL.h:226
CStdGL * pGL
Definition: C4DrawGL.cpp:905
int32_t Hgt
Definition: C4Rect.h:30
C4Rect GetClipRect() const
Definition: C4Draw.cpp:730
bool NoPrimaryClipper()
Definition: C4Draw.cpp:237
int Locked
Definition: C4Surface.h:87
bool InvalidateDeviceObjects() override
Definition: C4DrawGL.cpp:806
void Start()
Definition: C4Shader.cpp:689
C4Shader SpriteShaderLight
Definition: C4DrawGL.h:197
C4Shader SpriteShaderLightBase
Definition: C4DrawGL.h:199
C4Shader * GetSpriteShader(int ssc)
Definition: C4DrawGL.cpp:674
uint32_t DWORD
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:260
StdProjectionMatrix ProjectionMatrix
Definition: C4DrawGL.h:184
bool BlitModulated
Definition: C4Draw.h:108
#define s
C4Window * pWindow
Definition: C4App.h:80
DrawOperation
Definition: C4Draw.h:87
void GetFragTransform(const struct FLOAT_RECT &vpRect, const C4Rect &clipRect, const C4Rect &outRect, float ambientTransform[6]) const
std::vector< GLuint > hVAOs
Definition: C4DrawGL.h:139
C4AbstractApp * pApp
Definition: C4Draw.h:95
void SetUniform4fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:301
bool CheckGLError(const char *szAtOp)
Definition: C4DrawGL.cpp:896
C4Shader SpriteShaderLightMod2
Definition: C4DrawGL.h:198