123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205 |
- //-----------------------------------------------------------------------------
- // 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 "VPathEditor.h"
- #include "console/consoleTypes.h"
- #include "gfx/gfxDrawUtil.h"
- #include "gfx/primBuilder.h"
- #include "gui/worldEditor/worldEditor.h"
- #include "math/mathUtils.h"
- #include "sim/netConnection.h"
- //-----------------------------------------------------------------------------
- static F32 gProjectDistance = 2000.f;
- static F32 gSelectionDistance = 2.f;
- static ColorI gPathColor( 255, 255, 255 );
- static ColorI gPathColorSel( 0, 255, 255 );
- static ColorI gNodeLookAtPointColor( 255, 127, 39 );
- //-----------------------------------------------------------------------------
- // Implement the Edit Mode enum list.
- ImplementEnumType( VPathEditorMode, "" )
- { VPathEditor::k_Gizmo, "GIZMO" },
- { VPathEditor::k_AddNode, "ADDNODE" },
- { VPathEditor::k_DeleteNode, "DELETENODE" },
- EndImplementEnumType;
- //-----------------------------------------------------------------------------
- IMPLEMENT_CONOBJECT( VPathEditor );
- //-----------------------------------------------------------------------------
- VPathEditor::VPathEditor( void ) :
- mIsDirty( false ),
- mEditMode( k_Gizmo ),
- mEditWeight( false ),
- mEditWeightHandle( -1 )
- {
- // Void.
- }
- bool VPathEditor::onAdd( void )
- {
- if ( !Parent::onAdd() )
- {
- return false;
- }
- // Assign Gizmo Name.
- mGizmo->assignName( "VPathEditorGizmo" );
- return true;
- }
- bool VPathEditor::onWake( void )
- {
- // Clear Selection.
- updateSelection( NULL, -1 );
- // Return Parent Value.
- return Parent::onWake();
- }
- void VPathEditor::initPersistFields( void )
- {
- addField( "IsDirty", TypeBool, Offset( mIsDirty, VPathEditor ) );
- addField( "EditMode", TYPEID<EditMode>(), Offset( mEditMode, VPathEditor ) );
- Parent::initPersistFields();
- }
- //-----------------------------------------------------------------------------
- //
- // Gui Events
- //
- //-----------------------------------------------------------------------------
- void VPathEditor::on3DMouseDown( const Gui3DMouseEvent &pEvent )
- {
- // Using the Gizmo?
- if ( mEditMode != k_Gizmo )
- {
- // No, Quit Now.
- return;
- }
- // Gizmo Event.
- mGizmo->on3DMouseDown( pEvent );
- if ( isValidSelection() )
- {
- // Store Node Information.
- pushNodeEdit();
- switch( mGizmoProfile->mode )
- {
- case MoveMode:
- case RotateMode:
- {
- if ( mGizmo->getSelection() != Gizmo::None )
- {
- // Using Gizmo.
- return;
- }
- } break;
- case ScaleMode:
- {
- if ( isEditingWeight( pEvent ) )
- {
- // Editing Weights.
- return;
- }
- } break;
- }
- }
- else if ( mSelection.Path )
- {
- // Store Path Information.
- pushPathEdit();
- if ( mGizmo->getSelection() != Gizmo::None )
- {
- // Using Gizmo.
- return;
- }
- }
- // Update Selection.
- if ( !updateSelection( pEvent ) )
- {
- // Clear Selection.
- updateSelection( NULL, -1 );
- }
- }
- void VPathEditor::on3DMouseUp( const Gui3DMouseEvent &pEvent )
- {
- switch ( mEditMode )
- {
- case k_Gizmo :
- {
- // Gizmo Event.
- mGizmo->on3DMouseUp( pEvent );
- // Handle History Actions.
- popPathEdit();
- popNodeEdit();
- // Clear Editing.
- mEditWeight = false;
- } break;
- case k_AddNode :
- {
- if ( mSelection.Path != NULL )
- {
- // Add New!
- addNode( pEvent );
- // Dirty.
- mIsDirty = true;
- }
- } break;
- case k_DeleteNode :
- {
- // Update Selection.
- if ( updateSelection( pEvent ) )
- {
- if ( isValidSelection() )
- {
- // Delete Node.
- deleteNode( mSelection.Node );
- // Dirty.
- mIsDirty = true;
- }
- // Clear Node Selection.
- updateSelection( mSelection.Path, -1 );
- }
- } break;
- }
- }
- void VPathEditor::on3DMouseMove( const Gui3DMouseEvent &pEvent )
- {
- // Update?
- if ( mEditMode != k_Gizmo || !mSelection.Path )
- {
- return;
- }
- // Update Gizmo?
- if ( mSelection.Node == -1 || mGizmoProfile->mode != ScaleMode )
- {
- // Gizmo Event.
- mGizmo->on3DMouseMove( pEvent );
- }
- }
- void VPathEditor::on3DMouseDragged( const Gui3DMouseEvent &pEvent )
- {
- // Update?
- if ( mEditMode != k_Gizmo || !mSelection.Path )
- {
- return;
- }
- // Update Gizmo?
- if ( mSelection.Node == -1 || mGizmoProfile->mode != ScaleMode )
- {
- // Gizmo Event.
- mGizmo->on3DMouseDragged( pEvent );
- // Handle Gizmo?
- if ( mGizmo->getSelection() == Gizmo::None )
- {
- // Return.
- return;
- }
- }
- // Editing the Path?
- if ( mSelection.Node == -1 )
- {
- switch ( mGizmoProfile->mode )
- {
- case MoveMode :
- {
- // Fetch Node Position.
- const Point3F oldPosition = mSelection.Path->getPosition();
- // Determine New Position.
- const Point3F newPosition = ( oldPosition + mGizmo->getOffset() );
- // Apply New Position.
- setPathPosition( newPosition );
- // Dirty.
- mIsDirty = true;
- mPathEdit.Dirty = true;
- } break;
- /*
- case RotateMode :
- {
- // Rotation Delta.
- MatrixF deltaRotation( EulerF( mGizmo->getDeltaRot() ) );
- // Fetch Current Transform.
- MatrixF mat = mSelection.Path->getTransform();
- mat.mul( deltaRotation );
- // Apply New Transform.
- setPathTransform( mat );
- // Dirty.
- mIsDirty = true;
- mPathEdit.Dirty = true;
- } break;
- case ScaleMode :
- {
- // Apply New Scale.
- setPathScale( mGizmo->getScale() );
- // Dirty.
- mIsDirty = true;
- mPathEdit.Dirty = true;
- } break;
- */
- }
- }
- // No, Editing a Node
- else
- {
- switch ( mGizmoProfile->mode )
- {
- case MoveMode :
- {
- // Fetch Node.
- VPathNode *node = mSelection.Path->getNode( mSelection.Node );
- // Fetch Node Position.
- const Point3F oldPosition = node->getLocalPosition();
- // Invert Transform.
- MatrixF pathTransform = mSelection.Path->getTransform();
- pathTransform.setPosition( Point3F::Zero );
- pathTransform.inverse();
- Point3F deltaPosition = mGizmo->getOffset();
- pathTransform.mulP( deltaPosition );
- // Apply New Position.
- setNodePosition( mSelection.Node, ( oldPosition + deltaPosition ) );
- } break;
- case RotateMode :
- {
- // Fetch Node.
- VPathNode *node = mSelection.Path->getNode( mSelection.Node );
- // Invert Transform.
- MatrixF pathTransform = mSelection.Path->getTransform();
- pathTransform.setPosition( Point3F::Zero );
- pathTransform.inverse();
- // Rotation Delta.
- MatrixF deltaRotation( EulerF( mGizmo->getDeltaRot() ) );
- pathTransform.mul( deltaRotation );
- // Fetch Current Transform.
- MatrixF mat = node->getWorldTransform();
- mat.mul( deltaRotation );
- // Construct Quat.
- QuatF newRotation;
- newRotation.set( mat );
- // Apply New Rotation.
- setNodeRotation( mSelection.Node, newRotation );
- } break;
- case ScaleMode :
- {
- if ( isEditingWeight() )
- {
- // Edit Weight.
- updateWeight( pEvent );
- }
- } break;
- }
- }
- }
- //-----------------------------------------------------------------------------
- //
- // Reference Methods.
- //
- //-----------------------------------------------------------------------------
- VPath *VPathEditor::getClientPath( VPath *pPath )
- {
- if ( !pPath )
- {
- return NULL;
- }
- NetConnection *toServer = NetConnection::getConnectionToServer();
- NetConnection *toClient = NetConnection::getLocalClientConnection();
- if ( !toServer || !toClient )
- {
- return NULL;
- }
- const S32 ghostIndex = toClient->getGhostIndex( pPath );
- if ( ghostIndex == -1 )
- {
- return NULL;
- }
- return dynamic_cast<VPath*>( toServer->resolveGhost( ghostIndex ) );
- }
- //-----------------------------------------------------------------------------
- //
- // Selection Methods.
- //
- //-----------------------------------------------------------------------------
- bool VPathEditor::updateSelection( const Gui3DMouseEvent &pEvent )
- {
- const Point3F pt0 = pEvent.pos;
- const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
- RayInfo ri;
- if ( !gServerContainer.collideBox( pt0, pt1, MarkerObjectType, &ri ) )
- {
- // No Object.
- return false;
- }
- VPath *path = dynamic_cast<VPath*>( ri.object );
- if ( !path )
- {
- // No Path Object.
- return false;
- }
- // No Node.
- S32 nodeIndex = -1;
- for ( VPathNodeIterator itr = path->mNodeList.begin(); itr != path->mNodeList.end(); itr++ )
- {
- VPathNode *node = ( *itr );
- Point3F projPosition;
- project( node->getWorldPosition(), &projPosition );
- if ( projPosition.z <= 0.0f )
- {
- continue;
- }
- const Point2I rectHalfSize( 8, 8 );
- const Point2I screenPosition( ( S32 )projPosition.x, ( S32 )projPosition.y );
- const RectI screenRect( screenPosition - rectHalfSize, 2 * rectHalfSize );
- // Mouse Close Enough?
- if ( screenRect.pointInRect( pEvent.mousePoint ) )
- {
- // Select Node.
- nodeIndex = ( itr - path->mNodeList.begin() );
- }
- }
- // Set Selection.
- updateSelection( path, nodeIndex );
- // Valid Selection.
- return true;
- }
- void VPathEditor::updateSelection( VPath *pPathObject, const S32 &pNodeIndex )
- {
- // Store Selection.
- mSelection.Path = pPathObject;
- mSelection.Node = pNodeIndex;
- // Quick Update.
- updateSelection();
- // Return Buffer.
- char buffer[2][32];
- dSprintf( buffer[0], sizeof( buffer[0] ), "%d", ( pPathObject ) ? pPathObject->getId() : 0 );
- dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
- // Callback.
- Con::executef( this, "onUpdateSelection", buffer[0], buffer[1] );
- }
- void VPathEditor::updateSelection( void )
- {
- if ( !isValidSelection() )
- {
- // No Further Updates.
- return;
- }
- // Fetch Node.
- VPathNode *node = mSelection.Path->getNode( mSelection.Node );
- // Fetch Node Rotation Matrix.
- MatrixF mat;
- node->getWorldRotation().setMatrix( &mat );
- // Determine Tangent Axis.
- Point3F pt0( VPath::gBezierAxis * node->getWeight() );
- Point3F pt1( -VPath::gBezierAxis * node->getWeight() );
- // Rotate Axis.
- mat.mulP( pt0 );
- mat.mulP( pt1 );
- // Offset Points.
- pt0 += node->getWorldPosition();
- pt1 += node->getWorldPosition();
- // Store Points.
- mSelection.TangentHandle[0] = pt0;
- mSelection.TangentHandle[1] = pt1;
- }
- ConsoleMethod( VPathEditor, clearSelection, void, 2, 2, "( void )" )
- {
- // Clear Selection.
- object->updateSelection( NULL, -1 );
- }
- ConsoleMethod( VPathEditor, setSelection, void, 3, 4, "( pObject, [pNodeIndex] )" )
- {
- // Fetch Path.
- VPath *path = dynamic_cast<VPath*>( Sim::findObject( argv[2] ) );
- if ( !path )
- {
- Con::errorf( "VPathEditor::setSelection() - Unable to select target Object." );
- return;
- }
- if ( argc == 3 )
- {
- // Select Path.
- object->updateSelection( path, -1 );
- return;
- }
- // Select Path & Node.
- object->updateSelection( path, dAtoi( argv[3] ) );
- }
- ConsoleMethod( VPathEditor, isValidSelection, bool, 2, 2, "( void )" )
- {
- return object->isValidSelection();
- }
- ConsoleMethod( VPathEditor, getSelectedPath, S32, 2, 2, "( void )" )
- {
- // Fetch Path.
- VPath *path = object->mSelection.Path;
- // Return ID.
- return ( path ) ? path->getId() : 0;
- }
- ConsoleMethod( VPathEditor, getSelectedNode, S32, 2, 2, "( void )" )
- {
- // Return Node Index.
- return ( object->mSelection.Path ) ? object->mSelection.Node : -1;
- }
- ConsoleMethod( VPathEditor, deleteSelection, void, 2, 2, "( void )" )
- {
- // Valid Selection?
- if ( object->isValidSelection() )
- {
- object->deleteNode( object->mSelection.Node );
- }
- }
- //-----------------------------------------------------------------------------
- //
- // Weight Editing Methods.
- //
- //-----------------------------------------------------------------------------
- bool VPathEditor::isEditingWeight( const Gui3DMouseEvent &pEvent )
- {
- if ( !isValidSelection() || mSelection.Path->mPathType != VPath::k_PathBezier )
- {
- // False.
- mEditWeight = false;
- // Invalid Selection.
- return false;
- }
- const Point3F pt0 = pEvent.pos;
- const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
- // Min Index.
- S32 minNode = -1;
- F32 minDistance = F32_MAX;
- for ( S32 i = 0; i < 2; i++ )
- {
- Point3F pt;
- if ( !Utility::FindNearestPointOnLine( mSelection.TangentHandle[i], pt0, pt1, &pt ) )
- {
- // Skip.
- continue;
- }
- // Distance.
- const F32 ptDistance = ( pt - mSelection.TangentHandle[i] ).len();
- if ( ptDistance < minDistance )
- {
- // Store Index.
- minNode = i;
- // Store Distance.
- minDistance = ptDistance;
- }
- }
- if ( minDistance > gSelectionDistance )
- {
- // False.
- mEditWeight = false;
- // Too Far Away.
- return false;
- }
- // True.
- mEditWeight = true;
- mEditWeightHandle = minNode;
- return true;
- }
- void VPathEditor::updateWeight( const Gui3DMouseEvent &pEvent )
- {
- if ( !isEditingWeight() )
- {
- // Woops!
- return;
- }
- // Fetch Current Node.
- VPathNode *node = mSelection.Path->getNode( mSelection.Node );
- Point3F nodePos = node->getWorldPosition();
- // Fetch Node Transform.
- MatrixF mat = node->getWorldTransform();
- // Fetch the Normal.
- const VectorF planeNormal = mat.getColumn3F( 0 );
- // Construct Plane.
- const PlaneF plane( nodePos, planeNormal );
- Point3F iPt;
- if ( plane.intersect( pEvent.pos, pEvent.vec, &iPt ) )
- {
- /*
- // Fetch Edit Vector.
- VectorF tangentVect( mSelection.TangentHandle[mEditWeightHandle] - nodePos );
- tangentVect.normalize();
- // Fetch Mouse Vector.
- VectorF mouseVec( iPt - nodePos );
- F32 mouseDist = mouseVec.len();
- mouseVec.normalize();
- // Find the Angles.
- F32 tangentAngle = mAtan2( -tangentVect.z, tangentVect.x );
- F32 mouseAngle = mAtan2( -mouseVec.z, mouseVec.x );
- // Determine Sign.
- const S32 sign = ( planeNormal.y > 0.f ) ? -1.f : 1.f;
- // Delta Rotation..
- const QuatF deltaRotation( AngAxisF( planeNormal, sign * ( mouseAngle - tangentAngle ) ) );
- // Calculate New Rotation.
- QuatF newRotation;
- newRotation.mul( nodePos, deltaRotation );
- // Apply Rotation.
- setNodeRotation( mSelection.Node, newRotation );
- */
- /*
- // Fetch Edit Vector.
- VectorF handleVec( mSelection.TangentHandle[mEditWeightHandle] - nodePos );
- handleVec.normalize();
- // Fetch Mouse Vector.
- VectorF mouseVec( iPt - nodePos );
- mouseVec.normalize();
- // Find the Angles.
- F32 handleAngle = Utility::GetPitch( handleVec ); //mAtan2( -handleVec.z, handleVec.x );
- F32 mouseAngle = Utility::GetPitch( mouseVec ); //mAtan2( -mouseVec.z, mouseVec.x );
- // Determine Sign.
- const S32 sign = ( planeNormal.y > 0.f ) ? -1.f : 1.f;
- // Delta Rotation.
- MatrixF rotMat;
- AngAxisF::RotateY( sign * ( mouseAngle - handleAngle ), &rotMat );
- // Rotate.
- mat.mul( rotMat );
- QuatF newRotation;
- newRotation.set( mat );
- // Apply Rotation.
- setNodeRotation( mSelection.Node, newRotation );
- */
- // Apply Weight.
- setNodeWeight( mSelection.Node, ( iPt - nodePos ).len() );
- }
- }
- //-----------------------------------------------------------------------------
- //
- // Path Editing Methods.
- //
- //-----------------------------------------------------------------------------
- void VPathEditor::setPathPosition( const Point3F &pPosition )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Update Position.
- serverPath->setPosition( pPosition );
- clientPath->setPosition( pPosition );
- // Update Selection.
- updateSelection();
- }
- void VPathEditor::setPathRotation( const QuatF &pRotation )
- {
- // Determine the Matrix.
- MatrixF mat;
- pRotation.setMatrix( &mat );
- mat.setPosition( mSelection.Path->getPosition() );
- // Update Transform.
- setPathTransform( mat );
- }
- void VPathEditor::setPathTransform( const MatrixF &pTransform )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Update Transform.
- serverPath->setTransform( pTransform );
- clientPath->setTransform( pTransform );
- // Update Selection.
- updateSelection();
- }
- void VPathEditor::setPathScale( const VectorF &pScale )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Fetch Current Scale.
- VectorF scale = serverPath->getScale();
- scale.convolve( pScale );
- // Update Scale.
- serverPath->setScale( scale );
- clientPath->setScale( scale );
- // Update Selection.
- updateSelection();
- }
- //-----------------------------------------------------------------------------
- //
- // Node Editing Methods.
- //
- //-----------------------------------------------------------------------------
- bool VPathEditor::getPointOnPath( VPath *pPath, const Gui3DMouseEvent &pEvent, S32 &pNode, MatrixF &pTransform )
- {
- if ( pPath->getNodeCount() < 2 )
- {
- // Start / End Points.
- const Point3F pt0 = pEvent.pos;
- const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
- // Create Intersection Plane.
- const PlaneF plane( pPath->getPosition(), VPath::gBezierUp );
- // Intersection Point.
- Point3F intersectionPoint;
- if ( !plane.intersect( pEvent.pos, pEvent.vec, &intersectionPoint ) )
- {
- // No Intersection.
- return false;
- }
- // I'th Node.
- pNode = pPath->getNodeCount();
- // Set Identity.
- pTransform.identity();
- // Set Position.
- pTransform.setPosition( intersectionPoint );
- // Return.
- return true;
- }
- switch ( pPath->mPathType )
- {
- case VPath::k_PathLinear :
- {
- return getPointOnLinearPath( pPath, pEvent, pNode, pTransform );
- } break;
- case VPath::k_PathBezier :
- {
- return getPointOnBezierPath( pPath, pEvent, pNode, pTransform );
- } break;
- }
- return false;
- }
- bool VPathEditor::getPointOnLinearPath( VPath *pPath, const Gui3DMouseEvent &pEvent, S32 &pNode, MatrixF &pTransform )
- {
- // Start / End Points.
- const Point3F pt0 = pEvent.pos;
- const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
- S32 minNode = -1;
- F32 minDistance = F32_MAX;
- Point3F minPoint( 0.f, 0.f, 0.f );
- for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
- {
- // Fetch Nodes.
- VPathNode *srcNode = ( *itr );
- VPathNode *dstNode = ( itr == ( pPath->mNodeList.end() - 1 ) ) ? ( *( pPath->mNodeList.begin() ) ) : ( *( itr + 1 ) );
- // Project to Screen.
- Point3F srcNodeScreenPosition, dstNodeScreenPosition;
- project( srcNode->getWorldPosition(), &srcNodeScreenPosition );
- project( dstNode->getWorldPosition(), &dstNodeScreenPosition );
- // Skip?
- if ( srcNodeScreenPosition.z > 1.f && dstNodeScreenPosition.z > 1.f )
- {
- continue;
- }
- Point3F ptOut0, ptOut1;
- F32 ptOutDistance;
- if ( !Utility::FindNearestDistanceBetweenLines( pt0, pt1,
- srcNode->getWorldPosition(), dstNode->getWorldPosition(),
- &ptOut0, &ptOut1, &ptOutDistance ) )
- {
- continue;
- }
- if ( ptOutDistance < minDistance )
- {
- minDistance = ptOutDistance;
- minPoint = ptOut1;
- minNode = ( itr - pPath->mNodeList.begin() );
- }
- }
- // Distance too Large?
- if ( minDistance > 0.25f )
- {
- // Invalid.
- return false;
- }
- // Setup.
- pTransform.identity();
- pTransform.setPosition( minPoint );
- // Store Node.
- pNode = minNode;
- return true;
- }
- bool VPathEditor::getPointOnBezierPath( VPath *pPath, const Gui3DMouseEvent &pEvent, S32 &pNode, MatrixF &pTransform )
- {
- S32 minNode = -1;
- F32 minInterp = 0.f;
- F32 minDistance = F32_MAX;
- Point3F minPoint( 0.f, 0.f, 0.f );
- for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
- {
- // Fetch Nodes.
- VPathNode *srcNode = ( *itr );
- VPathNode *dstNode = ( itr == ( pPath->mNodeList.end() - 1 ) ) ? ( *( pPath->mNodeList.begin() ) ) : ( *( itr + 1 ) );
- // Project to Screen.
- Point3F srcNodeScreenPosition, dstNodeScreenPosition;
- project( srcNode->getWorldPosition(), &srcNodeScreenPosition );
- project( dstNode->getWorldPosition(), &dstNodeScreenPosition );
- // Skip?
- if ( srcNodeScreenPosition.z > 1.f && dstNodeScreenPosition.z > 1.f )
- {
- continue;
- }
- // Positions.
- const Point3F &pt0 = srcNode->getWorldPosition();
- const Point3F &pt3 = dstNode->getWorldPosition();
- // Fetch Node Rotation Matrices.
- MatrixF mat0, mat1;
- srcNode->getWorldRotation().setMatrix( &mat0 );
- dstNode->getWorldRotation().setMatrix( &mat1 );
- // Determine Tangent Axis.
- Point3F pt1( VPath::gBezierAxis * srcNode->getWeight() );
- Point3F pt2( -VPath::gBezierAxis * dstNode->getWeight() );
- // Rotate Axis.
- mat0.mulP( pt1 );
- mat1.mulP( pt2 );
- // Offset Points.
- pt1 += pt0;
- pt2 += pt3;
- for ( F32 t = 0.f, it = 1.f; t <= 1.f; t += 0.1f, it = ( 1.f - t ) )
- {
- // Calculate Position.
- Point3F pos = ( pt0 * it * it * it ) + ( 3 * pt1 * it * it * t ) + ( 3 * pt2 * it * t * t ) + ( pt3 * t * t * t );
- // Determine the Screen Position.
- Point3F screenPos;
- project( pos, &screenPos );
- // Behind?
- if ( screenPos.z > 1.f )
- {
- // Skip Point.
- continue;
- }
- // Determine the Distance.
- F32 screenDistance = Point2F( screenPos.x - pEvent.mousePoint.x, screenPos.y - pEvent.mousePoint.y ).lenSquared();
- // Min Distance?
- if ( screenDistance < minDistance )
- {
- // Store.
- minDistance = screenDistance;
- minInterp = t;
- minPoint = pos;
- minNode = ( itr - pPath->mNodeList.begin() );
- }
- }
- }
- // Distance too Large?
- if ( minDistance > 1000.f )
- {
- // Invalid.
- return false;
- }
- // Fetch Orientation.
- const VectorF &orientation = pPath->getPathOrientation( pPath->getNode( minNode ),
- pPath->getNode( ( minNode + 1 ) % pPath->getNodeCount() ),
- minInterp, true );
- // Z-Axis.
- VectorF zVec = -orientation;
- zVec.normalize();
- // X-Axis.
- VectorF xVec = mCross( VPath::gBezierUp, zVec );
- xVec.normalize();
- // Y-Axis.
- VectorF yVec = mCross( zVec, xVec );
- yVec.normalize();
- // Setup Object Transform.
- pTransform.identity();
- pTransform.setColumn( 0, xVec );
- pTransform.setColumn( 1, -zVec );
- pTransform.setColumn( 2, yVec );
- // Set the Position.
- pTransform.setPosition( minPoint );
- // Store Node.
- pNode = minNode;
- return true;
- }
- void VPathEditor::addNode( const Gui3DMouseEvent &pEvent )
- {
- VPath *path = mSelection.Path;
- if ( !path )
- {
- // Woops!
- return;
- }
- // Min Index.
- S32 nodeIndex = -1;
- MatrixF nodeTransform( true );
- if ( !getPointOnPath( path, pEvent, nodeIndex, nodeTransform ) )
- {
- // Can't Add.
- return;
- }
- // Invert Transform.
- MatrixF pathTransform = mSelection.Path->getTransform();
- pathTransform.setPosition( Point3F::Zero );
- pathTransform.inverse();
- Point3F nodePosition = ( nodeTransform.getPosition() - mSelection.Path->getPosition() );
- pathTransform.mulP( nodePosition );
- // Node Rotation.
- nodeTransform.mul( pathTransform );
- QuatF nodeRotation( nodeTransform );
- // Node Weights.
- F32 nodeWeight = 10.f;
- // Add New Node.
- VPathNode *node = path->addNode( nodePosition, nodeRotation, nodeWeight, ++nodeIndex );
- // Valid Node?
- if ( !node )
- {
- return;
- }
- // Update Size.
- path->updateContainer();
- // Calculate Path.
- path->calculatePath();
- UndoManager *historyManager = NULL;
- if ( !Sim::findObject( "EUndoManager", historyManager ) )
- {
- Con::errorf( "VPathEditor::addNode() - EUndoManager not found!" );
- return;
- }
- // Create Undo Action.
- VPathEditorAddNodeAction *editAction = new VPathEditorAddNodeAction();
- // Store Editor.
- editAction->mEditor = this;
- // Store Node Details.
- editAction->mPath = path;
- editAction->mNodeIndex = nodeIndex;
- editAction->mNodePosition = nodePosition;
- editAction->mNodeRotation = nodeRotation;
- editAction->mNodeWeight = nodeWeight;
- // Add To Manager.
- historyManager->addAction( editAction );
- // Set World Editor Dirty.
- setWorldEditorDirty();
- }
- void VPathEditor::deleteNode( const S32 &pNodeIndex )
- {
- VPath *path = mSelection.Path;
- if ( !path )
- {
- // Woops!
- return;
- }
- // Fetch Node Properites.
- VPathNode *node = path->getNode( pNodeIndex );
- const Point3F position = node->getLocalPosition();
- const QuatF rotation = node->getLocalRotation();
- const F32 weight = node->getWeight();
- // Delete Node.
- path->deleteNode( pNodeIndex );
-
- // Update Path.
- path->updateContainer();
- // Calculate Path.
- path->calculatePath();
- // Selected Node?
- const S32 _nodeIndex = pNodeIndex;
- if ( pNodeIndex == mSelection.Node )
- {
- // Update Selection.
- updateSelection( mSelection.Path, -1 );
- }
- UndoManager *historyManager = NULL;
- if ( !Sim::findObject( "EUndoManager", historyManager ) )
- {
- Con::errorf( "VPathEditor::deleteNode() - EUndoManager not found!" );
- return;
- }
- // Create Undo Action.
- VPathEditorDeleteNodeAction *editAction = new VPathEditorDeleteNodeAction();
- // Store Editor.
- editAction->mEditor = this;
- // Store Node Details.
- editAction->mPath = path;
- editAction->mNodeIndex = _nodeIndex;
- editAction->mNodePosition = position;
- editAction->mNodeRotation = rotation;
- editAction->mNodeWeight = weight;
- // Add To Manager.
- historyManager->addAction( editAction );
- // Set World Editor Dirty.
- setWorldEditorDirty();
- }
- void VPathEditor::setNodePosition( const S32 &pNodeIndex, const Point3F &pPosition )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Sanity!
- if ( !serverPath || !clientPath )
- {
- return;
- }
- // Change?
- if ( serverPath->getNodeLocalPosition( pNodeIndex ) == pPosition )
- {
- return;
- }
- // Set Position.
- serverPath->setNodePosition( pNodeIndex, pPosition );
- clientPath->setNodePosition( pNodeIndex, pPosition );
- // Update Selection.
- updateSelection();
-
- // Dirty.
- mIsDirty = true;
- mNodeEdit.Dirty = true;
- // Arg Buffer.
- char buffer[3][32];
- dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
- dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
- dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
- // Callback.
- Con::executef( this, "onUpdateNodePosition", buffer[0], buffer[1], buffer[2] );
- }
- void VPathEditor::setNodeRotation( const S32 &pNodeIndex, const QuatF &pRotation )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Sanity!
- if ( !serverPath || !clientPath )
- {
- return;
- }
- // Change?
- if ( serverPath->getNodeLocalRotation( pNodeIndex ) == pRotation )
- {
- return;
- }
- // Set Position.
- serverPath->setNodeRotation( pNodeIndex, pRotation );
- clientPath->setNodeRotation( pNodeIndex, pRotation );
- // Update Selection.
- updateSelection();
-
- // Dirty.
- mIsDirty = true;
- mNodeEdit.Dirty = true;
- // Arg Buffer.
- char buffer[3][32];
- dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
- dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
- dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
- // Callback.
- Con::executef( this, "onUpdateNodeRotation", buffer[0], buffer[1], buffer[2] );
- }
- void VPathEditor::setNodeWeight( const S32 &pNodeIndex, const F32 &pWeight )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Sanity!
- if ( !serverPath || !clientPath )
- {
- return;
- }
- // Change?
- if ( serverPath->getNodeWeight( pNodeIndex ) == pWeight )
- {
- return;
- }
- // Set Weight.
- serverPath->setNodeWeight( pNodeIndex, pWeight );
- clientPath->setNodeWeight( pNodeIndex, pWeight );
- // Update Selection.
- updateSelection();
-
- // Dirty.
- mIsDirty = true;
- mNodeEdit.Dirty = true;
- // Arg Buffer.
- char buffer[3][32];
- dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
- dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
- dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
- // Callback.
- Con::executef( this, "onUpdateNodeWeight", buffer[0], buffer[1], buffer[2] );
- }
- void VPathEditor::setNodeOrientationMode( const S32 &pNodeIndex, const VPathNode::eOrientationType &pType )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Sanity!
- if ( !serverPath || !clientPath )
- {
- return;
- }
- // Set Orientation Mode.
- serverPath->setNodeOrientationMode( pNodeIndex, pType );
- clientPath->setNodeOrientationMode( pNodeIndex, pType );
-
- // Dirty.
- mIsDirty = true;
- mNodeEdit.Dirty = true;
- // Arg Buffer.
- char buffer[3][32];
- dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
- dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
- dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
- // Callback.
- Con::executef( this, "onUpdateNodeOrientation", buffer[0], buffer[1], buffer[2] );
- }
- void VPathEditor::setNodeOrientationMode( const S32 &pNodeIndex, const VPathNode::eOrientationType &pType, const Point3F &pPoint )
- {
- // Fetch Paths.
- VPath *serverPath = mSelection.Path;
- VPath *clientPath = getClientPath( serverPath );
- // Sanity!
- if ( !serverPath || !clientPath )
- {
- return;
- }
- // Set Orientation Mode.
- serverPath->setNodeOrientationMode( pNodeIndex, pType, pPoint );
- clientPath->setNodeOrientationMode( pNodeIndex, pType, pPoint );
-
- // Dirty.
- mIsDirty = true;
- mNodeEdit.Dirty = true;
- // Arg Buffer.
- char buffer[3][32];
- dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
- dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
- dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
- // Callback.
- Con::executef( this, "onUpdateNodeOrientation", buffer[0], buffer[1], buffer[2] );
- }
- void VPathEditor::pushPathEdit( void )
- {
- // Clear Current Edit Dirty.
- mPathEdit.Dirty = false;
- if ( mSelection.Path != NULL )
- {
- // Store Node Details.
- mPathEdit.Transform = mSelection.Path->getTransform();
- }
- }
- void VPathEditor::popPathEdit( void )
- {
- // Did Edit?
- if ( mPathEdit.Dirty && mSelection.Path != NULL )
- {
- UndoManager *historyManager = NULL;
- if ( !Sim::findObject( "EUndoManager", historyManager ) )
- {
- Con::errorf( "VPathEditor - EUndoManager not found!" );
- return;
- }
- // Create Undo Action.
- VPathEditorEditPathAction *editAction = new VPathEditorEditPathAction( "Edit Path" );
- // Store Editor.
- editAction->mEditor = this;
- // Store Path Details.
- editAction->mPath = mSelection.Path;
- editAction->mTransform = mPathEdit.Transform;
- // Add To Manager.
- historyManager->addAction( editAction );
- // Clear Dirty.
- mPathEdit.Dirty = false;
- // Set World Editor Dirty.
- setWorldEditorDirty();
- }
- }
- void VPathEditor::pushNodeEdit( void )
- {
- // Clear Current Edit Dirty.
- mNodeEdit.Dirty = false;
- if ( isValidSelection() )
- {
- // Fetch Node.
- VPathNode *node = mSelection.Path->getNode( mSelection.Node );
- // Store Node Details.
- mNodeEdit.Position = node->getLocalPosition();
- mNodeEdit.Rotation = node->getLocalRotation();
- mNodeEdit.Weight = node->getWeight();
- }
- }
- void VPathEditor::popNodeEdit( void )
- {
- // Did Edit?
- if ( mNodeEdit.Dirty && isValidSelection() )
- {
- UndoManager *historyManager = NULL;
- if ( !Sim::findObject( "EUndoManager", historyManager ) )
- {
- Con::errorf( "VPathEditor - EUndoManager not found!" );
- return;
- }
- // Create Undo Action.
- VPathEditorEditNodeAction *editAction = new VPathEditorEditNodeAction( "Edit Node" );
- // Store Editor.
- editAction->mEditor = this;
- // Store Node Details.
- editAction->mPath = mSelection.Path;
- editAction->mNodeIndex = mSelection.Node;
- editAction->mNodePosition = mNodeEdit.Position;
- editAction->mNodeRotation = mNodeEdit.Rotation;
- editAction->mNodeWeight = mNodeEdit.Weight;
- editAction->mNodeOrientation = mSelection.Path->getNode( mSelection.Node )->getOrientationMode();
- // Add To Manager.
- historyManager->addAction( editAction );
- // Clear Dirty.
- mNodeEdit.Dirty = false;
- // Set World Editor Dirty.
- setWorldEditorDirty();
- }
- }
- void VPathEditor::setWorldEditorDirty( void )
- {
- WorldEditor *worldEditor;
- if ( Sim::findObject( "EWorldEditor", worldEditor ) )
- {
- worldEditor->setDirty();
- }
- }
- //-----------------------------------------------------------------------------
- //
- // Render Methods.
- //
- //-----------------------------------------------------------------------------
- void VPathEditor::setStateBlock( void )
- {
- // Valid State Block?
- if ( !mStateBlock )
- {
- // Setup Definition.
- GFXStateBlockDesc def;
- def.blendDefined = true;
- def.blendEnable = true;
- def.blendSrc = GFXBlendSrcAlpha;
- def.blendDest = GFXBlendInvSrcAlpha;
- def.zDefined = true;
- def.cullDefined = false;
- // Create State Block.
- mStateBlock = GFX->createStateBlock( def );
- }
- // Set State Block.
- GFX->setStateBlock( mStateBlock );
- }
- void VPathEditor::renderScene( const RectI &pUpdateRect )
- {
- // Setup State Block.
- setStateBlock();
- if ( isValidSelection() )
- {
- // Fetch Current Node.
- VPathNode *node = mSelection.Path->getNode( mSelection.Node );
- // Render Gizmo?
- if ( mEditMode == k_Gizmo && mGizmoProfile->mode != ScaleMode )
- {
- // Fetch Node Transform.
- MatrixF mat= node->getWorldTransform();
- // Move Gizmo.
- mGizmo->set( mat, node->getWorldPosition(), Point3F( 1.0f, 1.0f, 1.0f ) );
- // Render Gizmo.
- mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix );
- }
- // Render Handles?
- if ( mSelection.Path->mPathType == VPath::k_PathBezier )
- {
- // Fetch Tangent Handles.
- const Point3F &pt0 = mSelection.TangentHandle[0];
- const Point3F &pt1 = mSelection.TangentHandle[1];
- // State Block.
- GFXStateBlockDesc desc;
- desc.setZReadWrite( true, true );
- desc.fillMode = GFXFillSolid;
- // Set Color.
- PrimBuild::color( gPathColorSel );
- // Render Line.
- PrimBuild::begin( GFXLineList, 2 );
- PrimBuild::vertex3fv( pt0 );
- PrimBuild::vertex3fv( pt1 );
- PrimBuild::end();
- // Render Handles.
- GFX->getDrawUtil()->drawSphere( desc, 0.1f, pt0, gPathColorSel );
- GFX->getDrawUtil()->drawSphere( desc, 0.1f, pt1, gPathColorSel );
- }
- // ToPoint Node?
- if ( node->getOrientationMode().Type == VPathNode::k_OrientationToPoint )
- {
- PrimBuild::color( gNodeLookAtPointColor );
- PrimBuild::begin( GFXLineStrip, 2 );
- PrimBuild::vertex3fv( node->getWorldPosition() );
- PrimBuild::vertex3fv( node->getOrientationMode().Point );
- PrimBuild::end();
- }
- }
- else if ( mSelection.Path && mEditMode == k_Gizmo )
- {
- switch ( mGizmoProfile->mode )
- {
- case MoveMode:
- {
- // Fetch Path Transform.
- const MatrixF &mat = mSelection.Path->getTransform();
- // Fetch the Path's Box Center.
- const Point3F &pos = mSelection.Path->getWorldBox().getCenter();
- // Move Gizmo.
- mGizmo->set( mat, pos, Point3F( 1.0f, 1.0f, 1.0f ) );
- // Render Gizmo.
- mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix );
- } break;
- }
- }
- // Render Path Segments.
- renderPaths( k_RenderSegments );
- // Set Clip Rect.
- GFX->setClipRect( pUpdateRect );
- // Render Path Nodes.
- renderPaths( k_RenderNodes );
- if ( isValidSelection() )
- {
- // Fetch Current Node.
- VPathNode *node = mSelection.Path->getNode( mSelection.Node );
- // ToPoint Node?
- if ( node->getOrientationMode().Type == VPathNode::k_OrientationToPoint )
- {
- // Project to Screen.
- Point3F screenPosition;
- project( node->getOrientationMode().Point, &screenPosition );
- if ( screenPosition.z <= 1.0f )
- {
- // Determine the center & size of the node rectangle.
- Point2I nodeCenter = Point2I( screenPosition.x, screenPosition.y );
- Point2I nodeHalfSize = Point2I( 8, 8 );
- // Determine Render Rectangle.
- RectI nodeRect;
- nodeRect.point = nodeCenter - nodeHalfSize;
- nodeRect.extent = ( 2 * nodeHalfSize );
- // Draw?
- if ( getBounds().overlaps( nodeRect ) )
- {
- // Render the Point.
- GFX->getDrawUtil()->drawRectFill( nodeRect, gNodeLookAtPointColor );
- }
- }
- }
- }
- }
- void VPathEditor::renderPaths( const RenderType &pRenderType )
- {
- SimSet *objectSet = VPath::getServerSet();
- for ( SimSetIterator itr( objectSet ); *itr; ++itr )
- {
- VPath *path = dynamic_cast<VPath*>( *itr );
- if ( path )
- {
- // Render Path.
- renderPath( pRenderType, path, ( path == mSelection.Path ) ? gPathColorSel : gPathColor );
- }
- }
- }
- void VPathEditor::renderPath( const RenderType &pRenderType, VPath *pPath, const ColorI &pColor )
- {
- if ( !pPath )
- {
- // Sanity!
- return;
- }
- switch ( pRenderType )
- {
- case k_RenderSegments :
- {
- switch ( pPath->mPathType )
- {
- case VPath::k_PathLinear :
- {
- renderLinearPath( pPath, pColor );
- } break;
- case VPath::k_PathBezier :
- {
- renderBezierPath( pPath, pColor );
- } break;
- }
- } break;
- case k_RenderNodes :
- {
- // Fetch Draw Util.
- GFXDrawUtil *drawUtil = GFX->getDrawUtil();
- // Fetch Bounds.
- RectI bounds = getBounds();
- const Point2I nodeMinHalfSize( 8, 8 );
- for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
- {
- // Fetch Node.
- VPathNode *node = ( *itr );
- // Project to Screen.
- Point3F screenPosition;
- project( node->getWorldPosition(), &screenPosition );
- if ( screenPosition.z > 1.0f )
- {
- continue;
- }
- // Determine the node text information.
- const char *nodeText = avar( "%d", ( itr - pPath->mNodeList.begin() ) );
- const Point2I nodeTextHalfSize = Point2I( 0.5f * (F32)getControlProfile()->mFont->getStrWidth( nodeText ),
- 0.5f * (F32)getControlProfile()->mFont->getHeight() );
- // Determine the center & size of the node rectangle.
- Point2I nodeCenter = Point2I( screenPosition.x, screenPosition.y );
- Point2I nodeHalfSize = Point2I( nodeTextHalfSize.x + 3, nodeTextHalfSize.y + 3 );
- nodeHalfSize.setMax( nodeMinHalfSize );
- // Determine Render Rectangle.
- RectI nodeRect;
- nodeRect.point = nodeCenter - nodeHalfSize;
- nodeRect.extent = ( 2 * nodeHalfSize );
- // Draw?
- if ( !bounds.overlaps( nodeRect ) )
- {
- continue;
- }
- // Render the Point.
- drawUtil->drawRectFill( nodeRect, pColor );
- // Draw the node index text.
- drawUtil->setBitmapModulation( getControlProfile()->mFontColor );
- drawUtil->drawText( getControlProfile()->mFont, nodeCenter - nodeTextHalfSize, nodeText );
- }
- } break;
- }
- }
- void VPathEditor::renderLinearPath( VPath *pPath, const ColorI &pColor )
- {
- if ( pPath->mNodeList.size() < 2 )
- {
- // No Lines.
- return;
- }
- PrimBuild::color( pColor );
- PrimBuild::begin( GFXLineStrip, ( pPath->mNodeList.size() + 1 ) );
- for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
- {
- // Apply Vertex.
- PrimBuild::vertex3fv( ( *itr )->getWorldPosition() );
- }
- // Loop Back.
- PrimBuild::vertex3fv( pPath->mNodeList.front()->getWorldPosition() );
- PrimBuild::end();
- }
- void VPathEditor::renderBezierPath( VPath *pPath, const ColorI &pColor )
- {
- if ( pPath->mNodeList.size() < 2 )
- {
- // No Lines.
- return;
- }
- PrimBuild::color( pColor );
- PrimBuild::begin( GFXLineStrip, U32( ( ( 1.01f / 0.01f ) + 1 ) * pPath->mNodeList.size() ) );
- for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
- {
- // Fetch Nodes.
- VPathNode *srcNode = ( *itr );
- VPathNode *dstNode = ( itr == ( pPath->mNodeList.end() - 1 ) ) ? ( *( pPath->mNodeList.begin() ) ) : ( *( itr + 1 ) );
- // Positions.
- const Point3F &pt0 = srcNode->getWorldPosition();
- const Point3F &pt3 = dstNode->getWorldPosition();
- // Fetch Node Rotation Matrices.
- MatrixF mat0, mat1;
- srcNode->getWorldRotation().setMatrix( &mat0 );
- dstNode->getWorldRotation().setMatrix( &mat1 );
- // Determine Tangent Axis.
- Point3F pt1( VPath::gBezierAxis * srcNode->getWeight() );
- Point3F pt2( -VPath::gBezierAxis * dstNode->getWeight() );
- // Rotate Axis.
- mat0.mulP( pt1 );
- mat1.mulP( pt2 );
- // Offset Points.
- pt1 += pt0;
- pt2 += pt3;
- for ( F32 t = 0.f, it = 1.f; t <= 1.f; t += 0.01f, it = ( 1.f - t ) )
- {
- // Calculate Position.
- Point3F pos = ( pt0 * it * it * it ) + ( 3 * pt1 * it * it * t ) + ( 3 * pt2 * it * t * t ) + ( pt3 * t * t * t );
- // Apply Vertex.
- PrimBuild::vertex3fv( pos );
- }
- }
- PrimBuild::end();
- }
- //-----------------------------------------------------------------------------
- //
- // History Events
- //
- //-----------------------------------------------------------------------------
- void VPathEditor::VPathEditorEditPathAction::undo( void )
- {
- const MatrixF oldTransform = mTransform;
- const MatrixF newTransform = mPath->getTransform();
- // Apply Old Values.
- mEditor->setPathTransform( oldTransform );
- // The ol' Switcheroo.
- mTransform = newTransform;
- // Update Selection.
- mEditor->updateSelection();
- if ( mPath == mEditor->mSelection.Path )
- {
- // Arg Buffer.
- char buffer[32];
- dSprintf( buffer, sizeof( buffer ), "%d", mPath->getId() );
- // Callback.
- Con::executef( mEditor, "onUpdatePath", buffer );
- }
- // Set World Editor Dirty.
- mEditor->setWorldEditorDirty();
- }
- void VPathEditor::VPathEditorEditPathAction::redo( void )
- {
- // Undo.
- undo();
- }
- void VPathEditor::VPathEditorEditNodeAction::undo( void )
- {
- // Fetch Properties.
- const Point3F oldPosition = mNodePosition;
- const QuatF oldRotation = mNodeRotation;
- const F32 oldWeight = mNodeWeight;
- const VPathNode::sOrientation oldOrientation = mNodeOrientation;
- VPathNode *node = mPath->getNode( mNodeIndex );
- const Point3F newPosition = node->getLocalPosition();
- const QuatF newRotation = node->getLocalRotation();
- const F32 newWeight = node->getWeight();
- const VPathNode::sOrientation newOrientation = node->getOrientationMode();
- // Apply Old Values.
- mPath->setNodePosition( mNodeIndex, oldPosition );
- mPath->setNodeRotation( mNodeIndex, oldRotation );
- mPath->setNodeWeight( mNodeIndex, oldWeight );
- switch( oldOrientation.Type )
- {
- case VPathNode::k_OrientationFree :
- {
- // Orient Free.
- mPath->setNodeOrientationMode( mNodeIndex, oldOrientation.Type );
- } break;
- case VPathNode::k_OrientationToPoint :
- {
- // Orient To Point.
- mPath->setNodeOrientationMode( mNodeIndex, oldOrientation.Type, oldOrientation.Point );
- } break;
- }
- // The ol' Switcheroo.
- mNodePosition = newPosition;
- mNodeRotation = newRotation;
- mNodeWeight = newWeight;
- mNodeOrientation = newOrientation;
- // Update Selection.
- mEditor->updateSelection();
- if ( mPath == mEditor->mSelection.Path )
- {
- // Arg Buffer.
- char buffer[3][32];
- dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mPath->getId() );
- dSprintf( buffer[1], sizeof( buffer[1] ), "%d", mNodeIndex );
- dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mEditor->mSelection.Node == mNodeIndex ) );
- // Callback.
- Con::executef( mEditor, "onUpdateNode", buffer[0], buffer[1], buffer[2] );
- }
- // Set World Editor Dirty.
- mEditor->setWorldEditorDirty();
- }
- void VPathEditor::VPathEditorEditNodeAction::redo( void )
- {
- // Undo.
- undo();
- }
- void VPathEditor::VPathEditorAddNodeAction::undo( void )
- {
- // Selected Node?
- if ( mNodeIndex == mEditor->mSelection.Node )
- {
- // Update Selection.
- mEditor->updateSelection( mEditor->mSelection.Path, -1 );
- }
- // Delete Node.
- mPath->deleteNode( mNodeIndex );
- // Update Size.
- mPath->updateContainer();
- // Calculate Path.
- mPath->calculatePath();
- // Set World Editor Dirty.
- mEditor->setWorldEditorDirty();
- }
- void VPathEditor::VPathEditorAddNodeAction::redo( void )
- {
- // Add Node.
- VPathNode *node = mPath->addNode( mNodePosition, mNodeRotation, mNodeWeight, mNodeIndex );
- // Valid Node?
- if ( node )
- {
- // Update Size.
- mPath->updateContainer();
- // Calculate Path.
- mPath->calculatePath();
- }
- // Set World Editor Dirty.
- mEditor->setWorldEditorDirty();
- }
- void VPathEditor::VPathEditorDeleteNodeAction::undo( void )
- {
- // Add Node.
- VPathNode *node = mPath->addNode( mNodePosition, mNodeRotation, mNodeWeight, mNodeIndex );
- // Valid Node?
- if ( node )
- {
- // Update Size.
- mPath->updateContainer();
- // Calculate Path.
- mPath->calculatePath();
- }
- // Set World Editor Dirty.
- mEditor->setWorldEditorDirty();
- }
- void VPathEditor::VPathEditorDeleteNodeAction::redo( void )
- {
- // Delete Node.
- mPath->deleteNode( mNodeIndex );
- // Update Size.
- mPath->updateContainer();
- // Calculate Path.
- mPath->calculatePath();
- // Set World Editor Dirty.
- mEditor->setWorldEditorDirty();
- }
- //-----------------------------------------------------------------------------
- //
- // Script Edit Methods
- //
- //-----------------------------------------------------------------------------
- ConsoleMethod( VPathEditor, setNodePosition, void, 3, 3, "( pPosition )" )
- {
- // Valid Selection?
- if ( !object->isValidSelection() )
- {
- Con::warnf( "VPathEditor::setNodePosition() - Invalid Node Selection." );
- return;
- }
- // Fetch Position.
- Point3F position;
- dSscanf( argv[2], "%g %g %g", &position.x, &position.y, &position.z );
- // Store.
- object->pushNodeEdit();
- // Apply Update.
- object->setNodePosition( object->mSelection.Node, position );
- // Create Undo Action.
- object->popNodeEdit();
- }
- ConsoleMethod( VPathEditor, setNodeRotation, void, 3, 3, "( pRotation )" )
- {
- // Valid Selection?
- if ( !object->isValidSelection() )
- {
- Con::warnf( "VPathEditor::setNodeRotation() - Invalid Node Selection." );
- return;
- }
- // Fetch Rotation.
- AngAxisF aa;
- QuatF rotation;
- dSscanf( argv[2], "%g %g %g %g", &aa.axis.x, &aa.axis.y, &aa.axis.z, &aa.angle );
- // Set Rotation.
- rotation.set( aa );
- // Store.
- object->pushNodeEdit();
- // Apply Update.
- object->setNodeRotation( object->mSelection.Node, rotation );
- // Create Undo Action.
- object->popNodeEdit();
- }
- ConsoleMethod( VPathEditor, setNodeWeight, void, 3, 3, "( pWeight )" )
- {
- // Valid Selection?
- if ( !object->isValidSelection() )
- {
- Con::warnf( "VPathEditor::setNodeWeight() - Invalid Node Selection." );
- return;
- }
- // Store.
- object->pushNodeEdit();
- // Apply Update.
- object->setNodeWeight( object->mSelection.Node, dAtof( argv[2] ) );
- // Create Undo Action.
- object->popNodeEdit();
- }
- ConsoleMethod( VPathEditor, setNodeOrientationMode, void, 3, 4, "( string pOrientationType, [vector pPoint] )" )
- {
- // Valid Selection?
- if ( !object->isValidSelection() )
- {
- Con::warnf( "VPathEditor::setNodeOrientationMode() - Invalid Node Selection." );
- return;
- }
- // Store.
- object->pushNodeEdit();
- // Orient?
- const VPathNode::eOrientationType type = VPathNode::getOrientationTypeEnum( argv[2] );
- switch ( type )
- {
- case VPathNode::k_OrientationFree :
- {
- // Apply Mode.
- object->setNodeOrientationMode( object->mSelection.Node, type );
- } break;
- case VPathNode::k_OrientationToPoint:
- {
- // Fetch Point.
- Point3F lookAtPoint( 0.f, 0.f, 0.f );
- dSscanf( argv[3], "%g %g %g", &lookAtPoint.x, &lookAtPoint.y, &lookAtPoint.z );
- // Apply Mode.
- object->setNodeOrientationMode( object->mSelection.Node, type, lookAtPoint );
- } break;
- }
- // Create Undo Action.
- object->popNodeEdit();
- }
- //-----------------------------------------------------------------------------
- //
- // Utility
- //
- //-----------------------------------------------------------------------------
- bool Utility::FindNearestDistanceBetweenLines( const Point3F &pA0, const Point3F &pA1, const Point3F &pB0, const Point3F &pB1, Point3F *pOutA, Point3F *pOutB, F32 *pDist )
- {
- const Point3F pA1A0 = ( pA1 - pA0 );
- if ( pA1A0.isZero() )
- {
- return false;
- }
- const Point3F pB1B0 = ( pB1 - pB0 );
- if ( pB1B0.isZero() )
- {
- return false;
- }
- const Point3F pA0B0 = ( pA0 - pB0 );
- const F32 &d1343 = pA0B0.x * pB1B0.x + pA0B0.y * pB1B0.y + pA0B0.z * pB1B0.z;
- const F32 &d4321 = pB1B0.x * pA1A0.x + pB1B0.y * pA1A0.y + pB1B0.z * pA1A0.z;
- const F32 &d1321 = pA0B0.x * pA1A0.x + pA0B0.y * pA1A0.y + pA0B0.z * pA1A0.z;
- const F32 &d4343 = pB1B0.x * pB1B0.x + pB1B0.y * pB1B0.y + pB1B0.z * pB1B0.z;
- const F32 &d2121 = pA1A0.x * pA1A0.x + pA1A0.y * pA1A0.y + pA1A0.z * pA1A0.z;
- const F32 &denom = d2121 * d4343 - d4321 * d4321;
- if ( mIsZero( denom ) )
- {
- return false;
- }
- const F32 &mua = ( d1343 * d4321 - d1321 * d4343 ) / denom;
- const F32 &mub = ( d1343 + d4321 * mua ) / d4343;
- *pOutA = pA0 + mua *pA1A0;
- *pOutB = pB0 + mub *pB1B0;
- // Store Distance.
- *pDist = ( ( *pOutA ) - ( *pOutB ) ).len();
- return true;
- }
- bool Utility::IntersectLineSegment( const Point3F &pA0, const Point3F &pA1, const Point3F &pB0, const Point3F &pB1, const bool pSnap, Point3F *pX )
- {
- //
- // Finding the intersection with the following method:
- // We have line a going from P1 to P2:
- // Pa = P1 + ua( P2 - P1 )
- // and line b going from P3 to P4:
- // Pb = P3 + ub( P4 - P3 )
- //
- // Solving for Pa = Pb:
- // x1 + ua( x2 - x1 ) = x3 + ub( x4 - x3 )
- // y1 + ua( y2 - y1 ) = y3 + ub( y4 - y3 )
- //
- // Solving for ua and ub:
- // ua = ( ( x4 - x3 )( y1 - y3 ) - ( y4 - y3 )( x1 - x3 ) ) / d
- // ub = ( ( x2 - x1 )( y1 - y3 ) - ( y2 - y1 )( x1 - x3 ) ) / d
- // denom = ( y4 - y3 )( x2 - x1 ) - ( x4 - x3 )( y2 - y1 )
- //
- // x = x1 + ua( x2 - x1 )
- // y = y1 + ua( y2 - y1 )
- //
- const F32 d = ( ( pB1.y - pB0.y ) * ( pA1.x - pA0.x ) ) - ( ( pB1.x - pB0.x ) * ( pA1.y - pA0.y ) );
- if ( d == 0.0f )
- {
- // Lines are parallel
- return false;
- }
- // Find the point of intersection
- const F32 uA = ( ( ( pB1.x - pB0.x ) * ( pA0.y - pB0.y ) ) - ( ( pB1.y - pB0.y ) * ( pA0.x - pB0.x ) ) ) / d;
- const F32 uB = ( ( ( pA1.x - pA0.x ) * ( pA0.y - pB0.y ) ) - ( ( pA1.y - pA0.y ) * ( pA0.x - pB0.x ) ) ) / d;
- if ( !pSnap
- && ( ( uA < 0.0f ) || ( uA > 1.0f )
- || ( uB < 0.0f ) || ( uB > 1.0f ) ) )
- {
- return false;
- }
- if ( pX )
- {
- if ( uA < 0.0f )
- {
- *pX = pA0;
- }
- else if ( uA > 1.f )
- {
- *pX = pA1;
- }
- else
- {
- // The path intersects the segment
- *pX = pA0 + uA * ( pA1 - pA0 );
- }
- }
- return true;
- }
- bool Utility::FindNearestPointOnLine( const Point3F &pSrcPosition, const Point3F &pA0, const Point3F &pA1, Point3F *pDstPosition )
- {
- const Point3F up( 0.0f, 0.0f, 1.0f );
-
- Point3F dir = ( pA1 - pA0 );
- dir.normalize();
- Point3F normal = mCross( dir, up );
- normal.normalize();
- // Find the nearest intersection point between the point and the line
- const Point3F b0 = pSrcPosition + ( normal * 100000.0f );
- const Point3F b1 = pSrcPosition - ( normal * 100000.0f );
- return IntersectLineSegment( pA0, pA1, b0, b1, true, pDstPosition );
- }
- F32 Utility::GetPitch( const VectorF &pVec )
- {
- F32 pitch;
- if ( mFabs( pVec.x ) > mFabs( pVec.y ) )
- {
- pitch = mAtan2( mFabs( pVec.z ), mFabs( pVec.x ) );
- }
- else
- {
- pitch = mAtan2( mFabs( pVec.z ), mFabs( pVec.y ) );
- }
- if ( pVec.z < 0.f )
- {
- pitch = -pitch;
- }
- return pitch;
- }
- F32 Utility::GetYaw( const VectorF &pVec )
- {
- F32 yaw = mAtan2( pVec.x, pVec.y );
- if ( yaw < 0.f )
- {
- yaw += M_2PI_F;
- }
- return yaw;
- }
|