SpriteBatch.hx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. package h2d;
  2. private class ElementsIterator {
  3. var e : BatchElement;
  4. public inline function new(e) {
  5. this.e = e;
  6. }
  7. public inline function hasNext() {
  8. return e != null;
  9. }
  10. public inline function next() {
  11. var n = e;
  12. e = @:privateAccess e.next;
  13. return n;
  14. }
  15. }
  16. @:allow(h2d.SpriteBatch)
  17. class BatchElement {
  18. public var x : Float;
  19. public var y : Float;
  20. public var scale : Float;
  21. public var rotation : Float;
  22. public var r : Float;
  23. public var g : Float;
  24. public var b : Float;
  25. public var a : Float;
  26. public var t : Tile;
  27. public var alpha(get,set) : Float;
  28. public var batch(default, null) : SpriteBatch;
  29. var prev : BatchElement;
  30. var next : BatchElement;
  31. function new(t) {
  32. x = 0; y = 0; r = 1; g = 1; b = 1; a = 1;
  33. rotation = 0; scale = 1;
  34. this.t = t;
  35. }
  36. inline function get_alpha() {
  37. return a;
  38. }
  39. inline function set_alpha(v) {
  40. return a = v;
  41. }
  42. function update(et:Float) {
  43. return true;
  44. }
  45. public inline function remove() {
  46. batch.delete(this);
  47. }
  48. }
  49. class SpriteBatch extends Drawable {
  50. public var tile : Tile;
  51. public var hasRotationScale : Bool;
  52. public var hasUpdate : Bool;
  53. var first : BatchElement;
  54. var last : BatchElement;
  55. var tmpBuf : hxd.FloatBuffer;
  56. public function new(t,?parent) {
  57. super(parent);
  58. tile = t;
  59. }
  60. public function add(e:BatchElement) {
  61. e.batch = this;
  62. if( first == null )
  63. first = last = e;
  64. else {
  65. last.next = e;
  66. e.prev = last;
  67. last = e;
  68. }
  69. return e;
  70. }
  71. public function alloc(t) {
  72. return add(new BatchElement(t));
  73. }
  74. @:allow(h2d.BatchElement)
  75. function delete(e : BatchElement) {
  76. if( e.prev == null ) {
  77. if( first == e )
  78. first = e.next;
  79. } else
  80. e.prev.next = e.next;
  81. if( e.next == null ) {
  82. if( last == e )
  83. last = e.prev;
  84. } else
  85. e.next.prev = e.prev;
  86. }
  87. override function sync(ctx) {
  88. super.sync(ctx);
  89. if( hasUpdate ) {
  90. var e = first;
  91. while( e != null ) {
  92. if( !e.update(ctx.elapsedTime) )
  93. e.remove();
  94. e = e.next;
  95. }
  96. }
  97. }
  98. override function getBoundsRec( relativeTo, out ) {
  99. super.getBoundsRec(relativeTo, out);
  100. var e = first;
  101. while( e != null ) {
  102. var t = e.t;
  103. if( hasRotationScale ) {
  104. var ca = Math.cos(e.rotation), sa = Math.sin(e.rotation);
  105. var hx = t.width, hy = t.height;
  106. var px = t.dx, py = t.dy;
  107. var x, y;
  108. x = (px * ca - py * sa) * e.scale + e.x;
  109. y = (py * ca + px * sa) * e.scale + e.y;
  110. addBounds(relativeTo, out, x, y, 1e-10, 1e-10);
  111. var px = t.dx + hx, py = t.dy;
  112. x = (px * ca - py * sa) * e.scale + e.x;
  113. y = (py * ca + px * sa) * e.scale + e.y;
  114. addBounds(relativeTo, out, x, y, 1e-10, 1e-10);
  115. var px = t.dx, py = t.dy + hy;
  116. x = (px * ca - py * sa) * e.scale + e.x;
  117. y = (py * ca + px * sa) * e.scale + e.y;
  118. addBounds(relativeTo, out, x, y, 1e-10, 1e-10);
  119. var px = t.dx + hx, py = t.dy + hy;
  120. x = (px * ca - py * sa) * e.scale + e.x;
  121. y = (py * ca + px * sa) * e.scale + e.y;
  122. addBounds(relativeTo, out, x, y, 1e-10, 1e-10);
  123. } else
  124. addBounds(relativeTo, out, e.x + tile.dx, e.y + tile.dy, tile.width, tile.height);
  125. e = e.next;
  126. }
  127. }
  128. override function draw( ctx : RenderContext ) {
  129. if( first == null )
  130. return;
  131. if( tmpBuf == null ) tmpBuf = new hxd.FloatBuffer();
  132. var pos = 0;
  133. var e = first;
  134. var tmp = tmpBuf;
  135. while( e != null ) {
  136. var t = e.t;
  137. if( hasRotationScale ) {
  138. var ca = Math.cos(e.rotation), sa = Math.sin(e.rotation);
  139. var hx = t.width, hy = t.height;
  140. var px = t.dx, py = t.dy;
  141. tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
  142. tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
  143. tmp[pos++] = t.u;
  144. tmp[pos++] = t.v;
  145. tmp[pos++] = e.r;
  146. tmp[pos++] = e.g;
  147. tmp[pos++] = e.b;
  148. tmp[pos++] = e.a;
  149. var px = t.dx + hx, py = t.dy;
  150. tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
  151. tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
  152. tmp[pos++] = t.u2;
  153. tmp[pos++] = t.v;
  154. tmp[pos++] = e.r;
  155. tmp[pos++] = e.g;
  156. tmp[pos++] = e.b;
  157. tmp[pos++] = e.a;
  158. var px = t.dx, py = t.dy + hy;
  159. tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
  160. tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
  161. tmp[pos++] = t.u;
  162. tmp[pos++] = t.v2;
  163. tmp[pos++] = e.r;
  164. tmp[pos++] = e.g;
  165. tmp[pos++] = e.b;
  166. tmp[pos++] = e.a;
  167. var px = t.dx + hx, py = t.dy + hy;
  168. tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
  169. tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
  170. tmp[pos++] = t.u2;
  171. tmp[pos++] = t.v2;
  172. tmp[pos++] = e.r;
  173. tmp[pos++] = e.g;
  174. tmp[pos++] = e.b;
  175. tmp[pos++] = e.a;
  176. } else {
  177. var sx = e.x + t.dx;
  178. var sy = e.y + t.dy;
  179. tmp[pos++] = sx;
  180. tmp[pos++] = sy;
  181. tmp[pos++] = t.u;
  182. tmp[pos++] = t.v;
  183. tmp[pos++] = e.r;
  184. tmp[pos++] = e.g;
  185. tmp[pos++] = e.b;
  186. tmp[pos++] = e.a;
  187. tmp[pos++] = sx + t.width + 0.1;
  188. tmp[pos++] = sy;
  189. tmp[pos++] = t.u2;
  190. tmp[pos++] = t.v;
  191. tmp[pos++] = e.r;
  192. tmp[pos++] = e.g;
  193. tmp[pos++] = e.b;
  194. tmp[pos++] = e.a;
  195. tmp[pos++] = sx;
  196. tmp[pos++] = sy + t.height + 0.1;
  197. tmp[pos++] = t.u;
  198. tmp[pos++] = t.v2;
  199. tmp[pos++] = e.r;
  200. tmp[pos++] = e.g;
  201. tmp[pos++] = e.b;
  202. tmp[pos++] = e.a;
  203. tmp[pos++] = sx + t.width + 0.1;
  204. tmp[pos++] = sy + t.height + 0.1;
  205. tmp[pos++] = t.u2;
  206. tmp[pos++] = t.v2;
  207. tmp[pos++] = e.r;
  208. tmp[pos++] = e.g;
  209. tmp[pos++] = e.b;
  210. tmp[pos++] = e.a;
  211. }
  212. e = e.next;
  213. }
  214. var buffer = h3d.Buffer.ofFloats(tmpBuf, 8, [Dynamic, Quads]);
  215. ctx.beginDrawObject(this, tile.getTexture());
  216. ctx.engine.renderQuadBuffer(buffer);
  217. buffer.dispose();
  218. }
  219. public inline function isEmpty() {
  220. return first == null;
  221. }
  222. public inline function getElements() {
  223. return new ElementsIterator(first);
  224. }
  225. }