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