1 /**
2  * @file
3  * @brief Shader (GLSL) backend functions
4  */
5 
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 
35 typedef enum {SHQ_LOW, SHQ_MID, SHQ_HIGH, SHQ_NUM} shaderQualityLevel_t;
36 
37 const char* shaderQualityLevelNames[SHQ_NUM][2] = {
38 	{"world_low","model_low"},
39 	{"world_med","model_med"},
40 	{"world_med","model_high"} /** @todo high quality world shader */
41 };
42 
R_UseProgram(r_program_t * prog)43 void R_UseProgram  (r_program_t* prog)
44 {
45 	if (!qglUseProgram || r_state.active_program == prog)
46 		return;
47 
48 	if (!r_state.active_program)
49 		refdef.FFPToShaderCount++;
50 	else if (!prog)
51 		refdef.shaderToFFPCount++;
52 	else
53 		refdef.shaderToShaderCount++;
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 
R_ProgramVariable(int type,const char * name)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++) {
79 		v = &r_state.active_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 
R_ProgramParameter1i(const char * name,GLint value)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 
R_ProgramParameter1f(const char * name,GLfloat value)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 
R_ProgramParameter1fvs(const char * name,GLint size,GLfloat * value)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 
R_ProgramParameter2fv(const char * name,GLfloat * value)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 
R_ProgramParameter2fvs(const char * name,GLint size,GLfloat * value)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 
R_ProgramParameter3fv(const char * name,GLfloat * value)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 
R_ProgramParameter3fvs(const char * name,GLint size,GLfloat * value)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 
R_ProgramParameter4fv(const char * name,GLfloat * value)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 
R_ProgramParameter4fvs(const char * name,GLint size,GLfloat * value)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 
R_ProgramParameterMatrix4fv(const char * name,GLfloat * value)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 
R_AttributePointer(const char * name,GLuint size,const GLvoid * array)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 
R_EnableAttribute(const char * name)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 
R_DisableAttribute(const char * name)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 
R_ShutdownShader(r_shader_t * sh)241 static void R_ShutdownShader (r_shader_t* sh)
242 {
243 	qglDeleteShader(sh->id);
244 	OBJZERO(*sh);
245 }
246 
R_ShutdownProgram(r_program_t * prog)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 
R_ShutdownPrograms(void)265 void R_ShutdownPrograms (void)
266 {
267 	int i;
268 
269 	if (!qglDeleteProgram)
270 		return;
271 
272 	if (!r_programs->integer)
273 		return;
274 
275 	for (i = 0; i < MAX_PROGRAMS; i++) {
276 		if (!r_state.programs[i].id)
277 			continue;
278 
279 		R_ShutdownProgram(&r_state.programs[i]);
280 	}
281 }
282 
283 /**
284  * @brief Prefixes shader string (out) with in.
285  * @param[in] name The name of the shader.
286  * @param[in] in The string to prefix onto the shader string (out).
287  * @param[in,out] out The shader string (initially was the whole shader file).
288  * @param[in,out] len The amount of space left in the buffer pointed to by *out.
289  * @return strlen(in)
290  */
R_PreprocessShaderAddToShaderBuf(const char * name,const char * in,char ** out,size_t * len)291 static size_t R_PreprocessShaderAddToShaderBuf (const char* name, const char* in, char** out, size_t* len)
292 {
293 	const size_t inLength = strlen(in);
294 	strcpy(*out, in);
295 	*out += inLength;
296 	*len -= inLength;
297 	return inLength;
298 }
299 
300 /**
301  * @brief Prefixes the shader string with user settings and the video hardware manufacturer.
302  *
303  * The shader needs to know the rendered width & height, the glsl version, and
304  * the hardware manufacturer.
305  * @param[in] type The type of shader, currently either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
306  * @param[in] name The name of the shader.
307  * @param[in,out] out
308  * @param[in,out] len The amount of space left in the buffer pointed to by *out.
309  * @return The number of characters prefixed to the shader string.
310  */
R_InitializeShader(const GLenum type,const char * name,char * out,size_t len)311 static size_t R_InitializeShader (const GLenum type, const char* name, char* out, size_t len)
312 {
313 	size_t initialChars = 0;
314 	const char* hwHack, *defines;
315 	/* in the format GLSL compiler expects it -- e.g. 110 for version 1.10 */
316 	const int shaderVersion = (int)(r_glsl_version->value * 100 + 0.1);
317 
318 	switch (r_config.hardwareType) {
319 	case GLHW_ATI:
320 		hwHack = "#ifndef ATI\n#define ATI\n#endif\n";
321 		break;
322 	case GLHW_INTEL:
323 		hwHack = "#ifndef INTEL\n#define INTEL\n#endif\n";
324 		break;
325 	case GLHW_NVIDIA:
326 		hwHack = "#ifndef NVIDIA\n#define NVIDIA\n#endif\n";
327 		break;
328 	case GLHW_MESA:
329 		hwHack = "#ifndef MESA\n#define MESA\n#endif\n";
330 		break;
331 	case GLHW_GENERIC:
332 		hwHack = nullptr;
333 		break;
334 	default:
335 		Com_Error(ERR_FATAL, "R_PreprocessShader: Unknown hardwaretype");
336 	}
337 
338 	/*
339 	 * Prefix "#version xxx" onto shader string.
340 	 * This causes GLSL compiler to compile to that version.
341 	 */
342 	defines = va("#version %d\n", shaderVersion);
343 	initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
344 
345 	/*
346 	 * Prefix "#define glslxxx" onto shader string.
347 	 * This named constant is used to setup shader code to match the desired GLSL spec.
348 	 */
349 	defines = va("#define glsl%d\n", shaderVersion);
350 	initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
351 
352 	/* Define r_width.*/
353 	defines = va("#ifndef r_width\n#define r_width %f\n#endif\n", (float)viddef.context.width);
354 	initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
355 
356 	/* Define r_height.*/
357 	defines = va("#ifndef r_height\n#define r_height %f\n#endif\n", (float)viddef.context.height);
358 	initialChars += R_PreprocessShaderAddToShaderBuf(name, defines, &out, &len);
359 
360 	if (hwHack) {
361 		initialChars += R_PreprocessShaderAddToShaderBuf(name, hwHack, &out, &len);
362 	}
363 
364 	if (GL_VERTEX_SHADER == type) {
365 		/* Define 'in_qualifier as 'attribute' & 'out_qualifier' as 'varying' if GLSL v1.10, otherwise define them as 'in' and 'out' respectively.*/
366 		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);
367 	} else if (GL_FRAGMENT_SHADER == type) {
368 		/* Define 'texture2D' as 'texture', as texture2D was deprecated (replaced with 'texture') as of GLSL v1.30.*/
369 		initialChars += R_PreprocessShaderAddToShaderBuf(name, "#ifndef glsl110\n#define texture2D texture\n#endif\n", &out, &len);
370 		/* Define 'in_qualifier as 'varying' if GLSL v1.10, otherwise define it as 'in'.*/
371 		initialChars += R_PreprocessShaderAddToShaderBuf(name, "#ifndef glsl110\n#define in_qualifier in\n#else\n#define in_qualifier varying\n#endif\n", &out, &len);
372 	}
373 
374 	return initialChars;
375 }
376 
377 /**
378  * @brief Do our own preprocessing to the shader file, before the
379  * GLSL implementation calls it's preprocessor.
380  *
381  * "#if/#endif" pairs, "#unroll", "#endunroll", "#include", "#replace" are handled by our
382  * preprocessor, not the GLSL implementation's preprocessor (except "#include" which may
383  * also be handled by the implementation's preprocessor).  "#if" operates off
384  * of the value of a cvar interpreted as a bool. Note the GLSL implementation
385  * preprocessor handles "#ifdef" and "#ifndef", not "#if".
386  * @param[in] name The file name of the shader (e.g. "world_fs.glsl").
387  * @param[in] inPtr The non-preprocessed shader string.
388  * @param[in,out] out The preprocessed shader string, nullptr if we don't want to write to it.
389  * @param[in,out] remainingOutChars The number of characters left in the out buffer.
390  * @param[in] nested If true, parsing a part of "#if" clause, so "#else" and "#endif" tokens are allowed
391  * @param[in] inElse If true, parsing an "#else" clause and shouldn't expect another "#else"
392  * @return The number of characters added to the buffer pointed to by out.
393  */
R_PreprocessShaderR(const char * name,const char ** inPtr,char * out,long * remainingOutChars,bool nested,bool inElse)394 static size_t R_PreprocessShaderR (const char* name, const char** inPtr, char* out, long *remainingOutChars, bool nested, bool inElse)
395 {
396 	const size_t INITIAL_REMAINING_OUT_CHARS = (size_t)*remainingOutChars;
397 	/* Keep looping till we reach the end of the shader string, or a parsing error.*/
398 	while (**inPtr) {
399 		if ('#' == **inPtr) {
400 			bool endBlockToken;
401 			(*inPtr)++;
402 
403 			endBlockToken = !strncmp(*inPtr, "endif", 5);
404 
405 			if (!strncmp(*inPtr, "else", 4)) {
406 				if (inElse) {
407 					/* Error in shader! Print a message saying our preprocessor failed parsing.*/
408 					Com_Error(ERR_DROP, "R_PreprocessShaderR: #else without #if: %s", name);
409 				}
410 				endBlockToken = true;
411 			}
412 
413 			if (endBlockToken) {
414 				if (!nested) {
415 					/* Error in shader! Print a message saying our preprocessor failed parsing.*/
416 					Com_Error(ERR_DROP, "R_PreprocessShaderR: Unmatched #endif/#else: %s", name);
417 				}
418 				/* Whoever called us will have to deal with closing the block */
419 				return (INITIAL_REMAINING_OUT_CHARS - (size_t)*remainingOutChars);
420 			}
421 
422 			if (!strncmp((*inPtr), "if ", 3)) {
423 				/* The line looks like "#if r_postprocess".*/
424 				(*inPtr) += 3;
425 				/* Get the corresponding cvar value.*/
426 				float f = Cvar_GetValue(Com_Parse(inPtr));
427 				if (f) { /* Condition is true, recursively preprocess #if block, and skip over #else block, if any */
428 					int size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, false);
429 					if (out) out += size;
430 
431 					if (!strncmp((*inPtr), "else", 4)) {/* Preprocess and skip #else block */
432 						(*inPtr) +=4 ;
433 						R_PreprocessShaderR(name, inPtr, (char*)0, remainingOutChars, true, true);
434 					}
435 				} else {
436 					/* The cvar was false, don't add to out. Lets look and see if we hit a #else, or #endif.*/
437 					R_PreprocessShaderR(name, inPtr, (char*)0, remainingOutChars, true, false);
438 					if (!strncmp((*inPtr), "else", 4)) {
439 						int size;
440 						/* All right, we want to add this to out.*/
441 						(*inPtr) +=4 ;
442 						size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, true);
443 						if (out) out += size;
444 					}
445 				}
446 				/* skip #endif, if any (could also get here by unexpected EOF */
447 				if (!strncmp((*inPtr), "endif", 5))
448 					(*inPtr) +=5 ;
449 			} else if (!strncmp((*inPtr), "ifndef", 6) || !strncmp((*inPtr), "ifdef", 5)) { /* leave those for GLSL compiler, but follow #else/#endif nesting */
450 				int size;
451 				if (out) {
452 					if (*remainingOutChars <= 0)
453 						Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
454 					*out++ = '#';
455 					(*remainingOutChars)--;
456 				}
457 
458 				size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, false);
459 				if (out) out += size;
460 
461 				if (!strncmp((*inPtr), "else", 4)) {
462 					if (out) {
463 						if (*remainingOutChars <= 0)
464 							Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
465 						*out++ = '#';
466 						(*remainingOutChars)--;
467 					}
468 					size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, true);
469 					if (out) out += size;
470 				}
471 
472 				if (out) {
473 					if (*remainingOutChars <= 0)
474 						Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
475 					*out++ = '#';
476 					(*remainingOutChars)--;
477 				}
478 
479 			} else if (!strncmp((*inPtr), "include", 7)) {
480 				char path[MAX_QPATH];
481 				byte* buf = (byte*)0;
482 				const char* bufAsChar = (const char*)0;
483 				const char** bufAsCharPtr = (const char**)0;
484 				(*inPtr) += 8;
485 				Com_sprintf(path, sizeof(path), "shaders/%s", Com_Parse(inPtr));
486 				if (FS_LoadFile(path, &buf) == -1) {
487 					Com_Printf("Failed to resolve #include: %s.\n", path);
488 					continue;
489 				}
490 				bufAsChar = (const char*)buf;
491 				bufAsCharPtr = &bufAsChar;
492 				if (out) {
493 					out += R_PreprocessShaderR(name, bufAsCharPtr, out, remainingOutChars, nested, false);
494 				} else {
495 					R_PreprocessShaderR(name, bufAsCharPtr, out, remainingOutChars, nested, false);
496 				}
497 				FS_FreeFile(buf);
498 			} else if (!strncmp((*inPtr), "unroll", 6)) {
499 				/* loop unrolling */
500 				size_t subLength = 0;
501 				byte* const buffer = Mem_PoolAllocTypeN(byte, SHADER_BUF_SIZE, vid_imagePool);
502 				(*inPtr) += 6;
503 				int z = Cvar_GetValue(Com_Parse(inPtr));
504 				while (*(*inPtr)) {
505 					if (!strncmp((*inPtr), "#endunroll", 10)) {
506 						(*inPtr) += 10;
507 						break;
508 					}
509 					buffer[subLength++] = *(*inPtr)++;
510 					if (subLength >= SHADER_BUF_SIZE)
511 						Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
512 				}
513 				if (out) {
514 					for (int j = 0; j < z; j++) {
515 						int l = 0;
516 						for (; l < subLength; l++) {
517 							if (buffer[l] == '$') {
518 								byte insertedLen = (j / 10) + 1;
519 								if (!Com_sprintf(out, (size_t)*remainingOutChars, "%d", j))
520 									Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
521 								out += insertedLen;
522 								(*remainingOutChars) -= insertedLen;
523 							} else {
524 								if (*remainingOutChars <= 0)
525 									Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
526 								*out++ = buffer[l];
527 								(*remainingOutChars)--;
528 							}
529 						}
530 					}
531 				}
532 				Mem_Free(buffer);
533 			} else if (!strncmp((*inPtr), "replace", 7)) {
534 				int r = 0;
535 				(*inPtr) += 8;
536 				r = Cvar_GetValue(Com_Parse(inPtr));
537 				if (out) {
538 					byte insertedLen = 0;
539 					if (!Com_sprintf(out, (size_t)*remainingOutChars, "%d", r))
540 						Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
541 					insertedLen = (r / 10) + 1;
542 					out += insertedLen;
543 					(*remainingOutChars) -= insertedLen;
544 				}
545 			} else {
546 				/* general case is to copy so long as the buffer has room */
547 				if (out) {
548 					if (*remainingOutChars <= 0)
549 						Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
550 					*out++ = '#';
551 					(*remainingOutChars)--;
552 				}
553 			}
554 		} else {
555 			/* general case is to copy so long as the buffer has room */
556 			if (out) {
557 				if (*remainingOutChars <= 0)
558 					Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name);
559 				*out++ = *(*inPtr);
560 				(*remainingOutChars)--;
561 			}
562 			(*inPtr)++;
563 		}
564 	}
565 	/* Return the number of characters added to the buffer.*/
566 	return (INITIAL_REMAINING_OUT_CHARS - *remainingOutChars);
567 }
568 
569 /**
570  * @brief Do our own preprocessing to the shader file, before the
571  * GLSL implementation calls it's preprocessor.
572  *
573  * "#if/#endif" pairs, "#unroll", "#endunroll", "#include", "#replace" are handled by our
574  * preprocessor, not the GLSL implementation's preprocessor (except "#include" which may
575  * also be handled by the implementation's preprocessor). "#if" operates off
576  * of the value of a cvar interpreted as a bool. Note the GLSL implementation
577  * preprocessor handles "#ifdef" and "#ifndef", not "#if".
578  * @param[in] name The file name of the shader (e.g. "world_fs.glsl").
579  * @param[in] in The non-preprocessed shader string.
580  * @param[in,out] out The preprocessed shader string, nullptr if we don't want to write to it.
581  * @param[in,out] remainingOutChars The number of characters left in the out buffer.
582  * @return The number of characters added to the buffer pointed to by out.
583  */
R_PreprocessShader(const char * name,const char * in,char * out,size_t * remainingOutChars)584 static size_t R_PreprocessShader (const char* name, const char* in, char* out, size_t* remainingOutChars)
585 {
586 	long remainingOutCharsAsLong = *remainingOutChars;
587 	size_t numCharactersAddedToOutBuffer = R_PreprocessShaderR(name, &in, out, &remainingOutCharsAsLong, false, false);
588 	*remainingOutChars = remainingOutCharsAsLong;
589 	return numCharactersAddedToOutBuffer;
590 }
591 
592 /**
593  * @brief Reads/Preprocesses/Compiles the specified shader into a program.
594  * @param[in] type The type of shader, currently either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
595  * @param[in] name The file name of the shader to load from ./base/shaders/ (e.g. "world_fs.glsl").
596  * @return A structure used as a handle to the compiled shader (program).
597  */
R_LoadShader(const GLenum type,const char * name)598 static r_shader_t* R_LoadShader (const GLenum type, const char* name)
599 {
600 	r_shader_t* sh;
601 	char path[MAX_QPATH], *src[1];
602 	unsigned e, length[1];
603 	char* srcBuf;
604 	byte* buf;
605 	int i;
606 	size_t bufLength = SHADER_BUF_SIZE;
607 	size_t initializeLength;
608 
609 #ifdef DEBUG
610 	/* Used to contain result of shader compile.*/
611 	char log[MAX_STRING_CHARS];
612 #endif
613 
614 	snprintf(path, sizeof(path), "shaders/%s", name);
615 
616 	if (FS_LoadFile(path, &buf) == -1) {
617 		Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Failed to load ./base/shaders/%s.\n", name);
618 		return nullptr;
619 	}
620 
621 	Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Loading ./base/shaders/%s.\n", name);
622 
623 	char* const source = srcBuf = Mem_PoolAllocTypeN(char, bufLength, vid_imagePool);
624 
625 	initializeLength = R_InitializeShader(type, name, srcBuf, bufLength);
626 	srcBuf += initializeLength;
627 	bufLength -= initializeLength;
628 
629 	R_PreprocessShader(name, (const char*)buf, srcBuf, &bufLength);
630 	FS_FreeFile(buf);
631 
632 	src[0] = source;
633 	length[0] = strlen(source);
634 
635 	for (i = 0; i < MAX_SHADERS; i++) {
636 		sh = &r_state.shaders[i];
637 
638 		if (!sh->id)
639 			break;
640 	}
641 
642 	if (i == MAX_SHADERS) {
643 		Com_Printf("R_LoadShader: MAX_SHADERS reached.\n");
644 		Mem_Free(source);
645 		return nullptr;
646 	}
647 
648 	Q_strncpyz(sh->name, name, sizeof(sh->name));
649 
650 	sh->type = type;
651 
652 	sh->id = qglCreateShader(sh->type);
653 	if (!sh->id) {
654 		Mem_Free(source);
655 		return nullptr;
656 	}
657 
658 	/* upload the shader source */
659 	qglShaderSource(sh->id, 1, src, length);
660 
661 	/* compile it and check for errors */
662 	qglCompileShader(sh->id);
663 
664 	Mem_Free(source);
665 
666 	qglGetShaderiv(sh->id, GL_COMPILE_STATUS, &e);
667 #ifdef DEBUG
668 	qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log);
669 	Com_Printf("R_LoadShader: %s: %s", sh->name, log);
670 #endif
671 	if (!e) {
672 #ifndef DEBUG
673 		char log[MAX_STRING_CHARS];
674 		qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log);
675 		Com_Printf("R_LoadShader: %s: %s", sh->name, log);
676 #endif
677 
678 		qglDeleteShader(sh->id);
679 		OBJZERO(*sh);
680 
681 		return nullptr;
682 	}
683 
684 	return sh;
685 }
686 
R_LoadProgram(const char * name,programInitFunc_t init,programUseFunc_t use)687 r_program_t* R_LoadProgram (const char* name, programInitFunc_t init, programUseFunc_t use)
688 {
689 	r_program_t* prog;
690 	unsigned e;
691 	int i;
692 
693 	/* shaders are deactivated */
694 	if (!r_programs->integer)
695 		return nullptr;
696 
697 	/* search existing one */
698 	for (i = 0; i < MAX_PROGRAMS; i++) {
699 		prog = &r_state.programs[i];
700 
701 		if (Q_streq(prog->name, name))
702 			return prog;
703 	}
704 
705 	/* search free slot */
706 	for (i = 0; i < MAX_PROGRAMS; i++) {
707 		prog = &r_state.programs[i];
708 
709 		if (!prog->id)
710 			break;
711 	}
712 
713 	if (i == MAX_PROGRAMS) {
714 		Com_Printf("R_LoadProgram: MAX_PROGRAMS reached.\n");
715 		return nullptr;
716 	}
717 
718 	Q_strncpyz(prog->name, name, sizeof(prog->name));
719 
720 	prog->id = qglCreateProgram();
721 
722 	prog->v = R_LoadShader(GL_VERTEX_SHADER, va("%s_vs.glsl", name));
723 	prog->f = R_LoadShader(GL_FRAGMENT_SHADER, va("%s_fs.glsl", name));
724 
725 	if (prog->v)
726 		qglAttachShader(prog->id, prog->v->id);
727 	if (prog->f)
728 		qglAttachShader(prog->id, prog->f->id);
729 
730 	qglLinkProgram(prog->id);
731 
732 	qglGetProgramiv(prog->id, GL_LINK_STATUS, &e);
733 	if (!e || !prog->v || !prog->f) {
734 		char log[MAX_STRING_CHARS];
735 		qglGetProgramInfoLog(prog->id, sizeof(log) - 1, nullptr, log);
736 		Com_Printf("R_LoadProgram: %s: %s\n", prog->name, log);
737 
738 		R_ShutdownProgram(prog);
739 		return nullptr;
740 	}
741 
742 	prog->init = init;
743 
744 	if (prog->init) {  /* invoke initialization function */
745 		R_UseProgram(prog);
746 
747 		prog->init(prog);
748 
749 		R_UseProgram(nullptr);
750 	}
751 
752 	prog->use = use;
753 
754 	Com_Printf("R_LoadProgram: '%s' loaded.\n", name);
755 
756 	return prog;
757 }
758 
759 extern vec2_t fogRange;
760 
R_InitWorldProgram(r_program_t * prog)761 static void R_InitWorldProgram (r_program_t* prog)
762 {
763 	R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
764 	R_ProgramParameter1i("SAMPLER_LIGHTMAP", 1);
765 	R_ProgramParameter1i("SAMPLER_DELUXEMAP", 2);
766 	R_ProgramParameter1i("SAMPLER_NORMALMAP", 3);
767 	R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
768 
769 	R_ProgramParameter1i("BUMPMAP", 0);
770 
771 	if (r_programs->integer > 1) {
772 		R_ProgramParameter3fv("AMBIENT", refdef.ambientColor);
773 
774 		R_ProgramParameter1i("SPECULARMAP", 0);
775 		R_ProgramParameter1i("SAMPLER_SPECULAR", 5);
776 
777 		R_ProgramParameter1f("HARDNESS", defaultMaterial.hardness);
778 		R_ProgramParameter1f("SPECULAR", defaultMaterial.specular);
779 		R_ProgramParameter1f("PARALLAX", defaultMaterial.parallax);
780 	}
781 
782 	R_ProgramParameter1f("BUMP", defaultMaterial.bump);
783 	R_ProgramParameter1f("GLOWSCALE", defaultMaterial.glowscale);
784 
785 	if (r_fog->integer) {
786 		if (r_state.fog_enabled) {
787 			R_ProgramParameter3fv("FOGCOLOR", refdef.fogColor);
788 			R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
789 			R_ProgramParameter2fv("FOGRANGE", fogRange);
790 		} else {
791 			R_ProgramParameter1f("FOGDENSITY", 0.0f);
792 		}
793 	}
794 }
795 
R_UseWorldProgram(r_program_t * prog)796 static void R_UseWorldProgram (r_program_t* prog)
797 {
798 	if (r_programs->integer > 1) {
799 		R_ProgramParameter3fv("AMBIENT", refdef.ambientColor);
800 	}
801 
802 	if (r_fog->integer) {
803 		if (r_state.fog_enabled) {
804 			R_ProgramParameter3fv("FOGCOLOR", refdef.fogColor);
805 			R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
806 			R_ProgramParameter2fv("FOGRANGE", fogRange);
807 		} else {
808 			R_ProgramParameter1f("FOGDENSITY", 0.0f);
809 		}
810 	}
811 }
812 
R_InitModelProgram(r_program_t * prog)813 static void R_InitModelProgram (r_program_t* prog)
814 {
815 	vec4_t sunDirection;
816 
817 	R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
818 	R_ProgramParameter1i("SAMPLER_NORMALMAP", 3);
819 	R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
820 
821 	R_ProgramParameter1i("BUMPMAP", 0);
822 	R_ProgramParameter1i("ANIMATE", 0);
823 
824 	R_ProgramParameter1f("BUMP", defaultMaterial.bump);
825 	R_ProgramParameter1f("GLOWSCALE", defaultMaterial.glowscale);
826 	R_ProgramParameter1f("OFFSET", 0.0);
827 
828 	R_ProgramParameter3fv("AMBIENT", refdef.modelAmbientColor);
829 	R_ProgramParameter3fv("SUNCOLOR", refdef.sunDiffuseColor);
830 
831 	GLVectorTransform(r_locals.world_matrix, refdef.sunVector, sunDirection);
832 	R_ProgramParameter3fv("SUNDIRECTION", sunDirection); /* last component is not needed */
833 
834 	if (r_programs->integer > 1) {
835 		R_ProgramParameter1i("SAMPLER_SPECULAR", 5);
836 		R_ProgramParameter1i("SPECULARMAP", 0);
837 		R_ProgramParameter1f("HARDNESS", defaultMaterial.hardness);
838 		R_ProgramParameter1f("SPECULAR", defaultMaterial.specular);
839 		R_ProgramParameter1f("PARALLAX", defaultMaterial.parallax);
840 		if (r_programs->integer > 2) {
841 			R_ProgramParameter1i("SAMPLER_ROUGHMAP", 2);
842 			R_ProgramParameter1i("ROUGHMAP", 0);
843 		}
844 	}
845 
846 	if (r_fog->integer) {
847 		if (r_state.fog_enabled) {
848 			R_ProgramParameter3fv("FOGCOLOR", refdef.fogColor);
849 			R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
850 			R_ProgramParameter2fv("FOGRANGE", fogRange);
851 		} else {
852 			R_ProgramParameter1f("FOGDENSITY", 0.0f);
853 		}
854 	}
855 }
856 
R_UseModelProgram(r_program_t * prog)857 static void R_UseModelProgram (r_program_t* prog)
858 {
859 	vec4_t sunDirection;
860 	/*R_ProgramParameter1i("LIGHTS", refdef.numLights);*/
861 
862 	R_ProgramParameter1f("OFFSET", 0.0);
863 	R_ProgramParameter3fv("AMBIENT", refdef.modelAmbientColor);
864 	R_ProgramParameter3fv("SUNCOLOR", refdef.sunDiffuseColor);
865 
866 	GLVectorTransform(r_locals.world_matrix, refdef.sunVector, sunDirection);
867 	R_ProgramParameter3fv("SUNDIRECTION", sunDirection); /* last component is not needed */
868 
869 	if (r_fog->integer) {
870 		if (r_state.fog_enabled) {
871 			R_ProgramParameter3fv("FOGCOLOR", refdef.fogColor);
872 			R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
873 			R_ProgramParameter2fv("FOGRANGE", fogRange);
874 		} else {
875 			R_ProgramParameter1f("FOGDENSITY", 0.0f);
876 		}
877 	}
878 }
879 
R_InitWarpProgram(r_program_t * prog)880 static void R_InitWarpProgram (r_program_t* prog)
881 {
882 	static vec4_t offset;
883 
884 	R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
885 	R_ProgramParameter1i("SAMPLER_WARP", 1);
886 	R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
887 	R_ProgramParameter1f("GLOWSCALE", 0.0);
888 	R_ProgramParameter4fv("OFFSET", offset);
889 	if (r_fog->integer) {
890 		if (r_state.fog_enabled) {
891 			R_ProgramParameter3fv("FOGCOLOR", refdef.fogColor);
892 			R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
893 			R_ProgramParameter2fv("FOGRANGE", fogRange);
894 		} else {
895 			R_ProgramParameter1f("FOGDENSITY", 0.0f);
896 		}
897 	}
898 }
899 
R_UseWarpProgram(r_program_t * prog)900 static void R_UseWarpProgram (r_program_t* prog)
901 {
902 	static vec4_t offset;
903 
904 	offset[0] = offset[1] = refdef.time / 8.0;
905 	R_ProgramParameter4fv("OFFSET", offset);
906 	if (r_fog->integer) {
907 		if (r_state.fog_enabled) {
908 			R_ProgramParameter3fv("FOGCOLOR", refdef.fogColor);
909 			R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
910 			R_ProgramParameter2fv("FOGRANGE", fogRange);
911 		} else {
912 			R_ProgramParameter1f("FOGDENSITY", 0.0f);
913 		}
914 	}
915 }
916 
R_InitGeoscapeProgram(r_program_t * prog)917 static void R_InitGeoscapeProgram (r_program_t* prog)
918 {
919 	static vec4_t defaultColor = {0.0, 0.0, 0.0, 1.0};
920 	static vec4_t cityLightColor = {1.0, 1.0, 0.8, 1.0};
921 	static vec2_t uvScale = {2.0, 1.0};
922 
923 	R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
924 	R_ProgramParameter1i("SAMPLER_BLEND", 1);
925 	R_ProgramParameter1i("SAMPLER_NORMALMAP", 2);
926 
927 	R_ProgramParameter4fv("DEFAULTCOLOR", defaultColor);
928 	R_ProgramParameter4fv("CITYLIGHTCOLOR", cityLightColor);
929 	R_ProgramParameter2fv("UVSCALE", uvScale);
930 }
931 
932 /**
933  * @note this is a not-terribly-efficient recursive implementation,
934  * but it only happens once and shouldn't have to go very deep.
935  */
R_PascalTriangle(int row,int col)936 static int R_PascalTriangle (int row, int col)
937 {
938 	if (row <= 1 || col <= 1 || col >= row)
939 		return 1;
940 	return R_PascalTriangle(row - 1, col) + R_PascalTriangle(row - 1, col - 1);
941 }
942 
943 /** @brief width of convolution filter (for blur/bloom effects) */
944 #define FILTER_SIZE 3
945 
R_InitConvolveProgram(r_program_t * prog)946 static void R_InitConvolveProgram (r_program_t* prog)
947 {
948 	float filter[FILTER_SIZE];
949 	float sum = 0;
950 	int i;
951 	const size_t size = lengthof(filter);
952 
953 	/* approximate a Gaussian by normalizing the Nth row of Pascale's Triangle */
954 	for (i = 0; i < size; i++) {
955 		filter[i] = (float)R_PascalTriangle(size, i + 1);
956 		sum += filter[i];
957 	}
958 
959 	for (i = 0; i < size; i++)
960 		filter[i] = (filter[i] / sum);
961 
962 	R_ProgramParameter1i("SAMPLER0", 0);
963 	R_ProgramParameter1fvs("COEFFICIENTS", size, filter);
964 }
965 
966 /**
967  * @brief Use the filter convolution glsl program
968  */
R_UseConvolveProgram(r_program_t * prog)969 static void R_UseConvolveProgram (r_program_t* prog)
970 {
971 	int i;
972 	const float* userdata= (float*)prog->userdata;
973 	float offsets[FILTER_SIZE * 2];
974 	const float halfWidth = (FILTER_SIZE - 1) * 0.5;
975 	const float offset = 1.2f / userdata[0];
976 	const float x = userdata[1] * offset;
977 
978 	for (i = 0; i < FILTER_SIZE; i++) {
979 		const float y = (float)i - halfWidth;
980 		const float z = x * y;
981 		offsets[i * 2 + 0] = offset * y - z;
982 		offsets[i * 2 + 1] = z;
983 	}
984 	R_ProgramParameter2fvs("OFFSETS", FILTER_SIZE, offsets);
985 }
986 
R_InitCombine2Program(r_program_t * prog)987 static void R_InitCombine2Program (r_program_t* prog)
988 {
989 	GLfloat defaultColor[4] = {0.0, 0.0, 0.0, 0.0};
990 
991 	R_ProgramParameter1i("SAMPLER0", 0);
992 	R_ProgramParameter1i("SAMPLER1", 1);
993 
994 	R_ProgramParameter4fv("DEFAULTCOLOR", defaultColor);
995 }
996 
R_InitAtmosphereProgram(r_program_t * prog)997 static void R_InitAtmosphereProgram (r_program_t* prog)
998 {
999 	static vec4_t defaultColor = {0.0, 0.0, 0.0, 1.0};
1000 	static vec2_t uvScale = {2.0, 1.0};
1001 
1002 	R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
1003 	R_ProgramParameter1i("SAMPLER_NORMALMAP", 2);
1004 
1005 	R_ProgramParameter4fv("DEFAULTCOLOR", defaultColor);
1006 	R_ProgramParameter2fv("UVSCALE", uvScale);
1007 }
1008 
R_InitSimpleGlowProgram(r_program_t * prog)1009 static void R_InitSimpleGlowProgram (r_program_t* prog)
1010 {
1011 	R_ProgramParameter1i("SAMPLER_DIFFUSE", 0);
1012 	R_ProgramParameter1i("SAMPLER_GLOWMAP", 4);
1013 	R_ProgramParameter1f("GLOWSCALE", 1.0);
1014 }
1015 
R_InitParticleProgram(r_program_t * prog)1016 void R_InitParticleProgram (r_program_t* prog)
1017 {
1018 	R_ProgramParameter1i("SAMPLER0", 0);
1019 }
1020 
R_UseParticleProgram(r_program_t * prog)1021 void R_UseParticleProgram (r_program_t* prog)
1022 {
1023 /*	ptl_t* ptl = (ptl_t*)prog->userdata;*/
1024 }
1025 
R_InitPrograms(void)1026 void R_InitPrograms (void)
1027 {
1028 	if (!qglCreateProgram) {
1029 		Com_Printf("not using GLSL shaders\n");
1030 		Cvar_Set("r_programs", "0");
1031 		r_programs->modified = false;
1032 		return;
1033 	}
1034 
1035 	OBJZERO(r_state.shaders);
1036 	OBJZERO(r_state.programs);
1037 
1038 	/* Capable of running shaders, but have got them disabled, so do nothing */
1039 	if (!r_programs->integer)
1040 		return;
1041 
1042 	r_state.world_program = R_LoadProgram(shaderQualityLevelNames[r_programs->integer - 1][0], R_InitWorldProgram, R_UseWorldProgram);
1043 	r_state.model_program = R_LoadProgram(shaderQualityLevelNames[r_programs->integer - 1][1], R_InitModelProgram, R_UseModelProgram);
1044 	r_state.warp_program = R_LoadProgram("warp", R_InitWarpProgram, R_UseWarpProgram);
1045 	r_state.geoscape_program = R_LoadProgram("geoscape", R_InitGeoscapeProgram, nullptr);
1046 	r_state.combine2_program = R_LoadProgram("combine2", R_InitCombine2Program, nullptr);
1047 	r_state.convolve_program = R_LoadProgram("convolve" DOUBLEQUOTE(FILTER_SIZE), R_InitConvolveProgram, R_UseConvolveProgram);
1048 	r_state.atmosphere_program = R_LoadProgram("atmosphere", R_InitAtmosphereProgram, nullptr);
1049 	r_state.simple_glow_program = R_LoadProgram("simple_glow", R_InitSimpleGlowProgram, nullptr);
1050 
1051 	if (!(r_state.world_program && r_state.model_program && r_state.warp_program && r_state.geoscape_program && r_state.combine2_program
1052 		&& r_state.convolve_program && r_state.atmosphere_program && r_state.simple_glow_program)) {
1053 		Com_Printf("disabled shaders because they failed to compile\n");
1054 		Cvar_Set("r_programs", "0");
1055 		r_programs->modified = false;
1056 	}
1057 }
1058 
1059 /**
1060  * @brief Reloads the glsl shaders
1061  */
R_RestartPrograms_f(void)1062 void R_RestartPrograms_f (void)
1063 {
1064 	if (r_programs->integer) {
1065 		Com_Printf("glsl restart to a version of v%s\n", Cvar_Get("r_glsl_version", nullptr, 0, nullptr)->string);
1066 	} else {
1067 		Com_Printf("glsl shutdown\n");
1068 	}
1069 
1070 	R_ShutdownPrograms();
1071 	R_InitPrograms();
1072 	R_InitFBObjects();
1073 }
1074