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