1
0
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:
Joe Ludwig
2013-06-26 15:22:04 -07:00
commit e7d6f4c174
3682 changed files with 1624327 additions and 0 deletions

332
utils/vrad/disp_vrad.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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");
}

View 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

File diff suppressed because it is too large Load Diff

141
utils/vrad/lightmap.h Normal file
View 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

View 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 );
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

610
utils/vrad/vrad.h Normal file
View 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

File diff suppressed because it is too large Load Diff

View 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

View 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 &quot;..\..\..\game\bin&quot; mkdir &quot;..\..\..\game\bin&quot;&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetFileName) &quot;..\..\..\game\bin\$(TargetFileName)&quot;&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;if exist &quot;$(TargetDir)&quot;$(TargetName).map copy &quot;$(TargetDir)&quot;$(TargetName).map ..\..\..\game\bin\$(TargetName).map&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetName).pdb ..\..\..\game\bin\$(TargetName).pdb&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;goto BuildEventOK&#x0D;&#x0A;:BuildEventFailed&#x0D;&#x0A;echo *** ERROR! PostBuildStep FAILED for $(ProjectName)! EXE or DLL is probably running. ***&#x0D;&#x0A;del /q &quot;$(TargetDir)&quot;$(TargetFileName)&#x0D;&#x0A;exit 1&#x0D;&#x0A;:BuildEventOK&#x0D;&#x0A;</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 &quot;..\..\..\game\bin&quot; mkdir &quot;..\..\..\game\bin&quot;&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetFileName) &quot;..\..\..\game\bin\$(TargetFileName)&quot;&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;if exist &quot;$(TargetDir)&quot;$(TargetName).map copy &quot;$(TargetDir)&quot;$(TargetName).map ..\..\..\game\bin\$(TargetName).map&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetName).pdb ..\..\..\game\bin\$(TargetName).pdb&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;goto BuildEventOK&#x0D;&#x0A;:BuildEventFailed&#x0D;&#x0A;echo *** ERROR! PostBuildStep FAILED for $(ProjectName)! EXE or DLL is probably running. ***&#x0D;&#x0A;del /q &quot;$(TargetDir)&quot;$(TargetFileName)&#x0D;&#x0A;exit 1&#x0D;&#x0A;:BuildEventOK&#x0D;&#x0A;</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'">&quot;$(VCInstallDir)bin\ml.exe&quot; /c /Cp /Zi /Fo&quot;$(IntDir)\%(Filename).obj&quot; &quot;%(FullPath)&quot;</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'">&quot;$(VCInstallDir)bin\ml.exe&quot; /c /Cp /Zi /Fo&quot;$(IntDir)\%(Filename).obj&quot; &quot;%(FullPath)&quot;</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>

View 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>

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

243
utils/vrad/vraddll.cpp Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff