Fix line endings. WHAMMY.

This commit is contained in:
Jørgen P. Tjernø
2013-12-02 19:31:46 -08:00
parent c47ad60970
commit f56bb35301
6719 changed files with 2805089 additions and 2805089 deletions

View File

@@ -1,285 +1,285 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "vbsp.h"
#include "BoundBox.h"
//#include "hammer_mathlib.h"
//#include "MapDefs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
float rint(float f)
{
if (f > 0.0f) {
return (float) floor(f + 0.5f);
} else if (f < 0.0f) {
return (float) ceil(f - 0.5f);
} else
return 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
BoundBox::BoundBox(void)
{
ResetBounds();
}
BoundBox::BoundBox(const Vector &mins, const Vector &maxs)
{
bmins = mins;
bmaxs = maxs;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the box to an uninitialized state, so that calls to UpdateBounds
// will properly set the mins and maxs.
//-----------------------------------------------------------------------------
void BoundBox::ResetBounds(void)
{
bmins[0] = bmins[1] = bmins[2] = COORD_NOTINIT;
bmaxs[0] = bmaxs[1] = bmaxs[2] = -COORD_NOTINIT;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pt -
//-----------------------------------------------------------------------------
void BoundBox::UpdateBounds(const Vector& pt)
{
if(pt[0] < bmins[0])
bmins[0] = pt[0];
if(pt[1] < bmins[1])
bmins[1] = pt[1];
if(pt[2] < bmins[2])
bmins[2] = pt[2];
if(pt[0] > bmaxs[0])
bmaxs[0] = pt[0];
if(pt[1] > bmaxs[1])
bmaxs[1] = pt[1];
if(pt[2] > bmaxs[2])
bmaxs[2] = pt[2];
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bmins -
// bmaxs -
//-----------------------------------------------------------------------------
void BoundBox::UpdateBounds(const Vector& mins, const Vector& maxs)
{
if(mins[0] < bmins[0])
bmins[0] = mins[0];
if(mins[1] < bmins[1])
bmins[1] = mins[1];
if(mins[2] < bmins[2])
bmins[2] = mins[2];
if(maxs[0] > bmaxs[0])
bmaxs[0] = maxs[0];
if(maxs[1] > bmaxs[1])
bmaxs[1] = maxs[1];
if(maxs[2] > bmaxs[2])
bmaxs[2] = maxs[2];
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pBox -
//-----------------------------------------------------------------------------
void BoundBox::UpdateBounds(const BoundBox *pBox)
{
UpdateBounds(pBox->bmins, pBox->bmaxs);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ptdest -
//-----------------------------------------------------------------------------
void BoundBox::GetBoundsCenter(Vector& ptdest)
{
ptdest = (bmins + bmaxs)/2.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pt -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool BoundBox::ContainsPoint(const Vector& pt) const
{
for (int i = 0; i < 3; i++)
{
if (pt[i] < bmins[i] || pt[i] > bmaxs[i])
{
return(false);
}
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pfMins -
// pfMaxs -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool BoundBox::IsIntersectingBox(const Vector& pfMins, const Vector& pfMaxs) const
{
if ((bmins[0] >= pfMaxs[0]) || (bmaxs[0] <= pfMins[0]))
{
return(false);
}
if ((bmins[1] >= pfMaxs[1]) || (bmaxs[1] <= pfMins[1]))
{
return(false);
}
if ((bmins[2] >= pfMaxs[2]) || (bmaxs[2] <= pfMins[2]))
{
return(false);
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pfMins -
// pfMaxs -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool BoundBox::IsInsideBox(const Vector& pfMins, const Vector& pfMaxs) const
{
if ((bmins[0] < pfMins[0]) || (bmaxs[0] > pfMaxs[0]))
{
return(false);
}
if ((bmins[1] < pfMins[1]) || (bmaxs[1] > pfMaxs[1]))
{
return(false);
}
if ((bmins[2] < pfMins[2]) || (bmaxs[2] > pfMaxs[2]))
{
return(false);
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether this bounding box is valid, ie maxs >= mins.
//-----------------------------------------------------------------------------
bool BoundBox::IsValidBox(void) const
{
for (int i = 0; i < 3; i++)
{
if (bmins[i] > bmaxs[i])
{
return(false);
}
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : size -
//-----------------------------------------------------------------------------
void BoundBox::GetBoundsSize(Vector& size)
{
size[0] = bmaxs[0] - bmins[0];
size[1] = bmaxs[1] - bmins[1];
size[2] = bmaxs[2] - bmins[2];
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iValue -
// iGridSize -
// Output :
//-----------------------------------------------------------------------------
static int Snap(/*int*/ float iValue, int iGridSize)
{
return (int)(rint(iValue/iGridSize) * iGridSize);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iGridSize -
//-----------------------------------------------------------------------------
void BoundBox::SnapToGrid(int iGridSize)
{
// does not alter the size of the box .. snaps its minimal coordinates
// to the grid size specified in iGridSize
Vector size;
GetBoundsSize(size);
for(int i = 0; i < 3; i++)
{
bmins[i] = (float)Snap(/* YWB (int)*/bmins[i], iGridSize);
bmaxs[i] = bmins[i] + size[i];
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : axis -
//-----------------------------------------------------------------------------
void BoundBox::Rotate90(int axis)
{
int e1 = AXIS_X, e2 = AXIS_Y;
// get bounds center first
Vector center;
GetBoundsCenter(center);
switch(axis)
{
case AXIS_Z:
e1 = AXIS_X;
e2 = AXIS_Y;
break;
case AXIS_X:
e1 = AXIS_Y;
e2 = AXIS_Z;
break;
case AXIS_Y:
e1 = AXIS_X;
e2 = AXIS_Z;
break;
}
float tmp1, tmp2;
tmp1 = bmins[e1] - center[e1] + center[e2];
tmp2 = bmaxs[e1] - center[e1] + center[e2];
bmins[e1] = bmins[e2] - center[e2] + center[e1];
bmaxs[e1] = bmaxs[e2] - center[e2] + center[e1];
bmins[e2] = tmp1;
bmaxs[e2] = tmp2;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "vbsp.h"
#include "BoundBox.h"
//#include "hammer_mathlib.h"
//#include "MapDefs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
float rint(float f)
{
if (f > 0.0f) {
return (float) floor(f + 0.5f);
} else if (f < 0.0f) {
return (float) ceil(f - 0.5f);
} else
return 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
BoundBox::BoundBox(void)
{
ResetBounds();
}
BoundBox::BoundBox(const Vector &mins, const Vector &maxs)
{
bmins = mins;
bmaxs = maxs;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the box to an uninitialized state, so that calls to UpdateBounds
// will properly set the mins and maxs.
//-----------------------------------------------------------------------------
void BoundBox::ResetBounds(void)
{
bmins[0] = bmins[1] = bmins[2] = COORD_NOTINIT;
bmaxs[0] = bmaxs[1] = bmaxs[2] = -COORD_NOTINIT;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pt -
//-----------------------------------------------------------------------------
void BoundBox::UpdateBounds(const Vector& pt)
{
if(pt[0] < bmins[0])
bmins[0] = pt[0];
if(pt[1] < bmins[1])
bmins[1] = pt[1];
if(pt[2] < bmins[2])
bmins[2] = pt[2];
if(pt[0] > bmaxs[0])
bmaxs[0] = pt[0];
if(pt[1] > bmaxs[1])
bmaxs[1] = pt[1];
if(pt[2] > bmaxs[2])
bmaxs[2] = pt[2];
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bmins -
// bmaxs -
//-----------------------------------------------------------------------------
void BoundBox::UpdateBounds(const Vector& mins, const Vector& maxs)
{
if(mins[0] < bmins[0])
bmins[0] = mins[0];
if(mins[1] < bmins[1])
bmins[1] = mins[1];
if(mins[2] < bmins[2])
bmins[2] = mins[2];
if(maxs[0] > bmaxs[0])
bmaxs[0] = maxs[0];
if(maxs[1] > bmaxs[1])
bmaxs[1] = maxs[1];
if(maxs[2] > bmaxs[2])
bmaxs[2] = maxs[2];
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pBox -
//-----------------------------------------------------------------------------
void BoundBox::UpdateBounds(const BoundBox *pBox)
{
UpdateBounds(pBox->bmins, pBox->bmaxs);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ptdest -
//-----------------------------------------------------------------------------
void BoundBox::GetBoundsCenter(Vector& ptdest)
{
ptdest = (bmins + bmaxs)/2.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pt -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool BoundBox::ContainsPoint(const Vector& pt) const
{
for (int i = 0; i < 3; i++)
{
if (pt[i] < bmins[i] || pt[i] > bmaxs[i])
{
return(false);
}
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pfMins -
// pfMaxs -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool BoundBox::IsIntersectingBox(const Vector& pfMins, const Vector& pfMaxs) const
{
if ((bmins[0] >= pfMaxs[0]) || (bmaxs[0] <= pfMins[0]))
{
return(false);
}
if ((bmins[1] >= pfMaxs[1]) || (bmaxs[1] <= pfMins[1]))
{
return(false);
}
if ((bmins[2] >= pfMaxs[2]) || (bmaxs[2] <= pfMins[2]))
{
return(false);
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pfMins -
// pfMaxs -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool BoundBox::IsInsideBox(const Vector& pfMins, const Vector& pfMaxs) const
{
if ((bmins[0] < pfMins[0]) || (bmaxs[0] > pfMaxs[0]))
{
return(false);
}
if ((bmins[1] < pfMins[1]) || (bmaxs[1] > pfMaxs[1]))
{
return(false);
}
if ((bmins[2] < pfMins[2]) || (bmaxs[2] > pfMaxs[2]))
{
return(false);
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether this bounding box is valid, ie maxs >= mins.
//-----------------------------------------------------------------------------
bool BoundBox::IsValidBox(void) const
{
for (int i = 0; i < 3; i++)
{
if (bmins[i] > bmaxs[i])
{
return(false);
}
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : size -
//-----------------------------------------------------------------------------
void BoundBox::GetBoundsSize(Vector& size)
{
size[0] = bmaxs[0] - bmins[0];
size[1] = bmaxs[1] - bmins[1];
size[2] = bmaxs[2] - bmins[2];
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iValue -
// iGridSize -
// Output :
//-----------------------------------------------------------------------------
static int Snap(/*int*/ float iValue, int iGridSize)
{
return (int)(rint(iValue/iGridSize) * iGridSize);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iGridSize -
//-----------------------------------------------------------------------------
void BoundBox::SnapToGrid(int iGridSize)
{
// does not alter the size of the box .. snaps its minimal coordinates
// to the grid size specified in iGridSize
Vector size;
GetBoundsSize(size);
for(int i = 0; i < 3; i++)
{
bmins[i] = (float)Snap(/* YWB (int)*/bmins[i], iGridSize);
bmaxs[i] = bmins[i] + size[i];
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : axis -
//-----------------------------------------------------------------------------
void BoundBox::Rotate90(int axis)
{
int e1 = AXIS_X, e2 = AXIS_Y;
// get bounds center first
Vector center;
GetBoundsCenter(center);
switch(axis)
{
case AXIS_Z:
e1 = AXIS_X;
e2 = AXIS_Y;
break;
case AXIS_X:
e1 = AXIS_Y;
e2 = AXIS_Z;
break;
case AXIS_Y:
e1 = AXIS_X;
e2 = AXIS_Z;
break;
}
float tmp1, tmp2;
tmp1 = bmins[e1] - center[e1] + center[e2];
tmp2 = bmaxs[e1] - center[e1] + center[e2];
bmins[e1] = bmins[e2] - center[e2] + center[e1];
bmaxs[e1] = bmaxs[e2] - center[e2] + center[e1];
bmins[e2] = tmp1;
bmaxs[e2] = tmp2;
}

View File

@@ -1,79 +1,79 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: An axis aligned bounding box class.
//
// $NoKeywords: $
//=============================================================================//
#ifndef BOUNDBOX_H
#define BOUNDBOX_H
#ifdef _WIN32
#pragma once
#endif
#include "mathlib/vector.h"
#define COORD_NOTINIT ((float)(99999.0))
enum
{
AXIS_X = 0,
AXIS_Y,
AXIS_Z
};
class BoundBox
{
public:
BoundBox(void);
BoundBox(const Vector &mins, const Vector &maxs);
void ResetBounds(void);
inline void SetBounds(const Vector &mins, const Vector &maxs);
void UpdateBounds(const Vector& bmins, const Vector& bmaxs);
void UpdateBounds(const Vector& pt);
void UpdateBounds(const BoundBox *pBox);
void GetBoundsCenter(Vector& ptdest);
inline void GetBounds(Vector& Mins, Vector& Maxs);
virtual bool IsIntersectingBox(const Vector& pfMins, const Vector& pfMaxs) const;
bool IsInsideBox(const Vector& pfMins, const Vector& pfMaxs) const;
bool ContainsPoint(const Vector& pt) const;
bool IsValidBox(void) const;
void GetBoundsSize(Vector& size);
void SnapToGrid(int iGridSize);
void Rotate90(int axis);
Vector bmins;
Vector bmaxs;
};
//-----------------------------------------------------------------------------
// Purpose: Gets the bounding box as two vectors, a min and a max.
// Input : Mins - Receives the box's minima.
// Maxs - Receives the box's maxima.
//-----------------------------------------------------------------------------
void BoundBox::GetBounds(Vector &Mins, Vector &Maxs)
{
Mins = bmins;
Maxs = bmaxs;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the box outright, equivalent to ResetBounds + UpdateBounds.
// Input : mins - Minima to set.
// maxs - Maxima to set.
//-----------------------------------------------------------------------------
void BoundBox::SetBounds(const Vector &mins, const Vector &maxs)
{
bmins = mins;
bmaxs = maxs;
}
#endif // BOUNDBOX_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: An axis aligned bounding box class.
//
// $NoKeywords: $
//=============================================================================//
#ifndef BOUNDBOX_H
#define BOUNDBOX_H
#ifdef _WIN32
#pragma once
#endif
#include "mathlib/vector.h"
#define COORD_NOTINIT ((float)(99999.0))
enum
{
AXIS_X = 0,
AXIS_Y,
AXIS_Z
};
class BoundBox
{
public:
BoundBox(void);
BoundBox(const Vector &mins, const Vector &maxs);
void ResetBounds(void);
inline void SetBounds(const Vector &mins, const Vector &maxs);
void UpdateBounds(const Vector& bmins, const Vector& bmaxs);
void UpdateBounds(const Vector& pt);
void UpdateBounds(const BoundBox *pBox);
void GetBoundsCenter(Vector& ptdest);
inline void GetBounds(Vector& Mins, Vector& Maxs);
virtual bool IsIntersectingBox(const Vector& pfMins, const Vector& pfMaxs) const;
bool IsInsideBox(const Vector& pfMins, const Vector& pfMaxs) const;
bool ContainsPoint(const Vector& pt) const;
bool IsValidBox(void) const;
void GetBoundsSize(Vector& size);
void SnapToGrid(int iGridSize);
void Rotate90(int axis);
Vector bmins;
Vector bmaxs;
};
//-----------------------------------------------------------------------------
// Purpose: Gets the bounding box as two vectors, a min and a max.
// Input : Mins - Receives the box's minima.
// Maxs - Receives the box's maxima.
//-----------------------------------------------------------------------------
void BoundBox::GetBounds(Vector &Mins, Vector &Maxs)
{
Mins = bmins;
Maxs = bmaxs;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the box outright, equivalent to ResetBounds + UpdateBounds.
// Input : mins - Minima to set.
// maxs - Maxima to set.
//-----------------------------------------------------------------------------
void BoundBox::SetBounds(const Vector &mins, const Vector &maxs)
{
bmins = mins;
bmaxs = maxs;
}
#endif // BOUNDBOX_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef CSG_H
#define CSG_H
#ifdef _WIN32
#pragma once
#endif
// Print a CONTENTS_ mask to a string.
void PrintBrushContentsToString( int contents, char *pOut, int nMaxChars );
// Print a CONTENTS_ mask with Msg().
void PrintBrushContents( int contents );
void FixupAreaportalWaterBrushes( bspbrush_t *pList );
bspbrush_t *MakeBspBrushList (int startbrush, int endbrush,
const Vector& clipmins, const Vector& clipmaxs, int detailScreen);
bspbrush_t *MakeBspBrushList (mapbrush_t **pBrushes, int nBrushCount, const Vector& clipmins, const Vector& clipmaxs);
void WriteBrushMap (char *name, bspbrush_t *list);
bspbrush_t *ChopBrushes (bspbrush_t *head);
bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b);
qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b);
#endif // CSG_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef CSG_H
#define CSG_H
#ifdef _WIN32
#pragma once
#endif
// Print a CONTENTS_ mask to a string.
void PrintBrushContentsToString( int contents, char *pOut, int nMaxChars );
// Print a CONTENTS_ mask with Msg().
void PrintBrushContents( int contents );
void FixupAreaportalWaterBrushes( bspbrush_t *pList );
bspbrush_t *MakeBspBrushList (int startbrush, int endbrush,
const Vector& clipmins, const Vector& clipmaxs, int detailScreen);
bspbrush_t *MakeBspBrushList (mapbrush_t **pBrushes, int nBrushCount, const Vector& clipmins, const Vector& clipmaxs);
void WriteBrushMap (char *name, bspbrush_t *list);
bspbrush_t *ChopBrushes (bspbrush_t *head);
bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b);
qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b);
#endif // CSG_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DETAIL_H
#define DETAIL_H
#ifdef _WIN32
#pragma once
#endif
face_t *MergeDetailTree( tree_t *worldtree, int brush_start, int brush_end );
#endif // DETAIL_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DETAIL_H
#define DETAIL_H
#ifdef _WIN32
#pragma once
#endif
face_t *MergeDetailTree( tree_t *worldtree, int brush_start, int brush_end );
#endif // DETAIL_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,359 +1,359 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "vbsp.h"
#include "disp_vbsp.h"
#include "builddisp.h"
#include "disp_common.h"
#include "ivp.h"
#include "disp_ivp.h"
#include "vphysics_interface.h"
#include "vphysics/virtualmesh.h"
#include "utlrbtree.h"
#include "tier1/utlbuffer.h"
#include "materialpatch.h"
struct disp_grid_t
{
int gridIndex;
CUtlVector<int> dispList;
};
static CUtlVector<disp_grid_t> gDispGridList;
disp_grid_t &FindOrInsertGrid( int gridIndex )
{
// linear search is slow, but only a few grids will be present
for ( int i = gDispGridList.Count()-1; i >= 0; i-- )
{
if ( gDispGridList[i].gridIndex == gridIndex )
{
return gDispGridList[i];
}
}
int index = gDispGridList.AddToTail();
gDispGridList[index].gridIndex = gridIndex;
// must be empty
Assert( gDispGridList[index].dispList.Count() == 0 );
return gDispGridList[index];
}
// UNDONE: Tune these or adapt them to map size or triangle count?
#define DISP_GRID_SIZEX 4096
#define DISP_GRID_SIZEY 4096
#define DISP_GRID_SIZEZ 8192
int Disp_GridIndex( CCoreDispInfo *pDispInfo )
{
// quick hash the center into the grid and put the whole terrain in that grid
Vector mins, maxs;
pDispInfo->GetNode(0)->GetBoundingBox( mins, maxs );
Vector center;
center = 0.5 * (mins + maxs);
// make sure it's positive
center += Vector(MAX_COORD_INTEGER,MAX_COORD_INTEGER,MAX_COORD_INTEGER);
int gridX = center.x / DISP_GRID_SIZEX;
int gridY = center.y / DISP_GRID_SIZEY;
int gridZ = center.z / DISP_GRID_SIZEZ;
gridX &= 0xFF;
gridY &= 0xFF;
gridZ &= 0xFF;
return MAKEID( gridX, gridY, gridZ, 0 );
}
void AddToGrid( int gridIndex, int dispIndex )
{
disp_grid_t &grid = FindOrInsertGrid( gridIndex );
grid.dispList.AddToTail( dispIndex );
}
MaterialSystemMaterial_t GetMatIDFromDisp( mapdispinfo_t *pMapDisp )
{
texinfo_t *pTexInfo = &texinfo[pMapDisp->face.texinfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
MaterialSystemMaterial_t matID = FindOriginalMaterial( TexDataStringTable_GetString( pTexData->nameStringTableID ), NULL, true );
return matID;
}
// check this and disable virtual mesh if in use
bool Disp_HasPower4Displacements()
{
for ( int i = 0; i < g_CoreDispInfos.Count(); i++ )
{
if ( g_CoreDispInfos[i]->GetPower() > 3 )
{
return true;
}
}
return false;
}
// adds all displacement faces as a series of convex objects
// UNDONE: Only add the displacements for this model?
void Disp_AddCollisionModels( CUtlVector<CPhysCollisionEntry *> &collisionList, dmodel_t *pModel, int contentsMask)
{
int dispIndex;
// Add each displacement to the grid hash
for ( dispIndex = 0; dispIndex < g_CoreDispInfos.Count(); dispIndex++ )
{
CCoreDispInfo *pDispInfo = g_CoreDispInfos[ dispIndex ];
mapdispinfo_t *pMapDisp = &mapdispinfo[ dispIndex ];
// not solid for this pass
if ( !(pMapDisp->contents & contentsMask) )
continue;
int gridIndex = Disp_GridIndex( pDispInfo );
AddToGrid( gridIndex, dispIndex );
}
// now make a polysoup for the terrain in each grid
for ( int grid = 0; grid < gDispGridList.Count(); grid++ )
{
int triCount = 0;
CPhysPolysoup *pTerrainPhysics = physcollision->PolysoupCreate();
// iterate the displacements in this grid
for ( int listIndex = 0; listIndex < gDispGridList[grid].dispList.Count(); listIndex++ )
{
dispIndex = gDispGridList[grid].dispList[listIndex];
CCoreDispInfo *pDispInfo = g_CoreDispInfos[ dispIndex ];
mapdispinfo_t *pMapDisp = &mapdispinfo[ dispIndex ];
// Get the material id.
MaterialSystemMaterial_t matID = GetMatIDFromDisp( pMapDisp );
// Build a triangle list. This shares the tesselation code with the engine.
CUtlVector<unsigned short> indices;
CVBSPTesselateHelper helper;
helper.m_pIndices = &indices;
helper.m_pActiveVerts = pDispInfo->GetAllowedVerts().Base();
helper.m_pPowerInfo = pDispInfo->GetPowerInfo();
::TesselateDisplacement( &helper );
Assert( indices.Count() > 0 );
Assert( indices.Count() % 3 == 0 ); // Make sure indices are a multiple of 3.
int nTriCount = indices.Count() / 3;
triCount += nTriCount;
if ( triCount >= 65536 )
{
// don't put more than 64K tris in any single collision model
CPhysCollide *pCollide = physcollision->ConvertPolysoupToCollide( pTerrainPhysics, false );
if ( pCollide )
{
collisionList.AddToTail( new CPhysCollisionEntryStaticMesh( pCollide, NULL ) );
}
// Throw this polysoup away and start over for the remaining triangles
physcollision->PolysoupDestroy( pTerrainPhysics );
pTerrainPhysics = physcollision->PolysoupCreate();
triCount = nTriCount;
}
Vector tmpVerts[3];
for ( int iTri = 0; iTri < nTriCount; ++iTri )
{
float flAlphaTotal = 0.0f;
for ( int iTriVert = 0; iTriVert < 3; ++iTriVert )
{
pDispInfo->GetVert( indices[iTri*3+iTriVert], tmpVerts[iTriVert] );
flAlphaTotal += pDispInfo->GetAlpha( indices[iTri*3+iTriVert] );
}
int nProp = g_SurfaceProperties[texinfo[pMapDisp->face.texinfo].texdata];
if ( flAlphaTotal > DISP_ALPHA_PROP_DELTA )
{
int nProp2 = GetSurfaceProperties2( matID, "surfaceprop2" );
if ( nProp2 != -1 )
{
nProp = nProp2;
}
}
int nMaterialIndex = RemapWorldMaterial( nProp );
physcollision->PolysoupAddTriangle( pTerrainPhysics, tmpVerts[0], tmpVerts[1], tmpVerts[2], nMaterialIndex );
}
}
// convert the whole grid's polysoup to a collide and store in the collision list
CPhysCollide *pCollide = physcollision->ConvertPolysoupToCollide( pTerrainPhysics, false );
if ( pCollide )
{
collisionList.AddToTail( new CPhysCollisionEntryStaticMesh( pCollide, NULL ) );
}
// now that we have the collide, we're done with the soup
physcollision->PolysoupDestroy( pTerrainPhysics );
}
}
class CDispMeshEvent : public IVirtualMeshEvent
{
public:
CDispMeshEvent( unsigned short *pIndices, int indexCount, CCoreDispInfo *pDispInfo );
virtual void GetVirtualMesh( void *userData, virtualmeshlist_t *pList );
virtual void GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs );
virtual void GetTrianglesInSphere( void *userData, const Vector &center, float radius, virtualmeshtrianglelist_t *pList );
CUtlVector<Vector> m_verts;
unsigned short *m_pIndices;
int m_indexCount;
};
CDispMeshEvent::CDispMeshEvent( unsigned short *pIndices, int indexCount, CCoreDispInfo *pDispInfo )
{
m_pIndices = pIndices;
m_indexCount = indexCount;
int maxIndex = 0;
for ( int i = 0; i < indexCount; i++ )
{
if ( pIndices[i] > maxIndex )
{
maxIndex = pIndices[i];
}
}
for ( int i = 0; i < indexCount/2; i++ )
{
V_swap( pIndices[i], pIndices[(indexCount-i)-1] );
}
int count = maxIndex + 1;
m_verts.SetCount( count );
for ( int i = 0; i < count; i++ )
{
m_verts[i] = pDispInfo->GetVert(i);
}
}
void CDispMeshEvent::GetVirtualMesh( void *userData, virtualmeshlist_t *pList )
{
Assert(userData==((void *)this));
pList->pVerts = m_verts.Base();
pList->indexCount = m_indexCount;
pList->triangleCount = m_indexCount/3;
pList->vertexCount = m_verts.Count();
pList->surfacePropsIndex = 0; // doesn't matter here, reset at runtime
pList->pHull = NULL;
int indexMax = ARRAYSIZE(pList->indices);
int indexCount = min(m_indexCount, indexMax);
Assert(m_indexCount < indexMax);
Q_memcpy( pList->indices, m_pIndices, sizeof(*m_pIndices) * indexCount );
}
void CDispMeshEvent::GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs )
{
Assert(userData==((void *)this));
ClearBounds( *pMins, *pMaxs );
for ( int i = 0; i < m_verts.Count(); i++ )
{
AddPointToBounds( m_verts[i], *pMins, *pMaxs );
}
}
void CDispMeshEvent::GetTrianglesInSphere( void *userData, const Vector &center, float radius, virtualmeshtrianglelist_t *pList )
{
Assert(userData==((void *)this));
pList->triangleCount = m_indexCount/3;
int indexMax = ARRAYSIZE(pList->triangleIndices);
int indexCount = min(m_indexCount, indexMax);
Assert(m_indexCount < MAX_VIRTUAL_TRIANGLES*3);
Q_memcpy( pList->triangleIndices, m_pIndices, sizeof(*m_pIndices) * indexCount );
}
void Disp_BuildVirtualMesh( int contentsMask )
{
CUtlVector<CPhysCollide *> virtualMeshes;
virtualMeshes.EnsureCount( g_CoreDispInfos.Count() );
for ( int i = 0; i < g_CoreDispInfos.Count(); i++ )
{
CCoreDispInfo *pDispInfo = g_CoreDispInfos[ i ];
mapdispinfo_t *pMapDisp = &mapdispinfo[ i ];
virtualMeshes[i] = NULL;
// not solid for this pass
if ( !(pMapDisp->contents & contentsMask) )
continue;
// Build a triangle list. This shares the tesselation code with the engine.
CUtlVector<unsigned short> indices;
CVBSPTesselateHelper helper;
helper.m_pIndices = &indices;
helper.m_pActiveVerts = pDispInfo->GetAllowedVerts().Base();
helper.m_pPowerInfo = pDispInfo->GetPowerInfo();
::TesselateDisplacement( &helper );
// validate the collision data
if ( 1 )
{
int triCount = indices.Count() / 3;
for ( int j = 0; j < triCount; j++ )
{
int index = j * 3;
Vector v0 = pDispInfo->GetVert( indices[index+0] );
Vector v1 = pDispInfo->GetVert( indices[index+1] );
Vector v2 = pDispInfo->GetVert( indices[index+2] );
if ( v0 == v1 || v1 == v2 || v2 == v0 )
{
Warning( "Displacement %d has bad geometry near %.2f %.2f %.2f\n", i, v0.x, v0.y, v0.z );
texinfo_t *pTexInfo = &texinfo[pMapDisp->face.texinfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
const char *pMatName = TexDataStringTable_GetString( pTexData->nameStringTableID );
Error( "Can't compile displacement physics, exiting. Texture is %s\n", pMatName );
}
}
}
CDispMeshEvent meshHandler( indices.Base(), indices.Count(), pDispInfo );
virtualmeshparams_t params;
params.buildOuterHull = true;
params.pMeshEventHandler = &meshHandler;
params.userData = &meshHandler;
virtualMeshes[i] = physcollision->CreateVirtualMesh( params );
}
unsigned int totalSize = 0;
CUtlBuffer buf;
dphysdisp_t header;
header.numDisplacements = g_CoreDispInfos.Count();
buf.PutObjects( &header );
CUtlVector<char> dispBuf;
for ( int i = 0; i < header.numDisplacements; i++ )
{
if ( virtualMeshes[i] )
{
unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] );
totalSize += testSize;
buf.PutShort( testSize );
}
else
{
buf.PutShort( -1 );
}
}
for ( int i = 0; i < header.numDisplacements; i++ )
{
if ( virtualMeshes[i] )
{
unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] );
dispBuf.RemoveAll();
dispBuf.EnsureCount(testSize);
unsigned int outSize = physcollision->CollideWrite( dispBuf.Base(), virtualMeshes[i], false );
Assert( outSize == testSize );
buf.Put( dispBuf.Base(), outSize );
}
}
g_PhysDispSize = totalSize + sizeof(dphysdisp_t) + (sizeof(unsigned short) * header.numDisplacements);
Assert( buf.TellMaxPut() == g_PhysDispSize );
g_PhysDispSize = buf.TellMaxPut();
g_pPhysDisp = new byte[g_PhysDispSize];
Q_memcpy( g_pPhysDisp, buf.Base(), g_PhysDispSize );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "vbsp.h"
#include "disp_vbsp.h"
#include "builddisp.h"
#include "disp_common.h"
#include "ivp.h"
#include "disp_ivp.h"
#include "vphysics_interface.h"
#include "vphysics/virtualmesh.h"
#include "utlrbtree.h"
#include "tier1/utlbuffer.h"
#include "materialpatch.h"
struct disp_grid_t
{
int gridIndex;
CUtlVector<int> dispList;
};
static CUtlVector<disp_grid_t> gDispGridList;
disp_grid_t &FindOrInsertGrid( int gridIndex )
{
// linear search is slow, but only a few grids will be present
for ( int i = gDispGridList.Count()-1; i >= 0; i-- )
{
if ( gDispGridList[i].gridIndex == gridIndex )
{
return gDispGridList[i];
}
}
int index = gDispGridList.AddToTail();
gDispGridList[index].gridIndex = gridIndex;
// must be empty
Assert( gDispGridList[index].dispList.Count() == 0 );
return gDispGridList[index];
}
// UNDONE: Tune these or adapt them to map size or triangle count?
#define DISP_GRID_SIZEX 4096
#define DISP_GRID_SIZEY 4096
#define DISP_GRID_SIZEZ 8192
int Disp_GridIndex( CCoreDispInfo *pDispInfo )
{
// quick hash the center into the grid and put the whole terrain in that grid
Vector mins, maxs;
pDispInfo->GetNode(0)->GetBoundingBox( mins, maxs );
Vector center;
center = 0.5 * (mins + maxs);
// make sure it's positive
center += Vector(MAX_COORD_INTEGER,MAX_COORD_INTEGER,MAX_COORD_INTEGER);
int gridX = center.x / DISP_GRID_SIZEX;
int gridY = center.y / DISP_GRID_SIZEY;
int gridZ = center.z / DISP_GRID_SIZEZ;
gridX &= 0xFF;
gridY &= 0xFF;
gridZ &= 0xFF;
return MAKEID( gridX, gridY, gridZ, 0 );
}
void AddToGrid( int gridIndex, int dispIndex )
{
disp_grid_t &grid = FindOrInsertGrid( gridIndex );
grid.dispList.AddToTail( dispIndex );
}
MaterialSystemMaterial_t GetMatIDFromDisp( mapdispinfo_t *pMapDisp )
{
texinfo_t *pTexInfo = &texinfo[pMapDisp->face.texinfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
MaterialSystemMaterial_t matID = FindOriginalMaterial( TexDataStringTable_GetString( pTexData->nameStringTableID ), NULL, true );
return matID;
}
// check this and disable virtual mesh if in use
bool Disp_HasPower4Displacements()
{
for ( int i = 0; i < g_CoreDispInfos.Count(); i++ )
{
if ( g_CoreDispInfos[i]->GetPower() > 3 )
{
return true;
}
}
return false;
}
// adds all displacement faces as a series of convex objects
// UNDONE: Only add the displacements for this model?
void Disp_AddCollisionModels( CUtlVector<CPhysCollisionEntry *> &collisionList, dmodel_t *pModel, int contentsMask)
{
int dispIndex;
// Add each displacement to the grid hash
for ( dispIndex = 0; dispIndex < g_CoreDispInfos.Count(); dispIndex++ )
{
CCoreDispInfo *pDispInfo = g_CoreDispInfos[ dispIndex ];
mapdispinfo_t *pMapDisp = &mapdispinfo[ dispIndex ];
// not solid for this pass
if ( !(pMapDisp->contents & contentsMask) )
continue;
int gridIndex = Disp_GridIndex( pDispInfo );
AddToGrid( gridIndex, dispIndex );
}
// now make a polysoup for the terrain in each grid
for ( int grid = 0; grid < gDispGridList.Count(); grid++ )
{
int triCount = 0;
CPhysPolysoup *pTerrainPhysics = physcollision->PolysoupCreate();
// iterate the displacements in this grid
for ( int listIndex = 0; listIndex < gDispGridList[grid].dispList.Count(); listIndex++ )
{
dispIndex = gDispGridList[grid].dispList[listIndex];
CCoreDispInfo *pDispInfo = g_CoreDispInfos[ dispIndex ];
mapdispinfo_t *pMapDisp = &mapdispinfo[ dispIndex ];
// Get the material id.
MaterialSystemMaterial_t matID = GetMatIDFromDisp( pMapDisp );
// Build a triangle list. This shares the tesselation code with the engine.
CUtlVector<unsigned short> indices;
CVBSPTesselateHelper helper;
helper.m_pIndices = &indices;
helper.m_pActiveVerts = pDispInfo->GetAllowedVerts().Base();
helper.m_pPowerInfo = pDispInfo->GetPowerInfo();
::TesselateDisplacement( &helper );
Assert( indices.Count() > 0 );
Assert( indices.Count() % 3 == 0 ); // Make sure indices are a multiple of 3.
int nTriCount = indices.Count() / 3;
triCount += nTriCount;
if ( triCount >= 65536 )
{
// don't put more than 64K tris in any single collision model
CPhysCollide *pCollide = physcollision->ConvertPolysoupToCollide( pTerrainPhysics, false );
if ( pCollide )
{
collisionList.AddToTail( new CPhysCollisionEntryStaticMesh( pCollide, NULL ) );
}
// Throw this polysoup away and start over for the remaining triangles
physcollision->PolysoupDestroy( pTerrainPhysics );
pTerrainPhysics = physcollision->PolysoupCreate();
triCount = nTriCount;
}
Vector tmpVerts[3];
for ( int iTri = 0; iTri < nTriCount; ++iTri )
{
float flAlphaTotal = 0.0f;
for ( int iTriVert = 0; iTriVert < 3; ++iTriVert )
{
pDispInfo->GetVert( indices[iTri*3+iTriVert], tmpVerts[iTriVert] );
flAlphaTotal += pDispInfo->GetAlpha( indices[iTri*3+iTriVert] );
}
int nProp = g_SurfaceProperties[texinfo[pMapDisp->face.texinfo].texdata];
if ( flAlphaTotal > DISP_ALPHA_PROP_DELTA )
{
int nProp2 = GetSurfaceProperties2( matID, "surfaceprop2" );
if ( nProp2 != -1 )
{
nProp = nProp2;
}
}
int nMaterialIndex = RemapWorldMaterial( nProp );
physcollision->PolysoupAddTriangle( pTerrainPhysics, tmpVerts[0], tmpVerts[1], tmpVerts[2], nMaterialIndex );
}
}
// convert the whole grid's polysoup to a collide and store in the collision list
CPhysCollide *pCollide = physcollision->ConvertPolysoupToCollide( pTerrainPhysics, false );
if ( pCollide )
{
collisionList.AddToTail( new CPhysCollisionEntryStaticMesh( pCollide, NULL ) );
}
// now that we have the collide, we're done with the soup
physcollision->PolysoupDestroy( pTerrainPhysics );
}
}
class CDispMeshEvent : public IVirtualMeshEvent
{
public:
CDispMeshEvent( unsigned short *pIndices, int indexCount, CCoreDispInfo *pDispInfo );
virtual void GetVirtualMesh( void *userData, virtualmeshlist_t *pList );
virtual void GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs );
virtual void GetTrianglesInSphere( void *userData, const Vector &center, float radius, virtualmeshtrianglelist_t *pList );
CUtlVector<Vector> m_verts;
unsigned short *m_pIndices;
int m_indexCount;
};
CDispMeshEvent::CDispMeshEvent( unsigned short *pIndices, int indexCount, CCoreDispInfo *pDispInfo )
{
m_pIndices = pIndices;
m_indexCount = indexCount;
int maxIndex = 0;
for ( int i = 0; i < indexCount; i++ )
{
if ( pIndices[i] > maxIndex )
{
maxIndex = pIndices[i];
}
}
for ( int i = 0; i < indexCount/2; i++ )
{
V_swap( pIndices[i], pIndices[(indexCount-i)-1] );
}
int count = maxIndex + 1;
m_verts.SetCount( count );
for ( int i = 0; i < count; i++ )
{
m_verts[i] = pDispInfo->GetVert(i);
}
}
void CDispMeshEvent::GetVirtualMesh( void *userData, virtualmeshlist_t *pList )
{
Assert(userData==((void *)this));
pList->pVerts = m_verts.Base();
pList->indexCount = m_indexCount;
pList->triangleCount = m_indexCount/3;
pList->vertexCount = m_verts.Count();
pList->surfacePropsIndex = 0; // doesn't matter here, reset at runtime
pList->pHull = NULL;
int indexMax = ARRAYSIZE(pList->indices);
int indexCount = min(m_indexCount, indexMax);
Assert(m_indexCount < indexMax);
Q_memcpy( pList->indices, m_pIndices, sizeof(*m_pIndices) * indexCount );
}
void CDispMeshEvent::GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs )
{
Assert(userData==((void *)this));
ClearBounds( *pMins, *pMaxs );
for ( int i = 0; i < m_verts.Count(); i++ )
{
AddPointToBounds( m_verts[i], *pMins, *pMaxs );
}
}
void CDispMeshEvent::GetTrianglesInSphere( void *userData, const Vector &center, float radius, virtualmeshtrianglelist_t *pList )
{
Assert(userData==((void *)this));
pList->triangleCount = m_indexCount/3;
int indexMax = ARRAYSIZE(pList->triangleIndices);
int indexCount = min(m_indexCount, indexMax);
Assert(m_indexCount < MAX_VIRTUAL_TRIANGLES*3);
Q_memcpy( pList->triangleIndices, m_pIndices, sizeof(*m_pIndices) * indexCount );
}
void Disp_BuildVirtualMesh( int contentsMask )
{
CUtlVector<CPhysCollide *> virtualMeshes;
virtualMeshes.EnsureCount( g_CoreDispInfos.Count() );
for ( int i = 0; i < g_CoreDispInfos.Count(); i++ )
{
CCoreDispInfo *pDispInfo = g_CoreDispInfos[ i ];
mapdispinfo_t *pMapDisp = &mapdispinfo[ i ];
virtualMeshes[i] = NULL;
// not solid for this pass
if ( !(pMapDisp->contents & contentsMask) )
continue;
// Build a triangle list. This shares the tesselation code with the engine.
CUtlVector<unsigned short> indices;
CVBSPTesselateHelper helper;
helper.m_pIndices = &indices;
helper.m_pActiveVerts = pDispInfo->GetAllowedVerts().Base();
helper.m_pPowerInfo = pDispInfo->GetPowerInfo();
::TesselateDisplacement( &helper );
// validate the collision data
if ( 1 )
{
int triCount = indices.Count() / 3;
for ( int j = 0; j < triCount; j++ )
{
int index = j * 3;
Vector v0 = pDispInfo->GetVert( indices[index+0] );
Vector v1 = pDispInfo->GetVert( indices[index+1] );
Vector v2 = pDispInfo->GetVert( indices[index+2] );
if ( v0 == v1 || v1 == v2 || v2 == v0 )
{
Warning( "Displacement %d has bad geometry near %.2f %.2f %.2f\n", i, v0.x, v0.y, v0.z );
texinfo_t *pTexInfo = &texinfo[pMapDisp->face.texinfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
const char *pMatName = TexDataStringTable_GetString( pTexData->nameStringTableID );
Error( "Can't compile displacement physics, exiting. Texture is %s\n", pMatName );
}
}
}
CDispMeshEvent meshHandler( indices.Base(), indices.Count(), pDispInfo );
virtualmeshparams_t params;
params.buildOuterHull = true;
params.pMeshEventHandler = &meshHandler;
params.userData = &meshHandler;
virtualMeshes[i] = physcollision->CreateVirtualMesh( params );
}
unsigned int totalSize = 0;
CUtlBuffer buf;
dphysdisp_t header;
header.numDisplacements = g_CoreDispInfos.Count();
buf.PutObjects( &header );
CUtlVector<char> dispBuf;
for ( int i = 0; i < header.numDisplacements; i++ )
{
if ( virtualMeshes[i] )
{
unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] );
totalSize += testSize;
buf.PutShort( testSize );
}
else
{
buf.PutShort( -1 );
}
}
for ( int i = 0; i < header.numDisplacements; i++ )
{
if ( virtualMeshes[i] )
{
unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] );
dispBuf.RemoveAll();
dispBuf.EnsureCount(testSize);
unsigned int outSize = physcollision->CollideWrite( dispBuf.Base(), virtualMeshes[i], false );
Assert( outSize == testSize );
buf.Put( dispBuf.Base(), outSize );
}
}
g_PhysDispSize = totalSize + sizeof(dphysdisp_t) + (sizeof(unsigned short) * header.numDisplacements);
Assert( buf.TellMaxPut() == g_PhysDispSize );
g_PhysDispSize = buf.TellMaxPut();
g_pPhysDisp = new byte[g_PhysDispSize];
Q_memcpy( g_pPhysDisp, buf.Base(), g_PhysDispSize );
}

View File

@@ -1,49 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DISP_IVP_H
#define DISP_IVP_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
#include "../../public/disp_tesselate.h"
class CPhysCollisionEntry;
struct dmodel_t;
// This provides the template functions that the engine's tesselation code needs
// so we can share the code in VBSP.
class CVBSPTesselateHelper : public CBaseTesselateHelper
{
public:
void EndTriangle()
{
m_pIndices->AddToTail( m_TempIndices[0] );
m_pIndices->AddToTail( m_TempIndices[1] );
m_pIndices->AddToTail( m_TempIndices[2] );
}
DispNodeInfo_t& GetNodeInfo( int iNodeBit )
{
// VBSP doesn't care about these. Give it back something to play with.
static DispNodeInfo_t dummy;
return dummy;
}
public:
CUtlVector<unsigned short> *m_pIndices;
};
extern void Disp_AddCollisionModels( CUtlVector<CPhysCollisionEntry *> &collisionList, dmodel_t *pModel, int contentsMask );
extern void Disp_BuildVirtualMesh( int contentsMask );
extern bool Disp_HasPower4Displacements();
#endif // DISP_IVP_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DISP_IVP_H
#define DISP_IVP_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
#include "../../public/disp_tesselate.h"
class CPhysCollisionEntry;
struct dmodel_t;
// This provides the template functions that the engine's tesselation code needs
// so we can share the code in VBSP.
class CVBSPTesselateHelper : public CBaseTesselateHelper
{
public:
void EndTriangle()
{
m_pIndices->AddToTail( m_TempIndices[0] );
m_pIndices->AddToTail( m_TempIndices[1] );
m_pIndices->AddToTail( m_TempIndices[2] );
}
DispNodeInfo_t& GetNodeInfo( int iNodeBit )
{
// VBSP doesn't care about these. Give it back something to play with.
static DispNodeInfo_t dummy;
return dummy;
}
public:
CUtlVector<unsigned short> *m_pIndices;
};
extern void Disp_AddCollisionModels( CUtlVector<CPhysCollisionEntry *> &collisionList, dmodel_t *pModel, int contentsMask );
extern void Disp_BuildVirtualMesh( int contentsMask );
extern bool Disp_HasPower4Displacements();
#endif // DISP_IVP_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,46 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VBSP_DISPINFO_H
#define VBSP_DISPINFO_H
#ifdef _WIN32
#pragma once
#endif
#include "vbsp.h"
class CCoreDispInfo;
extern CUtlVector<CCoreDispInfo*> g_CoreDispInfos;
// Setup initial entries in g_dispinfo with some of the vertex data from the mapdisps.
void EmitInitialDispInfos();
// Resample vertex alpha into lightmap alpha for displacement surfaces so LOD popping artifacts are
// less noticeable on the mid-to-high end.
//
// Also builds neighbor data.
void EmitDispLMAlphaAndNeighbors();
// Setup a CCoreDispInfo given a mapdispinfo_t.
// If pFace is non-NULL, then lightmap texture coordinates will be generated.
void DispMapToCoreDispInfo( mapdispinfo_t *pMapDisp,
CCoreDispInfo *pCoreDispInfo, dface_t *pFace, int *pSwappedTexInfos );
void DispGetFaceInfo( mapbrush_t *pBrush );
bool HasDispInfo( mapbrush_t *pBrush );
// Computes the bounds for a disp info
void ComputeDispInfoBounds( int dispinfo, Vector& mins, Vector& maxs );
#endif // VBSP_DISPINFO_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VBSP_DISPINFO_H
#define VBSP_DISPINFO_H
#ifdef _WIN32
#pragma once
#endif
#include "vbsp.h"
class CCoreDispInfo;
extern CUtlVector<CCoreDispInfo*> g_CoreDispInfos;
// Setup initial entries in g_dispinfo with some of the vertex data from the mapdisps.
void EmitInitialDispInfos();
// Resample vertex alpha into lightmap alpha for displacement surfaces so LOD popping artifacts are
// less noticeable on the mid-to-high end.
//
// Also builds neighbor data.
void EmitDispLMAlphaAndNeighbors();
// Setup a CCoreDispInfo given a mapdispinfo_t.
// If pFace is non-NULL, then lightmap texture coordinates will be generated.
void DispMapToCoreDispInfo( mapdispinfo_t *pMapDisp,
CCoreDispInfo *pCoreDispInfo, dface_t *pFace, int *pSwappedTexInfos );
void DispGetFaceInfo( mapbrush_t *pBrush );
bool HasDispInfo( mapbrush_t *pBrush );
// Computes the bounds for a disp info
void ComputeDispInfoBounds( int dispinfo, Vector& mins, Vector& maxs );
#endif // VBSP_DISPINFO_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,20 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef FACES_H
#define FACES_H
#ifdef _WIN32
#pragma once
#endif
void GetEdge2_InitOptimizedList(); // Call this before calling GetEdge2() on a bunch of edges.
int AddEdge( int v1, int v2, face_t *f );
int GetEdge2(int v1, int v2, face_t *f);
#endif // FACES_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef FACES_H
#define FACES_H
#ifdef _WIN32
#pragma once
#endif
void GetEdge2_InitOptimizedList(); // Call this before calling GetEdge2() on a bunch of edges.
int AddEdge( int v1, int v2, face_t *f );
int GetEdge2(int v1, int v2, face_t *f);
#endif // FACES_H

View File

@@ -1,219 +1,219 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
int c_glfaces;
int PortalVisibleSides (portal_t *p)
{
int fcon, bcon;
if (!p->onnode)
return 0; // outside
fcon = p->nodes[0]->contents;
bcon = p->nodes[1]->contents;
// same contents never create a face
if (fcon == bcon)
return 0;
// FIXME: is this correct now?
if (!fcon)
return 1;
if (!bcon)
return 2;
return 0;
}
void OutputWinding (winding_t *w, FileHandle_t glview)
{
static int level = 128;
vec_t light;
int i;
CmdLib_FPrintf( glview, "%i\n", w->numpoints);
level+=28;
light = (level&255)/255.0;
for (i=0 ; i<w->numpoints ; i++)
{
CmdLib_FPrintf(glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
w->p[i][0],
w->p[i][1],
w->p[i][2],
light,
light,
light);
}
//CmdLib_FPrintf(glview, "\n");
}
void OutputWindingColor (winding_t *w, FileHandle_t glview, int r, int g, int b)
{
int i;
CmdLib_FPrintf( glview, "%i\n", w->numpoints);
float lr = r * (1.0f/255.0f);
float lg = g * (1.0f/255.0f);
float lb = b * (1.0f/255.0f);
for (i=0 ; i<w->numpoints ; i++)
{
CmdLib_FPrintf(glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
w->p[i][0],
w->p[i][1],
w->p[i][2],
lr,
lg,
lb);
}
//CmdLib_FPrintf(glview, "\n");
}
/*
=============
OutputPortal
=============
*/
void OutputPortal (portal_t *p, FileHandle_t glview)
{
winding_t *w;
int sides;
sides = PortalVisibleSides (p);
if (!sides)
return;
c_glfaces++;
w = p->winding;
if (sides == 2) // back side
w = ReverseWinding (w);
OutputWinding (w, glview);
if (sides == 2)
FreeWinding(w);
}
/*
=============
WriteGLView_r
=============
*/
void WriteGLView_r (node_t *node, FileHandle_t glview)
{
portal_t *p, *nextp;
if (node->planenum != PLANENUM_LEAF)
{
WriteGLView_r (node->children[0], glview);
WriteGLView_r (node->children[1], glview);
return;
}
// write all the portals
for (p=node->portals ; p ; p=nextp)
{
if (p->nodes[0] == node)
{
OutputPortal (p, glview);
nextp = p->next[0];
}
else
nextp = p->next[1];
}
}
void WriteGLViewFaces_r( node_t *node, FileHandle_t glview )
{
portal_t *p, *nextp;
if (node->planenum != PLANENUM_LEAF)
{
WriteGLViewFaces_r (node->children[0], glview);
WriteGLViewFaces_r (node->children[1], glview);
return;
}
// write all the portals
for (p=node->portals ; p ; p=nextp)
{
int s = (p->nodes[1] == node);
if ( p->face[s] )
{
OutputWinding( p->face[s]->w, glview );
}
nextp = p->next[s];
}
}
/*
=============
WriteGLView
=============
*/
void WriteGLView (tree_t *tree, char *source)
{
char name[1024];
FileHandle_t glview;
c_glfaces = 0;
sprintf (name, "%s%s.gl",outbase, source);
Msg("Writing %s\n", name);
glview = g_pFileSystem->Open( name, "w" );
if (!glview)
Error ("Couldn't open %s", name);
WriteGLView_r (tree->headnode, glview);
g_pFileSystem->Close( glview );
Msg("%5i c_glfaces\n", c_glfaces);
}
void WriteGLViewFaces( tree_t *tree, const char *pName )
{
char name[1024];
FileHandle_t glview;
c_glfaces = 0;
sprintf (name, "%s%s.gl", outbase, pName);
Msg("Writing %s\n", name);
glview = g_pFileSystem->Open( name, "w" );
if (!glview)
Error ("Couldn't open %s", name);
WriteGLViewFaces_r (tree->headnode, glview);
g_pFileSystem->Close( glview );
Msg("%5i c_glfaces\n", c_glfaces);
}
void WriteGLViewBrushList( bspbrush_t *pList, const char *pName )
{
char name[1024];
FileHandle_t glview;
sprintf (name, "%s%s.gl", outbase, pName );
Msg("Writing %s\n", name);
glview = g_pFileSystem->Open( name, "w" );
if (!glview)
Error ("Couldn't open %s", name);
for ( bspbrush_t *pBrush = pList; pBrush; pBrush = pBrush->next )
{
for (int i = 0; i < pBrush->numsides; i++ )
OutputWinding( pBrush->sides[i].winding, glview );
}
g_pFileSystem->Close( glview );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
int c_glfaces;
int PortalVisibleSides (portal_t *p)
{
int fcon, bcon;
if (!p->onnode)
return 0; // outside
fcon = p->nodes[0]->contents;
bcon = p->nodes[1]->contents;
// same contents never create a face
if (fcon == bcon)
return 0;
// FIXME: is this correct now?
if (!fcon)
return 1;
if (!bcon)
return 2;
return 0;
}
void OutputWinding (winding_t *w, FileHandle_t glview)
{
static int level = 128;
vec_t light;
int i;
CmdLib_FPrintf( glview, "%i\n", w->numpoints);
level+=28;
light = (level&255)/255.0;
for (i=0 ; i<w->numpoints ; i++)
{
CmdLib_FPrintf(glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
w->p[i][0],
w->p[i][1],
w->p[i][2],
light,
light,
light);
}
//CmdLib_FPrintf(glview, "\n");
}
void OutputWindingColor (winding_t *w, FileHandle_t glview, int r, int g, int b)
{
int i;
CmdLib_FPrintf( glview, "%i\n", w->numpoints);
float lr = r * (1.0f/255.0f);
float lg = g * (1.0f/255.0f);
float lb = b * (1.0f/255.0f);
for (i=0 ; i<w->numpoints ; i++)
{
CmdLib_FPrintf(glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
w->p[i][0],
w->p[i][1],
w->p[i][2],
lr,
lg,
lb);
}
//CmdLib_FPrintf(glview, "\n");
}
/*
=============
OutputPortal
=============
*/
void OutputPortal (portal_t *p, FileHandle_t glview)
{
winding_t *w;
int sides;
sides = PortalVisibleSides (p);
if (!sides)
return;
c_glfaces++;
w = p->winding;
if (sides == 2) // back side
w = ReverseWinding (w);
OutputWinding (w, glview);
if (sides == 2)
FreeWinding(w);
}
/*
=============
WriteGLView_r
=============
*/
void WriteGLView_r (node_t *node, FileHandle_t glview)
{
portal_t *p, *nextp;
if (node->planenum != PLANENUM_LEAF)
{
WriteGLView_r (node->children[0], glview);
WriteGLView_r (node->children[1], glview);
return;
}
// write all the portals
for (p=node->portals ; p ; p=nextp)
{
if (p->nodes[0] == node)
{
OutputPortal (p, glview);
nextp = p->next[0];
}
else
nextp = p->next[1];
}
}
void WriteGLViewFaces_r( node_t *node, FileHandle_t glview )
{
portal_t *p, *nextp;
if (node->planenum != PLANENUM_LEAF)
{
WriteGLViewFaces_r (node->children[0], glview);
WriteGLViewFaces_r (node->children[1], glview);
return;
}
// write all the portals
for (p=node->portals ; p ; p=nextp)
{
int s = (p->nodes[1] == node);
if ( p->face[s] )
{
OutputWinding( p->face[s]->w, glview );
}
nextp = p->next[s];
}
}
/*
=============
WriteGLView
=============
*/
void WriteGLView (tree_t *tree, char *source)
{
char name[1024];
FileHandle_t glview;
c_glfaces = 0;
sprintf (name, "%s%s.gl",outbase, source);
Msg("Writing %s\n", name);
glview = g_pFileSystem->Open( name, "w" );
if (!glview)
Error ("Couldn't open %s", name);
WriteGLView_r (tree->headnode, glview);
g_pFileSystem->Close( glview );
Msg("%5i c_glfaces\n", c_glfaces);
}
void WriteGLViewFaces( tree_t *tree, const char *pName )
{
char name[1024];
FileHandle_t glview;
c_glfaces = 0;
sprintf (name, "%s%s.gl", outbase, pName);
Msg("Writing %s\n", name);
glview = g_pFileSystem->Open( name, "w" );
if (!glview)
Error ("Couldn't open %s", name);
WriteGLViewFaces_r (tree->headnode, glview);
g_pFileSystem->Close( glview );
Msg("%5i c_glfaces\n", c_glfaces);
}
void WriteGLViewBrushList( bspbrush_t *pList, const char *pName )
{
char name[1024];
FileHandle_t glview;
sprintf (name, "%s%s.gl", outbase, pName );
Msg("Writing %s\n", name);
glview = g_pFileSystem->Open( name, "w" );
if (!glview)
Error ("Couldn't open %s", name);
for ( bspbrush_t *pBrush = pList; pBrush; pBrush = pBrush->next )
{
for (int i = 0; i < pBrush->numsides; i++ )
OutputWinding( pBrush->sides[i].winding, glview );
}
g_pFileSystem->Close( glview );
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +1,75 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef IVP_H
#define IVP_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
class CPhysCollide;
class CTextBuffer;
class IPhysicsCollision;
extern IPhysicsCollision *physcollision;
// a list of all of the materials in the world model
extern int RemapWorldMaterial( int materialIndexIn );
class CPhysCollisionEntry
{
public:
CPhysCollisionEntry( CPhysCollide *pCollide );
virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) = 0;
virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) = 0;
unsigned int GetCollisionBinarySize();
unsigned int WriteCollisionBinary( char *pDest );
protected:
void DumpCollideFileName( const char *pName, int modelIndex, CTextBuffer *pTextBuffer );
protected:
CPhysCollide *m_pCollide;
};
class CPhysCollisionEntryStaticMesh : public CPhysCollisionEntry
{
public:
CPhysCollisionEntryStaticMesh( CPhysCollide *pCollide, const char *pMaterialName );
virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex );
virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex );
private:
const char *m_pMaterial;
};
class CTextBuffer
{
public:
CTextBuffer( void );
~CTextBuffer( void );
inline int GetSize( void ) { return m_buffer.Count(); }
inline char *GetData( void ) { return m_buffer.Base(); }
void WriteText( const char *pText );
void WriteIntKey( const char *pKeyName, int outputData );
void WriteStringKey( const char *pKeyName, const char *outputData );
void WriteFloatKey( const char *pKeyName, float outputData );
void WriteFloatArrayKey( const char *pKeyName, const float *outputData, int count );
void CopyStringQuotes( const char *pString );
void Terminate( void );
private:
void CopyData( const char *pData, int len );
CUtlVector<char> m_buffer;
};
#endif // IVP_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef IVP_H
#define IVP_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
class CPhysCollide;
class CTextBuffer;
class IPhysicsCollision;
extern IPhysicsCollision *physcollision;
// a list of all of the materials in the world model
extern int RemapWorldMaterial( int materialIndexIn );
class CPhysCollisionEntry
{
public:
CPhysCollisionEntry( CPhysCollide *pCollide );
virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) = 0;
virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) = 0;
unsigned int GetCollisionBinarySize();
unsigned int WriteCollisionBinary( char *pDest );
protected:
void DumpCollideFileName( const char *pName, int modelIndex, CTextBuffer *pTextBuffer );
protected:
CPhysCollide *m_pCollide;
};
class CPhysCollisionEntryStaticMesh : public CPhysCollisionEntry
{
public:
CPhysCollisionEntryStaticMesh( CPhysCollide *pCollide, const char *pMaterialName );
virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex );
virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex );
private:
const char *m_pMaterial;
};
class CTextBuffer
{
public:
CTextBuffer( void );
~CTextBuffer( void );
inline int GetSize( void ) { return m_buffer.Count(); }
inline char *GetData( void ) { return m_buffer.Base(); }
void WriteText( const char *pText );
void WriteIntKey( const char *pKeyName, int outputData );
void WriteStringKey( const char *pKeyName, const char *outputData );
void WriteFloatKey( const char *pKeyName, float outputData );
void WriteFloatArrayKey( const char *pKeyName, const float *outputData, int count );
void CopyStringQuotes( const char *pString );
void Terminate( void );
private:
void CopyData( const char *pData, int len );
CUtlVector<char> m_buffer;
};
#endif // IVP_H

View File

@@ -1,168 +1,168 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
#include "color.h"
/*
==============================================================================
LEAF FILE GENERATION
Save out name.line for qe3 to read
==============================================================================
*/
/*
=============
LeakFile
Finds the shortest possible chain of portals
that leads from the outside leaf to a specifically
occupied leaf
=============
*/
void LeakFile (tree_t *tree)
{
Vector mid;
FILE *linefile;
char filename[1024];
node_t *node;
int count;
if (!tree->outside_node.occupied)
return;
tree->leaked = true;
qprintf ("--- LeakFile ---\n");
//
// write the points to the file
//
sprintf (filename, "%s.lin", source);
linefile = fopen (filename, "w");
if (!linefile)
Error ("Couldn't open %s\n", filename);
count = 0;
node = &tree->outside_node;
while (node->occupied > 1)
{
portal_t *nextportal = NULL;
node_t *nextnode = NULL;
int s = 0;
// find the best portal exit
int next = node->occupied;
for (portal_t *p=node->portals ; p ; p = p->next[!s])
{
s = (p->nodes[0] == node);
if (p->nodes[s]->occupied
&& p->nodes[s]->occupied < next)
{
nextportal = p;
nextnode = p->nodes[s];
next = nextnode->occupied;
}
}
node = nextnode;
WindingCenter (nextportal->winding, mid);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
count++;
}
// Add the occupant's origin to the leakfile.
Vector origin;
GetVectorForKey (node->occupant, "origin", origin);
fprintf (linefile, "%f %f %f\n", origin[0], origin[1], origin[2]);
qprintf ("%5i point linefile\n", count+1);
fclose (linefile);
// Emit a leak warning.
const char *cl = ValueForKey (node->occupant, "classname");
Color red(255,0,0,255);
ColorSpewMessage( SPEW_MESSAGE, &red, "Entity %s (%.2f %.2f %.2f) leaked!\n", cl, origin[0], origin[1], origin[2] );
}
void AreaportalLeakFile( tree_t *tree, portal_t *pStartPortal, portal_t *pEndPortal, node_t *pStart )
{
Vector mid;
FILE *linefile;
char filename[1024];
node_t *node;
int count;
// wrote a leak line file already, don't overwrite it with the areaportal leak file
if ( tree->leaked )
return;
tree->leaked = true;
qprintf ("--- LeakFile ---\n");
//
// write the points to the file
//
sprintf (filename, "%s.lin", source);
linefile = fopen (filename, "w");
if (!linefile)
Error ("Couldn't open %s\n", filename);
count = 2;
WindingCenter (pEndPortal->winding, mid);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
mid = 0.5 * (pStart->mins + pStart->maxs);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
node = pStart;
while (node->occupied >= 1)
{
portal_t *nextportal = NULL;
node_t *nextnode = NULL;
int s = 0;
// find the best portal exit
int next = node->occupied;
for (portal_t *p=node->portals ; p ; p = p->next[!s])
{
s = (p->nodes[0] == node);
if (p->nodes[s]->occupied
&& p->nodes[s]->occupied < next)
{
nextportal = p;
nextnode = p->nodes[s];
next = nextnode->occupied;
}
}
if ( !nextnode )
break;
node = nextnode;
WindingCenter (nextportal->winding, mid);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
count++;
}
// add the occupant center
if ( node )
{
mid = 0.5 * (node->mins + node->maxs);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
count++;
}
WindingCenter (pStartPortal->winding, mid);
count++;
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
qprintf ("%5i point linefile\n", count);
fclose (linefile);
Warning( "Wrote %s\n", filename );
Color red(255,0,0,255);
ColorSpewMessage( SPEW_MESSAGE, &red, "Areaportal leak ! File: %s ", filename );
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
#include "color.h"
/*
==============================================================================
LEAF FILE GENERATION
Save out name.line for qe3 to read
==============================================================================
*/
/*
=============
LeakFile
Finds the shortest possible chain of portals
that leads from the outside leaf to a specifically
occupied leaf
=============
*/
void LeakFile (tree_t *tree)
{
Vector mid;
FILE *linefile;
char filename[1024];
node_t *node;
int count;
if (!tree->outside_node.occupied)
return;
tree->leaked = true;
qprintf ("--- LeakFile ---\n");
//
// write the points to the file
//
sprintf (filename, "%s.lin", source);
linefile = fopen (filename, "w");
if (!linefile)
Error ("Couldn't open %s\n", filename);
count = 0;
node = &tree->outside_node;
while (node->occupied > 1)
{
portal_t *nextportal = NULL;
node_t *nextnode = NULL;
int s = 0;
// find the best portal exit
int next = node->occupied;
for (portal_t *p=node->portals ; p ; p = p->next[!s])
{
s = (p->nodes[0] == node);
if (p->nodes[s]->occupied
&& p->nodes[s]->occupied < next)
{
nextportal = p;
nextnode = p->nodes[s];
next = nextnode->occupied;
}
}
node = nextnode;
WindingCenter (nextportal->winding, mid);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
count++;
}
// Add the occupant's origin to the leakfile.
Vector origin;
GetVectorForKey (node->occupant, "origin", origin);
fprintf (linefile, "%f %f %f\n", origin[0], origin[1], origin[2]);
qprintf ("%5i point linefile\n", count+1);
fclose (linefile);
// Emit a leak warning.
const char *cl = ValueForKey (node->occupant, "classname");
Color red(255,0,0,255);
ColorSpewMessage( SPEW_MESSAGE, &red, "Entity %s (%.2f %.2f %.2f) leaked!\n", cl, origin[0], origin[1], origin[2] );
}
void AreaportalLeakFile( tree_t *tree, portal_t *pStartPortal, portal_t *pEndPortal, node_t *pStart )
{
Vector mid;
FILE *linefile;
char filename[1024];
node_t *node;
int count;
// wrote a leak line file already, don't overwrite it with the areaportal leak file
if ( tree->leaked )
return;
tree->leaked = true;
qprintf ("--- LeakFile ---\n");
//
// write the points to the file
//
sprintf (filename, "%s.lin", source);
linefile = fopen (filename, "w");
if (!linefile)
Error ("Couldn't open %s\n", filename);
count = 2;
WindingCenter (pEndPortal->winding, mid);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
mid = 0.5 * (pStart->mins + pStart->maxs);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
node = pStart;
while (node->occupied >= 1)
{
portal_t *nextportal = NULL;
node_t *nextnode = NULL;
int s = 0;
// find the best portal exit
int next = node->occupied;
for (portal_t *p=node->portals ; p ; p = p->next[!s])
{
s = (p->nodes[0] == node);
if (p->nodes[s]->occupied
&& p->nodes[s]->occupied < next)
{
nextportal = p;
nextnode = p->nodes[s];
next = nextnode->occupied;
}
}
if ( !nextnode )
break;
node = nextnode;
WindingCenter (nextportal->winding, mid);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
count++;
}
// add the occupant center
if ( node )
{
mid = 0.5 * (node->mins + node->maxs);
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
count++;
}
WindingCenter (pStartPortal->winding, mid);
count++;
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
qprintf ("%5i point linefile\n", count);
fclose (linefile);
Warning( "Wrote %s\n", filename );
Color red(255,0,0,255);
ColorSpewMessage( SPEW_MESSAGE, &red, "Areaportal leak ! File: %s ", filename );
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,73 +1,73 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef __MANIFEST_H
#define __MANIFEST_H
#ifdef _WIN32
#pragma once
#endif
#include "boundbox.h"
//
// Each cordon is a named collection of bounding boxes.
//
struct Cordon_t
{
inline Cordon_t()
{
m_bActive = false;
}
CUtlString m_szName;
bool m_bActive; // True means cull using this cordon when cordoning is enabled.
CUtlVector<BoundBox> m_Boxes;
};
class CManifestMap
{
public:
CManifestMap( void );
char m_RelativeMapFileName[ MAX_PATH ];
bool m_bTopLevelMap;
};
class CManifest
{
public:
CManifest( void );
static ChunkFileResult_t LoadManifestMapKeyCallback( const char *szKey, const char *szValue, CManifestMap *pManifestMap );
static ChunkFileResult_t LoadManifestVMFCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadManifestMapsCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadCordonBoxCallback( CChunkFile *pFile, Cordon_t *pCordon );
static ChunkFileResult_t LoadCordonBoxKeyCallback( const char *szKey, const char *szValue, BoundBox *pBox );
static ChunkFileResult_t LoadCordonKeyCallback( const char *szKey, const char *szValue, Cordon_t *pCordon );
static ChunkFileResult_t LoadCordonCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadCordonsKeyCallback( const char *pszKey, const char *pszValue, CManifest *pManifest );
static ChunkFileResult_t LoadCordonsCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadManifestCordoningPrefsCallback( CChunkFile *pFile, CManifest *pManifest );
bool LoadSubMaps( CMapFile *pMapFile, const char *pszFileName );
epair_t *CreateEPair( char *pKey, char *pValue );
bool LoadVMFManifest( const char *pszFileName );
const char *GetInstancePath( ) { return m_InstancePath; }
void CordonWorld( );
private:
bool LoadVMFManifestUserPrefs( const char *pszFileName );
CUtlVector< CManifestMap * > m_Maps;
char m_InstancePath[ MAX_PATH ];
bool m_bIsCordoning;
CUtlVector< Cordon_t > m_Cordons;
entity_t *m_CordoningMapEnt;
};
#endif // #ifndef __MANIFEST_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef __MANIFEST_H
#define __MANIFEST_H
#ifdef _WIN32
#pragma once
#endif
#include "boundbox.h"
//
// Each cordon is a named collection of bounding boxes.
//
struct Cordon_t
{
inline Cordon_t()
{
m_bActive = false;
}
CUtlString m_szName;
bool m_bActive; // True means cull using this cordon when cordoning is enabled.
CUtlVector<BoundBox> m_Boxes;
};
class CManifestMap
{
public:
CManifestMap( void );
char m_RelativeMapFileName[ MAX_PATH ];
bool m_bTopLevelMap;
};
class CManifest
{
public:
CManifest( void );
static ChunkFileResult_t LoadManifestMapKeyCallback( const char *szKey, const char *szValue, CManifestMap *pManifestMap );
static ChunkFileResult_t LoadManifestVMFCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadManifestMapsCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadCordonBoxCallback( CChunkFile *pFile, Cordon_t *pCordon );
static ChunkFileResult_t LoadCordonBoxKeyCallback( const char *szKey, const char *szValue, BoundBox *pBox );
static ChunkFileResult_t LoadCordonKeyCallback( const char *szKey, const char *szValue, Cordon_t *pCordon );
static ChunkFileResult_t LoadCordonCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadCordonsKeyCallback( const char *pszKey, const char *pszValue, CManifest *pManifest );
static ChunkFileResult_t LoadCordonsCallback( CChunkFile *pFile, CManifest *pManifest );
static ChunkFileResult_t LoadManifestCordoningPrefsCallback( CChunkFile *pFile, CManifest *pManifest );
bool LoadSubMaps( CMapFile *pMapFile, const char *pszFileName );
epair_t *CreateEPair( char *pKey, char *pValue );
bool LoadVMFManifest( const char *pszFileName );
const char *GetInstancePath( ) { return m_InstancePath; }
void CordonWorld( );
private:
bool LoadVMFManifestUserPrefs( const char *pszFileName );
CUtlVector< CManifestMap * > m_Maps;
char m_InstancePath[ MAX_PATH ];
bool m_bIsCordoning;
CUtlVector< Cordon_t > m_Cordons;
entity_t *m_CordoningMapEnt;
};
#endif // #ifndef __MANIFEST_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef MAP_H
#define MAP_H
#ifdef _WIN32
#pragma once
#endif
// All the brush sides referenced by info_no_dynamic_shadow entities.
extern CUtlVector<int> g_NoDynamicShadowSides;
#endif // MAP_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef MAP_H
#define MAP_H
#ifdef _WIN32
#pragma once
#endif
// All the brush sides referenced by info_no_dynamic_shadow entities.
extern CUtlVector<int> g_NoDynamicShadowSides;
#endif // MAP_H

View File

@@ -1,440 +1,440 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
#include "UtlBuffer.h"
#include "utlsymbol.h"
#include "utlrbtree.h"
#include "KeyValues.h"
#include "bsplib.h"
#include "materialpatch.h"
#include "tier1/strtools.h"
// case insensitive
static CUtlSymbolTable s_SymbolTable( 0, 32, true );
struct NameTranslationLookup_t
{
CUtlSymbol m_OriginalFileName;
CUtlSymbol m_PatchFileName;
};
static bool NameTranslationLessFunc( NameTranslationLookup_t const& src1,
NameTranslationLookup_t const& src2 )
{
return src1.m_PatchFileName < src2.m_PatchFileName;
}
CUtlRBTree<NameTranslationLookup_t, int> s_MapPatchedMatToOriginalMat( 0, 256, NameTranslationLessFunc );
void AddNewTranslation( const char *pOriginalMaterialName, const char *pNewMaterialName )
{
NameTranslationLookup_t newEntry;
newEntry.m_OriginalFileName = s_SymbolTable.AddString( pOriginalMaterialName );
newEntry.m_PatchFileName = s_SymbolTable.AddString( pNewMaterialName );
s_MapPatchedMatToOriginalMat.Insert( newEntry );
}
const char *GetOriginalMaterialNameForPatchedMaterial( const char *pPatchMaterialName )
{
const char *pRetName = NULL;
int id;
NameTranslationLookup_t lookup;
lookup.m_PatchFileName = s_SymbolTable.AddString( pPatchMaterialName );
do
{
id = s_MapPatchedMatToOriginalMat.Find( lookup );
if( id >= 0 )
{
NameTranslationLookup_t &found = s_MapPatchedMatToOriginalMat[id];
lookup.m_PatchFileName = found.m_OriginalFileName;
pRetName = s_SymbolTable.String( found.m_OriginalFileName );
}
} while( id >= 0 );
if( !pRetName )
{
// This isn't a patched material, so just return the original name.
return pPatchMaterialName;
}
return pRetName;
}
void CreateMaterialPatchRecursive( KeyValues *pOriginalKeyValues, KeyValues *pPatchKeyValues, int nKeys, const MaterialPatchInfo_t *pInfo )
{
int i;
for( i = 0; i < nKeys; i++ )
{
const char *pVal = pOriginalKeyValues->GetString( pInfo[i].m_pKey, NULL );
if( !pVal )
continue;
if( pInfo[i].m_pRequiredOriginalValue && Q_stricmp( pVal, pInfo[i].m_pRequiredOriginalValue ) != 0 )
continue;
pPatchKeyValues->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
}
KeyValues *pScan;
for( pScan = pOriginalKeyValues->GetFirstTrueSubKey(); pScan; pScan = pScan->GetNextTrueSubKey() )
{
CreateMaterialPatchRecursive( pScan, pPatchKeyValues->FindKey( pScan->GetName(), true ), nKeys, pInfo );
}
}
//-----------------------------------------------------------------------------
// A version which allows you to patch multiple key values
//-----------------------------------------------------------------------------
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
int nKeys, const MaterialPatchInfo_t *pInfo, MaterialPatchType_t nPatchType )
{
char pOldVMTFile[ 512 ];
char pNewVMTFile[ 512 ];
AddNewTranslation( pOriginalMaterialName, pNewMaterialName );
Q_snprintf( pOldVMTFile, 512, "materials/%s.vmt", pOriginalMaterialName );
Q_snprintf( pNewVMTFile, 512, "materials/%s.vmt", pNewMaterialName );
// printf( "Creating material patch file %s which points at %s\n", newVMTFile, oldVMTFile );
KeyValues *kv = new KeyValues( "patch" );
if ( !kv )
{
Error( "Couldn't allocate KeyValues for %s!!!", pNewMaterialName );
}
kv->SetString( "include", pOldVMTFile );
const char *pSectionName = (nPatchType == PATCH_INSERT) ? "insert" : "replace";
KeyValues *section = kv->FindKey( pSectionName, true );
if( nPatchType == PATCH_REPLACE )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pOriginalMaterialName ) );
KeyValues *origkv = new KeyValues( "blah" );
if ( !origkv->LoadFromFile( g_pFileSystem, name ) )
{
origkv->deleteThis();
Assert( 0 );
return;
}
CreateMaterialPatchRecursive( origkv, section, nKeys, pInfo );
origkv->deleteThis();
}
else
{
for ( int i = 0; i < nKeys; ++i )
{
section->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
}
}
// Write patched .vmt into a memory buffer
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
kv->RecursiveSaveToFile( buf, 0 );
// Add to pak file for this .bsp
AddBufferToPak( GetPakFile(), pNewVMTFile, (void*)buf.Base(), buf.TellPut(), true );
// Cleanup
kv->deleteThis();
}
//-----------------------------------------------------------------------------
// Patches a single keyvalue in a material
//-----------------------------------------------------------------------------
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
const char *pNewKey, const char *pNewValue, MaterialPatchType_t nPatchType )
{
MaterialPatchInfo_t info;
info.m_pKey = pNewKey;
info.m_pValue = pNewValue;
CreateMaterialPatch( pOriginalMaterialName, pNewMaterialName, 1, &info, nPatchType );
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key
//-----------------------------------------------------------------------------
static bool DoesMaterialHaveKey( KeyValues *pKeyValues, const char *pKeyName )
{
const char *pVal;
pVal = pKeyValues->GetString( pKeyName, NULL );
if ( pVal != NULL )
return true;
for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
{
if ( DoesMaterialHaveKey( pSubKey, pKeyName) )
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key/value pair
//-----------------------------------------------------------------------------
static bool DoesMaterialHaveKeyValuePair( KeyValues *pKeyValues, const char *pKeyName, const char *pSearchValue )
{
const char *pVal;
pVal = pKeyValues->GetString( pKeyName, NULL );
if ( pVal != NULL && ( Q_stricmp( pSearchValue, pVal ) == 0 ) )
return true;
for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
{
if ( DoesMaterialHaveKeyValuePair( pSubKey, pKeyName, pSearchValue ) )
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key
//-----------------------------------------------------------------------------
bool DoesMaterialHaveKey( const char *pMaterialName, const char *pKeyName )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
KeyValues *kv = new KeyValues( "blah" );
if ( !kv->LoadFromFile( g_pFileSystem, name ) )
{
kv->deleteThis();
return NULL;
}
bool retVal = DoesMaterialHaveKey( kv, pKeyName );
kv->deleteThis();
return retVal;
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key/value pair
//-----------------------------------------------------------------------------
bool DoesMaterialHaveKeyValuePair( const char *pMaterialName, const char *pKeyName, const char *pSearchValue )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
KeyValues *kv = new KeyValues( "blah" );
if ( !kv->LoadFromFile( g_pFileSystem, name ) )
{
kv->deleteThis();
return NULL;
}
bool retVal = DoesMaterialHaveKeyValuePair( kv, pKeyName, pSearchValue );
kv->deleteThis();
return retVal;
}
//-----------------------------------------------------------------------------
// Gets a material value from a material. Ignores all patches
//-----------------------------------------------------------------------------
bool GetValueFromMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
KeyValues *kv = new KeyValues( "blah" );
if ( !kv->LoadFromFile( g_pFileSystem, name ) )
{
// Assert( 0 );
kv->deleteThis();
return NULL;
}
const char *pTmpValue = kv->GetString( pKey, NULL );
if( pTmpValue )
{
Q_strncpy( pValue, pTmpValue, len );
}
kv->deleteThis();
return ( pTmpValue != NULL );
}
//-----------------------------------------------------------------------------
// Finds the original material associated with a patched material
//-----------------------------------------------------------------------------
MaterialSystemMaterial_t FindOriginalMaterial( const char *materialName, bool *pFound, bool bComplain )
{
MaterialSystemMaterial_t matID;
matID = FindMaterial( GetOriginalMaterialNameForPatchedMaterial( materialName ), pFound, bComplain );
return matID;
}
//-----------------------------------------------------------------------------
// Load keyvalues from the local pack file, or from a file
//-----------------------------------------------------------------------------
bool LoadKeyValuesFromPackOrFile( const char *pFileName, KeyValues *pKeyValues )
{
CUtlBuffer buf;
if ( ReadFileFromPak( GetPakFile(), pFileName, true, buf ) )
{
return pKeyValues->LoadFromBuffer( pFileName, buf );
}
return pKeyValues->LoadFromFile( g_pFileSystem, pFileName );
}
//-----------------------------------------------------------------------------
// VMT parser
//-----------------------------------------------------------------------------
static void InsertKeyValues( KeyValues &dst, KeyValues& src, bool bCheckForExistence )
{
KeyValues *pSrcVar = src.GetFirstSubKey();
while( pSrcVar )
{
if ( !bCheckForExistence || dst.FindKey( pSrcVar->GetName() ) )
{
switch( pSrcVar->GetDataType() )
{
case KeyValues::TYPE_STRING:
dst.SetString( pSrcVar->GetName(), pSrcVar->GetString() );
break;
case KeyValues::TYPE_INT:
dst.SetInt( pSrcVar->GetName(), pSrcVar->GetInt() );
break;
case KeyValues::TYPE_FLOAT:
dst.SetFloat( pSrcVar->GetName(), pSrcVar->GetFloat() );
break;
case KeyValues::TYPE_PTR:
dst.SetPtr( pSrcVar->GetName(), pSrcVar->GetPtr() );
break;
}
}
pSrcVar = pSrcVar->GetNextKey();
}
}
static void ExpandPatchFile( KeyValues &keyValues )
{
int nCount = 0;
while( nCount < 10 && stricmp( keyValues.GetName(), "patch" ) == 0 )
{
// WriteKeyValuesToFile( "patch.txt", keyValues );
const char *pIncludeFileName = keyValues.GetString( "include" );
if( !pIncludeFileName )
return;
KeyValues * includeKeyValues = new KeyValues( "vmt" );
int nBufLen = Q_strlen( pIncludeFileName ) + Q_strlen( "materials/.vmt" ) + 1;
char *pFileName = ( char * )stackalloc( nBufLen );
Q_strncpy( pFileName, pIncludeFileName, nBufLen );
bool bSuccess = LoadKeyValuesFromPackOrFile( pFileName, includeKeyValues );
if ( !bSuccess )
{
includeKeyValues->deleteThis();
return;
}
KeyValues *pInsertSection = keyValues.FindKey( "insert" );
if( pInsertSection )
{
InsertKeyValues( *includeKeyValues, *pInsertSection, false );
keyValues = *includeKeyValues;
}
KeyValues *pReplaceSection = keyValues.FindKey( "replace" );
if( pReplaceSection )
{
InsertKeyValues( *includeKeyValues, *pReplaceSection, true );
keyValues = *includeKeyValues;
}
// Could add other commands here, like "delete", "rename", etc.
includeKeyValues->deleteThis();
nCount++;
}
if( nCount >= 10 )
{
Warning( "Infinite recursion in patch file?\n" );
}
}
KeyValues *LoadMaterialKeyValues( const char *pMaterialName, unsigned int nFlags )
{
// Load the underlying file
KeyValues *kv = new KeyValues( "blah" );
char pFullMaterialName[512];
Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
{
// Assert( 0 );
kv->deleteThis();
return NULL;
}
if( nFlags & LOAD_MATERIAL_KEY_VALUES_FLAGS_EXPAND_PATCH )
{
ExpandPatchFile( *kv );
}
return kv;
}
void WriteMaterialKeyValuesToPak( const char *pMaterialName, KeyValues *kv )
{
char pFullMaterialName[512];
Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
// Write patched .vmt into a memory buffer
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
kv->RecursiveSaveToFile( buf, 0 );
// Add to pak file for this .bsp
AddBufferToPak( GetPakFile(), pFullMaterialName, (void*)buf.Base(), buf.TellPut(), true );
// Cleanup
kv->deleteThis();
}
//-----------------------------------------------------------------------------
// Gets a keyvalue from a *patched* material
//-----------------------------------------------------------------------------
bool GetValueFromPatchedMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
{
// Load the underlying file so that we can check if env_cubemap is in there.
KeyValues *kv = new KeyValues( "blah" );
char pFullMaterialName[512];
Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
{
// Assert( 0 );
kv->deleteThis();
return NULL;
}
ExpandPatchFile( *kv );
const char *pTmpValue = kv->GetString( pKey, NULL );
if( pTmpValue )
{
Q_strncpy( pValue, pTmpValue, len );
}
kv->deleteThis();
return ( pTmpValue != NULL );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
#include "UtlBuffer.h"
#include "utlsymbol.h"
#include "utlrbtree.h"
#include "KeyValues.h"
#include "bsplib.h"
#include "materialpatch.h"
#include "tier1/strtools.h"
// case insensitive
static CUtlSymbolTable s_SymbolTable( 0, 32, true );
struct NameTranslationLookup_t
{
CUtlSymbol m_OriginalFileName;
CUtlSymbol m_PatchFileName;
};
static bool NameTranslationLessFunc( NameTranslationLookup_t const& src1,
NameTranslationLookup_t const& src2 )
{
return src1.m_PatchFileName < src2.m_PatchFileName;
}
CUtlRBTree<NameTranslationLookup_t, int> s_MapPatchedMatToOriginalMat( 0, 256, NameTranslationLessFunc );
void AddNewTranslation( const char *pOriginalMaterialName, const char *pNewMaterialName )
{
NameTranslationLookup_t newEntry;
newEntry.m_OriginalFileName = s_SymbolTable.AddString( pOriginalMaterialName );
newEntry.m_PatchFileName = s_SymbolTable.AddString( pNewMaterialName );
s_MapPatchedMatToOriginalMat.Insert( newEntry );
}
const char *GetOriginalMaterialNameForPatchedMaterial( const char *pPatchMaterialName )
{
const char *pRetName = NULL;
int id;
NameTranslationLookup_t lookup;
lookup.m_PatchFileName = s_SymbolTable.AddString( pPatchMaterialName );
do
{
id = s_MapPatchedMatToOriginalMat.Find( lookup );
if( id >= 0 )
{
NameTranslationLookup_t &found = s_MapPatchedMatToOriginalMat[id];
lookup.m_PatchFileName = found.m_OriginalFileName;
pRetName = s_SymbolTable.String( found.m_OriginalFileName );
}
} while( id >= 0 );
if( !pRetName )
{
// This isn't a patched material, so just return the original name.
return pPatchMaterialName;
}
return pRetName;
}
void CreateMaterialPatchRecursive( KeyValues *pOriginalKeyValues, KeyValues *pPatchKeyValues, int nKeys, const MaterialPatchInfo_t *pInfo )
{
int i;
for( i = 0; i < nKeys; i++ )
{
const char *pVal = pOriginalKeyValues->GetString( pInfo[i].m_pKey, NULL );
if( !pVal )
continue;
if( pInfo[i].m_pRequiredOriginalValue && Q_stricmp( pVal, pInfo[i].m_pRequiredOriginalValue ) != 0 )
continue;
pPatchKeyValues->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
}
KeyValues *pScan;
for( pScan = pOriginalKeyValues->GetFirstTrueSubKey(); pScan; pScan = pScan->GetNextTrueSubKey() )
{
CreateMaterialPatchRecursive( pScan, pPatchKeyValues->FindKey( pScan->GetName(), true ), nKeys, pInfo );
}
}
//-----------------------------------------------------------------------------
// A version which allows you to patch multiple key values
//-----------------------------------------------------------------------------
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
int nKeys, const MaterialPatchInfo_t *pInfo, MaterialPatchType_t nPatchType )
{
char pOldVMTFile[ 512 ];
char pNewVMTFile[ 512 ];
AddNewTranslation( pOriginalMaterialName, pNewMaterialName );
Q_snprintf( pOldVMTFile, 512, "materials/%s.vmt", pOriginalMaterialName );
Q_snprintf( pNewVMTFile, 512, "materials/%s.vmt", pNewMaterialName );
// printf( "Creating material patch file %s which points at %s\n", newVMTFile, oldVMTFile );
KeyValues *kv = new KeyValues( "patch" );
if ( !kv )
{
Error( "Couldn't allocate KeyValues for %s!!!", pNewMaterialName );
}
kv->SetString( "include", pOldVMTFile );
const char *pSectionName = (nPatchType == PATCH_INSERT) ? "insert" : "replace";
KeyValues *section = kv->FindKey( pSectionName, true );
if( nPatchType == PATCH_REPLACE )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pOriginalMaterialName ) );
KeyValues *origkv = new KeyValues( "blah" );
if ( !origkv->LoadFromFile( g_pFileSystem, name ) )
{
origkv->deleteThis();
Assert( 0 );
return;
}
CreateMaterialPatchRecursive( origkv, section, nKeys, pInfo );
origkv->deleteThis();
}
else
{
for ( int i = 0; i < nKeys; ++i )
{
section->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
}
}
// Write patched .vmt into a memory buffer
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
kv->RecursiveSaveToFile( buf, 0 );
// Add to pak file for this .bsp
AddBufferToPak( GetPakFile(), pNewVMTFile, (void*)buf.Base(), buf.TellPut(), true );
// Cleanup
kv->deleteThis();
}
//-----------------------------------------------------------------------------
// Patches a single keyvalue in a material
//-----------------------------------------------------------------------------
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
const char *pNewKey, const char *pNewValue, MaterialPatchType_t nPatchType )
{
MaterialPatchInfo_t info;
info.m_pKey = pNewKey;
info.m_pValue = pNewValue;
CreateMaterialPatch( pOriginalMaterialName, pNewMaterialName, 1, &info, nPatchType );
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key
//-----------------------------------------------------------------------------
static bool DoesMaterialHaveKey( KeyValues *pKeyValues, const char *pKeyName )
{
const char *pVal;
pVal = pKeyValues->GetString( pKeyName, NULL );
if ( pVal != NULL )
return true;
for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
{
if ( DoesMaterialHaveKey( pSubKey, pKeyName) )
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key/value pair
//-----------------------------------------------------------------------------
static bool DoesMaterialHaveKeyValuePair( KeyValues *pKeyValues, const char *pKeyName, const char *pSearchValue )
{
const char *pVal;
pVal = pKeyValues->GetString( pKeyName, NULL );
if ( pVal != NULL && ( Q_stricmp( pSearchValue, pVal ) == 0 ) )
return true;
for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
{
if ( DoesMaterialHaveKeyValuePair( pSubKey, pKeyName, pSearchValue ) )
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key
//-----------------------------------------------------------------------------
bool DoesMaterialHaveKey( const char *pMaterialName, const char *pKeyName )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
KeyValues *kv = new KeyValues( "blah" );
if ( !kv->LoadFromFile( g_pFileSystem, name ) )
{
kv->deleteThis();
return NULL;
}
bool retVal = DoesMaterialHaveKey( kv, pKeyName );
kv->deleteThis();
return retVal;
}
//-----------------------------------------------------------------------------
// Scan material + all subsections for key/value pair
//-----------------------------------------------------------------------------
bool DoesMaterialHaveKeyValuePair( const char *pMaterialName, const char *pKeyName, const char *pSearchValue )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
KeyValues *kv = new KeyValues( "blah" );
if ( !kv->LoadFromFile( g_pFileSystem, name ) )
{
kv->deleteThis();
return NULL;
}
bool retVal = DoesMaterialHaveKeyValuePair( kv, pKeyName, pSearchValue );
kv->deleteThis();
return retVal;
}
//-----------------------------------------------------------------------------
// Gets a material value from a material. Ignores all patches
//-----------------------------------------------------------------------------
bool GetValueFromMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
{
char name[512];
Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
KeyValues *kv = new KeyValues( "blah" );
if ( !kv->LoadFromFile( g_pFileSystem, name ) )
{
// Assert( 0 );
kv->deleteThis();
return NULL;
}
const char *pTmpValue = kv->GetString( pKey, NULL );
if( pTmpValue )
{
Q_strncpy( pValue, pTmpValue, len );
}
kv->deleteThis();
return ( pTmpValue != NULL );
}
//-----------------------------------------------------------------------------
// Finds the original material associated with a patched material
//-----------------------------------------------------------------------------
MaterialSystemMaterial_t FindOriginalMaterial( const char *materialName, bool *pFound, bool bComplain )
{
MaterialSystemMaterial_t matID;
matID = FindMaterial( GetOriginalMaterialNameForPatchedMaterial( materialName ), pFound, bComplain );
return matID;
}
//-----------------------------------------------------------------------------
// Load keyvalues from the local pack file, or from a file
//-----------------------------------------------------------------------------
bool LoadKeyValuesFromPackOrFile( const char *pFileName, KeyValues *pKeyValues )
{
CUtlBuffer buf;
if ( ReadFileFromPak( GetPakFile(), pFileName, true, buf ) )
{
return pKeyValues->LoadFromBuffer( pFileName, buf );
}
return pKeyValues->LoadFromFile( g_pFileSystem, pFileName );
}
//-----------------------------------------------------------------------------
// VMT parser
//-----------------------------------------------------------------------------
static void InsertKeyValues( KeyValues &dst, KeyValues& src, bool bCheckForExistence )
{
KeyValues *pSrcVar = src.GetFirstSubKey();
while( pSrcVar )
{
if ( !bCheckForExistence || dst.FindKey( pSrcVar->GetName() ) )
{
switch( pSrcVar->GetDataType() )
{
case KeyValues::TYPE_STRING:
dst.SetString( pSrcVar->GetName(), pSrcVar->GetString() );
break;
case KeyValues::TYPE_INT:
dst.SetInt( pSrcVar->GetName(), pSrcVar->GetInt() );
break;
case KeyValues::TYPE_FLOAT:
dst.SetFloat( pSrcVar->GetName(), pSrcVar->GetFloat() );
break;
case KeyValues::TYPE_PTR:
dst.SetPtr( pSrcVar->GetName(), pSrcVar->GetPtr() );
break;
}
}
pSrcVar = pSrcVar->GetNextKey();
}
}
static void ExpandPatchFile( KeyValues &keyValues )
{
int nCount = 0;
while( nCount < 10 && stricmp( keyValues.GetName(), "patch" ) == 0 )
{
// WriteKeyValuesToFile( "patch.txt", keyValues );
const char *pIncludeFileName = keyValues.GetString( "include" );
if( !pIncludeFileName )
return;
KeyValues * includeKeyValues = new KeyValues( "vmt" );
int nBufLen = Q_strlen( pIncludeFileName ) + Q_strlen( "materials/.vmt" ) + 1;
char *pFileName = ( char * )stackalloc( nBufLen );
Q_strncpy( pFileName, pIncludeFileName, nBufLen );
bool bSuccess = LoadKeyValuesFromPackOrFile( pFileName, includeKeyValues );
if ( !bSuccess )
{
includeKeyValues->deleteThis();
return;
}
KeyValues *pInsertSection = keyValues.FindKey( "insert" );
if( pInsertSection )
{
InsertKeyValues( *includeKeyValues, *pInsertSection, false );
keyValues = *includeKeyValues;
}
KeyValues *pReplaceSection = keyValues.FindKey( "replace" );
if( pReplaceSection )
{
InsertKeyValues( *includeKeyValues, *pReplaceSection, true );
keyValues = *includeKeyValues;
}
// Could add other commands here, like "delete", "rename", etc.
includeKeyValues->deleteThis();
nCount++;
}
if( nCount >= 10 )
{
Warning( "Infinite recursion in patch file?\n" );
}
}
KeyValues *LoadMaterialKeyValues( const char *pMaterialName, unsigned int nFlags )
{
// Load the underlying file
KeyValues *kv = new KeyValues( "blah" );
char pFullMaterialName[512];
Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
{
// Assert( 0 );
kv->deleteThis();
return NULL;
}
if( nFlags & LOAD_MATERIAL_KEY_VALUES_FLAGS_EXPAND_PATCH )
{
ExpandPatchFile( *kv );
}
return kv;
}
void WriteMaterialKeyValuesToPak( const char *pMaterialName, KeyValues *kv )
{
char pFullMaterialName[512];
Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
// Write patched .vmt into a memory buffer
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
kv->RecursiveSaveToFile( buf, 0 );
// Add to pak file for this .bsp
AddBufferToPak( GetPakFile(), pFullMaterialName, (void*)buf.Base(), buf.TellPut(), true );
// Cleanup
kv->deleteThis();
}
//-----------------------------------------------------------------------------
// Gets a keyvalue from a *patched* material
//-----------------------------------------------------------------------------
bool GetValueFromPatchedMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
{
// Load the underlying file so that we can check if env_cubemap is in there.
KeyValues *kv = new KeyValues( "blah" );
char pFullMaterialName[512];
Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
{
// Assert( 0 );
kv->deleteThis();
return NULL;
}
ExpandPatchFile( *kv );
const char *pTmpValue = kv->GetString( pKey, NULL );
if( pTmpValue )
{
Q_strncpy( pValue, pTmpValue, len );
}
kv->deleteThis();
return ( pTmpValue != NULL );
}

View File

@@ -1,60 +1,60 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef MATERIALPATCH_H
#define MATERIALPATCH_H
#ifdef _WIN32
#pragma once
#endif
#include "utilmatlib.h"
struct MaterialPatchInfo_t
{
const char *m_pKey;
const char *m_pRequiredOriginalValue; // NULL if you don't require one.
const char *m_pValue;
MaterialPatchInfo_t()
{
memset( this, 0, sizeof( *this ) );
}
};
enum MaterialPatchType_t
{
PATCH_INSERT = 0, // Add the key no matter what
PATCH_REPLACE, // Add the key only if it exists
};
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
const char *pNewKey, const char *pNewValue, MaterialPatchType_t nPatchType );
// A version which allows you to use multiple key values
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
int nKeys, const MaterialPatchInfo_t *pInfo, MaterialPatchType_t nPatchType );
// This gets a keyvalue from the *unpatched* version of the passed-in material
bool GetValueFromMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len );
// Gets a keyvalue from a *patched* material
bool GetValueFromPatchedMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len );
const char *GetOriginalMaterialNameForPatchedMaterial( const char *pPatchMaterialName );
MaterialSystemMaterial_t FindOriginalMaterial( const char *materialName, bool *pFound, bool bComplain = true );
bool DoesMaterialHaveKeyValuePair( const char *pMaterialName, const char *pKeyName, const char *pSearchValue );
bool DoesMaterialHaveKey( const char *pMaterialName, const char *pKeyName );
enum LoadMaterialKeyValuesFlags_t
{
LOAD_MATERIAL_KEY_VALUES_FLAGS_EXPAND_PATCH = 1,
};
KeyValues *LoadMaterialKeyValues( const char *pMaterialName, unsigned int nFlags );
void WriteMaterialKeyValuesToPak( const char *pMaterialName, KeyValues *kv );
#endif // MATERIALPATCH_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef MATERIALPATCH_H
#define MATERIALPATCH_H
#ifdef _WIN32
#pragma once
#endif
#include "utilmatlib.h"
struct MaterialPatchInfo_t
{
const char *m_pKey;
const char *m_pRequiredOriginalValue; // NULL if you don't require one.
const char *m_pValue;
MaterialPatchInfo_t()
{
memset( this, 0, sizeof( *this ) );
}
};
enum MaterialPatchType_t
{
PATCH_INSERT = 0, // Add the key no matter what
PATCH_REPLACE, // Add the key only if it exists
};
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
const char *pNewKey, const char *pNewValue, MaterialPatchType_t nPatchType );
// A version which allows you to use multiple key values
void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
int nKeys, const MaterialPatchInfo_t *pInfo, MaterialPatchType_t nPatchType );
// This gets a keyvalue from the *unpatched* version of the passed-in material
bool GetValueFromMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len );
// Gets a keyvalue from a *patched* material
bool GetValueFromPatchedMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len );
const char *GetOriginalMaterialNameForPatchedMaterial( const char *pPatchMaterialName );
MaterialSystemMaterial_t FindOriginalMaterial( const char *materialName, bool *pFound, bool bComplain = true );
bool DoesMaterialHaveKeyValuePair( const char *pMaterialName, const char *pKeyName, const char *pSearchValue );
bool DoesMaterialHaveKey( const char *pMaterialName, const char *pKeyName );
enum LoadMaterialKeyValuesFlags_t
{
LOAD_MATERIAL_KEY_VALUES_FLAGS_EXPAND_PATCH = 1,
};
KeyValues *LoadMaterialKeyValues( const char *pMaterialName, unsigned int nFlags );
void WriteMaterialKeyValuesToPak( const char *pMaterialName, KeyValues *kv );
#endif // MATERIALPATCH_H

View File

@@ -1,90 +1,90 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: This file loads a KeyValues file containing material name mappings.
// When the bsp is compiled, all materials listed in the file will
// be replaced by the second material in the pair.
//
//=============================================================================
#include "vbsp.h"
#include "materialsub.h"
#include "KeyValues.h"
#include "tier1/strtools.h"
bool g_ReplaceMaterials = false;
static KeyValues *kv = 0;
static KeyValues *allMapKeys = 0;
static KeyValues *curMapKeys = 0;
//-----------------------------------------------------------------------------
// Purpose: Loads the KeyValues file for materials replacements
//-----------------------------------------------------------------------------
void LoadMaterialReplacementKeys( const char *gamedir, const char *mapname )
{
// Careful with static variables
if( kv )
{
kv->deleteThis();
kv = 0;
}
if( allMapKeys )
allMapKeys = 0;
if( curMapKeys )
curMapKeys = 0;
Msg( "Loading Replacement Keys\n" );
// Attach the path to the keyValues file
char path[1024];
Q_snprintf( path, sizeof( path ), "%scfg\\materialsub.cfg", gamedir );
// Load the keyvalues file
kv = new KeyValues( "MaterialReplacements" );
Msg( "File path: %s", path );
if( !kv->LoadFromFile( g_pFileSystem, path ) )
{
Msg( "Failed to load KeyValues file!\n" );
g_ReplaceMaterials = false;
kv->deleteThis();
kv = 0;
return;
}
// Load global replace keys
allMapKeys = kv->FindKey( "AllMaps", true );
// Load keys for the current map
curMapKeys = kv->FindKey( mapname );
allMapKeys->ChainKeyValue( curMapKeys );
}
//-----------------------------------------------------------------------------
// Purpose: Deletes all keys
//-----------------------------------------------------------------------------
void DeleteMaterialReplacementKeys( void )
{
if( kv )
{
kv->deleteThis();
kv = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose: Replace the passed-in material name with a replacement name, if one exists
//-----------------------------------------------------------------------------
const char* ReplaceMaterialName( const char *name )
{
// Look for the material name in the global and map KeyValues
// If it's not there, just return the original name
// HACK: This stinks - KeyValues won't take a string with '/' in it.
// If they did, this could be a simple pointer swap.
char newName[1024];
Q_strncpy( newName, name, sizeof( newName ) );
Q_FixSlashes( newName );
return allMapKeys->GetString( newName, name );
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: This file loads a KeyValues file containing material name mappings.
// When the bsp is compiled, all materials listed in the file will
// be replaced by the second material in the pair.
//
//=============================================================================
#include "vbsp.h"
#include "materialsub.h"
#include "KeyValues.h"
#include "tier1/strtools.h"
bool g_ReplaceMaterials = false;
static KeyValues *kv = 0;
static KeyValues *allMapKeys = 0;
static KeyValues *curMapKeys = 0;
//-----------------------------------------------------------------------------
// Purpose: Loads the KeyValues file for materials replacements
//-----------------------------------------------------------------------------
void LoadMaterialReplacementKeys( const char *gamedir, const char *mapname )
{
// Careful with static variables
if( kv )
{
kv->deleteThis();
kv = 0;
}
if( allMapKeys )
allMapKeys = 0;
if( curMapKeys )
curMapKeys = 0;
Msg( "Loading Replacement Keys\n" );
// Attach the path to the keyValues file
char path[1024];
Q_snprintf( path, sizeof( path ), "%scfg\\materialsub.cfg", gamedir );
// Load the keyvalues file
kv = new KeyValues( "MaterialReplacements" );
Msg( "File path: %s", path );
if( !kv->LoadFromFile( g_pFileSystem, path ) )
{
Msg( "Failed to load KeyValues file!\n" );
g_ReplaceMaterials = false;
kv->deleteThis();
kv = 0;
return;
}
// Load global replace keys
allMapKeys = kv->FindKey( "AllMaps", true );
// Load keys for the current map
curMapKeys = kv->FindKey( mapname );
allMapKeys->ChainKeyValue( curMapKeys );
}
//-----------------------------------------------------------------------------
// Purpose: Deletes all keys
//-----------------------------------------------------------------------------
void DeleteMaterialReplacementKeys( void )
{
if( kv )
{
kv->deleteThis();
kv = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose: Replace the passed-in material name with a replacement name, if one exists
//-----------------------------------------------------------------------------
const char* ReplaceMaterialName( const char *name )
{
// Look for the material name in the global and map KeyValues
// If it's not there, just return the original name
// HACK: This stinks - KeyValues won't take a string with '/' in it.
// If they did, this could be a simple pointer swap.
char newName[1024];
Q_strncpy( newName, name, sizeof( newName ) );
Q_FixSlashes( newName );
return allMapKeys->GetString( newName, name );
}

View File

@@ -1,25 +1,25 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: This file loads a KeyValues file containing material name mappings.
// When the bsp is compiled, all materials listed in the file will
// be replaced by the second material in the pair.
//
//=============================================================================
#ifndef MATERIALSUB_H
#define MATERIALSUB_H
#ifdef _WIN32
#pragma once
#endif
extern bool g_ReplaceMaterials;
// Setup / Cleanup
void LoadMaterialReplacementKeys( const char *gamedir, const char *mapname );
void DeleteMaterialReplacementKeys( void );
// Takes a material name and returns it's replacement, if there is one.
// If there isn't a replacement, it returns the original.
const char* ReplaceMaterialName( const char *name );
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: This file loads a KeyValues file containing material name mappings.
// When the bsp is compiled, all materials listed in the file will
// be replaced by the second material in the pair.
//
//=============================================================================
#ifndef MATERIALSUB_H
#define MATERIALSUB_H
#ifdef _WIN32
#pragma once
#endif
extern bool g_ReplaceMaterials;
// Setup / Cleanup
void LoadMaterialReplacementKeys( const char *gamedir, const char *mapname );
void DeleteMaterialReplacementKeys( void );
// Takes a material name and returns it's replacement, if there is one.
// If there isn't a replacement, it returns the original.
const char* ReplaceMaterialName( const char *name );
#endif // MATERIALSUB_H

View File

@@ -1,32 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
Vector draw_mins, draw_maxs;
void Draw_ClearWindow (void)
{
}
//============================================================
#define GLSERV_PORT 25001
void GLS_BeginScene (void)
{
}
void GLS_Winding (winding_t *w, int code)
{
}
void GLS_EndScene (void)
{
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
Vector draw_mins, draw_maxs;
void Draw_ClearWindow (void)
{
}
//============================================================
#define GLSERV_PORT 25001
void GLS_BeginScene (void)
{
}
void GLS_Winding (winding_t *w, int code)
{
}
void GLS_EndScene (void)
{
}

View File

@@ -1,50 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "bsplib.h"
#include "vbsp.h"
void SaveVertexNormals( void )
{
int i, j;
dface_t *f;
texinfo_t *tex;
g_numvertnormalindices = 0;
g_numvertnormals = 0;
for( i = 0 ;i<numfaces ; i++ )
{
f = &dfaces[i];
tex = &texinfo[f->texinfo];
for( j = 0; j < f->numedges; j++ )
{
if( g_numvertnormalindices == MAX_MAP_VERTNORMALINDICES )
{
Error( "g_numvertnormalindices == MAX_MAP_VERTNORMALINDICES (%d)", MAX_MAP_VERTNORMALINDICES );
}
g_vertnormalindices[g_numvertnormalindices] = g_numvertnormals;
g_numvertnormalindices++;
}
// Add this face plane's normal.
// Note: this doesn't do an exhaustive vertex normal match because the vrad does it.
// The result is that a little extra memory is wasted coming out of vbsp, but it
// goes away after vrad.
if( g_numvertnormals == MAX_MAP_VERTNORMALS )
{
Error( "g_numvertnormals == MAX_MAP_VERTNORMALS (%d)", MAX_MAP_VERTNORMALS );
}
g_vertnormals[g_numvertnormals] = dplanes[f->planenum].normal;
g_numvertnormals++;
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "bsplib.h"
#include "vbsp.h"
void SaveVertexNormals( void )
{
int i, j;
dface_t *f;
texinfo_t *tex;
g_numvertnormalindices = 0;
g_numvertnormals = 0;
for( i = 0 ;i<numfaces ; i++ )
{
f = &dfaces[i];
tex = &texinfo[f->texinfo];
for( j = 0; j < f->numedges; j++ )
{
if( g_numvertnormalindices == MAX_MAP_VERTNORMALINDICES )
{
Error( "g_numvertnormalindices == MAX_MAP_VERTNORMALINDICES (%d)", MAX_MAP_VERTNORMALINDICES );
}
g_vertnormalindices[g_numvertnormalindices] = g_numvertnormals;
g_numvertnormalindices++;
}
// Add this face plane's normal.
// Note: this doesn't do an exhaustive vertex normal match because the vrad does it.
// The result is that a little extra memory is wasted coming out of vbsp, but it
// goes away after vrad.
if( g_numvertnormals == MAX_MAP_VERTNORMALS )
{
Error( "g_numvertnormals == MAX_MAP_VERTNORMALS (%d)", MAX_MAP_VERTNORMALS );
}
g_vertnormals[g_numvertnormals] = dplanes[f->planenum].normal;
g_numvertnormals++;
}
}

View File

@@ -1,487 +1,487 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "vbsp.h"
#include "disp_vbsp.h"
#include "builddisp.h"
#include "mathlib/vmatrix.h"
void Overlay_BuildBasisOrigin( doverlay_t *pOverlay );
// Overlay list.
CUtlVector<mapoverlay_t> g_aMapOverlays;
CUtlVector<mapoverlay_t> g_aMapWaterOverlays;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int Overlay_GetFromEntity( entity_t *pMapEnt )
{
int iAccessorID = -1;
// Allocate the new overlay.
int iOverlay = g_aMapOverlays.AddToTail();
mapoverlay_t *pMapOverlay = &g_aMapOverlays[iOverlay];
// Get the overlay data.
pMapOverlay->nId = g_aMapOverlays.Count() - 1;
if ( ValueForKey( pMapEnt, "targetname" )[ 0 ] != '\0' )
{
// Overlay has a name, remember it's ID for accessing
iAccessorID = pMapOverlay->nId;
}
pMapOverlay->flU[0] = FloatForKey( pMapEnt, "StartU" );
pMapOverlay->flU[1] = FloatForKey( pMapEnt, "EndU" );
pMapOverlay->flV[0] = FloatForKey( pMapEnt, "StartV" );
pMapOverlay->flV[1] = FloatForKey( pMapEnt, "EndV" );
pMapOverlay->flFadeDistMinSq = FloatForKey( pMapEnt, "fademindist" );
if ( pMapOverlay->flFadeDistMinSq > 0 )
{
pMapOverlay->flFadeDistMinSq *= pMapOverlay->flFadeDistMinSq;
}
pMapOverlay->flFadeDistMaxSq = FloatForKey( pMapEnt, "fademaxdist" );
if ( pMapOverlay->flFadeDistMaxSq > 0 )
{
pMapOverlay->flFadeDistMaxSq *= pMapOverlay->flFadeDistMaxSq;
}
GetVectorForKey( pMapEnt, "BasisOrigin", pMapOverlay->vecOrigin );
pMapOverlay->m_nRenderOrder = IntForKey( pMapEnt, "RenderOrder" );
if ( pMapOverlay->m_nRenderOrder < 0 || pMapOverlay->m_nRenderOrder >= OVERLAY_NUM_RENDER_ORDERS )
Error( "Overlay (%s) at %f %f %f has invalid render order (%d).\n", ValueForKey( pMapEnt, "material" ),
pMapOverlay->vecOrigin.x, pMapOverlay->vecOrigin.y, pMapOverlay->vecOrigin.z,
pMapOverlay->m_nRenderOrder );
GetVectorForKey( pMapEnt, "uv0", pMapOverlay->vecUVPoints[0] );
GetVectorForKey( pMapEnt, "uv1", pMapOverlay->vecUVPoints[1] );
GetVectorForKey( pMapEnt, "uv2", pMapOverlay->vecUVPoints[2] );
GetVectorForKey( pMapEnt, "uv3", pMapOverlay->vecUVPoints[3] );
GetVectorForKey( pMapEnt, "BasisU", pMapOverlay->vecBasis[0] );
GetVectorForKey( pMapEnt, "BasisV", pMapOverlay->vecBasis[1] );
GetVectorForKey( pMapEnt, "BasisNormal", pMapOverlay->vecBasis[2] );
const char *pMaterialName = ValueForKey( pMapEnt, "material" );
Assert( strlen( pMaterialName ) < OVERLAY_MAP_STRLEN );
if ( strlen( pMaterialName ) >= OVERLAY_MAP_STRLEN )
{
Error( "Overlay Material Name (%s) too long! > OVERLAY_MAP_STRLEN (%d)", pMaterialName, OVERLAY_MAP_STRLEN );
return -1;
}
strcpy( pMapOverlay->szMaterialName, pMaterialName );
// Convert the sidelist to side id(s).
const char *pSideList = ValueForKey( pMapEnt, "sides" );
char *pTmpList = ( char* )_alloca( strlen( pSideList ) + 1 );
strcpy( pTmpList, pSideList );
const char *pScan = strtok( pTmpList, " " );
if ( !pScan )
return iAccessorID;
pMapOverlay->aSideList.Purge();
pMapOverlay->aFaceList.Purge();
do
{
int nSideId;
if ( sscanf( pScan, "%d", &nSideId ) == 1 )
{
pMapOverlay->aSideList.AddToTail( nSideId );
}
} while ( ( pScan = strtok( NULL, " " ) ) );
return iAccessorID;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
side_t *GetSide( int nSideId )
{
for( int iSide = 0; iSide < g_LoadingMap->nummapbrushsides; ++iSide )
{
if ( g_LoadingMap->brushsides[iSide].id == nSideId )
return &g_LoadingMap->brushsides[iSide];
}
return NULL;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void Overlay_UpdateSideLists( int StartIndex )
{
int nMapOverlayCount = g_aMapOverlays.Count();
for( int iMapOverlay = StartIndex; iMapOverlay < nMapOverlayCount; ++iMapOverlay )
{
mapoverlay_t *pMapOverlay = &g_aMapOverlays.Element( iMapOverlay );
if ( pMapOverlay )
{
int nSideCount = pMapOverlay->aSideList.Count();
for( int iSide = 0; iSide < nSideCount; ++iSide )
{
side_t *pSide = GetSide( pMapOverlay->aSideList[iSide] );
if ( pSide )
{
if ( pSide->aOverlayIds.Find( pMapOverlay->nId ) == -1 )
{
pSide->aOverlayIds.AddToTail( pMapOverlay->nId );
}
}
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void OverlayTransition_UpdateSideLists( int StartIndex )
{
int nOverlayCount = g_aMapWaterOverlays.Count();
for( int iOverlay = StartIndex; iOverlay < nOverlayCount; ++iOverlay )
{
mapoverlay_t *pOverlay = &g_aMapWaterOverlays.Element( iOverlay );
if ( pOverlay )
{
int nSideCount = pOverlay->aSideList.Count();
for( int iSide = 0; iSide < nSideCount; ++iSide )
{
side_t *pSide = GetSide( pOverlay->aSideList[iSide] );
if ( pSide )
{
if ( pSide->aWaterOverlayIds.Find( pOverlay->nId ) == -1 )
{
pSide->aWaterOverlayIds.AddToTail( pOverlay->nId );
}
}
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void Overlay_AddFaceToLists( int iFace, side_t *pSide )
{
int nOverlayIdCount = pSide->aOverlayIds.Count();
for( int iOverlayId = 0; iOverlayId < nOverlayIdCount; ++iOverlayId )
{
mapoverlay_t *pMapOverlay = &g_aMapOverlays.Element( pSide->aOverlayIds[iOverlayId] );
if ( pMapOverlay )
{
if( pMapOverlay->aFaceList.Find( iFace ) == -1 )
{
pMapOverlay->aFaceList.AddToTail( iFace );
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void OverlayTransition_AddFaceToLists( int iFace, side_t *pSide )
{
int nOverlayIdCount = pSide->aWaterOverlayIds.Count();
for( int iOverlayId = 0; iOverlayId < nOverlayIdCount; ++iOverlayId )
{
mapoverlay_t *pMapOverlay = &g_aMapWaterOverlays.Element( pSide->aWaterOverlayIds[iOverlayId] - ( MAX_MAP_OVERLAYS + 1 ) );
if ( pMapOverlay )
{
if( pMapOverlay->aFaceList.Find( iFace ) == -1 )
{
pMapOverlay->aFaceList.AddToTail( iFace );
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void Overlay_EmitOverlayFace( mapoverlay_t *pMapOverlay )
{
Assert( g_nOverlayCount < MAX_MAP_OVERLAYS );
if ( g_nOverlayCount >= MAX_MAP_OVERLAYS )
{
Error ( "Too Many Overlays!\nMAX_MAP_OVERLAYS = %d", MAX_MAP_OVERLAYS );
return;
}
doverlay_t *pOverlay = &g_Overlays[g_nOverlayCount];
doverlayfade_t *pOverlayFade = &g_OverlayFades[g_nOverlayCount];
g_nOverlayCount++;
// Conver the map overlay into a .bsp overlay (doverlay_t).
if ( pOverlay )
{
pOverlay->nId = pMapOverlay->nId;
pOverlay->flU[0] = pMapOverlay->flU[0];
pOverlay->flU[1] = pMapOverlay->flU[1];
pOverlay->flV[0] = pMapOverlay->flV[0];
pOverlay->flV[1] = pMapOverlay->flV[1];
VectorCopy( pMapOverlay->vecUVPoints[0], pOverlay->vecUVPoints[0] );
VectorCopy( pMapOverlay->vecUVPoints[1], pOverlay->vecUVPoints[1] );
VectorCopy( pMapOverlay->vecUVPoints[2], pOverlay->vecUVPoints[2] );
VectorCopy( pMapOverlay->vecUVPoints[3], pOverlay->vecUVPoints[3] );
VectorCopy( pMapOverlay->vecOrigin, pOverlay->vecOrigin );
VectorCopy( pMapOverlay->vecBasis[2], pOverlay->vecBasisNormal );
pOverlay->SetRenderOrder( pMapOverlay->m_nRenderOrder );
// Encode the BasisU into the unused z component of the vecUVPoints 0, 1, 2
pOverlay->vecUVPoints[0].z = pMapOverlay->vecBasis[0].x;
pOverlay->vecUVPoints[1].z = pMapOverlay->vecBasis[0].y;
pOverlay->vecUVPoints[2].z = pMapOverlay->vecBasis[0].z;
// Encode whether or not the v axis should be flipped.
Vector vecCross = pMapOverlay->vecBasis[2].Cross( pMapOverlay->vecBasis[0] );
if ( vecCross.Dot( pMapOverlay->vecBasis[1] ) < 0.0f )
{
pOverlay->vecUVPoints[3].z = 1.0f;
}
// Texinfo.
texinfo_t texInfo;
texInfo.flags = 0;
texInfo.texdata = FindOrCreateTexData( pMapOverlay->szMaterialName );
for( int iVec = 0; iVec < 2; ++iVec )
{
for( int iAxis = 0; iAxis < 3; ++iAxis )
{
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][iAxis] = 0.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][iAxis] = 0.0f;
}
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][3] = -99999.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][3] = -99999.0f;
}
pOverlay->nTexInfo = FindOrCreateTexInfo( texInfo );
// Face List
int nFaceCount = pMapOverlay->aFaceList.Count();
Assert( nFaceCount < OVERLAY_BSP_FACE_COUNT );
if ( nFaceCount >= OVERLAY_BSP_FACE_COUNT )
{
Error( "Overlay touching too many faces (touching %d, max %d)\nOverlay %s at %.1f %.1f %.1f", nFaceCount, OVERLAY_BSP_FACE_COUNT, pMapOverlay->szMaterialName, pMapOverlay->vecOrigin.x, pMapOverlay->vecOrigin.y, pMapOverlay->vecOrigin.z );
return;
}
pOverlay->SetFaceCount( nFaceCount );
for( int iFace = 0; iFace < nFaceCount; ++iFace )
{
pOverlay->aFaces[iFace] = pMapOverlay->aFaceList.Element( iFace );
}
}
// Convert the map overlay fade data into a .bsp overlay fade (doverlayfade_t).
if ( pOverlayFade )
{
pOverlayFade->flFadeDistMinSq = pMapOverlay->flFadeDistMinSq;
pOverlayFade->flFadeDistMaxSq = pMapOverlay->flFadeDistMaxSq;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void OverlayTransition_EmitOverlayFace( mapoverlay_t *pMapOverlay )
{
Assert( g_nWaterOverlayCount < MAX_MAP_WATEROVERLAYS );
if ( g_nWaterOverlayCount >= MAX_MAP_WATEROVERLAYS )
{
Error ( "Too many water overlays!\nMAX_MAP_WATEROVERLAYS = %d", MAX_MAP_WATEROVERLAYS );
return;
}
dwateroverlay_t *pOverlay = &g_WaterOverlays[g_nWaterOverlayCount];
g_nWaterOverlayCount++;
// Conver the map overlay into a .bsp overlay (doverlay_t).
if ( pOverlay )
{
pOverlay->nId = pMapOverlay->nId;
pOverlay->flU[0] = pMapOverlay->flU[0];
pOverlay->flU[1] = pMapOverlay->flU[1];
pOverlay->flV[0] = pMapOverlay->flV[0];
pOverlay->flV[1] = pMapOverlay->flV[1];
VectorCopy( pMapOverlay->vecUVPoints[0], pOverlay->vecUVPoints[0] );
VectorCopy( pMapOverlay->vecUVPoints[1], pOverlay->vecUVPoints[1] );
VectorCopy( pMapOverlay->vecUVPoints[2], pOverlay->vecUVPoints[2] );
VectorCopy( pMapOverlay->vecUVPoints[3], pOverlay->vecUVPoints[3] );
VectorCopy( pMapOverlay->vecOrigin, pOverlay->vecOrigin );
VectorCopy( pMapOverlay->vecBasis[2], pOverlay->vecBasisNormal );
pOverlay->SetRenderOrder( pMapOverlay->m_nRenderOrder );
// Encode the BasisU into the unused z component of the vecUVPoints 0, 1, 2
pOverlay->vecUVPoints[0].z = pMapOverlay->vecBasis[0].x;
pOverlay->vecUVPoints[1].z = pMapOverlay->vecBasis[0].y;
pOverlay->vecUVPoints[2].z = pMapOverlay->vecBasis[0].z;
// Encode whether or not the v axis should be flipped.
Vector vecCross = pMapOverlay->vecBasis[2].Cross( pMapOverlay->vecBasis[0] );
if ( vecCross.Dot( pMapOverlay->vecBasis[1] ) < 0.0f )
{
pOverlay->vecUVPoints[3].z = 1.0f;
}
// Texinfo.
texinfo_t texInfo;
texInfo.flags = 0;
texInfo.texdata = FindOrCreateTexData( pMapOverlay->szMaterialName );
for( int iVec = 0; iVec < 2; ++iVec )
{
for( int iAxis = 0; iAxis < 3; ++iAxis )
{
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][iAxis] = 0.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][iAxis] = 0.0f;
}
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][3] = -99999.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][3] = -99999.0f;
}
pOverlay->nTexInfo = FindOrCreateTexInfo( texInfo );
// Face List
int nFaceCount = pMapOverlay->aFaceList.Count();
Assert( nFaceCount < WATEROVERLAY_BSP_FACE_COUNT );
if ( nFaceCount >= WATEROVERLAY_BSP_FACE_COUNT )
{
Error( "Water Overlay touching too many faces (touching %d, max %d)\nOverlay %s at %.1f %.1f %.1f", nFaceCount, OVERLAY_BSP_FACE_COUNT, pMapOverlay->szMaterialName, pMapOverlay->vecOrigin.x, pMapOverlay->vecOrigin.y, pMapOverlay->vecOrigin.z );
return;
}
pOverlay->SetFaceCount( nFaceCount );
for( int iFace = 0; iFace < nFaceCount; ++iFace )
{
pOverlay->aFaces[iFace] = pMapOverlay->aFaceList.Element( iFace );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void Overlay_EmitOverlayFaces( void )
{
int nMapOverlayCount = g_aMapOverlays.Count();
for( int iMapOverlay = 0; iMapOverlay < nMapOverlayCount; ++iMapOverlay )
{
Overlay_EmitOverlayFace( &g_aMapOverlays.Element( iMapOverlay ) );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void OverlayTransition_EmitOverlayFaces( void )
{
int nMapOverlayCount = g_aMapWaterOverlays.Count();
for( int iMapOverlay = 0; iMapOverlay < nMapOverlayCount; ++iMapOverlay )
{
OverlayTransition_EmitOverlayFace( &g_aMapWaterOverlays.Element( iMapOverlay ) );
}
}
//-----------------------------------------------------------------------------
// These routines were mostly stolen from MapOverlay.cpp in Hammer
//-----------------------------------------------------------------------------
#define OVERLAY_BASIS_U 0
#define OVERLAY_BASIS_V 1
#define OVERLAY_BASIS_NORMAL 2
#define OVERLAY_HANDLES_COUNT 4
inline void TransformPoint( const VMatrix& matrix, Vector &point )
{
Vector orgVector = point;
matrix.V3Mul( orgVector, point );
}
inline bool fequal( float value, float target, float delta) { return ( (value<(target+delta))&&(value>(target-delta)) ); }
//-----------------------------------------------------------------------------
// Purpose: this function translate / rotate an overlay.
// Input : pOverlay - the overlay to be translated
// OriginOffset - the translation
// AngleOffset - the rotation
// Matrix - the translation / rotation matrix
// Output : none
//-----------------------------------------------------------------------------
void Overlay_Translate( mapoverlay_t *pOverlay, Vector &OriginOffset, QAngle &AngleOffset, matrix3x4_t &Matrix )
{
VMatrix tmpMatrix( Matrix );
Vector temp = pOverlay->vecOrigin;
VectorTransform( temp, Matrix, pOverlay->vecOrigin );
// erase move component
tmpMatrix.SetTranslation( vec3_origin );
// check if matrix would still change something
if ( !tmpMatrix.IsIdentity() )
{
// make sure axes are normalized (they should be anyways)
pOverlay->vecBasis[OVERLAY_BASIS_U].NormalizeInPlace();
pOverlay->vecBasis[OVERLAY_BASIS_V].NormalizeInPlace();
Vector vecU = pOverlay->vecBasis[OVERLAY_BASIS_U];
Vector vecV = pOverlay->vecBasis[OVERLAY_BASIS_V];
Vector vecNormal = pOverlay->vecBasis[OVERLAY_BASIS_NORMAL];
TransformPoint( tmpMatrix, vecU );
TransformPoint( tmpMatrix, vecV );
TransformPoint( tmpMatrix, vecNormal );
float fScaleU = vecU.Length();
float fScaleV = vecV.Length();
float flScaleNormal = vecNormal.Length();
bool bIsUnit = ( fequal( fScaleU, 1.0f, 0.0001 ) && fequal( fScaleV, 1.0f, 0.0001 ) && fequal( flScaleNormal, 1.0f, 0.0001 ) );
bool bIsPerp = ( fequal( DotProduct( vecU, vecV ), 0.0f, 0.0025 ) && fequal( DotProduct( vecU, vecNormal ), 0.0f, 0.0025 ) && fequal( DotProduct( vecV, vecNormal ), 0.0f, 0.0025 ) );
// if ( fequal(fScaleU,1,0.0001) && fequal(fScaleV,1,0.0001) && fequal(DotProduct( vecU, vecV ),0,0.0025) )
if ( bIsUnit && bIsPerp )
{
// transformation doesnt scale or shear anything, so just update base axes
pOverlay->vecBasis[OVERLAY_BASIS_U] = vecU;
pOverlay->vecBasis[OVERLAY_BASIS_V] = vecV;
pOverlay->vecBasis[OVERLAY_BASIS_NORMAL] = vecNormal;
}
else
{
// more complex transformation, move UV coordinates, but leave base axes
for ( int iHandle=0; iHandle<OVERLAY_HANDLES_COUNT;iHandle++)
{
Vector vecUV = pOverlay->vecUVPoints[iHandle];
Vector vecPos = ( vecUV.x * pOverlay->vecBasis[OVERLAY_BASIS_U] + vecUV.y * pOverlay->vecBasis[OVERLAY_BASIS_V] );
// to transform in world space
TransformPoint( tmpMatrix, vecPos );
vecUV.x = pOverlay->vecBasis[OVERLAY_BASIS_U].Dot( vecPos );
vecUV.y = pOverlay->vecBasis[OVERLAY_BASIS_V].Dot( vecPos );
pOverlay->vecUVPoints[iHandle] = vecUV;
}
}
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "vbsp.h"
#include "disp_vbsp.h"
#include "builddisp.h"
#include "mathlib/vmatrix.h"
void Overlay_BuildBasisOrigin( doverlay_t *pOverlay );
// Overlay list.
CUtlVector<mapoverlay_t> g_aMapOverlays;
CUtlVector<mapoverlay_t> g_aMapWaterOverlays;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int Overlay_GetFromEntity( entity_t *pMapEnt )
{
int iAccessorID = -1;
// Allocate the new overlay.
int iOverlay = g_aMapOverlays.AddToTail();
mapoverlay_t *pMapOverlay = &g_aMapOverlays[iOverlay];
// Get the overlay data.
pMapOverlay->nId = g_aMapOverlays.Count() - 1;
if ( ValueForKey( pMapEnt, "targetname" )[ 0 ] != '\0' )
{
// Overlay has a name, remember it's ID for accessing
iAccessorID = pMapOverlay->nId;
}
pMapOverlay->flU[0] = FloatForKey( pMapEnt, "StartU" );
pMapOverlay->flU[1] = FloatForKey( pMapEnt, "EndU" );
pMapOverlay->flV[0] = FloatForKey( pMapEnt, "StartV" );
pMapOverlay->flV[1] = FloatForKey( pMapEnt, "EndV" );
pMapOverlay->flFadeDistMinSq = FloatForKey( pMapEnt, "fademindist" );
if ( pMapOverlay->flFadeDistMinSq > 0 )
{
pMapOverlay->flFadeDistMinSq *= pMapOverlay->flFadeDistMinSq;
}
pMapOverlay->flFadeDistMaxSq = FloatForKey( pMapEnt, "fademaxdist" );
if ( pMapOverlay->flFadeDistMaxSq > 0 )
{
pMapOverlay->flFadeDistMaxSq *= pMapOverlay->flFadeDistMaxSq;
}
GetVectorForKey( pMapEnt, "BasisOrigin", pMapOverlay->vecOrigin );
pMapOverlay->m_nRenderOrder = IntForKey( pMapEnt, "RenderOrder" );
if ( pMapOverlay->m_nRenderOrder < 0 || pMapOverlay->m_nRenderOrder >= OVERLAY_NUM_RENDER_ORDERS )
Error( "Overlay (%s) at %f %f %f has invalid render order (%d).\n", ValueForKey( pMapEnt, "material" ),
pMapOverlay->vecOrigin.x, pMapOverlay->vecOrigin.y, pMapOverlay->vecOrigin.z,
pMapOverlay->m_nRenderOrder );
GetVectorForKey( pMapEnt, "uv0", pMapOverlay->vecUVPoints[0] );
GetVectorForKey( pMapEnt, "uv1", pMapOverlay->vecUVPoints[1] );
GetVectorForKey( pMapEnt, "uv2", pMapOverlay->vecUVPoints[2] );
GetVectorForKey( pMapEnt, "uv3", pMapOverlay->vecUVPoints[3] );
GetVectorForKey( pMapEnt, "BasisU", pMapOverlay->vecBasis[0] );
GetVectorForKey( pMapEnt, "BasisV", pMapOverlay->vecBasis[1] );
GetVectorForKey( pMapEnt, "BasisNormal", pMapOverlay->vecBasis[2] );
const char *pMaterialName = ValueForKey( pMapEnt, "material" );
Assert( strlen( pMaterialName ) < OVERLAY_MAP_STRLEN );
if ( strlen( pMaterialName ) >= OVERLAY_MAP_STRLEN )
{
Error( "Overlay Material Name (%s) too long! > OVERLAY_MAP_STRLEN (%d)", pMaterialName, OVERLAY_MAP_STRLEN );
return -1;
}
strcpy( pMapOverlay->szMaterialName, pMaterialName );
// Convert the sidelist to side id(s).
const char *pSideList = ValueForKey( pMapEnt, "sides" );
char *pTmpList = ( char* )_alloca( strlen( pSideList ) + 1 );
strcpy( pTmpList, pSideList );
const char *pScan = strtok( pTmpList, " " );
if ( !pScan )
return iAccessorID;
pMapOverlay->aSideList.Purge();
pMapOverlay->aFaceList.Purge();
do
{
int nSideId;
if ( sscanf( pScan, "%d", &nSideId ) == 1 )
{
pMapOverlay->aSideList.AddToTail( nSideId );
}
} while ( ( pScan = strtok( NULL, " " ) ) );
return iAccessorID;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
side_t *GetSide( int nSideId )
{
for( int iSide = 0; iSide < g_LoadingMap->nummapbrushsides; ++iSide )
{
if ( g_LoadingMap->brushsides[iSide].id == nSideId )
return &g_LoadingMap->brushsides[iSide];
}
return NULL;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void Overlay_UpdateSideLists( int StartIndex )
{
int nMapOverlayCount = g_aMapOverlays.Count();
for( int iMapOverlay = StartIndex; iMapOverlay < nMapOverlayCount; ++iMapOverlay )
{
mapoverlay_t *pMapOverlay = &g_aMapOverlays.Element( iMapOverlay );
if ( pMapOverlay )
{
int nSideCount = pMapOverlay->aSideList.Count();
for( int iSide = 0; iSide < nSideCount; ++iSide )
{
side_t *pSide = GetSide( pMapOverlay->aSideList[iSide] );
if ( pSide )
{
if ( pSide->aOverlayIds.Find( pMapOverlay->nId ) == -1 )
{
pSide->aOverlayIds.AddToTail( pMapOverlay->nId );
}
}
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void OverlayTransition_UpdateSideLists( int StartIndex )
{
int nOverlayCount = g_aMapWaterOverlays.Count();
for( int iOverlay = StartIndex; iOverlay < nOverlayCount; ++iOverlay )
{
mapoverlay_t *pOverlay = &g_aMapWaterOverlays.Element( iOverlay );
if ( pOverlay )
{
int nSideCount = pOverlay->aSideList.Count();
for( int iSide = 0; iSide < nSideCount; ++iSide )
{
side_t *pSide = GetSide( pOverlay->aSideList[iSide] );
if ( pSide )
{
if ( pSide->aWaterOverlayIds.Find( pOverlay->nId ) == -1 )
{
pSide->aWaterOverlayIds.AddToTail( pOverlay->nId );
}
}
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void Overlay_AddFaceToLists( int iFace, side_t *pSide )
{
int nOverlayIdCount = pSide->aOverlayIds.Count();
for( int iOverlayId = 0; iOverlayId < nOverlayIdCount; ++iOverlayId )
{
mapoverlay_t *pMapOverlay = &g_aMapOverlays.Element( pSide->aOverlayIds[iOverlayId] );
if ( pMapOverlay )
{
if( pMapOverlay->aFaceList.Find( iFace ) == -1 )
{
pMapOverlay->aFaceList.AddToTail( iFace );
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void OverlayTransition_AddFaceToLists( int iFace, side_t *pSide )
{
int nOverlayIdCount = pSide->aWaterOverlayIds.Count();
for( int iOverlayId = 0; iOverlayId < nOverlayIdCount; ++iOverlayId )
{
mapoverlay_t *pMapOverlay = &g_aMapWaterOverlays.Element( pSide->aWaterOverlayIds[iOverlayId] - ( MAX_MAP_OVERLAYS + 1 ) );
if ( pMapOverlay )
{
if( pMapOverlay->aFaceList.Find( iFace ) == -1 )
{
pMapOverlay->aFaceList.AddToTail( iFace );
}
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void Overlay_EmitOverlayFace( mapoverlay_t *pMapOverlay )
{
Assert( g_nOverlayCount < MAX_MAP_OVERLAYS );
if ( g_nOverlayCount >= MAX_MAP_OVERLAYS )
{
Error ( "Too Many Overlays!\nMAX_MAP_OVERLAYS = %d", MAX_MAP_OVERLAYS );
return;
}
doverlay_t *pOverlay = &g_Overlays[g_nOverlayCount];
doverlayfade_t *pOverlayFade = &g_OverlayFades[g_nOverlayCount];
g_nOverlayCount++;
// Conver the map overlay into a .bsp overlay (doverlay_t).
if ( pOverlay )
{
pOverlay->nId = pMapOverlay->nId;
pOverlay->flU[0] = pMapOverlay->flU[0];
pOverlay->flU[1] = pMapOverlay->flU[1];
pOverlay->flV[0] = pMapOverlay->flV[0];
pOverlay->flV[1] = pMapOverlay->flV[1];
VectorCopy( pMapOverlay->vecUVPoints[0], pOverlay->vecUVPoints[0] );
VectorCopy( pMapOverlay->vecUVPoints[1], pOverlay->vecUVPoints[1] );
VectorCopy( pMapOverlay->vecUVPoints[2], pOverlay->vecUVPoints[2] );
VectorCopy( pMapOverlay->vecUVPoints[3], pOverlay->vecUVPoints[3] );
VectorCopy( pMapOverlay->vecOrigin, pOverlay->vecOrigin );
VectorCopy( pMapOverlay->vecBasis[2], pOverlay->vecBasisNormal );
pOverlay->SetRenderOrder( pMapOverlay->m_nRenderOrder );
// Encode the BasisU into the unused z component of the vecUVPoints 0, 1, 2
pOverlay->vecUVPoints[0].z = pMapOverlay->vecBasis[0].x;
pOverlay->vecUVPoints[1].z = pMapOverlay->vecBasis[0].y;
pOverlay->vecUVPoints[2].z = pMapOverlay->vecBasis[0].z;
// Encode whether or not the v axis should be flipped.
Vector vecCross = pMapOverlay->vecBasis[2].Cross( pMapOverlay->vecBasis[0] );
if ( vecCross.Dot( pMapOverlay->vecBasis[1] ) < 0.0f )
{
pOverlay->vecUVPoints[3].z = 1.0f;
}
// Texinfo.
texinfo_t texInfo;
texInfo.flags = 0;
texInfo.texdata = FindOrCreateTexData( pMapOverlay->szMaterialName );
for( int iVec = 0; iVec < 2; ++iVec )
{
for( int iAxis = 0; iAxis < 3; ++iAxis )
{
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][iAxis] = 0.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][iAxis] = 0.0f;
}
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][3] = -99999.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][3] = -99999.0f;
}
pOverlay->nTexInfo = FindOrCreateTexInfo( texInfo );
// Face List
int nFaceCount = pMapOverlay->aFaceList.Count();
Assert( nFaceCount < OVERLAY_BSP_FACE_COUNT );
if ( nFaceCount >= OVERLAY_BSP_FACE_COUNT )
{
Error( "Overlay touching too many faces (touching %d, max %d)\nOverlay %s at %.1f %.1f %.1f", nFaceCount, OVERLAY_BSP_FACE_COUNT, pMapOverlay->szMaterialName, pMapOverlay->vecOrigin.x, pMapOverlay->vecOrigin.y, pMapOverlay->vecOrigin.z );
return;
}
pOverlay->SetFaceCount( nFaceCount );
for( int iFace = 0; iFace < nFaceCount; ++iFace )
{
pOverlay->aFaces[iFace] = pMapOverlay->aFaceList.Element( iFace );
}
}
// Convert the map overlay fade data into a .bsp overlay fade (doverlayfade_t).
if ( pOverlayFade )
{
pOverlayFade->flFadeDistMinSq = pMapOverlay->flFadeDistMinSq;
pOverlayFade->flFadeDistMaxSq = pMapOverlay->flFadeDistMaxSq;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void OverlayTransition_EmitOverlayFace( mapoverlay_t *pMapOverlay )
{
Assert( g_nWaterOverlayCount < MAX_MAP_WATEROVERLAYS );
if ( g_nWaterOverlayCount >= MAX_MAP_WATEROVERLAYS )
{
Error ( "Too many water overlays!\nMAX_MAP_WATEROVERLAYS = %d", MAX_MAP_WATEROVERLAYS );
return;
}
dwateroverlay_t *pOverlay = &g_WaterOverlays[g_nWaterOverlayCount];
g_nWaterOverlayCount++;
// Conver the map overlay into a .bsp overlay (doverlay_t).
if ( pOverlay )
{
pOverlay->nId = pMapOverlay->nId;
pOverlay->flU[0] = pMapOverlay->flU[0];
pOverlay->flU[1] = pMapOverlay->flU[1];
pOverlay->flV[0] = pMapOverlay->flV[0];
pOverlay->flV[1] = pMapOverlay->flV[1];
VectorCopy( pMapOverlay->vecUVPoints[0], pOverlay->vecUVPoints[0] );
VectorCopy( pMapOverlay->vecUVPoints[1], pOverlay->vecUVPoints[1] );
VectorCopy( pMapOverlay->vecUVPoints[2], pOverlay->vecUVPoints[2] );
VectorCopy( pMapOverlay->vecUVPoints[3], pOverlay->vecUVPoints[3] );
VectorCopy( pMapOverlay->vecOrigin, pOverlay->vecOrigin );
VectorCopy( pMapOverlay->vecBasis[2], pOverlay->vecBasisNormal );
pOverlay->SetRenderOrder( pMapOverlay->m_nRenderOrder );
// Encode the BasisU into the unused z component of the vecUVPoints 0, 1, 2
pOverlay->vecUVPoints[0].z = pMapOverlay->vecBasis[0].x;
pOverlay->vecUVPoints[1].z = pMapOverlay->vecBasis[0].y;
pOverlay->vecUVPoints[2].z = pMapOverlay->vecBasis[0].z;
// Encode whether or not the v axis should be flipped.
Vector vecCross = pMapOverlay->vecBasis[2].Cross( pMapOverlay->vecBasis[0] );
if ( vecCross.Dot( pMapOverlay->vecBasis[1] ) < 0.0f )
{
pOverlay->vecUVPoints[3].z = 1.0f;
}
// Texinfo.
texinfo_t texInfo;
texInfo.flags = 0;
texInfo.texdata = FindOrCreateTexData( pMapOverlay->szMaterialName );
for( int iVec = 0; iVec < 2; ++iVec )
{
for( int iAxis = 0; iAxis < 3; ++iAxis )
{
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][iAxis] = 0.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][iAxis] = 0.0f;
}
texInfo.lightmapVecsLuxelsPerWorldUnits[iVec][3] = -99999.0f;
texInfo.textureVecsTexelsPerWorldUnits[iVec][3] = -99999.0f;
}
pOverlay->nTexInfo = FindOrCreateTexInfo( texInfo );
// Face List
int nFaceCount = pMapOverlay->aFaceList.Count();
Assert( nFaceCount < WATEROVERLAY_BSP_FACE_COUNT );
if ( nFaceCount >= WATEROVERLAY_BSP_FACE_COUNT )
{
Error( "Water Overlay touching too many faces (touching %d, max %d)\nOverlay %s at %.1f %.1f %.1f", nFaceCount, OVERLAY_BSP_FACE_COUNT, pMapOverlay->szMaterialName, pMapOverlay->vecOrigin.x, pMapOverlay->vecOrigin.y, pMapOverlay->vecOrigin.z );
return;
}
pOverlay->SetFaceCount( nFaceCount );
for( int iFace = 0; iFace < nFaceCount; ++iFace )
{
pOverlay->aFaces[iFace] = pMapOverlay->aFaceList.Element( iFace );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void Overlay_EmitOverlayFaces( void )
{
int nMapOverlayCount = g_aMapOverlays.Count();
for( int iMapOverlay = 0; iMapOverlay < nMapOverlayCount; ++iMapOverlay )
{
Overlay_EmitOverlayFace( &g_aMapOverlays.Element( iMapOverlay ) );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void OverlayTransition_EmitOverlayFaces( void )
{
int nMapOverlayCount = g_aMapWaterOverlays.Count();
for( int iMapOverlay = 0; iMapOverlay < nMapOverlayCount; ++iMapOverlay )
{
OverlayTransition_EmitOverlayFace( &g_aMapWaterOverlays.Element( iMapOverlay ) );
}
}
//-----------------------------------------------------------------------------
// These routines were mostly stolen from MapOverlay.cpp in Hammer
//-----------------------------------------------------------------------------
#define OVERLAY_BASIS_U 0
#define OVERLAY_BASIS_V 1
#define OVERLAY_BASIS_NORMAL 2
#define OVERLAY_HANDLES_COUNT 4
inline void TransformPoint( const VMatrix& matrix, Vector &point )
{
Vector orgVector = point;
matrix.V3Mul( orgVector, point );
}
inline bool fequal( float value, float target, float delta) { return ( (value<(target+delta))&&(value>(target-delta)) ); }
//-----------------------------------------------------------------------------
// Purpose: this function translate / rotate an overlay.
// Input : pOverlay - the overlay to be translated
// OriginOffset - the translation
// AngleOffset - the rotation
// Matrix - the translation / rotation matrix
// Output : none
//-----------------------------------------------------------------------------
void Overlay_Translate( mapoverlay_t *pOverlay, Vector &OriginOffset, QAngle &AngleOffset, matrix3x4_t &Matrix )
{
VMatrix tmpMatrix( Matrix );
Vector temp = pOverlay->vecOrigin;
VectorTransform( temp, Matrix, pOverlay->vecOrigin );
// erase move component
tmpMatrix.SetTranslation( vec3_origin );
// check if matrix would still change something
if ( !tmpMatrix.IsIdentity() )
{
// make sure axes are normalized (they should be anyways)
pOverlay->vecBasis[OVERLAY_BASIS_U].NormalizeInPlace();
pOverlay->vecBasis[OVERLAY_BASIS_V].NormalizeInPlace();
Vector vecU = pOverlay->vecBasis[OVERLAY_BASIS_U];
Vector vecV = pOverlay->vecBasis[OVERLAY_BASIS_V];
Vector vecNormal = pOverlay->vecBasis[OVERLAY_BASIS_NORMAL];
TransformPoint( tmpMatrix, vecU );
TransformPoint( tmpMatrix, vecV );
TransformPoint( tmpMatrix, vecNormal );
float fScaleU = vecU.Length();
float fScaleV = vecV.Length();
float flScaleNormal = vecNormal.Length();
bool bIsUnit = ( fequal( fScaleU, 1.0f, 0.0001 ) && fequal( fScaleV, 1.0f, 0.0001 ) && fequal( flScaleNormal, 1.0f, 0.0001 ) );
bool bIsPerp = ( fequal( DotProduct( vecU, vecV ), 0.0f, 0.0025 ) && fequal( DotProduct( vecU, vecNormal ), 0.0f, 0.0025 ) && fequal( DotProduct( vecV, vecNormal ), 0.0f, 0.0025 ) );
// if ( fequal(fScaleU,1,0.0001) && fequal(fScaleV,1,0.0001) && fequal(DotProduct( vecU, vecV ),0,0.0025) )
if ( bIsUnit && bIsPerp )
{
// transformation doesnt scale or shear anything, so just update base axes
pOverlay->vecBasis[OVERLAY_BASIS_U] = vecU;
pOverlay->vecBasis[OVERLAY_BASIS_V] = vecV;
pOverlay->vecBasis[OVERLAY_BASIS_NORMAL] = vecNormal;
}
else
{
// more complex transformation, move UV coordinates, but leave base axes
for ( int iHandle=0; iHandle<OVERLAY_HANDLES_COUNT;iHandle++)
{
Vector vecUV = pOverlay->vecUVPoints[iHandle];
Vector vecPos = ( vecUV.x * pOverlay->vecBasis[OVERLAY_BASIS_U] + vecUV.y * pOverlay->vecBasis[OVERLAY_BASIS_V] );
// to transform in world space
TransformPoint( tmpMatrix, vecPos );
vecUV.x = pOverlay->vecBasis[OVERLAY_BASIS_U].Dot( vecPos );
vecUV.y = pOverlay->vecBasis[OVERLAY_BASIS_V].Dot( vecPos );
pOverlay->vecUVPoints[iHandle] = vecUV;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,19 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PORTALS_H
#define PORTALS_H
#ifdef _WIN32
#pragma once
#endif
// Sets up the g_ClipPortalIndices array.
void TranslateClipPortalIndices();
#endif // PORTALS_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PORTALS_H
#define PORTALS_H
#ifdef _WIN32
#pragma once
#endif
// Sets up the g_ClipPortalIndices array.
void TranslateClipPortalIndices();
#endif // PORTALS_H

View File

@@ -1,374 +1,374 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
#include "collisionutils.h"
/*
==============================================================================
PORTAL FILE GENERATION
Save out name.prt for qvis to read
==============================================================================
*/
#define PORTALFILE "PRT1"
struct cluster_portals_t
{
CUtlVector<portal_t *> portals;
};
int num_visclusters; // clusters the player can be in
int num_visportals;
int g_SkyCluster = -1;
void WriteFloat (FILE *f, vec_t v)
{
if ( fabs(v - RoundInt(v)) < 0.001 )
fprintf (f,"%i ",(int)RoundInt(v));
else
fprintf (f,"%f ",v);
}
/*
=================
WritePortalFile_r
=================
*/
void WritePortalFile(FILE *pFile, const CUtlVector<cluster_portals_t> &list)
{
portal_t *p;
winding_t *w;
Vector normal;
vec_t dist;
for ( int clusterIndex = 0; clusterIndex < list.Count(); clusterIndex++ )
{
for ( int j = 0; j < list[clusterIndex].portals.Count(); j++ )
{
p = list[clusterIndex].portals[j];
w = p->winding;
// write out to the file
// sometimes planes get turned around when they are very near
// the changeover point between different axis. interpret the
// plane the same way vis will, and flip the side orders if needed
// FIXME: is this still relevent?
WindingPlane (w, normal, &dist);
if ( DotProduct (p->plane.normal, normal) < 0.99 )
{ // backwards...
fprintf (pFile,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
}
else
{
fprintf (pFile,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
}
for (int i=0 ; i<w->numpoints ; i++)
{
fprintf (pFile,"(");
WriteFloat (pFile, w->p[i][0]);
WriteFloat (pFile, w->p[i][1]);
WriteFloat (pFile, w->p[i][2]);
fprintf (pFile,") ");
}
fprintf (pFile,"\n");
}
}
}
struct viscluster_t
{
bspbrush_t *pBrushes;
int clusterIndex;
int leafCount;
int leafStart;
};
static CUtlVector<viscluster_t> g_VisClusters;
// add to the list of brushes the merge leaves into single vis clusters
void AddVisCluster( entity_t *pFuncVisCluster )
{
viscluster_t tmp;
Vector clipMins, clipMaxs;
clipMins[0] = clipMins[1] = clipMins[2] = MIN_COORD_INTEGER;
clipMaxs[0] = clipMaxs[1] = clipMaxs[2] = MAX_COORD_INTEGER;
// build the map brushes out into the minimum non-overlapping set of brushes
bspbrush_t *pBSPBrush = MakeBspBrushList( pFuncVisCluster->firstbrush, pFuncVisCluster->firstbrush + pFuncVisCluster->numbrushes,
clipMins, clipMaxs, NO_DETAIL);
tmp.pBrushes = ChopBrushes( pBSPBrush );
// store the entry in the list
tmp.clusterIndex = -1;
tmp.leafCount = 0;
tmp.leafStart = 0;
#if DEBUG_VISUALIZE_CLUSTERS
int debug = atoi(ValueForKey(pFuncVisCluster,"debug"));
if ( debug )
{
Msg("Debug vis cluster %d\n", g_VisClusters.Count() );
}
#endif
g_VisClusters.AddToTail( tmp );
// clear out this entity so it won't get written to the bsp
pFuncVisCluster->epairs = NULL;
pFuncVisCluster->numbrushes = 0;
}
// returns the total overlapping volume of intersection between the node and the brush list
float VolumeOfIntersection( bspbrush_t *pBrushList, node_t *pNode )
{
float volume = 0.0f;
for ( bspbrush_t *pBrush = pBrushList; pBrush; pBrush = pBrush->next )
{
if ( IsBoxIntersectingBox( pNode->mins, pNode->maxs, pBrush->mins, pBrush->maxs ) )
{
bspbrush_t *pIntersect = IntersectBrush( pNode->volume, pBrush );
if ( pIntersect )
{
volume += BrushVolume( pIntersect );
FreeBrush( pIntersect );
}
}
}
return volume;
}
// Search for a forced cluster that this node is within
// NOTE: Returns the first one found, these won't merge themselves together
int GetVisCluster( node_t *pNode )
{
float maxVolume = BrushVolume(pNode->volume) * 0.10f; // needs to cover at least 10% of the volume to overlap
int maxIndex = -1;
// UNDONE: This could get slow
for ( int i = g_VisClusters.Count(); --i >= 0; )
{
float volume = VolumeOfIntersection( g_VisClusters[i].pBrushes, pNode );
if ( volume > maxVolume )
{
volume = maxVolume;
maxIndex = i;
}
}
return maxIndex;
}
/*
================
NumberLeafs_r
================
*/
void BuildVisLeafList_r (node_t *node, CUtlVector<node_t *> &leaves)
{
if (node->planenum != PLANENUM_LEAF)
{ // decision node
node->cluster = -99;
BuildVisLeafList_r (node->children[0], leaves);
BuildVisLeafList_r (node->children[1], leaves);
return;
}
if ( node->contents & CONTENTS_SOLID )
{ // solid block, viewpoint never inside
node->cluster = -1;
return;
}
leaves.AddToTail(node);
}
// Give each leaf in the list of empty leaves a vis cluster number
// some are within func_viscluster volumes and will be merged together
// every other leaf gets its own unique number
void NumberLeafs( const CUtlVector<node_t *> &leaves )
{
for ( int i = 0; i < leaves.Count(); i++ )
{
node_t *node = leaves[i];
int visCluster = GetVisCluster( node );
if ( visCluster >= 0 )
{
if ( g_VisClusters[visCluster].clusterIndex < 0 )
{
g_VisClusters[visCluster].clusterIndex = num_visclusters;
num_visclusters++;
}
g_VisClusters[visCluster].leafCount++;
node->cluster = g_VisClusters[visCluster].clusterIndex;
}
else
{
if ( !g_bSkyVis && Is3DSkyboxArea( node->area ) )
{
if ( g_SkyCluster < 0 )
{
// allocate a cluster for the sky
g_SkyCluster = num_visclusters;
num_visclusters++;
}
node->cluster = g_SkyCluster;
}
else
{
node->cluster = num_visclusters;
num_visclusters++;
}
}
}
#if DEBUG_VISUALIZE_CLUSTERS
for ( int i = 0; i < g_VisClusters.Count(); i++ )
{
char name[256];
sprintf(name, "u:\\main\\game\\ep2\\maps\\vis_%02d.gl", i );
FileHandle_t fp = g_pFileSystem->Open( name, "w" );
Msg("Writing %s\n", name );
for ( bspbrush_t *pBrush = g_VisClusters[i].pBrushes; pBrush; pBrush = pBrush->next )
{
for (int i = 0; i < pBrush->numsides; i++ )
OutputWindingColor( pBrush->sides[i].winding, fp, 0, 255, 0 );
}
for ( int j = 0; j < leaves.Count(); j++ )
{
if ( leaves[j]->cluster == g_VisClusters[i].clusterIndex )
{
bspbrush_t *pBrush = leaves[j]->volume;
for (int k = 0; k < pBrush->numsides; k++ )
OutputWindingColor( pBrush->sides[k].winding, fp, 64 + (j&31), 64, 64 - (j&31) );
}
}
g_pFileSystem->Close(fp);
}
#endif
}
// build a list of all vis portals that connect clusters
int BuildPortalList( CUtlVector<cluster_portals_t> &portalList, const CUtlVector<node_t *> &leaves )
{
int portalCount = 0;
for ( int i = 0; i < leaves.Count(); i++ )
{
node_t *node = leaves[i];
// count the portals
for (portal_t *p = node->portals ; p ; )
{
if (p->nodes[0] == node) // only write out from first leaf
{
if ( p->nodes[0]->cluster != p->nodes[1]->cluster )
{
if (Portal_VisFlood (p))
{
portalCount++;
portalList[node->cluster].portals.AddToTail(p);
}
}
p = p->next[0];
}
else
p = p->next[1];
}
}
return portalCount;
}
/*
================
CreateVisPortals_r
================
*/
void CreateVisPortals_r (node_t *node)
{
// stop as soon as we get to a leaf
if (node->planenum == PLANENUM_LEAF )
return;
MakeNodePortal (node);
SplitNodePortals (node);
CreateVisPortals_r (node->children[0]);
CreateVisPortals_r (node->children[1]);
}
int clusterleaf;
void SaveClusters_r (node_t *node)
{
if (node->planenum == PLANENUM_LEAF)
{
dleafs[clusterleaf++].cluster = node->cluster;
return;
}
SaveClusters_r (node->children[0]);
SaveClusters_r (node->children[1]);
}
/*
================
WritePortalFile
================
*/
void WritePortalFile (tree_t *tree)
{
char filename[1024];
node_t *headnode;
int start = Plat_FloatTime();
qprintf ("--- WritePortalFile ---\n");
sprintf (filename, "%s.prt", source);
Msg ("writing %s...", filename);
headnode = tree->headnode;
FreeTreePortals_r (headnode);
MakeHeadnodePortals (tree);
CreateVisPortals_r (headnode);
// set the cluster field in every leaf and count the total number of portals
num_visclusters = 0;
Msg("Building visibility clusters...\n");
CUtlVector<node_t *> leaves;
BuildVisLeafList_r( headnode, leaves );
NumberLeafs (leaves);
CUtlVector<cluster_portals_t> portalList;
portalList.SetCount( num_visclusters );
num_visportals = BuildPortalList( portalList, leaves );
// write the file
FILE *pf = fopen (filename, "w");
if (!pf)
Error ("Error opening %s", filename);
fprintf (pf, "%s\n", PORTALFILE);
fprintf (pf, "%i\n", num_visclusters);
fprintf (pf, "%i\n", num_visportals);
qprintf ("%5i visclusters\n", num_visclusters);
qprintf ("%5i visportals\n", num_visportals);
WritePortalFile(pf, portalList);
fclose (pf);
// we need to store the clusters out now because ordering
// issues made us do this after writebsp...
clusterleaf = 1;
SaveClusters_r (headnode);
Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
#include "collisionutils.h"
/*
==============================================================================
PORTAL FILE GENERATION
Save out name.prt for qvis to read
==============================================================================
*/
#define PORTALFILE "PRT1"
struct cluster_portals_t
{
CUtlVector<portal_t *> portals;
};
int num_visclusters; // clusters the player can be in
int num_visportals;
int g_SkyCluster = -1;
void WriteFloat (FILE *f, vec_t v)
{
if ( fabs(v - RoundInt(v)) < 0.001 )
fprintf (f,"%i ",(int)RoundInt(v));
else
fprintf (f,"%f ",v);
}
/*
=================
WritePortalFile_r
=================
*/
void WritePortalFile(FILE *pFile, const CUtlVector<cluster_portals_t> &list)
{
portal_t *p;
winding_t *w;
Vector normal;
vec_t dist;
for ( int clusterIndex = 0; clusterIndex < list.Count(); clusterIndex++ )
{
for ( int j = 0; j < list[clusterIndex].portals.Count(); j++ )
{
p = list[clusterIndex].portals[j];
w = p->winding;
// write out to the file
// sometimes planes get turned around when they are very near
// the changeover point between different axis. interpret the
// plane the same way vis will, and flip the side orders if needed
// FIXME: is this still relevent?
WindingPlane (w, normal, &dist);
if ( DotProduct (p->plane.normal, normal) < 0.99 )
{ // backwards...
fprintf (pFile,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
}
else
{
fprintf (pFile,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
}
for (int i=0 ; i<w->numpoints ; i++)
{
fprintf (pFile,"(");
WriteFloat (pFile, w->p[i][0]);
WriteFloat (pFile, w->p[i][1]);
WriteFloat (pFile, w->p[i][2]);
fprintf (pFile,") ");
}
fprintf (pFile,"\n");
}
}
}
struct viscluster_t
{
bspbrush_t *pBrushes;
int clusterIndex;
int leafCount;
int leafStart;
};
static CUtlVector<viscluster_t> g_VisClusters;
// add to the list of brushes the merge leaves into single vis clusters
void AddVisCluster( entity_t *pFuncVisCluster )
{
viscluster_t tmp;
Vector clipMins, clipMaxs;
clipMins[0] = clipMins[1] = clipMins[2] = MIN_COORD_INTEGER;
clipMaxs[0] = clipMaxs[1] = clipMaxs[2] = MAX_COORD_INTEGER;
// build the map brushes out into the minimum non-overlapping set of brushes
bspbrush_t *pBSPBrush = MakeBspBrushList( pFuncVisCluster->firstbrush, pFuncVisCluster->firstbrush + pFuncVisCluster->numbrushes,
clipMins, clipMaxs, NO_DETAIL);
tmp.pBrushes = ChopBrushes( pBSPBrush );
// store the entry in the list
tmp.clusterIndex = -1;
tmp.leafCount = 0;
tmp.leafStart = 0;
#if DEBUG_VISUALIZE_CLUSTERS
int debug = atoi(ValueForKey(pFuncVisCluster,"debug"));
if ( debug )
{
Msg("Debug vis cluster %d\n", g_VisClusters.Count() );
}
#endif
g_VisClusters.AddToTail( tmp );
// clear out this entity so it won't get written to the bsp
pFuncVisCluster->epairs = NULL;
pFuncVisCluster->numbrushes = 0;
}
// returns the total overlapping volume of intersection between the node and the brush list
float VolumeOfIntersection( bspbrush_t *pBrushList, node_t *pNode )
{
float volume = 0.0f;
for ( bspbrush_t *pBrush = pBrushList; pBrush; pBrush = pBrush->next )
{
if ( IsBoxIntersectingBox( pNode->mins, pNode->maxs, pBrush->mins, pBrush->maxs ) )
{
bspbrush_t *pIntersect = IntersectBrush( pNode->volume, pBrush );
if ( pIntersect )
{
volume += BrushVolume( pIntersect );
FreeBrush( pIntersect );
}
}
}
return volume;
}
// Search for a forced cluster that this node is within
// NOTE: Returns the first one found, these won't merge themselves together
int GetVisCluster( node_t *pNode )
{
float maxVolume = BrushVolume(pNode->volume) * 0.10f; // needs to cover at least 10% of the volume to overlap
int maxIndex = -1;
// UNDONE: This could get slow
for ( int i = g_VisClusters.Count(); --i >= 0; )
{
float volume = VolumeOfIntersection( g_VisClusters[i].pBrushes, pNode );
if ( volume > maxVolume )
{
volume = maxVolume;
maxIndex = i;
}
}
return maxIndex;
}
/*
================
NumberLeafs_r
================
*/
void BuildVisLeafList_r (node_t *node, CUtlVector<node_t *> &leaves)
{
if (node->planenum != PLANENUM_LEAF)
{ // decision node
node->cluster = -99;
BuildVisLeafList_r (node->children[0], leaves);
BuildVisLeafList_r (node->children[1], leaves);
return;
}
if ( node->contents & CONTENTS_SOLID )
{ // solid block, viewpoint never inside
node->cluster = -1;
return;
}
leaves.AddToTail(node);
}
// Give each leaf in the list of empty leaves a vis cluster number
// some are within func_viscluster volumes and will be merged together
// every other leaf gets its own unique number
void NumberLeafs( const CUtlVector<node_t *> &leaves )
{
for ( int i = 0; i < leaves.Count(); i++ )
{
node_t *node = leaves[i];
int visCluster = GetVisCluster( node );
if ( visCluster >= 0 )
{
if ( g_VisClusters[visCluster].clusterIndex < 0 )
{
g_VisClusters[visCluster].clusterIndex = num_visclusters;
num_visclusters++;
}
g_VisClusters[visCluster].leafCount++;
node->cluster = g_VisClusters[visCluster].clusterIndex;
}
else
{
if ( !g_bSkyVis && Is3DSkyboxArea( node->area ) )
{
if ( g_SkyCluster < 0 )
{
// allocate a cluster for the sky
g_SkyCluster = num_visclusters;
num_visclusters++;
}
node->cluster = g_SkyCluster;
}
else
{
node->cluster = num_visclusters;
num_visclusters++;
}
}
}
#if DEBUG_VISUALIZE_CLUSTERS
for ( int i = 0; i < g_VisClusters.Count(); i++ )
{
char name[256];
sprintf(name, "u:\\main\\game\\ep2\\maps\\vis_%02d.gl", i );
FileHandle_t fp = g_pFileSystem->Open( name, "w" );
Msg("Writing %s\n", name );
for ( bspbrush_t *pBrush = g_VisClusters[i].pBrushes; pBrush; pBrush = pBrush->next )
{
for (int i = 0; i < pBrush->numsides; i++ )
OutputWindingColor( pBrush->sides[i].winding, fp, 0, 255, 0 );
}
for ( int j = 0; j < leaves.Count(); j++ )
{
if ( leaves[j]->cluster == g_VisClusters[i].clusterIndex )
{
bspbrush_t *pBrush = leaves[j]->volume;
for (int k = 0; k < pBrush->numsides; k++ )
OutputWindingColor( pBrush->sides[k].winding, fp, 64 + (j&31), 64, 64 - (j&31) );
}
}
g_pFileSystem->Close(fp);
}
#endif
}
// build a list of all vis portals that connect clusters
int BuildPortalList( CUtlVector<cluster_portals_t> &portalList, const CUtlVector<node_t *> &leaves )
{
int portalCount = 0;
for ( int i = 0; i < leaves.Count(); i++ )
{
node_t *node = leaves[i];
// count the portals
for (portal_t *p = node->portals ; p ; )
{
if (p->nodes[0] == node) // only write out from first leaf
{
if ( p->nodes[0]->cluster != p->nodes[1]->cluster )
{
if (Portal_VisFlood (p))
{
portalCount++;
portalList[node->cluster].portals.AddToTail(p);
}
}
p = p->next[0];
}
else
p = p->next[1];
}
}
return portalCount;
}
/*
================
CreateVisPortals_r
================
*/
void CreateVisPortals_r (node_t *node)
{
// stop as soon as we get to a leaf
if (node->planenum == PLANENUM_LEAF )
return;
MakeNodePortal (node);
SplitNodePortals (node);
CreateVisPortals_r (node->children[0]);
CreateVisPortals_r (node->children[1]);
}
int clusterleaf;
void SaveClusters_r (node_t *node)
{
if (node->planenum == PLANENUM_LEAF)
{
dleafs[clusterleaf++].cluster = node->cluster;
return;
}
SaveClusters_r (node->children[0]);
SaveClusters_r (node->children[1]);
}
/*
================
WritePortalFile
================
*/
void WritePortalFile (tree_t *tree)
{
char filename[1024];
node_t *headnode;
int start = Plat_FloatTime();
qprintf ("--- WritePortalFile ---\n");
sprintf (filename, "%s.prt", source);
Msg ("writing %s...", filename);
headnode = tree->headnode;
FreeTreePortals_r (headnode);
MakeHeadnodePortals (tree);
CreateVisPortals_r (headnode);
// set the cluster field in every leaf and count the total number of portals
num_visclusters = 0;
Msg("Building visibility clusters...\n");
CUtlVector<node_t *> leaves;
BuildVisLeafList_r( headnode, leaves );
NumberLeafs (leaves);
CUtlVector<cluster_portals_t> portalList;
portalList.SetCount( num_visclusters );
num_visportals = BuildPortalList( portalList, leaves );
// write the file
FILE *pf = fopen (filename, "w");
if (!pf)
Error ("Error opening %s", filename);
fprintf (pf, "%s\n", PORTALFILE);
fprintf (pf, "%i\n", num_visclusters);
fprintf (pf, "%i\n", num_visportals);
qprintf ("%5i visclusters\n", num_visclusters);
qprintf ("%5i visportals\n", num_visportals);
WritePortalFile(pf, portalList);
fclose (pf);
// we need to store the clusters out now because ordering
// issues made us do this after writebsp...
clusterleaf = 1;
SaveClusters_r (headnode);
Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,207 +1,207 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
extern int c_nodes;
void RemovePortalFromNode (portal_t *portal, node_t *l);
node_t *NodeForPoint (node_t *node, Vector& origin)
{
plane_t *plane;
vec_t d;
while (node->planenum != PLANENUM_LEAF)
{
plane = &g_MainMap->mapplanes[node->planenum];
d = DotProduct (origin, plane->normal) - plane->dist;
if (d >= 0)
node = node->children[0];
else
node = node->children[1];
}
return node;
}
/*
=============
FreeTreePortals_r
=============
*/
void FreeTreePortals_r (node_t *node)
{
portal_t *p, *nextp;
int s;
// free children
if (node->planenum != PLANENUM_LEAF)
{
FreeTreePortals_r (node->children[0]);
FreeTreePortals_r (node->children[1]);
}
// free portals
for (p=node->portals ; p ; p=nextp)
{
s = (p->nodes[1] == node);
nextp = p->next[s];
RemovePortalFromNode (p, p->nodes[!s]);
FreePortal (p);
}
node->portals = NULL;
}
/*
=============
FreeTree_r
=============
*/
void FreeTree_r (node_t *node)
{
face_t *f, *nextf;
// free children
if (node->planenum != PLANENUM_LEAF)
{
FreeTree_r (node->children[0]);
FreeTree_r (node->children[1]);
}
// free bspbrushes
FreeBrushList (node->brushlist);
// free faces
for (f=node->faces ; f ; f=nextf)
{
nextf = f->next;
FreeFace (f);
}
// free the node
if (node->volume)
FreeBrush (node->volume);
if (numthreads == 1)
c_nodes--;
free (node);
}
/*
=============
FreeTree
=============
*/
void FreeTree (tree_t *tree)
{
if ( !tree )
return;
FreeTreePortals_r (tree->headnode);
FreeTree_r (tree->headnode);
free (tree);
}
//===============================================================
void PrintTree_r (node_t *node, int depth)
{
int i;
plane_t *plane;
bspbrush_t *bb;
for (i=0 ; i<depth ; i++)
Msg (" ");
if (node->planenum == PLANENUM_LEAF)
{
if (!node->brushlist)
Msg ("NULL\n");
else
{
for (bb=node->brushlist ; bb ; bb=bb->next)
Msg ("%i ", bb->original->brushnum);
Msg ("\n");
}
return;
}
plane = &g_MainMap->mapplanes[node->planenum];
Msg ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
plane->normal[0], plane->normal[1], plane->normal[2],
plane->dist);
PrintTree_r (node->children[0], depth+1);
PrintTree_r (node->children[1], depth+1);
}
/*
=========================================================
NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED
=========================================================
*/
int c_pruned;
/*
============
PruneNodes_r
============
*/
void PruneNodes_r (node_t *node)
{
bspbrush_t *b, *next;
if (node->planenum == PLANENUM_LEAF)
return;
PruneNodes_r (node->children[0]);
PruneNodes_r (node->children[1]);
if ( (node->children[0]->contents & CONTENTS_SOLID)
&& (node->children[1]->contents & CONTENTS_SOLID) )
{
if (node->faces)
Error ("node->faces seperating CONTENTS_SOLID");
if (node->children[0]->faces || node->children[1]->faces)
Error ("!node->faces with children");
// FIXME: free stuff
node->planenum = PLANENUM_LEAF;
node->contents = CONTENTS_SOLID;
if (node->brushlist)
Error ("PruneNodes: node->brushlist");
// combine brush lists
node->brushlist = node->children[1]->brushlist;
for (b=node->children[0]->brushlist ; b ; b=next)
{
next = b->next;
b->next = node->brushlist;
node->brushlist = b;
}
c_pruned++;
}
}
void PruneNodes (node_t *node)
{
qprintf ("--- PruneNodes ---\n");
c_pruned = 0;
PruneNodes_r (node);
qprintf ("%5i pruned nodes\n", c_pruned);
}
//===========================================================
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "vbsp.h"
extern int c_nodes;
void RemovePortalFromNode (portal_t *portal, node_t *l);
node_t *NodeForPoint (node_t *node, Vector& origin)
{
plane_t *plane;
vec_t d;
while (node->planenum != PLANENUM_LEAF)
{
plane = &g_MainMap->mapplanes[node->planenum];
d = DotProduct (origin, plane->normal) - plane->dist;
if (d >= 0)
node = node->children[0];
else
node = node->children[1];
}
return node;
}
/*
=============
FreeTreePortals_r
=============
*/
void FreeTreePortals_r (node_t *node)
{
portal_t *p, *nextp;
int s;
// free children
if (node->planenum != PLANENUM_LEAF)
{
FreeTreePortals_r (node->children[0]);
FreeTreePortals_r (node->children[1]);
}
// free portals
for (p=node->portals ; p ; p=nextp)
{
s = (p->nodes[1] == node);
nextp = p->next[s];
RemovePortalFromNode (p, p->nodes[!s]);
FreePortal (p);
}
node->portals = NULL;
}
/*
=============
FreeTree_r
=============
*/
void FreeTree_r (node_t *node)
{
face_t *f, *nextf;
// free children
if (node->planenum != PLANENUM_LEAF)
{
FreeTree_r (node->children[0]);
FreeTree_r (node->children[1]);
}
// free bspbrushes
FreeBrushList (node->brushlist);
// free faces
for (f=node->faces ; f ; f=nextf)
{
nextf = f->next;
FreeFace (f);
}
// free the node
if (node->volume)
FreeBrush (node->volume);
if (numthreads == 1)
c_nodes--;
free (node);
}
/*
=============
FreeTree
=============
*/
void FreeTree (tree_t *tree)
{
if ( !tree )
return;
FreeTreePortals_r (tree->headnode);
FreeTree_r (tree->headnode);
free (tree);
}
//===============================================================
void PrintTree_r (node_t *node, int depth)
{
int i;
plane_t *plane;
bspbrush_t *bb;
for (i=0 ; i<depth ; i++)
Msg (" ");
if (node->planenum == PLANENUM_LEAF)
{
if (!node->brushlist)
Msg ("NULL\n");
else
{
for (bb=node->brushlist ; bb ; bb=bb->next)
Msg ("%i ", bb->original->brushnum);
Msg ("\n");
}
return;
}
plane = &g_MainMap->mapplanes[node->planenum];
Msg ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
plane->normal[0], plane->normal[1], plane->normal[2],
plane->dist);
PrintTree_r (node->children[0], depth+1);
PrintTree_r (node->children[1], depth+1);
}
/*
=========================================================
NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED
=========================================================
*/
int c_pruned;
/*
============
PruneNodes_r
============
*/
void PruneNodes_r (node_t *node)
{
bspbrush_t *b, *next;
if (node->planenum == PLANENUM_LEAF)
return;
PruneNodes_r (node->children[0]);
PruneNodes_r (node->children[1]);
if ( (node->children[0]->contents & CONTENTS_SOLID)
&& (node->children[1]->contents & CONTENTS_SOLID) )
{
if (node->faces)
Error ("node->faces seperating CONTENTS_SOLID");
if (node->children[0]->faces || node->children[1]->faces)
Error ("!node->faces with children");
// FIXME: free stuff
node->planenum = PLANENUM_LEAF;
node->contents = CONTENTS_SOLID;
if (node->brushlist)
Error ("PruneNodes: node->brushlist");
// combine brush lists
node->brushlist = node->children[1]->brushlist;
for (b=node->children[0]->brushlist ; b ; b=next)
{
next = b->next;
b->next = node->brushlist;
node->brushlist = b;
}
c_pruned++;
}
}
void PruneNodes (node_t *node)
{
qprintf ("--- PruneNodes ---\n");
c_pruned = 0;
PruneNodes_r (node);
qprintf ("%5i pruned nodes\n", c_pruned);
}
//===========================================================

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,184 +1,184 @@
//-----------------------------------------------------------------------------
// VBSP.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR "..\.."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE,..\common,..\vmpi"
$PreprocessorDefinitions "$BASE;MACRO_MATHLIB;PROTECTED_THINGS_DISABLE"
}
$Linker
{
$AdditionalDependencies "$BASE ws2_32.lib odbc32.lib odbccp32.lib winmm.lib"
}
}
$Project "Vbsp"
{
$Folder "Source Files"
{
$File "boundbox.cpp"
$File "brushbsp.cpp"
$File "$SRCDIR\public\CollisionUtils.cpp"
$File "csg.cpp"
$File "cubemap.cpp"
$File "detail.cpp"
$File "detailObjects.cpp"
$File "$SRCDIR\public\disp_common.cpp"
$File "disp_ivp.cpp"
$File "$SRCDIR\public\disp_powerinfo.cpp"
$File "disp_vbsp.cpp"
$File "faces.cpp"
$File "glfile.cpp"
$File "ivp.cpp"
$File "leakfile.cpp"
$File "$SRCDIR\public\loadcmdline.cpp"
$File "$SRCDIR\public\lumpfiles.cpp"
$File "map.cpp"
$File "manifest.cpp"
$File "materialpatch.cpp"
$File "materialsub.cpp"
$File "..\common\mstristrip.cpp"
$File "nodraw.cpp"
$File "normals.cpp"
$File "overlay.cpp"
$File "..\common\physdll.cpp"
$File "portals.cpp"
$File "prtfile.cpp"
$File "$SRCDIR\public\ScratchPad3D.cpp"
$File "..\common\scratchpad_helpers.cpp"
$File "StaticProp.cpp"
$File "textures.cpp"
$File "tree.cpp"
$File "..\common\utilmatlib.cpp"
$File "vbsp.cpp"
$File "worldvertextransitionfixup.cpp"
$File "writebsp.cpp"
$File "$SRCDIR\public\zip_utils.cpp"
$Folder "Common Files"
{
$File "..\common\bsplib.cpp"
$File "$SRCDIR\public\builddisp.cpp"
$File "$SRCDIR\public\ChunkFile.cpp"
$File "..\common\cmdlib.cpp"
$File "$SRCDIR\public\filesystem_helpers.cpp"
$File "$SRCDIR\public\filesystem_init.cpp"
$File "..\common\filesystem_tools.cpp"
$File "..\common\map_shared.cpp"
$File "..\common\pacifier.cpp"
$File "..\common\polylib.cpp"
$File "..\common\scriplib.cpp"
$File "..\common\threads.cpp"
$File "..\common\tools_minidump.cpp"
$File "..\common\tools_minidump.h"
}
}
$Folder "Header Files"
{
$File "boundbox.h"
$File "csg.h"
$File "detail.h"
$File "$SRCDIR\public\disp_powerinfo.h"
$File "disp_vbsp.h"
$File "$SRCDIR\public\disp_vertindex.h"
$File "faces.h"
$File "map.h"
$File "manifest.h"
$File "materialpatch.h"
$File "materialsub.h"
$File "..\common\scratchpad_helpers.h"
$File "vbsp.h"
$File "worldvertextransitionfixup.h"
$File "writebsp.h"
$Folder "Common header files"
{
$File "..\common\bsplib.h"
$File "$SRCDIR\public\builddisp.h"
$File "$SRCDIR\public\ChunkFile.h"
$File "..\common\cmdlib.h"
$File "disp_ivp.h"
$File "$SRCDIR\public\filesystem.h"
$File "$SRCDIR\public\filesystem_helpers.h"
$File "..\common\FileSystem_Tools.h"
$File "$SRCDIR\public\GameBSPFile.h"
$File "$SRCDIR\public\tier1\interface.h"
$File "ivp.h"
$File "..\common\map_shared.h"
$File "..\common\pacifier.h"
$File "..\common\polylib.h"
$File "$SRCDIR\public\tier1\tokenreader.h"
$File "..\common\utilmatlib.h"
$File "..\vmpi\vmpi.h"
$File "$SRCDIR\public\zip_uncompressed.h"
}
}
$Folder "Public Headers"
{
$File "$SRCDIR\public\mathlib\amd3dx.h"
$File "$SRCDIR\public\arraystack.h"
$File "$SRCDIR\public\tier0\basetypes.h"
$File "$SRCDIR\public\BSPFILE.H"
$File "$SRCDIR\public\bspflags.h"
$File "$SRCDIR\public\BSPTreeData.h"
$File "$SRCDIR\public\mathlib\bumpvects.h"
$File "$SRCDIR\public\tier1\byteswap.h"
$File "$SRCDIR\public\cmodel.h"
$File "$SRCDIR\public\CollisionUtils.h"
$File "$SRCDIR\public\tier0\commonmacros.h"
$File "$SRCDIR\public\tier0\dbg.h"
$File "$SRCDIR\public\disp_common.h"
$File "$SRCDIR\public\IScratchPad3D.h"
$File "$SRCDIR\public\mathlib\mathlib.h"
$File "..\common\mstristrip.h"
$File "$SRCDIR\public\nmatrix.h"
$File "$SRCDIR\public\NTree.h"
$File "$SRCDIR\public\nvector.h"
$File "$SRCDIR\public\phyfile.h"
$File "..\common\physdll.h"
$File "..\common\qfiles.h"
$File "$SRCDIR\public\ScratchPad3D.h"
$File "..\common\scriplib.h"
$File "$SRCDIR\public\studio.h"
$File "..\common\threads.h"
$File "$SRCDIR\public\tier1\utlbuffer.h"
$File "$SRCDIR\public\tier1\utllinkedlist.h"
$File "$SRCDIR\public\tier1\utlmemory.h"
$File "$SRCDIR\public\tier1\utlrbtree.h"
$File "$SRCDIR\public\tier1\utlsymbol.h"
$File "$SRCDIR\public\tier1\utlvector.h"
$File "$SRCDIR\public\vcollide.h"
$File "$SRCDIR\public\mathlib\vector.h"
$File "$SRCDIR\public\mathlib\vector2d.h"
$File "$SRCDIR\public\mathlib\vector4d.h"
$File "$SRCDIR\public\mathlib\vmatrix.h"
$File "$SRCDIR\public\vphysics_interface.h"
$File "$SRCDIR\public\mathlib\vplane.h"
$File "$SRCDIR\public\wadtypes.h"
$File "$SRCDIR\public\worldsize.h"
}
$Folder "Link Libraries"
{
$Lib bitmap
$Lib fgdlib
$Lib mathlib
$Lib tier2
$Lib vtf
}
$File "notes.txt"
}
//-----------------------------------------------------------------------------
// VBSP.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR "..\.."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE,..\common,..\vmpi"
$PreprocessorDefinitions "$BASE;MACRO_MATHLIB;PROTECTED_THINGS_DISABLE"
}
$Linker
{
$AdditionalDependencies "$BASE ws2_32.lib odbc32.lib odbccp32.lib winmm.lib"
}
}
$Project "Vbsp"
{
$Folder "Source Files"
{
$File "boundbox.cpp"
$File "brushbsp.cpp"
$File "$SRCDIR\public\CollisionUtils.cpp"
$File "csg.cpp"
$File "cubemap.cpp"
$File "detail.cpp"
$File "detailObjects.cpp"
$File "$SRCDIR\public\disp_common.cpp"
$File "disp_ivp.cpp"
$File "$SRCDIR\public\disp_powerinfo.cpp"
$File "disp_vbsp.cpp"
$File "faces.cpp"
$File "glfile.cpp"
$File "ivp.cpp"
$File "leakfile.cpp"
$File "$SRCDIR\public\loadcmdline.cpp"
$File "$SRCDIR\public\lumpfiles.cpp"
$File "map.cpp"
$File "manifest.cpp"
$File "materialpatch.cpp"
$File "materialsub.cpp"
$File "..\common\mstristrip.cpp"
$File "nodraw.cpp"
$File "normals.cpp"
$File "overlay.cpp"
$File "..\common\physdll.cpp"
$File "portals.cpp"
$File "prtfile.cpp"
$File "$SRCDIR\public\ScratchPad3D.cpp"
$File "..\common\scratchpad_helpers.cpp"
$File "StaticProp.cpp"
$File "textures.cpp"
$File "tree.cpp"
$File "..\common\utilmatlib.cpp"
$File "vbsp.cpp"
$File "worldvertextransitionfixup.cpp"
$File "writebsp.cpp"
$File "$SRCDIR\public\zip_utils.cpp"
$Folder "Common Files"
{
$File "..\common\bsplib.cpp"
$File "$SRCDIR\public\builddisp.cpp"
$File "$SRCDIR\public\ChunkFile.cpp"
$File "..\common\cmdlib.cpp"
$File "$SRCDIR\public\filesystem_helpers.cpp"
$File "$SRCDIR\public\filesystem_init.cpp"
$File "..\common\filesystem_tools.cpp"
$File "..\common\map_shared.cpp"
$File "..\common\pacifier.cpp"
$File "..\common\polylib.cpp"
$File "..\common\scriplib.cpp"
$File "..\common\threads.cpp"
$File "..\common\tools_minidump.cpp"
$File "..\common\tools_minidump.h"
}
}
$Folder "Header Files"
{
$File "boundbox.h"
$File "csg.h"
$File "detail.h"
$File "$SRCDIR\public\disp_powerinfo.h"
$File "disp_vbsp.h"
$File "$SRCDIR\public\disp_vertindex.h"
$File "faces.h"
$File "map.h"
$File "manifest.h"
$File "materialpatch.h"
$File "materialsub.h"
$File "..\common\scratchpad_helpers.h"
$File "vbsp.h"
$File "worldvertextransitionfixup.h"
$File "writebsp.h"
$Folder "Common header files"
{
$File "..\common\bsplib.h"
$File "$SRCDIR\public\builddisp.h"
$File "$SRCDIR\public\ChunkFile.h"
$File "..\common\cmdlib.h"
$File "disp_ivp.h"
$File "$SRCDIR\public\filesystem.h"
$File "$SRCDIR\public\filesystem_helpers.h"
$File "..\common\FileSystem_Tools.h"
$File "$SRCDIR\public\GameBSPFile.h"
$File "$SRCDIR\public\tier1\interface.h"
$File "ivp.h"
$File "..\common\map_shared.h"
$File "..\common\pacifier.h"
$File "..\common\polylib.h"
$File "$SRCDIR\public\tier1\tokenreader.h"
$File "..\common\utilmatlib.h"
$File "..\vmpi\vmpi.h"
$File "$SRCDIR\public\zip_uncompressed.h"
}
}
$Folder "Public Headers"
{
$File "$SRCDIR\public\mathlib\amd3dx.h"
$File "$SRCDIR\public\arraystack.h"
$File "$SRCDIR\public\tier0\basetypes.h"
$File "$SRCDIR\public\BSPFILE.H"
$File "$SRCDIR\public\bspflags.h"
$File "$SRCDIR\public\BSPTreeData.h"
$File "$SRCDIR\public\mathlib\bumpvects.h"
$File "$SRCDIR\public\tier1\byteswap.h"
$File "$SRCDIR\public\cmodel.h"
$File "$SRCDIR\public\CollisionUtils.h"
$File "$SRCDIR\public\tier0\commonmacros.h"
$File "$SRCDIR\public\tier0\dbg.h"
$File "$SRCDIR\public\disp_common.h"
$File "$SRCDIR\public\IScratchPad3D.h"
$File "$SRCDIR\public\mathlib\mathlib.h"
$File "..\common\mstristrip.h"
$File "$SRCDIR\public\nmatrix.h"
$File "$SRCDIR\public\NTree.h"
$File "$SRCDIR\public\nvector.h"
$File "$SRCDIR\public\phyfile.h"
$File "..\common\physdll.h"
$File "..\common\qfiles.h"
$File "$SRCDIR\public\ScratchPad3D.h"
$File "..\common\scriplib.h"
$File "$SRCDIR\public\studio.h"
$File "..\common\threads.h"
$File "$SRCDIR\public\tier1\utlbuffer.h"
$File "$SRCDIR\public\tier1\utllinkedlist.h"
$File "$SRCDIR\public\tier1\utlmemory.h"
$File "$SRCDIR\public\tier1\utlrbtree.h"
$File "$SRCDIR\public\tier1\utlsymbol.h"
$File "$SRCDIR\public\tier1\utlvector.h"
$File "$SRCDIR\public\vcollide.h"
$File "$SRCDIR\public\mathlib\vector.h"
$File "$SRCDIR\public\mathlib\vector2d.h"
$File "$SRCDIR\public\mathlib\vector4d.h"
$File "$SRCDIR\public\mathlib\vmatrix.h"
$File "$SRCDIR\public\vphysics_interface.h"
$File "$SRCDIR\public\mathlib\vplane.h"
$File "$SRCDIR\public\wadtypes.h"
$File "$SRCDIR\public\worldsize.h"
}
$Folder "Link Libraries"
{
$Lib bitmap
$Lib fgdlib
$Lib mathlib
$Lib tier2
$Lib vtf
}
$File "notes.txt"
}

View File

@@ -1,212 +1,212 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "bsplib.h"
#include "vbsp.h"
#include "tier1/UtlBuffer.h"
#include "tier1/utlvector.h"
#include "KeyValues.h"
#include "materialpatch.h"
struct entitySideList_t
{
int firstBrushSide;
int brushSideCount;
};
static bool SideIsNotDispAndHasDispMaterial( int iSide )
{
side_t *pSide = &g_MainMap->brushsides[iSide];
// If it's a displacement, then it's fine to have a displacement-only material.
if ( pSide->pMapDisp )
{
return false;
}
pSide->texinfo;
return true;
}
static void BackSlashToForwardSlash( char *pname )
{
while ( *pname ) {
if ( *pname == '\\' )
*pname = '/';
pname++;
}
}
//-----------------------------------------------------------------------------
// Generate patched material name
//-----------------------------------------------------------------------------
static void GeneratePatchedMaterialName( const char *pMaterialName, char *pBuffer, int nMaxLen )
{
int nLen = Q_snprintf( pBuffer, nMaxLen, "maps/%s/%s_wvt_patch", mapbase, pMaterialName );
Assert( nLen < TEXTURE_NAME_LENGTH - 1 );
if ( nLen >= TEXTURE_NAME_LENGTH - 1 )
{
Error( "Generated worldvertextransition patch name : %s too long! (max = %d)\n", pBuffer, TEXTURE_NAME_LENGTH );
}
BackSlashToForwardSlash( pBuffer );
Q_strlower( pBuffer );
}
static void RemoveKey( KeyValues *kv, const char *pSubKeyName )
{
KeyValues *pSubKey = kv->FindKey( pSubKeyName );
if( pSubKey )
{
kv->RemoveSubKey( pSubKey );
pSubKey->deleteThis();
}
}
void CreateWorldVertexTransitionPatchedMaterial( const char *pOriginalMaterialName, const char *pPatchedMaterialName )
{
KeyValues *kv = LoadMaterialKeyValues( pOriginalMaterialName, 0 );
if( kv )
{
// change shader to Lightmappedgeneric (from worldvertextransition*)
kv->SetName( "LightmappedGeneric" );
// don't need no stinking $basetexture2 or any other second texture vars
RemoveKey( kv, "$basetexture2" );
RemoveKey( kv, "$bumpmap2" );
RemoveKey( kv, "$bumpframe2" );
RemoveKey( kv, "$basetexture2noenvmap" );
RemoveKey( kv, "$blendmodulatetexture" );
RemoveKey( kv, "$maskedblending" );
RemoveKey( kv, "$surfaceprop2" );
// If we didn't want a basetexture on the first texture in the blend, we don't want an envmap at all.
KeyValues *basetexturenoenvmap = kv->FindKey( "$BASETEXTURENOENVMAP" );
if( basetexturenoenvmap->GetInt() )
{
RemoveKey( kv, "$envmap" );
}
Warning( "Patching WVT material: %s\n", pPatchedMaterialName );
WriteMaterialKeyValuesToPak( pPatchedMaterialName, kv );
}
}
int CreateBrushVersionOfWorldVertexTransitionMaterial( int originalTexInfo )
{
// Don't make cubemap tex infos for nodes
if ( originalTexInfo == TEXINFO_NODE )
return originalTexInfo;
texinfo_t *pTexInfo = &texinfo[originalTexInfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
const char *pOriginalMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
// Get out of here if the originalTexInfo is already a patched wvt material
if ( Q_stristr( pOriginalMaterialName, "_wvt_patch" ) )
return originalTexInfo;
char patchedMaterialName[1024];
GeneratePatchedMaterialName( pOriginalMaterialName, patchedMaterialName, 1024 );
// Warning( "GeneratePatchedMaterialName: %s %s\n", pMaterialName, patchedMaterialName );
// Make sure the texdata doesn't already exist.
int nTexDataID = FindTexData( patchedMaterialName );
bool bHasTexData = (nTexDataID != -1);
if( !bHasTexData )
{
// Create the new vmt material file
CreateWorldVertexTransitionPatchedMaterial( pOriginalMaterialName, patchedMaterialName );
// Make a new texdata
nTexDataID = AddCloneTexData( pTexData, patchedMaterialName );
}
Assert( nTexDataID != -1 );
texinfo_t newTexInfo;
newTexInfo = *pTexInfo;
newTexInfo.texdata = nTexDataID;
int nTexInfoID = -1;
// See if we need to make a new texinfo
bool bHasTexInfo = false;
if( bHasTexData )
{
nTexInfoID = FindTexInfo( newTexInfo );
bHasTexInfo = (nTexInfoID != -1);
}
// Make a new texinfo if we need to.
if( !bHasTexInfo )
{
nTexInfoID = texinfo.AddToTail( newTexInfo );
}
Assert( nTexInfoID != -1 );
return nTexInfoID;
}
const char *GetShaderNameForTexInfo( int iTexInfo )
{
texinfo_t *pTexInfo = &texinfo[iTexInfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
const char *pMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
MaterialSystemMaterial_t hMaterial = FindMaterial( pMaterialName, NULL, false );
const char *pShaderName = GetMaterialShaderName( hMaterial );
return pShaderName;
}
void WorldVertexTransitionFixup( void )
{
CUtlVector<entitySideList_t> sideList;
sideList.SetCount( g_MainMap->num_entities );
int i;
for ( i = 0; i < g_MainMap->num_entities; i++ )
{
sideList[i].firstBrushSide = 0;
sideList[i].brushSideCount = 0;
}
for ( i = 0; i < g_MainMap->nummapbrushes; i++ )
{
sideList[g_MainMap->mapbrushes[i].entitynum].brushSideCount += g_MainMap->mapbrushes[i].numsides;
}
int curSide = 0;
for ( i = 0; i < g_MainMap->num_entities; i++ )
{
sideList[i].firstBrushSide = curSide;
curSide += sideList[i].brushSideCount;
}
int currentEntity = 0;
for ( int iSide = 0; iSide < g_MainMap->nummapbrushsides; ++iSide )
{
side_t *pSide = &g_MainMap->brushsides[iSide];
// skip displacments
if ( pSide->pMapDisp )
continue;
if( pSide->texinfo < 0 )
continue;
const char *pShaderName = GetShaderNameForTexInfo( pSide->texinfo );
if ( !pShaderName || !Q_stristr( pShaderName, "worldvertextransition" ) )
{
continue;
}
while ( currentEntity < g_MainMap->num_entities-1 &&
iSide > sideList[currentEntity].firstBrushSide + sideList[currentEntity].brushSideCount )
{
currentEntity++;
}
pSide->texinfo = CreateBrushVersionOfWorldVertexTransitionMaterial( pSide->texinfo );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "bsplib.h"
#include "vbsp.h"
#include "tier1/UtlBuffer.h"
#include "tier1/utlvector.h"
#include "KeyValues.h"
#include "materialpatch.h"
struct entitySideList_t
{
int firstBrushSide;
int brushSideCount;
};
static bool SideIsNotDispAndHasDispMaterial( int iSide )
{
side_t *pSide = &g_MainMap->brushsides[iSide];
// If it's a displacement, then it's fine to have a displacement-only material.
if ( pSide->pMapDisp )
{
return false;
}
pSide->texinfo;
return true;
}
static void BackSlashToForwardSlash( char *pname )
{
while ( *pname ) {
if ( *pname == '\\' )
*pname = '/';
pname++;
}
}
//-----------------------------------------------------------------------------
// Generate patched material name
//-----------------------------------------------------------------------------
static void GeneratePatchedMaterialName( const char *pMaterialName, char *pBuffer, int nMaxLen )
{
int nLen = Q_snprintf( pBuffer, nMaxLen, "maps/%s/%s_wvt_patch", mapbase, pMaterialName );
Assert( nLen < TEXTURE_NAME_LENGTH - 1 );
if ( nLen >= TEXTURE_NAME_LENGTH - 1 )
{
Error( "Generated worldvertextransition patch name : %s too long! (max = %d)\n", pBuffer, TEXTURE_NAME_LENGTH );
}
BackSlashToForwardSlash( pBuffer );
Q_strlower( pBuffer );
}
static void RemoveKey( KeyValues *kv, const char *pSubKeyName )
{
KeyValues *pSubKey = kv->FindKey( pSubKeyName );
if( pSubKey )
{
kv->RemoveSubKey( pSubKey );
pSubKey->deleteThis();
}
}
void CreateWorldVertexTransitionPatchedMaterial( const char *pOriginalMaterialName, const char *pPatchedMaterialName )
{
KeyValues *kv = LoadMaterialKeyValues( pOriginalMaterialName, 0 );
if( kv )
{
// change shader to Lightmappedgeneric (from worldvertextransition*)
kv->SetName( "LightmappedGeneric" );
// don't need no stinking $basetexture2 or any other second texture vars
RemoveKey( kv, "$basetexture2" );
RemoveKey( kv, "$bumpmap2" );
RemoveKey( kv, "$bumpframe2" );
RemoveKey( kv, "$basetexture2noenvmap" );
RemoveKey( kv, "$blendmodulatetexture" );
RemoveKey( kv, "$maskedblending" );
RemoveKey( kv, "$surfaceprop2" );
// If we didn't want a basetexture on the first texture in the blend, we don't want an envmap at all.
KeyValues *basetexturenoenvmap = kv->FindKey( "$BASETEXTURENOENVMAP" );
if( basetexturenoenvmap->GetInt() )
{
RemoveKey( kv, "$envmap" );
}
Warning( "Patching WVT material: %s\n", pPatchedMaterialName );
WriteMaterialKeyValuesToPak( pPatchedMaterialName, kv );
}
}
int CreateBrushVersionOfWorldVertexTransitionMaterial( int originalTexInfo )
{
// Don't make cubemap tex infos for nodes
if ( originalTexInfo == TEXINFO_NODE )
return originalTexInfo;
texinfo_t *pTexInfo = &texinfo[originalTexInfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
const char *pOriginalMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
// Get out of here if the originalTexInfo is already a patched wvt material
if ( Q_stristr( pOriginalMaterialName, "_wvt_patch" ) )
return originalTexInfo;
char patchedMaterialName[1024];
GeneratePatchedMaterialName( pOriginalMaterialName, patchedMaterialName, 1024 );
// Warning( "GeneratePatchedMaterialName: %s %s\n", pMaterialName, patchedMaterialName );
// Make sure the texdata doesn't already exist.
int nTexDataID = FindTexData( patchedMaterialName );
bool bHasTexData = (nTexDataID != -1);
if( !bHasTexData )
{
// Create the new vmt material file
CreateWorldVertexTransitionPatchedMaterial( pOriginalMaterialName, patchedMaterialName );
// Make a new texdata
nTexDataID = AddCloneTexData( pTexData, patchedMaterialName );
}
Assert( nTexDataID != -1 );
texinfo_t newTexInfo;
newTexInfo = *pTexInfo;
newTexInfo.texdata = nTexDataID;
int nTexInfoID = -1;
// See if we need to make a new texinfo
bool bHasTexInfo = false;
if( bHasTexData )
{
nTexInfoID = FindTexInfo( newTexInfo );
bHasTexInfo = (nTexInfoID != -1);
}
// Make a new texinfo if we need to.
if( !bHasTexInfo )
{
nTexInfoID = texinfo.AddToTail( newTexInfo );
}
Assert( nTexInfoID != -1 );
return nTexInfoID;
}
const char *GetShaderNameForTexInfo( int iTexInfo )
{
texinfo_t *pTexInfo = &texinfo[iTexInfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
const char *pMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
MaterialSystemMaterial_t hMaterial = FindMaterial( pMaterialName, NULL, false );
const char *pShaderName = GetMaterialShaderName( hMaterial );
return pShaderName;
}
void WorldVertexTransitionFixup( void )
{
CUtlVector<entitySideList_t> sideList;
sideList.SetCount( g_MainMap->num_entities );
int i;
for ( i = 0; i < g_MainMap->num_entities; i++ )
{
sideList[i].firstBrushSide = 0;
sideList[i].brushSideCount = 0;
}
for ( i = 0; i < g_MainMap->nummapbrushes; i++ )
{
sideList[g_MainMap->mapbrushes[i].entitynum].brushSideCount += g_MainMap->mapbrushes[i].numsides;
}
int curSide = 0;
for ( i = 0; i < g_MainMap->num_entities; i++ )
{
sideList[i].firstBrushSide = curSide;
curSide += sideList[i].brushSideCount;
}
int currentEntity = 0;
for ( int iSide = 0; iSide < g_MainMap->nummapbrushsides; ++iSide )
{
side_t *pSide = &g_MainMap->brushsides[iSide];
// skip displacments
if ( pSide->pMapDisp )
continue;
if( pSide->texinfo < 0 )
continue;
const char *pShaderName = GetShaderNameForTexInfo( pSide->texinfo );
if ( !pShaderName || !Q_stristr( pShaderName, "worldvertextransition" ) )
{
continue;
}
while ( currentEntity < g_MainMap->num_entities-1 &&
iSide > sideList[currentEntity].firstBrushSide + sideList[currentEntity].brushSideCount )
{
currentEntity++;
}
pSide->texinfo = CreateBrushVersionOfWorldVertexTransitionMaterial( pSide->texinfo );
}
}

View File

@@ -1,15 +1,15 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef WORLDVERTEXTRANSITIONFIXUP_H
#define WORLDVERTEXTRANSITIONFIXUP_H
#ifdef _WIN32
#pragma once
#endif
void WorldVertexTransitionFixup( void );
#endif // WORLDVERTEXTRANSITIONFIXUP_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef WORLDVERTEXTRANSITIONFIXUP_H
#define WORLDVERTEXTRANSITIONFIXUP_H
#ifdef _WIN32
#pragma once
#endif
void WorldVertexTransitionFixup( void );
#endif // WORLDVERTEXTRANSITIONFIXUP_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,34 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef WRITEBSP_H
#define WRITEBSP_H
#ifdef _WIN32
#pragma once
#endif
#include "bspfile.h"
#include "utlmap.h"
struct node_t;
//-----------------------------------------------------------------------------
// Emits occluder faces
//-----------------------------------------------------------------------------
void EmitOccluderFaces (node_t *node);
//-----------------------------------------------------------------------------
// Purpose: Free the list of faces stored at the leaves
//-----------------------------------------------------------------------------
void FreeLeafFaces( face_t *pLeafFaceList );
//-----------------------------------------------------------------------------
// Purpose: Make sure that we have a water lod control entity if we have water in the map.
//-----------------------------------------------------------------------------
void EnsurePresenceOfWaterLODControlEntity( void );
#endif // WRITEBSP_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef WRITEBSP_H
#define WRITEBSP_H
#ifdef _WIN32
#pragma once
#endif
#include "bspfile.h"
#include "utlmap.h"
struct node_t;
//-----------------------------------------------------------------------------
// Emits occluder faces
//-----------------------------------------------------------------------------
void EmitOccluderFaces (node_t *node);
//-----------------------------------------------------------------------------
// Purpose: Free the list of faces stored at the leaves
//-----------------------------------------------------------------------------
void FreeLeafFaces( face_t *pLeafFaceList );
//-----------------------------------------------------------------------------
// Purpose: Make sure that we have a water lod control entity if we have water in the map.
//-----------------------------------------------------------------------------
void EnsurePresenceOfWaterLODControlEntity( void );
#endif // WRITEBSP_H