guiDecalEditorCtrl.cpp 35 KB

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