diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/createarch.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'hammer/createarch.cpp')
| -rw-r--r-- | hammer/createarch.cpp | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/hammer/createarch.cpp b/hammer/createarch.cpp new file mode 100644 index 0000000..6e4e2c0 --- /dev/null +++ b/hammer/createarch.cpp @@ -0,0 +1,657 @@ +//========= 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; +} + + |