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