guiSpriteCtrl.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  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. #ifndef _GUISPRITECTRL_H_
  23. #include "2d/gui/guiSpriteCtrl.h"
  24. #endif
  25. #ifndef _CONSOLE_H_
  26. #include "console/console.h"
  27. #endif
  28. #ifndef _CONSOLETYPES_H_
  29. #include "console/consoleTypes.h"
  30. #endif
  31. #ifndef _DGL_H_
  32. #include "graphics/dgl.h"
  33. #endif
  34. #ifndef _H_GUIDEFAULTCONTROLRENDER_
  35. #include "gui/guiDefaultControlRender.h"
  36. #endif
  37. #include "guiSpriteCtrl_ScriptBindings.h"
  38. //-----------------------------------------------------------------------------
  39. IMPLEMENT_CONOBJECT(GuiSpriteCtrl);
  40. //-----------------------------------------------------------------------------
  41. GuiSpriteCtrl::GuiSpriteCtrl( void ) :
  42. mImageAssetId(StringTable->EmptyString),
  43. mFrame(0),
  44. mNamedImageFrameId(StringTable-> EmptyString),
  45. mAnimationAssetId(StringTable->EmptyString),
  46. mBitmapName(StringTable->EmptyString)
  47. {
  48. // Set to self ticking.
  49. mSelfTick = true;
  50. // Default to static provider.
  51. mStaticProvider = true;
  52. mTileImage = false;
  53. mPositionOffset.set(0, 0);
  54. mImageColor = FluidColorI(255, 255, 255, 255);
  55. mImageSize.set(10, 10);
  56. mFullSize = true;
  57. mConstrainProportions = true;
  58. mSingleFrameBitmap = true;
  59. }
  60. //-----------------------------------------------------------------------------
  61. GuiSpriteCtrl::~GuiSpriteCtrl()
  62. {
  63. }
  64. //-----------------------------------------------------------------------------
  65. void GuiSpriteCtrl::initPersistFields()
  66. {
  67. // Call parent.
  68. Parent::initPersistFields();
  69. addGroup("GuiSpriteCtrl");
  70. addProtectedField("Image", TypeAssetId, Offset(mImageAssetId, GuiSpriteCtrl), &setImage, &defaultProtectedGetFn, &writeImage, "The image asset Id used for the image.");
  71. addProtectedField("Frame", TypeS32, Offset(mFrame, GuiSpriteCtrl), &setImageFrame, &defaultProtectedGetFn, &writeImageFrame, "The image frame used for the image or bitmap.");
  72. addProtectedField("NamedFrame", TypeString, Offset(mNamedImageFrameId, GuiSpriteCtrl), &setNamedImageFrame, &defaultProtectedGetFn, &writeNamedImageFrame, "The named image frame used for the image.");
  73. addProtectedField("Animation", TypeAssetId, Offset(mAnimationAssetId, GuiSpriteCtrl), &setAnimation, &defaultProtectedGetFn, &writeAnimation, "The animation to use.");
  74. addProtectedField("Bitmap", TypeFilename, Offset(mBitmapName, GuiSpriteCtrl), &setBitmapName, &getBitmapName, &writeBitmapName, "The bitmap to use in absence of an asset.");
  75. addProtectedField("singleFrameBitmap", TypeBool, Offset(mSingleFrameBitmap, GuiSpriteCtrl), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeBitmapName, "If true, will assume there is a single frame when scanning the bitmap.");
  76. addField("tileImage", TypeBool, Offset(mTileImage, GuiSpriteCtrl));
  77. addField("positionOffset", TypePoint2I, Offset(mPositionOffset, GuiSpriteCtrl));
  78. addField("imageColor", TypeFluidColorI, Offset(mImageColor, GuiSpriteCtrl));
  79. addField("imageSize", TypePoint2I, Offset(mImageSize, GuiSpriteCtrl));
  80. addField("fullSize", TypeBool, Offset(mFullSize, GuiSpriteCtrl));
  81. addField("constrainProportions", TypeBool, Offset(mConstrainProportions, GuiSpriteCtrl));
  82. endGroup("GuiSpriteCtrl");
  83. }
  84. //------------------------------------------------------------------------------
  85. void GuiSpriteCtrl::copyTo(SimObject* object)
  86. {
  87. // Call to parent.
  88. Parent::copyTo(object);
  89. // Cast to control.
  90. GuiSpriteCtrl* pGuiSpriteCtrl = static_cast<GuiSpriteCtrl*>(object);
  91. // Sanity!
  92. AssertFatal(pGuiSpriteCtrl != NULL, "GuiSpriteCtrl::copyTo() - Object is not the correct type.");
  93. // Copy asset fields.
  94. if ( mImageAssetId != StringTable->EmptyString )
  95. {
  96. if ( !isUsingNamedImageFrame() )
  97. pGuiSpriteCtrl->setImage( getImage(), getImageFrame() );
  98. else
  99. pGuiSpriteCtrl->setImage( getImage(), getNamedImageFrame() );
  100. }
  101. else if ( mAnimationAssetId != StringTable->EmptyString )
  102. {
  103. pGuiSpriteCtrl->setAnimation( getAnimation() );
  104. }
  105. }
  106. //-----------------------------------------------------------------------------
  107. bool GuiSpriteCtrl::onWake()
  108. {
  109. // Call parent.
  110. if (!Parent::onWake())
  111. return false;
  112. mActive = true;
  113. if ( mImageAssetId != StringTable->EmptyString )
  114. {
  115. if ( mNamedImageFrameId != StringTable->EmptyString)
  116. {
  117. // Set the image asset and named frame
  118. setImage( mImageAssetId, mNamedImageFrameId );
  119. }
  120. else
  121. {
  122. // Set image asset and numerical frame.
  123. setImage( mImageAssetId, mFrame );
  124. }
  125. }
  126. else if ( mAnimationAssetId != StringTable->EmptyString )
  127. {
  128. // Play animation asset.
  129. setAnimation( mAnimationAssetId );
  130. }
  131. else if (mBitmapName != StringTable->EmptyString)
  132. {
  133. setBitmap(mBitmapName);
  134. }
  135. else
  136. {
  137. // Not good, so warn.
  138. Con::warnf("GuiSpriteCtrl::onWake() - No Image, Animation, or bitmap defined.");
  139. }
  140. return true;
  141. }
  142. //-----------------------------------------------------------------------------
  143. void GuiSpriteCtrl::onSleep()
  144. {
  145. // Clear assets.
  146. ImageFrameProvider::clearAssets();
  147. mBitmapTextureHandle = NULL;
  148. // Call parent.
  149. Parent::onSleep();
  150. }
  151. void GuiSpriteCtrl::setBitmap(const char *name)
  152. {
  153. mBitmapName = StringTable->insert(name);
  154. if (*mBitmapName) {
  155. mBitmapTextureHandle = TextureHandle(mBitmapName, TextureHandle::BitmapTexture, true);
  156. mBitmapTextureHandle.setFilter(GL_LINEAR);
  157. }
  158. else
  159. mBitmapTextureHandle = NULL;
  160. }
  161. U32 GuiSpriteCtrl::constructBitmapArray()
  162. {
  163. if (mSingleFrameBitmap)
  164. return 0;
  165. if (mBitmapArrayRects.size())
  166. return mBitmapArrayRects.size();
  167. GBitmap *bmp = mBitmapTextureHandle.getBitmap();
  168. // Make sure the texture exists.
  169. if (!bmp)
  170. return 0;
  171. //get the separator color
  172. ColorI sepColor;
  173. if (!bmp || !bmp->getColor(0, 0, sepColor))
  174. {
  175. Con::errorf("GuiSpriteCtrl::constructBitmapArray: Failed to create bitmap array from %s - couldn't ascertain seperator color!", mBitmapName);
  176. AssertFatal(false, avar("GuiSpriteCtrl::constructBitmapArray: Failed to create bitmap array from %s - couldn't ascertain seperator color!", mBitmapName));
  177. return 0;
  178. }
  179. //now loop through all the scroll pieces, and find the bounding rectangle for each piece in each state
  180. S32 curY = 0;
  181. // ascertain the height of this row...
  182. ColorI color;
  183. mBitmapArrayRects.clear();
  184. while (curY < (S32)bmp->getHeight())
  185. {
  186. // skip any sep colors
  187. bmp->getColor(0, curY, color);
  188. if (color == sepColor)
  189. {
  190. curY++;
  191. continue;
  192. }
  193. // ok, process left to right, grabbing bitmaps as we go...
  194. S32 curX = 0;
  195. while (curX < (S32)bmp->getWidth())
  196. {
  197. bmp->getColor(curX, curY, color);
  198. if (color == sepColor)
  199. {
  200. curX++;
  201. continue;
  202. }
  203. S32 startX = curX;
  204. while (curX < (S32)bmp->getWidth())
  205. {
  206. bmp->getColor(curX, curY, color);
  207. if (color == sepColor)
  208. break;
  209. curX++;
  210. }
  211. S32 stepY = curY;
  212. while (stepY < (S32)bmp->getHeight())
  213. {
  214. bmp->getColor(startX, stepY, color);
  215. if (color == sepColor)
  216. break;
  217. stepY++;
  218. }
  219. mBitmapArrayRects.push_back(RectI(startX, curY, curX - startX, stepY - curY));
  220. }
  221. // ok, now skip to the next separation color on column 0
  222. while (curY < (S32)bmp->getHeight())
  223. {
  224. bmp->getColor(0, curY, color);
  225. if (color == sepColor)
  226. break;
  227. curY++;
  228. }
  229. }
  230. return mBitmapArrayRects.size();
  231. }
  232. Point2I GuiSpriteCtrl::constrain(Point2I &point, bool grow)
  233. {
  234. if (!mConstrainProportions)
  235. {
  236. return point;
  237. }
  238. F32 targetRatio = getAspectRatio();
  239. F32 currentRatio = (F32)(point.y / point.x);
  240. if (targetRatio > currentRatio) //Too short
  241. {
  242. return grow ? Point2I(point.x, mRound(point.x * targetRatio)) : Point2I(mRound(point.y / targetRatio), point.y);
  243. }
  244. else if (targetRatio < currentRatio) //Too tall
  245. {
  246. return grow ? Point2I(mRound(point.y / targetRatio), point.y) : Point2I(point.x, mRound(point.x * targetRatio));
  247. }
  248. return point;
  249. }
  250. Point2I GuiSpriteCtrl::constrainLockX(Point2I &point)
  251. {
  252. if (!mConstrainProportions)
  253. {
  254. return point;
  255. }
  256. F32 targetRatio = getAspectRatio();
  257. return Point2I(point.x, mRound(point.x * targetRatio));
  258. }
  259. Point2I GuiSpriteCtrl::constrainLockY(Point2I &point)
  260. {
  261. if (!mConstrainProportions)
  262. {
  263. return point;
  264. }
  265. F32 targetRatio = getAspectRatio();
  266. return Point2I(point.y / targetRatio, point.y);
  267. }
  268. F32 GuiSpriteCtrl::getAspectRatio()
  269. {
  270. RectI src = getSourceRect(usesAsset() ? getProviderTexture() : mBitmapTextureHandle);
  271. if (src.isValidRect())
  272. {
  273. return ((F32)src.extent.y / (F32)src.extent.x);
  274. }
  275. return 1.0;
  276. }
  277. Point2I GuiSpriteCtrl::applyAlignment(RectI &bounds, Point2I &size)
  278. {
  279. Point2I offset = Point2I(0, 0);
  280. AlignmentType align = getAlignmentType();
  281. VertAlignmentType vAlign = getVertAlignmentType();
  282. if (align == AlignmentType::RightAlign)
  283. {
  284. offset.x = bounds.extent.x - size.x;
  285. }
  286. else if (align == AlignmentType::CenterAlign)
  287. {
  288. S32 halfW = mRound(size.x / 2);
  289. offset.x = mRound(bounds.extent.x / 2) - halfW;
  290. }
  291. if (vAlign == VertAlignmentType::BottomVAlign)
  292. {
  293. offset.y = bounds.extent.y - size.y;
  294. }
  295. else if (vAlign == VertAlignmentType::MiddleVAlign)
  296. {
  297. S32 halfH = mRound(size.y / 2);
  298. offset.y = mRound(bounds.extent.y / 2) - halfH;
  299. }
  300. //Apply the image offset
  301. S32 maxX = bounds.extent.x - size.x;
  302. S32 maxY = bounds.extent.y - size.y;
  303. offset.x = mClamp(offset.x + mPositionOffset.x, 0, maxX);
  304. offset.y = mClamp(offset.y + mPositionOffset.y, 0, maxY);
  305. return offset;
  306. }
  307. //-----------------------------------------------------------------------------
  308. bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const U32 frame )
  309. {
  310. // Sanity!
  311. AssertFatal( pImageAssetId != NULL, "Cannot use a NULL asset Id." );
  312. //Capture the current tick state
  313. bool isTicking = isProcessingTicks();
  314. // Reset animation.
  315. if ( mAnimationAssetId != StringTable->EmptyString )
  316. mAnimationAssetId = StringTable->EmptyString;
  317. // Fetch the asset Id.
  318. if ( mImageAssetId != pImageAssetId )
  319. mImageAssetId = StringTable->insert(pImageAssetId);
  320. // Finish if not awake.
  321. if ( !isAwake() )
  322. return true;
  323. // Call parent.
  324. if ( !ImageFrameProvider::setImage(pImageAssetId, frame) )
  325. return false;
  326. //Restore the tick state
  327. if (isProcessingTicks() != isTicking)
  328. {
  329. setProcessTicks(true);
  330. }
  331. // Update control.
  332. setUpdate();
  333. return true;
  334. }
  335. //-----------------------------------------------------------------------------
  336. bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const char* pNamedFrame )
  337. {
  338. // Sanity!
  339. AssertFatal( pImageAssetId != NULL, "Cannot use a NULL asset Id." );
  340. //Capture the current tick state
  341. bool isTicking = isProcessingTicks();
  342. // Reset animation.
  343. if ( mAnimationAssetId != StringTable->EmptyString )
  344. mAnimationAssetId = StringTable->EmptyString;
  345. // Fetch the asset Id.
  346. if ( mImageAssetId != pImageAssetId )
  347. mImageAssetId = StringTable->insert(pImageAssetId);
  348. // Finish if not awake.
  349. if ( !isAwake() )
  350. return true;
  351. // Call parent.
  352. if ( !ImageFrameProvider::setImage(pImageAssetId, pNamedFrame) )
  353. return false;
  354. //Restore the tick state
  355. if (isProcessingTicks() != isTicking)
  356. {
  357. setProcessTicks(true);
  358. }
  359. // Update control.
  360. setUpdate();
  361. return true;
  362. }
  363. //-----------------------------------------------------------------------------
  364. bool GuiSpriteCtrl::setImageFrame( const U32 frame )
  365. {
  366. // Check Existing Image.
  367. if ( mImageAssetId == StringTable->EmptyString && mBitmapName == StringTable->EmptyString )
  368. {
  369. // Warn.
  370. Con::warnf("GuiSpriteCtrl::setImageFrame() - Cannot set frame without existing image asset or bitmap.");
  371. // Return Here.
  372. return false;
  373. }
  374. // Set frame.
  375. mFrame = frame;
  376. // Finish if not awake.
  377. if ( !isAwake() )
  378. return true;
  379. if(usesAsset())
  380. {
  381. // Call parent.
  382. if ( !ImageFrameProvider::setImageFrame(frame) )
  383. return false;
  384. }
  385. // Update control.
  386. setUpdate();
  387. return true;
  388. }
  389. //-----------------------------------------------------------------------------
  390. bool GuiSpriteCtrl::setNamedImageFrame( const char* pNamedFrame )
  391. {
  392. // Check Existing Image.
  393. if ( mImageAssetId == StringTable->EmptyString )
  394. {
  395. // Warn.
  396. Con::warnf("GuiSpriteCtrl::setNamedImageFrame() - Cannot set named frame without existing asset Id.");
  397. // Return Here.
  398. return false;
  399. }
  400. // Set named frame.
  401. mNamedImageFrameId = StringTable->insert(pNamedFrame);
  402. // Finish if not awake.
  403. if ( !isAwake() )
  404. return true;
  405. // Call parent.
  406. if ( !ImageFrameProvider::setNamedImageFrame(pNamedFrame) )
  407. return false;
  408. // Update control.
  409. setUpdate();
  410. return true;
  411. }
  412. //-----------------------------------------------------------------------------
  413. bool GuiSpriteCtrl::setAnimation( const char* pAnimationAssetId )
  414. {
  415. // Sanity!
  416. AssertFatal( pAnimationAssetId != NULL, "Cannot use a NULL asset Id." );
  417. // Reset the image asset Id.
  418. if ( mImageAssetId != StringTable->EmptyString )
  419. mImageAssetId = StringTable->EmptyString;
  420. // Fetch the asset Id.
  421. if ( mAnimationAssetId != pAnimationAssetId )
  422. mAnimationAssetId = StringTable->insert(pAnimationAssetId);
  423. // Finish if not awake.
  424. if ( !isAwake() )
  425. return true;
  426. // Play animation asset if it's valid.
  427. if ( mAnimationAssetId != StringTable->EmptyString )
  428. ImageFrameProvider::setAnimation( mAnimationAssetId );
  429. return true;
  430. }
  431. void GuiSpriteCtrl::onRender(Point2I offset, const RectI &updateRect)
  432. {
  433. RectI ctrlRect = applyMargins(offset, mBounds.extent, NormalState, mProfile);
  434. if (!ctrlRect.isValidRect())
  435. {
  436. return;
  437. }
  438. renderUniversalRect(ctrlRect, mProfile, NormalState);
  439. RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
  440. RectI contentRect = applyPadding(fillRect.point, fillRect.extent, NormalState, mProfile);
  441. if (contentRect.isValidRect() && (usesAsset() || mBitmapName != StringTable->EmptyString))
  442. {
  443. RectI oldClip = dglGetClipRect();
  444. RectI clipRect = contentRect;
  445. if (clipRect.intersect(oldClip))
  446. {
  447. dglSetClipRect(clipRect);
  448. dglSetBitmapModulation(ColorF(mImageColor));
  449. Point2I offset = Point2I(0, 0);
  450. Point2I size = constrain(mImageSize);
  451. if (mTileImage) //Tile the image
  452. {
  453. offset = mPositionOffset;
  454. offset.x = (mPositionOffset.x % size.x);
  455. if (offset.x > 0)
  456. {
  457. offset.x -= size.x;
  458. }
  459. offset.y = (mPositionOffset.y % size.y);
  460. if (offset.y > 0)
  461. {
  462. offset.y -= size.y;
  463. }
  464. RenderTiledImage(contentRect, offset, size);
  465. }
  466. else if (mFullSize) //Fill with the image
  467. {
  468. size = constrain(contentRect.extent, false);
  469. if (mConstrainProportions)
  470. {
  471. offset = applyAlignment(contentRect, size);
  472. }
  473. RenderImage(contentRect, offset, size);
  474. }
  475. else //Position the image by profile alignment
  476. {
  477. size = constrain(mImageSize);
  478. if (size.x > contentRect.extent.x)
  479. {
  480. size.x = contentRect.extent.x;
  481. size = constrainLockX(size);
  482. }
  483. if (size.y > contentRect.extent.y)
  484. {
  485. size.y = contentRect.extent.y;
  486. size = constrainLockY(size);
  487. }
  488. offset = applyAlignment(contentRect, size);
  489. RenderImage(contentRect, offset, size);
  490. }
  491. dglClearBitmapModulation();
  492. dglSetClipRect(oldClip);
  493. //Render the childen
  494. renderChildControls(offset, contentRect, updateRect);
  495. }
  496. //One more thing...
  497. if (usesAsset() && !isStaticFrameProvider() && !isAnimationFinished() && !isAnimationPaused() && !isProcessingTicks())
  498. {
  499. setProcessTicks(true);
  500. }
  501. }
  502. }
  503. void GuiSpriteCtrl::RenderImage(RectI &bounds, Point2I &offset, Point2I &size)
  504. {
  505. TextureObject* texture = usesAsset() ? (TextureObject *) getProviderTexture() : (TextureObject *)mBitmapTextureHandle;
  506. RectI srcRegion = getSourceRect(texture);
  507. if (!srcRegion.isValidRect())
  508. {
  509. return;
  510. }
  511. RectI dstRegion = RectI(bounds.point + offset, size);
  512. dglDrawBitmapStretchSR(texture, dstRegion, srcRegion, false);
  513. }
  514. void GuiSpriteCtrl::RenderTiledImage(RectI &bounds, Point2I &start, Point2I &size)
  515. {
  516. TextureObject* texture = usesAsset() ? (TextureObject *)getProviderTexture() : (TextureObject *)mBitmapTextureHandle;
  517. RectI srcRegion = getSourceRect(texture);
  518. if (!srcRegion.isValidRect())
  519. {
  520. return;
  521. }
  522. RectI dstRegion;
  523. float xdone = ((float)(bounds.extent.x - start.x) / (float)size.x) + 1;
  524. float ydone = ((float)(bounds.extent.y - start.y) / (float)size.y) + 1;
  525. // We manually draw each repeat because non power of two textures will
  526. // not tile correctly when rendered with dglDrawBitmapTile().
  527. for (int y = 0; y < ydone; ++y)
  528. {
  529. for (int x = 0; x < xdone; ++x)
  530. {
  531. dstRegion.set((size.x * x) + start.x, (size.y * y) + start.y, size.x, size.y);
  532. dglDrawBitmapStretchSR(texture, dstRegion, srcRegion, false);
  533. }
  534. }
  535. }
  536. RectI GuiSpriteCtrl::getSourceRect(TextureObject* texture)
  537. {
  538. RectI srcRegion = RectI(0, 0, 0, 0);
  539. bool hasAsset = usesAsset();
  540. if (hasAsset)
  541. {
  542. const ImageAsset::FrameArea& frameArea = getProviderImageFrameArea();
  543. srcRegion = RectI(frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight));
  544. }
  545. else if (!hasAsset && mSingleFrameBitmap)
  546. {
  547. srcRegion = RectI(0, 0, texture->getBitmapWidth(), texture->getBitmapHeight());
  548. }
  549. else if (!hasAsset && constructBitmapArray() > mFrame)
  550. {
  551. RectI* frameRect = mBitmapArrayRects.address();
  552. srcRegion = frameRect[mFrame];
  553. }
  554. return srcRegion;
  555. }
  556. void GuiSpriteCtrl::moveTo(S32 x, S32 y, S32 time, EasingFunction ease)
  557. {
  558. mStartOffset.set(mPositionOffset.x, mPositionOffset.y);
  559. mTargetOffset.set(x, y);
  560. mFluidMoveTo.setAnimationLength(getMax(time, 0));
  561. mFluidMoveTo.setEasingFunction(ease);
  562. mFluidMoveTo.startFluidAnimation();
  563. setProcessTicks(true);
  564. }
  565. void GuiSpriteCtrl::growTo(S32 x, S32 y, S32 time, EasingFunction ease)
  566. {
  567. mStartSize.set(mImageSize.x, mImageSize.y);
  568. mTargetSize.set(x, y);
  569. mFluidGrowTo.setAnimationLength(getMax(time, 0));
  570. mFluidGrowTo.setEasingFunction(ease);
  571. mFluidGrowTo.startFluidAnimation();
  572. setProcessTicks(true);
  573. }
  574. void GuiSpriteCtrl::fadeTo(const ColorI &color, S32 time, EasingFunction ease)
  575. {
  576. mImageColor.setAnimationLength(getMax(time, 0));
  577. mImageColor.setEasingFunction(ease);
  578. mImageColor.startFluidAnimation(color);
  579. setProcessTicks(true);
  580. }
  581. void GuiSpriteCtrl::processTick()
  582. {
  583. bool shouldWeContinue = false;
  584. //Animating
  585. shouldWeContinue |= update(Tickable::smTickSec);
  586. shouldWeContinue |= animateMoveTo();
  587. shouldWeContinue |= animateGrowTo();
  588. shouldWeContinue |= animateFadeTo();
  589. if (!shouldWeContinue)
  590. {
  591. setProcessTicks(false);
  592. }
  593. }
  594. bool GuiSpriteCtrl::update(const F32 elapsedTime)
  595. {
  596. //Note: although this overrides ImageFrameProviderCore::update, the return value has a different meaning.
  597. //True means the control should continue ticking. False means the animation now longer needs tickets.
  598. // Static provider or bitmap?
  599. if (!usesAsset() || isStaticFrameProvider())
  600. {
  601. return false;
  602. }
  603. // Finish if the animation has finished or paused.
  604. if (isAnimationFinished() || isAnimationPaused())
  605. return false;
  606. // Update the animation.
  607. if (updateAnimation(elapsedTime))
  608. {
  609. setUpdate();
  610. }
  611. // Finish if the animation has NOT finished.
  612. if (!isAnimationFinished())
  613. return true;
  614. // Perform callback.
  615. onAnimationEnd();
  616. //We no longer need ticks.
  617. return false;
  618. }
  619. bool GuiSpriteCtrl::animateMoveTo()
  620. {
  621. if (!mFluidMoveTo.isAnimating())
  622. {
  623. return false;
  624. }
  625. setUpdate();
  626. F32 progress = mFluidMoveTo.getProgress(32.0f);
  627. mPositionOffset.set(
  628. mFluidMoveTo.processValue(progress, mStartOffset.x, mTargetOffset.x),
  629. mFluidMoveTo.processValue(progress, mStartOffset.y, mTargetOffset.y));
  630. if (!mFluidMoveTo.isAnimating() && isMethod("onMoveToComplete"))
  631. {
  632. Con::executef(this, 1, "onMoveToComplete");
  633. }
  634. return mFluidMoveTo.isAnimating();
  635. }
  636. bool GuiSpriteCtrl::animateGrowTo()
  637. {
  638. if (!mFluidGrowTo.isAnimating())
  639. {
  640. return false;
  641. }
  642. setUpdate();
  643. F32 progress = mFluidGrowTo.getProgress(32.0f);
  644. mImageSize.set(
  645. mFluidGrowTo.processValue(progress, mStartSize.x, mTargetSize.x),
  646. mFluidGrowTo.processValue(progress, mStartSize.y, mTargetSize.y));
  647. if (!mFluidGrowTo.isAnimating() && isMethod("onGrowToComplete"))
  648. {
  649. Con::executef(this, 1, "onGrowToComplete");
  650. }
  651. return mFluidGrowTo.isAnimating();
  652. }
  653. bool GuiSpriteCtrl::animateFadeTo()
  654. {
  655. if (!mImageColor.isAnimating())
  656. {
  657. return false;
  658. }
  659. setUpdate();
  660. mImageColor.processTick();
  661. if (!mImageColor.isAnimating() && isMethod("onFadeToComplete"))
  662. {
  663. Con::executef(this, 1, "onFadeToComplete");
  664. }
  665. return mImageColor.isAnimating();
  666. }
  667. //------------------------------------------------------------------------------
  668. void GuiSpriteCtrl::onAnimationEnd( void )
  669. {
  670. // We've arrived at the end - pause it
  671. ImageFrameProvider::pauseAnimation(true);
  672. // Send a callback
  673. if(isMethod("onAnimationEnd"))
  674. Con::executef(this, 3, "onAnimationEnd", ImageFrameProvider::getCurrentAnimationAssetId());
  675. }