babylon.spriteManager.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. var BABYLON;
  2. (function (BABYLON) {
  3. var SpriteManager = (function () {
  4. function SpriteManager(name, imgUrl, capacity, cellSize, scene, epsilon, samplingMode) {
  5. if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
  6. this.name = name;
  7. this.sprites = new Array();
  8. this.renderingGroupId = 0;
  9. this.layerMask = 0x0FFFFFFF;
  10. this.fogEnabled = true;
  11. this.isPickable = false;
  12. /**
  13. * An event triggered when the manager is disposed.
  14. * @type {BABYLON.Observable}
  15. */
  16. this.onDisposeObservable = new BABYLON.Observable();
  17. this._vertexBuffers = {};
  18. this._capacity = capacity;
  19. this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false, samplingMode);
  20. this._spriteTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
  21. this._spriteTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
  22. this._epsilon = epsilon === undefined ? 0.01 : epsilon;
  23. if (cellSize.width) {
  24. this.cellWidth = cellSize.width;
  25. this.cellHeight = cellSize.height;
  26. }
  27. else {
  28. this.cellWidth = cellSize;
  29. this.cellHeight = cellSize;
  30. }
  31. this._scene = scene;
  32. this._scene.spriteManagers.push(this);
  33. var indices = [];
  34. var index = 0;
  35. for (var count = 0; count < capacity; count++) {
  36. indices.push(index);
  37. indices.push(index + 1);
  38. indices.push(index + 2);
  39. indices.push(index);
  40. indices.push(index + 2);
  41. indices.push(index + 3);
  42. index += 4;
  43. }
  44. this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
  45. // VBO
  46. // 16 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color r, color g, color b, color a)
  47. this._vertexData = new Float32Array(capacity * 16 * 4);
  48. this._buffer = new BABYLON.Buffer(scene.getEngine(), this._vertexData, true, 16);
  49. var positions = this._buffer.createVertexBuffer(BABYLON.VertexBuffer.PositionKind, 0, 4);
  50. var options = this._buffer.createVertexBuffer("options", 4, 4);
  51. var cellInfo = this._buffer.createVertexBuffer("cellInfo", 8, 4);
  52. var colors = this._buffer.createVertexBuffer(BABYLON.VertexBuffer.ColorKind, 12, 4);
  53. this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = positions;
  54. this._vertexBuffers["options"] = options;
  55. this._vertexBuffers["cellInfo"] = cellInfo;
  56. this._vertexBuffers[BABYLON.VertexBuffer.ColorKind] = colors;
  57. // Effects
  58. this._effectBase = this._scene.getEngine().createEffect("sprites", [BABYLON.VertexBuffer.PositionKind, "options", "cellInfo", BABYLON.VertexBuffer.ColorKind], ["view", "projection", "textureInfos", "alphaTest"], ["diffuseSampler"], "");
  59. this._effectFog = this._scene.getEngine().createEffect("sprites", [BABYLON.VertexBuffer.PositionKind, "options", "cellInfo", BABYLON.VertexBuffer.ColorKind], ["view", "projection", "textureInfos", "alphaTest", "vFogInfos", "vFogColor"], ["diffuseSampler"], "#define FOG");
  60. }
  61. Object.defineProperty(SpriteManager.prototype, "onDispose", {
  62. set: function (callback) {
  63. if (this._onDisposeObserver) {
  64. this.onDisposeObservable.remove(this._onDisposeObserver);
  65. }
  66. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  67. },
  68. enumerable: true,
  69. configurable: true
  70. });
  71. Object.defineProperty(SpriteManager.prototype, "texture", {
  72. get: function () {
  73. return this._spriteTexture;
  74. },
  75. set: function (value) {
  76. this._spriteTexture = value;
  77. },
  78. enumerable: true,
  79. configurable: true
  80. });
  81. SpriteManager.prototype._appendSpriteVertex = function (index, sprite, offsetX, offsetY, rowSize) {
  82. var arrayOffset = index * 16;
  83. if (offsetX === 0)
  84. offsetX = this._epsilon;
  85. else if (offsetX === 1)
  86. offsetX = 1 - this._epsilon;
  87. if (offsetY === 0)
  88. offsetY = this._epsilon;
  89. else if (offsetY === 1)
  90. offsetY = 1 - this._epsilon;
  91. this._vertexData[arrayOffset] = sprite.position.x;
  92. this._vertexData[arrayOffset + 1] = sprite.position.y;
  93. this._vertexData[arrayOffset + 2] = sprite.position.z;
  94. this._vertexData[arrayOffset + 3] = sprite.angle;
  95. this._vertexData[arrayOffset + 4] = sprite.width;
  96. this._vertexData[arrayOffset + 5] = sprite.height;
  97. this._vertexData[arrayOffset + 6] = offsetX;
  98. this._vertexData[arrayOffset + 7] = offsetY;
  99. this._vertexData[arrayOffset + 8] = sprite.invertU ? 1 : 0;
  100. this._vertexData[arrayOffset + 9] = sprite.invertV ? 1 : 0;
  101. var offset = (sprite.cellIndex / rowSize) >> 0;
  102. this._vertexData[arrayOffset + 10] = sprite.cellIndex - offset * rowSize;
  103. this._vertexData[arrayOffset + 11] = offset;
  104. // Color
  105. this._vertexData[arrayOffset + 12] = sprite.color.r;
  106. this._vertexData[arrayOffset + 13] = sprite.color.g;
  107. this._vertexData[arrayOffset + 14] = sprite.color.b;
  108. this._vertexData[arrayOffset + 15] = sprite.color.a;
  109. };
  110. SpriteManager.prototype.intersects = function (ray, camera, predicate, fastCheck) {
  111. var count = Math.min(this._capacity, this.sprites.length);
  112. var min = BABYLON.Vector3.Zero();
  113. var max = BABYLON.Vector3.Zero();
  114. var distance = Number.MAX_VALUE;
  115. var currentSprite;
  116. var cameraSpacePosition = BABYLON.Vector3.Zero();
  117. var cameraView = camera.getViewMatrix();
  118. for (var index = 0; index < count; index++) {
  119. var sprite = this.sprites[index];
  120. if (!sprite) {
  121. continue;
  122. }
  123. if (predicate) {
  124. if (!predicate(sprite)) {
  125. continue;
  126. }
  127. }
  128. else if (!sprite.isPickable) {
  129. continue;
  130. }
  131. BABYLON.Vector3.TransformCoordinatesToRef(sprite.position, cameraView, cameraSpacePosition);
  132. min.copyFromFloats(cameraSpacePosition.x - sprite.width / 2, cameraSpacePosition.y - sprite.height / 2, cameraSpacePosition.z);
  133. max.copyFromFloats(cameraSpacePosition.x + sprite.width / 2, cameraSpacePosition.y + sprite.height / 2, cameraSpacePosition.z);
  134. if (ray.intersectsBoxMinMax(min, max)) {
  135. var currentDistance = BABYLON.Vector3.Distance(cameraSpacePosition, ray.origin);
  136. if (distance > currentDistance) {
  137. distance = currentDistance;
  138. currentSprite = sprite;
  139. if (fastCheck) {
  140. break;
  141. }
  142. }
  143. }
  144. }
  145. if (currentSprite) {
  146. var result = new BABYLON.PickingInfo();
  147. result.hit = true;
  148. result.pickedSprite = currentSprite;
  149. result.distance = distance;
  150. return result;
  151. }
  152. return null;
  153. };
  154. SpriteManager.prototype.render = function () {
  155. // Check
  156. if (!this._effectBase.isReady() || !this._effectFog.isReady() || !this._spriteTexture || !this._spriteTexture.isReady())
  157. return;
  158. var engine = this._scene.getEngine();
  159. var baseSize = this._spriteTexture.getBaseSize();
  160. // Sprites
  161. var deltaTime = engine.getDeltaTime();
  162. var max = Math.min(this._capacity, this.sprites.length);
  163. var rowSize = baseSize.width / this.cellWidth;
  164. var offset = 0;
  165. for (var index = 0; index < max; index++) {
  166. var sprite = this.sprites[index];
  167. if (!sprite) {
  168. continue;
  169. }
  170. sprite._animate(deltaTime);
  171. this._appendSpriteVertex(offset++, sprite, 0, 0, rowSize);
  172. this._appendSpriteVertex(offset++, sprite, 1, 0, rowSize);
  173. this._appendSpriteVertex(offset++, sprite, 1, 1, rowSize);
  174. this._appendSpriteVertex(offset++, sprite, 0, 1, rowSize);
  175. }
  176. this._buffer.update(this._vertexData);
  177. // Render
  178. var effect = this._effectBase;
  179. if (this._scene.fogEnabled && this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
  180. effect = this._effectFog;
  181. }
  182. engine.enableEffect(effect);
  183. var viewMatrix = this._scene.getViewMatrix();
  184. effect.setTexture("diffuseSampler", this._spriteTexture);
  185. effect.setMatrix("view", viewMatrix);
  186. effect.setMatrix("projection", this._scene.getProjectionMatrix());
  187. effect.setFloat2("textureInfos", this.cellWidth / baseSize.width, this.cellHeight / baseSize.height);
  188. // Fog
  189. if (this._scene.fogEnabled && this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
  190. effect.setFloat4("vFogInfos", this._scene.fogMode, this._scene.fogStart, this._scene.fogEnd, this._scene.fogDensity);
  191. effect.setColor3("vFogColor", this._scene.fogColor);
  192. }
  193. // VBOs
  194. engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
  195. // Draw order
  196. engine.setDepthFunctionToLessOrEqual();
  197. effect.setBool("alphaTest", true);
  198. engine.setColorWrite(false);
  199. engine.draw(true, 0, max * 6);
  200. engine.setColorWrite(true);
  201. effect.setBool("alphaTest", false);
  202. engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
  203. engine.draw(true, 0, max * 6);
  204. engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
  205. };
  206. SpriteManager.prototype.dispose = function () {
  207. if (this._buffer) {
  208. this._buffer.dispose();
  209. this._buffer = null;
  210. }
  211. if (this._indexBuffer) {
  212. this._scene.getEngine()._releaseBuffer(this._indexBuffer);
  213. this._indexBuffer = null;
  214. }
  215. if (this._spriteTexture) {
  216. this._spriteTexture.dispose();
  217. this._spriteTexture = null;
  218. }
  219. // Remove from scene
  220. var index = this._scene.spriteManagers.indexOf(this);
  221. this._scene.spriteManagers.splice(index, 1);
  222. // Callback
  223. this.onDisposeObservable.notifyObservers(this);
  224. this.onDisposeObservable.clear();
  225. };
  226. return SpriteManager;
  227. }());
  228. BABYLON.SpriteManager = SpriteManager;
  229. })(BABYLON || (BABYLON = {}));