1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "sys/platform.h"
30
31 #include "renderer/tr_local.h"
32
33 typedef struct {
34 idVec3 origin;
35 idMat3 axis;
36 } orientation_t;
37
38
39 /*
40 =================
41 R_MirrorPoint
42 =================
43 */
R_MirrorPoint(const idVec3 in,orientation_t * surface,orientation_t * camera,idVec3 & out)44 static void R_MirrorPoint( const idVec3 in, orientation_t *surface, orientation_t *camera, idVec3 &out ) {
45 int i;
46 idVec3 local;
47 idVec3 transformed;
48 float d;
49
50 local = in - surface->origin;
51
52 transformed = vec3_origin;
53 for ( i = 0 ; i < 3 ; i++ ) {
54 d = local * surface->axis[i];
55 transformed += d * camera->axis[i];
56 }
57
58 out = transformed + camera->origin;
59 }
60
61 /*
62 =================
63 R_MirrorVector
64 =================
65 */
R_MirrorVector(const idVec3 in,orientation_t * surface,orientation_t * camera,idVec3 & out)66 static void R_MirrorVector( const idVec3 in, orientation_t *surface, orientation_t *camera, idVec3 &out ) {
67 int i;
68 float d;
69
70 out = vec3_origin;
71 for ( i = 0 ; i < 3 ; i++ ) {
72 d = in * surface->axis[i];
73 out += d * camera->axis[i];
74 }
75 }
76
77 /*
78 =============
79 R_PlaneForSurface
80
81 Returns the plane for the first triangle in the surface
82 FIXME: check for degenerate triangle?
83 =============
84 */
R_PlaneForSurface(const srfTriangles_t * tri,idPlane & plane)85 static void R_PlaneForSurface( const srfTriangles_t *tri, idPlane &plane ) {
86 idDrawVert *v1, *v2, *v3;
87
88 v1 = tri->verts + tri->indexes[0];
89 v2 = tri->verts + tri->indexes[1];
90 v3 = tri->verts + tri->indexes[2];
91 plane.FromPoints( v1->xyz, v2->xyz, v3->xyz );
92 }
93
94 /*
95 =========================
96 R_PreciseCullSurface
97
98 Check the surface for visibility on a per-triangle basis
99 for cases when it is going to be VERY expensive to draw (subviews)
100
101 If not culled, also returns the bounding box of the surface in
102 Normalized Device Coordinates, so it can be used to crop the scissor rect.
103
104 OPTIMIZE: we could also take exact portal passing into consideration
105 =========================
106 */
R_PreciseCullSurface(const drawSurf_t * drawSurf,idBounds & ndcBounds)107 bool R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds ) {
108 const srfTriangles_t *tri;
109 idPlane clip, eye;
110 int i, j;
111 unsigned int pointOr;
112 unsigned int pointAnd;
113 idVec3 localView;
114 idFixedWinding w;
115
116 tri = drawSurf->geo;
117
118 pointOr = 0;
119 pointAnd = (unsigned int)~0;
120
121 // get an exact bounds of the triangles for scissor cropping
122 ndcBounds.Clear();
123
124 for ( i = 0; i < tri->numVerts; i++ ) {
125 int j;
126 unsigned int pointFlags;
127
128 R_TransformModelToClip( tri->verts[i].xyz, drawSurf->space->modelViewMatrix,
129 tr.viewDef->projectionMatrix, eye, clip );
130
131 pointFlags = 0;
132 for ( j = 0; j < 3; j++ ) {
133 if ( clip[j] >= clip[3] ) {
134 pointFlags |= (1 << (j*2));
135 } else if ( clip[j] <= -clip[3] ) {
136 pointFlags |= ( 1 << (j*2+1));
137 }
138 }
139
140 pointAnd &= pointFlags;
141 pointOr |= pointFlags;
142 }
143
144 // trivially reject
145 if ( pointAnd ) {
146 return true;
147 }
148
149 // backface and frustum cull
150 R_GlobalPointToLocal( drawSurf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView );
151
152 for ( i = 0; i < tri->numIndexes; i += 3 ) {
153 idVec3 dir, normal;
154 float dot;
155 idVec3 d1, d2;
156
157 const idVec3 &v1 = tri->verts[tri->indexes[i]].xyz;
158 const idVec3 &v2 = tri->verts[tri->indexes[i+1]].xyz;
159 const idVec3 &v3 = tri->verts[tri->indexes[i+2]].xyz;
160
161 // this is a hack, because R_GlobalPointToLocal doesn't work with the non-normalized
162 // axis that we get from the gui view transform. It doesn't hurt anything, because
163 // we know that all gui generated surfaces are front facing
164 if ( tr.guiRecursionLevel == 0 ) {
165 // we don't care that it isn't normalized,
166 // all we want is the sign
167 d1 = v2 - v1;
168 d2 = v3 - v1;
169 normal = d2.Cross( d1 );
170
171 dir = v1 - localView;
172
173 dot = normal * dir;
174 if ( dot >= 0.0f ) {
175 return true;
176 }
177 }
178
179 // now find the exact screen bounds of the clipped triangle
180 w.SetNumPoints( 3 );
181 R_LocalPointToGlobal( drawSurf->space->modelMatrix, v1, w[0].ToVec3() );
182 R_LocalPointToGlobal( drawSurf->space->modelMatrix, v2, w[1].ToVec3() );
183 R_LocalPointToGlobal( drawSurf->space->modelMatrix, v3, w[2].ToVec3() );
184 w[0].s = w[0].t = w[1].s = w[1].t = w[2].s = w[2].t = 0.0f;
185
186 for ( j = 0; j < 4; j++ ) {
187 if ( !w.ClipInPlace( -tr.viewDef->frustum[j], 0.1f ) ) {
188 break;
189 }
190 }
191 for ( j = 0; j < w.GetNumPoints(); j++ ) {
192 idVec3 screen;
193
194 R_GlobalToNormalizedDeviceCoordinates( w[j].ToVec3(), screen );
195 ndcBounds.AddPoint( screen );
196 }
197 }
198
199 // if we don't enclose any area, return
200 if ( ndcBounds.IsCleared() ) {
201 return true;
202 }
203
204 return false;
205 }
206
207 /*
208 ========================
209 R_MirrorViewBySurface
210 ========================
211 */
R_MirrorViewBySurface(drawSurf_t * drawSurf)212 static viewDef_t *R_MirrorViewBySurface( drawSurf_t *drawSurf ) {
213 viewDef_t *parms;
214 orientation_t surface, camera;
215 idPlane originalPlane, plane;
216
217 // copy the viewport size from the original
218 parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
219 *parms = *tr.viewDef;
220 parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
221
222 parms->isSubview = true;
223 parms->isMirror = true;
224
225 // create plane axis for the portal we are seeing
226 R_PlaneForSurface( drawSurf->geo, originalPlane );
227 R_LocalPlaneToGlobal( drawSurf->space->modelMatrix, originalPlane, plane );
228
229 surface.origin = plane.Normal() * -plane[3];
230 surface.axis[0] = plane.Normal();
231 surface.axis[0].NormalVectors( surface.axis[1], surface.axis[2] );
232 surface.axis[2] = -surface.axis[2];
233
234 camera.origin = surface.origin;
235 camera.axis[0] = -surface.axis[0];
236 camera.axis[1] = surface.axis[1];
237 camera.axis[2] = surface.axis[2];
238
239 // set the mirrored origin and axis
240 R_MirrorPoint( tr.viewDef->renderView.vieworg, &surface, &camera, parms->renderView.vieworg );
241
242 R_MirrorVector( tr.viewDef->renderView.viewaxis[0], &surface, &camera, parms->renderView.viewaxis[0] );
243 R_MirrorVector( tr.viewDef->renderView.viewaxis[1], &surface, &camera, parms->renderView.viewaxis[1] );
244 R_MirrorVector( tr.viewDef->renderView.viewaxis[2], &surface, &camera, parms->renderView.viewaxis[2] );
245
246 // make the view origin 16 units away from the center of the surface
247 idVec3 viewOrigin = ( drawSurf->geo->bounds[0] + drawSurf->geo->bounds[1] ) * 0.5;
248 viewOrigin += ( originalPlane.Normal() * 16 );
249
250 R_LocalPointToGlobal( drawSurf->space->modelMatrix, viewOrigin, parms->initialViewAreaOrigin );
251
252 // set the mirror clip plane
253 parms->numClipPlanes = 1;
254 parms->clipPlanes[0] = -camera.axis[0];
255
256 parms->clipPlanes[0][3] = -( camera.origin * parms->clipPlanes[0].Normal() );
257
258 return parms;
259 }
260
261 /*
262 ========================
263 R_XrayViewBySurface
264 ========================
265 */
R_XrayViewBySurface(drawSurf_t * drawSurf)266 static viewDef_t *R_XrayViewBySurface( drawSurf_t *drawSurf ) {
267 viewDef_t *parms;
268 idPlane originalPlane, plane;
269
270 // copy the viewport size from the original
271 parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
272 *parms = *tr.viewDef;
273 parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
274
275 parms->isSubview = true;
276 parms->isXraySubview = true;
277
278 return parms;
279 }
280
281 /*
282 ===============
283 R_RemoteRender
284 ===============
285 */
R_RemoteRender(drawSurf_t * surf,textureStage_t * stage)286 static void R_RemoteRender( drawSurf_t *surf, textureStage_t *stage ) {
287 viewDef_t *parms;
288
289 // remote views can be reused in a single frame
290 if ( stage->dynamicFrameCount == tr.frameCount ) {
291 return;
292 }
293
294 // if the entity doesn't have a remoteRenderView, do nothing
295 if ( !surf->space->entityDef->parms.remoteRenderView ) {
296 return;
297 }
298
299 // copy the viewport size from the original
300 parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
301 *parms = *tr.viewDef;
302
303 parms->isSubview = true;
304 parms->isMirror = false;
305
306 parms->renderView = *surf->space->entityDef->parms.remoteRenderView;
307 parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
308 parms->initialViewAreaOrigin = parms->renderView.vieworg;
309
310 tr.CropRenderSize( stage->width, stage->height, true );
311
312 parms->renderView.x = 0;
313 parms->renderView.y = 0;
314 parms->renderView.width = SCREEN_WIDTH;
315 parms->renderView.height = SCREEN_HEIGHT;
316
317 tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
318
319 parms->scissor.x1 = 0;
320 parms->scissor.y1 = 0;
321 parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
322 parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
323
324 parms->superView = tr.viewDef;
325 parms->subviewSurface = surf;
326
327 // generate render commands for it
328 R_RenderView(parms);
329
330 // copy this rendering to the image
331 stage->dynamicFrameCount = tr.frameCount;
332 if (!stage->image) {
333 stage->image = globalImages->scratchImage;
334 }
335
336 tr.CaptureRenderToImage( stage->image->imgName );
337 tr.UnCrop();
338 }
339
340 /*
341 =================
342 R_MirrorRender
343 =================
344 */
R_MirrorRender(drawSurf_t * surf,textureStage_t * stage,idScreenRect scissor)345 void R_MirrorRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) {
346 viewDef_t *parms;
347
348 // remote views can be reused in a single frame
349 if ( stage->dynamicFrameCount == tr.frameCount ) {
350 return;
351 }
352
353 // issue a new view command
354 parms = R_MirrorViewBySurface( surf );
355 if ( !parms ) {
356 return;
357 }
358
359 tr.CropRenderSize( stage->width, stage->height, true );
360
361 parms->renderView.x = 0;
362 parms->renderView.y = 0;
363 parms->renderView.width = SCREEN_WIDTH;
364 parms->renderView.height = SCREEN_HEIGHT;
365
366 tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
367
368 parms->scissor.x1 = 0;
369 parms->scissor.y1 = 0;
370 parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
371 parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
372
373 parms->superView = tr.viewDef;
374 parms->subviewSurface = surf;
375
376 // triangle culling order changes with mirroring
377 parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
378
379 // generate render commands for it
380 R_RenderView( parms );
381
382 // copy this rendering to the image
383 stage->dynamicFrameCount = tr.frameCount;
384 stage->image = globalImages->scratchImage;
385
386 tr.CaptureRenderToImage( stage->image->imgName );
387 tr.UnCrop();
388 }
389
390 /*
391 =================
392 R_XrayRender
393 =================
394 */
R_XrayRender(drawSurf_t * surf,textureStage_t * stage,idScreenRect scissor)395 void R_XrayRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) {
396 viewDef_t *parms;
397
398 // remote views can be reused in a single frame
399 if ( stage->dynamicFrameCount == tr.frameCount ) {
400 return;
401 }
402
403 // issue a new view command
404 parms = R_XrayViewBySurface( surf );
405 if ( !parms ) {
406 return;
407 }
408
409 tr.CropRenderSize( stage->width, stage->height, true );
410
411 parms->renderView.x = 0;
412 parms->renderView.y = 0;
413 parms->renderView.width = SCREEN_WIDTH;
414 parms->renderView.height = SCREEN_HEIGHT;
415
416 tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
417
418 parms->scissor.x1 = 0;
419 parms->scissor.y1 = 0;
420 parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
421 parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
422
423 parms->superView = tr.viewDef;
424 parms->subviewSurface = surf;
425
426 // triangle culling order changes with mirroring
427 parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
428
429 // generate render commands for it
430 R_RenderView( parms );
431
432 // copy this rendering to the image
433 stage->dynamicFrameCount = tr.frameCount;
434 stage->image = globalImages->scratchImage2;
435
436 tr.CaptureRenderToImage( stage->image->imgName );
437 tr.UnCrop();
438 }
439
440 /*
441 ==================
442 R_GenerateSurfaceSubview
443 ==================
444 */
R_GenerateSurfaceSubview(drawSurf_t * drawSurf)445 bool R_GenerateSurfaceSubview( drawSurf_t *drawSurf ) {
446 idBounds ndcBounds;
447 viewDef_t *parms;
448 const idMaterial *shader;
449
450 // for testing the performance hit
451 if ( r_skipSubviews.GetBool() ) {
452 return false;
453 }
454
455 if ( R_PreciseCullSurface( drawSurf, ndcBounds ) ) {
456 return false;
457 }
458
459 shader = drawSurf->material;
460
461 // never recurse through a subview surface that we are
462 // already seeing through
463 for ( parms = tr.viewDef ; parms ; parms = parms->superView ) {
464 if ( parms->subviewSurface
465 && parms->subviewSurface->geo == drawSurf->geo
466 && parms->subviewSurface->space->entityDef == drawSurf->space->entityDef ) {
467 break;
468 }
469 }
470 if ( parms ) {
471 return false;
472 }
473
474 // crop the scissor bounds based on the precise cull
475 idScreenRect scissor;
476
477 idScreenRect *v = &tr.viewDef->viewport;
478 scissor.x1 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[0][0] + 1.0f ));
479 scissor.y1 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[0][1] + 1.0f ));
480 scissor.x2 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[1][0] + 1.0f ));
481 scissor.y2 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[1][1] + 1.0f ));
482
483 // nudge a bit for safety
484 scissor.Expand();
485
486 scissor.Intersect( tr.viewDef->scissor );
487
488 if ( scissor.IsEmpty() ) {
489 // cropped out
490 return false;
491 }
492
493 // see what kind of subview we are making
494 if ( shader->GetSort() != SS_SUBVIEW ) {
495 for ( int i = 0 ; i < shader->GetNumStages() ; i++ ) {
496 const shaderStage_t *stage = shader->GetStage( i );
497 switch ( stage->texture.dynamic ) {
498 case DI_REMOTE_RENDER:
499 R_RemoteRender( drawSurf, const_cast<textureStage_t *>(&stage->texture) );
500 break;
501 case DI_MIRROR_RENDER:
502 R_MirrorRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor );
503 break;
504 case DI_XRAY_RENDER:
505 R_XrayRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor );
506 break;
507 }
508 }
509 return true;
510 }
511
512 // issue a new view command
513 parms = R_MirrorViewBySurface( drawSurf );
514 if ( !parms ) {
515 return false;
516 }
517
518 parms->scissor = scissor;
519 parms->superView = tr.viewDef;
520 parms->subviewSurface = drawSurf;
521
522 // triangle culling order changes with mirroring
523 parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
524
525 // generate render commands for it
526 R_RenderView( parms );
527
528 return true;
529 }
530
531 /*
532 ================
533 R_GenerateSubViews
534
535 If we need to render another view to complete the current view,
536 generate it first.
537
538 It is important to do this after all drawSurfs for the current
539 view have been generated, because it may create a subview which
540 would change tr.viewCount.
541 ================
542 */
R_GenerateSubViews(void)543 bool R_GenerateSubViews( void ) {
544 drawSurf_t *drawSurf;
545 int i;
546 bool subviews;
547 const idMaterial *shader;
548
549 // for testing the performance hit
550 if ( r_skipSubviews.GetBool() ) {
551 return false;
552 }
553
554 subviews = false;
555
556 // scan the surfaces until we either find a subview, or determine
557 // there are no more subview surfaces.
558 for ( i = 0 ; i < tr.viewDef->numDrawSurfs ; i++ ) {
559 drawSurf = tr.viewDef->drawSurfs[i];
560 shader = drawSurf->material;
561
562 if ( !shader || !shader->HasSubview() ) {
563 continue;
564 }
565
566 if ( R_GenerateSurfaceSubview( drawSurf ) ) {
567 subviews = true;
568 }
569 }
570
571 return subviews;
572 }
573