source-engine/hammer/stocksolids.cpp

689 lines
16 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "stdafx.h"
#include "hammer.h"
#include "StockSolids.h"
#include "hammer_mathlib.h"
#include "MapSolid.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
#pragma warning(disable:4244)
//Vector pmPoints[64];
StockSolid::StockSolid(int nFields)
{
AllocateDataFields(nFields);
cofs.Init();
}
StockSolid::~StockSolid()
{
if ( pFields )
{
delete[] pFields;
pFields = NULL;
}
}
void StockSolid::AllocateDataFields(int nFields_)
{
pFields = new STSDATAFIELD[nFields_];
Assert(pFields);
iMaxFields = nFields_;
this->nFields = 0; // none yet
}
void StockSolid::Serialize(std::fstream& file, BOOL bIsStoring)
{
}
int StockSolid::GetFieldCount() const
{
return nFields;
}
void StockSolid::SetFieldData(int iIndex, int iData)
{
Assert(iIndex < nFields);
STSDATAFIELD& field = pFields[iIndex];
field.iValue = iData;
if(field.flags & DFFLAG_RANGED)
{
Assert(!(iData < field.iRangeLower || iData > field.iRangeUpper));
}
}
int StockSolid::GetFieldData(int iIndex, int *piData) const
{
Assert(iIndex < nFields);
STSDATAFIELD& field = pFields[iIndex];
if(piData)
piData[0] = field.iValue;
return field.iValue;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void StockSolid::SetOrigin(const Vector &o)
{
origin = o;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void StockSolid::SetCenterOffset(const Vector &ofs)
{
cofs = ofs;
}
void StockSolid::AddDataField(STSDF_TYPE type, const char *pszName, int iRangeLower, int iRangeUpper)
{
Assert(nFields < iMaxFields);
STSDATAFIELD& field = pFields[nFields++];
field.type = type;
field.flags = 0;
strcpy(field.szName, pszName);
if(iRangeLower != -1)
{
field.flags |= DFFLAG_RANGED;
field.iRangeLower = iRangeLower;
field.iRangeUpper = iRangeUpper;
}
}
// ----------------------------------------------------------------------------
// StockBlock()
// ----------------------------------------------------------------------------
StockBlock::StockBlock() :
StockSolid(3)
{
AddDataField(DFTYPE_INTEGER, "Width (X)");
AddDataField(DFTYPE_INTEGER, "Depth (Y)");
AddDataField(DFTYPE_INTEGER, "Height (Z)");
}
void StockBlock::SetFromBox(BoundBox *pBox)
{
// round floats before converting to integers
SetFieldData(fieldWidth, (pBox->bmaxs[0] - pBox->bmins[0])+0.5f );
SetFieldData(fieldDepth, (pBox->bmaxs[1] - pBox->bmins[1])+0.5f );
SetFieldData(fieldHeight, (pBox->bmaxs[2] - pBox->bmins[2])+0.5f );
Vector o;
pBox->GetBoundsCenter(o);
SetOrigin(o);
}
void StockBlock::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eAlignment)
{
CMapFace Face;
float fDepth = float(GetFieldData(fieldDepth))/2;
float fWidth = float(GetFieldData(fieldWidth))/2;
float fHeight = float(GetFieldData(fieldHeight))/2;
// create box
Vector bmins, bmaxs;
bmins[0] = origin[0] - fWidth + cofs[0];
bmins[1] = origin[1] - fDepth + cofs[1];
bmins[2] = origin[2] - fHeight + cofs[2];
bmaxs[0] = origin[0] + fWidth + cofs[0];
bmaxs[1] = origin[1] + fDepth + cofs[1];
bmaxs[2] = origin[2] + fHeight + cofs[2];
Vector Points[4];
// x planes - top first
Points[0][0] = bmins[0];
Points[0][1] = bmaxs[1];
Points[0][2] = bmaxs[2];
Points[1][0] = bmaxs[0];
Points[1][1] = bmaxs[1];
Points[1][2] = bmaxs[2];
Points[2][0] = bmaxs[0];
Points[2][1] = bmins[1];
Points[2][2] = bmaxs[2];
Points[3][0] = bmins[0];
Points[3][1] = bmins[1];
Points[3][2] = bmaxs[2];
Face.CreateFace(Points, 4, pSolid->IsCordonBrush());
pSolid->AddFace(&Face);
// top - modify heights
for(int i = 0; i < 4; i++)
{
Points[i][2] = bmins[2];
}
Face.CreateFace(Points, -4, pSolid->IsCordonBrush());
pSolid->AddFace(&Face);
// y planes - left
Points[0][0] = bmins[0];
Points[0][1] = bmaxs[1];
Points[0][2] = bmaxs[2];
Points[1][0] = bmins[0];
Points[1][1] = bmins[1];
Points[1][2] = bmaxs[2];
Points[2][0] = bmins[0];
Points[2][1] = bmins[1];
Points[2][2] = bmins[2];
Points[3][0] = bmins[0];
Points[3][1] = bmaxs[1];
Points[3][2] = bmins[2];
Face.CreateFace(Points, 4, pSolid->IsCordonBrush());
pSolid->AddFace(&Face);
// right - modify xloc
for(int i = 0; i < 4; i++)
{
Points[i][0] = bmaxs[0];
}
Face.CreateFace(Points, -4, pSolid->IsCordonBrush());
pSolid->AddFace(&Face);
// x planes - farthest
Points[0][0] = bmaxs[0];
Points[0][1] = bmaxs[1];
Points[0][2] = bmaxs[2];
Points[1][0] = bmins[0];
Points[1][1] = bmaxs[1];
Points[1][2] = bmaxs[2];
Points[2][0] = bmins[0];
Points[2][1] = bmaxs[1];
Points[2][2] = bmins[2];
Points[3][0] = bmaxs[0];
Points[3][1] = bmaxs[1];
Points[3][2] = bmins[2];
Face.CreateFace(Points, 4, pSolid->IsCordonBrush());
pSolid->AddFace(&Face);
// nearest - modify yloc
for(int i = 0; i < 4; i++)
{
Points[i][1] = bmins[1];
}
Face.CreateFace(Points, -4, pSolid->IsCordonBrush());
pSolid->AddFace(&Face);
pSolid->CalcBounds();
pSolid->InitializeTextureAxes(eAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
}
// ----------------------------------------------------------------------------
// StockWedge()
// ----------------------------------------------------------------------------
StockWedge::StockWedge() :
StockSolid(3)
{
AddDataField(DFTYPE_INTEGER, "Width (X)");
AddDataField(DFTYPE_INTEGER, "Depth (Y)");
AddDataField(DFTYPE_INTEGER, "Height (Z)");
}
void StockWedge::SetFromBox(BoundBox *pBox)
{
SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
Vector o;
pBox->GetBoundsCenter(o);
SetOrigin(o);
}
void StockWedge::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
{
CMapFace Face;
float fDepth = float(GetFieldData(fieldDepth))/2;
float fWidth = float(GetFieldData(fieldWidth))/2;
float fHeight = float(GetFieldData(fieldHeight))/2;
Vector Points[4];
// x planes - top
Points[0][0] = origin[0] + fWidth;
Points[0][1] = origin[1] + fDepth;
Points[0][2] = origin[2] + fHeight;
Points[1][0] = origin[0] + fWidth;
Points[1][1] = origin[1] - fDepth;
Points[1][2] = origin[2] + fHeight;
Points[2][0] = origin[0] - fWidth;
Points[2][1] = origin[1] - fDepth;
Points[2][2] = origin[2] + fHeight;
Face.CreateFace(Points, 3);
pSolid->AddFace(&Face);
// bottom
for (int i = 0; i < 3; i++)
{
Points[i][2] = origin[2] - fHeight;
}
Face.CreateFace(Points, -3);
pSolid->AddFace(&Face);
// left (slant)
Points[0][0] = origin[0] + fWidth;
Points[0][1] = origin[1] + fDepth;
Points[0][2] = origin[2] - fHeight;
Points[1][0] = origin[0] + fWidth;
Points[1][1] = origin[1] + fDepth;
Points[1][2] = origin[2] + fHeight;
Points[2][0] = origin[0] - fWidth;
Points[2][1] = origin[1] - fDepth;
Points[2][2] = origin[2] + fHeight;
Points[3][0] = origin[0] - fWidth;
Points[3][1] = origin[1] - fDepth;
Points[3][2] = origin[2] - fHeight;
Face.CreateFace(Points, 4);
pSolid->AddFace(&Face);
// south
Points[0][0] = origin[0] + fWidth;
Points[0][1] = origin[1] - fDepth;
Points[0][2] = origin[2] + fHeight;
Points[1][0] = origin[0] + fWidth;
Points[1][1] = origin[1] - fDepth;
Points[1][2] = origin[2] - fHeight;
Points[2][0] = origin[0] - fWidth;
Points[2][1] = origin[1] - fDepth;
Points[2][2] = origin[2] - fHeight;
Points[3][0] = origin[0] - fWidth;
Points[3][1] = origin[1] - fDepth;
Points[3][2] = origin[2] + fHeight;
Face.CreateFace(Points, 4);
pSolid->AddFace(&Face);
// right
Points[0][0] = origin[0] + fWidth;
Points[0][1] = origin[1] + fDepth;
Points[0][2] = origin[2] + fHeight;
Points[1][0] = origin[0] + fWidth;
Points[1][1] = origin[1] + fDepth;
Points[1][2] = origin[2] - fHeight;
Points[2][0] = origin[0] + fWidth;
Points[2][1] = origin[1] - fDepth;
Points[2][2] = origin[2] - fHeight;
Points[3][0] = origin[0] + fWidth;
Points[3][1] = origin[1] - fDepth;
Points[3][2] = origin[2] + fHeight;
Face.CreateFace(Points, 4);
pSolid->AddFace(&Face);
pSolid->CalcBounds();
pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
}
// ----------------------------------------------------------------------------
// StockCylinder()
// ----------------------------------------------------------------------------
StockCylinder::StockCylinder()
: StockSolid(4)
{
AddDataField(DFTYPE_INTEGER, "Width (X)");
AddDataField(DFTYPE_INTEGER, "Depth (Y)");
AddDataField(DFTYPE_INTEGER, "Height (Z)");
AddDataField(DFTYPE_INTEGER, "Number of Sides");
SetFieldData(fieldSideCount, 8);
}
void StockCylinder::SetFromBox(BoundBox *pBox)
{
SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
Vector o;
pBox->GetBoundsCenter(o);
SetOrigin(o);
}
void StockCylinder::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
{
CMapFace Face;
float fDepth = float(GetFieldData(fieldDepth))/2;
float fWidth = float(GetFieldData(fieldWidth))/2;
float fHeight = float(GetFieldData(fieldHeight))/2;
int nSides = GetFieldData(fieldSideCount);
Vector pmPoints[64];
polyMake(origin[0] - fWidth, origin[1] - fDepth, origin[0] + fWidth, origin[1] + fDepth, nSides, 0, pmPoints );
// face 0 - top face
for(int i = 0; i < nSides+1; i++)
{
pmPoints[i][2] = origin[2] - fHeight;
}
Face.CreateFace( pmPoints, -nSides);
pSolid->AddFace(&Face);
// bottom face
for(int i = 0; i < nSides+1; i++)
{
pmPoints[i][2] = origin[2] + fHeight;
}
Face.CreateFace( pmPoints, nSides);
pSolid->AddFace(&Face);
// other sides
Vector Points[4];
for(int i = 0; i < nSides; i++)
{
Points[0][0] = pmPoints[i][0];
Points[0][1] = pmPoints[i][1];
Points[0][2] = origin[2] - fHeight;
Points[1][0] = pmPoints[i+1][0];
Points[1][1] = pmPoints[i+1][1];
Points[1][2] = origin[2] - fHeight;
Points[2][0] = pmPoints[i+1][0];
Points[2][1] = pmPoints[i+1][1];
Points[2][2] = origin[2] + fHeight;
Points[3][0] = pmPoints[i][0];
Points[3][1] = pmPoints[i][1];
Points[3][2] = origin[2] + fHeight;
Face.CreateFace(Points, 4);
Face.texture.smooth = 1.f;
pSolid->AddFace(&Face);
}
pSolid->CalcBounds();
pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
}
// ----------------------------------------------------------------------------
// StockSpike()
// ----------------------------------------------------------------------------
StockSpike::StockSpike()
: StockSolid(4)
{
AddDataField(DFTYPE_INTEGER, "Width (X)");
AddDataField(DFTYPE_INTEGER, "Depth (Y)");
AddDataField(DFTYPE_INTEGER, "Height (Z)");
AddDataField(DFTYPE_INTEGER, "Number of Sides");
SetFieldData(fieldSideCount, 8);
}
void StockSpike::SetFromBox(BoundBox *pBox)
{
SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
Vector o;
pBox->GetBoundsCenter(o);
SetOrigin(o);
}
void StockSpike::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
{
float fDepth = float(GetFieldData(fieldDepth))/2;
float fWidth = float(GetFieldData(fieldWidth))/2;
float fHeight = float(GetFieldData(fieldHeight))/2;
int nSides = GetFieldData(fieldSideCount);
CMapFace NewFace;
// create bottom poly
Vector pmPoints[64];
polyMake(origin[0] - fWidth, origin[1] - fDepth, origin[0] + fWidth, origin[1] + fDepth, nSides, 0, pmPoints);
// bottom face
for(int i = 0; i < nSides+1; i++)
{
// YWB rounding???
pmPoints[i][2] = V_rint(origin[2] - fHeight);
}
NewFace.CreateFace(pmPoints, -nSides);
pSolid->AddFace(&NewFace);
// other sides
Vector Points[3];
// get centerpoint
Points[0][0] = origin[0];
Points[0][1] = origin[1];
// YWB rounding???
Points[0][2] = V_rint(origin[2] + fHeight);
for(int i = 0; i < nSides; i++)
{
Points[1][0] = pmPoints[i][0];
Points[1][1] = pmPoints[i][1];
Points[1][2] = pmPoints[i][2];
Points[2][0] = pmPoints[i+1][0];
Points[2][1] = pmPoints[i+1][1];
Points[2][2] = pmPoints[i+1][2];
NewFace.CreateFace(Points, 3);
pSolid->AddFace(&NewFace);
}
pSolid->CalcBounds();
pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
}
StockSphere::StockSphere()
: StockSolid(4)
{
AddDataField(DFTYPE_INTEGER, "Width (X)");
AddDataField(DFTYPE_INTEGER, "Depth (Y)");
AddDataField(DFTYPE_INTEGER, "Height (Z)");
AddDataField(DFTYPE_INTEGER, "Subdivisions");
SetFieldData(fieldSideCount, 8);
}
void StockSphere::SetFromBox(BoundBox *pBox)
{
SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
Vector o;
pBox->GetBoundsCenter(o);
SetOrigin(o);
}
//-----------------------------------------------------------------------------
// Purpose: Builds a tesselated sphere.
// Input : pSolid - Pointer to a solid that will become a sphere.
//-----------------------------------------------------------------------------
void StockSphere::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
{
CMapFace Face;
float fDepth = (float)GetFieldData(fieldDepth) / 2;
float fWidth = (float)GetFieldData(fieldWidth) / 2;
float fHeight = (float)GetFieldData(fieldHeight) / 2;
int nSides = GetFieldData(fieldSideCount);
float fAngle = 0;
float fAngleStep = 180.0 / nSides;
//
// Build the sphere by building slices at constant angular intervals.
//
// Each slice is a ring of four-sided faces, except for the top and bottom slices,
// which are flattened cones.
//
// Unrolled, a sphere made with 5 'sides' has 25 faces and looks like this:
//
// /\ /\ /\ /\ /\
// / 0\/ 1\/ 2\/ 3\/ 4\
// | 5| 6| 7| 8| 9|
// | 10| 11| 12| 13| 14|
// | 15| 16| 17| 18| 19|
// \20/\21/\22/\23/\24/
// \/ \/ \/ \/ \/
//
for (int nSlice = 0; nSlice < nSides; nSlice++)
{
float fAngle1 = fAngle + fAngleStep;
//
// Make the upper polygon.
//
Vector TopPoints[64];
float fUpperWidth = fWidth * sin(DEG2RAD(fAngle));
float fUpperDepth = fDepth * sin(DEG2RAD(fAngle));
polyMake(origin[0] - fUpperWidth, origin[1] - fUpperDepth, origin[0] + fUpperWidth, origin[1] + fUpperDepth, nSides, 0, TopPoints);
//
// Make the lower polygon.
//
Vector BottomPoints[64];
float fLowerWidth = fWidth * sin(DEG2RAD(fAngle1));
float fLowerDepth = fDepth * sin(DEG2RAD(fAngle1));
polyMake(origin[0] - fLowerWidth, origin[1] - fLowerDepth, origin[0] + fLowerWidth, origin[1] + fLowerDepth, nSides, 0, BottomPoints);
//
// Build the faces that connect the upper and lower polygons.
//
Vector Points[4];
float fUpperHeight = origin[2] + fHeight * cos(DEG2RAD(fAngle));
float fLowerHeight = origin[2] + fHeight * cos(DEG2RAD(fAngle1));
for (int i = 0; i < nSides; i++)
{
if (nSlice != 0)
{
Points[0][0] = TopPoints[i + 1][0];
Points[0][1] = TopPoints[i + 1][1];
Points[0][2] = fUpperHeight;
}
Points[1][0] = TopPoints[i][0];
Points[1][1] = TopPoints[i][1];
Points[1][2] = fUpperHeight;
Points[2][0] = BottomPoints[i][0];
Points[2][1] = BottomPoints[i][1];
Points[2][2] = fLowerHeight;
if (nSlice != nSides - 1)
{
Points[3][0] = BottomPoints[i + 1][0];
Points[3][1] = BottomPoints[i + 1][1];
Points[3][2] = fLowerHeight;
}
//
// Top and bottom are cones, not rings, so remove one vertex per face.
//
if (nSlice == 0)
{
Face.CreateFace(&Points[1], 3);
}
else if (nSlice == nSides - 1)
{
Face.CreateFace(Points, 3);
}
else
{
Face.CreateFace(Points, 4);
}
Face.texture.smooth = 1.f;
pSolid->AddFace(&Face);
}
fAngle += fAngleStep;
}
pSolid->CalcBounds();
pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
}