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