guiDecalEditorCtrl.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  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. docsURL;
  69. addField( "currentDecalData", TYPEID< DecalData >(), Offset( mCurrentDecalData, GuiDecalEditorCtrl ) );
  70. Parent::initPersistFields();
  71. }
  72. void GuiDecalEditorCtrl::consoleInit()
  73. {
  74. Con::addVariable( "$DecalEditor::renderPixelSize", TypeBool, &smRenderDecalPixelSize,
  75. "Set true to render the pixel size as on overlay on the selected decal instance. "
  76. "This is the value used to fade distant decals and is intended to help the user adjust "
  77. "the values of DecalData::pixelSizeStartFade and pixelSizeEndFade.\n\n"
  78. "@internal" );
  79. Parent::consoleInit();
  80. }
  81. void GuiDecalEditorCtrl::onEditorDisable()
  82. {
  83. // Tools are not deleted/recreated between missions, but decals instances
  84. // ARE. So we must release any references.
  85. mSELDecal = NULL;
  86. mHLDecal = NULL;
  87. }
  88. bool GuiDecalEditorCtrl::onWake()
  89. {
  90. if ( !Parent::onWake() )
  91. return false;
  92. return true;
  93. }
  94. void GuiDecalEditorCtrl::onSleep()
  95. {
  96. Parent::onSleep();
  97. }
  98. void GuiDecalEditorCtrl::get3DCursor( GuiCursor *&cursor,
  99. bool &visible,
  100. const Gui3DMouseEvent &event_ )
  101. {
  102. cursor = NULL;
  103. visible = false;
  104. GuiCanvas *root = getRoot();
  105. if ( !root )
  106. return;
  107. S32 currCursor = PlatformCursorController::curArrow;
  108. if ( root->mCursorChanged == currCursor )
  109. return;
  110. PlatformWindow *window = root->getPlatformWindow();
  111. PlatformCursorController *controller = window->getCursorController();
  112. // We've already changed the cursor,
  113. // so set it back before we change it again.
  114. if( root->mCursorChanged != -1)
  115. controller->popCursor();
  116. // Now change the cursor shape
  117. controller->pushCursor(currCursor);
  118. root->mCursorChanged = currCursor;
  119. }
  120. void GuiDecalEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
  121. {
  122. mPerformedDragCopy = false;
  123. if ( !isFirstResponder() )
  124. setFirstResponder();
  125. bool dblClick = ( event.mouseClickCount > 1 );
  126. // Gather selected decal information
  127. RayInfo ri;
  128. bool hit = getRayInfo( event, &ri );
  129. Point3F start = event.pos;
  130. Point3F end = start + event.vec * 3000.0f; // use visible distance here??
  131. DecalInstance *pDecal = gDecalManager->raycast( start, end );
  132. if( mMode.compare("AddDecalMode") != 0 )
  133. {
  134. if ( mSELDecal )
  135. {
  136. // If our click hit the gizmo we are done.
  137. if ( mGizmo->getSelection() != Gizmo::None )
  138. {
  139. mGizmo->on3DMouseDown( event );
  140. char returnBuffer[256];
  141. dSprintf(returnBuffer, sizeof(returnBuffer), "%f %f %f %f %f %f %f",
  142. mSELDecal->mPosition.x, mSELDecal->mPosition.y, mSELDecal->mPosition.z,
  143. mSELDecal->mTangent.x, mSELDecal->mTangent.y, mSELDecal->mTangent.z,
  144. mSELDecal->mSize);
  145. Con::executef( this, "prepGizmoTransform", Con::getIntArg(mSELDecal->mId), returnBuffer );
  146. return;
  147. }
  148. }
  149. if ( mHLDecal && pDecal == mHLDecal )
  150. {
  151. mHLDecal = NULL;
  152. selectDecal( pDecal );
  153. if ( isMethod( "onSelectInstance" ) )
  154. {
  155. char idBuf[512];
  156. dSprintf(idBuf, 512, "%i", pDecal->mId);
  157. Con::executef( this, "onSelectInstance", String(idBuf).c_str(), pDecal->mDataBlock->lookupName.c_str() );
  158. }
  159. return;
  160. }
  161. else if ( hit && !pDecal)
  162. {
  163. if ( dblClick )
  164. setMode( String("AddDecalMode"), true );
  165. return;
  166. }
  167. }
  168. else
  169. {
  170. // If we accidently hit a decal, then bail(probably an accident). If the use hits the decal twice,
  171. // then boot them into selection mode and select the decal.
  172. if ( mHLDecal && pDecal == mHLDecal )
  173. {
  174. if ( dblClick )
  175. {
  176. mHLDecal = NULL;
  177. selectDecal( pDecal );
  178. if ( isMethod( "onSelectInstance" ) )
  179. {
  180. char idBuf[512];
  181. dSprintf(idBuf, 512, "%i", pDecal->mId);
  182. Con::executef( this, "onSelectInstance", String(idBuf).c_str(), pDecal->mDataBlock->lookupName.c_str() );
  183. }
  184. setMode( String("SelectDecalMode"), true );
  185. }
  186. return;
  187. }
  188. if ( hit && mCurrentDecalData ) // Create a new decal...
  189. {
  190. U8 flags = PermanentDecal | SaveDecal;
  191. DecalInstance *decalInst = gDecalManager->addDecal( ri.point, ri.normal, 0.0f, mCurrentDecalData, 1.0f, -1, flags );
  192. if ( decalInst )
  193. {
  194. // Give the decal an id
  195. decalInst->mId = gDecalManager->mDecalInstanceVec.size();
  196. gDecalManager->mDecalInstanceVec.push_back(decalInst);
  197. selectDecal( decalInst );
  198. // Grab the mission editor undo manager.
  199. UndoManager *undoMan = NULL;
  200. if ( !Sim::findObject( "EUndoManager", undoMan ) )
  201. {
  202. Con::errorf( "GuiMeshRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
  203. return;
  204. }
  205. // Create the UndoAction.
  206. DICreateUndoAction *action = new DICreateUndoAction("Create Decal");
  207. action->addDecal( *decalInst );
  208. action->mEditor = this;
  209. // Submit it.
  210. undoMan->addAction( action );
  211. if ( isMethod( "onCreateInstance" ) )
  212. {
  213. char buffer[512];
  214. dSprintf(buffer, 512, "%i", decalInst->mId);
  215. Con::executef( this, "onCreateInstance", buffer, decalInst->mDataBlock->lookupName.c_str());
  216. }
  217. }
  218. return;
  219. }
  220. }
  221. if ( !mSELDecal )
  222. return;
  223. }
  224. void GuiDecalEditorCtrl::on3DRightMouseDown(const Gui3DMouseEvent & event)
  225. {
  226. //mIsPanning = true;
  227. //mGizmo->on3DRightMouseDown( event );
  228. }
  229. void GuiDecalEditorCtrl::on3DRightMouseUp(const Gui3DMouseEvent & event)
  230. {
  231. //mIsPanning = false;
  232. // mGizmo->on3DRightMouseUp( event );
  233. }
  234. void GuiDecalEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
  235. {
  236. if ( mSELDecal )
  237. {
  238. if ( mGizmo->isDirty() )
  239. {
  240. char returnBuffer[256];
  241. dSprintf(returnBuffer, sizeof(returnBuffer), "%f %f %f %f %f %f %f",
  242. mSELDecal->mPosition.x, mSELDecal->mPosition.y, mSELDecal->mPosition.z,
  243. mSELDecal->mTangent.x, mSELDecal->mTangent.y, mSELDecal->mTangent.z,
  244. mSELDecal->mSize);
  245. Con::executef( this, "completeGizmoTransform", Con::getIntArg(mSELDecal->mId), returnBuffer );
  246. mGizmo->markClean();
  247. }
  248. mGizmo->on3DMouseUp( event );
  249. }
  250. }
  251. void GuiDecalEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
  252. {
  253. if ( mSELDecal )
  254. mGizmo->on3DMouseMove( event );
  255. RayInfo ri;
  256. if ( !getRayInfo( event, &ri ) )
  257. return;
  258. Point3F start = event.pos;
  259. Point3F end = start + event.vec * 3000.0f; // use visible distance here??
  260. DecalInstance *pDecal = gDecalManager->raycast( start, end );
  261. if ( pDecal && pDecal != mSELDecal )
  262. mHLDecal = pDecal;
  263. else if ( !pDecal )
  264. mHLDecal = NULL;
  265. }
  266. void GuiDecalEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
  267. {
  268. if ( !mSELDecal )
  269. return;
  270. // Doing a drag copy of the decal?
  271. if ( event.modifier & SI_SHIFT && !mPerformedDragCopy )
  272. {
  273. mPerformedDragCopy = true;
  274. DecalInstance *newDecal = gDecalManager->addDecal( mSELDecal->mPosition,
  275. mSELDecal->mNormal,
  276. 0.0f,
  277. mSELDecal->mDataBlock,
  278. 1.0f,
  279. -1,
  280. PermanentDecal | SaveDecal );
  281. newDecal->mTangent = mSELDecal->mTangent;
  282. newDecal->mSize = mSELDecal->mSize;
  283. newDecal->mTextureRectIdx = mSELDecal->mTextureRectIdx;
  284. // TODO: This is crazy... we should move this sort of tracking
  285. // inside of the decal manager... IdDecal flag maybe or just a
  286. // byproduct of PermanentDecal?
  287. //
  288. newDecal->mId = gDecalManager->mDecalInstanceVec.size();
  289. gDecalManager->mDecalInstanceVec.push_back( newDecal );
  290. selectDecal( newDecal );
  291. // Grab the mission editor undo manager.
  292. UndoManager *undoMan = NULL;
  293. if ( Sim::findObject( "EUndoManager", undoMan ) )
  294. {
  295. // Create the UndoAction.
  296. DICreateUndoAction *action = new DICreateUndoAction("Create Decal");
  297. action->addDecal( *mSELDecal );
  298. action->mEditor = this;
  299. undoMan->addAction( action );
  300. if ( isMethod( "onCreateInstance" ) )
  301. {
  302. char buffer[512];
  303. dSprintf( buffer, 512, "%i", mSELDecal->mId );
  304. Con::executef( this, "onCreateInstance", buffer, mSELDecal->mDataBlock->lookupName.c_str());
  305. }
  306. }
  307. }
  308. // Update the Gizmo.
  309. if (mGizmo->getSelection() != Gizmo::None)
  310. {
  311. mGizmo->on3DMouseDragged( event );
  312. // Pull out the Gizmo transform
  313. // and position.
  314. const MatrixF &gizmoMat = mGizmo->getTransform();
  315. const Point3F &gizmoPos = gizmoMat.getPosition();
  316. // Get the new projection vector.
  317. VectorF upVec, rightVec;
  318. gizmoMat.getColumn( 0, &rightVec );
  319. gizmoMat.getColumn( 2, &upVec );
  320. const Point3F &scale = mGizmo->getScale();
  321. // Assign the appropriate changed value back to the decal.
  322. if ( mGizmo->getMode() == ScaleMode )
  323. {
  324. // Save old size.
  325. const F32 oldSize = mSELDecal->mSize;
  326. // Set new size.
  327. mSELDecal->mSize = ( scale.x + scale.y ) * 0.5f;
  328. // See if the decal properly clips/projects at this size. If not,
  329. // stick to the old size.
  330. mSELEdgeVerts.clear();
  331. if ( !gDecalManager->clipDecal( mSELDecal, &mSELEdgeVerts ) )
  332. mSELDecal->mSize = oldSize;
  333. }
  334. else if ( mGizmo->getMode() == MoveMode )
  335. mSELDecal->mPosition = gizmoPos;
  336. else if ( mGizmo->getMode() == RotateMode )
  337. {
  338. mSELDecal->mNormal = upVec;
  339. mSELDecal->mTangent = rightVec;
  340. }
  341. gDecalManager->notifyDecalModified( mSELDecal );
  342. Con::executef( this, "syncNodeDetails" );
  343. }
  344. }
  345. void GuiDecalEditorCtrl::on3DMouseEnter(const Gui3DMouseEvent & event)
  346. {
  347. // nothing to do
  348. }
  349. void GuiDecalEditorCtrl::on3DMouseLeave(const Gui3DMouseEvent & event)
  350. {
  351. // nothing to do
  352. }
  353. void GuiDecalEditorCtrl::updateGuiInfo()
  354. {
  355. // nothing to do
  356. }
  357. void GuiDecalEditorCtrl::onRender( Point2I offset, const RectI &updateRect )
  358. {
  359. Parent::onRender( offset, updateRect );
  360. }
  361. void GuiDecalEditorCtrl::renderGui( Point2I offset, const RectI &updateRect )
  362. {
  363. Parent::renderGui( offset, updateRect );
  364. PROFILE_SCOPE( GuiDecalEditorCtrl_renderGui );
  365. // Show the pixelSize of the selected decal as a text overlay.
  366. if ( smRenderDecalPixelSize && mSELDecal != NULL )
  367. {
  368. const F32 pixelSize = mSELDecal->calcPixelSize( mSaveViewport.extent.y, mLastCameraQuery.cameraMatrix.getPosition(), mSaveWorldToScreenScale.y );
  369. // Find position onscreen to render the text.
  370. Point3F screenPos;
  371. bool onScreen = project( mSELDecal->mPosition, &screenPos );
  372. if ( onScreen )
  373. {
  374. // It is extremely annoying to require the GuiProfile to have a font
  375. // or to create one within the decal editor for only this single use,
  376. // so we instead rely on the fact that we already have a Gizmo, that
  377. // all Gizmo's have a GizmoProfile, and that GizmoProfile has a font.
  378. GFont *font = mGizmo->getProfile()->font;
  379. // Might as well use some colors defined in GizmoProfile too instead
  380. // of just hardcoding it here.
  381. const ColorI bgColor = mGizmo->getProfile()->inActiveColor;
  382. const ColorI textColor = mGizmo->getProfile()->activeColor;
  383. // Note: This mostly mirrors the way WorldEditor renders popupText for
  384. // the gizmo during a drag operation, consider unifying this into a utility method.
  385. char buf[256];
  386. dSprintf( buf, 256, "%0.3f", pixelSize );
  387. const U32 width = font->getStrWidth((const UTF8 *)buf);;
  388. const Point2I posi( (U32)screenPos.x, (U32)screenPos.y + 12 );
  389. const Point2I minPt(posi.x - width / 2 - 2, posi.y - 1);
  390. const Point2I maxPt(posi.x + width / 2 + 2, posi.y + font->getHeight() + 1);
  391. GFXDrawUtil *drawer = GFX->getDrawUtil();
  392. drawer->drawRectFill( minPt, maxPt, bgColor );
  393. GFX->getDrawUtil()->setBitmapModulation( textColor );
  394. GFX->getDrawUtil()->drawText( mProfile->mFont, Point2I( posi.x - width / 2, posi.y ), buf );
  395. }
  396. }
  397. }
  398. void GuiDecalEditorCtrl::renderScene(const RectI & updateRect)
  399. {
  400. PROFILE_SCOPE( GuiDecalEditorCtrl_renderScene );
  401. GFXTransformSaver saver;
  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. DefineEngineMethod( GuiDecalEditorCtrl, deleteSelectedDecal, void, (), , "deleteSelectedDecal()" )
  632. {
  633. object->deleteSelectedDecal();
  634. }
  635. DefineEngineMethod( 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. DefineEngineMethod( GuiDecalEditorCtrl, setMode, void, ( String newMode ), , "setMode( String mode )()" )
  643. {
  644. object->setMode( newMode );
  645. }
  646. DefineEngineMethod( GuiDecalEditorCtrl, getMode, const char*, (), , "getMode()" )
  647. {
  648. return object->mMode;
  649. }
  650. DefineEngineMethod( GuiDecalEditorCtrl, getDecalCount, S32, (), , "getDecalCount()" )
  651. {
  652. return gDecalManager->mDecalInstanceVec.size();
  653. }
  654. DefineEngineMethod( 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. DefineEngineMethod( 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. DefineEngineMethod( 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. DefineEngineMethod( 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. DefineEngineMethod( GuiDecalEditorCtrl, getSelectionCount, S32, (), , "" )
  699. {
  700. if ( object->mSELDecal != NULL )
  701. return 1;
  702. return 0;
  703. }
  704. DefineEngineMethod( GuiDecalEditorCtrl, retargetDecalDatablock, void, ( const char * dbFrom, const char * dbTo ), , "" )
  705. {
  706. if( String::compare( dbFrom, "" ) != 0 && String::compare( 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. docsURL;
  733. Parent::initPersistFields();
  734. }
  735. void DICreateUndoAction::addDecal(const DecalInstance& decal)
  736. {
  737. mDecalInstance = decal;
  738. mDatablockId = decal.mDataBlock->getId();
  739. }
  740. void DICreateUndoAction::undo()
  741. {
  742. Vector<DecalInstance *>::iterator iter;
  743. for(iter = gDecalManager->mDecalInstanceVec.begin();iter != gDecalManager->mDecalInstanceVec.end();iter++)
  744. {
  745. if( !(*iter) )
  746. continue;
  747. if( (*iter)->mId != mDecalInstance.mId )
  748. continue;
  749. if ( mEditor->isMethod( "onDeleteInstance" ) )
  750. {
  751. char buffer[512];
  752. dSprintf(buffer, 512, "%i", (*iter)->mId);
  753. Con::executef( mEditor, "onDeleteInstance", String(buffer).c_str(), (*iter)->mDataBlock->lookupName.c_str() );
  754. }
  755. // Decal manager handles clearing the vector if the decal contains a valid id
  756. if( mEditor->mSELDecal == (*iter) )
  757. mEditor->mSELDecal = NULL;
  758. if( mEditor->mHLDecal == (*iter) )
  759. mEditor->mHLDecal = NULL;
  760. gDecalManager->removeDecal( (*iter) );
  761. break;
  762. }
  763. }
  764. void DICreateUndoAction::redo()
  765. {
  766. //Reinstate the valid datablock pointer
  767. mDecalInstance.mDataBlock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
  768. DecalInstance * decal = gDecalManager->addDecal( mDecalInstance.mPosition,
  769. mDecalInstance.mNormal,
  770. mDecalInstance.mTangent,
  771. mDecalInstance.mDataBlock,
  772. ( mDecalInstance.mSize / mDecalInstance.mDataBlock->size ),
  773. mDecalInstance.mTextureRectIdx,
  774. mDecalInstance.mFlags );
  775. decal->mId = mDecalInstance.mId;
  776. // Override the rectIdx regardless of random decision in addDecal
  777. decal->mTextureRectIdx = mDecalInstance.mTextureRectIdx;
  778. // We take care of filling in the vector space that was once there
  779. gDecalManager->mDecalInstanceVec[decal->mId] = decal;
  780. if ( mEditor->isMethod( "onCreateInstance" ) )
  781. {
  782. char buffer[512];
  783. dSprintf(buffer, 512, "%i", decal->mId);
  784. Con::executef( mEditor, "onCreateInstance", buffer, decal->mDataBlock->lookupName.c_str());
  785. }
  786. mEditor->selectDecal( decal );
  787. }
  788. //Decal Instance Delete Undo Actions
  789. IMPLEMENT_CONOBJECT( DIDeleteUndoAction );
  790. ConsoleDocClass( DIDeleteUndoAction,
  791. "@brief Decal Instance Delete Undo Actions\n\n"
  792. "Not intended for game development, for editors or internal use only.\n\n "
  793. "@internal");
  794. DIDeleteUndoAction::DIDeleteUndoAction( const UTF8 *actionName )
  795. : UndoAction( actionName ), mEditor(0), mDatablockId(0)
  796. {
  797. }
  798. DIDeleteUndoAction::~DIDeleteUndoAction()
  799. {
  800. }
  801. void DIDeleteUndoAction::initPersistFields()
  802. {
  803. docsURL;
  804. Parent::initPersistFields();
  805. }
  806. void DIDeleteUndoAction::deleteDecal(const DecalInstance& decal)
  807. {
  808. mDecalInstance = decal;
  809. mDatablockId = decal.mDataBlock->getId();
  810. }
  811. void DIDeleteUndoAction::undo()
  812. {
  813. //Reinstate the valid datablock pointer
  814. mDecalInstance.mDataBlock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
  815. DecalInstance * decal = gDecalManager->addDecal( mDecalInstance.mPosition,
  816. mDecalInstance.mNormal,
  817. mDecalInstance.mTangent,
  818. mDecalInstance.mDataBlock,
  819. ( mDecalInstance.mSize / mDecalInstance.mDataBlock->size ),
  820. mDecalInstance.mTextureRectIdx,
  821. mDecalInstance.mFlags );
  822. decal->mId = mDecalInstance.mId;
  823. // Override the rectIdx regardless of random decision in addDecal
  824. decal->mTextureRectIdx = mDecalInstance.mTextureRectIdx;
  825. // We take care of filling in the vector space that was once there
  826. gDecalManager->mDecalInstanceVec[decal->mId] = decal;
  827. if ( mEditor->isMethod( "onCreateInstance" ) )
  828. {
  829. char buffer[512];
  830. dSprintf(buffer, 512, "%i", decal->mId);
  831. Con::executef( mEditor, "onCreateInstance", buffer, decal->mDataBlock->lookupName.c_str());
  832. }
  833. mEditor->selectDecal( decal );
  834. }
  835. void DIDeleteUndoAction::redo()
  836. {
  837. Vector<DecalInstance *>::iterator iter;
  838. for(iter = gDecalManager->mDecalInstanceVec.begin();iter != gDecalManager->mDecalInstanceVec.end();iter++)
  839. {
  840. if( !(*iter) )
  841. continue;
  842. if( (*iter)->mId != mDecalInstance.mId )
  843. continue;
  844. if ( mEditor->isMethod( "onDeleteInstance" ) )
  845. {
  846. char buffer[512];
  847. dSprintf(buffer, 512, "%i", (*iter)->mId);
  848. Con::executef( mEditor, "onDeleteInstance", String(buffer).c_str(), (*iter)->mDataBlock->lookupName.c_str() );
  849. }
  850. // Decal manager handles clearing the vector if the decal contains a valid id
  851. if( mEditor->mSELDecal == (*iter) )
  852. mEditor->mSELDecal = NULL;
  853. if( mEditor->mHLDecal == (*iter) )
  854. mEditor->mHLDecal = NULL;
  855. gDecalManager->removeDecal( (*iter) );
  856. break;
  857. }
  858. }
  859. //Decal Datablock Delete Undo Actions
  860. IMPLEMENT_CONOBJECT( DBDeleteUndoAction );
  861. ConsoleDocClass( DBDeleteUndoAction,
  862. "@brief Decal Datablock Delete Undo Actions\n\n"
  863. "Not intended for game development, for editors or internal use only.\n\n "
  864. "@internal");
  865. DBDeleteUndoAction::DBDeleteUndoAction( const UTF8 *actionName )
  866. : UndoAction( actionName ), mEditor(0), mDatablockId(0)
  867. {
  868. }
  869. DBDeleteUndoAction::~DBDeleteUndoAction()
  870. {
  871. }
  872. void DBDeleteUndoAction::initPersistFields()
  873. {
  874. docsURL;
  875. Parent::initPersistFields();
  876. }
  877. void DBDeleteUndoAction::deleteDecal(const DecalInstance& decal)
  878. {
  879. mDecalInstanceVec.increment();
  880. mDecalInstanceVec.last() = decal;
  881. }
  882. void DBDeleteUndoAction::undo()
  883. {
  884. DecalData * datablock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
  885. if ( mEditor->isMethod( "undoDeleteDecalDatablock" ) )
  886. Con::executef( mEditor, "undoDeleteDecalDatablock", datablock->lookupName.c_str());
  887. // Create and restore the decal instances
  888. for ( S32 i= mDecalInstanceVec.size()-1; i >= 0; i-- )
  889. {
  890. DecalInstance vecInstance = mDecalInstanceVec[i];
  891. //Reinstate the valid datablock pointer
  892. vecInstance.mDataBlock = datablock;
  893. DecalInstance * decalInstance = gDecalManager->addDecal( vecInstance.mPosition,
  894. vecInstance.mNormal,
  895. vecInstance.mTangent,
  896. vecInstance.mDataBlock,
  897. ( vecInstance.mSize / vecInstance.mDataBlock->size ),
  898. vecInstance.mTextureRectIdx,
  899. vecInstance.mFlags );
  900. decalInstance->mId = vecInstance.mId;
  901. // Override the rectIdx regardless of random decision in addDecal
  902. decalInstance->mTextureRectIdx = vecInstance.mTextureRectIdx;
  903. // We take care of filling in the vector space that was once there
  904. gDecalManager->mDecalInstanceVec[decalInstance->mId] = decalInstance;
  905. if ( mEditor->isMethod( "onCreateInstance" ) )
  906. {
  907. char buffer[512];
  908. dSprintf(buffer, 512, "%i", decalInstance->mId);
  909. Con::executef( mEditor, "onCreateInstance", buffer, decalInstance->mDataBlock->lookupName.c_str());
  910. }
  911. }
  912. }
  913. void DBDeleteUndoAction::redo()
  914. {
  915. for ( S32 i=0; i < mDecalInstanceVec.size(); i++ )
  916. {
  917. DecalInstance vecInstance = mDecalInstanceVec[i];
  918. Vector<DecalInstance *>::iterator iter;
  919. for(iter = gDecalManager->mDecalInstanceVec.begin();iter != gDecalManager->mDecalInstanceVec.end();iter++)
  920. {
  921. DecalInstance * decalInstance = (*iter);
  922. if( !decalInstance )
  923. continue;
  924. if( decalInstance->mId != vecInstance.mId )
  925. continue;
  926. if ( mEditor->isMethod( "onDeleteInstance" ) )
  927. {
  928. char buffer[512];
  929. dSprintf(buffer, 512, "%i", decalInstance->mId);
  930. Con::executef( mEditor, "onDeleteInstance", String(buffer).c_str(), decalInstance->mDataBlock->lookupName.c_str() );
  931. }
  932. // Decal manager handles clearing the vector if the decal contains a valid id
  933. if( mEditor->mSELDecal == decalInstance )
  934. mEditor->mSELDecal = NULL;
  935. if( mEditor->mHLDecal == decalInstance )
  936. mEditor->mHLDecal = NULL;
  937. gDecalManager->removeDecal( decalInstance );
  938. break;
  939. }
  940. }
  941. DecalData * datablock = dynamic_cast<DecalData *>( Sim::findObject( mDatablockId ) );
  942. if ( mEditor->isMethod( "redoDeleteDecalDatablock" ) )
  943. Con::executef( mEditor, "redoDeleteDecalDatablock", datablock->lookupName.c_str());
  944. }
  945. //------------------------------
  946. //Decal Datablock Retarget Undo Actions
  947. IMPLEMENT_CONOBJECT( DBRetargetUndoAction );
  948. ConsoleDocClass( DBRetargetUndoAction,
  949. "@brief Decal Datablock Retarget Undo Actions\n\n"
  950. "Not intended for game development, for editors or internal use only.\n\n "
  951. "@internal");
  952. DBRetargetUndoAction::DBRetargetUndoAction( const UTF8 *actionName )
  953. : UndoAction( actionName ), mEditor(0), mDBFromId(0), mDBToId(0)
  954. {
  955. }
  956. DBRetargetUndoAction::~DBRetargetUndoAction()
  957. {
  958. }
  959. void DBRetargetUndoAction::initPersistFields()
  960. {
  961. docsURL;
  962. Parent::initPersistFields();
  963. }
  964. void DBRetargetUndoAction::retargetDecal( DecalInstance* decal )
  965. {
  966. mDecalInstanceVec.increment();
  967. mDecalInstanceVec.last() = decal;
  968. }
  969. void DBRetargetUndoAction::undo()
  970. {
  971. DecalData * ptrFrom = dynamic_cast<DecalData*> ( Sim::findObject(mDBFromId) );
  972. if( !ptrFrom )
  973. return;
  974. Vector<DecalInstance *>::iterator iter;
  975. for(iter = mDecalInstanceVec.begin();iter != mDecalInstanceVec.end();iter++)
  976. {
  977. (*iter)->mDataBlock = ptrFrom;
  978. mEditor->forceRedraw((*iter));
  979. }
  980. if ( mEditor->isMethod( "rebuildInstanceTree" ) )
  981. Con::executef( mEditor, "rebuildInstanceTree" );
  982. }
  983. void DBRetargetUndoAction::redo()
  984. {
  985. DecalData * ptrTo = dynamic_cast<DecalData*> ( Sim::findObject(mDBToId) );
  986. if( !ptrTo )
  987. return;
  988. Vector<DecalInstance *>::iterator iter;
  989. for(iter = mDecalInstanceVec.begin();iter != mDecalInstanceVec.end();iter++)
  990. {
  991. (*iter)->mDataBlock = ptrTo;
  992. mEditor->forceRedraw((*iter));
  993. }
  994. if ( mEditor->isMethod( "rebuildInstanceTree" ) )
  995. Con::executef( mEditor, "rebuildInstanceTree" );
  996. }
  997. #endif