123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // 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 "platform/platform.h"
- #include "forest/editor/forestSelectionTool.h"
- #include "forest/forest.h"
- #include "forest/editor/forestUndo.h"
- #include "forest/editor/forestEditorCtrl.h"
- #include "gui/worldEditor/editTSCtrl.h"
- #include "gui/worldEditor/gizmo.h"
- #include "console/consoleTypes.h"
- #include "console/engineAPI.h"
- #include "core/util/tVector.h"
- #include "core/util/safeDelete.h"
- #include "gfx/gfxDrawUtil.h"
- #include "gui/worldEditor/worldEditor.h"
- #include "math/mMatrix.h"
- template <>
- MatrixF Selection<ForestItem>::getOrientation()
- {
- if ( size() == 1 )
- return first().getTransform();
- return MatrixF::Identity;
- }
- template <>
- Point3F Selection<ForestItem>::getOrigin()
- {
- Point3F centroid( Point3F::Zero );
- if ( empty() )
- return centroid;
- Selection<ForestItem>::iterator itr = begin();
- for (; itr != end(); ++itr)
- {
- const MatrixF &mat = itr->getTransform();
- Point3F wPos;
- mat.getColumn( 3, &wPos );
- centroid += wPos;
- }
- centroid /= (F32)size();
- return centroid;
- }
- template <>
- Point3F Selection<ForestItem>::getScale()
- {
- if ( size() == 1 )
- return Point3F( first().getScale() );
- return Point3F::One;
- }
- void ForestItemSelection::offsetObject( ForestItem &object, const Point3F &delta )
- {
- if ( !mData )
- return;
- MatrixF newMat( object.getTransform() );
- newMat.displace( delta );
- object = mData->updateItem( object.getKey(), object.getPosition(), object.getData(), newMat, object.getScale() );
- }
- void ForestItemSelection::rotateObject( ForestItem &object, const EulerF &delta, const Point3F &origin )
- {
- if ( !mData )
- return;
- MatrixF mat = object.getTransform();
- Point3F pos;
- mat.getColumn( 3, &pos );
- MatrixF wMat( mat );
- wMat.inverse();
- // get offset in obj space
- Point3F offset = pos - origin;
- if ( size() == 1 )
- {
- wMat.mulV(offset);
- MatrixF transform(EulerF::Zero, -offset);
- transform.mul(MatrixF(delta));
- transform.mul(MatrixF(EulerF::Zero, offset));
- mat.mul(transform);
- }
- else
- {
- MatrixF transform( delta );
- Point3F wOffset;
- transform.mulV( offset, &wOffset );
- wMat.mulV( offset );
- transform.set( EulerF::Zero, -offset );
- mat.setColumn( 3, Point3F::Zero );
- wMat.setColumn( 3, Point3F::Zero );
- transform.mul( wMat );
- transform.mul( MatrixF(delta) );
- transform.mul( mat );
- mat.mul( transform );
- mat.normalize();
- mat.setColumn( 3, wOffset + origin );
- }
- object = mData->updateItem( object.getKey(), object.getPosition(), object.getData(), mat, object.getScale() );
- }
- void ForestItemSelection::scaleObject( ForestItem &object, const Point3F &delta )
- {
- if ( !mData )
- return;
- object = mData->updateItem( object.getKey(), object.getPosition(), object.getData(), object.getTransform(), delta.z );
- }
- IMPLEMENT_CONOBJECT( ForestSelectionTool );
- ConsoleDocClass( ForestSelectionTool,
- "@brief Specialized selection tool for picking individual trees in a forest.\n\n"
- "Editor use only.\n\n"
- "@internal"
- );
- ForestSelectionTool::ForestSelectionTool()
- : Parent(),
- mCurrAction( NULL ),
- mGizmo( NULL ),
- mGizmoProfile( NULL )
- {
- mBounds = Box3F::Invalid;
- mDragRectColor.set(255,255,0);
- mMouseDown = false;
- mDragSelect = false;
- }
- ForestSelectionTool::~ForestSelectionTool()
- {
- SAFE_DELETE( mCurrAction );
- }
- void ForestSelectionTool::setParentEditor( ForestEditorCtrl *editor )
- {
- mEditor = editor;
- mGizmo = editor->getGizmo();
- mGizmoProfile = mGizmo->getProfile();
- }
- void ForestSelectionTool::_selectItem( const ForestItem &item )
- {
- // Make sure its not already selected.
- for ( U32 i=0; i < mSelection.size(); i++ )
- {
- if ( mSelection[i].getKey() == item.getKey() )
- return;
- }
- mSelection.push_back( item );
- mBounds.intersect( item.getWorldBox() );
- }
- void ForestSelectionTool::deleteSelection()
- {
- if (!mEditor)
- return;
- ForestDeleteUndoAction *action = new ForestDeleteUndoAction( mForest->getData(), mEditor );
- for ( U32 i=0; i < mSelection.size(); i++ )
- {
- const ForestItem &item = mSelection[i];
- action->removeItem( item );
- }
- clearSelection();
- _submitUndo( action );
- }
- void ForestSelectionTool::clearSelection()
- {
- mSelection.clear();
- mBounds = Box3F::Invalid;
- }
- void ForestSelectionTool::cutSelection()
- {
- }
- void ForestSelectionTool::copySelection()
- {
- }
- void ForestSelectionTool::pasteSelection()
- {
- }
- void ForestSelectionTool::setActiveForest( Forest *forest )
- {
- mForest = forest;
-
- if ( forest )
- mSelection.setForestData( forest->getData() );
- else
- mSelection.setForestData( NULL );
- }
- void ForestSelectionTool::on3DMouseDown( const Gui3DMouseEvent &evt )
- {
- mMouseDown = true;
- mMouseDragged = false;
- mUsingGizmo = !mSelection.empty() && mGizmo->getSelection() != Gizmo::None;
- if ( mUsingGizmo )
- {
- mGizmo->on3DMouseDown( evt );
- return;
- }
-
- mDragSelection.clear();
- mDragRect.set( Point2I(evt.mousePoint), Point2I(0,0) );
- mDragStart = evt.mousePoint;
- const bool multiSel = evt.modifier & SI_CTRL;
- if ( !multiSel )
- clearSelection();
- if ( mHoverItem.isValid() )
- _selectItem( mHoverItem );
- // This should never happen... it should have been
- // submitted and nulled in on3DMouseUp()!
- //
- // Yeah, unless you had a breakpoint there and on3DMouseUp never fired,
- // in which case this is really annoying.
- //
- //AssertFatal( !mCurrAction, "ForestSelectionTool::on3DMouseDown() - Dangling undo action!" );
- }
- void ForestSelectionTool::on3DMouseMove( const Gui3DMouseEvent &evt )
- {
- // Invalidate the hover item first... we're gonna find a new one.
- mHoverItem.makeInvalid();
- if ( !mForest )
- return;
- if ( !mSelection.empty() )
- mGizmo->on3DMouseMove( evt );
- RayInfo ri;
- ri.userData = new ForestItem;
- Point3F startPnt = evt.pos;
- Point3F endPnt = evt.pos + evt.vec * 1000.0f;
- if ( mForest->castRayRendered( startPnt, endPnt, &ri ) )
- mHoverItem = (*(ForestItem*)ri.userData);
- delete static_cast<ForestItem*>(ri.userData);
- }
- void ForestSelectionTool::on3DMouseDragged( const Gui3DMouseEvent &evt )
- {
- mHoverItem.makeInvalid();
- if ( mUsingGizmo )
- {
- mGizmo->on3DMouseDragged( evt );
- const Point3F &deltaRot = mGizmo->getDeltaRot();
- const Point3F &deltaPos = mGizmo->getOffset();
- const Point3F &deltaScale = mGizmo->getDeltaScale();
- if ( deltaRot.isZero() && deltaPos.isZero() && deltaScale.isZero() )
- return;
- // Store the current item states!
- if ( !mCurrAction )
- {
- mCurrAction = new ForestUpdateAction( mForest->getData(), mEditor );
- for ( U32 i=0; i < mSelection.size(); i++ )
- {
- const ForestItem &item = mSelection[i];
- mCurrAction->saveItem( item );
- }
- }
- switch ( mGizmo->getMode() )
- {
- case MoveMode:
- mSelection.offset( deltaPos ); break;
- case RotateMode:
- mSelection.rotate( deltaRot ); break;
- case ScaleMode:
- mSelection.scale( mGizmo->getScale() ); break;
- default: ;
- }
- return;
- }
- mDragSelect = true;
- mHoverItem.makeInvalid();
- // Doing a drag selection.
- if ( mDragSelect )
- {
- // build the drag selection on the renderScene method - make sure no neg extent!
- mDragRect.point.x = (evt.mousePoint.x < mDragStart.x) ? evt.mousePoint.x : mDragStart.x;
- mDragRect.extent.x = (evt.mousePoint.x > mDragStart.x) ? evt.mousePoint.x - mDragStart.x : mDragStart.x - evt.mousePoint.x;
- mDragRect.point.y = (evt.mousePoint.y < mDragStart.y) ? evt.mousePoint.y : mDragStart.y;
- mDragRect.extent.y = (evt.mousePoint.y > mDragStart.y) ? evt.mousePoint.y - mDragStart.y : mDragStart.y - evt.mousePoint.y;
- return;
- }
- }
- void ForestSelectionTool::on3DMouseUp( const Gui3DMouseEvent &evt )
- {
- mGizmo->on3DMouseUp( evt );
- mMouseDown = false;
- // If we have an undo action then we must have
- // moved, rotated, or scaled something.
- if ( mCurrAction )
- {
- _submitUndo( mCurrAction );
- mCurrAction = NULL;
- return;
- }
- // If we were performing a drag select, finalize it now.
- if ( mDragSelect )
- {
- mDragSelect = false;
- clearSelection();
- for ( S32 i = 0; i < mDragSelection.size(); i++ )
- _selectItem( mDragSelection[i] );
-
- mDragSelection.clear();
-
- return;
- }
- }
- void ForestSelectionTool::onRender3D()
- {
- GFXDrawUtil *drawUtil = GFX->getDrawUtil();
- ColorI color( 255, 255, 255, 255 );
- MatrixF treeMat;
- GFXStateBlockDesc desc;
- desc.setBlend( true );
- desc.setZReadWrite( true, false );
- if ( mHoverItem.isValid() )
- {
- treeMat = mHoverItem.getTransform();
- drawUtil->drawObjectBox( desc, mHoverItem.getSize(), mHoverItem.getWorldBox().getCenter(), treeMat, color );
- }
- if ( !mSelection.empty() )
- {
- for ( U32 i = 0; i < mSelection.size(); i++ )
- {
- const ForestItem &item = mSelection[i];
- treeMat = item.getTransform();
- drawUtil->drawObjectBox( desc, item.getSize(), item.getWorldBox().getCenter(), treeMat, color );
- }
- mGizmo->set( mSelection.getOrientation(), mSelection.getOrigin(), mSelection.getScale() );
- mGizmo->renderGizmo( mEditor->getLastCameraQuery().cameraMatrix, mEditor->getLastCameraQuery().fov );
- }
- }
- static Frustum gDragFrustum;
- void ForestSelectionTool::onRender2D()
- {
- // Draw drag selection rect.
- if ( mDragSelect && mDragRect.extent.x > 1 && mDragRect.extent.y > 1 )
- GFX->getDrawUtil()->drawRect( mDragRect, mDragRectColor );
- // update what is in the selection
- if ( mDragSelect )
- mDragSelection.clear();
- // Determine selected objects based on the drag box touching
- // a mesh if a drag operation has begun.
- if ( mDragSelect && mDragRect.extent.x > 1 && mDragRect.extent.y > 1 )
- {
- // Build the drag frustum based on the rect
- F32 wwidth;
- F32 wheight;
- F32 aspectRatio = F32(mEditor->getWidth()) / F32(mEditor->getHeight());
- const CameraQuery &lastCameraQuery = mEditor->getLastCameraQuery();
- if(!lastCameraQuery.ortho)
- {
- wheight = lastCameraQuery.nearPlane * mTan(lastCameraQuery.fov / 2);
- wwidth = aspectRatio * wheight;
- }
- else
- {
- wheight = lastCameraQuery.fov;
- wwidth = aspectRatio * wheight;
- }
- F32 hscale = wwidth * 2 / F32(mEditor->getWidth());
- F32 vscale = wheight * 2 / F32(mEditor->getHeight());
- Point2I editorPosition = mEditor->getPosition();
- F32 left = (mDragRect.point.x - editorPosition.x) * hscale - wwidth;
- F32 right = (mDragRect.point.x - editorPosition.x + mDragRect.extent.x) * hscale - wwidth;
- F32 top = wheight - vscale * (mDragRect.point.y - editorPosition.y);
- F32 bottom = wheight - vscale * (mDragRect.point.y - editorPosition.y + mDragRect.extent.y);
- gDragFrustum.set(lastCameraQuery.ortho, left, right, top, bottom, lastCameraQuery.nearPlane, lastCameraQuery.farPlane, lastCameraQuery.cameraMatrix );
- mForest->getData()->getItems( gDragFrustum, &mDragSelection );
- }
- }
- bool ForestSelectionTool::updateGuiInfo()
- {
- SimObject *statusbar;
- if ( !Sim::findObject( "EditorGuiStatusBar", statusbar ) )
- return false;
- String text( "Forest Editor." );
- GizmoMode mode = mGizmoProfile->mode;
- if ( mMouseDown && mGizmo->getSelection() != Gizmo::None )
- {
- Point3F delta;
- String qualifier;
- if ( mode == RotateMode )
- delta = mGizmo->getDeltaTotalRot();
- else if ( mode == MoveMode )
- delta = mGizmo->getTotalOffset();
- else if ( mode == ScaleMode )
- delta = mGizmo->getDeltaTotalScale();
- if ( mGizmo->getAlignment() == Object && mode != ScaleMode )
- {
- mSelection.getOrientation().mulV( delta );
- }
- if ( mIsZero( delta.x, 0.0001f ) )
- delta.x = 0.0f;
- if ( mIsZero( delta.y, 0.0001f ) )
- delta.y = 0.0f;
- if ( mIsZero( delta.z, 0.0001f ) )
- delta.z = 0.0f;
- if ( mode == RotateMode )
- {
- delta.x = mRadToDeg( delta.x );
- delta.y = mRadToDeg( delta.y );
- delta.z = mRadToDeg( delta.z );
- text = String::ToString( "Delta angle ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z );
- }
- else if ( mode == MoveMode )
- text = String::ToString( "Delta position ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z );
- else if ( mode == ScaleMode )
- text = String::ToString( "Delta scale ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z );
- }
- else
- {
- if ( mode == MoveMode )
- text = "Move selection. SHIFT while dragging duplicates objects.";
- else if ( mode == RotateMode )
- text = "Rotate selection.";
- else if ( mode == ScaleMode )
- text = "Scale selection.";
- }
- Con::executef( statusbar, "setInfo", text.c_str() );
- Con::executef( statusbar, "setSelectionObjectsByCount", mSelection.size() );
- return true;
- }
- void ForestSelectionTool::updateGizmo()
- {
- mGizmoProfile->restoreDefaultState();
- const GizmoMode &mode = mGizmoProfile->mode;
- if ( mode == ScaleMode )
- {
- mGizmoProfile->flags &= ~GizmoProfile::PlanarHandlesOn;
- mGizmoProfile->allAxesScaleUniform = true;
- }
- }
- void ForestSelectionTool::onUndoAction()
- {
- ForestData *data = mForest->getData();
- // Remove items from our selection that no longer exist.
- for ( S32 i = 0; i < mSelection.size(); i++ )
- {
- const ForestItem &item = data->findItem( mSelection[i].getKey(), mSelection[i].getPosition() );
- if ( item == ForestItem::Invalid )
- {
- mSelection.erase_fast( i );
- i--;
- }
- else
- mSelection[i] = item;
- }
- // Recalculate our selection bounds.
- mBounds = Box3F::Invalid;
- for ( S32 i = 0; i < mSelection.size(); i++ )
- mBounds.intersect( mSelection[i].getWorldBox() );
- }
- DefineConsoleMethod( ForestSelectionTool, getSelectionCount, S32, (), , "" )
- {
- return object->getSelectionCount();
- }
- DefineConsoleMethod( ForestSelectionTool, deleteSelection, void, (), , "" )
- {
- object->deleteSelection();
- }
- DefineConsoleMethod( ForestSelectionTool, clearSelection, void, (), , "" )
- {
- object->clearSelection();
- }
- DefineConsoleMethod( ForestSelectionTool, cutSelection, void, (), , "" )
- {
- object->cutSelection();
- }
- DefineConsoleMethod( ForestSelectionTool, copySelection, void, (), , "" )
- {
- object->copySelection();
- }
- DefineConsoleMethod( ForestSelectionTool, pasteSelection, void, (), , "" )
- {
- object->pasteSelection();
- }
|