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