var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 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; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var BABYLON; (function (BABYLON) { var Rectangle2DRenderCache = (function (_super) { __extends(Rectangle2DRenderCache, _super); function Rectangle2DRenderCache(engine, modelKey) { _super.call(this, engine, modelKey); this.effectsReady = false; this.fillVB = null; this.fillIB = null; this.fillIndicesCount = 0; this.instancingFillAttributes = null; this.effectFill = null; this.effectFillInstanced = null; this.borderVB = null; this.borderIB = null; this.borderIndicesCount = 0; this.instancingBorderAttributes = null; this.effectBorder = null; this.effectBorderInstanced = null; } Rectangle2DRenderCache.prototype.render = function (instanceInfo, context) { // Do nothing if the shader is still loading/preparing if (!this.effectsReady) { if ((this.effectFill && (!this.effectFill.isReady() || (this.effectFillInstanced && !this.effectFillInstanced.isReady()))) || (this.effectBorder && (!this.effectBorder.isReady() || (this.effectBorderInstanced && !this.effectBorderInstanced.isReady())))) { return false; } this.effectsReady = true; } var engine = instanceInfo.owner.owner.engine; var depthFunction = 0; if (this.effectFill && this.effectBorder) { depthFunction = engine.getDepthFunction(); engine.setDepthFunctionToLessOrEqual(); } var curAlphaMode = engine.getAlphaMode(); if (this.effectFill) { var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString()); var pid = context.groupInfoPartData[partIndex]; if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) { engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE); } var effect = context.useInstancing ? this.effectFillInstanced : this.effectFill; engine.enableEffect(effect); engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, effect); if (context.useInstancing) { if (!this.instancingFillAttributes) { this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, effect); } engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingFillAttributes); engine.draw(true, 0, this.fillIndicesCount, pid._partData.usedElementCount); engine.unbindInstanceAttributes(); } else { for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) { this.setupUniforms(effect, partIndex, pid._partData, i); engine.draw(true, 0, this.fillIndicesCount); } } } if (this.effectBorder) { var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString()); var pid = context.groupInfoPartData[partIndex]; if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) { engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE); } var effect = context.useInstancing ? this.effectBorderInstanced : this.effectBorder; engine.enableEffect(effect); engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, effect); if (context.useInstancing) { if (!this.instancingBorderAttributes) { this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, effect); } engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingBorderAttributes); engine.draw(true, 0, this.borderIndicesCount, pid._partData.usedElementCount); engine.unbindInstanceAttributes(); } else { for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) { this.setupUniforms(effect, partIndex, pid._partData, i); engine.draw(true, 0, this.borderIndicesCount); } } } engine.setAlphaMode(curAlphaMode); if (this.effectFill && this.effectBorder) { engine.setDepthFunction(depthFunction); } return true; }; Rectangle2DRenderCache.prototype.dispose = function () { if (!_super.prototype.dispose.call(this)) { return false; } if (this.fillVB) { this._engine._releaseBuffer(this.fillVB); this.fillVB = null; } if (this.fillIB) { this._engine._releaseBuffer(this.fillIB); this.fillIB = null; } if (this.effectFill) { this._engine._releaseEffect(this.effectFill); this.effectFill = null; } if (this.effectFillInstanced) { this._engine._releaseEffect(this.effectFillInstanced); this.effectFillInstanced = null; } if (this.borderVB) { this._engine._releaseBuffer(this.borderVB); this.borderVB = null; } if (this.borderIB) { this._engine._releaseBuffer(this.borderIB); this.borderIB = null; } if (this.effectBorder) { this._engine._releaseEffect(this.effectBorder); this.effectBorder = null; } if (this.effectBorderInstanced) { this._engine._releaseEffect(this.effectBorderInstanced); this.effectBorderInstanced = null; } return true; }; return Rectangle2DRenderCache; }(BABYLON.ModelRenderCache)); BABYLON.Rectangle2DRenderCache = Rectangle2DRenderCache; var Rectangle2DInstanceData = (function (_super) { __extends(Rectangle2DInstanceData, _super); function Rectangle2DInstanceData(partId) { _super.call(this, partId, 1); } Object.defineProperty(Rectangle2DInstanceData.prototype, "properties", { get: function () { return null; }, enumerable: true, configurable: true }); __decorate([ BABYLON.instanceData() ], Rectangle2DInstanceData.prototype, "properties", null); return Rectangle2DInstanceData; }(BABYLON.Shape2DInstanceData)); BABYLON.Rectangle2DInstanceData = Rectangle2DInstanceData; var Rectangle2D = (function (_super) { __extends(Rectangle2D, _super); /** * Create an Rectangle 2D Shape primitive. May be a sharp rectangle (with sharp corners), or a rounded one. * @param parent the parent primitive, must be a valid primitive (or the Canvas) * options: * - id a text identifier, for information purpose * - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0] * - origin: define the normalized origin point location, default [0.5;0.5] * - size: the size of the group. Alternatively the width and height properties can be set. Default will be [10;10]. * - roundRadius: if the rectangle has rounded corner, set their radius, default is 0 (to get a sharp rectangle). * - 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. * - 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. * - borderThickness: the thickness of the drawn border, default is 1. * - isVisible: true if the primitive must be visible, false for hidden. Default is true. * - 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. * - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment. * - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment. */ function Rectangle2D(settings) { // Avoid checking every time if the object exists if (settings == null) { settings = {}; } _super.call(this, settings); if (settings.size != null) { this.size = settings.size; } else if (settings.width || settings.height) { var size = new BABYLON.Size(settings.width, settings.height); this.size = size; } //let size = settings.size || (new Size((settings.width === null) ? null : (settings.width || 10), (settings.height === null) ? null : (settings.height || 10))); var roundRadius = (settings.roundRadius == null) ? 0 : settings.roundRadius; var borderThickness = (settings.borderThickness == null) ? 1 : settings.borderThickness; //this.size = size; this.roundRadius = roundRadius; this.borderThickness = borderThickness; } Object.defineProperty(Rectangle2D.prototype, "actualSize", { get: function () { if (this._actualSize) { return this._actualSize; } return this.size; }, set: function (value) { this._actualSize = value; }, enumerable: true, configurable: true }); Object.defineProperty(Rectangle2D.prototype, "notRounded", { get: function () { return this._notRounded; }, set: function (value) { this._notRounded = value; }, enumerable: true, configurable: true }); Object.defineProperty(Rectangle2D.prototype, "roundRadius", { get: function () { return this._roundRadius; }, set: function (value) { this._roundRadius = value; this.notRounded = value === 0; this._positioningDirty(); }, enumerable: true, configurable: true }); Rectangle2D.prototype.levelIntersect = function (intersectInfo) { // If we got there it mean the boundingInfo intersection succeed, if the rectangle has not roundRadius, it means it succeed! if (this.notRounded) { return true; } // If we got so far it means the bounding box at least passed, so we know it's inside the bounding rectangle, but it can be outside the roundedRectangle. // The easiest way is to check if the point is inside on of the four corners area (a little square of roundRadius size at the four corners) // If it's the case for one, check if the mouse is located in the quarter that we care about (the one who is visible) then finally make a distance check with the roundRadius radius to see if it's inside the circle quarter or outside. // First let remove the origin out the equation, to have the rectangle with an origin at bottom/left var size = this.size; Rectangle2D._i0.x = intersectInfo._localPickPosition.x; Rectangle2D._i0.y = intersectInfo._localPickPosition.y; var rr = this.roundRadius; var rrs = rr * rr; // Check if the point is in the bottom/left quarter area Rectangle2D._i1.x = rr; Rectangle2D._i1.y = rr; if (Rectangle2D._i0.x <= Rectangle2D._i1.x && Rectangle2D._i0.y <= Rectangle2D._i1.y) { // Compute the intersection point in the quarter local space Rectangle2D._i2.x = Rectangle2D._i0.x - Rectangle2D._i1.x; Rectangle2D._i2.y = Rectangle2D._i0.y - Rectangle2D._i1.y; // It's a hit if the squared distance is less/equal to the squared radius of the round circle return Rectangle2D._i2.lengthSquared() <= rrs; } // Check if the point is in the top/left quarter area Rectangle2D._i1.x = rr; Rectangle2D._i1.y = size.height - rr; if (Rectangle2D._i0.x <= Rectangle2D._i1.x && Rectangle2D._i0.y >= Rectangle2D._i1.y) { // Compute the intersection point in the quarter local space Rectangle2D._i2.x = Rectangle2D._i0.x - Rectangle2D._i1.x; Rectangle2D._i2.y = Rectangle2D._i0.y - Rectangle2D._i1.y; // It's a hit if the squared distance is less/equal to the squared radius of the round circle return Rectangle2D._i2.lengthSquared() <= rrs; } // Check if the point is in the top/right quarter area Rectangle2D._i1.x = size.width - rr; Rectangle2D._i1.y = size.height - rr; if (Rectangle2D._i0.x >= Rectangle2D._i1.x && Rectangle2D._i0.y >= Rectangle2D._i1.y) { // Compute the intersection point in the quarter local space Rectangle2D._i2.x = Rectangle2D._i0.x - Rectangle2D._i1.x; Rectangle2D._i2.y = Rectangle2D._i0.y - Rectangle2D._i1.y; // It's a hit if the squared distance is less/equal to the squared radius of the round circle return Rectangle2D._i2.lengthSquared() <= rrs; } // Check if the point is in the bottom/right quarter area Rectangle2D._i1.x = size.width - rr; Rectangle2D._i1.y = rr; if (Rectangle2D._i0.x >= Rectangle2D._i1.x && Rectangle2D._i0.y <= Rectangle2D._i1.y) { // Compute the intersection point in the quarter local space Rectangle2D._i2.x = Rectangle2D._i0.x - Rectangle2D._i1.x; Rectangle2D._i2.y = Rectangle2D._i0.y - Rectangle2D._i1.y; // It's a hit if the squared distance is less/equal to the squared radius of the round circle return Rectangle2D._i2.lengthSquared() <= rrs; } // At any other locations the point is guarantied to be inside return true; }; Rectangle2D.prototype.updateLevelBoundingInfo = function () { BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.actualSize, this._levelBoundingInfo); }; Rectangle2D.prototype.createModelRenderCache = function (modelKey) { var renderCache = new Rectangle2DRenderCache(this.owner.engine, modelKey); return renderCache; }; Rectangle2D.prototype.setupModelRenderCache = function (modelRenderCache) { var renderCache = modelRenderCache; var engine = this.owner.engine; // Need to create WebGL resources for fill part? if (this.fill) { var vbSize = ((this.notRounded ? 1 : Rectangle2D.roundSubdivisions) * 4) + 1; var vb = new Float32Array(vbSize); for (var i = 0; i < vbSize; i++) { vb[i] = i; } renderCache.fillVB = engine.createVertexBuffer(vb); var triCount = vbSize - 1; var ib = new Float32Array(triCount * 3); for (var i = 0; i < triCount; i++) { ib[i * 3 + 0] = 0; ib[i * 3 + 2] = i + 1; ib[i * 3 + 1] = i + 2; } ib[triCount * 3 - 2] = 1; renderCache.fillIB = engine.createIndexBuffer(ib); renderCache.fillIndicesCount = triCount * 3; // 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 var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], true); if (ei) { renderCache.effectFillInstanced = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null); } // Get the non instanced version ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], false); renderCache.effectFill = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null); } // Need to create WebGL resource for border part? if (this.border) { var vbSize = (this.notRounded ? 1 : Rectangle2D.roundSubdivisions) * 4 * 2; var vb = new Float32Array(vbSize); for (var i = 0; i < vbSize; i++) { vb[i] = i; } renderCache.borderVB = engine.createVertexBuffer(vb); var triCount = vbSize; var rs = triCount / 2; var ib = new Float32Array(triCount * 3); for (var i = 0; i < rs; i++) { var r0 = i; var r1 = (i + 1) % rs; ib[i * 6 + 0] = rs + r1; ib[i * 6 + 1] = rs + r0; ib[i * 6 + 2] = r0; ib[i * 6 + 3] = r1; ib[i * 6 + 4] = rs + r1; ib[i * 6 + 5] = r0; } renderCache.borderIB = engine.createIndexBuffer(ib); renderCache.borderIndicesCount = triCount * 3; // 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 var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], true); if (ei) { renderCache.effectBorderInstanced = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null); } // Get the non instanced version ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], false); renderCache.effectBorder = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null); } return renderCache; }; // We override this method because if there's a roundRadius set, we will reduce the initial Content Area to make sure the computed area won't intersect with the shape contour. The formula is simple: we shrink the incoming size by the amount of the roundRadius Rectangle2D.prototype._getInitialContentAreaToRef = function (primSize, initialContentPosition, initialContentArea) { // Fall back to default implementation if there's no round Radius if (this._notRounded) { _super.prototype._getInitialContentAreaToRef.call(this, primSize, initialContentPosition, initialContentArea); } else { var rr = Math.round((this.roundRadius - (this.roundRadius / Math.sqrt(2))) * 1.3); initialContentPosition.x = initialContentPosition.y = rr; initialContentArea.width = Math.max(0, primSize.width - (rr * 2)); initialContentArea.height = Math.max(0, primSize.height - (rr * 2)); } }; Rectangle2D.prototype.createInstanceDataParts = function () { var res = new Array(); if (this.border) { res.push(new Rectangle2DInstanceData(BABYLON.Shape2D.SHAPE2D_BORDERPARTID)); } if (this.fill) { res.push(new Rectangle2DInstanceData(BABYLON.Shape2D.SHAPE2D_FILLPARTID)); } return res; }; Rectangle2D.prototype.refreshInstanceDataPart = function (part) { if (!_super.prototype.refreshInstanceDataPart.call(this, part)) { return false; } if (part.id === BABYLON.Shape2D.SHAPE2D_BORDERPARTID) { var d = part; var size = this.actualSize; d.properties = new BABYLON.Vector3(size.width, size.height, this.roundRadius || 0); } else if (part.id === BABYLON.Shape2D.SHAPE2D_FILLPARTID) { var d = part; var size = this.actualSize; d.properties = new BABYLON.Vector3(size.width, size.height, this.roundRadius || 0); } return true; }; Rectangle2D._i0 = BABYLON.Vector2.Zero(); Rectangle2D._i1 = BABYLON.Vector2.Zero(); Rectangle2D._i2 = BABYLON.Vector2.Zero(); Rectangle2D.roundSubdivisions = 16; __decorate([ BABYLON.instanceLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 1, function (pi) { return Rectangle2D.actualSizeProperty = pi; }, false, true) ], Rectangle2D.prototype, "actualSize", null); __decorate([ BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 2, function (pi) { return Rectangle2D.notRoundedProperty = pi; }) ], Rectangle2D.prototype, "notRounded", null); __decorate([ BABYLON.instanceLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 3, function (pi) { return Rectangle2D.roundRadiusProperty = pi; }) ], Rectangle2D.prototype, "roundRadius", null); Rectangle2D = __decorate([ BABYLON.className("Rectangle2D") ], Rectangle2D); return Rectangle2D; }(BABYLON.Shape2D)); BABYLON.Rectangle2D = Rectangle2D; })(BABYLON || (BABYLON = {}));