1 /* Copyright (C) 2017 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"
23 #include "graphics/TextureManager.h"
24 #include "lib/res/graphics/ogl_tex.h"
25 #include "maths/Matrix3D.h"
26 #include "maths/Vector3D.h"
27 #include "ps/CLogger.h"
28 #include "ps/Filesystem.h"
29 #include "ps/PreprocessorWrapper.h"
30 #include "ps/Shapes.h"
31
32 #if !CONFIG2_GLES
33
34 class CShaderProgramARB : public CShaderProgram
35 {
36 public:
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)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
~CShaderProgramARB()50 ~CShaderProgramARB()
51 {
52 Unload();
53
54 pglDeleteProgramsARB(1, &m_VertexProgram);
55 pglDeleteProgramsARB(1, &m_FragmentProgram);
56 }
57
Compile(GLuint target,const char * targetName,GLuint program,const VfsPath & file,const CStr & code)58 bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code)
59 {
60 ogl_WarnIfError();
61
62 pglBindProgramARB(target, program);
63
64 ogl_WarnIfError();
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("Failed to compile %s program '%s' (line %d):\n%s", targetName, file.string8(), errLine, errStr);
75 return false;
76 }
77
78 pglBindProgramARB(target, 0);
79
80 ogl_WarnIfError();
81
82 return true;
83 }
84
Reload()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
Unload()115 void Unload()
116 {
117 m_IsValid = false;
118 }
119
Bind()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
127 BindClientStates();
128 }
129
Unbind()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
137 UnbindClientStates();
138
139 // TODO: should unbind textures, probably
140 }
141
GetUniformVertexIndex(CStrIntern id)142 int GetUniformVertexIndex(CStrIntern id)
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
GetUniformFragmentIndex(CStrIntern id)150 frag_index_pair_t GetUniformFragmentIndex(CStrIntern id)
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
GetTextureBinding(texture_id_t id)158 virtual Binding GetTextureBinding(texture_id_t id)
159 {
160 frag_index_pair_t fPair = GetUniformFragmentIndex(id);
161 int index = fPair.first;
162 if (index == -1)
163 return Binding();
164 else
165 return Binding((int)fPair.second, index);
166 }
167
BindTexture(texture_id_t id,Handle tex)168 virtual void BindTexture(texture_id_t id, Handle tex)
169 {
170 frag_index_pair_t fPair = GetUniformFragmentIndex(id);
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
BindTexture(texture_id_t id,GLuint tex)181 virtual void BindTexture(texture_id_t id, GLuint tex)
182 {
183 frag_index_pair_t fPair = GetUniformFragmentIndex(id);
184 int index = fPair.first;
185 if (index != -1)
186 {
187 pglActiveTextureARB(GL_TEXTURE0+index);
188 glBindTexture(fPair.second, tex);
189 }
190 }
191
BindTexture(Binding id,Handle tex)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
GetUniformBinding(uniform_id_t id)199 virtual Binding GetUniformBinding(uniform_id_t id)
200 {
201 return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id).first);
202 }
203
Uniform(Binding id,float v0,float v1,float v2,float v3)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
Uniform(Binding id,const CMatrix3D & v)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
Uniform(Binding id,size_t count,const CMatrix3D * v)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:
239 VfsPath m_VertexFile;
240 VfsPath m_FragmentFile;
241 CShaderDefines m_Defines;
242
243 GLuint m_VertexProgram;
244 GLuint m_FragmentProgram;
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
259 class CShaderProgramGLSL : public CShaderProgram
260 {
261 public:
CShaderProgramGLSL(const VfsPath & vertexFile,const VfsPath & fragmentFile,const CShaderDefines & defines,const std::map<CStrIntern,int> & vertexAttribs,int streamflags)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
~CShaderProgramGLSL()276 ~CShaderProgramGLSL()
277 {
278 Unload();
279
280 pglDeleteShader(m_VertexShader);
281 pglDeleteShader(m_FragmentShader);
282 }
283
Compile(GLhandleARB shader,const VfsPath & file,const CStr & code)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("Info when compiling shader '%s':\n%s", file.string8(), infolog);
314 else
315 LOGERROR("Failed to compile shader '%s':\n%s", file.string8(), infolog);
316
317 delete[] infolog;
318 }
319
320 ogl_WarnIfError();
321
322 return (ok ? true : false);
323 }
324
Link()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("Info when linking program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog);
361 else
362 LOGERROR("Failed to link program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), 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
Reload()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
Unload()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
Bind()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
Unbind()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
GetTextureBinding(texture_id_t id)500 virtual Binding GetTextureBinding(texture_id_t id)
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
BindTexture(texture_id_t id,Handle tex)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
BindTexture(texture_id_t id,GLuint tex)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
BindTexture(Binding id,Handle tex)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
GetUniformBinding(uniform_id_t id)542 virtual Binding GetUniformBinding(uniform_id_t id)
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
Uniform(Binding id,float v0,float v1,float v2,float v3)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("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float, vec2, vec3, vec4)");
565 }
566 }
567
Uniform(Binding id,const CMatrix3D & v)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("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)");
576 }
577 }
578
Uniform(Binding id,size_t count,const CMatrix3D * v)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("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
VertexPointer(GLint size,GLenum type,GLsizei stride,const void * pointer)593 virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer)
594 {
595 pglVertexAttribPointerARB(0, size, type, GL_FALSE, stride, pointer);
596 m_ValidStreams |= STREAM_POS;
597 }
598
NormalPointer(GLenum type,GLsizei stride,const void * pointer)599 virtual void NormalPointer(GLenum type, GLsizei stride, const void* pointer)
600 {
601 pglVertexAttribPointerARB(2, 3, type, GL_TRUE, stride, pointer);
602 m_ValidStreams |= STREAM_NORMAL;
603 }
604
ColorPointer(GLint size,GLenum type,GLsizei stride,const void * pointer)605 virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer)
606 {
607 pglVertexAttribPointerARB(3, size, type, GL_TRUE, stride, pointer);
608 m_ValidStreams |= STREAM_COLOR;
609 }
610
TexCoordPointer(GLenum texture,GLint size,GLenum type,GLsizei stride,const void * pointer)611 virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const 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
VertexAttribPointer(attrib_id_t id,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const void * pointer)617 virtual void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const 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
VertexAttribIPointer(attrib_id_t id,GLint size,GLenum type,GLsizei stride,const void * pointer)626 virtual void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, const 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:
640 VfsPath m_VertexFile;
641 VfsPath m_FragmentFile;
642 CShaderDefines m_Defines;
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
CShaderProgram(int streamflags)655 CShaderProgram::CShaderProgram(int streamflags)
656 : m_IsValid(false), m_StreamFlags(streamflags), m_ValidStreams(0)
657 {
658 }
659
660 #if CONFIG2_GLES
ConstructARB(const VfsPath & vertexFile,const VfsPath & fragmentFile,const CShaderDefines & UNUSED (defines),const std::map<CStrIntern,int> & UNUSED (vertexIndexes),const std::map<CStrIntern,frag_index_pair_t> & UNUSED (fragmentIndexes),int UNUSED (streamflags))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, frag_index_pair_t>& UNUSED(fragmentIndexes),
664 int UNUSED(streamflags))
665 {
666 LOGERROR("CShaderProgram::ConstructARB: '%s'+'%s': ARB shaders not supported on this device",
667 vertexFile.string8(), fragmentFile.string8());
668 return NULL;
669 }
670 #else
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)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
ConstructGLSL(const VfsPath & vertexFile,const VfsPath & fragmentFile,const CShaderDefines & defines,const std::map<CStrIntern,int> & vertexAttribs,int streamflags)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
IsValid() const688 bool CShaderProgram::IsValid() const
689 {
690 return m_IsValid;
691 }
692
GetStreamFlags() const693 int CShaderProgram::GetStreamFlags() const
694 {
695 return m_StreamFlags;
696 }
697
BindTexture(texture_id_t id,CTexturePtr tex)698 void CShaderProgram::BindTexture(texture_id_t id, CTexturePtr tex)
699 {
700 BindTexture(id, tex->GetHandle());
701 }
702
Uniform(Binding id,int v)703 void CShaderProgram::Uniform(Binding id, int v)
704 {
705 Uniform(id, (float)v, (float)v, (float)v, (float)v);
706 }
707
Uniform(Binding id,float v)708 void CShaderProgram::Uniform(Binding id, float v)
709 {
710 Uniform(id, v, v, v, v);
711 }
712
Uniform(Binding id,float v0,float v1)713 void CShaderProgram::Uniform(Binding id, float v0, float v1)
714 {
715 Uniform(id, v0, v1, 0.0f, 0.0f);
716 }
717
Uniform(Binding id,const CVector3D & v)718 void CShaderProgram::Uniform(Binding id, const CVector3D& v)
719 {
720 Uniform(id, v.X, v.Y, v.Z, 0.0f);
721 }
722
Uniform(Binding id,const CColor & v)723 void CShaderProgram::Uniform(Binding id, const CColor& v)
724 {
725 Uniform(id, v.r, v.g, v.b, v.a);
726 }
727
Uniform(uniform_id_t id,int v)728 void CShaderProgram::Uniform(uniform_id_t id, int v)
729 {
730 Uniform(GetUniformBinding(id), (float)v, (float)v, (float)v, (float)v);
731 }
732
Uniform(uniform_id_t id,float v)733 void CShaderProgram::Uniform(uniform_id_t id, float v)
734 {
735 Uniform(GetUniformBinding(id), v, v, v, v);
736 }
737
Uniform(uniform_id_t id,float v0,float v1)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
Uniform(uniform_id_t id,const CVector3D & v)743 void CShaderProgram::Uniform(uniform_id_t id, const CVector3D& v)
744 {
745 Uniform(GetUniformBinding(id), v.X, v.Y, v.Z, 0.0f);
746 }
747
Uniform(uniform_id_t id,const CColor & v)748 void CShaderProgram::Uniform(uniform_id_t id, const CColor& v)
749 {
750 Uniform(GetUniformBinding(id), v.r, v.g, v.b, v.a);
751 }
752
Uniform(uniform_id_t id,float v0,float v1,float v2,float v3)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
Uniform(uniform_id_t id,const CMatrix3D & v)758 void CShaderProgram::Uniform(uniform_id_t id, const CMatrix3D& v)
759 {
760 Uniform(GetUniformBinding(id), v);
761 }
762
Uniform(uniform_id_t id,size_t count,const CMatrix3D * v)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
VertexAttribPointer(attrib_id_t UNUSED (id),GLint UNUSED (size),GLenum UNUSED (type),GLboolean UNUSED (normalized),GLsizei UNUSED (stride),const void * UNUSED (pointer))772 void CShaderProgram::VertexAttribPointer(attrib_id_t UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type),
773 GLboolean UNUSED(normalized), GLsizei UNUSED(stride), const void* UNUSED(pointer))
774 {
775 debug_warn("Shader type doesn't support VertexAttribPointer");
776 }
777
VertexAttribIPointer(attrib_id_t UNUSED (id),GLint UNUSED (size),GLenum UNUSED (type),GLsizei UNUSED (stride),const void * UNUSED (pointer))778 void CShaderProgram::VertexAttribIPointer(attrib_id_t UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type),
779 GLsizei UNUSED(stride), const 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
VertexPointer(GLint UNUSED (size),GLenum UNUSED (type),GLsizei UNUSED (stride),const void * UNUSED (pointer))789 void CShaderProgram::VertexPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer))
790 {
791 debug_warn("CShaderProgram::VertexPointer should be overridden");
792 }
NormalPointer(GLenum UNUSED (type),GLsizei UNUSED (stride),const void * UNUSED (pointer))793 void CShaderProgram::NormalPointer(GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer))
794 {
795 debug_warn("CShaderProgram::NormalPointer should be overridden");
796 }
ColorPointer(GLint UNUSED (size),GLenum UNUSED (type),GLsizei UNUSED (stride),const void * UNUSED (pointer))797 void CShaderProgram::ColorPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer))
798 {
799 debug_warn("CShaderProgram::ColorPointer should be overridden");
800 }
TexCoordPointer(GLenum UNUSED (texture),GLint UNUSED (size),GLenum UNUSED (type),GLsizei UNUSED (stride),const void * UNUSED (pointer))801 void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const 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
VertexPointer(GLint size,GLenum type,GLsizei stride,const void * pointer)812 void CShaderProgram::VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer)
813 {
814 glVertexPointer(size, type, stride, pointer);
815 m_ValidStreams |= STREAM_POS;
816 }
817
NormalPointer(GLenum type,GLsizei stride,const void * pointer)818 void CShaderProgram::NormalPointer(GLenum type, GLsizei stride, const void* pointer)
819 {
820 glNormalPointer(type, stride, pointer);
821 m_ValidStreams |= STREAM_NORMAL;
822 }
823
ColorPointer(GLint size,GLenum type,GLsizei stride,const void * pointer)824 void CShaderProgram::ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer)
825 {
826 glColorPointer(size, type, stride, pointer);
827 m_ValidStreams |= STREAM_COLOR;
828 }
829
TexCoordPointer(GLenum texture,GLint size,GLenum type,GLsizei stride,const void * pointer)830 void CShaderProgram::TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const 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
BindClientStates()838 void CShaderProgram::BindClientStates()
839 {
840 ENSURE(m_StreamFlags == (m_StreamFlags & (STREAM_POS|STREAM_NORMAL|STREAM_COLOR|STREAM_UV0|STREAM_UV1)));
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
848 if (m_StreamFlags & STREAM_UV0)
849 {
850 pglClientActiveTextureARB(GL_TEXTURE0);
851 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
852 }
853
854 if (m_StreamFlags & STREAM_UV1)
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
UnbindClientStates()867 void CShaderProgram::UnbindClientStates()
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
873 if (m_StreamFlags & STREAM_UV0)
874 {
875 pglClientActiveTextureARB(GL_TEXTURE0);
876 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
877 }
878
879 if (m_StreamFlags & STREAM_UV1)
880 {
881 pglClientActiveTextureARB(GL_TEXTURE1);
882 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
883 pglClientActiveTextureARB(GL_TEXTURE0);
884 }
885 }
886
887 #endif // !CONFIG2_GLES
888
AssertPointersBound()889 void CShaderProgram::AssertPointersBound()
890 {
891 ENSURE((m_StreamFlags & ~m_ValidStreams) == 0);
892 }
893