//========= Copyright © 1996-2005, 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 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); }