1 /* Copyright (C) 2014 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/ShaderDefines.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 "renderer/Renderer.h"
29 
30 #if !CONFIG2_GLES
31 
32 /**
33  * CShaderProgramFFP allows rendering code to use the shader-based API
34  * even if the 'shader' is actually implemented with the fixed-function
35  * pipeline instead of anything programmable.
36  *
37  * Currently we just hard-code a number of FFP programs as subclasses of this.
38  * If we have lots, it might be nicer to abstract out the common functionality
39  * and load these from text files or something.
40  */
41 class CShaderProgramFFP : public CShaderProgram
42 {
43 public:
CShaderProgramFFP(int streamflags)44 	CShaderProgramFFP(int streamflags) :
45 		CShaderProgram(streamflags)
46 	{
47 	}
48 
~CShaderProgramFFP()49 	~CShaderProgramFFP()
50 	{
51 	}
52 
Reload()53 	virtual void Reload()
54 	{
55 		m_IsValid = true;
56 	}
57 
GetUniformIndex(CStrIntern id)58 	int GetUniformIndex(CStrIntern id)
59 	{
60 		std::map<CStrIntern, int>::iterator it = m_UniformIndexes.find(id);
61 		if (it == m_UniformIndexes.end())
62 			return -1;
63 		return it->second;
64 	}
65 
GetTextureBinding(uniform_id_t id)66 	virtual Binding GetTextureBinding(uniform_id_t id)
67 	{
68 		int index = GetUniformIndex(CStrIntern(id));
69 		if (index == -1)
70 			return Binding();
71 		else
72 			return Binding((int)GL_TEXTURE_2D, index);
73 	}
74 
BindTexture(texture_id_t id,Handle tex)75 	virtual void BindTexture(texture_id_t id, Handle tex)
76 	{
77 		int index = GetUniformIndex(CStrIntern(id));
78 		if (index != -1)
79 			ogl_tex_bind(tex, index);
80 	}
81 
BindTexture(texture_id_t id,GLuint tex)82 	virtual void BindTexture(texture_id_t id, GLuint tex)
83 	{
84 		int index = GetUniformIndex(CStrIntern(id));
85 		if (index != -1)
86 		{
87 			pglActiveTextureARB((int)(GL_TEXTURE0+index));
88 			glBindTexture(GL_TEXTURE_2D, tex);
89 		}
90 	}
91 
BindTexture(Binding id,Handle tex)92 	virtual void BindTexture(Binding id, Handle tex)
93 	{
94 		int index = id.second;
95 		if (index != -1)
96 			ogl_tex_bind(tex, index);
97 	}
98 
GetUniformBinding(uniform_id_t id)99 	virtual Binding GetUniformBinding(uniform_id_t id)
100 	{
101 		return Binding(-1, GetUniformIndex(id));
102 	}
103 
Uniform(Binding UNUSED (id),float UNUSED (v0),float UNUSED (v1),float UNUSED (v2),float UNUSED (v3))104 	virtual void Uniform(Binding UNUSED(id), float UNUSED(v0), float UNUSED(v1), float UNUSED(v2), float UNUSED(v3))
105 	{
106 	}
107 
Uniform(Binding UNUSED (id),const CMatrix3D & UNUSED (v))108 	virtual void Uniform(Binding UNUSED(id), const CMatrix3D& UNUSED(v))
109 	{
110 	}
111 
Uniform(Binding UNUSED (id),size_t UNUSED (count),const CMatrix3D * UNUSED (v))112 	virtual void Uniform(Binding UNUSED(id), size_t UNUSED(count), const CMatrix3D* UNUSED(v))
113 	{
114 	}
115 
116 protected:
117 	std::map<CStrIntern, int> m_UniformIndexes;
118 
SetUniformIndex(const char * id,int value)119 	void SetUniformIndex(const char* id, int value)
120 	{
121 		m_UniformIndexes[CStrIntern(id)] = value;
122 	}
123 };
124 
125 //////////////////////////////////////////////////////////////////////////
126 
127 /**
128  * A shader that does nothing but provide a shader-compatible interface to
129  * fixed-function features, for compatibility with existing fixed-function
130  * code that isn't fully ported to the shader API.
131  */
132 class CShaderProgramFFP_Dummy : public CShaderProgramFFP
133 {
134 public:
CShaderProgramFFP_Dummy()135 	CShaderProgramFFP_Dummy() :
136 		CShaderProgramFFP(0)
137 	{
138 		// Texture units, for when this shader is used with terrain:
139 		SetUniformIndex("baseTex", 0);
140 	}
141 
Bind()142 	virtual void Bind()
143 	{
144 		BindClientStates();
145 	}
146 
Unbind()147 	virtual void Unbind()
148 	{
149 		UnbindClientStates();
150 	}
151 };
152 
153 //////////////////////////////////////////////////////////////////////////
154 
155 class CShaderProgramFFP_OverlayLine : public CShaderProgramFFP
156 {
157 	// Uniforms
158 	enum
159 	{
160 		ID_losTransform,
161 		ID_objectColor
162 	};
163 
164 	bool m_IgnoreLos;
165 	bool m_UseObjectColor;
166 
167 public:
CShaderProgramFFP_OverlayLine(const CShaderDefines & defines)168 	CShaderProgramFFP_OverlayLine(const CShaderDefines& defines) :
169 		CShaderProgramFFP(0) // will be set manually in initializer below
170 	{
171 		SetUniformIndex("losTransform", ID_losTransform);
172 		SetUniformIndex("objectColor", ID_objectColor);
173 
174 		// Texture units:
175 		SetUniformIndex("baseTex", 0);
176 		SetUniformIndex("maskTex", 1);
177 		SetUniformIndex("losTex", 2);
178 
179 		m_IgnoreLos = (defines.GetInt("IGNORE_LOS") != 0);
180 		m_UseObjectColor = (defines.GetInt("USE_OBJECTCOLOR") != 0);
181 
182 		m_StreamFlags = STREAM_POS | STREAM_UV0 | STREAM_UV1;
183 		if (!m_UseObjectColor)
184 			m_StreamFlags |= STREAM_COLOR;
185 	}
186 
IsIgnoreLos()187 	bool IsIgnoreLos()
188 	{
189 		return m_IgnoreLos;
190 	}
191 
Uniform(Binding id,float v0,float v1,float v2,float v3)192 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
193 	{
194 		if (id.second == ID_losTransform)
195 		{
196 			pglActiveTextureARB(GL_TEXTURE2);
197 			GLfloat texgenS1[4] = { v0, 0, 0, v1 };
198 			GLfloat texgenT1[4] = { 0, 0, v0, v1 };
199 			glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1);
200 			glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1);
201 		}
202 		else if (id.second == ID_objectColor)
203 		{
204 			float c[] = { v0, v1, v2, v3 };
205 			pglActiveTextureARB(GL_TEXTURE1);
206 			glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, c);
207 		}
208 		else
209 		{
210 			debug_warn(L"Invalid id");
211 		}
212 	}
213 
Uniform(Binding UNUSED (id),const CMatrix3D & UNUSED (v))214 	virtual void Uniform(Binding UNUSED(id), const CMatrix3D& UNUSED(v))
215 	{
216 		debug_warn(L"Not implemented");
217 	}
218 
Bind()219 	virtual void Bind()
220 	{
221 		// RGB channels:
222 		//   Unit 0: Sample base texture
223 		//   Unit 1: Sample mask texture; interpolate with [objectColor or vertexColor] and base, depending on USE_OBJECTCOLOR
224 		//   Unit 2: (Load LOS texture; multiply) if not #IGNORE_LOS, pass through otherwise
225 		// Alpha channel:
226 		//   Unit 0: Sample base texture
227 		//   Unit 1: Multiply by objectColor
228 		//   Unit 2: Pass through
229 
230 		pglActiveTextureARB(GL_TEXTURE0);
231 		glEnable(GL_TEXTURE_2D);
232 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
233 
234 		// Sample base texture RGB
235 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
236 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
237 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
238 
239 		// Sample base texture Alpha
240 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
241 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
242 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
243 
244 		// -----------------------------------------------------------------------------
245 
246 		pglActiveTextureARB(GL_TEXTURE1);
247 		glEnable(GL_TEXTURE_2D);
248 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
249 
250 		// RGB: interpolate component-wise between [objectColor or vertexColor] and base using mask:
251 		//   a0 * a2 + a1 * (1 - a2)
252 		// Overridden implementation of Uniform() sets GL_TEXTURE_ENV_COLOR to objectColor, which
253 		// is referenced as GL_CONSTANT (see spec)
254 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE);
255 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, m_UseObjectColor ? GL_CONSTANT : GL_PRIMARY_COLOR);
256 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
257 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);
258 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
259 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
260 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
261 
262 		// ALPHA: Multiply base alpha with [objectColor or vertexColor] alpha
263 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
264 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, m_UseObjectColor ? GL_CONSTANT : GL_PRIMARY_COLOR);
265 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
266 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS);
267 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
268 
269 		// -----------------------------------------------------------------------------
270 
271 		pglActiveTextureARB(GL_TEXTURE2);
272 		glEnable(GL_TEXTURE_2D);
273 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
274 
275 		bool ignoreLos = IsIgnoreLos();
276 		if (ignoreLos)
277 		{
278 			// RGB pass through
279 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
280 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
281 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
282 		}
283 		else
284 		{
285 			// Multiply RGB result up till now with LoS texture alpha channel
286 			glEnable(GL_TEXTURE_GEN_S);
287 			glEnable(GL_TEXTURE_GEN_T);
288 			glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
289 			glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
290 			// Overridden implementation of Uniform() sets GL_OBJECT_PLANE values
291 
292 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
293 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
294 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
295 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
296 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
297 		}
298 
299 		// alpha pass through
300 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
301 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
302 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
303 
304 		BindClientStates();
305 	}
306 
Unbind()307 	virtual void Unbind()
308 	{
309 		UnbindClientStates();
310 
311 		pglActiveTextureARB(GL_TEXTURE2);
312 		glDisable(GL_TEXTURE_2D);
313 
314 		glDisable(GL_TEXTURE_GEN_S);
315 		glDisable(GL_TEXTURE_GEN_T);
316 
317 		pglActiveTextureARB(GL_TEXTURE1);
318 		glDisable(GL_TEXTURE_2D);
319 
320 		pglActiveTextureARB(GL_TEXTURE0);
321 		glDisable(GL_TEXTURE_2D);
322 	}
323 };
324 
325 //////////////////////////////////////////////////////////////////////////
326 
327 class CShaderProgramFFP_GuiText : public CShaderProgramFFP
328 {
329 	// Uniforms
330 	enum
331 	{
332 		ID_transform,
333 		ID_colorMul
334 	};
335 
336 public:
CShaderProgramFFP_GuiText()337 	CShaderProgramFFP_GuiText() :
338 		CShaderProgramFFP(STREAM_POS | STREAM_UV0)
339 	{
340 		SetUniformIndex("transform", ID_transform);
341 		SetUniformIndex("colorMul", ID_colorMul);
342 
343 		// Texture units:
344 		SetUniformIndex("tex", 0);
345 	}
346 
Uniform(Binding id,float v0,float v1,float v2,float v3)347 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
348 	{
349 		if (id.second == ID_colorMul)
350 			glColor4f(v0, v1, v2, v3);
351 	}
352 
Uniform(Binding id,const CMatrix3D & v)353 	virtual void Uniform(Binding id, const CMatrix3D& v)
354 	{
355 		if (id.second == ID_transform)
356 			glLoadMatrixf(&v._11);
357 	}
358 
Bind()359 	virtual void Bind()
360 	{
361 		glMatrixMode(GL_PROJECTION);
362 		glPushMatrix();
363 		glLoadIdentity();
364 		glMatrixMode(GL_MODELVIEW);
365 		glPushMatrix();
366 
367 		pglActiveTextureARB(GL_TEXTURE0);
368 		glEnable(GL_TEXTURE_2D);
369 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
370 
371 		BindClientStates();
372 	}
373 
Unbind()374 	virtual void Unbind()
375 	{
376 		UnbindClientStates();
377 
378 		pglActiveTextureARB(GL_TEXTURE0);
379 		glDisable(GL_TEXTURE_2D);
380 
381 		glMatrixMode(GL_PROJECTION);
382 		glPopMatrix();
383 		glMatrixMode(GL_MODELVIEW);
384 		glPopMatrix();
385 	}
386 };
387 
388 //////////////////////////////////////////////////////////////////////////
389 
390 class CShaderProgramFFP_Gui_Base : public CShaderProgramFFP
391 {
392 protected:
393 	// Uniforms
394 	enum
395 	{
396 		ID_transform,
397 		ID_color
398 	};
399 
400 public:
CShaderProgramFFP_Gui_Base(int streamflags)401 	CShaderProgramFFP_Gui_Base(int streamflags) :
402 		CShaderProgramFFP(streamflags)
403 	{
404 		SetUniformIndex("transform", ID_transform);
405 		SetUniformIndex("color", ID_color);
406 
407 		// Texture units:
408 		SetUniformIndex("tex", 0);
409 	}
410 
Uniform(Binding id,const CMatrix3D & v)411 	virtual void Uniform(Binding id, const CMatrix3D& v)
412 	{
413 		if (id.second == ID_transform)
414 			glLoadMatrixf(&v._11);
415 	}
416 
Bind()417 	virtual void Bind()
418 	{
419 		glMatrixMode(GL_PROJECTION);
420 		glPushMatrix();
421 		glLoadIdentity();
422 		glMatrixMode(GL_MODELVIEW);
423 		glPushMatrix();
424 
425 		BindClientStates();
426 	}
427 
Unbind()428 	virtual void Unbind()
429 	{
430 		UnbindClientStates();
431 
432 		glMatrixMode(GL_PROJECTION);
433 		glPopMatrix();
434 		glMatrixMode(GL_MODELVIEW);
435 		glPopMatrix();
436 	}
437 };
438 
439 class CShaderProgramFFP_GuiMinimap : public CShaderProgramFFP
440 {
441 protected:
442 	CShaderDefines m_Defines;
443 	// Uniforms
444 	enum
445 	{
446 		ID_transform,
447 		ID_textureTransform,
448 		ID_color,
449 		ID_pointSize,
450 	};
451 public:
CShaderProgramFFP_GuiMinimap(const CShaderDefines & defines)452 	CShaderProgramFFP_GuiMinimap(const CShaderDefines& defines) :
453 		CShaderProgramFFP(0) // We set the streamflags later, during initialization.
454 	{
455 		m_Defines = defines;
456 		SetUniformIndex("transform", ID_transform);
457 		SetUniformIndex("textureTransform", ID_textureTransform);
458 		SetUniformIndex("color", ID_color);
459 		SetUniformIndex("pointSize", ID_pointSize);
460 
461 		if (m_Defines.GetInt("MINIMAP_BASE") || m_Defines.GetInt("MINIMAP_LOS"))
462 		{
463 			SetUniformIndex("baseTex", 0);
464 			m_StreamFlags = STREAM_POS | STREAM_UV0;
465 		}
466 		else if (m_Defines.GetInt("MINIMAP_POINT"))
467 			m_StreamFlags = STREAM_POS | STREAM_COLOR;
468 		else
469 			m_StreamFlags = STREAM_POS;
470 	}
471 
Uniform(Binding id,const CMatrix3D & v)472 	virtual void Uniform(Binding id, const CMatrix3D& v)
473 	{
474 		if (id.second == ID_textureTransform)
475 		{
476 			glMatrixMode(GL_TEXTURE);
477 			glLoadMatrixf(&v._11);
478 		}
479 		else if (id.second == ID_transform)
480 		{
481 			glMatrixMode(GL_MODELVIEW);
482 			glLoadMatrixf(&v._11);
483 		}
484 	}
485 
Uniform(Binding id,float v0,float v1,float v2,float v3)486 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
487 	{
488 		if (id.second == ID_color)
489 			glColor4f(v0, v1, v2, v3);
490 		else if (id.second == ID_pointSize)
491 			glPointSize(v0);
492 	}
493 
Bind()494 	virtual void Bind()
495 	{
496 		// Setup matrix environment
497 		glMatrixMode(GL_PROJECTION);
498 		glPushMatrix();
499 		glLoadIdentity();
500 		glMatrixMode(GL_MODELVIEW);
501 		glPushMatrix();
502 		glLoadIdentity();
503 		glMatrixMode(GL_TEXTURE);
504 		glPushMatrix();
505 		glLoadIdentity();
506 
507 		BindClientStates();
508 
509 		// Setup texture environment
510 		if (m_Defines.GetInt("MINIMAP_BASE"))
511 		{
512 			pglActiveTextureARB(GL_TEXTURE0);
513 			glEnable(GL_TEXTURE_2D);
514 			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
515 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
516 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
517 		}
518 		else if (m_Defines.GetInt("MINIMAP_LOS"))
519 		{
520 			pglActiveTextureARB(GL_TEXTURE0);
521 			glEnable(GL_TEXTURE_2D);
522 			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
523 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
524 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
525 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
526 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
527 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
528 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
529 			glColor3f(0.0f, 0.0f, 0.0f);
530 		}
531 		else if (m_Defines.GetInt("MINIMAP_POINT"))
532 		{
533 			pglActiveTextureARB(GL_TEXTURE0);
534 			glDisable(GL_TEXTURE_2D);
535 			glEnableClientState(GL_VERTEX_ARRAY);
536 			glEnableClientState(GL_COLOR_ARRAY);
537 		}
538 		else if (m_Defines.GetInt("MINIMAP_LINE"))
539 		{
540 			// JoshuaJB 13.7.2014: This doesn't seem to do anything on my drivers.
541 			glEnable(GL_LINE_SMOOTH);
542 		}
543 	}
544 
Unbind()545 	virtual void Unbind()
546 	{
547 		// Reset texture environment
548 		if (m_Defines.GetInt("MINIMAP_POINT"))
549 		{
550 			pglActiveTextureARB(GL_TEXTURE0);
551 			glEnable(GL_TEXTURE_2D);
552 			glDisableClientState(GL_VERTEX_ARRAY);
553 			glDisableClientState(GL_COLOR_ARRAY);
554 		}
555 		else if (m_Defines.GetInt("MINIMAP_LINE"))
556 		{
557 			glDisable(GL_LINE_SMOOTH);
558 		}
559 
560 		UnbindClientStates();
561 
562 		// Clear matrix stack
563 		glMatrixMode(GL_TEXTURE);
564 		glPopMatrix();
565 		glMatrixMode(GL_PROJECTION);
566 		glPopMatrix();
567 		glMatrixMode(GL_MODELVIEW);
568 		glPopMatrix();
569 	}
570 };
571 
572 class CShaderProgramFFP_GuiBasic : public CShaderProgramFFP_Gui_Base
573 {
574 public:
CShaderProgramFFP_GuiBasic()575 	CShaderProgramFFP_GuiBasic() :
576 		CShaderProgramFFP_Gui_Base(STREAM_POS | STREAM_UV0)
577 	{
578 	}
579 
Bind()580 	virtual void Bind()
581 	{
582 		CShaderProgramFFP_Gui_Base::Bind();
583 
584 		pglActiveTextureARB(GL_TEXTURE0);
585 		glEnable(GL_TEXTURE_2D);
586 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
587 	}
588 
Unbind()589 	virtual void Unbind()
590 	{
591 		pglActiveTextureARB(GL_TEXTURE0);
592 		glDisable(GL_TEXTURE_2D);
593 
594 		CShaderProgramFFP_Gui_Base::Unbind();
595 	}
596 };
597 
598 class CShaderProgramFFP_GuiAdd : public CShaderProgramFFP_Gui_Base
599 {
600 public:
601 	using CShaderProgramFFP_Gui_Base::Uniform;
602 
CShaderProgramFFP_GuiAdd()603 	CShaderProgramFFP_GuiAdd() :
604 		CShaderProgramFFP_Gui_Base(STREAM_POS | STREAM_UV0)
605 	{
606 	}
607 
Uniform(Binding id,float v0,float v1,float v2,float v3)608 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
609 	{
610 		if (id.second == ID_color)
611 			glColor4f(v0, v1, v2, v3);
612 	}
613 
Bind()614 	virtual void Bind()
615 	{
616 		CShaderProgramFFP_Gui_Base::Bind();
617 
618 		pglActiveTextureARB(GL_TEXTURE0);
619 		glEnable(GL_TEXTURE_2D);
620 
621 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
622 
623 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
624 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
625 
626 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
627 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
628 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
629 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
630 
631 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
632 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
633 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
634 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
635 	}
636 
Unbind()637 	virtual void Unbind()
638 	{
639 		glColor4f(1.f, 1.f, 1.f, 1.f);
640 
641 		pglActiveTextureARB(GL_TEXTURE0);
642 		glDisable(GL_TEXTURE_2D);
643 
644 		CShaderProgramFFP_Gui_Base::Unbind();
645 	}
646 };
647 
648 class CShaderProgramFFP_GuiGrayscale : public CShaderProgramFFP_Gui_Base
649 {
650 public:
CShaderProgramFFP_GuiGrayscale()651 	CShaderProgramFFP_GuiGrayscale() :
652 		CShaderProgramFFP_Gui_Base(STREAM_POS | STREAM_UV0)
653 	{
654 	}
655 
Bind()656 	virtual void Bind()
657 	{
658 		CShaderProgramFFP_Gui_Base::Bind();
659 
660 		/*
661 
662 		For the main conversion, use GL_DOT3_RGB, which is defined as
663 		    L = 4 * ((Arg0r - 0.5) * (Arg1r - 0.5)+
664 		             (Arg0g - 0.5) * (Arg1g - 0.5)+
665 			         (Arg0b - 0.5) * (Arg1b - 0.5))
666 		where each of the RGB components is given the value 'L'.
667 
668 		Use the magical luminance formula
669 		    L = 0.3R + 0.59G + 0.11B
670 		to calculate the greyscale value.
671 
672 		But to work around the annoying "Arg0-0.5", we need to calculate
673 		Arg0+0.5. But we also need to scale it into the range 0.5-1.0, else
674 		Arg0>0.5 will be clamped to 1.0. So use GL_INTERPOLATE, which outputs:
675 		    A0 * A2 + A1 * (1 - A2)
676 		and set A2 = 0.5, A1 = 1.0, and A0 = texture (i.e. interpolating halfway
677 		between the texture and {1,1,1}) giving
678 		    A0/2 + 0.5
679 		and use that as Arg0.
680 
681 		So L = 4*(A0/2 * (Arg1-.5))
682 		     = 2 (Rx+Gy+Bz)      (where Arg1 = {x+0.5, y+0.5, z+0.5})
683 			 = 2x R + 2y G + 2z B
684 			 = 0.3R + 0.59G + 0.11B
685 		so e.g. 2y = 0.59 = 2(Arg1g-0.5) => Arg1g = 0.59/2+0.5
686 		which fortunately doesn't get clamped.
687 
688 		So, just implement that:
689 
690 		*/
691 
692 		static const float GreyscaleDotColor[4] = {
693 			0.3f / 2.f + 0.5f,
694 			0.59f / 2.f + 0.5f,
695 			0.11f / 2.f + 0.5f,
696 			1.0f
697 		};
698 		static const float GreyscaleInterpColor0[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
699 		static const float GreyscaleInterpColor1[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
700 
701 		pglActiveTextureARB(GL_TEXTURE0);
702 		glEnable(GL_TEXTURE_2D);
703 
704 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
705 
706 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
707 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
708 
709 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
710 
711 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
712 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
713 		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GreyscaleInterpColor0);
714 
715 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS);
716 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
717 
718 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
719 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
720 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
721 
722 		glColor4fv(GreyscaleInterpColor1);
723 
724 		pglActiveTextureARB(GL_TEXTURE1);
725 		glEnable(GL_TEXTURE_2D);
726 
727 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
728 
729 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
730 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
731 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
732 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
733 
734 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
735 
736 		// GL_DOT3_RGB requires GL_(EXT|ARB)_texture_env_dot3.
737 		// We currently don't bother implementing a fallback because it's
738 		// only lacking on Riva-class HW, but at least want the rest of the
739 		// game to run there without errors. Therefore, squelch the
740 		// OpenGL error that's raised if they aren't actually present.
741 		// Note: higher-level code checks for this extension, but
742 		// allows users the choice of continuing even if not present.
743 		ogl_SquelchError(GL_INVALID_ENUM);
744 
745 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
746 
747 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
748 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
749 		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GreyscaleDotColor);
750 
751 		// To activate the second texture unit, we have to have some kind
752 		// of texture bound into it, but we don't actually use the texture data,
753 		// so bind a dummy texture
754 		g_Renderer.GetTextureManager().GetErrorTexture()->Bind(1);
755 	}
756 
Unbind()757 	virtual void Unbind()
758 	{
759 		glColor4f(1.f, 1.f, 1.f, 1.f);
760 
761 		pglActiveTextureARB(GL_TEXTURE1);
762 		glDisable(GL_TEXTURE_2D);
763 
764 		pglActiveTextureARB(GL_TEXTURE0);
765 		glDisable(GL_TEXTURE_2D);
766 
767 		CShaderProgramFFP_Gui_Base::Unbind();
768 	}
769 };
770 
771 class CShaderProgramFFP_GuiSolid : public CShaderProgramFFP_Gui_Base
772 {
773 public:
774 	using CShaderProgramFFP_Gui_Base::Uniform;
775 
CShaderProgramFFP_GuiSolid()776 	CShaderProgramFFP_GuiSolid() :
777 		CShaderProgramFFP_Gui_Base(STREAM_POS)
778 	{
779 	}
780 
Uniform(Binding id,float v0,float v1,float v2,float v3)781 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
782 	{
783 		if (id.second == ID_color)
784 			glColor4f(v0, v1, v2, v3);
785 	}
786 
Bind()787 	virtual void Bind()
788 	{
789 		CShaderProgramFFP_Gui_Base::Bind();
790 
791 		pglActiveTextureARB(GL_TEXTURE0);
792 		glDisable(GL_TEXTURE_2D);
793 	}
794 };
795 
796 //////////////////////////////////////////////////////////////////////////
797 
798 /**
799  * Common functionality for model rendering in the fixed renderpath.
800  */
801 class CShaderProgramFFP_Model_Base : public CShaderProgramFFP
802 {
803 protected:
804 	// Uniforms
805 	enum
806 	{
807 		ID_transform,
808 		ID_objectColor,
809 		ID_playerColor,
810 		ID_losTransform
811 	};
812 
813 	bool m_IgnoreLos;
814 
815 public:
CShaderProgramFFP_Model_Base(const CShaderDefines & defines,int streamflags)816 	CShaderProgramFFP_Model_Base(const CShaderDefines& defines, int streamflags)
817 		: CShaderProgramFFP(streamflags)
818 	{
819 		SetUniformIndex("transform", ID_transform);
820 		SetUniformIndex("losTransform", ID_losTransform);
821 
822 		if (defines.GetInt("USE_OBJECTCOLOR"))
823 			SetUniformIndex("objectColor", ID_objectColor);
824 
825 		if (defines.GetInt("USE_PLAYERCOLOR"))
826 			SetUniformIndex("playerColor", ID_playerColor);
827 
828 		m_IgnoreLos = (defines.GetInt("IGNORE_LOS") != 0);
829 
830 		// Texture units:
831 		SetUniformIndex("baseTex", 0);
832 		SetUniformIndex("losTex", 3);
833 	}
834 
Uniform(Binding id,const CMatrix3D & v)835 	virtual void Uniform(Binding id, const CMatrix3D& v)
836 	{
837 		if (id.second == ID_transform)
838 			glLoadMatrixf(&v._11);
839 	}
840 
Uniform(Binding id,float v0,float v1,float UNUSED (v2),float UNUSED (v3))841 	virtual void Uniform(Binding id, float v0, float v1, float UNUSED(v2), float UNUSED(v3))
842 	{
843 		if (id.second == ID_losTransform)
844 		{
845 			pglActiveTextureARB(GL_TEXTURE3);
846 			GLfloat texgenS1[4] = { v0, 0, 0, v1 };
847 			GLfloat texgenT1[4] = { 0, 0, v0, v1 };
848 			glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1);
849 			glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1);
850 		}
851 	}
852 
Bind()853 	virtual void Bind()
854 	{
855 		glMatrixMode(GL_PROJECTION);
856 		glPushMatrix();
857 		glLoadIdentity();
858 		glMatrixMode(GL_MODELVIEW);
859 		glPushMatrix();
860 
861 		// -----------------------------------------------------------------------------
862 
863 		pglActiveTextureARB(GL_TEXTURE3);
864 		glEnable(GL_TEXTURE_2D);
865 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
866 
867 		if (m_IgnoreLos)
868 		{
869 			// RGB pass through
870 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
871 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
872 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
873 		}
874 		else
875 		{
876 			// Multiply RGB result up till now with LoS texture alpha channel
877 			glEnable(GL_TEXTURE_GEN_S);
878 			glEnable(GL_TEXTURE_GEN_T);
879 			glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
880 			glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
881 			// Overridden implementation of Uniform() sets GL_OBJECT_PLANE values
882 
883 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
884 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
885 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
886 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
887 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
888 		}
889 
890 		// alpha pass through
891 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
892 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
893 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
894 
895 		// -----------------------------------------------------------------------------
896 
897 		BindClientStates();
898 	}
899 
Unbind()900 	virtual void Unbind()
901 	{
902 		UnbindClientStates();
903 
904 		pglActiveTextureARB(GL_TEXTURE3);
905 		glDisable(GL_TEXTURE_2D);
906 
907 		glDisable(GL_TEXTURE_GEN_S);
908 		glDisable(GL_TEXTURE_GEN_T);
909 
910 		pglActiveTextureARB(GL_TEXTURE0);
911 
912 		glMatrixMode(GL_PROJECTION);
913 		glPopMatrix();
914 		glMatrixMode(GL_MODELVIEW);
915 		glPopMatrix();
916 	}
917 };
918 
919 /**
920  * Basic non-recolored diffuse-textured model rendering.
921  */
922 class CShaderProgramFFP_Model : public CShaderProgramFFP_Model_Base
923 {
924 public:
CShaderProgramFFP_Model(const CShaderDefines & defines)925 	CShaderProgramFFP_Model(const CShaderDefines& defines)
926 		: CShaderProgramFFP_Model_Base(defines, STREAM_POS | STREAM_COLOR | STREAM_UV0)
927 	{
928 	}
929 
Bind()930 	virtual void Bind()
931 	{
932 		// Set up texture environment for base pass - modulate texture and vertex color
933 		pglActiveTextureARB(GL_TEXTURE0);
934 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
935 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
936 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
937 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
938 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
939 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
940 
941 		// Copy alpha channel from texture
942 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
943 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
944 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
945 
946 		// The vertex color is scaled by 0.5 to permit overbrightness without clamping.
947 		// We therefore need to scale by 2.0 after the modulation, and before any
948 		// further clamping, to get the right color.
949 		float scale2[] = { 2.0f, 2.0f, 2.0f };
950 		glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale2);
951 
952 		CShaderProgramFFP_Model_Base::Bind();
953 	}
954 
Unbind()955 	virtual void Unbind()
956 	{
957 		CShaderProgramFFP_Model_Base::Unbind();
958 
959 		pglActiveTextureARB(GL_TEXTURE0);
960 
961 		// Revert the scaling to default
962 		float scale1[] = { 1.0f, 1.0f, 1.0f };
963 		glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale1);
964 	}
965 };
966 
967 /**
968  * Player-coloring diffuse-textured model rendering.
969  */
970 class CShaderProgramFFP_ModelColor : public CShaderProgramFFP_Model_Base
971 {
972 public:
CShaderProgramFFP_ModelColor(const CShaderDefines & defines)973 	CShaderProgramFFP_ModelColor(const CShaderDefines& defines)
974 		: CShaderProgramFFP_Model_Base(defines, STREAM_POS | STREAM_COLOR | STREAM_UV0)
975 	{
976 	}
977 
Uniform(Binding id,float v0,float v1,float v2,float v3)978 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
979 	{
980 		if (id.second == ID_objectColor || id.second == ID_playerColor)
981 		{
982 			// (Player color and object color are mutually exclusive)
983 			float color[] = { v0, v1, v2, v3 };
984 			glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
985 		}
986 	}
987 
Bind()988 	virtual void Bind()
989 	{
990 		// Player color uses a single pass with three texture environments
991 		// Note: This uses ARB_texture_env_crossbar (which is checked in GameSetup),
992 		// and it requires MAX_TEXTURE_IMAGE_UNITS >= 3 (which only excludes GF2MX/GF4MX)
993 		//
994 		// We calculate: Result = Color*Texture*(PlayerColor*(1-Texture.a) + 1.0*Texture.a)
995 		// Algebra gives us:
996 		// Result = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture*Color
997 
998 		// TexEnv #0
999 		pglActiveTextureARB(GL_TEXTURE0);
1000 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1001 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1002 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
1003 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_ALPHA);
1004 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
1005 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_ONE_MINUS_SRC_COLOR);
1006 
1007 		// Don't care about alpha; set it to something harmless
1008 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
1009 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1010 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1011 
1012 		// TexEnv #1
1013 		pglActiveTextureARB(GL_TEXTURE1);
1014 		glEnable(GL_TEXTURE_2D);
1015 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1016 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1017 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1018 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
1019 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
1020 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
1021 
1022 		// Don't care about alpha; set it to something harmless
1023 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
1024 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1025 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1026 
1027 		// TexEnv #2
1028 		pglActiveTextureARB(GL_TEXTURE2);
1029 		glEnable(GL_TEXTURE_2D);
1030 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1031 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1032 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1033 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1034 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0);
1035 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
1036 
1037 		// Don't care about alpha; set it to something harmless
1038 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
1039 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1040 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1041 
1042 		float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
1043 		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1044 
1045 		// Scale colors at the end of all the computation (see CShaderProgramFFP_Model::Bind)
1046 		float scale[] = { 2.0f, 2.0f, 2.0f };
1047 		glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale);
1048 
1049 		// Need to bind some kind of texture to enable the texture units.
1050 		// Unit 0 has baseTex, but the others need a texture.
1051 		g_Renderer.GetTextureManager().GetErrorTexture()->Bind(1);
1052 		g_Renderer.GetTextureManager().GetErrorTexture()->Bind(2);
1053 
1054 		CShaderProgramFFP_Model_Base::Bind();
1055 	}
1056 
Unbind()1057 	virtual void Unbind()
1058 	{
1059 		CShaderProgramFFP_Model_Base::Unbind();
1060 
1061 		pglActiveTextureARB(GL_TEXTURE2);
1062 		glDisable(GL_TEXTURE_2D);
1063 
1064 		float scale[] = { 1.0f, 1.0f, 1.0f };
1065 		glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale);
1066 
1067 		pglActiveTextureARB(GL_TEXTURE1);
1068 		glDisable(GL_TEXTURE_2D);
1069 
1070 		pglActiveTextureARB(GL_TEXTURE0);
1071 	}
1072 };
1073 
1074 /**
1075  * Optionally-player-colored untextured model rendering.
1076  */
1077 class CShaderProgramFFP_ModelSolid : public CShaderProgramFFP_Model_Base
1078 {
1079 public:
CShaderProgramFFP_ModelSolid(const CShaderDefines & defines)1080 	CShaderProgramFFP_ModelSolid(const CShaderDefines& defines)
1081 		: CShaderProgramFFP_Model_Base(defines, STREAM_POS)
1082 	{
1083 	}
1084 
Uniform(Binding id,float v0,float v1,float v2,float v3)1085 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
1086 	{
1087 		if (id.second == ID_playerColor)
1088 		{
1089 			float color[] = { v0, v1, v2, v3 };
1090 			glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1091 		}
1092 	}
1093 
Bind()1094 	virtual void Bind()
1095 	{
1096 		float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
1097 		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1098 
1099 		pglActiveTextureARB(GL_TEXTURE0);
1100 		glEnable(GL_TEXTURE_2D);
1101 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1102 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
1103 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT);
1104 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1105 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
1106 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
1107 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1108 
1109 		CShaderProgramFFP_Model_Base::Bind();
1110 	}
1111 };
1112 
1113 /**
1114  * Plain unlit texture model rendering, for e.g. alpha-blended shadow casters.
1115  */
1116 class CShaderProgramFFP_ModelSolidTex : public CShaderProgramFFP_Model_Base
1117 {
1118 public:
CShaderProgramFFP_ModelSolidTex(const CShaderDefines & defines)1119 	CShaderProgramFFP_ModelSolidTex(const CShaderDefines& defines)
1120 		: CShaderProgramFFP_Model_Base(defines, STREAM_POS | STREAM_UV0)
1121 	{
1122 	}
1123 
Bind()1124 	virtual void Bind()
1125 	{
1126 		pglActiveTextureARB(GL_TEXTURE0);
1127 		glEnable(GL_TEXTURE_2D);
1128 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1129 
1130 		CShaderProgramFFP_Model_Base::Bind();
1131 	}
1132 };
1133 
1134 //////////////////////////////////////////////////////////////////////////
1135 
ConstructFFP(const std::string & id,const CShaderDefines & defines)1136 /*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& id, const CShaderDefines& defines)
1137 {
1138 	if (id == "dummy")
1139 		return new CShaderProgramFFP_Dummy();
1140 	if (id == "overlayline")
1141 		return new CShaderProgramFFP_OverlayLine(defines);
1142 	if (id == "gui_text")
1143 		return new CShaderProgramFFP_GuiText();
1144 	if (id == "gui_basic")
1145 		return new CShaderProgramFFP_GuiBasic();
1146 	if (id == "gui_add")
1147 		return new CShaderProgramFFP_GuiAdd();
1148 	if (id == "gui_grayscale")
1149 		return new CShaderProgramFFP_GuiGrayscale();
1150 	if (id == "gui_solid")
1151 		return new CShaderProgramFFP_GuiSolid();
1152 	if (id == "minimap")
1153 		return new CShaderProgramFFP_GuiMinimap(defines);
1154 	if (id == "solid")
1155 		return new CShaderProgramFFP_GuiSolid(); // works for non-GUI objects too
1156 	if (id == "model")
1157 		return new CShaderProgramFFP_Model(defines);
1158 	if (id == "model_color")
1159 		return new CShaderProgramFFP_ModelColor(defines);
1160 	if (id == "model_solid")
1161 		return new CShaderProgramFFP_ModelSolid(defines);
1162 	if (id == "model_solid_tex")
1163 		return new CShaderProgramFFP_ModelSolidTex(defines);
1164 
1165 	LOGERROR("CShaderProgram::ConstructFFP: '%s': Invalid id", id.c_str());
1166 	debug_warn(L"CShaderProgram::ConstructFFP: Invalid id");
1167 	return NULL;
1168 }
1169 
1170 #else // CONFIG2_GLES
1171 
ConstructFFP(const std::string & UNUSED (id),const CShaderDefines & UNUSED (defines))1172 /*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& UNUSED(id), const CShaderDefines& UNUSED(defines))
1173 {
1174 	debug_warn(L"CShaderProgram::ConstructFFP: FFP not supported on this device");
1175 	return NULL;
1176 }
1177 
1178 #endif // CONFIG2_GLES
1179