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
535 lines
13 KiB
//========= 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); |
|
}
|
|
|