/* ======================== 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_DeriveLightData Fills everything in based on light->parms ================= */ void R_DeriveLightData( idRenderLightLocal* light ) { // decide which light shader we are going to use if( light->parms.shader != NULL ) { light->lightShader = light->parms.shader; } else if( light->lightShader == NULL ) { if( light->parms.pointLight ) { light->lightShader = tr.defaultPointLight; } else { light->lightShader = tr.defaultProjectedLight; } } // get the falloff image light->falloffImage = light->lightShader->LightFalloffImage(); if( light->falloffImage == NULL ) { // use the falloff from the default shader of the correct type const idMaterial* defaultShader; if( light->parms.pointLight ) { defaultShader = tr.defaultPointLight; // Touch the default shader. to make sure it's decl has been parsed ( it might have been purged ). declManager->Touch( static_cast< const idDecl*>( defaultShader ) ); light->falloffImage = defaultShader->LightFalloffImage(); } else { // projected lights by default don't diminish with distance defaultShader = tr.defaultProjectedLight; // Touch the light shader. to make sure it's decl has been parsed ( it might have been purged ). declManager->Touch( static_cast< const idDecl*>( defaultShader ) ); light->falloffImage = defaultShader->LightFalloffImage(); } } // ------------------------------------ // compute the light projection matrix // ------------------------------------ idRenderMatrix localProject; float zScale = 1.0f; if( light->parms.parallel ) { zScale = R_ComputeParallelLightProjectionMatrix( light, localProject ); } else if( light->parms.pointLight ) { zScale = R_ComputePointLightProjectionMatrix( light, localProject ); } else { zScale = R_ComputeSpotLightProjectionMatrix( light, localProject ); } // set the old style light projection where Z and W are flipped and // for projected lights lightProject[3] is divided by ( zNear + zFar ) light->lightProject[0][0] = localProject[0][0]; light->lightProject[0][1] = localProject[0][1]; light->lightProject[0][2] = localProject[0][2]; light->lightProject[0][3] = localProject[0][3]; light->lightProject[1][0] = localProject[1][0]; light->lightProject[1][1] = localProject[1][1]; light->lightProject[1][2] = localProject[1][2]; light->lightProject[1][3] = localProject[1][3]; light->lightProject[2][0] = localProject[3][0]; light->lightProject[2][1] = localProject[3][1]; light->lightProject[2][2] = localProject[3][2]; light->lightProject[2][3] = localProject[3][3]; light->lightProject[3][0] = localProject[2][0] * zScale; light->lightProject[3][1] = localProject[2][1] * zScale; light->lightProject[3][2] = localProject[2][2] * zScale; light->lightProject[3][3] = localProject[2][3] * zScale; // transform the lightProject float lightTransform[16]; R_AxisToModelMatrix( light->parms.axis, light->parms.origin, lightTransform ); for( int i = 0; i < 4; i++ ) { idPlane temp = light->lightProject[i]; R_LocalPlaneToGlobal( lightTransform, temp, light->lightProject[i] ); } // adjust global light origin for off center projections and parallel projections // we are just faking parallel by making it a very far off center for now if( light->parms.parallel ) { idVec3 dir = light->parms.lightCenter; if( dir.Normalize() == 0.0f ) { // make point straight up if not specified dir[2] = 1.0f; } light->globalLightOrigin = light->parms.origin + dir * 100000.0f; } else { light->globalLightOrigin = light->parms.origin + light->parms.axis * light->parms.lightCenter; } // Rotate and translate the light projection by the light matrix. // 99% of lights remain axis aligned in world space. idRenderMatrix lightMatrix; idRenderMatrix::CreateFromOriginAxis( light->parms.origin, light->parms.axis, lightMatrix ); idRenderMatrix inverseLightMatrix; if( !idRenderMatrix::Inverse( lightMatrix, inverseLightMatrix ) ) { idLib::Warning( "lightMatrix invert failed" ); } // 'baseLightProject' goes from global space -> light local space -> light projective space idRenderMatrix::Multiply( localProject, inverseLightMatrix, light->baseLightProject ); // Invert the light projection so we can deform zero-to-one cubes into // the light model and calculate global bounds. if( !idRenderMatrix::Inverse( light->baseLightProject, light->inverseBaseLightProject ) ) { idLib::Warning( "baseLightProject invert failed" ); } // calculate the global light bounds by inverse projecting the zero to one cube with the 'inverseBaseLightProject' idRenderMatrix::ProjectedBounds( light->globalLightBounds, light->inverseBaseLightProject, bounds_zeroOneCube, false ); }
/* ======================== 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; }