1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (RTCW SP Source Code).
8
9 RTCW SP 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 RTCW SP 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 RTCW SP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW SP 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 RTCW SP 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
30 #include "tr_local.h"
31
32 int r_firstSceneDrawSurf;
33
34 int r_numdlights;
35 int r_firstSceneDlight;
36
37 int r_numcoronas;
38 int r_firstSceneCorona;
39
40 int r_numentities;
41 int r_firstSceneEntity;
42
43 int r_numpolys;
44 int r_firstScenePoly;
45
46 int r_numpolyverts;
47
48 int skyboxportal;
49 int drawskyboxportal;
50
51 /*
52 ====================
53 R_InitNextFrame
54 ====================
55 */
R_InitNextFrame(void)56 void R_InitNextFrame( void ) {
57 backEndData->commands.used = 0;
58
59 r_firstSceneDrawSurf = 0;
60
61 r_numdlights = 0;
62 r_firstSceneDlight = 0;
63
64 r_numcoronas = 0;
65 r_firstSceneCorona = 0;
66
67 r_numentities = 0;
68 r_firstSceneEntity = 0;
69
70 r_numpolys = 0;
71 r_firstScenePoly = 0;
72
73 r_numpolyverts = 0;
74 }
75
76
77 /*
78 ====================
79 RE_ClearScene
80
81 ====================
82 */
RE_ClearScene(void)83 void RE_ClearScene( void ) {
84 r_firstSceneDlight = r_numdlights;
85 r_firstSceneCorona = r_numcoronas;
86 r_firstSceneEntity = r_numentities;
87 r_firstScenePoly = r_numpolys;
88 }
89
90 /*
91 ===========================================================================
92
93 DISCRETE POLYS
94
95 ===========================================================================
96 */
97
98 /*
99 =====================
100 R_AddPolygonSurfaces
101
102 Adds all the scene's polys into this view's drawsurf list
103 =====================
104 */
R_AddPolygonSurfaces(void)105 void R_AddPolygonSurfaces( void ) {
106 int i;
107 shader_t *sh;
108 srfPoly_t *poly;
109
110 tr.currentEntityNum = REFENTITYNUM_WORLD;
111 tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
112
113 for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
114 sh = R_GetShaderByHandle( poly->hShader );
115 // GR - not tessellated
116 R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse, ATI_TESS_NONE );
117 }
118 }
119
120 /*
121 =====================
122 RE_AddPolyToScene
123
124 =====================
125 */
RE_AddPolyToScene(qhandle_t hShader,int numVerts,const polyVert_t * verts)126 void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts ) {
127 srfPoly_t *poly;
128 int i;
129 int fogIndex;
130 fog_t *fog;
131 vec3_t bounds[2];
132
133 if ( !tr.registered ) {
134 return;
135 }
136
137 if ( !hShader ) {
138 ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n" );
139 return;
140 }
141
142 if ( ( ( r_numpolyverts + numVerts ) >= max_polyverts ) || ( r_numpolys >= max_polys ) ) {
143 return;
144 }
145
146 poly = &backEndData->polys[r_numpolys];
147 poly->surfaceType = SF_POLY;
148 poly->hShader = hShader;
149 poly->numVerts = numVerts;
150 poly->verts = &backEndData->polyVerts[r_numpolyverts];
151
152 memcpy( poly->verts, verts, numVerts * sizeof( *verts ) );
153 // Ridah
154 if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
155 poly->verts->modulate[0] = 255;
156 poly->verts->modulate[1] = 255;
157 poly->verts->modulate[2] = 255;
158 poly->verts->modulate[3] = 255;
159 }
160 // done.
161 r_numpolys++;
162 r_numpolyverts += numVerts;
163
164 // see if it is in a fog volume
165 if ( tr.world->numfogs == 1 ) {
166 fogIndex = 0;
167 } else {
168 // find which fog volume the poly is in
169 VectorCopy( poly->verts[0].xyz, bounds[0] );
170 VectorCopy( poly->verts[0].xyz, bounds[1] );
171 for ( i = 1 ; i < poly->numVerts ; i++ ) {
172 AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
173 }
174 for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
175 fog = &tr.world->fogs[fogIndex];
176 if ( bounds[1][0] >= fog->bounds[0][0]
177 && bounds[1][1] >= fog->bounds[0][1]
178 && bounds[1][2] >= fog->bounds[0][2]
179 && bounds[0][0] <= fog->bounds[1][0]
180 && bounds[0][1] <= fog->bounds[1][1]
181 && bounds[0][2] <= fog->bounds[1][2] ) {
182 break;
183 }
184 }
185 if ( fogIndex == tr.world->numfogs ) {
186 fogIndex = 0;
187 }
188 }
189 poly->fogIndex = fogIndex;
190 }
191
192 // Ridah
193 /*
194 =====================
195 RE_AddPolysToScene
196
197 =====================
198 */
RE_AddPolysToScene(qhandle_t hShader,int numVerts,const polyVert_t * verts,int numPolys)199 void RE_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
200 srfPoly_t *poly;
201 int i;
202 int fogIndex;
203 fog_t *fog;
204 vec3_t bounds[2];
205 int j;
206
207 if ( !tr.registered ) {
208 return;
209 }
210
211 if ( !hShader ) {
212 ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolysToScene: NULL poly shader\n" );
213 return;
214 }
215
216 for ( j = 0; j < numPolys; j++ ) {
217 if ( r_numpolyverts + numVerts >= max_polyverts || r_numpolys >= max_polys ) {
218 // ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolysToScene: MAX_POLYS or MAX_POLYVERTS reached\n");
219 return;
220 }
221
222 poly = &backEndData->polys[r_numpolys];
223 poly->surfaceType = SF_POLY;
224 poly->hShader = hShader;
225 poly->numVerts = numVerts;
226 poly->verts = &backEndData->polyVerts[r_numpolyverts];
227
228 memcpy( poly->verts, &verts[numVerts * j], numVerts * sizeof( *verts ) );
229 // Ridah
230 if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
231 poly->verts->modulate[0] = 255;
232 poly->verts->modulate[1] = 255;
233 poly->verts->modulate[2] = 255;
234 poly->verts->modulate[3] = 255;
235 }
236 // done.
237 r_numpolys++;
238 r_numpolyverts += numVerts;
239
240 // if no world is loaded
241 if ( tr.world == NULL ) {
242 fogIndex = 0;
243 }
244 // see if it is in a fog volume
245 else if ( tr.world->numfogs == 1 ) {
246 fogIndex = 0;
247 } else {
248 // find which fog volume the poly is in
249 VectorCopy( poly->verts[0].xyz, bounds[0] );
250 VectorCopy( poly->verts[0].xyz, bounds[1] );
251 for ( i = 1 ; i < poly->numVerts ; i++ ) {
252 AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
253 }
254 for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
255 fog = &tr.world->fogs[fogIndex];
256 if ( bounds[1][0] >= fog->bounds[0][0]
257 && bounds[1][1] >= fog->bounds[0][1]
258 && bounds[1][2] >= fog->bounds[0][2]
259 && bounds[0][0] <= fog->bounds[1][0]
260 && bounds[0][1] <= fog->bounds[1][1]
261 && bounds[0][2] <= fog->bounds[1][2] ) {
262 break;
263 }
264 }
265 if ( fogIndex == tr.world->numfogs ) {
266 fogIndex = 0;
267 }
268 }
269 poly->fogIndex = fogIndex;
270 }
271 }
272 // done.
273
274
275 //=================================================================================
276
277
278 /*
279 =====================
280 RE_AddRefEntityToScene
281
282 =====================
283 */
RE_AddRefEntityToScene(const refEntity_t * ent)284 void RE_AddRefEntityToScene( const refEntity_t *ent ) {
285 if ( !tr.registered ) {
286 return;
287 }
288 // show_bug.cgi?id=402
289 if ( r_numentities >= MAX_REFENTITIES ) {
290 ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n");
291 return;
292 }
293 if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
294 static qboolean firstTime = qtrue;
295 if (firstTime) {
296 firstTime = qfalse;
297 ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
298 }
299 return;
300 }
301 if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
302 ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
303 }
304
305 backEndData->entities[r_numentities].e = *ent;
306 backEndData->entities[r_numentities].lightingCalculated = qfalse;
307
308 r_numentities++;
309 }
310
311 // Ridah, added support for overdraw field
312 /*
313 =====================
314 RE_AddLightToScene
315
316 =====================
317 */
RE_AddLightToScene(const vec3_t org,float intensity,float r,float g,float b,int overdraw)318 void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b, int overdraw ) {
319 dlight_t *dl;
320
321 if ( !tr.registered ) {
322 return;
323 }
324 if ( r_numdlights >= MAX_DLIGHTS ) {
325 return;
326 }
327 if ( intensity <= 0 ) {
328 return;
329 }
330 // these cards don't have the correct blend mode
331 if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
332 return;
333 }
334 // RF, allow us to force some dlights under all circumstances
335 if ( !( overdraw & REF_FORCE_DLIGHT ) ) {
336 if ( r_dynamiclight->integer == 0 ) {
337 return;
338 }
339 if ( r_dynamiclight->integer == 2 && !( backEndData->dlights[r_numdlights].forced ) ) {
340 return;
341 }
342 }
343
344 if ( r_dlightScale->value <= 0 ) { //----(SA) added
345 return;
346 }
347
348 overdraw &= ~REF_FORCE_DLIGHT;
349 overdraw &= ~REF_JUNIOR_DLIGHT;
350
351 dl = &backEndData->dlights[r_numdlights++];
352 VectorCopy( org, dl->origin );
353
354 dl->radius = intensity * r_dlightScale->value; //----(SA) modified
355 dl->color[0] = r;
356 dl->color[1] = g;
357 dl->color[2] = b;
358 dl->dlshader = NULL;
359 dl->overdraw = 0;
360
361 if ( overdraw == 10 ) { // sorry, hijacking 10 for a quick hack (SA)
362 dl->dlshader = R_GetShaderByHandle( RE_RegisterShader( "negdlightshader" ) );
363 } else if ( overdraw == 11 ) { // 11 is flames
364 dl->dlshader = R_GetShaderByHandle( RE_RegisterShader( "flamedlightshader" ) );
365 } else {
366 dl->overdraw = overdraw;
367 }
368 }
369 // done.
370
371
372 /*
373 ==============
374 RE_AddCoronaToScene
375 ==============
376 */
RE_AddCoronaToScene(const vec3_t org,float r,float g,float b,float scale,int id,int flags)377 void RE_AddCoronaToScene( const vec3_t org, float r, float g, float b, float scale, int id, int flags ) {
378 corona_t *cor;
379
380 if ( !tr.registered ) {
381 return;
382 }
383 if ( r_numcoronas >= MAX_CORONAS ) {
384 return;
385 }
386
387 cor = &backEndData->coronas[r_numcoronas++];
388 VectorCopy( org, cor->origin );
389 cor->color[0] = r;
390 cor->color[1] = g;
391 cor->color[2] = b;
392 cor->scale = scale;
393 cor->id = id;
394 cor->flags = flags;
395 }
396
397 /*
398 @@@@@@@@@@@@@@@@@@@@@
399 RE_RenderScene
400
401 Draw a 3D view into a part of the window, then return
402 to 2D drawing.
403
404 Rendering a scene may require multiple views to be rendered
405 to handle mirrors,
406 @@@@@@@@@@@@@@@@@@@@@
407 */
RE_RenderScene(const refdef_t * fd)408 void RE_RenderScene( const refdef_t *fd ) {
409 viewParms_t parms;
410 int startTime;
411
412 if ( !tr.registered ) {
413 return;
414 }
415 GLimp_LogComment( "====== RE_RenderScene =====\n" );
416
417 if ( r_norefresh->integer ) {
418 return;
419 }
420
421 startTime = ri.Milliseconds();
422
423 if ( !tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
424 ri.Error( ERR_DROP, "R_RenderScene: NULL worldmodel" );
425 }
426
427 memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
428
429 tr.refdef.x = fd->x;
430 tr.refdef.y = fd->y;
431 tr.refdef.width = fd->width;
432 tr.refdef.height = fd->height;
433 tr.refdef.fov_x = fd->fov_x;
434 tr.refdef.fov_y = fd->fov_y;
435
436 VectorCopy( fd->vieworg, tr.refdef.vieworg );
437 VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
438 VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
439 VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
440
441 tr.refdef.time = fd->time;
442 tr.refdef.rdflags = fd->rdflags;
443
444 if ( fd->rdflags & RDF_SKYBOXPORTAL ) {
445 skyboxportal = 1;
446 }
447
448 if ( fd->rdflags & RDF_DRAWSKYBOX ) {
449 drawskyboxportal = 1;
450 } else {
451 drawskyboxportal = 0;
452 }
453
454 // copy the areamask data over and note if it has changed, which
455 // will force a reset of the visible leafs even if the view hasn't moved
456 tr.refdef.areamaskModified = qfalse;
457 if ( !( tr.refdef.rdflags & RDF_NOWORLDMODEL ) ) {
458 int areaDiff;
459 int i;
460
461 // compare the area bits
462 areaDiff = 0;
463 for ( i = 0 ; i < MAX_MAP_AREA_BYTES / 4 ; i++ ) {
464 areaDiff |= ( (int *)tr.refdef.areamask )[i] ^ ( (int *)fd->areamask )[i];
465 ( (int *)tr.refdef.areamask )[i] = ( (int *)fd->areamask )[i];
466 }
467
468 if ( areaDiff ) {
469 // a door just opened or something
470 tr.refdef.areamaskModified = qtrue;
471 }
472 }
473
474
475 // derived info
476
477 tr.refdef.floatTime = tr.refdef.time * 0.001;
478
479 tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
480 tr.refdef.drawSurfs = backEndData->drawSurfs;
481
482 tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
483 tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
484
485 tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
486 tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
487
488 tr.refdef.num_coronas = r_numcoronas - r_firstSceneCorona;
489 tr.refdef.coronas = &backEndData->coronas[r_firstSceneCorona];
490
491 tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
492 tr.refdef.polys = &backEndData->polys[r_firstScenePoly];
493
494 // turn off dynamic lighting globally by clearing all the
495 // dlights if it needs to be disabled or if vertex lighting is enabled
496 if ( /*r_dynamiclight->integer == 0 ||*/ // RF, disabled so we can force things like lightning dlights
497 r_vertexLight->integer == 1 ||
498 glConfig.hardwareType == GLHW_PERMEDIA2 ) {
499 tr.refdef.num_dlights = 0;
500 }
501
502 // a single frame may have multiple scenes draw inside it --
503 // a 3D game view, 3D status bar renderings, 3D menus, etc.
504 // They need to be distinguished by the light flare code, because
505 // the visibility state for a given surface may be different in
506 // each scene / view.
507 tr.frameSceneNum++;
508 tr.sceneCount++;
509
510 // setup view parms for the initial view
511 //
512 // set up viewport
513 // The refdef takes 0-at-the-top y coordinates, so
514 // convert to GL's 0-at-the-bottom space
515 //
516 memset( &parms, 0, sizeof( parms ) );
517 parms.viewportX = tr.refdef.x;
518 parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
519 parms.viewportWidth = tr.refdef.width;
520 parms.viewportHeight = tr.refdef.height;
521 parms.isPortal = qfalse;
522
523 parms.fovX = tr.refdef.fov_x;
524 parms.fovY = tr.refdef.fov_y;
525
526 parms.stereoFrame = tr.refdef.stereoFrame;
527
528 VectorCopy( fd->vieworg, parms.or.origin );
529 VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
530 VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
531 VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
532
533 VectorCopy( fd->vieworg, parms.pvsOrigin );
534
535 R_RenderView( &parms );
536
537 // the next scene rendered in this frame will tack on after this one
538 r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
539 r_firstSceneEntity = r_numentities;
540 r_firstSceneDlight = r_numdlights;
541 r_firstScenePoly = r_numpolys;
542
543 tr.frontEndMsec += ri.Milliseconds() - startTime;
544 }
545