Torque3D Documentation / _generateds / forestSelectionTool.cpp

forestSelectionTool.cpp

Engine/source/forest/editor/forestSelectionTool.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(ForestSelectionTool , "@brief Specialized selection tool <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> picking individual trees in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">forest.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(ForestSelectionTool , clearSelection , void , () , "" )
DefineEngineMethod(ForestSelectionTool , copySelection , void , () , "" )
DefineEngineMethod(ForestSelectionTool , cutSelection , void , () , "" )
DefineEngineMethod(ForestSelectionTool , deleteSelection , void , () , "" )
DefineEngineMethod(ForestSelectionTool , getSelectionCount , S32 , () , "" )
DefineEngineMethod(ForestSelectionTool , pasteSelection , void , () , "" )

Detailed Description

Public Variables

Frustum gDragFrustum 

Public Functions

ConsoleDocClass(ForestSelectionTool , "@brief Specialized selection tool <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> picking individual trees in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">forest.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )

DefineEngineMethod(ForestSelectionTool , clearSelection , void , () , "" )

DefineEngineMethod(ForestSelectionTool , copySelection , void , () , "" )

DefineEngineMethod(ForestSelectionTool , cutSelection , void , () , "" )

DefineEngineMethod(ForestSelectionTool , deleteSelection , void , () , "" )

DefineEngineMethod(ForestSelectionTool , getSelectionCount , S32 , () , "" )

DefineEngineMethod(ForestSelectionTool , pasteSelection , void , () , "" )

IMPLEMENT_CONOBJECT(ForestSelectionTool )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "forest/editor/forestSelectionTool.h"
 26
 27#include "forest/forest.h"
 28#include "forest/editor/forestUndo.h"
 29#include "forest/editor/forestEditorCtrl.h"
 30
 31#include "gui/worldEditor/editTSCtrl.h"
 32#include "gui/worldEditor/gizmo.h"
 33#include "console/consoleTypes.h"
 34#include "console/engineAPI.h"
 35#include "core/util/tVector.h"
 36#include "core/util/safeDelete.h"
 37#include "gfx/gfxDrawUtil.h"
 38#include "gui/worldEditor/worldEditor.h"
 39#include "math/mMatrix.h"
 40
 41template <>
 42MatrixF Selection<ForestItem>::getOrientation()
 43{
 44   if ( size() == 1 )
 45      return first().getTransform();
 46
 47   return MatrixF::Identity;
 48}
 49
 50template <>
 51Point3F Selection<ForestItem>::getOrigin()
 52{
 53   Point3F centroid( Point3F::Zero );
 54
 55   if ( empty() )
 56      return centroid;
 57
 58   Selection<ForestItem>::iterator itr = begin();
 59
 60   for (; itr != end(); ++itr)
 61   {
 62      const MatrixF &mat = itr->getTransform();
 63      Point3F wPos;
 64      mat.getColumn( 3, &wPos );
 65
 66      centroid += wPos;
 67   }
 68
 69   centroid /= (F32)size();
 70
 71   return centroid;
 72}
 73
 74template <>
 75Point3F Selection<ForestItem>::getScale()
 76{
 77   if ( size() == 1 )
 78      return Point3F( first().getScale() );
 79
 80   return Point3F::One;
 81}
 82
 83void ForestItemSelection::offsetObject( ForestItem &object, const Point3F &delta )
 84{
 85   if ( !mData )
 86      return;
 87
 88   MatrixF newMat( object.getTransform() );
 89   newMat.displace( delta );
 90
 91   object = mData->updateItem( object.getKey(), object.getPosition(), object.getData(), newMat, object.getScale() );   
 92}
 93
 94void ForestItemSelection::rotateObject( ForestItem &object, const EulerF &delta, const Point3F &origin )
 95{
 96   if ( !mData )
 97      return;
 98
 99   MatrixF mat = object.getTransform();
100
101   Point3F pos;
102   mat.getColumn( 3, &pos );
103
104   MatrixF wMat( mat );
105   wMat.inverse();   
106
107   // get offset in obj space
108   Point3F offset = pos - origin;
109
110   if ( size() == 1 )
111   {
112      wMat.mulV(offset);
113
114      MatrixF transform(EulerF::Zero, -offset);
115      transform.mul(MatrixF(delta));
116      transform.mul(MatrixF(EulerF::Zero, offset));
117      mat.mul(transform);
118   }
119   else
120   {
121      MatrixF transform( delta );
122      Point3F wOffset;
123      transform.mulV( offset, &wOffset );
124
125      wMat.mulV( offset );
126
127      transform.set( EulerF::Zero, -offset );
128
129      mat.setColumn( 3, Point3F::Zero );
130      wMat.setColumn( 3, Point3F::Zero );
131
132      transform.mul( wMat );
133      transform.mul( MatrixF(delta) );
134      transform.mul( mat );
135      mat.mul( transform );
136
137      mat.normalize();
138      mat.setColumn( 3, wOffset + origin );
139   }
140
141   object = mData->updateItem( object.getKey(), object.getPosition(), object.getData(), mat, object.getScale() );
142}
143
144void ForestItemSelection::scaleObject( ForestItem &object, const Point3F &delta )
145{
146   if ( !mData )
147      return;
148
149   object = mData->updateItem( object.getKey(), object.getPosition(), object.getData(), object.getTransform(), delta.z );
150}
151
152
153IMPLEMENT_CONOBJECT( ForestSelectionTool );
154
155ConsoleDocClass( ForestSelectionTool,
156   "@brief Specialized selection tool for picking individual trees in a forest.\n\n"
157   "Editor use only.\n\n"
158   "@internal"
159);
160
161ForestSelectionTool::ForestSelectionTool()
162   :  Parent(),
163      mGizmo( NULL ),
164      mCurrAction( NULL ),
165      mGizmoProfile( NULL ),
166      mMouseDragged(false),
167      mUsingGizmo(false)
168{
169   mBounds = Box3F::Invalid;
170
171   mDragRectColor.set(255,255,0);
172   mMouseDown = false;
173   mDragSelect = false;
174}
175
176ForestSelectionTool::~ForestSelectionTool()
177{
178   SAFE_DELETE( mCurrAction );
179}
180
181void ForestSelectionTool::setParentEditor( ForestEditorCtrl *editor )
182{
183   mEditor = editor;
184   mGizmo = editor->getGizmo();
185   mGizmoProfile = mGizmo->getProfile();
186}
187
188void ForestSelectionTool::_selectItem( const ForestItem &item )
189{
190   // Make sure its not already selected.
191   for ( U32 i=0; i < mSelection.size(); i++ )
192   {
193      if ( mSelection[i].getKey() == item.getKey() )
194         return;
195   }
196
197   mSelection.push_back( item );
198   mBounds.intersect( item.getWorldBox() );
199}
200
201void ForestSelectionTool::deleteSelection()
202{
203   if (!mEditor)
204      return;
205
206   ForestDeleteUndoAction *action = new ForestDeleteUndoAction( mForest->getData(), mEditor );
207
208   for ( U32 i=0; i < mSelection.size(); i++ )
209   {
210      const ForestItem &item = mSelection[i];
211      action->removeItem( item );
212   }
213
214   clearSelection();
215   _submitUndo( action );
216}
217
218void ForestSelectionTool::clearSelection()
219{
220   mSelection.clear();
221   mBounds = Box3F::Invalid;
222}
223
224void ForestSelectionTool::cutSelection()
225{
226
227}
228
229void ForestSelectionTool::copySelection()
230{
231
232}
233
234void ForestSelectionTool::pasteSelection()
235{
236
237}
238
239void ForestSelectionTool::setActiveForest( Forest *forest )
240{
241   mForest = forest;
242   
243   if ( forest )
244      mSelection.setForestData( forest->getData() );
245   else
246      mSelection.setForestData( NULL );
247}
248
249void ForestSelectionTool::on3DMouseDown( const Gui3DMouseEvent &evt )
250{   
251   mMouseDown = true;
252   mMouseDragged = false;
253
254   mUsingGizmo = !mSelection.empty() && mGizmo->getSelection() != Gizmo::None;
255
256   if ( mUsingGizmo )
257   {
258      mGizmo->on3DMouseDown( evt );   
259      return;
260   }   
261     
262   mDragSelection.clear();
263   mDragRect.set( Point2I(evt.mousePoint), Point2I(0,0) );
264   mDragStart = evt.mousePoint;
265
266   const bool multiSel = evt.modifier & SI_CTRL;
267
268   if ( !multiSel )
269      clearSelection();
270
271   if ( mHoverItem.isValid() )
272      _selectItem( mHoverItem );   
273
274   // This should never happen... it should have been 
275   // submitted and nulled in on3DMouseUp()!
276   //
277   // Yeah, unless you had a breakpoint there and on3DMouseUp never fired,
278   // in which case this is really annoying.
279   //
280   //AssertFatal( !mCurrAction, "ForestSelectionTool::on3DMouseDown() - Dangling undo action!" );
281}
282
283void ForestSelectionTool::on3DMouseMove( const Gui3DMouseEvent &evt )
284{
285   // Invalidate the hover item first... we're gonna find a new one.
286   mHoverItem.makeInvalid();
287
288   if ( !mForest )
289      return;   
290
291   if ( !mSelection.empty() )
292      mGizmo->on3DMouseMove( evt );
293
294   RayInfo ri;
295   ri.userData = new ForestItem;
296   Point3F startPnt = evt.pos;
297   Point3F endPnt = evt.pos + evt.vec * 1000.0f;   
298
299   if ( mForest->castRayRendered( startPnt, endPnt, &ri ) )
300      mHoverItem = (*(ForestItem*)ri.userData);
301
302   delete static_cast<ForestItem*>(ri.userData);
303}
304
305void ForestSelectionTool::on3DMouseDragged( const Gui3DMouseEvent &evt )
306{
307   mHoverItem.makeInvalid();
308
309   if ( mUsingGizmo )
310   {
311      mGizmo->on3DMouseDragged( evt );
312
313      const Point3F &deltaRot = mGizmo->getDeltaRot();
314      const Point3F &deltaPos = mGizmo->getOffset();
315      const Point3F &deltaScale = mGizmo->getDeltaScale();
316
317      if ( deltaRot.isZero() && deltaPos.isZero() && deltaScale.isZero() )
318         return;
319
320      // Store the current item states!
321      if ( !mCurrAction )
322      {
323         mCurrAction = new ForestUpdateAction( mForest->getData(), mEditor );
324         for ( U32 i=0; i < mSelection.size(); i++ )
325         {
326            const ForestItem &item = mSelection[i];
327            mCurrAction->saveItem( item );
328         }
329      }
330
331      switch ( mGizmo->getMode() )
332      {
333      case MoveMode:
334         mSelection.offset( deltaPos ); break;
335      case RotateMode:
336         mSelection.rotate( deltaRot ); break;
337      case ScaleMode:         
338         mSelection.scale( mGizmo->getScale() ); break;
339      default: ;
340      }
341
342      return;
343   }
344
345   mDragSelect = true;
346   mHoverItem.makeInvalid();
347
348   // Doing a drag selection.
349
350   if ( mDragSelect )
351   {
352      // build the drag selection on the renderScene method - make sure no neg extent!
353      mDragRect.point.x = (evt.mousePoint.x < mDragStart.x) ? evt.mousePoint.x : mDragStart.x;
354      mDragRect.extent.x = (evt.mousePoint.x > mDragStart.x) ? evt.mousePoint.x - mDragStart.x : mDragStart.x - evt.mousePoint.x;
355      mDragRect.point.y = (evt.mousePoint.y < mDragStart.y) ? evt.mousePoint.y : mDragStart.y;
356      mDragRect.extent.y = (evt.mousePoint.y > mDragStart.y) ? evt.mousePoint.y - mDragStart.y : mDragStart.y - evt.mousePoint.y;
357      return;
358   }   
359}
360
361void ForestSelectionTool::on3DMouseUp( const Gui3DMouseEvent &evt )
362{
363   mGizmo->on3DMouseUp( evt );
364
365   mMouseDown = false;
366
367   // If we have an undo action then we must have
368   // moved, rotated, or scaled something.
369   if ( mCurrAction )
370   {
371      _submitUndo( mCurrAction );
372      mCurrAction = NULL;
373      return;
374   }
375
376   // If we were performing a drag select, finalize it now.
377   if ( mDragSelect )
378   {
379      mDragSelect = false;
380
381      clearSelection();
382
383      for ( S32 i = 0; i < mDragSelection.size(); i++ )      
384         _selectItem( mDragSelection[i] );
385      
386      mDragSelection.clear();
387      
388      return;
389   }
390}
391
392void ForestSelectionTool::onRender3D()
393{
394   GFXDrawUtil *drawUtil = GFX->getDrawUtil();
395   ColorI color( 255, 255, 255, 255 );
396   MatrixF treeMat;
397
398   GFXStateBlockDesc desc;
399   desc.setBlend( true );
400   desc.setZReadWrite( true, false );
401
402   if ( mHoverItem.isValid() )
403   {      
404      treeMat = mHoverItem.getTransform();
405      drawUtil->drawObjectBox( desc, mHoverItem.getSize(), mHoverItem.getWorldBox().getCenter(), treeMat, color );
406   }
407
408   if ( !mSelection.empty() )
409   {      
410      for ( U32 i = 0; i < mSelection.size(); i++ )
411      {
412         const ForestItem &item = mSelection[i];
413         treeMat = item.getTransform();
414         drawUtil->drawObjectBox( desc, item.getSize(), item.getWorldBox().getCenter(), treeMat, color );
415      }
416
417      mGizmo->set( mSelection.getOrientation(), mSelection.getOrigin(), mSelection.getScale() );
418
419      mGizmo->renderGizmo( mEditor->getLastCameraQuery().cameraMatrix, mEditor->getLastCameraQuery().fov );  
420   }
421}
422
423static Frustum gDragFrustum;
424
425void ForestSelectionTool::onRender2D()
426{
427   // Draw drag selection rect.
428   if ( mDragSelect && mDragRect.extent.x > 1 && mDragRect.extent.y > 1 )
429      GFX->getDrawUtil()->drawRect( mDragRect, mDragRectColor );
430
431   // update what is in the selection
432   if ( mDragSelect )
433      mDragSelection.clear();
434
435   // Determine selected objects based on the drag box touching
436   // a mesh if a drag operation has begun.
437   if ( mDragSelect && mDragRect.extent.x > 1 && mDragRect.extent.y > 1 )
438   {
439      // Build the drag frustum based on the rect
440      F32 wwidth;
441      F32 wheight;
442      F32 aspectRatio = F32(mEditor->getWidth()) / F32(mEditor->getHeight());
443
444      const CameraQuery &lastCameraQuery = mEditor->getLastCameraQuery();
445      if(!lastCameraQuery.ortho)
446      {
447         wheight = lastCameraQuery.nearPlane * mTan(lastCameraQuery.fov / 2);
448         wwidth = aspectRatio * wheight;
449      }
450      else
451      {
452         wheight = lastCameraQuery.fov;
453         wwidth = aspectRatio * wheight;
454      }
455
456      F32 hscale = wwidth * 2 / F32(mEditor->getWidth());
457      F32 vscale = wheight * 2 / F32(mEditor->getHeight());
458
459      Point2I editorPosition = mEditor->getPosition();
460      F32 left = (mDragRect.point.x - editorPosition.x) * hscale - wwidth;
461      F32 right = (mDragRect.point.x - editorPosition.x + mDragRect.extent.x) * hscale - wwidth;
462      F32 top = wheight - vscale * (mDragRect.point.y - editorPosition.y);
463      F32 bottom = wheight - vscale * (mDragRect.point.y - editorPosition.y + mDragRect.extent.y);
464      gDragFrustum.set(lastCameraQuery.ortho, left, right, top, bottom, lastCameraQuery.nearPlane, lastCameraQuery.farPlane, lastCameraQuery.cameraMatrix );
465
466      mForest->getData()->getItems( gDragFrustum, &mDragSelection );      
467   }
468}
469
470bool ForestSelectionTool::updateGuiInfo()
471{
472   SimObject *statusbar;
473   if ( !Sim::findObject( "EditorGuiStatusBar", statusbar ) )
474      return false;
475
476   String text( "Forest Editor." );      
477   GizmoMode mode = mGizmoProfile->mode;
478
479   if ( mMouseDown && mGizmo->getSelection() != Gizmo::None )
480   {
481      Point3F delta;
482      String qualifier;
483
484      if ( mode == RotateMode )   
485         delta = mGizmo->getDeltaTotalRot();         
486      else if ( mode == MoveMode )         
487         delta = mGizmo->getTotalOffset();         
488      else if ( mode == ScaleMode )
489         delta = mGizmo->getDeltaTotalScale();            
490
491      if ( mGizmo->getAlignment() == Object && mode != ScaleMode )
492      {       
493         mSelection.getOrientation().mulV( delta );
494      }
495
496      if ( mIsZero( delta.x, 0.0001f ) )
497         delta.x = 0.0f;
498      if ( mIsZero( delta.y, 0.0001f ) )
499         delta.y = 0.0f;
500      if ( mIsZero( delta.z, 0.0001f ) )
501         delta.z = 0.0f;
502
503      if ( mode == RotateMode )         
504      {         
505         delta.x = mRadToDeg( delta.x );
506         delta.y = mRadToDeg( delta.y );
507         delta.z = mRadToDeg( delta.z );
508         text = String::ToString( "Delta angle ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z ); 
509      }
510      else if ( mode == MoveMode )     
511         text = String::ToString( "Delta position ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z ); 
512      else if ( mode == ScaleMode )
513         text = String::ToString( "Delta scale ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z ); 
514   }
515   else 
516   {     
517      if ( mode == MoveMode )            
518         text = "Move selection.  SHIFT while dragging duplicates objects.";
519      else if ( mode == RotateMode )            
520         text = "Rotate selection.";
521      else if ( mode == ScaleMode )            
522         text = "Scale selection.";        
523   }   
524
525   Con::executef( statusbar, "setInfo", text.c_str() );
526
527   Con::executef( statusbar, "setSelectionObjectsByCount", mSelection.size() );
528
529   return true;
530}
531
532void ForestSelectionTool::updateGizmo()
533{
534   mGizmoProfile->restoreDefaultState();     
535
536   const GizmoMode &mode = mGizmoProfile->mode;
537
538   if ( mode == ScaleMode )   
539   {
540      mGizmoProfile->flags &= ~<a href="/coding/class/classgizmoprofile/">GizmoProfile</a>::PlanarHandlesOn;
541      mGizmoProfile->allAxesScaleUniform = true;
542   }
543}
544
545void ForestSelectionTool::onUndoAction()
546{
547   ForestData *data = mForest->getData();
548
549   // Remove items from our selection that no longer exist.
550   for ( S32 i = 0; i < mSelection.size(); i++ )
551   {
552      const ForestItem &item = data->findItem( mSelection[i].getKey(), mSelection[i].getPosition() );
553
554      if ( item == ForestItem::Invalid )
555      {
556         mSelection.erase_fast( i );
557         i--;
558      }
559      else      
560         mSelection[i] = item;      
561   }
562
563   // Recalculate our selection bounds.
564   mBounds = Box3F::Invalid;
565   for ( S32 i = 0; i < mSelection.size(); i++ )   
566      mBounds.intersect( mSelection[i].getWorldBox() );
567}
568
569DefineEngineMethod( ForestSelectionTool, getSelectionCount, S32, (), , "" )
570{
571   return object->getSelectionCount();
572}
573
574DefineEngineMethod( ForestSelectionTool, deleteSelection, void, (), , "" )
575{
576   object->deleteSelection();
577}
578
579DefineEngineMethod( ForestSelectionTool, clearSelection, void, (), , "" )
580{
581   object->clearSelection();
582}
583
584DefineEngineMethod( ForestSelectionTool, cutSelection, void, (), , "" )
585{
586   object->cutSelection();
587}
588
589DefineEngineMethod( ForestSelectionTool, copySelection, void, (), , "" )
590{
591   object->copySelection();
592}
593
594DefineEngineMethod( ForestSelectionTool, pasteSelection, void, (), , "" )
595{
596   object->pasteSelection();
597}
598
599