Fix line endings. WHAMMY.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user