guiSpriteCtrl.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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. if (mProfile->mAlignment == GuiControlProfile::AlignmentType::RightAlign)
  281. {
  282. offset.x = bounds.extent.x - size.x;
  283. }
  284. else if (mProfile->mAlignment == GuiControlProfile::AlignmentType::CenterAlign)
  285. {
  286. S32 halfW = mRound(size.x / 2);
  287. offset.x = mRound(bounds.extent.x / 2) - halfW;
  288. }
  289. if (mProfile->mVAlignment == GuiControlProfile::VertAlignmentType::BottomVAlign)
  290. {
  291. offset.y = bounds.extent.y - size.y;
  292. }
  293. else if (mProfile->mVAlignment == GuiControlProfile::VertAlignmentType::MiddleVAlign)
  294. {
  295. S32 halfH = mRound(size.y / 2);
  296. offset.y = mRound(bounds.extent.y / 2) - halfH;
  297. }
  298. //Apply the image offset
  299. S32 maxX = bounds.extent.x - size.x;
  300. S32 maxY = bounds.extent.y - size.y;
  301. offset.x = mClamp(offset.x + mPositionOffset.x, 0, maxX);
  302. offset.y = mClamp(offset.y + mPositionOffset.y, 0, maxY);
  303. return offset;
  304. }
  305. //-----------------------------------------------------------------------------
  306. bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const U32 frame )
  307. {
  308. // Sanity!
  309. AssertFatal( pImageAssetId != NULL, "Cannot use a NULL asset Id." );
  310. //Capture the current tick state
  311. bool isTicking = isProcessingTicks();
  312. // Reset animation.
  313. if ( mAnimationAssetId != StringTable->EmptyString )
  314. mAnimationAssetId = StringTable->EmptyString;
  315. // Fetch the asset Id.
  316. if ( mImageAssetId != pImageAssetId )
  317. mImageAssetId = StringTable->insert(pImageAssetId);
  318. // Finish if not awake.
  319. if ( !isAwake() )
  320. return true;
  321. // Call parent.
  322. if ( !ImageFrameProvider::setImage(pImageAssetId, frame) )
  323. return false;
  324. //Restore the tick state
  325. if (isProcessingTicks() != isTicking)
  326. {
  327. setProcessTicks(true);
  328. }
  329. // Update control.
  330. setUpdate();
  331. return true;
  332. }
  333. //-----------------------------------------------------------------------------
  334. bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const char* pNamedFrame )
  335. {
  336. // Sanity!
  337. AssertFatal( pImageAssetId != NULL, "Cannot use a NULL asset Id." );
  338. //Capture the current tick state
  339. bool isTicking = isProcessingTicks();
  340. // Reset animation.
  341. if ( mAnimationAssetId != StringTable->EmptyString )
  342. mAnimationAssetId = StringTable->EmptyString;
  343. // Fetch the asset Id.
  344. if ( mImageAssetId != pImageAssetId )
  345. mImageAssetId = StringTable->insert(pImageAssetId);
  346. // Finish if not awake.
  347. if ( !isAwake() )
  348. return true;
  349. // Call parent.
  350. if ( !ImageFrameProvider::setImage(pImageAssetId, pNamedFrame) )
  351. return false;
  352. //Restore the tick state
  353. if (isProcessingTicks() != isTicking)
  354. {
  355. setProcessTicks(true);
  356. }
  357. // Update control.
  358. setUpdate();
  359. return true;
  360. }
  361. //-----------------------------------------------------------------------------
  362. bool GuiSpriteCtrl::setImageFrame( const U32 frame )
  363. {
  364. // Check Existing Image.
  365. if ( mImageAssetId == StringTable->EmptyString && mBitmapName == StringTable->EmptyString )
  366. {
  367. // Warn.
  368. Con::warnf("GuiSpriteCtrl::setImageFrame() - Cannot set frame without existing image asset or bitmap.");
  369. // Return Here.
  370. return false;
  371. }
  372. // Set frame.
  373. mFrame = frame;
  374. // Finish if not awake.
  375. if ( !isAwake() )
  376. return true;
  377. if(usesAsset())
  378. {
  379. // Call parent.
  380. if ( !ImageFrameProvider::setImageFrame(frame) )
  381. return false;
  382. }
  383. // Update control.
  384. setUpdate();
  385. return true;
  386. }
  387. //-----------------------------------------------------------------------------
  388. bool GuiSpriteCtrl::setNamedImageFrame( const char* pNamedFrame )
  389. {
  390. // Check Existing Image.
  391. if ( mImageAssetId == StringTable->EmptyString )
  392. {
  393. // Warn.
  394. Con::warnf("GuiSpriteCtrl::setNamedImageFrame() - Cannot set named frame without existing asset Id.");
  395. // Return Here.
  396. return false;
  397. }
  398. // Set named frame.
  399. mNamedImageFrameId = StringTable->insert(pNamedFrame);
  400. // Finish if not awake.
  401. if ( !isAwake() )
  402. return true;
  403. // Call parent.
  404. if ( !ImageFrameProvider::setNamedImageFrame(pNamedFrame) )
  405. return false;
  406. // Update control.
  407. setUpdate();
  408. return true;
  409. }
  410. //-----------------------------------------------------------------------------
  411. bool GuiSpriteCtrl::setAnimation( const char* pAnimationAssetId )
  412. {
  413. // Sanity!
  414. AssertFatal( pAnimationAssetId != NULL, "Cannot use a NULL asset Id." );
  415. // Reset the image asset Id.
  416. if ( mImageAssetId != StringTable->EmptyString )
  417. mImageAssetId = StringTable->EmptyString;
  418. // Fetch the asset Id.
  419. if ( mAnimationAssetId != pAnimationAssetId )
  420. mAnimationAssetId = StringTable->insert(pAnimationAssetId);
  421. // Finish if not awake.
  422. if ( !isAwake() )
  423. return true;
  424. // Play animation asset if it's valid.
  425. if ( mAnimationAssetId != StringTable->EmptyString )
  426. ImageFrameProvider::setAnimation( mAnimationAssetId );
  427. return true;
  428. }
  429. void GuiSpriteCtrl::onRender(Point2I offset, const RectI &updateRect)
  430. {
  431. RectI ctrlRect = applyMargins(offset, mBounds.extent, NormalState, mProfile);
  432. if (!ctrlRect.isValidRect())
  433. {
  434. return;
  435. }
  436. renderUniversalRect(ctrlRect, mProfile, NormalState);
  437. RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
  438. RectI contentRect = applyPadding(fillRect.point, fillRect.extent, NormalState, mProfile);
  439. if (contentRect.isValidRect() && (usesAsset() || mBitmapName != StringTable->EmptyString))
  440. {
  441. RectI oldClip = dglGetClipRect();
  442. RectI clipRect = contentRect;
  443. if (clipRect.intersect(oldClip))
  444. {
  445. dglSetClipRect(clipRect);
  446. dglSetBitmapModulation(ColorF(mImageColor));
  447. Point2I offset = Point2I(0, 0);
  448. Point2I size = constrain(mImageSize);
  449. if (mTileImage) //Tile the image
  450. {
  451. offset = mPositionOffset;
  452. offset.x = (mPositionOffset.x % size.x);
  453. if (offset.x > 0)
  454. {
  455. offset.x -= size.x;
  456. }
  457. offset.y = (mPositionOffset.y % size.y);
  458. if (offset.y > 0)
  459. {
  460. offset.y -= size.y;
  461. }
  462. RenderTiledImage(contentRect, offset, size);
  463. }
  464. else if (mFullSize) //Fill with the image
  465. {
  466. size = constrain(contentRect.extent, false);
  467. if (mConstrainProportions)
  468. {
  469. offset = applyAlignment(contentRect, size);
  470. }
  471. RenderImage(contentRect, offset, size);
  472. }
  473. else //Position the image by profile alignment
  474. {
  475. size = constrain(mImageSize);
  476. if (size.x > contentRect.extent.x)
  477. {
  478. size.x = contentRect.extent.x;
  479. size = constrainLockX(size);
  480. }
  481. if (size.y > contentRect.extent.y)
  482. {
  483. size.y = contentRect.extent.y;
  484. size = constrainLockY(size);
  485. }
  486. offset = applyAlignment(contentRect, size);
  487. RenderImage(contentRect, offset, size);
  488. }
  489. dglClearBitmapModulation();
  490. dglSetClipRect(oldClip);
  491. //Render the childen
  492. renderChildControls(offset, contentRect, updateRect);
  493. }
  494. //One more thing...
  495. if (usesAsset() && !isStaticFrameProvider() && !isAnimationFinished() && !isAnimationPaused() && !isProcessingTicks())
  496. {
  497. setProcessTicks(true);
  498. }
  499. }
  500. }
  501. void GuiSpriteCtrl::RenderImage(RectI &bounds, Point2I &offset, Point2I &size)
  502. {
  503. TextureObject* texture = usesAsset() ? getProviderTexture() : (TextureObject *)mBitmapTextureHandle;
  504. RectI srcRegion = getSourceRect(texture);
  505. if (!srcRegion.isValidRect())
  506. {
  507. return;
  508. }
  509. RectI dstRegion = RectI(bounds.point + offset, size);
  510. dglDrawBitmapStretchSR(texture, dstRegion, srcRegion, false);
  511. }
  512. void GuiSpriteCtrl::RenderTiledImage(RectI &bounds, Point2I &start, Point2I &size)
  513. {
  514. TextureObject* texture = usesAsset() ? getProviderTexture() : (TextureObject *)mBitmapTextureHandle;
  515. RectI srcRegion = getSourceRect(texture);
  516. if (!srcRegion.isValidRect())
  517. {
  518. return;
  519. }
  520. RectI dstRegion;
  521. float xdone = ((float)(bounds.extent.x - start.x) / (float)size.x) + 1;
  522. float ydone = ((float)(bounds.extent.y - start.y) / (float)size.y) + 1;
  523. // We manually draw each repeat because non power of two textures will
  524. // not tile correctly when rendered with dglDrawBitmapTile().
  525. for (int y = 0; y < ydone; ++y)
  526. {
  527. for (int x = 0; x < xdone; ++x)
  528. {
  529. dstRegion.set((size.x * x) + start.x, (size.y * y) + start.y, size.x, size.y);
  530. dglDrawBitmapStretchSR(texture, dstRegion, srcRegion, false);
  531. }
  532. }
  533. }
  534. RectI GuiSpriteCtrl::getSourceRect(TextureObject* texture)
  535. {
  536. RectI srcRegion = RectI(0, 0, 0, 0);
  537. bool hasAsset = usesAsset();
  538. if (hasAsset)
  539. {
  540. const ImageAsset::FrameArea& frameArea = getProviderImageFrameArea();
  541. srcRegion = RectI(frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight));
  542. }
  543. else if (!hasAsset && mSingleFrameBitmap)
  544. {
  545. srcRegion = RectI(0, 0, texture->getBitmapWidth(), texture->getBitmapHeight());
  546. }
  547. else if (!hasAsset && constructBitmapArray() > mFrame)
  548. {
  549. RectI* frameRect = mBitmapArrayRects.address();
  550. srcRegion = frameRect[mFrame];
  551. }
  552. return srcRegion;
  553. }
  554. void GuiSpriteCtrl::moveTo(S32 x, S32 y, S32 time, EasingFunction ease)
  555. {
  556. mStartOffset.set(mPositionOffset.x, mPositionOffset.y);
  557. mTargetOffset.set(x, y);
  558. mFluidMoveTo.setAnimationLength(getMax(time, 0));
  559. mFluidMoveTo.setEasingFunction(ease);
  560. mFluidMoveTo.startFluidAnimation();
  561. setProcessTicks(true);
  562. }
  563. void GuiSpriteCtrl::growTo(S32 x, S32 y, S32 time, EasingFunction ease)
  564. {
  565. mStartSize.set(mImageSize.x, mImageSize.y);
  566. mTargetSize.set(x, y);
  567. mFluidGrowTo.setAnimationLength(getMax(time, 0));
  568. mFluidGrowTo.setEasingFunction(ease);
  569. mFluidGrowTo.startFluidAnimation();
  570. setProcessTicks(true);
  571. }
  572. void GuiSpriteCtrl::fadeTo(const ColorI &color, S32 time, EasingFunction ease)
  573. {
  574. mImageColor.setAnimationLength(getMax(time, 0));
  575. mImageColor.setEasingFunction(ease);
  576. mImageColor.startFluidAnimation(color);
  577. setProcessTicks(true);
  578. }
  579. void GuiSpriteCtrl::processTick()
  580. {
  581. bool shouldWeContinue = false;
  582. //Animating
  583. shouldWeContinue |= update(Tickable::smTickSec);
  584. shouldWeContinue |= animateMoveTo();
  585. shouldWeContinue |= animateGrowTo();
  586. shouldWeContinue |= animateFadeTo();
  587. if (!shouldWeContinue)
  588. {
  589. setProcessTicks(false);
  590. }
  591. }
  592. bool GuiSpriteCtrl::update(const F32 elapsedTime)
  593. {
  594. //Note: although this overrides ImageFrameProviderCore::update, the return value has a different meaning.
  595. //True means the control should continue ticking. False means the animation now longer needs tickets.
  596. // Static provider or bitmap?
  597. if (!usesAsset() || isStaticFrameProvider())
  598. {
  599. return false;
  600. }
  601. // Finish if the animation has finished or paused.
  602. if (isAnimationFinished() || isAnimationPaused())
  603. return false;
  604. // Update the animation.
  605. if (updateAnimation(elapsedTime))
  606. {
  607. setUpdate();
  608. }
  609. // Finish if the animation has NOT finished.
  610. if (!isAnimationFinished())
  611. return true;
  612. // Perform callback.
  613. onAnimationEnd();
  614. //We no longer need ticks.
  615. return false;
  616. }
  617. bool GuiSpriteCtrl::animateMoveTo()
  618. {
  619. if (!mFluidMoveTo.isAnimating())
  620. {
  621. return false;
  622. }
  623. setUpdate();
  624. F32 progress = mFluidMoveTo.getProgress(32.0f);
  625. mPositionOffset.set(
  626. mFluidMoveTo.processValue(progress, mStartOffset.x, mTargetOffset.x),
  627. mFluidMoveTo.processValue(progress, mStartOffset.y, mTargetOffset.y));
  628. if (!mFluidMoveTo.isAnimating() && isMethod("onMoveToComplete"))
  629. {
  630. Con::executef(this, 1, "onMoveToComplete");
  631. }
  632. return mFluidMoveTo.isAnimating();
  633. }
  634. bool GuiSpriteCtrl::animateGrowTo()
  635. {
  636. if (!mFluidGrowTo.isAnimating())
  637. {
  638. return false;
  639. }
  640. setUpdate();
  641. F32 progress = mFluidGrowTo.getProgress(32.0f);
  642. mImageSize.set(
  643. mFluidGrowTo.processValue(progress, mStartSize.x, mTargetSize.x),
  644. mFluidGrowTo.processValue(progress, mStartSize.y, mTargetSize.y));
  645. if (!mFluidGrowTo.isAnimating() && isMethod("onGrowToComplete"))
  646. {
  647. Con::executef(this, 1, "onGrowToComplete");
  648. }
  649. return mFluidGrowTo.isAnimating();
  650. }
  651. bool GuiSpriteCtrl::animateFadeTo()
  652. {
  653. if (!mImageColor.isAnimating())
  654. {
  655. return false;
  656. }
  657. setUpdate();
  658. mImageColor.processTick();
  659. if (!mImageColor.isAnimating() && isMethod("onFadeToComplete"))
  660. {
  661. Con::executef(this, 1, "onFadeToComplete");
  662. }
  663. return mImageColor.isAnimating();
  664. }
  665. //------------------------------------------------------------------------------
  666. void GuiSpriteCtrl::onAnimationEnd( void )
  667. {
  668. // We've arrived at the end - pause it
  669. ImageFrameProvider::pauseAnimation(true);
  670. // Send a callback
  671. if(isMethod("onAnimationEnd"))
  672. Con::executef(this, 3, "onAnimationEnd", ImageFrameProvider::getCurrentAnimationAssetId());
  673. }