Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ShaderProgramFFP.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "ShaderProgram.h"
21 
22 #include "graphics/ShaderDefines.h"
25 #include "maths/Matrix3D.h"
26 #include "maths/Vector3D.h"
27 #include "ps/CLogger.h"
28 #include "ps/Overlay.h"
29 #include "renderer/Renderer.h"
30 
31 #if !CONFIG2_GLES
32 
33 /**
34  * CShaderProgramFFP allows rendering code to use the shader-based API
35  * even if the 'shader' is actually implemented with the fixed-function
36  * pipeline instead of anything programmable.
37  *
38  * Currently we just hard-code a number of FFP programs as subclasses of this.
39  * If we have lots, it might be nicer to abstract out the common functionality
40  * and load these from text files or something.
41  */
43 {
44 public:
45  CShaderProgramFFP(int streamflags) :
46  CShaderProgram(streamflags)
47  {
48  }
49 
51  {
52  }
53 
54  virtual void Reload()
55  {
56  m_IsValid = true;
57  }
58 
60  {
61  std::map<CStrIntern, int>::iterator it = m_UniformIndexes.find(id);
62  if (it == m_UniformIndexes.end())
63  return -1;
64  return it->second;
65  }
66 
68  {
69  int index = GetUniformIndex(CStrIntern(id));
70  if (index == -1)
71  return Binding();
72  else
73  return Binding((int)GL_TEXTURE_2D, index);
74  }
75 
76  virtual void BindTexture(texture_id_t id, Handle tex)
77  {
78  int index = GetUniformIndex(CStrIntern(id));
79  if (index != -1)
80  ogl_tex_bind(tex, index);
81  }
82 
83  virtual void BindTexture(texture_id_t id, GLuint tex)
84  {
85  int index = GetUniformIndex(CStrIntern(id));
86  if (index != -1)
87  {
88  pglActiveTextureARB((int)(GL_TEXTURE0+index));
89  glBindTexture(GL_TEXTURE_2D, tex);
90  }
91  }
92 
93  virtual void BindTexture(Binding id, Handle tex)
94  {
95  int index = id.second;
96  if (index != -1)
97  ogl_tex_bind(tex, index);
98  }
99 
101  {
102  return Binding(-1, GetUniformIndex(id));
103  }
104 
105  virtual void Uniform(Binding UNUSED(id), float UNUSED(v0), float UNUSED(v1), float UNUSED(v2), float UNUSED(v3))
106  {
107  }
108 
109  virtual void Uniform(Binding UNUSED(id), const CMatrix3D& UNUSED(v))
110  {
111  }
112 
113  virtual void Uniform(Binding UNUSED(id), size_t UNUSED(count), const CMatrix3D* UNUSED(v))
114  {
115  }
116 
117 protected:
118  std::map<CStrIntern, int> m_UniformIndexes;
119 
120  void SetUniformIndex(const char* id, int value)
121  {
122  m_UniformIndexes[CStrIntern(id)] = value;
123  }
124 };
125 
126 //////////////////////////////////////////////////////////////////////////
127 
128 /**
129  * A shader that does nothing but provide a shader-compatible interface to
130  * fixed-function features, for compatibility with existing fixed-function
131  * code that isn't fully ported to the shader API.
132  */
134 {
135 public:
138  {
139  // Texture units, for when this shader is used with terrain:
140  SetUniformIndex("baseTex", 0);
141  }
142 
143  virtual void Bind()
144  {
146  }
147 
148  virtual void Unbind()
149  {
151  }
152 };
153 
154 //////////////////////////////////////////////////////////////////////////
155 
157 {
158  // Uniforms
159  enum
160  {
163  };
164 
167 
168 public:
170  CShaderProgramFFP(0) // will be set manually in initializer below
171  {
172  SetUniformIndex("losTransform", ID_losTransform);
173  SetUniformIndex("objectColor", ID_objectColor);
174 
175  // Texture units:
176  SetUniformIndex("baseTex", 0);
177  SetUniformIndex("maskTex", 1);
178  SetUniformIndex("losTex", 2);
179 
180  m_IgnoreLos = (defines.GetInt("IGNORE_LOS") != 0);
181  m_UseObjectColor = (defines.GetInt("USE_OBJECTCOLOR") != 0);
182 
184  if (!m_UseObjectColor)
186  }
187 
188  bool IsIgnoreLos()
189  {
190  return m_IgnoreLos;
191  }
192 
193  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
194  {
195  if (id.second == ID_losTransform)
196  {
197  pglActiveTextureARB(GL_TEXTURE2);
198  GLfloat texgenS1[4] = { v0, 0, 0, v1 };
199  GLfloat texgenT1[4] = { 0, 0, v0, v1 };
200  glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1);
201  glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1);
202  }
203  else if (id.second == ID_objectColor)
204  {
205  float c[] = { v0, v1, v2, v3 };
206  pglActiveTextureARB(GL_TEXTURE1);
207  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, c);
208  }
209  else
210  {
211  debug_warn(L"Invalid id");
212  }
213  }
214 
215  virtual void Uniform(Binding UNUSED(id), const CMatrix3D& UNUSED(v))
216  {
217  debug_warn(L"Not implemented");
218  }
219 
220  virtual void Bind()
221  {
222  // RGB channels:
223  // Unit 0: Sample base texture
224  // Unit 1: Sample mask texture; interpolate with [objectColor or vertexColor] and base, depending on USE_OBJECTCOLOR
225  // Unit 2: (Load LOS texture; multiply) if not #IGNORE_LOS, pass through otherwise
226  // Alpha channel:
227  // Unit 0: Sample base texture
228  // Unit 1: Multiply by objectColor
229  // Unit 2: Pass through
230 
231  pglActiveTextureARB(GL_TEXTURE0);
232  glEnable(GL_TEXTURE_2D);
233  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
234 
235  // Sample base texture RGB
236  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
237  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
238  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
239 
240  // Sample base texture Alpha
241  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
242  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
243  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
244 
245  // -----------------------------------------------------------------------------
246 
247  pglActiveTextureARB(GL_TEXTURE1);
248  glEnable(GL_TEXTURE_2D);
249  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
250 
251  // RGB: interpolate component-wise between [objectColor or vertexColor] and base using mask:
252  // a0 * a2 + a1 * (1 - a2)
253  // Overridden implementation of Uniform() sets GL_TEXTURE_ENV_COLOR to objectColor, which
254  // is referenced as GL_CONSTANT (see spec)
255  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE);
256  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, m_UseObjectColor ? GL_CONSTANT : GL_PRIMARY_COLOR);
257  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
258  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);
259  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
260  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
261  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
262 
263  // ALPHA: Multiply base alpha with [objectColor or vertexColor] alpha
264  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
265  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, m_UseObjectColor ? GL_CONSTANT : GL_PRIMARY_COLOR);
266  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
267  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS);
268  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
269 
270  // -----------------------------------------------------------------------------
271 
272  pglActiveTextureARB(GL_TEXTURE2);
273  glEnable(GL_TEXTURE_2D);
274  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
275 
276  bool ignoreLos = IsIgnoreLos();
277  if (ignoreLos)
278  {
279  // RGB pass through
280  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
281  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
282  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
283  }
284  else
285  {
286  // Multiply RGB result up till now with LoS texture alpha channel
287  glEnable(GL_TEXTURE_GEN_S);
288  glEnable(GL_TEXTURE_GEN_T);
289  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
290  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
291  // Overridden implementation of Uniform() sets GL_OBJECT_PLANE values
292 
293  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
294  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
295  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
296  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
297  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
298  }
299 
300  // alpha pass through
301  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
302  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
303  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
304 
306  }
307 
308  virtual void Unbind()
309  {
311 
312  pglActiveTextureARB(GL_TEXTURE2);
313  glDisable(GL_TEXTURE_2D);
314 
315  glDisable(GL_TEXTURE_GEN_S);
316  glDisable(GL_TEXTURE_GEN_T);
317 
318  pglActiveTextureARB(GL_TEXTURE1);
319  glDisable(GL_TEXTURE_2D);
320 
321  pglActiveTextureARB(GL_TEXTURE0);
322  glDisable(GL_TEXTURE_2D);
323  }
324 };
325 
326 //////////////////////////////////////////////////////////////////////////
327 
329 {
330  // Uniforms
331  enum
332  {
335  };
336 
337 public:
340  {
341  SetUniformIndex("transform", ID_transform);
342  SetUniformIndex("colorMul", ID_colorMul);
343 
344  // Texture units:
345  SetUniformIndex("tex", 0);
346  }
347 
348  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
349  {
350  if (id.second == ID_colorMul)
351  glColor4f(v0, v1, v2, v3);
352  }
353 
354  virtual void Uniform(Binding id, const CMatrix3D& v)
355  {
356  if (id.second == ID_transform)
357  glLoadMatrixf(&v._11);
358  }
359 
360  virtual void Bind()
361  {
362  glMatrixMode(GL_PROJECTION);
363  glPushMatrix();
364  glLoadIdentity();
365  glMatrixMode(GL_MODELVIEW);
366  glPushMatrix();
367 
368  pglActiveTextureARB(GL_TEXTURE0);
369  glEnable(GL_TEXTURE_2D);
370  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
371 
373  }
374 
375  virtual void Unbind()
376  {
378 
379  pglActiveTextureARB(GL_TEXTURE0);
380  glDisable(GL_TEXTURE_2D);
381 
382  glMatrixMode(GL_PROJECTION);
383  glPopMatrix();
384  glMatrixMode(GL_MODELVIEW);
385  glPopMatrix();
386  }
387 };
388 
389 //////////////////////////////////////////////////////////////////////////
390 
392 {
393 protected:
394  // Uniforms
395  enum
396  {
399  };
400 
401 public:
402  CShaderProgramFFP_Gui_Base(int streamflags) :
403  CShaderProgramFFP(streamflags)
404  {
405  SetUniformIndex("transform", ID_transform);
406  SetUniformIndex("color", ID_color);
407 
408  // Texture units:
409  SetUniformIndex("tex", 0);
410  }
411 
412  virtual void Uniform(Binding id, const CMatrix3D& v)
413  {
414  if (id.second == ID_transform)
415  glLoadMatrixf(&v._11);
416  }
417 
418  virtual void Bind()
419  {
420  glMatrixMode(GL_PROJECTION);
421  glPushMatrix();
422  glLoadIdentity();
423  glMatrixMode(GL_MODELVIEW);
424  glPushMatrix();
425 
427  }
428 
429  virtual void Unbind()
430  {
432 
433  glMatrixMode(GL_PROJECTION);
434  glPopMatrix();
435  glMatrixMode(GL_MODELVIEW);
436  glPopMatrix();
437  }
438 };
439 
441 {
442 public:
445  {
446  }
447 
448  virtual void Bind()
449  {
451 
452  pglActiveTextureARB(GL_TEXTURE0);
453  glEnable(GL_TEXTURE_2D);
454  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
455  }
456 
457  virtual void Unbind()
458  {
459  pglActiveTextureARB(GL_TEXTURE0);
460  glDisable(GL_TEXTURE_2D);
461 
463  }
464 };
465 
467 {
468 public:
471  {
472  }
473 
474  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
475  {
476  if (id.second == ID_color)
477  glColor4f(v0, v1, v2, v3);
478  }
479 
480  virtual void Bind()
481  {
483 
484  pglActiveTextureARB(GL_TEXTURE0);
485  glEnable(GL_TEXTURE_2D);
486 
487  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
488 
489  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
490  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
491 
492  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
493  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
494  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
495  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
496 
497  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
498  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
499  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
500  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
501  }
502 
503  virtual void Unbind()
504  {
505  glColor4f(1.f, 1.f, 1.f, 1.f);
506 
507  pglActiveTextureARB(GL_TEXTURE0);
508  glDisable(GL_TEXTURE_2D);
509 
511  }
512 };
513 
515 {
516 public:
519  {
520  }
521 
522  virtual void Bind()
523  {
525 
526  /*
527 
528  For the main conversion, use GL_DOT3_RGB, which is defined as
529  L = 4 * ((Arg0r - 0.5) * (Arg1r - 0.5)+
530  (Arg0g - 0.5) * (Arg1g - 0.5)+
531  (Arg0b - 0.5) * (Arg1b - 0.5))
532  where each of the RGB components is given the value 'L'.
533 
534  Use the magical luminance formula
535  L = 0.3R + 0.59G + 0.11B
536  to calculate the greyscale value.
537 
538  But to work around the annoying "Arg0-0.5", we need to calculate
539  Arg0+0.5. But we also need to scale it into the range 0.5-1.0, else
540  Arg0>0.5 will be clamped to 1.0. So use GL_INTERPOLATE, which outputs:
541  A0 * A2 + A1 * (1 - A2)
542  and set A2 = 0.5, A1 = 1.0, and A0 = texture (i.e. interpolating halfway
543  between the texture and {1,1,1}) giving
544  A0/2 + 0.5
545  and use that as Arg0.
546 
547  So L = 4*(A0/2 * (Arg1-.5))
548  = 2 (Rx+Gy+Bz) (where Arg1 = {x+0.5, y+0.5, z+0.5})
549  = 2x R + 2y G + 2z B
550  = 0.3R + 0.59G + 0.11B
551  so e.g. 2y = 0.59 = 2(Arg1g-0.5) => Arg1g = 0.59/2+0.5
552  which fortunately doesn't get clamped.
553 
554  So, just implement that:
555 
556  */
557 
558  static const float GreyscaleDotColor[4] = {
559  0.3f / 2.f + 0.5f,
560  0.59f / 2.f + 0.5f,
561  0.11f / 2.f + 0.5f,
562  1.0f
563  };
564  static const float GreyscaleInterpColor0[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
565  static const float GreyscaleInterpColor1[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
566 
567  pglActiveTextureARB(GL_TEXTURE0);
568  glEnable(GL_TEXTURE_2D);
569 
570  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
571 
572  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
573  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
574 
575  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
576 
577  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
578  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
579  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GreyscaleInterpColor0);
580 
581  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS);
582  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
583 
584  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
585  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
586  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
587 
588  glColor4fv(GreyscaleInterpColor1);
589 
590  pglActiveTextureARB(GL_TEXTURE1);
591  glEnable(GL_TEXTURE_2D);
592 
593  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
594 
595  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
596  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
597  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
598  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
599 
600  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
601 
602  // GL_DOT3_RGB requires GL_(EXT|ARB)_texture_env_dot3.
603  // We currently don't bother implementing a fallback because it's
604  // only lacking on Riva-class HW, but at least want the rest of the
605  // game to run there without errors. Therefore, squelch the
606  // OpenGL error that's raised if they aren't actually present.
607  // Note: higher-level code checks for this extension, but
608  // allows users the choice of continuing even if not present.
609  ogl_SquelchError(GL_INVALID_ENUM);
610 
611  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
612 
613  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
614  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
615  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GreyscaleDotColor);
616 
617  // To activate the second texture unit, we have to have some kind
618  // of texture bound into it, but we don't actually use the texture data,
619  // so bind a dummy texture
620  g_Renderer.GetTextureManager().GetErrorTexture()->Bind(1);
621  }
622 
623  virtual void Unbind()
624  {
625  glColor4f(1.f, 1.f, 1.f, 1.f);
626 
627  pglActiveTextureARB(GL_TEXTURE1);
628  glDisable(GL_TEXTURE_2D);
629 
630  pglActiveTextureARB(GL_TEXTURE0);
631  glDisable(GL_TEXTURE_2D);
632 
634  }
635 };
636 
638 {
639 public:
642  {
643  }
644 
645  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
646  {
647  if (id.second == ID_color)
648  glColor4f(v0, v1, v2, v3);
649  }
650 
651  virtual void Bind()
652  {
654 
655  pglActiveTextureARB(GL_TEXTURE0);
656  glDisable(GL_TEXTURE_2D);
657  }
658 };
659 
660 //////////////////////////////////////////////////////////////////////////
661 
662 /**
663  * Common functionality for model rendering in the fixed renderpath.
664  */
666 {
667 protected:
668  // Uniforms
669  enum
670  {
675  };
676 
678 
679 public:
680  CShaderProgramFFP_Model_Base(const CShaderDefines& defines, int streamflags)
681  : CShaderProgramFFP(streamflags)
682  {
683  SetUniformIndex("transform", ID_transform);
684  SetUniformIndex("losTransform", ID_losTransform);
685 
686  if (defines.GetInt("USE_OBJECTCOLOR"))
687  SetUniformIndex("objectColor", ID_objectColor);
688 
689  if (defines.GetInt("USE_PLAYERCOLOR"))
690  SetUniformIndex("playerColor", ID_playerColor);
691 
692  m_IgnoreLos = (defines.GetInt("IGNORE_LOS") != 0);
693 
694  // Texture units:
695  SetUniformIndex("baseTex", 0);
696  SetUniformIndex("losTex", 3);
697  }
698 
699  virtual void Uniform(Binding id, const CMatrix3D& v)
700  {
701  if (id.second == ID_transform)
702  glLoadMatrixf(&v._11);
703  }
704 
705  virtual void Uniform(Binding id, float v0, float v1, float UNUSED(v2), float UNUSED(v3))
706  {
707  if (id.second == ID_losTransform)
708  {
709  pglActiveTextureARB(GL_TEXTURE3);
710  GLfloat texgenS1[4] = { v0, 0, 0, v1 };
711  GLfloat texgenT1[4] = { 0, 0, v0, v1 };
712  glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1);
713  glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1);
714  }
715  }
716 
717  virtual void Bind()
718  {
719  glMatrixMode(GL_PROJECTION);
720  glPushMatrix();
721  glLoadIdentity();
722  glMatrixMode(GL_MODELVIEW);
723  glPushMatrix();
724 
725  // -----------------------------------------------------------------------------
726 
727  pglActiveTextureARB(GL_TEXTURE3);
728  glEnable(GL_TEXTURE_2D);
729  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
730 
731  if (m_IgnoreLos)
732  {
733  // RGB pass through
734  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
735  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
736  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
737  }
738  else
739  {
740  // Multiply RGB result up till now with LoS texture alpha channel
741  glEnable(GL_TEXTURE_GEN_S);
742  glEnable(GL_TEXTURE_GEN_T);
743  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
744  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
745  // Overridden implementation of Uniform() sets GL_OBJECT_PLANE values
746 
747  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
748  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
749  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
750  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
751  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
752  }
753 
754  // alpha pass through
755  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
756  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
757  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
758 
759  // -----------------------------------------------------------------------------
760 
762  }
763 
764  virtual void Unbind()
765  {
767 
768  pglActiveTextureARB(GL_TEXTURE3);
769  glDisable(GL_TEXTURE_2D);
770 
771  glDisable(GL_TEXTURE_GEN_S);
772  glDisable(GL_TEXTURE_GEN_T);
773 
774  pglActiveTextureARB(GL_TEXTURE0);
775 
776  glMatrixMode(GL_PROJECTION);
777  glPopMatrix();
778  glMatrixMode(GL_MODELVIEW);
779  glPopMatrix();
780  }
781 };
782 
783 /**
784  * Basic non-recolored diffuse-textured model rendering.
785  */
787 {
788 public:
791  {
792  }
793 
794  virtual void Bind()
795  {
796  // Set up texture environment for base pass - modulate texture and vertex color
797  pglActiveTextureARB(GL_TEXTURE0);
798  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
799  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
800  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
801  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
802  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
803  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
804 
805  // Copy alpha channel from texture
806  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
807  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
808  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
809 
810  // The vertex color is scaled by 0.5 to permit overbrightness without clamping.
811  // We therefore need to scale by 2.0 after the modulation, and before any
812  // further clamping, to get the right color.
813  float scale2[] = { 2.0f, 2.0f, 2.0f };
814  glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale2);
815 
817  }
818 
819  virtual void Unbind()
820  {
822 
823  pglActiveTextureARB(GL_TEXTURE0);
824 
825  // Revert the scaling to default
826  float scale1[] = { 1.0f, 1.0f, 1.0f };
827  glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale1);
828  }
829 };
830 
831 /**
832  * Player-coloring diffuse-textured model rendering.
833  */
835 {
836 public:
839  {
840  }
841 
842  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
843  {
844  if (id.second == ID_objectColor || id.second == ID_playerColor)
845  {
846  // (Player color and object color are mutually exclusive)
847  float color[] = { v0, v1, v2, v3 };
848  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
849  }
850  }
851 
852  virtual void Bind()
853  {
854  // Player color uses a single pass with three texture environments
855  // Note: This uses ARB_texture_env_crossbar (which is checked in GameSetup),
856  // and it requires MAX_TEXTURE_IMAGE_UNITS >= 3 (which only excludes GF2MX/GF4MX)
857  //
858  // We calculate: Result = Color*Texture*(PlayerColor*(1-Texture.a) + 1.0*Texture.a)
859  // Algebra gives us:
860  // Result = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture*Color
861 
862  // TexEnv #0
863  pglActiveTextureARB(GL_TEXTURE0);
864  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
865  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
866  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
867  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_ALPHA);
868  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
869  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_ONE_MINUS_SRC_COLOR);
870 
871  // Don't care about alpha; set it to something harmless
872  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
873  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
874  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
875 
876  // TexEnv #1
877  pglActiveTextureARB(GL_TEXTURE1);
878  glEnable(GL_TEXTURE_2D);
879  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
880  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
881  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
882  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
883  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
884  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
885 
886  // Don't care about alpha; set it to something harmless
887  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
888  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
889  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
890 
891  // TexEnv #2
892  pglActiveTextureARB(GL_TEXTURE2);
893  glEnable(GL_TEXTURE_2D);
894  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
895  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
896  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
897  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
898  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0);
899  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
900 
901  // Don't care about alpha; set it to something harmless
902  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
903  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
904  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
905 
906  float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
907  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
908 
909  // Scale colors at the end of all the computation (see CShaderProgramFFP_Model::Bind)
910  float scale[] = { 2.0f, 2.0f, 2.0f };
911  glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale);
912 
913  // Need to bind some kind of texture to enable the texture units.
914  // Unit 0 has baseTex, but the others need a texture.
915  g_Renderer.GetTextureManager().GetErrorTexture()->Bind(1);
916  g_Renderer.GetTextureManager().GetErrorTexture()->Bind(2);
917 
919  }
920 
921  virtual void Unbind()
922  {
924 
925  pglActiveTextureARB(GL_TEXTURE2);
926  glDisable(GL_TEXTURE_2D);
927 
928  float scale[] = { 1.0f, 1.0f, 1.0f };
929  glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale);
930 
931  pglActiveTextureARB(GL_TEXTURE1);
932  glDisable(GL_TEXTURE_2D);
933 
934  pglActiveTextureARB(GL_TEXTURE0);
935  }
936 };
937 
938 /**
939  * Optionally-player-colored untextured model rendering.
940  */
942 {
943 public:
946  {
947  }
948 
949  virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
950  {
951  if (id.second == ID_playerColor)
952  {
953  float color[] = { v0, v1, v2, v3 };
954  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
955  }
956  }
957 
958  virtual void Bind()
959  {
960  float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
961  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
962 
963  pglActiveTextureARB(GL_TEXTURE0);
964  glEnable(GL_TEXTURE_2D);
965  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
966  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
967  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT);
968  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
969  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
970  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
971  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
972 
974  }
975 };
976 
977 /**
978  * Plain unlit texture model rendering, for e.g. alpha-blended shadow casters.
979  */
981 {
982 public:
985  {
986  }
987 
988  virtual void Bind()
989  {
990  pglActiveTextureARB(GL_TEXTURE0);
991  glEnable(GL_TEXTURE_2D);
992  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
993 
995  }
996 };
997 
998 //////////////////////////////////////////////////////////////////////////
999 
1000 /*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& id, const CShaderDefines& defines)
1001 {
1002  if (id == "dummy")
1003  return new CShaderProgramFFP_Dummy();
1004  if (id == "overlayline")
1005  return new CShaderProgramFFP_OverlayLine(defines);
1006  if (id == "gui_text")
1007  return new CShaderProgramFFP_GuiText();
1008  if (id == "gui_basic")
1009  return new CShaderProgramFFP_GuiBasic();
1010  if (id == "gui_add")
1011  return new CShaderProgramFFP_GuiAdd();
1012  if (id == "gui_grayscale")
1013  return new CShaderProgramFFP_GuiGrayscale();
1014  if (id == "gui_solid")
1015  return new CShaderProgramFFP_GuiSolid();
1016  if (id == "solid")
1017  return new CShaderProgramFFP_GuiSolid(); // works for non-GUI objects too
1018  if (id == "model")
1019  return new CShaderProgramFFP_Model(defines);
1020  if (id == "model_color")
1021  return new CShaderProgramFFP_ModelColor(defines);
1022  if (id == "model_solid")
1023  return new CShaderProgramFFP_ModelSolid(defines);
1024  if (id == "model_solid_tex")
1025  return new CShaderProgramFFP_ModelSolidTex(defines);
1026 
1027  LOGERROR(L"CShaderProgram::ConstructFFP: '%hs': Invalid id", id.c_str());
1028  debug_warn(L"CShaderProgram::ConstructFFP: Invalid id");
1029  return NULL;
1030 }
1031 
1032 #else // CONFIG2_GLES
1033 
1034 /*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& UNUSED(id), const CShaderDefines& UNUSED(defines))
1035 {
1036  debug_warn(L"CShaderProgram::ConstructFFP: FFP not supported on this device");
1037  return NULL;
1038 }
1039 
1040 #endif // CONFIG2_GLES
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
virtual void Bind()
Binds the shader into the GL context.
CShaderProgramFFP_Model(const CShaderDefines &defines)
virtual void Bind()
Binds the shader into the GL context.
int GetUniformIndex(CStrIntern id)
virtual void Bind()
Binds the shader into the GL context.
virtual void Bind()
Binds the shader into the GL context.
virtual void Bind()
Binds the shader into the GL context.
virtual void Uniform(Binding id, const CMatrix3D &v)
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
#define LOGERROR
Definition: CLogger.h:35
void SetUniformIndex(const char *id, int value)
Player-coloring diffuse-textured model rendering.
virtual void Unbind()
Unbinds the shader from the GL context.
virtual void Bind()
Binds the shader into the GL context.
virtual void Unbind()
Unbinds the shader from the GL context.
virtual void Unbind()
Unbinds the shader from the GL context.
virtual void Unbind()
Unbinds the shader from the GL context.
void UnbindClientStates()
bool ogl_SquelchError(GLenum err_to_ignore)
ignore and reset the specified OpenGL error.
Definition: ogl.cpp:430
Common functionality for model rendering in the fixed renderpath.
virtual void Uniform(Binding id, const CMatrix3D &v)
float _11
Definition: Matrix3D.h:42
CShaderProgramFFP_ModelSolid(const CShaderDefines &defines)
#define g_Renderer
Definition: Renderer.h:61
static CShaderProgram * ConstructFFP(const std::string &id, const CShaderDefines &defines)
Construct an instance of a pre-defined fixed-function pipeline setup.
virtual void Bind()
Binds the shader into the GL context.
virtual void Uniform(Binding id, size_t count, const CMatrix3D *v)
Status ogl_tex_bind(Handle ht, size_t unit)
Bind texture to the specified unit in preparation for using it in rendering.
Definition: ogl_tex.cpp:1054
virtual void BindTexture(Binding id, Handle tex)
virtual void Bind()
Binds the shader into the GL context.
virtual void Bind()
Binds the shader into the GL context.
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
Interned 8-bit strings.
Definition: CStrIntern.h:37
virtual Binding GetUniformBinding(uniform_id_t id)
virtual void Unbind()
Unbinds the shader from the GL context.
virtual void Bind()
Binds the shader into the GL context.
CShaderProgramFFP_Gui_Base(int streamflags)
virtual void Uniform(Binding id, const CMatrix3D &v)
virtual void Bind()
Binds the shader into the GL context.
virtual void Unbind()
Unbinds the shader from the GL context.
virtual void Unbind()
Unbinds the shader from the GL context.
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
i64 Handle
`handle&#39; representing a reference to a resource (sound, texture, etc.)
Definition: handle.h:41
std::map< CStrIntern, int > m_UniformIndexes
CShaderProgramFFP_ModelColor(const CShaderDefines &defines)
A shader that does nothing but provide a shader-compatible interface to fixed-function features...
Plain unlit texture model rendering, for e.g.
virtual void Unbind()
Unbinds the shader from the GL context.
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
Represents a mapping of name strings to value strings, for use with #if and #ifdef and similar condit...
virtual void Bind()
Binds the shader into the GL context.
virtual void Uniform(Binding id, const CMatrix3D &v)
virtual Binding GetTextureBinding(uniform_id_t id)
CShaderProgramFFP allows rendering code to use the shader-based API even if the &#39;shader&#39; is actually ...
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
virtual void BindTexture(texture_id_t id, Handle tex)
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
CShaderProgramFFP_OverlayLine(const CShaderDefines &defines)
Optionally-player-colored untextured model rendering.
virtual void Bind()
Binds the shader into the GL context.
int GetInt(const char *name) const
Return the value for the given name as an integer, or 0 if not defined.
Represents a uniform attribute or texture binding.
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
CShaderProgramFFP_Model_Base(const CShaderDefines &defines, int streamflags)
virtual void Uniform(Binding id, const CMatrix3D &v)
CShaderProgramFFP_ModelSolidTex(const CShaderDefines &defines)
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
virtual void BindTexture(texture_id_t id, GLuint tex)
virtual void Unbind()
Unbinds the shader from the GL context.
A compiled vertex+fragment shader program.
Definition: ShaderProgram.h:65
virtual void Unbind()
Unbinds the shader from the GL context.
CShaderProgramFFP(int streamflags)
Basic non-recolored diffuse-textured model rendering.
virtual void Reload()