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