|
|
//========= 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); }
|