// Aqsis // Copyright © 1997 - 2001, Paul C. Gregory // // Contact: pgregory@aqsis.org // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /** \file \brief Implements the CqTransform class for handling GPrim coordinate systems. \author Paul C. Gregory (pgregory@aqsis.org) */ #include "aqsis.h" #include "transform.h" #include "renderer.h" #include "imagebuffer.h" START_NAMESPACE( Aqsis ) //--------------------------------------------------------------------- /** Constructor. */ CqTransform::CqTransform() : CqMotionSpec(SqTransformation()), m_IsMoving(TqFalse) {} //--------------------------------------------------------------------- /** Copy constructor. */ CqTransform::CqTransform( const CqTransform& From ) : CqMotionSpec( From ) { m_IsMoving = From.m_IsMoving; m_StaticMatrix = From.m_StaticMatrix; m_Handedness = From.m_Handedness; /* *this = From; // Get the state of the transformation at the last stack entry, and use this as the default value for new timeslots. // if the previous level has motion specification, the value will be interpolated. CqMatrix matOtoWLast; TqBool handLast = TqFalse; if ( !Transform_stack.empty() ) { TqFloat time = QGetRenderContext()->Time(); matOtoWLast = Transform_stack.front() ->matObjectToWorld( time ); handLast = Transform_stack.front() ->GetHandedness( time ); } SqTransformation ct; ct.m_Handedness = handLast; ct.m_matTransform = matOtoWLast; SetDefaultObject( ct ); */ } //--------------------------------------------------------------------- /** Initialise the default object. */ void CqTransform::InitialiseDefaultObject( const CqTransformPtr& From ) { // Get the state of the transformation at the last stack entry, and use this as the default value for new timeslots. // if the previous level has motion specification, the value will be interpolated. TqFloat time = QGetRenderContext()->Time(); CqMatrix matOtoWLast = From->matObjectToWorld( time ); TqBool handLast = From->GetHandedness( time ); SqTransformation ct; ct.m_Handedness = handLast; ct.m_matTransform = matOtoWLast; SetDefaultObject( ct ); } //--------------------------------------------------------------------- /** Copy constructor. */ CqTransform::CqTransform( const CqTransformPtr& From ) : CqMotionSpec( *From ), m_IsMoving(TqFalse), m_StaticMatrix( From->m_StaticMatrix ), m_Handedness( From->m_Handedness ) { InitialiseDefaultObject( From ); } //--------------------------------------------------------------------- /** Concatenation constructors. */ CqTransform::CqTransform( const CqTransformPtr& From, TqFloat time, const CqMatrix& matTrans, const Set& /* set */ ) : CqMotionSpec( *From ), m_IsMoving( From->m_IsMoving ), m_StaticMatrix( From->m_StaticMatrix ), m_Handedness( From->m_Handedness ) { SetTransform( time, matTrans ); } CqTransform::CqTransform( const CqTransformPtr& From, TqFloat time, const CqMatrix& matTrans, const ConcatCurrent& /* concatCurrent */ ) : CqMotionSpec( *From ), m_IsMoving( From->m_IsMoving ), m_StaticMatrix( From->m_StaticMatrix ), m_Handedness( From->m_Handedness ) { ConcatCurrentTransform( time, matTrans ); } CqTransform::CqTransform( const CqTransformPtr& From, TqFloat time, const CqMatrix& matTrans, const SetCurrent& /* setCurrent */ ) : CqMotionSpec( *From ), m_IsMoving( From->m_IsMoving ), m_StaticMatrix( From->m_StaticMatrix ), m_Handedness( From->m_Handedness ) { SetCurrentTransform( time, matTrans ); } //--------------------------------------------------------------------- /** Destructor. */ CqTransform::~CqTransform() {} //--------------------------------------------------------------------- /** Copy function. */ #if 0 CqTransform& CqTransform::operator=( const CqTransform& From ) { CqMotionSpec::operator=( From ); m_IsMoving = From.m_IsMoving; m_StaticMatrix = From.m_StaticMatrix; m_Handedness = From.m_Handedness; return ( *this ); } #endif //--------------------------------------------------------------------- /** Set the transformation at the specified time. */ void CqTransform::SetCurrentTransform( TqFloat time, const CqMatrix& matTrans ) { TqFloat det = matTrans.Determinant(); TqBool flip = ( !matTrans.fIdentity() && det < 0 ); SqTransformation ct; ct.m_matTransform = matTrans; if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() ) { AddTimeSlot( time, ct ); m_IsMoving = TqTrue; } else { if( m_IsMoving ) { AddTimeSlot( time, ct ); } else { m_StaticMatrix = matTrans; m_Handedness = flip; ct.m_Handedness = flip; SetDefaultObject( ct ); } } } void CqTransform::SetTransform( TqFloat time, const CqMatrix& matTrans ) { TqFloat det = matTrans.Determinant(); TqBool flip = ( !matTrans.fIdentity() && det < 0 ); CqMatrix matCtoW = QGetRenderContext()->matSpaceToSpace("world", "camera", NULL, NULL, QGetRenderContext()->Time()); TqFloat camdet = matCtoW.Determinant(); TqBool camhand = ( !matCtoW.fIdentity() && camdet < 0 ); if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() ) { SqTransformation ct; ct.m_Handedness = (flip)? !camhand : camhand; ct.m_matTransform = matTrans; AddTimeSlot( time, ct ); m_IsMoving = TqTrue; } else { // If not in a motion block, but we are moving, apply the transform to all keys. if( m_IsMoving ) { CqMatrix mat0 = matObjectToWorld(Time(0)); SqTransformation ct; ct.m_Handedness = (flip)? !camhand : camhand; TqBool hand0 = ct.m_Handedness; ct.m_matTransform = matTrans; AddTimeSlot( Time(0), ct ); TqInt i; for(i=1; ipconCurrent() ->fMotionBlock() ) { ConcatTimeSlot( time, ct ); m_IsMoving = TqTrue; } else // else, if we are moving, apply this transform at all time slots, otherwise apply to static matrix. { if( m_IsMoving ) ConcatAllTimeSlots( ct ); else { m_StaticMatrix = m_StaticMatrix * matTrans; m_Handedness = (flip)? !m_Handedness : m_Handedness; ct.m_Handedness = m_Handedness; SetDefaultObject( ct ); } } } //--------------------------------------------------------------------- /** Get the transformation at the specified time. */ const CqMatrix& CqTransform::matObjectToWorld( TqFloat time ) const { static CqMatrix matInt; if( m_IsMoving ) { matInt = GetMotionObjectInterpolated( time ).m_matTransform; return ( matInt ); } else return ( m_StaticMatrix ); } //--------------------------------------------------------------------- /** Invert the transformation */ CqTransform* CqTransform::Inverse( ) { CqTransform* result = new CqTransform(); if( m_IsMoving ) { } else result->m_StaticMatrix = m_StaticMatrix.Inverse(); return(result); } //--------------------------------------------------------------------- /** Get the handedness at the specified time. */ TqBool CqTransform::GetHandedness( TqFloat time ) const { if( m_IsMoving ) return ( GetMotionObject( time ).m_Handedness ); else return ( m_Handedness ); } //--------------------------------------------------------------------- /** Reset the transform to the specified matrix, if the flag makeStatic is true * then make the transform static and clear the motion keyframes. */ void CqTransform::ResetTransform(const CqMatrix& mat, TqBool hand, TqBool makeStatic) { if( makeStatic ) { Reset(); m_IsMoving=TqFalse; m_StaticMatrix = mat; m_Handedness = hand; } else { TqInt i; for(i=0; i