Torque3D Documentation / _generateds / worldEditorSelection.cpp

worldEditorSelection.cpp

Engine/source/gui/worldEditor/worldEditorSelection.cpp

More...

Public Functions

ConsoleDocClass(WorldEditorSelection , "@brief Specialized simset that stores the objects selected by the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(WorldEditorSelection , containsGlobalBounds , bool , () , "True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> an object with global bounds is contained in the selection." )
DefineEngineMethod(WorldEditorSelection , getBoxCentroid , Point3F , () , "Return the center of the bounding box around the selection." )
DefineEngineMethod(WorldEditorSelection , getCentroid , Point3F , () , "Return the median of all object positions in the selection." )
DefineEngineMethod(WorldEditorSelection , offset , void , (Point3F delta, F32 gridSnap) , (0.0f) , "Move all objects in the selection by the given delta." )
DefineEngineMethod(WorldEditorSelection , subtract , void , (SimSet *selection) , "Remove all objects in the given set from this selection." )
DefineEngineMethod(WorldEditorSelection , union , <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> , (SimSet *selection) , "Add all objects in the given set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this selection." )

Detailed Description

Public Functions

ConsoleDocClass(WorldEditorSelection , "@brief Specialized simset that stores the objects selected by the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )

DefineEngineMethod(WorldEditorSelection , containsGlobalBounds , bool , () , "True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> an object with global bounds is contained in the selection." )

DefineEngineMethod(WorldEditorSelection , getBoxCentroid , Point3F , () , "Return the center of the bounding box around the selection." )

DefineEngineMethod(WorldEditorSelection , getCentroid , Point3F , () , "Return the median of all object positions in the selection." )

DefineEngineMethod(WorldEditorSelection , offset , void , (Point3F delta, F32 gridSnap) , (0.0f) , "Move all objects in the selection by the given delta." )

DefineEngineMethod(WorldEditorSelection , subtract , void , (SimSet *selection) , "Remove all objects in the given set from this selection." )

DefineEngineMethod(WorldEditorSelection , union , <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> , (SimSet *selection) , "Add all objects in the given set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this selection." )

IMPLEMENT_CONOBJECT(WorldEditorSelection )

  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 "gui/worldEditor/worldEditorSelection.h"
 25#include "gui/worldEditor/worldEditor.h"
 26#include "scene/sceneObject.h"
 27
 28IMPLEMENT_CONOBJECT( WorldEditorSelection );
 29
 30ConsoleDocClass( WorldEditorSelection,
 31   "@brief Specialized simset that stores the objects selected by the World Editor\n\n"
 32   "Editor use only.\n\n"
 33   "@internal"
 34);
 35
 36//-----------------------------------------------------------------------------
 37
 38WorldEditorSelection::WorldEditorSelection()
 39   :  mCentroidValid(false),
 40      mAutoSelect(false),
 41      mContainsGlobalBounds(false),
 42      mPrevCentroid(0.0f, 0.0f, 0.0f)
 43{
 44   // Selections are transient by default.
 45   setCanSave( false );
 46   setEditorOnly( true );
 47}
 48
 49//-----------------------------------------------------------------------------
 50
 51WorldEditorSelection::~WorldEditorSelection()
 52{
 53}
 54
 55//-----------------------------------------------------------------------------
 56
 57void WorldEditorSelection::initPersistFields()
 58{
 59   Parent::initPersistFields();
 60}
 61
 62//-----------------------------------------------------------------------------
 63
 64void WorldEditorSelection::setCanSave( bool value )
 65{
 66   if( getCanSave() == value )
 67      return;
 68      
 69   Parent::setCanSave( value );
 70   
 71   // If we went from being transient to being persistent,
 72   // make sure all objects in the selection have persistent IDs.
 73   
 74   if( getCanSave() )
 75      for( iterator iter = begin(); iter != end(); ++ iter )
 76         ( *iter )->getOrCreatePersistentId();
 77}
 78
 79//-----------------------------------------------------------------------------
 80
 81bool WorldEditorSelection::objInSet( SimObject* obj )
 82{
 83   if( !mIsResolvingPIDs )
 84      resolvePIDs();
 85      
 86   lock();
 87      
 88   bool result = false;
 89   for( iterator iter = begin(); iter != end(); ++ iter )
 90   {
 91      if( obj == *iter )
 92      {
 93         result = true;
 94         break;
 95      }
 96         
 97      WorldEditorSelection* set = dynamic_cast< WorldEditorSelection* >( *iter );
 98      if( set && set->objInSet( obj ) )
 99      {
100         result = true;
101         break;
102      }
103   }
104   
105   unlock();
106   
107   return result;
108}
109
110//-----------------------------------------------------------------------------
111
112void WorldEditorSelection::addObject( SimObject* obj )
113{
114   // Return if object is already in selection.
115   
116   if( objInSet( obj ) )
117      return;
118      
119   // Refuse to add object if this selection is locked.
120      
121   if( isLocked() )
122      return;
123      
124   // Prevent adding us to ourselves.
125      
126   if( obj == this )
127      return;
128      
129   // If the object is itself a selection set, make sure we
130   // don't create a cycle.
131   
132   WorldEditorSelection* selection = dynamic_cast< WorldEditorSelection* >( obj );
133   if( selection && !selection->objInSet( this ) )
134      return;
135      
136   // Refuse to add any of our parents.
137   
138   for( SimGroup* group = getGroup(); group != NULL; group = group->getGroup() )
139      if( obj == group )
140         return;
141      
142   invalidateCentroid();
143   
144   Parent::addObject( obj );
145      
146   if( mAutoSelect )
147      WorldEditor::markAsSelected( obj, true );
148
149   return;
150}
151
152//-----------------------------------------------------------------------------
153
154void WorldEditorSelection::removeObject( SimObject* obj )
155{
156   if( !objInSet( obj ) )
157      return;
158      
159   // Refuse to remove object if this selection is locked.
160      
161   if( isLocked() )
162      return;
163
164   invalidateCentroid();
165   
166   Parent::removeObject( obj );
167
168   if( mAutoSelect )
169      WorldEditor::markAsSelected( obj, false );
170
171   return;
172}
173
174//-----------------------------------------------------------------------------
175
176bool WorldEditorSelection::containsGlobalBounds()
177{
178   updateCentroid();
179   return mContainsGlobalBounds;
180}
181
182//-----------------------------------------------------------------------------
183
184void WorldEditorSelection::updateCentroid()
185{
186   if( mCentroidValid )
187      return;
188      
189   resolvePIDs();
190
191   mCentroidValid = true;
192
193   mCentroid.set(0,0,0);
194   mBoxCentroid = mCentroid;
195   mBoxBounds.minExtents.set(1e10, 1e10, 1e10);
196   mBoxBounds.maxExtents.set(-1e10, -1e10, -1e10);
197
198   mContainsGlobalBounds = false;
199
200   if( empty() )
201      return;
202
203   //
204   for( SimSet::iterator iter = begin(); iter != end(); ++ iter )
205   {
206      SceneObject* obj = dynamic_cast<SceneObject*>( *iter );
207      if( !obj )
208         continue;
209
210      const MatrixF & mat = obj->getTransform();
211      Point3F wPos;
212      mat.getColumn(3, &wPos);
213
214      //
215      mCentroid += wPos;
216
217      //
218      const Box3F& bounds = obj->getWorldBox();
219      mBoxBounds.minExtents.setMin(bounds.minExtents);
220      mBoxBounds.maxExtents.setMax(bounds.maxExtents);
221
222      if(obj->isGlobalBounds())
223         mContainsGlobalBounds = true;
224   }
225
226   mCentroid /= (F32) size();
227   mBoxCentroid = mBoxBounds.getCenter();
228}
229
230//-----------------------------------------------------------------------------
231
232const Point3F & WorldEditorSelection::getCentroid()
233{
234   updateCentroid();
235   return(mCentroid);
236}
237
238//-----------------------------------------------------------------------------
239
240const Point3F & WorldEditorSelection::getBoxCentroid()
241{
242   updateCentroid();
243   return(mBoxCentroid);
244}
245
246//-----------------------------------------------------------------------------
247
248const Box3F & WorldEditorSelection::getBoxBounds()
249{
250   updateCentroid();
251   return(mBoxBounds);
252}
253
254//-----------------------------------------------------------------------------
255
256Point3F WorldEditorSelection::getBoxBottomCenter()
257{
258   updateCentroid();
259   
260   Point3F bottomCenter = mBoxCentroid;
261   bottomCenter.z -= mBoxBounds.len_z() * 0.5f;
262   
263   return bottomCenter;
264}
265
266//-----------------------------------------------------------------------------
267
268void WorldEditorSelection::enableCollision()
269{
270   for( iterator iter = begin(); iter != end(); ++ iter )
271   {
272      SceneObject* object = dynamic_cast<SceneObject*>( *iter );
273      if( object )
274         object->enableCollision();
275   }
276}
277
278//-----------------------------------------------------------------------------
279
280void WorldEditorSelection::disableCollision()
281{
282   for( iterator iter = begin(); iter != end(); ++ iter )
283   {
284      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
285      if( object )
286         object->disableCollision();
287   }
288}
289
290//-----------------------------------------------------------------------------
291
292void WorldEditorSelection::offset( const Point3F& offset, F32 gridSnap )
293{
294   for( iterator iter = begin(); iter != end(); ++ iter )
295   {
296      SceneObject* obj = dynamic_cast<SceneObject*>( *iter );
297      if( !obj )
298         continue;
299
300      MatrixF mat = obj->getTransform();
301      Point3F wPos;
302      mat.getColumn(3, &wPos);
303
304      // adjust
305      wPos += offset;
306      
307      if( gridSnap != 0.f )
308      {
309         wPos.x = _snapFloat(wPos.x, gridSnap);
310         wPos.y = _snapFloat(wPos.y, gridSnap);
311         wPos.z = _snapFloat(wPos.z, gridSnap);
312      }
313      
314      mat.setColumn(3, wPos);
315      obj->setTransform(mat);
316   }
317
318   mCentroidValid = false;
319}
320
321F32 WorldEditorSelection::_snapFloat(const F32 &val, const F32 &snap) const
322{
323   if (snap == 0.0f)
324      return val;
325
326   F32 a = mFmod(val, snap);
327
328   F32 temp = val;
329
330   if (mFabs(a) > (snap / 2))
331      val < 0.0f ? temp -= snap : temp += snap;
332
333   return(temp - a);
334}
335
336
337//-----------------------------------------------------------------------------
338
339void WorldEditorSelection::setPosition(const Point3F & pos)
340{
341   for( iterator iter = begin(); iter != end(); ++ iter )
342   {
343      SceneObject* object = dynamic_cast<SceneObject*>( *iter );
344      if( object )
345         object->setPosition(pos);
346   }
347
348   mCentroidValid = false;
349}
350
351//-----------------------------------------------------------------------------
352
353void WorldEditorSelection::setCentroidPosition(bool useBoxCenter, const Point3F & pos)
354{
355   Point3F centroid;
356   if( containsGlobalBounds() )
357   {
358      centroid = getCentroid();
359   }
360   else
361   {
362      centroid = useBoxCenter ? getBoxCentroid() : getCentroid();
363   }
364
365   offset(pos - centroid);
366}
367
368//-----------------------------------------------------------------------------
369
370void WorldEditorSelection::orient(const MatrixF & rot, const Point3F & center)
371{
372   // Orient all the selected objects to the given rotation
373   for( iterator iter = begin(); iter != end(); ++ iter )
374   {
375      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
376      if( !object )
377         continue;
378         
379      MatrixF mat = rot;
380      mat.setPosition( object->getPosition() );
381      object->setTransform(mat);
382   }
383
384   mCentroidValid = false;
385}
386
387//-----------------------------------------------------------------------------
388
389void WorldEditorSelection::rotate(const EulerF &rot)
390{
391   for( iterator iter = begin(); iter != end(); ++ iter )
392   {
393      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
394      if( !object )
395         continue;
396
397         MatrixF mat = object->getTransform();
398
399         MatrixF transform(rot);
400         mat.mul(transform);
401
402         object->setTransform(mat);
403   }
404}
405
406//-----------------------------------------------------------------------------
407
408void WorldEditorSelection::rotate(const EulerF & rot, const Point3F & center)
409{
410   // single selections will rotate around own axis, multiple about world
411   if(size() == 1)
412   {
413      SceneObject* object = dynamic_cast<SceneObject*>(at(0));
414      if (object)
415      {
416         MatrixF mat = object->getTransform();
417
418         Point3F pos;
419         mat.getColumn(3, &pos);
420
421         // get offset in obj space
422         Point3F offset = pos - center;
423         MatrixF wMat = object->getWorldTransform();
424         wMat.mulV(offset);
425
426         //
427         MatrixF transform(EulerF(0, 0, 0), -offset);
428         transform.mul(MatrixF(rot));
429         transform.mul(MatrixF(EulerF(0, 0, 0), offset));
430         mat.mul(transform);
431
432         object->setTransform(mat);
433      }
434   }
435   else
436   {
437      for( iterator iter = begin(); iter != end(); ++ iter )
438      {
439         SceneObject* object = dynamic_cast< SceneObject* >( *iter );
440         if( !object )
441            continue;
442            
443         MatrixF mat = object->getTransform();
444
445         Point3F pos;
446         mat.getColumn(3, &pos);
447
448         // get offset in obj space
449         Point3F offset = pos - center;
450
451         MatrixF transform(rot);
452         Point3F wOffset;
453         transform.mulV(offset, &wOffset);
454
455         MatrixF wMat = object->getWorldTransform();
456         wMat.mulV(offset);
457
458         //
459         transform.set(EulerF(0,0,0), -offset);
460
461         mat.setColumn(3, Point3F(0,0,0));
462         wMat.setColumn(3, Point3F(0,0,0));
463
464         transform.mul(wMat);
465         transform.mul(MatrixF(rot));
466         transform.mul(mat);
467         mat.mul(transform);
468
469         mat.normalize();
470         mat.setColumn(3, wOffset + center);
471
472         object->setTransform(mat);
473      }
474   }
475
476   mCentroidValid = false;
477}
478
479//-----------------------------------------------------------------------------
480
481void WorldEditorSelection::setRotate(const EulerF & rot)
482{
483   for( iterator iter = begin(); iter != end(); ++ iter )
484   {
485      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
486      if( !object )
487         continue;
488
489      MatrixF mat = object->getTransform();
490      Point3F pos;
491      mat.getColumn(3, &pos);
492
493      MatrixF rmat(rot);
494      rmat.setPosition(pos);
495
496      object->setTransform(rmat);
497   }
498}
499
500//-----------------------------------------------------------------------------
501
502void WorldEditorSelection::scale(const VectorF & scale)
503{
504   for( iterator iter = begin(); iter != end(); ++ iter )
505   {
506      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
507      if( !object )
508         continue;
509         
510      VectorF current = object->getScale();
511      current.convolve(scale);
512
513      // clamp scale to sensible limits
514      current.setMax( Point3F( 0.01f ) );
515      current.setMin( Point3F( 1000.0f ) );
516
517      object->setScale(current);
518   }
519
520   mCentroidValid = false;
521}
522
523//-----------------------------------------------------------------------------
524
525void WorldEditorSelection::scale(const VectorF & scale, const Point3F & center)
526{
527   for( iterator iter = begin(); iter != end(); ++ iter )
528   {
529      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
530      if( !object )
531         continue;
532
533      VectorF current = object->getScale();
534      current.convolve(scale);
535
536      // clamp scale to sensible limits
537      current.setMax( Point3F( 0.01f ) );
538      current.setMin( Point3F( 1000.0f ) );
539
540      // Apply the scale first.  If the object's scale doesn't change with
541      // this operation then this object doesn't scale.  In this case
542      // we don't want to continue with the offset operation.
543      VectorF prevScale = object->getScale();
544      object->setScale(current);
545      if( !object->getScale().equal(current) )
546         continue;
547
548      // determine the actual scale factor to apply to the object offset
549      // need to account for the scale limiting above to prevent offsets
550      // being reduced to 0 which then cannot be restored by unscaling
551      VectorF adjustedScale = current / prevScale;
552
553      MatrixF mat = object->getTransform();
554
555      Point3F pos;
556      mat.getColumn(3, &pos);
557
558      Point3F offset = pos - center;
559      offset *= adjustedScale;
560
561      object->setPosition(offset + center);
562   }
563}
564
565//-----------------------------------------------------------------------------
566
567void WorldEditorSelection::setScale(const VectorF & scale)
568{
569   for( iterator iter = begin(); iter != end(); ++ iter )
570   {
571      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
572      if( object )
573         object->setScale( scale );
574   }
575
576   mCentroidValid = false;
577}
578
579//-----------------------------------------------------------------------------
580
581void WorldEditorSelection::setScale(const VectorF & scale, const Point3F & center)
582{
583   for( iterator iter = begin(); iter != end(); ++ iter )
584   {
585      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
586      if( !object )
587         continue;
588         
589      MatrixF mat = object->getTransform();
590
591      Point3F pos;
592      mat.getColumn(3, &pos);
593
594      Point3F offset = pos - center;
595      offset *= scale;
596
597      object->setPosition(offset + center);
598      object->setScale(scale);
599   }
600}
601
602//-----------------------------------------------------------------------------
603
604void WorldEditorSelection::addSize(const VectorF & newsize)
605{
606   for( iterator iter = begin(); iter != end(); ++ iter )
607   {
608      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
609      if( !object )
610         continue;
611
612      if( object->isGlobalBounds() )
613         continue;
614
615      const Box3F& bounds = object->getObjBox();
616      VectorF extent = bounds.getExtents();
617      VectorF scaledextent = object->getScale() * extent;
618
619      VectorF scale = (newsize + scaledextent) / scaledextent;
620      object->setScale( object->getScale() * scale );
621   }
622}
623
624//-----------------------------------------------------------------------------
625
626void WorldEditorSelection::setSize(const VectorF & newsize)
627{
628   for( iterator iter = begin(); iter != end(); ++ iter )
629   {
630      SceneObject* object = dynamic_cast< SceneObject* >( *iter );
631      if( !object )
632         continue;
633
634      if( object->isGlobalBounds() )
635         continue;
636
637      const Box3F& bounds = object->getObjBox();
638      VectorF extent = bounds.getExtents();
639
640      VectorF scale = newsize / extent;
641      object->setScale( scale );
642   }
643}
644
645//=============================================================================
646//    Console Methods.
647//=============================================================================
648// MARK: ---- Console Methods ----
649
650//-----------------------------------------------------------------------------
651
652DefineEngineMethod( WorldEditorSelection, containsGlobalBounds, bool, (),, "True if an object with global bounds is contained in the selection." )
653{
654   return object->containsGlobalBounds();
655}
656
657//-----------------------------------------------------------------------------
658
659DefineEngineMethod( WorldEditorSelection, getCentroid, Point3F, (),, "Return the median of all object positions in the selection." )
660{
661   const Point3F& centroid = object->getCentroid();
662   return centroid;
663}
664
665//-----------------------------------------------------------------------------
666
667DefineEngineMethod( WorldEditorSelection, getBoxCentroid, Point3F, (),, "Return the center of the bounding box around the selection." )
668{
669   const Point3F& boxCentroid = object->getBoxCentroid();
670   return boxCentroid;
671}
672
673//-----------------------------------------------------------------------------
674
675DefineEngineMethod(WorldEditorSelection, offset, void, (Point3F delta, F32 gridSnap), (0.0f), "Move all objects in the selection by the given delta.")
676{     
677   object->offset( delta, gridSnap );
678   WorldEditor::updateClientTransforms( object );
679}
680
681//-----------------------------------------------------------------------------
682
683DefineEngineMethod( WorldEditorSelection, union, void, (SimSet* selection),, "Add all objects in the given set to this selection." )
684{
685   if( !selection)
686   {
687      Con::errorf( "WorldEditorSelection::union - no SimSet");
688      return;
689   }
690   
691   const U32 numObjects = selection->size();
692   for( U32 i = 0; i < numObjects; ++ i )
693      object->addObject( selection->at( i ) );
694}
695
696//-----------------------------------------------------------------------------
697
698DefineEngineMethod( WorldEditorSelection, subtract, void, (SimSet* selection),, "Remove all objects in the given set from this selection." )
699{
700   if( !selection )
701   {
702      Con::errorf( "WorldEditorSelection::subtract - no SimSet" );
703      return;
704   }
705   
706   const U32 numObjects = selection->size();
707   for( U32 i = 0; i < numObjects; ++ i )
708      object->removeObject( selection->at( i ) );
709}
710