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 ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
215 ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
216 }
217
218 backEndData[tr.smpFrame]->entities[r_numentities].e = *ent;
219 backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse;
220
221 r_numentities++;
222 }
223
224
225 /*
226 =====================
227 RE_AddDynamicLightToScene
228
229 =====================
230 */
RE_AddDynamicLightToScene(const vec3_t org,float intensity,float r,float g,float b,int additive)231 void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
232 dlight_t *dl;
233
234 if ( !tr.registered ) {
235 return;
236 }
237 if ( r_numdlights >= MAX_DLIGHTS ) {
238 return;
239 }
240 if ( intensity <= 0 ) {
241 return;
242 }
243 // these cards don't have the correct blend mode
244 if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
245 return;
246 }
247 dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++];
248 VectorCopy (org, dl->origin);
249 dl->radius = intensity;
250 dl->color[0] = r;
251 dl->color[1] = g;
252 dl->color[2] = b;
253 dl->additive = additive;
254 }
255
256 /*
257 =====================
258 RE_AddLightToScene
259
260 =====================
261 */
RE_AddLightToScene(const vec3_t org,float intensity,float r,float g,float b)262 void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
263 RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
264 }
265
266 /*
267 =====================
268 RE_AddAdditiveLightToScene
269
270 =====================
271 */
RE_AddAdditiveLightToScene(const vec3_t org,float intensity,float r,float g,float b)272 void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
273 RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
274 }
275
276 /*
277 @@@@@@@@@@@@@@@@@@@@@
278 RE_RenderScene
279
280 Draw a 3D view into a part of the window, then return
281 to 2D drawing.
282
283 Rendering a scene may require multiple views to be rendered
284 to handle mirrors,
285 @@@@@@@@@@@@@@@@@@@@@
286 */
RE_RenderScene(const refdef_t * fd)287 void RE_RenderScene( const refdef_t *fd ) {
288 viewParms_t parms;
289 int startTime;
290
291 if ( !tr.registered ) {
292 return;
293 }
294 GLimp_LogComment( "====== RE_RenderScene =====\n" );
295
296 if ( r_norefresh->integer ) {
297 return;
298 }
299
300 startTime = ri.Milliseconds();
301
302 if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
303 ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
304 }
305
306 Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
307
308 tr.refdef.x = fd->x;
309 tr.refdef.y = fd->y;
310 tr.refdef.width = fd->width;
311 tr.refdef.height = fd->height;
312 tr.refdef.fov_x = fd->fov_x;
313 tr.refdef.fov_y = fd->fov_y;
314
315 VectorCopy( fd->vieworg, tr.refdef.vieworg );
316 VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
317 VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
318 VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
319
320 tr.refdef.time = fd->time;
321 tr.refdef.rdflags = fd->rdflags;
322
323 // copy the areamask data over and note if it has changed, which
324 // will force a reset of the visible leafs even if the view hasn't moved
325 tr.refdef.areamaskModified = qfalse;
326 if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
327 int areaDiff;
328 int i;
329
330 // compare the area bits
331 areaDiff = 0;
332 for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
333 areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
334 ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
335 }
336
337 if ( areaDiff ) {
338 // a door just opened or something
339 tr.refdef.areamaskModified = qtrue;
340 }
341 }
342
343
344 // derived info
345
346 tr.refdef.floatTime = tr.refdef.time * 0.001f;
347
348 tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
349 tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs;
350
351 tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
352 tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity];
353
354 tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
355 tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight];
356
357 tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
358 tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly];
359
360 // turn off dynamic lighting globally by clearing all the
361 // dlights if it needs to be disabled or if vertex lighting is enabled
362 if ( r_dynamiclight->integer == 0 ||
363 r_vertexLight->integer == 1 ||
364 glConfig.hardwareType == GLHW_PERMEDIA2 ) {
365 tr.refdef.num_dlights = 0;
366 }
367
368 // a single frame may have multiple scenes draw inside it --
369 // a 3D game view, 3D status bar renderings, 3D menus, etc.
370 // They need to be distinguished by the light flare code, because
371 // the visibility state for a given surface may be different in
372 // each scene / view.
373 tr.frameSceneNum++;
374 tr.sceneCount++;
375
376 // setup view parms for the initial view
377 //
378 // set up viewport
379 // The refdef takes 0-at-the-top y coordinates, so
380 // convert to GL's 0-at-the-bottom space
381 //
382 Com_Memset( &parms, 0, sizeof( parms ) );
383 parms.viewportX = tr.refdef.x;
384 parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
385 parms.viewportWidth = tr.refdef.width;
386 parms.viewportHeight = tr.refdef.height;
387 parms.isPortal = qfalse;
388
389 parms.fovX = tr.refdef.fov_x;
390 parms.fovY = tr.refdef.fov_y;
391
392 parms.stereoFrame = tr.refdef.stereoFrame;
393
394 VectorCopy( fd->vieworg, parms.or.origin );
395 VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
396 VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
397 VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
398
399 VectorCopy( fd->vieworg, parms.pvsOrigin );
400
401 R_RenderView( &parms );
402
403 // the next scene rendered in this frame will tack on after this one
404 r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
405 r_firstSceneEntity = r_numentities;
406 r_firstSceneDlight = r_numdlights;
407 r_firstScenePoly = r_numpolys;
408
409 tr.frontEndMsec += ri.Milliseconds() - startTime;
410 }
411