Team Fortress 2 Source Code as on 22/4/2020
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.

657 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "OPTGeneral.h"
  9. #include "Options.h"
  10. #include "hammer_mathlib.h"
  11. #include "MapFace.h"
  12. #include "MapGroup.h"
  13. #include "MapSolid.h"
  14. #include "hammer.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include <tier0/memdbgon.h>
  17. //-----------------------------------------------------------------------------
  18. // Purpose: Create a segment using two polygons and a start and end position in
  19. // those polygons.
  20. // Input : fZMin -
  21. // fZMax -
  22. // fOuterPoints -
  23. // fInnerPoints -
  24. // iStart -
  25. // iEnd -
  26. // bCreateSouthFace -
  27. // Output :
  28. //-----------------------------------------------------------------------------
  29. static CMapSolid *CreateSegment(float fZMin, float fZMax, float fOuterPoints[][2], float fInnerPoints[][2], int iStart, int iEnd, BOOL bCreateSouthFace)
  30. {
  31. CMapFace Face;
  32. Vector points[4]; // all sides have four vertices
  33. CMapSolid *pSolid = new CMapSolid;
  34. int iNorthSouthPoints = 3 + (bCreateSouthFace ? 1 : 0);
  35. // create top face
  36. points[0][0] = fOuterPoints[iStart][0];
  37. points[0][1] = fOuterPoints[iStart][1];
  38. points[0][2] = fZMin;
  39. points[1][0] = fOuterPoints[iEnd][0];
  40. points[1][1] = fOuterPoints[iEnd][1];
  41. points[1][2] = fZMin;
  42. points[2][0] = fInnerPoints[iEnd][0];
  43. points[2][1] = fInnerPoints[iEnd][1];
  44. points[2][2] = fZMin;
  45. points[3][0] = fInnerPoints[iStart][0];
  46. points[3][1] = fInnerPoints[iStart][1];
  47. points[3][2] = fZMin;
  48. Face.CreateFace(points, iNorthSouthPoints);
  49. pSolid->AddFace(&Face);
  50. // bottom face - set other z value and reverse order
  51. for (int i = 0; i < 4; i++)
  52. {
  53. points[i][2] = fZMax;
  54. }
  55. Face.CreateFace(points, -iNorthSouthPoints);
  56. pSolid->AddFace(&Face);
  57. // left side
  58. points[0][0] = fOuterPoints[iStart][0];
  59. points[0][1] = fOuterPoints[iStart][1];
  60. points[0][2] = fZMax;
  61. points[1][0] = fOuterPoints[iStart][0];
  62. points[1][1] = fOuterPoints[iStart][1];
  63. points[1][2] = fZMin;
  64. points[2][0] = fInnerPoints[iStart][0];
  65. points[2][1] = fInnerPoints[iStart][1];
  66. points[2][2] = fZMin;
  67. points[3][0] = fInnerPoints[iStart][0];
  68. points[3][1] = fInnerPoints[iStart][1];
  69. points[3][2] = fZMax;
  70. Face.CreateFace(points, 4);
  71. pSolid->AddFace(&Face);
  72. // right side
  73. points[0][0] = fOuterPoints[iEnd][0];
  74. points[0][1] = fOuterPoints[iEnd][1];
  75. points[0][2] = fZMin;
  76. points[1][0] = fOuterPoints[iEnd][0];
  77. points[1][1] = fOuterPoints[iEnd][1];
  78. points[1][2] = fZMax;
  79. points[2][0] = fInnerPoints[iEnd][0];
  80. points[2][1] = fInnerPoints[iEnd][1];
  81. points[2][2] = fZMax;
  82. points[3][0] = fInnerPoints[iEnd][0];
  83. points[3][1] = fInnerPoints[iEnd][1];
  84. points[3][2] = fZMin;
  85. Face.CreateFace(points, 4);
  86. pSolid->AddFace(&Face);
  87. // north face
  88. points[0][0] = fOuterPoints[iEnd][0];
  89. points[0][1] = fOuterPoints[iEnd][1];
  90. points[0][2] = fZMin;
  91. points[1][0] = fOuterPoints[iStart][0];
  92. points[1][1] = fOuterPoints[iStart][1];
  93. points[1][2] = fZMin;
  94. points[2][0] = fOuterPoints[iStart][0];
  95. points[2][1] = fOuterPoints[iStart][1];
  96. points[2][2] = fZMax;
  97. points[3][0] = fOuterPoints[iEnd][0];
  98. points[3][1] = fOuterPoints[iEnd][1];
  99. points[3][2] = fZMax;
  100. Face.CreateFace(points, 4);
  101. pSolid->AddFace(&Face);
  102. // south face
  103. if (bCreateSouthFace)
  104. {
  105. points[0][0] = fInnerPoints[iStart][0];
  106. points[0][1] = fInnerPoints[iStart][1];
  107. points[0][2] = fZMin;
  108. points[1][0] = fInnerPoints[iEnd][0];
  109. points[1][1] = fInnerPoints[iEnd][1];
  110. points[1][2] = fZMin;
  111. points[2][0] = fInnerPoints[iEnd][0];
  112. points[2][1] = fInnerPoints[iEnd][1];
  113. points[2][2] = fZMax;
  114. points[3][0] = fInnerPoints[iStart][0];
  115. points[3][1] = fInnerPoints[iStart][1];
  116. points[3][2] = fZMax;
  117. Face.CreateFace(points, 4);
  118. pSolid->AddFace(&Face);
  119. }
  120. pSolid->InitializeTextureAxes(Options.GetTextureAlignment(), INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
  121. return(pSolid);
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose: Create a segment using two polygons and a start and end position in
  125. // those polygons.
  126. // Input : fZMin -
  127. // fZMax -
  128. // fOuterPoints -
  129. // fInnerPoints -
  130. // iStart -
  131. // iEnd -
  132. // bCreateSouthFace -
  133. // Output :
  134. //-----------------------------------------------------------------------------
  135. static CMapSolid *CreateSegment(float fStartOuterPoints[][3], float fStartInnerPoints[][3],
  136. float fEndOuterPoints[][3], float fEndInnerPoints[][3],
  137. int iStart, int iEnd, BOOL bCreateSouthFace)
  138. {
  139. CMapFace Face;
  140. Vector points[4]; // all sides have four vertices
  141. CMapSolid *pSolid = new CMapSolid;
  142. // create top face
  143. points[0][0] = fStartOuterPoints[iStart][0];
  144. points[0][1] = fStartOuterPoints[iStart][1];
  145. points[0][2] = fStartOuterPoints[iStart][2];
  146. points[1][0] = fStartOuterPoints[iEnd][0];
  147. points[1][1] = fStartOuterPoints[iEnd][1];
  148. points[1][2] = fStartOuterPoints[iEnd][2];
  149. points[2][0] = fStartInnerPoints[iEnd][0];
  150. points[2][1] = fStartInnerPoints[iEnd][1];
  151. points[2][2] = fStartInnerPoints[iEnd][2];
  152. points[3][0] = fStartInnerPoints[iStart][0];
  153. points[3][1] = fStartInnerPoints[iStart][1];
  154. points[3][2] = fStartInnerPoints[iStart][2];
  155. Face.CreateFace(points, -4);
  156. pSolid->AddFace(&Face);
  157. // bottom face - set other z value and reverse order
  158. points[0][0] = fEndOuterPoints[iStart][0];
  159. points[0][1] = fEndOuterPoints[iStart][1];
  160. points[0][2] = fEndOuterPoints[iStart][2];
  161. points[1][0] = fEndOuterPoints[iEnd][0];
  162. points[1][1] = fEndOuterPoints[iEnd][1];
  163. points[1][2] = fEndOuterPoints[iEnd][2];
  164. points[2][0] = fEndInnerPoints[iEnd][0];
  165. points[2][1] = fEndInnerPoints[iEnd][1];
  166. points[2][2] = fEndInnerPoints[iEnd][2];
  167. points[3][0] = fEndInnerPoints[iStart][0];
  168. points[3][1] = fEndInnerPoints[iStart][1];
  169. points[3][2] = fEndInnerPoints[iStart][2];
  170. Face.CreateFace(points, 4);
  171. pSolid->AddFace(&Face);
  172. // left side
  173. points[0][0] = fEndOuterPoints[iStart][0];
  174. points[0][1] = fEndOuterPoints[iStart][1];
  175. points[0][2] = fEndOuterPoints[iStart][2];
  176. points[1][0] = fStartOuterPoints[iStart][0];
  177. points[1][1] = fStartOuterPoints[iStart][1];
  178. points[1][2] = fStartOuterPoints[iStart][2];
  179. points[2][0] = fStartInnerPoints[iStart][0];
  180. points[2][1] = fStartInnerPoints[iStart][1];
  181. points[2][2] = fStartInnerPoints[iStart][2];
  182. points[3][0] = fEndInnerPoints[iStart][0];
  183. points[3][1] = fEndInnerPoints[iStart][1];
  184. points[3][2] = fEndInnerPoints[iStart][2];
  185. Face.CreateFace(points, -4);
  186. pSolid->AddFace(&Face);
  187. // right side
  188. points[0][0] = fStartOuterPoints[iEnd][0];
  189. points[0][1] = fStartOuterPoints[iEnd][1];
  190. points[0][2] = fStartOuterPoints[iEnd][2];
  191. points[1][0] = fEndOuterPoints[iEnd][0];
  192. points[1][1] = fEndOuterPoints[iEnd][1];
  193. points[1][2] = fEndOuterPoints[iEnd][2];
  194. points[2][0] = fEndInnerPoints[iEnd][0];
  195. points[2][1] = fEndInnerPoints[iEnd][1];
  196. points[2][2] = fEndInnerPoints[iEnd][2];
  197. points[3][0] = fStartInnerPoints[iEnd][0];
  198. points[3][1] = fStartInnerPoints[iEnd][1];
  199. points[3][2] = fStartInnerPoints[iEnd][2];
  200. Face.CreateFace(points, -4);
  201. pSolid->AddFace(&Face);
  202. // north face
  203. points[0][0] = fStartOuterPoints[iEnd][0];
  204. points[0][1] = fStartOuterPoints[iEnd][1];
  205. points[0][2] = fStartOuterPoints[iEnd][2];
  206. points[1][0] = fStartOuterPoints[iStart][0];
  207. points[1][1] = fStartOuterPoints[iStart][1];
  208. points[1][2] = fStartOuterPoints[iStart][2];
  209. points[2][0] = fEndOuterPoints[iStart][0];
  210. points[2][1] = fEndOuterPoints[iStart][1];
  211. points[2][2] = fEndOuterPoints[iStart][2];
  212. points[3][0] = fEndOuterPoints[iEnd][0];
  213. points[3][1] = fEndOuterPoints[iEnd][1];
  214. points[3][2] = fEndOuterPoints[iEnd][2];
  215. Face.CreateFace(points, -4);
  216. pSolid->AddFace(&Face);
  217. // south face
  218. if (bCreateSouthFace)
  219. {
  220. points[0][0] = fStartInnerPoints[iStart][0];
  221. points[0][1] = fStartInnerPoints[iStart][1];
  222. points[0][2] = fStartInnerPoints[iStart][2];
  223. points[1][0] = fStartInnerPoints[iEnd][0];
  224. points[1][1] = fStartInnerPoints[iEnd][1];
  225. points[1][2] = fStartInnerPoints[iEnd][2];
  226. points[2][0] = fEndInnerPoints[iEnd][0];
  227. points[2][1] = fEndInnerPoints[iEnd][1];
  228. points[2][2] = fEndInnerPoints[iEnd][2];
  229. points[3][0] = fEndInnerPoints[iStart][0];
  230. points[3][1] = fEndInnerPoints[iStart][1];
  231. points[3][2] = fEndInnerPoints[iStart][2];
  232. Face.CreateFace(points, -4);
  233. pSolid->AddFace(&Face);
  234. }
  235. pSolid->InitializeTextureAxes(Options.GetTextureAlignment(), INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
  236. return(pSolid);
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Make a 2d arc
  240. //-----------------------------------------------------------------------------
  241. void MakeArcCenterRadius(float xCenter, float yCenter, float xrad, float yrad, int npoints, float start_ang, float fArc, float points[][2])
  242. {
  243. int point;
  244. float angle = start_ang;
  245. float angle_delta;
  246. angle_delta = fArc / (float)npoints;
  247. // Add an additional points if we are not doing a full circle
  248. if (fArc != 360.0)
  249. {
  250. ++npoints;
  251. }
  252. for( point = 0; point < npoints; point++ )
  253. {
  254. if ( angle > 360 )
  255. {
  256. angle -= 360;
  257. }
  258. points[point][0] = V_rint(xCenter + (float)cos(DEG2RAD(angle)) * xrad);
  259. points[point][1] = V_rint(yCenter + (float)sin(DEG2RAD(angle)) * yrad);
  260. angle += angle_delta;
  261. }
  262. // Full circle, recopy the first point as the closing point.
  263. if (fArc == 360.0)
  264. {
  265. points[point][0] = points[0][0];
  266. points[point][1] = points[0][1];
  267. }
  268. }
  269. void MakeArc(float x1, float y1, float x2, float y2, int npoints, float start_ang, float fArc, float points[][2])
  270. {
  271. float xrad = (x2 - x1) / 2.0f;
  272. float yrad = (y2 - y1) / 2.0f;
  273. // make centerpoint for polygon:
  274. float xCenter = x1 + xrad;
  275. float yCenter = y1 + yrad;
  276. MakeArcCenterRadius( xCenter, yCenter, xrad, yrad, npoints, start_ang, fArc, points );
  277. }
  278. #define ARC_MAX_POINTS 4096
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. // Input : pBox -
  282. // fStartAngle -
  283. // iSides -
  284. // fArc -
  285. // iWallWidth -
  286. // iAddHeight -
  287. // bPreview -
  288. // Output : Returns a group containing the arch solids.
  289. //-----------------------------------------------------------------------------
  290. CMapClass *CreateArch(BoundBox *pBox, float fStartAngle, int iSides, float fArc, int iWallWidth, int iAddHeight, BOOL bPreview)
  291. {
  292. float fOuterPoints[ARC_MAX_POINTS][2];
  293. float fInnerPoints[ARC_MAX_POINTS][2];
  294. //
  295. // create outer points
  296. //
  297. MakeArc(pBox->bmins[AXIS_X], pBox->bmins[AXIS_Y],
  298. pBox->bmaxs[AXIS_X], pBox->bmaxs[AXIS_Y], iSides,
  299. fStartAngle, fArc, fOuterPoints);
  300. //
  301. // create inner points
  302. //
  303. MakeArc(pBox->bmins[AXIS_X] + iWallWidth,
  304. pBox->bmins[AXIS_Y] + iWallWidth,
  305. pBox->bmaxs[AXIS_X] - iWallWidth,
  306. pBox->bmaxs[AXIS_Y] - iWallWidth, iSides,
  307. fStartAngle, fArc, fInnerPoints);
  308. //
  309. // check wall width - if it's half or more of the total,
  310. // set the inner poinst to the center point of the box
  311. // and turn off the CreateSouthFace flag
  312. //
  313. BOOL bCreateSouthFace = TRUE;
  314. Vector Center;
  315. pBox->GetBoundsCenter(Center);
  316. if((iWallWidth*2+8) >= (pBox->bmaxs[AXIS_X] - pBox->bmins[AXIS_X]) ||
  317. (iWallWidth*2+8) >= (pBox->bmaxs[AXIS_Y] - pBox->bmins[AXIS_Y]))
  318. {
  319. for(int i = 0; i < ARC_MAX_POINTS; i++)
  320. {
  321. fInnerPoints[i][AXIS_X] = Center[AXIS_X];
  322. fInnerPoints[i][AXIS_Y] = Center[AXIS_Y];
  323. }
  324. bCreateSouthFace = FALSE;
  325. }
  326. // create group for segments
  327. CMapGroup *pGroup = new CMapGroup;
  328. Vector MoveAccum( 0.f, 0.f, 0.f );
  329. float fMinZ, fMaxZ;
  330. fMinZ = pBox->bmins[2];
  331. fMaxZ = pBox->bmaxs[2];
  332. if ((fMaxZ - fMinZ) < 1.0f)
  333. fMaxZ = fMinZ + 1.0f;
  334. for (int i = 0; i < iSides; i++)
  335. {
  336. int iNextPoint = i+1;
  337. if (iNextPoint >= iSides + 1)
  338. iNextPoint = 0;
  339. CMapSolid *pSolid = CreateSegment(
  340. fMinZ, fMaxZ,
  341. fOuterPoints, fInnerPoints,
  342. i, iNextPoint, bCreateSouthFace);
  343. pGroup->AddChild(pSolid);
  344. if (iAddHeight && i) // don't move first segment
  345. {
  346. MoveAccum[2] += iAddHeight;
  347. pSolid->TransMove(MoveAccum);
  348. }
  349. }
  350. pGroup->CalcBounds(TRUE);
  351. if (Options.general.bStretchArches)
  352. {
  353. // make sure size of group's bounds are size of original bounds -
  354. // if not, scale up. this can happen when we use rotation.
  355. Vector objsize, boundsize;
  356. pBox->GetBoundsSize(boundsize);
  357. pGroup->GetBoundsSize(objsize);
  358. if (boundsize[AXIS_X] > objsize[AXIS_X] ||
  359. boundsize[AXIS_Y] > objsize[AXIS_Y])
  360. {
  361. Vector scale;
  362. scale[AXIS_X] = boundsize[AXIS_X] / objsize[AXIS_X];
  363. scale[AXIS_Y] = boundsize[AXIS_Y] / objsize[AXIS_Y];
  364. scale[AXIS_Z] = 1.0f; // xxxYWB scaling by 0 causes veneers, so I changed to 1.0
  365. Vector center;
  366. pBox->GetBoundsCenter(center);
  367. pGroup->TransScale(center, scale);
  368. }
  369. }
  370. return pGroup;
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose:
  374. // Input : pBox -
  375. // fStartAngle -
  376. // iSides -
  377. // fArc -
  378. // iWallWidth -
  379. // iAddHeight -
  380. // bPreview -
  381. // Output : Returns a group containing the arch solids.
  382. //-----------------------------------------------------------------------------
  383. typedef float TorusPointList_t[ARC_MAX_POINTS][3];
  384. CMapClass *CreateTorus(BoundBox *pBox, float fStartAngle, int iSides, float fArc, int iWallWidth, float flCrossSectionalRadius,
  385. float fRotationStartAngle, int iRotationSides, float fRotationArc, int iAddHeight, BOOL bPreview)
  386. {
  387. float xCenter = (pBox->bmaxs[AXIS_X] + pBox->bmins[AXIS_X]) * 0.5f;
  388. float yCenter = (pBox->bmaxs[AXIS_Y] + pBox->bmins[AXIS_Y]) * 0.5f;
  389. float xRad = (pBox->bmaxs[AXIS_X] - xCenter);
  390. float yRad = (pBox->bmaxs[AXIS_Y] - yCenter);
  391. if (xRad < 0.0f )
  392. {
  393. xRad = 0.0f;
  394. }
  395. if (yRad < 0.0f )
  396. {
  397. yRad = 0.0f;
  398. }
  399. if ( flCrossSectionalRadius > (xRad * 0.5f) )
  400. {
  401. flCrossSectionalRadius = (xRad * 0.5f);
  402. }
  403. if ( flCrossSectionalRadius > (yRad * 0.5f) )
  404. {
  405. flCrossSectionalRadius = (yRad * 0.5f);
  406. }
  407. if ( iWallWidth < flCrossSectionalRadius )
  408. {
  409. flCrossSectionalRadius -= iWallWidth;
  410. }
  411. else
  412. {
  413. iWallWidth = flCrossSectionalRadius;
  414. flCrossSectionalRadius = 0.0f;
  415. }
  416. float flCrossSectionHalfWidth = flCrossSectionalRadius + iWallWidth;
  417. xRad -= flCrossSectionHalfWidth;
  418. yRad -= flCrossSectionHalfWidth;
  419. float fOuterPoints[ARC_MAX_POINTS][2];
  420. float fInnerPoints[ARC_MAX_POINTS][2];
  421. // create outer points (unrotated)
  422. MakeArcCenterRadius(0.0f, 0.0f,
  423. flCrossSectionalRadius + iWallWidth, flCrossSectionalRadius + iWallWidth,
  424. iSides, fStartAngle, fArc, fOuterPoints);
  425. BOOL bCreateSouthFace = TRUE;
  426. if ( flCrossSectionalRadius != 0.0f )
  427. {
  428. // create inner points (unrotated)
  429. MakeArcCenterRadius(0.0f, 0.0f, flCrossSectionalRadius, flCrossSectionalRadius,
  430. iSides, fStartAngle, fArc, fInnerPoints);
  431. }
  432. else
  433. {
  434. for( int i = 0; i < iSides; i++)
  435. {
  436. fInnerPoints[i][0] = fInnerPoints[i][1] = 0.0f;
  437. }
  438. bCreateSouthFace = FALSE;
  439. }
  440. // create group for segments
  441. CMapGroup *pGroup = new CMapGroup;
  442. TorusPointList_t innerPoints[2];
  443. TorusPointList_t outerPoints[2];
  444. TorusPointList_t *pStartInnerPoints;
  445. TorusPointList_t *pStartOuterPoints;
  446. TorusPointList_t *pEndInnerPoints = &innerPoints[1];
  447. TorusPointList_t *pEndOuterPoints = &outerPoints[1];
  448. int nCurrIndex = 0;
  449. float flCurrentZ = pBox->bmins[AXIS_Z] + iWallWidth + flCrossSectionalRadius;
  450. float flDeltaZ = (float)iAddHeight / (float)(iRotationSides);
  451. float flRotationAngle = fRotationStartAngle;
  452. float flRotationDeltaAngle = fRotationArc / iRotationSides;
  453. bool bIsCircle = ( iAddHeight == 0.0f ) && ( fRotationArc == 360.0f );
  454. ++iRotationSides;
  455. for ( int i = 0; i != iRotationSides; ++i )
  456. {
  457. // This eliminates a seam in circular toruses
  458. if ( bIsCircle && (i == iRotationSides - 1) )
  459. {
  460. flRotationAngle = fRotationStartAngle;
  461. }
  462. float xCurrCenter, yCurrCenter;
  463. float flCosAngle = cos( DEG2RAD(flRotationAngle) );
  464. float flSinAngle = sin( DEG2RAD(flRotationAngle) );
  465. xCurrCenter = xCenter + xRad * flCosAngle;
  466. yCurrCenter = yCenter + yRad * flSinAngle;
  467. // Update buffers
  468. pStartInnerPoints = pEndInnerPoints;
  469. pStartOuterPoints = pEndOuterPoints;
  470. pEndInnerPoints = &innerPoints[nCurrIndex];
  471. pEndOuterPoints = &outerPoints[nCurrIndex];
  472. nCurrIndex = 1 - nCurrIndex;
  473. // Transform points into actual space.
  474. int jPrevPoint = -1;
  475. int j = 0;
  476. do
  477. {
  478. // x original is transformed into x/y based on rotation
  479. // y original is transformed into z
  480. (*pEndInnerPoints)[j][0] = xCurrCenter + fInnerPoints[j][0] * flCosAngle;
  481. (*pEndInnerPoints)[j][1] = yCurrCenter + fInnerPoints[j][0] * flSinAngle;
  482. (*pEndInnerPoints)[j][2] = flCurrentZ + fInnerPoints[j][1];
  483. (*pEndOuterPoints)[j][0] = xCurrCenter + fOuterPoints[j][0] * flCosAngle;
  484. (*pEndOuterPoints)[j][1] = yCurrCenter + fOuterPoints[j][0] * flSinAngle;
  485. (*pEndOuterPoints)[j][2] = flCurrentZ + fOuterPoints[j][1];
  486. // We'll use the j == 0 data when iNextPoint = iSides - 1
  487. if (( i != 0 ) && ( jPrevPoint != -1 ))
  488. {
  489. CMapSolid *pSolid = CreateSegment(
  490. *pStartOuterPoints, *pStartInnerPoints,
  491. *pEndOuterPoints, *pEndInnerPoints,
  492. jPrevPoint, j, bCreateSouthFace);
  493. pGroup->AddChild(pSolid);
  494. }
  495. jPrevPoint = j;
  496. ++j;
  497. } while( jPrevPoint != iSides );
  498. flRotationAngle += flRotationDeltaAngle;
  499. flCurrentZ += flDeltaZ;
  500. if ( flRotationAngle >= 360.0f )
  501. {
  502. flRotationAngle -= 360.0f;
  503. }
  504. }
  505. pGroup->CalcBounds(TRUE);
  506. if (Options.general.bStretchArches)
  507. {
  508. // make sure size of group's bounds are size of original bounds -
  509. // if not, scale up. this can happen when we use rotation.
  510. Vector objsize, boundsize;
  511. pBox->GetBoundsSize(boundsize);
  512. pGroup->GetBoundsSize(objsize);
  513. if (boundsize[AXIS_X] > objsize[AXIS_X] ||
  514. boundsize[AXIS_Y] > objsize[AXIS_Y])
  515. {
  516. Vector scale;
  517. scale[AXIS_X] = boundsize[AXIS_X] / objsize[AXIS_X];
  518. scale[AXIS_Y] = boundsize[AXIS_Y] / objsize[AXIS_Y];
  519. scale[AXIS_Z] = 1.0f; // xxxYWB scaling by 0 causes veneers, so I changed to 1.0
  520. Vector center;
  521. pBox->GetBoundsCenter(center);
  522. pGroup->TransScale(center, scale);
  523. }
  524. }
  525. return pGroup;
  526. }