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.

535 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "stdafx.h"
  10. #include "hammer.h"
  11. #include "hammer_mathlib.h"
  12. #include "TorusDlg.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include <tier0/memdbgon.h>
  15. static LPCTSTR pszSection = "Torus";
  16. void MakeArcCenterRadius(float xCenter, float yCenter, float xrad, float yrad, int npoints, float start_ang, float fArc, float points[][2]);
  17. void MakeArc(float x1, float y1, float x2, float y2, int npoints, float start_ang, float fArc, float points[][2]);
  18. CTorusDlg::CTorusDlg(Vector& boxmins, Vector& boxmaxs, CWnd* pParent /*=NULL*/)
  19. : CDialog(CTorusDlg::IDD, pParent)
  20. {
  21. bmins = boxmins;
  22. bmaxs = boxmaxs;
  23. //{{AFX_DATA_INIT(CTorusDlg)
  24. m_iSides = 0;
  25. m_iWallWidth = 0;
  26. m_iAddHeight = 0;
  27. m_fArc = 0.0f;
  28. m_fAngle = 0.0f;
  29. m_fRotationArc = 0.0f;
  30. m_fRotationAngle = 0.0f;
  31. m_iRotationSides = 0;
  32. m_fCrossSectionRadius = 0;
  33. //}}AFX_DATA_INIT
  34. // load up old defaults
  35. CString str;
  36. m_iWallWidth = AfxGetApp()->GetProfileInt(pszSection, "Wall Width", 32);
  37. str = AfxGetApp()->GetProfileString(pszSection, "Arc_", "360");
  38. m_fArc = atof(str);
  39. m_iSides = AfxGetApp()->GetProfileInt(pszSection, "Sides", 16);
  40. str = AfxGetApp()->GetProfileString(pszSection, "Start Angle_", "0");
  41. m_fAngle = atof(str);
  42. str = AfxGetApp()->GetProfileString(pszSection, "Rotation Arc_", "360");
  43. m_fRotationArc = atof(str);
  44. m_iRotationSides = AfxGetApp()->GetProfileInt(pszSection, "Rotation Sides", 16);
  45. str = AfxGetApp()->GetProfileString(pszSection, "Rotation Start Angle_", "0");
  46. m_fRotationAngle = atof(str);
  47. m_iAddHeight = AfxGetApp()->GetProfileInt(pszSection, "Add Height", 0);
  48. Vector vecSize;
  49. VectorSubtract( bmaxs, bmins, vecSize );
  50. if ( m_iAddHeight > vecSize.z )
  51. {
  52. m_iAddHeight = vecSize.z;
  53. }
  54. // This is the maximum cross-section radius
  55. m_fCrossSectionRadius = MaxTorusCrossSectionRadius();
  56. }
  57. void CTorusDlg::SaveValues()
  58. {
  59. CString str;
  60. AfxGetApp()->WriteProfileInt(pszSection, "Wall Width", m_iWallWidth);
  61. str.Format("%f", m_fArc);
  62. AfxGetApp()->WriteProfileString(pszSection, "Arc_", str);
  63. AfxGetApp()->WriteProfileInt(pszSection, "Sides", m_iSides);
  64. str.Format("%f", m_fAngle);
  65. AfxGetApp()->WriteProfileString(pszSection, "Start Angle_", str);
  66. str.Format("%f", m_fRotationArc);
  67. AfxGetApp()->WriteProfileString(pszSection, "Rotation Arc_", str);
  68. str.Format("%f", m_fRotationAngle);
  69. AfxGetApp()->WriteProfileString(pszSection, "Rotation Start Angle_", str);
  70. AfxGetApp()->WriteProfileInt(pszSection, "Rotation Sides", m_iRotationSides);
  71. AfxGetApp()->WriteProfileInt(pszSection, "Add Height", m_iAddHeight);
  72. }
  73. void CTorusDlg::DoDataExchange(CDataExchange* pDX)
  74. {
  75. CDialog::DoDataExchange(pDX);
  76. //{{AFX_DATA_MAP(CTorusDlg)
  77. DDX_Control(pDX, IDC_ANGLESPIN, m_cStartAngleSpin);
  78. DDX_Control(pDX, IDC_WALLWIDTHSPIN, m_cWallWidthSpin);
  79. DDX_Control(pDX, IDC_WALLWIDTH, m_cWallWidth);
  80. DDX_Control(pDX, IDC_SIDESSPIN, m_cSidesSpin);
  81. DDX_Control(pDX, IDC_SIDES, m_cSides);
  82. DDX_Control(pDX, IDC_ARCSPIN, m_cArcSpin);
  83. DDX_Control(pDX, IDC_ARC, m_cArc);
  84. DDX_Control(pDX, IDC_PREVIEW, m_cPreview);
  85. DDX_Control(pDX, IDC_PREVIEW_TOP_VIEW, m_cTopViewPreview);
  86. DDX_Text(pDX, IDC_SIDES, m_iSides);
  87. DDV_MinMaxInt(pDX, m_iSides, 3, 2048);
  88. DDX_Text(pDX, IDC_WALLWIDTH, m_iWallWidth);
  89. DDX_Text(pDX, IDC_ADDHEIGHT, m_iAddHeight);
  90. DDX_Text(pDX, IDC_ARC, m_fArc);
  91. DDV_MinMaxFloat(pDX, m_fArc, 8.f, 360.f);
  92. DDX_Text(pDX, IDC_ANGLE, m_fAngle);
  93. DDV_MinMaxFloat(pDX, m_fAngle, -360.0f, 360.f);
  94. DDX_Text(pDX, IDC_ROTATION_ARC, m_fRotationArc);
  95. DDV_MinMaxFloat(pDX, m_fRotationArc, 0.f, 3600.f);
  96. DDX_Text(pDX, IDC_ROTATION_ANGLE, m_fRotationAngle);
  97. DDV_MinMaxFloat(pDX, m_fRotationAngle, -360.0f, 360.f);
  98. DDX_Text(pDX, IDC_ROTATION_SIDES, m_iRotationSides);
  99. DDV_MinMaxInt(pDX, m_iRotationSides, 3, 2048);
  100. DDX_Text(pDX, IDC_CROSS_SECTION_RADIUS, m_fCrossSectionRadius);
  101. DDV_MinMaxFloat(pDX, m_fCrossSectionRadius, 0.f, 5000.f);
  102. //}}AFX_DATA_MAP
  103. if ( pDX->m_bSaveAndValidate )
  104. {
  105. Vector vecSize;
  106. VectorSubtract( bmaxs, bmins, vecSize );
  107. if ( m_iAddHeight > vecSize.z )
  108. {
  109. m_iAddHeight = vecSize.z;
  110. }
  111. }
  112. }
  113. BEGIN_MESSAGE_MAP(CTorusDlg, CDialog)
  114. //{{AFX_MSG_MAP(CTorusDlg)
  115. ON_EN_CHANGE(IDC_ARC, OnChangeArc)
  116. ON_EN_CHANGE(IDC_ROTATION_ARC, OnChangeTorusArc)
  117. ON_BN_CLICKED(IDC_CIRCLE, OnCircle)
  118. ON_BN_CLICKED(IDC_TORUS_COMPUTE_RADIUS, OnComputeRadius)
  119. ON_EN_UPDATE(IDC_SIDES, OnUpdateSides)
  120. ON_EN_UPDATE(IDC_WALLWIDTH, OnUpdateWallwidth)
  121. ON_WM_PAINT()
  122. ON_BN_CLICKED(IDC_TORUS_PREVIEW, OnTorusPreview)
  123. //}}AFX_MSG_MAP
  124. END_MESSAGE_MAP()
  125. /////////////////////////////////////////////////////////////////////////////
  126. // CTorusDlg message handlers
  127. void CTorusDlg::OnChangeArc()
  128. {
  129. }
  130. void CTorusDlg::OnChangeTorusArc()
  131. {
  132. }
  133. void CTorusDlg::OnCircle()
  134. {
  135. m_cArcSpin.SetPos(360);
  136. OnTorusPreview();
  137. }
  138. void CTorusDlg::OnComputeRadius()
  139. {
  140. UpdateData( TRUE );
  141. // This is the maximum cross-section radius
  142. m_fCrossSectionRadius = MaxTorusCrossSectionRadius();
  143. UpdateData( FALSE );
  144. OnTorusPreview();
  145. }
  146. void CTorusDlg::OnUpdateSides()
  147. {
  148. }
  149. void CTorusDlg::OnUpdateWallwidth()
  150. {
  151. }
  152. BOOL CTorusDlg::OnInitDialog()
  153. {
  154. CDialog::OnInitDialog();
  155. m_cArcSpin.SetRange(8, 360);
  156. m_cSidesSpin.SetRange(3, 100);
  157. m_cWallWidthSpin.SetRange(2, m_iMaxWallWidth);
  158. m_cStartAngleSpin.SetRange(0, 360);
  159. m_cPreview.ShowWindow(SW_HIDE);
  160. m_cTopViewPreview.ShowWindow(SW_HIDE);
  161. bInitialized = TRUE;
  162. return TRUE;
  163. }
  164. void CTorusDlg::OnPaint()
  165. {
  166. CPaintDC dc(this); // device context for painting
  167. CBrush black(RGB(0,0,0));
  168. CBrush grey(RGB(128,128,128));
  169. // Do not call CDialog::OnPaint() for painting messages
  170. CRect rcPreview;
  171. m_cPreview.GetWindowRect(&rcPreview);
  172. ScreenToClient(&rcPreview);
  173. dc.FillRect(rcPreview, &black);
  174. DrawTorusCrossSection( &dc );
  175. rcPreview.InflateRect(1,1);
  176. dc.FrameRect(rcPreview, &grey);
  177. ValidateRect(rcPreview);
  178. m_cTopViewPreview.GetWindowRect(&rcPreview);
  179. ScreenToClient(&rcPreview);
  180. dc.FillRect(rcPreview, &black);
  181. DrawTorusTopView( &dc );
  182. rcPreview.InflateRect(1,1);
  183. dc.FrameRect(rcPreview, &grey);
  184. ValidateRect(rcPreview);
  185. bInitialized = TRUE;
  186. }
  187. void CTorusDlg::OnTorusPreview()
  188. {
  189. //
  190. // Build preview.
  191. //
  192. bInitialized = TRUE;
  193. InvalidateRect(NULL);
  194. UpdateWindow();
  195. }
  196. CTorusDlg::~CTorusDlg()
  197. {
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Gets the inner radius of the torus cross-section
  201. //-----------------------------------------------------------------------------
  202. float CTorusDlg::MaxTorusCrossSectionRadius() const
  203. {
  204. Vector vecSize;
  205. VectorSubtract( bmaxs, bmins, vecSize );
  206. float flTorusRadius = (vecSize.z - m_iAddHeight);
  207. // Check for multiple revolutions...
  208. if ( ( m_fRotationArc > 360 ) || (( m_fRotationArc == 360 ) && ( m_iAddHeight != 0 )) )
  209. {
  210. // Height per revolution
  211. float flHeightPerRev = 360.0f * m_iAddHeight / m_fRotationArc;
  212. if ( flHeightPerRev < flTorusRadius )
  213. {
  214. flTorusRadius = flHeightPerRev;
  215. }
  216. }
  217. // Also constrain it based on x & y too...
  218. if ( (vecSize.x * 0.5f) < flTorusRadius )
  219. {
  220. flTorusRadius = vecSize.x * 0.5f;
  221. }
  222. if ( (vecSize.y * 0.5f) < flTorusRadius )
  223. {
  224. flTorusRadius = vecSize.y * 0.5f;
  225. }
  226. flTorusRadius *= 0.5f;
  227. if ( flTorusRadius < m_iWallWidth )
  228. {
  229. flTorusRadius = m_iWallWidth;
  230. }
  231. return flTorusRadius;
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Gets the inner radius of the torus cross-section
  235. //-----------------------------------------------------------------------------
  236. float CTorusDlg::GetTorusCrossSectionRadius() const
  237. {
  238. Vector vecSize;
  239. VectorSubtract( bmaxs, bmins, vecSize );
  240. float flTorusRadius = m_fCrossSectionRadius;
  241. // Also constrain it based on x & y too...
  242. if ( (vecSize.x * 0.25f) < flTorusRadius )
  243. {
  244. flTorusRadius = vecSize.x * 0.25f;
  245. }
  246. if ( (vecSize.y * 0.25f) < flTorusRadius )
  247. {
  248. flTorusRadius = vecSize.y * 0.25f;
  249. }
  250. return flTorusRadius;
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Draws the torus cross-section
  254. //-----------------------------------------------------------------------------
  255. void CTorusDlg::DrawTorusCrossSection(CDC* pDC )
  256. {
  257. int iSides, iWallWidth;
  258. float fArc, fStartAngle;
  259. int i;
  260. float fOuterPoints[ARC_MAX_POINTS][2];
  261. float fInnerPoints[ARC_MAX_POINTS][2];
  262. float fScaleX;
  263. float fScaleY;
  264. UpdateData(TRUE);
  265. CPen m_hPen, *pOldPen;
  266. m_hPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
  267. pOldPen = pDC->SelectObject(&m_hPen);
  268. CRect rcItem;
  269. m_cPreview.GetWindowRect(&rcItem);
  270. ScreenToClient(&rcItem);
  271. CPoint pt;
  272. pt.x = rcItem.left + rcItem.Width() / 2;
  273. pt.y = rcItem.top + rcItem.Height() / 2;
  274. float flMaxRadius = GetTorusCrossSectionRadius();
  275. iWallWidth = m_iWallWidth;
  276. if ( iWallWidth > flMaxRadius )
  277. iWallWidth = flMaxRadius;
  278. float flTorusRadius = flMaxRadius - iWallWidth;
  279. float flDeltaZ = bmaxs[2] - bmins[2];
  280. if (flDeltaZ)
  281. {
  282. if ( flDeltaZ < flMaxRadius * 2.0f )
  283. {
  284. flDeltaZ = flMaxRadius * 2.0f;
  285. }
  286. fScaleX = rcItem.Width()/flDeltaZ;
  287. fScaleY = rcItem.Height()/flDeltaZ;
  288. }
  289. else
  290. {
  291. fScaleX = fScaleY = 1.0f;
  292. // fScaleX = rcItem.Width() / (2.0f * flMaxRadius);
  293. // fScaleY = rcItem.Height() / (2.0f * flMaxRadius);
  294. }
  295. fArc = m_fArc;
  296. fStartAngle = m_fAngle;
  297. iSides = m_iSides;
  298. MakeArcCenterRadius(0, 0,
  299. flTorusRadius + iWallWidth, flTorusRadius + iWallWidth,
  300. iSides, fStartAngle, fArc, fOuterPoints);
  301. MakeArcCenterRadius(0, 0,
  302. flTorusRadius, flTorusRadius,
  303. iSides, fStartAngle, fArc, fInnerPoints);
  304. // check wall width - if it's half or more of the total,
  305. // set the inner poinst to the center point of the box
  306. // and turn off the CreateSouthFace flag
  307. Vector points[4];
  308. for (i = 0; i < iSides; i++)
  309. {
  310. int iNextPoint = i+1;
  311. if (iNextPoint >= iSides + 1)
  312. {
  313. iNextPoint = 0;
  314. }
  315. points[0][0] = fOuterPoints[i][0];
  316. points[0][1] = fOuterPoints[i][1];
  317. points[1][0] = fOuterPoints[iNextPoint][0];
  318. points[1][1] = fOuterPoints[iNextPoint][1];
  319. points[2][0] = fInnerPoints[iNextPoint][0];
  320. points[2][1] = fInnerPoints[iNextPoint][1];
  321. points[3][0] = fInnerPoints[i][0];
  322. points[3][1] = fInnerPoints[i][1];
  323. for (int j = 0; j < 4; j++)
  324. {
  325. points[j][0] = fScaleX * points[j][0];
  326. points[j][1] = fScaleY * points[j][1];
  327. }
  328. pDC->MoveTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
  329. pDC->LineTo(pt.x + (int)points[0][0], pt.y - (int)points[0][1]);
  330. pDC->LineTo(pt.x + (int)points[3][0], pt.y - (int)points[3][1]);
  331. pDC->LineTo(pt.x + (int)points[2][0], pt.y - (int)points[2][1]);
  332. }
  333. // Close the cross-section off...
  334. if ( fArc != 360.0f )
  335. {
  336. pDC->LineTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
  337. }
  338. pDC->SelectObject(pOldPen);
  339. }
  340. void CTorusDlg::DrawTorusTopView( CDC* pDC )
  341. {
  342. int i;
  343. float fOuterPoints[ARC_MAX_POINTS][2];
  344. float fInnerPoints[ARC_MAX_POINTS][2];
  345. float fScaleX;
  346. float fScaleY;
  347. UpdateData(TRUE);
  348. CPen m_hPen, *pOldPen;
  349. m_hPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
  350. pOldPen = pDC->SelectObject(&m_hPen);
  351. CRect rcItem;
  352. m_cTopViewPreview.GetWindowRect(&rcItem);
  353. ScreenToClient(&rcItem);
  354. CPoint pt;
  355. pt.x = rcItem.left + rcItem.Width() / 2;
  356. pt.y = rcItem.top + rcItem.Height() / 2;
  357. if (bmaxs[0] - bmins[0])
  358. {
  359. fScaleX = rcItem.Width() /(bmaxs[0] - bmins[0]);
  360. }
  361. else
  362. {
  363. fScaleX = 1.0f;
  364. }
  365. if (bmaxs[1] - bmins[1])
  366. {
  367. fScaleY = rcItem.Height() /(bmaxs[1] - bmins[1]);
  368. }
  369. else
  370. {
  371. fScaleY = 1.0f;
  372. }
  373. int iSides, iWallWidth;
  374. float fArc, fStartAngle;
  375. fArc = m_fRotationArc;
  376. fStartAngle = m_fRotationAngle;
  377. iSides = m_iRotationSides;
  378. iWallWidth = GetTorusCrossSectionRadius() * 2.0f;
  379. float xCenter = (bmaxs[0] + bmins[0]) * 0.5f;
  380. float yCenter = (bmaxs[1] + bmins[1]) * 0.5f;
  381. float xRad = (bmaxs[0] - xCenter - iWallWidth);
  382. float yRad = (bmaxs[1] - yCenter - iWallWidth);
  383. if (xRad < 0.0f )
  384. {
  385. xRad = 0.0f;
  386. }
  387. if (yRad < 0.0f )
  388. {
  389. yRad = 0.0f;
  390. }
  391. MakeArcCenterRadius(xCenter, yCenter, xRad + iWallWidth, yRad + iWallWidth,
  392. iSides, fStartAngle, fArc, fOuterPoints);
  393. MakeArcCenterRadius(xCenter, yCenter, xRad, yRad,
  394. iSides, fStartAngle, fArc, fInnerPoints);
  395. Vector vecCenter;
  396. VectorLerp( bmins, bmaxs, 0.5f, vecCenter );
  397. Vector points[4];
  398. for (i = 0; i < iSides; i++)
  399. {
  400. int iNextPoint = i+1;
  401. if (iNextPoint >= iSides + 1)
  402. {
  403. iNextPoint = 0;
  404. }
  405. points[0][0] = fOuterPoints[i][0];
  406. points[0][1] = fOuterPoints[i][1];
  407. points[1][0] = fOuterPoints[iNextPoint][0];
  408. points[1][1] = fOuterPoints[iNextPoint][1];
  409. points[2][0] = fInnerPoints[iNextPoint][0];
  410. points[2][1] = fInnerPoints[iNextPoint][1];
  411. points[3][0] = fInnerPoints[i][0];
  412. points[3][1] = fInnerPoints[i][1];
  413. for (int j = 0; j < 4; j++)
  414. {
  415. points[j][0] = fScaleX * (points[j][0] - vecCenter[0]);
  416. points[j][1] = fScaleY * (points[j][1] - vecCenter[1]);
  417. }
  418. pDC->MoveTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
  419. pDC->LineTo(pt.x + (int)points[0][0], pt.y - (int)points[0][1]);
  420. pDC->LineTo(pt.x + (int)points[3][0], pt.y - (int)points[3][1]);
  421. pDC->LineTo(pt.x + (int)points[2][0], pt.y - (int)points[2][1]);
  422. }
  423. // Close the cross-section off...
  424. if ( fArc != 360.0f )
  425. {
  426. pDC->LineTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
  427. }
  428. pDC->SelectObject(pOldPen);
  429. }