guiSceneObjectCtrl.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 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 "graphics/dgl.h"
  23. #include "console/consoleTypes.h"
  24. #include "gui/guiDefaultControlRender.h"
  25. #include "guiSceneObjectCtrl.h"
  26. #include "debug/profiler.h"
  27. // -----------------------------------------------------------------------------
  28. IMPLEMENT_CONOBJECT(GuiSceneObjectCtrl);
  29. // -----------------------------------------------------------------------------
  30. // -----------------------------------------------------------------------------
  31. // Constructor.
  32. // -----------------------------------------------------------------------------
  33. GuiSceneObjectCtrl::GuiSceneObjectCtrl(void)
  34. {
  35. // Reset Scene Object Name.
  36. mSceneObjectName = StringTable->EmptyString;
  37. // Default to no render margin
  38. mMargin = 0;
  39. mCaption = StringTable->EmptyString;
  40. mStateOn = false;
  41. mButtonType = ButtonTypeRadio;
  42. // Set-up private batcher.
  43. mBatchRenderer.setDebugStats( &mDebugStats );
  44. mBatchRenderer.setStrictOrderMode( true, true );
  45. mBatchRenderer.setBatchEnabled( false );
  46. }
  47. // -----------------------------------------------------------------------------
  48. // Persistent Fields.
  49. // -----------------------------------------------------------------------------
  50. void GuiSceneObjectCtrl::initPersistFields()
  51. {
  52. // Call Parent.
  53. Parent::initPersistFields();
  54. // Define Fields.
  55. addGroup("GuiSceneObjectCtrl");
  56. addField("renderMargin", TypeS32, Offset(mMargin, GuiSceneObjectCtrl));
  57. addField("sceneObject", TypeString, Offset(mSceneObjectName, GuiSceneObjectCtrl));
  58. endGroup("GuiSceneObjectCtrl");
  59. }
  60. // -----------------------------------------------------------------------------
  61. // Wake!
  62. // -----------------------------------------------------------------------------
  63. bool GuiSceneObjectCtrl::onWake()
  64. {
  65. // Call Parent.
  66. if (!Parent::onWake())
  67. return false;
  68. if( mProfile->constructBitmapArray() >= 36 )
  69. mHasTexture = true;
  70. else
  71. mHasTexture = false;
  72. // Activate.
  73. setActive(true);
  74. // All Okay.
  75. return true;
  76. }
  77. // -----------------------------------------------------------------------------
  78. // Sleep!
  79. // -----------------------------------------------------------------------------
  80. void GuiSceneObjectCtrl::onSleep()
  81. {
  82. Parent::onSleep();
  83. }
  84. // -----------------------------------------------------------------------------
  85. //
  86. // -----------------------------------------------------------------------------
  87. void GuiSceneObjectCtrl::inspectPostApply()
  88. {
  89. // Call Parent.
  90. Parent::inspectPostApply();
  91. // Set the Scene Object.
  92. setSceneObject( mSceneObjectName );
  93. }
  94. // -----------------------------------------------------------------------------
  95. // Set Scene Object.
  96. // -----------------------------------------------------------------------------
  97. ConsoleMethod( GuiSceneObjectCtrl, setSceneObject, void, 3, 3, "(string obj) Set the scene-object displayed in the control."
  98. "@param obj Either the object's ID or its name."
  99. "@return No return value.")
  100. {
  101. // Set Scene Object.
  102. object->setSceneObject( argv[2] );
  103. }
  104. // Set Scene Object.
  105. void GuiSceneObjectCtrl::setSceneObject( const char* name )
  106. {
  107. // Reset existing object.
  108. mSelectedSceneObject = NULL;
  109. // Get Scene Name.
  110. mSceneObjectName = StringTable->insert( name ? name : "" );
  111. // Valid Scene Object Name?
  112. if ( *mSceneObjectName )
  113. {
  114. // Fetch Scene Object.
  115. SceneObject* pSceneObject = dynamic_cast<SceneObject*>(Sim::findObject( name ));
  116. // Valid?
  117. if ( pSceneObject )
  118. {
  119. // Yes, so set Scene Object.
  120. mSelectedSceneObject = pSceneObject;
  121. // The scene object needs to be integrated otherwise the render OOBB which this GUI control
  122. // relies upon will be undefined. This dependency needs resolving but I suspect it never will.
  123. DebugStats debugStats;
  124. mSelectedSceneObject->preIntegrate(0.0f, 0.0f, &debugStats );
  125. }
  126. }
  127. else
  128. mSelectedSceneObject = NULL;
  129. // Do an update.
  130. setUpdate();
  131. }
  132. ConsoleMethod( GuiSceneObjectCtrl, getSceneObject, const char*, 2,2, "() \n@return Returns displaying sceneobject id")
  133. {
  134. SceneObject *sceneObject = object->getSceneObject();
  135. if( !sceneObject )
  136. return "";
  137. return sceneObject->getIdString();
  138. }
  139. ConsoleMethod( GuiSceneObjectCtrl, setCaption, void, 3, 3, "(string caption) Sets the object caption to specified string.\n"
  140. "@return No return value.")
  141. {
  142. object->setCaption( argv[2] );
  143. }
  144. void GuiSceneObjectCtrl::setCaption( const char* caption )
  145. {
  146. if( caption != NULL )
  147. mCaption = StringTable->insert( caption );
  148. }
  149. //
  150. //
  151. //
  152. void GuiSceneObjectCtrl::onMouseUp(const GuiEvent &event)
  153. {
  154. if( mDepressed && ( event.mouseClickCount % 2 ) == 0 )
  155. Con::executef( this, 2, "onDoubleClick" );
  156. Parent::onMouseUp( event );
  157. }
  158. void GuiSceneObjectCtrl::onMouseLeave( const GuiEvent &event )
  159. {
  160. Con::executef( this, 2, "onMouseLeave" );
  161. Parent::onMouseLeave( event );
  162. }
  163. void GuiSceneObjectCtrl::onMouseEnter( const GuiEvent &event )
  164. {
  165. Con::executef( this, 2, "onMouseEnter" );
  166. Parent::onMouseEnter( event );
  167. }
  168. void GuiSceneObjectCtrl::onMouseDragged( const GuiEvent &event )
  169. {
  170. Con::executef( this, 2, "onMouseDragged" );
  171. Parent::onMouseDragged( event );
  172. }
  173. // -----------------------------------------------------------------------------
  174. // Render any selected Scene Object.
  175. // -----------------------------------------------------------------------------
  176. void GuiSceneObjectCtrl::onRender(Point2I offset, const RectI& updateRect)
  177. {
  178. PROFILE_SCOPE(guiT2DObjectCtrl_onRender);
  179. RectI ctrlRect( offset, mBounds.extent );
  180. // Draw Background
  181. if( mProfile->mOpaque )
  182. {
  183. if( mDepressed || mStateOn )
  184. {
  185. if( mHasTexture )
  186. renderSizableBitmapBordersFilled( ctrlRect, 3, mProfile );
  187. else
  188. dglDrawRectFill( ctrlRect, mProfile->mFillColorHL );
  189. }
  190. else if ( mMouseOver )
  191. {
  192. if( mHasTexture )
  193. renderSizableBitmapBordersFilled( ctrlRect, 2, mProfile );
  194. else
  195. dglDrawRectFill( ctrlRect, mProfile->mFillColorHL );
  196. }
  197. else
  198. {
  199. if( mHasTexture )
  200. renderSizableBitmapBordersFilled( ctrlRect, 1, mProfile );
  201. else
  202. dglDrawRectFill( ctrlRect, mProfile->mFillColor );
  203. }
  204. }
  205. //// Render Border.
  206. //if( mProfile->mBorder || mStateOn )
  207. // dglDrawRect(ctrlRect, mProfile->mBorderColor);
  208. // Valid Scene Object?
  209. if ( !mSelectedSceneObject.isNull() )
  210. {
  211. RectI objRect = updateRect;
  212. objRect.inset( mMargin, mMargin );
  213. RectI ctrlRectInset = ctrlRect;
  214. ctrlRectInset.inset( mMargin, mMargin);
  215. // Draw Canvas color for object
  216. if ( mProfile->mOpaque )
  217. {
  218. if( mHasTexture )
  219. renderSizableBitmapBordersFilled( objRect, 4, mProfile );
  220. else
  221. dglDrawRectFill( objRect, mProfile->mFillColorNA );
  222. }
  223. // Yes, so fetch object clip boundary.
  224. const b2Vec2* pClipBoundary = mSelectedSceneObject->getRenderOOBB();
  225. // Calculate the GUI-Control Clip Boundary.
  226. const F32 xscale = (pClipBoundary[1].x - pClipBoundary[0].x) / ctrlRectInset.extent.x;
  227. const F32 yscale = (pClipBoundary[2].y - pClipBoundary[0].y) / ctrlRectInset.extent.y;
  228. F32 x1 = pClipBoundary[0].x + ( objRect.point.x - ctrlRectInset.point.x) * xscale;
  229. F32 x2 = pClipBoundary[1].x + ( objRect.point.x + objRect.extent.x - ctrlRectInset.extent.x - ctrlRectInset.point.x) * xscale;
  230. F32 y1 = pClipBoundary[0].y + ( objRect.point.y - ctrlRectInset.point.y) * yscale;
  231. F32 y2 = pClipBoundary[2].y + ( objRect.point.y + objRect.extent.y - ctrlRectInset.extent.y - ctrlRectInset.point.y) * yscale;
  232. Vector2 size = mSelectedSceneObject->getSize();
  233. if (size.x > size.y)
  234. {
  235. S32 center = ctrlRectInset.point.y + (ctrlRectInset.extent.y / 2);
  236. // Save the base state of the objRect before transforming it
  237. S32 baseTop = objRect.point.y;
  238. S32 baseExtent = objRect.extent.y;
  239. S32 baseBottom = baseTop + baseExtent;
  240. // Transform the objRect extent by the aspect ratio
  241. objRect.extent.y = (S32)(ctrlRectInset.extent.y * (size.y / size.x));
  242. // Save the transformed positions of the objRect before clipping
  243. S32 targetTop = (S32)(center - ((ctrlRectInset.extent.y * (size.y / size.x)) / 2));
  244. S32 targetExtent = (S32)(objRect.extent.y);
  245. S32 targetBottom = (S32)(targetTop + objRect.extent.y);
  246. // Set the objRect position based on its aspect ratio
  247. objRect.point.y = (S32)(center - ((ctrlRectInset.extent.y * (size.y / size.x)) / 2));
  248. // Reset the clipping bounds
  249. y1 = pClipBoundary[0].y;
  250. y2 = pClipBoundary[2].y;
  251. // If the object clips of the top or bottom, adjust the extent and clipping bounds accordingly
  252. if (baseTop > targetTop)
  253. {
  254. // Adjust the position and extent
  255. objRect.point.y = baseTop;
  256. objRect.extent.y = getMax(targetBottom - baseTop, 0);
  257. // Set the top clipping boundary
  258. F32 clipRatio = 1.0f - ((1.0f * objRect.extent.y)/targetExtent);
  259. y1 = pClipBoundary[0].y + (pClipBoundary[2].y - pClipBoundary[0].y)*(clipRatio);
  260. }
  261. if (baseBottom < targetBottom)
  262. {
  263. // Adjust the extent
  264. objRect.extent.y = getMax(baseBottom - targetTop, 0);
  265. // Set the bottom clipping boundary
  266. F32 clipRatio = 1.0f - ((1.0f * objRect.extent.y)/targetExtent);
  267. y2 = pClipBoundary[2].y - (pClipBoundary[2].y - pClipBoundary[0].y)*(clipRatio);
  268. }
  269. }
  270. else
  271. {
  272. S32 center = ctrlRectInset.point.x + (ctrlRectInset.extent.x / 2);
  273. // Save the base state of the objRect before transforming it
  274. S32 baseLeft = objRect.point.x;
  275. S32 baseExtent = objRect.extent.x;
  276. S32 baseRight = baseLeft + baseExtent;
  277. // Transform the objRect extent by the aspect ratio
  278. objRect.extent.x = (S32)(ctrlRectInset.extent.x * (size.x / size.y));
  279. // Save the transformed positions of the objRect before clipping
  280. S32 targetLeft = (S32)(center - ((ctrlRectInset.extent.x * (size.x / size.y)) / 2));
  281. S32 targetExtent = (S32)(objRect.extent.x);
  282. S32 targetRight = (S32)(targetLeft + objRect.extent.x);
  283. // Set the objRect position based on its aspect ratio
  284. objRect.point.x = (S32)(center - ((ctrlRectInset.extent.x * (size.x / size.y)) / 2));
  285. // Reset the clipping bounds
  286. x1 = pClipBoundary[0].x;
  287. x2 = pClipBoundary[1].x;
  288. // If the object clips of the left or right, adjust the extent and clipping bounds accordingly
  289. if (baseLeft > targetLeft)
  290. {
  291. // Adjust the position and extent
  292. objRect.point.x = baseLeft;
  293. objRect.extent.x = getMax(targetRight - baseLeft, 0);
  294. // Set the left clipping boundary
  295. F32 clipRatio = 1.0f - ((1.0f * objRect.extent.x)/targetExtent);
  296. x1 = pClipBoundary[0].x + (pClipBoundary[1].x - pClipBoundary[0].x)*(clipRatio);
  297. }
  298. if (baseRight < targetRight)
  299. {
  300. // Adjust the extent
  301. objRect.extent.x = getMax(baseRight - targetLeft, 0);
  302. // Set the right clipping boundary
  303. F32 clipRatio = 1.0f - ((1.0f * objRect.extent.x)/targetExtent);
  304. x2 = pClipBoundary[1].x - (pClipBoundary[1].x - pClipBoundary[0].x)*(clipRatio);
  305. }
  306. }
  307. // Negate the y-clippingpoints to convert to positive-y-up coordinate system of the object
  308. y1 *= -1;
  309. y2 *= -1;
  310. // Setup new logical coordinate system.
  311. glMatrixMode(GL_PROJECTION);
  312. glPushMatrix();
  313. glLoadIdentity();
  314. RectI viewport;
  315. dglGetViewport(&viewport);
  316. if (x1 > x2)
  317. {
  318. F32 temp = x1;
  319. x1 = x2;
  320. x2 = temp;
  321. }
  322. if (y1 > y2)
  323. {
  324. F32 temp = y1;
  325. y1 = y2;
  326. y2 = temp;
  327. }
  328. // Setup Orthographic Projection for Object Area.
  329. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
  330. glOrthof( x1, x2, y1, y2, 0.0f, MAX_LAYERS_SUPPORTED );
  331. #else
  332. glOrtho( x1, x2, y1, y2, 0.0f, MAX_LAYERS_SUPPORTED );
  333. #endif
  334. // Setup new viewport.
  335. dglSetViewport(objRect);
  336. // Set ModelView.
  337. glMatrixMode(GL_MODELVIEW);
  338. glPushMatrix();
  339. glLoadIdentity();
  340. // Enable Alpha Test.
  341. glEnable ( GL_ALPHA_TEST );
  342. glAlphaFunc ( GL_GREATER, 0.0f );
  343. // Calculate maximal clip bounds.
  344. RectF clipBounds( -x1,-y1, x2-x1, y2-y1 );
  345. DebugStats debugStats;
  346. // Render Object in GUI-space.
  347. SceneRenderState guiSceneRenderState(
  348. clipBounds,
  349. clipBounds.centre(),
  350. 0.0f,
  351. MASK_ALL,
  352. MASK_ALL,
  353. Vector2::getOne(),
  354. &debugStats,
  355. this );
  356. SceneRenderRequest guiSceneRenderRequest;
  357. guiSceneRenderRequest.set(
  358. mSelectedSceneObject,
  359. mSelectedSceneObject->getRenderPosition(),
  360. 0.0f );
  361. mSelectedSceneObject->sceneRender( &guiSceneRenderState, &guiSceneRenderRequest, &mBatchRenderer );
  362. // Restore Standard Settings.
  363. glDisable ( GL_DEPTH_TEST );
  364. glDisable ( GL_ALPHA_TEST );
  365. // Restore Matrices.
  366. glMatrixMode(GL_MODELVIEW);
  367. glPopMatrix();
  368. glMatrixMode(GL_PROJECTION);
  369. glPopMatrix();
  370. }
  371. else
  372. {
  373. // No Object so reset name.
  374. mSceneObjectName = NULL;
  375. }
  376. RectI captionRect = ctrlRect;
  377. captionRect.point.y += (captionRect.extent.y / 8);
  378. captionRect.inset(1, 1);
  379. dglSetBitmapModulation( ColorI(0,0,0,255) );
  380. renderJustifiedText(captionRect.point, captionRect.extent, mCaption);
  381. captionRect.inset(1, 1);
  382. dglSetBitmapModulation( mProfile->mFontColor );
  383. renderJustifiedText(captionRect.point, captionRect.extent, mCaption);
  384. // Render Child Controls.
  385. renderChildControls(offset, updateRect);
  386. }