Torque3D Documentation / _generateds / guiDecalEditorCtrl.cpp

guiDecalEditorCtrl.cpp

Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp

More...

Public Functions

ConsoleDocClass(DBDeleteUndoAction , "@brief Decal Datablock Delete Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
ConsoleDocClass(DBRetargetUndoAction , "@brief Decal Datablock Retarget Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
ConsoleDocClass(DICreateUndoAction , "@brief Decal Instance Create Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
ConsoleDocClass(DIDeleteUndoAction , "@brief Decal Instance Delete Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
ConsoleDocClass(GuiDecalEditorCtrl , "@brief The base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the Decal Editor <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tool\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiDecalEditorCtrl , deleteDecalDatablock , void , (const char *datablock) , "deleteSelectedDecalDatablock( <a href="/coding/class/classstring/">String</a> datablock )" )
DefineEngineMethod(GuiDecalEditorCtrl , deleteSelectedDecal , void , () , "deleteSelectedDecal()" )
DefineEngineMethod(GuiDecalEditorCtrl , editDecalDetails , void , (U32 id, Point3F pos, Point3F tan, F32 size) , "editDecalDetails( <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> )()" )
DefineEngineMethod(GuiDecalEditorCtrl , getDecalCount , S32 , () , "getDecalCount()" )
DefineEngineMethod(GuiDecalEditorCtrl , getDecalLookupName , const char * , (U32 id) , "getDecalLookupName( <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> )()" )
DefineEngineMethod(GuiDecalEditorCtrl , getDecalTransform , const char * , (U32 id) , "getDecalTransform()" )
DefineEngineMethod(GuiDecalEditorCtrl , getMode , const char * , () , "getMode()" )
DefineEngineMethod(GuiDecalEditorCtrl , getSelectionCount , S32 , () , "" )
DefineEngineMethod(GuiDecalEditorCtrl , retargetDecalDatablock , void , (const char *dbFrom, const char *dbTo) , "" )
DefineEngineMethod(GuiDecalEditorCtrl , selectDecal , void , (U32 id) , "selectDecal( <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> )()" )
DefineEngineMethod(GuiDecalEditorCtrl , setMode , void , (String newMode) , "setMode( <a href="/coding/class/classstring/">String</a> <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> )()" )

Detailed Description

Public Functions

ConsoleDocClass(DBDeleteUndoAction , "@brief Decal Datablock Delete Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

ConsoleDocClass(DBRetargetUndoAction , "@brief Decal Datablock Retarget Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

ConsoleDocClass(DICreateUndoAction , "@brief Decal Instance Create Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

ConsoleDocClass(DIDeleteUndoAction , "@brief Decal Instance Delete Undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Actions\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

ConsoleDocClass(GuiDecalEditorCtrl , "@brief The base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the Decal Editor <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tool\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )

DefineEngineMethod(GuiDecalEditorCtrl , deleteDecalDatablock , void , (const char *datablock) , "deleteSelectedDecalDatablock( <a href="/coding/class/classstring/">String</a> datablock )" )

DefineEngineMethod(GuiDecalEditorCtrl , deleteSelectedDecal , void , () , "deleteSelectedDecal()" )

DefineEngineMethod(GuiDecalEditorCtrl , editDecalDetails , void , (U32 id, Point3F pos, Point3F tan, F32 size) , "editDecalDetails( <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> )()" )

DefineEngineMethod(GuiDecalEditorCtrl , getDecalCount , S32 , () , "getDecalCount()" )

DefineEngineMethod(GuiDecalEditorCtrl , getDecalLookupName , const char * , (U32 id) , "getDecalLookupName( <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> )()" )

DefineEngineMethod(GuiDecalEditorCtrl , getDecalTransform , const char * , (U32 id) , "getDecalTransform()" )

DefineEngineMethod(GuiDecalEditorCtrl , getMode , const char * , () , "getMode()" )

DefineEngineMethod(GuiDecalEditorCtrl , getSelectionCount , S32 , () , "" )

DefineEngineMethod(GuiDecalEditorCtrl , retargetDecalDatablock , void , (const char *dbFrom, const char *dbTo) , "" )

DefineEngineMethod(GuiDecalEditorCtrl , selectDecal , void , (U32 id) , "selectDecal( <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> )()" )

DefineEngineMethod(GuiDecalEditorCtrl , setMode , void , (String newMode) , "setMode( <a href="/coding/class/classstring/">String</a> <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> )()" )

IMPLEMENT_CONOBJECT(DBDeleteUndoAction )

IMPLEMENT_CONOBJECT(DBRetargetUndoAction )

IMPLEMENT_CONOBJECT(DICreateUndoAction )

IMPLEMENT_CONOBJECT(DIDeleteUndoAction )

IMPLEMENT_CONOBJECT(GuiDecalEditorCtrl )

   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#ifndef TORQUE_TGB_ONLY
  25
  26#include "guiDecalEditorCtrl.h"
  27#include "platform/platform.h"
  28
  29#include "console/consoleTypes.h"
  30#include "console/engineAPI.h"
  31#include "scene/sceneManager.h"
  32#include "collision/collision.h"
  33#include "math/util/frustum.h"
  34#include "gfx/gfxPrimitiveBuffer.h"
  35#include "gfx/gfxTextureHandle.h"
  36#include "gfx/gfxTransformSaver.h"
  37#include "gfx/primBuilder.h"
  38#include "gfx/gfxDrawUtil.h"
  39#include "gui/core/guiCanvas.h"
  40#include "gui/buttons/guiButtonCtrl.h"
  41#include "gui/worldEditor/gizmo.h"
  42#include "T3D/decal/decalManager.h"
  43#include "T3D/decal/decalInstance.h"
  44#include "gui/worldEditor/undoActions.h"
  45
  46IMPLEMENT_CONOBJECT(GuiDecalEditorCtrl);
  47
  48ConsoleDocClass( GuiDecalEditorCtrl,
  49   "@brief The base class for the Decal Editor tool\n\n"
  50   "Editor use only.\n\n"
  51   "@internal"
  52);
  53
  54bool GuiDecalEditorCtrl::smRenderDecalPixelSize = false;
  55
  56GuiDecalEditorCtrl::GuiDecalEditorCtrl()
  57{   
  58   mSELDecal = NULL;
  59   mHLDecal = NULL;
  60   mCurrentDecalData = NULL;
  61   mMode = "AddDecalMode";
  62   mPerformedDragCopy = false;
  63}
  64
  65GuiDecalEditorCtrl::~GuiDecalEditorCtrl()
  66{
  67   // nothing to do
  68}
  69
  70bool GuiDecalEditorCtrl::onAdd()
  71{
  72   if( !Parent::onAdd() )
  73      return false;
  74
  75   return true;
  76}
  77
  78void GuiDecalEditorCtrl::initPersistFields()
  79{
  80   addField( "currentDecalData", TYPEID< DecalData >(), Offset( mCurrentDecalData, GuiDecalEditorCtrl ) );
  81
  82   Parent::initPersistFields();
  83}
  84
  85void GuiDecalEditorCtrl::consoleInit()
  86{
  87   Con::addVariable( "$DecalEditor::renderPixelSize", TypeBool, &smRenderDecalPixelSize, 
  88      "Set true to render the pixel size as on overlay on the selected decal instance. "
  89      "This is the value used to fade distant decals and is intended to help the user adjust "
  90      "the values of DecalData::pixelSizeStartFade and pixelSizeEndFade.\n\n"
  91     "@internal" );
  92
  93   Parent::consoleInit();
  94}
  95
  96void GuiDecalEditorCtrl::onEditorDisable()
  97{
  98   // Tools are not deleted/recreated between missions, but decals instances
  99   // ARE. So we must release any references.
 100   mSELDecal = NULL;
 101   mHLDecal = NULL;
 102}
 103
 104bool GuiDecalEditorCtrl::onWake()
 105{
 106   if ( !Parent::onWake() )
 107      return false;
 108   
 109   
 110
 111   return true;
 112}
 113
 114void GuiDecalEditorCtrl::onSleep()
 115{
 116   Parent::onSleep();   
 117}
 118
 119void GuiDecalEditorCtrl::get3DCursor( GuiCursor *&cursor, 
 120                                       bool &visible, 
 121                                       const Gui3DMouseEvent &event_ )
 122{
 123   cursor = NULL;
 124   visible = false;
 125
 126   GuiCanvas *root = getRoot();
 127   if ( !root )
 128      return;
 129
 130   S32 currCursor = PlatformCursorController::curArrow;
 131
 132   if ( root->mCursorChanged == currCursor )
 133      return;
 134
 135   PlatformWindow *window = root->getPlatformWindow();
 136   PlatformCursorController *controller = window->getCursorController();
 137   
 138   // We've already changed the cursor, 
 139   // so set it back before we change it again.
 140   if( root->mCursorChanged != -1)
 141      controller->popCursor();
 142
 143   // Now change the cursor shape
 144   controller->pushCursor(currCursor);
 145   root->mCursorChanged = currCursor;   
 146}
 147
 148void GuiDecalEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
 149{
 150   mPerformedDragCopy = false;
 151
 152   if ( !isFirstResponder() )
 153      setFirstResponder();
 154   
 155   bool dblClick = ( event.mouseClickCount > 1 );
 156
 157   // Gather selected decal information 
 158   RayInfo ri;
 159   bool hit = getRayInfo( event, &ri );
 160
 161   Point3F start = event.pos;
 162   Point3F end = start + event.vec * 3000.0f; // use visible distance here??
 163
 164   DecalInstance *pDecal = gDecalManager->raycast( start, end );
 165   
 166   if( mMode.compare("AddDecalMode") != 0 )
 167   {
 168      if ( mSELDecal )
 169      {
 170         // If our click hit the gizmo we are done.         
 171         if ( mGizmo->getSelection() != Gizmo::None )
 172         {
 173            mGizmo->on3DMouseDown( event );
 174
 175            char returnBuffer[256];
 176            dSprintf(returnBuffer, sizeof(returnBuffer), "%f %f %f %f %f %f %f", 
 177            mSELDecal->mPosition.x, mSELDecal->mPosition.y, mSELDecal->mPosition.z, 
 178            mSELDecal->mTangent.x, mSELDecal->mTangent.y, mSELDecal->mTangent.z,
 179            mSELDecal->mSize);
 180
 181            Con::executef( this, "prepGizmoTransform", Con::getIntArg(mSELDecal->mId), returnBuffer );
 182
 183            return;
 184         }
 185      }
 186
 187      if ( mHLDecal && pDecal == mHLDecal )
 188      {
 189         mHLDecal = NULL;            
 190         selectDecal( pDecal );   
 191
 192         if ( isMethod( "onSelectInstance" ) )
 193         {
 194            char idBuf[512];
 195            dSprintf(idBuf, 512, "%i", pDecal->mId);
 196            Con::executef( this, "onSelectInstance", String(idBuf).c_str(), pDecal->mDataBlock->lookupName.c_str() );
 197         }
 198
 199         return;
 200      }
 201      else if ( hit && !pDecal)
 202      {
 203         if ( dblClick )
 204            setMode( String("AddDecalMode"), true );
 205
 206         return;
 207      }
 208   }
 209   else
 210   {
 211      // If we accidently hit a decal, then bail(probably an accident). If the use hits the decal twice,
 212      // then boot them into selection mode and select the decal.
 213      if ( mHLDecal && pDecal == mHLDecal )
 214      {
 215         if ( dblClick )
 216         {
 217            mHLDecal = NULL;            
 218            selectDecal( pDecal );   
 219
 220            if ( isMethod( "onSelectInstance" ) )
 221            {
 222               char idBuf[512];
 223               dSprintf(idBuf, 512, "%i", pDecal->mId);
 224               Con::executef( this, "onSelectInstance", String(idBuf).c_str(), pDecal->mDataBlock->lookupName.c_str() );
 225            }
 226            setMode( String("SelectDecalMode"), true );
 227         }
 228         return;  
 229      }
 230
 231      if ( hit && mCurrentDecalData ) // Create a new decal...
 232      {
 233         U8 flags = PermanentDecal | SaveDecal;
 234
 235         DecalInstance *decalInst = gDecalManager->addDecal( ri.point, ri.normal, 0.0f, mCurrentDecalData, 1.0f, -1, flags );      
 236         
 237         if ( decalInst )  
 238         {
 239            // Give the decal an id
 240            decalInst->mId = gDecalManager->mDecalInstanceVec.size();
 241            gDecalManager->mDecalInstanceVec.push_back(decalInst);
 242
 243            selectDecal( decalInst );
 244            
 245            // Grab the mission editor undo manager.
 246            UndoManager *undoMan = NULL;
 247            if ( !Sim::findObject( "EUndoManager", undoMan ) )
 248            {
 249               Con::errorf( "GuiMeshRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
 250               return;           
 251            }
 252
 253            // Create the UndoAction.
 254            DICreateUndoAction *action = new DICreateUndoAction("Create Decal");
 255            action->addDecal( *decalInst );
 256            
 257            action->mEditor = this;
 258            // Submit it.               
 259            undoMan->addAction( action );
 260
 261            if ( isMethod( "onCreateInstance" ) )
 262            {
 263               char buffer[512];
 264               dSprintf(buffer, 512, "%i", decalInst->mId);
 265               Con::executef( this, "onCreateInstance", buffer, decalInst->mDataBlock->lookupName.c_str());
 266            }
 267         }
 268
 269         return;
 270      }
 271   }
 272
 273   if ( !mSELDecal )
 274      return;
 275}
 276
 277void GuiDecalEditorCtrl::on3DRightMouseDown(const Gui3DMouseEvent & event)
 278{
 279   //mIsPanning = true;
 280   //mGizmo->on3DRightMouseDown( event );
 281}
 282
 283void GuiDecalEditorCtrl::on3DRightMouseUp(const Gui3DMouseEvent & event)
 284{
 285   //mIsPanning = false;
 286//   mGizmo->on3DRightMouseUp( event );
 287}
 288
 289void GuiDecalEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
 290{
 291   if ( mSELDecal )
 292   {
 293      if ( mGizmo->isDirty() )
 294      {
 295         char returnBuffer[256];
 296         dSprintf(returnBuffer, sizeof(returnBuffer), "%f %f %f %f %f %f %f", 
 297         mSELDecal->mPosition.x, mSELDecal->mPosition.y, mSELDecal->mPosition.z, 
 298         mSELDecal->mTangent.x, mSELDecal->mTangent.y, mSELDecal->mTangent.z,
 299         mSELDecal->mSize);
 300
 301         Con::executef( this, "completeGizmoTransform", Con::getIntArg(mSELDecal->mId), returnBuffer );
 302
 303         mGizmo->markClean();
 304      }
 305
 306      mGizmo->on3DMouseUp( event );
 307   }
 308}
 309
 310void GuiDecalEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
 311{
 312   if ( mSELDecal )
 313      mGizmo->on3DMouseMove( event );
 314
 315   RayInfo ri;
 316   if ( !getRayInfo( event, &ri ) )
 317      return; 
 318
 319   Point3F start = event.pos;
 320   Point3F end = start + event.vec * 3000.0f; // use visible distance here??
 321
 322   DecalInstance *pDecal = gDecalManager->raycast( start, end );
 323
 324   if ( pDecal && pDecal != mSELDecal )
 325      mHLDecal = pDecal;   
 326   else if ( !pDecal )
 327      mHLDecal = NULL;
 328}
 329
 330void GuiDecalEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
 331{ 
 332   if ( !mSELDecal )
 333      return;
 334
 335   // Doing a drag copy of the decal?
 336   if ( event.modifier & SI_SHIFT && !mPerformedDragCopy )
 337   {
 338      mPerformedDragCopy = true;
 339
 340      DecalInstance *newDecal = gDecalManager->addDecal(    mSELDecal->mPosition, 
 341                                                            mSELDecal->mNormal, 
 342                                                            0.0f, 
 343                                                            mSELDecal->mDataBlock, 
 344                                                            1.0f, 
 345                                                            -1, 
 346                                                            PermanentDecal | SaveDecal );
 347
 348      newDecal->mTangent = mSELDecal->mTangent;
 349      newDecal->mSize = mSELDecal->mSize;
 350      newDecal->mTextureRectIdx = mSELDecal->mTextureRectIdx;
 351
 352      // TODO: This is crazy... we should move this sort of tracking
 353      // inside of the decal manager... IdDecal flag maybe or just a
 354      // byproduct of PermanentDecal?
 355      //
 356      newDecal->mId = gDecalManager->mDecalInstanceVec.size();
 357      gDecalManager->mDecalInstanceVec.push_back( newDecal );
 358
 359      selectDecal( newDecal );
 360         
 361      // Grab the mission editor undo manager.
 362      UndoManager *undoMan = NULL;
 363      if ( Sim::findObject( "EUndoManager", undoMan ) )
 364      {
 365         // Create the UndoAction.
 366         DICreateUndoAction *action = new DICreateUndoAction("Create Decal");
 367         action->addDecal( *mSELDecal );
 368         action->mEditor = this;
 369         undoMan->addAction( action );
 370
 371         if ( isMethod( "onCreateInstance" ) )
 372         {
 373            char buffer[512];
 374            dSprintf( buffer, 512, "%i", mSELDecal->mId );
 375            Con::executef( this, "onCreateInstance", buffer, mSELDecal->mDataBlock->lookupName.c_str());
 376         }
 377      }
 378   }
 379
 380   // Update the Gizmo.
 381   if (mGizmo->getSelection() != Gizmo::None)
 382   {
 383      mGizmo->on3DMouseDragged( event );
 384
 385      // Pull out the Gizmo transform
 386      // and position.
 387      const MatrixF &gizmoMat = mGizmo->getTransform();
 388      const Point3F &gizmoPos = gizmoMat.getPosition();
 389      
 390      // Get the new projection vector.
 391      VectorF upVec, rightVec;
 392      gizmoMat.getColumn( 0, &rightVec );
 393      gizmoMat.getColumn( 2, &upVec );
 394
 395      const Point3F &scale = mGizmo->getScale();
 396
 397      // Assign the appropriate changed value back to the decal.
 398      if ( mGizmo->getMode() == ScaleMode )
 399      {
 400         // Save old size.
 401         const F32 oldSize = mSELDecal->mSize;
 402
 403         // Set new size.
 404         mSELDecal->mSize = ( scale.x + scale.y ) * 0.5f;
 405
 406         // See if the decal properly clips/projects at this size.  If not,
 407         // stick to the old size.
 408         mSELEdgeVerts.clear();
 409         if ( !gDecalManager->clipDecal( mSELDecal, &mSELEdgeVerts ) )
 410            mSELDecal->mSize = oldSize;
 411      }
 412      else if ( mGizmo->getMode() == MoveMode )
 413         mSELDecal->mPosition = gizmoPos;
 414      else if ( mGizmo->getMode() == RotateMode )
 415      {
 416         mSELDecal->mNormal = upVec;
 417         mSELDecal->mTangent = rightVec;
 418      }
 419
 420      gDecalManager->notifyDecalModified( mSELDecal );
 421
 422      Con::executef( this, "syncNodeDetails" );
 423   }
 424}
 425
 426void GuiDecalEditorCtrl::on3DMouseEnter(const Gui3DMouseEvent & event)
 427{
 428   // nothing to do
 429}
 430
 431void GuiDecalEditorCtrl::on3DMouseLeave(const Gui3DMouseEvent & event)
 432{
 433   // nothing to do
 434}
 435
 436void GuiDecalEditorCtrl::updateGuiInfo()
 437{
 438   // nothing to do
 439}
 440      
 441void GuiDecalEditorCtrl::onRender( Point2I offset, const RectI &updateRect )
 442{
 443   Parent::onRender( offset, updateRect );
 444}
 445
 446void GuiDecalEditorCtrl::renderGui( Point2I offset, const RectI &updateRect )
 447{
 448   Parent::renderGui( offset, updateRect );
 449
 450   PROFILE_SCOPE( GuiDecalEditorCtrl_renderGui );
 451
 452   // Show the pixelSize of the selected decal as a text overlay.
 453   if ( smRenderDecalPixelSize && mSELDecal != NULL )
 454   {
 455      const F32 pixelSize = mSELDecal->calcPixelSize( mSaveViewport.extent.y, mLastCameraQuery.cameraMatrix.getPosition(), mSaveWorldToScreenScale.y );
 456      
 457      // Find position onscreen to render the text.
 458      Point3F screenPos;
 459      bool onScreen = project( mSELDecal->mPosition, &screenPos );
 460
 461      if ( onScreen )
 462      {
 463         // It is extremely annoying to require the GuiProfile to have a font
 464         // or to create one within the decal editor for only this single use,
 465         // so we instead rely on the fact that we already have a Gizmo, that
 466         // all Gizmo's have a GizmoProfile, and that GizmoProfile has a font.
 467         GFont *font = mGizmo->getProfile()->font;
 468
 469         // Might as well use some colors defined in GizmoProfile too instead
 470         // of just hardcoding it here.
 471         const ColorI bgColor = mGizmo->getProfile()->inActiveColor;
 472         const ColorI textColor = mGizmo->getProfile()->activeColor;
 473
 474         // Note: This mostly mirrors the way WorldEditor renders popupText for
 475         // the gizmo during a drag operation, consider unifying this into a utility method.
 476
 477         char buf[256];
 478         dSprintf( buf, 256, "%0.3f", pixelSize );
 479
 480         const U32 width = font->getStrWidth((const UTF8 *)buf);;
 481         const Point2I posi( (U32)screenPos.x, (U32)screenPos.y + 12 );   
 482         const Point2I minPt(posi.x - width / 2 - 2, posi.y - 1);
 483         const Point2I maxPt(posi.x + width / 2 + 2, posi.y + font->getHeight() + 1);
 484
 485         GFXDrawUtil *drawer = GFX->getDrawUtil();
 486         drawer->drawRectFill( minPt, maxPt, bgColor );
 487         GFX->getDrawUtil()->setBitmapModulation( textColor );
 488         GFX->getDrawUtil()->drawText( mProfile->mFont, Point2I( posi.x - width / 2, posi.y ), buf );
 489      }      
 490   }
 491}
 492
 493void GuiDecalEditorCtrl::renderScene(const RectI & updateRect)
 494{
 495   PROFILE_SCOPE( GuiDecalEditorCtrl_renderScene );
 496
 497   GFXTransformSaver saver;
 498   
 499   ColorI hlColor(0,255,0,255);
 500   ColorI regColor(255,0,0,255);
 501   ColorI selColor(0,0,255,255);
 502   ColorI color;
 503   
 504   GFXDrawUtil *drawUtil = GFX->getDrawUtil();   
 505
 506   GFXStateBlockDesc desc;
 507   desc.setBlend( true );
 508   desc.setZReadWrite( true, false );
 509
 510   // Draw 3D stuff here.   
 511   if ( mSELDecal )
 512   {
 513      mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix, mLastCameraQuery.fov );
 514
 515      mSELEdgeVerts.clear();
 516      if ( gDecalManager->clipDecal( mSELDecal, &mSELEdgeVerts ) )
 517         _renderDecalEdge( mSELEdgeVerts, ColorI( 255, 255, 255, 255 ) );
 518
 519      const F32 &decalSize = mSELDecal->mSize;
 520      Point3F boxSize( decalSize, decalSize, decalSize );
 521
 522      MatrixF worldMat( true );
 523      mSELDecal->getWorldMatrix( &worldMat, true );   
 524
 525      drawUtil->drawObjectBox( desc, boxSize, mSELDecal->mPosition, worldMat, ColorI( 255, 255, 255, 255 ) );
 526   }
 527
 528   if ( mHLDecal )
 529   {
 530      mHLEdgeVerts.clear();
 531      if ( gDecalManager->clipDecal( mHLDecal, &mHLEdgeVerts ) )
 532         _renderDecalEdge( mHLEdgeVerts, ColorI( 255, 255, 255, 255 ) );
 533
 534      const F32 &decalSize = mHLDecal->mSize;
 535      Point3F boxSize( decalSize, decalSize, decalSize );
 536
 537      MatrixF worldMat( true );
 538      mHLDecal->getWorldMatrix( &worldMat, true );  
 539
 540      drawUtil->drawObjectBox( desc, boxSize, mHLDecal->mPosition, worldMat, ColorI( 255, 255, 255, 255 ) );
 541   }
 542} 
 543
 544void GuiDecalEditorCtrl::forceRedraw( DecalInstance * decalInstance )
 545{ 
 546   // This should be redundant because the decal is already reclipped
 547   // on each frame. Also it is not possible execute rendering code like
 548   // this in response to UI events from script.
 549   /*
 550   if ( !decalInstance )
 551      return;
 552
 553   GFXDrawUtil *drawUtil = GFX->getDrawUtil();  
 554   GFXStateBlockDesc desc;
 555   desc.setBlend( true );
 556   desc.setZReadWrite( true, false );
 557
 558   Vector<Point3F> verts;
 559   verts.clear();
 560   if ( gDecalManager->clipDecal( decalInstance, &verts ) )
 561   if ( gDecalManager->clipDecal( decalInstance, &verts ) )
 562      _renderDecalEdge( verts, ColorI( 255, 255, 255, 255 ) );
 563
 564   const F32 &decalSize = decalInstance->mSize;
 565   Point3F boxSize( decalSize, decalSize, decalSize );
 566
 567   MatrixF worldMat( true );
 568   decalInstance->getWorldMatrix( &worldMat, true );   
 569
 570   drawUtil->drawObjectBox( desc, boxSize, decalInstance->mPosition, worldMat, ColorI( 255, 255, 255, 255 ) );
 571   */
 572}
 573
 574void GuiDecalEditorCtrl::_renderDecalEdge( const Vector<Point3F> &verts, const ColorI &color )
 575{
 576   U32 vertCount = verts.size();
 577
 578   GFXTransformSaver saver;
 579
 580   PrimBuild::color( color );
 581
 582   Point3F endPt( 0, 0, 0 );
 583   for ( U32 i = 0; i < vertCount; i++ )
 584   {
 585      const Point3F &vert = verts[i];
 586      if ( i + 1 < vertCount )
 587         endPt = verts[i + 1];
 588      else
 589         break;
 590
 591      PrimBuild::begin( GFXLineList, 2 );
 592
 593      PrimBuild::vertex3f( vert.x, vert.y, vert.z );
 594      PrimBuild::vertex3f( endPt.x, endPt.y, endPt.z );
 595
 596      PrimBuild::end();
 597   }
 598}
 599
 600bool GuiDecalEditorCtrl::getRayInfo( const Gui3DMouseEvent & event, RayInfo *rInfo )
 601{       
 602   Point3F startPnt = event.pos;
 603   Point3F endPnt = event.pos + event.vec * 3000.0f;
 604
 605   bool hit;         
 606         
 607   hit = gServerContainer.castRayRendered( startPnt, endPnt, STATIC_COLLISION_TYPEMASK, rInfo );    
 608   
 609   return hit;
 610}
 611
 612void GuiDecalEditorCtrl::selectDecal( DecalInstance *decalInst )
 613{
 614   // If id is zero or invalid we set the selected decal to null
 615   // which is correct.
 616   mSELDecal = decalInst;
 617
 618   if ( decalInst )
 619      setGizmoFocus( decalInst );
 620}
 621
 622void GuiDecalEditorCtrl::deleteSelectedDecal()
 623{
 624   if ( !mSELDecal )
 625      return;
 626   
 627   // Grab the mission editor undo manager.
 628   UndoManager *undoMan = NULL;
 629   if ( !Sim::findObject( "EUndoManager", undoMan ) )
 630   {
 631      Con::errorf( "GuiMeshRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
 632      return;           
 633   }
 634
 635   // Create the UndoAction.
 636   DIDeleteUndoAction *action = new DIDeleteUndoAction("Delete Decal");
 637   action->deleteDecal( *mSELDecal );
 638   
 639   action->mEditor = this;
 640   // Submit it.               
 641   undoMan->addAction( action );
 642   
 643   if ( isMethod( "onDeleteInstance" ) )
 644   {
 645      char buffer[512];
 646      dSprintf(buffer, 512, "%i", mSELDecal->mId);
 647      Con::executef( this, "onDeleteInstance", String(buffer).c_str(), mSELDecal->mDataBlock->lookupName.c_str() );
 648   }
 649
 650   gDecalManager->removeDecal( mSELDecal );
 651   mSELDecal = NULL;
 652}
 653
 654void GuiDecalEditorCtrl::deleteDecalDatablock( String lookupName )
 655{
 656   DecalData * datablock = dynamic_cast<DecalData*> ( Sim::findObject(lookupName.c_str()) );
 657   if( !datablock )
 658      return;
 659
 660   // Grab the mission editor undo manager.
 661   UndoManager *undoMan = NULL;
 662   if ( !Sim::findObject( "EUndoManager", undoMan ) )
 663   {
 664      Con::errorf( "GuiMeshRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
 665      return;           
 666   }
 667
 668   // Create the UndoAction.
 669   DBDeleteUndoAction *action = new DBDeleteUndoAction("Delete Decal Datablock");
 670   action->mEditor = this;
 671   action->mDatablockId = datablock->getId();
 672   
 673   Vector<DecalInstance*> mDecalQueue;
 674   Vector<DecalInstance *>::iterator iter;
 675   mDecalQueue.clear();
 676   const Vector<DecalSphere*> &grid = gDecalManager->getDecalDataFile()->getSphereList();
 677
 678   for ( U32 i = 0; i < grid.size(); i++ )
 679   {
 680      const DecalSphere *decalSphere = grid[i];
 681      mDecalQueue.merge( decalSphere->mItems );
 682   }
 683
 684   for ( iter = mDecalQueue.begin();iter != mDecalQueue.end();iter++ )
 685   {  
 686      if( !(*iter) )
 687         continue;
 688
 689      if( (*iter)->mDataBlock->lookupName.compare( lookupName ) == 0 )
 690      {
 691         if( (*iter)->mId != -1 )
 692         {
 693            //make sure to call onDeleteInstance as well
 694            if ( isMethod( "onDeleteInstance" ) )
 695            {
 696               char buffer[512];
 697               dSprintf(buffer, 512, "%i", (*iter)->mId);
 698               Con::executef( this, "onDeleteInstance", String(buffer).c_str(), (*iter)->mDataBlock->lookupName.c_str() );
 699            }
 700            
 701            action->deleteDecal( *(*iter) );
 702            
 703            if( mSELDecal == (*iter) )
 704               mSELDecal = NULL;
 705
 706            if( mHLDecal == (*iter) )
 707               mHLDecal = NULL;
 708         }
 709         gDecalManager->removeDecal( (*iter) );
 710      }
 711   }
 712   
 713   undoMan->addAction( action );
 714
 715   mCurrentDecalData = NULL;
 716}
 717
 718void GuiDecalEditorCtrl::retargetDecalDatablock( String dbFrom, String dbTo )
 719{
 720   DecalData * ptrFrom = dynamic_cast<DecalData*> ( Sim::findObject(dbFrom.c_str()) );
 721   DecalData * ptrTo = dynamic_cast<DecalData*> ( Sim::findObject(dbTo.c_str()) );
 722   
 723   if( !ptrFrom || !ptrTo )
 724      return;
 725   
 726   // Grab the mission editor undo manager.
 727   UndoManager *undoMan = NULL;
 728   if ( !Sim::findObject( "EUndoManager", undoMan ) )
 729   {
 730      Con::errorf( "GuiMeshRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
 731      return;           
 732   }
 733
 734   // Create the UndoAction.
 735   DBRetargetUndoAction *action = new DBRetargetUndoAction("Retarget Decal Datablock");
 736   action->mEditor = this;
 737   action->mDBFromId = ptrFrom->getId();
 738   action->mDBToId = ptrTo->getId();
 739
 740   Vector<DecalInstance*> mDecalQueue;
 741   Vector<DecalInstance *>::iterator iter;
 742   mDecalQueue.clear();
 743   const Vector<DecalSphere*> &grid = gDecalManager->getDecalDataFile()->getSphereList();
 744   for ( U32 i = 0; i < grid.size(); i++ )
 745   {
 746      const DecalSphere *decalSphere = grid[i];
 747      mDecalQueue.merge( decalSphere->mItems );
 748   }
 749
 750   for ( iter = mDecalQueue.begin();iter != mDecalQueue.end();iter++ )
 751   {  
 752      if( !(*iter) )
 753         continue;
 754
 755      if( (*iter)->mDataBlock->lookupName.compare( dbFrom ) == 0 )
 756      {
 757         if( (*iter)->mId != -1 )
 758         {
 759            action->retargetDecal((*iter));  
 760            (*iter)->mDataBlock = ptrTo;
 761            forceRedraw((*iter));
 762         }
 763      }
 764   }
 765
 766   undoMan->addAction( action );
 767}
 768
 769void GuiDecalEditorCtrl::setMode( String mode, bool sourceShortcut = false )
 770{
 771   if( mode.compare("SelectDecalMode") == 0)
 772      mGizmo->getProfile()->mode = NoneMode;
 773   else if( mode.compare("AddDecalMode") == 0)
 774      mGizmo->getProfile()->mode = NoneMode;
 775   else if( mode.compare("MoveDecalMode") == 0)
 776      mGizmo->getProfile()->mode = MoveMode;
 777   else if( mode.compare("RotateDecalMode") == 0)
 778      mGizmo->getProfile()->mode = RotateMode;
 779   else if( mode.compare("ScaleDecalMode") == 0)
 780      mGizmo->getProfile()->mode = ScaleMode;
 781   
 782   mMode = mode;
 783
 784   if( sourceShortcut )
 785      Con::executef( this, "paletteSync", mMode );
 786}
 787
 788DefineEngineMethod( GuiDecalEditorCtrl, deleteSelectedDecal, void, (), , "deleteSelectedDecal()" )
 789{
 790   object->deleteSelectedDecal();
 791}
 792
 793DefineEngineMethod( GuiDecalEditorCtrl, deleteDecalDatablock, void, ( const char * datablock ), , "deleteSelectedDecalDatablock( String datablock )" )
 794{
 795   String lookupName( datablock );
 796   if( lookupName == String::EmptyString )
 797      return;
 798   
 799   object->deleteDecalDatablock( lookupName );
 800}
 801
 802DefineEngineMethod( GuiDecalEditorCtrl, setMode, void, ( String newMode ), , "setMode( String mode )()" )
 803{
 804   object->setMode( newMode );
 805}
 806
 807DefineEngineMethod( GuiDecalEditorCtrl, getMode, const char*, (), , "getMode()" )
 808{
 809   return object->mMode;
 810}
 811
 812DefineEngineMethod( GuiDecalEditorCtrl, getDecalCount, S32, (), , "getDecalCount()" )
 813{
 814   return gDecalManager->mDecalInstanceVec.size();
 815}
 816
 817DefineEngineMethod( GuiDecalEditorCtrl, getDecalTransform, const char*, ( U32 id ), , "getDecalTransform()" )
 818{
 819   DecalInstance *decalInstance = gDecalManager->mDecalInstanceVec[id];
 820
 821   if( decalInstance == NULL )
 822      return "";
 823
 824   static const U32 bufSize = 256;
 825   char* returnBuffer = Con::getReturnBuffer(bufSize);
 826   returnBuffer[0] = 0;
 827
 828   if ( decalInstance )
 829   {
 830      dSprintf(returnBuffer, bufSize, "%f %f %f %f %f %f %f",
 831         decalInstance->mPosition.x, decalInstance->mPosition.y, decalInstance->mPosition.z, 
 832         decalInstance->mTangent.x, decalInstance->mTangent.y, decalInstance->mTangent.z,
 833         decalInstance->mSize);
 834   }
 835
 836   return returnBuffer;
 837}
 838
 839DefineEngineMethod( GuiDecalEditorCtrl, getDecalLookupName, const char*, ( U32 id ), , "getDecalLookupName( S32 )()" )
 840{
 841   DecalInstance *decalInstance = gDecalManager->mDecalInstanceVec[id];
 842   if( decalInstance == NULL )
 843      return "invalid";
 844
 845   return decalInstance->mDataBlock->lookupName;
 846}
 847
 848DefineEngineMethod( GuiDecalEditorCtrl, selectDecal, void, ( U32 id ), , "selectDecal( S32 )()" )
 849{
 850   DecalInstance *decalInstance = gDecalManager->mDecalInstanceVec[id];
 851   if( decalInstance == NULL )
 852      return;
 853
 854   object->selectDecal( decalInstance );
 855}
 856
 857DefineEngineMethod( GuiDecalEditorCtrl, editDecalDetails, void, ( U32 id, Point3F pos, Point3F tan,F32 size ), , "editDecalDetails( S32 )()" )
 858{
 859   DecalInstance *decalInstance = gDecalManager->mDecalInstanceVec[id];
 860   if( decalInstance == NULL )
 861      return;
 862
 863
 864   decalInstance->mPosition = pos;
 865   decalInstance->mTangent = tan;
 866   decalInstance->mSize = size;
 867   
 868   if ( decalInstance == object->mSELDecal )
 869      object->setGizmoFocus( decalInstance );
 870
 871   object->forceRedraw( decalInstance );
 872
 873   gDecalManager->notifyDecalModified( decalInstance );
 874}
 875
 876DefineEngineMethod( GuiDecalEditorCtrl, getSelectionCount, S32, (), , "" )
 877{
 878   if ( object->mSELDecal != NULL )
 879      return 1;
 880   return 0;
 881}
 882
 883DefineEngineMethod( GuiDecalEditorCtrl, retargetDecalDatablock, void, ( const char * dbFrom, const char * dbTo ), , "" )
 884{
 885   if( String::compare( dbFrom, "" ) != 0 && String::compare( dbTo, "" ) != 0 )
 886      object->retargetDecalDatablock( dbFrom, dbTo );
 887}
 888
 889void GuiDecalEditorCtrl::setGizmoFocus( DecalInstance * decalInstance )
 890{
 891   const F32 &size = decalInstance->mSize;
 892   MatrixF worldMat( true );
 893   decalInstance->getWorldMatrix( &worldMat, true );
 894   worldMat.setPosition( Point3F( 0, 0, 0 ) );
 895   mGizmo->set( worldMat, decalInstance->mPosition, Point3F( size, size, size ) );
 896}
 897
 898//Decal Instance Create Undo Actions
 899IMPLEMENT_CONOBJECT( DICreateUndoAction );
 900
 901ConsoleDocClass( DICreateUndoAction,
 902            "@brief Decal Instance Create Undo Actions\n\n"
 903            "Not intended for game development, for editors or internal use only.\n\n "
 904            "@internal");
 905
 906DICreateUndoAction::DICreateUndoAction( const UTF8* actionName )
 907   :  UndoAction( actionName ), mEditor(0), mDatablockId(0)
 908{
 909}
 910
 911DICreateUndoAction::~DICreateUndoAction()
 912{
 913}
 914
 915void DICreateUndoAction::initPersistFields()
 916{
 917   Parent::initPersistFields();
 918}
 919
 920void DICreateUndoAction::addDecal(const DecalInstance& decal)
 921{
 922   mDecalInstance = decal;
 923   mDatablockId = decal.mDataBlock->getId();
 924}
 925
 926void DICreateUndoAction::undo()
 927{
 928   Vector<DecalInstance *>::iterator iter;
 929   for(iter = gDecalManager->mDecalInstanceVec.begin();iter != gDecalManager->mDecalInstanceVec.end();iter++)
 930   {
 931      if( !(*iter) )
 932         continue;
 933      
 934      if( (*iter)->mId != mDecalInstance.mId )
 935         continue;
 936
 937      if ( mEditor->isMethod( "onDeleteInstance" ) )
 938      {
 939         char buffer[512];
 940         dSprintf(buffer, 512, "%i", (*iter)->mId);
 941         Con::executef( mEditor, "onDeleteInstance", String(buffer).c_str(), (*iter)->mDataBlock->lookupName.c_str() );
 942      }
 943      
 944      // Decal manager handles clearing the vector if the decal contains a valid id
 945      if( mEditor->mSELDecal == (*iter) )
 946         mEditor->mSELDecal = NULL;
 947
 948      if( mEditor->mHLDecal == (*iter) )
 949         mEditor->mHLDecal = NULL;
 950
 951      gDecalManager->removeDecal( (*iter) );
 952      break;
 953   }
 954}
 955
 956void DICreateUndoAction::redo()
 957{
 958   //Reinstate the valid datablock pointer   
 959   mDecalInstance.mDataBlock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
 960
 961   DecalInstance * decal = gDecalManager->addDecal( mDecalInstance.mPosition, 
 962      mDecalInstance.mNormal, 
 963      mDecalInstance.mTangent, 
 964      mDecalInstance.mDataBlock,
 965      ( mDecalInstance.mSize / mDecalInstance.mDataBlock->size ), 
 966      mDecalInstance.mTextureRectIdx, 
 967      mDecalInstance.mFlags );
 968   
 969   decal->mId = mDecalInstance.mId;
 970
 971   // Override the rectIdx regardless of random decision in addDecal
 972   decal->mTextureRectIdx = mDecalInstance.mTextureRectIdx;
 973   
 974   // We take care of filling in the vector space that was once there
 975   gDecalManager->mDecalInstanceVec[decal->mId] = decal;
 976
 977   if ( mEditor->isMethod( "onCreateInstance" ) )
 978   {
 979      char buffer[512];
 980      dSprintf(buffer, 512, "%i", decal->mId);
 981      Con::executef( mEditor, "onCreateInstance", buffer, decal->mDataBlock->lookupName.c_str());
 982   }
 983   mEditor->selectDecal( decal );
 984}
 985
 986//Decal Instance Delete Undo Actions
 987IMPLEMENT_CONOBJECT( DIDeleteUndoAction );
 988
 989ConsoleDocClass( DIDeleteUndoAction,
 990            "@brief Decal Instance Delete Undo Actions\n\n"
 991            "Not intended for game development, for editors or internal use only.\n\n "
 992            "@internal");
 993
 994DIDeleteUndoAction::DIDeleteUndoAction( const UTF8 *actionName )
 995   :  UndoAction( actionName ), mEditor(0), mDatablockId(0)
 996{
 997}
 998
 999DIDeleteUndoAction::~DIDeleteUndoAction()
1000{
1001}
1002
1003void DIDeleteUndoAction::initPersistFields()
1004{
1005   Parent::initPersistFields();
1006}
1007
1008void DIDeleteUndoAction::deleteDecal(const DecalInstance& decal)
1009{
1010   mDecalInstance = decal;
1011   mDatablockId = decal.mDataBlock->getId();
1012}
1013
1014void DIDeleteUndoAction::undo()
1015{
1016   //Reinstate the valid datablock pointer   
1017   mDecalInstance.mDataBlock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
1018
1019   DecalInstance * decal = gDecalManager->addDecal( mDecalInstance.mPosition, 
1020      mDecalInstance.mNormal, 
1021      mDecalInstance.mTangent, 
1022      mDecalInstance.mDataBlock,
1023      ( mDecalInstance.mSize / mDecalInstance.mDataBlock->size ), 
1024      mDecalInstance.mTextureRectIdx, 
1025      mDecalInstance.mFlags );
1026   
1027   decal->mId = mDecalInstance.mId;
1028
1029   // Override the rectIdx regardless of random decision in addDecal
1030   decal->mTextureRectIdx = mDecalInstance.mTextureRectIdx;
1031   
1032   // We take care of filling in the vector space that was once there
1033   gDecalManager->mDecalInstanceVec[decal->mId] = decal;
1034
1035   if ( mEditor->isMethod( "onCreateInstance" ) )
1036   {
1037      char buffer[512];
1038      dSprintf(buffer, 512, "%i", decal->mId);
1039      Con::executef( mEditor, "onCreateInstance", buffer, decal->mDataBlock->lookupName.c_str());
1040   }
1041   mEditor->selectDecal( decal );
1042}
1043
1044void DIDeleteUndoAction::redo()
1045{
1046   Vector<DecalInstance *>::iterator iter;
1047   for(iter = gDecalManager->mDecalInstanceVec.begin();iter != gDecalManager->mDecalInstanceVec.end();iter++)
1048   {
1049      if( !(*iter) )
1050         continue;
1051      
1052      if( (*iter)->mId != mDecalInstance.mId )
1053         continue;
1054
1055      if ( mEditor->isMethod( "onDeleteInstance" ) )
1056      {
1057         char buffer[512];
1058         dSprintf(buffer, 512, "%i", (*iter)->mId);
1059         Con::executef( mEditor, "onDeleteInstance", String(buffer).c_str(), (*iter)->mDataBlock->lookupName.c_str() );
1060      }
1061      
1062      // Decal manager handles clearing the vector if the decal contains a valid id
1063      if( mEditor->mSELDecal == (*iter) )
1064         mEditor->mSELDecal = NULL;
1065
1066      if( mEditor->mHLDecal == (*iter) )
1067         mEditor->mHLDecal = NULL;
1068
1069      gDecalManager->removeDecal( (*iter) );
1070      break;
1071   }
1072}
1073
1074//Decal Datablock Delete Undo Actions
1075IMPLEMENT_CONOBJECT( DBDeleteUndoAction );
1076
1077ConsoleDocClass( DBDeleteUndoAction,
1078            "@brief Decal Datablock Delete Undo Actions\n\n"
1079            "Not intended for game development, for editors or internal use only.\n\n "
1080            "@internal");
1081
1082DBDeleteUndoAction::DBDeleteUndoAction( const UTF8 *actionName )
1083   :  UndoAction( actionName ), mEditor(0), mDatablockId(0)
1084{
1085}
1086
1087DBDeleteUndoAction::~DBDeleteUndoAction()
1088{
1089}
1090
1091void DBDeleteUndoAction::initPersistFields()
1092{
1093   Parent::initPersistFields();
1094}
1095
1096void DBDeleteUndoAction::deleteDecal(const DecalInstance& decal)
1097{
1098   mDecalInstanceVec.increment();
1099   mDecalInstanceVec.last() = decal;
1100}
1101
1102void DBDeleteUndoAction::undo()
1103{
1104   DecalData * datablock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
1105   if ( mEditor->isMethod( "undoDeleteDecalDatablock" ) )
1106         Con::executef( mEditor, "undoDeleteDecalDatablock", datablock->lookupName.c_str());
1107
1108   // Create and restore the decal instances
1109   for ( S32 i= mDecalInstanceVec.size()-1; i >= 0; i-- )
1110   {
1111      DecalInstance vecInstance = mDecalInstanceVec[i];
1112
1113      //Reinstate the valid datablock pointer      
1114      vecInstance.mDataBlock = datablock;
1115
1116      DecalInstance * decalInstance = gDecalManager->addDecal( vecInstance.mPosition, 
1117      vecInstance.mNormal, 
1118      vecInstance.mTangent, 
1119      vecInstance.mDataBlock,
1120      ( vecInstance.mSize / vecInstance.mDataBlock->size ), 
1121      vecInstance.mTextureRectIdx, 
1122      vecInstance.mFlags );
1123   
1124      decalInstance->mId = vecInstance.mId;
1125
1126      // Override the rectIdx regardless of random decision in addDecal
1127      decalInstance->mTextureRectIdx = vecInstance.mTextureRectIdx;
1128   
1129      // We take care of filling in the vector space that was once there
1130      gDecalManager->mDecalInstanceVec[decalInstance->mId] = decalInstance;
1131
1132      if ( mEditor->isMethod( "onCreateInstance" ) )
1133      {
1134         char buffer[512];
1135         dSprintf(buffer, 512, "%i", decalInstance->mId);
1136         Con::executef( mEditor, "onCreateInstance", buffer, decalInstance->mDataBlock->lookupName.c_str());
1137      }
1138   }
1139   
1140}
1141
1142void DBDeleteUndoAction::redo()
1143{
1144   for ( S32 i=0; i < mDecalInstanceVec.size(); i++ )
1145   {
1146      DecalInstance vecInstance = mDecalInstanceVec[i];
1147
1148      Vector<DecalInstance *>::iterator iter;
1149      for(iter = gDecalManager->mDecalInstanceVec.begin();iter != gDecalManager->mDecalInstanceVec.end();iter++)
1150      {
1151         DecalInstance * decalInstance = (*iter);
1152         if( !decalInstance )
1153            continue;
1154         
1155         if( decalInstance->mId != vecInstance.mId )
1156            continue;
1157
1158         if ( mEditor->isMethod( "onDeleteInstance" ) )
1159         {
1160            char buffer[512];
1161            dSprintf(buffer, 512, "%i", decalInstance->mId);
1162            Con::executef( mEditor, "onDeleteInstance", String(buffer).c_str(), decalInstance->mDataBlock->lookupName.c_str() );
1163         }
1164         
1165         // Decal manager handles clearing the vector if the decal contains a valid id
1166         if( mEditor->mSELDecal == decalInstance )
1167            mEditor->mSELDecal = NULL;
1168
1169         if( mEditor->mHLDecal == decalInstance )
1170            mEditor->mHLDecal = NULL;
1171
1172         gDecalManager->removeDecal( decalInstance );
1173         break;
1174      }
1175   }
1176   
1177   DecalData * datablock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
1178   if ( mEditor->isMethod( "redoDeleteDecalDatablock" ) )
1179      Con::executef( mEditor, "redoDeleteDecalDatablock", datablock->lookupName.c_str());
1180}
1181
1182//------------------------------
1183//Decal Datablock Retarget Undo Actions
1184IMPLEMENT_CONOBJECT( DBRetargetUndoAction );
1185
1186ConsoleDocClass( DBRetargetUndoAction,
1187            "@brief Decal Datablock Retarget Undo Actions\n\n"
1188            "Not intended for game development, for editors or internal use only.\n\n "
1189            "@internal");
1190
1191DBRetargetUndoAction::DBRetargetUndoAction( const UTF8 *actionName )
1192   :  UndoAction( actionName ), mEditor(0), mDBFromId(0), mDBToId(0)
1193{
1194}
1195
1196DBRetargetUndoAction::~DBRetargetUndoAction()
1197{
1198}
1199
1200void DBRetargetUndoAction::initPersistFields()
1201{
1202   Parent::initPersistFields();
1203}
1204
1205void DBRetargetUndoAction::retargetDecal( DecalInstance* decal )
1206{
1207   mDecalInstanceVec.increment();
1208   mDecalInstanceVec.last() = decal;
1209}
1210
1211void DBRetargetUndoAction::undo()
1212{
1213   DecalData * ptrFrom = dynamic_cast<DecalData*> ( Sim::findObject(mDBFromId) );
1214   
1215   if( !ptrFrom )
1216      return;
1217
1218   Vector<DecalInstance *>::iterator iter;
1219   for(iter = mDecalInstanceVec.begin();iter != mDecalInstanceVec.end();iter++)
1220   {
1221      (*iter)->mDataBlock = ptrFrom;
1222      mEditor->forceRedraw((*iter));
1223   }
1224   if ( mEditor->isMethod( "rebuildInstanceTree" ) )
1225         Con::executef( mEditor, "rebuildInstanceTree" );
1226}
1227
1228void DBRetargetUndoAction::redo()
1229{
1230   DecalData * ptrTo = dynamic_cast<DecalData*> ( Sim::findObject(mDBToId) );
1231   
1232   if( !ptrTo )
1233      return;
1234
1235   Vector<DecalInstance *>::iterator iter;
1236   for(iter = mDecalInstanceVec.begin();iter != mDecalInstanceVec.end();iter++)
1237   {
1238      (*iter)->mDataBlock = ptrTo;
1239      mEditor->forceRedraw((*iter));
1240   }
1241   
1242   if ( mEditor->isMethod( "rebuildInstanceTree" ) )
1243      Con::executef( mEditor, "rebuildInstanceTree" );
1244}
1245#endif
1246