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