babylon.spriteManager.ts 10 KB

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