Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ShaderProgram.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "ShaderProgram.h"
21 
22 #include "graphics/ShaderManager.h"
25 #include "maths/Matrix3D.h"
26 #include "maths/Vector3D.h"
27 #include "ps/CLogger.h"
28 #include "ps/Filesystem.h"
29 #include "ps/Overlay.h"
30 #include "ps/PreprocessorWrapper.h"
31 
32 #if !CONFIG2_GLES
33 
35 {
36 public:
37  CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
38  const CShaderDefines& defines,
39  const std::map<CStrIntern, int>& vertexIndexes, const std::map<CStrIntern, frag_index_pair_t>& fragmentIndexes,
40  int streamflags) :
41  CShaderProgram(streamflags),
42  m_VertexFile(vertexFile), m_FragmentFile(fragmentFile),
43  m_Defines(defines),
44  m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes)
45  {
46  pglGenProgramsARB(1, &m_VertexProgram);
47  pglGenProgramsARB(1, &m_FragmentProgram);
48  }
49 
51  {
52  Unload();
53 
54  pglDeleteProgramsARB(1, &m_VertexProgram);
55  pglDeleteProgramsARB(1, &m_FragmentProgram);
56  }
57 
58  bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code)
59  {
61 
62  pglBindProgramARB(target, program);
63 
65 
66  pglProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str());
67 
68  if (ogl_SquelchError(GL_INVALID_OPERATION))
69  {
70  GLint errPos = 0;
71  glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
72  int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1;
73  char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
74  LOGERROR(L"Failed to compile %hs program '%ls' (line %d):\n%hs", targetName, file.string().c_str(), errLine, errStr);
75  return false;
76  }
77 
78  pglBindProgramARB(target, 0);
79 
81 
82  return true;
83  }
84 
85  virtual void Reload()
86  {
87  Unload();
88 
89  CVFSFile vertexFile;
90  if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK)
91  return;
92 
93  CVFSFile fragmentFile;
94  if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK)
95  return;
96 
97  CPreprocessorWrapper preprocessor;
98  preprocessor.AddDefines(m_Defines);
99 
100  CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString());
101  CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString());
102 
103 // printf(">>>\n%s<<<\n", vertexCode.c_str());
104 // printf(">>>\n%s<<<\n", fragmentCode.c_str());
105 
106  if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode))
107  return;
108 
109  if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode))
110  return;
111 
112  m_IsValid = true;
113  }
114 
115  void Unload()
116  {
117  m_IsValid = false;
118  }
119 
120  virtual void Bind()
121  {
122  glEnable(GL_VERTEX_PROGRAM_ARB);
123  glEnable(GL_FRAGMENT_PROGRAM_ARB);
124  pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram);
125  pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram);
126 
128  }
129 
130  virtual void Unbind()
131  {
132  glDisable(GL_VERTEX_PROGRAM_ARB);
133  glDisable(GL_FRAGMENT_PROGRAM_ARB);
134  pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0);
135  pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
136 
138 
139  // TODO: should unbind textures, probably
140  }
141 
143  {
144  std::map<CStrIntern, int>::iterator it = m_VertexIndexes.find(id);
145  if (it == m_VertexIndexes.end())
146  return -1;
147  return it->second;
148  }
149 
151  {
152  std::map<CStrIntern, frag_index_pair_t>::iterator it = m_FragmentIndexes.find(id);
153  if (it == m_FragmentIndexes.end())
154  return std::make_pair(-1, 0);
155  return it->second;
156  }
157 
159  {
161  int index = fPair.first;
162  if (index == -1)
163  return Binding();
164  else
165  return Binding((int)fPair.second, index);
166  }
167 
168  virtual void BindTexture(texture_id_t id, Handle tex)
169  {
171  int index = fPair.first;
172  if (index != -1)
173  {
174  GLuint h;
175  ogl_tex_get_texture_id(tex, &h);
176  pglActiveTextureARB(GL_TEXTURE0+index);
177  glBindTexture(fPair.second, h);
178  }
179  }
180 
181  virtual void BindTexture(texture_id_t id, GLuint tex)
182  {
184  int index = fPair.first;
185  if (index != -1)
186  {
187  pglActiveTextureARB(GL_TEXTURE0+index);
188  glBindTexture(fPair.second, tex);
189  }
190  }
191 
192  virtual void BindTexture(Binding id, Handle tex)
193  {
194  int index = id.second;
195  if (index != -1)
196  ogl_tex_bind(tex, index);
197  }
198 
200  {
202  }
203 
204  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
205  {
206  if (id.first != -1)
207  pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3);
208 
209  if (id.second != -1)
210  pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3);
211  }
212 
213  virtual void Uniform(Binding id, const CMatrix3D& v)
214  {
215  if (id.first != -1)
216  {
217  pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+0, v._11, v._12, v._13, v._14);
218  pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+1, v._21, v._22, v._23, v._24);
219  pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+2, v._31, v._32, v._33, v._34);
220  pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+3, v._41, v._42, v._43, v._44);
221  }
222 
223  if (id.second != -1)
224  {
225  pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+0, v._11, v._12, v._13, v._14);
226  pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+1, v._21, v._22, v._23, v._24);
227  pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+2, v._31, v._32, v._33, v._34);
228  pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+3, v._41, v._42, v._43, v._44);
229  }
230  }
231 
232  virtual void Uniform(Binding id, size_t count, const CMatrix3D* v)
233  {
234  ENSURE(count == 1);
235  Uniform(id, v[0]);
236  }
237 
238 private:
242 
245 
246  std::map<CStrIntern, int> m_VertexIndexes;
247 
248  // pair contains <index, gltype>
249  std::map<CStrIntern, frag_index_pair_t> m_FragmentIndexes;
250 };
251 
252 #endif // #if !CONFIG2_GLES
253 
254 //////////////////////////////////////////////////////////////////////////
255 
256 TIMER_ADD_CLIENT(tc_ShaderGLSLCompile);
257 TIMER_ADD_CLIENT(tc_ShaderGLSLLink);
258 
260 {
261 public:
262  CShaderProgramGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
263  const CShaderDefines& defines,
264  const std::map<CStrIntern, int>& vertexAttribs,
265  int streamflags) :
266  CShaderProgram(streamflags),
267  m_VertexFile(vertexFile), m_FragmentFile(fragmentFile),
268  m_Defines(defines),
269  m_VertexAttribs(vertexAttribs)
270  {
271  m_Program = 0;
272  m_VertexShader = pglCreateShaderObjectARB(GL_VERTEX_SHADER);
273  m_FragmentShader = pglCreateShaderObjectARB(GL_FRAGMENT_SHADER);
274  }
275 
277  {
278  Unload();
279 
280  pglDeleteShader(m_VertexShader);
281  pglDeleteShader(m_FragmentShader);
282  }
283 
284  bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code)
285  {
286  TIMER_ACCRUE(tc_ShaderGLSLCompile);
287 
288  ogl_WarnIfError();
289 
290  const char* code_string = code.c_str();
291  GLint code_length = code.length();
292  pglShaderSourceARB(shader, 1, &code_string, &code_length);
293 
294  pglCompileShaderARB(shader);
295 
296  GLint ok = 0;
297  pglGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
298 
299  GLint length = 0;
300  pglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
301 
302  // Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0
303  // (http://code.google.com/p/android/issues/detail?id=9953)
304  if (!ok && length == 0)
305  length = 4096;
306 
307  if (length > 1)
308  {
309  char* infolog = new char[length];
310  pglGetShaderInfoLog(shader, length, NULL, infolog);
311 
312  if (ok)
313  LOGMESSAGE(L"Info when compiling shader '%ls':\n%hs", file.string().c_str(), infolog);
314  else
315  LOGERROR(L"Failed to compile shader '%ls':\n%hs", file.string().c_str(), infolog);
316 
317  delete[] infolog;
318  }
319 
320  ogl_WarnIfError();
321 
322  return (ok ? true : false);
323  }
324 
325  bool Link()
326  {
327  TIMER_ACCRUE(tc_ShaderGLSLLink);
328 
329  ENSURE(!m_Program);
330  m_Program = pglCreateProgramObjectARB();
331 
332  pglAttachObjectARB(m_Program, m_VertexShader);
333  ogl_WarnIfError();
334  pglAttachObjectARB(m_Program, m_FragmentShader);
335  ogl_WarnIfError();
336 
337  // Set up the attribute bindings explicitly, since apparently drivers
338  // don't always pick the most efficient bindings automatically,
339  // and also this lets us hardcode indexes into VertexPointer etc
340  for (std::map<CStrIntern, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
341  pglBindAttribLocationARB(m_Program, it->second, it->first.c_str());
342 
343  pglLinkProgramARB(m_Program);
344 
345  GLint ok = 0;
346  pglGetProgramiv(m_Program, GL_LINK_STATUS, &ok);
347 
348  GLint length = 0;
349  pglGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length);
350 
351  if (!ok && length == 0)
352  length = 4096;
353 
354  if (length > 1)
355  {
356  char* infolog = new char[length];
357  pglGetProgramInfoLog(m_Program, length, NULL, infolog);
358 
359  if (ok)
360  LOGMESSAGE(L"Info when linking program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog);
361  else
362  LOGERROR(L"Failed to link program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog);
363 
364  delete[] infolog;
365  }
366 
367  ogl_WarnIfError();
368 
369  if (!ok)
370  return false;
371 
372  m_Uniforms.clear();
373  m_Samplers.clear();
374 
375  Bind();
376 
377  ogl_WarnIfError();
378 
379  GLint numUniforms = 0;
380  pglGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms);
381  ogl_WarnIfError();
382  for (GLint i = 0; i < numUniforms; ++i)
383  {
384  char name[256] = {0};
385  GLsizei nameLength = 0;
386  GLint size = 0;
387  GLenum type = 0;
388  pglGetActiveUniformARB(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name);
389  ogl_WarnIfError();
390 
391  GLint loc = pglGetUniformLocationARB(m_Program, name);
392 
393  CStrIntern nameIntern(name);
394  m_Uniforms[nameIntern] = std::make_pair(loc, type);
395 
396  // Assign sampler uniforms to sequential texture units
397  if (type == GL_SAMPLER_2D
398  || type == GL_SAMPLER_CUBE
399 #if !CONFIG2_GLES
400  || type == GL_SAMPLER_2D_SHADOW
401 #endif
402  )
403  {
404  int unit = (int)m_Samplers.size();
405  m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
406  m_Samplers[nameIntern].second = unit;
407  pglUniform1iARB(loc, unit); // link uniform to unit
408  ogl_WarnIfError();
409  }
410  }
411 
412  // TODO: verify that we're not using more samplers than is supported
413 
414  Unbind();
415 
416  ogl_WarnIfError();
417 
418  return true;
419  }
420 
421  virtual void Reload()
422  {
423  Unload();
424 
425  CVFSFile vertexFile;
426  if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK)
427  return;
428 
429  CVFSFile fragmentFile;
430  if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK)
431  return;
432 
433  CPreprocessorWrapper preprocessor;
434  preprocessor.AddDefines(m_Defines);
435 
436 #if CONFIG2_GLES
437  // GLES defines the macro "GL_ES" in its GLSL preprocessor,
438  // but since we run our own preprocessor first, we need to explicitly
439  // define it here
440  preprocessor.AddDefine("GL_ES", "1");
441 #endif
442 
443  CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString());
444  CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString());
445 
446 #if CONFIG2_GLES
447  // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00,
448  // and also to set default float precision for fragment shaders
449  vertexCode.Replace("#version 110\n", "#version 100\n");
450  vertexCode.Replace("#version 110\r\n", "#version 100\n");
451  vertexCode.Replace("#version 120\n", "#version 100\n");
452  vertexCode.Replace("#version 120\r\n", "#version 100\n");
453  fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n");
454  fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n");
455  fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n");
456  fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n");
457 #endif
458 
459  if (!Compile(m_VertexShader, m_VertexFile, vertexCode))
460  return;
461 
462  if (!Compile(m_FragmentShader, m_FragmentFile, fragmentCode))
463  return;
464 
465  if (!Link())
466  return;
467 
468  m_IsValid = true;
469  }
470 
471  void Unload()
472  {
473  m_IsValid = false;
474 
475  if (m_Program)
476  pglDeleteProgram(m_Program);
477  m_Program = 0;
478 
479  // The shader objects can be reused and don't need to be deleted here
480  }
481 
482  virtual void Bind()
483  {
484  pglUseProgramObjectARB(m_Program);
485 
486  for (std::map<CStrIntern, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
487  pglEnableVertexAttribArrayARB(it->second);
488  }
489 
490  virtual void Unbind()
491  {
492  pglUseProgramObjectARB(0);
493 
494  for (std::map<CStrIntern, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
495  pglDisableVertexAttribArrayARB(it->second);
496 
497  // TODO: should unbind textures, probably
498  }
499 
501  {
502  std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
503  if (it == m_Samplers.end())
504  return Binding();
505  else
506  return Binding((int)it->second.first, it->second.second);
507  }
508 
509  virtual void BindTexture(texture_id_t id, Handle tex)
510  {
511  std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
512  if (it == m_Samplers.end())
513  return;
514 
515  GLuint h;
516  ogl_tex_get_texture_id(tex, &h);
517  pglActiveTextureARB(GL_TEXTURE0 + it->second.second);
518  glBindTexture(it->second.first, h);
519  }
520 
521  virtual void BindTexture(texture_id_t id, GLuint tex)
522  {
523  std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
524  if (it == m_Samplers.end())
525  return;
526 
527  pglActiveTextureARB(GL_TEXTURE0 + it->second.second);
528  glBindTexture(it->second.first, tex);
529  }
530 
531  virtual void BindTexture(Binding id, Handle tex)
532  {
533  if (id.second == -1)
534  return;
535 
536  GLuint h;
537  ogl_tex_get_texture_id(tex, &h);
538  pglActiveTextureARB(GL_TEXTURE0 + id.second);
539  glBindTexture(id.first, h);
540  }
541 
543  {
544  std::map<CStrIntern, std::pair<int, GLenum> >::iterator it = m_Uniforms.find(id);
545  if (it == m_Uniforms.end())
546  return Binding();
547  else
548  return Binding(it->second.first, (int)it->second.second);
549  }
550 
551  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
552  {
553  if (id.first != -1)
554  {
555  if (id.second == GL_FLOAT)
556  pglUniform1fARB(id.first, v0);
557  else if (id.second == GL_FLOAT_VEC2)
558  pglUniform2fARB(id.first, v0, v1);
559  else if (id.second == GL_FLOAT_VEC3)
560  pglUniform3fARB(id.first, v0, v1, v2);
561  else if (id.second == GL_FLOAT_VEC4)
562  pglUniform4fARB(id.first, v0, v1, v2, v3);
563  else
564  LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float, vec2, vec3, vec4)");
565  }
566  }
567 
568  virtual void Uniform(Binding id, const CMatrix3D& v)
569  {
570  if (id.first != -1)
571  {
572  if (id.second == GL_FLOAT_MAT4)
573  pglUniformMatrix4fvARB(id.first, 1, GL_FALSE, &v._11);
574  else
575  LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)");
576  }
577  }
578 
579  virtual void Uniform(Binding id, size_t count, const CMatrix3D* v)
580  {
581  if (id.first != -1)
582  {
583  if (id.second == GL_FLOAT_MAT4)
584  pglUniformMatrix4fvARB(id.first, count, GL_FALSE, &v->_11);
585  else
586  LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)");
587  }
588  }
589 
590  // Map the various fixed-function Pointer functions onto generic vertex attributes
591  // (matching the attribute indexes from ShaderManager's ParseAttribSemantics):
592 
593  virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
594  {
595  pglVertexAttribPointerARB(0, size, type, GL_FALSE, stride, pointer);
597  }
598 
599  virtual void NormalPointer(GLenum type, GLsizei stride, void* pointer)
600  {
601  pglVertexAttribPointerARB(2, 3, type, GL_TRUE, stride, pointer);
603  }
604 
605  virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
606  {
607  pglVertexAttribPointerARB(3, size, type, GL_TRUE, stride, pointer);
609  }
610 
611  virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void* pointer)
612  {
613  pglVertexAttribPointerARB(8 + texture - GL_TEXTURE0, size, type, GL_FALSE, stride, pointer);
614  m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0);
615  }
616 
617  virtual void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void* pointer)
618  {
619  std::map<CStrIntern, int>::iterator it = m_VertexAttribs.find(id);
620  if (it != m_VertexAttribs.end())
621  {
622  pglVertexAttribPointerARB(it->second, size, type, normalized, stride, pointer);
623  }
624  }
625 
626  virtual void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, void* pointer)
627  {
628  std::map<CStrIntern, int>::iterator it = m_VertexAttribs.find(id);
629  if (it != m_VertexAttribs.end())
630  {
631 #if CONFIG2_GLES
632  debug_warn(L"glVertexAttribIPointer not supported on GLES");
633 #else
634  pglVertexAttribIPointerEXT(it->second, size, type, stride, pointer);
635 #endif
636  }
637  }
638 
639 private:
643  std::map<CStrIntern, int> m_VertexAttribs;
644 
645  GLhandleARB m_Program;
646  GLhandleARB m_VertexShader;
647  GLhandleARB m_FragmentShader;
648 
649  std::map<CStrIntern, std::pair<int, GLenum> > m_Uniforms;
650  std::map<CStrIntern, std::pair<GLenum, int> > m_Samplers; // texture target & unit chosen for each uniform sampler
651 };
652 
653 //////////////////////////////////////////////////////////////////////////
654 
656  : m_IsValid(false), m_StreamFlags(streamflags), m_ValidStreams(0)
657 {
658 }
659 
660 #if CONFIG2_GLES
661 /*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
662  const CShaderDefines& UNUSED(defines),
663  const std::map<CStrIntern, int>& UNUSED(vertexIndexes), const std::map<CStrIntern, int>& UNUSED(fragmentIndexes),
664  int UNUSED(streamflags))
665 {
666  LOGERROR(L"CShaderProgram::ConstructARB: '%ls'+'%ls': ARB shaders not supported on this device",
667  vertexFile.string().c_str(), fragmentFile.string().c_str());
668  return NULL;
669 }
670 #else
671 /*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
672  const CShaderDefines& defines,
673  const std::map<CStrIntern, int>& vertexIndexes, const std::map<CStrIntern, frag_index_pair_t>& fragmentIndexes,
674  int streamflags)
675 {
676  return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags);
677 }
678 #endif
679 
680 /*static*/ CShaderProgram* CShaderProgram::ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
681  const CShaderDefines& defines,
682  const std::map<CStrIntern, int>& vertexAttribs,
683  int streamflags)
684 {
685  return new CShaderProgramGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamflags);
686 }
687 
689 {
690  return m_IsValid;
691 }
692 
694 {
695  return m_StreamFlags;
696 }
697 
699 {
700  BindTexture(id, tex->GetHandle());
701 }
702 
704 {
705  Uniform(id, (float)v, (float)v, (float)v, (float)v);
706 }
707 
709 {
710  Uniform(id, v, v, v, v);
711 }
712 
713 void CShaderProgram::Uniform(Binding id, float v0, float v1)
714 {
715  Uniform(id, v0, v1, 0.0f, 0.0f);
716 }
717 
719 {
720  Uniform(id, v.X, v.Y, v.Z, 0.0f);
721 }
722 
724 {
725  Uniform(id, v.r, v.g, v.b, v.a);
726 }
727 
729 {
730  Uniform(GetUniformBinding(id), (float)v, (float)v, (float)v, (float)v);
731 }
732 
734 {
735  Uniform(GetUniformBinding(id), v, v, v, v);
736 }
737 
738 void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1)
739 {
740  Uniform(GetUniformBinding(id), v0, v1, 0.0f, 0.0f);
741 }
742 
744 {
745  Uniform(GetUniformBinding(id), v.X, v.Y, v.Z, 0.0f);
746 }
747 
749 {
750  Uniform(GetUniformBinding(id), v.r, v.g, v.b, v.a);
751 }
752 
753 void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1, float v2, float v3)
754 {
755  Uniform(GetUniformBinding(id), v0, v1, v2, v3);
756 }
757 
759 {
760  Uniform(GetUniformBinding(id), v);
761 }
762 
763 void CShaderProgram::Uniform(uniform_id_t id, size_t count, const CMatrix3D* v)
764 {
765  Uniform(GetUniformBinding(id), count, v);
766 }
767 
768 
769 // These should all be overridden by CShaderProgramGLSL, and not used
770 // if a non-GLSL shader was loaded instead:
771 
773  GLboolean UNUSED(normalized), GLsizei UNUSED(stride), void* UNUSED(pointer))
774 {
775  debug_warn("Shader type doesn't support VertexAttribPointer");
776 }
777 
779  GLsizei UNUSED(stride), void* UNUSED(pointer))
780 {
781  debug_warn("Shader type doesn't support VertexAttribIPointer");
782 }
783 
784 #if CONFIG2_GLES
785 
786 // These should all be overridden by CShaderProgramGLSL
787 // (GLES doesn't support any other types of shader program):
788 
789 void CShaderProgram::VertexPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
790 {
791  debug_warn("CShaderProgram::VertexPointer should be overridden");
792 }
793 void CShaderProgram::NormalPointer(GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
794 {
795  debug_warn("CShaderProgram::NormalPointer should be overridden");
796 }
797 void CShaderProgram::ColorPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
798 {
799  debug_warn("CShaderProgram::ColorPointer should be overridden");
800 }
801 void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
802 {
803  debug_warn("CShaderProgram::TexCoordPointer should be overridden");
804 }
805 
806 #else
807 
808 // These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders
809 // both use the fixed-function vertex attribute pointers so we'll share their
810 // definitions here:
811 
812 void CShaderProgram::VertexPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
813 {
814  glVertexPointer(size, type, stride, pointer);
816 }
817 
818 void CShaderProgram::NormalPointer(GLenum type, GLsizei stride, void* pointer)
819 {
820  glNormalPointer(type, stride, pointer);
822 }
823 
824 void CShaderProgram::ColorPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
825 {
826  glColorPointer(size, type, stride, pointer);
828 }
829 
830 void CShaderProgram::TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void* pointer)
831 {
832  pglClientActiveTextureARB(texture);
833  glTexCoordPointer(size, type, stride, pointer);
834  pglClientActiveTextureARB(GL_TEXTURE0);
835  m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0);
836 }
837 
839 {
841 
842  // Enable all the desired client states for non-GLSL rendering
843 
844  if (m_StreamFlags & STREAM_POS) glEnableClientState(GL_VERTEX_ARRAY);
845  if (m_StreamFlags & STREAM_NORMAL) glEnableClientState(GL_NORMAL_ARRAY);
846  if (m_StreamFlags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
847 
849  {
850  pglClientActiveTextureARB(GL_TEXTURE0);
851  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
852  }
853 
855  {
856  pglClientActiveTextureARB(GL_TEXTURE1);
857  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
858  pglClientActiveTextureARB(GL_TEXTURE0);
859  }
860 
861  // Rendering code must subsequently call VertexPointer etc for all of the streams
862  // that were activated in this function, else AssertPointersBound will complain
863  // that some arrays were unspecified
864  m_ValidStreams = 0;
865 }
866 
868 {
869  if (m_StreamFlags & STREAM_POS) glDisableClientState(GL_VERTEX_ARRAY);
870  if (m_StreamFlags & STREAM_NORMAL) glDisableClientState(GL_NORMAL_ARRAY);
871  if (m_StreamFlags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
872 
874  {
875  pglClientActiveTextureARB(GL_TEXTURE0);
876  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
877  }
878 
880  {
881  pglClientActiveTextureARB(GL_TEXTURE1);
882  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
883  pglClientActiveTextureARB(GL_TEXTURE0);
884  }
885 }
886 
887 #endif // !CONFIG2_GLES
888 
890 {
892 }
float _21
Definition: Matrix3D.h:42
virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, void *pointer)
virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, void *pointer)
float g
Definition: Overlay.h:57
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
void BindTexture(texture_id_t id, CTexturePtr tex)
float _22
Definition: Matrix3D.h:43
GLhandleARB m_FragmentShader
int GetStreamFlags() const
Returns bitset of STREAM_* value, indicating what vertex data streams the vertex shader needs (e...
float _12
Definition: Matrix3D.h:43
virtual Binding GetUniformBinding(uniform_id_t id)=0
#define LOGERROR
Definition: CLogger.h:35
frag_index_pair_t GetUniformFragmentIndex(CStrIntern id)
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
float _44
Definition: Matrix3D.h:45
Reads a file, then gives read-only access to the contents.
Definition: Filesystem.h:69
bool IsValid() const
Returns whether this shader was successfully loaded.
Definition: Overlay.h:34
virtual void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, void *pointer)
virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, void *pointer)
virtual void Reload()
virtual void Unbind()
Unbinds the shader from the GL context.
std::map< CStrIntern, int > m_VertexIndexes
#define LOGMESSAGE
Definition: CLogger.h:32
virtual void Unbind()
Unbinds the shader from the GL context.
CShaderProgramARB(const VfsPath &vertexFile, const VfsPath &fragmentFile, const CShaderDefines &defines, const std::map< CStrIntern, int > &vertexIndexes, const std::map< CStrIntern, frag_index_pair_t > &fragmentIndexes, int streamflags)
float _43
Definition: Matrix3D.h:44
virtual void BindTexture(texture_id_t id, GLuint tex)
void UnbindClientStates()
virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void *pointer)
virtual void BindTexture(texture_id_t id, GLuint tex)
static CShaderProgram * ConstructARB(const VfsPath &vertexFile, const VfsPath &fragmentFile, const CShaderDefines &defines, const std::map< CStrIntern, int > &vertexIndexes, const std::map< CStrIntern, frag_index_pair_t > &fragmentIndexes, int streamflags)
Construct based on ARB vertex/fragment program files.
virtual void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, void *pointer)
float _32
Definition: Matrix3D.h:43
bool ogl_SquelchError(GLenum err_to_ignore)
ignore and reset the specified OpenGL error.
Definition: ogl.cpp:430
void AssertPointersBound()
Checks that all the required vertex attributes have been set.
int GetUniformVertexIndex(CStrIntern id)
float _11
Definition: Matrix3D.h:42
#define ARRAY_SIZE(name)
virtual void Uniform(Binding id, size_t count, const CMatrix3D *v)
#define TIMER_ACCRUE(client)
Measure the time taken to execute code up until end of the current scope; bill it to the given TimerC...
Definition: timer.h:389
float _33
Definition: Matrix3D.h:44
Status ogl_tex_bind(Handle ht, size_t unit)
Bind texture to the specified unit in preparation for using it in rendering.
Definition: ogl_tex.cpp:1054
CStr GetAsString() const
Returns contents of file as a string.
Definition: Filesystem.cpp:148
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
float b
Definition: Overlay.h:57
virtual void Uniform(Binding id, size_t count, const CMatrix3D *v)
std::map< CStrIntern, frag_index_pair_t > m_FragmentIndexes
Interned 8-bit strings.
Definition: CStrIntern.h:37
float X
Definition: Vector3D.h:31
std::map< CStrIntern, std::pair< int, GLenum > > m_Uniforms
Definition: path.h:75
virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void *pointer)
float Y
Definition: Vector3D.h:31
bool Compile(GLhandleARB shader, const VfsPath &file, const CStr &code)
const String & string() const
Definition: path.h:123
virtual Binding GetTextureBinding(texture_id_t id)
virtual void BindTexture(Binding id, Handle tex)
float _13
Definition: Matrix3D.h:44
float _31
Definition: Matrix3D.h:42
float a
Definition: Overlay.h:57
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
float _42
Definition: Matrix3D.h:43
bool Compile(GLuint target, const char *targetName, GLuint program, const VfsPath &file, const CStr &code)
float _24
Definition: Matrix3D.h:45
i64 Handle
`handle&#39; representing a reference to a resource (sound, texture, etc.)
Definition: handle.h:41
virtual void Reload()
virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, void *pointer)
CShaderProgram(int streamflags)
CShaderProgramGLSL(const VfsPath &vertexFile, const VfsPath &fragmentFile, const CShaderDefines &defines, const std::map< CStrIntern, int > &vertexAttribs, int streamflags)
std::map< CStrIntern, int > m_VertexAttribs
float _34
Definition: Matrix3D.h:45
virtual Binding GetUniformBinding(uniform_id_t id)
virtual void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void *pointer)
Represents a mapping of name strings to value strings, for use with #if and #ifdef and similar condit...
CStr Preprocess(const CStr &input)
virtual void Uniform(Binding id, const CMatrix3D &v)
virtual void BindTexture(Binding id, Handle tex)
std::map< CStrIntern, std::pair< GLenum, int > > m_Samplers
void AddDefines(const CShaderDefines &defines)
#define TIMER_ADD_CLIENT(id)
&quot;allocate&quot; a new TimerClient that will keep track of the total time billed to it, along with a descri...
Definition: timer.h:308
Status ogl_tex_get_texture_id(Handle ht, GLuint *id)
Return the GL handle of the loaded texture in *id, or 0 on failure.
Definition: ogl_tex.cpp:1085
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
Definition: Filesystem.cpp:117
float _23
Definition: Matrix3D.h:44
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)=0
Represents a uniform attribute or texture binding.
virtual void BindTexture(texture_id_t id, Handle tex)
virtual void NormalPointer(GLenum type, GLsizei stride, void *pointer)
virtual void NormalPointer(GLenum type, GLsizei stride, void *pointer)
std::pair< int, GLenum > frag_index_pair_t
Definition: ShaderProgram.h:73
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
virtual Binding GetTextureBinding(texture_id_t id)
float Z
Definition: Vector3D.h:31
void AddDefine(const char *name, const char *value)
GLhandleARB m_VertexShader
void ogl_WarnIfError()
raise a warning (break into the debugger) if an OpenGL error is pending.
Definition: ogl.cpp:398
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
virtual void Bind()
Binds the shader into the GL context.
CShaderDefines m_Defines
Convenience wrapper around CPreprocessor.
virtual void BindTexture(texture_id_t id, Handle tex)
virtual void Uniform(Binding id, const CMatrix3D &v)
#define CONFIG2_GLES
Definition: config2.h:101
A compiled vertex+fragment shader program.
Definition: ShaderProgram.h:65
PIVFS g_VFS
Definition: Filesystem.cpp:30
float _41
Definition: Matrix3D.h:42
static CShaderProgram * ConstructGLSL(const VfsPath &vertexFile, const VfsPath &fragmentFile, const CShaderDefines &defines, const std::map< CStrIntern, int > &vertexAttribs, int streamflags)
Construct based on GLSL vertex/fragment shader files.
virtual void Bind()
Binds the shader into the GL context.
virtual Binding GetUniformBinding(uniform_id_t id)
CShaderDefines m_Defines
float r
Definition: Overlay.h:57
virtual void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void *pointer)
float _14
Definition: Matrix3D.h:45
shared_ptr< CTexture > CTexturePtr
Definition: Texture.h:22