mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
470 lines
13 KiB
C++
470 lines
13 KiB
C++
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Verve
|
||
|
|
// Copyright (C) 2014 - Violent Tulip
|
||
|
|
//
|
||
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
|
// of this software and associated documentation files (the "Software"), to
|
||
|
|
// deal in the Software without restriction, including without limitation the
|
||
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||
|
|
// furnished to do so, subject to the following conditions:
|
||
|
|
//
|
||
|
|
// The above copyright notice and this permission notice shall be included in
|
||
|
|
// all copies or substantial portions of the Software.
|
||
|
|
//
|
||
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||
|
|
// IN THE SOFTWARE.
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
#include "VPathNode.h"
|
||
|
|
#include "VPath.h"
|
||
|
|
|
||
|
|
#include "core/stream/bitStream.h"
|
||
|
|
#include "core/strings/stringUnit.h"
|
||
|
|
#include "sim/netConnection.h"
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
static U32 gOrientationTypeBits = getBinLog2( getNextPow2( VPathNode::k_OrientationTypeSize ) );
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
VPathNode::VPathNode( void ) :
|
||
|
|
mPath( NULL ),
|
||
|
|
mLocalPosition( Point3F( 0.f, 0.f, 0.f ) ),
|
||
|
|
mLocalRotation( QuatF( 0.f, 0.f, 0.f, 1.f ) ),
|
||
|
|
mWorldPosition( Point3F( 0.f, 0.f, 0.f ) ),
|
||
|
|
mWorldRotation( QuatF( 0.f, 0.f, 0.f, 1.f ) ),
|
||
|
|
mWeight( 10.f ),
|
||
|
|
mLength( 0.f )
|
||
|
|
{
|
||
|
|
// Init.
|
||
|
|
mOrientationMode.Type = k_OrientationFree;
|
||
|
|
mOrientationMode.Point = Point3F::Zero;
|
||
|
|
|
||
|
|
// Set the initial mask.
|
||
|
|
mNetState.setMaskBits( k_StateInit );
|
||
|
|
|
||
|
|
VECTOR_SET_ASSOCIATION( mNetState );
|
||
|
|
}
|
||
|
|
|
||
|
|
VPathNode::~VPathNode( void )
|
||
|
|
{
|
||
|
|
mNetState.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
//
|
||
|
|
// Network Methods.
|
||
|
|
//
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
U32 VPathNode::packNode( NetConnection *pConnection, BitStream *pStream )
|
||
|
|
{
|
||
|
|
// Init Return Mask.
|
||
|
|
U32 retMask = 0;
|
||
|
|
|
||
|
|
// Fetch State.
|
||
|
|
VNetStateInfo *state = getState( pConnection );
|
||
|
|
|
||
|
|
// Note: This is out of sync with VPathNode::unpackUpdate().
|
||
|
|
// If you're ever going to use these methods outside of VPath, you
|
||
|
|
// will need to read a flag *before* calling unpack!
|
||
|
|
|
||
|
|
// Was the Node Created?
|
||
|
|
if ( pStream->writeFlag( state->Mask & k_StateCreate ) )
|
||
|
|
{
|
||
|
|
// Clear Update.
|
||
|
|
state->Mask &= ~k_StateCreate;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Send mLocalPosition?
|
||
|
|
if ( pStream->writeFlag( state->Mask & k_StateUpdatePosition ) )
|
||
|
|
{
|
||
|
|
// Write mLocalPosition.
|
||
|
|
pStream->write( mLocalPosition.x );
|
||
|
|
pStream->write( mLocalPosition.y );
|
||
|
|
pStream->write( mLocalPosition.z );
|
||
|
|
|
||
|
|
// Clear Update.
|
||
|
|
state->Mask &= ~k_StateUpdatePosition;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Send mLocalRotation?
|
||
|
|
if ( pStream->writeFlag( state->Mask & k_StateUpdateRotation ) )
|
||
|
|
{
|
||
|
|
// Write mLocalRotation.
|
||
|
|
pStream->write( mLocalRotation.x );
|
||
|
|
pStream->write( mLocalRotation.y );
|
||
|
|
pStream->write( mLocalRotation.z );
|
||
|
|
pStream->write( mLocalRotation.w );
|
||
|
|
|
||
|
|
// Clear Update.
|
||
|
|
state->Mask &= ~k_StateUpdateRotation;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Send mWeight?
|
||
|
|
if ( pStream->writeFlag( state->Mask & k_StateUpdateWeight ) )
|
||
|
|
{
|
||
|
|
// Write mWeight.
|
||
|
|
pStream->write( mWeight );
|
||
|
|
|
||
|
|
// Clear Update.
|
||
|
|
state->Mask &= ~k_StateUpdateWeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Send Orientation Update?
|
||
|
|
if ( pStream->writeFlag( state->Mask & k_StateUpdateOrientation ) )
|
||
|
|
{
|
||
|
|
// Clear Update?
|
||
|
|
bool clearUpdate = true;
|
||
|
|
|
||
|
|
// Write State.
|
||
|
|
pStream->writeInt( mOrientationMode.Type, gOrientationTypeBits );
|
||
|
|
|
||
|
|
switch ( mOrientationMode.Type )
|
||
|
|
{
|
||
|
|
case k_OrientationToPoint :
|
||
|
|
{
|
||
|
|
// Write Point.
|
||
|
|
pStream->write( mOrientationMode.Point.x );
|
||
|
|
pStream->write( mOrientationMode.Point.y );
|
||
|
|
pStream->write( mOrientationMode.Point.z );
|
||
|
|
|
||
|
|
} break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( clearUpdate )
|
||
|
|
{
|
||
|
|
// Clear Update.
|
||
|
|
state->Mask &= ~k_StateUpdateOrientation;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return Mask.
|
||
|
|
return retMask;
|
||
|
|
}
|
||
|
|
|
||
|
|
void VPathNode::unpackNode( NetConnection *pConnection, BitStream *pStream )
|
||
|
|
{
|
||
|
|
// Note: This is out of sync with VPathNode::packUpdate().
|
||
|
|
// If you're ever going to use these methods outside of VPath, you
|
||
|
|
// will need to read a flag *before* calling unpack!
|
||
|
|
|
||
|
|
// Update World Data.
|
||
|
|
bool updateWorld = false;
|
||
|
|
|
||
|
|
// Update Local Position?
|
||
|
|
if ( pStream->readFlag() )
|
||
|
|
{
|
||
|
|
// Read Local Position.
|
||
|
|
pStream->read( &mLocalPosition.x );
|
||
|
|
pStream->read( &mLocalPosition.y );
|
||
|
|
pStream->read( &mLocalPosition.z );
|
||
|
|
|
||
|
|
updateWorld = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update Local Rotation?
|
||
|
|
if ( pStream->readFlag() )
|
||
|
|
{
|
||
|
|
// Read Local Rotation.
|
||
|
|
pStream->read( &mLocalRotation.x );
|
||
|
|
pStream->read( &mLocalRotation.y );
|
||
|
|
pStream->read( &mLocalRotation.z );
|
||
|
|
pStream->read( &mLocalRotation.w );
|
||
|
|
|
||
|
|
updateWorld = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update Weight?
|
||
|
|
if ( pStream->readFlag() )
|
||
|
|
{
|
||
|
|
// Read Weight.
|
||
|
|
pStream->read( &mWeight );
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update Orientation?
|
||
|
|
if ( pStream->readFlag() )
|
||
|
|
{
|
||
|
|
// Read Orientation Mode.
|
||
|
|
mOrientationMode.Type = ( eOrientationType )pStream->readInt( gOrientationTypeBits );
|
||
|
|
|
||
|
|
switch ( mOrientationMode.Type )
|
||
|
|
{
|
||
|
|
case k_OrientationToPoint :
|
||
|
|
{
|
||
|
|
// Read Point.
|
||
|
|
pStream->read( &mOrientationMode.Point.x );
|
||
|
|
pStream->read( &mOrientationMode.Point.y );
|
||
|
|
pStream->read( &mOrientationMode.Point.z );
|
||
|
|
|
||
|
|
} break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( updateWorld )
|
||
|
|
{
|
||
|
|
// Update World Position.
|
||
|
|
updateWorldData();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
String VPathNode::toString( void )
|
||
|
|
{
|
||
|
|
String retBuffer;
|
||
|
|
|
||
|
|
// Buffer Node Properties.
|
||
|
|
// {Position} {Rotation} {Weight}
|
||
|
|
const AngAxisF aa( mLocalRotation );
|
||
|
|
retBuffer = String::ToString( "%f %f %f %f %f %f %f %f", mLocalPosition.x, mLocalPosition.y, mLocalPosition.z,
|
||
|
|
aa.axis.x, aa.axis.y, aa.axis.z, aa.angle,
|
||
|
|
mWeight );
|
||
|
|
|
||
|
|
// Add Tab.
|
||
|
|
retBuffer += "\t";
|
||
|
|
|
||
|
|
// Determine the Type.
|
||
|
|
StringTableEntry typeString = getOrientationTypeLabel( mOrientationMode.Type );
|
||
|
|
switch( mOrientationMode.Type )
|
||
|
|
{
|
||
|
|
case k_OrientationFree :
|
||
|
|
{
|
||
|
|
// Buffer String.
|
||
|
|
retBuffer += typeString;
|
||
|
|
|
||
|
|
} break;
|
||
|
|
|
||
|
|
case k_OrientationToPoint:
|
||
|
|
{
|
||
|
|
// Fetch Point.
|
||
|
|
const Point3F &lookAtPoint = mOrientationMode.Point;
|
||
|
|
|
||
|
|
// Buffer String.
|
||
|
|
retBuffer += String::ToString( "%s %f %f %f", typeString, lookAtPoint.x, lookAtPoint.y, lookAtPoint.z );
|
||
|
|
|
||
|
|
} break;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return String.
|
||
|
|
return retBuffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool VPathNode::fromString( const String &pString )
|
||
|
|
{
|
||
|
|
// Split Data.
|
||
|
|
// {Position} {Rotation} {Weight}
|
||
|
|
const char *baseData = StringUnit::getUnit( pString.c_str(), 0, "\t" );
|
||
|
|
|
||
|
|
Point3F pos;
|
||
|
|
AngAxisF aa;
|
||
|
|
F32 weight;
|
||
|
|
|
||
|
|
// Scan Base.
|
||
|
|
dSscanf( baseData, "%g %g %g %g %g %g %g %g", &pos.x, &pos.y, &pos.z,
|
||
|
|
&aa.axis.x, &aa.axis.y, &aa.axis.z, &aa.angle,
|
||
|
|
&weight );
|
||
|
|
|
||
|
|
// Apply Changes.
|
||
|
|
setLocalPosition( pos );
|
||
|
|
setLocalRotation( QuatF( aa ) );
|
||
|
|
setWeight( weight );
|
||
|
|
|
||
|
|
// Fetch Orientation Data.
|
||
|
|
String orientationData = StringUnit::getUnit( pString.c_str(), 1, "\t" );
|
||
|
|
|
||
|
|
// Fetch Orientation Type.
|
||
|
|
String orientationTypeString = orientationData;
|
||
|
|
if ( orientationData.find( " " ) )
|
||
|
|
{
|
||
|
|
// Use First Word.
|
||
|
|
orientationTypeString = orientationData.substr( 0, orientationData.find( " " ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set Orientation Type.
|
||
|
|
const eOrientationType &orientationType = getOrientationTypeEnum( orientationTypeString.c_str() );
|
||
|
|
switch( orientationType )
|
||
|
|
{
|
||
|
|
case k_OrientationFree :
|
||
|
|
{
|
||
|
|
// Apply Mode.
|
||
|
|
setOrientationMode( orientationType );
|
||
|
|
|
||
|
|
} break;
|
||
|
|
|
||
|
|
case k_OrientationToPoint:
|
||
|
|
{
|
||
|
|
// Fetch Point.
|
||
|
|
Point3F lookAtPoint;
|
||
|
|
// Buffer String.
|
||
|
|
dSscanf( orientationData.c_str(), "%*s %f %f %f", &lookAtPoint.x, &lookAtPoint.y, &lookAtPoint.z );
|
||
|
|
|
||
|
|
// Apply Mode.
|
||
|
|
setOrientationMode( orientationType, lookAtPoint );
|
||
|
|
|
||
|
|
} break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
//
|
||
|
|
// Property Methods.
|
||
|
|
//
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
Point3F VPathNode::getWorldPosition( void ) const
|
||
|
|
{
|
||
|
|
return mWorldPosition;
|
||
|
|
}
|
||
|
|
|
||
|
|
QuatF VPathNode::getWorldRotation( void ) const
|
||
|
|
{
|
||
|
|
return mWorldRotation;
|
||
|
|
}
|
||
|
|
|
||
|
|
MatrixF VPathNode::getWorldTransform( void ) const
|
||
|
|
{
|
||
|
|
MatrixF mat;
|
||
|
|
getWorldRotation().setMatrix( &mat );
|
||
|
|
mat.setPosition( getWorldPosition() );
|
||
|
|
|
||
|
|
return mat;
|
||
|
|
}
|
||
|
|
|
||
|
|
void VPathNode::setLocalPosition( const Point3F &pPosition )
|
||
|
|
{
|
||
|
|
// Update?
|
||
|
|
if ( mLocalPosition != pPosition )
|
||
|
|
{
|
||
|
|
// Apply.
|
||
|
|
mLocalPosition = pPosition;
|
||
|
|
|
||
|
|
// Update World Position.
|
||
|
|
updateWorldData();
|
||
|
|
|
||
|
|
// Flag Update.
|
||
|
|
setMaskBits( k_StateUpdatePosition );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void VPathNode::setLocalRotation( const QuatF &pRotation )
|
||
|
|
{
|
||
|
|
// Update?
|
||
|
|
if ( mLocalRotation != pRotation )
|
||
|
|
{
|
||
|
|
// Apply.
|
||
|
|
mLocalRotation = pRotation;
|
||
|
|
|
||
|
|
// Update World Rotation.
|
||
|
|
updateWorldData();
|
||
|
|
|
||
|
|
// Flag Update.
|
||
|
|
setMaskBits( k_StateUpdateRotation );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void VPathNode::setWeight( const F32 &pWeight )
|
||
|
|
{
|
||
|
|
// Update?
|
||
|
|
if ( mWeight != pWeight )
|
||
|
|
{
|
||
|
|
// Apply.
|
||
|
|
mWeight = pWeight;
|
||
|
|
|
||
|
|
// Flag Update.
|
||
|
|
setMaskBits( k_StateUpdateWeight );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void VPathNode::setOrientationMode( const eOrientationType &pType )
|
||
|
|
{
|
||
|
|
// Update?
|
||
|
|
if ( mOrientationMode.Type != pType )
|
||
|
|
{
|
||
|
|
// Update.
|
||
|
|
mOrientationMode.Type = pType;
|
||
|
|
|
||
|
|
// Flag Update.
|
||
|
|
setMaskBits( k_StateUpdateOrientation );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void VPathNode::setOrientationMode( const eOrientationType &pType, const Point3F &pPoint )
|
||
|
|
{
|
||
|
|
AssertFatal( pType == k_OrientationToPoint, "VPathNode::setOrientationMode() - Invalid mOrientation Type." );
|
||
|
|
|
||
|
|
// Update?
|
||
|
|
if ( ( mOrientationMode.Type != pType ) || ( mOrientationMode.Point != pPoint ) )
|
||
|
|
{
|
||
|
|
// Update.
|
||
|
|
mOrientationMode.Type = pType;
|
||
|
|
mOrientationMode.Point = pPoint;
|
||
|
|
|
||
|
|
// Flag Update.
|
||
|
|
setMaskBits( k_StateUpdateOrientation );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void VPathNode::updateWorldData( void )
|
||
|
|
{
|
||
|
|
if ( !mPath )
|
||
|
|
{
|
||
|
|
setWorldPosition( getLocalPosition() );
|
||
|
|
setWorldRotation( getLocalRotation() );
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fetch Path Details.
|
||
|
|
const MatrixF &pathTransform = mPath->getTransform();
|
||
|
|
const QuatF &pathRotation( pathTransform );
|
||
|
|
|
||
|
|
// Calculate the World Position.
|
||
|
|
Point3F newPosition = getLocalPosition();
|
||
|
|
newPosition.convolve( mPath->getScale() );
|
||
|
|
pathTransform.mulP( newPosition );
|
||
|
|
|
||
|
|
// Calculate the new Rotation.
|
||
|
|
QuatF newRotation;
|
||
|
|
newRotation.mul( getLocalRotation(), pathRotation );
|
||
|
|
|
||
|
|
// Apply.
|
||
|
|
setWorldPosition( newPosition );
|
||
|
|
setWorldRotation( newRotation );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
//
|
||
|
|
// Enumeration Methods.
|
||
|
|
//
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
// Implement the Orientation Type enum list.
|
||
|
|
ImplementEnumType( VPathNodeOrientationType,"" )
|
||
|
|
{ VPathNode::k_OrientationFree, "FREE" },
|
||
|
|
{ VPathNode::k_OrientationToPoint, "TOPOINT" },
|
||
|
|
EndImplementEnumType;
|
||
|
|
|
||
|
|
VPathNode::eOrientationType VPathNode::getOrientationTypeEnum( const char *pLabel )
|
||
|
|
{
|
||
|
|
VPathNode::eOrientationType out;
|
||
|
|
if ( !castConsoleTypeFromString( out, pLabel ) )
|
||
|
|
{
|
||
|
|
// Bah!
|
||
|
|
return VPathNode::k_OrientationFree;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return.
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
StringTableEntry VPathNode::getOrientationTypeLabel( const eOrientationType &pType )
|
||
|
|
{
|
||
|
|
// Return.
|
||
|
|
return castConsoleTypeToString( pType );
|
||
|
|
}
|