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