diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/debug_leafvis.cpp | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'engine/debug_leafvis.cpp')
| -rw-r--r-- | engine/debug_leafvis.cpp | 580 |
1 files changed, 580 insertions, 0 deletions
diff --git a/engine/debug_leafvis.cpp b/engine/debug_leafvis.cpp new file mode 100644 index 0000000..db6469f --- /dev/null +++ b/engine/debug_leafvis.cpp @@ -0,0 +1,580 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include "render_pch.h" +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Leaf visualization routines + +struct leafvis_t +{ + leafvis_t() + { + leafIndex = 0; + CCollisionBSPData *pBSP = GetCollisionBSPData(); + if ( pBSP ) + { + numbrushes = pBSP->numbrushes; + numentitychars = pBSP->numentitychars; + } + } + + bool IsValid() + { + CCollisionBSPData *pBSP = GetCollisionBSPData(); + if ( !pBSP || numbrushes != pBSP->numbrushes || numentitychars != pBSP->numentitychars ) + return false; + + return true; + } + + CUtlVector<Vector> verts; + CUtlVector<int> polyVertCount; + Vector color; + int numbrushes; + int numentitychars; + int leafIndex; +}; +const int MAX_LEAF_PVERTS = 128; + +// Only allocate this after it is turned on +leafvis_t *g_LeafVis = NULL; + +static void AddPlaneToList( CUtlVector<cplane_t> &list, const Vector& normal, float dist, int invert ) +{ + cplane_t plane; + plane.dist = invert ? -dist : dist; + plane.normal = invert ? -normal : normal; + + Vector point = plane.dist * plane.normal; + for ( int i = 0; i < list.Count(); i++ ) + { + // same plane, remove or replace + if ( list[i].normal == plane.normal ) + { + float d = DotProduct(point, list[i].normal) - list[i].dist; + if ( d > 0 ) + { + // new plane is in front of the old one + list[i].dist = plane.dist; + } + // new plane is behind the old one + return; + } + + } + list.AddToTail( plane ); +} + +static void PlaneList( int leafIndex, model_t *model, CUtlVector<cplane_t> &planeList ) +{ + if (!model || !model->brush.pShared || !model->brush.pShared->nodes) + Sys_Error ("PlaneList: bad model"); + + mleaf_t *pLeaf = &model->brush.pShared->leafs[leafIndex]; + mnode_t *pNode = pLeaf->parent; + mnode_t *pChild = (mnode_t *)pLeaf; + while (pNode) + { + // was the child on the front or back of the plane of this node? + bool front = (pNode->children[0] == pChild) ? true : false; + AddPlaneToList( planeList, pNode->plane->normal, pNode->plane->dist, !front ); + pChild = pNode; + pNode = pNode->parent; + } +} + +Vector CSGInsidePoint( cplane_t *pPlanes, int planeCount ) +{ + Vector point = vec3_origin; + + for ( int i = 0; i < planeCount; i++ ) + { + float d = DotProduct( pPlanes[i].normal, point ) - pPlanes[i].dist; + if ( d < 0 ) + { + point -= d * pPlanes[i].normal; + } + } + return point; +} + +void TranslatePlaneList( cplane_t *pPlanes, int planeCount, const Vector &offset ) +{ + for ( int i = 0; i < planeCount; i++ ) + { + pPlanes[i].dist += DotProduct( offset, pPlanes[i].normal ); + } +} + + +void CSGPlaneList( leafvis_t *pVis, CUtlVector<cplane_t> &planeList) +{ + int planeCount = planeList.Count(); + Vector vertsIn[MAX_LEAF_PVERTS], vertsOut[MAX_LEAF_PVERTS]; + + // compute a point inside the volume defined by these planes + Vector insidePoint = CSGInsidePoint( planeList.Base(), planeList.Count() ); + // move the planes so that the inside point is at the origin + // NOTE: This is to maximize precision for the CSG operations + TranslatePlaneList( planeList.Base(), planeList.Count(), -insidePoint ); + + // Build the CSG solid of this leaf given that the planes in the list define a convex solid + for ( int i = 0; i < planeCount; i++ ) + { + // Build a big-ass poly in this plane + int vertCount = PolyFromPlane( vertsIn, planeList[i].normal, planeList[i].dist ); // BaseWindingForPlane() + + // Now chop it by every other plane + int j; + for ( j = 0; j < planeCount; j++ ) + { + // don't clip planes with themselves + if ( i == j ) + continue; + + // Less than a poly left, something's wrong, don't bother with this polygon + if ( vertCount < 3 ) + continue; + + // Chop the polygon against this plane + vertCount = ClipPolyToPlane( vertsIn, vertCount, vertsOut, planeList[j].normal, planeList[j].dist ); + + // Just copy the verts each time, don't bother swapping pointers (efficiency is not a goal here) + for ( int k = 0; k < vertCount; k++ ) + { + VectorCopy( vertsOut[k], vertsIn[k] ); + } + } + + // We've got a polygon here + if ( vertCount >= 3 ) + { + // Copy polygon out + pVis->polyVertCount.AddToTail( vertCount ); + for ( j = 0; j < vertCount; j++ ) + { + // move the verts back by the initial translation + Vector vert = vertsIn[j] + insidePoint; + pVis->verts.AddToTail( vert ); + } + } + } +} + +void LeafvisChanged( IConVar *pLeafvisVar, const char *pOld, float flOldValue ) +{ + if ( g_LeafVis ) + { + delete g_LeafVis; + g_LeafVis = NULL; + } +} + +void AddLeafPortals( leafvis_t *pLeafvis, int leafIndex ) +{ + CUtlVector<cplane_t> planeList; + Vector normal; + + // Build a list of inward pointing planes of the tree descending to this + PlaneList( leafIndex, host_state.worldmodel, planeList ); + + VectorCopy( vec3_origin, normal ); + // Add world bounding box planes in case the world isn't closed + // x-axis + normal[0] = 1; + AddPlaneToList( planeList, normal, MAX_COORD_INTEGER, true ); + AddPlaneToList( planeList, normal, -MAX_COORD_INTEGER, false ); + normal[0] = 0; + + // y-axis + normal[1] = 1; + AddPlaneToList( planeList, normal, MAX_COORD_INTEGER, true ); + AddPlaneToList( planeList, normal, -MAX_COORD_INTEGER, false ); + normal[1] = 0; + + // z-axis + normal[2] = 1; + AddPlaneToList( planeList, normal, MAX_COORD_INTEGER, true ); + AddPlaneToList( planeList, normal, -MAX_COORD_INTEGER, false ); + CSGPlaneList( pLeafvis, planeList ); +} + +ConVar mat_leafvis("mat_leafvis","0", FCVAR_CHEAT, "Draw wireframe of current leaf", LeafvisChanged ); +ConVar r_visambient("r_visambient","0", 0, "Draw leaf ambient lighting samples. Needs mat_leafvis 1 to work" ); + +//----------------------------------------------------------------------------- +// Purpose: Builds a convex polyhedron of the leaf boundary around p +// Input : p - point to classify determining the leaf +//----------------------------------------------------------------------------- +void LeafVisBuild( const Vector &p ) +{ + if ( !mat_leafvis.GetInt() ) + { + Assert( !g_LeafVis ); + return; + } + else + { + static int last_leaf = -1; + + int leafIndex = CM_PointLeafnum( p ); + if ( g_LeafVis && last_leaf == leafIndex ) + return; + + DevMsg( 1, "Leaf %d, Area %d, Cluster %d\n", leafIndex, CM_LeafArea( leafIndex ), CM_LeafCluster( leafIndex ) ); + last_leaf = leafIndex; + + delete g_LeafVis; + g_LeafVis = new leafvis_t; + g_LeafVis->color.Init( 1.0f, 0.0f, 0.0f ); + g_LeafVis->leafIndex = leafIndex; + switch( mat_leafvis.GetInt() ) + { + case 2: + { + const mleaf_t *pLeaf = host_state.worldmodel->brush.pShared->leafs; + int leafCount = host_state.worldmodel->brush.pShared->numleafs; + int visCluster = pLeaf[leafIndex].cluster; + // do entire viscluster + for ( int i = 0; i < leafCount; i++ ) + { + if ( pLeaf[i].cluster == visCluster ) + { + AddLeafPortals( g_LeafVis, i ); + } + } + } + break; + case 3: + { + // do entire pvs + byte pvs[ MAX_MAP_LEAFS/8 ]; + const mleaf_t *pLeaf = host_state.worldmodel->brush.pShared->leafs; + int leafCount = host_state.worldmodel->brush.pShared->numleafs; + int visCluster = pLeaf[leafIndex].cluster; + CM_Vis( pvs, sizeof( pvs ), visCluster, DVIS_PVS ); + + for ( int i = 0; i < leafCount; i++ ) + { + int cluster = pLeaf[i].cluster; + if ( cluster >= 0 && (pvs[cluster>>3] & (1<<(cluster&7))) ) + { + AddLeafPortals( g_LeafVis, i ); + } + } + } + break; + case 0: + default: + AddLeafPortals( g_LeafVis, leafIndex ); + break; + } + } +} + + +#ifndef SWDS +void DrawLeafvis( leafvis_t *pVis ) +{ + CMatRenderContextPtr pRenderContext( materials ); + + int vert = 0; + g_materialLeafVisWireframe->ColorModulate( pVis->color[0], pVis->color[1], pVis->color[2] ); + pRenderContext->Bind( g_materialLeafVisWireframe ); + for ( int i = 0; i < pVis->polyVertCount.Count(); i++ ) + { + if ( pVis->polyVertCount[i] >= 3 ) + { + IMesh *pMesh = pRenderContext->GetDynamicMesh( ); + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_LINES, pVis->polyVertCount[i] ); + for ( int j = 0; j < pVis->polyVertCount[i]; j++ ) + { + meshBuilder.Position3fv( pVis->verts[ vert + j ].Base() ); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3fv( pVis->verts[ vert + ( ( j + 1 ) % pVis->polyVertCount[i] ) ].Base() ); + meshBuilder.AdvanceVertex(); + } + meshBuilder.End(); + pMesh->Draw(); + } + vert += pVis->polyVertCount[i]; + } +} + +void DrawLeafvis_Solid( leafvis_t *pVis ) +{ + CMatRenderContextPtr pRenderContext( materials ); + + int vert = 0; + + Vector lightNormal(1,1,1); + VectorNormalize(lightNormal); + pRenderContext->Bind( g_pMaterialDebugFlat ); + for ( int i = 0; i < pVis->polyVertCount.Count(); i++ ) + { + int vertCount = pVis->polyVertCount[i]; + if ( vertCount >= 3 ) + { + IMesh *pMesh = pRenderContext->GetDynamicMesh( ); + CMeshBuilder meshBuilder; + int triangleCount = vertCount-2; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, triangleCount ); + Vector e0 = pVis->verts[vert+1] - pVis->verts[vert]; + Vector e1 = pVis->verts[vert+2] - pVis->verts[vert]; + Vector normal = CrossProduct(e1,e0); + VectorNormalize( normal ); + float light = 0.5f + (DotProduct(normal, lightNormal)*0.5f); + Vector color = pVis->color * light; + + for ( int j = 0; j < vertCount; j++ ) + { + meshBuilder.Position3fv( pVis->verts[ vert + j ].Base() ); + meshBuilder.Color3fv( color.Base() ); + meshBuilder.AdvanceVertex(); + } + for ( int j = 0; j < triangleCount; j++ ) + { + meshBuilder.FastIndex(0); + meshBuilder.FastIndex(j+2); + meshBuilder.FastIndex(j+1); + } + meshBuilder.End(); + pMesh->Draw(); + } + vert += vertCount; + } +} + +leafvis_t *g_FrustumVis = NULL, *g_ClipVis[3] = {NULL,NULL,NULL}; + +int FindMinBrush( CCollisionBSPData *pBSPData, int nodenum, int brushIndex ) +{ + while (1) + { + if (nodenum < 0) + { + int leafIndex = -1 - nodenum; + cleaf_t &leaf = pBSPData->map_leafs[leafIndex]; + int firstbrush = pBSPData->map_leafbrushes[ leaf.firstleafbrush ]; + if ( firstbrush < brushIndex ) + { + brushIndex = firstbrush; + } + return brushIndex; + } + + cnode_t &node = pBSPData->map_rootnode[nodenum]; + brushIndex = FindMinBrush( pBSPData, node.children[0], brushIndex ); + nodenum = node.children[1]; + } + + return brushIndex; +} + +void RecomputeClipbrushes( bool bEnabled ) +{ + for ( int v = 0; v < 3; v++ ) + { + delete g_ClipVis[v]; + g_ClipVis[v] = NULL; + } + + if ( !bEnabled ) + return; + + for ( int v = 0; v < 3; v++ ) + { + int contents[3] = {CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP, CONTENTS_MONSTERCLIP, CONTENTS_PLAYERCLIP}; + g_ClipVis[v] = new leafvis_t; + g_ClipVis[v]->color.Init( v != 1 ? 1.0f : 0.5, 0.0f, v != 0 ? 1.0f : 0.0f ); + CCollisionBSPData *pBSP = GetCollisionBSPData(); + int lastBrush = pBSP->numbrushes; + if ( pBSP->numcmodels > 1 ) + { + lastBrush = FindMinBrush( pBSP, pBSP->map_cmodels[1].headnode, lastBrush ); + } + for ( int i = 0; i < lastBrush; i++ ) + { + cbrush_t *pBrush = &pBSP->map_brushes[i]; + if ( (pBrush->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP)) == contents[v] ) + { + CUtlVector<cplane_t> planeList; + if ( pBrush->IsBox() ) + { + cboxbrush_t *pBox = &pBSP->map_boxbrushes[pBrush->GetBox()]; + for ( int idxSide = 0; idxSide < 3; idxSide++ ) + { + Vector normal = vec3_origin; + normal[idxSide] = 1.0f; + AddPlaneToList( planeList, normal, pBox->maxs[idxSide], true ); + AddPlaneToList( planeList, -normal, -pBox->mins[idxSide], true ); + } + } + else + { + for ( int j = 0; j < pBrush->numsides; j++ ) + { + cbrushside_t *pSide = &pBSP->map_brushsides[pBrush->firstbrushside + j]; + if ( pSide->bBevel ) + continue; + AddPlaneToList( planeList, pSide->plane->normal, pSide->plane->dist, true ); + } + } + CSGPlaneList( g_ClipVis[v], planeList ); + } + } + } +} + +// NOTE: UNDONE: This doesn't work on brush models - only the world. +void ClipChanged( IConVar *pConVar, const char *pOld, float flOldValue ) +{ + ConVarRef clipVar( pConVar ); + RecomputeClipbrushes( clipVar.GetBool() ); +} + +static ConVar r_drawclipbrushes( "r_drawclipbrushes", "0", FCVAR_CHEAT, "Draw clip brushes (red=NPC+player, pink=player, purple=NPC)", ClipChanged ); + +static Vector LeafAmbientSamplePos( int leafIndex, const mleafambientlighting_t &sample ) +{ + mleaf_t *pLeaf = &host_state.worldbrush->leafs[leafIndex]; + Vector out = pLeaf->m_vecCenter - pLeaf->m_vecHalfDiagonal; + out.x += float(sample.x) * pLeaf->m_vecHalfDiagonal.x * (2.0f / 255.0f); + out.y += float(sample.y) * pLeaf->m_vecHalfDiagonal.y * (2.0f / 255.0f); + out.z += float(sample.z) * pLeaf->m_vecHalfDiagonal.z * (2.0f / 255.0f); + + return out; +} + +// convert color formats +static void ColorRGBExp32ToColor32( const ColorRGBExp32 &color, color32 &out ) +{ + Vector tmp; + ColorRGBExp32ToVector( color, tmp ); + out.r = LinearToScreenGamma(tmp.x); + out.g = LinearToScreenGamma(tmp.y); + out.b = LinearToScreenGamma(tmp.z); +} + +// some simple helpers to draw a cube in the special way the ambient visualization wants +static Vector CubeSide( const Vector &pos, float size, int vert ) +{ + Vector side = pos; + side.x += (vert & 1) ? -size : size; + side.y += (vert & 2) ? -size : size; + side.z += (vert & 4) ? -size : size; + return side; +} + +static void CubeFace( CMeshBuilder &meshBuilder, const Vector org, int v0, int v1, int v2, int v3, float size, const color32 &color ) +{ + meshBuilder.Position3fv( CubeSide(org,size,v0).Base() ); + meshBuilder.Color4ubv( (byte *)&color ); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3fv( CubeSide(org,size,v1).Base() ); + meshBuilder.Color4ubv( (byte *)&color ); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3fv( CubeSide(org,size,v2).Base() ); + meshBuilder.Color4ubv( (byte *)&color ); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3fv( CubeSide(org,size,v3).Base() ); + meshBuilder.Color4ubv( (byte *)&color ); + meshBuilder.AdvanceVertex(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Draw the leaf geometry that was computed by LeafVisBuild() +//----------------------------------------------------------------------------- +void LeafVisDraw( void ) +{ + if ( g_FrustumVis ) + { + DrawLeafvis( g_FrustumVis ); + } + if ( g_LeafVis ) + { + DrawLeafvis( g_LeafVis ); + } + if ( g_ClipVis[0] ) + { + if ( !g_ClipVis[0]->IsValid() ) + { + RecomputeClipbrushes(true); + } + if ( r_drawclipbrushes.GetInt() == 2 ) + { + DrawLeafvis_Solid( g_ClipVis[0] ); + DrawLeafvis_Solid( g_ClipVis[1] ); + DrawLeafvis_Solid( g_ClipVis[2] ); + } + else + { + DrawLeafvis( g_ClipVis[0] ); + DrawLeafvis( g_ClipVis[1] ); + DrawLeafvis( g_ClipVis[2] ); + } + } + + if ( g_LeafVis && r_visambient.GetBool() ) + { + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( g_pMaterialDebugFlat ); + float cubesize = 12.0f; + int leafIndex = g_LeafVis->leafIndex; + mleafambientindex_t *pAmbient = &host_state.worldbrush->m_pLeafAmbient[leafIndex]; + if ( !pAmbient->ambientSampleCount && pAmbient->firstAmbientSample ) + { + // this leaf references another leaf, move there (this leaf is a solid leaf so it borrows samples from a neighbor) + leafIndex = pAmbient->firstAmbientSample; + pAmbient = &host_state.worldbrush->m_pLeafAmbient[leafIndex]; + } + for ( int i = 0; i < pAmbient->ambientSampleCount; i++ ) + { + IMesh *pMesh = pRenderContext->GetDynamicMesh( ); + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 6 ); + const mleafambientlighting_t &sample = host_state.worldbrush->m_pAmbientSamples[pAmbient->firstAmbientSample+i]; + Vector pos = LeafAmbientSamplePos( leafIndex, sample ); + // x axis + color32 color; + ColorRGBExp32ToColor32( sample.cube.m_Color[0], color ); // x + CubeFace( meshBuilder, pos, 4, 6, 2, 0, cubesize, color ); + ColorRGBExp32ToColor32( sample.cube.m_Color[1], color ); // -x + CubeFace( meshBuilder, pos, 7, 5, 1, 3, cubesize, color ); + ColorRGBExp32ToColor32( sample.cube.m_Color[2], color ); // y + CubeFace( meshBuilder, pos, 0, 1, 5, 4, cubesize, color ); + ColorRGBExp32ToColor32( sample.cube.m_Color[3], color ); // -y + CubeFace( meshBuilder, pos, 3, 2, 6, 7, cubesize, color ); + ColorRGBExp32ToColor32( sample.cube.m_Color[4], color ); // z + CubeFace( meshBuilder, pos, 2, 3, 1, 0, cubesize, color ); + ColorRGBExp32ToColor32( sample.cube.m_Color[5], color ); // -z + CubeFace( meshBuilder, pos, 4, 5, 7, 6, cubesize, color ); + meshBuilder.End(); + pMesh->Draw(); + } + } +} + + +void CSGFrustum( Frustum_t &frustum ) +{ + delete g_FrustumVis; + g_FrustumVis = new leafvis_t; + + g_FrustumVis->color.Init(1.0f, 1.0f, 1.0f); + CUtlVector<cplane_t> planeList; + for ( int i = 0; i < 6; i++ ) + { + planeList.AddToTail( *frustum.GetPlane( i ) ); + } + CSGPlaneList( g_FrustumVis, planeList ); +} +#endif |