123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- module BABYLON {
- export class Ellipse2DRenderCache extends ModelRenderCache {
- effectsReady: boolean = false;
- fillVB: WebGLBuffer = null;
- fillIB: WebGLBuffer = null;
- fillIndicesCount: number = 0;
- instancingFillAttributes: InstancingAttributeInfo[] = null;
- effectFillInstanced: Effect = null;
- effectFill: Effect = null;
- borderVB: WebGLBuffer = null;
- borderIB: WebGLBuffer = null;
- borderIndicesCount: number = 0;
- instancingBorderAttributes: InstancingAttributeInfo[] = null;
- effectBorderInstanced: Effect = null;
- effectBorder: Effect = null;
- constructor(engine: Engine, modelKey: string) {
- super(engine, modelKey);
- }
- render(instanceInfo: GroupInstanceInfo, context: Render2DContext): boolean {
- // 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;
- }
- let canvas = instanceInfo.owner.owner;
- var engine = canvas.engine;
- let depthFunction = 0;
- if (this.effectFill && this.effectBorder) {
- depthFunction = engine.getDepthFunction();
- engine.setDepthFunctionToLessOrEqual();
- }
- var curAlphaMode = engine.getAlphaMode();
- if (this.effectFill) {
- let partIndex = instanceInfo.partIndexFromId.get(Shape2D.SHAPE2D_FILLPARTID.toString());
- let pid = context.groupInfoPartData[partIndex];
- if (context.renderMode !== Render2DContext.RenderModeOpaque) {
- engine.setAlphaMode(Engine.ALPHA_COMBINE, true);
- }
- let 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(Shape2D.SHAPE2D_FILLPARTID, effect);
- }
- let glBuffer = context.instancedBuffers ? context.instancedBuffers[partIndex] : pid._partBuffer;
- let count = context.instancedBuffers ? context.instancesCount : pid._partData.usedElementCount;
- canvas._addDrawCallCount(1, context.renderMode);
- engine.updateAndBindInstancesBuffer(glBuffer, null, this.instancingFillAttributes);
- engine.draw(true, 0, this.fillIndicesCount, count);
- engine.unbindInstanceAttributes();
- } else {
- canvas._addDrawCallCount(context.partDataEndIndex - context.partDataStartIndex, context.renderMode);
- for (let i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
- this.setupUniforms(effect, partIndex, pid._partData, i);
- engine.draw(true, 0, this.fillIndicesCount);
- }
- }
- }
- if (this.effectBorder) {
- let partIndex = instanceInfo.partIndexFromId.get(Shape2D.SHAPE2D_BORDERPARTID.toString());
- let pid = context.groupInfoPartData[partIndex];
- if (context.renderMode !== Render2DContext.RenderModeOpaque) {
- engine.setAlphaMode(Engine.ALPHA_COMBINE, true);
- }
- let 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(Shape2D.SHAPE2D_BORDERPARTID, effect);
- }
- let glBuffer = context.instancedBuffers ? context.instancedBuffers[partIndex] : pid._partBuffer;
- let count = context.instancedBuffers ? context.instancesCount : pid._partData.usedElementCount;
- canvas._addDrawCallCount(1, context.renderMode);
- engine.updateAndBindInstancesBuffer(glBuffer, null, this.instancingBorderAttributes);
- engine.draw(true, 0, this.borderIndicesCount, count);
- engine.unbindInstanceAttributes();
- } else {
- canvas._addDrawCallCount(context.partDataEndIndex - context.partDataStartIndex, context.renderMode);
- for (let i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
- this.setupUniforms(effect, partIndex, pid._partData, i);
- engine.draw(true, 0, this.borderIndicesCount);
- }
- }
- }
- engine.setAlphaMode(curAlphaMode, true);
- if (this.effectFill && this.effectBorder) {
- engine.setDepthFunction(depthFunction);
- }
- return true;
- }
- public dispose(): boolean {
- if (!super.dispose()) {
- return false;
- }
- if (this.fillVB) {
- this._engine._releaseBuffer(this.fillVB);
- this.fillVB = null;
- }
- if (this.fillIB) {
- this._engine._releaseBuffer(this.fillIB);
- this.fillIB = null;
- }
- this.effectFill = null;
- this.effectFillInstanced = null;
- this.effectBorder = null;
- this.effectBorderInstanced = null;
- if (this.borderVB) {
- this._engine._releaseBuffer(this.borderVB);
- this.borderVB = null;
- }
- if (this.borderIB) {
- this._engine._releaseBuffer(this.borderIB);
- this.borderIB = null;
- }
- return true;
- }
- }
- export class Ellipse2DInstanceData extends Shape2DInstanceData {
- constructor(partId: number) {
- super(partId, 1);
- }
- @instanceData()
- get properties(): Vector3 {
- return null;
- }
- set properties(value: Vector3) {
- }
- }
- @className("Ellipse2D", "BABYLON")
- /**
- * Ellipse Primitive class
- */
- export class Ellipse2D extends Shape2D {
- public static acutalSizeProperty: Prim2DPropInfo;
- public static subdivisionsProperty: Prim2DPropInfo;
- @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Ellipse2D.subdivisionsProperty = pi)
- /**
- * Get/set the number of subdivisions used to draw the ellipsis. Default is 64.
- */
- public get subdivisions(): number {
- return this._subdivisions;
- }
- public set subdivisions(value: number) {
- this._subdivisions = value;
- }
- protected levelIntersect(intersectInfo: IntersectInfo2D): boolean {
- let w = this.size.width / 2;
- let h = this.size.height / 2;
- let x = intersectInfo._localPickPosition.x-w;
- let y = intersectInfo._localPickPosition.y-h;
- return ((x * x) / (w * w) + (y * y) / (h * h)) <= 1;
- }
- protected updateLevelBoundingInfo(): boolean {
- BoundingInfo2D.CreateFromSizeToRef(this.actualSize, this._levelBoundingInfo);
- return true;
- }
- /**
- * Create an Ellipse 2D Shape primitive
- * @param settings a combination of settings, possible ones are
- * - 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)
- * - children: an array of direct children
- * - 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]
- * - rotation: the initial rotation (in radian) of the primitive. default is 0
- * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
- * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
- * - alignToPixel: if true the primitive will be aligned to the target rendering device's pixel
- * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
- * - zOrder: override the zOrder with the specified value
- * - 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].
- * - subdivision: the number of subdivision to create the ellipse perimeter, default is 64.
- * - 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. can also be a string value (see Canvas2D.GetBrushFromString)
- * - 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. can be a string value (see Canvas2D.GetBrushFromString)
- * - borderThickness: the thickness of the drawn border, default is 1.
- * - isVisible: true if the group must be visible, false for hidden. Default is true.
- * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
- * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersection, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
- * - 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!
- * - levelCollision: this primitive is an actor of the Collision Manager and only this level will be used for collision (i.e. not the children). Use deepCollision if you want collision detection on the primitives and its children.
- * - deepCollision: this primitive is an actor of the Collision Manager, this level AND ALSO its children will be used for collision (note: you don't need to set the children as level/deepCollision).
- * - layoutData: a instance of a class implementing the ILayoutData interface that contain data to pass to the primitive parent's layout engine
- * - marginTop: top margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - marginLeft: left margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - marginRight: right margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - marginBottom: bottom margin, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - margin: top, left, right and bottom margin formatted as a single string (see PrimitiveThickness.fromString)
- * - marginHAlignment: one value of the PrimitiveAlignment type's static properties
- * - marginVAlignment: one value of the PrimitiveAlignment type's static properties
- * - marginAlignment: a string defining the alignment, see PrimitiveAlignment.fromString
- * - paddingTop: top padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - paddingLeft: left padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - paddingRight: right padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - paddingBottom: bottom padding, can be a number (will be pixels) or a string (see PrimitiveThickness.fromString)
- * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
- */
- constructor(settings?: {
- parent ?: Prim2DBase,
- children ?: Array<Prim2DBase>,
- id ?: string,
- position ?: Vector2,
- x ?: number,
- y ?: number,
- rotation ?: number,
- scale ?: number,
- scaleX ?: number,
- scaleY ?: number,
- dontInheritParentScale?: boolean,
- alignToPixel ?: boolean,
- opacity ?: number,
- zOrder ?: number,
- origin ?: Vector2,
- size ?: Size,
- width ?: number,
- height ?: number,
- subdivisions ?: number,
- fill ?: IBrush2D | string,
- border ?: IBrush2D | string,
- borderThickness ?: number,
- isVisible ?: boolean,
- isPickable ?: boolean,
- isContainer ?: boolean,
- childrenFlatZOrder ?: boolean,
- levelCollision ?: boolean,
- deepCollision ?: boolean,
- layoutData ?: ILayoutData,
- marginTop ?: number | string,
- marginLeft ?: number | string,
- marginRight ?: number | string,
- marginBottom ?: number | string,
- margin ?: number | string,
- marginHAlignment ?: number,
- marginVAlignment ?: number,
- marginAlignment ?: string,
- paddingTop ?: number | string,
- paddingLeft ?: number | string,
- paddingRight ?: number | string,
- paddingBottom ?: number | string,
- padding ?: number | string,
- }) {
- // Avoid checking every time if the object exists
- if (settings == null) {
- settings = {};
- }
- super(settings);
- if (settings.size != null) {
- this.size = settings.size;
- }
- else if (settings.width || settings.height) {
- let size = new Size(settings.width, settings.height);
- this.size = size;
- }
- let sub = (settings.subdivisions == null) ? 64 : settings.subdivisions;
- this.subdivisions = sub;
- }
- protected updateTriArray() {
- let subDiv = this._subdivisions;
- if (this._primTriArray == null) {
- this._primTriArray = new Tri2DArray(subDiv);
- } else {
- this._primTriArray.clear(subDiv);
- }
- let size = this.actualSize;
- let center = new Vector2(0.5 * size.width, 0.5 * size.height);
- let v1 = Vector2.Zero();
- let v2 = Vector2.Zero();
- for (let i = 0; i < subDiv; i++) {
- let angle1 = Math.PI * 2 * (i-1) / subDiv;
- let angle2 = Math.PI * 2 * i / subDiv;
- v1.x = ((Math.cos(angle1) / 2.0) + 0.5) * size.width;
- v1.y = ((Math.sin(angle1) / 2.0) + 0.5) * size.height;
- v2.x = ((Math.cos(angle2) / 2.0) + 0.5) * size.width;
- v2.y = ((Math.sin(angle2) / 2.0) + 0.5) * size.height;
- this._primTriArray.storeTriangle(i, center, v1, v2);
- }
- }
- protected createModelRenderCache(modelKey: string): ModelRenderCache {
- let renderCache = new Ellipse2DRenderCache(this.owner.engine, modelKey);
- return renderCache;
- }
- protected setupModelRenderCache(modelRenderCache: ModelRenderCache) {
- let renderCache = <Ellipse2DRenderCache>modelRenderCache;
- let engine = this.owner.engine;
- // Need to create WebGL resources for fill part?
- if (this.fill) {
- let vbSize = this.subdivisions + 1;
- let vb = new Float32Array(vbSize);
- for (let i = 0; i < vbSize; i++) {
- vb[i] = i;
- }
- renderCache.fillVB = engine.createVertexBuffer(vb);
- let triCount = vbSize - 1;
- let ib = new Float32Array(triCount * 3);
- for (let i = 0; i < triCount; i++) {
- ib[i * 3 + 0] = 0;
- ib[i * 3 + 2] = i + 2;
- ib[i * 3 + 1] = i + 1;
- }
- ib[triCount * 3 - 1] = 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
- let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_FILLPARTID, ["index"], null, true);
- if (ei) {
- renderCache.effectFillInstanced = engine.createEffect({ vertex: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
- }
- // Get the non instanced version
- ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_FILLPARTID, ["index"], null, false);
- renderCache.effectFill = engine.createEffect({ vertex: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
- }
- // Need to create WebGL resource for border part?
- if (this.border) {
- let vbSize = this.subdivisions * 2;
- let vb = new Float32Array(vbSize);
- for (let i = 0; i < vbSize; i++) {
- vb[i] = i;
- }
- renderCache.borderVB = engine.createVertexBuffer(vb);
- let triCount = vbSize;
- let rs = triCount / 2;
- let ib = new Float32Array(triCount * 3);
- for (let i = 0; i < rs; i++) {
- let r0 = i;
- let 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
- let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_BORDERPARTID, ["index"], null, true);
- if (ei) {
- renderCache.effectBorderInstanced = engine.createEffect("ellipse2d", ei.attributes, ei.uniforms, [], ei.defines, null);
- }
- // Get the non instanced version
- ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_BORDERPARTID, ["index"], null, false);
- renderCache.effectBorder = engine.createEffect("ellipse2d", ei.attributes, ei.uniforms, [], ei.defines, null);
- }
- return renderCache;
- }
- protected createInstanceDataParts(): InstanceDataBase[] {
- var res = new Array<InstanceDataBase>();
- if (this.border) {
- res.push(new Ellipse2DInstanceData(Shape2D.SHAPE2D_BORDERPARTID));
- }
- if (this.fill) {
- res.push(new Ellipse2DInstanceData(Shape2D.SHAPE2D_FILLPARTID));
- }
- return res;
- }
- private static _riv0 = new Vector2(0,0);
- protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
- if (!super.refreshInstanceDataPart(part)) {
- return false;
- }
- //let s = Ellipse2D._riv0;
- //this.getActualGlobalScaleToRef(s);
- if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
- let d = <Ellipse2DInstanceData>part;
- let size = this.actualSize;
- d.properties = new Vector3(size.width/* * s.x*/, size.height/* * s.y*/, this.subdivisions);
- }
- else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
- let d = <Ellipse2DInstanceData>part;
- let size = this.actualSize;
- d.properties = new Vector3(size.width/* * s.x*/, size.height/* * s.y*/, this.subdivisions);
- }
- return true;
- }
- private _subdivisions: number;
- }
- }
|