123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- 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();
- }
- let 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;
- }
- }
- @className("Ellipse2D")
- /**
- * Ellipse Primitive class
- */
- export class Ellipse2D extends Shape2D {
- public static acutalSizeProperty: Prim2DPropInfo;
- public static subdivisionsProperty: Prim2DPropInfo;
- @instanceLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 1, pi => Ellipse2D.acutalSizeProperty = pi, false, true)
- /**
- * Get/Set the size of the ellipse
- */
- public get actualSize(): Size {
- if (this._actualSize) {
- return this._actualSize;
- }
- return this.size;
- }
- public set actualSize(value: Size) {
- this._actualSize = value;
- }
- @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() {
- BoundingInfo2D.CreateFromSizeToRef(this.actualSize, this._levelBoundingInfo);
- }
- /**
- * 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
- * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
- * - 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.
- * - 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!
- * - 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,
- opacity ?: number,
- origin ?: Vector2,
- size ?: Size,
- width ?: number,
- height ?: number,
- subdivisions ?: number,
- fill ?: IBrush2D | string,
- border ?: IBrush2D | string,
- borderThickness ?: number,
- isVisible ?: boolean,
- childrenFlatZOrder?: boolean,
- 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 ?: 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 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 + 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
- let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_FILLPARTID, ["index"], 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"], 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"], 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"], 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;
- }
- protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
- if (!super.refreshInstanceDataPart(part)) {
- return false;
- }
- if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
- let d = <Ellipse2DInstanceData>part;
- let size = this.actualSize;
- d.properties = new Vector3(size.width, size.height, this.subdivisions);
- }
- else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
- let d = <Ellipse2DInstanceData>part;
- let size = this.actualSize;
- d.properties = new Vector3(size.width, size.height, this.subdivisions);
- }
- return true;
- }
- private _subdivisions: number;
- }
- }
|