windows-nt/Source/XPSP1/NT/shell/osshell/control/scrnsave/pipes/xc.cpp
2020-09-26 16:20:57 +08:00

428 lines
12 KiB
C++

//-----------------------------------------------------------------------------
// File: xc.cpp
//
// Desc: Cross-section (xc) object stuff
//
// Copyright (c) 1995-2000 Microsoft Corporation
//-----------------------------------------------------------------------------
#include "stdafx.h"
//-----------------------------------------------------------------------------
// Name: XC::CalcArcACValues90
// Desc: Calculate arc control points for a 90 degree rotation of an xc
//
// Arc is a quarter-circle
// - 90 degree is much easier, so we special case it
// radius is distance from xc-origin to hinge of turn
//-----------------------------------------------------------------------------
void XC::CalcArcACValues90( int dir, float radius, float *acPts )
{
int i;
float sign;
int offset;
float* ppts = (float *) m_pts;
// 1) calc 'r' values for each point (4 turn possibilities/point). From
// this can determine ac, which is extrusion of point from xc face
switch( dir )
{
case PLUS_X:
offset = 0;
sign = -1.0f;
break;
case MINUS_X:
offset = 0;
sign = 1.0f;
break;
case PLUS_Y:
offset = 1;
sign = -1.0f;
break;
case MINUS_Y:
offset = 1;
sign = 1.0f;
break;
}
for( i = 0; i < m_numPts; i++, ppts+=2, acPts++ )
{
*acPts = EVAL_CIRC_ARC_CONTROL * (radius + (sign * ppts[offset]));
}
// replicate !
*acPts = *(acPts - m_numPts);
}
//-----------------------------------------------------------------------------
// Name: XC::CalcArcACValuesByDistance
// Desc: Use the distance of each xc point from the xc origin, as the radius for
// an arc control value.
//-----------------------------------------------------------------------------
void XC::CalcArcACValuesByDistance( float *acPts )
{
int i;
float r;
D3DXVECTOR2* ppts = m_pts;
for( i = 0; i < m_numPts; i++, ppts++ )
{
r = (float) sqrt( ppts->x*ppts->x + ppts->y*ppts->y );
*acPts++ = EVAL_CIRC_ARC_CONTROL * r;
}
// replicate !
*acPts = *(acPts - m_numPts);
}
//-----------------------------------------------------------------------------
// Name: ELLIPTICAL_XC::SetControlPoints
// Desc: Set the 12 control points for a circle at origin in z=0 plane
//-----------------------------------------------------------------------------
void ELLIPTICAL_XC::SetControlPoints( float r1, float r2 )
{
float ac1, ac2;
ac1 = EVAL_CIRC_ARC_CONTROL * r2;
ac2 = EVAL_CIRC_ARC_CONTROL * r1;
// create 12-pt. set CCW from +x
// last 2 points of right triplet
m_pts[0].x = r1;
m_pts[0].y = 0.0f;
m_pts[1].x = r1;
m_pts[1].y = ac1;
// top triplet
m_pts[2].x = ac2;
m_pts[2].y = r2;
m_pts[3].x = 0.0f;
m_pts[3].y = r2;
m_pts[4].x = -ac2;
m_pts[4].y = r2;
// left triplet
m_pts[5].x = -r1;
m_pts[5].y = ac1;
m_pts[6].x = -r1;
m_pts[6].y = 0.0f;
m_pts[7].x = -r1;
m_pts[7].y = -ac1;
// bottom triplet
m_pts[8].x = -ac2;
m_pts[8].y = -r2;
m_pts[9].x = 0.0f;
m_pts[9].y = -r2;
m_pts[10].x = ac2;
m_pts[10].y = -r2;
// first point of first triplet
m_pts[11].x = r1;
m_pts[11].y = -ac1;
}
//-----------------------------------------------------------------------------
// Name: RANDOM4ARC_XC::SetControlPoints
// Desc: Set random control points for xc
// Points go CCW from +x
//-----------------------------------------------------------------------------
void RANDOM4ARC_XC::SetControlPoints( float radius )
{
int i;
float r[4];
float rMin = 0.5f * radius;
float distx, disty;
// figure the radius of each side first
for( i = 0; i < 4; i ++ )
r[i] = CPipesScreensaver::fRand( rMin, radius );
// The 4 r's now describe a box around the origin - this restricts stuff
// Now need to select a point along each edge of the box as the joining
// points for each arc (join points are at indices 0,3,6,9)
m_pts[0].x = r[RIGHT];
m_pts[3].y = r[TOP];
m_pts[6].x = -r[LEFT];
m_pts[9].y = -r[BOTTOM];
// quarter of distance between edges
disty = (r[TOP] - -r[BOTTOM]) / 4.0f;
distx = (r[RIGHT] - -r[LEFT]) / 4.0f;
// uh, put'em somwhere in the middle half of each side
m_pts[0].y = CPipesScreensaver::fRand( -r[BOTTOM] + disty, r[TOP] - disty );
m_pts[6].y = CPipesScreensaver::fRand( -r[BOTTOM] + disty, r[TOP] - disty );
m_pts[3].x = CPipesScreensaver::fRand( -r[LEFT] + distx, r[RIGHT] - distx );
m_pts[9].x = CPipesScreensaver::fRand( -r[LEFT] + distx, r[RIGHT] - distx );
// now can calc ac's
// easy part first:
m_pts[1].x = m_pts[11].x = m_pts[0].x;
m_pts[2].y = m_pts[4].y = m_pts[3].y;
m_pts[5].x = m_pts[7].x = m_pts[6].x;
m_pts[8].y = m_pts[10].y = m_pts[9].y;
// right side ac's
disty = (r[TOP] - m_pts[0].y) / 4.0f;
m_pts[1].y = CPipesScreensaver::fRand( m_pts[0].y + disty, r[TOP] );
disty = (m_pts[0].y - -r[BOTTOM]) / 4.0f;
m_pts[11].y = CPipesScreensaver::fRand( -r[BOTTOM], m_pts[0].y - disty );
// left side ac's
disty = (r[TOP] - m_pts[6].y) / 4.0f;
m_pts[5].y = CPipesScreensaver::fRand( m_pts[6].y + disty, r[TOP]);
disty = (m_pts[6].y - -r[BOTTOM]) / 4.0f;
m_pts[7].y = CPipesScreensaver::fRand( -r[BOTTOM], m_pts[6].y - disty );
// top ac's
distx = (r[RIGHT] - m_pts[3].x) / 4.0f;
m_pts[2].x = CPipesScreensaver::fRand( m_pts[3].x + distx, r[RIGHT] );
distx = (m_pts[3].x - -r[LEFT]) / 4.0f;
m_pts[4].x = CPipesScreensaver::fRand( -r[LEFT], m_pts[3].x - distx );
// bottom ac's
distx = (r[RIGHT] - m_pts[9].x) / 4.0f;
m_pts[10].x = CPipesScreensaver::fRand( m_pts[9].x + distx, r[RIGHT] );
distx = (m_pts[9].x - -r[LEFT]) / 4.0f;
m_pts[8].x = CPipesScreensaver::fRand( -r[LEFT], m_pts[9].x - distx );
}
//-----------------------------------------------------------------------------
// Name: ConvertPtsZ
// Desc: Convert the 2D pts in an xc, to 3D pts in point buffer, with z.
//
// Also replicate the last point.
//-----------------------------------------------------------------------------
void XC::ConvertPtsZ( D3DXVECTOR3 *newpts, float z )
{
int i;
D3DXVECTOR2* xcPts = m_pts;
for( i = 0; i < m_numPts; i++, newpts++ )
{
*( (D3DXVECTOR2 *) newpts ) = *xcPts++;
newpts->z = z;
}
*newpts = *(newpts - m_numPts);
}
//-----------------------------------------------------------------------------
// Name: XC::CalcBoundingBox
// Desc: Calculate bounding box in x/y plane for xc
//-----------------------------------------------------------------------------
void XC::CalcBoundingBox( )
{
D3DXVECTOR2* ppts = m_pts;
int i;
float xMin, xMax, yMax, yMin;
// initialize to really insane numbers
xMax = yMax = -FLT_MAX;
xMin = yMin = FLT_MAX;
// compare with rest of points
for( i = 0; i < m_numPts; i ++, ppts++ )
{
if( ppts->x < xMin )
xMin = ppts->x;
else if( ppts->x > xMax )
xMax = ppts->x;
if( ppts->y < yMin )
yMin = ppts->y;
else if( ppts->y > yMax )
yMax = ppts->y;
}
m_xLeft = xMin;
m_xRight = xMax;
m_yBottom = yMin;
m_yTop = yMax;
}
//-----------------------------------------------------------------------------
// Name: MinTurnRadius
// Desc: Get minimum radius for the xc to turn in given direction.
//
// If the turn radius is less than this minimum, then primitive will 'fold'
// over itself at the inside of the turn, creating ugliness.
//-----------------------------------------------------------------------------
float XC::MinTurnRadius( int relDir )
{
// For now, assume xRight, yTop positive, xLeft, yBottom negative
// otherwise, might want to consider 'negative'radius
switch( relDir )
{
case PLUS_X:
return( m_xRight );
case MINUS_X:
return( - m_xLeft );
case PLUS_Y:
return( m_yTop );
case MINUS_Y:
return( - m_yBottom );
default:
return(0.0f);
}
}
//-----------------------------------------------------------------------------
// Name: XC::MaxExtent
// Desc: Get maximum extent of the xc in x and y
//-----------------------------------------------------------------------------
float XC::MaxExtent( )
{
float max;
max = m_xRight;
if( m_yTop > max )
max = m_yTop;
if( -m_xLeft > max )
max = -m_xLeft;
if( -m_yBottom > max )
max = -m_yBottom;
return max;
}
//-----------------------------------------------------------------------------
// Name: XC::Scale
// Desc: Scale an XC's points and extents by supplied scale value
//-----------------------------------------------------------------------------
void XC::Scale( float scale )
{
int i;
D3DXVECTOR2* ppts = m_pts;
if( ppts == NULL )
return;
for( i = 0; i < m_numPts; i ++, ppts++ )
{
ppts->x *= scale;
ppts->y *= scale;
}
m_xLeft *= scale;
m_xRight *= scale;
m_yBottom *= scale;
m_yTop *= scale;
}
//-----------------------------------------------------------------------------
// Name: ~XC::XC
// Desc: Destructor
//-----------------------------------------------------------------------------
XC::~XC()
{
if( m_pts )
LocalFree( m_pts );
}
//-----------------------------------------------------------------------------
// Name: XC::XC
// Desc: Constructor
// Allocates point buffer for the xc
//-----------------------------------------------------------------------------
XC::XC( int nPts )
{
m_numPts = nPts;
m_pts = (D3DXVECTOR2 *) LocalAlloc( LMEM_FIXED, m_numPts * sizeof(D3DXVECTOR2) );
assert( m_pts != 0 && "XC constructor\n" );
}
//-----------------------------------------------------------------------------
// Name: XC::XC
// Desc: Constructor
// Allocates point buffer for the xc from another XC
//-----------------------------------------------------------------------------
XC::XC( XC *xc )
{
m_numPts = xc->m_numPts;
m_pts = (D3DXVECTOR2 *) LocalAlloc( LMEM_FIXED, m_numPts * sizeof(D3DXVECTOR2) );
assert( m_pts != 0 && "XC constructor\n" );
if( m_pts != NULL )
RtlCopyMemory( m_pts, xc->m_pts, m_numPts * sizeof(D3DXVECTOR2) );
m_xLeft = xc->m_xLeft;
m_xRight = xc->m_xRight;
m_yBottom = xc->m_yBottom;
m_yTop = xc->m_yTop;
}
//-----------------------------------------------------------------------------
// Name: ELLIPTICAL_XC::ELLIPTICALXC
// Desc: Elliptical XC constructor
// These have 4 sections of 4 pts each, with pts shared between sections.
//-----------------------------------------------------------------------------
ELLIPTICAL_XC::ELLIPTICAL_XC( float r1, float r2 )
// initialize base XC with numPts
: XC( (int) EVAL_XC_CIRC_SECTION_COUNT * (EVAL_ARC_ORDER - 1))
{
SetControlPoints( r1, r2 );
CalcBoundingBox( );
}
//-----------------------------------------------------------------------------
// Name: RANDOM4ARC_XC::RANDOM4ARC_XC
// Desc: Random 4-arc XC constructor
// The bounding box is 2*r each side
// These have 4 sections of 4 pts each, with pts shared between sections.
//-----------------------------------------------------------------------------
RANDOM4ARC_XC::RANDOM4ARC_XC( float r )
// initialize base XC with numPts
: XC( (int) EVAL_XC_CIRC_SECTION_COUNT * (EVAL_ARC_ORDER - 1))
{
SetControlPoints( r );
CalcBoundingBox( );
}