1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2006 Robert Beckebans <trebor_7@users.sourceforge.net>
5 
6 This file is part of XreaL source code.
7 
8 XreaL source code 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 XreaL source code 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 XreaL source code; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 ===========================================================================
22 */
23 // tr_scene.c
24 #include "tr_local.h"
25 
26 static int      r_firstSceneDrawSurf;
27 static int      r_firstSceneInteraction;
28 
29 static int      r_numLights;
30 static int      r_firstSceneLight;
31 
32 static int      r_numentities;
33 static int      r_firstSceneEntity;
34 
35 static int      r_numpolys;
36 static int      r_firstScenePoly;
37 
38 static int      r_numpolyverts;
39 
40 
41 /*
42 ====================
43 R_ToggleSmpFrame
44 ====================
45 */
R_ToggleSmpFrame(void)46 void R_ToggleSmpFrame(void)
47 {
48 	if(r_smp->integer)
49 	{
50 		// use the other buffers next frame, because another CPU
51 		// may still be rendering into the current ones
52 		tr.smpFrame ^= 1;
53 	}
54 	else
55 	{
56 		tr.smpFrame = 0;
57 	}
58 
59 	backEndData[tr.smpFrame]->commands.used = 0;
60 
61 	r_firstSceneDrawSurf = 0;
62 	r_firstSceneInteraction = 0;
63 
64 	r_numLights = 0;
65 	r_firstSceneLight = 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 */
RE_ClearScene(void)82 void RE_ClearScene(void)
83 {
84 	r_firstSceneLight = r_numLights;
85 	r_firstSceneEntity = r_numentities;
86 	r_firstScenePoly = r_numpolys;
87 }
88 
89 /*
90 ===========================================================================
91 
92 DISCRETE POLYS
93 
94 ===========================================================================
95 */
96 
97 /*
98 =====================
99 R_AddPolygonSurfaces
100 
101 Adds all the scene's polys into this view's drawsurf list
102 =====================
103 */
R_AddPolygonSurfaces(void)104 void R_AddPolygonSurfaces(void)
105 {
106 	int             i;
107 	shader_t       *sh;
108 	srfPoly_t      *poly;
109 
110 	tr.currentEntity = &tr.worldEntity;
111 
112 	for(i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys; i++, poly++)
113 	{
114 		sh = R_GetShaderByHandle(poly->hShader);
115 		R_AddDrawSurf((void *)poly, sh, -1, poly->fogIndex);
116 	}
117 }
118 
119 /*
120 =====================
121 RE_AddPolyToScene
122 =====================
123 */
RE_AddPolyToScene(qhandle_t hShader,int numVerts,const polyVert_t * verts,int numPolys)124 void RE_AddPolyToScene(qhandle_t hShader, int numVerts, const polyVert_t * verts, int numPolys)
125 {
126 	srfPoly_t      *poly;
127 	int             i, j;
128 	int             fogIndex;
129 	fog_t          *fog;
130 	vec3_t          bounds[2];
131 
132 	if(!tr.registered)
133 	{
134 		return;
135 	}
136 
137 	if(!hShader)
138 	{
139 		ri.Printf(PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
140 		return;
141 	}
142 
143 	for(j = 0; j < numPolys; j++)
144 	{
145 		if(r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys)
146 		{
147 			/*
148 			   NOTE TTimo this was initially a PRINT_WARNING
149 			   but it happens a lot with high fighting scenes and particles
150 			   since we don't plan on changing the const and making for room for those effects
151 			   simply cut this message to developer only
152 			 */
153 			ri.Printf(PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
154 			return;
155 		}
156 
157 		poly = &backEndData[tr.smpFrame]->polys[r_numpolys];
158 		poly->surfaceType = SF_POLY;
159 		poly->hShader = hShader;
160 		poly->numVerts = numVerts;
161 		poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts];
162 
163 		Com_Memcpy(poly->verts, &verts[numVerts * j], numVerts * sizeof(*verts));
164 
165 		if(glConfig.hardwareType == GLHW_RAGEPRO)
166 		{
167 			poly->verts->modulate[0] = 255;
168 			poly->verts->modulate[1] = 255;
169 			poly->verts->modulate[2] = 255;
170 			poly->verts->modulate[3] = 255;
171 		}
172 		// done.
173 		r_numpolys++;
174 		r_numpolyverts += numVerts;
175 
176 		// if no world is loaded
177 		if(tr.world == NULL)
178 		{
179 			fogIndex = 0;
180 		}
181 		// see if it is in a fog volume
182 		else if(tr.world->numfogs == 1)
183 		{
184 			fogIndex = 0;
185 		}
186 		else
187 		{
188 			// find which fog volume the poly is in
189 			VectorCopy(poly->verts[0].xyz, bounds[0]);
190 			VectorCopy(poly->verts[0].xyz, bounds[1]);
191 			for(i = 1; i < poly->numVerts; i++)
192 			{
193 				AddPointToBounds(poly->verts[i].xyz, bounds[0], bounds[1]);
194 			}
195 			for(fogIndex = 1; fogIndex < tr.world->numfogs; fogIndex++)
196 			{
197 				fog = &tr.world->fogs[fogIndex];
198 				if(bounds[1][0] >= fog->bounds[0][0]
199 				   && bounds[1][1] >= fog->bounds[0][1]
200 				   && bounds[1][2] >= fog->bounds[0][2]
201 				   && bounds[0][0] <= fog->bounds[1][0]
202 				   && bounds[0][1] <= fog->bounds[1][1] && bounds[0][2] <= fog->bounds[1][2])
203 				{
204 					break;
205 				}
206 			}
207 			if(fogIndex == tr.world->numfogs)
208 			{
209 				fogIndex = 0;
210 			}
211 		}
212 		poly->fogIndex = fogIndex;
213 	}
214 }
215 
216 
217 //=================================================================================
218 
219 
220 /*
221 =====================
222 RE_AddRefEntityToScene
223 =====================
224 */
RE_AddRefEntityToScene(const refEntity_t * ent)225 void RE_AddRefEntityToScene(const refEntity_t * ent)
226 {
227 	if(!tr.registered)
228 	{
229 		return;
230 	}
231 
232 	// Tr3B: fixed was ENTITYNUM_WORLD
233 	if(r_numentities >= MAX_ENTITIES)
234 	{
235 		return;
236 	}
237 
238 	if(ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE)
239 	{
240 		ri.Error(ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType);
241 	}
242 
243 	Com_Memcpy(&backEndData[tr.smpFrame]->entities[r_numentities].e, ent, sizeof(refEntity_t));
244 	//backEndData[tr.smpFrame]->entities[r_numentities].e = *ent;
245 	backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse;
246 
247 	r_numentities++;
248 }
249 
250 /*
251 =====================
252 RE_AddRefDlightToScene
253 =====================
254 */
RE_AddRefDlightToScene(const refLight_t * light)255 void RE_AddRefDlightToScene(const refLight_t * light)
256 {
257 	trRefDlight_t *dl;
258 
259 	if(!tr.registered)
260 	{
261 		return;
262 	}
263 
264 	if(r_numLights >= MAX_LIGHTS)
265 	{
266 		return;
267 	}
268 
269 	if(light->radius[0] <= 0 && !VectorLength(light->radius))
270 	{
271 		return;
272 	}
273 
274 	if(light->rlType < 0 || light->rlType >= RL_MAX_REF_LIGHT_TYPE)
275 	{
276 		ri.Error(ERR_DROP, "RE_AddRefDlightToScene: bad rlType %i", light->rlType);
277 	}
278 
279 	dl = &backEndData[tr.smpFrame]->dlights[r_numLights++];
280 	dl->l = *light;
281 
282 	dl->isStatic = qfalse;
283 	dl->additive = qtrue;
284 }
285 
286 /*
287 =====================
288 RE_AddDynamicLightToScene
289 =====================
290 */
RE_AddDynamicLightToScene(const vec3_t org,float intensity,float r,float g,float b,int additive)291 static void RE_AddDynamicLightToScene(const vec3_t org, float intensity, float r, float g, float b, int additive)
292 {
293 	trRefDlight_t *dl;
294 
295 	if(!tr.registered)
296 	{
297 		return;
298 	}
299 
300 	if(r_numLights >= MAX_LIGHTS)
301 	{
302 		return;
303 	}
304 
305 	if(intensity <= 0)
306 	{
307 		return;
308 	}
309 
310 	dl = &backEndData[tr.smpFrame]->dlights[r_numLights++];
311 
312 	dl->l.rlType = RL_OMNI;
313 //	dl->l.lightfx = 0;
314 	VectorCopy(org, dl->l.origin);
315 
316 	// HACK: this will tell the renderer backend to use tr.defaultDynamicLightShader
317 	dl->l.attenuationShader = 0;
318 
319 	dl->l.radius[0] = intensity;
320 	dl->l.radius[1] = intensity;
321 	dl->l.radius[2] = intensity;
322 
323 	dl->l.color[0] = r;
324 	dl->l.color[1] = g;
325 	dl->l.color[2] = b;
326 
327 	AxisCopy(axisDefault, dl->l.axis);
328 	dl->l.nonNormalizedAxes = qfalse;
329 	dl->l.noShadows = qfalse;
330 
331 	dl->isStatic = qfalse;
332 	dl->additive = additive;
333 }
334 
335 /*
336 =====================
337 RE_AddLightToScene
338 =====================
339 */
RE_AddLightToScene(const vec3_t org,float intensity,float r,float g,float b)340 void RE_AddLightToScene(const vec3_t org, float intensity, float r, float g, float b)
341 {
342 	RE_AddDynamicLightToScene(org, intensity, r, g, b, qfalse);
343 }
344 
345 /*
346 =====================
347 RE_AddAdditiveLightToScene
348 =====================
349 */
RE_AddAdditiveLightToScene(const vec3_t org,float intensity,float r,float g,float b)350 void RE_AddAdditiveLightToScene(const vec3_t org, float intensity, float r, float g, float b)
351 {
352 	RE_AddDynamicLightToScene(org, intensity, r, g, b, qtrue);
353 }
354 
355 /*
356 @@@@@@@@@@@@@@@@@@@@@
357 RE_RenderScene
358 
359 Draw a 3D view into a part of the window, then return
360 to 2D drawing.
361 
362 Rendering a scene may require multiple views to be rendered
363 to handle mirrors,
364 @@@@@@@@@@@@@@@@@@@@@
365 */
RE_RenderScene(const refdef_t * fd)366 void RE_RenderScene(const refdef_t * fd)
367 {
368 	viewParms_t     parms;
369 	int             startTime;
370 
371 	if(!tr.registered)
372 	{
373 		return;
374 	}
375 	GLimp_LogComment("====== RE_RenderScene =====\n");
376 
377 	if(r_norefresh->integer)
378 	{
379 		return;
380 	}
381 
382 	startTime = ri.Milliseconds();
383 
384 	if(!tr.world && !(fd->rdflags & RDF_NOWORLDMODEL))
385 	{
386 		ri.Error(ERR_DROP, "R_RenderScene: NULL worldmodel");
387 	}
388 
389 	Com_Memcpy(tr.refdef.text, fd->text, sizeof(tr.refdef.text));
390 
391 	tr.refdef.x = fd->x;
392 	tr.refdef.y = fd->y;
393 	tr.refdef.width = fd->width;
394 	tr.refdef.height = fd->height;
395 	tr.refdef.fov_x = fd->fov_x;
396 	tr.refdef.fov_y = fd->fov_y;
397 
398 	VectorCopy(fd->vieworg, tr.refdef.vieworg);
399 	VectorCopy(fd->viewaxis[0], tr.refdef.viewaxis[0]);
400 	VectorCopy(fd->viewaxis[1], tr.refdef.viewaxis[1]);
401 	VectorCopy(fd->viewaxis[2], tr.refdef.viewaxis[2]);
402 
403 	tr.refdef.time = fd->time;
404 	tr.refdef.rdflags = fd->rdflags;
405 
406 	// copy the areamask data over and note if it has changed, which
407 	// will force a reset of the visible leafs even if the view hasn't moved
408 	tr.refdef.areamaskModified = qfalse;
409 	if(!(tr.refdef.rdflags & RDF_NOWORLDMODEL))
410 	{
411 		int             areaDiff;
412 		int             i;
413 
414 		// compare the area bits
415 		areaDiff = 0;
416 		for(i = 0; i < MAX_MAP_AREA_BYTES / 4; i++)
417 		{
418 			areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
419 			((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
420 		}
421 
422 		if(areaDiff)
423 		{
424 			// a door just opened or something
425 			tr.refdef.areamaskModified = qtrue;
426 		}
427 	}
428 
429 
430 	// derived info
431 	tr.refdef.floatTime = tr.refdef.time * 0.001f;
432 
433 	tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
434 	tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs;
435 
436 	tr.refdef.numInteractions = r_firstSceneInteraction;
437 	tr.refdef.interactions = backEndData[tr.smpFrame]->interactions;
438 
439 	tr.refdef.numEntities = r_numentities - r_firstSceneEntity;
440 	tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity];
441 
442 	tr.refdef.numDlights = r_numLights - r_firstSceneLight;
443 	tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneLight];
444 
445 	tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
446 	tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly];
447 
448 	// a single frame may have multiple scenes draw inside it --
449 	// a 3D game view, 3D status bar renderings, 3D menus, etc.
450 	// They need to be distinguished by the light flare code, because
451 	// the visibility state for a given surface may be different in
452 	// each scene / view.
453 	tr.frameSceneNum++;
454 	tr.sceneCount++;
455 
456 	// setup view parms for the initial view
457 	//
458 	// set up viewport
459 	// The refdef takes 0-at-the-top y coordinates, so
460 	// convert to GL's 0-at-the-bottom space
461 	//
462 	Com_Memset(&parms, 0, sizeof(parms));
463 	parms.viewportX = tr.refdef.x;
464 	parms.viewportY = glConfig.vidHeight - (tr.refdef.y + tr.refdef.height);
465 	parms.viewportWidth = tr.refdef.width;
466 	parms.viewportHeight = tr.refdef.height;
467 	parms.isPortal = qfalse;
468 
469 	parms.fovX = tr.refdef.fov_x;
470 	parms.fovY = tr.refdef.fov_y;
471 
472 	VectorCopy(fd->vieworg, parms.or.origin);
473 	VectorCopy(fd->viewaxis[0], parms.or.axis[0]);
474 	VectorCopy(fd->viewaxis[1], parms.or.axis[1]);
475 	VectorCopy(fd->viewaxis[2], parms.or.axis[2]);
476 
477 	VectorCopy(fd->vieworg, parms.pvsOrigin);
478 
479 	R_RenderView(&parms);
480 
481 	// the next scene rendered in this frame will tack on after this one
482 	r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
483 	r_firstSceneInteraction = tr.refdef.numInteractions;
484 	r_firstSceneEntity = r_numentities;
485 	r_firstSceneLight = r_numLights;
486 	r_firstScenePoly = r_numpolys;
487 
488 	tr.frontEndMsec += ri.Milliseconds() - startTime;
489 }
490