/* ================= R_MirrorRender ================= */ void R_MirrorRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) { viewDef_t *parms; // remote views can be reused in a single frame if( stage->dynamicFrameCount == tr.frameCount ) { return; } // issue a new view command parms = R_MirrorViewBySurface( surf ); if( !parms ) { return; } tr.CropRenderSize( stage->width, stage->height, true ); parms->renderView.x = 0; parms->renderView.y = 0; parms->renderView.width = SCREEN_WIDTH; parms->renderView.height = SCREEN_HEIGHT; tr.RenderViewToViewport( &parms->renderView, &parms->viewport ); parms->scissor.x1 = 0; parms->scissor.y1 = 0; parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1; parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1; parms->superView = tr.viewDef; parms->subviewSurface = surf; // triangle culling order changes with mirroring parms->isMirror = ( ( ( int )parms->isMirror ^ ( int )tr.viewDef->isMirror ) != 0 ); // generate render commands for it R_RenderView( parms ); // copy this rendering to the image stage->dynamicFrameCount = tr.frameCount; stage->image = globalImages->scratchImage; tr.CaptureRenderToImage( stage->image->imgName ); tr.UnCrop(); }
/* ================== R_GenerateSurfaceSubview ================== */ bool R_GenerateSurfaceSubview( drawSurf_t *drawSurf ) { idBounds ndcBounds; viewDef_t *parms; const idMaterial *shader; // for testing the performance hit if ( r_skipSubviews.GetBool() ) { return false; } if ( R_PreciseCullSurface( drawSurf, ndcBounds ) ) { return false; } shader = drawSurf->material; // never recurse through a subview surface that we are // already seeing through for ( parms = tr.viewDef ; parms ; parms = parms->superView ) { if ( parms->subviewSurface && parms->subviewSurface->geo == drawSurf->geo && parms->subviewSurface->space->entityDef == drawSurf->space->entityDef ) { break; } } if ( parms ) { return false; } // crop the scissor bounds based on the precise cull idScreenRect scissor; idScreenRect *v = &tr.viewDef->viewport; scissor.x1 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[0][0] + 1.0f )); scissor.y1 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[0][1] + 1.0f )); scissor.x2 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[1][0] + 1.0f )); scissor.y2 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[1][1] + 1.0f )); // nudge a bit for safety scissor.Expand(); scissor.Intersect( tr.viewDef->scissor ); if ( scissor.IsEmpty() ) { // cropped out return false; } // see what kind of subview we are making if ( shader->GetSort() != SS_SUBVIEW ) { for ( int i = 0 ; i < shader->GetNumStages() ; i++ ) { const shaderStage_t *stage = shader->GetStage( i ); switch ( stage->texture.dynamic ) { case DI_REMOTE_RENDER: R_RemoteRender( drawSurf, const_cast<textureStage_t *>(&stage->texture) ); break; case DI_MIRROR_RENDER: R_MirrorRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor ); break; case DI_XRAY_RENDER: R_XrayRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor ); break; } } return true; } // issue a new view command parms = R_MirrorViewBySurface( drawSurf ); if ( !parms ) { return false; } parms->scissor = scissor; parms->superView = tr.viewDef; parms->subviewSurface = drawSurf; // triangle culling order changes with mirroring parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 ); // generate render commands for it R_RenderView( parms ); return true; }