1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22
23 #include "tr_local.h"
24
25 int r_firstSceneDrawSurf;
26
27 int r_numdlights;
28 int r_firstSceneDlight;
29
30 int r_numentities;
31 int r_firstSceneEntity;
32
33 int r_numpolys;
34 int r_firstScenePoly;
35
36 int r_numpolyverts;
37
38
39 /*
40 ====================
41 R_ToggleSmpFrame
42
43 ====================
44 */
R_ToggleSmpFrame(void)45 void R_ToggleSmpFrame( void ) {
46 if ( r_smp->integer ) {
47 // use the other buffers next frame, because another CPU
48 // may still be rendering into the current ones
49 tr.smpFrame ^= 1;
50 } else {
51 tr.smpFrame = 0;
52 }
53
54 backEndData[tr.smpFrame]->commands.used = 0;
55
56 r_firstSceneDrawSurf = 0;
57
58 r_numdlights = 0;
59 r_firstSceneDlight = 0;
60
61 r_numentities = 0;
62 r_firstSceneEntity = 0;
63
64 r_numpolys = 0;
65 r_firstScenePoly = 0;
66
67 r_numpolyverts = 0;
68 }
69
70
71 /*
72 ====================
73 RE_ClearScene
74
75 ====================
76 */
RE_ClearScene(void)77 void RE_ClearScene( void ) {
78 r_firstSceneDlight = r_numdlights;
79 r_firstSceneEntity = r_numentities;
80 r_firstScenePoly = r_numpolys;
81 }
82
83 /*
84 ===========================================================================
85
86 DISCRETE POLYS
87
88 ===========================================================================
89 */
90
91 /*
92 =====================
93 R_AddPolygonSurfaces
94
95 Adds all the scene's polys into this view's drawsurf list
96 =====================
97 */
R_AddPolygonSurfaces(void)98 void R_AddPolygonSurfaces( void ) {
99 int i;
100 shader_t *sh;
101 srfPoly_t *poly;
102
103 tr.currentEntityNum = ENTITYNUM_WORLD;
104 tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
105
106 for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
107 sh = R_GetShaderByHandle( poly->hShader );
108 R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
109 }
110 }
111
112 /*
113 =====================
114 RE_AddPolyToScene
115
116 =====================
117 */
RE_AddPolyToScene(qhandle_t hShader,int numVerts,const polyVert_t * verts,int numPolys)118 void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
119 srfPoly_t *poly;
120 int i, j;
121 int fogIndex;
122 fog_t *fog;
123 vec3_t bounds[2];
124
125 if ( !tr.registered ) {
126 return;
127 }
128
129 if ( !hShader ) {
130 ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
131 return;
132 }
133
134 for ( j = 0; j < numPolys; j++ ) {
135 if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
136 /*
137 NOTE TTimo this was initially a PRINT_WARNING
138 but it happens a lot with high fighting scenes and particles
139 since we don't plan on changing the const and making for room for those effects
140 simply cut this message to developer only
141 */
142 ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
143 return;
144 }
145
146 poly = &backEndData[tr.smpFrame]->polys[r_numpolys];
147 poly->surfaceType = SF_POLY;
148 poly->hShader = hShader;
149 poly->numVerts = numVerts;
150 poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts];
151
152 Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
153
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 // if no world is loaded
165 if ( tr.world == NULL ) {
166 fogIndex = 0;
167 }
168 // see if it is in a fog volume
169 else if ( tr.world->numfogs == 1 ) {
170 fogIndex = 0;
171 } else {
172 // find which fog volume the poly is in
173 VectorCopy( poly->verts[0].xyz, bounds[0] );
174 VectorCopy( poly->verts[0].xyz, bounds[1] );
175 for ( i = 1 ; i < poly->numVerts ; i++ ) {
176 AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
177 }
178 for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
179 fog = &tr.world->fogs[fogIndex];
180 if ( bounds[1][0] >= fog->bounds[0][0]
181 && bounds[1][1] >= fog->bounds[0][1]
182 && bounds[1][2] >= fog->bounds[0][2]
183 && bounds[0][0] <= fog->bounds[1][0]
184 && bounds[0][1] <= fog->bounds[1][1]
185 && bounds[0][2] <= fog->bounds[1][2] ) {
186 break;
187 }
188 }
189 if ( fogIndex == tr.world->numfogs ) {
190 fogIndex = 0;
191 }
192 }
193 poly->fogIndex = fogIndex;
194 }
195 }
196
197
198 //=================================================================================
199
200
201 /*
202 =====================
203 RE_AddRefEntityToScene
204
205 =====================
206 */
RE_AddRefEntityToScene(const refEntity_t * ent)207 void RE_AddRefEntityToScene( const refEntity_t *ent ) {
208 if ( !tr.registered ) {
209 return;
210 }
211 if ( r_numentities >= MAX_ENTITIES ) {
212 return;
213 }
214 if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
215 static qboolean firstTime = qtrue;
216 if (firstTime) {
217 firstTime = qfalse;
218 Com_DPrintf(S_COLOR_YELLOW "WARNING: RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
219 }
220 return;
221 }
222 if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
223 ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
224 }
225
226 backEndData[tr.smpFrame]->entities[r_numentities].e = *ent;
227 backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse;
228
229 r_numentities++;
230 }
231
232
233 /*
234 =====================
235 RE_AddDynamicLightToScene
236
237 =====================
238 */
RE_AddDynamicLightToScene(const vec3_t org,float intensity,float r,float g,float b,int additive)239 void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
240 dlight_t *dl;
241
242 if ( !tr.registered ) {
243 return;
244 }
245 if ( r_numdlights >= MAX_DLIGHTS ) {
246 return;
247 }
248 if ( intensity <= 0 ) {
249 return;
250 }
251 // these cards don't have the correct blend mode
252 if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
253 return;
254 }
255 dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++];
256 VectorCopy (org, dl->origin);
257 dl->radius = intensity;
258 dl->color[0] = r;
259 dl->color[1] = g;
260 dl->color[2] = b;
261 dl->additive = additive;
262 }
263
264 /*
265 =====================
266 RE_AddLightToScene
267
268 =====================
269 */
RE_AddLightToScene(const vec3_t org,float intensity,float r,float g,float b)270 void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
271 RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
272 }
273
274 /*
275 =====================
276 RE_AddAdditiveLightToScene
277
278 =====================
279 */
RE_AddAdditiveLightToScene(const vec3_t org,float intensity,float r,float g,float b)280 void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
281 RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
282 }
283
284 /*
285 @@@@@@@@@@@@@@@@@@@@@
286 RE_RenderScene
287
288 Draw a 3D view into a part of the window, then return
289 to 2D drawing.
290
291 Rendering a scene may require multiple views to be rendered
292 to handle mirrors,
293 @@@@@@@@@@@@@@@@@@@@@
294 */
RE_RenderScene(const refdef_t * fd)295 void RE_RenderScene( const refdef_t *fd ) {
296 viewParms_t parms;
297 int startTime;
298
299 if ( !tr.registered ) {
300 return;
301 }
302 GLimp_LogComment( "====== RE_RenderScene =====\n" );
303
304 if ( r_norefresh->integer ) {
305 return;
306 }
307
308 startTime = ri.Milliseconds();
309
310 if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
311 ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
312 }
313
314 Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
315
316 tr.refdef.x = fd->x;
317 tr.refdef.y = fd->y;
318 tr.refdef.width = fd->width;
319 tr.refdef.height = fd->height;
320 tr.refdef.fov_x = fd->fov_x;
321 tr.refdef.fov_y = fd->fov_y;
322
323 VectorCopy( fd->vieworg, tr.refdef.vieworg );
324 VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
325 VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
326 VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
327
328 tr.refdef.time = fd->time;
329 tr.refdef.rdflags = fd->rdflags;
330
331 // copy the areamask data over and note if it has changed, which
332 // will force a reset of the visible leafs even if the view hasn't moved
333 tr.refdef.areamaskModified = qfalse;
334 if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
335 int areaDiff;
336 int i;
337
338 // compare the area bits
339 areaDiff = 0;
340 for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
341 areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
342 ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
343 }
344
345 if ( areaDiff ) {
346 // a door just opened or something
347 tr.refdef.areamaskModified = qtrue;
348 }
349 }
350
351
352 // derived info
353
354 tr.refdef.floatTime = tr.refdef.time * 0.001f;
355
356 tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
357 tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs;
358
359 tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
360 tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity];
361
362 tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
363 tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight];
364
365 tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
366 tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly];
367
368 // turn off dynamic lighting globally by clearing all the
369 // dlights if it needs to be disabled or if vertex lighting is enabled
370 if ( r_dynamiclight->integer == 0 ||
371 r_vertexLight->integer == 1 ||
372 glConfig.hardwareType == GLHW_PERMEDIA2 ) {
373 tr.refdef.num_dlights = 0;
374 }
375
376 // a single frame may have multiple scenes draw inside it --
377 // a 3D game view, 3D status bar renderings, 3D menus, etc.
378 // They need to be distinguished by the light flare code, because
379 // the visibility state for a given surface may be different in
380 // each scene / view.
381 tr.frameSceneNum++;
382 tr.sceneCount++;
383
384 // setup view parms for the initial view
385 //
386 // set up viewport
387 // The refdef takes 0-at-the-top y coordinates, so
388 // convert to GL's 0-at-the-bottom space
389 //
390 Com_Memset( &parms, 0, sizeof( parms ) );
391 parms.viewportX = tr.refdef.x;
392 parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
393 parms.viewportWidth = tr.refdef.width;
394 parms.viewportHeight = tr.refdef.height;
395 parms.isPortal = qfalse;
396
397 parms.fovX = tr.refdef.fov_x;
398 parms.fovY = tr.refdef.fov_y;
399
400 parms.stereoFrame = tr.refdef.stereoFrame;
401
402 VectorCopy( fd->vieworg, parms.or.origin );
403 VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
404 VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
405 VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
406
407 VectorCopy( fd->vieworg, parms.pvsOrigin );
408
409 R_RenderView( &parms );
410
411 // the next scene rendered in this frame will tack on after this one
412 r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
413 r_firstSceneEntity = r_numentities;
414 r_firstSceneDlight = r_numdlights;
415 r_firstScenePoly = r_numpolys;
416
417 tr.frontEndMsec += ri.Milliseconds() - startTime;
418 }
419