You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
658 lines
18 KiB
658 lines
18 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "OPTGeneral.h"
|
||
|
#include "Options.h"
|
||
|
#include "hammer_mathlib.h"
|
||
|
#include "MapFace.h"
|
||
|
#include "MapGroup.h"
|
||
|
#include "MapSolid.h"
|
||
|
#include "hammer.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include <tier0/memdbgon.h>
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Create a segment using two polygons and a start and end position in
|
||
|
// those polygons.
|
||
|
// Input : fZMin -
|
||
|
// fZMax -
|
||
|
// fOuterPoints -
|
||
|
// fInnerPoints -
|
||
|
// iStart -
|
||
|
// iEnd -
|
||
|
// bCreateSouthFace -
|
||
|
// Output :
|
||
|
//-----------------------------------------------------------------------------
|
||
|
static CMapSolid *CreateSegment(float fZMin, float fZMax, float fOuterPoints[][2], float fInnerPoints[][2], int iStart, int iEnd, BOOL bCreateSouthFace)
|
||
|
{
|
||
|
CMapFace Face;
|
||
|
Vector points[4]; // all sides have four vertices
|
||
|
|
||
|
CMapSolid *pSolid = new CMapSolid;
|
||
|
|
||
|
int iNorthSouthPoints = 3 + (bCreateSouthFace ? 1 : 0);
|
||
|
|
||
|
// create top face
|
||
|
points[0][0] = fOuterPoints[iStart][0];
|
||
|
points[0][1] = fOuterPoints[iStart][1];
|
||
|
points[0][2] = fZMin;
|
||
|
|
||
|
points[1][0] = fOuterPoints[iEnd][0];
|
||
|
points[1][1] = fOuterPoints[iEnd][1];
|
||
|
points[1][2] = fZMin;
|
||
|
|
||
|
points[2][0] = fInnerPoints[iEnd][0];
|
||
|
points[2][1] = fInnerPoints[iEnd][1];
|
||
|
points[2][2] = fZMin;
|
||
|
|
||
|
points[3][0] = fInnerPoints[iStart][0];
|
||
|
points[3][1] = fInnerPoints[iStart][1];
|
||
|
points[3][2] = fZMin;
|
||
|
|
||
|
Face.CreateFace(points, iNorthSouthPoints);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// bottom face - set other z value and reverse order
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
{
|
||
|
points[i][2] = fZMax;
|
||
|
}
|
||
|
|
||
|
Face.CreateFace(points, -iNorthSouthPoints);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// left side
|
||
|
points[0][0] = fOuterPoints[iStart][0];
|
||
|
points[0][1] = fOuterPoints[iStart][1];
|
||
|
points[0][2] = fZMax;
|
||
|
|
||
|
points[1][0] = fOuterPoints[iStart][0];
|
||
|
points[1][1] = fOuterPoints[iStart][1];
|
||
|
points[1][2] = fZMin;
|
||
|
|
||
|
points[2][0] = fInnerPoints[iStart][0];
|
||
|
points[2][1] = fInnerPoints[iStart][1];
|
||
|
points[2][2] = fZMin;
|
||
|
|
||
|
points[3][0] = fInnerPoints[iStart][0];
|
||
|
points[3][1] = fInnerPoints[iStart][1];
|
||
|
points[3][2] = fZMax;
|
||
|
|
||
|
Face.CreateFace(points, 4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// right side
|
||
|
points[0][0] = fOuterPoints[iEnd][0];
|
||
|
points[0][1] = fOuterPoints[iEnd][1];
|
||
|
points[0][2] = fZMin;
|
||
|
|
||
|
points[1][0] = fOuterPoints[iEnd][0];
|
||
|
points[1][1] = fOuterPoints[iEnd][1];
|
||
|
points[1][2] = fZMax;
|
||
|
|
||
|
points[2][0] = fInnerPoints[iEnd][0];
|
||
|
points[2][1] = fInnerPoints[iEnd][1];
|
||
|
points[2][2] = fZMax;
|
||
|
|
||
|
points[3][0] = fInnerPoints[iEnd][0];
|
||
|
points[3][1] = fInnerPoints[iEnd][1];
|
||
|
points[3][2] = fZMin;
|
||
|
|
||
|
Face.CreateFace(points, 4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// north face
|
||
|
points[0][0] = fOuterPoints[iEnd][0];
|
||
|
points[0][1] = fOuterPoints[iEnd][1];
|
||
|
points[0][2] = fZMin;
|
||
|
|
||
|
points[1][0] = fOuterPoints[iStart][0];
|
||
|
points[1][1] = fOuterPoints[iStart][1];
|
||
|
points[1][2] = fZMin;
|
||
|
|
||
|
points[2][0] = fOuterPoints[iStart][0];
|
||
|
points[2][1] = fOuterPoints[iStart][1];
|
||
|
points[2][2] = fZMax;
|
||
|
|
||
|
points[3][0] = fOuterPoints[iEnd][0];
|
||
|
points[3][1] = fOuterPoints[iEnd][1];
|
||
|
points[3][2] = fZMax;
|
||
|
|
||
|
Face.CreateFace(points, 4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// south face
|
||
|
if (bCreateSouthFace)
|
||
|
{
|
||
|
points[0][0] = fInnerPoints[iStart][0];
|
||
|
points[0][1] = fInnerPoints[iStart][1];
|
||
|
points[0][2] = fZMin;
|
||
|
|
||
|
points[1][0] = fInnerPoints[iEnd][0];
|
||
|
points[1][1] = fInnerPoints[iEnd][1];
|
||
|
points[1][2] = fZMin;
|
||
|
|
||
|
points[2][0] = fInnerPoints[iEnd][0];
|
||
|
points[2][1] = fInnerPoints[iEnd][1];
|
||
|
points[2][2] = fZMax;
|
||
|
|
||
|
points[3][0] = fInnerPoints[iStart][0];
|
||
|
points[3][1] = fInnerPoints[iStart][1];
|
||
|
points[3][2] = fZMax;
|
||
|
|
||
|
Face.CreateFace(points, 4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
}
|
||
|
|
||
|
pSolid->InitializeTextureAxes(Options.GetTextureAlignment(), INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
|
||
|
|
||
|
return(pSolid);
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Create a segment using two polygons and a start and end position in
|
||
|
// those polygons.
|
||
|
// Input : fZMin -
|
||
|
// fZMax -
|
||
|
// fOuterPoints -
|
||
|
// fInnerPoints -
|
||
|
// iStart -
|
||
|
// iEnd -
|
||
|
// bCreateSouthFace -
|
||
|
// Output :
|
||
|
//-----------------------------------------------------------------------------
|
||
|
static CMapSolid *CreateSegment(float fStartOuterPoints[][3], float fStartInnerPoints[][3],
|
||
|
float fEndOuterPoints[][3], float fEndInnerPoints[][3],
|
||
|
int iStart, int iEnd, BOOL bCreateSouthFace)
|
||
|
{
|
||
|
CMapFace Face;
|
||
|
Vector points[4]; // all sides have four vertices
|
||
|
|
||
|
CMapSolid *pSolid = new CMapSolid;
|
||
|
|
||
|
// create top face
|
||
|
points[0][0] = fStartOuterPoints[iStart][0];
|
||
|
points[0][1] = fStartOuterPoints[iStart][1];
|
||
|
points[0][2] = fStartOuterPoints[iStart][2];
|
||
|
|
||
|
points[1][0] = fStartOuterPoints[iEnd][0];
|
||
|
points[1][1] = fStartOuterPoints[iEnd][1];
|
||
|
points[1][2] = fStartOuterPoints[iEnd][2];
|
||
|
|
||
|
points[2][0] = fStartInnerPoints[iEnd][0];
|
||
|
points[2][1] = fStartInnerPoints[iEnd][1];
|
||
|
points[2][2] = fStartInnerPoints[iEnd][2];
|
||
|
|
||
|
points[3][0] = fStartInnerPoints[iStart][0];
|
||
|
points[3][1] = fStartInnerPoints[iStart][1];
|
||
|
points[3][2] = fStartInnerPoints[iStart][2];
|
||
|
|
||
|
Face.CreateFace(points, -4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// bottom face - set other z value and reverse order
|
||
|
points[0][0] = fEndOuterPoints[iStart][0];
|
||
|
points[0][1] = fEndOuterPoints[iStart][1];
|
||
|
points[0][2] = fEndOuterPoints[iStart][2];
|
||
|
|
||
|
points[1][0] = fEndOuterPoints[iEnd][0];
|
||
|
points[1][1] = fEndOuterPoints[iEnd][1];
|
||
|
points[1][2] = fEndOuterPoints[iEnd][2];
|
||
|
|
||
|
points[2][0] = fEndInnerPoints[iEnd][0];
|
||
|
points[2][1] = fEndInnerPoints[iEnd][1];
|
||
|
points[2][2] = fEndInnerPoints[iEnd][2];
|
||
|
|
||
|
points[3][0] = fEndInnerPoints[iStart][0];
|
||
|
points[3][1] = fEndInnerPoints[iStart][1];
|
||
|
points[3][2] = fEndInnerPoints[iStart][2];
|
||
|
|
||
|
Face.CreateFace(points, 4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// left side
|
||
|
points[0][0] = fEndOuterPoints[iStart][0];
|
||
|
points[0][1] = fEndOuterPoints[iStart][1];
|
||
|
points[0][2] = fEndOuterPoints[iStart][2];
|
||
|
|
||
|
points[1][0] = fStartOuterPoints[iStart][0];
|
||
|
points[1][1] = fStartOuterPoints[iStart][1];
|
||
|
points[1][2] = fStartOuterPoints[iStart][2];
|
||
|
|
||
|
points[2][0] = fStartInnerPoints[iStart][0];
|
||
|
points[2][1] = fStartInnerPoints[iStart][1];
|
||
|
points[2][2] = fStartInnerPoints[iStart][2];
|
||
|
|
||
|
points[3][0] = fEndInnerPoints[iStart][0];
|
||
|
points[3][1] = fEndInnerPoints[iStart][1];
|
||
|
points[3][2] = fEndInnerPoints[iStart][2];
|
||
|
|
||
|
Face.CreateFace(points, -4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// right side
|
||
|
points[0][0] = fStartOuterPoints[iEnd][0];
|
||
|
points[0][1] = fStartOuterPoints[iEnd][1];
|
||
|
points[0][2] = fStartOuterPoints[iEnd][2];
|
||
|
|
||
|
points[1][0] = fEndOuterPoints[iEnd][0];
|
||
|
points[1][1] = fEndOuterPoints[iEnd][1];
|
||
|
points[1][2] = fEndOuterPoints[iEnd][2];
|
||
|
|
||
|
points[2][0] = fEndInnerPoints[iEnd][0];
|
||
|
points[2][1] = fEndInnerPoints[iEnd][1];
|
||
|
points[2][2] = fEndInnerPoints[iEnd][2];
|
||
|
|
||
|
points[3][0] = fStartInnerPoints[iEnd][0];
|
||
|
points[3][1] = fStartInnerPoints[iEnd][1];
|
||
|
points[3][2] = fStartInnerPoints[iEnd][2];
|
||
|
|
||
|
Face.CreateFace(points, -4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// north face
|
||
|
points[0][0] = fStartOuterPoints[iEnd][0];
|
||
|
points[0][1] = fStartOuterPoints[iEnd][1];
|
||
|
points[0][2] = fStartOuterPoints[iEnd][2];
|
||
|
|
||
|
points[1][0] = fStartOuterPoints[iStart][0];
|
||
|
points[1][1] = fStartOuterPoints[iStart][1];
|
||
|
points[1][2] = fStartOuterPoints[iStart][2];
|
||
|
|
||
|
points[2][0] = fEndOuterPoints[iStart][0];
|
||
|
points[2][1] = fEndOuterPoints[iStart][1];
|
||
|
points[2][2] = fEndOuterPoints[iStart][2];
|
||
|
|
||
|
points[3][0] = fEndOuterPoints[iEnd][0];
|
||
|
points[3][1] = fEndOuterPoints[iEnd][1];
|
||
|
points[3][2] = fEndOuterPoints[iEnd][2];
|
||
|
|
||
|
Face.CreateFace(points, -4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
|
||
|
// south face
|
||
|
if (bCreateSouthFace)
|
||
|
{
|
||
|
points[0][0] = fStartInnerPoints[iStart][0];
|
||
|
points[0][1] = fStartInnerPoints[iStart][1];
|
||
|
points[0][2] = fStartInnerPoints[iStart][2];
|
||
|
|
||
|
points[1][0] = fStartInnerPoints[iEnd][0];
|
||
|
points[1][1] = fStartInnerPoints[iEnd][1];
|
||
|
points[1][2] = fStartInnerPoints[iEnd][2];
|
||
|
|
||
|
points[2][0] = fEndInnerPoints[iEnd][0];
|
||
|
points[2][1] = fEndInnerPoints[iEnd][1];
|
||
|
points[2][2] = fEndInnerPoints[iEnd][2];
|
||
|
|
||
|
points[3][0] = fEndInnerPoints[iStart][0];
|
||
|
points[3][1] = fEndInnerPoints[iStart][1];
|
||
|
points[3][2] = fEndInnerPoints[iStart][2];
|
||
|
|
||
|
Face.CreateFace(points, -4);
|
||
|
pSolid->AddFace(&Face);
|
||
|
}
|
||
|
|
||
|
pSolid->InitializeTextureAxes(Options.GetTextureAlignment(), INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
|
||
|
|
||
|
return(pSolid);
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Make a 2d arc
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void MakeArcCenterRadius(float xCenter, float yCenter, float xrad, float yrad, int npoints, float start_ang, float fArc, float points[][2])
|
||
|
{
|
||
|
int point;
|
||
|
float angle = start_ang;
|
||
|
float angle_delta;
|
||
|
|
||
|
angle_delta = fArc / (float)npoints;
|
||
|
|
||
|
// Add an additional points if we are not doing a full circle
|
||
|
if (fArc != 360.0)
|
||
|
{
|
||
|
++npoints;
|
||
|
}
|
||
|
|
||
|
for( point = 0; point < npoints; point++ )
|
||
|
{
|
||
|
if ( angle > 360 )
|
||
|
{
|
||
|
angle -= 360;
|
||
|
}
|
||
|
|
||
|
points[point][0] = V_rint(xCenter + (float)cos(DEG2RAD(angle)) * xrad);
|
||
|
points[point][1] = V_rint(yCenter + (float)sin(DEG2RAD(angle)) * yrad);
|
||
|
|
||
|
angle += angle_delta;
|
||
|
}
|
||
|
|
||
|
// Full circle, recopy the first point as the closing point.
|
||
|
if (fArc == 360.0)
|
||
|
{
|
||
|
points[point][0] = points[0][0];
|
||
|
points[point][1] = points[0][1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MakeArc(float x1, float y1, float x2, float y2, int npoints, float start_ang, float fArc, float points[][2])
|
||
|
{
|
||
|
float xrad = (x2 - x1) / 2.0f;
|
||
|
float yrad = (y2 - y1) / 2.0f;
|
||
|
|
||
|
// make centerpoint for polygon:
|
||
|
float xCenter = x1 + xrad;
|
||
|
float yCenter = y1 + yrad;
|
||
|
|
||
|
MakeArcCenterRadius( xCenter, yCenter, xrad, yrad, npoints, start_ang, fArc, points );
|
||
|
}
|
||
|
|
||
|
#define ARC_MAX_POINTS 4096
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : pBox -
|
||
|
// fStartAngle -
|
||
|
// iSides -
|
||
|
// fArc -
|
||
|
// iWallWidth -
|
||
|
// iAddHeight -
|
||
|
// bPreview -
|
||
|
// Output : Returns a group containing the arch solids.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CMapClass *CreateArch(BoundBox *pBox, float fStartAngle, int iSides, float fArc, int iWallWidth, int iAddHeight, BOOL bPreview)
|
||
|
{
|
||
|
float fOuterPoints[ARC_MAX_POINTS][2];
|
||
|
float fInnerPoints[ARC_MAX_POINTS][2];
|
||
|
|
||
|
//
|
||
|
// create outer points
|
||
|
//
|
||
|
MakeArc(pBox->bmins[AXIS_X], pBox->bmins[AXIS_Y],
|
||
|
pBox->bmaxs[AXIS_X], pBox->bmaxs[AXIS_Y], iSides,
|
||
|
fStartAngle, fArc, fOuterPoints);
|
||
|
|
||
|
//
|
||
|
// create inner points
|
||
|
//
|
||
|
MakeArc(pBox->bmins[AXIS_X] + iWallWidth,
|
||
|
pBox->bmins[AXIS_Y] + iWallWidth,
|
||
|
pBox->bmaxs[AXIS_X] - iWallWidth,
|
||
|
pBox->bmaxs[AXIS_Y] - iWallWidth, iSides,
|
||
|
fStartAngle, fArc, fInnerPoints);
|
||
|
|
||
|
|
||
|
//
|
||
|
// check wall width - if it's half or more of the total,
|
||
|
// set the inner poinst to the center point of the box
|
||
|
// and turn off the CreateSouthFace flag
|
||
|
//
|
||
|
BOOL bCreateSouthFace = TRUE;
|
||
|
Vector Center;
|
||
|
pBox->GetBoundsCenter(Center);
|
||
|
if((iWallWidth*2+8) >= (pBox->bmaxs[AXIS_X] - pBox->bmins[AXIS_X]) ||
|
||
|
(iWallWidth*2+8) >= (pBox->bmaxs[AXIS_Y] - pBox->bmins[AXIS_Y]))
|
||
|
{
|
||
|
for(int i = 0; i < ARC_MAX_POINTS; i++)
|
||
|
{
|
||
|
fInnerPoints[i][AXIS_X] = Center[AXIS_X];
|
||
|
fInnerPoints[i][AXIS_Y] = Center[AXIS_Y];
|
||
|
}
|
||
|
bCreateSouthFace = FALSE;
|
||
|
}
|
||
|
|
||
|
// create group for segments
|
||
|
CMapGroup *pGroup = new CMapGroup;
|
||
|
|
||
|
Vector MoveAccum( 0.f, 0.f, 0.f );
|
||
|
|
||
|
float fMinZ, fMaxZ;
|
||
|
|
||
|
fMinZ = pBox->bmins[2];
|
||
|
fMaxZ = pBox->bmaxs[2];
|
||
|
|
||
|
if ((fMaxZ - fMinZ) < 1.0f)
|
||
|
fMaxZ = fMinZ + 1.0f;
|
||
|
|
||
|
for (int i = 0; i < iSides; i++)
|
||
|
{
|
||
|
int iNextPoint = i+1;
|
||
|
if (iNextPoint >= iSides + 1)
|
||
|
iNextPoint = 0;
|
||
|
|
||
|
CMapSolid *pSolid = CreateSegment(
|
||
|
fMinZ, fMaxZ,
|
||
|
fOuterPoints, fInnerPoints,
|
||
|
i, iNextPoint, bCreateSouthFace);
|
||
|
|
||
|
pGroup->AddChild(pSolid);
|
||
|
|
||
|
if (iAddHeight && i) // don't move first segment
|
||
|
{
|
||
|
MoveAccum[2] += iAddHeight;
|
||
|
pSolid->TransMove(MoveAccum);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pGroup->CalcBounds(TRUE);
|
||
|
if (Options.general.bStretchArches)
|
||
|
{
|
||
|
// make sure size of group's bounds are size of original bounds -
|
||
|
// if not, scale up. this can happen when we use rotation.
|
||
|
Vector objsize, boundsize;
|
||
|
pBox->GetBoundsSize(boundsize);
|
||
|
pGroup->GetBoundsSize(objsize);
|
||
|
|
||
|
if (boundsize[AXIS_X] > objsize[AXIS_X] ||
|
||
|
boundsize[AXIS_Y] > objsize[AXIS_Y])
|
||
|
{
|
||
|
Vector scale;
|
||
|
scale[AXIS_X] = boundsize[AXIS_X] / objsize[AXIS_X];
|
||
|
scale[AXIS_Y] = boundsize[AXIS_Y] / objsize[AXIS_Y];
|
||
|
scale[AXIS_Z] = 1.0f; // xxxYWB scaling by 0 causes veneers, so I changed to 1.0
|
||
|
Vector center;
|
||
|
pBox->GetBoundsCenter(center);
|
||
|
pGroup->TransScale(center, scale);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pGroup;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : pBox -
|
||
|
// fStartAngle -
|
||
|
// iSides -
|
||
|
// fArc -
|
||
|
// iWallWidth -
|
||
|
// iAddHeight -
|
||
|
// bPreview -
|
||
|
// Output : Returns a group containing the arch solids.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
typedef float TorusPointList_t[ARC_MAX_POINTS][3];
|
||
|
|
||
|
CMapClass *CreateTorus(BoundBox *pBox, float fStartAngle, int iSides, float fArc, int iWallWidth, float flCrossSectionalRadius,
|
||
|
float fRotationStartAngle, int iRotationSides, float fRotationArc, int iAddHeight, BOOL bPreview)
|
||
|
{
|
||
|
float xCenter = (pBox->bmaxs[AXIS_X] + pBox->bmins[AXIS_X]) * 0.5f;
|
||
|
float yCenter = (pBox->bmaxs[AXIS_Y] + pBox->bmins[AXIS_Y]) * 0.5f;
|
||
|
float xRad = (pBox->bmaxs[AXIS_X] - xCenter);
|
||
|
float yRad = (pBox->bmaxs[AXIS_Y] - yCenter);
|
||
|
if (xRad < 0.0f )
|
||
|
{
|
||
|
xRad = 0.0f;
|
||
|
}
|
||
|
|
||
|
if (yRad < 0.0f )
|
||
|
{
|
||
|
yRad = 0.0f;
|
||
|
}
|
||
|
|
||
|
if ( flCrossSectionalRadius > (xRad * 0.5f) )
|
||
|
{
|
||
|
flCrossSectionalRadius = (xRad * 0.5f);
|
||
|
}
|
||
|
if ( flCrossSectionalRadius > (yRad * 0.5f) )
|
||
|
{
|
||
|
flCrossSectionalRadius = (yRad * 0.5f);
|
||
|
}
|
||
|
|
||
|
if ( iWallWidth < flCrossSectionalRadius )
|
||
|
{
|
||
|
flCrossSectionalRadius -= iWallWidth;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
iWallWidth = flCrossSectionalRadius;
|
||
|
flCrossSectionalRadius = 0.0f;
|
||
|
}
|
||
|
|
||
|
float flCrossSectionHalfWidth = flCrossSectionalRadius + iWallWidth;
|
||
|
xRad -= flCrossSectionHalfWidth;
|
||
|
yRad -= flCrossSectionHalfWidth;
|
||
|
|
||
|
float fOuterPoints[ARC_MAX_POINTS][2];
|
||
|
float fInnerPoints[ARC_MAX_POINTS][2];
|
||
|
|
||
|
// create outer points (unrotated)
|
||
|
MakeArcCenterRadius(0.0f, 0.0f,
|
||
|
flCrossSectionalRadius + iWallWidth, flCrossSectionalRadius + iWallWidth,
|
||
|
iSides, fStartAngle, fArc, fOuterPoints);
|
||
|
|
||
|
BOOL bCreateSouthFace = TRUE;
|
||
|
if ( flCrossSectionalRadius != 0.0f )
|
||
|
{
|
||
|
// create inner points (unrotated)
|
||
|
MakeArcCenterRadius(0.0f, 0.0f, flCrossSectionalRadius, flCrossSectionalRadius,
|
||
|
iSides, fStartAngle, fArc, fInnerPoints);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( int i = 0; i < iSides; i++)
|
||
|
{
|
||
|
fInnerPoints[i][0] = fInnerPoints[i][1] = 0.0f;
|
||
|
}
|
||
|
bCreateSouthFace = FALSE;
|
||
|
}
|
||
|
|
||
|
// create group for segments
|
||
|
CMapGroup *pGroup = new CMapGroup;
|
||
|
|
||
|
TorusPointList_t innerPoints[2];
|
||
|
TorusPointList_t outerPoints[2];
|
||
|
TorusPointList_t *pStartInnerPoints;
|
||
|
TorusPointList_t *pStartOuterPoints;
|
||
|
TorusPointList_t *pEndInnerPoints = &innerPoints[1];
|
||
|
TorusPointList_t *pEndOuterPoints = &outerPoints[1];
|
||
|
int nCurrIndex = 0;
|
||
|
|
||
|
float flCurrentZ = pBox->bmins[AXIS_Z] + iWallWidth + flCrossSectionalRadius;
|
||
|
float flDeltaZ = (float)iAddHeight / (float)(iRotationSides);
|
||
|
|
||
|
float flRotationAngle = fRotationStartAngle;
|
||
|
float flRotationDeltaAngle = fRotationArc / iRotationSides;
|
||
|
|
||
|
bool bIsCircle = ( iAddHeight == 0.0f ) && ( fRotationArc == 360.0f );
|
||
|
++iRotationSides;
|
||
|
for ( int i = 0; i != iRotationSides; ++i )
|
||
|
{
|
||
|
// This eliminates a seam in circular toruses
|
||
|
if ( bIsCircle && (i == iRotationSides - 1) )
|
||
|
{
|
||
|
flRotationAngle = fRotationStartAngle;
|
||
|
}
|
||
|
|
||
|
float xCurrCenter, yCurrCenter;
|
||
|
|
||
|
float flCosAngle = cos( DEG2RAD(flRotationAngle) );
|
||
|
float flSinAngle = sin( DEG2RAD(flRotationAngle) );
|
||
|
xCurrCenter = xCenter + xRad * flCosAngle;
|
||
|
yCurrCenter = yCenter + yRad * flSinAngle;
|
||
|
|
||
|
// Update buffers
|
||
|
pStartInnerPoints = pEndInnerPoints;
|
||
|
pStartOuterPoints = pEndOuterPoints;
|
||
|
pEndInnerPoints = &innerPoints[nCurrIndex];
|
||
|
pEndOuterPoints = &outerPoints[nCurrIndex];
|
||
|
nCurrIndex = 1 - nCurrIndex;
|
||
|
|
||
|
// Transform points into actual space.
|
||
|
int jPrevPoint = -1;
|
||
|
int j = 0;
|
||
|
do
|
||
|
{
|
||
|
// x original is transformed into x/y based on rotation
|
||
|
// y original is transformed into z
|
||
|
(*pEndInnerPoints)[j][0] = xCurrCenter + fInnerPoints[j][0] * flCosAngle;
|
||
|
(*pEndInnerPoints)[j][1] = yCurrCenter + fInnerPoints[j][0] * flSinAngle;
|
||
|
(*pEndInnerPoints)[j][2] = flCurrentZ + fInnerPoints[j][1];
|
||
|
|
||
|
(*pEndOuterPoints)[j][0] = xCurrCenter + fOuterPoints[j][0] * flCosAngle;
|
||
|
(*pEndOuterPoints)[j][1] = yCurrCenter + fOuterPoints[j][0] * flSinAngle;
|
||
|
(*pEndOuterPoints)[j][2] = flCurrentZ + fOuterPoints[j][1];
|
||
|
|
||
|
// We'll use the j == 0 data when iNextPoint = iSides - 1
|
||
|
if (( i != 0 ) && ( jPrevPoint != -1 ))
|
||
|
{
|
||
|
CMapSolid *pSolid = CreateSegment(
|
||
|
*pStartOuterPoints, *pStartInnerPoints,
|
||
|
*pEndOuterPoints, *pEndInnerPoints,
|
||
|
jPrevPoint, j, bCreateSouthFace);
|
||
|
|
||
|
pGroup->AddChild(pSolid);
|
||
|
}
|
||
|
|
||
|
jPrevPoint = j;
|
||
|
++j;
|
||
|
} while( jPrevPoint != iSides );
|
||
|
|
||
|
flRotationAngle += flRotationDeltaAngle;
|
||
|
flCurrentZ += flDeltaZ;
|
||
|
|
||
|
if ( flRotationAngle >= 360.0f )
|
||
|
{
|
||
|
flRotationAngle -= 360.0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pGroup->CalcBounds(TRUE);
|
||
|
|
||
|
if (Options.general.bStretchArches)
|
||
|
{
|
||
|
// make sure size of group's bounds are size of original bounds -
|
||
|
// if not, scale up. this can happen when we use rotation.
|
||
|
Vector objsize, boundsize;
|
||
|
pBox->GetBoundsSize(boundsize);
|
||
|
pGroup->GetBoundsSize(objsize);
|
||
|
|
||
|
if (boundsize[AXIS_X] > objsize[AXIS_X] ||
|
||
|
boundsize[AXIS_Y] > objsize[AXIS_Y])
|
||
|
{
|
||
|
Vector scale;
|
||
|
scale[AXIS_X] = boundsize[AXIS_X] / objsize[AXIS_X];
|
||
|
scale[AXIS_Y] = boundsize[AXIS_Y] / objsize[AXIS_Y];
|
||
|
scale[AXIS_Z] = 1.0f; // xxxYWB scaling by 0 causes veneers, so I changed to 1.0
|
||
|
Vector center;
|
||
|
pBox->GetBoundsCenter(center);
|
||
|
pGroup->TransScale(center, scale);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pGroup;
|
||
|
}
|
||
|
|
||
|
|