OpenClonk
C4Shader.h
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2014-2016, The OpenClonk Team and contributors
5  *
6  * Distributed under the terms of the ISC license; see accompanying file
7  * "COPYING" for details.
8  *
9  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10  * See accompanying file "TRADEMARK" for details.
11  *
12  * To redistribute this file separately, substitute the full license texts
13  * for the above references.
14  */
15 
16 // Shader implementation somewhere in the middle between easy and extensible.
17 
18 #ifndef INC_C4Shader
19 #define INC_C4Shader
20 
22 #include "lib/StdMeshMath.h"
23 #include "graphics/C4Surface.h"
24 
25 #ifdef _WIN32
27 #endif
28 
29 #ifndef USE_CONSOLE
30 #include <epoxy/gl.h>
31 #endif
32 
33 #include <stack>
34 
35 // Shader version
36 const int C4Shader_Version = 150; // GLSL 1.50 / OpenGL 3.2
37 
38 // Maximum number of texture coordinates
39 const int C4Shader_MaxTexCoords = 8;
40 
41 // Maximum number of texture units per shader call
42 const int C4ShaderCall_MaxUnits = 32;
43 
44 // Positions in fragment shader
45 const int C4Shader_PositionInit = 0;
47 const int C4Shader_PositionTexture = 40;
49 const int C4Shader_PositionNormal = 80;
50 const int C4Shader_PositionLight = 100;
51 const int C4Shader_PositionColor = 120;
52 const int C4Shader_PositionFinish = 140;
53 const int C4Shader_LastPosition = 256;
54 
55 // Positions in vertex shader
58 const int C4Shader_Vertex_ColorPos = 70;
60 
61 class C4Shader
62 {
63  friend class C4ShaderCall;
64  friend class C4ScriptUniform;
65 public:
66  C4Shader();
67  ~C4Shader();
68 
69 private:
70 
71  StdStrBuf Name;
72 
73  // Program texts
74  struct ShaderSlice {
75  int Position;
76  StdCopyStrBuf Text;
77  StdCopyStrBuf Source;
78  int SourceLine;
79  int SourceTime;
80  };
81  typedef std::list<ShaderSlice> ShaderSliceList;
82  ShaderSliceList VertexSlices, FragmentSlices;
83  std::vector<std::string> SourceFiles;
84  std::vector<std::string> Categories;
85  std::set<int> ScriptShaders;
86 
87  int GetSourceFileId(const char *file) const;
88 
89  // Last refresh check
90  C4TimeMilliseconds LastRefresh;
91  bool ScriptSlicesLoaded = false;
92 
93  // Used texture coordinates
94  int iTexCoords{0};
95 
96 #ifndef USE_CONSOLE
97  // shaders
98  GLuint hProg{0};
99  // shader variables
100  struct Variable { int address; const char* name; };
101  std::vector<Variable> Uniforms;
102  std::vector<Variable> Attributes;
103 #endif
104 
105 public:
106  bool Initialised() const
107  {
108 #ifndef USE_CONSOLE
109  return hProg != 0;
110 #else
111  return true;
112 #endif
113  }
114 
115  // Uniform getters
116 #ifndef USE_CONSOLE
117  GLint GetUniform(int iUniform) const
118  {
119  return iUniform >= 0 && static_cast<unsigned int>(iUniform) < Uniforms.size() ? Uniforms[iUniform].address : -1;
120  }
121 
122  bool HaveUniform(int iUniform) const
123  {
124  return GetUniform(iUniform) != GLint(-1);
125  }
126 
127  GLint GetAttribute(int iAttribute) const
128  {
129  return iAttribute >= 0 && static_cast<unsigned int>(iAttribute) < Attributes.size() ? Attributes[iAttribute].address : -1;
130  }
131 
132 #else
133  int GetUniform(int iUniform) const
134  {
135  return -1;
136  }
137  bool HaveUniform(int iUniform) const
138  {
139  return false;
140  }
141  int GetAttribute(int iAttribute) const
142  {
143  return -1;
144  }
145 #endif
146 
147  // Shader is composed from various slices
148  void AddDefine(const char* name);
149  void AddVertexSlice(int iPos, const char *szText);
150  void AddFragmentSlice(int iPos, const char *szText);
151  void AddVertexSlices(const char *szWhat, const char *szText, const char *szSource = "", int iFileTime = 0);
152  void AddFragmentSlices(const char *szWhat, const char *szText, const char *szSource = "", int iFileTime = 0);
153  bool LoadFragmentSlices(C4GroupSet *pGroupSet, const char *szFile);
154  bool LoadVertexSlices(C4GroupSet *pGroupSet, const char *szFile);
155  void SetScriptCategories(const std::vector<std::string>& categories);
156 
157  // Assemble and link the shader. Should be called again after new slices are added.
158  bool Init(const char *szWhat, const char **szUniforms, const char **szAttributes);
159  bool Refresh();
160 
161  void ClearSlices();
162  void Clear();
163 
164 private:
165  void AddSlice(ShaderSliceList& slices, int iPos, const char *szText, const char *szSource, int line, int iFileTime);
166  void AddSlices(ShaderSliceList& slices, const char *szWhat, const char *szText, const char *szSource, int iFileTime);
167  bool LoadSlices(ShaderSliceList& slices, C4GroupSet *pGroupSet, const char *szFile);
168  int ParsePosition(const char *szWhat, const char **ppPos);
169 
170  void LoadScriptSlices();
171  void LoadScriptSlice(int id);
172 
173  StdStrBuf Build(const ShaderSliceList &Slices, bool fDebug = false);
174 
175 #ifndef USE_CONSOLE
176  GLuint Create(GLenum iShaderType, const char *szWhat, const char *szShader);
177  void DumpInfoLog(const char *szWhat, GLuint hShader, bool forProgram);
178 #endif
179 
180 public:
181  static bool IsLogging();
182 };
183 
184 #ifndef USE_CONSOLE
186 {
187  friend class C4ScriptUniform;
188 public:
189  C4ShaderCall(const C4Shader *pShader)
190  : fStarted(false), pShader(pShader), iUnits(0)
191  { }
193 
194  GLint GetAttribute(int iAttribute) const
195  {
196  return pShader->GetAttribute(iAttribute);
197  }
198 
199 private:
200  bool fStarted;
201  const C4Shader *pShader;
202  int iUnits;
203 
204 public:
205  GLint AllocTexUnit(int iUniform);
206 
207  // Setting uniforms... Lots of code duplication here, not quite sure whether
208  // something could be done about it.
209  void SetUniform1i(int iUniform, int iX) const {
210  if (pShader->HaveUniform(iUniform))
211  glUniform1i(pShader->GetUniform(iUniform), iX);
212  }
213  void SetUniform2i(int iUniform, int iX, int iY) const {
214  if (pShader->HaveUniform(iUniform))
215  glUniform2i(pShader->GetUniform(iUniform), iX, iY);
216  }
217  void SetUniform3i(int iUniform, int iX, int iY, int iZ) const {
218  if (pShader->HaveUniform(iUniform))
219  glUniform3i(pShader->GetUniform(iUniform), iX, iY, iZ);
220  }
221  void SetUniform4i(int iUniform, int iX, int iY, int iZ, int iW) const {
222  if (pShader->HaveUniform(iUniform))
223  glUniform4i(pShader->GetUniform(iUniform), iX, iY, iZ, iW);
224  }
225  void SetUniform1ui(int iUniform, unsigned int iX) const {
226  if (pShader->HaveUniform(iUniform))
227  glUniform1ui(pShader->GetUniform(iUniform), iX);
228  }
229  void Setuniform2ui(int iUniform, unsigned int iX, unsigned int iY) const {
230  if (pShader->HaveUniform(iUniform))
231  glUniform2ui(pShader->GetUniform(iUniform), iX, iY);
232  }
233  void Setuniform3ui(int iUniform, unsigned int iX, unsigned int iY, unsigned int iZ) const {
234  if (pShader->HaveUniform(iUniform))
235  glUniform3ui(pShader->GetUniform(iUniform), iX, iY, iZ);
236  }
237  void Setuniform4ui(int iUniform, unsigned int iX, unsigned int iY, unsigned int iZ, unsigned int iW) const {
238  if (pShader->HaveUniform(iUniform))
239  glUniform4ui(pShader->GetUniform(iUniform), iX, iY, iZ, iW);
240  }
241  void SetUniform1f(int iUniform, float gX) const {
242  if (pShader->HaveUniform(iUniform))
243  glUniform1f(pShader->GetUniform(iUniform), gX);
244  }
245  void SetUniform2f(int iUniform, float gX, float gY) const {
246  if (pShader->HaveUniform(iUniform))
247  glUniform2f(pShader->GetUniform(iUniform), gX, gY);
248  }
249  void SetUniform3f(int iUniform, float gX, float gY, float gZ) const {
250  if (pShader->HaveUniform(iUniform))
251  glUniform3f(pShader->GetUniform(iUniform), gX, gY, gZ);
252  }
253  void SetUniform4f(int iUniform, float gX, float gY, float gZ, float gW) const {
254  if (pShader->HaveUniform(iUniform))
255  glUniform4f(pShader->GetUniform(iUniform), gX, gY, gZ, gW);
256  }
257  void SetUniform1iv(int iUniform, int iLength, const int *pVals) const {
258  if (pShader->HaveUniform(iUniform))
259  glUniform1iv(pShader->GetUniform(iUniform), iLength, pVals);
260  }
261  void SetUniform2iv(int iUniform, int iLength, const int *pVals) const {
262  if (pShader->HaveUniform(iUniform))
263  glUniform2iv(pShader->GetUniform(iUniform), iLength, pVals);
264  }
265  void SetUniform3iv(int iUniform, int iLength, const int *pVals) const {
266  if (pShader->HaveUniform(iUniform))
267  glUniform3iv(pShader->GetUniform(iUniform), iLength, pVals);
268  }
269  void SetUniform4iv(int iUniform, int iLength, const int *pVals) const {
270  if (pShader->HaveUniform(iUniform))
271  glUniform4iv(pShader->GetUniform(iUniform), iLength, pVals);
272  }
273  void SetUniform1uiv(int iUniform, int iLength, const unsigned int *pVals) const {
274  if (pShader->HaveUniform(iUniform))
275  glUniform1uiv(pShader->GetUniform(iUniform), iLength, pVals);
276  }
277  void SetUniform2uiv(int iUniform, int iLength, const unsigned int *pVals) const {
278  if (pShader->HaveUniform(iUniform))
279  glUniform2uiv(pShader->GetUniform(iUniform), iLength, pVals);
280  }
281  void SetUniform3uiv(int iUniform, int iLength, const unsigned int *pVals) const {
282  if (pShader->HaveUniform(iUniform))
283  glUniform3uiv(pShader->GetUniform(iUniform), iLength, pVals);
284  }
285  void SetUniform4uiv(int iUniform, int iLength, const unsigned int *pVals) const {
286  if (pShader->HaveUniform(iUniform))
287  glUniform4uiv(pShader->GetUniform(iUniform), iLength, pVals);
288  }
289  void SetUniform1fv(int iUniform, int iLength, const float *pVals) const {
290  if (pShader->HaveUniform(iUniform))
291  glUniform1fv(pShader->GetUniform(iUniform), iLength, pVals);
292  }
293  void SetUniform2fv(int iUniform, int iLength, const float *pVals) const {
294  if (pShader->HaveUniform(iUniform))
295  glUniform2fv(pShader->GetUniform(iUniform), iLength, pVals);
296  }
297  void SetUniform3fv(int iUniform, int iLength, const float *pVals) const {
298  if (pShader->HaveUniform(iUniform))
299  glUniform3fv(pShader->GetUniform(iUniform), iLength, pVals);
300  }
301  void SetUniform4fv(int iUniform, int iLength, const float *pVals) const {
302  if (pShader->HaveUniform(iUniform))
303  glUniform4fv(pShader->GetUniform(iUniform), iLength, pVals);
304  }
305 
306  // Matrices are in row-major order
307  void SetUniformMatrix2x3fv(int iUniform, int iLength, const float* pVals) const {
308  if (pShader->HaveUniform(iUniform))
309  glUniformMatrix3x2fv(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
310  }
311 
312  void SetUniformMatrix3x3fv(int iUniform, int iLength, const float *pVals) const {
313  if (pShader->HaveUniform(iUniform))
314  glUniformMatrix3fv(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
315  }
316 
317  void SetUniformMatrix3x4fv(int iUniform, int iLength, const float *pVals) const {
318  if (pShader->HaveUniform(iUniform))
319  glUniformMatrix4x3fv(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
320  }
321 
322  void SetUniformMatrix4x4fv(int iUniform, int iLength, const float* pVals) const {
323  if (pShader->HaveUniform(iUniform))
324  glUniformMatrix4fv(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
325  }
326 
327  void SetUniformMatrix3x3(int iUniform, const StdMeshMatrix& matrix)
328  {
329  if (pShader->HaveUniform(iUniform))
330  {
331  const float mat[9] = { matrix(0, 0), matrix(1, 0), matrix(2, 0), matrix(0, 1), matrix(1, 1), matrix(2, 1), matrix(0, 2), matrix(1, 2), matrix(2, 2) };
332  glUniformMatrix3fv(pShader->GetUniform(iUniform), 1, GL_FALSE, mat);
333  }
334  }
335 
336  void SetUniformMatrix3x3Transpose(int iUniform, const StdMeshMatrix& matrix)
337  {
338  if (pShader->HaveUniform(iUniform))
339  {
340  const float mat[9] = { matrix(0, 0), matrix(0, 1), matrix(0, 2), matrix(1, 0), matrix(1, 1), matrix(1, 2), matrix(2, 0), matrix(2, 1), matrix(2, 2) };
341  glUniformMatrix3fv(pShader->GetUniform(iUniform), 1, GL_FALSE, mat);
342  }
343  }
344 
345  void SetUniformMatrix3x4(int iUniform, const StdMeshMatrix& matrix)
346  {
347  if (pShader->HaveUniform(iUniform))
348  glUniformMatrix4x3fv(pShader->GetUniform(iUniform), 1, GL_TRUE, matrix.data());
349  }
350 
351  void SetUniformMatrix4x4(int iUniform, const StdMeshMatrix& matrix)
352  {
353  if (pShader->HaveUniform(iUniform))
354  {
355  const float mat[16] = { matrix(0, 0), matrix(1, 0), matrix(2, 0), 0.0f, matrix(0, 1), matrix(1, 1), matrix(2, 1), 0.0f, matrix(0, 2), matrix(1, 2), matrix(2, 2), 0.0f, matrix(0, 3), matrix(1, 3), matrix(2, 3), 1.0f };
356  glUniformMatrix4fv(pShader->GetUniform(iUniform), 1, GL_FALSE, mat);
357  }
358  }
359 
360  void SetUniformMatrix4x4(int iUniform, const StdProjectionMatrix& matrix)
361  {
362  if (pShader->HaveUniform(iUniform))
363  glUniformMatrix4fv(pShader->GetUniform(iUniform), 1, GL_TRUE, matrix.data());
364  }
365 
366  void Start();
367  void Finish();
368 };
369 #else // USE_CONSOLE
370 class C4ShaderCall {
371  public:
372  C4ShaderCall(const C4Shader *) {};
373 };
374 #endif
375 
377 {
378  friend class C4Shader;
379  friend class C4ShaderCall;
380 
381 public:
383  {
384  VertexShader, // Note: Reloading is currently only implemented for fragment shaders.
386  };
387 private:
388  struct ShaderInstance
389  {
391  std::string source;
392  };
393 
394  // Map of shader names -> ids. The indirection is there as each C4Shader
395  // may load script shaders from multiple categories.
396  std::map<std::string, std::set<int>> categories;
397  // Map of ids -> script-loaded shaders.
398  std::map<int, ShaderInstance> shaders;
399  int NextID = 0;
400  uint32_t LastUpdate = 0;
401 
402 protected: // Interface for C4Shader friend class
403  std::set<int> GetShaderIDs(const std::vector<std::string>& cats);
404 
405 public: // Interface for script
406  // Adds a shader, returns its id for removal.
407  int Add(const std::string& shaderName, ShaderType type, const std::string& source);
408  // Removes a shader, returning true on success.
409  bool Remove(int id);
410 };
411 
413 
415 {
416  friend class C4Shader;
417 
418  struct Uniform
419  {
420 #ifndef USE_CONSOLE
421  GLenum type;
422  union
423  {
424  int intVec[4];
425  // TODO: Support for other uniform types.
426  };
427 #endif
428  };
429 
430  typedef std::map<std::string, Uniform> UniformMap;
431  std::stack<UniformMap> uniformStack;
432 
433 public:
434  class Popper
435  {
436  C4ScriptUniform* p;
437  size_t size;
438  public:
439  Popper(C4ScriptUniform* p) : p(p), size(p->uniformStack.size()) { }
440  ~Popper() { assert(size == p->uniformStack.size()); p->uniformStack.pop(); }
441  };
442 
443  // Remove all uniforms.
444  void Clear();
445  // Walk the proplist `proplist.Uniforms` and add uniforms. Automatically pops when the return value is destroyed.
446  std::unique_ptr<Popper> Push(C4PropList* proplist);
447  // Apply uniforms to a shader call.
448  void Apply(C4ShaderCall& call);
449 
451 };
452 
453 #endif // INC_C4Shader
const int C4Shader_PositionMaterial
Definition: C4Shader.h:48
const int C4Shader_Vertex_NormalPos
Definition: C4Shader.h:57
const int C4Shader_PositionTexture
Definition: C4Shader.h:47
const int C4Shader_Vertex_ColorPos
Definition: C4Shader.h:58
const int C4Shader_Vertex_TexCoordPos
Definition: C4Shader.h:56
const int C4Shader_PositionFinish
Definition: C4Shader.h:52
const int C4Shader_LastPosition
Definition: C4Shader.h:53
const int C4ShaderCall_MaxUnits
Definition: C4Shader.h:42
const int C4Shader_PositionNormal
Definition: C4Shader.h:49
const int C4Shader_Vertex_PositionPos
Definition: C4Shader.h:59
const int C4Shader_PositionColor
Definition: C4Shader.h:51
const int C4Shader_MaxTexCoords
Definition: C4Shader.h:39
const int C4Shader_PositionCoordinate
Definition: C4Shader.h:46
const int C4Shader_PositionInit
Definition: C4Shader.h:45
C4ScriptShader ScriptShader
Definition: C4Shader.cpp:719
const int C4Shader_Version
Definition: C4Shader.h:36
const int C4Shader_PositionLight
Definition: C4Shader.h:50
int Add(const std::string &shaderName, ShaderType type, const std::string &source)
Definition: C4Shader.cpp:730
bool Remove(int id)
Definition: C4Shader.cpp:742
std::set< int > GetShaderIDs(const std::vector< std::string > &cats)
Definition: C4Shader.cpp:721
Popper(C4ScriptUniform *p)
Definition: C4Shader.h:439
std::unique_ptr< Popper > Push(C4PropList *proplist)
Definition: C4Shader.cpp:757
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
void SetUniform1ui(int iUniform, unsigned int iX) const
Definition: C4Shader.h:225
void SetUniformMatrix4x4fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:322
void SetUniformMatrix3x3(int iUniform, const StdMeshMatrix &matrix)
Definition: C4Shader.h:327
GLint GetAttribute(int iAttribute) const
Definition: C4Shader.h:194
void SetUniform2f(int iUniform, float gX, float gY) const
Definition: C4Shader.h:245
void SetUniform3i(int iUniform, int iX, int iY, int iZ) const
Definition: C4Shader.h:217
void Finish()
Definition: C4Shader.cpp:705
void SetUniform4fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:301
void SetUniform2i(int iUniform, int iX, int iY) const
Definition: C4Shader.h:213
void Setuniform4ui(int iUniform, unsigned int iX, unsigned int iY, unsigned int iZ, unsigned int iW) const
Definition: C4Shader.h:237
void SetUniformMatrix3x4fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:317
void SetUniformMatrix3x3fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:312
void SetUniform1uiv(int iUniform, int iLength, const unsigned int *pVals) const
Definition: C4Shader.h:273
void SetUniform3f(int iUniform, float gX, float gY, float gZ) const
Definition: C4Shader.h:249
void SetUniform3uiv(int iUniform, int iLength, const unsigned int *pVals) const
Definition: C4Shader.h:281
void SetUniformMatrix3x4(int iUniform, const StdMeshMatrix &matrix)
Definition: C4Shader.h:345
void SetUniform2fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:293
void SetUniform1iv(int iUniform, int iLength, const int *pVals) const
Definition: C4Shader.h:257
void SetUniform3fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:297
void SetUniform4f(int iUniform, float gX, float gY, float gZ, float gW) const
Definition: C4Shader.h:253
void SetUniform2uiv(int iUniform, int iLength, const unsigned int *pVals) const
Definition: C4Shader.h:277
void SetUniform4uiv(int iUniform, int iLength, const unsigned int *pVals) const
Definition: C4Shader.h:285
void SetUniform1fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:289
void SetUniform2iv(int iUniform, int iLength, const int *pVals) const
Definition: C4Shader.h:261
void Setuniform3ui(int iUniform, unsigned int iX, unsigned int iY, unsigned int iZ) const
Definition: C4Shader.h:233
void SetUniformMatrix2x3fv(int iUniform, int iLength, const float *pVals) const
Definition: C4Shader.h:307
void Setuniform2ui(int iUniform, unsigned int iX, unsigned int iY) const
Definition: C4Shader.h:229
void SetUniform4iv(int iUniform, int iLength, const int *pVals) const
Definition: C4Shader.h:269
void SetUniform4i(int iUniform, int iX, int iY, int iZ, int iW) const
Definition: C4Shader.h:221
void SetUniformMatrix4x4(int iUniform, const StdProjectionMatrix &matrix)
Definition: C4Shader.h:360
void SetUniform3iv(int iUniform, int iLength, const int *pVals) const
Definition: C4Shader.h:265
C4ShaderCall(const C4Shader *pShader)
Definition: C4Shader.h:189
void SetUniform1i(int iUniform, int iX) const
Definition: C4Shader.h:209
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 AddFragmentSlice(int iPos, const char *szText)
Definition: C4Shader.cpp:77
bool Initialised() const
Definition: C4Shader.h:106
void AddDefine(const char *name)
Definition: C4Shader.cpp:65
C4Shader()
Definition: C4Shader.cpp:47
GLint GetAttribute(int iAttribute) const
Definition: C4Shader.h:127
void Clear()
Definition: C4Shader.cpp:335
bool HaveUniform(int iUniform) const
Definition: C4Shader.h:122
bool Refresh()
Definition: C4Shader.cpp:445
void AddVertexSlice(int iPos, const char *szText)
Definition: C4Shader.cpp:72
void AddVertexSlices(const char *szWhat, const char *szText, const char *szSource="", int iFileTime=0)
Definition: C4Shader.cpp:82
~C4Shader()
Definition: C4Shader.cpp:53
void SetScriptCategories(const std::vector< std::string > &categories)
Definition: C4Shader.cpp:102
GLint GetUniform(int iUniform) const
Definition: C4Shader.h:117
void ClearSlices()
Definition: C4Shader.cpp:324
static bool IsLogging()
Definition: C4Shader.cpp:665
bool Init(const char *szWhat, const char **szUniforms, const char **szAttributes)
Definition: C4Shader.cpp:348
void AddFragmentSlices(const char *szWhat, const char *szText, const char *szSource="", int iFileTime=0)
Definition: C4Shader.cpp:87
const float * data() const
Definition: StdMeshMath.h:111
const float * data() const
Definition: StdMeshMath.h:137