guiMissionArea.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  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. #include "gui/worldEditor/guiMissionArea.h"
  23. #include "console/consoleTypes.h"
  24. #include "console/engineAPI.h"
  25. #include "gfx/gfxDrawUtil.h"
  26. #include "gfx/primBuilder.h"
  27. #include "gfx/bitmap/gBitmap.h"
  28. #include "gui/3d/guiTSControl.h"
  29. #include "T3D/gameFunctions.h"
  30. #include "terrain/terrData.h"
  31. #include "gfx/gfxTransformSaver.h"
  32. #include "scene/sceneManager.h"
  33. #include "scene/sceneRenderState.h"
  34. #include "lighting/lightManager.h"
  35. #include "lighting/shadowMap/lightShadowMap.h"
  36. #include "math/mathUtils.h"
  37. #include "math/util/frustum.h"
  38. namespace {
  39. F32 round_local(F32 val)
  40. {
  41. if(val >= 0.f)
  42. {
  43. F32 floor = mFloor(val);
  44. if((val - floor) >= 0.5f)
  45. return(floor + 1.f);
  46. return(floor);
  47. }
  48. else
  49. {
  50. F32 ceil = mCeil(val);
  51. if((val - ceil) <= -0.5f)
  52. return(ceil - 1.f);
  53. return(ceil);
  54. }
  55. }
  56. }
  57. IMPLEMENT_CONOBJECT(GuiMissionAreaCtrl);
  58. ConsoleDocClass( GuiMissionAreaCtrl,
  59. "@brief Visual representation of Mission Area Editor.\n\n"
  60. "@internal"
  61. );
  62. GuiMissionAreaCtrl::GuiMissionAreaCtrl()
  63. {
  64. mHandleTextureSize = Point2I::Zero;
  65. mHandleTextureHalfSize = Point2F::Zero;
  66. mSquareBitmap = true;
  67. mMissionArea = 0;
  68. mLevelTexture = NULL;
  69. mLevelBounds = Box3F::Zero;
  70. mMissionBoundsColor.set(255,0,0);
  71. mCameraColor.set(255,0,0);
  72. mBlendStateBlock = NULL;
  73. mSolidStateBlock = NULL;
  74. mLastHitMode = Handle_None;
  75. mSavedDrag = false;
  76. mBitmap.set(256, 256, GFXFormatR8G8B8, &GFXRenderTargetProfile, "MissionAreaRenderTarget");
  77. }
  78. GuiMissionAreaCtrl::~GuiMissionAreaCtrl()
  79. {
  80. }
  81. //------------------------------------------------------------------------------
  82. void GuiMissionAreaCtrl::initPersistFields()
  83. {
  84. docsURL;
  85. addField( "squareBitmap", TypeBool, Offset(mSquareBitmap, GuiMissionAreaCtrl));
  86. INITPERSISTFIELD_IMAGEASSET(HandleBitmap, GuiMissionAreaCtrl, "Bitmap for the mission area handles.\n");
  87. addField( "missionBoundsColor", TypeColorI, Offset(mMissionBoundsColor, GuiMissionAreaCtrl));
  88. addField( "cameraColor", TypeColorI, Offset(mCameraColor, GuiMissionAreaCtrl));
  89. Parent::initPersistFields();
  90. }
  91. //------------------------------------------------------------------------------
  92. bool GuiMissionAreaCtrl::onAdd()
  93. {
  94. if(!Parent::onAdd())
  95. return(false);
  96. GFXStateBlockDesc desc;
  97. desc.setCullMode(GFXCullNone);
  98. desc.setZReadWrite(false);
  99. desc.setBlend(false, GFXBlendOne, GFXBlendZero);
  100. mSolidStateBlock = GFX->createStateBlock( desc );
  101. desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  102. mBlendStateBlock = GFX->createStateBlock( desc );
  103. if (!mHandleBitmapAsset.isNull())
  104. {
  105. mHandleTextureSize = Point2I(getHandleBitmap()->getWidth(), getHandleBitmap()->getHeight());
  106. mHandleTextureHalfSize = Point2F(mHandleTextureSize.x, mHandleTextureSize.y) * 0.5f;
  107. }
  108. else
  109. {
  110. mHandleTextureSize = Point2I::Zero;
  111. mHandleTextureHalfSize = Point2F::Zero;
  112. }
  113. return(true);
  114. }
  115. bool GuiMissionAreaCtrl::onWake()
  116. {
  117. if(!Parent::onWake())
  118. return(false);
  119. // make sure mission area is clamped
  120. setArea(getArea());
  121. //onUpdate();
  122. setActive(true);
  123. return(true);
  124. }
  125. void GuiMissionAreaCtrl::onSleep()
  126. {
  127. mBitmap = NULL;
  128. mMissionArea = 0;
  129. Parent::onSleep();
  130. }
  131. //------------------------------------------------------------------------------
  132. void GuiMissionAreaCtrl::onMouseUp(const GuiEvent & event)
  133. {
  134. if(!bool(mMissionArea))
  135. return;
  136. //unlock the mouse
  137. mouseUnlock();
  138. mLastMousePoint = event.mousePoint;
  139. RectI box;
  140. getScreenMissionArea(box);
  141. S32 hit = getHitHandles(event.mousePoint, box);
  142. // set the current cursor
  143. //updateCursor(hit);
  144. mLastHitMode = hit;
  145. if(mSavedDrag)
  146. {
  147. // Let the script get a chance at it.
  148. Con::executef( this, "onMissionAreaModified" );
  149. }
  150. mSavedDrag = false;
  151. }
  152. void GuiMissionAreaCtrl::onMouseDown(const GuiEvent & event)
  153. {
  154. if(!bool(mMissionArea))
  155. return;
  156. setFirstResponder();
  157. // lock mouse
  158. mouseLock();
  159. RectI box;
  160. getScreenMissionArea(box);
  161. mLastHitMode = getHitHandles(event.mousePoint, box);
  162. //if(mLastHitMode == Handle_Middle)
  163. // setCursor(GrabCursor);
  164. mLastMousePoint = event.mousePoint;
  165. }
  166. void GuiMissionAreaCtrl::onMouseMove(const GuiEvent & event)
  167. {
  168. if(!bool(mMissionArea))
  169. return;
  170. RectI box;
  171. getScreenMissionArea(box);
  172. S32 hit = getHitHandles(event.mousePoint, box);
  173. // set the current cursor...
  174. //updateCursor(hit);
  175. mLastHitMode = hit;
  176. }
  177. void GuiMissionAreaCtrl::onMouseDragged(const GuiEvent & event)
  178. {
  179. if(!bool(mMissionArea))
  180. return;
  181. if(mLastHitMode == Handle_None)
  182. return;
  183. // If we haven't already saved,
  184. // save an undo action to get back to this state,
  185. // before we make any modifications.
  186. if ( !mSavedDrag )
  187. {
  188. submitUndo( "Modify Node" );
  189. mSavedDrag = true;
  190. }
  191. RectI box;
  192. getScreenMissionArea(box);
  193. Point2I mouseDiff(event.mousePoint.x - mLastMousePoint.x,
  194. event.mousePoint.y - mLastMousePoint.y);
  195. // what we drag'n?
  196. RectI area = getArea();
  197. Point2I wp = screenDeltaToWorldDelta(mouseDiff);
  198. if (mLastHitMode == Handle_Middle)
  199. {
  200. area.point += wp;
  201. }
  202. if (mLastHitMode & Handle_Left)
  203. {
  204. if ((area.extent.x - wp.x) >= 1)
  205. {
  206. area.point.x += wp.x;
  207. area.extent.x -= wp.x;
  208. }
  209. }
  210. if (mLastHitMode & Handle_Right)
  211. {
  212. if ((area.extent.x + wp.x) >= 1)
  213. {
  214. area.extent.x += wp.x;
  215. }
  216. }
  217. if (mLastHitMode & Handle_Bottom)
  218. {
  219. if ((area.extent.y - wp.y) >= 1)
  220. {
  221. area.point.y += wp.y;
  222. area.extent.y -= wp.y;
  223. }
  224. }
  225. if (mLastHitMode & Handle_Top)
  226. {
  227. if ((area.extent.y + wp.y) >= 1)
  228. {
  229. area.extent.y += wp.y;
  230. }
  231. }
  232. setArea(area);
  233. mLastMousePoint = event.mousePoint;
  234. }
  235. void GuiMissionAreaCtrl::onMouseEnter(const GuiEvent &)
  236. {
  237. mLastHitMode = Handle_None;
  238. //setCursor(DefaultCursor);
  239. }
  240. void GuiMissionAreaCtrl::onMouseLeave(const GuiEvent &)
  241. {
  242. mLastHitMode = Handle_None;
  243. //setCursor(DefaultCursor);
  244. }
  245. //------------------------------------------------------------------------------
  246. void GuiMissionAreaCtrl::submitUndo( const UTF8 *name )
  247. {
  248. // Grab the mission editor undo manager.
  249. UndoManager *undoMan = NULL;
  250. if ( !Sim::findObject( "EUndoManager", undoMan ) )
  251. {
  252. Con::errorf( "GuiRiverEditorCtrl::submitUndo() - EUndoManager not found!" );
  253. return;
  254. }
  255. // Setup the action.
  256. GuiMissionAreaUndoAction *action = new GuiMissionAreaUndoAction( name );
  257. action->mMissionAreaEditor = this;
  258. action->mObjId = mMissionArea->getId();
  259. action->mArea = mMissionArea->getArea();
  260. undoMan->addAction( action );
  261. }
  262. //------------------------------------------------------------------------------
  263. void GuiMissionAreaCtrl::setMissionArea( MissionArea* area )
  264. {
  265. mMissionArea = area;
  266. if( mMissionArea )
  267. {
  268. setArea(getArea());
  269. }
  270. }
  271. void GuiMissionAreaCtrl::updateLevelBitmap()
  272. {
  273. if (mLevelTexture.isNull())
  274. mLevelTexture = GFX->allocRenderToTextureTarget();
  275. mLevelTexture->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
  276. mLevelTexture->attachTexture(GFXTextureTarget::Color0, mBitmap);
  277. mLevelBounds = Box3F::Zero;
  278. for (SimSetIterator iter(Sim::getRootGroup()); *iter; ++iter)
  279. {
  280. SceneObject* obj = dynamic_cast<SceneObject*>(*iter);
  281. if (!obj)
  282. continue;
  283. if (obj->isGlobalBounds())
  284. continue;
  285. // Merge bounds
  286. mLevelBounds.intersect(obj->getWorldBox());
  287. }
  288. const F32 minSize = 256.0f;
  289. // Ensure the bounding box has a minimum size and is square
  290. VectorF size = mLevelBounds.getExtents();
  291. F32 maxExtent = getMax(getMax(size.x, size.y), minSize);
  292. // Expand to make it square and centered
  293. Point3F center = mLevelBounds.getCenter();
  294. Point3F halfExtents(maxExtent * 0.5f, maxExtent * 0.5f, size.z * 0.5f);
  295. mLevelBounds.minExtents = center - halfExtents;
  296. mLevelBounds.maxExtents = center + halfExtents;
  297. GFXTransformSaver saver;
  298. // Calculate orthographic dimensions
  299. Point3F minPt = mLevelBounds.minExtents;
  300. Point3F maxPt = mLevelBounds.maxExtents;
  301. F32 orthoWidth = maxPt.x - minPt.x;
  302. F32 orthoHeight = maxPt.y - minPt.y;
  303. F32 nearPlane = 0.01f;
  304. F32 farPlane = 1000.0f;
  305. // Set orthographic projection centered around level bounds
  306. GFX->setOrtho(
  307. -orthoWidth * 0.5f, orthoWidth * 0.5f, // left/right
  308. -orthoHeight * 0.5f, orthoHeight * 0.5f, // bottom/top
  309. nearPlane, farPlane,
  310. true // flip y
  311. );
  312. GFX->pushActiveRenderTarget();
  313. // create camera matrix
  314. MatrixF lightMatrix(true);
  315. VectorF eye = mLevelBounds.getCenter();
  316. eye.z += 500.0f;
  317. lightMatrix.LookAt(eye, VectorF(0.0f, 0.0f, -1.0f), VectorF(0.0f, -1.0f, 0.0f));
  318. lightMatrix.inverse();
  319. GFX->setWorldMatrix(lightMatrix);
  320. GFX->clearTextureStateImmediate(0);
  321. GFX->setActiveRenderTarget(mLevelTexture);
  322. GFX->clear(GFXClearStencil | GFXClearTarget | GFXClearZBuffer, ColorI::BLACK, 1.0f, 0);
  323. SceneRenderState reflectRenderState
  324. (
  325. gClientSceneGraph,
  326. SPT_Reflect,
  327. SceneCameraState::fromGFX()
  328. );
  329. // We don't use a special clipping projection, but still need to initialize
  330. // this for objects like SkyBox which will use it during a reflect pass.
  331. gClientSceneGraph->setNonClipProjection(GFX->getProjectionMatrix());
  332. // render scene
  333. LIGHTMGR->registerGlobalLights(&reflectRenderState.getCullingFrustum(), false);
  334. gClientSceneGraph->renderSceneNoLights(&reflectRenderState);
  335. LIGHTMGR->unregisterAllLights();
  336. // Clean up.
  337. mLevelTexture->resolve();
  338. GFX->popActiveRenderTarget();
  339. }
  340. const RectI & GuiMissionAreaCtrl::getArea()
  341. {
  342. if( !bool(mMissionArea) )
  343. return(MissionArea::smMissionArea);
  344. return(mMissionArea->getArea());
  345. }
  346. void GuiMissionAreaCtrl::setArea(const RectI & area)
  347. {
  348. if( bool(mMissionArea) )
  349. {
  350. mMissionArea->setArea(area);
  351. mMissionArea->inspectPostApply();
  352. //onUpdate();
  353. }
  354. }
  355. //------------------------------------------------------------------------------
  356. void GuiMissionAreaCtrl::drawHandle(const Point2F & pos)
  357. {
  358. Point2F pnt(pos.x-mHandleTextureHalfSize.x, pos.y-mHandleTextureHalfSize.y);
  359. GFX->getDrawUtil()->drawBitmap(getHandleBitmap(), pnt);
  360. }
  361. void GuiMissionAreaCtrl::drawHandles(RectI & box)
  362. {
  363. F32 fillOffset = GFX->getFillConventionOffset();
  364. F32 lx = box.point.x + fillOffset, rx = box.point.x + box.extent.x + fillOffset;
  365. F32 cx = (lx + rx) * 0.5f;
  366. F32 by = box.point.y + fillOffset, ty = box.point.y + box.extent.y + fillOffset;
  367. F32 cy = (ty + by) * 0.5f;
  368. GFX->getDrawUtil()->clearBitmapModulation();
  369. drawHandle(Point2F(lx, ty));
  370. drawHandle(Point2F(lx, cy));
  371. drawHandle(Point2F(lx, by));
  372. drawHandle(Point2F(rx, ty));
  373. drawHandle(Point2F(rx, cy));
  374. drawHandle(Point2F(rx, by));
  375. drawHandle(Point2F(cx, ty));
  376. drawHandle(Point2F(cx, by));
  377. }
  378. bool GuiMissionAreaCtrl::testWithinHandle(const Point2I & testPoint, S32 handleX, S32 handleY)
  379. {
  380. S32 dx = testPoint.x - handleX;
  381. S32 dy = testPoint.y - handleY;
  382. return dx <= Handle_Pixel_Size && dx >= -Handle_Pixel_Size && dy <= Handle_Pixel_Size && dy >= -Handle_Pixel_Size;
  383. }
  384. S32 GuiMissionAreaCtrl::getHitHandles(const Point2I & mousePnt, const RectI & box)
  385. {
  386. S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
  387. S32 cx = (lx + rx) >> 1;
  388. S32 by = box.point.y, ty = box.point.y + box.extent.y - 1;
  389. S32 cy = (ty + by) >> 1;
  390. if (testWithinHandle(mousePnt, lx, ty))
  391. return Handle_Left | Handle_Top;
  392. if (testWithinHandle(mousePnt, cx, ty))
  393. return Handle_Top;
  394. if (testWithinHandle(mousePnt, rx, ty))
  395. return Handle_Right | Handle_Top;
  396. if (testWithinHandle(mousePnt, lx, by))
  397. return Handle_Left | Handle_Bottom;
  398. if (testWithinHandle(mousePnt, cx, by))
  399. return Handle_Bottom;
  400. if (testWithinHandle(mousePnt, rx, by))
  401. return Handle_Right | Handle_Bottom;
  402. if (testWithinHandle(mousePnt, lx, cy))
  403. return Handle_Left;
  404. if (testWithinHandle(mousePnt, rx, cy))
  405. return Handle_Right;
  406. if(mousePnt.x >= lx && mousePnt.x <= rx &&
  407. mousePnt.y >= ty && mousePnt.y <= by)
  408. return(Handle_Middle);
  409. return Handle_None;
  410. }
  411. //------------------------------------------------------------------------------
  412. Point2F GuiMissionAreaCtrl::worldToScreen(const Point2F & pos)
  413. {
  414. return(Point2F(mCenterPos.x + (pos.x * mScale.x), mCenterPos.y + (pos.y * mScale.y)));
  415. }
  416. Point2I GuiMissionAreaCtrl::worldToScreen(const Point2I &pos)
  417. {
  418. return(Point2I(S32(mCenterPos.x + (pos.x * mScale.x)), S32(mCenterPos.y + (pos.y * mScale.y))));
  419. }
  420. Point2F GuiMissionAreaCtrl::screenToWorld(const Point2F & pos)
  421. {
  422. return(Point2F((pos.x - mCenterPos.x) / mScale.x, (pos.y - mCenterPos.y) / mScale.y));
  423. }
  424. Point2I GuiMissionAreaCtrl::screenToWorld(const Point2I &pos)
  425. {
  426. return(Point2I(S32((pos.x - mCenterPos.x) / mScale.x), S32((pos.y - mCenterPos.y) / mScale.y)));
  427. }
  428. Point2I GuiMissionAreaCtrl::screenDeltaToWorldDelta(const Point2I &screenPoint)
  429. {
  430. return(Point2I(S32(screenPoint.x / mScale.x), S32(screenPoint.y / mScale.y)));
  431. }
  432. void GuiMissionAreaCtrl::setupScreenTransform(const Point2I& offset)
  433. {
  434. // Compute 2D size of the bounding box
  435. Point2F boxSize(mLevelBounds.len_x(), mLevelBounds.len_y());
  436. Point2F boxMin(mLevelBounds.minExtents.x, mLevelBounds.minExtents.y);
  437. Point2F boxCenter = Point2F(mLevelBounds.getCenter().x, mLevelBounds.getCenter().y);
  438. // GUI control size
  439. const Point2I& extenti = getExtent();
  440. Point2F extent((F32)extenti.x, (F32)extenti.y);
  441. // Maintain square aspect ratio if requested
  442. if (mSquareBitmap)
  443. extent.x > extent.y ? extent.x = extent.y : extent.y = extent.x;
  444. // Compute scale (how many pixels per world unit)
  445. mScale.set(extent.x / boxSize.x, -extent.y / boxSize.y, 0); // Y flipped
  446. // Instead of offsetting the center to (0,0), we want to place the box center at GUI center
  447. // So we compute the world-to-screen offset for center
  448. Point2F screenCenter((F32)offset.x + extent.x * 0.5f, (F32)offset.y + extent.y * 0.5f);
  449. Point2F worldCenterOffset = boxCenter * Point2F(mScale.x, mScale.y);
  450. // Compute the final offset that maps world center to screen center
  451. mCenterPos.set(screenCenter.x - worldCenterOffset.x,
  452. screenCenter.y - worldCenterOffset.y);
  453. }
  454. void GuiMissionAreaCtrl::getScreenMissionArea(RectI & rect)
  455. {
  456. RectI area = mMissionArea->getArea();
  457. Point2F pos = worldToScreen(Point2F(F32(area.point.x), F32(area.point.y)));
  458. Point2F end = worldToScreen(Point2F(F32(area.point.x + area.extent.x), F32(area.point.y + area.extent.y)));
  459. //
  460. rect.point.x = S32(round_local(pos.x));
  461. rect.point.y = S32(round_local(pos.y));
  462. rect.extent.x = S32(round_local(end.x - pos.x));
  463. rect.extent.y = S32(round_local(end.y - pos.y));
  464. }
  465. void GuiMissionAreaCtrl::getScreenMissionArea(RectF & rect)
  466. {
  467. RectI area = mMissionArea->getArea();
  468. Point2F pos = worldToScreen(Point2F(F32(area.point.x), F32(area.point.y)));
  469. Point2F end = worldToScreen(Point2F(F32(area.point.x + area.extent.x), F32(area.point.y + area.extent.y)));
  470. //
  471. rect.point.x = pos.x;
  472. rect.point.y = pos.y;
  473. rect.extent.x = end.x - pos.x;
  474. rect.extent.y = end.y - pos.y;
  475. }
  476. Point2I GuiMissionAreaCtrl::convertOrigin(const Point2I &pos)
  477. {
  478. // Convert screen point to our bottom left origin
  479. Point2I pnt = globalToLocalCoord(pos);
  480. const Point2I& extent = getExtent( );
  481. pnt.y = extent.y - pnt.y;
  482. Point2I pt = localToGlobalCoord(pnt);
  483. return pt;
  484. }
  485. void GuiMissionAreaCtrl::onRender(Point2I offset, const RectI & updateRect)
  486. {
  487. RectI rect(offset, getExtent());
  488. F32 fillOffset = GFX->getFillConventionOffset();
  489. setUpdate();
  490. // draw an x
  491. if(!bool(mMissionArea))
  492. {
  493. GFX->setStateBlock(mSolidStateBlock);
  494. PrimBuild::color3i( 0, 0, 0 );
  495. PrimBuild::begin( GFXLineList, 4 );
  496. PrimBuild::vertex2f( rect.point.x + fillOffset, updateRect.point.y + fillOffset );
  497. PrimBuild::vertex2f( rect.point.x + updateRect.extent.x + fillOffset, updateRect.point.y + updateRect.extent.y + fillOffset );
  498. PrimBuild::vertex2f( rect.point.x + fillOffset, updateRect.point.y + updateRect.extent.y + fillOffset );
  499. PrimBuild::vertex2f( rect.point.x + updateRect.extent.x + fillOffset, updateRect.point.y + fillOffset );
  500. PrimBuild::end();
  501. return;
  502. }
  503. //
  504. setupScreenTransform(offset);
  505. // draw the terrain
  506. if(mSquareBitmap)
  507. rect.extent.x > rect.extent.y ? rect.extent.x = rect.extent.y : rect.extent.y = rect.extent.x;
  508. GFXDrawUtil *drawer = GFX->getDrawUtil();
  509. drawer->clearBitmapModulation();
  510. drawer->drawBitmapStretch(mBitmap, rect, GFXBitmapFlip_Y, GFXTextureFilterLinear, false);
  511. GFX->setStateBlock(mSolidStateBlock);
  512. drawer->clearBitmapModulation();
  513. // draw the reference axis
  514. PrimBuild::begin( GFXLineList, 4 );
  515. PrimBuild::color3i( 255, 0, 0 );
  516. PrimBuild::vertex2f( rect.point.x + 5 + fillOffset, rect.point.y + rect.extent.y - 5 + fillOffset );
  517. PrimBuild::vertex2f( rect.point.x + 25 + fillOffset, rect.point.y + rect.extent.y - 5 + fillOffset );
  518. PrimBuild::color3i( 0, 255, 0 );
  519. PrimBuild::vertex2f( rect.point.x + 5 + fillOffset, rect.point.y + rect.extent.y - 5 + fillOffset );
  520. PrimBuild::vertex2f( rect.point.x + 5 + fillOffset, rect.point.y + rect.extent.y - 25 + fillOffset );
  521. PrimBuild::end();
  522. RectF area;
  523. getScreenMissionArea(area);
  524. // render the mission area box
  525. PrimBuild::color( mMissionBoundsColor );
  526. PrimBuild::begin( GFXLineStrip, 5 );
  527. PrimBuild::vertex2f(area.point.x + fillOffset, area.point.y + fillOffset);
  528. PrimBuild::vertex2f(area.point.x + area.extent.x + fillOffset, area.point.y + fillOffset);
  529. PrimBuild::vertex2f(area.point.x + area.extent.x + fillOffset, area.point.y + area.extent.y + fillOffset);
  530. PrimBuild::vertex2f(area.point.x + fillOffset, area.point.y + area.extent.y + fillOffset);
  531. PrimBuild::vertex2f(area.point.x + fillOffset, area.point.y + fillOffset);
  532. PrimBuild::end();
  533. // render the camera
  534. //if(mRenderCamera)
  535. {
  536. CameraQuery camera;
  537. GameProcessCameraQuery(&camera);
  538. // farplane too far, 90' looks wrong...
  539. camera.fov = mDegToRad(60.f);
  540. camera.farPlane = 500.f;
  541. //
  542. F32 rot = camera.fov / 2;
  543. //
  544. VectorF ray;
  545. VectorF projRayA, projRayB;
  546. ray.set(camera.farPlane * -mSin(rot), camera.farPlane * mCos(rot), 0);
  547. camera.cameraMatrix.mulV(ray, &projRayA);
  548. ray.set(camera.farPlane * -mSin(-rot), camera.farPlane * mCos(-rot), 0);
  549. camera.cameraMatrix.mulV(ray, &projRayB);
  550. Point3F camPos;
  551. camera.cameraMatrix.getColumn(3, &camPos);
  552. Point2F s = worldToScreen(Point2F(camPos.x, camPos.y));
  553. Point2F e1 = worldToScreen(Point2F(camPos.x + projRayA.x, camPos.y + projRayA.y));
  554. Point2F e2 = worldToScreen(Point2F(camPos.x + projRayB.x, camPos.y + projRayB.y));
  555. PrimBuild::color( mCameraColor );
  556. PrimBuild::begin( GFXLineList, 4 );
  557. PrimBuild::vertex2f( s.x + fillOffset, s.y + fillOffset );
  558. PrimBuild::vertex2f( e1.x + fillOffset, e1.y + fillOffset );
  559. PrimBuild::vertex2f( s.x + fillOffset, s.y + fillOffset );
  560. PrimBuild::vertex2f( e2.x + fillOffset, e2.y + fillOffset );
  561. PrimBuild::end();
  562. }
  563. // render the handles
  564. RectI iArea;
  565. getScreenMissionArea(iArea);
  566. drawHandles(iArea);
  567. renderChildControls(offset, updateRect);
  568. }
  569. //------------------------------------------------------------------------------
  570. DefineEngineMethod( GuiMissionAreaCtrl, setMissionArea, void, ( MissionArea* area ),,
  571. "@brief Set the MissionArea to edit.\n\n")
  572. {
  573. object->setMissionArea( area );
  574. }
  575. DefineEngineMethod(GuiMissionAreaCtrl, updateLevelBitmap, void, (), ,
  576. "@brief Update the level bitmap and bounds.\n\n")
  577. {
  578. object->updateLevelBitmap();
  579. }
  580. //------------------------------------------------------------------------------
  581. void GuiMissionAreaUndoAction::undo()
  582. {
  583. MissionArea *ma = NULL;
  584. if ( !Sim::findObject( mObjId, ma ) )
  585. return;
  586. // Temporarily save the MissionArea's current data.
  587. RectI area = ma->getArea();
  588. // Restore the MissionArea properties saved in the UndoAction
  589. ma->setArea( mArea );
  590. ma->inspectPostApply();
  591. // Now save the previous Mission data in this UndoAction
  592. // since an undo action must become a redo action and vice-versa
  593. mArea = area;
  594. // Let the script get a chance at it.
  595. Con::executef( mMissionAreaEditor, "onUndo" );
  596. }