babylon.sprite2d.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. var __extends = (this && this.__extends) || function (d, b) {
  2. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  3. function __() { this.constructor = d; }
  4. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  5. };
  6. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  7. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  8. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  9. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  10. return c > 3 && r && Object.defineProperty(target, key, r), r;
  11. };
  12. var BABYLON;
  13. (function (BABYLON) {
  14. var Sprite2DRenderCache = (function (_super) {
  15. __extends(Sprite2DRenderCache, _super);
  16. function Sprite2DRenderCache() {
  17. _super.apply(this, arguments);
  18. this.effectsReady = false;
  19. this.vb = null;
  20. this.ib = null;
  21. this.instancingAttributes = null;
  22. this.texture = null;
  23. this.effect = null;
  24. this.effectInstanced = null;
  25. }
  26. Sprite2DRenderCache.prototype.render = function (instanceInfo, context) {
  27. // Do nothing if the shader is still loading/preparing
  28. if (!this.effectsReady) {
  29. if ((this.effect && (!this.effect.isReady() || (this.effectInstanced && !this.effectInstanced.isReady())))) {
  30. return false;
  31. }
  32. this.effectsReady = true;
  33. }
  34. // Compute the offset locations of the attributes in the vertex shader that will be mapped to the instance buffer data
  35. var canvas = instanceInfo.owner.owner;
  36. var engine = canvas.engine;
  37. var cur = engine.getAlphaMode();
  38. var effect = context.useInstancing ? this.effectInstanced : this.effect;
  39. engine.enableEffect(effect);
  40. effect.setTexture("diffuseSampler", this.texture);
  41. engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, effect);
  42. if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
  43. engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
  44. }
  45. var pid = context.groupInfoPartData[0];
  46. if (context.useInstancing) {
  47. if (!this.instancingAttributes) {
  48. this.instancingAttributes = this.loadInstancingAttributes(Sprite2D.SPRITE2D_MAINPARTID, effect);
  49. }
  50. var glBuffer = context.instancedBuffers ? context.instancedBuffers[0] : pid._partBuffer;
  51. var count = context.instancedBuffers ? context.instancesCount : pid._partData.usedElementCount;
  52. canvas._addDrawCallCount(1, context.renderMode);
  53. engine.updateAndBindInstancesBuffer(glBuffer, null, this.instancingAttributes);
  54. engine.draw(true, 0, 6, count);
  55. engine.unbindInstanceAttributes();
  56. }
  57. else {
  58. canvas._addDrawCallCount(context.partDataEndIndex - context.partDataStartIndex, context.renderMode);
  59. for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
  60. this.setupUniforms(effect, 0, pid._partData, i);
  61. engine.draw(true, 0, 6);
  62. }
  63. }
  64. engine.setAlphaMode(cur);
  65. return true;
  66. };
  67. Sprite2DRenderCache.prototype.dispose = function () {
  68. if (!_super.prototype.dispose.call(this)) {
  69. return false;
  70. }
  71. if (this.vb) {
  72. this._engine._releaseBuffer(this.vb);
  73. this.vb = null;
  74. }
  75. if (this.ib) {
  76. this._engine._releaseBuffer(this.ib);
  77. this.ib = null;
  78. }
  79. if (this.texture) {
  80. this.texture.dispose();
  81. this.texture = null;
  82. }
  83. if (this.effect) {
  84. this._engine._releaseEffect(this.effect);
  85. this.effect = null;
  86. }
  87. if (this.effectInstanced) {
  88. this._engine._releaseEffect(this.effectInstanced);
  89. this.effectInstanced = null;
  90. }
  91. return true;
  92. };
  93. return Sprite2DRenderCache;
  94. })(BABYLON.ModelRenderCache);
  95. BABYLON.Sprite2DRenderCache = Sprite2DRenderCache;
  96. var Sprite2DInstanceData = (function (_super) {
  97. __extends(Sprite2DInstanceData, _super);
  98. function Sprite2DInstanceData(partId) {
  99. _super.call(this, partId, 1);
  100. }
  101. Object.defineProperty(Sprite2DInstanceData.prototype, "topLeftUV", {
  102. get: function () {
  103. return null;
  104. },
  105. enumerable: true,
  106. configurable: true
  107. });
  108. Object.defineProperty(Sprite2DInstanceData.prototype, "sizeUV", {
  109. get: function () {
  110. return null;
  111. },
  112. enumerable: true,
  113. configurable: true
  114. });
  115. Object.defineProperty(Sprite2DInstanceData.prototype, "textureSize", {
  116. get: function () {
  117. return null;
  118. },
  119. enumerable: true,
  120. configurable: true
  121. });
  122. Object.defineProperty(Sprite2DInstanceData.prototype, "properties", {
  123. // 3 floats being:
  124. // - x: frame number to display
  125. // - y: invertY setting
  126. // - z: alignToPixel setting
  127. get: function () {
  128. return null;
  129. },
  130. enumerable: true,
  131. configurable: true
  132. });
  133. __decorate([
  134. BABYLON.instanceData()
  135. ], Sprite2DInstanceData.prototype, "topLeftUV", null);
  136. __decorate([
  137. BABYLON.instanceData()
  138. ], Sprite2DInstanceData.prototype, "sizeUV", null);
  139. __decorate([
  140. BABYLON.instanceData()
  141. ], Sprite2DInstanceData.prototype, "textureSize", null);
  142. __decorate([
  143. BABYLON.instanceData()
  144. ], Sprite2DInstanceData.prototype, "properties", null);
  145. return Sprite2DInstanceData;
  146. })(BABYLON.InstanceDataBase);
  147. BABYLON.Sprite2DInstanceData = Sprite2DInstanceData;
  148. var Sprite2D = (function (_super) {
  149. __extends(Sprite2D, _super);
  150. /**
  151. * Create an 2D Sprite primitive
  152. * @param texture the texture that stores the sprite to render
  153. * @param settings a combination of settings, possible ones are
  154. * - parent: the parent primitive/canvas, must be specified if the primitive is not constructed as a child of another one (i.e. as part of the children array setting)
  155. * - children: an array of direct children
  156. * - id a text identifier, for information purpose
  157. * - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0]
  158. * - rotation: the initial rotation (in radian) of the primitive. default is 0
  159. * - scale: the initial scale of the primitive. default is 1
  160. * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
  161. * - origin: define the normalized origin point location, default [0.5;0.5]
  162. * - spriteSize: the size of the sprite (in pixels), if null the size of the given texture will be used, default is null.
  163. * - spriteLocation: the location (in pixels) in the texture of the top/left corner of the Sprite to display, default is null (0,0)
  164. * - invertY: if true the texture Y will be inverted, default is false.
  165. * - alignToPixel: if true the sprite's texels will be aligned to the rendering viewport pixels, ensuring the best rendering quality but slow animations won't be done as smooth as if you set false. If false a texel could lies between two pixels, being blended by the texture sampling mode you choose, the rendering result won't be as good, but very slow animation will be overall better looking. Default is true: content will be aligned.
  166. * - isVisible: true if the sprite must be visible, false for hidden. Default is true.
  167. * - childrenFlatZOrder: if true all the children (direct and indirect) will share the same Z-Order. Use this when there's a lot of children which don't overlap. The drawing order IS NOT GUARANTED!
  168. * - marginTop: top margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  169. * - marginLeft: left margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  170. * - marginRight: right margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  171. * - marginBottom: bottom margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  172. * - margin: top, left, right and bottom margin formatted as a single string (see PrimitiveThickness.fromString)
  173. * - marginHAlignment: one value of the PrimitiveAlignment type's static properties
  174. * - marginVAlignment: one value of the PrimitiveAlignment type's static properties
  175. * - marginAlignment: a string defining the alignment, see PrimitiveAlignment.fromString
  176. * - paddingTop: top padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  177. * - paddingLeft: left padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  178. * - paddingRight: right padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  179. * - paddingBottom: bottom padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
  180. * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
  181. */
  182. function Sprite2D(texture, settings) {
  183. if (!settings) {
  184. settings = {};
  185. }
  186. _super.call(this, settings);
  187. this.texture = texture;
  188. this.texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
  189. this.texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
  190. this.size = settings.spriteSize;
  191. this.spriteLocation = settings.spriteLocation || new BABYLON.Vector2(0, 0);
  192. this.spriteFrame = 0;
  193. this.invertY = (settings.invertY == null) ? false : settings.invertY;
  194. this.alignToPixel = (settings.alignToPixel == null) ? true : settings.alignToPixel;
  195. this.isAlphaTest = true;
  196. if (settings.spriteSize == null) {
  197. var s = texture.getSize();
  198. this.size = new BABYLON.Size(s.width, s.height);
  199. }
  200. }
  201. Object.defineProperty(Sprite2D.prototype, "texture", {
  202. get: function () {
  203. return this._texture;
  204. },
  205. set: function (value) {
  206. this._texture = value;
  207. },
  208. enumerable: true,
  209. configurable: true
  210. });
  211. Object.defineProperty(Sprite2D.prototype, "actualSize", {
  212. get: function () {
  213. if (this._actualSize) {
  214. return this._actualSize;
  215. }
  216. return this.size;
  217. },
  218. set: function (value) {
  219. this._actualSize = value;
  220. },
  221. enumerable: true,
  222. configurable: true
  223. });
  224. Object.defineProperty(Sprite2D.prototype, "spriteLocation", {
  225. get: function () {
  226. return this._location;
  227. },
  228. set: function (value) {
  229. this._location = value;
  230. },
  231. enumerable: true,
  232. configurable: true
  233. });
  234. Object.defineProperty(Sprite2D.prototype, "spriteFrame", {
  235. get: function () {
  236. return this._spriteFrame;
  237. },
  238. set: function (value) {
  239. this._spriteFrame = value;
  240. },
  241. enumerable: true,
  242. configurable: true
  243. });
  244. Object.defineProperty(Sprite2D.prototype, "invertY", {
  245. get: function () {
  246. return this._invertY;
  247. },
  248. set: function (value) {
  249. this._invertY = value;
  250. },
  251. enumerable: true,
  252. configurable: true
  253. });
  254. Object.defineProperty(Sprite2D.prototype, "alignToPixel", {
  255. /**
  256. * Get/set if the sprite rendering should be aligned to the target rendering device pixel or not
  257. */
  258. get: function () {
  259. return this._alignToPixel;
  260. },
  261. set: function (value) {
  262. this._alignToPixel = value;
  263. },
  264. enumerable: true,
  265. configurable: true
  266. });
  267. Sprite2D.prototype.updateLevelBoundingInfo = function () {
  268. BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo);
  269. };
  270. /**
  271. * Get the animatable array (see http://doc.babylonjs.com/tutorials/Animations)
  272. */
  273. Sprite2D.prototype.getAnimatables = function () {
  274. var res = new Array();
  275. if (this.texture && this.texture.animations && this.texture.animations.length > 0) {
  276. res.push(this.texture);
  277. }
  278. return res;
  279. };
  280. Sprite2D.prototype.levelIntersect = function (intersectInfo) {
  281. // If we've made it so far it means the boundingInfo intersection test succeed, the Sprite2D is shaped the same, so we always return true
  282. return true;
  283. };
  284. Sprite2D._createCachedCanvasSprite = function (owner, texture, size, pos) {
  285. var sprite = new Sprite2D(texture, { parent: owner, id: "__cachedCanvasSprite__", position: BABYLON.Vector2.Zero(), origin: BABYLON.Vector2.Zero(), spriteSize: size, spriteLocation: pos, alignToPixel: true });
  286. return sprite;
  287. };
  288. Sprite2D.prototype.createModelRenderCache = function (modelKey) {
  289. var renderCache = new Sprite2DRenderCache(this.owner.engine, modelKey);
  290. return renderCache;
  291. };
  292. Sprite2D.prototype.setupModelRenderCache = function (modelRenderCache) {
  293. var renderCache = modelRenderCache;
  294. var engine = this.owner.engine;
  295. var vb = new Float32Array(4);
  296. for (var i = 0; i < 4; i++) {
  297. vb[i] = i;
  298. }
  299. renderCache.vb = engine.createVertexBuffer(vb);
  300. var ib = new Float32Array(6);
  301. ib[0] = 0;
  302. ib[1] = 2;
  303. ib[2] = 1;
  304. ib[3] = 0;
  305. ib[4] = 3;
  306. ib[5] = 2;
  307. renderCache.ib = engine.createIndexBuffer(ib);
  308. renderCache.texture = this.texture;
  309. // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
  310. var ei = this.getDataPartEffectInfo(Sprite2D.SPRITE2D_MAINPARTID, ["index"], true);
  311. if (ei) {
  312. renderCache.effectInstanced = engine.createEffect("sprite2d", ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null);
  313. }
  314. ei = this.getDataPartEffectInfo(Sprite2D.SPRITE2D_MAINPARTID, ["index"], false);
  315. renderCache.effect = engine.createEffect("sprite2d", ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null);
  316. return renderCache;
  317. };
  318. Sprite2D.prototype.createInstanceDataParts = function () {
  319. return [new Sprite2DInstanceData(Sprite2D.SPRITE2D_MAINPARTID)];
  320. };
  321. Sprite2D.prototype.refreshInstanceDataPart = function (part) {
  322. if (!_super.prototype.refreshInstanceDataPart.call(this, part)) {
  323. return false;
  324. }
  325. if (part.id === Sprite2D.SPRITE2D_MAINPARTID) {
  326. var d = this._instanceDataParts[0];
  327. var ts = this.texture.getBaseSize();
  328. var sl = this.spriteLocation;
  329. var ss = this.actualSize;
  330. d.topLeftUV = new BABYLON.Vector2(sl.x / ts.width, sl.y / ts.height);
  331. var suv = new BABYLON.Vector2(ss.width / ts.width, ss.height / ts.height);
  332. d.sizeUV = suv;
  333. Sprite2D._prop.x = this.spriteFrame;
  334. Sprite2D._prop.y = this.invertY ? 1 : 0;
  335. Sprite2D._prop.z = this.alignToPixel ? 1 : 0;
  336. d.properties = Sprite2D._prop;
  337. d.textureSize = new BABYLON.Vector2(ts.width, ts.height);
  338. }
  339. return true;
  340. };
  341. Sprite2D.SPRITE2D_MAINPARTID = 1;
  342. Sprite2D._prop = BABYLON.Vector3.Zero();
  343. __decorate([
  344. BABYLON.modelLevelProperty(BABYLON.RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 1, function (pi) { return Sprite2D.textureProperty = pi; })
  345. ], Sprite2D.prototype, "texture", null);
  346. __decorate([
  347. BABYLON.instanceLevelProperty(BABYLON.RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 2, function (pi) { return Sprite2D.actualSizeProperty = pi; }, false, true)
  348. ], Sprite2D.prototype, "actualSize", null);
  349. __decorate([
  350. BABYLON.instanceLevelProperty(BABYLON.RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 3, function (pi) { return Sprite2D.spriteLocationProperty = pi; })
  351. ], Sprite2D.prototype, "spriteLocation", null);
  352. __decorate([
  353. BABYLON.instanceLevelProperty(BABYLON.RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 4, function (pi) { return Sprite2D.spriteFrameProperty = pi; })
  354. ], Sprite2D.prototype, "spriteFrame", null);
  355. __decorate([
  356. BABYLON.instanceLevelProperty(BABYLON.RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 5, function (pi) { return Sprite2D.invertYProperty = pi; })
  357. ], Sprite2D.prototype, "invertY", null);
  358. Sprite2D = __decorate([
  359. BABYLON.className("Sprite2D")
  360. ], Sprite2D);
  361. return Sprite2D;
  362. })(BABYLON.RenderablePrim2D);
  363. BABYLON.Sprite2D = Sprite2D;
  364. })(BABYLON || (BABYLON = {}));