1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "sys/platform.h"
30 #include "renderer/VertexCache.h"
31 
32 #include "renderer/tr_local.h"
33 
34 /*
35 =========================================================================================
36 
37 GENERAL INTERACTION RENDERING
38 
39 =========================================================================================
40 */
41 
42 /*
43 ====================
44 GL_SelectTextureNoClient
45 ====================
46 */
GL_SelectTextureNoClient(int unit)47 static void GL_SelectTextureNoClient( int unit ) {
48 	backEnd.glState.currenttmu = unit;
49 	qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
50 }
51 
52 /*
53 ==================
54 RB_ARB2_DrawInteraction
55 ==================
56 */
RB_ARB2_DrawInteraction(const drawInteraction_t * din)57 void	RB_ARB2_DrawInteraction( const drawInteraction_t *din ) {
58 	// load all the vertex program parameters
59 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() );
60 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() );
61 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() );
62 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() );
63 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() );
64 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() );
65 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() );
66 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() );
67 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() );
68 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() );
69 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() );
70 	qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() );
71 
72 	// testing fragment based normal mapping
73 	if ( r_testARBProgram.GetBool() ) {
74 		qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, din->localLightOrigin.ToFloatPtr() );
75 		qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, din->localViewOrigin.ToFloatPtr() );
76 	}
77 
78 	static const float zero[4] = { 0, 0, 0, 0 };
79 	static const float one[4] = { 1, 1, 1, 1 };
80 	static const float negOne[4] = { -1, -1, -1, -1 };
81 
82 	switch ( din->vertexColor ) {
83 	case SVC_IGNORE:
84 		qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, zero );
85 		qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one );
86 		break;
87 	case SVC_MODULATE:
88 		qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, one );
89 		qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, zero );
90 		break;
91 	case SVC_INVERSE_MODULATE:
92 		qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, negOne );
93 		qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one );
94 		break;
95 	}
96 
97 	// set the constant colors
98 	qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, din->diffuseColor.ToFloatPtr() );
99 	qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, din->specularColor.ToFloatPtr() );
100 
101 	// set the textures
102 
103 	// texture 1 will be the per-surface bump map
104 	GL_SelectTextureNoClient( 1 );
105 	din->bumpImage->Bind();
106 
107 	// texture 2 will be the light falloff texture
108 	GL_SelectTextureNoClient( 2 );
109 	din->lightFalloffImage->Bind();
110 
111 	// texture 3 will be the light projection texture
112 	GL_SelectTextureNoClient( 3 );
113 	din->lightImage->Bind();
114 
115 	// texture 4 is the per-surface diffuse map
116 	GL_SelectTextureNoClient( 4 );
117 	din->diffuseImage->Bind();
118 
119 	// texture 5 is the per-surface specular map
120 	GL_SelectTextureNoClient( 5 );
121 	din->specularImage->Bind();
122 
123 	// draw it
124 	RB_DrawElementsWithCounters( din->surf->geo );
125 }
126 
127 
128 /*
129 =============
130 RB_ARB2_CreateDrawInteractions
131 
132 =============
133 */
RB_ARB2_CreateDrawInteractions(const drawSurf_t * surf)134 void RB_ARB2_CreateDrawInteractions( const drawSurf_t *surf ) {
135 	if ( !surf ) {
136 		return;
137 	}
138 
139 	// perform setup here that will be constant for all interactions
140 	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc );
141 
142 	// bind the vertex program
143 	if ( r_testARBProgram.GetBool() ) {
144 		qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_TEST );
145 		qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST );
146 	} else {
147 		qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION );
148 		qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION );
149 	}
150 
151 	qglEnable(GL_VERTEX_PROGRAM_ARB);
152 	qglEnable(GL_FRAGMENT_PROGRAM_ARB);
153 
154 	// enable the vertex arrays
155 	qglEnableVertexAttribArrayARB( 8 );
156 	qglEnableVertexAttribArrayARB( 9 );
157 	qglEnableVertexAttribArrayARB( 10 );
158 	qglEnableVertexAttribArrayARB( 11 );
159 	qglEnableClientState( GL_COLOR_ARRAY );
160 
161 	// texture 0 is the normalization cube map for the vector towards the light
162 	GL_SelectTextureNoClient( 0 );
163 	if ( backEnd.vLight->lightShader->IsAmbientLight() ) {
164 		globalImages->ambientNormalMap->Bind();
165 	} else {
166 		globalImages->normalCubeMapImage->Bind();
167 	}
168 
169 	// texture 6 is the specular lookup table
170 	GL_SelectTextureNoClient( 6 );
171 	if ( r_testARBProgram.GetBool() ) {
172 		globalImages->specular2DTableImage->Bind();	// variable specularity in alpha channel
173 	} else {
174 		globalImages->specularTableImage->Bind();
175 	}
176 
177 
178 	for ( ; surf ; surf=surf->nextOnLight ) {
179 		// perform setup here that will not change over multiple interaction passes
180 
181 		// set the vertex pointers
182 		idDrawVert	*ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache );
183 		qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
184 		qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
185 		qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
186 		qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
187 		qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
188 		qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
189 
190 		// this may cause RB_ARB2_DrawInteraction to be exacuted multiple
191 		// times with different colors and images if the surface or light have multiple layers
192 		RB_CreateSingleDrawInteractions( surf, RB_ARB2_DrawInteraction );
193 	}
194 
195 	qglDisableVertexAttribArrayARB( 8 );
196 	qglDisableVertexAttribArrayARB( 9 );
197 	qglDisableVertexAttribArrayARB( 10 );
198 	qglDisableVertexAttribArrayARB( 11 );
199 	qglDisableClientState( GL_COLOR_ARRAY );
200 
201 	// disable features
202 	GL_SelectTextureNoClient( 6 );
203 	globalImages->BindNull();
204 
205 	GL_SelectTextureNoClient( 5 );
206 	globalImages->BindNull();
207 
208 	GL_SelectTextureNoClient( 4 );
209 	globalImages->BindNull();
210 
211 	GL_SelectTextureNoClient( 3 );
212 	globalImages->BindNull();
213 
214 	GL_SelectTextureNoClient( 2 );
215 	globalImages->BindNull();
216 
217 	GL_SelectTextureNoClient( 1 );
218 	globalImages->BindNull();
219 
220 	backEnd.glState.currenttmu = -1;
221 	GL_SelectTexture( 0 );
222 
223 	qglDisable(GL_VERTEX_PROGRAM_ARB);
224 	qglDisable(GL_FRAGMENT_PROGRAM_ARB);
225 }
226 
227 
228 /*
229 ==================
230 RB_ARB2_DrawInteractions
231 ==================
232 */
RB_ARB2_DrawInteractions(void)233 void RB_ARB2_DrawInteractions( void ) {
234 	viewLight_t		*vLight;
235 
236 	GL_SelectTexture( 0 );
237 	qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
238 
239 	//
240 	// for each light, perform adding and shadowing
241 	//
242 	for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
243 		backEnd.vLight = vLight;
244 
245 		// do fogging later
246 		if ( vLight->lightShader->IsFogLight() ) {
247 			continue;
248 		}
249 		if ( vLight->lightShader->IsBlendLight() ) {
250 			continue;
251 		}
252 
253 		if ( !vLight->localInteractions && !vLight->globalInteractions
254 			&& !vLight->translucentInteractions ) {
255 			continue;
256 		}
257 
258 		// clear the stencil buffer if needed
259 		if ( vLight->globalShadows || vLight->localShadows ) {
260 			backEnd.currentScissor = vLight->scissorRect;
261 			if ( r_useScissor.GetBool() ) {
262 				qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
263 					backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
264 					backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
265 					backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
266 			}
267 			qglClear( GL_STENCIL_BUFFER_BIT );
268 		} else {
269 			// no shadows, so no need to read or write the stencil buffer
270 			// we might in theory want to use GL_ALWAYS instead of disabling
271 			// completely, to satisfy the invarience rules
272 			qglStencilFunc( GL_ALWAYS, 128, 255 );
273 		}
274 
275 		if ( r_useShadowVertexProgram.GetBool() ) {
276 			qglEnable( GL_VERTEX_PROGRAM_ARB );
277 			qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
278 			RB_StencilShadowPass( vLight->globalShadows );
279 			RB_ARB2_CreateDrawInteractions( vLight->localInteractions );
280 			qglEnable( GL_VERTEX_PROGRAM_ARB );
281 			qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
282 			RB_StencilShadowPass( vLight->localShadows );
283 			RB_ARB2_CreateDrawInteractions( vLight->globalInteractions );
284 			qglDisable( GL_VERTEX_PROGRAM_ARB );	// if there weren't any globalInteractions, it would have stayed on
285 		} else {
286 			RB_StencilShadowPass( vLight->globalShadows );
287 			RB_ARB2_CreateDrawInteractions( vLight->localInteractions );
288 			RB_StencilShadowPass( vLight->localShadows );
289 			RB_ARB2_CreateDrawInteractions( vLight->globalInteractions );
290 		}
291 
292 		// translucent surfaces never get stencil shadowed
293 		if ( r_skipTranslucent.GetBool() ) {
294 			continue;
295 		}
296 
297 		qglStencilFunc( GL_ALWAYS, 128, 255 );
298 
299 		backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
300 		RB_ARB2_CreateDrawInteractions( vLight->translucentInteractions );
301 
302 		backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
303 	}
304 
305 	// disable stencil shadow test
306 	qglStencilFunc( GL_ALWAYS, 128, 255 );
307 
308 	GL_SelectTexture( 0 );
309 	qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
310 }
311 
312 //===================================================================================
313 
314 
315 typedef struct {
316 	GLenum			target;
317 	GLuint			ident;
318 	char			name[64];
319 } progDef_t;
320 
321 static	const int	MAX_GLPROGS = 200;
322 
323 // a single file can have both a vertex program and a fragment program
324 static progDef_t	progs[MAX_GLPROGS] = {
325 	{ GL_VERTEX_PROGRAM_ARB, VPROG_TEST, "test.vfp" },
326 	{ GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST, "test.vfp" },
327 	{ GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION, "interaction.vfp" },
328 	{ GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION, "interaction.vfp" },
329 	{ GL_VERTEX_PROGRAM_ARB, VPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" },
330 	{ GL_FRAGMENT_PROGRAM_ARB, FPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" },
331 	{ GL_VERTEX_PROGRAM_ARB, VPROG_AMBIENT, "ambientLight.vfp" },
332 	{ GL_FRAGMENT_PROGRAM_ARB, FPROG_AMBIENT, "ambientLight.vfp" },
333 	{ GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW, "shadow.vp" },
334 	{ GL_VERTEX_PROGRAM_ARB, VPROG_ENVIRONMENT, "environment.vfp" },
335 	{ GL_FRAGMENT_PROGRAM_ARB, FPROG_ENVIRONMENT, "environment.vfp" },
336 	{ GL_VERTEX_PROGRAM_ARB, VPROG_GLASSWARP, "arbVP_glasswarp.txt" },
337 	{ GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP, "arbFP_glasswarp.txt" },
338 
339 	// additional programs can be dynamically specified in materials
340 };
341 
342 /*
343 =================
344 R_LoadARBProgram
345 =================
346 */
R_LoadARBProgram(int progIndex)347 void R_LoadARBProgram( int progIndex ) {
348 	int		ofs;
349 	int		err;
350 	idStr	fullPath = "glprogs/";
351 	fullPath += progs[progIndex].name;
352 	char	*fileBuffer;
353 	char	*buffer;
354 	char	*start = NULL, *end;
355 
356 	common->Printf( "%s", fullPath.c_str() );
357 
358 	// load the program even if we don't support it, so
359 	// fs_copyfiles can generate cross-platform data dumps
360 	fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL );
361 	if ( !fileBuffer ) {
362 		common->Printf( ": File not found\n" );
363 		return;
364 	}
365 
366 	// copy to stack memory and free
367 	buffer = (char *)_alloca( strlen( fileBuffer ) + 1 );
368 	strcpy( buffer, fileBuffer );
369 	fileSystem->FreeFile( fileBuffer );
370 
371 	if ( !glConfig.isInitialized ) {
372 		return;
373 	}
374 
375 	//
376 	// submit the program string at start to GL
377 	//
378 	if ( progs[progIndex].ident == 0 ) {
379 		// allocate a new identifier for this program
380 		progs[progIndex].ident = PROG_USER + progIndex;
381 	}
382 
383 	// vertex and fragment programs can both be present in a single file, so
384 	// scan for the proper header to be the start point, and stamp a 0 in after the end
385 
386 	if ( progs[progIndex].target == GL_VERTEX_PROGRAM_ARB ) {
387 		if ( !glConfig.ARBVertexProgramAvailable ) {
388 			common->Printf( ": GL_VERTEX_PROGRAM_ARB not available\n" );
389 			return;
390 		}
391 		start = strstr( buffer, "!!ARBvp" );
392 	}
393 	if ( progs[progIndex].target == GL_FRAGMENT_PROGRAM_ARB ) {
394 		if ( !glConfig.ARBFragmentProgramAvailable ) {
395 			common->Printf( ": GL_FRAGMENT_PROGRAM_ARB not available\n" );
396 			return;
397 		}
398 		start = strstr( buffer, "!!ARBfp" );
399 	}
400 	if ( !start ) {
401 		common->Printf( ": !!ARB not found\n" );
402 		return;
403 	}
404 	end = strstr( start, "END" );
405 
406 	if ( !end ) {
407 		common->Printf( ": END not found\n" );
408 		return;
409 	}
410 	end[3] = 0;
411 
412 	qglBindProgramARB( progs[progIndex].target, progs[progIndex].ident );
413 	qglGetError();
414 
415 	qglProgramStringARB( progs[progIndex].target, GL_PROGRAM_FORMAT_ASCII_ARB,
416 		strlen( start ), start );
417 
418 	err = qglGetError();
419 	qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, (GLint *)&ofs );
420 	if ( err == GL_INVALID_OPERATION ) {
421 		const GLubyte *str = qglGetString( GL_PROGRAM_ERROR_STRING_ARB );
422 		common->Printf( "\nGL_PROGRAM_ERROR_STRING_ARB: %s\n", str );
423 		if ( ofs < 0 ) {
424 			common->Printf( "GL_PROGRAM_ERROR_POSITION_ARB < 0 with error\n" );
425 		} else if ( ofs >= (int)strlen( start ) ) {
426 			common->Printf( "error at end of program\n" );
427 		} else {
428 			common->Printf( "error at %i:\n%s", ofs, start + ofs );
429 		}
430 		return;
431 	}
432 	if ( ofs != -1 ) {
433 		common->Printf( "\nGL_PROGRAM_ERROR_POSITION_ARB != -1 without error\n" );
434 		return;
435 	}
436 
437 	common->Printf( "\n" );
438 }
439 
440 /*
441 ==================
442 R_FindARBProgram
443 
444 Returns a GL identifier that can be bound to the given target, parsing
445 a text file if it hasn't already been loaded.
446 ==================
447 */
R_FindARBProgram(GLenum target,const char * program)448 int R_FindARBProgram( GLenum target, const char *program ) {
449 	int		i;
450 	idStr	stripped = program;
451 
452 	stripped.StripFileExtension();
453 
454 	// see if it is already loaded
455 	for ( i = 0 ; progs[i].name[0] ; i++ ) {
456 		if ( progs[i].target != target ) {
457 			continue;
458 		}
459 
460 		idStr	compare = progs[i].name;
461 		compare.StripFileExtension();
462 
463 		if ( !idStr::Icmp( stripped.c_str(), compare.c_str() ) ) {
464 			return progs[i].ident;
465 		}
466 	}
467 
468 	if ( i == MAX_GLPROGS ) {
469 		common->Error( "R_FindARBProgram: MAX_GLPROGS" );
470 	}
471 
472 	// add it to the list and load it
473 	progs[i].ident = (program_t)0;	// will be gen'd by R_LoadARBProgram
474 	progs[i].target = target;
475 	strncpy( progs[i].name, program, sizeof( progs[i].name ) - 1 );
476 
477 	R_LoadARBProgram( i );
478 
479 	return progs[i].ident;
480 }
481 
482 /*
483 ==================
484 R_ReloadARBPrograms_f
485 ==================
486 */
R_ReloadARBPrograms_f(const idCmdArgs & args)487 void R_ReloadARBPrograms_f( const idCmdArgs &args ) {
488 	int		i;
489 
490 	common->Printf( "----- R_ReloadARBPrograms -----\n" );
491 	for ( i = 0 ; progs[i].name[0] ; i++ ) {
492 		R_LoadARBProgram( i );
493 	}
494 }
495 
496 /*
497 ==================
498 R_ARB2_Init
499 
500 ==================
501 */
R_ARB2_Init(void)502 void R_ARB2_Init( void ) {
503 	glConfig.allowARB2Path = false;
504 
505 	common->Printf( "ARB2 renderer: " );
506 
507 	if ( !glConfig.ARBVertexProgramAvailable || !glConfig.ARBFragmentProgramAvailable ) {
508 		common->Printf( "Not available.\n" );
509 		return;
510 	}
511 
512 	common->Printf( "Available.\n" );
513 
514 	glConfig.allowARB2Path = true;
515 }
516