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