int R_MarkLightsLeaf( dlight_t *light, int bit, mleaf_t *pLeaf ) { int countMarked = 0; for ( int i = 0; i < pLeaf->dispCount; i++ ) { IDispInfo *pDispInfo = MLeaf_Disaplcement( pLeaf, i ); SurfaceHandle_t parentSurfID = pDispInfo->GetParent(); if ( parentSurfID ) { // Don't redo all this work if we already hit this surface and decided it's lit by this light. msurfacelighting_t *pLighting = SurfaceLighting( parentSurfID ); if( !R_IsDLightAlreadyMarked( pLighting, bit) ) { // Do a different test for displacement surfaces. Vector bmin, bmax; MSurf_DispInfo( parentSurfID )->GetBoundingBox( bmin, bmax ); if ( IsBoxIntersectingSphere(bmin, bmax, light->origin, light->GetRadius()) ) { R_MarkSurfaceDLight( parentSurfID, pLighting, bit ); countMarked++; } } } } SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pLeaf->firstmarksurface]; for ( int i = 0; i < pLeaf->nummarksurfaces; i++ ) { SurfaceHandle_t surfID = pHandle[i]; ASSERT_SURF_VALID( surfID ); // only process leaf surfaces if ( MSurf_Flags( surfID ) & SURFDRAW_NODE ) continue; // Don't redo all this work if we already hit this surface and decided it's lit by this light. msurfacelighting_t *pLighting = SurfaceLighting( surfID ); if(R_IsDLightAlreadyMarked(pLighting, bit)) continue; float dist = DotProduct( light->origin, MSurf_Plane( surfID ).normal) - MSurf_Plane( surfID ).dist; if ( dist > light->GetRadius() || dist < -light->GetRadius() ) continue; countMarked += R_TryLightMarkSurface( light, pLighting, surfID, bit ); } return countMarked; }
void R_MarkLightsLeaf( dlight_t *light, int bit, mleaf_t *pLeaf ) { for( CDispIterator it=pLeaf->GetDispIterator(); it.IsValid(); ) { CDispLeafLink *pCur = it.Inc(); // get current displacement surface info IDispInfo *pDispInfo = static_cast<IDispInfo*>( pCur->m_pDispInfo ); int parentSurfID = pDispInfo->GetParent(); if ( parentSurfID ) { // Don't redo all this work if we already hit this surface and decided it's lit by this light. msurfacelighting_t *pLighting = SurfaceLighting( parentSurfID ); if( !R_IsDLightAlreadyMarked( pLighting, bit) ) { // Do a different test for displacement surfaces. Vector bmin, bmax; MSurf_DispInfo( parentSurfID )->GetBoundingBox( bmin, bmax ); if ( SphereToAABBIntersection( light->origin, light->radius, bmin, bmax ) ) { R_MarkSurfaceDLight( pLighting, bit ); } } } } for ( int i = 0; i < pLeaf->nummarksurfaces; i++ ) { int surfID = host_state.worldmodel->brush.marksurfaces[pLeaf->firstmarksurface + i]; ASSERT_SURF_VALID( surfID ); // only process leaf surfaces if ( MSurf_Flags( surfID ) & SURFDRAW_NODE ) continue; // Don't redo all this work if we already hit this surface and decided it's lit by this light. msurfacelighting_t *pLighting = SurfaceLighting( surfID ); if(R_IsDLightAlreadyMarked(pLighting, bit)) continue; float dist = DotProduct( light->origin, MSurf_Plane( surfID ).normal) - MSurf_Plane( surfID ).dist; if ( dist > light->radius || dist < -light->radius ) continue; R_TryLightMarkSurface( light, pLighting, surfID, bit ); } }
// ----------------------------------------------------------------------------- // // Add/remove decals // ----------------------------------------------------------------------------- // DispDecalHandle_t CDispInfo::NotifyAddDecal( decal_t *pDecal ) { // FIXME: Add decal retirement... // if( m_Decals.Size() < MAX_DISP_DECALS ) // return; // Create a new decal, link it in DispDecalHandle_t h = s_DispDecals.Alloc( true ); // When linking, insert it in sorted order based on material enumeration ID // This will help us when rendering later int last = DISP_DECAL_HANDLE_INVALID; int i = m_FirstDecal; int enumerationId = pDecal->material->GetEnumerationID(); while( i != s_DispDecals.InvalidIndex() ) { int testId = s_DispDecals[i].m_pDecal->material->GetEnumerationID(); if (enumerationId <= testId) break; last = i; i = s_DispDecals.Next(i); } // NOTE: when the list is used in multimode, we can't use LinkBefore( i, INVALID_INDEX ), // since the Head and Tail of the linked list are meaningless... if ( last != DISP_DECAL_HANDLE_INVALID ) s_DispDecals.LinkAfter( last, h ); else { s_DispDecals.LinkBefore( m_FirstDecal, h ); m_FirstDecal = h; } CDispDecal *pDispDecal = &s_DispDecals[h]; pDispDecal->m_pDecal = pDecal; pDispDecal->m_FirstFragment = DISP_DECAL_FRAGMENT_HANDLE_INVALID; pDispDecal->m_nVerts = 0; pDispDecal->m_nTris = 0; // Setup a basis for it. CDecalVert *pOutVerts = NULL; R_SetupDecalClip( pOutVerts, pDispDecal->m_pDecal, MSurf_Plane( m_ParentSurfID ).normal, pDispDecal->m_pDecal->material, pDispDecal->m_TextureSpaceBasis, pDispDecal->m_DecalWorldScale ); // Recurse and precalculate which nodes this thing can touch. SetupDecalNodeIntersect( m_pPowerInfo->m_RootNode, 0, // node bit index into CDispDecal::m_NodeIntersects pDispDecal, 0 ); return h; }
// returns surfID static int FASTCALL FindIntersectionSurfaceAtLeaf( mleaf_t *pLeaf, float start, float end, Vector& c, LightVecState_t& state ) { Vector pt; int closestSurfID = -1; // Adds displacements in the leaf to a list of displacements to test at the end AddDisplacementsInLeafToTestList( pLeaf, state ); // Add non-displacement surfaces // Since there's no BSP tree here, we gotta test *all* surfaces! (blech) for ( int i = 0; i < pLeaf->nummarksurfaces; i++ ) { int surfID = host_state.worldmodel->brush.marksurfaces[pLeaf->firstmarksurface + i]; ASSERT_SURF_VALID( surfID ); // Don't add surfaces that have displacement; they are handled above // In fact, don't even set the vis frame; we need it unset for translucent // displacement code if ( SurfaceHasDispInfo(surfID) ) continue; if ( MSurf_Flags( surfID ) & (SURFDRAW_NODE | SURFDRAW_NODRAW | SURFDRAW_WATERSURFACE) ) continue; cplane_t* pPlane = &MSurf_Plane( surfID ); // Backface cull... if (DotProduct( pPlane->normal, state.m_Ray.m_Delta ) > 0.f) continue; float startDotN = DotProduct( state.m_Ray.m_Start, pPlane->normal ); float deltaDotN = DotProduct( state.m_Ray.m_Delta, pPlane->normal ); float front = startDotN + start * deltaDotN - pPlane->dist; float back = startDotN + end * deltaDotN - pPlane->dist; int side = front < 0.f; // Blow it off if it doesn't split the plane... if ( (back < 0.f) == side ) continue; // Don't test a surface that is farther away from the closest found intersection float frac = front / (front-back); if (frac >= state.m_HitFrac) continue; float mid = start * (1.0f - frac) + end * frac; // Check this surface to see if there's an intersection if (FindIntersectionAtSurface( surfID, mid, c, state )) { closestSurfID = surfID; } } // Return the closest surface hit return closestSurfID; }
int R_TryLightMarkSurface( dlight_t *light, msurfacelighting_t *pLighting, SurfaceHandle_t surfID, int bit ) { // Make sure this light actually intersects the surface cache of the surfaces it hits mtexinfo_t *tex; // FIXME: No worky for brush models // Find the perpendicular distance to the surface we're lighting // NOTE: Allow some stuff that's slightly behind it because view models can get behind walls // FIXME: We should figure out a better way to deal with view models float perpDistSq = DotProduct (light->origin, MSurf_Plane( surfID ).normal) - MSurf_Plane( surfID ).dist; if (perpDistSq < DLIGHT_BEHIND_PLANE_DIST) return 0; perpDistSq *= perpDistSq; float flInPlaneRadiusSq = light->GetRadiusSquared() - perpDistSq; if (flInPlaneRadiusSq <= 0) return 0; tex = MSurf_TexInfo( surfID ); Vector2D mins, maxs; mins.Init( pLighting->m_LightmapMins[0], pLighting->m_LightmapMins[1] ); maxs.Init( mins.x + pLighting->m_LightmapExtents[0], mins.y + pLighting->m_LightmapExtents[1] ); // Project light center into texture coordinates Vector2D vecCircleCenter; vecCircleCenter.x = DotProduct (light->origin, tex->lightmapVecsLuxelsPerWorldUnits[0].AsVector3D()) + tex->lightmapVecsLuxelsPerWorldUnits[0][3]; vecCircleCenter.y = DotProduct (light->origin, tex->lightmapVecsLuxelsPerWorldUnits[1].AsVector3D()) + tex->lightmapVecsLuxelsPerWorldUnits[1][3]; // convert from world space to luxel space and convert to int float flInPlaneLuxelRadius = sqrtf( flInPlaneRadiusSq * tex->luxelsPerWorldUnit * tex->luxelsPerWorldUnit ); // Does the circle intersect the square? if ( !IsCircleIntersectingRectangle( mins, maxs, vecCircleCenter, flInPlaneLuxelRadius ) ) return 0; // Ok, mark the surface as using this light. R_MarkSurfaceDLight( surfID, pLighting, bit); return 1; }