UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
r_program.cpp
Go to the documentation of this file.
1 
6 /*
7 * Copyright(c) 1997-2001 Id Software, Inc.
8 * Copyright(c) 2002 The Quakeforge Project.
9 * Copyright(c) 2006 Quake2World.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or(at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26 
27 #include "r_local.h"
28 #include "r_error.h"
29 #include "r_program.h"
30 #include "../../shared/parse.h"
31 #include "../../shared/shared.h"
32 
33 #define SHADER_BUF_SIZE 16384
34 
36 
37 const char* shaderQualityLevelNames[SHQ_NUM][2] = {
38  {"world_low","model_low"},
39  {"world_med","model_med"},
40  {"world_med","model_high"}
41 };
42 
44 {
45  if (!qglUseProgram || r_state.active_program == prog)
46  return;
47 
50  else if (!prog)
52  else
54 
55  r_state.active_program = prog;
56 
57  if (prog) {
58  qglUseProgram(prog->id);
59 
60  if (prog->use) /* invoke use function */
61  prog->use(prog);
62  } else {
63  qglUseProgram(0);
64  }
65 }
66 
67 static r_progvar_t* R_ProgramVariable (int type, const char* name)
68 {
69  r_progvar_t* v;
70  int i;
71 
72  if (!r_state.active_program) {
73  Com_DPrintf(DEBUG_RENDERER, "R_ProgramVariable: \"%s\" - No program bound.\n", name);
74  return nullptr;
75  }
76 
77  /* find the variable */
78  for (i = 0; i < MAX_PROGRAM_VARS; i++) {
80 
81  if (!v->location)
82  break;
83 
84  if (v->type == type && Q_streq(v->name, name))
85  return v;
86  }
87 
88  if (i == MAX_PROGRAM_VARS) {
89  Com_Printf("R_ProgramVariable: MAX_PROGRAM_VARS reached.\n");
90  return nullptr;
91  }
92 
93  /* or query for it */
94  if (type == GL_UNIFORM)
95  v->location = qglGetUniformLocation(r_state.active_program->id, name);
96  else
97  v->location = qglGetAttribLocation(r_state.active_program->id, name);
98 
99  if (v->location == -1) {
100  Com_Printf("R_ProgramVariable: Could not find parameter %s in program %s.\n", name, r_state.active_program->name);
101  v->location = 0;
102  return nullptr;
103  }
104 
105  v->type = type;
106  Q_strncpyz(v->name, name, sizeof(v->name));
107 
108  return v;
109 }
110 
111 void R_ProgramParameter1i (const char* name, GLint value)
112 {
113  r_progvar_t* v;
114 
115  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
116  return;
117 
118  qglUniform1i(v->location, value);
119 }
120 
121 void R_ProgramParameter1f (const char* name, GLfloat value)
122 {
123  r_progvar_t* v;
124 
125  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
126  return;
127 
128  qglUniform1f(v->location, value);
129 }
130 
131 void R_ProgramParameter1fvs (const char* name, GLint size, GLfloat* value)
132 {
133  r_progvar_t* v;
134 
135  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
136  return;
137 
138  qglUniform1fv(v->location, size, value);
139 }
140 
141 void R_ProgramParameter2fv (const char* name, GLfloat* value)
142 {
143  r_progvar_t* v;
144 
145  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
146  return;
147 
148  qglUniform2fv(v->location, 1, value);
149 }
150 
151 void R_ProgramParameter2fvs (const char* name, GLint size, GLfloat* value)
152 {
153  r_progvar_t* v;
154 
155  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
156  return;
157 
158  qglUniform2fv(v->location, size, value);
159 }
160 
161 void R_ProgramParameter3fv (const char* name, GLfloat* value)
162 {
163  r_progvar_t* v;
164 
165  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
166  return;
167 
168  qglUniform3fv(v->location, 1, value);
169 }
170 
171 void R_ProgramParameter3fvs (const char* name, GLint size, GLfloat* value)
172 {
173  r_progvar_t* v;
174 
175  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
176  return;
177 
178  qglUniform3fv(v->location, size, value);
179 }
180 
181 void R_ProgramParameter4fv (const char* name, GLfloat* value)
182 {
183  r_progvar_t* v;
184 
185  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
186  return;
187 
188  qglUniform4fv(v->location, 1, value);
189 }
190 
191 void R_ProgramParameter4fvs (const char* name, GLint size, GLfloat* value)
192 {
193  r_progvar_t* v;
194 
195  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
196  return;
197 
198  qglUniform4fv(v->location, size, value);
199 }
200 
201 void R_ProgramParameterMatrix4fv (const char* name, GLfloat* value)
202 {
203  r_progvar_t* v;
204 
205  if (!(v = R_ProgramVariable(GL_UNIFORM, name)))
206  return;
207 
208  qglUniformMatrix4fv(v->location, 1, GL_FALSE, value);
209 }
210 
211 void R_AttributePointer (const char* name, GLuint size, const GLvoid* array)
212 {
213  r_progvar_t* v;
214 
215  if (!(v = R_ProgramVariable(GL_ATTRIBUTE, name)))
216  return;
217 
218  qglVertexAttribPointer(v->location, size, GL_FLOAT, GL_FALSE, 0, array);
219 }
220 
221 void R_EnableAttribute (const char* name)
222 {
223  r_progvar_t* v;
224 
225  if (!(v = R_ProgramVariable(GL_ATTRIBUTE, name)))
226  return;
227 
228  qglEnableVertexAttribArray(v->location);
229 }
230 
231 void R_DisableAttribute (const char* name)
232 {
233  r_progvar_t* v;
234 
235  if (!(v = R_ProgramVariable(GL_ATTRIBUTE, name)))
236  return;
237 
238  qglDisableVertexAttribArray(v->location);
239 }
240 
241 static void R_ShutdownShader (r_shader_t* sh)
242 {
243  qglDeleteShader(sh->id);
244  OBJZERO(*sh);
245 }
246 
247 static void R_ShutdownProgram (r_program_t* prog)
248 {
249  if (prog->v) {
250  qglDetachShader(prog->id, prog->v->id);
251  R_ShutdownShader(prog->v);
252  R_CheckError();
253  }
254  if (prog->f) {
255  qglDetachShader(prog->id, prog->f->id);
256  R_ShutdownShader(prog->f);
257  R_CheckError();
258  }
259 
260  qglDeleteProgram(prog->id);
261 
262  OBJZERO(*prog);
263 }
264 
266 {
267  if (!qglDeleteProgram)
268  return;
269 
270  if (!r_programs->integer)
271  return;
272 
273  for (int i = 0; i < MAX_PROGRAMS; i++) {
274  if (!r_state.programs[i].id)
275  continue;
276 
278  }
279 }
280 
289 static size_t R_PreprocessShaderAddToShaderBuf (const char* name, const char* in, char** out, size_t* len)
290 {
291  const size_t inLength = strlen(in);
292  strcpy(*out, in);
293  *out += inLength;
294  *len -= inLength;
295  return inLength;
296 }
297 
309 static size_t R_InitializeShader (const GLenum type, const char* name, char* out, size_t len)
310 {
311  size_t initialChars = 0;
312  const char* hwHack, *defines;
313  /* in the format GLSL compiler expects it -- e.g. 110 for version 1.10 */
314  const int shaderVersion = (int)(r_glsl_version->value * 100 + 0.1);
315 
316  switch (r_config.hardwareType) {
317  case GLHW_ATI:
318  hwHack = "#ifndef ATI\n#define ATI\n#endif\n";
319  break;
320  case GLHW_INTEL:
321  hwHack = "#ifndef INTEL\n#define INTEL\n#endif\n";
322  break;
323  case GLHW_NVIDIA:
324  hwHack = "#ifndef NVIDIA\n#define NVIDIA\n#endif\n";
325  break;
326  case GLHW_MESA:
327  hwHack = "#ifndef MESA\n#define MESA\n#endif\n";
328  break;
329  case GLHW_GENERIC:
330  hwHack = nullptr;
331  break;
332  default:
333  Com_Error(ERR_FATAL, "R_PreprocessShader: Unknown hardwaretype");
334  }
335 
336  /*
337  * Prefix "#version xxx" onto shader string.
338  * This causes GLSL compiler to compile to that version.
339  */
340  defines = va("#version %d\n", shaderVersion);
341  initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
342 
343  /*
344  * Prefix "#define glslxxx" onto shader string.
345  * This named constant is used to setup shader code to match the desired GLSL spec.
346  */
347  defines = va("#define glsl%d\n", shaderVersion);
348  initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
349 
350  /* Define r_width.*/
351  defines = va("#ifndef r_width\n#define r_width %f\n#endif\n", (float)viddef.context.width);
352  initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
353 
354  /* Define r_height.*/
355  defines = va("#ifndef r_height\n#define r_height %f\n#endif\n", (float)viddef.context.height);
356  initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
357 
358  if (hwHack) {
359  initialChars += R_PreprocessShaderAddToShaderBuf(name, hwHack, &out, &len);
360  }
361 
362  if (GL_VERTEX_SHADER == type) {
363  /* Define 'in_qualifier as 'attribute' & 'out_qualifier' as 'varying' if GLSL v1.10, otherwise define them as 'in' and 'out' respectively.*/
364  initialChars += R_PreprocessShaderAddToShaderBuf(name, "#ifndef glsl110\n#define in_qualifier in\n#define out_qualifier out\n#else\n#define in_qualifier attribute\n#define out_qualifier varying\n#endif\n", &out, &len);
365  } else if (GL_FRAGMENT_SHADER == type) {
366  /* Define 'texture2D' as 'texture', as texture2D was deprecated (replaced with 'texture') as of GLSL v1.30.*/
367  initialChars += R_PreprocessShaderAddToShaderBuf(name, "#ifndef glsl110\n#define texture2D texture\n#endif\n", &out, &len);
368  /* Define 'in_qualifier as 'varying' if GLSL v1.10, otherwise define it as 'in'.*/
369  initialChars += R_PreprocessShaderAddToShaderBuf(name, "#ifndef glsl110\n#define in_qualifier in\n#else\n#define in_qualifier varying\n#endif\n", &out, &len);
370  }
371 
372  return initialChars;
373 }
374 
392 static size_t R_PreprocessShaderR (const char* name, const char** inPtr, char* out, long* remainingOutChars, bool nested, bool inElse)
393 {
394  const size_t INITIAL_REMAINING_OUT_CHARS = (size_t)*remainingOutChars;
395  /* Keep looping till we reach the end of the shader string, or a parsing error.*/
396  while (**inPtr) {
397  if ('#' == **inPtr) {
398  bool endBlockToken;
399  (*inPtr)++;
400 
401  endBlockToken = !strncmp(*inPtr, "endif", 5);
402 
403  if (!strncmp(*inPtr, "else", 4)) {
404  if (inElse) {
405  /* Error in shader! Print a message saying our preprocessor failed parsing.*/
406  Com_Error(ERR_DROP, "R_PreprocessShaderR: #else without #if: %s", name);
407  }
408  endBlockToken = true;
409  }
410 
411  if (endBlockToken) {
412  if (!nested) {
413  /* Error in shader! Print a message saying our preprocessor failed parsing.*/
414  Com_Error(ERR_DROP, "R_PreprocessShaderR: Unmatched #endif/#else: %s", name);
415  }
416  /* Whoever called us will have to deal with closing the block */
417  return (INITIAL_REMAINING_OUT_CHARS - (size_t)*remainingOutChars);
418  }
419 
420  if (!strncmp((*inPtr), "if ", 3)) {
421  /* The line looks like "#if r_postprocess".*/
422  (*inPtr) += 3;
423  /* Get the corresponding cvar value.*/
424  float f = Cvar_GetValue(Com_Parse(inPtr));
425  if (f) { /* Condition is true, recursively preprocess #if block, and skip over #else block, if any */
426  int size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, false);
427  if (out) out += size;
428 
429  if (!strncmp((*inPtr), "else", 4)) {/* Preprocess and skip #else block */
430  (*inPtr) +=4 ;
431  R_PreprocessShaderR(name, inPtr, (char*)0, remainingOutChars, true, true);
432  }
433  } else {
434  /* The cvar was false, don't add to out. Lets look and see if we hit a #else, or #endif.*/
435  R_PreprocessShaderR(name, inPtr, (char*)0, remainingOutChars, true, false);
436  if (!strncmp((*inPtr), "else", 4)) {
437  int size;
438  /* All right, we want to add this to out.*/
439  (*inPtr) +=4 ;
440  size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, true);
441  if (out) out += size;
442  }
443  }
444  /* skip #endif, if any (could also get here by unexpected EOF */
445  if (!strncmp((*inPtr), "endif", 5))
446  (*inPtr) +=5 ;
447  } else if (!strncmp((*inPtr), "ifndef", 6) || !strncmp((*inPtr), "ifdef", 5)) { /* leave those for GLSL compiler, but follow #else/#endif nesting */
448  int size;
449  if (out) {
450  if (*remainingOutChars <= 0)
451  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
452  *out++ = '#';
453  (*remainingOutChars)--;
454  }
455 
456  size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, false);
457  if (out) out += size;
458 
459  if (!strncmp((*inPtr), "else", 4)) {
460  if (out) {
461  if (*remainingOutChars <= 0)
462  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
463  *out++ = '#';
464  (*remainingOutChars)--;
465  }
466  size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, true);
467  if (out) out += size;
468  }
469 
470  if (out) {
471  if (*remainingOutChars <= 0)
472  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
473  *out++ = '#';
474  (*remainingOutChars)--;
475  }
476 
477  } else if (!strncmp((*inPtr), "include", 7)) {
478  char path[MAX_QPATH];
479  byte* buf = (byte*)0;
480  const char* bufAsChar = (const char*)0;
481  const char** bufAsCharPtr = (const char**)0;
482  (*inPtr) += 8;
483  Com_sprintf(path, sizeof(path), "shaders/%s", Com_Parse(inPtr));
484  if (FS_LoadFile(path, &buf) == -1) {
485  Com_Printf("Failed to resolve #include: %s.\n", path);
486  continue;
487  }
488  bufAsChar = (const char*)buf;
489  bufAsCharPtr = &bufAsChar;
490  if (out) {
491  out += R_PreprocessShaderR(name, bufAsCharPtr, out, remainingOutChars, nested, false);
492  } else {
493  R_PreprocessShaderR(name, bufAsCharPtr, out, remainingOutChars, nested, false);
494  }
495  FS_FreeFile(buf);
496  } else if (!strncmp((*inPtr), "unroll", 6)) {
497  /* loop unrolling */
498  size_t subLength = 0;
500  (*inPtr) += 6;
501  int z = Cvar_GetValue(Com_Parse(inPtr));
502  while (*(*inPtr)) {
503  if (!strncmp((*inPtr), "#endunroll", 10)) {
504  (*inPtr) += 10;
505  break;
506  }
507  buffer[subLength++] = *(*inPtr)++;
508  if (subLength >= SHADER_BUF_SIZE)
509  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
510  }
511  if (out) {
512  for (int j = 0; j < z; j++) {
513  for (int l = 0; l < subLength; l++) {
514  if (buffer[l] == '$') {
515  byte insertedLen = (j / 10) + 1;
516  if (!Com_sprintf(out, (size_t)*remainingOutChars, "%d", j))
517  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
518  out += insertedLen;
519  (*remainingOutChars) -= insertedLen;
520  } else {
521  if (*remainingOutChars <= 0)
522  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
523  *out++ = buffer[l];
524  (*remainingOutChars)--;
525  }
526  }
527  }
528  }
529  Mem_Free(buffer);
530  } else if (!strncmp((*inPtr), "replace", 7)) {
531  int r = 0;
532  (*inPtr) += 8;
533  r = Cvar_GetValue(Com_Parse(inPtr));
534  if (out) {
535  byte insertedLen = 0;
536  if (!Com_sprintf(out, (size_t)*remainingOutChars, "%d", r))
537  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
538  insertedLen = (r / 10) + 1;
539  out += insertedLen;
540  (*remainingOutChars) -= insertedLen;
541  }
542  } else {
543  /* general case is to copy so long as the buffer has room */
544  if (out) {
545  if (*remainingOutChars <= 0)
546  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
547  *out++ = '#';
548  (*remainingOutChars)--;
549  }
550  }
551  } else {
552  /* general case is to copy so long as the buffer has room */
553  if (out) {
554  if (*remainingOutChars <= 0)
555  Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
556  *out++ = *(*inPtr);
557  (*remainingOutChars)--;
558  }
559  (*inPtr)++;
560  }
561  }
562  /* Return the number of characters added to the buffer.*/
563  return (INITIAL_REMAINING_OUT_CHARS - *remainingOutChars);
564 }
565 
581 static size_t R_PreprocessShader (const char* name, const char* in, char* out, size_t* remainingOutChars)
582 {
583  long remainingOutCharsAsLong = *remainingOutChars;
584  size_t numCharactersAddedToOutBuffer = R_PreprocessShaderR(name, &in, out, &remainingOutCharsAsLong, false, false);
585  *remainingOutChars = remainingOutCharsAsLong;
586  return numCharactersAddedToOutBuffer;
587 }
588 
595 static r_shader_t* R_LoadShader (const GLenum type, const char* name)
596 {
597  r_shader_t* sh;
598  char path[MAX_QPATH], *src[1];
599  unsigned e, length[1];
600  char* srcBuf;
601  byte* buf;
602  int i;
603  size_t bufLength = SHADER_BUF_SIZE;
604  size_t initializeLength;
605 
606 #ifdef DEBUG
607  /* Used to contain result of shader compile.*/
608  char log[MAX_STRING_CHARS];
609 #endif
610 
611  snprintf(path, sizeof(path), "shaders/%s", name);
612 
613  if (FS_LoadFile(path, &buf) == -1) {
614  Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Failed to load ./base/shaders/%s.\n", name);
615  return nullptr;
616  }
617 
618  Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Loading ./base/shaders/%s.\n", name);
619 
620  char* const source = srcBuf = Mem_PoolAllocTypeN(char, bufLength, vid_imagePool);
621 
622  initializeLength = R_InitializeShader(type, name, srcBuf, bufLength);
623  srcBuf += initializeLength;
624  bufLength -= initializeLength;
625 
626  R_PreprocessShader(name, (const char*)buf, srcBuf, &bufLength);
627  FS_FreeFile(buf);
628 
629  src[0] = source;
630  length[0] = strlen(source);
631 
632  for (i = 0; i < MAX_SHADERS; i++) {
633  sh = &r_state.shaders[i];
634 
635  if (!sh->id)
636  break;
637  }
638 
639  if (i == MAX_SHADERS) {
640  Com_Printf("R_LoadShader: MAX_SHADERS reached.\n");
641  Mem_Free(source);
642  return nullptr;
643  }
644 
645  Q_strncpyz(sh->name, name, sizeof(sh->name));
646 
647  sh->type = type;
648 
649  sh->id = qglCreateShader(sh->type);
650  if (!sh->id) {
651  Mem_Free(source);
652  return nullptr;
653  }
654 
655  /* upload the shader source */
656  qglShaderSource(sh->id, 1, src, length);
657 
658  /* compile it and check for errors */
659  qglCompileShader(sh->id);
660 
661  Mem_Free(source);
662 
663  qglGetShaderiv(sh->id, GL_COMPILE_STATUS, &e);
664 #ifdef DEBUG
665  qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log);
666  Com_Printf("R_LoadShader: %s: %s", sh->name, log);
667 #endif
668  if (!e) {
669 #ifndef DEBUG
670  char log[MAX_STRING_CHARS];
671  qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log);
672  Com_Printf("R_LoadShader: %s: %s", sh->name, log);
673 #endif
674 
675  qglDeleteShader(sh->id);
676  OBJZERO(*sh);
677 
678  return nullptr;
679  }
680 
681  return sh;
682 }
683 
685 {
686  r_program_t* prog;
687  unsigned e;
688  int i;
689 
690  /* shaders are deactivated */
691  if (!r_programs->integer)
692  return nullptr;
693 
694  /* search existing one */
695  for (i = 0; i < MAX_PROGRAMS; i++) {
696  prog = &r_state.programs[i];
697 
698  if (Q_streq(prog->name, name))
699  return prog;
700  }
701 
702  /* search free slot */
703  for (i = 0; i < MAX_PROGRAMS; i++) {
704  prog = &r_state.programs[i];
705 
706  if (!prog->id)
707  break;
708  }
709 
710  if (i == MAX_PROGRAMS) {
711  Com_Printf("R_LoadProgram: MAX_PROGRAMS reached.\n");
712  return nullptr;
713  }
714 
715  Q_strncpyz(prog->name, name, sizeof(prog->name));
716 
717  prog->id = qglCreateProgram();
718 
719  prog->v = R_LoadShader(GL_VERTEX_SHADER, va("%s_vs.glsl", name));
720  prog->f = R_LoadShader(GL_FRAGMENT_SHADER, va("%s_fs.glsl", name));
721 
722  if (prog->v)
723  qglAttachShader(prog->id, prog->v->id);
724  if (prog->f)
725  qglAttachShader(prog->id, prog->f->id);
726 
727  qglLinkProgram(prog->id);
728 
729  qglGetProgramiv(prog->id, GL_LINK_STATUS, &e);
730  if (!e || !prog->v || !prog->f) {
731  char log[MAX_STRING_CHARS];
732  qglGetProgramInfoLog(prog->id, sizeof(log) - 1, nullptr, log);
733  Com_Printf("R_LoadProgram: %s: %s\n", prog->name, log);
734 
735  R_ShutdownProgram(prog);
736  return nullptr;
737  }
738 
739  prog->init = init;
740 
741  if (prog->init) { /* invoke initialization function */
742  R_UseProgram(prog);
743 
744  prog->init(prog);
745 
746  R_UseProgram(nullptr);
747  }
748 
749  prog->use = use;
750 
751  Com_Printf("R_LoadProgram: '%s' loaded.\n", name);
752 
753  return prog;
754 }
755 
756 extern vec2_t fogRange;
757 
758 static void R_InitWorldProgram (r_program_t* prog)
759 {
760  R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
761  R_ProgramParameter1i("SAMPLER_LIGHTMAP", 1);
762  R_ProgramParameter1i("SAMPLER_DELUXEMAP", 2);
763  R_ProgramParameter1i("SAMPLER_NORMALMAP", 3);
764  R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
765 
766  R_ProgramParameter1i("BUMPMAP", 0);
767 
768  if (r_programs->integer > 1) {
770 
771  R_ProgramParameter1i("SPECULARMAP", 0);
772  R_ProgramParameter1i("SAMPLER_SPECULAR", 5);
773 
777  }
778 
781 
782  if (r_fog->integer) {
783  if (r_state.fog_enabled) {
785  R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
786  R_ProgramParameter2fv("FOGRANGE", fogRange);
787  } else {
788  R_ProgramParameter1f("FOGDENSITY", 0.0f);
789  }
790  }
791 }
792 
793 static void R_UseWorldProgram (r_program_t* prog)
794 {
795  if (r_programs->integer > 1) {
797  }
798 
799  if (r_fog->integer) {
800  if (r_state.fog_enabled) {
802  R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
803  R_ProgramParameter2fv("FOGRANGE", fogRange);
804  } else {
805  R_ProgramParameter1f("FOGDENSITY", 0.0f);
806  }
807  }
808 }
809 
810 static void R_InitModelProgram (r_program_t* prog)
811 {
812  vec4_t sunDirection;
813 
814  R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
815  R_ProgramParameter1i("SAMPLER_NORMALMAP", 3);
816  R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
817 
818  R_ProgramParameter1i("BUMPMAP", 0);
819  R_ProgramParameter1i("ANIMATE", 0);
820 
823  R_ProgramParameter1f("OFFSET", 0.0);
824 
827 
829  R_ProgramParameter3fv("SUNDIRECTION", sunDirection); /* last component is not needed */
830 
831  if (r_programs->integer > 1) {
832  R_ProgramParameter1i("SAMPLER_SPECULAR", 5);
833  R_ProgramParameter1i("SPECULARMAP", 0);
837  if (r_programs->integer > 2) {
838  R_ProgramParameter1i("SAMPLER_ROUGHMAP", 2);
839  R_ProgramParameter1i("ROUGHMAP", 0);
840  }
841  }
842 
843  if (r_fog->integer) {
844  if (r_state.fog_enabled) {
846  R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
847  R_ProgramParameter2fv("FOGRANGE", fogRange);
848  } else {
849  R_ProgramParameter1f("FOGDENSITY", 0.0f);
850  }
851  }
852 }
853 
854 static void R_UseModelProgram (r_program_t* prog)
855 {
856  vec4_t sunDirection;
857  /*R_ProgramParameter1i("LIGHTS", refdef.numLights);*/
858 
859  R_ProgramParameter1f("OFFSET", 0.0);
862 
864  R_ProgramParameter3fv("SUNDIRECTION", sunDirection); /* last component is not needed */
865 
866  if (r_fog->integer) {
867  if (r_state.fog_enabled) {
869  R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
870  R_ProgramParameter2fv("FOGRANGE", fogRange);
871  } else {
872  R_ProgramParameter1f("FOGDENSITY", 0.0f);
873  }
874  }
875 }
876 
877 static void R_InitWarpProgram (r_program_t* prog)
878 {
879  static vec4_t offset;
880 
881  R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
882  R_ProgramParameter1i("SAMPLER_WARP", 1);
883  R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
884  R_ProgramParameter1f("GLOWSCALE", 0.0);
885  R_ProgramParameter4fv("OFFSET", offset);
886  if (r_fog->integer) {
887  if (r_state.fog_enabled) {
889  R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
890  R_ProgramParameter2fv("FOGRANGE", fogRange);
891  } else {
892  R_ProgramParameter1f("FOGDENSITY", 0.0f);
893  }
894  }
895 }
896 
897 static void R_UseWarpProgram (r_program_t* prog)
898 {
899  static vec4_t offset;
900 
901  offset[0] = offset[1] = refdef.time / 8.0;
902  R_ProgramParameter4fv("OFFSET", offset);
903  if (r_fog->integer) {
904  if (r_state.fog_enabled) {
906  R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
907  R_ProgramParameter2fv("FOGRANGE", fogRange);
908  } else {
909  R_ProgramParameter1f("FOGDENSITY", 0.0f);
910  }
911  }
912 }
913 
915 {
916  static vec4_t defaultColor = {0.0, 0.0, 0.0, 1.0};
917  static vec4_t cityLightColor = {1.0, 1.0, 0.8, 1.0};
918  static vec2_t uvScale = {2.0, 1.0};
919 
920  R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
921  R_ProgramParameter1i("SAMPLER_BLEND", 1);
922  R_ProgramParameter1i("SAMPLER_NORMALMAP", 2);
923 
924  R_ProgramParameter4fv("DEFAULTCOLOR", defaultColor);
925  R_ProgramParameter4fv("CITYLIGHTCOLOR", cityLightColor);
926  R_ProgramParameter2fv("UVSCALE", uvScale);
927 }
928 
933 static int R_PascalTriangle (int row, int col)
934 {
935  if (row <= 1 || col <= 1 || col >= row)
936  return 1;
937  return R_PascalTriangle(row - 1, col) + R_PascalTriangle(row - 1, col - 1);
938 }
939 
941 #define FILTER_SIZE 3
942 
944 {
945  float filter[FILTER_SIZE];
946  float sum = 0;
947  int i;
948  const size_t size = lengthof(filter);
949 
950  /* approximate a Gaussian by normalizing the Nth row of Pascale's Triangle */
951  for (i = 0; i < size; i++) {
952  filter[i] = (float)R_PascalTriangle(size, i + 1);
953  sum += filter[i];
954  }
955 
956  for (i = 0; i < size; i++)
957  filter[i] = (filter[i] / sum);
958 
959  R_ProgramParameter1i("SAMPLER0", 0);
960  R_ProgramParameter1fvs("COEFFICIENTS", size, filter);
961 }
962 
967 {
968  const float* userdata= (float*)prog->userdata;
969  float offsets[FILTER_SIZE * 2];
970  const float halfWidth = (FILTER_SIZE - 1) * 0.5;
971  const float offset = 1.2f / userdata[0];
972  const float x = userdata[1] * offset;
973 
974  for (int i = 0; i < FILTER_SIZE; i++) {
975  const float y = (float)i - halfWidth;
976  const float z = x * y;
977  offsets[i * 2 + 0] = offset * y - z;
978  offsets[i * 2 + 1] = z;
979  }
980  R_ProgramParameter2fvs("OFFSETS", FILTER_SIZE, offsets);
981 }
982 
984 {
985  GLfloat defaultColor[4] = {0.0, 0.0, 0.0, 0.0};
986 
987  R_ProgramParameter1i("SAMPLER0", 0);
988  R_ProgramParameter1i("SAMPLER1", 1);
989 
990  R_ProgramParameter4fv("DEFAULTCOLOR", defaultColor);
991 }
992 
994 {
995  static vec4_t defaultColor = {0.0, 0.0, 0.0, 1.0};
996  static vec2_t uvScale = {2.0, 1.0};
997 
998  R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
999  R_ProgramParameter1i("SAMPLER_NORMALMAP", 2);
1000 
1001  R_ProgramParameter4fv("DEFAULTCOLOR", defaultColor);
1002  R_ProgramParameter2fv("UVSCALE", uvScale);
1003 }
1004 
1006 {
1007  R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
1008  R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
1009  R_ProgramParameter1f("GLOWSCALE", 1.0);
1010 }
1011 
1013 {
1014  R_ProgramParameter1i("SAMPLER0", 0);
1015 }
1016 
1018 {
1019 /* ptl_t* ptl = (ptl_t*)prog->userdata;*/
1020 }
1021 
1022 void R_InitPrograms (void)
1023 {
1024  if (!qglCreateProgram) {
1025  Com_Printf("not using GLSL shaders\n");
1026  Cvar_Set("r_programs", "0");
1027  r_programs->modified = false;
1028  return;
1029  }
1030 
1033 
1034  /* Capable of running shaders, but have got them disabled, so do nothing */
1035  if (!r_programs->integer)
1036  return;
1037 
1046 
1049  Com_Printf("disabled shaders because they failed to compile\n");
1050  Cvar_Set("r_programs", "0");
1051  r_programs->modified = false;
1052  }
1053 }
1054 
1059 {
1060  if (r_programs->integer) {
1061  Com_Printf("glsl restart to a version of v%s\n", Cvar_Get("r_glsl_version", nullptr, 0, nullptr)->string);
1062  } else {
1063  Com_Printf("glsl shutdown\n");
1064  }
1065 
1067  R_InitPrograms();
1068  R_InitFBObjects();
1069 }
const char * shaderQualityLevelNames[SHQ_NUM][2]
Definition: r_program.cpp:37
static void R_InitConvolveProgram(r_program_t *prog)
Definition: r_program.cpp:943
vec4_t sunDiffuseColor
Definition: cl_renderer.h:184
void R_DisableAttribute(const char *name)
Definition: r_program.cpp:231
void R_UseProgram(r_program_t *prog)
Definition: r_program.cpp:43
programInitFunc_t init
Definition: r_program.h:60
r_program_t * warp_program
Definition: r_state.h:134
bool fog_enabled
Definition: r_state.h:156
#define GL_FRAGMENT_SHADER
void R_RestartPrograms_f(void)
Reloads the glsl shaders.
Definition: r_program.cpp:1058
static size_t R_PreprocessShaderR(const char *name, const char **inPtr, char *out, long *remainingOutChars, bool nested, bool inElse)
Do our own preprocessing to the shader file, before the GLSL implementation calls it's preprocessor...
Definition: r_program.cpp:392
void * userdata
Definition: r_program.h:62
r_program_t * R_LoadProgram(const char *name, programInitFunc_t init, programUseFunc_t use)
Definition: r_program.cpp:684
shaderQualityLevel_t
Definition: r_program.cpp:35
char name[MAX_QPATH]
Definition: r_program.h:30
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
#define FILTER_SIZE
width of convolution filter (for blur/bloom effects)
Definition: r_program.cpp:941
programUseFunc_t use
Definition: r_program.h:61
#define GL_ATTRIBUTE
Definition: r_program.h:36
void R_InitParticleProgram(r_program_t *prog)
Definition: r_program.cpp:1012
void R_ProgramParameter2fv(const char *name, GLfloat *value)
Definition: r_program.cpp:141
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
static size_t R_InitializeShader(const GLenum type, const char *name, char *out, size_t len)
Prefixes the shader string with user settings and the video hardware manufacturer.
Definition: r_program.cpp:309
r_program_t * atmosphere_program
Definition: r_state.h:138
r_program_t * active_program
Definition: r_state.h:140
r_shader_t * f
Definition: r_program.h:58
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
GLint location
Definition: r_program.h:41
const GLenum *typedef GLint
Definition: r_gl.h:205
cvar_t * r_programs
Definition: r_main.cpp:97
static void R_InitAtmosphereProgram(r_program_t *prog)
Definition: r_program.cpp:993
r_program_t * combine2_program
Definition: r_state.h:137
vec4_t sunVector
Definition: cl_renderer.h:186
float value
Definition: cvar.h:80
static r_shader_t * R_LoadShader(const GLenum type, const char *name)
Reads/Preprocesses/Compiles the specified shader into a program.
Definition: r_program.cpp:595
viddef_t viddef
Definition: cl_video.cpp:34
local graphics definitions
float bump
Definition: r_material.h:159
#define GL_VERTEX_SHADER
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
char name[MAX_VAR]
Definition: r_program.h:56
unsigned width
Definition: cl_video.h:44
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
rconfig_t r_config
Definition: r_main.cpp:47
static void R_InitCombine2Program(r_program_t *prog)
Definition: r_program.cpp:983
GLint type
Definition: r_program.h:39
char name[MAX_QPATH]
Definition: r_program.h:40
QGL_EXTERN GLuint
Definition: r_gl.h:124
int integer
Definition: cvar.h:81
static r_progvar_t * R_ProgramVariable(int type, const char *name)
Definition: r_program.cpp:67
const GLuint *typedef GLuint *typedef GLenum
Definition: r_gl.h:190
voidpf void * buf
Definition: ioapi.h:42
#define ERR_FATAL
Definition: common.h:210
static void R_UseConvolveProgram(r_program_t *prog)
Use the filter convolution glsl program.
Definition: r_program.cpp:966
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
void R_ProgramParameter2fvs(const char *name, GLint size, GLfloat *value)
Definition: r_program.cpp:151
r_progvar_t vars[MAX_PROGRAM_VARS]
Definition: r_program.h:59
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
r_shader_t * v
Definition: r_program.h:57
void(* programInitFunc_t)(struct r_program_s *prog)
Definition: r_program.h:50
#define SHADER_BUF_SIZE
Definition: r_program.cpp:33
float world_matrix[16]
Definition: r_local.h:112
#define ERR_DROP
Definition: common.h:211
static void R_InitGeoscapeProgram(r_program_t *prog)
Definition: r_program.cpp:914
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition: cvar.cpp:342
GLsizei size
Definition: r_gl.h:152
#define MAX_PROGRAMS
Definition: r_program.h:65
rendererData_t refdef
Definition: r_main.cpp:45
#define OBJZERO(obj)
Definition: shared.h:178
float Cvar_GetValue(const char *varName)
Returns the float value of a cvar.
Definition: cvar.cpp:125
rlocals_t r_locals
Definition: r_main.cpp:49
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
void R_ProgramParameter3fv(const char *name, GLfloat *value)
Definition: r_program.cpp:161
#define GL_UNIFORM
Definition: r_program.h:34
static void R_UseModelProgram(r_program_t *prog)
Definition: r_program.cpp:854
GLuint id
Definition: r_program.h:55
void R_UseParticleProgram(r_program_t *prog)
Definition: r_program.cpp:1017
GLenum type
Definition: r_program.h:28
void R_ProgramParameter1i(const char *name, GLint value)
Definition: r_program.cpp:111
void(* programUseFunc_t)(struct r_program_s *prog)
Definition: r_program.h:51
void R_InitFBObjects(void)
static void R_InitWorldProgram(r_program_t *prog)
Definition: r_program.cpp:758
void R_ShutdownPrograms(void)
Definition: r_program.cpp:265
static void R_UseWorldProgram(r_program_t *prog)
Definition: r_program.cpp:793
r_program_t * geoscape_program
Definition: r_state.h:135
hardwareType_t hardwareType
Definition: r_local.h:202
r_program_t programs[MAX_PROGRAMS]
Definition: r_state.h:131
material_t defaultMaterial
Definition: r_material.cpp:34
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
#define GL_LINK_STATUS
viddefContext_t context
Definition: cl_video.h:67
r_program_t * simple_glow_program
Definition: r_state.h:139
float specular
Definition: r_material.h:162
vec2_t fogRange
Definition: r_state.cpp:584
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
static void R_InitWarpProgram(r_program_t *prog)
Definition: r_program.cpp:877
void R_ProgramParameter4fv(const char *name, GLfloat *value)
Definition: r_program.cpp:181
void R_ProgramParameterMatrix4fv(const char *name, GLfloat *value)
Definition: r_program.cpp:201
cvar_t * r_glsl_version
The GLSL version being used (not necessarily a supported version by the OpenGL implementation). Stored as a c-string and integer.
Definition: r_main.cpp:99
void R_ProgramParameter4fvs(const char *name, GLint size, GLfloat *value)
Definition: r_program.cpp:191
static void R_UseWarpProgram(r_program_t *prog)
Definition: r_program.cpp:897
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
void R_ProgramParameter1fvs(const char *name, GLint size, GLfloat *value)
Definition: r_program.cpp:131
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition: parse.cpp:107
float parallax
Definition: r_material.h:160
r_program_t * world_program
Definition: r_state.h:132
static int R_PascalTriangle(int row, int col)
Definition: r_program.cpp:933
void R_EnableAttribute(const char *name)
Definition: r_program.cpp:221
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
#define MAX_STRING_CHARS
Definition: defines.h:90
void R_AttributePointer(const char *name, GLuint size, const GLvoid *array)
Definition: r_program.cpp:211
r_shader_t shaders[MAX_SHADERS]
Definition: r_state.h:130
int shaderToShaderCount
Definition: cl_renderer.h:178
#define MAX_SHADERS
Definition: r_program.h:66
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
static void R_ShutdownShader(r_shader_t *sh)
Definition: r_program.cpp:241
static size_t R_PreprocessShader(const char *name, const char *in, char *out, size_t *remainingOutChars)
Do our own preprocessing to the shader file, before the GLSL implementation calls it's preprocessor...
Definition: r_program.cpp:581
#define Mem_Free(ptr)
Definition: mem.h:35
Error checking function.
vec_t vec2_t[2]
Definition: ufotypes.h:38
memPool_t * vid_imagePool
Definition: cl_main.cpp:88
rstate_t r_state
Definition: r_main.cpp:48
void R_ProgramParameter3fvs(const char *name, GLint size, GLfloat *value)
Definition: r_program.cpp:171
r_program_t * model_program
Definition: r_state.h:133
vec4_t ambientColor
Definition: cl_renderer.h:182
vec4_t modelAmbientColor
Definition: cl_renderer.h:183
#define lengthof(x)
Definition: shared.h:105
#define R_CheckError()
Definition: r_error.h:30
cvar_t * Cvar_Set(const char *varName, const char *value,...)
Sets a cvar value.
Definition: cvar.cpp:615
float glowscale
Definition: r_material.h:163
#define Q_streq(a, b)
Definition: shared.h:136
r_program_t * convolve_program
Definition: r_state.h:136
static void R_InitSimpleGlowProgram(r_program_t *prog)
Definition: r_program.cpp:1005
bool modified
Definition: cvar.h:79
static size_t R_PreprocessShaderAddToShaderBuf(const char *name, const char *in, char **out, size_t *len)
Prefixes shader string (out) with in.
Definition: r_program.cpp:289
voidpf uLong offset
Definition: ioapi.h:45
unsigned height
Definition: cl_video.h:45
void GLVectorTransform(const float m[16], const vec4_t in, vec4_t out)
Multiply 4*4 matrix by 4d vector.
Definition: mathlib.cpp:366
#define MAX_PROGRAM_VARS
Definition: r_program.h:46
static void R_ShutdownProgram(r_program_t *prog)
Definition: r_program.cpp:247
uint8_t byte
Definition: ufotypes.h:34
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
void R_ProgramParameter1f(const char *name, GLfloat value)
Definition: r_program.cpp:121
void R_InitPrograms(void)
Definition: r_program.cpp:1022
#define DEBUG_RENDERER
Definition: defines.h:62
cvar_t * r_fog
Definition: r_main.cpp:107
#define GL_COMPILE_STATUS
GLuint id
Definition: r_program.h:29
static void R_InitModelProgram(r_program_t *prog)
Definition: r_program.cpp:810
float hardness
Definition: r_material.h:161
#define DOUBLEQUOTE(x)
Definition: shared.h:90
void FS_FreeFile(void *buffer)
Definition: files.cpp:411
vec_t vec4_t[4]
Definition: ufotypes.h:40