1 /**
2  * @file
3  */
4 
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 
23 */
24 
25 #include "r_local.h"
26 #include "r_program.h"
27 #include "r_error.h"
28 
29 /* useful for particles, pics, etc.. */
30 const vec2_t default_texcoords[4] = {
31 	{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}
32 };
33 
34 /* Hack to keep track of active rendering program (have to reinit binings&parameters once it changed)*/
35 static r_program_t* lastProgram = nullptr;
36 
37 /**
38  * @brief Returns false if the texunit is not supported
39  */
R_SelectTexture(gltexunit_t * texunit)40 bool R_SelectTexture (gltexunit_t* texunit)
41 {
42 	if (texunit == r_state.active_texunit)
43 		return true;
44 
45 	/* not supported */
46 	if (texunit->texture >= r_config.maxTextureCoords + GL_TEXTURE0)
47 		return false;
48 
49 	r_state.active_texunit = texunit;
50 
51 	qglActiveTexture(texunit->texture);
52 	qglClientActiveTexture(texunit->texture);
53 	return true;
54 }
55 
R_BindTexture_(int texnum)56 static void R_BindTexture_ (int texnum)
57 {
58 	if (texnum == r_state.active_texunit->texnum)
59 		return;
60 
61 	assert(texnum > 0);
62 
63 	r_state.active_texunit->texnum = texnum;
64 
65 	glBindTexture(GL_TEXTURE_2D, texnum);
66 	R_CheckError();
67 }
68 
R_BindTextureDebug(int texnum,const char * file,int line,const char * function)69 void R_BindTextureDebug (int texnum, const char* file, int line, const char* function)
70 {
71 	if (texnum <= 0) {
72 		Com_Printf("Bad texnum (%d) in: %s (%d): %s\n", texnum, file, line, function);
73 	}
74 	R_BindTexture_(texnum);
75 }
76 
R_BindTextureForTexUnit(GLuint texnum,gltexunit_t * texunit)77 void R_BindTextureForTexUnit (GLuint texnum, gltexunit_t* texunit)
78 {
79 	/* small optimization to save state changes */
80 	if (texnum == texunit->texnum)
81 		return;
82 
83 	R_SelectTexture(texunit);
84 
85 	R_BindTexture(texnum);
86 
87 	R_SelectTexture(&texunit_diffuse);
88 }
89 
R_BindLightmapTexture(GLuint texnum)90 void R_BindLightmapTexture (GLuint texnum)
91 {
92 	R_BindTextureForTexUnit(texnum, &texunit_lightmap);
93 }
94 
R_BindDeluxemapTexture(GLuint texnum)95 void R_BindDeluxemapTexture (GLuint texnum)
96 {
97 	R_BindTextureForTexUnit(texnum, &texunit_deluxemap);
98 }
99 
R_BindNormalmapTexture(GLuint texnum)100 void R_BindNormalmapTexture (GLuint texnum)
101 {
102 	R_BindTextureForTexUnit(texnum, &texunit_normalmap);
103 }
104 
R_UseMaterial(const material_t * material)105 void R_UseMaterial (const material_t* material)
106 {
107 	static float last_b, last_p, last_s, last_h;
108 	float b;
109 
110 	if (r_state.active_material == material)
111 		return;
112 
113 	if (!r_state.active_normalmap)
114 		return;
115 
116 	if (material)
117 		r_state.active_material = material;
118 	else
119 		r_state.active_material = &defaultMaterial;
120 
121 	b = r_state.active_material->bump * r_bumpmap->value;
122 	if (b != last_b)
123 		R_ProgramParameter1f("BUMP", b);
124 	last_b = b;
125 
126 	if (r_state.active_program != r_state.world_program || r_programs->integer > 1) {
127 		const float p = r_state.active_material->parallax * r_parallax->value;
128 		if (p != last_p)
129 			R_ProgramParameter1f("PARALLAX", p);
130 		last_p = p;
131 
132 		const float h = r_state.active_material->hardness * r_hardness->value;
133 		if (h != last_h)
134 			R_ProgramParameter1f("HARDNESS", h);
135 		last_h = h;
136 
137 		const float s = r_state.active_material->specular * r_specular->value;
138 		if (s != last_s)
139 			R_ProgramParameter1f("SPECULAR", s);
140 		last_s = s;
141 	} else {
142 		last_p = -1;
143 		last_h = -1;
144 		last_s = -1;
145 	}
146 }
147 
R_BindArray(GLenum target,GLenum type,const void * array)148 void R_BindArray (GLenum target, GLenum type, const void* array)
149 {
150 	const int v = static_cast<int>(target);
151 	switch (v) {
152 	case GL_VERTEX_ARRAY:
153 		glVertexPointer(COMPONENTS_VERTEX_ARRAY3D, type, 0, array);
154 		break;
155 	case GL_TEXTURE_COORD_ARRAY:
156 		glTexCoordPointer(COMPONENTS_TEXCOORD_ARRAY, type, 0, array);
157 		break;
158 	case GL_COLOR_ARRAY:
159 		glColorPointer(COMPONENTS_COLOR_ARRAY, type, 0, array);
160 		break;
161 	case GL_NORMAL_ARRAY:
162 		glNormalPointer(type, 0, array);
163 		break;
164 	case GL_TANGENT_ARRAY:
165 		R_AttributePointer("TANGENTS", COMPONENTS_TANGENT_ARRAY, array);
166 		break;
167 	case GL_NEXT_VERTEX_ARRAY:
168 		R_AttributePointer("NEXT_FRAME_VERTS", COMPONENTS_VERTEX_ARRAY3D, array);
169 		break;
170 	case GL_NEXT_NORMAL_ARRAY:
171 		R_AttributePointer("NEXT_FRAME_NORMALS", COMPONENTS_NORMAL_ARRAY, array);
172 		break;
173 	case GL_NEXT_TANGENT_ARRAY:
174 		R_AttributePointer("NEXT_FRAME_TANGENTS", COMPONENTS_TANGENT_ARRAY, array);
175 		break;
176 	}
177 }
178 
179 /**
180  * @brief Binds the appropriate shared vertex array to the specified target.
181  */
R_BindDefaultArray(GLenum target)182 void R_BindDefaultArray (GLenum target)
183 {
184 	const int v = static_cast<int>(target);
185 	switch (v) {
186 	case GL_VERTEX_ARRAY:
187 		R_BindArray(target, GL_FLOAT, r_state.vertex_array_3d);
188 		break;
189 	case GL_TEXTURE_COORD_ARRAY:
190 		R_BindArray(target, GL_FLOAT, r_state.active_texunit->texcoord_array);
191 		break;
192 	case GL_COLOR_ARRAY:
193 		R_BindArray(target, GL_FLOAT, r_state.color_array);
194 		break;
195 	case GL_NORMAL_ARRAY:
196 		R_BindArray(target, GL_FLOAT, r_state.normal_array);
197 		break;
198 	case GL_TANGENT_ARRAY:
199 		R_BindArray(target, GL_FLOAT, r_state.tangent_array);
200 		break;
201 	case GL_NEXT_VERTEX_ARRAY:
202 		R_BindArray(target, GL_FLOAT, r_state.next_vertex_array_3d);
203 		break;
204 	case GL_NEXT_NORMAL_ARRAY:
205 		R_BindArray(target, GL_FLOAT, r_state.next_normal_array);
206 		break;
207 	case GL_NEXT_TANGENT_ARRAY:
208 		R_BindArray(target, GL_FLOAT, r_state.next_tangent_array);
209 		break;
210 	}
211 }
212 
R_BindBuffer(GLenum target,GLenum type,GLuint id)213 void R_BindBuffer (GLenum target, GLenum type, GLuint id)
214 {
215 	if (!qglBindBuffer)
216 		return;
217 
218 	if (!r_vertexbuffers->integer)
219 		return;
220 
221 	if (target == GL_ELEMENT_ARRAY_BUFFER) {
222 		qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
223 		return; /* No need to call gl***Poiner -- this binding is special and automates that */
224 	} else {
225 		qglBindBuffer(GL_ARRAY_BUFFER, id);
226 	}
227 
228 	if (type && id)  /* assign the array pointer as well */
229 		R_BindArray(target, type, nullptr);
230 }
231 
R_BlendFunc(GLenum src,GLenum dest)232 void R_BlendFunc (GLenum src, GLenum dest)
233 {
234 	if (r_state.blend_src == src && r_state.blend_dest == dest)
235 		return;
236 
237 	r_state.blend_src = src;
238 	r_state.blend_dest = dest;
239 
240 	glBlendFunc(src, dest);
241 }
242 
R_EnableMultisample(bool enable)243 void R_EnableMultisample (bool enable)
244 {
245 	if (r_multisample->integer == 0 && enable)
246 		return;
247 
248 	if (r_state.multisample_enabled == enable)
249 		return;
250 
251 	r_state.multisample_enabled = enable;
252 
253 	if (enable) {
254 		glEnable(GL_MULTISAMPLE);
255 	} else {
256 		glDisable(GL_MULTISAMPLE);
257 	}
258 	R_CheckError();
259 }
260 
R_EnableBlend(bool enable)261 void R_EnableBlend (bool enable)
262 {
263 	if (r_state.blend_enabled == enable)
264 		return;
265 
266 	r_state.blend_enabled = enable;
267 
268 	if (enable) {
269 		glEnable(GL_BLEND);
270 		glDepthMask(GL_FALSE);
271 	} else {
272 		glDisable(GL_BLEND);
273 		glDepthMask(GL_TRUE);
274 	}
275 }
276 
R_EnableAlphaTest(bool enable)277 void R_EnableAlphaTest (bool enable)
278 {
279 	if (r_state.alpha_test_enabled == enable)
280 		return;
281 
282 	r_state.alpha_test_enabled = enable;
283 
284 	if (enable)
285 		glEnable(GL_ALPHA_TEST);
286 	else
287 		glDisable(GL_ALPHA_TEST);
288 }
289 
R_EnableStencilTest(bool enable)290 void R_EnableStencilTest (bool enable)
291 {
292 	if (r_state.stencil_test_enabled == enable)
293 		return;
294 
295 	r_state.stencil_test_enabled = enable;
296 
297 	if (enable)
298 		glEnable(GL_STENCIL_TEST);
299 	else
300 		glDisable(GL_STENCIL_TEST);
301 }
302 
R_EnableTexture(gltexunit_t * texunit,bool enable)303 void R_EnableTexture (gltexunit_t* texunit, bool enable)
304 {
305 	if (enable == texunit->enabled)
306 		return;
307 
308 	texunit->enabled = enable;
309 
310 	R_SelectTexture(texunit);
311 
312 	if (enable) {
313 		/* activate texture unit */
314 		glEnable(GL_TEXTURE_2D);
315 
316 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
317 
318 		if (texunit == &texunit_lightmap) {
319 			if (r_lightmap->integer)
320 				R_TexEnv(GL_REPLACE);
321 			else
322 				R_TexEnv(GL_MODULATE);
323 		}
324 	} else {
325 		/* disable on the second texture unit */
326 		glDisable(GL_TEXTURE_2D);
327 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
328 	}
329 	R_SelectTexture(&texunit_diffuse);
330 }
331 
R_EnableColorArray(bool enable)332 void R_EnableColorArray (bool enable)
333 {
334 	if (r_state.color_array_enabled == enable)
335 		return;
336 
337 	r_state.color_array_enabled = enable;
338 
339 	if (enable)
340 		glEnableClientState(GL_COLOR_ARRAY);
341 	else
342 		glDisableClientState(GL_COLOR_ARRAY);
343 }
344 
345 /**
346  * @brief Enables hardware-accelerated lighting with the specified program.  This
347  * should be called after any texture units which will be active for lighting
348  * have been enabled.
349  */
R_EnableLighting(r_program_t * program,bool enable)350 bool R_EnableLighting (r_program_t* program, bool enable)
351 {
352 	if (!r_programs->integer)
353 		return r_state.lighting_enabled;
354 
355 	if (enable && (!program || !program->id))
356 		return r_state.lighting_enabled;
357 
358 	if (r_state.lighting_enabled == enable && r_state.active_program == program)
359 		return r_state.lighting_enabled;
360 
361 	r_state.lighting_enabled = enable;
362 
363 	if (enable) {  /* toggle state */
364 		R_UseProgram(program);
365 
366 		glEnableClientState(GL_NORMAL_ARRAY);
367 	} else {
368 		glDisableClientState(GL_NORMAL_ARRAY);
369 
370 		R_UseProgram(nullptr);
371 	}
372 
373 	return r_state.lighting_enabled;
374 }
375 
R_SetupSpotLight(int index,const light_t * light)376 void R_SetupSpotLight (int index, const light_t* light)
377 {
378 	const vec4_t blackColor = {0.0, 0.0, 0.0, 1.0};
379 	vec4_t position;
380 
381 	if (!r_programs->integer || !r_dynamic_lights->integer)
382 		return;
383 
384 	if (index < 0 || index >= r_dynamic_lights->integer)
385 		return;
386 
387 	index += GL_LIGHT0;
388 
389 	glEnable(index);
390 	glLightf(index, GL_CONSTANT_ATTENUATION, MIN_GL_CONSTANT_ATTENUATION);
391 	glLightf(index, GL_LINEAR_ATTENUATION, 0);
392 	glLightf(index, GL_QUADRATIC_ATTENUATION, 16.0 / (light->radius * light->radius));
393 
394 	VectorCopy(light->origin, position);
395 	position[3] = 1.0; /* spot light */
396 
397 	glLightfv(index, GL_POSITION, position);
398 	glLightfv(index, GL_AMBIENT, blackColor);
399 	glLightfv(index, GL_DIFFUSE, light->color);
400 	glLightfv(index, GL_SPECULAR, blackColor);
401 }
402 
R_DisableSpotLight(int index)403 void R_DisableSpotLight (int index)
404 {
405 	const vec4_t blackColor = {0.0, 0.0, 0.0, 1.0};
406 
407 	if (!r_programs->integer || !r_dynamic_lights)
408 		return;
409 
410 	if (index < 0 || index >= MAX_GL_LIGHTS - 1)
411 		return;
412 
413 	index += GL_LIGHT0;
414 
415 	glDisable(index);
416 	glLightf(index, GL_CONSTANT_ATTENUATION, MIN_GL_CONSTANT_ATTENUATION);
417 	glLightf(index, GL_LINEAR_ATTENUATION, 0.0);
418 	glLightf(index, GL_QUADRATIC_ATTENUATION, 0.0);
419 	glLightfv(index, GL_AMBIENT, blackColor);
420 	glLightfv(index, GL_DIFFUSE, blackColor);
421 	glLightfv(index, GL_SPECULAR, blackColor);
422 }
423 
424 /**
425  * @brief Enables animation using keyframe interpolation on the GPU
426  * @param mesh The mesh to animate
427  * @param backlerp The temporal proximity to the previous keyframe (in the range 0.0 to 1.0)
428  * @param enable Whether to turn animation on or off
429  */
R_EnableAnimation(const mAliasMesh_t * mesh,float backlerp,bool enable)430 void R_EnableAnimation (const mAliasMesh_t* mesh, float backlerp, bool enable)
431 {
432 	if (!r_programs->integer || !r_state.lighting_enabled)
433 		return;
434 
435 	r_state.animation_enabled = enable;
436 
437 	if (enable) {
438 		R_EnableAttribute("NEXT_FRAME_VERTS");
439 		R_EnableAttribute("NEXT_FRAME_NORMALS");
440 		R_EnableAttribute("NEXT_FRAME_TANGENTS");
441 		R_ProgramParameter1i("ANIMATE", 1);
442 
443 		R_ProgramParameter1f("TIME", backlerp);
444 
445 		R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, mesh->texcoords);
446 		R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, mesh->verts);
447 		R_BindArray(GL_NORMAL_ARRAY, GL_FLOAT, mesh->normals);
448 		R_BindArray(GL_TANGENT_ARRAY, GL_FLOAT, mesh->tangents);
449 		R_BindArray(GL_NEXT_VERTEX_ARRAY, GL_FLOAT, mesh->next_verts);
450 		R_BindArray(GL_NEXT_NORMAL_ARRAY, GL_FLOAT, mesh->next_normals);
451 		R_BindArray(GL_NEXT_TANGENT_ARRAY, GL_FLOAT, mesh->next_tangents);
452 	} else {
453 		R_DisableAttribute("NEXT_FRAME_VERTS");
454 		R_DisableAttribute("NEXT_FRAME_NORMALS");
455 		R_DisableAttribute("NEXT_FRAME_TANGENTS");
456 		R_ProgramParameter1i("ANIMATE", 0);
457 	}
458 }
459 
460 /**
461  * @brief Enables bumpmapping and binds the given normalmap.
462  * @note Don't forget to bind the deluxe map, too.
463  * @sa R_BindDeluxemapTexture
464  */
R_EnableBumpmap(const image_t * normalmap)465 void R_EnableBumpmap (const image_t* normalmap)
466 {
467 	if (!r_state.lighting_enabled)
468 		return;
469 
470 	if (!r_bumpmap->value)
471 		return;
472 
473 	if (r_state.active_normalmap == normalmap)
474 		return;
475 
476 	if (!normalmap) {
477 		/* disable bump mapping */
478 		R_ProgramParameter1i("BUMPMAP", 0);
479 
480 		r_state.active_normalmap = normalmap;
481 		return;
482 	}
483 
484 	if (!r_state.active_normalmap) {
485 		/* enable bump mapping */
486 		R_ProgramParameter1i("BUMPMAP", 1);
487 		/* default material to use if no material gets loaded */
488 		R_UseMaterial(&defaultMaterial);
489 	}
490 
491 	R_BindNormalmapTexture(normalmap->texnum);
492 
493 	r_state.active_normalmap = normalmap;
494 }
495 
R_EnableWarp(r_program_t * program,bool enable)496 void R_EnableWarp (r_program_t* program, bool enable)
497 {
498 	if (!r_programs->integer)
499 		return;
500 
501 	if (enable && (!program || !program->id))
502 		return;
503 
504 	if (!r_warp->integer || r_state.warp_enabled == enable)
505 		return;
506 
507 	r_state.warp_enabled = enable;
508 
509 	R_SelectTexture(&texunit_lightmap);
510 
511 	if (enable) {
512 		glEnable(GL_TEXTURE_2D);
513 		R_BindTexture(r_warpTexture->texnum);
514 		R_UseProgram(program);
515 	} else {
516 		glDisable(GL_TEXTURE_2D);
517 		R_UseProgram(nullptr);
518 	}
519 
520 	R_SelectTexture(&texunit_diffuse);
521 }
522 
R_EnableBlur(r_program_t * program,bool enable,r_framebuffer_t * source,r_framebuffer_t * dest,int dir)523 void R_EnableBlur (r_program_t* program, bool enable, r_framebuffer_t* source, r_framebuffer_t* dest, int dir)
524 {
525 	if (!r_programs->integer)
526 		return;
527 
528 	if (enable && (!program || !program->id))
529 		return;
530 
531 	if (!r_postprocess->integer || r_state.blur_enabled == enable)
532 		return;
533 
534 	r_state.blur_enabled = enable;
535 
536 	R_SelectTexture(&texunit_lightmap);
537 
538 	if (enable) {
539 		float userdata[] = { static_cast<float>(source->width), static_cast<float>(dir) };
540 		R_UseFramebuffer(dest);
541 		program->userdata = userdata;
542 		R_UseProgram(program);
543 	} else {
544 		R_UseFramebuffer(fbo_screen);
545 		R_UseProgram(nullptr);
546 	}
547 
548 	R_SelectTexture(&texunit_diffuse);
549 }
550 
R_EnableShell(bool enable)551 void R_EnableShell (bool enable)
552 {
553 	if (enable == r_state.shell_enabled)
554 		return;
555 
556 	r_state.shell_enabled = enable;
557 
558 	if (enable) {
559 		glEnable(GL_POLYGON_OFFSET_FILL);
560 		glPolygonOffset(-1.0, 1.0);
561 
562 		R_EnableDrawAsGlow(true);
563 		R_EnableBlend(true);
564 		R_BlendFunc(GL_SRC_ALPHA, GL_ONE);
565 
566 		if (r_state.lighting_enabled)
567 			R_ProgramParameter1f("OFFSET", refdef.time / 3.0);
568 	} else {
569 		R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
570 		R_EnableBlend(false);
571 		R_EnableDrawAsGlow(false);
572 
573 		glPolygonOffset(0.0, 0.0);
574 		glDisable(GL_POLYGON_OFFSET_FILL);
575 
576 		if (r_state.lighting_enabled)
577 			R_ProgramParameter1f("OFFSET", 0.0);
578 	}
579 }
580 
581 #define FOG_START	300.0
582 #define FOG_END		2500.0
583 
584 vec2_t fogRange = {FOG_START, FOG_END};
585 
R_EnableFog(bool enable)586 void R_EnableFog (bool enable)
587 {
588 	if (!r_fog->integer || r_state.fog_enabled == enable)
589 		return;
590 
591 	r_state.fog_enabled = false;
592 
593 	/* This is ugly. Shaders could be enabled or disabled between this and rendering call, so we have to setup both FFP and GLSL */
594 	if (enable) {
595 		if (((refdef.weather & WEATHER_FOG) && r_fog->integer) || r_fog->integer == 2) {
596 			r_state.fog_enabled = true;
597 
598 			glFogfv(GL_FOG_COLOR, refdef.fogColor);
599 			glFogf(GL_FOG_DENSITY, refdef.fogColor[3]);
600 			glEnable(GL_FOG);
601 
602 			if (r_programs->integer && (r_state.active_program == r_state.world_program || r_state.active_program == r_state.model_program || r_state.active_program == r_state.warp_program)) {
603 				R_ProgramParameter3fv("FOGCOLOR", refdef.fogColor);
604 				R_ProgramParameter1f("FOGDENSITY", refdef.fogColor[3]);
605 				R_ProgramParameter2fv("FOGRANGE", fogRange);
606 			}
607 		}
608 	} else {
609 		glFogf(GL_FOG_DENSITY, 0.0);
610 		glDisable(GL_FOG);
611 		if (r_programs->integer && (r_state.active_program == r_state.world_program || r_state.active_program == r_state.model_program || r_state.active_program == r_state.warp_program))
612 			R_ProgramParameter1f("FOGDENSITY", 0.0f);
613 	}
614 }
615 
R_UpdateGlowBufferBinding(void)616 static void R_UpdateGlowBufferBinding (void)
617 {
618 #ifndef GL_VERSION_ES_CM_1_0
619 	static GLenum glowRenderTarget = GL_COLOR_ATTACHMENT1_EXT; // Not supported in GLES
620 
621 	if (r_state.active_program) {
622 		/* got an active shader */
623 		if (r_state.draw_glow_enabled) {
624 			/* switch the draw buffer to the glow buffer */
625 			R_BindColorAttachments(1, &glowRenderTarget);
626 			R_ProgramParameter1f("GLOWSCALE", 0.0); /* Plumbing to avoid state leak */
627 		} else {
628 			/* switch back to the draw buffer we are currently rendering into ... */
629 			R_DrawBuffers(2);
630 			/* ... and enable glow, if there is a glow map */
631 			if (r_state.glowmap_enabled) {
632 				R_ProgramParameter1f("GLOWSCALE", 1.0);
633 			} else {
634 				R_ProgramParameter1f("GLOWSCALE", 0.0);
635 			}
636 		}
637 	} else {
638 		/* no shader */
639 		if (r_state.draw_glow_enabled) {
640 			/* switch the draw buffer to the glow buffer */
641 			R_BindColorAttachments(1, &glowRenderTarget);
642 		} else {
643 			if (!r_state.glowmap_enabled) {
644 				/* Awkward case. Postprocessing is requested, but fragment
645 				 * shader is disabled, and we are supposed to draw non-glowing object.
646 				 * So we just draw this object into color buffer only and hope that it's not
647 				 * supposed to overlay any glowing objects.
648 				 */
649 				R_DrawBuffers(1);
650 			} else {
651 				/* FIXME: Had to draw glowmapped object,  but don't know how to do it
652 				 * when rendering through FFP.
653 				 * So -- just copy color into glow buffer.
654 				 * (R_DrawAsGlow may hit this)
655 				 */
656 				R_DrawBuffers(2);
657 				/*Con_Print("GLSL glow with no program!\n");*/
658 			}
659 		}
660 	}
661 #endif
662 }
663 
R_EnableGlowMap(const image_t * image)664 void R_EnableGlowMap (const image_t* image)
665 {
666 	if (!r_programs->integer)
667 		return;
668 
669 	if (image)
670 		R_BindTextureForTexUnit(image->texnum, &texunit_glowmap);
671 
672 	/** @todo Is the following condition correct or not? Either fix it or write the comment why it should be done that way */
673 	if (!image && r_state.glowmap_enabled == !!image && r_state.active_program == lastProgram)
674 		return;
675 
676 	r_state.glowmap_enabled = !!image;
677 
678 	/* Shouldn't render glow without GLSL, so enable simple program for it */
679 	if (image) {
680 		if (!r_state.active_program)
681 			R_UseProgram(r_state.simple_glow_program);
682 	} else {
683 		if (r_state.active_program == r_state.simple_glow_program)
684 			R_UseProgram(nullptr);
685 	}
686 
687 	lastProgram = r_state.active_program;
688 
689 	R_UpdateGlowBufferBinding();
690 }
691 
R_EnableDrawAsGlow(bool enable)692 void R_EnableDrawAsGlow (bool enable)
693 {
694 	if (!r_programs->integer)
695 		return;
696 
697 	if (r_state.draw_glow_enabled == enable && r_state.active_program == lastProgram)
698 		return;
699 
700 	r_state.draw_glow_enabled = enable;
701 
702 	lastProgram = r_state.active_program;
703 
704 	R_UpdateGlowBufferBinding();
705 }
706 
R_EnableSpecularMap(const image_t * image,bool enable)707 void R_EnableSpecularMap (const image_t* image, bool enable)
708 {
709 	if (!r_state.dynamic_lighting_enabled)
710 		return;
711 
712 	if (r_programs->integer < 2)
713 		return;
714 
715 	if (enable && image != nullptr) {
716 		R_BindTextureForTexUnit(image->texnum, &texunit_specularmap);
717 		R_ProgramParameter1i("SPECULARMAP", 1);
718 		r_state.specularmap_enabled = enable;
719 	} else {
720 		R_ProgramParameter1i("SPECULARMAP", 0);
721 		r_state.specularmap_enabled = false;
722 	}
723 }
724 
R_EnableRoughnessMap(const image_t * image,bool enable)725 void R_EnableRoughnessMap (const image_t* image, bool enable)
726 {
727 	if (!r_state.dynamic_lighting_enabled)
728 		return;
729 
730 	if (enable && image != nullptr) {
731 		R_BindTextureForTexUnit(image->texnum, &texunit_roughnessmap);
732 		R_ProgramParameter1i("ROUGHMAP", 1);
733 		r_state.roughnessmap_enabled = enable;
734 	} else {
735 		R_ProgramParameter1i("ROUGHMAP", 0);
736 		r_state.roughnessmap_enabled = false;
737 	}
738 }
739 
740 /**
741  * @sa R_Setup3D
742  */
MYgluPerspective(GLfloat zNear,GLfloat zFar)743 static void MYgluPerspective (GLfloat zNear, GLfloat zFar)
744 {
745 	GLfloat xmin, xmax, ymin, ymax, yaspect = (float) viddef.context.height / viddef.context.width;
746 
747 	if (r_isometric->integer) {
748 		glOrtho(-10 * refdef.fieldOfViewX, 10 * refdef.fieldOfViewX, -10 * refdef.fieldOfViewX * yaspect, 10 * refdef.fieldOfViewX * yaspect, -zFar, zFar);
749 	} else {
750 		xmax = zNear * tan(refdef.fieldOfViewX * (M_PI / 360.0));
751 		xmin = -xmax;
752 
753 		ymin = xmin * yaspect;
754 		ymax = xmax * yaspect;
755 
756 		glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
757 	}
758 }
759 
760 /**
761  * @sa R_Setup2D
762  */
R_Setup3D(void)763 void R_Setup3D (void)
764 {
765 	/* only for the battlescape rendering */
766 	if ((refdef.rendererFlags & RDF_NOWORLDMODEL) == 0) {
767 		int x, x2, y2, y, w, h;
768 
769 		/* set up viewport */
770 		x = floorf(viddef.x * viddef.context.width / viddef.context.width);
771 		x2 = ceilf((viddef.x + viddef.viewWidth) * viddef.context.width / viddef.context.width);
772 		y = floorf(viddef.context.height - viddef.y * viddef.context.height / viddef.context.height);
773 		y2 = ceilf(viddef.context.height - (viddef.y + viddef.viewHeight) * viddef.context.height / viddef.context.height);
774 
775 		w = x2 - x;
776 		h = y - y2;
777 
778 		glViewport(x, y2, w, h);
779 		R_CheckError();
780 	}
781 
782 	/* set up projection matrix */
783 	glMatrixMode(GL_PROJECTION);
784 
785 	glLoadIdentity();
786 	if ((refdef.rendererFlags & RDF_NOWORLDMODEL) != 0) {
787 		/* center image into the viewport */
788 		float x = viddef.x + (viddef.viewWidth - VID_NORM_WIDTH) / 2.0 - (viddef.virtualWidth - VID_NORM_WIDTH) / 2.0;
789 		float y = viddef.y + (viddef.viewHeight - VID_NORM_HEIGHT) / 2.0 - (viddef.virtualHeight - VID_NORM_HEIGHT) / 2.0;
790 		/* @todo magic coef, i dont know where it come from */
791 		x *=  2.0f / (float) viddef.virtualWidth;
792 		y *=  2.0f / (float) viddef.virtualHeight;
793 		glTranslatef(x, -y, 0.0f);
794 	}
795 	MYgluPerspective(4.0, MAX_WORLD_WIDTH);
796 
797 	glMatrixMode(GL_MODELVIEW);
798 	glLoadIdentity();
799 	glRotatef(-90.0, 1.0, 0.0, 0.0);	/* put Z going up */
800 	glRotatef(90.0, 0.0, 0.0, 1.0);	/* put Z going up */
801 	glRotatef(-refdef.viewAngles[2], 1.0, 0.0, 0.0);
802 	glRotatef(-refdef.viewAngles[0], 0.0, 1.0, 0.0);
803 	glRotatef(-refdef.viewAngles[1], 0.0, 0.0, 1.0);
804 	glTranslatef(-refdef.viewOrigin[0], -refdef.viewOrigin[1], -refdef.viewOrigin[2]);
805 
806 	/* retrieve the resulting matrix for other manipulations  */
807 	glGetFloatv(GL_MODELVIEW_MATRIX, r_locals.world_matrix);
808 
809 	/* set vertex array pointer */
810 	R_BindDefaultArray(GL_VERTEX_ARRAY);
811 
812 	glDisable(GL_BLEND);
813 
814 	glEnable(GL_DEPTH_TEST);
815 
816 	/* set up framebuffers for postprocessing */
817 	R_EnableRenderbuffer(true);
818 
819 	R_CheckError();
820 }
821 
822 /**
823  * @sa R_Setup3D
824  */
R_Setup2D(void)825 void R_Setup2D (void)
826 {
827 	/* only for the battlescape rendering */
828 	if ((refdef.rendererFlags & RDF_NOWORLDMODEL) == 0) {
829 		/* set 2D virtual screen size */
830 		glViewport(0, 0, viddef.context.width, viddef.context.height);
831 	}
832 
833 	glMatrixMode(GL_PROJECTION);
834 	glLoadIdentity();
835 
836 	/* switch to orthographic (2 dimensional) projection
837 	 * don't draw anything before skybox */
838 	glOrtho(0, viddef.context.width, viddef.context.height, 0, 9999.0f, SKYBOX_DEPTH);
839 
840 	glMatrixMode(GL_MODELVIEW);
841 	glLoadIdentity();
842 
843 	/* bind default vertex array */
844 	R_BindDefaultArray(GL_VERTEX_ARRAY);
845 
846 	R_Color(nullptr);
847 
848 	glEnable(GL_BLEND);
849 
850 	glDisable(GL_DEPTH_TEST);
851 
852 	glDisable(GL_LIGHTING);
853 
854 	/* disable render-to-framebuffer */
855 	R_EnableRenderbuffer(false);
856 
857 	R_CheckError();
858 }
859 
R_SetDefaultState(void)860 void R_SetDefaultState (void)
861 {
862 	int i;
863 
864 	r_state.shell_enabled = false;
865 	r_state.blend_enabled = false;
866 	r_state.color_array_enabled = false;
867 	r_state.alpha_test_enabled = false;
868 	r_state.stencil_test_enabled = false;
869 	r_state.lighting_enabled = false;
870 	r_state.warp_enabled = false;
871 	r_state.fog_enabled = false;
872 	r_state.blur_enabled = false;
873 	r_state.glowmap_enabled = false;
874 	r_state.draw_glow_enabled = false;
875 	r_state.dynamic_lighting_enabled = false;
876 	r_state.specularmap_enabled = false;
877 	r_state.roughnessmap_enabled = false;
878 	r_state.animation_enabled = false;
879 	r_state.renderbuffer_enabled = false;
880 	r_state.active_material = nullptr;
881 	r_state.blend_src = 0;
882 	r_state.blend_dest = 0;
883 	r_state.active_texunit = nullptr;
884 
885 	glClearColor(0, 0, 0, 0);
886 
887 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
888 
889 	R_ReallocateStateArrays(GL_ARRAY_LENGTH_CHUNK);
890 	R_ReallocateTexunitArray(&texunit_0, GL_ARRAY_LENGTH_CHUNK);
891 	R_ReallocateTexunitArray(&texunit_1, GL_ARRAY_LENGTH_CHUNK);
892 	R_ReallocateTexunitArray(&texunit_2, GL_ARRAY_LENGTH_CHUNK);
893 	R_ReallocateTexunitArray(&texunit_3, GL_ARRAY_LENGTH_CHUNK);
894 	R_ReallocateTexunitArray(&texunit_4, GL_ARRAY_LENGTH_CHUNK);
895 
896 	/* setup vertex array pointers */
897 	glEnableClientState(GL_VERTEX_ARRAY);
898 	R_BindDefaultArray(GL_VERTEX_ARRAY);
899 
900 	R_EnableColorArray(true);
901 	R_BindDefaultArray(GL_COLOR_ARRAY);
902 	R_EnableColorArray(false);
903 
904 	glEnableClientState(GL_NORMAL_ARRAY);
905 	R_BindDefaultArray(GL_NORMAL_ARRAY);
906 	glDisableClientState(GL_NORMAL_ARRAY);
907 
908 	R_EnableAlphaTest(false);
909 
910 	/* reset gl error state */
911 	R_CheckError();
912 
913 	/* setup texture units */
914 	for (i = 0; i < r_config.maxTextureCoords && i < MAX_GL_TEXUNITS; i++) {
915 		gltexunit_t* tex = &r_state.texunits[i];
916 		tex->texture = GL_TEXTURE0 + i;
917 		tex->enabled = false;
918 
919 		R_EnableTexture(tex, true);
920 
921 		R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
922 		R_TexEnv(GL_MODULATE);
923 		R_ReallocateTexunitArray(tex, GL_ARRAY_LENGTH_CHUNK);
924 
925 		if (i > 0)  /* turn them off for now */
926 			R_EnableTexture(tex, false);
927 
928 		R_CheckError();
929 	}
930 
931 	R_SelectTexture(&texunit_diffuse);
932 	/* alpha test parameters */
933 	glAlphaFunc(GL_GREATER, 0.01f);
934 
935 	/* fog parameters */
936 	glFogi(GL_FOG_MODE, GL_LINEAR);
937 	glFogf(GL_FOG_START, FOG_START);
938 	glFogf(GL_FOG_END, FOG_END);
939 
940 	/* stencil test parameters */
941 	glStencilFunc(GL_GEQUAL, 1, 0xff);
942 	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
943 
944 	/* polygon offset parameters */
945 	glPolygonOffset(1, 1);
946 
947 	/* alpha blend parameters */
948 	R_EnableBlend(true);
949 	R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
950 
951 	/* remove leftover lights */
952 	R_ClearStaticLights();
953 
954 	/* reset gl error state */
955 	R_CheckError();
956 }
957 
R_TexEnv(GLenum mode)958 void R_TexEnv (GLenum mode)
959 {
960 	if (mode == r_state.active_texunit->texenv)
961 		return;
962 
963 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode);
964 	r_state.active_texunit->texenv = mode;
965 }
966 
967 /**
968  * @brief Sets special texture environment mode to override texture color; don't forget to call R_TexOverride(nullptr) to reset after drawing; intended for UI only, will conflict with lightmaps
969  */
R_TexOverride(vec4_t rgba)970 void R_TexOverride (vec4_t rgba)
971 {
972 	R_SelectTexture(&texunit_lightmap); /* abuse lightmap texture unit for color manipulation */
973 
974 	if (!rgba) {
975 		R_TexEnv(GL_MODULATE);
976 		glDisable(GL_TEXTURE_2D);
977 		R_SelectTexture(&texunit_diffuse);
978 		return;
979 	}
980 
981 	glEnable(GL_TEXTURE_2D);
982 
983 	R_TexEnv(GL_COMBINE); /* enable color combiner */
984 	/* setup texture combiner to blend between actual color of previous texture stage and the constant rgb color given as the parameter to this function
985 	 * amount of blending is defined by alpha channel of constant color
986 	 */
987 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT); /* set constant color as blending target*/
988 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
989 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS); /* set incoming color as blending source */
990 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
991 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT); /* set constant color alpha as blending factor */
992 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
993 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); /* set blending mode to interpolation from src1 to src0 */
994 	/* copy alpha from incoming color, it could be used later for framebuffer operations */
995 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
996 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
997 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
998 
999 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
1000 
1001 	R_BindTexture(r_dummyTexture->texnum);
1002 
1003 	R_SelectTexture(&texunit_diffuse);
1004 }
1005 
1006 const vec4_t color_white = {1, 1, 1, 1};
1007 
1008 /**
1009  * @brief Change the color to given value
1010  * @param[in] rgba A pointer to a vec4_t with rgba color value
1011  * @note To reset the color let rgba be nullptr
1012  */
R_Color(const vec4_t rgba)1013 void R_Color (const vec4_t rgba)
1014 {
1015 	const float* color;
1016 	if (rgba)
1017 		color = rgba;
1018 	else
1019 		color = color_white;
1020 
1021 	glColor4f(color[0], color[1], color[2], color[3]);
1022 	R_CheckError();
1023 }
1024 
1025 /**
1026  * @brief Reallocate arrays of GL primitives if needed
1027  * @param size The new array size
1028  * @note Also resets all non-default GL array bindings
1029  * @sa R_ReallocateTexunitArray
1030 */
R_ReallocateStateArrays(int size)1031 void R_ReallocateStateArrays (int size)
1032 {
1033 	if (size <= r_state.array_size)
1034 		return;
1035 	r_state.vertex_array_3d = (GLfloat*) Mem_SafeReAlloc(r_state.vertex_array_3d, size * COMPONENTS_VERTEX_ARRAY3D * sizeof(GLfloat));
1036 	r_state.vertex_array_2d = (GLshort*) Mem_SafeReAlloc(r_state.vertex_array_2d, size * COMPONENTS_VERTEX_ARRAY2D * sizeof(GLshort));
1037 	r_state.color_array = (GLfloat*) Mem_SafeReAlloc(r_state.color_array, size * COMPONENTS_COLOR_ARRAY * sizeof(GLfloat));
1038 	r_state.index_array = (GLint*) Mem_SafeReAlloc(r_state.index_array, size * COMPONENTS_INDEX_ARRAY * sizeof(GLint));
1039 	r_state.normal_array = (GLfloat*) Mem_SafeReAlloc(r_state.normal_array, size * COMPONENTS_NORMAL_ARRAY * sizeof(GLfloat));
1040 	r_state.tangent_array = (GLfloat*) Mem_SafeReAlloc(r_state.tangent_array, size * COMPONENTS_TANGENT_ARRAY * sizeof(GLfloat));
1041 	r_state.next_vertex_array_3d = (GLfloat*) Mem_SafeReAlloc(r_state.next_vertex_array_3d, size * COMPONENTS_VERTEX_ARRAY3D * sizeof(GLfloat));
1042 	r_state.next_normal_array = (GLfloat*) Mem_SafeReAlloc(r_state.next_normal_array, size * COMPONENTS_NORMAL_ARRAY * sizeof(GLfloat));
1043 	r_state.next_tangent_array = (GLfloat*) Mem_SafeReAlloc(r_state.next_tangent_array, size * COMPONENTS_TANGENT_ARRAY * sizeof(GLfloat));
1044 	r_state.array_size = size;
1045 	R_BindDefaultArray(GL_VERTEX_ARRAY);
1046 	R_BindDefaultArray(GL_COLOR_ARRAY);
1047 	R_BindDefaultArray(GL_NORMAL_ARRAY);
1048 	R_BindDefaultArray(GL_TANGENT_ARRAY);
1049 	R_BindDefaultArray(GL_NEXT_VERTEX_ARRAY);
1050 	R_BindDefaultArray(GL_NEXT_NORMAL_ARRAY);
1051 	R_BindDefaultArray(GL_NEXT_TANGENT_ARRAY);
1052 }
1053 
1054 /**
1055  * @brief Reallocate texcoord array of the specified texunit, if needed
1056  * @param texunit Pointer to texunit (TODO: remove this comment as obvious and redundant)
1057  * @param size The new array size
1058  * @note Also resets active texunit
1059  * @sa R_ReallocateStateArrays
1060 */
R_ReallocateTexunitArray(gltexunit_t * texunit,int size)1061 void R_ReallocateTexunitArray (gltexunit_t* texunit, int size)
1062 {
1063 	if (size <= texunit->array_size)
1064 		return;
1065 	texunit->texcoord_array = (GLfloat*) Mem_SafeReAlloc(texunit->texcoord_array, size * COMPONENTS_TEXCOORD_ARRAY * sizeof(GLfloat));
1066 	texunit->array_size = size;
1067 	if (!r_state.active_texunit)
1068 		r_state.active_texunit = texunit;
1069 	R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
1070 }
1071