// Returns qtrue if another view has been rendered qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { vector4 clipDest[128]; viewParms_t newParms; viewParms_t oldParms; orientation_t surface, camera; // don't recursively mirror if (tr.viewParms.isPortal) { ri->Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); return qfalse; } if ( r_noportals->integer || (r_fastsky->integer == 1) ) { return qfalse; } // trivially reject portal/mirror if ( SurfIsOffscreen( drawSurf, clipDest ) ) { return qfalse; } // save old viewParms so we can return to it after the mirror view oldParms = tr.viewParms; newParms = tr.viewParms; newParms.isPortal = qtrue; if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, &newParms.pvsOrigin, &newParms.isMirror ) ) { return qfalse; // bad portal, no portalentity } R_MirrorPoint (&oldParms.or.origin, &surface, &camera, &newParms.or.origin ); VectorSubtract( &vec3_origin, &camera.axis[0], &newParms.portalPlane.normal ); newParms.portalPlane.dist = DotProduct( &camera.origin, &newParms.portalPlane.normal ); R_MirrorVector (&oldParms.or.axis[0], &surface, &camera, &newParms.or.axis[0]); R_MirrorVector (&oldParms.or.axis[1], &surface, &camera, &newParms.or.axis[1]); R_MirrorVector (&oldParms.or.axis[2], &surface, &camera, &newParms.or.axis[2]); // OPTIMIZE: restrict the viewport on the mirrored view // render the mirror view R_RenderView (&newParms); tr.viewParms = oldParms; return qtrue; }
/* ======================== R_MirrorViewBySurface ======================== */ static viewDef_t *R_MirrorViewBySurface( drawSurf_t *drawSurf ) { viewDef_t *parms; orientation_t surface, camera; idPlane originalPlane, plane; // copy the viewport size from the original parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) ); *parms = *tr.viewDef; parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons parms->isSubview = true; parms->isMirror = true; // create plane axis for the portal we are seeing R_PlaneForSurface( drawSurf->geo, originalPlane ); R_LocalPlaneToGlobal( drawSurf->space->modelMatrix, originalPlane, plane ); surface.origin = plane.Normal() * -plane[3]; surface.axis[0] = plane.Normal(); surface.axis[0].NormalVectors( surface.axis[1], surface.axis[2] ); surface.axis[2] = -surface.axis[2]; camera.origin = surface.origin; camera.axis[0] = -surface.axis[0]; camera.axis[1] = surface.axis[1]; camera.axis[2] = surface.axis[2]; // set the mirrored origin and axis R_MirrorPoint( tr.viewDef->renderView.vieworg, &surface, &camera, parms->renderView.vieworg ); R_MirrorVector( tr.viewDef->renderView.viewaxis[0], &surface, &camera, parms->renderView.viewaxis[0] ); R_MirrorVector( tr.viewDef->renderView.viewaxis[1], &surface, &camera, parms->renderView.viewaxis[1] ); R_MirrorVector( tr.viewDef->renderView.viewaxis[2], &surface, &camera, parms->renderView.viewaxis[2] ); // make the view origin 16 units away from the center of the surface idVec3 viewOrigin = ( drawSurf->geo->bounds[0] + drawSurf->geo->bounds[1] ) * 0.5; viewOrigin += ( originalPlane.Normal() * 16 ); R_LocalPointToGlobal( drawSurf->space->modelMatrix, viewOrigin, parms->initialViewAreaOrigin ); // set the mirror clip plane parms->numClipPlanes = 1; parms->clipPlanes[0] = -camera.axis[0]; parms->clipPlanes[0][3] = -( camera.origin * parms->clipPlanes[0].Normal() ); return parms; }
/* ======================== R_DoWaterView Returns qtrue if another view has been rendered ======================== */ qboolean R_DoWaterView (drawSurf_t *drawSurf, int entityNum) { // vec4_t clipDest[128]; viewParms_t newParms; viewParms_t oldParms; orientation_t surface, camera; cplane_t plane; srfSurfaceStatic_t *srf; // don't recursively do water if (tr.viewParms.doWater) { // tesselated water has this issue - so we just ignore and not spam console // ri.Printf( PRINT_DEVELOPER, "WARNING: recursive water found\n" ); return qfalse; } srf = (srfSurfaceStatic_t *)drawSurf->surface; // trivially reject portal/mirror //This wont work because vbo surfs dont fill out tess... //if ( SurfIsOffscreen( drawSurf, clipDest ) ) { // return qfalse; //} //Set plane tr.viewParms.doWater = qtrue; tr.viewParms.waterPlane.normal[0] = 0; tr.viewParms.waterPlane.normal[1] = 0; tr.viewParms.waterPlane.normal[2] = -1; tr.viewParms.waterPlane.dist = srf->origin[2]; if ( DotProduct(tr.viewParms.waterPlane.normal,tr.viewParms.or.origin)+tr.viewParms.waterPlane.dist >0) { tr.viewParms.isUnderwater=qtrue; } // save old viewParms so we can return to it after the mirror view oldParms = tr.viewParms; newParms = tr.viewParms; newParms.isWater = 1; newParms.viewportWidth=WATER_RES_X; newParms.viewportHeight=WATER_RES_Y; newParms.viewportX =0;//tr.refdef.x; newParms.viewportY =0;// glConfig.vidHeight - ( tr.refdef.y + WATER_RES_Y ); tr.refdef.rdflags|= RDF_NOEFFECTS ; // render the mirror view R_RenderView (&newParms); //Do the second view now newParms = tr.viewParms; newParms.isWater = 2; newParms.isMirror = qtrue; newParms.viewportWidth = WATER_RES_X; newParms.viewportHeight = WATER_RES_Y; newParms.viewportX = 0;//tr.refdef.x; newParms.viewportY = 0;//glConfig.vidHeight - ( tr.refdef.y + WATER_RES_Y ); plane.dist=tr.viewParms.waterPlane.dist; plane.normal[0]=-tr.viewParms.waterPlane.normal[0]; plane.normal[1]=-tr.viewParms.waterPlane.normal[1]; plane.normal[2]=-tr.viewParms.waterPlane.normal[2]; R_GetSurfaceOrientations( &plane, &surface, &camera ); R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); // render the mirror view tr.refdef.rdflags|= RDF_NOEFFECTS; R_RenderView (&newParms); tr.viewParms = oldParms; tr.refdef.rdflags&= ~RDF_NOEFFECTS; return qtrue; }
/* ======================== R_MirrorViewBySurface ======================== */ static viewDef_t* R_MirrorViewBySurface( const drawSurf_t* drawSurf ) { // copy the viewport size from the original viewDef_t* parms = ( viewDef_t* )R_FrameAlloc( sizeof( *parms ) ); *parms = *tr.viewDef; parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons parms->isSubview = true; parms->isMirror = true; parms->isObliqueProjection = false; // create plane axis for the portal we are seeing idPlane originalPlane, plane; R_PlaneForSurface( drawSurf->frontEndGeo, originalPlane ); R_LocalPlaneToGlobal( drawSurf->space->modelMatrix, originalPlane, plane ); orientation_t surface; surface.origin = plane.Normal() * -plane[3]; surface.axis[0] = plane.Normal(); surface.axis[0].NormalVectors( surface.axis[1], surface.axis[2] ); surface.axis[2] = -surface.axis[2]; orientation_t camera; camera.origin = surface.origin; camera.axis[0] = -surface.axis[0]; camera.axis[1] = surface.axis[1]; camera.axis[2] = surface.axis[2]; // set the mirrored origin and axis R_MirrorPoint( tr.viewDef->renderView.vieworg, &surface, &camera, parms->renderView.vieworg ); R_MirrorVector( tr.viewDef->renderView.viewaxis[0], &surface, &camera, parms->renderView.viewaxis[0] ); R_MirrorVector( tr.viewDef->renderView.viewaxis[1], &surface, &camera, parms->renderView.viewaxis[1] ); R_MirrorVector( tr.viewDef->renderView.viewaxis[2], &surface, &camera, parms->renderView.viewaxis[2] ); // make the view origin 16 units away from the center of the surface const idVec3 center = (drawSurf->frontEndGeo->bounds[0] + drawSurf->frontEndGeo->bounds[1]) * 0.5f; const idVec3 viewOrigin = center + (originalPlane.Normal() * 16.0f); R_LocalPointToGlobal(drawSurf->space->modelMatrix, viewOrigin, parms->initialViewAreaOrigin); // set the mirror clip plane parms->numClipPlanes = 1; parms->clipPlanes[0] = -camera.axis[0]; parms->clipPlanes[0][3] = -( camera.origin * parms->clipPlanes[0].Normal() ); if (r_waterReflectFix.GetBool() && !parms->is2Dgui && drawSurf->material->GetSurfaceType() == SURFTYPE_MIRROR) { parms->isObliqueProjection = true; float dist = parms->clipPlanes[0].Dist(); float viewdist = parms->renderView.vieworg * parms->clipPlanes[0].Normal(); float fDist = -dist + viewdist; static const float fudge = 2.f; //fudge avoids depth precision artifacts when performing oblique projection if (fDist > fudge || fDist < -fudge) { if (fDist < 0.f) fDist += fudge; else fDist -= fudge; } parms->clipPlanes[0][3] = fDist; R_SetupViewMatrix(parms); R_SetupProjectionMatrix(parms); R_ObliqueProjection(parms); } return parms; }