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.

688 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "stdafx.h"
  7. #include "hammer.h"
  8. #include "StockSolids.h"
  9. #include "hammer_mathlib.h"
  10. #include "MapSolid.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include <tier0/memdbgon.h>
  13. #pragma warning(disable:4244)
  14. //Vector pmPoints[64];
  15. StockSolid::StockSolid(int nFields)
  16. {
  17. AllocateDataFields(nFields);
  18. cofs.Init();
  19. }
  20. StockSolid::~StockSolid()
  21. {
  22. if ( pFields )
  23. {
  24. delete[] pFields;
  25. pFields = NULL;
  26. }
  27. }
  28. void StockSolid::AllocateDataFields(int nFields_)
  29. {
  30. pFields = new STSDATAFIELD[nFields_];
  31. Assert(pFields);
  32. iMaxFields = nFields_;
  33. this->nFields = 0; // none yet
  34. }
  35. void StockSolid::Serialize(std::fstream& file, BOOL bIsStoring)
  36. {
  37. }
  38. int StockSolid::GetFieldCount() const
  39. {
  40. return nFields;
  41. }
  42. void StockSolid::SetFieldData(int iIndex, int iData)
  43. {
  44. Assert(iIndex < nFields);
  45. STSDATAFIELD& field = pFields[iIndex];
  46. field.iValue = iData;
  47. if(field.flags & DFFLAG_RANGED)
  48. {
  49. Assert(!(iData < field.iRangeLower || iData > field.iRangeUpper));
  50. }
  51. }
  52. int StockSolid::GetFieldData(int iIndex, int *piData) const
  53. {
  54. Assert(iIndex < nFields);
  55. STSDATAFIELD& field = pFields[iIndex];
  56. if(piData)
  57. piData[0] = field.iValue;
  58. return field.iValue;
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose:
  62. //-----------------------------------------------------------------------------
  63. void StockSolid::SetOrigin(const Vector &o)
  64. {
  65. origin = o;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. void StockSolid::SetCenterOffset(const Vector &ofs)
  71. {
  72. cofs = ofs;
  73. }
  74. void StockSolid::AddDataField(STSDF_TYPE type, const char *pszName, int iRangeLower, int iRangeUpper)
  75. {
  76. Assert(nFields < iMaxFields);
  77. STSDATAFIELD& field = pFields[nFields++];
  78. field.type = type;
  79. field.flags = 0;
  80. strcpy(field.szName, pszName);
  81. if(iRangeLower != -1)
  82. {
  83. field.flags |= DFFLAG_RANGED;
  84. field.iRangeLower = iRangeLower;
  85. field.iRangeUpper = iRangeUpper;
  86. }
  87. }
  88. // ----------------------------------------------------------------------------
  89. // StockBlock()
  90. // ----------------------------------------------------------------------------
  91. StockBlock::StockBlock() :
  92. StockSolid(3)
  93. {
  94. AddDataField(DFTYPE_INTEGER, "Width (X)");
  95. AddDataField(DFTYPE_INTEGER, "Depth (Y)");
  96. AddDataField(DFTYPE_INTEGER, "Height (Z)");
  97. }
  98. void StockBlock::SetFromBox(BoundBox *pBox)
  99. {
  100. // round floats before converting to integers
  101. SetFieldData(fieldWidth, (pBox->bmaxs[0] - pBox->bmins[0])+0.5f );
  102. SetFieldData(fieldDepth, (pBox->bmaxs[1] - pBox->bmins[1])+0.5f );
  103. SetFieldData(fieldHeight, (pBox->bmaxs[2] - pBox->bmins[2])+0.5f );
  104. Vector o;
  105. pBox->GetBoundsCenter(o);
  106. SetOrigin(o);
  107. }
  108. void StockBlock::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eAlignment)
  109. {
  110. CMapFace Face;
  111. float fDepth = float(GetFieldData(fieldDepth))/2;
  112. float fWidth = float(GetFieldData(fieldWidth))/2;
  113. float fHeight = float(GetFieldData(fieldHeight))/2;
  114. // create box
  115. Vector bmins, bmaxs;
  116. bmins[0] = origin[0] - fWidth + cofs[0];
  117. bmins[1] = origin[1] - fDepth + cofs[1];
  118. bmins[2] = origin[2] - fHeight + cofs[2];
  119. bmaxs[0] = origin[0] + fWidth + cofs[0];
  120. bmaxs[1] = origin[1] + fDepth + cofs[1];
  121. bmaxs[2] = origin[2] + fHeight + cofs[2];
  122. Vector Points[4];
  123. // x planes - top first
  124. Points[0][0] = bmins[0];
  125. Points[0][1] = bmaxs[1];
  126. Points[0][2] = bmaxs[2];
  127. Points[1][0] = bmaxs[0];
  128. Points[1][1] = bmaxs[1];
  129. Points[1][2] = bmaxs[2];
  130. Points[2][0] = bmaxs[0];
  131. Points[2][1] = bmins[1];
  132. Points[2][2] = bmaxs[2];
  133. Points[3][0] = bmins[0];
  134. Points[3][1] = bmins[1];
  135. Points[3][2] = bmaxs[2];
  136. Face.CreateFace(Points, 4, pSolid->IsCordonBrush());
  137. pSolid->AddFace(&Face);
  138. // top - modify heights
  139. for(int i = 0; i < 4; i++)
  140. {
  141. Points[i][2] = bmins[2];
  142. }
  143. Face.CreateFace(Points, -4, pSolid->IsCordonBrush());
  144. pSolid->AddFace(&Face);
  145. // y planes - left
  146. Points[0][0] = bmins[0];
  147. Points[0][1] = bmaxs[1];
  148. Points[0][2] = bmaxs[2];
  149. Points[1][0] = bmins[0];
  150. Points[1][1] = bmins[1];
  151. Points[1][2] = bmaxs[2];
  152. Points[2][0] = bmins[0];
  153. Points[2][1] = bmins[1];
  154. Points[2][2] = bmins[2];
  155. Points[3][0] = bmins[0];
  156. Points[3][1] = bmaxs[1];
  157. Points[3][2] = bmins[2];
  158. Face.CreateFace(Points, 4, pSolid->IsCordonBrush());
  159. pSolid->AddFace(&Face);
  160. // right - modify xloc
  161. for(int i = 0; i < 4; i++)
  162. {
  163. Points[i][0] = bmaxs[0];
  164. }
  165. Face.CreateFace(Points, -4, pSolid->IsCordonBrush());
  166. pSolid->AddFace(&Face);
  167. // x planes - farthest
  168. Points[0][0] = bmaxs[0];
  169. Points[0][1] = bmaxs[1];
  170. Points[0][2] = bmaxs[2];
  171. Points[1][0] = bmins[0];
  172. Points[1][1] = bmaxs[1];
  173. Points[1][2] = bmaxs[2];
  174. Points[2][0] = bmins[0];
  175. Points[2][1] = bmaxs[1];
  176. Points[2][2] = bmins[2];
  177. Points[3][0] = bmaxs[0];
  178. Points[3][1] = bmaxs[1];
  179. Points[3][2] = bmins[2];
  180. Face.CreateFace(Points, 4, pSolid->IsCordonBrush());
  181. pSolid->AddFace(&Face);
  182. // nearest - modify yloc
  183. for(int i = 0; i < 4; i++)
  184. {
  185. Points[i][1] = bmins[1];
  186. }
  187. Face.CreateFace(Points, -4, pSolid->IsCordonBrush());
  188. pSolid->AddFace(&Face);
  189. pSolid->CalcBounds();
  190. pSolid->InitializeTextureAxes(eAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
  191. }
  192. // ----------------------------------------------------------------------------
  193. // StockWedge()
  194. // ----------------------------------------------------------------------------
  195. StockWedge::StockWedge() :
  196. StockSolid(3)
  197. {
  198. AddDataField(DFTYPE_INTEGER, "Width (X)");
  199. AddDataField(DFTYPE_INTEGER, "Depth (Y)");
  200. AddDataField(DFTYPE_INTEGER, "Height (Z)");
  201. }
  202. void StockWedge::SetFromBox(BoundBox *pBox)
  203. {
  204. SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
  205. SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
  206. SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
  207. Vector o;
  208. pBox->GetBoundsCenter(o);
  209. SetOrigin(o);
  210. }
  211. void StockWedge::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
  212. {
  213. CMapFace Face;
  214. float fDepth = float(GetFieldData(fieldDepth))/2;
  215. float fWidth = float(GetFieldData(fieldWidth))/2;
  216. float fHeight = float(GetFieldData(fieldHeight))/2;
  217. Vector Points[4];
  218. // x planes - top
  219. Points[0][0] = origin[0] + fWidth;
  220. Points[0][1] = origin[1] + fDepth;
  221. Points[0][2] = origin[2] + fHeight;
  222. Points[1][0] = origin[0] + fWidth;
  223. Points[1][1] = origin[1] - fDepth;
  224. Points[1][2] = origin[2] + fHeight;
  225. Points[2][0] = origin[0] - fWidth;
  226. Points[2][1] = origin[1] - fDepth;
  227. Points[2][2] = origin[2] + fHeight;
  228. Face.CreateFace(Points, 3);
  229. pSolid->AddFace(&Face);
  230. // bottom
  231. for (int i = 0; i < 3; i++)
  232. {
  233. Points[i][2] = origin[2] - fHeight;
  234. }
  235. Face.CreateFace(Points, -3);
  236. pSolid->AddFace(&Face);
  237. // left (slant)
  238. Points[0][0] = origin[0] + fWidth;
  239. Points[0][1] = origin[1] + fDepth;
  240. Points[0][2] = origin[2] - fHeight;
  241. Points[1][0] = origin[0] + fWidth;
  242. Points[1][1] = origin[1] + fDepth;
  243. Points[1][2] = origin[2] + fHeight;
  244. Points[2][0] = origin[0] - fWidth;
  245. Points[2][1] = origin[1] - fDepth;
  246. Points[2][2] = origin[2] + fHeight;
  247. Points[3][0] = origin[0] - fWidth;
  248. Points[3][1] = origin[1] - fDepth;
  249. Points[3][2] = origin[2] - fHeight;
  250. Face.CreateFace(Points, 4);
  251. pSolid->AddFace(&Face);
  252. // south
  253. Points[0][0] = origin[0] + fWidth;
  254. Points[0][1] = origin[1] - fDepth;
  255. Points[0][2] = origin[2] + fHeight;
  256. Points[1][0] = origin[0] + fWidth;
  257. Points[1][1] = origin[1] - fDepth;
  258. Points[1][2] = origin[2] - fHeight;
  259. Points[2][0] = origin[0] - fWidth;
  260. Points[2][1] = origin[1] - fDepth;
  261. Points[2][2] = origin[2] - fHeight;
  262. Points[3][0] = origin[0] - fWidth;
  263. Points[3][1] = origin[1] - fDepth;
  264. Points[3][2] = origin[2] + fHeight;
  265. Face.CreateFace(Points, 4);
  266. pSolid->AddFace(&Face);
  267. // right
  268. Points[0][0] = origin[0] + fWidth;
  269. Points[0][1] = origin[1] + fDepth;
  270. Points[0][2] = origin[2] + fHeight;
  271. Points[1][0] = origin[0] + fWidth;
  272. Points[1][1] = origin[1] + fDepth;
  273. Points[1][2] = origin[2] - fHeight;
  274. Points[2][0] = origin[0] + fWidth;
  275. Points[2][1] = origin[1] - fDepth;
  276. Points[2][2] = origin[2] - fHeight;
  277. Points[3][0] = origin[0] + fWidth;
  278. Points[3][1] = origin[1] - fDepth;
  279. Points[3][2] = origin[2] + fHeight;
  280. Face.CreateFace(Points, 4);
  281. pSolid->AddFace(&Face);
  282. pSolid->CalcBounds();
  283. pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
  284. }
  285. // ----------------------------------------------------------------------------
  286. // StockCylinder()
  287. // ----------------------------------------------------------------------------
  288. StockCylinder::StockCylinder()
  289. : StockSolid(4)
  290. {
  291. AddDataField(DFTYPE_INTEGER, "Width (X)");
  292. AddDataField(DFTYPE_INTEGER, "Depth (Y)");
  293. AddDataField(DFTYPE_INTEGER, "Height (Z)");
  294. AddDataField(DFTYPE_INTEGER, "Number of Sides");
  295. SetFieldData(fieldSideCount, 8);
  296. }
  297. void StockCylinder::SetFromBox(BoundBox *pBox)
  298. {
  299. SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
  300. SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
  301. SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
  302. Vector o;
  303. pBox->GetBoundsCenter(o);
  304. SetOrigin(o);
  305. }
  306. void StockCylinder::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
  307. {
  308. CMapFace Face;
  309. float fDepth = float(GetFieldData(fieldDepth))/2;
  310. float fWidth = float(GetFieldData(fieldWidth))/2;
  311. float fHeight = float(GetFieldData(fieldHeight))/2;
  312. int nSides = GetFieldData(fieldSideCount);
  313. Vector pmPoints[64];
  314. polyMake(origin[0] - fWidth, origin[1] - fDepth, origin[0] + fWidth, origin[1] + fDepth, nSides, 0, pmPoints );
  315. // face 0 - top face
  316. for(int i = 0; i < nSides+1; i++)
  317. {
  318. pmPoints[i][2] = origin[2] - fHeight;
  319. }
  320. Face.CreateFace( pmPoints, -nSides);
  321. pSolid->AddFace(&Face);
  322. // bottom face
  323. for(int i = 0; i < nSides+1; i++)
  324. {
  325. pmPoints[i][2] = origin[2] + fHeight;
  326. }
  327. Face.CreateFace( pmPoints, nSides);
  328. pSolid->AddFace(&Face);
  329. // other sides
  330. Vector Points[4];
  331. for(int i = 0; i < nSides; i++)
  332. {
  333. Points[0][0] = pmPoints[i][0];
  334. Points[0][1] = pmPoints[i][1];
  335. Points[0][2] = origin[2] - fHeight;
  336. Points[1][0] = pmPoints[i+1][0];
  337. Points[1][1] = pmPoints[i+1][1];
  338. Points[1][2] = origin[2] - fHeight;
  339. Points[2][0] = pmPoints[i+1][0];
  340. Points[2][1] = pmPoints[i+1][1];
  341. Points[2][2] = origin[2] + fHeight;
  342. Points[3][0] = pmPoints[i][0];
  343. Points[3][1] = pmPoints[i][1];
  344. Points[3][2] = origin[2] + fHeight;
  345. Face.CreateFace(Points, 4);
  346. Face.texture.smooth = 1.f;
  347. pSolid->AddFace(&Face);
  348. }
  349. pSolid->CalcBounds();
  350. pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
  351. }
  352. // ----------------------------------------------------------------------------
  353. // StockSpike()
  354. // ----------------------------------------------------------------------------
  355. StockSpike::StockSpike()
  356. : StockSolid(4)
  357. {
  358. AddDataField(DFTYPE_INTEGER, "Width (X)");
  359. AddDataField(DFTYPE_INTEGER, "Depth (Y)");
  360. AddDataField(DFTYPE_INTEGER, "Height (Z)");
  361. AddDataField(DFTYPE_INTEGER, "Number of Sides");
  362. SetFieldData(fieldSideCount, 8);
  363. }
  364. void StockSpike::SetFromBox(BoundBox *pBox)
  365. {
  366. SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
  367. SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
  368. SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
  369. Vector o;
  370. pBox->GetBoundsCenter(o);
  371. SetOrigin(o);
  372. }
  373. void StockSpike::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
  374. {
  375. float fDepth = float(GetFieldData(fieldDepth))/2;
  376. float fWidth = float(GetFieldData(fieldWidth))/2;
  377. float fHeight = float(GetFieldData(fieldHeight))/2;
  378. int nSides = GetFieldData(fieldSideCount);
  379. CMapFace NewFace;
  380. // create bottom poly
  381. Vector pmPoints[64];
  382. polyMake(origin[0] - fWidth, origin[1] - fDepth, origin[0] + fWidth, origin[1] + fDepth, nSides, 0, pmPoints);
  383. // bottom face
  384. for(int i = 0; i < nSides+1; i++)
  385. {
  386. // YWB rounding???
  387. pmPoints[i][2] = V_rint(origin[2] - fHeight);
  388. }
  389. NewFace.CreateFace(pmPoints, -nSides);
  390. pSolid->AddFace(&NewFace);
  391. // other sides
  392. Vector Points[3];
  393. // get centerpoint
  394. Points[0][0] = origin[0];
  395. Points[0][1] = origin[1];
  396. // YWB rounding???
  397. Points[0][2] = V_rint(origin[2] + fHeight);
  398. for(int i = 0; i < nSides; i++)
  399. {
  400. Points[1][0] = pmPoints[i][0];
  401. Points[1][1] = pmPoints[i][1];
  402. Points[1][2] = pmPoints[i][2];
  403. Points[2][0] = pmPoints[i+1][0];
  404. Points[2][1] = pmPoints[i+1][1];
  405. Points[2][2] = pmPoints[i+1][2];
  406. NewFace.CreateFace(Points, 3);
  407. pSolid->AddFace(&NewFace);
  408. }
  409. pSolid->CalcBounds();
  410. pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
  411. }
  412. StockSphere::StockSphere()
  413. : StockSolid(4)
  414. {
  415. AddDataField(DFTYPE_INTEGER, "Width (X)");
  416. AddDataField(DFTYPE_INTEGER, "Depth (Y)");
  417. AddDataField(DFTYPE_INTEGER, "Height (Z)");
  418. AddDataField(DFTYPE_INTEGER, "Subdivisions");
  419. SetFieldData(fieldSideCount, 8);
  420. }
  421. void StockSphere::SetFromBox(BoundBox *pBox)
  422. {
  423. SetFieldData(fieldWidth, pBox->bmaxs[0] - pBox->bmins[0]);
  424. SetFieldData(fieldDepth, pBox->bmaxs[1] - pBox->bmins[1]);
  425. SetFieldData(fieldHeight, pBox->bmaxs[2] - pBox->bmins[2]);
  426. Vector o;
  427. pBox->GetBoundsCenter(o);
  428. SetOrigin(o);
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Purpose: Builds a tesselated sphere.
  432. // Input : pSolid - Pointer to a solid that will become a sphere.
  433. //-----------------------------------------------------------------------------
  434. void StockSphere::CreateMapSolid(CMapSolid *pSolid, TextureAlignment_t eTextureAlignment)
  435. {
  436. CMapFace Face;
  437. float fDepth = (float)GetFieldData(fieldDepth) / 2;
  438. float fWidth = (float)GetFieldData(fieldWidth) / 2;
  439. float fHeight = (float)GetFieldData(fieldHeight) / 2;
  440. int nSides = GetFieldData(fieldSideCount);
  441. float fAngle = 0;
  442. float fAngleStep = 180.0 / nSides;
  443. //
  444. // Build the sphere by building slices at constant angular intervals.
  445. //
  446. // Each slice is a ring of four-sided faces, except for the top and bottom slices,
  447. // which are flattened cones.
  448. //
  449. // Unrolled, a sphere made with 5 'sides' has 25 faces and looks like this:
  450. //
  451. // /\ /\ /\ /\ /\
  452. // / 0\/ 1\/ 2\/ 3\/ 4\
  453. // | 5| 6| 7| 8| 9|
  454. // | 10| 11| 12| 13| 14|
  455. // | 15| 16| 17| 18| 19|
  456. // \20/\21/\22/\23/\24/
  457. // \/ \/ \/ \/ \/
  458. //
  459. for (int nSlice = 0; nSlice < nSides; nSlice++)
  460. {
  461. float fAngle1 = fAngle + fAngleStep;
  462. //
  463. // Make the upper polygon.
  464. //
  465. Vector TopPoints[64];
  466. float fUpperWidth = fWidth * sin(DEG2RAD(fAngle));
  467. float fUpperDepth = fDepth * sin(DEG2RAD(fAngle));
  468. polyMake(origin[0] - fUpperWidth, origin[1] - fUpperDepth, origin[0] + fUpperWidth, origin[1] + fUpperDepth, nSides, 0, TopPoints);
  469. //
  470. // Make the lower polygon.
  471. //
  472. Vector BottomPoints[64];
  473. float fLowerWidth = fWidth * sin(DEG2RAD(fAngle1));
  474. float fLowerDepth = fDepth * sin(DEG2RAD(fAngle1));
  475. polyMake(origin[0] - fLowerWidth, origin[1] - fLowerDepth, origin[0] + fLowerWidth, origin[1] + fLowerDepth, nSides, 0, BottomPoints);
  476. //
  477. // Build the faces that connect the upper and lower polygons.
  478. //
  479. Vector Points[4];
  480. float fUpperHeight = origin[2] + fHeight * cos(DEG2RAD(fAngle));
  481. float fLowerHeight = origin[2] + fHeight * cos(DEG2RAD(fAngle1));
  482. for (int i = 0; i < nSides; i++)
  483. {
  484. if (nSlice != 0)
  485. {
  486. Points[0][0] = TopPoints[i + 1][0];
  487. Points[0][1] = TopPoints[i + 1][1];
  488. Points[0][2] = fUpperHeight;
  489. }
  490. Points[1][0] = TopPoints[i][0];
  491. Points[1][1] = TopPoints[i][1];
  492. Points[1][2] = fUpperHeight;
  493. Points[2][0] = BottomPoints[i][0];
  494. Points[2][1] = BottomPoints[i][1];
  495. Points[2][2] = fLowerHeight;
  496. if (nSlice != nSides - 1)
  497. {
  498. Points[3][0] = BottomPoints[i + 1][0];
  499. Points[3][1] = BottomPoints[i + 1][1];
  500. Points[3][2] = fLowerHeight;
  501. }
  502. //
  503. // Top and bottom are cones, not rings, so remove one vertex per face.
  504. //
  505. if (nSlice == 0)
  506. {
  507. Face.CreateFace(&Points[1], 3);
  508. }
  509. else if (nSlice == nSides - 1)
  510. {
  511. Face.CreateFace(Points, 3);
  512. }
  513. else
  514. {
  515. Face.CreateFace(Points, 4);
  516. }
  517. Face.texture.smooth = 1.f;
  518. pSolid->AddFace(&Face);
  519. }
  520. fAngle += fAngleStep;
  521. }
  522. pSolid->CalcBounds();
  523. pSolid->InitializeTextureAxes(eTextureAlignment, INIT_TEXTURE_ALL | INIT_TEXTURE_FORCE);
  524. }