summaryrefslogtreecommitdiff
path: root/hammer/TorusDlg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hammer/TorusDlg.cpp')
-rw-r--r--hammer/TorusDlg.cpp535
1 files changed, 535 insertions, 0 deletions
diff --git a/hammer/TorusDlg.cpp b/hammer/TorusDlg.cpp
new file mode 100644
index 0000000..44ce445
--- /dev/null
+++ b/hammer/TorusDlg.cpp
@@ -0,0 +1,535 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include "stdafx.h"
+#include "hammer.h"
+#include "hammer_mathlib.h"
+#include "TorusDlg.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+static LPCTSTR pszSection = "Torus";
+
+void MakeArcCenterRadius(float xCenter, float yCenter, float xrad, float yrad, int npoints, float start_ang, float fArc, float points[][2]);
+void MakeArc(float x1, float y1, float x2, float y2, int npoints, float start_ang, float fArc, float points[][2]);
+
+CTorusDlg::CTorusDlg(Vector& boxmins, Vector& boxmaxs, CWnd* pParent /*=NULL*/)
+ : CDialog(CTorusDlg::IDD, pParent)
+{
+ bmins = boxmins;
+ bmaxs = boxmaxs;
+
+ //{{AFX_DATA_INIT(CTorusDlg)
+ m_iSides = 0;
+ m_iWallWidth = 0;
+ m_iAddHeight = 0;
+ m_fArc = 0.0f;
+ m_fAngle = 0.0f;
+ m_fRotationArc = 0.0f;
+ m_fRotationAngle = 0.0f;
+ m_iRotationSides = 0;
+ m_fCrossSectionRadius = 0;
+ //}}AFX_DATA_INIT
+
+ // load up old defaults
+ CString str;
+ m_iWallWidth = AfxGetApp()->GetProfileInt(pszSection, "Wall Width", 32);
+ str = AfxGetApp()->GetProfileString(pszSection, "Arc_", "360");
+ m_fArc = atof(str);
+ m_iSides = AfxGetApp()->GetProfileInt(pszSection, "Sides", 16);
+ str = AfxGetApp()->GetProfileString(pszSection, "Start Angle_", "0");
+ m_fAngle = atof(str);
+
+ str = AfxGetApp()->GetProfileString(pszSection, "Rotation Arc_", "360");
+ m_fRotationArc = atof(str);
+ m_iRotationSides = AfxGetApp()->GetProfileInt(pszSection, "Rotation Sides", 16);
+ str = AfxGetApp()->GetProfileString(pszSection, "Rotation Start Angle_", "0");
+ m_fRotationAngle = atof(str);
+
+ m_iAddHeight = AfxGetApp()->GetProfileInt(pszSection, "Add Height", 0);
+
+ Vector vecSize;
+ VectorSubtract( bmaxs, bmins, vecSize );
+ if ( m_iAddHeight > vecSize.z )
+ {
+ m_iAddHeight = vecSize.z;
+ }
+
+ // This is the maximum cross-section radius
+ m_fCrossSectionRadius = MaxTorusCrossSectionRadius();
+}
+
+void CTorusDlg::SaveValues()
+{
+ CString str;
+ AfxGetApp()->WriteProfileInt(pszSection, "Wall Width", m_iWallWidth);
+ str.Format("%f", m_fArc);
+ AfxGetApp()->WriteProfileString(pszSection, "Arc_", str);
+ AfxGetApp()->WriteProfileInt(pszSection, "Sides", m_iSides);
+ str.Format("%f", m_fAngle);
+ AfxGetApp()->WriteProfileString(pszSection, "Start Angle_", str);
+
+ str.Format("%f", m_fRotationArc);
+ AfxGetApp()->WriteProfileString(pszSection, "Rotation Arc_", str);
+ str.Format("%f", m_fRotationAngle);
+ AfxGetApp()->WriteProfileString(pszSection, "Rotation Start Angle_", str);
+ AfxGetApp()->WriteProfileInt(pszSection, "Rotation Sides", m_iRotationSides);
+ AfxGetApp()->WriteProfileInt(pszSection, "Add Height", m_iAddHeight);
+}
+
+void CTorusDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CTorusDlg)
+ DDX_Control(pDX, IDC_ANGLESPIN, m_cStartAngleSpin);
+ DDX_Control(pDX, IDC_WALLWIDTHSPIN, m_cWallWidthSpin);
+ DDX_Control(pDX, IDC_WALLWIDTH, m_cWallWidth);
+ DDX_Control(pDX, IDC_SIDESSPIN, m_cSidesSpin);
+ DDX_Control(pDX, IDC_SIDES, m_cSides);
+ DDX_Control(pDX, IDC_ARCSPIN, m_cArcSpin);
+ DDX_Control(pDX, IDC_ARC, m_cArc);
+ DDX_Control(pDX, IDC_PREVIEW, m_cPreview);
+ DDX_Control(pDX, IDC_PREVIEW_TOP_VIEW, m_cTopViewPreview);
+ DDX_Text(pDX, IDC_SIDES, m_iSides);
+ DDV_MinMaxInt(pDX, m_iSides, 3, 2048);
+ DDX_Text(pDX, IDC_WALLWIDTH, m_iWallWidth);
+ DDX_Text(pDX, IDC_ADDHEIGHT, m_iAddHeight);
+ DDX_Text(pDX, IDC_ARC, m_fArc);
+ DDV_MinMaxFloat(pDX, m_fArc, 8.f, 360.f);
+ DDX_Text(pDX, IDC_ANGLE, m_fAngle);
+ DDV_MinMaxFloat(pDX, m_fAngle, -360.0f, 360.f);
+ DDX_Text(pDX, IDC_ROTATION_ARC, m_fRotationArc);
+ DDV_MinMaxFloat(pDX, m_fRotationArc, 0.f, 3600.f);
+ DDX_Text(pDX, IDC_ROTATION_ANGLE, m_fRotationAngle);
+ DDV_MinMaxFloat(pDX, m_fRotationAngle, -360.0f, 360.f);
+ DDX_Text(pDX, IDC_ROTATION_SIDES, m_iRotationSides);
+ DDV_MinMaxInt(pDX, m_iRotationSides, 3, 2048);
+ DDX_Text(pDX, IDC_CROSS_SECTION_RADIUS, m_fCrossSectionRadius);
+ DDV_MinMaxFloat(pDX, m_fCrossSectionRadius, 0.f, 5000.f);
+ //}}AFX_DATA_MAP
+
+ if ( pDX->m_bSaveAndValidate )
+ {
+ Vector vecSize;
+ VectorSubtract( bmaxs, bmins, vecSize );
+ if ( m_iAddHeight > vecSize.z )
+ {
+ m_iAddHeight = vecSize.z;
+ }
+ }
+}
+
+
+BEGIN_MESSAGE_MAP(CTorusDlg, CDialog)
+ //{{AFX_MSG_MAP(CTorusDlg)
+ ON_EN_CHANGE(IDC_ARC, OnChangeArc)
+ ON_EN_CHANGE(IDC_ROTATION_ARC, OnChangeTorusArc)
+ ON_BN_CLICKED(IDC_CIRCLE, OnCircle)
+ ON_BN_CLICKED(IDC_TORUS_COMPUTE_RADIUS, OnComputeRadius)
+ ON_EN_UPDATE(IDC_SIDES, OnUpdateSides)
+ ON_EN_UPDATE(IDC_WALLWIDTH, OnUpdateWallwidth)
+ ON_WM_PAINT()
+ ON_BN_CLICKED(IDC_TORUS_PREVIEW, OnTorusPreview)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTorusDlg message handlers
+
+void CTorusDlg::OnChangeArc()
+{
+}
+
+void CTorusDlg::OnChangeTorusArc()
+{
+}
+
+void CTorusDlg::OnCircle()
+{
+ m_cArcSpin.SetPos(360);
+ OnTorusPreview();
+}
+
+void CTorusDlg::OnComputeRadius()
+{
+ UpdateData( TRUE );
+
+ // This is the maximum cross-section radius
+ m_fCrossSectionRadius = MaxTorusCrossSectionRadius();
+ UpdateData( FALSE );
+ OnTorusPreview();
+}
+
+void CTorusDlg::OnUpdateSides()
+{
+}
+
+void CTorusDlg::OnUpdateWallwidth()
+{
+}
+
+BOOL CTorusDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ m_cArcSpin.SetRange(8, 360);
+ m_cSidesSpin.SetRange(3, 100);
+ m_cWallWidthSpin.SetRange(2, m_iMaxWallWidth);
+ m_cStartAngleSpin.SetRange(0, 360);
+
+ m_cPreview.ShowWindow(SW_HIDE);
+ m_cTopViewPreview.ShowWindow(SW_HIDE);
+
+ bInitialized = TRUE;
+ return TRUE;
+}
+
+void CTorusDlg::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ CBrush black(RGB(0,0,0));
+ CBrush grey(RGB(128,128,128));
+
+ // Do not call CDialog::OnPaint() for painting messages
+ CRect rcPreview;
+ m_cPreview.GetWindowRect(&rcPreview);
+ ScreenToClient(&rcPreview);
+ dc.FillRect(rcPreview, &black);
+
+ DrawTorusCrossSection( &dc );
+
+ rcPreview.InflateRect(1,1);
+ dc.FrameRect(rcPreview, &grey);
+ ValidateRect(rcPreview);
+
+ m_cTopViewPreview.GetWindowRect(&rcPreview);
+ ScreenToClient(&rcPreview);
+ dc.FillRect(rcPreview, &black);
+
+ DrawTorusTopView( &dc );
+
+ rcPreview.InflateRect(1,1);
+ dc.FrameRect(rcPreview, &grey);
+ ValidateRect(rcPreview);
+
+ bInitialized = TRUE;
+}
+
+void CTorusDlg::OnTorusPreview()
+{
+ //
+ // Build preview.
+ //
+ bInitialized = TRUE;
+ InvalidateRect(NULL);
+ UpdateWindow();
+}
+
+CTorusDlg::~CTorusDlg()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the inner radius of the torus cross-section
+//-----------------------------------------------------------------------------
+float CTorusDlg::MaxTorusCrossSectionRadius() const
+{
+ Vector vecSize;
+ VectorSubtract( bmaxs, bmins, vecSize );
+
+ float flTorusRadius = (vecSize.z - m_iAddHeight);
+
+ // Check for multiple revolutions...
+ if ( ( m_fRotationArc > 360 ) || (( m_fRotationArc == 360 ) && ( m_iAddHeight != 0 )) )
+ {
+ // Height per revolution
+ float flHeightPerRev = 360.0f * m_iAddHeight / m_fRotationArc;
+ if ( flHeightPerRev < flTorusRadius )
+ {
+ flTorusRadius = flHeightPerRev;
+ }
+ }
+
+ // Also constrain it based on x & y too...
+ if ( (vecSize.x * 0.5f) < flTorusRadius )
+ {
+ flTorusRadius = vecSize.x * 0.5f;
+ }
+
+ if ( (vecSize.y * 0.5f) < flTorusRadius )
+ {
+ flTorusRadius = vecSize.y * 0.5f;
+ }
+
+ flTorusRadius *= 0.5f;
+ if ( flTorusRadius < m_iWallWidth )
+ {
+ flTorusRadius = m_iWallWidth;
+ }
+
+ return flTorusRadius;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the inner radius of the torus cross-section
+//-----------------------------------------------------------------------------
+float CTorusDlg::GetTorusCrossSectionRadius() const
+{
+ Vector vecSize;
+ VectorSubtract( bmaxs, bmins, vecSize );
+
+ float flTorusRadius = m_fCrossSectionRadius;
+
+ // Also constrain it based on x & y too...
+ if ( (vecSize.x * 0.25f) < flTorusRadius )
+ {
+ flTorusRadius = vecSize.x * 0.25f;
+ }
+
+ if ( (vecSize.y * 0.25f) < flTorusRadius )
+ {
+ flTorusRadius = vecSize.y * 0.25f;
+ }
+
+ return flTorusRadius;
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the torus cross-section
+//-----------------------------------------------------------------------------
+void CTorusDlg::DrawTorusCrossSection(CDC* pDC )
+{
+ int iSides, iWallWidth;
+ float fArc, fStartAngle;
+
+ int i;
+ float fOuterPoints[ARC_MAX_POINTS][2];
+ float fInnerPoints[ARC_MAX_POINTS][2];
+
+ float fScaleX;
+ float fScaleY;
+
+ UpdateData(TRUE);
+
+ CPen m_hPen, *pOldPen;
+
+ m_hPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
+
+ pOldPen = pDC->SelectObject(&m_hPen);
+
+ CRect rcItem;
+ m_cPreview.GetWindowRect(&rcItem);
+ ScreenToClient(&rcItem);
+
+ CPoint pt;
+ pt.x = rcItem.left + rcItem.Width() / 2;
+ pt.y = rcItem.top + rcItem.Height() / 2;
+
+ float flMaxRadius = GetTorusCrossSectionRadius();
+ iWallWidth = m_iWallWidth;
+ if ( iWallWidth > flMaxRadius )
+ iWallWidth = flMaxRadius;
+ float flTorusRadius = flMaxRadius - iWallWidth;
+
+ float flDeltaZ = bmaxs[2] - bmins[2];
+ if (flDeltaZ)
+ {
+ if ( flDeltaZ < flMaxRadius * 2.0f )
+ {
+ flDeltaZ = flMaxRadius * 2.0f;
+ }
+ fScaleX = rcItem.Width()/flDeltaZ;
+ fScaleY = rcItem.Height()/flDeltaZ;
+ }
+ else
+ {
+ fScaleX = fScaleY = 1.0f;
+// fScaleX = rcItem.Width() / (2.0f * flMaxRadius);
+// fScaleY = rcItem.Height() / (2.0f * flMaxRadius);
+ }
+
+ fArc = m_fArc;
+ fStartAngle = m_fAngle;
+ iSides = m_iSides;
+
+ MakeArcCenterRadius(0, 0,
+ flTorusRadius + iWallWidth, flTorusRadius + iWallWidth,
+ iSides, fStartAngle, fArc, fOuterPoints);
+
+ MakeArcCenterRadius(0, 0,
+ flTorusRadius, flTorusRadius,
+ 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
+
+ Vector points[4];
+ for (i = 0; i < iSides; i++)
+ {
+ int iNextPoint = i+1;
+ if (iNextPoint >= iSides + 1)
+ {
+ iNextPoint = 0;
+ }
+
+ points[0][0] = fOuterPoints[i][0];
+ points[0][1] = fOuterPoints[i][1];
+
+ points[1][0] = fOuterPoints[iNextPoint][0];
+ points[1][1] = fOuterPoints[iNextPoint][1];
+
+ points[2][0] = fInnerPoints[iNextPoint][0];
+ points[2][1] = fInnerPoints[iNextPoint][1];
+
+ points[3][0] = fInnerPoints[i][0];
+ points[3][1] = fInnerPoints[i][1];
+
+ for (int j = 0; j < 4; j++)
+ {
+ points[j][0] = fScaleX * points[j][0];
+ points[j][1] = fScaleY * points[j][1];
+ }
+
+ pDC->MoveTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
+ pDC->LineTo(pt.x + (int)points[0][0], pt.y - (int)points[0][1]);
+ pDC->LineTo(pt.x + (int)points[3][0], pt.y - (int)points[3][1]);
+ pDC->LineTo(pt.x + (int)points[2][0], pt.y - (int)points[2][1]);
+ }
+
+ // Close the cross-section off...
+ if ( fArc != 360.0f )
+ {
+ pDC->LineTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
+ }
+
+ pDC->SelectObject(pOldPen);
+}
+
+
+void CTorusDlg::DrawTorusTopView( CDC* pDC )
+{
+ int i;
+ float fOuterPoints[ARC_MAX_POINTS][2];
+ float fInnerPoints[ARC_MAX_POINTS][2];
+
+ float fScaleX;
+ float fScaleY;
+
+ UpdateData(TRUE);
+
+ CPen m_hPen, *pOldPen;
+
+ m_hPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
+
+ pOldPen = pDC->SelectObject(&m_hPen);
+
+ CRect rcItem;
+ m_cTopViewPreview.GetWindowRect(&rcItem);
+ ScreenToClient(&rcItem);
+
+ CPoint pt;
+ pt.x = rcItem.left + rcItem.Width() / 2;
+ pt.y = rcItem.top + rcItem.Height() / 2;
+
+ if (bmaxs[0] - bmins[0])
+ {
+ fScaleX = rcItem.Width() /(bmaxs[0] - bmins[0]);
+ }
+ else
+ {
+ fScaleX = 1.0f;
+ }
+
+ if (bmaxs[1] - bmins[1])
+ {
+ fScaleY = rcItem.Height() /(bmaxs[1] - bmins[1]);
+ }
+ else
+ {
+ fScaleY = 1.0f;
+ }
+
+ int iSides, iWallWidth;
+ float fArc, fStartAngle;
+
+ fArc = m_fRotationArc;
+ fStartAngle = m_fRotationAngle;
+ iSides = m_iRotationSides;
+ iWallWidth = GetTorusCrossSectionRadius() * 2.0f;
+
+ float xCenter = (bmaxs[0] + bmins[0]) * 0.5f;
+ float yCenter = (bmaxs[1] + bmins[1]) * 0.5f;
+ float xRad = (bmaxs[0] - xCenter - iWallWidth);
+ float yRad = (bmaxs[1] - yCenter - iWallWidth);
+ if (xRad < 0.0f )
+ {
+ xRad = 0.0f;
+ }
+ if (yRad < 0.0f )
+ {
+ yRad = 0.0f;
+ }
+
+ MakeArcCenterRadius(xCenter, yCenter, xRad + iWallWidth, yRad + iWallWidth,
+ iSides, fStartAngle, fArc, fOuterPoints);
+
+ MakeArcCenterRadius(xCenter, yCenter, xRad, yRad,
+ iSides, fStartAngle, fArc, fInnerPoints);
+
+ Vector vecCenter;
+ VectorLerp( bmins, bmaxs, 0.5f, vecCenter );
+
+ Vector points[4];
+ for (i = 0; i < iSides; i++)
+ {
+ int iNextPoint = i+1;
+ if (iNextPoint >= iSides + 1)
+ {
+ iNextPoint = 0;
+ }
+
+ points[0][0] = fOuterPoints[i][0];
+ points[0][1] = fOuterPoints[i][1];
+
+ points[1][0] = fOuterPoints[iNextPoint][0];
+ points[1][1] = fOuterPoints[iNextPoint][1];
+
+ points[2][0] = fInnerPoints[iNextPoint][0];
+ points[2][1] = fInnerPoints[iNextPoint][1];
+
+ points[3][0] = fInnerPoints[i][0];
+ points[3][1] = fInnerPoints[i][1];
+
+ for (int j = 0; j < 4; j++)
+ {
+ points[j][0] = fScaleX * (points[j][0] - vecCenter[0]);
+ points[j][1] = fScaleY * (points[j][1] - vecCenter[1]);
+ }
+
+ pDC->MoveTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
+ pDC->LineTo(pt.x + (int)points[0][0], pt.y - (int)points[0][1]);
+ pDC->LineTo(pt.x + (int)points[3][0], pt.y - (int)points[3][1]);
+ pDC->LineTo(pt.x + (int)points[2][0], pt.y - (int)points[2][1]);
+ }
+
+ // Close the cross-section off...
+ if ( fArc != 360.0f )
+ {
+ pDC->LineTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
+ }
+
+ pDC->SelectObject(pOldPen);
+}