2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
46 static void R_MirrorPoint( const idVec3 in, orientation_t *surface, orientation_t *camera, idVec3 &out ) {
52 local = in - surface->origin;
54 transformed = vec3_origin;
55 for ( i = 0 ; i < 3 ; i++ ) {
56 d = local * surface->axis[i];
57 transformed += d * camera->axis[i];
60 out = transformed + camera->origin;
68 static void R_MirrorVector( const idVec3 in, orientation_t *surface, orientation_t *camera, idVec3 &out ) {
73 for ( i = 0 ; i < 3 ; i++ ) {
74 d = in * surface->axis[i];
75 out += d * camera->axis[i];
83 Returns the plane for the first triangle in the surface
84 FIXME: check for degenerate triangle?
87 static void R_PlaneForSurface( const srfTriangles_t *tri, idPlane &plane ) {
88 idDrawVert *v1, *v2, *v3;
90 v1 = tri->verts + tri->indexes[0];
91 v2 = tri->verts + tri->indexes[1];
92 v3 = tri->verts + tri->indexes[2];
93 plane.FromPoints( v1->xyz, v2->xyz, v3->xyz );
97 =========================
100 Check the surface for visibility on a per-triangle basis
101 for cases when it is going to be VERY expensive to draw (subviews)
103 If not culled, also returns the bounding box of the surface in
104 Normalized Device Coordinates, so it can be used to crop the scissor rect.
106 OPTIMIZE: we could also take exact portal passing into consideration
107 =========================
109 bool R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds ) {
110 const srfTriangles_t *tri;
114 unsigned int pointOr;
115 unsigned int pointAnd;
122 pointAnd = (unsigned int)~0;
124 // get an exact bounds of the triangles for scissor cropping
127 for ( i = 0; i < tri->numVerts; i++ ) {
129 unsigned int pointFlags;
131 R_TransformModelToClip( tri->verts[i].xyz, drawSurf->space->modelViewMatrix,
132 tr.viewDef->projectionMatrix, eye, clip );
135 for ( j = 0; j < 3; j++ ) {
136 if ( clip[j] >= clip[3] ) {
137 pointFlags |= (1 << (j*2));
138 } else if ( clip[j] <= -clip[3] ) {
139 pointFlags |= ( 1 << (j*2+1));
143 pointAnd &= pointFlags;
144 pointOr |= pointFlags;
152 // backface and frustum cull
153 numTriangles = tri->numIndexes / 3;
155 R_GlobalPointToLocal( drawSurf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView );
157 for ( i = 0; i < tri->numIndexes; i += 3 ) {
162 const idVec3 &v1 = tri->verts[tri->indexes[i]].xyz;
163 const idVec3 &v2 = tri->verts[tri->indexes[i+1]].xyz;
164 const idVec3 &v3 = tri->verts[tri->indexes[i+2]].xyz;
166 // this is a hack, because R_GlobalPointToLocal doesn't work with the non-normalized
167 // axis that we get from the gui view transform. It doesn't hurt anything, because
168 // we know that all gui generated surfaces are front facing
169 if ( tr.guiRecursionLevel == 0 ) {
170 // we don't care that it isn't normalized,
171 // all we want is the sign
174 normal = d2.Cross( d1 );
176 dir = v1 - localView;
184 // now find the exact screen bounds of the clipped triangle
186 R_LocalPointToGlobal( drawSurf->space->modelMatrix, v1, w[0].ToVec3() );
187 R_LocalPointToGlobal( drawSurf->space->modelMatrix, v2, w[1].ToVec3() );
188 R_LocalPointToGlobal( drawSurf->space->modelMatrix, v3, w[2].ToVec3() );
189 w[0].s = w[0].t = w[1].s = w[1].t = w[2].s = w[2].t = 0.0f;
191 for ( j = 0; j < 4; j++ ) {
192 if ( !w.ClipInPlace( -tr.viewDef->frustum[j], 0.1f ) ) {
196 for ( j = 0; j < w.GetNumPoints(); j++ ) {
199 R_GlobalToNormalizedDeviceCoordinates( w[j].ToVec3(), screen );
200 ndcBounds.AddPoint( screen );
204 // if we don't enclose any area, return
205 if ( ndcBounds.IsCleared() ) {
213 ========================
214 R_MirrorViewBySurface
215 ========================
217 static viewDef_t *R_MirrorViewBySurface( drawSurf_t *drawSurf ) {
219 orientation_t surface, camera;
220 idPlane originalPlane, plane;
222 // copy the viewport size from the original
223 parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
224 *parms = *tr.viewDef;
225 parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
227 parms->isSubview = true;
228 parms->isMirror = true;
230 // create plane axis for the portal we are seeing
231 R_PlaneForSurface( drawSurf->geo, originalPlane );
232 R_LocalPlaneToGlobal( drawSurf->space->modelMatrix, originalPlane, plane );
234 surface.origin = plane.Normal() * -plane[3];
235 surface.axis[0] = plane.Normal();
236 surface.axis[0].NormalVectors( surface.axis[1], surface.axis[2] );
237 surface.axis[2] = -surface.axis[2];
239 camera.origin = surface.origin;
240 camera.axis[0] = -surface.axis[0];
241 camera.axis[1] = surface.axis[1];
242 camera.axis[2] = surface.axis[2];
244 // set the mirrored origin and axis
245 R_MirrorPoint( tr.viewDef->renderView.vieworg, &surface, &camera, parms->renderView.vieworg );
247 R_MirrorVector( tr.viewDef->renderView.viewaxis[0], &surface, &camera, parms->renderView.viewaxis[0] );
248 R_MirrorVector( tr.viewDef->renderView.viewaxis[1], &surface, &camera, parms->renderView.viewaxis[1] );
249 R_MirrorVector( tr.viewDef->renderView.viewaxis[2], &surface, &camera, parms->renderView.viewaxis[2] );
251 // make the view origin 16 units away from the center of the surface
252 idVec3 viewOrigin = ( drawSurf->geo->bounds[0] + drawSurf->geo->bounds[1] ) * 0.5;
253 viewOrigin += ( originalPlane.Normal() * 16 );
255 R_LocalPointToGlobal( drawSurf->space->modelMatrix, viewOrigin, parms->initialViewAreaOrigin );
257 // set the mirror clip plane
258 parms->numClipPlanes = 1;
259 parms->clipPlanes[0] = -camera.axis[0];
261 parms->clipPlanes[0][3] = -( camera.origin * parms->clipPlanes[0].Normal() );
267 ========================
269 ========================
271 static viewDef_t *R_XrayViewBySurface( drawSurf_t *drawSurf ) {
273 orientation_t surface, camera;
274 idPlane originalPlane, plane;
276 // copy the viewport size from the original
277 parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
278 *parms = *tr.viewDef;
279 parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
281 parms->isSubview = true;
282 parms->isXraySubview = true;
292 static void R_RemoteRender( drawSurf_t *surf, textureStage_t *stage ) {
295 // remote views can be reused in a single frame
296 if ( stage->dynamicFrameCount == tr.frameCount ) {
300 // if the entity doesn't have a remoteRenderView, do nothing
301 if ( !surf->space->entityDef->parms.remoteRenderView ) {
305 // copy the viewport size from the original
306 parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
307 *parms = *tr.viewDef;
309 parms->isSubview = true;
310 parms->isMirror = false;
312 parms->renderView = *surf->space->entityDef->parms.remoteRenderView;
313 parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
314 parms->initialViewAreaOrigin = parms->renderView.vieworg;
316 tr.CropRenderSize( stage->width, stage->height, true );
318 parms->renderView.x = 0;
319 parms->renderView.y = 0;
320 parms->renderView.width = SCREEN_WIDTH;
321 parms->renderView.height = SCREEN_HEIGHT;
323 tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
325 parms->scissor.x1 = 0;
326 parms->scissor.y1 = 0;
327 parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
328 parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
330 parms->superView = tr.viewDef;
331 parms->subviewSurface = surf;
333 // generate render commands for it
336 // copy this rendering to the image
337 stage->dynamicFrameCount = tr.frameCount;
339 stage->image = globalImages->scratchImage;
342 tr.CaptureRenderToImage( stage->image->imgName );
351 void R_MirrorRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) {
354 // remote views can be reused in a single frame
355 if ( stage->dynamicFrameCount == tr.frameCount ) {
359 // issue a new view command
360 parms = R_MirrorViewBySurface( surf );
365 tr.CropRenderSize( stage->width, stage->height, true );
367 parms->renderView.x = 0;
368 parms->renderView.y = 0;
369 parms->renderView.width = SCREEN_WIDTH;
370 parms->renderView.height = SCREEN_HEIGHT;
372 tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
374 parms->scissor.x1 = 0;
375 parms->scissor.y1 = 0;
376 parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
377 parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
379 parms->superView = tr.viewDef;
380 parms->subviewSurface = surf;
382 // triangle culling order changes with mirroring
383 parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
385 // generate render commands for it
386 R_RenderView( parms );
388 // copy this rendering to the image
389 stage->dynamicFrameCount = tr.frameCount;
390 stage->image = globalImages->scratchImage;
392 tr.CaptureRenderToImage( stage->image->imgName );
401 void R_XrayRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) {
404 // remote views can be reused in a single frame
405 if ( stage->dynamicFrameCount == tr.frameCount ) {
409 // issue a new view command
410 parms = R_XrayViewBySurface( surf );
415 tr.CropRenderSize( stage->width, stage->height, true );
417 parms->renderView.x = 0;
418 parms->renderView.y = 0;
419 parms->renderView.width = SCREEN_WIDTH;
420 parms->renderView.height = SCREEN_HEIGHT;
422 tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
424 parms->scissor.x1 = 0;
425 parms->scissor.y1 = 0;
426 parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
427 parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
429 parms->superView = tr.viewDef;
430 parms->subviewSurface = surf;
432 // triangle culling order changes with mirroring
433 parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
435 // generate render commands for it
436 R_RenderView( parms );
438 // copy this rendering to the image
439 stage->dynamicFrameCount = tr.frameCount;
440 stage->image = globalImages->scratchImage2;
442 tr.CaptureRenderToImage( stage->image->imgName );
448 R_GenerateSurfaceSubview
451 bool R_GenerateSurfaceSubview( drawSurf_t *drawSurf ) {
454 const idMaterial *shader;
456 // for testing the performance hit
457 if ( r_skipSubviews.GetBool() ) {
461 if ( R_PreciseCullSurface( drawSurf, ndcBounds ) ) {
465 shader = drawSurf->material;
467 // never recurse through a subview surface that we are
468 // already seeing through
469 for ( parms = tr.viewDef ; parms ; parms = parms->superView ) {
470 if ( parms->subviewSurface
471 && parms->subviewSurface->geo == drawSurf->geo
472 && parms->subviewSurface->space->entityDef == drawSurf->space->entityDef ) {
480 // crop the scissor bounds based on the precise cull
481 idScreenRect scissor;
483 idScreenRect *v = &tr.viewDef->viewport;
484 scissor.x1 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[0][0] + 1.0f ));
485 scissor.y1 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[0][1] + 1.0f ));
486 scissor.x2 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[1][0] + 1.0f ));
487 scissor.y2 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[1][1] + 1.0f ));
489 // nudge a bit for safety
492 scissor.Intersect( tr.viewDef->scissor );
494 if ( scissor.IsEmpty() ) {
499 // see what kind of subview we are making
500 if ( shader->GetSort() != SS_SUBVIEW ) {
501 for ( int i = 0 ; i < shader->GetNumStages() ; i++ ) {
502 const shaderStage_t *stage = shader->GetStage( i );
503 switch ( stage->texture.dynamic ) {
504 case DI_REMOTE_RENDER:
505 R_RemoteRender( drawSurf, const_cast<textureStage_t *>(&stage->texture) );
507 case DI_MIRROR_RENDER:
508 R_MirrorRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor );
511 R_XrayRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor );
518 // issue a new view command
519 parms = R_MirrorViewBySurface( drawSurf );
524 parms->scissor = scissor;
525 parms->superView = tr.viewDef;
526 parms->subviewSurface = drawSurf;
528 // triangle culling order changes with mirroring
529 parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
531 // generate render commands for it
532 R_RenderView( parms );
541 If we need to render another view to complete the current view,
544 It is important to do this after all drawSurfs for the current
545 view have been generated, because it may create a subview which
546 would change tr.viewCount.
549 bool R_GenerateSubViews( void ) {
550 drawSurf_t *drawSurf;
553 const idMaterial *shader;
555 // for testing the performance hit
556 if ( r_skipSubviews.GetBool() ) {
562 // scan the surfaces until we either find a subview, or determine
563 // there are no more subview surfaces.
564 for ( i = 0 ; i < tr.viewDef->numDrawSurfs ; i++ ) {
565 drawSurf = tr.viewDef->drawSurfs[i];
566 shader = drawSurf->material;
568 if ( !shader || !shader->HasSubview() ) {
572 if ( R_GenerateSurfaceSubview( drawSurf ) ) {