From 3e389c103b320773fa1daaf38a8085e5571dc658 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sat, 5 Feb 2005 03:12:04 +0000 Subject: [PATCH] Translation and scaling (when applied in that order) are trivially combined; save a matrix multiply for every actor. (Maybe we can avoid doing any, for objects which are neither rotated nor scaled--such as those positioned based on their parent--but I'm not sure it's worth it.) Rotations can be combined without doing a full matrix multiply, too; if an actor rotates at all, only do one matrix multiply. --- stepmania/src/Actor.cpp | 44 ++++++++++++------- stepmania/src/RageMath.cpp | 87 ++++++++++++++++++++++++++++++++++++++ stepmania/src/RageMath.h | 2 + 3 files changed, 117 insertions(+), 16 deletions(-) diff --git a/stepmania/src/Actor.cpp b/stepmania/src/Actor.cpp index 2ecf0b9435..4289be2ad3 100644 --- a/stepmania/src/Actor.cpp +++ b/stepmania/src/Actor.cpp @@ -246,23 +246,35 @@ void Actor::BeginDraw() // set the world matrix and calculate actor properties } } - DISPLAY->Translate( - m_pTempState->pos.x, - m_pTempState->pos.y, - m_pTempState->pos.z ); - DISPLAY->Scale( - m_pTempState->scale.x * m_baseScale.x, - m_pTempState->scale.y * m_baseScale.y, - m_pTempState->scale.z * m_baseScale.z ); + { + RageMatrix m; + RageMatrixTranslateAndScale( &m, + m_pTempState->pos.x, + m_pTempState->pos.y, + m_pTempState->pos.z, + m_pTempState->scale.x * m_baseScale.x, + m_pTempState->scale.y * m_baseScale.y, + m_pTempState->scale.z * m_baseScale.z ); - /* The only time rotation and quat should normally be used simultaneously - * is for m_baseRotation. */ - if( m_pTempState->rotation.x + m_baseRotation.x != 0 ) - DISPLAY->RotateX( m_pTempState->rotation.x + m_baseRotation.x ); - if( m_pTempState->rotation.y + m_baseRotation.y != 0 ) - DISPLAY->RotateY( m_pTempState->rotation.y + m_baseRotation.y ); - if( m_pTempState->rotation.z + m_baseRotation.z != 0 ) - DISPLAY->RotateZ( m_pTempState->rotation.z + m_baseRotation.z ); + DISPLAY->PreMultMatrix( m ); + } + + { + /* The only time rotation and quat should normally be used simultaneously + * is for m_baseRotation. Most objects aren't rotated at all, so optimize + * that case. */ + const float fRotateX = m_pTempState->rotation.x + m_baseRotation.x; + const float fRotateY = m_pTempState->rotation.y + m_baseRotation.y; + const float fRotateZ = m_pTempState->rotation.z + m_baseRotation.z; + + if( fRotateX != 0 || fRotateY != 0 || fRotateZ != 0 ) + { + RageMatrix m; + RageMatrixRotationXYZ( &m, fRotateX, fRotateY, fRotateZ ); + + DISPLAY->PreMultMatrix( m ); + } + } if( m_pTempState->quat.x != 0 || m_pTempState->quat.y != 0 || m_pTempState->quat.z != 0 || m_pTempState->quat.w != 1 ) { diff --git a/stepmania/src/RageMath.cpp b/stepmania/src/RageMath.cpp index 74e68f0334..14ab1188c0 100644 --- a/stepmania/src/RageMath.cpp +++ b/stepmania/src/RageMath.cpp @@ -151,6 +151,40 @@ void RageMatrixScaling( RageMatrix* pOut, float x, float y, float z ) pOut->m[2][2] = z; } +/* + * Return: + * + * RageMatrix translate; + * RageMatrixTranslation( &translate, fTransX, fTransY, fTransZ ); + * RageMatrix scale; + * RageMatrixScaling( &scale, fScaleX, float fScaleY, float fScaleZ ); + * RageMatrixMultiply( pOut, &translate, &scale ); + */ +void RageMatrixTranslateAndScale( RageMatrix* pOut, + float fTransX, float fTransY, float fTransZ, + float fScaleX, float fScaleY, float fScaleZ ) +{ + pOut->m00 = fScaleX; + pOut->m01 = 0; + pOut->m02 = 0; + pOut->m03 = 0; + + pOut->m10 = 0; + pOut->m11 = fScaleY; + pOut->m12 = 0; + pOut->m13 = 0; + + pOut->m20 = 0; + pOut->m21 = 0; + pOut->m22 = fScaleZ; + pOut->m23 = 0; + + pOut->m30 = fTransX; + pOut->m31 = fTransY; + pOut->m32 = fTransZ; + pOut->m33 = 1; +} + void RageMatrixRotationX( RageMatrix* pOut, float theta ) { theta *= PI/180; @@ -187,6 +221,59 @@ void RageMatrixRotationZ( RageMatrix* pOut, float theta ) pOut->m[1][0] = -pOut->m[0][1]; } +/* Return RageMatrixRotationX(rX) * RageMatrixRotationY(rY) * RageMatrixRotationZ(rZ) + * quickly (without actually doing two complete matrix multiplies), by removing the + * parts of the matrix multiplies that we know will be 0. */ +void RageMatrixRotationXYZ( RageMatrix* pOut, float rX, float rY, float rZ ) +{ + rX *= PI/180; + rY *= PI/180; + rZ *= PI/180; + + const float cX = cosf(rX); + const float sX = sinf(rX); + const float cY = cosf(rY); + const float sY = sinf(rY); + const float cZ = cosf(rZ); + const float sZ = sinf(rZ); + + /* + * X*Y: + * RageMatrix( + * cY, sY*sX, sY*cX, 0, + * 0, cX, -sX, 0, + * -sY, cY*sX, cY*cX, 0, + * 0, 0, 0, 1 + * ); + * + * X*Y*Z: + * + * RageMatrix( + * cZ*cY, cZ*sY*sX+sZ*cX, cZ*sY*cX+sZ*(-sX), 0, + * (-sZ)*cY, (-sZ)*sY*sX+cZ*cX, (-sZ)*sY*cX+cZ*(-sX), 0, + * -sY, cY*sX, cY*cX, 0, + * 0, 0, 0, 1 + * ); + */ + + pOut->m00 = cZ*cY; + pOut->m01 = cZ*sY*sX+sZ*cX; + pOut->m02 = cZ*sY*cX+sZ*(-sX); + pOut->m03 = 0; + pOut->m10 = (-sZ)*cY; + pOut->m11 = (-sZ)*sY*sX+cZ*cX; + pOut->m12 = (-sZ)*sY*cX+cZ*(-sX); + pOut->m13 = 0; + pOut->m20 = -sY; + pOut->m21 = cY*sX; + pOut->m22 = cY*cX; + pOut->m23 = 0; + pOut->m30 = 0; + pOut->m31 = 0; + pOut->m32 = 0; + pOut->m33 = 1; +} + /* This is similar in style to Actor::Command. However, Actors don't store * matrix stacks; they only store offsets and scales, and compound them into * a single transformations at once. This makes some things easy, but it's not diff --git a/stepmania/src/RageMath.h b/stepmania/src/RageMath.h index 1cd03ae685..77d936e644 100644 --- a/stepmania/src/RageMath.h +++ b/stepmania/src/RageMath.h @@ -31,9 +31,11 @@ void RageMatrixIdentity( RageMatrix* pOut ); void RageMatrixMultiply( RageMatrix* pOut, const RageMatrix* pA, const RageMatrix* pB ); void RageMatrixTranslation( RageMatrix* pOut, float x, float y, float z ); void RageMatrixScaling( RageMatrix* pOut, float x, float y, float z ); +void RageMatrixTranslateAndScale( RageMatrix* pOut, float fTransX, float fTransY, float fTransZ, float fScaleX, float fScaleY, float fScaleZ ); void RageMatrixRotationX( RageMatrix* pOut, float fTheta ); void RageMatrixRotationY( RageMatrix* pOut, float fTheta ); void RageMatrixRotationZ( RageMatrix* pOut, float fTheta ); +void RageMatrixRotationXYZ( RageMatrix* pOut, float rX, float rY, float rZ ); void RageMatrixCommand( CString sCommandString, RageMatrix &mat ); void RageQuatFromHPR(RageVector4* pOut, RageVector3 hpr ); void RageQuatFromPRH(RageVector4* pOut, RageVector3 prh );