babylon.rectangle2d.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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 Rectangle2DRenderCache = (function (_super) {
  15. __extends(Rectangle2DRenderCache, _super);
  16. function Rectangle2DRenderCache(engine, modelKey) {
  17. _super.call(this, engine, modelKey);
  18. this.effectsReady = false;
  19. this.fillVB = null;
  20. this.fillIB = null;
  21. this.fillIndicesCount = 0;
  22. this.instancingFillAttributes = null;
  23. this.effectFill = null;
  24. this.effectFillInstanced = null;
  25. this.borderVB = null;
  26. this.borderIB = null;
  27. this.borderIndicesCount = 0;
  28. this.instancingBorderAttributes = null;
  29. this.effectBorder = null;
  30. this.effectBorderInstanced = null;
  31. }
  32. Rectangle2DRenderCache.prototype.render = function (instanceInfo, context) {
  33. // Do nothing if the shader is still loading/preparing
  34. if (!this.effectsReady) {
  35. if ((this.effectFill && (!this.effectFill.isReady() || (this.effectFillInstanced && !this.effectFillInstanced.isReady()))) ||
  36. (this.effectBorder && (!this.effectBorder.isReady() || (this.effectBorderInstanced && !this.effectBorderInstanced.isReady())))) {
  37. return false;
  38. }
  39. this.effectsReady = true;
  40. }
  41. var engine = instanceInfo.owner.owner.engine;
  42. var depthFunction = 0;
  43. if (this.effectFill && this.effectBorder) {
  44. depthFunction = engine.getDepthFunction();
  45. engine.setDepthFunctionToLessOrEqual();
  46. }
  47. var curAlphaMode = engine.getAlphaMode();
  48. if (this.effectFill) {
  49. var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
  50. var pid = context.groupInfoPartData[partIndex];
  51. if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
  52. engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
  53. }
  54. var effect = context.useInstancing ? this.effectFillInstanced : this.effectFill;
  55. engine.enableEffect(effect);
  56. engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, effect);
  57. if (context.useInstancing) {
  58. if (!this.instancingFillAttributes) {
  59. this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, effect);
  60. }
  61. engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingFillAttributes);
  62. engine.draw(true, 0, this.fillIndicesCount, pid._partData.usedElementCount);
  63. engine.unbindInstanceAttributes();
  64. }
  65. else {
  66. for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
  67. this.setupUniforms(effect, partIndex, pid._partData, i);
  68. engine.draw(true, 0, this.fillIndicesCount);
  69. }
  70. }
  71. }
  72. if (this.effectBorder) {
  73. var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
  74. var pid = context.groupInfoPartData[partIndex];
  75. if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
  76. engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
  77. }
  78. var effect = context.useInstancing ? this.effectBorderInstanced : this.effectBorder;
  79. engine.enableEffect(effect);
  80. engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, effect);
  81. if (context.useInstancing) {
  82. if (!this.instancingBorderAttributes) {
  83. this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, effect);
  84. }
  85. engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingBorderAttributes);
  86. engine.draw(true, 0, this.borderIndicesCount, pid._partData.usedElementCount);
  87. engine.unbindInstanceAttributes();
  88. }
  89. else {
  90. for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
  91. this.setupUniforms(effect, partIndex, pid._partData, i);
  92. engine.draw(true, 0, this.borderIndicesCount);
  93. }
  94. }
  95. }
  96. engine.setAlphaMode(curAlphaMode);
  97. if (this.effectFill && this.effectBorder) {
  98. engine.setDepthFunction(depthFunction);
  99. }
  100. return true;
  101. };
  102. Rectangle2DRenderCache.prototype.dispose = function () {
  103. if (!_super.prototype.dispose.call(this)) {
  104. return false;
  105. }
  106. if (this.fillVB) {
  107. this._engine._releaseBuffer(this.fillVB);
  108. this.fillVB = null;
  109. }
  110. if (this.fillIB) {
  111. this._engine._releaseBuffer(this.fillIB);
  112. this.fillIB = null;
  113. }
  114. if (this.effectFill) {
  115. this._engine._releaseEffect(this.effectFill);
  116. this.effectFill = null;
  117. }
  118. if (this.effectFillInstanced) {
  119. this._engine._releaseEffect(this.effectFillInstanced);
  120. this.effectFillInstanced = null;
  121. }
  122. if (this.borderVB) {
  123. this._engine._releaseBuffer(this.borderVB);
  124. this.borderVB = null;
  125. }
  126. if (this.borderIB) {
  127. this._engine._releaseBuffer(this.borderIB);
  128. this.borderIB = null;
  129. }
  130. if (this.effectBorder) {
  131. this._engine._releaseEffect(this.effectBorder);
  132. this.effectBorder = null;
  133. }
  134. if (this.effectBorderInstanced) {
  135. this._engine._releaseEffect(this.effectBorderInstanced);
  136. this.effectBorderInstanced = null;
  137. }
  138. return true;
  139. };
  140. return Rectangle2DRenderCache;
  141. })(BABYLON.ModelRenderCache);
  142. BABYLON.Rectangle2DRenderCache = Rectangle2DRenderCache;
  143. var Rectangle2DInstanceData = (function (_super) {
  144. __extends(Rectangle2DInstanceData, _super);
  145. function Rectangle2DInstanceData(partId) {
  146. _super.call(this, partId, 1);
  147. }
  148. Object.defineProperty(Rectangle2DInstanceData.prototype, "properties", {
  149. get: function () {
  150. return null;
  151. },
  152. enumerable: true,
  153. configurable: true
  154. });
  155. __decorate([
  156. BABYLON.instanceData()
  157. ], Rectangle2DInstanceData.prototype, "properties", null);
  158. return Rectangle2DInstanceData;
  159. })(BABYLON.Shape2DInstanceData);
  160. BABYLON.Rectangle2DInstanceData = Rectangle2DInstanceData;
  161. var Rectangle2D = (function (_super) {
  162. __extends(Rectangle2D, _super);
  163. function Rectangle2D() {
  164. _super.apply(this, arguments);
  165. }
  166. Object.defineProperty(Rectangle2D.prototype, "actualSize", {
  167. get: function () {
  168. return this.size;
  169. },
  170. enumerable: true,
  171. configurable: true
  172. });
  173. Object.defineProperty(Rectangle2D.prototype, "size", {
  174. get: function () {
  175. return this._size;
  176. },
  177. set: function (value) {
  178. this._size = value;
  179. },
  180. enumerable: true,
  181. configurable: true
  182. });
  183. Object.defineProperty(Rectangle2D.prototype, "notRounded", {
  184. get: function () {
  185. return this._notRounded;
  186. },
  187. set: function (value) {
  188. this._notRounded = value;
  189. },
  190. enumerable: true,
  191. configurable: true
  192. });
  193. Object.defineProperty(Rectangle2D.prototype, "roundRadius", {
  194. get: function () {
  195. return this._roundRadius;
  196. },
  197. set: function (value) {
  198. this._roundRadius = value;
  199. this.notRounded = value === 0;
  200. },
  201. enumerable: true,
  202. configurable: true
  203. });
  204. Rectangle2D.prototype.levelIntersect = function (intersectInfo) {
  205. // If we got there it mean the boundingInfo intersection succeed, if the rectangle has not roundRadius, it means it succeed!
  206. if (this.notRounded) {
  207. return true;
  208. }
  209. // Well, for now we neglect the area where the pickPosition could be outside due to the roundRadius...
  210. // TODO make REAL intersection test here!
  211. return true;
  212. };
  213. Rectangle2D.prototype.updateLevelBoundingInfo = function () {
  214. BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
  215. };
  216. Rectangle2D.prototype.setupRectangle2D = function (owner, parent, id, position, origin, size, roundRadius, fill, border, borderThickness, isVisible, marginTop, marginLeft, marginRight, marginBottom, vAlignment, hAlignment) {
  217. this.setupShape2D(owner, parent, id, position, origin, isVisible, fill, border, borderThickness, marginTop, marginLeft, marginRight, marginBottom, hAlignment, vAlignment);
  218. this.size = size;
  219. this.notRounded = !roundRadius;
  220. this.roundRadius = roundRadius;
  221. };
  222. /**
  223. * Create an Rectangle 2D Shape primitive. May be a sharp rectangle (with sharp corners), or a rounded one.
  224. * @param parent the parent primitive, must be a valid primitive (or the Canvas)
  225. * options:
  226. * - id a text identifier, for information purpose
  227. * - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0]
  228. * - origin: define the normalized origin point location, default [0.5;0.5]
  229. * - size: the size of the group. Alternatively the width and height properties can be set. Default will be [10;10].
  230. * - roundRadius: if the rectangle has rounded corner, set their radius, default is 0 (to get a sharp rectangle).
  231. * - fill: the brush used to draw the fill content of the ellipse, you can set null to draw nothing (but you will have to set a border brush), default is a SolidColorBrush of plain white.
  232. * - border: the brush used to draw the border of the ellipse, you can set null to draw nothing (but you will have to set a fill brush), default is null.
  233. * - borderThickness: the thickness of the drawn border, default is 1.
  234. * - isVisible: true if the primitive must be visible, false for hidden. Default is true.
  235. * - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
  236. * - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
  237. * - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
  238. */
  239. Rectangle2D.Create = function (parent, options) {
  240. BABYLON.Prim2DBase.CheckParent(parent);
  241. var rect = new Rectangle2D();
  242. if (!options) {
  243. rect.setupRectangle2D(parent.owner, parent, null, BABYLON.Vector2.Zero(), null, new BABYLON.Size(10, 10), 0, BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF"), null, 1, true, null, null, null, null, null, null);
  244. }
  245. else {
  246. var pos = options.position || new BABYLON.Vector2(options.x || 0, options.y || 0);
  247. var size = options.size || (new BABYLON.Size(options.width || 10, options.height || 10));
  248. var fill = options.fill === undefined ? BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF") : options.fill;
  249. rect.setupRectangle2D(parent.owner, parent, options.id || null, pos, options.origin || null, size, options.roundRadius || 0, fill, options.border || null, options.borderThickness || 1, options.isVisible || true, options.marginTop || null, options.marginLeft || null, options.marginRight || null, options.marginBottom || null, options.vAlignment || null, options.hAlignment || null);
  250. }
  251. return rect;
  252. };
  253. Rectangle2D.prototype.createModelRenderCache = function (modelKey) {
  254. var renderCache = new Rectangle2DRenderCache(this.owner.engine, modelKey);
  255. return renderCache;
  256. };
  257. Rectangle2D.prototype.setupModelRenderCache = function (modelRenderCache) {
  258. var renderCache = modelRenderCache;
  259. var engine = this.owner.engine;
  260. // Need to create WebGL resources for fill part?
  261. if (this.fill) {
  262. var vbSize = ((this.notRounded ? 1 : Rectangle2D.roundSubdivisions) * 4) + 1;
  263. var vb = new Float32Array(vbSize);
  264. for (var i = 0; i < vbSize; i++) {
  265. vb[i] = i;
  266. }
  267. renderCache.fillVB = engine.createVertexBuffer(vb);
  268. var triCount = vbSize - 1;
  269. var ib = new Float32Array(triCount * 3);
  270. for (var i = 0; i < triCount; i++) {
  271. ib[i * 3 + 0] = 0;
  272. ib[i * 3 + 2] = i + 1;
  273. ib[i * 3 + 1] = i + 2;
  274. }
  275. ib[triCount * 3 - 2] = 1;
  276. renderCache.fillIB = engine.createIndexBuffer(ib);
  277. renderCache.fillIndicesCount = triCount * 3;
  278. // 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
  279. var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], true);
  280. if (ei) {
  281. renderCache.effectFillInstanced = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
  282. }
  283. // Get the non instanced version
  284. ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], false);
  285. renderCache.effectFill = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
  286. }
  287. // Need to create WebGL resource for border part?
  288. if (this.border) {
  289. var vbSize = (this.notRounded ? 1 : Rectangle2D.roundSubdivisions) * 4 * 2;
  290. var vb = new Float32Array(vbSize);
  291. for (var i = 0; i < vbSize; i++) {
  292. vb[i] = i;
  293. }
  294. renderCache.borderVB = engine.createVertexBuffer(vb);
  295. var triCount = vbSize;
  296. var rs = triCount / 2;
  297. var ib = new Float32Array(triCount * 3);
  298. for (var i = 0; i < rs; i++) {
  299. var r0 = i;
  300. var r1 = (i + 1) % rs;
  301. ib[i * 6 + 0] = rs + r1;
  302. ib[i * 6 + 1] = rs + r0;
  303. ib[i * 6 + 2] = r0;
  304. ib[i * 6 + 3] = r1;
  305. ib[i * 6 + 4] = rs + r1;
  306. ib[i * 6 + 5] = r0;
  307. }
  308. renderCache.borderIB = engine.createIndexBuffer(ib);
  309. renderCache.borderIndicesCount = triCount * 3;
  310. // 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
  311. var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], true);
  312. if (ei) {
  313. renderCache.effectBorderInstanced = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
  314. }
  315. // Get the non instanced version
  316. ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], false);
  317. renderCache.effectBorder = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
  318. }
  319. return renderCache;
  320. };
  321. Rectangle2D.prototype.createInstanceDataParts = function () {
  322. var res = new Array();
  323. if (this.border) {
  324. res.push(new Rectangle2DInstanceData(BABYLON.Shape2D.SHAPE2D_BORDERPARTID));
  325. }
  326. if (this.fill) {
  327. res.push(new Rectangle2DInstanceData(BABYLON.Shape2D.SHAPE2D_FILLPARTID));
  328. }
  329. return res;
  330. };
  331. Rectangle2D.prototype.refreshInstanceDataPart = function (part) {
  332. if (!_super.prototype.refreshInstanceDataPart.call(this, part)) {
  333. return false;
  334. }
  335. if (part.id === BABYLON.Shape2D.SHAPE2D_BORDERPARTID) {
  336. var d = part;
  337. var size = this.size;
  338. d.properties = new BABYLON.Vector3(size.width, size.height, this.roundRadius || 0);
  339. }
  340. else if (part.id === BABYLON.Shape2D.SHAPE2D_FILLPARTID) {
  341. var d = part;
  342. var size = this.size;
  343. d.properties = new BABYLON.Vector3(size.width, size.height, this.roundRadius || 0);
  344. }
  345. return true;
  346. };
  347. Rectangle2D.roundSubdivisions = 16;
  348. __decorate([
  349. BABYLON.instanceLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 1, function (pi) { return Rectangle2D.sizeProperty = pi; }, false, true)
  350. ], Rectangle2D.prototype, "size", null);
  351. __decorate([
  352. BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 2, function (pi) { return Rectangle2D.notRoundedProperty = pi; })
  353. ], Rectangle2D.prototype, "notRounded", null);
  354. __decorate([
  355. BABYLON.instanceLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 3, function (pi) { return Rectangle2D.roundRadiusProperty = pi; })
  356. ], Rectangle2D.prototype, "roundRadius", null);
  357. Rectangle2D = __decorate([
  358. BABYLON.className("Rectangle2D")
  359. ], Rectangle2D);
  360. return Rectangle2D;
  361. })(BABYLON.Shape2D);
  362. BABYLON.Rectangle2D = Rectangle2D;
  363. })(BABYLON || (BABYLON = {}));