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