// returns surfID SurfaceHandle_t RecursiveLightPoint (mnode_t *node, float start, float end, Vector& c, LightVecState_t& state ) { // didn't hit anything if (node->contents >= 0) { // FIXME: Should we always do this? It could get expensive... // Check all the faces at the leaves return FindIntersectionSurfaceAtLeaf( (mleaf_t*)node, start, end, c, state ); } // Determine which side of the node plane our points are on // FIXME: optimize for axial cplane_t* plane = node->plane; float startDotN = DotProduct( state.m_Ray.m_Start, plane->normal ); float deltaDotN = DotProduct( state.m_Ray.m_Delta, plane->normal ); float front = startDotN + start * deltaDotN - plane->dist; float back = startDotN + end * deltaDotN - plane->dist; int side = front < 0; // If they're both on the same side of the plane, don't bother to split // just check the appropriate child SurfaceHandle_t surfID; if ( (back < 0) == side ) { surfID = RecursiveLightPoint (node->children[side], start, end, c, state); return surfID; } // calculate mid point float frac = front / (front-back); float mid = start * (1.0f - frac) + end * frac; // go down front side surfID = RecursiveLightPoint (node->children[side], start, mid, c, state ); if ( IS_SURF_VALID( surfID ) ) return surfID; // hit something // check for impact on this node surfID = FindIntersectionSurfaceAtNode( node, mid, c, state ); if ( IS_SURF_VALID( surfID ) ) return surfID; // go down back side surfID = RecursiveLightPoint (node->children[!side], mid, end, c, state ); return surfID; }
void CDispInfo::AddDynamicLights( Vector4D *blocklight ) { #ifndef SWDS if( !IS_SURF_VALID( m_ParentSurfID ) ) { Assert( !"CDispInfo::AddDynamicLights: no parent surface" ); return; } for( int lnum=0 ; lnum<MAX_DLIGHTS ; lnum++ ) { // If the light's not active, then continue if ( (r_dlightactive & (1 << lnum)) == 0 ) continue; // not lit by this light if ( !(MSurf_DLightBits( m_ParentSurfID ) & (1<<lnum) ) ) continue; // This light doesn't affect the world if ( cl_dlights[lnum].flags & DLIGHT_NO_WORLD_ILLUMINATION) continue; if ( (cl_dlights[lnum].flags & DLIGHT_DISPLACEMENT_MASK) == 0) { AddSingleDynamicLight( cl_dlights[lnum], blocklight ); } else { AddSingleDynamicAlphaLight( cl_dlights[lnum], blocklight ); } } #endif }
// returns light in range from 0 to 1. colorVec R_LightPoint (Vector& p) { SurfaceHandle_t surfID; Vector end; colorVec c; Vector color; end[0] = p[0]; end[1] = p[1]; end[2] = p[2] - 2048; surfID = R_LightVec( p, end, true, color ); if( IS_SURF_VALID( surfID ) ) { c.r = LinearToScreenGamma( color[0] ) * 255; c.g = LinearToScreenGamma( color[1] ) * 255; c.b = LinearToScreenGamma( color[2] ) * 255; c.a = 1; } else { c.r = c.g = c.b = c.a = 0; } return c; }
//----------------------------------------------------------------------------- // returns light in range from 0 to 1. // lightmapS/T is in [0,1] within the space of the surface. // returns surfID //----------------------------------------------------------------------------- SurfaceHandle_t R_LightVec (const Vector& start, const Vector& end, bool bUseLightStyles, Vector& c, float *textureS, float *textureT, float *lightmapS, float *lightmapT ) { VPROF_INCREMENT_COUNTER( "R_LightVec", 1 ); SurfaceHandle_t retSurfID; SurfaceHandle_t dispSurfID; // We're using the vis frame here for lightvec tests // to make sure we test each displacement only once ++r_surfacevisframe; LightVecState_t state; state.m_HitFrac = 1.0f; state.m_Ray.Init( start, end ); state.m_pTextureS = textureS; state.m_pTextureT = textureT; state.m_pLightmapS = lightmapS; state.m_pLightmapT = lightmapT; state.m_nSkySurfID = SURFACE_HANDLE_INVALID; state.m_bUseLightStyles = bUseLightStyles; c[0] = c[1] = c[2] = 0.0f; model_t* model = s_pLightVecModel ? s_pLightVecModel : host_state.worldmodel; retSurfID = RecursiveLightPoint(&model->brush.pShared->nodes[model->brush.firstnode], 0.0f, 1.0f, c, state ); // While doing recursive light point, we built a list of all // displacement surfaces which we need to test, so let's test them dispSurfID = R_LightVecDisplacementChain( state, bUseLightStyles, c ); if( r_visualizelighttraces.GetBool() ) { if( r_visualizelighttracesshowfulltrace.GetBool() ) { CDebugOverlay::AddLineOverlay( start, end, 0, 255, 0, 255, true, -1.0f ); } else { CDebugOverlay::AddLineOverlay( start, start + ( end - start ) * state.m_HitFrac, 0, 255, 0, 255, true, -1.0f ); } } if ( IS_SURF_VALID( dispSurfID ) ) retSurfID = dispSurfID; // ConMsg( "R_LightVec: %f %f %f\n", c[0], c[1], c[2] ); // If we didn't hit anything else, but we hit a sky surface at // some point along the ray cast, return the sky id. if ( ( retSurfID == SURFACE_HANDLE_INVALID ) && ( state.m_nSkySurfID != SURFACE_HANDLE_INVALID ) ) return state.m_nSkySurfID; return retSurfID; }
//----------------------------------------------------------------------------- // A method to get the material color + texture coordinate //----------------------------------------------------------------------------- IMaterial* BrushModel_GetLightingAndMaterial( const Vector &start, const Vector &end, Vector &diffuseLightColor, Vector &baseColor) { float textureS, textureT; IMaterial *material; int surfID = R_LightVec( start, end, true, diffuseLightColor, &textureS, &textureT ); if( !IS_SURF_VALID( surfID ) || !MSurf_TexInfo( surfID ) ) { // Con_Printf( "didn't hit anything\n" ); return 0; } else { material = MSurf_TexInfo( surfID )->material; material->GetLowResColorSample( textureS, textureT, baseColor.Base() ); // Con_Printf( "%s: diff: %f %f %f base: %f %f %f\n", material->GetName(), diffuseLightColor[0], diffuseLightColor[1], diffuseLightColor[2], baseColor[0], baseColor[1], baseColor[2] ); return material; } }
//----------------------------------------------------------------------------- // returns light in range from 0 to 1. // lightmapS/T is in [0,1] within the space of the surface. // returns surfID //----------------------------------------------------------------------------- int R_LightVec (const Vector& start, const Vector& end, bool bUseLightStyles, Vector& c, float *textureS, float *textureT, float *lightmapS, float *lightmapT ) { int retSurfID; int dispSurfID; // We're using the vis frame here for lightvec tests // to make sure we test each displacement only once ++r_surfacevisframe; LightVecState_t state; state.m_HitFrac = 1.0f; state.m_Ray.Init( start, end ); state.m_pTextureS = textureS; state.m_pTextureT = textureT; state.m_pLightmapS = lightmapS; state.m_pLightmapT = lightmapT; state.m_nSkySurfID = -1; state.m_bUseLightStyles = bUseLightStyles; c[0] = c[1] = c[2] = 0.0f; model_t* model = s_pLightVecModel ? s_pLightVecModel : host_state.worldmodel; retSurfID = RecursiveLightPoint(&model->brush.nodes[model->brush.firstnode], 0.0f, 1.0f, c, state ); // While doing recursive light point, we built a list of all // displacement surfaces which we need to test, so let's test them dispSurfID = R_LightVecDisplacementChain( state, bUseLightStyles, c ); if ( IS_SURF_VALID( dispSurfID ) ) retSurfID = dispSurfID; // Con_Printf( "R_LightVec: %f %f %f\n", c[0], c[1], c[2] ); // If we didn't hit anything else, but we hit a sky surface at // some point along the ray cast, return the sky id. if ( ( retSurfID == -1 ) && ( state.m_nSkySurfID != -1 ) ) return state.m_nSkySurfID; return retSurfID; }