mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-09-19 03:56:10 +08:00
First version of the SOurce SDK 2013
This commit is contained in:
332
utils/vrad/disp_vrad.cpp
Normal file
332
utils/vrad/disp_vrad.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "disp_vrad.h"
|
||||
#include "utllinkedlist.h"
|
||||
#include "utlvector.h"
|
||||
#include "iscratchpad3d.h"
|
||||
#include "scratchpadutils.h"
|
||||
|
||||
|
||||
//#define USE_SCRATCHPAD
|
||||
#if defined( USE_SCRATCHPAD )
|
||||
static IScratchPad3D *g_pPad = 0;
|
||||
#endif
|
||||
|
||||
|
||||
int FindNeighborCornerVert( CCoreDispInfo *pDisp, const Vector &vTest )
|
||||
{
|
||||
CDispUtilsHelper *pDispHelper = pDisp;
|
||||
|
||||
int iClosest = 0;
|
||||
float flClosest = 1e24;
|
||||
for ( int iCorner=0; iCorner < 4; iCorner++ )
|
||||
{
|
||||
// Has it been touched?
|
||||
CVertIndex cornerVert = pDispHelper->GetPowerInfo()->GetCornerPointIndex( iCorner );
|
||||
int iCornerVert = pDispHelper->VertIndexToInt( cornerVert );
|
||||
const Vector &vCornerVert = pDisp->GetVert( iCornerVert );
|
||||
|
||||
float flDist = vCornerVert.DistTo( vTest );
|
||||
if ( flDist < flClosest )
|
||||
{
|
||||
iClosest = iCorner;
|
||||
flClosest = flDist;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flClosest <= 0.1f )
|
||||
return iClosest;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int GetAllNeighbors( const CCoreDispInfo *pDisp, int iNeighbors[512] )
|
||||
{
|
||||
int nNeighbors = 0;
|
||||
|
||||
// Check corner neighbors.
|
||||
for ( int iCorner=0; iCorner < 4; iCorner++ )
|
||||
{
|
||||
const CDispCornerNeighbors *pCorner = pDisp->GetCornerNeighbors( iCorner );
|
||||
|
||||
for ( int i=0; i < pCorner->m_nNeighbors; i++ )
|
||||
{
|
||||
if ( nNeighbors < _ARRAYSIZE( iNeighbors ) )
|
||||
iNeighbors[nNeighbors++] = pCorner->m_Neighbors[i];
|
||||
}
|
||||
}
|
||||
|
||||
for ( int iEdge=0; iEdge < 4; iEdge++ )
|
||||
{
|
||||
const CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge );
|
||||
|
||||
for ( int i=0; i < 2; i++ )
|
||||
{
|
||||
if ( pEdge->m_SubNeighbors[i].IsValid() )
|
||||
if ( nNeighbors < 512 )
|
||||
iNeighbors[nNeighbors++] = pEdge->m_SubNeighbors[i].GetNeighborIndex();
|
||||
}
|
||||
}
|
||||
|
||||
return nNeighbors;
|
||||
}
|
||||
|
||||
|
||||
void BlendCorners( CCoreDispInfo **ppListBase, int listSize )
|
||||
{
|
||||
CUtlVector<int> nbCornerVerts;
|
||||
|
||||
for ( int iDisp=0; iDisp < listSize; iDisp++ )
|
||||
{
|
||||
CCoreDispInfo *pDisp = ppListBase[iDisp];
|
||||
|
||||
int iNeighbors[512];
|
||||
int nNeighbors = GetAllNeighbors( pDisp, iNeighbors );
|
||||
|
||||
// Make sure we have room for all the neighbors.
|
||||
nbCornerVerts.RemoveAll();
|
||||
nbCornerVerts.EnsureCapacity( nNeighbors );
|
||||
nbCornerVerts.AddMultipleToTail( nNeighbors );
|
||||
|
||||
// For each corner.
|
||||
for ( int iCorner=0; iCorner < 4; iCorner++ )
|
||||
{
|
||||
// Has it been touched?
|
||||
CVertIndex cornerVert = pDisp->GetCornerPointIndex( iCorner );
|
||||
int iCornerVert = pDisp->VertIndexToInt( cornerVert );
|
||||
const Vector &vCornerVert = pDisp->GetVert( iCornerVert );
|
||||
|
||||
// For each displacement sharing this corner..
|
||||
Vector vAverage = pDisp->GetNormal( iCornerVert );
|
||||
|
||||
for ( int iNeighbor=0; iNeighbor < nNeighbors; iNeighbor++ )
|
||||
{
|
||||
int iNBListIndex = iNeighbors[iNeighbor];
|
||||
CCoreDispInfo *pNeighbor = ppListBase[iNBListIndex];
|
||||
|
||||
// Find out which vert it is on the neighbor.
|
||||
int iNBCorner = FindNeighborCornerVert( pNeighbor, vCornerVert );
|
||||
if ( iNBCorner == -1 )
|
||||
{
|
||||
nbCornerVerts[iNeighbor] = -1; // remove this neighbor from the list.
|
||||
}
|
||||
else
|
||||
{
|
||||
CVertIndex viNBCornerVert = pNeighbor->GetCornerPointIndex( iNBCorner );
|
||||
int iNBVert = pNeighbor->VertIndexToInt( viNBCornerVert );
|
||||
nbCornerVerts[iNeighbor] = iNBVert;
|
||||
vAverage += pNeighbor->GetNormal( iNBVert );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Blend all the neighbor normals with this one.
|
||||
VectorNormalize( vAverage );
|
||||
pDisp->SetNormal( iCornerVert, vAverage );
|
||||
|
||||
#if defined( USE_SCRATCHPAD )
|
||||
ScratchPad_DrawArrowSimple(
|
||||
g_pPad,
|
||||
pDisp->GetVert( iCornerVert ),
|
||||
pDisp->GetNormal( iCornerVert ),
|
||||
Vector( 0, 0, 1 ),
|
||||
25 );
|
||||
#endif
|
||||
|
||||
for ( int iNeighbor=0; iNeighbor < nNeighbors; iNeighbor++ )
|
||||
{
|
||||
int iNBListIndex = iNeighbors[iNeighbor];
|
||||
if ( nbCornerVerts[iNeighbor] == -1 )
|
||||
continue;
|
||||
|
||||
CCoreDispInfo *pNeighbor = ppListBase[iNBListIndex];
|
||||
pNeighbor->SetNormal( nbCornerVerts[iNeighbor], vAverage );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BlendTJuncs( CCoreDispInfo **ppListBase, int listSize )
|
||||
{
|
||||
for ( int iDisp=0; iDisp < listSize; iDisp++ )
|
||||
{
|
||||
CCoreDispInfo *pDisp = ppListBase[iDisp];
|
||||
|
||||
for ( int iEdge=0; iEdge < 4; iEdge++ )
|
||||
{
|
||||
CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge );
|
||||
|
||||
CVertIndex viMidPoint = pDisp->GetEdgeMidPoint( iEdge );
|
||||
int iMidPoint = pDisp->VertIndexToInt( viMidPoint );
|
||||
|
||||
if ( pEdge->m_SubNeighbors[0].IsValid() && pEdge->m_SubNeighbors[1].IsValid() )
|
||||
{
|
||||
const Vector &vMidPoint = pDisp->GetVert( iMidPoint );
|
||||
|
||||
CCoreDispInfo *pNeighbor1 = ppListBase[pEdge->m_SubNeighbors[0].GetNeighborIndex()];
|
||||
CCoreDispInfo *pNeighbor2 = ppListBase[pEdge->m_SubNeighbors[1].GetNeighborIndex()];
|
||||
|
||||
int iNBCorners[2];
|
||||
iNBCorners[0] = FindNeighborCornerVert( pNeighbor1, vMidPoint );
|
||||
iNBCorners[1] = FindNeighborCornerVert( pNeighbor2, vMidPoint );
|
||||
|
||||
if ( iNBCorners[0] != -1 && iNBCorners[1] != -1 )
|
||||
{
|
||||
CVertIndex viNBCorners[2] =
|
||||
{
|
||||
pNeighbor1->GetCornerPointIndex( iNBCorners[0] ),
|
||||
pNeighbor2->GetCornerPointIndex( iNBCorners[1] )
|
||||
};
|
||||
|
||||
Vector vAverage = pDisp->GetNormal( iMidPoint );
|
||||
vAverage += pNeighbor1->GetNormal( viNBCorners[0] );
|
||||
vAverage += pNeighbor2->GetNormal( viNBCorners[1] );
|
||||
|
||||
VectorNormalize( vAverage );
|
||||
pDisp->SetNormal( iMidPoint, vAverage );
|
||||
pNeighbor1->SetNormal( viNBCorners[0], vAverage );
|
||||
pNeighbor2->SetNormal( viNBCorners[1], vAverage );
|
||||
|
||||
#if defined( USE_SCRATCHPAD )
|
||||
ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( iMidPoint ), pDisp->GetNormal( iMidPoint ), Vector( 0, 1, 1 ), 25 );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BlendEdges( CCoreDispInfo **ppListBase, int listSize )
|
||||
{
|
||||
for ( int iDisp=0; iDisp < listSize; iDisp++ )
|
||||
{
|
||||
CCoreDispInfo *pDisp = ppListBase[iDisp];
|
||||
|
||||
for ( int iEdge=0; iEdge < 4; iEdge++ )
|
||||
{
|
||||
CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge );
|
||||
|
||||
for ( int iSub=0; iSub < 2; iSub++ )
|
||||
{
|
||||
CDispSubNeighbor *pSub = &pEdge->m_SubNeighbors[iSub];
|
||||
if ( !pSub->IsValid() )
|
||||
continue;
|
||||
|
||||
CCoreDispInfo *pNeighbor = ppListBase[ pSub->GetNeighborIndex() ];
|
||||
|
||||
int iEdgeDim = g_EdgeDims[iEdge];
|
||||
|
||||
CDispSubEdgeIterator it;
|
||||
it.Start( pDisp, iEdge, iSub, true );
|
||||
|
||||
// Get setup on the first corner vert.
|
||||
it.Next();
|
||||
CVertIndex viPrevPos = it.GetVertIndex();
|
||||
|
||||
while ( it.Next() )
|
||||
{
|
||||
// Blend the two.
|
||||
if ( !it.IsLastVert() )
|
||||
{
|
||||
Vector vAverage = pDisp->GetNormal( it.GetVertIndex() ) + pNeighbor->GetNormal( it.GetNBVertIndex() );
|
||||
VectorNormalize( vAverage );
|
||||
|
||||
pDisp->SetNormal( it.GetVertIndex(), vAverage );
|
||||
pNeighbor->SetNormal( it.GetNBVertIndex(), vAverage );
|
||||
|
||||
#if defined( USE_SCRATCHPAD )
|
||||
ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( it.GetVertIndex() ), pDisp->GetNormal( it.GetVertIndex() ), Vector( 1, 0, 0 ), 25 );
|
||||
#endif
|
||||
}
|
||||
|
||||
// Now blend the in-between verts (if this edge is high-res).
|
||||
int iPrevPos = viPrevPos[ !iEdgeDim ];
|
||||
int iCurPos = it.GetVertIndex()[ !iEdgeDim ];
|
||||
|
||||
for ( int iTween = iPrevPos+1; iTween < iCurPos; iTween++ )
|
||||
{
|
||||
float flPercent = RemapVal( iTween, iPrevPos, iCurPos, 0, 1 );
|
||||
Vector vNormal;
|
||||
VectorLerp( pDisp->GetNormal( viPrevPos ), pDisp->GetNormal( it.GetVertIndex() ), flPercent, vNormal );
|
||||
VectorNormalize( vNormal );
|
||||
|
||||
CVertIndex viTween;
|
||||
viTween[iEdgeDim] = it.GetVertIndex()[ iEdgeDim ];
|
||||
viTween[!iEdgeDim] = iTween;
|
||||
pDisp->SetNormal( viTween, vNormal );
|
||||
|
||||
#if defined( USE_SCRATCHPAD )
|
||||
ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( viTween ), pDisp->GetNormal( viTween ), Vector( 1, 0.5, 0 ), 25 );
|
||||
#endif
|
||||
}
|
||||
|
||||
viPrevPos = it.GetVertIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined( USE_SCRATCHPAD )
|
||||
void ScratchPad_DrawOriginalNormals( const CCoreDispInfo *pListBase, int listSize )
|
||||
{
|
||||
for ( int i=0; i < listSize; i++ )
|
||||
{
|
||||
const CCoreDispInfo *pDisp = &pListBase[i];
|
||||
const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo();
|
||||
|
||||
// Draw the triangles.
|
||||
for ( int iTri=0; iTri < pPowerInfo->GetNumTriInfos(); iTri++ )
|
||||
{
|
||||
const CTriInfo *pTriInfo = pPowerInfo->GetTriInfo( iTri );
|
||||
|
||||
for ( int iLine=0; iLine < 3; iLine++ )
|
||||
{
|
||||
const Vector &v1 = pDisp->GetVert( pTriInfo->m_Indices[iLine] );
|
||||
const Vector &v2 = pDisp->GetVert( pTriInfo->m_Indices[(iLine+1)%3] );
|
||||
|
||||
g_pPad->DrawLine( CSPVert( v1 ), CSPVert( v2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the normals.
|
||||
CDispCircumferenceIterator it( pPowerInfo->GetSideLength() );
|
||||
while ( it.Next() )
|
||||
{
|
||||
ScratchPad_DrawArrowSimple(
|
||||
g_pPad,
|
||||
pDisp->GetVert( it.GetVertIndex() ),
|
||||
pDisp->GetNormal( it.GetVertIndex() ),
|
||||
Vector( 0, 1, 0 ),
|
||||
15 );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void SmoothNeighboringDispSurfNormals( CCoreDispInfo **ppListBase, int listSize )
|
||||
{
|
||||
//#if defined( USE_SCRATCHPAD )
|
||||
// g_pPad = ScratchPad3D_Create();
|
||||
// ScratchPad_DrawOriginalNormals( pListBase, listSize );
|
||||
//#endif
|
||||
|
||||
BlendTJuncs( ppListBase, listSize );
|
||||
|
||||
BlendCorners( ppListBase, listSize );
|
||||
|
||||
BlendEdges( ppListBase, listSize );
|
||||
}
|
||||
|
||||
|
||||
|
22
utils/vrad/disp_vrad.h
Normal file
22
utils/vrad/disp_vrad.h
Normal file
@ -0,0 +1,22 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef DISP_VRAD_H
|
||||
#define DISP_VRAD_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "builddisp.h"
|
||||
|
||||
|
||||
// Blend the normals of neighboring displacement surfaces so they match at edges and corners.
|
||||
void SmoothNeighboringDispSurfNormals( CCoreDispInfo **ppListBase, int listSize );
|
||||
|
||||
|
||||
#endif // DISP_VRAD_H
|
71
utils/vrad/iincremental.h
Normal file
71
utils/vrad/iincremental.h
Normal file
@ -0,0 +1,71 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef IINCREMENTAL_H
|
||||
#define IINCREMENTAL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "mathlib/vector.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
|
||||
typedef unsigned short IncrementalLightID;
|
||||
|
||||
|
||||
// Incremental lighting manager.
|
||||
class IIncremental
|
||||
{
|
||||
// IIncremental overrides.
|
||||
public:
|
||||
|
||||
virtual ~IIncremental() {}
|
||||
|
||||
// Sets up for incremental mode. The BSP file (in bsplib) should be loaded
|
||||
// already so it can detect if the incremental file is up to date.
|
||||
virtual bool Init( char const *pBSPFilename, char const *pIncrementalFilename ) = 0;
|
||||
|
||||
// Prepare to light. You must call Init once, but then you can
|
||||
// do as many Prepare/AddLight/Finalize phases as you want.
|
||||
virtual bool PrepareForLighting() = 0;
|
||||
|
||||
// Called every time light is added to a face.
|
||||
// NOTE: This is the ONLY threadsafe function in IIncremental.
|
||||
virtual void AddLightToFace(
|
||||
IncrementalLightID lightID,
|
||||
int iFace,
|
||||
int iSample,
|
||||
int lmSize,
|
||||
float dot,
|
||||
int iThread ) = 0;
|
||||
|
||||
// Called when it's done applying light from the specified light to the specified face.
|
||||
virtual void FinishFace (
|
||||
IncrementalLightID lightID,
|
||||
int iFace,
|
||||
int iThread ) = 0;
|
||||
|
||||
// For each face that was changed during the lighting process, save out
|
||||
// new data for it in the incremental file.
|
||||
// Returns false if the incremental lighting isn't active.
|
||||
virtual bool Finalize() = 0;
|
||||
|
||||
// Grows touched to a size of 'numfaces' and sets each byte to 0 or 1 telling
|
||||
// if the face's lightmap was updated in Finalize.
|
||||
virtual void GetFacesTouched( CUtlVector<unsigned char> &touched ) = 0;
|
||||
|
||||
// This saves the .r0 file and updates the lighting in the BSP file.
|
||||
virtual bool Serialize() = 0;
|
||||
};
|
||||
|
||||
|
||||
extern IIncremental* GetIncremental();
|
||||
|
||||
|
||||
#endif // IINCREMENTAL_H
|
141
utils/vrad/imagepacker.cpp
Normal file
141
utils/vrad/imagepacker.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#include "vrad.h"
|
||||
#include "imagepacker.h"
|
||||
|
||||
|
||||
bool CImagePacker::Reset( int maxLightmapWidth, int maxLightmapHeight )
|
||||
{
|
||||
int i;
|
||||
|
||||
Assert( maxLightmapWidth <= MAX_MAX_LIGHTMAP_WIDTH );
|
||||
|
||||
m_MaxLightmapWidth = maxLightmapWidth;
|
||||
m_MaxLightmapHeight = maxLightmapHeight;
|
||||
|
||||
m_MaxBlockWidth = maxLightmapWidth + 1;
|
||||
m_MaxBlockHeight = maxLightmapHeight + 1;
|
||||
|
||||
m_AreaUsed = 0;
|
||||
m_MinimumHeight = -1;
|
||||
for( i = 0; i < m_MaxLightmapWidth; i++ )
|
||||
{
|
||||
m_pLightmapWavefront[i] = -1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline int CImagePacker::GetMaxYIndex( int firstX, int width )
|
||||
{
|
||||
int maxY = -1;
|
||||
int maxYIndex = 0;
|
||||
for( int x = firstX; x < firstX + width; ++x )
|
||||
{
|
||||
// NOTE: Want the equals here since we'll never be able to fit
|
||||
// in between the multiple instances of maxY
|
||||
if( m_pLightmapWavefront[x] >= maxY )
|
||||
{
|
||||
maxY = m_pLightmapWavefront[x];
|
||||
maxYIndex = x;
|
||||
}
|
||||
}
|
||||
return maxYIndex;
|
||||
}
|
||||
|
||||
|
||||
bool CImagePacker::AddBlock( int width, int height, int *returnX, int *returnY )
|
||||
{
|
||||
// If we've already determined that a block this big couldn't fit
|
||||
// then blow off checking again...
|
||||
if ( ( width >= m_MaxBlockWidth ) && ( height >= m_MaxBlockHeight ) )
|
||||
return false;
|
||||
|
||||
int bestX = -1;
|
||||
int maxYIdx;
|
||||
int outerX = 0;
|
||||
int outerMinY = m_MaxLightmapHeight;
|
||||
int lastX = m_MaxLightmapWidth - width;
|
||||
int lastMaxYVal = -2;
|
||||
while (outerX <= lastX)
|
||||
{
|
||||
// Skip all tiles that have the last Y value, these
|
||||
// aren't going to change our min Y value
|
||||
if (m_pLightmapWavefront[outerX] == lastMaxYVal)
|
||||
{
|
||||
++outerX;
|
||||
continue;
|
||||
}
|
||||
|
||||
maxYIdx = GetMaxYIndex( outerX, width );
|
||||
lastMaxYVal = m_pLightmapWavefront[maxYIdx];
|
||||
if (outerMinY > lastMaxYVal)
|
||||
{
|
||||
outerMinY = lastMaxYVal;
|
||||
bestX = outerX;
|
||||
}
|
||||
outerX = maxYIdx + 1;
|
||||
}
|
||||
|
||||
if( bestX == -1 )
|
||||
{
|
||||
// If we failed to add it, remember the block size that failed
|
||||
// *only if both dimensions are smaller*!!
|
||||
// Just because a 1x10 block failed, doesn't mean a 10x1 block will fail
|
||||
if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) )
|
||||
{
|
||||
m_MaxBlockWidth = width;
|
||||
m_MaxBlockHeight = height;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the return positions for the block.
|
||||
*returnX = bestX;
|
||||
*returnY = outerMinY + 1;
|
||||
|
||||
// Check if it actually fit height-wise.
|
||||
// hack
|
||||
// if( *returnY + height > maxLightmapHeight )
|
||||
if( *returnY + height >= m_MaxLightmapHeight - 1 )
|
||||
{
|
||||
if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) )
|
||||
{
|
||||
m_MaxBlockWidth = width;
|
||||
m_MaxBlockHeight = height;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// It fit!
|
||||
// Keep up with the smallest possible size for the image so far.
|
||||
if( *returnY + height > m_MinimumHeight )
|
||||
m_MinimumHeight = *returnY + height;
|
||||
|
||||
// Update the wavefront info.
|
||||
int x;
|
||||
for( x = bestX; x < bestX + width; x++ )
|
||||
{
|
||||
m_pLightmapWavefront[x] = outerMinY + height;
|
||||
}
|
||||
|
||||
// AddBlockToLightmapImage( *returnX, *returnY, width, height );
|
||||
m_AreaUsed += width * height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
51
utils/vrad/imagepacker.h
Normal file
51
utils/vrad/imagepacker.h
Normal file
@ -0,0 +1,51 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef IMAGEPACKER_H
|
||||
#define IMAGEPACKER_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#define MAX_MAX_LIGHTMAP_WIDTH 2048
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This packs a single lightmap
|
||||
//-----------------------------------------------------------------------------
|
||||
class CImagePacker
|
||||
{
|
||||
public:
|
||||
bool Reset( int maxLightmapWidth, int maxLightmapHeight );
|
||||
bool AddBlock( int width, int height, int *returnX, int *returnY );
|
||||
|
||||
protected:
|
||||
int GetMaxYIndex( int firstX, int width );
|
||||
|
||||
int m_MaxLightmapWidth;
|
||||
int m_MaxLightmapHeight;
|
||||
int m_pLightmapWavefront[MAX_MAX_LIGHTMAP_WIDTH];
|
||||
int m_AreaUsed;
|
||||
int m_MinimumHeight;
|
||||
|
||||
// For optimization purposes:
|
||||
// These store the width + height of the first image
|
||||
// that was unable to be stored in this image
|
||||
int m_MaxBlockWidth;
|
||||
int m_MaxBlockHeight;
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAGEPACKER_H
|
766
utils/vrad/incremental.cpp
Normal file
766
utils/vrad/incremental.cpp
Normal file
@ -0,0 +1,766 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "incremental.h"
|
||||
#include "lightmap.h"
|
||||
|
||||
|
||||
|
||||
static bool g_bFileError = false;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------- //
|
||||
// Static helpers.
|
||||
// -------------------------------------------------------------------------------- //
|
||||
|
||||
static bool CompareLights( dworldlight_t *a, dworldlight_t *b )
|
||||
{
|
||||
static float flEpsilon = 1e-7;
|
||||
|
||||
bool a1 = VectorsAreEqual( a->origin, b->origin, flEpsilon );
|
||||
bool a2 = VectorsAreEqual( a->intensity, b->intensity, 1.1f ); // intensities are huge numbers
|
||||
bool a3 = VectorsAreEqual( a->normal, b->normal, flEpsilon );
|
||||
bool a4 = fabs( a->constant_attn - b->constant_attn ) < flEpsilon;
|
||||
bool a5 = fabs( a->linear_attn - b->linear_attn ) < flEpsilon;
|
||||
bool a6 = fabs( a->quadratic_attn - b->quadratic_attn ) < flEpsilon;
|
||||
bool a7 = fabs( float( a->flags - b->flags ) ) < flEpsilon;
|
||||
bool a8 = fabs( a->stopdot - b->stopdot ) < flEpsilon;
|
||||
bool a9 = fabs( a->stopdot2 - b->stopdot2 ) < flEpsilon;
|
||||
bool a10 = fabs( a->exponent - b->exponent ) < flEpsilon;
|
||||
bool a11 = fabs( a->radius - b->radius ) < flEpsilon;
|
||||
|
||||
return a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11;
|
||||
}
|
||||
|
||||
|
||||
long FileOpen( char const *pFilename, bool bRead )
|
||||
{
|
||||
g_bFileError = false;
|
||||
return (long)g_pFileSystem->Open( pFilename, bRead ? "rb" : "wb" );
|
||||
}
|
||||
|
||||
|
||||
void FileClose( long fp )
|
||||
{
|
||||
if( fp )
|
||||
g_pFileSystem->Close( (FILE*)fp );
|
||||
}
|
||||
|
||||
|
||||
// Returns true if there was an error reading from the file.
|
||||
bool FileError()
|
||||
{
|
||||
return g_bFileError;
|
||||
}
|
||||
|
||||
static inline void FileRead( long fp, void *pOut, int size )
|
||||
{
|
||||
if( g_bFileError || g_pFileSystem->Read( pOut, size, (FileHandle_t)fp ) != size )
|
||||
{
|
||||
g_bFileError = true;
|
||||
memset( pOut, 0, size );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
static inline void FileRead( long fp, T &out )
|
||||
{
|
||||
FileRead( fp, &out, sizeof(out) );
|
||||
}
|
||||
|
||||
|
||||
static inline void FileWrite( long fp, void const *pData, int size )
|
||||
{
|
||||
if( g_bFileError || g_pFileSystem->Write( pData, size, (FileHandle_t)fp ) != size )
|
||||
{
|
||||
g_bFileError = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
static inline void FileWrite( long fp, T out )
|
||||
{
|
||||
FileWrite( fp, &out, sizeof(out) );
|
||||
}
|
||||
|
||||
|
||||
IIncremental* GetIncremental()
|
||||
{
|
||||
static CIncremental inc;
|
||||
return &inc;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------- //
|
||||
// CIncremental.
|
||||
// -------------------------------------------------------------------------------- //
|
||||
|
||||
CIncremental::CIncremental()
|
||||
{
|
||||
m_TotalMemory = 0;
|
||||
m_pIncrementalFilename = NULL;
|
||||
m_pBSPFilename = NULL;
|
||||
m_bSuccessfulRun = false;
|
||||
}
|
||||
|
||||
|
||||
CIncremental::~CIncremental()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::Init( char const *pBSPFilename, char const *pIncrementalFilename )
|
||||
{
|
||||
m_pBSPFilename = pBSPFilename;
|
||||
m_pIncrementalFilename = pIncrementalFilename;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::PrepareForLighting()
|
||||
{
|
||||
if( !m_pBSPFilename )
|
||||
return false;
|
||||
|
||||
// Clear the touched faces list.
|
||||
m_FacesTouched.SetSize( numfaces );
|
||||
memset( m_FacesTouched.Base(), 0, numfaces );
|
||||
|
||||
// If we haven't done a complete successful run yet, then we either haven't
|
||||
// loaded the lights, or a run was aborted and our lights are half-done so we
|
||||
// should reload them.
|
||||
if( !m_bSuccessfulRun )
|
||||
LoadIncrementalFile();
|
||||
|
||||
// unmatched = a list of the lights we have
|
||||
CUtlLinkedList<int,int> unmatched;
|
||||
for( int i=m_Lights.Head(); i != m_Lights.InvalidIndex(); i = m_Lights.Next(i) )
|
||||
unmatched.AddToTail( i );
|
||||
|
||||
// Match the light lists and get rid of lights that we already have all the data for.
|
||||
directlight_t *pNext;
|
||||
directlight_t **pPrev = &activelights;
|
||||
for( directlight_t *dl=activelights; dl != NULL; dl = pNext )
|
||||
{
|
||||
pNext = dl->next;
|
||||
|
||||
//float flClosest = 3000000000;
|
||||
//CIncLight *pClosest = 0;
|
||||
|
||||
// Look for this light in our light list.
|
||||
int iNextUnmatched, iUnmatched;
|
||||
for( iUnmatched=unmatched.Head(); iUnmatched != unmatched.InvalidIndex(); iUnmatched = iNextUnmatched )
|
||||
{
|
||||
iNextUnmatched = unmatched.Next( iUnmatched );
|
||||
|
||||
CIncLight *pLight = m_Lights[ unmatched[iUnmatched] ];
|
||||
|
||||
//float flTest = (pLight->m_Light.origin - dl->light.origin).Length();
|
||||
//if( flTest < flClosest )
|
||||
//{
|
||||
// flClosest = flTest;
|
||||
// pClosest = pLight;
|
||||
//}
|
||||
|
||||
if( CompareLights( &dl->light, &pLight->m_Light ) )
|
||||
{
|
||||
unmatched.Remove( iUnmatched );
|
||||
|
||||
// Ok, we have this light's data already, yay!
|
||||
// Get rid of it from the active light list.
|
||||
*pPrev = dl->next;
|
||||
free( dl );
|
||||
dl = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//bool bTest=false;
|
||||
//if(bTest)
|
||||
// CompareLights( &dl->light, &pClosest->m_Light );
|
||||
|
||||
if( iUnmatched == unmatched.InvalidIndex() )
|
||||
pPrev = &dl->next;
|
||||
}
|
||||
|
||||
// Remove any of our lights that were unmatched.
|
||||
for( int iUnmatched=unmatched.Head(); iUnmatched != unmatched.InvalidIndex(); iUnmatched = unmatched.Next( iUnmatched ) )
|
||||
{
|
||||
CIncLight *pLight = m_Lights[ unmatched[iUnmatched] ];
|
||||
|
||||
// First tag faces that it touched so they get recomposited.
|
||||
for( unsigned short iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) )
|
||||
{
|
||||
m_FacesTouched[ pLight->m_LightFaces[iFace]->m_FaceIndex ] = 1;
|
||||
}
|
||||
|
||||
delete pLight;
|
||||
m_Lights.Remove( unmatched[iUnmatched] );
|
||||
}
|
||||
|
||||
// Now add a light structure for each new light.
|
||||
AddLightsForActiveLights();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::ReadIncrementalHeader( long fp, CIncrementalHeader *pHeader )
|
||||
{
|
||||
int version;
|
||||
FileRead( fp, version );
|
||||
if( version != INCREMENTALFILE_VERSION )
|
||||
return false;
|
||||
|
||||
int nFaces;
|
||||
FileRead( fp, nFaces );
|
||||
|
||||
pHeader->m_FaceLightmapSizes.SetSize( nFaces );
|
||||
FileRead( fp, pHeader->m_FaceLightmapSizes.Base(), sizeof(CIncrementalHeader::CLMSize) * nFaces );
|
||||
|
||||
return !FileError();
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::WriteIncrementalHeader( long fp )
|
||||
{
|
||||
int version = INCREMENTALFILE_VERSION;
|
||||
FileWrite( fp, version );
|
||||
|
||||
int nFaces = numfaces;
|
||||
FileWrite( fp, nFaces );
|
||||
|
||||
CIncrementalHeader hdr;
|
||||
hdr.m_FaceLightmapSizes.SetSize( nFaces );
|
||||
|
||||
for( int i=0; i < nFaces; i++ )
|
||||
{
|
||||
hdr.m_FaceLightmapSizes[i].m_Width = g_pFaces[i].m_LightmapTextureSizeInLuxels[0];
|
||||
hdr.m_FaceLightmapSizes[i].m_Height = g_pFaces[i].m_LightmapTextureSizeInLuxels[1];
|
||||
}
|
||||
|
||||
FileWrite( fp, hdr.m_FaceLightmapSizes.Base(), sizeof(CIncrementalHeader::CLMSize) * nFaces );
|
||||
|
||||
return !FileError();
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::IsIncrementalFileValid()
|
||||
{
|
||||
long fp = FileOpen( m_pIncrementalFilename, true );
|
||||
if( !fp )
|
||||
return false;
|
||||
|
||||
bool bValid = false;
|
||||
CIncrementalHeader hdr;
|
||||
if( ReadIncrementalHeader( fp, &hdr ) )
|
||||
{
|
||||
// If the number of faces is the same and their lightmap sizes are the same,
|
||||
// then this file is considered a legitimate incremental file.
|
||||
if( hdr.m_FaceLightmapSizes.Count() == numfaces )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i < numfaces; i++ )
|
||||
{
|
||||
if( hdr.m_FaceLightmapSizes[i].m_Width != g_pFaces[i].m_LightmapTextureSizeInLuxels[0] ||
|
||||
hdr.m_FaceLightmapSizes[i].m_Height != g_pFaces[i].m_LightmapTextureSizeInLuxels[1] )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Were all faces valid?
|
||||
if( i == numfaces )
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
FileClose( fp );
|
||||
return bValid && !FileError();
|
||||
}
|
||||
|
||||
|
||||
void CIncremental::AddLightToFace(
|
||||
IncrementalLightID lightID,
|
||||
int iFace,
|
||||
int iSample,
|
||||
int lmSize,
|
||||
float dot,
|
||||
int iThread )
|
||||
{
|
||||
// If we're not being used, don't do anything.
|
||||
if( !m_pIncrementalFilename )
|
||||
return;
|
||||
|
||||
CIncLight *pLight = m_Lights[lightID];
|
||||
|
||||
// Check for the 99.99% case in which the face already exists.
|
||||
CLightFace *pFace;
|
||||
if( pLight->m_pCachedFaces[iThread] &&
|
||||
pLight->m_pCachedFaces[iThread]->m_FaceIndex == iFace )
|
||||
{
|
||||
pFace = pLight->m_pCachedFaces[iThread];
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bNew;
|
||||
|
||||
EnterCriticalSection( &pLight->m_CS );
|
||||
pFace = pLight->FindOrCreateLightFace( iFace, lmSize, &bNew );
|
||||
LeaveCriticalSection( &pLight->m_CS );
|
||||
|
||||
pLight->m_pCachedFaces[iThread] = pFace;
|
||||
|
||||
if( bNew )
|
||||
m_TotalMemory += pFace->m_LightValues.Count() * sizeof( pFace->m_LightValues[0] );
|
||||
}
|
||||
|
||||
// Add this into the light's data.
|
||||
pFace->m_LightValues[iSample].m_Dot = dot;
|
||||
}
|
||||
|
||||
|
||||
unsigned short DecodeCharOrShort( CUtlBuffer *pIn )
|
||||
{
|
||||
unsigned short val = pIn->GetUnsignedChar();
|
||||
if( val & 0x80 )
|
||||
{
|
||||
val = ((val & 0x7F) << 8) | pIn->GetUnsignedChar();
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
void EncodeCharOrShort( CUtlBuffer *pBuf, unsigned short val )
|
||||
{
|
||||
if( (val & 0xFF80) == 0 )
|
||||
{
|
||||
pBuf->PutUnsignedChar( (unsigned char)val );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( val > 32767 )
|
||||
val = 32767;
|
||||
|
||||
pBuf->PutUnsignedChar( (val >> 8) | 0x80 );
|
||||
pBuf->PutUnsignedChar( val & 0xFF );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DecompressLightData( CUtlBuffer *pIn, CUtlVector<CLightValue> *pOut )
|
||||
{
|
||||
int iOut = 0;
|
||||
while( pIn->TellGet() < pIn->TellPut() )
|
||||
{
|
||||
unsigned char runLength = pIn->GetUnsignedChar();
|
||||
unsigned short usVal = DecodeCharOrShort( pIn );
|
||||
|
||||
while( runLength > 0 )
|
||||
{
|
||||
--runLength;
|
||||
|
||||
pOut->Element(iOut).m_Dot = usVal;
|
||||
++iOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning (disable:4701)
|
||||
#endif
|
||||
|
||||
void CompressLightData(
|
||||
CLightValue const *pValues,
|
||||
int nValues,
|
||||
CUtlBuffer *pBuf )
|
||||
{
|
||||
unsigned char runLength=0;
|
||||
unsigned short flLastValue;
|
||||
|
||||
for( int i=0; i < nValues; i++ )
|
||||
{
|
||||
unsigned short flCurValue = (unsigned short)pValues[i].m_Dot;
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
flLastValue = flCurValue;
|
||||
runLength = 1;
|
||||
}
|
||||
else if( flCurValue == flLastValue && runLength < 255 )
|
||||
{
|
||||
++runLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBuf->PutUnsignedChar( runLength );
|
||||
EncodeCharOrShort( pBuf, flLastValue );
|
||||
|
||||
flLastValue = flCurValue;
|
||||
runLength = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the end..
|
||||
if( runLength )
|
||||
{
|
||||
pBuf->PutUnsignedChar( runLength );
|
||||
EncodeCharOrShort( pBuf, flLastValue );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning (default:4701)
|
||||
#endif
|
||||
|
||||
void MultiplyValues( CUtlVector<CLightValue> &values, float scale )
|
||||
{
|
||||
for( int i=0; i < values.Count(); i++ )
|
||||
values[i].m_Dot *= scale;
|
||||
}
|
||||
|
||||
|
||||
void CIncremental::FinishFace(
|
||||
IncrementalLightID lightID,
|
||||
int iFace,
|
||||
int iThread )
|
||||
{
|
||||
CIncLight *pLight = m_Lights[lightID];
|
||||
|
||||
// Check for the 99.99% case in which the face already exists.
|
||||
CLightFace *pFace;
|
||||
if( pLight->m_pCachedFaces[iThread] && pLight->m_pCachedFaces[iThread]->m_FaceIndex == iFace )
|
||||
{
|
||||
pFace = pLight->m_pCachedFaces[iThread];
|
||||
|
||||
// Compress the data.
|
||||
MultiplyValues( pFace->m_LightValues, pLight->m_flMaxIntensity );
|
||||
|
||||
pFace->m_CompressedData.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
|
||||
CompressLightData(
|
||||
pFace->m_LightValues.Base(),
|
||||
pFace->m_LightValues.Count(),
|
||||
&pFace->m_CompressedData );
|
||||
|
||||
#if 0
|
||||
// test decompression
|
||||
CUtlVector<CLightValue> test;
|
||||
test.SetSize( 2048 );
|
||||
pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
|
||||
DecompressLightData( &pFace->m_CompressedData, &test );
|
||||
#endif
|
||||
|
||||
if( pFace->m_CompressedData.TellPut() == 0 )
|
||||
{
|
||||
// No contribution.. delete this face from the light.
|
||||
EnterCriticalSection( &pLight->m_CS );
|
||||
pLight->m_LightFaces.Remove( pFace->m_LightFacesIndex );
|
||||
delete pFace;
|
||||
LeaveCriticalSection( &pLight->m_CS );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Discard the uncompressed data.
|
||||
pFace->m_LightValues.Purge();
|
||||
m_FacesTouched[ pFace->m_FaceIndex ] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::Finalize()
|
||||
{
|
||||
// If we're not being used, don't do anything.
|
||||
if( !m_pIncrementalFilename || !m_pBSPFilename )
|
||||
return false;
|
||||
|
||||
CUtlVector<CFaceLightList> faceLights;
|
||||
LinkLightsToFaces( faceLights );
|
||||
|
||||
Vector faceLight[(MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) * (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2)];
|
||||
CUtlVector<CLightValue> faceLightValues;
|
||||
faceLightValues.SetSize( (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) * (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) );
|
||||
|
||||
// Only update the faces we've touched.
|
||||
for( int facenum = 0; facenum < numfaces; facenum++ )
|
||||
{
|
||||
if( !m_FacesTouched[facenum] || !faceLights[facenum].Count() )
|
||||
continue;
|
||||
|
||||
int w = g_pFaces[facenum].m_LightmapTextureSizeInLuxels[0]+1;
|
||||
int h = g_pFaces[facenum].m_LightmapTextureSizeInLuxels[1]+1;
|
||||
int nLuxels = w * h;
|
||||
assert( nLuxels <= sizeof(faceLight) / sizeof(faceLight[0]) );
|
||||
|
||||
// Clear the lighting for this face.
|
||||
memset( faceLight, 0, nLuxels * sizeof(Vector) );
|
||||
|
||||
// Composite all the light contributions.
|
||||
for( int iFace=0; iFace < faceLights[facenum].Count(); iFace++ )
|
||||
{
|
||||
CLightFace *pFace = faceLights[facenum][iFace];
|
||||
|
||||
pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
|
||||
DecompressLightData( &pFace->m_CompressedData, &faceLightValues );
|
||||
|
||||
for( int iSample=0; iSample < nLuxels; iSample++ )
|
||||
{
|
||||
float flDot = faceLightValues[iSample].m_Dot;
|
||||
if( flDot )
|
||||
{
|
||||
VectorMA(
|
||||
faceLight[iSample],
|
||||
flDot / pFace->m_pLight->m_flMaxIntensity,
|
||||
pFace->m_pLight->m_Light.intensity,
|
||||
faceLight[iSample] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to the floating-point representation in the BSP file.
|
||||
Vector *pSrc = faceLight;
|
||||
unsigned char *pDest = &(*pdlightdata)[ g_pFaces[facenum].lightofs ];
|
||||
|
||||
for( int iSample=0; iSample < nLuxels; iSample++ )
|
||||
{
|
||||
VectorToColorRGBExp32( *pSrc, *( ColorRGBExp32 *)pDest );
|
||||
pDest += 4;
|
||||
pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
m_bSuccessfulRun = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CIncremental::GetFacesTouched( CUtlVector<unsigned char> &touched )
|
||||
{
|
||||
touched.CopyArray( m_FacesTouched.Base(), m_FacesTouched.Count() );
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::Serialize()
|
||||
{
|
||||
if( !SaveIncrementalFile() )
|
||||
return false;
|
||||
|
||||
WriteBSPFile( (char*)m_pBSPFilename );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CIncremental::Term()
|
||||
{
|
||||
m_Lights.PurgeAndDeleteElements();
|
||||
m_TotalMemory = 0;
|
||||
}
|
||||
|
||||
|
||||
void CIncremental::AddLightsForActiveLights()
|
||||
{
|
||||
// Create our lights.
|
||||
for( directlight_t *dl=activelights; dl != NULL; dl = dl->next )
|
||||
{
|
||||
CIncLight *pLight = new CIncLight;
|
||||
dl->m_IncrementalID = m_Lights.AddToTail( pLight );
|
||||
|
||||
// Copy the light information.
|
||||
pLight->m_Light = dl->light;
|
||||
pLight->m_flMaxIntensity = max( dl->light.intensity[0], max( dl->light.intensity[1], dl->light.intensity[2] ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::LoadIncrementalFile()
|
||||
{
|
||||
Term();
|
||||
|
||||
if( !IsIncrementalFileValid() )
|
||||
return false;
|
||||
|
||||
long fp = FileOpen( m_pIncrementalFilename, true );
|
||||
if( !fp )
|
||||
return false;
|
||||
|
||||
// Read the header.
|
||||
CIncrementalHeader hdr;
|
||||
if( !ReadIncrementalHeader( fp, &hdr ) )
|
||||
{
|
||||
FileClose( fp );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Read the lights.
|
||||
int nLights;
|
||||
FileRead( fp, nLights );
|
||||
for( int iLight=0; iLight < nLights; iLight++ )
|
||||
{
|
||||
CIncLight *pLight = new CIncLight;
|
||||
m_Lights.AddToTail( pLight );
|
||||
|
||||
FileRead( fp, pLight->m_Light );
|
||||
pLight->m_flMaxIntensity =
|
||||
max( pLight->m_Light.intensity.x,
|
||||
max( pLight->m_Light.intensity.y, pLight->m_Light.intensity.z ) );
|
||||
|
||||
int nFaces;
|
||||
FileRead( fp, nFaces );
|
||||
assert( nFaces < 70000 );
|
||||
|
||||
for( int iFace=0; iFace < nFaces; iFace++ )
|
||||
{
|
||||
CLightFace *pFace = new CLightFace;
|
||||
pLight->m_LightFaces.AddToTail( pFace );
|
||||
|
||||
pFace->m_pLight = pLight;
|
||||
FileRead( fp, pFace->m_FaceIndex );
|
||||
|
||||
int dataSize;
|
||||
FileRead( fp, dataSize );
|
||||
|
||||
pFace->m_CompressedData.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
|
||||
while( dataSize )
|
||||
{
|
||||
--dataSize;
|
||||
|
||||
unsigned char ucData;
|
||||
FileRead( fp, ucData );
|
||||
|
||||
pFace->m_CompressedData.PutUnsignedChar( ucData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FileClose( fp );
|
||||
return !FileError();
|
||||
}
|
||||
|
||||
|
||||
bool CIncremental::SaveIncrementalFile()
|
||||
{
|
||||
long fp = FileOpen( m_pIncrementalFilename, false );
|
||||
if( !fp )
|
||||
return false;
|
||||
|
||||
if( !WriteIncrementalHeader( fp ) )
|
||||
{
|
||||
FileClose( fp );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the lights.
|
||||
int nLights = m_Lights.Count();
|
||||
FileWrite( fp, nLights );
|
||||
for( int iLight=m_Lights.Head(); iLight != m_Lights.InvalidIndex(); iLight = m_Lights.Next( iLight ) )
|
||||
{
|
||||
CIncLight *pLight = m_Lights[iLight];
|
||||
|
||||
FileWrite( fp, pLight->m_Light );
|
||||
|
||||
int nFaces = pLight->m_LightFaces.Count();
|
||||
FileWrite( fp, nFaces );
|
||||
for( int iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) )
|
||||
{
|
||||
CLightFace *pFace = pLight->m_LightFaces[iFace];
|
||||
|
||||
FileWrite( fp, pFace->m_FaceIndex );
|
||||
|
||||
int dataSize = pFace->m_CompressedData.TellPut();
|
||||
FileWrite( fp, dataSize );
|
||||
|
||||
pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
|
||||
while( dataSize )
|
||||
{
|
||||
--dataSize;
|
||||
FileWrite( fp, pFace->m_CompressedData.GetUnsignedChar() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FileClose( fp );
|
||||
return !FileError();
|
||||
}
|
||||
|
||||
|
||||
void CIncremental::LinkLightsToFaces( CUtlVector<CFaceLightList> &faceLights )
|
||||
{
|
||||
faceLights.SetSize( numfaces );
|
||||
|
||||
for( int iLight=m_Lights.Head(); iLight != m_Lights.InvalidIndex(); iLight = m_Lights.Next( iLight ) )
|
||||
{
|
||||
CIncLight *pLight = m_Lights[iLight];
|
||||
|
||||
for( int iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) )
|
||||
{
|
||||
CLightFace *pFace = pLight->m_LightFaces[iFace];
|
||||
|
||||
if( m_FacesTouched[pFace->m_FaceIndex] )
|
||||
faceLights[ pFace->m_FaceIndex ].AddToTail( pFace );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------ //
|
||||
// CIncLight
|
||||
// ------------------------------------------------------------------ //
|
||||
|
||||
CIncLight::CIncLight()
|
||||
{
|
||||
memset( m_pCachedFaces, 0, sizeof(m_pCachedFaces) );
|
||||
InitializeCriticalSection( &m_CS );
|
||||
}
|
||||
|
||||
|
||||
CIncLight::~CIncLight()
|
||||
{
|
||||
m_LightFaces.PurgeAndDeleteElements();
|
||||
DeleteCriticalSection( &m_CS );
|
||||
}
|
||||
|
||||
|
||||
CLightFace* CIncLight::FindOrCreateLightFace( int iFace, int lmSize, bool *bNew )
|
||||
{
|
||||
if( bNew )
|
||||
*bNew = false;
|
||||
|
||||
|
||||
// Look for it.
|
||||
for( int i=m_LightFaces.Head(); i != m_LightFaces.InvalidIndex(); i=m_LightFaces.Next(i) )
|
||||
{
|
||||
CLightFace *pFace = m_LightFaces[i];
|
||||
|
||||
if( pFace->m_FaceIndex == iFace )
|
||||
{
|
||||
assert( pFace->m_LightValues.Count() == lmSize );
|
||||
return pFace;
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, create one.
|
||||
CLightFace *pFace = new CLightFace;
|
||||
pFace->m_LightFacesIndex = m_LightFaces.AddToTail( pFace );
|
||||
pFace->m_pLight = this;
|
||||
|
||||
pFace->m_FaceIndex = iFace;
|
||||
pFace->m_LightValues.SetSize( lmSize );
|
||||
memset( pFace->m_LightValues.Base(), 0, sizeof( CLightValue ) * lmSize );
|
||||
|
||||
if( bNew )
|
||||
*bNew = true;
|
||||
|
||||
return pFace;
|
||||
}
|
||||
|
||||
|
175
utils/vrad/incremental.h
Normal file
175
utils/vrad/incremental.h
Normal file
@ -0,0 +1,175 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef INCREMENTAL_H
|
||||
#define INCREMENTAL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "iincremental.h"
|
||||
#include "utllinkedlist.h"
|
||||
#include "utlvector.h"
|
||||
#include "utlbuffer.h"
|
||||
#include "vrad.h"
|
||||
|
||||
|
||||
#define INCREMENTALFILE_VERSION 31241
|
||||
|
||||
|
||||
class CIncLight;
|
||||
|
||||
|
||||
class CLightValue
|
||||
{
|
||||
public:
|
||||
float m_Dot;
|
||||
};
|
||||
|
||||
|
||||
class CLightFace
|
||||
{
|
||||
public:
|
||||
unsigned short m_FaceIndex; // global face index
|
||||
unsigned short m_LightFacesIndex; // index into CIncLight::m_LightFaces.
|
||||
|
||||
// The lightmap grid for this face. Only used while building lighting data for a face.
|
||||
// Compressed into m_CompressedData immediately afterwards.
|
||||
CUtlVector<CLightValue> m_LightValues;
|
||||
|
||||
CUtlBuffer m_CompressedData;
|
||||
CIncLight *m_pLight;
|
||||
};
|
||||
|
||||
|
||||
class CIncLight
|
||||
{
|
||||
public:
|
||||
CIncLight();
|
||||
~CIncLight();
|
||||
|
||||
CLightFace* FindOrCreateLightFace( int iFace, int lmSize, bool *bNew=NULL );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CRITICAL_SECTION m_CS;
|
||||
|
||||
// This is the light for which m_LightFaces was built.
|
||||
dworldlight_t m_Light;
|
||||
|
||||
CLightFace *m_pCachedFaces[MAX_TOOL_THREADS+1];
|
||||
|
||||
// The list of faces that this light contributes to.
|
||||
CUtlLinkedList<CLightFace*, unsigned short> m_LightFaces;
|
||||
|
||||
// Largest value in intensity of light. Used to scale dot products up into a
|
||||
// range where their values make sense.
|
||||
float m_flMaxIntensity;
|
||||
};
|
||||
|
||||
|
||||
class CIncrementalHeader
|
||||
{
|
||||
public:
|
||||
class CLMSize
|
||||
{
|
||||
public:
|
||||
unsigned char m_Width;
|
||||
unsigned char m_Height;
|
||||
};
|
||||
|
||||
CUtlVector<CLMSize> m_FaceLightmapSizes;
|
||||
};
|
||||
|
||||
|
||||
class CIncremental : public IIncremental
|
||||
{
|
||||
public:
|
||||
|
||||
CIncremental();
|
||||
~CIncremental();
|
||||
|
||||
|
||||
|
||||
// IIncremental overrides.
|
||||
public:
|
||||
|
||||
virtual bool Init( char const *pBSPFilename, char const *pIncrementalFilename );
|
||||
|
||||
// Load the light definitions out of the incremental file.
|
||||
// Figure out which lights have changed.
|
||||
// Change 'activelights' to only consist of new or changed lights.
|
||||
virtual bool PrepareForLighting();
|
||||
|
||||
virtual void AddLightToFace(
|
||||
IncrementalLightID lightID,
|
||||
int iFace,
|
||||
int iSample,
|
||||
int lmSize,
|
||||
float dot,
|
||||
int iThread );
|
||||
|
||||
virtual void FinishFace(
|
||||
IncrementalLightID lightID,
|
||||
int iFace,
|
||||
int iThread );
|
||||
|
||||
// For each face that was changed during the lighting process, save out
|
||||
// new data for it in the incremental file.
|
||||
virtual bool Finalize();
|
||||
|
||||
virtual void GetFacesTouched( CUtlVector<unsigned char> &touched );
|
||||
|
||||
virtual bool Serialize();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Read/write the header from the file.
|
||||
bool ReadIncrementalHeader( long fp, CIncrementalHeader *pHeader );
|
||||
bool WriteIncrementalHeader( long fp );
|
||||
|
||||
// Returns true if the incremental file is valid and we can use InitUpdate.
|
||||
bool IsIncrementalFileValid();
|
||||
|
||||
void Term();
|
||||
|
||||
// For each light in 'activelights', add a light to m_Lights and link them together.
|
||||
void AddLightsForActiveLights();
|
||||
|
||||
// Load and save the state.
|
||||
bool LoadIncrementalFile();
|
||||
bool SaveIncrementalFile();
|
||||
|
||||
typedef CUtlVector<CLightFace*> CFaceLightList;
|
||||
void LinkLightsToFaces( CUtlVector<CFaceLightList> &faceLights );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
char const *m_pIncrementalFilename;
|
||||
char const *m_pBSPFilename;
|
||||
|
||||
CUtlLinkedList<CIncLight*, IncrementalLightID>
|
||||
m_Lights;
|
||||
|
||||
// The face index is set to 1 if a face has new lighting data applied to it.
|
||||
// This is used to optimize the set of lightmaps we recomposite.
|
||||
CUtlVector<unsigned char> m_FacesTouched;
|
||||
|
||||
int m_TotalMemory;
|
||||
|
||||
// Set to true when one or more runs were completed successfully.
|
||||
bool m_bSuccessfulRun;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // INCREMENTAL_H
|
708
utils/vrad/leaf_ambient_lighting.cpp
Normal file
708
utils/vrad/leaf_ambient_lighting.cpp
Normal file
@ -0,0 +1,708 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "vrad.h"
|
||||
#include "leaf_ambient_lighting.h"
|
||||
#include "bsplib.h"
|
||||
#include "vraddetailprops.h"
|
||||
#include "mathlib/anorms.h"
|
||||
#include "pacifier.h"
|
||||
#include "coordsize.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "bsptreedata.h"
|
||||
#include "messbuf.h"
|
||||
#include "vmpi.h"
|
||||
#include "vmpi_distribute_work.h"
|
||||
|
||||
static TableVector g_BoxDirections[6] =
|
||||
{
|
||||
{ 1, 0, 0 },
|
||||
{ -1, 0, 0 },
|
||||
{ 0, 1, 0 },
|
||||
{ 0, -1, 0 },
|
||||
{ 0, 0, 1 },
|
||||
{ 0, 0, -1 },
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void ComputeAmbientFromSurface( dface_t *surfID, dworldlight_t* pSkylight,
|
||||
Vector& radcolor )
|
||||
{
|
||||
if ( !surfID )
|
||||
return;
|
||||
|
||||
texinfo_t *pTexInfo = &texinfo[surfID->texinfo];
|
||||
|
||||
// If we hit the sky, use the sky ambient
|
||||
if ( pTexInfo->flags & SURF_SKY )
|
||||
{
|
||||
if ( pSkylight )
|
||||
{
|
||||
// add in sky ambient
|
||||
VectorCopy( pSkylight->intensity, radcolor );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector reflectivity = dtexdata[pTexInfo->texdata].reflectivity;
|
||||
VectorMultiply( radcolor, reflectivity, radcolor );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: it's CRAZY how much lighting code we share with the engine. It should all be shared code.
|
||||
float Engine_WorldLightAngle( const dworldlight_t *wl, const Vector& lnormal, const Vector& snormal, const Vector& delta )
|
||||
{
|
||||
float dot, dot2;
|
||||
|
||||
Assert( wl->type == emit_surface );
|
||||
|
||||
dot = DotProduct( snormal, delta );
|
||||
if (dot < 0)
|
||||
return 0;
|
||||
|
||||
dot2 = -DotProduct (delta, lnormal);
|
||||
if (dot2 <= ON_EPSILON/10)
|
||||
return 0; // behind light surface
|
||||
|
||||
return dot * dot2;
|
||||
}
|
||||
|
||||
|
||||
// TODO: it's CRAZY how much lighting code we share with the engine. It should all be shared code.
|
||||
float Engine_WorldLightDistanceFalloff( const dworldlight_t *wl, const Vector& delta )
|
||||
{
|
||||
Assert( wl->type == emit_surface );
|
||||
|
||||
// Cull out stuff that's too far
|
||||
if (wl->radius != 0)
|
||||
{
|
||||
if ( DotProduct( delta, delta ) > (wl->radius * wl->radius))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return InvRSquared(delta);
|
||||
}
|
||||
|
||||
|
||||
void AddEmitSurfaceLights( const Vector &vStart, Vector lightBoxColor[6] )
|
||||
{
|
||||
fltx4 fractionVisible;
|
||||
|
||||
FourVectors vStart4, wlOrigin4;
|
||||
vStart4.DuplicateVector ( vStart );
|
||||
|
||||
for ( int iLight=0; iLight < *pNumworldlights; iLight++ )
|
||||
{
|
||||
dworldlight_t *wl = &dworldlights[iLight];
|
||||
|
||||
// Should this light even go in the ambient cubes?
|
||||
if ( !( wl->flags & DWL_FLAGS_INAMBIENTCUBE ) )
|
||||
continue;
|
||||
|
||||
Assert( wl->type == emit_surface );
|
||||
|
||||
// Can this light see the point?
|
||||
wlOrigin4.DuplicateVector ( wl->origin );
|
||||
TestLine ( vStart4, wlOrigin4, &fractionVisible );
|
||||
if ( !TestSignSIMD ( CmpGtSIMD ( fractionVisible, Four_Zeros ) ) )
|
||||
continue;
|
||||
|
||||
// Add this light's contribution.
|
||||
Vector vDelta = wl->origin - vStart;
|
||||
float flDistanceScale = Engine_WorldLightDistanceFalloff( wl, vDelta );
|
||||
|
||||
Vector vDeltaNorm = vDelta;
|
||||
VectorNormalize( vDeltaNorm );
|
||||
float flAngleScale = Engine_WorldLightAngle( wl, wl->normal, vDeltaNorm, vDeltaNorm );
|
||||
|
||||
float ratio = flDistanceScale * flAngleScale * SubFloat ( fractionVisible, 0 );
|
||||
if ( ratio == 0 )
|
||||
continue;
|
||||
|
||||
for ( int i=0; i < 6; i++ )
|
||||
{
|
||||
float t = DotProduct( g_BoxDirections[i], vDeltaNorm );
|
||||
if ( t > 0 )
|
||||
{
|
||||
lightBoxColor[i] += wl->intensity * (t * ratio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ComputeAmbientFromSphericalSamples( int iThread, const Vector &vStart, Vector lightBoxColor[6] )
|
||||
{
|
||||
// Figure out the color that rays hit when shot out from this position.
|
||||
Vector radcolor[NUMVERTEXNORMALS];
|
||||
float tanTheta = tan(VERTEXNORMAL_CONE_INNER_ANGLE);
|
||||
|
||||
for ( int i = 0; i < NUMVERTEXNORMALS; i++ )
|
||||
{
|
||||
Vector vEnd = vStart + g_anorms[i] * (COORD_EXTENT * 1.74);
|
||||
|
||||
// Now that we've got a ray, see what surface we've hit
|
||||
Vector lightStyleColors[MAX_LIGHTSTYLES];
|
||||
lightStyleColors[0].Init(); // We only care about light style 0 here.
|
||||
CalcRayAmbientLighting( iThread, vStart, vEnd, tanTheta, lightStyleColors );
|
||||
|
||||
radcolor[i] = lightStyleColors[0];
|
||||
}
|
||||
|
||||
// accumulate samples into radiant box
|
||||
for ( int j = 6; --j >= 0; )
|
||||
{
|
||||
float t = 0;
|
||||
|
||||
lightBoxColor[j].Init();
|
||||
|
||||
for (int i = 0; i < NUMVERTEXNORMALS; i++)
|
||||
{
|
||||
float c = DotProduct( g_anorms[i], g_BoxDirections[j] );
|
||||
if (c > 0)
|
||||
{
|
||||
t += c;
|
||||
lightBoxColor[j] += radcolor[i] * c;
|
||||
}
|
||||
}
|
||||
|
||||
lightBoxColor[j] *= 1/t;
|
||||
}
|
||||
|
||||
// Now add direct light from the emit_surface lights. These go in the ambient cube because
|
||||
// there are a ton of them and they are often so dim that they get filtered out by r_worldlightmin.
|
||||
AddEmitSurfaceLights( vStart, lightBoxColor );
|
||||
}
|
||||
|
||||
|
||||
bool IsLeafAmbientSurfaceLight( dworldlight_t *wl )
|
||||
{
|
||||
static const float g_flWorldLightMinEmitSurface = 0.005f;
|
||||
static const float g_flWorldLightMinEmitSurfaceDistanceRatio = ( InvRSquared( Vector( 0, 0, 512 ) ) );
|
||||
|
||||
if ( wl->type != emit_surface )
|
||||
return false;
|
||||
|
||||
if ( wl->style != 0 )
|
||||
return false;
|
||||
|
||||
float intensity = max( wl->intensity[0], wl->intensity[1] );
|
||||
intensity = max( intensity, wl->intensity[2] );
|
||||
|
||||
return (intensity * g_flWorldLightMinEmitSurfaceDistanceRatio) < g_flWorldLightMinEmitSurface;
|
||||
}
|
||||
|
||||
|
||||
class CLeafSampler
|
||||
{
|
||||
public:
|
||||
CLeafSampler( int iThread ) : m_iThread(iThread) {}
|
||||
|
||||
// Generate a random point in the leaf's bounding volume
|
||||
// reject any points that aren't actually in the leaf
|
||||
// do a couple of tracing heuristics to eliminate points that are inside detail brushes
|
||||
// or underneath displacement surfaces in the leaf
|
||||
// return once we have a valid point, use the center if one can't be computed quickly
|
||||
void GenerateLeafSamplePosition( int leafIndex, const CUtlVector<dplane_t> &leafPlanes, Vector &samplePosition )
|
||||
{
|
||||
dleaf_t *pLeaf = dleafs + leafIndex;
|
||||
|
||||
float dx = pLeaf->maxs[0] - pLeaf->mins[0];
|
||||
float dy = pLeaf->maxs[1] - pLeaf->mins[1];
|
||||
float dz = pLeaf->maxs[2] - pLeaf->mins[2];
|
||||
bool bValid = false;
|
||||
for ( int i = 0; i < 1000 && !bValid; i++ )
|
||||
{
|
||||
samplePosition.x = pLeaf->mins[0] + m_random.RandomFloat(0, dx);
|
||||
samplePosition.y = pLeaf->mins[1] + m_random.RandomFloat(0, dy);
|
||||
samplePosition.z = pLeaf->mins[2] + m_random.RandomFloat(0, dz);
|
||||
bValid = true;
|
||||
|
||||
for ( int j = leafPlanes.Count(); --j >= 0 && bValid; )
|
||||
{
|
||||
float d = DotProduct(leafPlanes[j].normal, samplePosition) - leafPlanes[j].dist;
|
||||
if ( d < DIST_EPSILON )
|
||||
{
|
||||
// not inside the leaf, try again
|
||||
bValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bValid )
|
||||
continue;
|
||||
|
||||
for ( int j = 0; j < 6; j++ )
|
||||
{
|
||||
Vector start = samplePosition;
|
||||
int axis = j%3;
|
||||
start[axis] = (j<3) ? pLeaf->mins[axis] : pLeaf->maxs[axis];
|
||||
float t;
|
||||
Vector normal;
|
||||
CastRayInLeaf( m_iThread, samplePosition, start, leafIndex, &t, &normal );
|
||||
if ( t == 0.0f )
|
||||
{
|
||||
// inside a func_detail, try again.
|
||||
bValid = false;
|
||||
break;
|
||||
}
|
||||
if ( t != 1.0f )
|
||||
{
|
||||
Vector delta = start - samplePosition;
|
||||
if ( DotProduct(delta, normal) > 0 )
|
||||
{
|
||||
// hit backside of displacement, try again.
|
||||
bValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !bValid )
|
||||
{
|
||||
// didn't generate a valid sample point, just use the center of the leaf bbox
|
||||
samplePosition = ( Vector( pLeaf->mins[0], pLeaf->mins[1], pLeaf->mins[2] ) + Vector( pLeaf->maxs[0], pLeaf->maxs[1], pLeaf->maxs[2] ) ) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_iThread;
|
||||
CUniformRandomStream m_random;
|
||||
};
|
||||
|
||||
// gets a list of the planes pointing into a leaf
|
||||
void GetLeafBoundaryPlanes( CUtlVector<dplane_t> &list, int leafIndex )
|
||||
{
|
||||
list.RemoveAll();
|
||||
int nodeIndex = leafparents[leafIndex];
|
||||
int child = -(leafIndex + 1);
|
||||
while ( nodeIndex >= 0 )
|
||||
{
|
||||
dnode_t *pNode = dnodes + nodeIndex;
|
||||
dplane_t *pNodePlane = dplanes + pNode->planenum;
|
||||
if ( pNode->children[0] == child )
|
||||
{
|
||||
// front side
|
||||
list.AddToTail( *pNodePlane );
|
||||
}
|
||||
else
|
||||
{
|
||||
// back side
|
||||
int plane = list.AddToTail();
|
||||
list[plane].dist = -pNodePlane->dist;
|
||||
list[plane].normal = -pNodePlane->normal;
|
||||
list[plane].type = pNodePlane->type;
|
||||
}
|
||||
child = nodeIndex;
|
||||
nodeIndex = nodeparents[child];
|
||||
}
|
||||
}
|
||||
|
||||
// this stores each sample of the ambient lighting
|
||||
struct ambientsample_t
|
||||
{
|
||||
Vector pos;
|
||||
Vector cube[6];
|
||||
};
|
||||
|
||||
// add the sample to the list. If we exceed the maximum number of samples, the worst sample will
|
||||
// be discarded. This has the effect of converging on the best samples when enough are added.
|
||||
void AddSampleToList( CUtlVector<ambientsample_t> &list, const Vector &samplePosition, Vector *pCube )
|
||||
{
|
||||
const int MAX_SAMPLES = 16;
|
||||
|
||||
int index = list.AddToTail();
|
||||
list[index].pos = samplePosition;
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
list[index].cube[i] = pCube[i];
|
||||
}
|
||||
|
||||
if ( list.Count() <= MAX_SAMPLES )
|
||||
return;
|
||||
|
||||
int nearestNeighborIndex = 0;
|
||||
float nearestNeighborDist = FLT_MAX;
|
||||
float nearestNeighborTotal = 0;
|
||||
for ( int i = 0; i < list.Count(); i++ )
|
||||
{
|
||||
int closestIndex = 0;
|
||||
float closestDist = FLT_MAX;
|
||||
float totalDC = 0;
|
||||
for ( int j = 0; j < list.Count(); j++ )
|
||||
{
|
||||
if ( j == i )
|
||||
continue;
|
||||
float dist = (list[i].pos - list[j].pos).Length();
|
||||
float maxDC = 0;
|
||||
for ( int k = 0; k < 6; k++ )
|
||||
{
|
||||
// color delta is computed per-component, per cube side
|
||||
for (int s = 0; s < 3; s++ )
|
||||
{
|
||||
float dc = fabs(list[i].cube[k][s] - list[j].cube[k][s]);
|
||||
maxDC = max(maxDC,dc);
|
||||
}
|
||||
totalDC += maxDC;
|
||||
}
|
||||
// need a measurable difference in color or we'll just rely on position
|
||||
if ( maxDC < 1e-4f )
|
||||
{
|
||||
maxDC = 0;
|
||||
}
|
||||
else if ( maxDC > 1.0f )
|
||||
{
|
||||
maxDC = 1.0f;
|
||||
}
|
||||
// selection criteria is 10% distance, 90% color difference
|
||||
// choose samples that fill the space (large distance from each other)
|
||||
// and have largest color variation
|
||||
float distanceFactor = 0.1f + (maxDC * 0.9f);
|
||||
dist *= distanceFactor;
|
||||
|
||||
// find the "closest" sample to this one
|
||||
if ( dist < closestDist )
|
||||
{
|
||||
closestDist = dist;
|
||||
closestIndex = j;
|
||||
}
|
||||
}
|
||||
// the sample with the "closest" neighbor is rejected
|
||||
if ( closestDist < nearestNeighborDist || (closestDist == nearestNeighborDist && totalDC < nearestNeighborTotal) )
|
||||
{
|
||||
nearestNeighborDist = closestDist;
|
||||
nearestNeighborIndex = i;
|
||||
}
|
||||
}
|
||||
list.FastRemove( nearestNeighborIndex );
|
||||
}
|
||||
|
||||
// max number of units in gamma space of per-side delta
|
||||
int CubeDeltaGammaSpace( Vector *pCube0, Vector *pCube1 )
|
||||
{
|
||||
int maxDelta = 0;
|
||||
// do this comparison in gamma space to try and get a perceptual basis for the compare
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
for ( int j = 0; j < 3; j++ )
|
||||
{
|
||||
int val0 = LinearToScreenGamma( pCube0[i][j] );
|
||||
int val1 = LinearToScreenGamma( pCube1[i][j] );
|
||||
int delta = abs(val0-val1);
|
||||
if ( delta > maxDelta )
|
||||
maxDelta = delta;
|
||||
}
|
||||
}
|
||||
return maxDelta;
|
||||
}
|
||||
// reconstruct the ambient lighting for a leaf at the given position in worldspace
|
||||
// optionally skip one of the entries in the list
|
||||
void Mod_LeafAmbientColorAtPos( Vector *pOut, const Vector &pos, const CUtlVector<ambientsample_t> &list, int skipIndex )
|
||||
{
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
pOut[i].Init();
|
||||
}
|
||||
float totalFactor = 0;
|
||||
for ( int i = 0; i < list.Count(); i++ )
|
||||
{
|
||||
if ( i == skipIndex )
|
||||
continue;
|
||||
// do an inverse squared distance weighted average of the samples to reconstruct
|
||||
// the original function
|
||||
float dist = (list[i].pos - pos).LengthSqr();
|
||||
float factor = 1.0f / (dist + 1.0f);
|
||||
totalFactor += factor;
|
||||
for ( int j = 0; j < 6; j++ )
|
||||
{
|
||||
pOut[j] += list[i].cube[j] * factor;
|
||||
}
|
||||
}
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
pOut[i] *= (1.0f / totalFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// this samples the lighting at each sample and removes any unnecessary samples
|
||||
void CompressAmbientSampleList( CUtlVector<ambientsample_t> &list )
|
||||
{
|
||||
Vector testCube[6];
|
||||
for ( int i = 0; i < list.Count(); i++ )
|
||||
{
|
||||
if ( list.Count() > 1 )
|
||||
{
|
||||
Mod_LeafAmbientColorAtPos( testCube, list[i].pos, list, i );
|
||||
if ( CubeDeltaGammaSpace(testCube, list[i].cube) < 3 )
|
||||
{
|
||||
list.FastRemove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// basically this is an intersection routine that returns a distance between the boxes
|
||||
float AABBDistance( const Vector &mins0, const Vector &maxs0, const Vector &mins1, const Vector &maxs1 )
|
||||
{
|
||||
Vector delta;
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
float greatestMin = max(mins0[i], mins1[i]);
|
||||
float leastMax = min(maxs0[i], maxs1[i]);
|
||||
delta[i] = (greatestMin < leastMax) ? 0 : (leastMax - greatestMin);
|
||||
}
|
||||
return delta.Length();
|
||||
}
|
||||
|
||||
// build a list of leaves from a query
|
||||
class CLeafList : public ISpatialLeafEnumerator
|
||||
{
|
||||
public:
|
||||
virtual bool EnumerateLeaf( int leaf, int context )
|
||||
{
|
||||
m_list.AddToTail(leaf);
|
||||
return true;
|
||||
}
|
||||
|
||||
CUtlVector<int> m_list;
|
||||
};
|
||||
|
||||
// conver short[3] to vector
|
||||
static void LeafBounds( int leafIndex, Vector &mins, Vector &maxs )
|
||||
{
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
mins[i] = dleafs[leafIndex].mins[i];
|
||||
maxs[i] = dleafs[leafIndex].maxs[i];
|
||||
}
|
||||
}
|
||||
|
||||
// returns the index of the nearest leaf with ambient samples
|
||||
int NearestNeighborWithLight(int leafID)
|
||||
{
|
||||
Vector mins, maxs;
|
||||
LeafBounds( leafID, mins, maxs );
|
||||
Vector size = maxs - mins;
|
||||
CLeafList leafList;
|
||||
ToolBSPTree()->EnumerateLeavesInBox( mins-size, maxs+size, &leafList, 0 );
|
||||
float bestDist = FLT_MAX;
|
||||
int bestIndex = leafID;
|
||||
for ( int i = 0; i < leafList.m_list.Count(); i++ )
|
||||
{
|
||||
int testIndex = leafList.m_list[i];
|
||||
if ( !g_pLeafAmbientIndex->Element(testIndex).ambientSampleCount )
|
||||
continue;
|
||||
|
||||
Vector testMins, testMaxs;
|
||||
LeafBounds( testIndex, testMins, testMaxs );
|
||||
float dist = AABBDistance( mins, maxs, testMins, testMaxs );
|
||||
if ( dist < bestDist )
|
||||
{
|
||||
bestDist = dist;
|
||||
bestIndex = testIndex;
|
||||
}
|
||||
}
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
// maps a float to a byte fraction between min & max
|
||||
static byte Fixed8Fraction( float t, float tMin, float tMax )
|
||||
{
|
||||
if ( tMax <= tMin )
|
||||
return 0;
|
||||
|
||||
float frac = RemapValClamped( t, tMin, tMax, 0.0f, 255.0f );
|
||||
return byte(frac+0.5f);
|
||||
}
|
||||
|
||||
CUtlVector< CUtlVector<ambientsample_t> > g_LeafAmbientSamples;
|
||||
|
||||
void ComputeAmbientForLeaf( int iThread, int leafID, CUtlVector<ambientsample_t> &list )
|
||||
{
|
||||
CUtlVector<dplane_t> leafPlanes;
|
||||
CLeafSampler sampler( iThread );
|
||||
|
||||
GetLeafBoundaryPlanes( leafPlanes, leafID );
|
||||
list.RemoveAll();
|
||||
// this heuristic tries to generate at least one sample per volume (chosen to be similar to the size of a player) in the space
|
||||
int xSize = (dleafs[leafID].maxs[0] - dleafs[leafID].mins[0]) / 32;
|
||||
int ySize = (dleafs[leafID].maxs[1] - dleafs[leafID].mins[1]) / 32;
|
||||
int zSize = (dleafs[leafID].maxs[2] - dleafs[leafID].mins[2]) / 64;
|
||||
xSize = max(xSize,1);
|
||||
ySize = max(xSize,1);
|
||||
zSize = max(xSize,1);
|
||||
// generate update 128 candidate samples, always at least one sample
|
||||
int volumeCount = xSize * ySize * zSize;
|
||||
if ( g_bFastAmbient )
|
||||
{
|
||||
// save compute time, only do one sample
|
||||
volumeCount = 1;
|
||||
}
|
||||
int sampleCount = clamp( volumeCount, 1, 128 );
|
||||
if ( dleafs[leafID].contents & CONTENTS_SOLID )
|
||||
{
|
||||
// don't generate any samples in solid leaves
|
||||
// NOTE: We copy the nearest non-solid leaf sample pointers into this leaf at the end
|
||||
return;
|
||||
}
|
||||
Vector cube[6];
|
||||
for ( int i = 0; i < sampleCount; i++ )
|
||||
{
|
||||
// compute each candidate sample and add to the list
|
||||
Vector samplePosition;
|
||||
sampler.GenerateLeafSamplePosition( leafID, leafPlanes, samplePosition );
|
||||
ComputeAmbientFromSphericalSamples( iThread, samplePosition, cube );
|
||||
// note this will remove the least valuable sample once the limit is reached
|
||||
AddSampleToList( list, samplePosition, cube );
|
||||
}
|
||||
|
||||
// remove any samples that can be reconstructed with the remaining data
|
||||
CompressAmbientSampleList( list );
|
||||
}
|
||||
|
||||
static void ThreadComputeLeafAmbient( int iThread, void *pUserData )
|
||||
{
|
||||
CUtlVector<ambientsample_t> list;
|
||||
while (1)
|
||||
{
|
||||
int leafID = GetThreadWork ();
|
||||
if (leafID == -1)
|
||||
break;
|
||||
list.RemoveAll();
|
||||
ComputeAmbientForLeaf(iThread, leafID, list);
|
||||
// copy to the output array
|
||||
g_LeafAmbientSamples[leafID].SetCount( list.Count() );
|
||||
for ( int i = 0; i < list.Count(); i++ )
|
||||
{
|
||||
g_LeafAmbientSamples[leafID].Element(i) = list.Element(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VMPI_ProcessLeafAmbient( int iThread, uint64 iLeaf, MessageBuffer *pBuf )
|
||||
{
|
||||
CUtlVector<ambientsample_t> list;
|
||||
ComputeAmbientForLeaf(iThread, (int)iLeaf, list);
|
||||
|
||||
VMPI_SetCurrentStage( "EncodeLeafAmbientResults" );
|
||||
|
||||
// Encode the results.
|
||||
int nSamples = list.Count();
|
||||
pBuf->write( &nSamples, sizeof( nSamples ) );
|
||||
if ( nSamples )
|
||||
{
|
||||
pBuf->write( list.Base(), list.Count() * sizeof( ambientsample_t ) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called on the master when a worker finishes processing a static prop.
|
||||
//-----------------------------------------------------------------------------
|
||||
void VMPI_ReceiveLeafAmbientResults( uint64 leafID, MessageBuffer *pBuf, int iWorker )
|
||||
{
|
||||
// Decode the results.
|
||||
int nSamples;
|
||||
pBuf->read( &nSamples, sizeof( nSamples ) );
|
||||
|
||||
g_LeafAmbientSamples[leafID].SetCount( nSamples );
|
||||
if ( nSamples )
|
||||
{
|
||||
pBuf->read(g_LeafAmbientSamples[leafID].Base(), nSamples * sizeof(ambientsample_t) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ComputePerLeafAmbientLighting()
|
||||
{
|
||||
// Figure out which lights should go in the per-leaf ambient cubes.
|
||||
int nInAmbientCube = 0;
|
||||
int nSurfaceLights = 0;
|
||||
for ( int i=0; i < *pNumworldlights; i++ )
|
||||
{
|
||||
dworldlight_t *wl = &dworldlights[i];
|
||||
|
||||
if ( IsLeafAmbientSurfaceLight( wl ) )
|
||||
wl->flags |= DWL_FLAGS_INAMBIENTCUBE;
|
||||
else
|
||||
wl->flags &= ~DWL_FLAGS_INAMBIENTCUBE;
|
||||
|
||||
if ( wl->type == emit_surface )
|
||||
++nSurfaceLights;
|
||||
|
||||
if ( wl->flags & DWL_FLAGS_INAMBIENTCUBE )
|
||||
++nInAmbientCube;
|
||||
}
|
||||
|
||||
Msg( "%d of %d (%d%% of) surface lights went in leaf ambient cubes.\n", nInAmbientCube, nSurfaceLights, nSurfaceLights ? ((nInAmbientCube*100) / nSurfaceLights) : 0 );
|
||||
|
||||
g_LeafAmbientSamples.SetCount(numleafs);
|
||||
|
||||
if ( g_bUseMPI )
|
||||
{
|
||||
// Distribute the work among the workers.
|
||||
VMPI_SetCurrentStage( "ComputeLeafAmbientLighting" );
|
||||
DistributeWork( numleafs, VMPI_DISTRIBUTEWORK_PACKETID, VMPI_ProcessLeafAmbient, VMPI_ReceiveLeafAmbientResults );
|
||||
}
|
||||
else
|
||||
{
|
||||
RunThreadsOn(numleafs, true, ThreadComputeLeafAmbient);
|
||||
}
|
||||
|
||||
// now write out the data
|
||||
Msg("Writing leaf ambient...");
|
||||
g_pLeafAmbientIndex->RemoveAll();
|
||||
g_pLeafAmbientLighting->RemoveAll();
|
||||
g_pLeafAmbientIndex->SetCount( numleafs );
|
||||
g_pLeafAmbientLighting->EnsureCapacity( numleafs*4 );
|
||||
for ( int leafID = 0; leafID < numleafs; leafID++ )
|
||||
{
|
||||
const CUtlVector<ambientsample_t> &list = g_LeafAmbientSamples[leafID];
|
||||
g_pLeafAmbientIndex->Element(leafID).ambientSampleCount = list.Count();
|
||||
if ( !list.Count() )
|
||||
{
|
||||
g_pLeafAmbientIndex->Element(leafID).firstAmbientSample = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pLeafAmbientIndex->Element(leafID).firstAmbientSample = g_pLeafAmbientLighting->Count();
|
||||
// compute the samples in disk format. Encode the positions in 8-bits using leaf bounds fractions
|
||||
for ( int i = 0; i < list.Count(); i++ )
|
||||
{
|
||||
int outIndex = g_pLeafAmbientLighting->AddToTail();
|
||||
dleafambientlighting_t &light = g_pLeafAmbientLighting->Element(outIndex);
|
||||
|
||||
light.x = Fixed8Fraction( list[i].pos.x, dleafs[leafID].mins[0], dleafs[leafID].maxs[0] );
|
||||
light.y = Fixed8Fraction( list[i].pos.y, dleafs[leafID].mins[1], dleafs[leafID].maxs[1] );
|
||||
light.z = Fixed8Fraction( list[i].pos.z, dleafs[leafID].mins[2], dleafs[leafID].maxs[2] );
|
||||
light.pad = 0;
|
||||
for ( int side = 0; side < 6; side++ )
|
||||
{
|
||||
VectorToColorRGBExp32( list[i].cube[side], light.cube.m_Color[side] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( int i = 0; i < numleafs; i++ )
|
||||
{
|
||||
// UNDONE: Do this dynamically in the engine instead. This will allow us to sample across leaf
|
||||
// boundaries always which should improve the quality of lighting in general
|
||||
if ( g_pLeafAmbientIndex->Element(i).ambientSampleCount == 0 )
|
||||
{
|
||||
if ( !(dleafs[i].contents & CONTENTS_SOLID) )
|
||||
{
|
||||
Msg("Bad leaf ambient for leaf %d\n", i );
|
||||
}
|
||||
|
||||
int refLeaf = NearestNeighborWithLight(i);
|
||||
g_pLeafAmbientIndex->Element(i).ambientSampleCount = 0;
|
||||
g_pLeafAmbientIndex->Element(i).firstAmbientSample = refLeaf;
|
||||
}
|
||||
}
|
||||
Msg("done\n");
|
||||
}
|
||||
|
17
utils/vrad/leaf_ambient_lighting.h
Normal file
17
utils/vrad/leaf_ambient_lighting.h
Normal file
@ -0,0 +1,17 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef LEAF_AMBIENT_LIGHTING_H
|
||||
#define LEAF_AMBIENT_LIGHTING_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
void ComputePerLeafAmbientLighting();
|
||||
|
||||
|
||||
#endif // LEAF_AMBIENT_LIGHTING_H
|
3576
utils/vrad/lightmap.cpp
Normal file
3576
utils/vrad/lightmap.cpp
Normal file
File diff suppressed because it is too large
Load Diff
141
utils/vrad/lightmap.h
Normal file
141
utils/vrad/lightmap.h
Normal file
@ -0,0 +1,141 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef LIGHTMAP_H
|
||||
#define LIGHTMAP_H
|
||||
#pragma once
|
||||
|
||||
#include "mathlib/bumpvects.h"
|
||||
#include "bsplib.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dface_t *faces[2];
|
||||
Vector interface_normal;
|
||||
qboolean coplanar;
|
||||
} edgeshare_t;
|
||||
|
||||
extern edgeshare_t edgeshare[MAX_MAP_EDGES];
|
||||
|
||||
|
||||
//==============================================
|
||||
|
||||
// This is incremented each time BuildFaceLights and FinalLightFace
|
||||
// are called. It's used for a status bar in WorldCraft.
|
||||
extern int g_iCurFace;
|
||||
|
||||
extern int vertexref[MAX_MAP_VERTS];
|
||||
extern int *vertexface[MAX_MAP_VERTS];
|
||||
|
||||
struct faceneighbor_t
|
||||
{
|
||||
int numneighbors; // neighboring faces that share vertices
|
||||
int *neighbor; // neighboring face list (max of 64)
|
||||
|
||||
Vector *normal; // adjusted normal per vertex
|
||||
Vector facenormal; // face normal
|
||||
|
||||
bool bHasDisp; // is this surface a displacement surface???
|
||||
};
|
||||
|
||||
extern faceneighbor_t faceneighbor[MAX_MAP_FACES];
|
||||
|
||||
//==============================================
|
||||
|
||||
|
||||
struct sample_t
|
||||
{
|
||||
// in local luxel space
|
||||
winding_t *w;
|
||||
int s, t;
|
||||
Vector2D coord;
|
||||
Vector2D mins;
|
||||
Vector2D maxs;
|
||||
// in world units
|
||||
Vector pos;
|
||||
Vector normal;
|
||||
float area;
|
||||
};
|
||||
|
||||
struct facelight_t
|
||||
{
|
||||
// irregularly shaped light sample data, clipped by face and luxel grid
|
||||
int numsamples;
|
||||
sample_t *sample;
|
||||
LightingValue_t *light[MAXLIGHTMAPS][NUM_BUMP_VECTS+1]; // result of direct illumination, indexed by sample
|
||||
|
||||
// regularly spaced lightmap grid
|
||||
int numluxels;
|
||||
Vector *luxel; // world space position of luxel
|
||||
Vector *luxelNormals; // world space normal of luxel
|
||||
float worldAreaPerLuxel;
|
||||
};
|
||||
|
||||
extern directlight_t *activelights;
|
||||
extern directlight_t *freelights;
|
||||
|
||||
extern facelight_t facelight[MAX_MAP_FACES];
|
||||
extern int numdlights;
|
||||
|
||||
|
||||
//==============================================
|
||||
|
||||
struct lightinfo_t
|
||||
{
|
||||
vec_t facedist;
|
||||
Vector facenormal;
|
||||
|
||||
Vector facemid; // world coordinates of center
|
||||
|
||||
Vector modelorg; // for origined bmodels
|
||||
|
||||
Vector luxelOrigin;
|
||||
Vector worldToLuxelSpace[2]; // s = (world - luxelOrigin) . worldToLuxelSpace[0], t = (world - luxelOrigin) . worldToLuxelSpace[1]
|
||||
Vector luxelToWorldSpace[2]; // world = luxelOrigin + s * luxelToWorldSpace[0] + t * luxelToWorldSpace[1]
|
||||
|
||||
int facenum;
|
||||
dface_t *face;
|
||||
|
||||
int isflat;
|
||||
int hasbumpmap;
|
||||
};
|
||||
|
||||
struct SSE_SampleInfo_t
|
||||
{
|
||||
int m_FaceNum;
|
||||
int m_WarnFace;
|
||||
dface_t *m_pFace;
|
||||
facelight_t *m_pFaceLight;
|
||||
int m_LightmapWidth;
|
||||
int m_LightmapHeight;
|
||||
int m_LightmapSize;
|
||||
int m_NormalCount;
|
||||
int m_iThread;
|
||||
texinfo_t *m_pTexInfo;
|
||||
bool m_IsDispFace;
|
||||
|
||||
int m_NumSamples;
|
||||
int m_NumSampleGroups;
|
||||
int m_Clusters[4];
|
||||
FourVectors m_Points;
|
||||
FourVectors m_PointNormals[ NUM_BUMP_VECTS + 1 ];
|
||||
};
|
||||
|
||||
extern void InitLightinfo( lightinfo_t *l, int facenum );
|
||||
|
||||
void FreeDLights();
|
||||
|
||||
void ExportDirectLightsToWorldLights();
|
||||
|
||||
|
||||
#endif // LIGHTMAP_H
|
166
utils/vrad/macro_texture.cpp
Normal file
166
utils/vrad/macro_texture.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier1/strtools.h"
|
||||
#include "macro_texture.h"
|
||||
#include "bsplib.h"
|
||||
#include "cmdlib.h"
|
||||
#include "vtf/vtf.h"
|
||||
#include "tier1/utldict.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "bitmap/imageformat.h"
|
||||
|
||||
|
||||
class CMacroTextureData
|
||||
{
|
||||
public:
|
||||
int m_Width, m_Height;
|
||||
CUtlMemory<unsigned char> m_ImageData;
|
||||
};
|
||||
|
||||
|
||||
CMacroTextureData *g_pGlobalMacroTextureData = NULL;
|
||||
|
||||
// Which macro texture each map face uses.
|
||||
static CUtlDict<CMacroTextureData*, int> g_MacroTextureLookup; // Stores a list of unique macro textures.
|
||||
static CUtlVector<CMacroTextureData*> g_FaceMacroTextures; // Which macro texture each face wants to use.
|
||||
static Vector g_MacroWorldMins, g_MacroWorldMaxs;
|
||||
|
||||
|
||||
CMacroTextureData* FindMacroTexture( const char *pFilename )
|
||||
{
|
||||
int index = g_MacroTextureLookup.Find( pFilename );
|
||||
if ( g_MacroTextureLookup.IsValidIndex( index ) )
|
||||
return g_MacroTextureLookup[index];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
CMacroTextureData* LoadMacroTextureFile( const char *pFilename )
|
||||
{
|
||||
FileHandle_t hFile = g_pFileSystem->Open( pFilename, "rb" );
|
||||
if ( hFile == FILESYSTEM_INVALID_HANDLE )
|
||||
return NULL;
|
||||
|
||||
// Read the file in.
|
||||
CUtlVector<char> tempData;
|
||||
tempData.SetSize( g_pFileSystem->Size( hFile ) );
|
||||
g_pFileSystem->Read( tempData.Base(), tempData.Count(), hFile );
|
||||
g_pFileSystem->Close( hFile );
|
||||
|
||||
|
||||
// Now feed the data into a CUtlBuffer (great...)
|
||||
CUtlBuffer buf;
|
||||
buf.Put( tempData.Base(), tempData.Count() );
|
||||
|
||||
|
||||
// Now make a texture out of it.
|
||||
IVTFTexture *pTex = CreateVTFTexture();
|
||||
if ( !pTex->Unserialize( buf ) )
|
||||
Error( "IVTFTexture::Unserialize( %s ) failed.", pFilename );
|
||||
|
||||
pTex->ConvertImageFormat( IMAGE_FORMAT_RGBA8888, false ); // Get it in a format we like.
|
||||
|
||||
|
||||
// Now convert to a CMacroTextureData.
|
||||
CMacroTextureData *pData = new CMacroTextureData;
|
||||
pData->m_Width = pTex->Width();
|
||||
pData->m_Height = pTex->Height();
|
||||
pData->m_ImageData.EnsureCapacity( pData->m_Width * pData->m_Height * 4 );
|
||||
memcpy( pData->m_ImageData.Base(), pTex->ImageData(), pData->m_Width * pData->m_Height * 4 );
|
||||
|
||||
DestroyVTFTexture( pTex );
|
||||
|
||||
Msg( "-- LoadMacroTextureFile: %s\n", pFilename );
|
||||
return pData;
|
||||
}
|
||||
|
||||
|
||||
void InitMacroTexture( const char *pBSPFilename )
|
||||
{
|
||||
// Get the world bounds (same ones used by minimaps and level designers know how to use).
|
||||
int i = 0;
|
||||
for (i; i < num_entities; ++i)
|
||||
{
|
||||
char* pEntity = ValueForKey(&entities[i], "classname");
|
||||
if( !strcmp(pEntity, "worldspawn") )
|
||||
{
|
||||
GetVectorForKey( &entities[i], "world_mins", g_MacroWorldMins );
|
||||
GetVectorForKey( &entities[i], "world_maxs", g_MacroWorldMaxs );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i == num_entities )
|
||||
{
|
||||
Warning( "MaskOnMacroTexture: can't find worldspawn" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Load the macro texture that is mapped onto everything.
|
||||
char mapName[512], vtfFilename[512];
|
||||
Q_FileBase( pBSPFilename, mapName, sizeof( mapName ) );
|
||||
Q_snprintf( vtfFilename, sizeof( vtfFilename ), "materials/macro/%s/base.vtf", mapName );
|
||||
g_pGlobalMacroTextureData = LoadMacroTextureFile( vtfFilename );
|
||||
|
||||
|
||||
// Now load the macro texture for each face.
|
||||
g_FaceMacroTextures.SetSize( numfaces );
|
||||
for ( int iFace=0; iFace < numfaces; iFace++ )
|
||||
{
|
||||
g_FaceMacroTextures[iFace] = NULL;
|
||||
|
||||
if ( iFace < g_FaceMacroTextureInfos.Count() )
|
||||
{
|
||||
unsigned short stringID = g_FaceMacroTextureInfos[iFace].m_MacroTextureNameID;
|
||||
if ( stringID != 0xFFFF )
|
||||
{
|
||||
const char *pMacroTextureName = &g_TexDataStringData[ g_TexDataStringTable[stringID] ];
|
||||
Q_snprintf( vtfFilename, sizeof( vtfFilename ), "%smaterials/%s.vtf", gamedir, pMacroTextureName );
|
||||
|
||||
g_FaceMacroTextures[iFace] = FindMacroTexture( vtfFilename );
|
||||
if ( !g_FaceMacroTextures[iFace] )
|
||||
{
|
||||
g_FaceMacroTextures[iFace] = LoadMacroTextureFile( vtfFilename );
|
||||
if ( g_FaceMacroTextures[iFace] )
|
||||
{
|
||||
g_MacroTextureLookup.Insert( vtfFilename, g_FaceMacroTextures[iFace] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline Vector SampleMacroTexture( const CMacroTextureData *t, const Vector &vWorldPos )
|
||||
{
|
||||
int ix = (int)RemapVal( vWorldPos.x, g_MacroWorldMins.x, g_MacroWorldMaxs.x, 0, t->m_Width-0.00001 );
|
||||
int iy = (int)RemapVal( vWorldPos.y, g_MacroWorldMins.y, g_MacroWorldMaxs.y, 0, t->m_Height-0.00001 );
|
||||
ix = clamp( ix, 0, t->m_Width-1 );
|
||||
iy = t->m_Height - 1 - clamp( iy, 0, t->m_Height-1 );
|
||||
|
||||
const unsigned char *pInputColor = &t->m_ImageData[(iy*t->m_Width + ix) * 4];
|
||||
return Vector( pInputColor[0] / 255.0, pInputColor[1] / 255.0, pInputColor[2] / 255.0 );
|
||||
}
|
||||
|
||||
|
||||
void ApplyMacroTextures( int iFace, const Vector &vWorldPos, Vector &outLuxel )
|
||||
{
|
||||
// Add the global macro texture.
|
||||
Vector vGlobal;
|
||||
if ( g_pGlobalMacroTextureData )
|
||||
outLuxel *= SampleMacroTexture( g_pGlobalMacroTextureData, vWorldPos );
|
||||
|
||||
// Now add the per-material macro texture.
|
||||
if ( g_FaceMacroTextures[iFace] )
|
||||
outLuxel *= SampleMacroTexture( g_FaceMacroTextures[iFace], vWorldPos );
|
||||
}
|
||||
|
||||
|
||||
|
24
utils/vrad/macro_texture.h
Normal file
24
utils/vrad/macro_texture.h
Normal file
@ -0,0 +1,24 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MACRO_TEXTURE_H
|
||||
#define MACRO_TEXTURE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
|
||||
// The macro texture looks for a TGA file with the same name as the BSP file and in
|
||||
// the same directory. If it finds one, it maps this texture onto the world dimensions
|
||||
// (in the worldspawn entity) and masks all lightmaps with it.
|
||||
void InitMacroTexture( const char *pBSPFilename );
|
||||
void ApplyMacroTextures( int iFace, const Vector &vWorldPos, Vector &outLuxel );
|
||||
|
||||
|
||||
#endif // MACRO_TEXTURE_H
|
496
utils/vrad/mpivrad.cpp
Normal file
496
utils/vrad/mpivrad.cpp
Normal file
@ -0,0 +1,496 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
//
|
||||
// mpivrad.cpp
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
#include <conio.h>
|
||||
#include "vrad.h"
|
||||
#include "physdll.h"
|
||||
#include "lightmap.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "radial.h"
|
||||
#include "utlbuffer.h"
|
||||
#include "pacifier.h"
|
||||
#include "messbuf.h"
|
||||
#include "bsplib.h"
|
||||
#include "consolewnd.h"
|
||||
#include "vismat.h"
|
||||
#include "vmpi_filesystem.h"
|
||||
#include "vmpi_dispatch.h"
|
||||
#include "utllinkedlist.h"
|
||||
#include "vmpi.h"
|
||||
#include "mpi_stats.h"
|
||||
#include "vmpi_distribute_work.h"
|
||||
#include "vmpi_tools_shared.h"
|
||||
|
||||
|
||||
|
||||
|
||||
CUtlVector<char> g_LightResultsFilename;
|
||||
|
||||
|
||||
extern int total_transfer;
|
||||
extern int max_transfer;
|
||||
|
||||
extern void BuildVisLeafs(int);
|
||||
extern void BuildPatchLights( int facenum );
|
||||
|
||||
|
||||
// Handle VRAD packets.
|
||||
bool VRAD_DispatchFn( MessageBuffer *pBuf, int iSource, int iPacketID )
|
||||
{
|
||||
switch( pBuf->data[1] )
|
||||
{
|
||||
case VMPI_SUBPACKETID_PLIGHTDATA_RESULTS:
|
||||
{
|
||||
const char *pFilename = &pBuf->data[2];
|
||||
g_LightResultsFilename.CopyArray( pFilename, strlen( pFilename ) + 1 );
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
CDispatchReg g_VRADDispatchReg( VMPI_VRAD_PACKET_ID, VRAD_DispatchFn ); // register to handle the messages we want
|
||||
CDispatchReg g_DistributeWorkReg( VMPI_DISTRIBUTEWORK_PACKETID, DistributeWorkDispatch );
|
||||
|
||||
|
||||
|
||||
void VRAD_SetupMPI( int &argc, char **&argv )
|
||||
{
|
||||
CmdLib_AtCleanup( VMPI_Stats_Term );
|
||||
|
||||
//
|
||||
// Preliminary check -mpi flag
|
||||
//
|
||||
if ( !VMPI_FindArg( argc, argv, "-mpi", "" ) && !VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Worker ), "" ) )
|
||||
return;
|
||||
|
||||
// Force local mode?
|
||||
VMPIRunMode mode;
|
||||
if ( VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Local ), "" ) )
|
||||
mode = VMPI_RUN_LOCAL;
|
||||
else
|
||||
mode = VMPI_RUN_NETWORKED;
|
||||
|
||||
VMPI_Stats_InstallSpewHook();
|
||||
|
||||
//
|
||||
// Extract mpi specific arguments
|
||||
//
|
||||
Msg( "Initializing VMPI...\n" );
|
||||
if ( !VMPI_Init(
|
||||
argc,
|
||||
argv,
|
||||
"dependency_info_vrad.txt",
|
||||
HandleMPIDisconnect,
|
||||
mode
|
||||
) )
|
||||
{
|
||||
Error( "MPI_Init failed." );
|
||||
}
|
||||
|
||||
StatsDB_InitStatsDatabase( argc, argv, "dbinfo_vrad.txt" );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
//
|
||||
// Run BuildFaceLights across all available processing nodes
|
||||
// and collect the results.
|
||||
//
|
||||
|
||||
CCycleCount g_CPUTime;
|
||||
|
||||
|
||||
template<class T> void WriteValues( MessageBuffer *pmb, T const *pSrc, int nNumValues)
|
||||
{
|
||||
pmb->write(pSrc, sizeof( pSrc[0]) * nNumValues );
|
||||
}
|
||||
|
||||
template<class T> int ReadValues( MessageBuffer *pmb, T *pDest, int nNumValues)
|
||||
{
|
||||
return pmb->read( pDest, sizeof( pDest[0]) * nNumValues );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Serialize face data
|
||||
void SerializeFace( MessageBuffer * pmb, int facenum )
|
||||
{
|
||||
int i, n;
|
||||
|
||||
dface_t * f = &g_pFaces[facenum];
|
||||
facelight_t * fl = &facelight[facenum];
|
||||
|
||||
pmb->write(f, sizeof(dface_t));
|
||||
pmb->write(fl, sizeof(facelight_t));
|
||||
|
||||
WriteValues( pmb, fl->sample, fl->numsamples);
|
||||
|
||||
//
|
||||
// Write the light information
|
||||
//
|
||||
for (i=0; i<MAXLIGHTMAPS; ++i) {
|
||||
for (n=0; n<NUM_BUMP_VECTS+1; ++n) {
|
||||
if (fl->light[i][n])
|
||||
{
|
||||
WriteValues( pmb, fl->light[i][n], fl->numsamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fl->luxel)
|
||||
WriteValues( pmb, fl->luxel, fl->numluxels);
|
||||
|
||||
if (fl->luxelNormals)
|
||||
WriteValues( pmb, fl->luxelNormals, fl->numluxels);
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// UnSerialize face data
|
||||
//
|
||||
void UnSerializeFace( MessageBuffer * pmb, int facenum, int iSource )
|
||||
{
|
||||
int i, n;
|
||||
|
||||
dface_t * f = &g_pFaces[facenum];
|
||||
facelight_t * fl = &facelight[facenum];
|
||||
|
||||
if (pmb->read(f, sizeof(dface_t)) < 0)
|
||||
Error("UnSerializeFace - invalid dface_t from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
|
||||
|
||||
if (pmb->read(fl, sizeof(facelight_t)) < 0)
|
||||
Error("UnSerializeFace - invalid facelight_t from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
|
||||
|
||||
fl->sample = (sample_t *) calloc(fl->numsamples, sizeof(sample_t));
|
||||
if (pmb->read(fl->sample, sizeof(sample_t) * fl->numsamples) < 0)
|
||||
Error("UnSerializeFace - invalid sample_t from %s (mb len: %d, offset: %d, fl->numsamples: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset(), fl->numsamples );
|
||||
|
||||
//
|
||||
// Read the light information
|
||||
//
|
||||
for (i=0; i<MAXLIGHTMAPS; ++i) {
|
||||
for (n=0; n<NUM_BUMP_VECTS+1; ++n) {
|
||||
if (fl->light[i][n])
|
||||
{
|
||||
fl->light[i][n] = (LightingValue_t *) calloc( fl->numsamples, sizeof(LightingValue_t ) );
|
||||
if ( ReadValues( pmb, fl->light[i][n], fl->numsamples) < 0)
|
||||
Error("UnSerializeFace - invalid fl->light from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fl->luxel) {
|
||||
fl->luxel = (Vector *) calloc(fl->numluxels, sizeof(Vector));
|
||||
if (ReadValues( pmb, fl->luxel, fl->numluxels) < 0)
|
||||
Error("UnSerializeFace - invalid fl->luxel from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
|
||||
}
|
||||
|
||||
if (fl->luxelNormals) {
|
||||
fl->luxelNormals = (Vector *) calloc(fl->numluxels, sizeof( Vector ));
|
||||
if ( ReadValues( pmb, fl->luxelNormals, fl->numluxels) < 0)
|
||||
Error("UnSerializeFace - invalid fl->luxelNormals from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MPI_ReceiveFaceResults( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker )
|
||||
{
|
||||
UnSerializeFace( pBuf, iWorkUnit, iWorker );
|
||||
}
|
||||
|
||||
|
||||
void MPI_ProcessFaces( int iThread, uint64 iWorkUnit, MessageBuffer *pBuf )
|
||||
{
|
||||
// Do BuildFacelights on the face.
|
||||
CTimeAdder adder( &g_CPUTime );
|
||||
|
||||
BuildFacelights( iThread, iWorkUnit );
|
||||
|
||||
// Send the results.
|
||||
if ( pBuf )
|
||||
{
|
||||
SerializeFace( pBuf, iWorkUnit );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RunMPIBuildFacelights()
|
||||
{
|
||||
g_CPUTime.Init();
|
||||
|
||||
Msg( "%-20s ", "BuildFaceLights:" );
|
||||
if ( g_bMPIMaster )
|
||||
{
|
||||
StartPacifier("");
|
||||
}
|
||||
|
||||
VMPI_SetCurrentStage( "RunMPIBuildFaceLights" );
|
||||
double elapsed = DistributeWork(
|
||||
numfaces,
|
||||
VMPI_DISTRIBUTEWORK_PACKETID,
|
||||
MPI_ProcessFaces,
|
||||
MPI_ReceiveFaceResults );
|
||||
|
||||
if ( g_bMPIMaster )
|
||||
{
|
||||
EndPacifier(false);
|
||||
Msg( " (%d)\n", (int)elapsed );
|
||||
}
|
||||
|
||||
if ( g_bMPIMaster )
|
||||
{
|
||||
//
|
||||
// BuildPatchLights is normally called from BuildFacelights(),
|
||||
// but in MPI mode we have the master do the calculation
|
||||
// We might be able to speed this up by doing while the master
|
||||
// is idling in the above loop. Wouldn't want to slow down the
|
||||
// handing out of work - maybe another thread?
|
||||
//
|
||||
for ( int i=0; i < numfaces; ++i )
|
||||
{
|
||||
BuildPatchLights(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( g_iVMPIVerboseLevel >= 1 )
|
||||
Msg( "\n\n%.1f%% CPU utilization during BuildFaceLights\n\n", ( g_CPUTime.GetSeconds() * 100 / elapsed ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
//
|
||||
// Run BuildVisLeafs across all available processing nodes
|
||||
// and collect the results.
|
||||
//
|
||||
|
||||
// This function is called when the master receives results back from a worker.
|
||||
void MPI_ReceiveVisLeafsResults( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker )
|
||||
{
|
||||
int patchesInCluster = 0;
|
||||
|
||||
pBuf->read(&patchesInCluster, sizeof(patchesInCluster));
|
||||
|
||||
for ( int k=0; k < patchesInCluster; ++k )
|
||||
{
|
||||
int patchnum = 0;
|
||||
pBuf->read(&patchnum, sizeof(patchnum));
|
||||
|
||||
CPatch * patch = &g_Patches[patchnum];
|
||||
int numtransfers;
|
||||
pBuf->read( &numtransfers, sizeof(numtransfers) );
|
||||
patch->numtransfers = numtransfers;
|
||||
if (numtransfers)
|
||||
{
|
||||
patch->transfers = new transfer_t[numtransfers];
|
||||
pBuf->read(patch->transfers, numtransfers * sizeof(transfer_t));
|
||||
}
|
||||
|
||||
total_transfer += numtransfers;
|
||||
if (max_transfer < numtransfers)
|
||||
max_transfer = numtransfers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Temporary variables used during callbacks. If we're going to be threadsafe, these
|
||||
// should go in a structure and get passed around.
|
||||
class CVMPIVisLeafsData
|
||||
{
|
||||
public:
|
||||
MessageBuffer *m_pVisLeafsMB;
|
||||
int m_nPatchesInCluster;
|
||||
transfer_t *m_pBuildVisLeafsTransfers;
|
||||
};
|
||||
|
||||
CVMPIVisLeafsData g_VMPIVisLeafsData[MAX_TOOL_THREADS+1];
|
||||
|
||||
|
||||
|
||||
// This is called by BuildVisLeafs_Cluster every time it finishes a patch.
|
||||
// The results are appended to g_VisLeafsMB and sent back to the master when all clusters are done.
|
||||
void MPI_AddPatchData( int iThread, int patchnum, CPatch *patch )
|
||||
{
|
||||
CVMPIVisLeafsData *pData = &g_VMPIVisLeafsData[iThread];
|
||||
if ( pData->m_pVisLeafsMB )
|
||||
{
|
||||
// Add in results for this patch
|
||||
++pData->m_nPatchesInCluster;
|
||||
pData->m_pVisLeafsMB->write(&patchnum, sizeof(patchnum));
|
||||
pData->m_pVisLeafsMB->write(&patch->numtransfers, sizeof(patch->numtransfers));
|
||||
pData->m_pVisLeafsMB->write( patch->transfers, patch->numtransfers * sizeof(transfer_t) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This handles a work unit sent by the master. Each work unit here is a
|
||||
// list of clusters.
|
||||
void MPI_ProcessVisLeafs( int iThread, uint64 iWorkUnit, MessageBuffer *pBuf )
|
||||
{
|
||||
CTimeAdder adder( &g_CPUTime );
|
||||
|
||||
CVMPIVisLeafsData *pData = &g_VMPIVisLeafsData[iThread];
|
||||
int iCluster = iWorkUnit;
|
||||
|
||||
// Start this cluster.
|
||||
pData->m_nPatchesInCluster = 0;
|
||||
pData->m_pVisLeafsMB = pBuf;
|
||||
|
||||
// Write a temp value in there. We overwrite it later.
|
||||
int iSavePos = 0;
|
||||
if ( pBuf )
|
||||
{
|
||||
iSavePos = pBuf->getLen();
|
||||
pBuf->write( &pData->m_nPatchesInCluster, sizeof(pData->m_nPatchesInCluster) );
|
||||
}
|
||||
|
||||
// Collect the results in MPI_AddPatchData.
|
||||
BuildVisLeafs_Cluster( iThread, pData->m_pBuildVisLeafsTransfers, iCluster, MPI_AddPatchData );
|
||||
|
||||
// Now send the results back..
|
||||
if ( pBuf )
|
||||
{
|
||||
pBuf->update( iSavePos, &pData->m_nPatchesInCluster, sizeof(pData->m_nPatchesInCluster) );
|
||||
pData->m_pVisLeafsMB = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RunMPIBuildVisLeafs()
|
||||
{
|
||||
g_CPUTime.Init();
|
||||
|
||||
Msg( "%-20s ", "BuildVisLeafs :" );
|
||||
if ( g_bMPIMaster )
|
||||
{
|
||||
StartPacifier("");
|
||||
}
|
||||
|
||||
memset( g_VMPIVisLeafsData, 0, sizeof( g_VMPIVisLeafsData ) );
|
||||
if ( !g_bMPIMaster || VMPI_GetActiveWorkUnitDistributor() == k_eWorkUnitDistributor_SDK )
|
||||
{
|
||||
// Allocate space for the transfers for each thread.
|
||||
for ( int i=0; i < numthreads; i++ )
|
||||
{
|
||||
g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers = BuildVisLeafs_Start();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Slaves ask for work via GetMPIBuildVisLeafWork()
|
||||
// Results are returned in BuildVisRow()
|
||||
//
|
||||
VMPI_SetCurrentStage( "RunMPIBuildVisLeafs" );
|
||||
|
||||
double elapsed = DistributeWork(
|
||||
dvis->numclusters,
|
||||
VMPI_DISTRIBUTEWORK_PACKETID,
|
||||
MPI_ProcessVisLeafs,
|
||||
MPI_ReceiveVisLeafsResults );
|
||||
|
||||
// Free the transfers from each thread.
|
||||
for ( int i=0; i < numthreads; i++ )
|
||||
{
|
||||
if ( g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers )
|
||||
BuildVisLeafs_End( g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers );
|
||||
}
|
||||
|
||||
if ( g_bMPIMaster )
|
||||
{
|
||||
EndPacifier(false);
|
||||
Msg( " (%d)\n", (int)elapsed );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( g_iVMPIVerboseLevel >= 1 )
|
||||
Msg( "%.1f%% CPU utilization during PortalFlow\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads );
|
||||
}
|
||||
}
|
||||
|
||||
void VMPI_DistributeLightData()
|
||||
{
|
||||
if ( !g_bUseMPI )
|
||||
return;
|
||||
|
||||
if ( g_bMPIMaster )
|
||||
{
|
||||
const char *pVirtualFilename = "--plightdata--";
|
||||
|
||||
CUtlBuffer lightFaceData;
|
||||
|
||||
// write out the light data
|
||||
lightFaceData.EnsureCapacity( pdlightdata->Count() + (numfaces * (MAXLIGHTMAPS+sizeof(int))) );
|
||||
Q_memcpy( lightFaceData.PeekPut(), pdlightdata->Base(), pdlightdata->Count() );
|
||||
lightFaceData.SeekPut( CUtlBuffer::SEEK_HEAD, pdlightdata->Count() );
|
||||
|
||||
// write out the relevant face info into the stream
|
||||
for ( int i = 0; i < numfaces; i++ )
|
||||
{
|
||||
for ( int j = 0; j < MAXLIGHTMAPS; j++ )
|
||||
{
|
||||
lightFaceData.PutChar(g_pFaces[i].styles[j]);
|
||||
}
|
||||
lightFaceData.PutInt(g_pFaces[i].lightofs);
|
||||
}
|
||||
VMPI_FileSystem_CreateVirtualFile( pVirtualFilename, lightFaceData.Base(), lightFaceData.TellMaxPut() );
|
||||
|
||||
char cPacketID[2] = { VMPI_VRAD_PACKET_ID, VMPI_SUBPACKETID_PLIGHTDATA_RESULTS };
|
||||
VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), pVirtualFilename, strlen( pVirtualFilename ) + 1, VMPI_PERSISTENT );
|
||||
}
|
||||
else
|
||||
{
|
||||
VMPI_SetCurrentStage( "VMPI_DistributeLightData" );
|
||||
|
||||
// Wait until we've received the filename from the master.
|
||||
while ( g_LightResultsFilename.Count() == 0 )
|
||||
{
|
||||
VMPI_DispatchNextMessage();
|
||||
}
|
||||
|
||||
// Open
|
||||
FileHandle_t fp = g_pFileSystem->Open( g_LightResultsFilename.Base(), "rb", VMPI_VIRTUAL_FILES_PATH_ID );
|
||||
if ( !fp )
|
||||
Error( "Can't open '%s' to read lighting info.", g_LightResultsFilename.Base() );
|
||||
|
||||
int size = g_pFileSystem->Size( fp );
|
||||
int faceSize = (numfaces*(MAXLIGHTMAPS+sizeof(int)));
|
||||
|
||||
if ( size > faceSize )
|
||||
{
|
||||
int lightSize = size - faceSize;
|
||||
CUtlBuffer faceData;
|
||||
pdlightdata->EnsureCount( lightSize );
|
||||
faceData.EnsureCapacity( faceSize );
|
||||
|
||||
g_pFileSystem->Read( pdlightdata->Base(), lightSize, fp );
|
||||
g_pFileSystem->Read( faceData.Base(), faceSize, fp );
|
||||
g_pFileSystem->Close( fp );
|
||||
|
||||
faceData.SeekPut( CUtlBuffer::SEEK_HEAD, faceSize );
|
||||
|
||||
// write out the face data
|
||||
for ( int i = 0; i < numfaces; i++ )
|
||||
{
|
||||
for ( int j = 0; j < MAXLIGHTMAPS; j++ )
|
||||
{
|
||||
g_pFaces[i].styles[j] = faceData.GetChar();
|
||||
}
|
||||
g_pFaces[i].lightofs = faceData.GetInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
36
utils/vrad/mpivrad.h
Normal file
36
utils/vrad/mpivrad.h
Normal file
@ -0,0 +1,36 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MPIVRAD_H
|
||||
#define MPIVRAD_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define VMPI_VRAD_PACKET_ID 1
|
||||
// Sub packet IDs.
|
||||
#define VMPI_SUBPACKETID_VIS_LEAFS 0
|
||||
#define VMPI_SUBPACKETID_BUILDFACELIGHTS 1
|
||||
#define VMPI_SUBPACKETID_PLIGHTDATA_RESULTS 2
|
||||
|
||||
// DistributeWork owns this packet ID.
|
||||
#define VMPI_DISTRIBUTEWORK_PACKETID 2
|
||||
|
||||
|
||||
// Called first thing in the exe.
|
||||
void VRAD_SetupMPI( int &argc, char **&argv );
|
||||
|
||||
void RunMPIBuildFacelights(void);
|
||||
void RunMPIBuildVisLeafs(void);
|
||||
void VMPI_DistributeLightData();
|
||||
|
||||
// This handles disconnections. They're usually not fatal for the master.
|
||||
void HandleMPIDisconnect( int procID );
|
||||
|
||||
|
||||
#endif // MPIVRAD_H
|
22
utils/vrad/notes.txt
Normal file
22
utils/vrad/notes.txt
Normal file
@ -0,0 +1,22 @@
|
||||
//=============================================================================
|
||||
// CHARLIE:
|
||||
|
||||
DONE: just rename files from .c to .cpp in source safe so history is kept
|
||||
converting files of to .cpp files -- just get stuff recompiling first
|
||||
make sure all common files and external dependencies handle .cpp files
|
||||
add the dispmap class
|
||||
add the dispface class
|
||||
get rid of patches.c or patches.cpp as the case may be
|
||||
|
||||
DONE: create a parallel array for visited displacement faces
|
||||
change the visited array to a flag in the "bsp" ddispface_t structure
|
||||
DONE: add reset visited displacement face functionality
|
||||
DONE: visited neighbor flags
|
||||
DONE: reset visited neighbor flags
|
||||
DONE: move the radial_t structure and some of its functionality to a more global scope
|
||||
DONE: create a finallightdispface
|
||||
DONE: generate luxels for displacement face
|
||||
DONE: fix precomplightmapoffsets to take displacement faces into account
|
||||
fill in luxel data from sample data
|
||||
modify the GetPhongNormal and GatherSampleLight functions to use displacement face normals at "spot"
|
||||
make a lightinfo list? -- so we don't regenerate initlightinfo so many times?
|
51
utils/vrad/origface.cpp
Normal file
51
utils/vrad/origface.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "vrad.h"
|
||||
|
||||
bool bOrigFacesTouched[MAX_MAP_FACES];
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Pupose: clear (reset) the bOrigFacesTouched list -- parellels the original
|
||||
// face list allowing an original face to only be processed once in
|
||||
// pairing edges!
|
||||
//-----------------------------------------------------------------------------
|
||||
void ResetOrigFacesTouched( void )
|
||||
{
|
||||
for( int i = 0; i < MAX_MAP_FACES; i++ )
|
||||
{
|
||||
bOrigFacesTouched[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: mark an original faces as touched (dirty)
|
||||
// Input: index - index of the original face touched
|
||||
//-----------------------------------------------------------------------------
|
||||
void SetOrigFaceTouched( int index )
|
||||
{
|
||||
bOrigFacesTouched[index] = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return whether or not an original face has been touched
|
||||
// Input: index - index of the original face touched
|
||||
// Output: true/false
|
||||
//-----------------------------------------------------------------------------
|
||||
bool IsOrigFaceTouched( int index )
|
||||
{
|
||||
return bOrigFacesTouched[index];
|
||||
}
|
882
utils/vrad/radial.cpp
Normal file
882
utils/vrad/radial.cpp
Normal file
@ -0,0 +1,882 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "vrad.h"
|
||||
#include "lightmap.h"
|
||||
#include "radial.h"
|
||||
#include "mathlib/bumpvects.h"
|
||||
#include "utlrbtree.h"
|
||||
#include "mathlib/VMatrix.h"
|
||||
#include "macro_texture.h"
|
||||
|
||||
|
||||
void WorldToLuxelSpace( lightinfo_t const *l, Vector const &world, Vector2D &coord )
|
||||
{
|
||||
Vector pos;
|
||||
|
||||
VectorSubtract( world, l->luxelOrigin, pos );
|
||||
coord[0] = DotProduct( pos, l->worldToLuxelSpace[0] ) - l->face->m_LightmapTextureMinsInLuxels[0];
|
||||
coord[1] = DotProduct( pos, l->worldToLuxelSpace[1] ) - l->face->m_LightmapTextureMinsInLuxels[1];
|
||||
}
|
||||
|
||||
void LuxelSpaceToWorld( lightinfo_t const *l, float s, float t, Vector &world )
|
||||
{
|
||||
Vector pos;
|
||||
|
||||
s += l->face->m_LightmapTextureMinsInLuxels[0];
|
||||
t += l->face->m_LightmapTextureMinsInLuxels[1];
|
||||
VectorMA( l->luxelOrigin, s, l->luxelToWorldSpace[0], pos );
|
||||
VectorMA( pos, t, l->luxelToWorldSpace[1], world );
|
||||
}
|
||||
|
||||
void WorldToLuxelSpace( lightinfo_t const *l, FourVectors const &world, FourVectors &coord )
|
||||
{
|
||||
FourVectors luxelOrigin;
|
||||
luxelOrigin.DuplicateVector ( l->luxelOrigin );
|
||||
|
||||
FourVectors pos = world;
|
||||
pos -= luxelOrigin;
|
||||
|
||||
coord.x = pos * l->worldToLuxelSpace[0];
|
||||
coord.x = SubSIMD ( coord.x, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[0] ) );
|
||||
coord.y = pos * l->worldToLuxelSpace[1];
|
||||
coord.y = SubSIMD ( coord.y, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[1] ) );
|
||||
coord.z = Four_Zeros;
|
||||
}
|
||||
|
||||
void LuxelSpaceToWorld( lightinfo_t const *l, fltx4 s, fltx4 t, FourVectors &world )
|
||||
{
|
||||
world.DuplicateVector ( l->luxelOrigin );
|
||||
FourVectors st;
|
||||
|
||||
s = AddSIMD ( s, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[0] ) );
|
||||
st.DuplicateVector ( l->luxelToWorldSpace[0] );
|
||||
st *= s;
|
||||
world += st;
|
||||
|
||||
t = AddSIMD ( t, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[1] ) );
|
||||
st.DuplicateVector ( l->luxelToWorldSpace[1] );
|
||||
st *= t;
|
||||
world += st;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AddDirectToRadial( radial_t *rad,
|
||||
Vector const &pnt,
|
||||
Vector2D const &coordmins, Vector2D const &coordmaxs,
|
||||
LightingValue_t const light[NUM_BUMP_VECTS+1],
|
||||
bool hasBumpmap, bool neighborHasBumpmap )
|
||||
{
|
||||
int s_min, s_max, t_min, t_max;
|
||||
Vector2D coord;
|
||||
int s, t;
|
||||
float ds, dt;
|
||||
float r;
|
||||
float area;
|
||||
int bumpSample;
|
||||
|
||||
// convert world pos into local lightmap texture coord
|
||||
WorldToLuxelSpace( &rad->l, pnt, coord );
|
||||
|
||||
s_min = ( int )( coordmins[0] );
|
||||
t_min = ( int )( coordmins[1] );
|
||||
s_max = ( int )( coordmaxs[0] + 0.9999f ) + 1; // ????
|
||||
t_max = ( int )( coordmaxs[1] + 0.9999f ) + 1;
|
||||
|
||||
s_min = max( s_min, 0 );
|
||||
t_min = max( t_min, 0 );
|
||||
s_max = min( s_max, rad->w );
|
||||
t_max = min( t_max, rad->h );
|
||||
|
||||
for( s = s_min; s < s_max; s++ )
|
||||
{
|
||||
for( t = t_min; t < t_max; t++ )
|
||||
{
|
||||
float s0 = max( coordmins[0] - s, -1.0 );
|
||||
float t0 = max( coordmins[1] - t, -1.0 );
|
||||
float s1 = min( coordmaxs[0] - s, 1.0 );
|
||||
float t1 = min( coordmaxs[1] - t, 1.0 );
|
||||
|
||||
area = (s1 - s0) * (t1 - t0);
|
||||
|
||||
if (area > EQUAL_EPSILON)
|
||||
{
|
||||
ds = fabs( coord[0] - s );
|
||||
dt = fabs( coord[1] - t );
|
||||
|
||||
r = max( ds, dt );
|
||||
|
||||
if (r < 0.1)
|
||||
{
|
||||
r = area / 0.1;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = area / r;
|
||||
}
|
||||
|
||||
int i = s+t*rad->w;
|
||||
|
||||
if( hasBumpmap )
|
||||
{
|
||||
if( neighborHasBumpmap )
|
||||
{
|
||||
for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
|
||||
{
|
||||
rad->light[bumpSample][i].AddWeighted( light[bumpSample], r );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rad->light[0][i].AddWeighted(light[0],r );
|
||||
for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
|
||||
{
|
||||
rad->light[bumpSample][i].AddWeighted( light[0], r * OO_SQRT_3 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rad->light[0][i].AddWeighted( light[0], r );
|
||||
}
|
||||
|
||||
rad->weight[i] += r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AddBouncedToRadial( radial_t *rad,
|
||||
Vector const &pnt,
|
||||
Vector2D const &coordmins, Vector2D const &coordmaxs,
|
||||
Vector const light[NUM_BUMP_VECTS+1],
|
||||
bool hasBumpmap, bool neighborHasBumpmap )
|
||||
{
|
||||
int s_min, s_max, t_min, t_max;
|
||||
Vector2D coord;
|
||||
int s, t;
|
||||
float ds, dt;
|
||||
float r;
|
||||
int bumpSample;
|
||||
|
||||
// convert world pos into local lightmap texture coord
|
||||
WorldToLuxelSpace( &rad->l, pnt, coord );
|
||||
|
||||
float dists, distt;
|
||||
|
||||
dists = (coordmaxs[0] - coordmins[0]);
|
||||
distt = (coordmaxs[1] - coordmins[1]);
|
||||
|
||||
// patches less than a luxel in size could be mistakeningly filtered, so clamp.
|
||||
dists = max( 1.0, dists );
|
||||
distt = max( 1.0, distt );
|
||||
|
||||
// find possible domain of patch influence
|
||||
s_min = ( int )( coord[0] - dists * RADIALDIST );
|
||||
t_min = ( int )( coord[1] - distt * RADIALDIST );
|
||||
s_max = ( int )( coord[0] + dists * RADIALDIST + 1.0f );
|
||||
t_max = ( int )( coord[1] + distt * RADIALDIST + 1.0f );
|
||||
|
||||
// clamp to valid luxel
|
||||
s_min = max( s_min, 0 );
|
||||
t_min = max( t_min, 0 );
|
||||
s_max = min( s_max, rad->w );
|
||||
t_max = min( t_max, rad->h );
|
||||
|
||||
for( s = s_min; s < s_max; s++ )
|
||||
{
|
||||
for( t = t_min; t < t_max; t++ )
|
||||
{
|
||||
// patch influence is based on patch size
|
||||
ds = ( coord[0] - s ) / dists;
|
||||
dt = ( coord[1] - t ) / distt;
|
||||
|
||||
r = RADIALDIST2 - (ds * ds + dt * dt);
|
||||
|
||||
int i = s+t*rad->w;
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
if( hasBumpmap )
|
||||
{
|
||||
if( neighborHasBumpmap )
|
||||
{
|
||||
for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
|
||||
{
|
||||
rad->light[bumpSample][i].AddWeighted( light[bumpSample], r );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rad->light[0][i].AddWeighted( light[0], r );
|
||||
for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
|
||||
{
|
||||
rad->light[bumpSample][i].AddWeighted( light[0], r * OO_SQRT_3 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rad->light[0][i].AddWeighted( light[0], r );
|
||||
}
|
||||
|
||||
rad->weight[i] += r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PatchLightmapCoordRange( radial_t *rad, int ndxPatch, Vector2D &mins, Vector2D &maxs )
|
||||
{
|
||||
winding_t *w;
|
||||
int i;
|
||||
Vector2D coord;
|
||||
|
||||
mins.Init( 1E30, 1E30 );
|
||||
maxs.Init( -1E30, -1E30 );
|
||||
|
||||
CPatch *patch = &g_Patches.Element( ndxPatch );
|
||||
w = patch->winding;
|
||||
|
||||
for (i = 0; i < w->numpoints; i++)
|
||||
{
|
||||
WorldToLuxelSpace( &rad->l, w->p[i], coord );
|
||||
mins[0] = min( mins[0], coord[0] );
|
||||
maxs[0] = max( maxs[0], coord[0] );
|
||||
mins[1] = min( mins[1], coord[1] );
|
||||
maxs[1] = max( maxs[1], coord[1] );
|
||||
}
|
||||
}
|
||||
|
||||
radial_t *AllocateRadial( int facenum )
|
||||
{
|
||||
radial_t *rad;
|
||||
|
||||
rad = ( radial_t* )calloc( 1, sizeof( *rad ) );
|
||||
|
||||
rad->facenum = facenum;
|
||||
InitLightinfo( &rad->l, facenum );
|
||||
|
||||
rad->w = rad->l.face->m_LightmapTextureSizeInLuxels[0]+1;
|
||||
rad->h = rad->l.face->m_LightmapTextureSizeInLuxels[1]+1;
|
||||
|
||||
return rad;
|
||||
}
|
||||
|
||||
void FreeRadial( radial_t *rad )
|
||||
{
|
||||
if (rad)
|
||||
free( rad );
|
||||
}
|
||||
|
||||
|
||||
radial_t *BuildPatchRadial( int facenum )
|
||||
{
|
||||
int j;
|
||||
radial_t *rad;
|
||||
CPatch *patch;
|
||||
faceneighbor_t *fn;
|
||||
Vector2D mins, maxs;
|
||||
bool needsBumpmap, neighborNeedsBumpmap;
|
||||
|
||||
needsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;
|
||||
|
||||
rad = AllocateRadial( facenum );
|
||||
|
||||
fn = &faceneighbor[ rad->facenum ];
|
||||
|
||||
CPatch *pNextPatch;
|
||||
|
||||
if( g_FacePatches.Element( rad->facenum ) != g_FacePatches.InvalidIndex() )
|
||||
{
|
||||
for( patch = &g_Patches.Element( g_FacePatches.Element( rad->facenum ) ); patch; patch = pNextPatch )
|
||||
{
|
||||
// next patch
|
||||
pNextPatch = NULL;
|
||||
if( patch->ndxNext != g_Patches.InvalidIndex() )
|
||||
{
|
||||
pNextPatch = &g_Patches.Element( patch->ndxNext );
|
||||
}
|
||||
|
||||
// skip patches with children
|
||||
if (patch->child1 != g_Patches.InvalidIndex() )
|
||||
continue;
|
||||
|
||||
// get the range of patch lightmap texture coords
|
||||
int ndxPatch = patch - g_Patches.Base();
|
||||
PatchLightmapCoordRange( rad, ndxPatch, mins, maxs );
|
||||
|
||||
if (patch->numtransfers == 0)
|
||||
{
|
||||
// Error, using patch that was never evaluated or has no samples
|
||||
// patch->totallight[1] = 255;
|
||||
}
|
||||
|
||||
//
|
||||
// displacement surface patch origin position and normal vectors have been changed to
|
||||
// represent the displacement surface position and normal -- for radial "blending"
|
||||
// we need to get the base surface patch origin!
|
||||
//
|
||||
if( ValidDispFace( &g_pFaces[facenum] ) )
|
||||
{
|
||||
Vector patchOrigin;
|
||||
WindingCenter (patch->winding, patchOrigin );
|
||||
AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light,
|
||||
needsBumpmap, needsBumpmap );
|
||||
}
|
||||
else
|
||||
{
|
||||
AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light,
|
||||
needsBumpmap, needsBumpmap );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0 ; j<fn->numneighbors; j++)
|
||||
{
|
||||
if( g_FacePatches.Element( fn->neighbor[j] ) != g_FacePatches.InvalidIndex() )
|
||||
{
|
||||
for( patch = &g_Patches.Element( g_FacePatches.Element( fn->neighbor[j] ) ); patch; patch = pNextPatch )
|
||||
{
|
||||
// next patch
|
||||
pNextPatch = NULL;
|
||||
if( patch->ndxNext != g_Patches.InvalidIndex() )
|
||||
{
|
||||
pNextPatch = &g_Patches.Element( patch->ndxNext );
|
||||
}
|
||||
|
||||
// skip patches with children
|
||||
if (patch->child1 != g_Patches.InvalidIndex() )
|
||||
continue;
|
||||
|
||||
// get the range of patch lightmap texture coords
|
||||
int ndxPatch = patch - g_Patches.Base();
|
||||
PatchLightmapCoordRange( rad, ndxPatch, mins, maxs );
|
||||
|
||||
neighborNeedsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;
|
||||
|
||||
//
|
||||
// displacement surface patch origin position and normal vectors have been changed to
|
||||
// represent the displacement surface position and normal -- for radial "blending"
|
||||
// we need to get the base surface patch origin!
|
||||
//
|
||||
if( ValidDispFace( &g_pFaces[fn->neighbor[j]] ) )
|
||||
{
|
||||
Vector patchOrigin;
|
||||
WindingCenter (patch->winding, patchOrigin );
|
||||
AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light,
|
||||
needsBumpmap, needsBumpmap );
|
||||
}
|
||||
else
|
||||
{
|
||||
AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light,
|
||||
needsBumpmap, needsBumpmap );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rad;
|
||||
}
|
||||
|
||||
|
||||
radial_t *BuildLuxelRadial( int facenum, int style )
|
||||
{
|
||||
LightingValue_t light[NUM_BUMP_VECTS + 1];
|
||||
|
||||
facelight_t *fl = &facelight[facenum];
|
||||
faceneighbor_t *fn = &faceneighbor[facenum];
|
||||
|
||||
radial_t *rad = AllocateRadial( facenum );
|
||||
|
||||
bool needsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;
|
||||
|
||||
for (int k=0 ; k<fl->numsamples ; k++)
|
||||
{
|
||||
if( needsBumpmap )
|
||||
{
|
||||
for( int bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
|
||||
{
|
||||
light[bumpSample] = fl->light[style][bumpSample][k];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
light[0] = fl->light[style][0][k];
|
||||
}
|
||||
|
||||
AddDirectToRadial( rad, fl->sample[k].pos, fl->sample[k].mins, fl->sample[k].maxs, light, needsBumpmap, needsBumpmap );
|
||||
}
|
||||
|
||||
for (int j = 0; j < fn->numneighbors; j++)
|
||||
{
|
||||
fl = &facelight[fn->neighbor[j]];
|
||||
|
||||
bool neighborHasBumpmap = false;
|
||||
|
||||
if( texinfo[g_pFaces[fn->neighbor[j]].texinfo].flags & SURF_BUMPLIGHT )
|
||||
{
|
||||
neighborHasBumpmap = true;
|
||||
}
|
||||
|
||||
int nstyle = 0;
|
||||
|
||||
// look for style that matches
|
||||
if (g_pFaces[fn->neighbor[j]].styles[nstyle] != g_pFaces[facenum].styles[style])
|
||||
{
|
||||
for (nstyle = 1; nstyle < MAXLIGHTMAPS; nstyle++ )
|
||||
if ( g_pFaces[fn->neighbor[j]].styles[nstyle] == g_pFaces[facenum].styles[style] )
|
||||
break;
|
||||
|
||||
// if not found, skip this neighbor
|
||||
if (nstyle >= MAXLIGHTMAPS)
|
||||
continue;
|
||||
}
|
||||
|
||||
lightinfo_t l;
|
||||
|
||||
InitLightinfo( &l, fn->neighbor[j] );
|
||||
|
||||
for (int k=0 ; k<fl->numsamples ; k++)
|
||||
{
|
||||
if( neighborHasBumpmap )
|
||||
{
|
||||
for( int bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
|
||||
{
|
||||
light[bumpSample] = fl->light[nstyle][bumpSample][k];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
light[0]=fl->light[nstyle][0][k];
|
||||
}
|
||||
|
||||
Vector tmp;
|
||||
Vector2D mins, maxs;
|
||||
|
||||
LuxelSpaceToWorld( &l, fl->sample[k].mins[0], fl->sample[k].mins[1], tmp );
|
||||
WorldToLuxelSpace( &rad->l, tmp, mins );
|
||||
LuxelSpaceToWorld( &l, fl->sample[k].maxs[0], fl->sample[k].maxs[1], tmp );
|
||||
WorldToLuxelSpace( &rad->l, tmp, maxs );
|
||||
|
||||
AddDirectToRadial( rad, fl->sample[k].pos, mins, maxs, light,
|
||||
needsBumpmap, neighborHasBumpmap );
|
||||
}
|
||||
}
|
||||
|
||||
return rad;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the closest light value for a given point on the surface
|
||||
// this is normally a 1:1 mapping
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SampleRadial( radial_t *rad, Vector& pnt, LightingValue_t light[NUM_BUMP_VECTS + 1], int bumpSampleCount )
|
||||
{
|
||||
int bumpSample;
|
||||
Vector2D coord;
|
||||
|
||||
WorldToLuxelSpace( &rad->l, pnt, coord );
|
||||
int u = ( int )( coord[0] + 0.5f );
|
||||
int v = ( int )( coord[1] + 0.5f );
|
||||
int i = u + v * rad->w;
|
||||
|
||||
if (u < 0 || u > rad->w || v < 0 || v > rad->h)
|
||||
{
|
||||
static bool warning = false;
|
||||
if ( !warning )
|
||||
{
|
||||
// punting over to KenB
|
||||
// 2d coord indexes off of lightmap, generation of pnt seems suspect
|
||||
Warning( "SampleRadial: Punting, Waiting for fix\n" );
|
||||
warning = true;
|
||||
}
|
||||
for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
|
||||
{
|
||||
light[bumpSample].m_vecLighting.Init( 2550, 0, 0 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool baseSampleOk = true;
|
||||
for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
|
||||
{
|
||||
light[bumpSample].Zero();
|
||||
|
||||
if (rad->weight[i] > WEIGHT_EPS)
|
||||
{
|
||||
light[bumpSample]= rad->light[bumpSample][i];
|
||||
light[bumpSample].Scale( 1.0 / rad->weight[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( bRed2Black )
|
||||
{
|
||||
// Error, luxel has no samples
|
||||
light[bumpSample].m_vecLighting.Init( 0, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error, luxel has no samples
|
||||
// Yes, it actually should be 2550
|
||||
light[bumpSample].m_vecLighting.Init( 2550, 0, 0 );
|
||||
}
|
||||
|
||||
if (bumpSample == 0)
|
||||
baseSampleOk = false;
|
||||
}
|
||||
}
|
||||
|
||||
return baseSampleOk;
|
||||
}
|
||||
|
||||
bool FloatLess( float const& src1, float const& src2 )
|
||||
{
|
||||
return src1 < src2;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Debugging!
|
||||
//-----------------------------------------------------------------------------
|
||||
void GetRandomColor( unsigned char *color )
|
||||
{
|
||||
static bool firstTime = true;
|
||||
|
||||
if( firstTime )
|
||||
{
|
||||
firstTime = false;
|
||||
srand( 0 );
|
||||
}
|
||||
|
||||
color[0] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) );
|
||||
color[1] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) );
|
||||
color[2] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) );
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// debugging! -- not accurate!
|
||||
void DumpLuxels( facelight_t *pFaceLight, Vector *luxelColors, int ndxFace )
|
||||
{
|
||||
static FileHandle_t pFpLuxels = NULL;
|
||||
|
||||
ThreadLock();
|
||||
|
||||
if( !pFpLuxels )
|
||||
{
|
||||
pFpLuxels = g_pFileSystem->Open( "luxels.txt", "w" );
|
||||
}
|
||||
|
||||
dface_t *pFace = &g_pFaces[ndxFace];
|
||||
bool bDisp = ( pFace->dispinfo != -1 );
|
||||
|
||||
for( int ndx = 0; ndx < pFaceLight->numluxels; ndx++ )
|
||||
{
|
||||
WriteWinding( pFpLuxels, pFaceLight->sample[ndx].w, luxelColors[ndx] );
|
||||
if( bDumpNormals && bDisp )
|
||||
{
|
||||
WriteNormal( pFpLuxels, pFaceLight->luxel[ndx], pFaceLight->luxelNormals[ndx], 15.0f, Vector( 255, 255, 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
ThreadUnlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static FileHandle_t pFileLuxels[4] = { NULL, NULL, NULL, NULL };
|
||||
|
||||
void DumpDispLuxels( int iFace, Vector &color, int iLuxel, int nBump )
|
||||
{
|
||||
// Lock the thread and dump the luxel data.
|
||||
ThreadLock();
|
||||
|
||||
// Get the face and facelight data.
|
||||
facelight_t *pFaceLight = &facelight[iFace];
|
||||
|
||||
// Open the luxel files.
|
||||
char szFileName[512];
|
||||
for ( int iBump = 0; iBump < ( NUM_BUMP_VECTS+1 ); ++iBump )
|
||||
{
|
||||
if ( pFileLuxels[iBump] == NULL )
|
||||
{
|
||||
sprintf( szFileName, "luxels_bump%d.txt", iBump );
|
||||
pFileLuxels[iBump] = g_pFileSystem->Open( szFileName, "w" );
|
||||
}
|
||||
}
|
||||
|
||||
WriteWinding( pFileLuxels[nBump], pFaceLight->sample[iLuxel].w, color );
|
||||
|
||||
ThreadUnlock();
|
||||
}
|
||||
|
||||
void CloseDispLuxels()
|
||||
{
|
||||
for ( int iBump = 0; iBump < ( NUM_BUMP_VECTS+1 ); ++iBump )
|
||||
{
|
||||
if ( pFileLuxels[iBump] )
|
||||
{
|
||||
g_pFileSystem->Close( pFileLuxels[iBump] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
FinalLightFace
|
||||
|
||||
Add the indirect lighting on top of the direct
|
||||
lighting and save into final map format
|
||||
=============
|
||||
*/
|
||||
void FinalLightFace( int iThread, int facenum )
|
||||
{
|
||||
dface_t *f;
|
||||
int i, j, k;
|
||||
facelight_t *fl;
|
||||
float minlight;
|
||||
int lightstyles;
|
||||
LightingValue_t lb[NUM_BUMP_VECTS + 1], v[NUM_BUMP_VECTS + 1];
|
||||
unsigned char *pdata[NUM_BUMP_VECTS + 1];
|
||||
int bumpSample;
|
||||
radial_t *rad = NULL;
|
||||
radial_t *prad = NULL;
|
||||
|
||||
f = &g_pFaces[facenum];
|
||||
|
||||
// test for non-lit texture
|
||||
if ( texinfo[f->texinfo].flags & TEX_SPECIAL)
|
||||
return;
|
||||
|
||||
fl = &facelight[facenum];
|
||||
|
||||
|
||||
for (lightstyles=0; lightstyles < MAXLIGHTMAPS; lightstyles++ )
|
||||
{
|
||||
if ( f->styles[lightstyles] == 255 )
|
||||
break;
|
||||
}
|
||||
if ( !lightstyles )
|
||||
return;
|
||||
|
||||
|
||||
//
|
||||
// sample the triangulation
|
||||
//
|
||||
minlight = FloatForKey (face_entity[facenum], "_minlight") * 128;
|
||||
|
||||
bool needsBumpmap = ( texinfo[f->texinfo].flags & SURF_BUMPLIGHT ) ? true : false;
|
||||
int bumpSampleCount = needsBumpmap ? NUM_BUMP_VECTS + 1 : 1;
|
||||
|
||||
bool bDisp = ( f->dispinfo != -1 );
|
||||
|
||||
//#define RANDOM_COLOR
|
||||
|
||||
#ifdef RANDOM_COLOR
|
||||
unsigned char randomColor[3];
|
||||
GetRandomColor( randomColor );
|
||||
#endif
|
||||
|
||||
|
||||
// NOTE: I'm using these RB trees to sort all the illumination values
|
||||
// to compute median colors. Turns out that this is a somewhat better
|
||||
// method that using the average; usually if there are surfaces
|
||||
// with a large light intensity variation, the extremely bright regions
|
||||
// have a very small area and tend to influence the average too much.
|
||||
CUtlRBTree< float, int > m_Red( 0, 256, FloatLess );
|
||||
CUtlRBTree< float, int > m_Green( 0, 256, FloatLess );
|
||||
CUtlRBTree< float, int > m_Blue( 0, 256, FloatLess );
|
||||
|
||||
for (k=0 ; k < lightstyles; k++ )
|
||||
{
|
||||
m_Red.RemoveAll();
|
||||
m_Green.RemoveAll();
|
||||
m_Blue.RemoveAll();
|
||||
|
||||
if (!do_fast)
|
||||
{
|
||||
if( !bDisp )
|
||||
{
|
||||
rad = BuildLuxelRadial( facenum, k );
|
||||
}
|
||||
else
|
||||
{
|
||||
rad = StaticDispMgr()->BuildLuxelRadial( facenum, k, needsBumpmap );
|
||||
}
|
||||
}
|
||||
|
||||
if (numbounce > 0 && k == 0)
|
||||
{
|
||||
// currently only radiosity light non-displacement surfaces!
|
||||
if( !bDisp )
|
||||
{
|
||||
prad = BuildPatchRadial( facenum );
|
||||
}
|
||||
else
|
||||
{
|
||||
prad = StaticDispMgr()->BuildPatchRadial( facenum, needsBumpmap );
|
||||
}
|
||||
}
|
||||
|
||||
// pack the nonbump texture and the three bump texture for the given
|
||||
// lightstyle right next to each other.
|
||||
// NOTE: Even though it's building positions for all bump-mapped data,
|
||||
// it isn't going to use those positions (see loop over bumpSample below)
|
||||
// The file offset is correctly computed to only store space for 1 set
|
||||
// of light data if we don't have bumped lighting.
|
||||
for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
|
||||
{
|
||||
pdata[bumpSample] = &(*pdlightdata)[f->lightofs + (k * bumpSampleCount + bumpSample) * fl->numluxels*4];
|
||||
}
|
||||
|
||||
// Compute the average luxel color, but not for the bump samples
|
||||
Vector avg( 0.0f, 0.0f, 0.0f );
|
||||
int avgCount = 0;
|
||||
|
||||
for (j=0 ; j<fl->numluxels; j++)
|
||||
{
|
||||
// garymct - direct lighting
|
||||
bool baseSampleOk = true;
|
||||
|
||||
if (!do_fast)
|
||||
{
|
||||
if( !bDisp )
|
||||
{
|
||||
baseSampleOk = SampleRadial( rad, fl->luxel[j], lb, bumpSampleCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
baseSampleOk = StaticDispMgr()->SampleRadial( facenum, rad, fl->luxel[j], j, lb, bumpSampleCount, false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int iBump = 0 ; iBump < bumpSampleCount; iBump++ )
|
||||
{
|
||||
lb[iBump] = fl->light[0][iBump][j];
|
||||
}
|
||||
}
|
||||
|
||||
if (prad)
|
||||
{
|
||||
// garymct - bounced light
|
||||
// v is indirect light that is received on the luxel.
|
||||
if( !bDisp )
|
||||
{
|
||||
SampleRadial( prad, fl->luxel[j], v, bumpSampleCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
StaticDispMgr()->SampleRadial( facenum, prad, fl->luxel[j], j, v, bumpSampleCount, true );
|
||||
}
|
||||
|
||||
for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
|
||||
{
|
||||
lb[bumpSample].AddLight( v[bumpSample] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( bDisp && g_bDumpPatches )
|
||||
{
|
||||
for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
|
||||
{
|
||||
DumpDispLuxels( facenum, lb[bumpSample].m_vecLighting, j, bumpSample );
|
||||
}
|
||||
}
|
||||
|
||||
if (fl->numsamples == 0)
|
||||
{
|
||||
for( i = 0; i < bumpSampleCount; i++ )
|
||||
{
|
||||
lb[i].Init( 255, 0, 0 );
|
||||
}
|
||||
baseSampleOk = false;
|
||||
}
|
||||
|
||||
int bumpSample;
|
||||
for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
|
||||
{
|
||||
// clip from the bottom first
|
||||
// garymct: minlight is a per entity minimum light value?
|
||||
for( i=0; i<3; i++ )
|
||||
{
|
||||
lb[bumpSample].m_vecLighting[i] = max( lb[bumpSample].m_vecLighting[i], minlight );
|
||||
}
|
||||
|
||||
// Do the average light computation, I'm assuming (perhaps incorrectly?)
|
||||
// that all luxels in a particular lightmap have the same area here.
|
||||
// Also, don't bother doing averages for the bump samples. Doing it here
|
||||
// because of the minlight clamp above + the random color testy thingy.
|
||||
// Also have to do it before Vec3toColorRGBExp32 because it
|
||||
// destructively modifies lb[bumpSample] (Feh!)
|
||||
if ((bumpSample == 0) && baseSampleOk)
|
||||
{
|
||||
++avgCount;
|
||||
|
||||
ApplyMacroTextures( facenum, fl->luxel[j], lb[0].m_vecLighting );
|
||||
|
||||
// For median computation
|
||||
m_Red.Insert( lb[bumpSample].m_vecLighting[0] );
|
||||
m_Green.Insert( lb[bumpSample].m_vecLighting[1] );
|
||||
m_Blue.Insert( lb[bumpSample].m_vecLighting[2] );
|
||||
}
|
||||
|
||||
#ifdef RANDOM_COLOR
|
||||
pdata[bumpSample][0] = randomColor[0] / ( bumpSample + 1 );
|
||||
pdata[bumpSample][1] = randomColor[1] / ( bumpSample + 1 );
|
||||
pdata[bumpSample][2] = randomColor[2] / ( bumpSample + 1 );
|
||||
pdata[bumpSample][3] = 0;
|
||||
#else
|
||||
// convert to a 4 byte r,g,b,signed exponent format
|
||||
VectorToColorRGBExp32( Vector( lb[bumpSample].m_vecLighting.x, lb[bumpSample].m_vecLighting.y,
|
||||
lb[bumpSample].m_vecLighting.z ), *( ColorRGBExp32 *)pdata[bumpSample] );
|
||||
#endif
|
||||
|
||||
pdata[bumpSample] += 4;
|
||||
}
|
||||
}
|
||||
FreeRadial( rad );
|
||||
if (prad)
|
||||
{
|
||||
FreeRadial( prad );
|
||||
prad = NULL;
|
||||
}
|
||||
|
||||
// Compute the median color for this lightstyle
|
||||
// Remember, the data goes *before* the specified light_ofs, in *reverse order*
|
||||
ColorRGBExp32 *pAvgColor = dface_AvgLightColor( f, k );
|
||||
if (avgCount == 0)
|
||||
{
|
||||
Vector median( 0, 0, 0 );
|
||||
VectorToColorRGBExp32( median, *pAvgColor );
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int r, g, b;
|
||||
r = m_Red.FirstInorder();
|
||||
g = m_Green.FirstInorder();
|
||||
b = m_Blue.FirstInorder();
|
||||
avgCount >>= 1;
|
||||
while (avgCount > 0)
|
||||
{
|
||||
r = m_Red.NextInorder(r);
|
||||
g = m_Green.NextInorder(g);
|
||||
b = m_Blue.NextInorder(b);
|
||||
--avgCount;
|
||||
}
|
||||
|
||||
Vector median( m_Red[r], m_Green[g], m_Blue[b] );
|
||||
VectorToColorRGBExp32( median, *pAvgColor );
|
||||
}
|
||||
}
|
||||
}
|
76
utils/vrad/radial.h
Normal file
76
utils/vrad/radial.h
Normal file
@ -0,0 +1,76 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef RADIAL_H
|
||||
#define RADIAL_H
|
||||
#pragma once
|
||||
|
||||
#include "mathlib/bumpvects.h"
|
||||
#include "mathlib/ssemath.h"
|
||||
#include "lightmap.h"
|
||||
|
||||
#define RADIALDIST2 2 // (1.25*1.25+1.25*1.25)
|
||||
#define RADIALDIST 1.42 // 1.77 // sqrt( RADIALDIST2 )
|
||||
|
||||
#define WEIGHT_EPS 0.00001f
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The radial_t data structure is used to accumulate irregularly spaced and irregularly
|
||||
// shaped direct and indirect lighting samples into a uniformly spaced and shaped luxel grid.
|
||||
//
|
||||
// The name "radial" is more historical than discriptive; it stems from the filtering method,
|
||||
// one of several methods initially tried. Since all the other methods have since been deleted,
|
||||
// it would probably be more accurate to rename it something like "LuxelAccumulationBucket" or
|
||||
// something similar, but since "radial" is fairly meaningless it's not like it's actually confusing
|
||||
// the issue.
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct radial_s
|
||||
{
|
||||
int facenum;
|
||||
lightinfo_t l;
|
||||
int w, h;
|
||||
float weight[SINGLEMAP];
|
||||
LightingValue_t light[NUM_BUMP_VECTS + 1][SINGLEMAP];
|
||||
} radial_t;
|
||||
|
||||
|
||||
void WorldToLuxelSpace( lightinfo_t const *l, Vector const &world, Vector2D &coord );
|
||||
void LuxelSpaceToWorld( lightinfo_t const *l, float s, float t, Vector &world );
|
||||
|
||||
void WorldToLuxelSpace( lightinfo_t const *l, FourVectors const &world, FourVectors &coord );
|
||||
void LuxelSpaceToWorld( lightinfo_t const *l, fltx4 s, fltx4 t, FourVectors &world );
|
||||
|
||||
void AddDirectToRadial( radial_t *rad,
|
||||
Vector const &pnt,
|
||||
Vector2D const &coordmins, Vector2D const &coordmaxs,
|
||||
Vector const light[NUM_BUMP_VECTS+1],
|
||||
bool hasBumpmap, bool neighborHasBumpmap );
|
||||
|
||||
void AddBounceToRadial( radial_t *rad,
|
||||
Vector const &pnt,
|
||||
Vector2D const &coordmins, Vector2D const &coordmaxs,
|
||||
Vector const light[NUM_BUMP_VECTS+1],
|
||||
bool hasBumpmap, bool neighborHasBumpmap );
|
||||
|
||||
bool SampleRadial( radial_t *rad, Vector& pnt, Vector light[NUM_BUMP_VECTS+1], int bumpSampleCount );
|
||||
|
||||
radial_t *AllocateRadial( int facenum );
|
||||
void FreeRadial( radial_t *rad );
|
||||
|
||||
bool SampleRadial( radial_t *rad, Vector& pnt, Vector light[NUM_BUMP_VECTS + 1], int bumpSampleCount );
|
||||
radial_t *BuildPatchRadial( int facenum );
|
||||
|
||||
// utilities
|
||||
bool FloatLess( float const& src1, float const& src2 );
|
||||
|
||||
#endif
|
230
utils/vrad/samplehash.cpp
Normal file
230
utils/vrad/samplehash.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "vrad.h"
|
||||
#include "lightmap.h"
|
||||
|
||||
#define SAMPLEHASH_NUM_BUCKETS 65536
|
||||
#define SAMPLEHASH_GROW_SIZE 0
|
||||
#define SAMPLEHASH_INIT_SIZE 0
|
||||
|
||||
int samplesAdded = 0;
|
||||
int patchSamplesAdded = 0;
|
||||
static unsigned short g_PatchIterationKey = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SampleData_CompareFunc( SampleData_t const &src1, SampleData_t const &src2 )
|
||||
{
|
||||
return ( ( src1.x == src2.x ) &&
|
||||
( src1.y == src2.y ) &&
|
||||
( src1.z == src2.z ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int SampleData_KeyFunc( SampleData_t const &src )
|
||||
{
|
||||
return ( src.x + src.y + src.z );
|
||||
}
|
||||
|
||||
|
||||
CUtlHash<SampleData_t> g_SampleHashTable( SAMPLEHASH_NUM_BUCKETS,
|
||||
SAMPLEHASH_GROW_SIZE,
|
||||
SAMPLEHASH_INIT_SIZE,
|
||||
SampleData_CompareFunc, SampleData_KeyFunc );
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
UtlHashHandle_t SampleData_Find( sample_t *pSample )
|
||||
{
|
||||
SampleData_t sampleData;
|
||||
sampleData.x = ( int )( pSample->pos.x / SAMPLEHASH_VOXEL_SIZE ) * 100;
|
||||
sampleData.y = ( int )( pSample->pos.y / SAMPLEHASH_VOXEL_SIZE ) * 10;
|
||||
sampleData.z = ( int )( pSample->pos.z / SAMPLEHASH_VOXEL_SIZE );
|
||||
|
||||
return g_SampleHashTable.Find( sampleData );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
UtlHashHandle_t SampleData_InsertIntoHashTable( sample_t *pSample, SampleHandle_t sampleHandle )
|
||||
{
|
||||
SampleData_t sampleData;
|
||||
sampleData.x = ( int )( pSample->pos.x / SAMPLEHASH_VOXEL_SIZE ) * 100;
|
||||
sampleData.y = ( int )( pSample->pos.y / SAMPLEHASH_VOXEL_SIZE ) * 10;
|
||||
sampleData.z = ( int )( pSample->pos.z / SAMPLEHASH_VOXEL_SIZE );
|
||||
|
||||
UtlHashHandle_t handle = g_SampleHashTable.AllocEntryFromKey( sampleData );
|
||||
|
||||
SampleData_t *pSampleData = &g_SampleHashTable.Element( handle );
|
||||
pSampleData->x = sampleData.x;
|
||||
pSampleData->y = sampleData.y;
|
||||
pSampleData->z = sampleData.z;
|
||||
pSampleData->m_Samples.AddToTail( sampleHandle );
|
||||
|
||||
samplesAdded++;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
UtlHashHandle_t SampleData_AddSample( sample_t *pSample, SampleHandle_t sampleHandle )
|
||||
{
|
||||
|
||||
// find the key -- if it doesn't exist add new sample data to the
|
||||
// hash table
|
||||
UtlHashHandle_t handle = SampleData_Find( pSample );
|
||||
if( handle == g_SampleHashTable.InvalidHandle() )
|
||||
{
|
||||
handle = SampleData_InsertIntoHashTable( pSample, sampleHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
SampleData_t *pSampleData = &g_SampleHashTable.Element( handle );
|
||||
pSampleData->m_Samples.AddToTail( sampleHandle );
|
||||
|
||||
samplesAdded++;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void SampleData_Log( void )
|
||||
{
|
||||
if( g_bLogHashData )
|
||||
{
|
||||
g_SampleHashTable.Log( "samplehash.txt" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//
|
||||
// PatchSample Functions
|
||||
//
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool PatchSampleData_CompareFunc( PatchSampleData_t const &src1, PatchSampleData_t const &src2 )
|
||||
{
|
||||
return ( ( src1.x == src2.x ) &&
|
||||
( src1.y == src2.y ) &&
|
||||
( src1.z == src2.z ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int PatchSampleData_KeyFunc( PatchSampleData_t const &src )
|
||||
{
|
||||
return ( src.x + src.y + src.z );
|
||||
}
|
||||
|
||||
|
||||
CUtlHash<PatchSampleData_t> g_PatchSampleHashTable( SAMPLEHASH_NUM_BUCKETS,
|
||||
SAMPLEHASH_GROW_SIZE,
|
||||
SAMPLEHASH_INIT_SIZE,
|
||||
PatchSampleData_CompareFunc, PatchSampleData_KeyFunc );
|
||||
|
||||
void GetPatchSampleHashXYZ( const Vector &vOrigin, int &x, int &y, int &z )
|
||||
{
|
||||
x = ( int )( vOrigin.x / SAMPLEHASH_VOXEL_SIZE );
|
||||
y = ( int )( vOrigin.y / SAMPLEHASH_VOXEL_SIZE );
|
||||
z = ( int )( vOrigin.z / SAMPLEHASH_VOXEL_SIZE );
|
||||
}
|
||||
|
||||
|
||||
unsigned short IncrementPatchIterationKey()
|
||||
{
|
||||
if ( g_PatchIterationKey == 0xFFFF )
|
||||
{
|
||||
g_PatchIterationKey = 1;
|
||||
for ( int i=0; i < g_Patches.Count(); i++ )
|
||||
g_Patches[i].m_IterationKey = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_PatchIterationKey++;
|
||||
}
|
||||
return g_PatchIterationKey;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void PatchSampleData_AddSample( CPatch *pPatch, int ndxPatch )
|
||||
{
|
||||
int patchSampleMins[3], patchSampleMaxs[3];
|
||||
|
||||
#if defined( SAMPLEHASH_USE_AREA_PATCHES )
|
||||
GetPatchSampleHashXYZ( pPatch->mins, patchSampleMins[0], patchSampleMins[1], patchSampleMins[2] );
|
||||
GetPatchSampleHashXYZ( pPatch->maxs, patchSampleMaxs[0], patchSampleMaxs[1], patchSampleMaxs[2] );
|
||||
#else
|
||||
// If not using area patches, just use the patch's origin to add it to the voxels.
|
||||
GetPatchSampleHashXYZ( pPatch->origin, patchSampleMins[0], patchSampleMins[1], patchSampleMins[2] );
|
||||
memcpy( patchSampleMaxs, patchSampleMins, sizeof( patchSampleMaxs ) );
|
||||
#endif
|
||||
|
||||
// Make sure mins are smaller than maxs so we don't iterate for 4 bil.
|
||||
Assert( patchSampleMins[0] <= patchSampleMaxs[0] && patchSampleMins[1] <= patchSampleMaxs[1] && patchSampleMins[2] <= patchSampleMaxs[2] );
|
||||
patchSampleMins[0] = min( patchSampleMins[0], patchSampleMaxs[0] );
|
||||
patchSampleMins[1] = min( patchSampleMins[1], patchSampleMaxs[1] );
|
||||
patchSampleMins[2] = min( patchSampleMins[2], patchSampleMaxs[2] );
|
||||
|
||||
int iterateCoords[3];
|
||||
for ( iterateCoords[0]=patchSampleMins[0]; iterateCoords[0] <= patchSampleMaxs[0]; iterateCoords[0]++ )
|
||||
{
|
||||
for ( iterateCoords[1]=patchSampleMins[1]; iterateCoords[1] <= patchSampleMaxs[1]; iterateCoords[1]++ )
|
||||
{
|
||||
for ( iterateCoords[2]=patchSampleMins[2]; iterateCoords[2] <= patchSampleMaxs[2]; iterateCoords[2]++ )
|
||||
{
|
||||
// find the key -- if it doesn't exist add new sample data to the
|
||||
// hash table
|
||||
PatchSampleData_t iteratePatch;
|
||||
iteratePatch.x = iterateCoords[0] * 100;
|
||||
iteratePatch.y = iterateCoords[1] * 10;
|
||||
iteratePatch.z = iterateCoords[2];
|
||||
|
||||
UtlHashHandle_t handle = g_PatchSampleHashTable.Find( iteratePatch );
|
||||
if( handle == g_PatchSampleHashTable.InvalidHandle() )
|
||||
{
|
||||
UtlHashHandle_t handle = g_PatchSampleHashTable.AllocEntryFromKey( iteratePatch );
|
||||
|
||||
PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
|
||||
pPatchData->x = iteratePatch.x;
|
||||
pPatchData->y = iteratePatch.y;
|
||||
pPatchData->z = iteratePatch.z;
|
||||
pPatchData->m_ndxPatches.AddToTail( ndxPatch );
|
||||
|
||||
patchSamplesAdded++;
|
||||
}
|
||||
else
|
||||
{
|
||||
PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
|
||||
pPatchData->m_ndxPatches.AddToTail( ndxPatch );
|
||||
|
||||
patchSamplesAdded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
644
utils/vrad/trace.cpp
Normal file
644
utils/vrad/trace.cpp
Normal file
@ -0,0 +1,644 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
// trace.c
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#include "vrad.h"
|
||||
#include "trace.h"
|
||||
#include "Cmodel.h"
|
||||
#include "mathlib/vmatrix.h"
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
class CToolTrace : public CBaseTrace
|
||||
{
|
||||
public:
|
||||
CToolTrace() {}
|
||||
|
||||
Vector mins;
|
||||
Vector maxs;
|
||||
Vector extents;
|
||||
|
||||
texinfo_t *surface;
|
||||
|
||||
qboolean ispoint;
|
||||
|
||||
private:
|
||||
CToolTrace( const CToolTrace& );
|
||||
};
|
||||
|
||||
|
||||
// 1/32 epsilon to keep floating point happy
|
||||
#define DIST_EPSILON (0.03125)
|
||||
|
||||
// JAYHL2: This used to be -1, but that caused lots of epsilon issues
|
||||
// around slow sloping planes. Perhaps Quake2 limited maps to a certain
|
||||
// slope / angle on walkable ground. It has to be a negative number
|
||||
// so that the tests work out.
|
||||
#define NEVER_UPDATED -9999
|
||||
|
||||
//=============================================================================
|
||||
|
||||
bool DM_RayDispIntersectTest( CVRADDispColl *pTree, Vector& rayStart, Vector& rayEnd, CToolTrace *pTrace );
|
||||
void DM_ClipBoxToBrush( CToolTrace *trace, const Vector & mins, const Vector & maxs, const Vector& p1, const Vector& p2, dbrush_t *brush );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
float TraceLeafBrushes( int leafIndex, const Vector &start, const Vector &end, CBaseTrace &traceOut )
|
||||
{
|
||||
dleaf_t *pLeaf = dleafs + leafIndex;
|
||||
CToolTrace trace;
|
||||
memset( &trace, 0, sizeof(trace) );
|
||||
trace.ispoint = true;
|
||||
trace.startsolid = false;
|
||||
trace.fraction = 1.0;
|
||||
|
||||
for ( int i = 0; i < pLeaf->numleafbrushes; i++ )
|
||||
{
|
||||
int brushnum = dleafbrushes[pLeaf->firstleafbrush+i];
|
||||
dbrush_t *b = &dbrushes[brushnum];
|
||||
if ( !(b->contents & MASK_OPAQUE))
|
||||
continue;
|
||||
|
||||
Vector zeroExtents = vec3_origin;
|
||||
DM_ClipBoxToBrush( &trace, zeroExtents, zeroExtents, start, end, b);
|
||||
if ( trace.fraction != 1.0 || trace.startsolid )
|
||||
{
|
||||
if ( trace.startsolid )
|
||||
trace.fraction = 0.0f;
|
||||
traceOut = trace;
|
||||
return trace.fraction;
|
||||
}
|
||||
}
|
||||
traceOut = trace;
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
DispTested_t s_DispTested[MAX_TOOL_THREADS+1];
|
||||
|
||||
// this just uses the average coverage for the triangle
|
||||
class CCoverageCount : public ITransparentTriangleCallback
|
||||
{
|
||||
public:
|
||||
CCoverageCount()
|
||||
{
|
||||
m_coverage = Four_Zeros;
|
||||
}
|
||||
|
||||
virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *pHitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID )
|
||||
{
|
||||
float color = g_RtEnv.GetTriangleColor( hitID ).x;
|
||||
m_coverage = AddSIMD( m_coverage, AndSIMD ( *pHitMask, ReplicateX4 ( color ) ) );
|
||||
m_coverage = MinSIMD( m_coverage, Four_Ones );
|
||||
|
||||
fltx4 onesMask = CmpEqSIMD( m_coverage, Four_Ones );
|
||||
|
||||
// we should continue if the ones that hit the triangle have onesMask set to zero
|
||||
// so hitMask & onesMask != hitMask
|
||||
// so hitMask & onesMask == hitMask means we're done
|
||||
// so ts(hitMask & onesMask == hitMask) != 0xF says go on
|
||||
return 0xF != TestSignSIMD ( CmpEqSIMD ( AndSIMD( *pHitMask, onesMask ), *pHitMask ) );
|
||||
}
|
||||
|
||||
fltx4 GetCoverage()
|
||||
{
|
||||
return m_coverage;
|
||||
}
|
||||
|
||||
fltx4 GetFractionVisible()
|
||||
{
|
||||
return SubSIMD ( Four_Ones, m_coverage );
|
||||
}
|
||||
|
||||
fltx4 m_coverage;
|
||||
};
|
||||
|
||||
// this will sample the texture to get a coverage at the ray intersection point
|
||||
class CCoverageCountTexture : public CCoverageCount
|
||||
{
|
||||
public:
|
||||
virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *pHitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID )
|
||||
{
|
||||
int sign = TestSignSIMD( *pHitMask );
|
||||
float addedCoverage[4];
|
||||
for ( int s = 0; s < 4; s++)
|
||||
{
|
||||
addedCoverage[s] = 0.0f;
|
||||
if ( ( sign >> s) & 0x1 )
|
||||
{
|
||||
addedCoverage[s] = ComputeCoverageFromTexture( b0->m128_f32[s], b1->m128_f32[s], b2->m128_f32[s], hitID );
|
||||
}
|
||||
}
|
||||
m_coverage = AddSIMD( m_coverage, LoadUnalignedSIMD( addedCoverage ) );
|
||||
m_coverage = MinSIMD( m_coverage, Four_Ones );
|
||||
fltx4 onesMask = CmpEqSIMD( m_coverage, Four_Ones );
|
||||
|
||||
// we should continue if the ones that hit the triangle have onesMask set to zero
|
||||
// so hitMask & onesMask != hitMask
|
||||
// so hitMask & onesMask == hitMask means we're done
|
||||
// so ts(hitMask & onesMask == hitMask) != 0xF says go on
|
||||
return 0xF != TestSignSIMD ( CmpEqSIMD ( AndSIMD( *pHitMask, onesMask ), *pHitMask ) );
|
||||
}
|
||||
};
|
||||
|
||||
void TestLine( const FourVectors& start, const FourVectors& stop,
|
||||
fltx4 *pFractionVisible, int static_prop_index_to_ignore )
|
||||
{
|
||||
FourRays myrays;
|
||||
myrays.origin = start;
|
||||
myrays.direction = stop;
|
||||
myrays.direction -= myrays.origin;
|
||||
fltx4 len = myrays.direction.length();
|
||||
myrays.direction *= ReciprocalSIMD( len );
|
||||
|
||||
RayTracingResult rt_result;
|
||||
CCoverageCountTexture coverageCallback;
|
||||
|
||||
g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_index_to_ignore, g_bTextureShadows ? &coverageCallback : 0 );
|
||||
|
||||
// Assume we can see the targets unless we get hits
|
||||
float visibility[4];
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
visibility[i] = 1.0f;
|
||||
if ( ( rt_result.HitIds[i] != -1 ) &&
|
||||
( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
|
||||
{
|
||||
visibility[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
*pFractionVisible = LoadUnalignedSIMD( visibility );
|
||||
if ( g_bTextureShadows )
|
||||
*pFractionVisible = MinSIMD( *pFractionVisible, coverageCallback.GetFractionVisible() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
DM_ClipBoxToBrush
|
||||
================
|
||||
*/
|
||||
void DM_ClipBoxToBrush( CToolTrace *trace, const Vector& mins, const Vector& maxs, const Vector& p1, const Vector& p2,
|
||||
dbrush_t *brush)
|
||||
{
|
||||
dplane_t *plane, *clipplane;
|
||||
float dist;
|
||||
Vector ofs;
|
||||
float d1, d2;
|
||||
float f;
|
||||
dbrushside_t *side, *leadside;
|
||||
|
||||
if (!brush->numsides)
|
||||
return;
|
||||
|
||||
float enterfrac = NEVER_UPDATED;
|
||||
float leavefrac = 1.f;
|
||||
clipplane = NULL;
|
||||
|
||||
bool getout = false;
|
||||
bool startout = false;
|
||||
leadside = NULL;
|
||||
|
||||
// Loop interchanged, so we don't have to check trace->ispoint every side.
|
||||
if ( !trace->ispoint )
|
||||
{
|
||||
for (int i=0 ; i<brush->numsides ; ++i)
|
||||
{
|
||||
side = &dbrushsides[brush->firstside+i];
|
||||
plane = dplanes + side->planenum;
|
||||
|
||||
// FIXME: special case for axial
|
||||
|
||||
// general box case
|
||||
// push the plane out apropriately for mins/maxs
|
||||
|
||||
// FIXME: use signbits into 8 way lookup for each mins/maxs
|
||||
ofs.x = (plane->normal.x < 0) ? maxs.x : mins.x;
|
||||
ofs.y = (plane->normal.y < 0) ? maxs.y : mins.y;
|
||||
ofs.z = (plane->normal.z < 0) ? maxs.z : mins.z;
|
||||
// for (j=0 ; j<3 ; j++)
|
||||
// {
|
||||
// Set signmask to either 0 if the sign is negative, or 0xFFFFFFFF is the sign is positive:
|
||||
//int signmask = (((*(int *)&(plane->normal[j]))&0x80000000) >> 31) - 1;
|
||||
|
||||
//float temp = maxs[j];
|
||||
//*(int *)&(ofs[j]) = (~signmask) & (*(int *)&temp);
|
||||
//float temp1 = mins[j];
|
||||
//*(int *)&(ofs[j]) |= (signmask) & (*(int *)&temp1);
|
||||
// }
|
||||
dist = DotProduct (ofs, plane->normal);
|
||||
dist = plane->dist - dist;
|
||||
|
||||
d1 = DotProduct (p1, plane->normal) - dist;
|
||||
d2 = DotProduct (p2, plane->normal) - dist;
|
||||
|
||||
// if completely in front of face, no intersection
|
||||
if (d1 > 0 && d2 > 0)
|
||||
return;
|
||||
|
||||
if (d2 > 0)
|
||||
getout = true; // endpoint is not in solid
|
||||
if (d1 > 0)
|
||||
startout = true;
|
||||
|
||||
if (d1 <= 0 && d2 <= 0)
|
||||
continue;
|
||||
|
||||
// crosses face
|
||||
if (d1 > d2)
|
||||
{ // enter
|
||||
f = (d1-DIST_EPSILON) / (d1-d2);
|
||||
if (f > enterfrac)
|
||||
{
|
||||
enterfrac = f;
|
||||
clipplane = plane;
|
||||
leadside = side;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // leave
|
||||
f = (d1+DIST_EPSILON) / (d1-d2);
|
||||
if (f < leavefrac)
|
||||
leavefrac = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0 ; i<brush->numsides ; ++i)
|
||||
{
|
||||
side = &dbrushsides[brush->firstside+i];
|
||||
plane = dplanes + side->planenum;
|
||||
|
||||
// FIXME: special case for axial
|
||||
|
||||
// special point case
|
||||
// don't ray trace against bevel planes
|
||||
if( side->bevel == 1 )
|
||||
continue;
|
||||
|
||||
dist = plane->dist;
|
||||
d1 = DotProduct (p1, plane->normal) - dist;
|
||||
d2 = DotProduct (p2, plane->normal) - dist;
|
||||
|
||||
// if completely in front of face, no intersection
|
||||
if (d1 > 0 && d2 > 0)
|
||||
return;
|
||||
|
||||
if (d2 > 0)
|
||||
getout = true; // endpoint is not in solid
|
||||
if (d1 > 0)
|
||||
startout = true;
|
||||
|
||||
if (d1 <= 0 && d2 <= 0)
|
||||
continue;
|
||||
|
||||
// crosses face
|
||||
if (d1 > d2)
|
||||
{ // enter
|
||||
f = (d1-DIST_EPSILON) / (d1-d2);
|
||||
if (f > enterfrac)
|
||||
{
|
||||
enterfrac = f;
|
||||
clipplane = plane;
|
||||
leadside = side;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // leave
|
||||
f = (d1+DIST_EPSILON) / (d1-d2);
|
||||
if (f < leavefrac)
|
||||
leavefrac = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!startout)
|
||||
{ // original point was inside brush
|
||||
trace->startsolid = true;
|
||||
if (!getout)
|
||||
trace->allsolid = true;
|
||||
return;
|
||||
}
|
||||
if (enterfrac < leavefrac)
|
||||
{
|
||||
if (enterfrac > NEVER_UPDATED && enterfrac < trace->fraction)
|
||||
{
|
||||
if (enterfrac < 0)
|
||||
enterfrac = 0;
|
||||
trace->fraction = enterfrac;
|
||||
trace->plane.dist = clipplane->dist;
|
||||
trace->plane.normal = clipplane->normal;
|
||||
trace->plane.type = clipplane->type;
|
||||
if (leadside->texinfo!=-1)
|
||||
trace->surface = &texinfo[leadside->texinfo];
|
||||
else
|
||||
trace->surface = 0;
|
||||
trace->contents = brush->contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestLine_DoesHitSky( FourVectors const& start, FourVectors const& stop,
|
||||
fltx4 *pFractionVisible, bool canRecurse, int static_prop_to_skip, bool bDoDebug )
|
||||
{
|
||||
FourRays myrays;
|
||||
myrays.origin = start;
|
||||
myrays.direction = stop;
|
||||
myrays.direction -= myrays.origin;
|
||||
fltx4 len = myrays.direction.length();
|
||||
myrays.direction *= ReciprocalSIMD( len );
|
||||
RayTracingResult rt_result;
|
||||
CCoverageCountTexture coverageCallback;
|
||||
|
||||
g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_to_skip, g_bTextureShadows? &coverageCallback : 0);
|
||||
|
||||
if ( bDoDebug )
|
||||
{
|
||||
WriteTrace( "trace.txt", myrays, rt_result );
|
||||
}
|
||||
|
||||
float aOcclusion[4];
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
aOcclusion[i] = 0.0f;
|
||||
if ( ( rt_result.HitIds[i] != -1 ) &&
|
||||
( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
|
||||
{
|
||||
int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID;
|
||||
if ( !( id & TRACE_ID_SKY ) )
|
||||
aOcclusion[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
fltx4 occlusion = LoadUnalignedSIMD( aOcclusion );
|
||||
if (g_bTextureShadows)
|
||||
occlusion = MaxSIMD ( occlusion, coverageCallback.GetCoverage() );
|
||||
|
||||
bool fullyOccluded = ( TestSignSIMD( CmpGeSIMD( occlusion, Four_Ones ) ) == 0xF );
|
||||
|
||||
// if we hit sky, and we're not in a sky camera's area, try clipping into the 3D sky boxes
|
||||
if ( (! fullyOccluded) && canRecurse && (! g_bNoSkyRecurse ) )
|
||||
{
|
||||
FourVectors dir = stop;
|
||||
dir -= start;
|
||||
dir.VectorNormalize();
|
||||
|
||||
int leafIndex = -1;
|
||||
leafIndex = PointLeafnum( start.Vec( 0 ) );
|
||||
if ( leafIndex >= 0 )
|
||||
{
|
||||
int area = dleafs[leafIndex].area;
|
||||
if (area >= 0 && area < numareas)
|
||||
{
|
||||
if (area_sky_cameras[area] < 0)
|
||||
{
|
||||
int cam;
|
||||
for (cam = 0; cam < num_sky_cameras; ++cam)
|
||||
{
|
||||
FourVectors skystart, skytrans, skystop;
|
||||
skystart.DuplicateVector( sky_cameras[cam].origin );
|
||||
skystop = start;
|
||||
skystop *= sky_cameras[cam].world_to_sky;
|
||||
skystart += skystop;
|
||||
|
||||
skystop = dir;
|
||||
skystop *= MAX_TRACE_LENGTH;
|
||||
skystop += skystart;
|
||||
TestLine_DoesHitSky ( skystart, skystop, pFractionVisible, false, static_prop_to_skip, bDoDebug );
|
||||
occlusion = AddSIMD ( occlusion, Four_Ones );
|
||||
occlusion = SubSIMD ( occlusion, *pFractionVisible );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
occlusion = MaxSIMD( occlusion, Four_Zeros );
|
||||
occlusion = MinSIMD( occlusion, Four_Ones );
|
||||
*pFractionVisible = SubSIMD( Four_Ones, occlusion );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int PointLeafnum_r( const Vector &point, int ndxNode )
|
||||
{
|
||||
// while loop here is to avoid recursion overhead
|
||||
while( ndxNode >= 0 )
|
||||
{
|
||||
dnode_t *pNode = dnodes + ndxNode;
|
||||
dplane_t *pPlane = dplanes + pNode->planenum;
|
||||
|
||||
float dist;
|
||||
if( pPlane->type < 3 )
|
||||
{
|
||||
dist = point[pPlane->type] - pPlane->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
dist = DotProduct( pPlane->normal, point ) - pPlane->dist;
|
||||
}
|
||||
|
||||
if( dist < 0.0f )
|
||||
{
|
||||
ndxNode = pNode->children[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
ndxNode = pNode->children[0];
|
||||
}
|
||||
}
|
||||
|
||||
return ( -1 - ndxNode );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int PointLeafnum( const Vector &point )
|
||||
{
|
||||
return PointLeafnum_r( point, 0 );
|
||||
}
|
||||
|
||||
// this iterates the list of entities looking for _vradshadows 1
|
||||
// each brush entity containing this key is added to the raytracing environment
|
||||
// as a triangle soup model.
|
||||
|
||||
dmodel_t *BrushmodelForEntity( entity_t *pEntity )
|
||||
{
|
||||
const char *pModelname = ValueForKey( pEntity, "model" );
|
||||
if ( Q_strlen(pModelname) > 1 )
|
||||
{
|
||||
int modelIndex = atol( pModelname + 1 );
|
||||
if ( modelIndex > 0 && modelIndex < nummodels )
|
||||
{
|
||||
return &dmodels[modelIndex];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AddBrushToRaytraceEnvironment( dbrush_t *pBrush, const VMatrix &xform )
|
||||
{
|
||||
if ( !( pBrush->contents & MASK_OPAQUE ) )
|
||||
return;
|
||||
|
||||
Vector v0, v1, v2;
|
||||
for (int i = 0; i < pBrush->numsides; i++ )
|
||||
{
|
||||
dbrushside_t *side = &dbrushsides[pBrush->firstside + i];
|
||||
dplane_t *plane = &dplanes[side->planenum];
|
||||
texinfo_t *tx = &texinfo[side->texinfo];
|
||||
winding_t *w = BaseWindingForPlane (plane->normal, plane->dist);
|
||||
|
||||
if ( tx->flags & SURF_SKY || side->dispinfo )
|
||||
continue;
|
||||
|
||||
for (int j=0 ; j<pBrush->numsides && w; j++)
|
||||
{
|
||||
if (i == j)
|
||||
continue;
|
||||
dbrushside_t *pOtherSide = &dbrushsides[pBrush->firstside + j];
|
||||
if (pOtherSide->bevel)
|
||||
continue;
|
||||
plane = &dplanes[pOtherSide->planenum^1];
|
||||
ChopWindingInPlace (&w, plane->normal, plane->dist, 0);
|
||||
}
|
||||
if ( w )
|
||||
{
|
||||
for ( int j = 2; j < w->numpoints; j++ )
|
||||
{
|
||||
v0 = xform.VMul4x3(w->p[0]);
|
||||
v1 = xform.VMul4x3(w->p[j-1]);
|
||||
v2 = xform.VMul4x3(w->p[j]);
|
||||
Vector fullCoverage;
|
||||
fullCoverage.x = 1.0f;
|
||||
g_RtEnv.AddTriangle(TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage);
|
||||
}
|
||||
FreeWinding( w );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// recurse the bsp and build a list of brushes at the leaves under this node
|
||||
void GetBrushes_r( int node, CUtlVector<int> &list )
|
||||
{
|
||||
if ( node < 0 )
|
||||
{
|
||||
int leafIndex = -1 - node;
|
||||
// Add the solids in the leaf
|
||||
for ( int i = 0; i < dleafs[leafIndex].numleafbrushes; i++ )
|
||||
{
|
||||
int brushIndex = dleafbrushes[dleafs[leafIndex].firstleafbrush + i];
|
||||
if ( list.Find(brushIndex) < 0 )
|
||||
{
|
||||
list.AddToTail( brushIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// recurse
|
||||
dnode_t *pnode = dnodes + node;
|
||||
|
||||
GetBrushes_r( pnode->children[0], list );
|
||||
GetBrushes_r( pnode->children[1], list );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AddBrushes( dmodel_t *pModel, const VMatrix &xform )
|
||||
{
|
||||
if ( pModel )
|
||||
{
|
||||
CUtlVector<int> brushList;
|
||||
GetBrushes_r( pModel->headnode, brushList );
|
||||
for ( int i = 0; i < brushList.Count(); i++ )
|
||||
{
|
||||
int ndxBrush = brushList[i];
|
||||
AddBrushToRaytraceEnvironment( &dbrushes[ndxBrush], xform );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Adds the brush entities that cast shadows to the raytrace environment
|
||||
void ExtractBrushEntityShadowCasters()
|
||||
{
|
||||
for ( int i = 0; i < num_entities; i++ )
|
||||
{
|
||||
if ( IntForKey( &entities[i], "vrad_brush_cast_shadows" ) != 0 )
|
||||
{
|
||||
Vector origin;
|
||||
QAngle angles;
|
||||
GetVectorForKey( &entities[i], "origin", origin );
|
||||
GetAnglesForKey( &entities[i], "angles", angles );
|
||||
VMatrix xform;
|
||||
xform.SetupMatrixOrgAngles( origin, angles );
|
||||
AddBrushes( BrushmodelForEntity( &entities[i] ), xform );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddBrushesForRayTrace( void )
|
||||
{
|
||||
if ( !nummodels )
|
||||
return;
|
||||
|
||||
VMatrix identity;
|
||||
identity.Identity();
|
||||
|
||||
CUtlVector<int> brushList;
|
||||
GetBrushes_r ( dmodels[0].headnode, brushList );
|
||||
|
||||
for ( int i = 0; i < brushList.Size(); i++ )
|
||||
{
|
||||
dbrush_t *brush = &dbrushes[brushList[i]];
|
||||
AddBrushToRaytraceEnvironment ( brush, identity );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < dmodels[0].numfaces; i++ )
|
||||
{
|
||||
int ndxFace = dmodels[0].firstface + i;
|
||||
dface_t *face = &g_pFaces[ndxFace];
|
||||
|
||||
texinfo_t *tx = &texinfo[face->texinfo];
|
||||
if ( !( tx->flags & SURF_SKY ) )
|
||||
continue;
|
||||
|
||||
Vector points[MAX_POINTS_ON_WINDING];
|
||||
|
||||
for ( int j = 0; j < face->numedges; j++ )
|
||||
{
|
||||
int surfEdge = dsurfedges[face->firstedge + j];
|
||||
short v;
|
||||
|
||||
if (surfEdge < 0)
|
||||
v = dedges[-surfEdge].v[1];
|
||||
else
|
||||
v = dedges[surfEdge].v[0];
|
||||
|
||||
dvertex_t *dv = &dvertexes[v];
|
||||
points[j] = dv->point;
|
||||
}
|
||||
|
||||
for ( int j = 2; j < face->numedges; j++ )
|
||||
{
|
||||
Vector fullCoverage;
|
||||
fullCoverage.x = 1.0f;
|
||||
g_RtEnv.AddTriangle ( TRACE_ID_SKY, points[0], points[j - 1], points[j], fullCoverage );
|
||||
}
|
||||
}
|
||||
}
|
483
utils/vrad/vismat.cpp
Normal file
483
utils/vrad/vismat.cpp
Normal file
@ -0,0 +1,483 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "vrad.h"
|
||||
#include "vmpi.h"
|
||||
#ifdef MPI
|
||||
#include "messbuf.h"
|
||||
static MessageBuffer mb;
|
||||
#endif
|
||||
|
||||
#define HALFBIT
|
||||
|
||||
extern char source[MAX_PATH];
|
||||
extern char vismatfile[_MAX_PATH];
|
||||
extern char incrementfile[_MAX_PATH];
|
||||
extern qboolean incremental;
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
VISIBILITY MATRIX
|
||||
|
||||
Determine which patches can see each other
|
||||
Use the PVS to accelerate if available
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
#define TEST_EPSILON 0.1
|
||||
#define PLANE_TEST_EPSILON 0.01 // patch must be this much in front of the plane to be considered "in front"
|
||||
#define PATCH_FACE_OFFSET 0.1 // push patch origins off from the face by this amount to avoid self collisions
|
||||
|
||||
#define STREAM_SIZE 512
|
||||
|
||||
class CTransferMaker
|
||||
{
|
||||
public:
|
||||
|
||||
CTransferMaker( transfer_t *all_transfers );
|
||||
~CTransferMaker();
|
||||
|
||||
FORCEINLINE void TestMakeTransfer( Vector start, Vector stop, int ndxShooter, int ndxReciever )
|
||||
{
|
||||
g_RtEnv.AddToRayStream( m_RayStream, start, stop, &m_pResults[m_nTests] );
|
||||
m_pShooterPatches[m_nTests] = ndxShooter;
|
||||
m_pRecieverPatches[m_nTests] = ndxReciever;
|
||||
++m_nTests;
|
||||
}
|
||||
|
||||
void Finish();
|
||||
|
||||
private:
|
||||
|
||||
int m_nTests;
|
||||
RayTracingSingleResult *m_pResults;
|
||||
int *m_pShooterPatches;
|
||||
int *m_pRecieverPatches;
|
||||
RayStream m_RayStream;
|
||||
transfer_t *m_AllTransfers;
|
||||
};
|
||||
|
||||
CTransferMaker::CTransferMaker( transfer_t *all_transfers ) :
|
||||
m_AllTransfers( all_transfers ), m_nTests( 0 )
|
||||
{
|
||||
m_pResults = (RayTracingSingleResult *)calloc( 1, MAX_PATCHES * sizeof ( RayTracingSingleResult ) );
|
||||
m_pShooterPatches = (int *)calloc( 1, MAX_PATCHES * sizeof( int ) );
|
||||
m_pRecieverPatches = (int *)calloc( 1, MAX_PATCHES * sizeof( int ) );
|
||||
}
|
||||
|
||||
CTransferMaker::~CTransferMaker()
|
||||
{
|
||||
free ( m_pResults );
|
||||
free ( m_pShooterPatches );
|
||||
free (m_pRecieverPatches );
|
||||
}
|
||||
|
||||
void CTransferMaker::Finish()
|
||||
{
|
||||
g_RtEnv.FinishRayStream( m_RayStream );
|
||||
for ( int i = 0; i < m_nTests; ++i )
|
||||
{
|
||||
if ( m_pResults[i].HitID == -1 || m_pResults[i].HitDistance >= m_pResults[i].ray_length )
|
||||
{
|
||||
MakeTransfer( m_pShooterPatches[i], m_pRecieverPatches[i], m_AllTransfers );
|
||||
}
|
||||
}
|
||||
m_nTests = 0;
|
||||
}
|
||||
|
||||
|
||||
dleaf_t* PointInLeaf (int iNode, Vector const& point)
|
||||
{
|
||||
if ( iNode < 0 )
|
||||
return &dleafs[ (-1-iNode) ];
|
||||
|
||||
dnode_t *node = &dnodes[iNode];
|
||||
dplane_t *plane = &dplanes[ node->planenum ];
|
||||
|
||||
float dist = DotProduct (point, plane->normal) - plane->dist;
|
||||
if ( dist > TEST_EPSILON )
|
||||
{
|
||||
return PointInLeaf( node->children[0], point );
|
||||
}
|
||||
else if ( dist < -TEST_EPSILON )
|
||||
{
|
||||
return PointInLeaf( node->children[1], point );
|
||||
}
|
||||
else
|
||||
{
|
||||
dleaf_t *pTest = PointInLeaf( node->children[0], point );
|
||||
if ( pTest->cluster != -1 )
|
||||
return pTest;
|
||||
|
||||
return PointInLeaf( node->children[1], point );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ClusterFromPoint( Vector const& point )
|
||||
{
|
||||
dleaf_t *leaf = PointInLeaf( 0, point );
|
||||
|
||||
return leaf->cluster;
|
||||
}
|
||||
|
||||
void PvsForOrigin (Vector& org, byte *pvs)
|
||||
{
|
||||
int visofs;
|
||||
int cluster;
|
||||
|
||||
if (!visdatasize)
|
||||
{
|
||||
memset (pvs, 255, (dvis->numclusters+7)/8 );
|
||||
return;
|
||||
}
|
||||
|
||||
cluster = ClusterFromPoint( org );
|
||||
if ( cluster < 0 )
|
||||
{
|
||||
visofs = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
visofs = dvis->bitofs[ cluster ][DVIS_PVS];
|
||||
}
|
||||
|
||||
if (visofs == -1)
|
||||
Error ("visofs == -1");
|
||||
|
||||
DecompressVis (&dvisdata[visofs], pvs);
|
||||
}
|
||||
|
||||
|
||||
void TestPatchToPatch( int ndxPatch1, int ndxPatch2, int head, transfer_t *transfers, CTransferMaker &transferMaker, int iThread )
|
||||
{
|
||||
Vector tmp;
|
||||
|
||||
//
|
||||
// get patches
|
||||
//
|
||||
if( ndxPatch1 == g_Patches.InvalidIndex() || ndxPatch2 == g_Patches.InvalidIndex() )
|
||||
return;
|
||||
|
||||
CPatch *patch = &g_Patches.Element( ndxPatch1 );
|
||||
CPatch *patch2 = &g_Patches.Element( ndxPatch2 );
|
||||
|
||||
if (patch2->child1 != g_Patches.InvalidIndex() )
|
||||
{
|
||||
// check to see if we should use a child node instead
|
||||
|
||||
VectorSubtract( patch->origin, patch2->origin, tmp );
|
||||
// SQRT( 1/4 )
|
||||
// FIXME: should be based on form-factor (ie. include visible angle, etc)
|
||||
if ( DotProduct(tmp, tmp) * 0.0625 < patch2->area )
|
||||
{
|
||||
TestPatchToPatch( ndxPatch1, patch2->child1, head, transfers, transferMaker, iThread );
|
||||
TestPatchToPatch( ndxPatch1, patch2->child2, head, transfers, transferMaker, iThread );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check vis between patch and patch2
|
||||
// if bit has not already been set
|
||||
// && v2 is not behind light plane
|
||||
// && v2 is visible from v1
|
||||
if ( DotProduct( patch2->origin, patch->normal ) > patch->planeDist + PLANE_TEST_EPSILON )
|
||||
{
|
||||
// push out origins from face so that don't intersect their owners
|
||||
Vector p1, p2;
|
||||
VectorAdd( patch->origin, patch->normal, p1 );
|
||||
VectorAdd( patch2->origin, patch2->normal, p2 );
|
||||
transferMaker.TestMakeTransfer( p1, p2, ndxPatch1, ndxPatch2 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
TestPatchToFace
|
||||
|
||||
Sets vis bits for all patches in the face
|
||||
==============
|
||||
*/
|
||||
void TestPatchToFace (unsigned patchnum, int facenum, int head, transfer_t *transfers, CTransferMaker &transferMaker, int iThread )
|
||||
{
|
||||
if( faceParents.Element( facenum ) == g_Patches.InvalidIndex() || patchnum == g_Patches.InvalidIndex() )
|
||||
return;
|
||||
|
||||
CPatch *patch = &g_Patches.Element( patchnum );
|
||||
CPatch *patch2 = &g_Patches.Element( faceParents.Element( facenum ) );
|
||||
|
||||
// if emitter is behind that face plane, skip all patches
|
||||
|
||||
CPatch *pNextPatch;
|
||||
|
||||
if ( patch2 && DotProduct(patch->origin, patch2->normal) > patch2->planeDist + PLANE_TEST_EPSILON )
|
||||
{
|
||||
// we need to do a real test
|
||||
for( ; patch2; patch2 = pNextPatch )
|
||||
{
|
||||
// next patch
|
||||
pNextPatch = NULL;
|
||||
if( patch2->ndxNextParent != g_Patches.InvalidIndex() )
|
||||
{
|
||||
pNextPatch = &g_Patches.Element( patch2->ndxNextParent );
|
||||
}
|
||||
|
||||
/*
|
||||
// skip patches too far away
|
||||
VectorSubtract( patch->origin, patch2->origin, tmp );
|
||||
if (DotProduct( tmp, tmp ) > 512 * 512)
|
||||
continue;
|
||||
*/
|
||||
|
||||
int ndxPatch2 = patch2 - g_Patches.Base();
|
||||
TestPatchToPatch( patchnum, ndxPatch2, head, transfers, transferMaker, iThread );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ClusterDispList_t
|
||||
{
|
||||
CUtlVector<int> dispFaces;
|
||||
};
|
||||
|
||||
static CUtlVector<ClusterDispList_t> g_ClusterDispFaces;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helps us find all displacements associated with a particular cluster
|
||||
//-----------------------------------------------------------------------------
|
||||
void AddDispsToClusterTable( void )
|
||||
{
|
||||
g_ClusterDispFaces.SetCount( g_ClusterLeaves.Count() );
|
||||
|
||||
//
|
||||
// add displacement faces to the cluster table
|
||||
//
|
||||
for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
|
||||
{
|
||||
// search for displacement faces
|
||||
if( g_pFaces[ndxFace].dispinfo == -1 )
|
||||
continue;
|
||||
|
||||
//
|
||||
// get the clusters associated with the face
|
||||
//
|
||||
if( g_FacePatches.Element( ndxFace ) != g_FacePatches.InvalidIndex() )
|
||||
{
|
||||
CPatch *pNextPatch = NULL;
|
||||
for( CPatch *pPatch = &g_Patches.Element( g_FacePatches.Element( ndxFace ) ); pPatch; pPatch = pNextPatch )
|
||||
{
|
||||
// next patch
|
||||
pNextPatch = NULL;
|
||||
if( pPatch->ndxNext != g_Patches.InvalidIndex() )
|
||||
{
|
||||
pNextPatch = &g_Patches.Element( pPatch->ndxNext );
|
||||
}
|
||||
|
||||
if( pPatch->clusterNumber != g_Patches.InvalidIndex() )
|
||||
{
|
||||
int ndxDisp = g_ClusterDispFaces[pPatch->clusterNumber].dispFaces.Find( ndxFace );
|
||||
if( ndxDisp == -1 )
|
||||
{
|
||||
ndxDisp = g_ClusterDispFaces[pPatch->clusterNumber].dispFaces.AddToTail();
|
||||
g_ClusterDispFaces[pPatch->clusterNumber].dispFaces[ndxDisp] = ndxFace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
BuildVisRow
|
||||
|
||||
Calc vis bits from a single patch
|
||||
==============
|
||||
*/
|
||||
void BuildVisRow (int patchnum, byte *pvs, int head, transfer_t *transfers, CTransferMaker &transferMaker, int iThread )
|
||||
{
|
||||
int j, k, l, leafIndex;
|
||||
CPatch *patch;
|
||||
dleaf_t *leaf;
|
||||
byte face_tested[MAX_MAP_FACES];
|
||||
byte disp_tested[MAX_MAP_FACES];
|
||||
|
||||
patch = &g_Patches.Element( patchnum );
|
||||
|
||||
memset( face_tested, 0, numfaces ) ;
|
||||
memset( disp_tested, 0, numfaces );
|
||||
|
||||
for (j=0; j<dvis->numclusters; j++)
|
||||
{
|
||||
if ( ! ( pvs[(j)>>3] & (1<<((j)&7)) ) )
|
||||
{
|
||||
continue; // not in pvs
|
||||
}
|
||||
|
||||
for ( leafIndex = 0; leafIndex < g_ClusterLeaves[j].leafCount; leafIndex++ )
|
||||
{
|
||||
leaf = dleafs + g_ClusterLeaves[j].leafs[leafIndex];
|
||||
|
||||
for (k=0 ; k<leaf->numleaffaces; k++)
|
||||
{
|
||||
l = dleaffaces[leaf->firstleafface + k];
|
||||
// faces can be marksurfed by multiple leaves, but
|
||||
// don't bother testing again
|
||||
if (face_tested[l])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
face_tested[l] = 1;
|
||||
|
||||
// don't check patches on the same face
|
||||
if (patch->faceNumber == l)
|
||||
continue;
|
||||
TestPatchToFace (patchnum, l, head, transfers, transferMaker, iThread );
|
||||
}
|
||||
}
|
||||
|
||||
int dispCount = g_ClusterDispFaces[j].dispFaces.Size();
|
||||
for( int ndxDisp = 0; ndxDisp < dispCount; ndxDisp++ )
|
||||
{
|
||||
int ndxFace = g_ClusterDispFaces[j].dispFaces[ndxDisp];
|
||||
if( disp_tested[ndxFace] )
|
||||
continue;
|
||||
|
||||
disp_tested[ndxFace] = 1;
|
||||
|
||||
// don't check patches on the same face
|
||||
if( patch->faceNumber == ndxFace )
|
||||
continue;
|
||||
|
||||
TestPatchToFace( patchnum, ndxFace, head, transfers, transferMaker, iThread );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Msg("%d) Transfers: %5d\n", patchnum, patch->numtransfers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
BuildVisLeafs
|
||||
|
||||
This is run by multiple threads
|
||||
===========
|
||||
*/
|
||||
|
||||
transfer_t* BuildVisLeafs_Start()
|
||||
{
|
||||
return (transfer_t *)calloc( 1, MAX_PATCHES * sizeof( transfer_t ) );
|
||||
}
|
||||
|
||||
|
||||
// If PatchCB is non-null, it is called after each row is generated (used by MPI).
|
||||
void BuildVisLeafs_Cluster(
|
||||
int threadnum,
|
||||
transfer_t *transfers,
|
||||
int iCluster,
|
||||
void (*PatchCB)(int iThread, int patchnum, CPatch *patch)
|
||||
)
|
||||
{
|
||||
byte pvs[(MAX_MAP_CLUSTERS+7)/8];
|
||||
CPatch *patch;
|
||||
int head;
|
||||
unsigned patchnum;
|
||||
|
||||
DecompressVis( &dvisdata[ dvis->bitofs[ iCluster ][DVIS_PVS] ], pvs);
|
||||
head = 0;
|
||||
|
||||
CTransferMaker transferMaker( transfers );
|
||||
|
||||
// light every patch in the cluster
|
||||
if( clusterChildren.Element( iCluster ) != clusterChildren.InvalidIndex() )
|
||||
{
|
||||
CPatch *pNextPatch;
|
||||
for( patch = &g_Patches.Element( clusterChildren.Element( iCluster ) ); patch; patch = pNextPatch )
|
||||
{
|
||||
//
|
||||
// next patch
|
||||
//
|
||||
pNextPatch = NULL;
|
||||
if( patch->ndxNextClusterChild != g_Patches.InvalidIndex() )
|
||||
{
|
||||
pNextPatch = &g_Patches.Element( patch->ndxNextClusterChild );
|
||||
}
|
||||
|
||||
patchnum = patch - g_Patches.Base();
|
||||
|
||||
// build to all other world clusters
|
||||
BuildVisRow (patchnum, pvs, head, transfers, transferMaker, threadnum );
|
||||
transferMaker.Finish();
|
||||
|
||||
// do the transfers
|
||||
MakeScales( patchnum, transfers );
|
||||
|
||||
// Let MPI aggregate the data if it's being used.
|
||||
if ( PatchCB )
|
||||
PatchCB( threadnum, patchnum, patch );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BuildVisLeafs_End( transfer_t *transfers )
|
||||
{
|
||||
free( transfers );
|
||||
}
|
||||
|
||||
|
||||
void BuildVisLeafs( int threadnum, void *pUserData )
|
||||
{
|
||||
transfer_t *transfers = BuildVisLeafs_Start();
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
//
|
||||
// build a minimal BSP tree that only
|
||||
// covers areas relevent to the PVS
|
||||
//
|
||||
// JAY: Now this returns a cluster index
|
||||
int iCluster = GetThreadWork();
|
||||
if ( iCluster == -1 )
|
||||
break;
|
||||
|
||||
BuildVisLeafs_Cluster( threadnum, transfers, iCluster, NULL );
|
||||
}
|
||||
|
||||
BuildVisLeafs_End( transfers );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
BuildVisMatrix
|
||||
==============
|
||||
*/
|
||||
void BuildVisMatrix (void)
|
||||
{
|
||||
if ( g_bUseMPI )
|
||||
{
|
||||
RunMPIBuildVisLeafs();
|
||||
}
|
||||
else
|
||||
{
|
||||
RunThreadsOn (dvis->numclusters, true, BuildVisLeafs);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeVisMatrix (void)
|
||||
{
|
||||
|
||||
}
|
34
utils/vrad/vismat.h
Normal file
34
utils/vrad/vismat.h
Normal file
@ -0,0 +1,34 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef VISMAT_H
|
||||
#define VISMAT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void BuildVisLeafs( int threadnum );
|
||||
|
||||
|
||||
// MPI uses these.
|
||||
struct transfer_t;
|
||||
transfer_t* BuildVisLeafs_Start();
|
||||
|
||||
// If PatchCB is non-null, it is called after each row is generated (used by MPI).
|
||||
void BuildVisLeafs_Cluster(
|
||||
int threadnum,
|
||||
transfer_t *transfers,
|
||||
int iCluster,
|
||||
void (*PatchCB)(int iThread, int patchnum, CPatch *patch) );
|
||||
|
||||
void BuildVisLeafs_End( transfer_t *transfers );
|
||||
|
||||
|
||||
|
||||
#endif // VISMAT_H
|
2936
utils/vrad/vrad.cpp
Normal file
2936
utils/vrad/vrad.cpp
Normal file
File diff suppressed because it is too large
Load Diff
610
utils/vrad/vrad.h
Normal file
610
utils/vrad/vrad.h
Normal file
@ -0,0 +1,610 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef VRAD_H
|
||||
#define VRAD_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "commonmacros.h"
|
||||
#include "worldsize.h"
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "bsplib.h"
|
||||
#include "polylib.h"
|
||||
#include "threads.h"
|
||||
#include "builddisp.h"
|
||||
#include "VRAD_DispColl.h"
|
||||
#include "UtlMemory.h"
|
||||
#include "UtlHash.h"
|
||||
#include "utlvector.h"
|
||||
#include "iincremental.h"
|
||||
#include "raytrace.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#pragma warning(disable: 4142 4028)
|
||||
#include <io.h>
|
||||
#pragma warning(default: 4142 4028)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <direct.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
// Can remove these options if they don't generate problems.
|
||||
//#define SAMPLEHASH_USE_AREA_PATCHES // Add patches to sample hash based on their AABB instead of as a single point.
|
||||
#define SAMPLEHASH_QUERY_ONCE // Big optimization - causes way less sample hash queries.
|
||||
|
||||
extern float dispchop; // "-dispchop" tightest number of luxel widths for a patch, used on edges
|
||||
extern float g_MaxDispPatchRadius;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct Ray_t;
|
||||
|
||||
#define TRANSFER_EPSILON 0.0000001
|
||||
|
||||
struct directlight_t
|
||||
{
|
||||
int index;
|
||||
|
||||
directlight_t *next;
|
||||
dworldlight_t light;
|
||||
|
||||
byte *pvs; // accumulated domain of the light
|
||||
int facenum; // domain of attached lights
|
||||
int texdata; // texture source of traced lights
|
||||
|
||||
Vector snormal;
|
||||
Vector tnormal;
|
||||
float sscale;
|
||||
float tscale;
|
||||
float soffset;
|
||||
float toffset;
|
||||
|
||||
int dorecalc; // position, vector, spot angle, etc.
|
||||
IncrementalLightID m_IncrementalID;
|
||||
|
||||
// hard-falloff lights (lights that fade to an actual zero). between m_flStartFadeDistance and
|
||||
// m_flEndFadeDistance, a smoothstep to zero will be done, so that the light goes to zero at
|
||||
// the end.
|
||||
float m_flStartFadeDistance;
|
||||
float m_flEndFadeDistance;
|
||||
float m_flCapDist; // max distance to feed in
|
||||
|
||||
directlight_t(void)
|
||||
{
|
||||
m_flEndFadeDistance = -1.0; // end<start indicates not set
|
||||
m_flStartFadeDistance= 0.0;
|
||||
m_flCapDist = 1.0e22;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct bumplights_t
|
||||
{
|
||||
Vector light[NUM_BUMP_VECTS+1];
|
||||
};
|
||||
|
||||
|
||||
struct transfer_t
|
||||
{
|
||||
int patch;
|
||||
float transfer;
|
||||
};
|
||||
|
||||
|
||||
struct LightingValue_t
|
||||
{
|
||||
Vector m_vecLighting;
|
||||
float m_flDirectSunAmount;
|
||||
|
||||
FORCEINLINE bool IsValid( void ) const
|
||||
{
|
||||
return ( m_vecLighting.x >= 0 &&
|
||||
m_vecLighting.y >= 0 &&
|
||||
m_vecLighting.z >= 0 &&
|
||||
m_vecLighting.x < 1e10 &&
|
||||
m_vecLighting.y < 1e10 &&
|
||||
m_vecLighting.z < 1e10 );
|
||||
}
|
||||
|
||||
FORCEINLINE void Zero( void )
|
||||
{
|
||||
m_vecLighting.Init( 0, 0, 0 );
|
||||
m_flDirectSunAmount = 0.0;
|
||||
}
|
||||
|
||||
FORCEINLINE void Scale( float m_flScale )
|
||||
{
|
||||
m_vecLighting *= m_flScale;
|
||||
m_flDirectSunAmount *= m_flScale;
|
||||
}
|
||||
|
||||
FORCEINLINE void AddWeighted( LightingValue_t const &src, float flWeight )
|
||||
{
|
||||
m_vecLighting += flWeight * src.m_vecLighting;
|
||||
m_flDirectSunAmount += flWeight * src.m_flDirectSunAmount;
|
||||
}
|
||||
|
||||
FORCEINLINE void AddWeighted( Vector const &src, float flWeight )
|
||||
{
|
||||
m_vecLighting += flWeight * src;
|
||||
}
|
||||
|
||||
FORCEINLINE float Intensity( void ) const
|
||||
{
|
||||
return m_vecLighting.x + m_vecLighting.y + m_vecLighting.z;
|
||||
}
|
||||
|
||||
FORCEINLINE void AddLight( float flAmount, Vector const &vecColor, float flSunAmount = 0.0 )
|
||||
{
|
||||
VectorMA( m_vecLighting, flAmount, vecColor, m_vecLighting );
|
||||
m_flDirectSunAmount += flSunAmount;
|
||||
Assert( this->IsValid() );
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE void AddLight( LightingValue_t const &src )
|
||||
{
|
||||
m_vecLighting += src.m_vecLighting;
|
||||
m_flDirectSunAmount += src.m_flDirectSunAmount;
|
||||
Assert( this->IsValid() );
|
||||
}
|
||||
|
||||
FORCEINLINE void Init( float x, float y, float z )
|
||||
{
|
||||
m_vecLighting.Init( x, y, z );
|
||||
m_flDirectSunAmount = 0.0;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define MAX_PATCHES (4*65536)
|
||||
|
||||
struct CPatch
|
||||
{
|
||||
winding_t *winding;
|
||||
Vector mins, maxs, face_mins, face_maxs;
|
||||
|
||||
Vector origin; // adjusted off face by face normal
|
||||
|
||||
dplane_t *plane; // plane (corrected for facing)
|
||||
|
||||
unsigned short m_IterationKey; // Used to prevent touching the same patch multiple times in the same query.
|
||||
// See IncrementPatchIterationKey().
|
||||
|
||||
// these are packed into one dword
|
||||
unsigned int normalMajorAxis : 2; // the major axis of base face normal
|
||||
unsigned int sky : 1;
|
||||
unsigned int needsBumpmap : 1;
|
||||
unsigned int pad : 28;
|
||||
|
||||
Vector normal; // adjusted for phong shading
|
||||
|
||||
float planeDist; // Fixes up patch planes for brush models with an origin brush
|
||||
|
||||
float chop; // smallest acceptable width of patch face
|
||||
float luxscale; // average luxels per world coord
|
||||
float scale[2]; // Scaling of texture in s & t
|
||||
|
||||
bumplights_t totallight; // accumulated by radiosity
|
||||
// does NOT include light
|
||||
// accounted for by direct lighting
|
||||
Vector baselight; // emissivity only
|
||||
float basearea; // surface per area per baselight instance
|
||||
|
||||
Vector directlight; // direct light value
|
||||
float area;
|
||||
|
||||
Vector reflectivity; // Average RGB of texture, modified by material type.
|
||||
|
||||
Vector samplelight;
|
||||
float samplearea; // for averaging direct light
|
||||
int faceNumber;
|
||||
int clusterNumber;
|
||||
|
||||
int parent; // patch index of parent
|
||||
int child1; // patch index for children
|
||||
int child2;
|
||||
|
||||
int ndxNext; // next patch index in face
|
||||
int ndxNextParent; // next parent patch index in face
|
||||
int ndxNextClusterChild; // next terminal child index in cluster
|
||||
// struct patch_s *next; // next in face
|
||||
// struct patch_s *nextparent; // next in face
|
||||
// struct patch_s *nextclusterchild; // next terminal child in cluster
|
||||
|
||||
int numtransfers;
|
||||
transfer_t *transfers;
|
||||
|
||||
short indices[3]; // displacement use these for subdivision
|
||||
};
|
||||
|
||||
|
||||
extern CUtlVector<CPatch> g_Patches;
|
||||
extern CUtlVector<int> g_FacePatches; // constains all patches, children first
|
||||
extern CUtlVector<int> faceParents; // contains only root patches, use next parent to iterate
|
||||
extern CUtlVector<int> clusterChildren;
|
||||
|
||||
|
||||
struct sky_camera_t
|
||||
{
|
||||
Vector origin;
|
||||
float world_to_sky;
|
||||
float sky_to_world;
|
||||
int area;
|
||||
};
|
||||
|
||||
extern int num_sky_cameras;
|
||||
extern sky_camera_t sky_cameras[MAX_MAP_AREAS];
|
||||
extern int area_sky_cameras[MAX_MAP_AREAS];
|
||||
void ProcessSkyCameras();
|
||||
|
||||
extern entity_t *face_entity[MAX_MAP_FACES];
|
||||
extern Vector face_offset[MAX_MAP_FACES]; // for rotating bmodels
|
||||
extern Vector face_centroids[MAX_MAP_EDGES];
|
||||
extern int leafparents[MAX_MAP_LEAFS];
|
||||
extern int nodeparents[MAX_MAP_NODES];
|
||||
extern float lightscale;
|
||||
extern float dlight_threshold;
|
||||
extern float coring;
|
||||
extern qboolean g_bDumpPatches;
|
||||
extern bool bRed2Black;
|
||||
extern bool g_bNoSkyRecurse;
|
||||
extern bool bDumpNormals;
|
||||
extern bool g_bFastAmbient;
|
||||
extern float maxchop;
|
||||
extern FileHandle_t pFileSamples[4][4];
|
||||
extern qboolean g_bLowPriority;
|
||||
extern qboolean do_fast;
|
||||
extern bool g_bInterrupt; // Was used with background lighting in WC. Tells VRAD to stop lighting.
|
||||
extern IIncremental *g_pIncremental; // null if not doing incremental lighting
|
||||
|
||||
extern float g_flSkySampleScale; // extra sampling factor for indirect light
|
||||
|
||||
extern bool g_bLargeDispSampleRadius;
|
||||
extern bool g_bStaticPropPolys;
|
||||
extern bool g_bTextureShadows;
|
||||
extern bool g_bShowStaticPropNormals;
|
||||
extern bool g_bDisablePropSelfShadowing;
|
||||
|
||||
extern CUtlVector<char const *> g_NonShadowCastingMaterialStrings;
|
||||
extern void ForceTextureShadowsOnModel( const char *pModelName );
|
||||
extern bool IsModelTextureShadowsForced( const char *pModelName );
|
||||
|
||||
// Raytracing
|
||||
|
||||
#define TRACE_ID_SKY 0x01000000 // sky face ray blocker
|
||||
#define TRACE_ID_OPAQUE 0x02000000 // everyday light blocking face
|
||||
#define TRACE_ID_STATICPROP 0x04000000 // static prop - lower bits are prop ID
|
||||
extern RayTracingEnvironment g_RtEnv;
|
||||
|
||||
#include "mpivrad.h"
|
||||
|
||||
void MakeShadowSplits (void);
|
||||
|
||||
//==============================================
|
||||
|
||||
void BuildVisMatrix (void);
|
||||
void BuildClusterTable( void );
|
||||
void AddDispsToClusterTable( void );
|
||||
void FreeVisMatrix (void);
|
||||
// qboolean CheckVisBit (unsigned int p1, unsigned int p2);
|
||||
void TouchVMFFile (void);
|
||||
|
||||
//==============================================
|
||||
|
||||
extern qboolean do_extra;
|
||||
extern qboolean do_fast;
|
||||
extern qboolean do_centersamples;
|
||||
extern int extrapasses;
|
||||
extern Vector ambient;
|
||||
extern float maxlight;
|
||||
extern unsigned numbounce;
|
||||
extern qboolean g_bLogHashData;
|
||||
extern bool debug_extra;
|
||||
extern directlight_t *activelights;
|
||||
extern directlight_t *freelights;
|
||||
|
||||
// because of hdr having two face lumps (light styles can cause them to be different, among other
|
||||
// things), we need to always access (r/w) face data though this pointer
|
||||
extern dface_t *g_pFaces;
|
||||
|
||||
|
||||
extern bool g_bMPIProps;
|
||||
|
||||
extern byte nodehit[MAX_MAP_NODES];
|
||||
extern float gamma;
|
||||
extern float indirect_sun;
|
||||
extern float smoothing_threshold;
|
||||
extern int dlight_map;
|
||||
|
||||
extern float g_flMaxDispSampleSize;
|
||||
extern float g_SunAngularExtent;
|
||||
|
||||
extern char source[MAX_PATH];
|
||||
|
||||
// Used by incremental lighting to trivial-reject faces.
|
||||
// There is a bit in here for each face telling whether or not any of the
|
||||
// active lights can see the face.
|
||||
extern CUtlVector<byte> g_FacesVisibleToLights;
|
||||
|
||||
void MakeTnodes (dmodel_t *bm);
|
||||
void PairEdges (void);
|
||||
|
||||
void SaveVertexNormals( void );
|
||||
|
||||
qboolean IsIncremental(char *filename);
|
||||
int SaveIncremental(char *filename);
|
||||
int PartialHead (void);
|
||||
void BuildFacelights (int facenum, int threadnum);
|
||||
void PrecompLightmapOffsets();
|
||||
void FinalLightFace (int threadnum, int facenum);
|
||||
void PvsForOrigin (Vector& org, byte *pvs);
|
||||
void ConvertRGBExp32ToRGBA8888( const ColorRGBExp32 *pSrc, unsigned char *pDst );
|
||||
|
||||
inline byte PVSCheck( const byte *pvs, int iCluster )
|
||||
{
|
||||
if ( iCluster >= 0 )
|
||||
{
|
||||
return pvs[iCluster >> 3] & ( 1 << ( iCluster & 7 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// PointInLeaf still returns -1 for valid points sometimes and rather than
|
||||
// have black samples, we assume the sample is in the PVS.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// outputs 1 in fractionVisible if no occlusion, 0 if full occlusion, and in-between values
|
||||
void TestLine( FourVectors const& start, FourVectors const& stop, fltx4 *pFractionVisible, int static_prop_index_to_ignore=-1);
|
||||
|
||||
// returns 1 if the ray sees the sky, 0 if it doesn't, and in-between values for partial coverage
|
||||
void TestLine_DoesHitSky( FourVectors const& start, FourVectors const& stop,
|
||||
fltx4 *pFractionVisible, bool canRecurse = true, int static_prop_to_skip=-1, bool bDoDebug = false );
|
||||
|
||||
// converts any marked brush entities to triangles for shadow casting
|
||||
void ExtractBrushEntityShadowCasters ( void );
|
||||
void AddBrushesForRayTrace ( void );
|
||||
|
||||
void BaseLightForFace( dface_t *f, Vector& light, float *parea, Vector& reflectivity );
|
||||
void CreateDirectLights (void);
|
||||
void GetPhongNormal( int facenum, Vector const& spot, Vector& phongnormal );
|
||||
int LightForString( char *pLight, Vector& intensity );
|
||||
void MakeTransfer( int ndxPatch1, int ndxPatch2, transfer_t *all_transfers );
|
||||
void MakeScales( int ndxPatch, transfer_t *all_transfers );
|
||||
|
||||
// Run startup code like initialize mathlib.
|
||||
void VRAD_Init();
|
||||
|
||||
// Load the BSP file and prepare to do the lighting.
|
||||
// This is called after any command-line parameters have been set.
|
||||
void VRAD_LoadBSP( char const *pFilename );
|
||||
|
||||
int VRAD_Main(int argc, char **argv);
|
||||
|
||||
// This performs an actual lighting pass.
|
||||
// Returns true if the process was interrupted (with g_bInterrupt).
|
||||
bool RadWorld_Go();
|
||||
|
||||
dleaf_t *PointInLeaf (Vector const& point);
|
||||
int ClusterFromPoint( Vector const& point );
|
||||
winding_t *WindingFromFace (dface_t *f, Vector& origin );
|
||||
|
||||
void WriteWinding (FileHandle_t out, winding_t *w, Vector& color );
|
||||
void WriteNormal( FileHandle_t out, Vector const &nPos, Vector const &nDir,
|
||||
float length, Vector const &color );
|
||||
void WriteLine( FileHandle_t out, const Vector &vecPos1, const Vector &vecPos2, const Vector &color );
|
||||
void WriteTrace( const char *pFileName, const FourRays &rays, const RayTracingResult& result );
|
||||
|
||||
#ifdef STATIC_FOG
|
||||
qboolean IsFog( dface_t * f );
|
||||
#endif
|
||||
|
||||
#define CONTENTS_EMPTY 0
|
||||
#define TEX_SPECIAL (SURF_SKY|SURF_NOLIGHT)
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// trace.cpp
|
||||
|
||||
bool AddDispCollTreesToWorld( void );
|
||||
int PointLeafnum( Vector const &point );
|
||||
float TraceLeafBrushes( int leafIndex, const Vector &start, const Vector &end, CBaseTrace &traceOut );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// dispinfo.cpp
|
||||
|
||||
struct SSE_sampleLightOutput_t
|
||||
{
|
||||
fltx4 m_flDot[NUM_BUMP_VECTS+1];
|
||||
fltx4 m_flFalloff;
|
||||
fltx4 m_flSunAmount;
|
||||
};
|
||||
|
||||
#define GATHERLFLAGS_FORCE_FAST 1
|
||||
#define GATHERLFLAGS_IGNORE_NORMALS 2
|
||||
|
||||
// SSE Gather light stuff
|
||||
void GatherSampleLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
|
||||
FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
|
||||
int nLFlags = 0, // GATHERLFLAGS_xxx
|
||||
int static_prop_to_skip=-1,
|
||||
float flEpsilon = 0.0 );
|
||||
//void GatherSampleSkyLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
|
||||
// FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
|
||||
// int nLFlags = 0,
|
||||
// int static_prop_to_skip=-1,
|
||||
// float flEpsilon = 0.0 );
|
||||
//void GatherSampleAmbientSkySSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
|
||||
// FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
|
||||
// int nLFlags = 0, // GATHERLFLAGS_xxx
|
||||
// int static_prop_to_skip=-1,
|
||||
// float flEpsilon = 0.0 );
|
||||
//void GatherSampleStandardLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
|
||||
// FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
|
||||
// int nLFlags = 0, // GATHERLFLAGS_xxx
|
||||
// int static_prop_to_skip=-1,
|
||||
// float flEpsilon = 0.0 );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// VRad Displacements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct facelight_t;
|
||||
typedef struct radial_s radial_t;
|
||||
struct lightinfo_t;
|
||||
|
||||
// NOTE: should probably come up with a bsptreetested_t struct or something,
|
||||
// see below (PropTested_t)
|
||||
struct DispTested_t
|
||||
{
|
||||
int m_Enum;
|
||||
int *m_pTested;
|
||||
};
|
||||
|
||||
class IVRadDispMgr
|
||||
{
|
||||
public:
|
||||
// creation/destruction
|
||||
virtual void Init( void ) = 0;
|
||||
virtual void Shutdown( void ) = 0;
|
||||
|
||||
// "CalcPoints"
|
||||
virtual bool BuildDispSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace ) = 0;
|
||||
virtual bool BuildDispLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace ) = 0;
|
||||
virtual bool BuildDispSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace ) = 0;
|
||||
|
||||
// patching functions
|
||||
virtual void MakePatches( void ) = 0;
|
||||
virtual void SubdividePatch( int iPatch ) = 0;
|
||||
|
||||
// pre "FinalLightFace"
|
||||
virtual void InsertSamplesDataIntoHashTable( void ) = 0;
|
||||
virtual void InsertPatchSampleDataIntoHashTable( void ) = 0;
|
||||
|
||||
// "FinalLightFace"
|
||||
virtual radial_t *BuildLuxelRadial( int ndxFace, int ndxStyle, bool bBump ) = 0;
|
||||
virtual bool SampleRadial( int ndxFace, radial_t *pRadial, Vector const &vPos, int ndxLxl, LightingValue_t *pLightSample, int sampleCount, bool bPatch ) = 0;
|
||||
virtual radial_t *BuildPatchRadial( int ndxFace, bool bBump ) = 0;
|
||||
|
||||
// utility
|
||||
virtual void GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal, bool bInside ) = 0;
|
||||
virtual void GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree ) = 0;
|
||||
|
||||
// bsp tree functions
|
||||
virtual bool ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray ) = 0;
|
||||
virtual bool ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray, int ndxLeaf ) = 0;
|
||||
virtual void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
|
||||
int ndxLeaf, float& dist, dface_t*& pFace, Vector2D& luxelCoord ) = 0;
|
||||
virtual void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
|
||||
int ndxLeaf, float& dist, Vector *pNormal ) = 0;
|
||||
virtual void StartRayTest( DispTested_t &dispTested ) = 0;
|
||||
virtual void AddPolysForRayTrace() = 0;
|
||||
|
||||
// general timing -- should be moved!!
|
||||
virtual void StartTimer( const char *name ) = 0;
|
||||
virtual void EndTimer( void ) = 0;
|
||||
};
|
||||
|
||||
IVRadDispMgr *StaticDispMgr( void );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool ValidDispFace( dface_t *pFace )
|
||||
{
|
||||
if( !pFace ) { return false; }
|
||||
if( pFace->dispinfo == -1 ) { return false; }
|
||||
if( pFace->numedges != 4 ) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SAMPLEHASH_VOXEL_SIZE 64.0f
|
||||
typedef unsigned int SampleHandle_t; // the upper 16 bits = facelight index (works because max face are 65536)
|
||||
// the lower 16 bits = sample index inside of facelight
|
||||
struct sample_t;
|
||||
struct SampleData_t
|
||||
{
|
||||
unsigned short x, y, z;
|
||||
CUtlVector<SampleHandle_t> m_Samples;
|
||||
};
|
||||
|
||||
struct PatchSampleData_t
|
||||
{
|
||||
unsigned short x, y, z;
|
||||
CUtlVector<int> m_ndxPatches;
|
||||
};
|
||||
|
||||
UtlHashHandle_t SampleData_AddSample( sample_t *pSample, SampleHandle_t sampleHandle );
|
||||
void PatchSampleData_AddSample( CPatch *pPatch, int ndxPatch );
|
||||
unsigned short IncrementPatchIterationKey();
|
||||
void SampleData_Log( void );
|
||||
|
||||
extern CUtlHash<SampleData_t> g_SampleHashTable;
|
||||
extern CUtlHash<PatchSampleData_t> g_PatchSampleHashTable;
|
||||
|
||||
extern int samplesAdded;
|
||||
extern int patchSamplesAdded;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes lighting for the detail props
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ComputeDetailPropLighting( int iThread );
|
||||
void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &outColor,
|
||||
int iThread, bool force_fast = false, bool bIgnoreNormals = false );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// VRad static props
|
||||
//-----------------------------------------------------------------------------
|
||||
class IPhysicsCollision;
|
||||
struct PropTested_t
|
||||
{
|
||||
int m_Enum;
|
||||
int* m_pTested;
|
||||
IPhysicsCollision *pThreadedCollision;
|
||||
};
|
||||
|
||||
class IVradStaticPropMgr
|
||||
{
|
||||
public:
|
||||
// methods of IStaticPropMgr
|
||||
virtual void Init() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual void ComputeLighting( int iThread ) = 0;
|
||||
virtual void AddPolysForRayTrace() = 0;
|
||||
};
|
||||
|
||||
//extern PropTested_t s_PropTested[MAX_TOOL_THREADS+1];
|
||||
extern DispTested_t s_DispTested[MAX_TOOL_THREADS+1];
|
||||
|
||||
IVradStaticPropMgr* StaticPropMgr();
|
||||
|
||||
extern float ComputeCoverageFromTexture( float b0, float b1, float b2, int32 hitID );
|
||||
|
||||
#endif // VRAD_H
|
1080
utils/vrad/vrad_dispcoll.cpp
Normal file
1080
utils/vrad/vrad_dispcoll.cpp
Normal file
File diff suppressed because it is too large
Load Diff
80
utils/vrad/vrad_dispcoll.h
Normal file
80
utils/vrad/vrad_dispcoll.h
Normal file
@ -0,0 +1,80 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef VRAD_DISPCOLL_H
|
||||
#define VRAD_DISPCOLL_H
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include "DispColl_Common.h"
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// VRAD specific collision
|
||||
//
|
||||
#define VRAD_QUAD_SIZE 4
|
||||
|
||||
struct CPatch;
|
||||
|
||||
class CVRADDispColl : public CDispCollTree
|
||||
{
|
||||
public:
|
||||
|
||||
// Creation/Destruction Functions
|
||||
CVRADDispColl();
|
||||
~CVRADDispColl();
|
||||
bool Create( CCoreDispInfo *pDisp );
|
||||
|
||||
// Patches.
|
||||
bool InitPatch( int iPatch, int iParentPatch, int iChild, Vector *pPoints, int *pIndices, float &flArea );
|
||||
bool InitParentPatch( int iPatch, Vector *pPoints, float &flArea );
|
||||
float CreateParentPatches( void );
|
||||
void CreateChildPatches( int iParentPatch, int nLevel );
|
||||
void CreateChildPatchesFromRoot( int iParentPatch, int *pChildPatch );
|
||||
void CreateChildPatchesSub( int iParentPatch );
|
||||
|
||||
// Operations Functions
|
||||
void BaseFacePlaneToDispUV( Vector const &vecPlanePt, Vector2D &dispUV );
|
||||
void DispUVToSurfPoint( Vector2D const &dispUV, Vector &vecPoint, float flPushEps );
|
||||
void DispUVToSurfNormal( Vector2D const &dispUV, Vector &vecNormal );
|
||||
|
||||
// Data.
|
||||
inline float GetSampleRadius2( void ) { return m_flSampleRadius2; }
|
||||
inline float GetPatchSampleRadius2( void ) { return m_flPatchSampleRadius2; }
|
||||
|
||||
inline int GetParentIndex( void ) { return m_iParent; }
|
||||
inline void GetParentFaceNormal( Vector &vecNormal ) { vecNormal = m_vecStabDir; }
|
||||
|
||||
inline void GetVert( int iVert, Vector &vecVert ) { Assert( ( iVert >= 0 ) && ( iVert < GetSize() ) ); vecVert = m_aVerts[iVert]; }
|
||||
inline void GetVertNormal( int iVert, Vector &vecNormal ) { Assert( ( iVert >= 0 ) && ( iVert < GetSize() ) ); vecNormal = m_aVertNormals[iVert]; }
|
||||
inline Vector2D const& GetLuxelCoord( int iLuxel ) { Assert( ( iLuxel >= 0 ) && ( iLuxel < GetSize() ) ); return m_aLuxelCoords[iLuxel]; }
|
||||
|
||||
// Raytracing
|
||||
void AddPolysForRayTrace( void );
|
||||
|
||||
protected:
|
||||
|
||||
void CalcSampleRadius2AndBox( dface_t *pFace );
|
||||
|
||||
// Utility.
|
||||
void DispUVToSurf_TriTLToBR( Vector &vecPoint, float flPushEps, float flU, float flV, int nSnapU, int nSnapV, int nWidth, int nHeight );
|
||||
void DispUVToSurf_TriBLToTR( Vector &vecPoint, float flPushEps, float flU, float flV, int nSnapU, int nSnapV, int nWidth, int nHeight );
|
||||
void GetSurfaceMinMax( Vector &boxMin, Vector &boxMax );
|
||||
void GetMinorAxes( Vector const &vecNormal, int &nAxis0, int &nAxis1 );
|
||||
|
||||
protected:
|
||||
|
||||
int m_iParent; // Parent index
|
||||
float m_flSampleRadius2; // Sampling radius
|
||||
float m_flPatchSampleRadius2; // Patch sampling radius (max bound)
|
||||
float m_flSampleWidth;
|
||||
float m_flSampleHeight;
|
||||
CUtlVector<Vector2D> m_aLuxelCoords; // Lightmap coordinates.
|
||||
CUtlVector<Vector> m_aVertNormals; // Displacement vertex normals
|
||||
};
|
||||
|
||||
#endif // VRAD_DISPCOLL_H
|
405
utils/vrad/vrad_dll-2010.vcxproj
Normal file
405
utils/vrad/vrad_dll-2010.vcxproj
Normal file
@ -0,0 +1,405 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>Vrad_dll</ProjectName>
|
||||
<ProjectGuid>{90A78BD4-2532-39D9-6D34-7A3C2648508C}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<TargetName>vrad_dll</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<TargetName>vrad_dll</TargetName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\win32\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\win32\</IntDir>
|
||||
<ExecutablePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\devtools\vstools;$(ExecutablePath);$(Path)</ExecutablePath>
|
||||
<PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</PreBuildEventUseInBuild>
|
||||
<PreLinkEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</PreLinkEventUseInBuild>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</GenerateManifest>
|
||||
<PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</PostBuildEventUseInBuild>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\win32\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\win32\</IntDir>
|
||||
<ExecutablePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\devtools\vstools;$(ExecutablePath);$(Path)</ExecutablePath>
|
||||
<PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</PreBuildEventUseInBuild>
|
||||
<PreLinkEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</PreLinkEventUseInBuild>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
<GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</GenerateManifest>
|
||||
<PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</PostBuildEventUseInBuild>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
<ClCompile>
|
||||
<AdditionalOptions> /MP</AdditionalOptions>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\common;..\..\public;..\..\public\tier0;..\..\public\tier1;..\common;..\vmpi;..\vmpi\mysql\mysqlpp\include;..\vmpi\mysql\include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_HAS_ITERATOR_DEBUGGING=0;WIN32;_WIN32;_DEBUG;DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DLLNAME=vrad_dll;RAD_TELEMETRY_DISABLED;COMPILER_MSVC32;MPI;PROTECTED_THINGS_DISABLE;VRAD;VPCGAMECAPS=VALVE;PROJECTDIR=D:\dev\games\rel\hl2\src\utils\vrad;_DLL_EXT=.dll;VPCGAME=valve</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AssemblerListingLocation>$(IntDir)/</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)/</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(IntDir)/</ProgramDataBaseFileName>
|
||||
<GenerateXMLDocumentationFiles>false</GenerateXMLDocumentationFiles>
|
||||
<BrowseInformation>false</BrowseInformation>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<BrowseInformationFile>$(IntDir)/</BrowseInformationFile>
|
||||
<ErrorReporting>Prompt</ErrorReporting>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
|
||||
<Culture>1033</Culture>
|
||||
</ResourceCompile>
|
||||
<PreLinkEvent>
|
||||
</PreLinkEvent>
|
||||
<Link>
|
||||
<AdditionalOptions> /ignore:4221</AdditionalOptions>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);ws2_32.lib</AdditionalDependencies>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<OutputFile>$(OutDir)\vrad_dll.dll</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>..\..\lib\common;..\..\lib\public</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>libc;libcd;libcmt</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)/$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<GenerateMapFile>false</GenerateMapFile>
|
||||
<MapFileName>$(IntDir)/$(TargetName).map</MapFileName>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<BaseAddress> </BaseAddress>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<LinkErrorReporting>PromptImmediately</LinkErrorReporting>
|
||||
<LinkLibraryDependencies>false</LinkLibraryDependencies>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Manifest>
|
||||
<Xdcmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Xdcmake>
|
||||
<Bscmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<OutputFile>$(OutDir)/vrad_dll.bsc</OutputFile>
|
||||
</Bscmake>
|
||||
<PostBuildEvent>
|
||||
<Message>Publishing to ..\..\..\game\bin</Message>
|
||||
<Command>if not exist "..\..\..\game\bin" mkdir "..\..\..\game\bin"
copy "$(TargetDir)"$(TargetFileName) "..\..\..\game\bin\$(TargetFileName)"
if ERRORLEVEL 1 goto BuildEventFailed
if exist "$(TargetDir)"$(TargetName).map copy "$(TargetDir)"$(TargetName).map ..\..\..\game\bin\$(TargetName).map
copy "$(TargetDir)"$(TargetName).pdb ..\..\..\game\bin\$(TargetName).pdb
if ERRORLEVEL 1 goto BuildEventFailed
goto BuildEventOK
:BuildEventFailed
echo *** ERROR! PostBuildStep FAILED for $(ProjectName)! EXE or DLL is probably running. ***
del /q "$(TargetDir)"$(TargetFileName)
exit 1
:BuildEventOK
</Command>
|
||||
</PostBuildEvent>
|
||||
<CustomBuildStep>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
<ClCompile>
|
||||
<AdditionalOptions> /MP /d2Zi+</AdditionalOptions>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..\..\common;..\..\public;..\..\public\tier0;..\..\public\tier1;..\common;..\vmpi;..\vmpi\mysql\mysqlpp\include;..\vmpi\mysql\include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DLLNAME=vrad_dll;RAD_TELEMETRY_DISABLED;COMPILER_MSVC32;MPI;PROTECTED_THINGS_DISABLE;VRAD;VPCGAMECAPS=VALVE;PROJECTDIR=D:\dev\games\rel\hl2\src\utils\vrad;_DLL_EXT=.dll;VPCGAME=valve</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AssemblerListingLocation>$(IntDir)/</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)/</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(IntDir)/</ProgramDataBaseFileName>
|
||||
<GenerateXMLDocumentationFiles>false</GenerateXMLDocumentationFiles>
|
||||
<BrowseInformation>false</BrowseInformation>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<BrowseInformationFile>$(IntDir)/</BrowseInformationFile>
|
||||
<ErrorReporting>Prompt</ErrorReporting>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
|
||||
<Culture>1033</Culture>
|
||||
</ResourceCompile>
|
||||
<PreLinkEvent>
|
||||
</PreLinkEvent>
|
||||
<Link>
|
||||
<AdditionalOptions> /DYNAMICBASE /ignore:4221</AdditionalOptions>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);ws2_32.lib</AdditionalDependencies>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<OutputFile>$(OutDir)\vrad_dll.dll</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>..\..\lib\common;..\..\lib\public</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>libc;libcd;libcmtd</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)/$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<GenerateMapFile>false</GenerateMapFile>
|
||||
<MapFileName>$(IntDir)/$(TargetName).map</MapFileName>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<BaseAddress> </BaseAddress>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<LinkErrorReporting>PromptImmediately</LinkErrorReporting>
|
||||
<LinkLibraryDependencies>false</LinkLibraryDependencies>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Manifest>
|
||||
<Xdcmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Xdcmake>
|
||||
<Bscmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<OutputFile>$(OutDir)/vrad_dll.bsc</OutputFile>
|
||||
</Bscmake>
|
||||
<PostBuildEvent>
|
||||
<Message>Publishing to ..\..\..\game\bin</Message>
|
||||
<Command>if not exist "..\..\..\game\bin" mkdir "..\..\..\game\bin"
copy "$(TargetDir)"$(TargetFileName) "..\..\..\game\bin\$(TargetFileName)"
if ERRORLEVEL 1 goto BuildEventFailed
if exist "$(TargetDir)"$(TargetName).map copy "$(TargetDir)"$(TargetName).map ..\..\..\game\bin\$(TargetName).map
copy "$(TargetDir)"$(TargetName).pdb ..\..\..\game\bin\$(TargetName).pdb
if ERRORLEVEL 1 goto BuildEventFailed
goto BuildEventOK
:BuildEventFailed
echo *** ERROR! PostBuildStep FAILED for $(ProjectName)! EXE or DLL is probably running. ***
del /q "$(TargetDir)"$(TargetFileName)
exit 1
:BuildEventOK
</Command>
|
||||
</PostBuildEvent>
|
||||
<CustomBuildStep>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="..\..\lib\public\bitmap.lib" />
|
||||
<Library Include="..\..\lib\public\mathlib.lib" />
|
||||
<Library Include="..\..\lib\public\raytrace.lib" />
|
||||
<Library Include="..\..\lib\public\tier0.lib" />
|
||||
<Library Include="..\..\lib\public\tier1.lib" />
|
||||
<Library Include="..\..\lib\public\tier2.lib" />
|
||||
<Library Include="..\..\lib\public\vmpi.lib" />
|
||||
<Library Include="..\..\lib\public\vstdlib.lib" />
|
||||
<Library Include="..\..\lib\public\vtf.lib" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="disp_vrad.h" />
|
||||
<ClInclude Include="iincremental.h" />
|
||||
<ClInclude Include="imagepacker.h" />
|
||||
<ClInclude Include="incremental.h" />
|
||||
<ClInclude Include="leaf_ambient_lighting.h" />
|
||||
<ClInclude Include="lightmap.h" />
|
||||
<ClInclude Include="macro_texture.h" />
|
||||
<ClInclude Include="..\..\public\map_utils.h" />
|
||||
<ClInclude Include="mpivrad.h" />
|
||||
<ClInclude Include="radial.h" />
|
||||
<ClInclude Include="..\..\public\bitmap\tgawriter.h" />
|
||||
<ClInclude Include="vismat.h" />
|
||||
<ClInclude Include="vrad.h" />
|
||||
<ClInclude Include="VRAD_DispColl.h" />
|
||||
<ClInclude Include="vraddetailprops.h" />
|
||||
<ClInclude Include="vraddll.h" />
|
||||
<ClInclude Include="..\common\bsplib.h" />
|
||||
<ClInclude Include="..\common\cmdlib.h" />
|
||||
<ClInclude Include="..\common\consolewnd.h" />
|
||||
<ClInclude Include="..\vmpi\ichannel.h" />
|
||||
<ClInclude Include="..\vmpi\imysqlwrapper.h" />
|
||||
<ClInclude Include="..\vmpi\iphelpers.h" />
|
||||
<ClInclude Include="..\common\ISQLDBReplyTarget.h" />
|
||||
<ClInclude Include="..\common\map_shared.h" />
|
||||
<ClInclude Include="..\vmpi\messbuf.h" />
|
||||
<ClInclude Include="..\common\mpi_stats.h" />
|
||||
<ClInclude Include="..\vmpi\mysql_wrapper.h" />
|
||||
<ClInclude Include="..\common\MySqlDatabase.h" />
|
||||
<ClInclude Include="..\common\pacifier.h" />
|
||||
<ClInclude Include="..\common\polylib.h" />
|
||||
<ClInclude Include="..\common\scriplib.h" />
|
||||
<ClInclude Include="..\vmpi\threadhelpers.h" />
|
||||
<ClInclude Include="..\common\threads.h" />
|
||||
<ClInclude Include="..\common\utilmatlib.h" />
|
||||
<ClInclude Include="..\vmpi\vmpi_defs.h" />
|
||||
<ClInclude Include="..\vmpi\vmpi_dispatch.h" />
|
||||
<ClInclude Include="..\vmpi\vmpi_distribute_work.h" />
|
||||
<ClInclude Include="..\vmpi\vmpi_filesystem.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\amd3dx.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\ANORMS.H" />
|
||||
<ClInclude Include="..\..\public\basehandle.h" />
|
||||
<ClInclude Include="..\..\public\tier0\basetypes.h" />
|
||||
<ClInclude Include="..\..\public\tier1\bitbuf.h" />
|
||||
<ClInclude Include="..\..\public\bitvec.h" />
|
||||
<ClInclude Include="..\..\public\BSPFILE.H" />
|
||||
<ClInclude Include="..\..\public\bspflags.h" />
|
||||
<ClInclude Include="..\..\public\BSPTreeData.h" />
|
||||
<ClInclude Include="..\..\public\builddisp.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\bumpvects.h" />
|
||||
<ClInclude Include="..\..\public\tier1\byteswap.h" />
|
||||
<ClInclude Include="..\..\public\tier1\characterset.h" />
|
||||
<ClInclude Include="..\..\public\tier1\checksum_crc.h" />
|
||||
<ClInclude Include="..\..\public\tier1\checksum_md5.h" />
|
||||
<ClInclude Include="..\..\public\ChunkFile.h" />
|
||||
<ClInclude Include="..\..\public\cmodel.h" />
|
||||
<ClInclude Include="..\..\public\CollisionUtils.h" />
|
||||
<ClInclude Include="..\..\public\tier0\commonmacros.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\compressed_vector.h" />
|
||||
<ClInclude Include="..\..\public\const.h" />
|
||||
<ClInclude Include="..\..\public\coordsize.h" />
|
||||
<ClInclude Include="..\..\public\tier0\dbg.h" />
|
||||
<ClInclude Include="..\..\public\disp_common.h" />
|
||||
<ClInclude Include="..\..\public\disp_powerinfo.h" />
|
||||
<ClInclude Include="..\..\public\disp_vertindex.h" />
|
||||
<ClInclude Include="..\..\public\DispColl_Common.h" />
|
||||
<ClInclude Include="..\..\public\tier0\fasttimer.h" />
|
||||
<ClInclude Include="..\..\public\filesystem.h" />
|
||||
<ClInclude Include="..\..\public\filesystem_helpers.h" />
|
||||
<ClInclude Include="..\..\public\GameBSPFile.h" />
|
||||
<ClInclude Include="..\..\public\gametrace.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\halton.h" />
|
||||
<ClInclude Include="..\..\public\materialsystem\hardwareverts.h" />
|
||||
<ClInclude Include="..\..\public\appframework\IAppSystem.h" />
|
||||
<ClInclude Include="..\..\public\tier0\icommandline.h" />
|
||||
<ClInclude Include="..\..\public\ihandleentity.h" />
|
||||
<ClInclude Include="..\..\public\materialsystem\imaterial.h" />
|
||||
<ClInclude Include="..\..\public\materialsystem\imaterialsystem.h" />
|
||||
<ClInclude Include="..\..\public\materialsystem\imaterialvar.h" />
|
||||
<ClInclude Include="..\..\public\tier1\interface.h" />
|
||||
<ClInclude Include="..\..\public\iscratchpad3d.h" />
|
||||
<ClInclude Include="..\..\public\ivraddll.h" />
|
||||
<ClInclude Include="..\..\public\materialsystem\materialsystem_config.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\mathlib.h" />
|
||||
<ClInclude Include="..\..\public\tier0\memdbgon.h" />
|
||||
<ClInclude Include="..\..\public\optimize.h" />
|
||||
<ClInclude Include="..\..\public\phyfile.h" />
|
||||
<ClInclude Include="..\common\physdll.h" />
|
||||
<ClInclude Include="..\..\public\tier0\platform.h" />
|
||||
<ClInclude Include="..\..\public\tier0\protected_things.h" />
|
||||
<ClInclude Include="..\..\public\vstdlib\random.h" />
|
||||
<ClInclude Include="..\..\public\ScratchPad3D.h" />
|
||||
<ClInclude Include="..\..\public\ScratchPadUtils.h" />
|
||||
<ClInclude Include="..\..\public\string_t.h" />
|
||||
<ClInclude Include="..\..\public\tier1\strtools.h" />
|
||||
<ClInclude Include="..\..\public\studio.h" />
|
||||
<ClInclude Include="..\..\public\tier1\tokenreader.h" />
|
||||
<ClInclude Include="..\..\public\trace.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utlbuffer.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utldict.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utlhash.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utllinkedlist.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utlmemory.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utlrbtree.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utlsymbol.h" />
|
||||
<ClInclude Include="..\..\public\tier1\utlvector.h" />
|
||||
<ClInclude Include="..\..\public\vcollide.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\vector.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\vector2d.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\vector4d.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\vmatrix.h" />
|
||||
<ClInclude Include="..\vmpi\vmpi.h" />
|
||||
<ClInclude Include="..\..\public\vphysics_interface.h" />
|
||||
<ClInclude Include="..\..\public\mathlib\vplane.h" />
|
||||
<ClInclude Include="..\..\public\tier0\vprof.h" />
|
||||
<ClInclude Include="..\..\public\vstdlib\vstdlib.h" />
|
||||
<ClInclude Include="..\..\public\vtf\vtf.h" />
|
||||
<ClInclude Include="..\..\public\wadtypes.h" />
|
||||
<ClInclude Include="..\..\public\worldsize.h" />
|
||||
<ClInclude Include="..\common\vmpi_tools_shared.h" />
|
||||
<ClInclude Include="..\common\tools_minidump.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\public\BSPTreeData.cpp" />
|
||||
<ClCompile Include="..\..\public\disp_common.cpp" />
|
||||
<ClCompile Include="..\..\public\disp_powerinfo.cpp" />
|
||||
<ClCompile Include="disp_vrad.cpp" />
|
||||
<ClCompile Include="imagepacker.cpp" />
|
||||
<ClCompile Include="incremental.cpp" />
|
||||
<ClCompile Include="leaf_ambient_lighting.cpp" />
|
||||
<ClCompile Include="lightmap.cpp" />
|
||||
<ClCompile Include="..\..\public\loadcmdline.cpp" />
|
||||
<ClCompile Include="..\..\public\lumpfiles.cpp" />
|
||||
<ClCompile Include="macro_texture.cpp" />
|
||||
<ClCompile Include="..\..\public\tier0\memoverride.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\mpi_stats.cpp" />
|
||||
<ClCompile Include="mpivrad.cpp" />
|
||||
<ClCompile Include="..\common\MySqlDatabase.cpp" />
|
||||
<ClCompile Include="..\common\pacifier.cpp" />
|
||||
<ClCompile Include="..\common\physdll.cpp" />
|
||||
<ClCompile Include="radial.cpp" />
|
||||
<ClCompile Include="SampleHash.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="..\common\utilmatlib.cpp" />
|
||||
<ClCompile Include="vismat.cpp" />
|
||||
<ClCompile Include="..\common\vmpi_tools_shared.cpp" />
|
||||
<ClCompile Include="vrad.cpp" />
|
||||
<ClCompile Include="VRAD_DispColl.cpp" />
|
||||
<ClCompile Include="VradDetailProps.cpp" />
|
||||
<ClCompile Include="VRadDisps.cpp" />
|
||||
<ClCompile Include="vraddll.cpp" />
|
||||
<ClCompile Include="VRadStaticProps.cpp" />
|
||||
<ClCompile Include="..\..\public\zip_utils.cpp" />
|
||||
<ClCompile Include="..\common\bsplib.cpp" />
|
||||
<ClCompile Include="..\..\public\builddisp.cpp" />
|
||||
<ClCompile Include="..\..\public\ChunkFile.cpp" />
|
||||
<ClCompile Include="..\common\cmdlib.cpp" />
|
||||
<ClCompile Include="..\..\public\DispColl_Common.cpp" />
|
||||
<ClCompile Include="..\common\map_shared.cpp" />
|
||||
<ClCompile Include="..\common\polylib.cpp" />
|
||||
<ClCompile Include="..\common\scriplib.cpp" />
|
||||
<ClCompile Include="..\common\threads.cpp" />
|
||||
<ClCompile Include="..\common\tools_minidump.cpp" />
|
||||
<ClCompile Include="..\..\public\CollisionUtils.cpp" />
|
||||
<ClCompile Include="..\..\public\filesystem_helpers.cpp" />
|
||||
<ClCompile Include="..\..\public\ScratchPad3D.cpp" />
|
||||
<ClCompile Include="..\..\public\ScratchPadUtils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\public\tier0\pointeroverride.asm">
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling pointeroverride.asm</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(VCInstallDir)bin\ml.exe" /c /Cp /Zi /Fo"$(IntDir)\%(Filename).obj" "%(FullPath)"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\%(Filename).obj</Outputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling pointeroverride.asm</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(VCInstallDir)bin\ml.exe" /c /Cp /Zi /Fo"$(IntDir)\%(Filename).obj" "%(FullPath)"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\%(Filename).obj</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="notes.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
563
utils/vrad/vrad_dll-2010.vcxproj.filters
Normal file
563
utils/vrad/vrad_dll-2010.vcxproj.filters
Normal file
@ -0,0 +1,563 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{1680C80B-FF1E-EA4D-9817-CC12254F2E40}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Common Header Files">
|
||||
<UniqueIdentifier>{AFC34ED7-EC78-E112-6213-16C13F1BBFB5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Public Header Files">
|
||||
<UniqueIdentifier>{53AF07E1-D7C4-FEE3-01A5-43636D973BE6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Link Libraries">
|
||||
<UniqueIdentifier>{C5D73B3A-C648-896C-B7CE-F174808E5BA5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{BA03E055-4FA2-FCE3-8A1C-D348547D379C}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Common Files">
|
||||
<UniqueIdentifier>{A7DC6913-C602-1488-0EDF-DE69D12F2421}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Public Files">
|
||||
<UniqueIdentifier>{A405CE38-5F8E-1A97-6C69-59BB1FF172C4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="..\..\lib\public\bitmap.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\mathlib.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\raytrace.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\tier0.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\tier1.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\tier2.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\vmpi.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\vstdlib.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
<Library Include="..\..\lib\public\vtf.lib">
|
||||
<Filter>Link Libraries</Filter>
|
||||
</Library>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="disp_vrad.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="iincremental.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="imagepacker.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="incremental.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="leaf_ambient_lighting.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="lightmap.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="macro_texture.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\map_utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mpivrad.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="radial.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\bitmap\tgawriter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vismat.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vrad.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VRAD_DispColl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vraddetailprops.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vraddll.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\bsplib.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\cmdlib.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\consolewnd.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\ichannel.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\imysqlwrapper.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\iphelpers.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\ISQLDBReplyTarget.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\map_shared.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\messbuf.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\mpi_stats.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\mysql_wrapper.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\MySqlDatabase.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\pacifier.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\polylib.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\scriplib.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\threadhelpers.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\threads.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\utilmatlib.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\vmpi_defs.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\vmpi_dispatch.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\vmpi_distribute_work.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\vmpi_filesystem.h">
|
||||
<Filter>Header Files\Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\amd3dx.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\ANORMS.H">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\basehandle.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\basetypes.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\bitbuf.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\bitvec.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\BSPFILE.H">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\bspflags.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\BSPTreeData.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\builddisp.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\bumpvects.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\byteswap.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\characterset.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\checksum_crc.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\checksum_md5.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\ChunkFile.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\cmodel.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\CollisionUtils.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\commonmacros.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\compressed_vector.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\const.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\coordsize.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\dbg.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\disp_common.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\disp_powerinfo.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\disp_vertindex.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\DispColl_Common.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\fasttimer.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\filesystem.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\filesystem_helpers.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\GameBSPFile.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\gametrace.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\halton.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\materialsystem\hardwareverts.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\appframework\IAppSystem.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\icommandline.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\ihandleentity.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\materialsystem\imaterial.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\materialsystem\imaterialsystem.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\materialsystem\imaterialvar.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\interface.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\iscratchpad3d.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\ivraddll.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\materialsystem\materialsystem_config.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\mathlib.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\memdbgon.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\optimize.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\phyfile.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\physdll.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\platform.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\protected_things.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\vstdlib\random.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\ScratchPad3D.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\ScratchPadUtils.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\string_t.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\strtools.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\studio.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\tokenreader.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\trace.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utlbuffer.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utldict.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utlhash.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utllinkedlist.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utlmemory.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utlrbtree.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utlsymbol.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier1\utlvector.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\vcollide.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\vector.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\vector2d.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\vector4d.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\vmatrix.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\vmpi\vmpi.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\vphysics_interface.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\mathlib\vplane.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\tier0\vprof.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\vstdlib\vstdlib.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\vtf\vtf.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\wadtypes.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\public\worldsize.h">
|
||||
<Filter>Header Files\Public Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\vmpi_tools_shared.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\tools_minidump.h">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\public\BSPTreeData.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\disp_common.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\disp_powerinfo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="disp_vrad.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="imagepacker.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="incremental.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="leaf_ambient_lighting.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="lightmap.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\loadcmdline.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\lumpfiles.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="macro_texture.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\tier0\memoverride.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\mpi_stats.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mpivrad.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\MySqlDatabase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\pacifier.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\physdll.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="radial.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SampleHash.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\utilmatlib.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vismat.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\vmpi_tools_shared.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vrad.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VRAD_DispColl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VradDetailProps.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VRadDisps.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vraddll.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VRadStaticProps.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\zip_utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\bsplib.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\builddisp.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\ChunkFile.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\cmdlib.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\DispColl_Common.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\map_shared.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\polylib.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\scriplib.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\threads.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\tools_minidump.cpp">
|
||||
<Filter>Source Files\Common Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\CollisionUtils.cpp">
|
||||
<Filter>Source Files\Public Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\filesystem_helpers.cpp">
|
||||
<Filter>Source Files\Public Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\ScratchPad3D.cpp">
|
||||
<Filter>Source Files\Public Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\public\ScratchPadUtils.cpp">
|
||||
<Filter>Source Files\Public Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\public\tier0\pointeroverride.asm">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="notes.txt">
|
||||
<Filter></Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
1034
utils/vrad/vraddetailprops.cpp
Normal file
1034
utils/vrad/vraddetailprops.cpp
Normal file
File diff suppressed because it is too large
Load Diff
34
utils/vrad/vraddetailprops.h
Normal file
34
utils/vrad/vraddetailprops.h
Normal file
@ -0,0 +1,34 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef VRADDETAILPROPS_H
|
||||
#define VRADDETAILPROPS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "bspfile.h"
|
||||
#include "mathlib/anorms.h"
|
||||
|
||||
|
||||
// Calculate the lighting at whatever surface the ray hits.
|
||||
// Note: this ADDS to the values already in color. So if you want absolute
|
||||
// values in there, then clear the values in color[] first.
|
||||
void CalcRayAmbientLighting(
|
||||
int iThread,
|
||||
const Vector &vStart,
|
||||
const Vector &vEnd,
|
||||
float tanTheta, // tangent of the inner angle of the cone
|
||||
Vector color[MAX_LIGHTSTYLES] // The color contribution from each lightstyle.
|
||||
);
|
||||
|
||||
bool CastRayInLeaf( int iThread, const Vector &start, const Vector &end, int leafIndex, float *pFraction, Vector *pNormal );
|
||||
|
||||
void ComputeDetailPropLighting( int iThread );
|
||||
|
||||
|
||||
#endif // VRADDETAILPROPS_H
|
1783
utils/vrad/vraddisps.cpp
Normal file
1783
utils/vrad/vraddisps.cpp
Normal file
File diff suppressed because it is too large
Load Diff
243
utils/vrad/vraddll.cpp
Normal file
243
utils/vrad/vraddll.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
//#include <strstrea.h>
|
||||
#include "vraddll.h"
|
||||
#include "bsplib.h"
|
||||
#include "vrad.h"
|
||||
#include "map_shared.h"
|
||||
#include "lightmap.h"
|
||||
#include "threads.h"
|
||||
|
||||
|
||||
static CUtlVector<unsigned char> g_LastGoodLightData;
|
||||
static CUtlVector<unsigned char> g_FacesTouched;
|
||||
|
||||
|
||||
static CVRadDLL g_VRadDLL;
|
||||
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CVRadDLL, IVRadDLL, VRAD_INTERFACE_VERSION, g_VRadDLL );
|
||||
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CVRadDLL, ILaunchableDLL, LAUNCHABLE_DLL_INTERFACE_VERSION, g_VRadDLL );
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------- //
|
||||
// temporary static array data size tracking
|
||||
// original data size = 143 megs
|
||||
// - converting ddispindices, ddispverts, g_dispinfo, and dlightdata to CUtlVector
|
||||
// - 51 megs
|
||||
// ---------------------------------------------------------------------------- //
|
||||
|
||||
class dat
|
||||
{
|
||||
public:
|
||||
char *name;
|
||||
int size;
|
||||
};
|
||||
#define DATENTRY(name) {#name, sizeof(name)}
|
||||
|
||||
dat g_Dats[] =
|
||||
{
|
||||
DATENTRY(dmodels),
|
||||
DATENTRY(dvisdata),
|
||||
DATENTRY(dlightdataLDR),
|
||||
DATENTRY(dlightdataHDR),
|
||||
DATENTRY(dentdata),
|
||||
DATENTRY(dleafs),
|
||||
DATENTRY(dplanes),
|
||||
DATENTRY(dvertexes),
|
||||
DATENTRY(g_vertnormalindices),
|
||||
DATENTRY(g_vertnormals),
|
||||
DATENTRY(texinfo),
|
||||
DATENTRY(dtexdata),
|
||||
DATENTRY(g_dispinfo),
|
||||
DATENTRY(dorigfaces),
|
||||
DATENTRY(g_primitives),
|
||||
DATENTRY(g_primverts),
|
||||
DATENTRY(g_primindices),
|
||||
DATENTRY(dfaces),
|
||||
DATENTRY(dedges),
|
||||
DATENTRY(dleaffaces),
|
||||
DATENTRY(dleafbrushes),
|
||||
DATENTRY(dsurfedges),
|
||||
DATENTRY(dbrushes),
|
||||
DATENTRY(dbrushsides),
|
||||
DATENTRY(dareas),
|
||||
DATENTRY(dareaportals),
|
||||
DATENTRY(dworldlights),
|
||||
DATENTRY(dleafwaterdata),
|
||||
DATENTRY(g_ClipPortalVerts),
|
||||
DATENTRY(g_CubemapSamples),
|
||||
DATENTRY(g_TexDataStringData),
|
||||
DATENTRY(g_TexDataStringTable),
|
||||
DATENTRY(g_Overlays)
|
||||
};
|
||||
|
||||
int CalcDatSize()
|
||||
{
|
||||
int ret = 0;
|
||||
int count = sizeof( g_Dats ) / sizeof( g_Dats[0] );
|
||||
|
||||
int i;
|
||||
for( i=1; i < count; i++ )
|
||||
{
|
||||
if( g_Dats[i-1].size > g_Dats[i].size )
|
||||
{
|
||||
dat temp = g_Dats[i-1];
|
||||
g_Dats[i-1] = g_Dats[i];
|
||||
g_Dats[i] = temp;
|
||||
|
||||
if( i > 1 )
|
||||
i -= 2;
|
||||
else
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
for( i=0; i < count; i++ )
|
||||
ret += g_Dats[i].size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int g_TotalDatSize = CalcDatSize();
|
||||
|
||||
|
||||
|
||||
|
||||
int CVRadDLL::main( int argc, char **argv )
|
||||
{
|
||||
return VRAD_Main( argc, argv );
|
||||
}
|
||||
|
||||
|
||||
bool CVRadDLL::Init( char const *pFilename )
|
||||
{
|
||||
VRAD_Init();
|
||||
|
||||
// Set options and run vrad startup code.
|
||||
do_fast = true;
|
||||
g_bLowPriorityThreads = true;
|
||||
g_pIncremental = GetIncremental();
|
||||
|
||||
VRAD_LoadBSP( pFilename );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CVRadDLL::Release()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CVRadDLL::GetBSPInfo( CBSPInfo *pInfo )
|
||||
{
|
||||
pInfo->dlightdata = pdlightdata->Base();
|
||||
pInfo->lightdatasize = pdlightdata->Count();
|
||||
|
||||
pInfo->dfaces = dfaces;
|
||||
pInfo->m_pFacesTouched = g_FacesTouched.Base();
|
||||
pInfo->numfaces = numfaces;
|
||||
|
||||
pInfo->dvertexes = dvertexes;
|
||||
pInfo->numvertexes = numvertexes;
|
||||
|
||||
pInfo->dedges = dedges;
|
||||
pInfo->numedges = numedges;
|
||||
|
||||
pInfo->dsurfedges = dsurfedges;
|
||||
pInfo->numsurfedges = numsurfedges;
|
||||
|
||||
pInfo->texinfo = texinfo.Base();
|
||||
pInfo->numtexinfo = texinfo.Count();
|
||||
|
||||
pInfo->g_dispinfo = g_dispinfo.Base();
|
||||
pInfo->g_numdispinfo = g_dispinfo.Count();
|
||||
|
||||
pInfo->dtexdata = dtexdata;
|
||||
pInfo->numtexdata = numtexdata;
|
||||
|
||||
pInfo->texDataStringData = g_TexDataStringData.Base();
|
||||
pInfo->nTexDataStringData = g_TexDataStringData.Count();
|
||||
|
||||
pInfo->texDataStringTable = g_TexDataStringTable.Base();
|
||||
pInfo->nTexDataStringTable = g_TexDataStringTable.Count();
|
||||
}
|
||||
|
||||
|
||||
bool CVRadDLL::DoIncrementalLight( char const *pVMFFile )
|
||||
{
|
||||
char tempPath[MAX_PATH], tempFilename[MAX_PATH];
|
||||
GetTempPath( sizeof( tempPath ), tempPath );
|
||||
GetTempFileName( tempPath, "vmf_entities_", 0, tempFilename );
|
||||
|
||||
FileHandle_t fp = g_pFileSystem->Open( tempFilename, "wb" );
|
||||
if( !fp )
|
||||
return false;
|
||||
|
||||
g_pFileSystem->Write( pVMFFile, strlen(pVMFFile)+1, fp );
|
||||
g_pFileSystem->Close( fp );
|
||||
|
||||
// Parse the new entities.
|
||||
if( !LoadEntsFromMapFile( tempFilename ) )
|
||||
return false;
|
||||
|
||||
// Create lights.
|
||||
CreateDirectLights();
|
||||
|
||||
// set up sky cameras
|
||||
ProcessSkyCameras();
|
||||
|
||||
g_bInterrupt = false;
|
||||
if( RadWorld_Go() )
|
||||
{
|
||||
// Save off the last finished lighting results for the BSP.
|
||||
g_LastGoodLightData.CopyArray( pdlightdata->Base(), pdlightdata->Count() );
|
||||
if( g_pIncremental )
|
||||
g_pIncremental->GetFacesTouched( g_FacesTouched );
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_iCurFace = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CVRadDLL::Serialize()
|
||||
{
|
||||
if( !g_pIncremental )
|
||||
return false;
|
||||
|
||||
if( g_LastGoodLightData.Count() > 0 )
|
||||
{
|
||||
pdlightdata->CopyArray( g_LastGoodLightData.Base(), g_LastGoodLightData.Count() );
|
||||
|
||||
if( g_pIncremental->Serialize() )
|
||||
{
|
||||
// Delete this so it doesn't keep re-saving it.
|
||||
g_LastGoodLightData.Purge();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float CVRadDLL::GetPercentComplete()
|
||||
{
|
||||
return (float)g_iCurFace / numfaces;
|
||||
}
|
||||
|
||||
|
||||
void CVRadDLL::Interrupt()
|
||||
{
|
||||
g_bInterrupt = true;
|
||||
}
|
||||
|
||||
|
34
utils/vrad/vraddll.h
Normal file
34
utils/vrad/vraddll.h
Normal file
@ -0,0 +1,34 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef VRADDLL_H
|
||||
#define VRADDLL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "ivraddll.h"
|
||||
#include "ilaunchabledll.h"
|
||||
|
||||
|
||||
class CVRadDLL : public IVRadDLL, public ILaunchableDLL
|
||||
{
|
||||
// IVRadDLL overrides.
|
||||
public:
|
||||
virtual int main( int argc, char **argv );
|
||||
virtual bool Init( char const *pFilename );
|
||||
virtual void Release();
|
||||
virtual void GetBSPInfo( CBSPInfo *pInfo );
|
||||
virtual bool DoIncrementalLight( char const *pVMFFile );
|
||||
virtual bool Serialize();
|
||||
virtual float GetPercentComplete();
|
||||
virtual void Interrupt();
|
||||
};
|
||||
|
||||
|
||||
#endif // VRADDLL_H
|
1915
utils/vrad/vradstaticprops.cpp
Normal file
1915
utils/vrad/vradstaticprops.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user