Scroller.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  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 _SCROLLER_H_
  23. #include "Scroller.h"
  24. #endif
  25. #ifndef _DGL_H_
  26. #include "graphics/dgl.h"
  27. #endif
  28. #ifndef _MMATHFN_H_
  29. #include "math/mMathFn.h"
  30. #endif
  31. #ifndef _CONSOLETYPES_H_
  32. #include "console/consoleTypes.h"
  33. #endif
  34. #ifndef _BITSTREAM_H_
  35. #include "io/bitStream.h"
  36. #endif
  37. // Script bindings.
  38. #include "Scroller_ScriptBinding.h"
  39. //------------------------------------------------------------------------------
  40. IMPLEMENT_CONOBJECT(Scroller);
  41. //------------------------------------------------------------------------------
  42. Scroller::Scroller() :
  43. mRepeatX(1.0f),
  44. mRepeatY(1.0f),
  45. mScrollX(0.0f),
  46. mScrollY(0.0f),
  47. mTextureOffsetX(0.0f),
  48. mTextureOffsetY(0.0f)
  49. {
  50. // Use a static body by default.
  51. mBodyDefinition.type = b2_staticBody;
  52. // Use fixed rotation by default.
  53. mBodyDefinition.fixedRotation = true;
  54. }
  55. //------------------------------------------------------------------------------
  56. Scroller::~Scroller()
  57. {
  58. }
  59. //------------------------------------------------------------------------------
  60. void Scroller::initPersistFields()
  61. {
  62. // Call parent.
  63. Parent::initPersistFields();
  64. addProtectedField("repeatX", TypeF32, Offset(mRepeatX, Scroller), &setRepeatX, &defaultProtectedGetFn, &writeRepeatX, "");
  65. addProtectedField("repeatY", TypeF32, Offset(mRepeatY, Scroller), &setRepeatY, &defaultProtectedGetFn, &writeRepeatY, "");
  66. addField("scrollX", TypeF32, Offset(mScrollX, Scroller), &writeScrollX, "");
  67. addField("scrollY", TypeF32, Offset(mScrollY, Scroller), &writeScrollY, "");
  68. addField("scrollPositionX", TypeF32, Offset(mTextureOffsetX, Scroller), &writeScrollPositionX, "");
  69. addField("scrollPositionY", TypeF32, Offset(mTextureOffsetY, Scroller), &writeScrollPositionY, "");
  70. }
  71. //------------------------------------------------------------------------------
  72. void Scroller::copyTo(SimObject* object)
  73. {
  74. Parent::copyTo(object);
  75. AssertFatal(dynamic_cast<Scroller*>(object), "Scroller::copyTo() - Object is not the correct type.");
  76. Scroller* scroller = static_cast<Scroller*>(object);
  77. scroller->setRepeat(getRepeatX(), getRepeatY());
  78. scroller->setScroll(getScrollX(), getScrollY());
  79. scroller->setScrollPosition(getScrollPositionX(), getScrollPositionY());
  80. }
  81. //------------------------------------------------------------------------------
  82. bool Scroller::onAdd()
  83. {
  84. // Call Parent.
  85. if(!Parent::onAdd())
  86. return false;
  87. // Reset Tick Scroll Positions.
  88. resetTickScrollPositions();
  89. // Return Okay.
  90. return true;
  91. }
  92. //------------------------------------------------------------------------------
  93. void Scroller::onRemove()
  94. {
  95. // Call Parent.
  96. Parent::onRemove();
  97. }
  98. //------------------------------------------------------------------------------
  99. void Scroller::integrateObject( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
  100. {
  101. // Call Parent.
  102. Parent::integrateObject( totalTime, elapsedTime, pDebugStats );
  103. // Calculate texel shift per world-unit.
  104. const F32 scrollTexelX = mRepeatX / getSize().x;
  105. const F32 scrollTexelY = mRepeatY / getSize().y;
  106. // Calculate Scrolling Offsets.
  107. const F32 scrollOffsetX = scrollTexelX * mScrollX * elapsedTime;
  108. const F32 scrollOffsetY = scrollTexelY * mScrollY * elapsedTime;
  109. // Calculate new offset.
  110. mTextureOffsetX += scrollOffsetX;
  111. mTextureOffsetY += scrollOffsetY;
  112. // Update Tick Scroll Position.
  113. // NOTE:- We *must* do the tick update here!
  114. updateTickScrollPosition();
  115. // Make sure the offsets used don't under/overflow.
  116. // NOTE- We could simply use 'mFmod' on the offsets but unfortunately
  117. // we need to ensure that we can do a modulo simultaneously on both
  118. // the pre/post ticks values otherwise the pre/post interpolation
  119. // won't worked correctly resulting in a nasty wrap 'hitch'.
  120. // Calculate Renormalized Offsets.
  121. const F32 renormalizedPreOffsetX = mFmod( mPreTickTextureOffset.x, 1.0f );
  122. const F32 renormalizedPreOffsetY = mFmod( mPreTickTextureOffset.y, 1.0f );
  123. const F32 renormalizedPostOffsetX = mFmod( mPostTickTextureOffset.x, 1.0f );
  124. const F32 renormalizedPostOffsetY = mFmod( mPostTickTextureOffset.y, 1.0f );
  125. // Scrolling X Positive?
  126. if ( mGreaterThanZero(scrollOffsetX) )
  127. {
  128. // Yes, so old/new normalised simultaneously?
  129. if ( mLessThan(renormalizedPreOffsetX, renormalizedPostOffsetX) )
  130. {
  131. // Yes, so normalised offset.
  132. mTextureOffsetX = renormalizedPostOffsetX;
  133. // Normalise Pre/Post Ticks.
  134. mPreTickTextureOffset.x = renormalizedPreOffsetX;
  135. mPostTickTextureOffset.x = renormalizedPostOffsetX;
  136. }
  137. }
  138. else
  139. {
  140. // No, so old/new normalised simultaneously?
  141. if ( mGreaterThan(renormalizedPreOffsetX, renormalizedPostOffsetX) )
  142. {
  143. // Yes, so normalised offset.
  144. mTextureOffsetX = renormalizedPostOffsetX;
  145. // Normalise Pre/Post Ticks.
  146. mPreTickTextureOffset.x = renormalizedPreOffsetX;
  147. mPostTickTextureOffset.x = renormalizedPostOffsetX;
  148. }
  149. }
  150. // Scrolling Y Positive?
  151. if ( mGreaterThanZero(scrollOffsetY) )
  152. {
  153. // Yes, so old/new normalised proportionally?
  154. if ( mLessThan(renormalizedPreOffsetY, renormalizedPostOffsetY) )
  155. {
  156. // Yes, so normalised offset.
  157. mTextureOffsetY = renormalizedPostOffsetY;
  158. // Normalise Pre/Post Ticks.
  159. mPreTickTextureOffset.y = renormalizedPreOffsetY;
  160. mPostTickTextureOffset.y = renormalizedPostOffsetY;
  161. }
  162. }
  163. else
  164. {
  165. // No, so old/new normalised proportionally?
  166. if ( mGreaterThan(renormalizedPreOffsetY, renormalizedPostOffsetY) )
  167. {
  168. // Yes, so normalised offset.
  169. mTextureOffsetY = renormalizedPostOffsetY;
  170. // Normalise Pre/Post Ticks.
  171. mPreTickTextureOffset.y = renormalizedPreOffsetY;
  172. mPostTickTextureOffset.y = renormalizedPostOffsetY;
  173. }
  174. }
  175. }
  176. //------------------------------------------------------------------------------
  177. void Scroller::interpolateObject( const F32 timeDelta )
  178. {
  179. // Base object interpolation.
  180. Parent::interpolateObject( timeDelta );
  181. // Calculate Render Tick Position.
  182. mRenderTickTextureOffset = (timeDelta * mPreTickTextureOffset) + ((1.0f-timeDelta) * mPostTickTextureOffset);
  183. }
  184. //------------------------------------------------------------------------------
  185. void Scroller::resetTickScrollPositions( void )
  186. {
  187. // Reset Scroll Positions.
  188. mRenderTickTextureOffset.Set( mTextureOffsetX, mTextureOffsetY );
  189. mPreTickTextureOffset = mPostTickTextureOffset = mRenderTickTextureOffset;
  190. }
  191. //------------------------------------------------------------------------------
  192. void Scroller::updateTickScrollPosition( void )
  193. {
  194. // Store Pre Tick Scroll Position.
  195. mPreTickTextureOffset = mPostTickTextureOffset;
  196. // Store Current Tick Scroll Position.
  197. mPostTickTextureOffset.Set( mTextureOffsetX, mTextureOffsetY );
  198. // Render Tick Position is at Pre-Tick Scroll Position.
  199. mRenderTickTextureOffset = mPreTickTextureOffset;
  200. };
  201. //------------------------------------------------------------------------------
  202. void Scroller::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
  203. {
  204. // Finish if we can't render.
  205. if ( !ImageFrameProvider::validRender() )
  206. return;
  207. // Fetch texture and texture area.
  208. const ImageAsset::FrameArea::TexelArea& frameTexelArea = getProviderImageFrameArea().mTexelArea;
  209. TextureHandle& texture = getProviderTexture();
  210. // Calculate render offset.
  211. F32 renderOffsetX = mFmod( mRenderTickTextureOffset.x, 1.0f );
  212. F32 renderOffsetY = mFmod( mRenderTickTextureOffset.y, 1.0f );
  213. if ( renderOffsetX < 0.0f ) renderOffsetX += 1.0f;
  214. if ( renderOffsetY < 0.0f ) renderOffsetY += 1.0f;
  215. // Calculate if frame has split rendering or not.
  216. const bool isSplitRenderFrameX = mNotZero( renderOffsetX );
  217. const bool isSplitRenderFrameY = mNotZero( renderOffsetY );
  218. // Clamp Texture Offsets.
  219. const F32 textureOffsetX = frameTexelArea.mTexelWidth * renderOffsetX;
  220. const F32 textureOffsetY = frameTexelArea.mTexelHeight * renderOffsetY;
  221. // Fetch lower/upper texture coordinates.
  222. const Vector2& texLower = frameTexelArea.mTexelLower;
  223. const Vector2& texUpper = frameTexelArea.mTexelUpper;
  224. ScrollSplitRegion baseSplitRegion;
  225. // Calculate split texel regions.
  226. baseSplitRegion.mTexSplitLowerX1 = texLower.x + textureOffsetX;
  227. baseSplitRegion.mTexSplitLowerY1 = texUpper.y - textureOffsetY;
  228. baseSplitRegion.mTexSplitLowerX2 = texUpper.x;
  229. baseSplitRegion.mTexSplitLowerY2 = texLower.y;
  230. baseSplitRegion.mTexSplitUpperX1 = texLower.x;
  231. baseSplitRegion.mTexSplitUpperY1 = texUpper.y;
  232. baseSplitRegion.mTexSplitUpperX2 = baseSplitRegion.mTexSplitLowerX1;
  233. baseSplitRegion.mTexSplitUpperY2 = baseSplitRegion.mTexSplitLowerY1;
  234. // Fetch render area.
  235. const Vector2& renderOOBB0 = mRenderOOBB[0];
  236. const Vector2& renderOOBB1 = mRenderOOBB[1];
  237. const Vector2& renderOOBB3 = mRenderOOBB[3];
  238. // Calculate region dimensions.
  239. const F32 regionWidth = (renderOOBB1.x - renderOOBB0.x) / mRepeatX;
  240. const F32 regionHeight = (renderOOBB3.y - renderOOBB0.y) / mRepeatY;
  241. // Calculate split region dimensions.
  242. const F32 splitRegionWidth = regionWidth * (1.0f-renderOffsetX);
  243. const F32 splitRegionHeight = regionHeight * (1.0f-renderOffsetY);
  244. // Calculate split vertex regions.
  245. baseSplitRegion.mVertSplitLowerX1 = renderOOBB0.x;
  246. baseSplitRegion.mVertSplitLowerX2 = renderOOBB0.x + splitRegionWidth;
  247. baseSplitRegion.mVertSplitUpperX1 = baseSplitRegion.mVertSplitLowerX2;
  248. baseSplitRegion.mVertSplitUpperX2 = renderOOBB0.x + regionWidth;
  249. baseSplitRegion.mVertSplitLowerY1 = renderOOBB0.y;
  250. baseSplitRegion.mVertSplitLowerY2 = renderOOBB0.y + splitRegionHeight;
  251. baseSplitRegion.mVertSplitUpperY1 = baseSplitRegion.mVertSplitLowerY2;
  252. baseSplitRegion.mVertSplitUpperY2 = renderOOBB0.y + regionHeight;
  253. // Fetch the whole regions.
  254. const S32 wholeRegionX = (S32)mCeil( mRepeatX );
  255. const S32 wholeRegionY = (S32)mCeil( mRepeatY );
  256. // Flush any existing batches.
  257. pBatchRenderer->flush();
  258. // jamesu - no clip planes in webgl
  259. #ifndef TORQUE_OS_EMSCRIPTEN
  260. // Set-up a set of clip-planes against the OOBB.
  261. GLdouble left[4] = {1, 0, 0, -renderOOBB0.x};
  262. GLdouble right[4] = {-1, 0, 0, renderOOBB1.x};
  263. GLdouble top[4] = {0, -1, 0, renderOOBB3.y};
  264. GLdouble bottom[4] = {0, 1, 0, -renderOOBB0.y};
  265. //This is to prevent some android devices from throwing opengl errors. For instance the tegra 3 only supports 1
  266. int maxClip = 4;
  267. glGetIntegerv(GL_MAX_CLIP_PLANES, &maxClip);
  268. glClipPlane(GL_CLIP_PLANE0, left);
  269. if (maxClip > 1)
  270. glClipPlane(GL_CLIP_PLANE1, right);
  271. if (maxClip > 2)
  272. glClipPlane(GL_CLIP_PLANE2, top);
  273. if (maxClip > 3)
  274. glClipPlane(GL_CLIP_PLANE3, bottom);
  275. glEnable(GL_CLIP_PLANE0);
  276. if (maxClip > 1)
  277. glEnable(GL_CLIP_PLANE1);
  278. if (maxClip > 2)
  279. glEnable(GL_CLIP_PLANE2);
  280. if (maxClip > 3)
  281. glEnable(GL_CLIP_PLANE3);
  282. #endif
  283. // Render repeat Y.
  284. for ( S32 repeatIndexY = 0; repeatIndexY < wholeRegionY; ++repeatIndexY )
  285. {
  286. // Set base split region.
  287. ScrollSplitRegion splitRegion = baseSplitRegion;
  288. // Move vertex if appropriate.
  289. if ( repeatIndexY > 0 )
  290. splitRegion.addVertexOffset( 0.0f, regionHeight * repeatIndexY );
  291. // Render repeat X.
  292. for ( S32 repeatIndexX = 0; repeatIndexX < wholeRegionX; ++repeatIndexX )
  293. {
  294. // Split in X only?
  295. if ( isSplitRenderFrameX && !isSplitRenderFrameY )
  296. {
  297. renderRegionSplitX( pBatchRenderer, texture, splitRegion );
  298. }
  299. // Split in Y only?
  300. else if ( !isSplitRenderFrameX && isSplitRenderFrameY )
  301. {
  302. renderRegionSplitY( pBatchRenderer, texture, splitRegion );
  303. }
  304. // Split in X and Y?
  305. else if ( isSplitRenderFrameX && isSplitRenderFrameY )
  306. {
  307. renderRegionSplitXY( pBatchRenderer, texture, splitRegion );
  308. }
  309. // Not split.
  310. else
  311. {
  312. renderRegionNoSplit( pBatchRenderer, texture, splitRegion );
  313. }
  314. // Offset vertexes.
  315. splitRegion.addVertexOffset( regionWidth, 0.0f );
  316. }
  317. }
  318. // Flush the scroller batches.
  319. pBatchRenderer->flush();
  320. #ifndef TORQUE_OS_EMSCRIPTEN
  321. // Disable the OOBB clip-planes.
  322. glDisable(GL_CLIP_PLANE0);
  323. if (maxClip > 1)
  324. glDisable(GL_CLIP_PLANE1);
  325. if (maxClip > 2)
  326. glDisable(GL_CLIP_PLANE2);
  327. if (maxClip > 3)
  328. glDisable(GL_CLIP_PLANE3);
  329. #endif
  330. }
  331. //------------------------------------------------------------------------------
  332. void Scroller::renderRegionSplitX( BatchRender* pBatchRenderer, TextureHandle& texture, const ScrollSplitRegion& splitRegion )
  333. {
  334. // Submit batched quad.
  335. pBatchRenderer->SubmitQuad(
  336. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitLowerY1 ),
  337. Vector2( splitRegion.mVertSplitLowerX2, splitRegion.mVertSplitLowerY1 ),
  338. Vector2( splitRegion.mVertSplitLowerX2, splitRegion.mVertSplitUpperY2 ),
  339. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitUpperY2 ),
  340. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY1 ),
  341. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY1 ),
  342. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY2 ),
  343. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY2 ),
  344. texture );
  345. // Submit batched quad.
  346. pBatchRenderer->SubmitQuad(
  347. Vector2( splitRegion.mVertSplitUpperX1, splitRegion.mVertSplitLowerY1 ),
  348. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitLowerY1 ),
  349. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitUpperY2 ),
  350. Vector2( splitRegion.mVertSplitUpperX1, splitRegion.mVertSplitUpperY2 ),
  351. Vector2( splitRegion.mTexSplitUpperX1, splitRegion.mTexSplitLowerY1 ),
  352. Vector2( splitRegion.mTexSplitUpperX2, splitRegion.mTexSplitLowerY1 ),
  353. Vector2( splitRegion.mTexSplitUpperX2, splitRegion.mTexSplitLowerY2 ),
  354. Vector2( splitRegion.mTexSplitUpperX1, splitRegion.mTexSplitLowerY2 ),
  355. texture );
  356. }
  357. //------------------------------------------------------------------------------
  358. void Scroller::renderRegionSplitY( BatchRender* pBatchRenderer, TextureHandle& texture, const ScrollSplitRegion& splitRegion )
  359. {
  360. // Submit batched quad.
  361. pBatchRenderer->SubmitQuad(
  362. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitLowerY1 ),
  363. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitLowerY1 ),
  364. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitLowerY2 ),
  365. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitLowerY2 ),
  366. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY1 ),
  367. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY1 ),
  368. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY2 ),
  369. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY2 ),
  370. texture );
  371. // Submit batched quad.
  372. pBatchRenderer->SubmitQuad(
  373. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitUpperY1 ),
  374. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitUpperY1 ),
  375. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitUpperY2 ),
  376. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitUpperY2 ),
  377. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitUpperY1 ),
  378. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitUpperY1 ),
  379. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitUpperY2 ),
  380. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitUpperY2 ),
  381. texture );
  382. }
  383. //------------------------------------------------------------------------------
  384. void Scroller::renderRegionSplitXY( BatchRender* pBatchRenderer, TextureHandle& texture, const ScrollSplitRegion& splitRegion )
  385. {
  386. // Submit batched quad.
  387. pBatchRenderer->SubmitQuad(
  388. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitLowerY1 ),
  389. Vector2( splitRegion.mVertSplitLowerX2, splitRegion.mVertSplitLowerY1 ),
  390. Vector2( splitRegion.mVertSplitLowerX2, splitRegion.mVertSplitLowerY2 ),
  391. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitLowerY2 ),
  392. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY1 ),
  393. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY1 ),
  394. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY2 ),
  395. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY2 ),
  396. texture );
  397. // Submit batched quad.
  398. pBatchRenderer->SubmitQuad(
  399. Vector2( splitRegion.mVertSplitUpperX1, splitRegion.mVertSplitLowerY1 ),
  400. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitLowerY1 ),
  401. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitLowerY2 ),
  402. Vector2( splitRegion.mVertSplitUpperX1, splitRegion.mVertSplitLowerY2 ),
  403. Vector2( splitRegion.mTexSplitUpperX1, splitRegion.mTexSplitLowerY1 ),
  404. Vector2( splitRegion.mTexSplitUpperX2, splitRegion.mTexSplitLowerY1 ),
  405. Vector2( splitRegion.mTexSplitUpperX2, splitRegion.mTexSplitLowerY2 ),
  406. Vector2( splitRegion.mTexSplitUpperX1, splitRegion.mTexSplitLowerY2 ),
  407. texture );
  408. // Submit batched quad.
  409. pBatchRenderer->SubmitQuad(
  410. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitUpperY1 ),
  411. Vector2( splitRegion.mVertSplitLowerX2, splitRegion.mVertSplitUpperY1 ),
  412. Vector2( splitRegion.mVertSplitLowerX2, splitRegion.mVertSplitUpperY2 ),
  413. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitUpperY2 ),
  414. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitUpperY1 ),
  415. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitUpperY1 ),
  416. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitUpperY2 ),
  417. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitUpperY2 ),
  418. texture );
  419. // Submit batched quad.
  420. pBatchRenderer->SubmitQuad(
  421. Vector2( splitRegion.mVertSplitUpperX1, splitRegion.mVertSplitUpperY1 ),
  422. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitUpperY1 ),
  423. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitUpperY2 ),
  424. Vector2( splitRegion.mVertSplitUpperX1, splitRegion.mVertSplitUpperY2 ),
  425. Vector2( splitRegion.mTexSplitUpperX1, splitRegion.mTexSplitUpperY1 ),
  426. Vector2( splitRegion.mTexSplitUpperX2, splitRegion.mTexSplitUpperY1 ),
  427. Vector2( splitRegion.mTexSplitUpperX2, splitRegion.mTexSplitUpperY2 ),
  428. Vector2( splitRegion.mTexSplitUpperX1, splitRegion.mTexSplitUpperY2 ),
  429. texture );
  430. }
  431. //------------------------------------------------------------------------------
  432. void Scroller::renderRegionNoSplit( BatchRender* pBatchRenderer, TextureHandle& texture, const ScrollSplitRegion& splitRegion )
  433. {
  434. // Submit batched quad.
  435. pBatchRenderer->SubmitQuad(
  436. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitLowerY1 ),
  437. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitLowerY1 ),
  438. Vector2( splitRegion.mVertSplitUpperX2, splitRegion.mVertSplitUpperY2 ),
  439. Vector2( splitRegion.mVertSplitLowerX1, splitRegion.mVertSplitUpperY2 ),
  440. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY1 ),
  441. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY1 ),
  442. Vector2( splitRegion.mTexSplitLowerX2, splitRegion.mTexSplitLowerY2 ),
  443. Vector2( splitRegion.mTexSplitLowerX1, splitRegion.mTexSplitLowerY2 ),
  444. texture );
  445. }
  446. //------------------------------------------------------------------------------
  447. void Scroller::setRepeat( const F32 repeatX, const F32 repeatY )
  448. {
  449. // Warn.
  450. if ( repeatX <= 0.0f || repeatY <= 0.0f )
  451. {
  452. Con::warnf("Scroller::setRepeat() - Repeats must be greater than zero!");
  453. return;
  454. }
  455. // Set Repeat X/Y.
  456. mRepeatX = repeatX;
  457. mRepeatY = repeatY;
  458. }
  459. //------------------------------------------------------------------------------
  460. void Scroller::setScroll( F32 scrollX, F32 scrollY )
  461. {
  462. // Set Scroll X/Y.
  463. mScrollX = scrollX;
  464. mScrollY = scrollY;
  465. // Reset Tick Scroll Positions.
  466. resetTickScrollPositions();
  467. }
  468. //------------------------------------------------------------------------------
  469. void Scroller::setScrollPosition( F32 scrollX, F32 scrollY )
  470. {
  471. // Yes, so calculate texel shift per world-unit.
  472. const F32 scrollTexelX = mRepeatX / getSize().x;
  473. const F32 scrollTexelY = mRepeatY / getSize().y;
  474. // Calculate new offset and clamp.
  475. mTextureOffsetX = mFmod( scrollTexelX * scrollX, 1.0f );
  476. mTextureOffsetY = mFmod( scrollTexelY * scrollY, 1.0f );
  477. // Reset Tick Scroll Positions.
  478. resetTickScrollPositions();
  479. }