Bläddra i källkod

Added support for non InstancedArray pipeline when the extension is not available. https://trello.com/c/BsZT9Nq4

nockawa 9 år sedan
förälder
incheckning
79d1e3d262

+ 8 - 0
src/Canvas2d/babylon.canvas2d.ts

@@ -91,6 +91,9 @@
                     this.render();
                 });
             }
+
+            this._supprtInstancedArray = this._engine.getCaps().instancedArrays !== null;
+            this._supprtInstancedArray = false; // TODO REMOVE!!!
         }
 
         public dispose(): boolean {
@@ -134,6 +137,10 @@
             return this._cachingStrategy;
         }
 
+        public get supportInstancedArray() {
+            return this._supprtInstancedArray;
+        }
+
         /**
          * Property that defines the fill object used to draw the background of the Canvas.
          * Note that Canvas with a Caching Strategy of
@@ -213,6 +220,7 @@
         private _groupCacheMaps: MapTexture[];
         private _beforeRenderObserver: Observer<Scene>;
         private _afterRenderObserver: Observer<Scene>;
+        private _supprtInstancedArray : boolean;
 
         public _renderingSize: Size;
 

+ 79 - 3
src/Canvas2d/babylon.modelRenderCache.ts

@@ -11,6 +11,7 @@
             this._instancesPartsBuffer = new Array<WebGLBuffer>();
             this._instancesPartsBufferSize = new Array<number>();
             this._partIndexFromId = new StringDictionary<number>();
+            this._instancesPartsUsedShaderCategories = new Array<string>();
         }
 
         _owner: Group2D;
@@ -20,6 +21,7 @@
         _dirtyInstancesData: boolean;
         _instancesPartsBuffer: WebGLBuffer[];
         _instancesPartsBufferSize: number[];
+        _instancesPartsUsedShaderCategories: string[];
     }
 
     export class ModelRenderCache {
@@ -54,13 +56,18 @@
             this._instancesData.remove(key);
         }
 
-        protected loadInstancingAttributes(partId: number, effect: Effect): InstancingAttributeInfo[] {
+        protected getPartIndexFromId(partId: number) {
             for (var i = 0; i < this._partIdList.length; i++) {
                 if (this._partIdList[i] === partId) {
-                    break;
+                    return i;
                 }
             }
-            if (i === this._partIdList.length) {
+            return null;
+        }
+
+        protected loadInstancingAttributes(partId: number, effect: Effect): InstancingAttributeInfo[] {
+            let i = this.getPartIndexFromId(partId);
+            if (i === null) {
                 return null;
             }
 
@@ -71,12 +78,81 @@
             return res;
         }
 
+        //setupUniformsLocation(effect: Effect, uniforms: string[], partId: number) {
+        //    let i = this.getPartIndexFromId(partId);
+        //    if (i === null) {
+        //        return null;
+        //    }
+
+        //    let pci = this._partsClassInfo[i];
+        //    pci.fullContent.forEach((k, v) => {
+        //        if (uniforms.indexOf(v.attributeName) !== -1) {
+        //            v.uniformLocation = effect.getUniform(v.attributeName);
+        //        }
+        //    });
+        //}
+
+        private static v2 = Vector2.Zero();
+        private static v3 = Vector3.Zero();
+        private static v4 = Vector4.Zero();
+
+        protected setupUniforms(effect: Effect, partIndex: number, data: DynamicFloatArray, elementCount: number) {
+            let offset = (this._partsDataStride[partIndex]/4) * elementCount;
+            let pci = this._partsClassInfo[partIndex];
+
+            let self = this;
+            pci.fullContent.forEach((k, v) => {
+                if (!v.category || self._partsUsedCategories[partIndex].indexOf(v.category)!==1) {
+                    switch (v.dataType) {
+                        case ShaderDataType.float:
+                        {
+                            let attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                            effect.setFloat(v.attributeName, data.buffer[offset + attribOffset]);
+                            break;
+                        }
+                        case ShaderDataType.Vector2:
+                        {
+                            let attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                            ModelRenderCache.v2.x = data.buffer[offset + attribOffset + 0];
+                            ModelRenderCache.v2.y = data.buffer[offset + attribOffset + 1];
+                            effect.setVector2(v.attributeName, ModelRenderCache.v2);
+                            break;
+                        }
+                        case ShaderDataType.Color3:
+                        case ShaderDataType.Vector3:
+                        {
+                            let attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                            ModelRenderCache.v3.x = data.buffer[offset + attribOffset + 0];
+                            ModelRenderCache.v3.y = data.buffer[offset + attribOffset + 1];
+                            ModelRenderCache.v3.z = data.buffer[offset + attribOffset + 2];
+                            effect.setVector3(v.attributeName, ModelRenderCache.v3);
+                            break;
+                        }
+                        case ShaderDataType.Color4:
+                        case ShaderDataType.Vector4:
+                        {
+                            let attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                            ModelRenderCache.v4.x = data.buffer[offset + attribOffset + 0];
+                            ModelRenderCache.v4.y = data.buffer[offset + attribOffset + 1];
+                            ModelRenderCache.v4.z = data.buffer[offset + attribOffset + 2];
+                            ModelRenderCache.v4.w = data.buffer[offset + attribOffset + 3];
+                            effect.setVector4(v.attributeName, ModelRenderCache.v4);
+                            break;
+                        }
+                        default:
+                    }
+                }
+            });
+        }
+
+
         _instancesData: StringDictionary<InstanceDataBase[]>;
 
         private _nextKey: number;
         _partIdList: number[];
         _partsDataStride: number[];
         _partsUsedCategories: Array<string[]>;
+        _partsJoinedUsedCategories: string[];
         _partsClassInfo: ClassTreeInfo<InstanceClassInfo, InstancePropInfo>[];
     }
 }

+ 37 - 23
src/Canvas2d/babylon.rectangle2d.ts

@@ -24,36 +24,46 @@
             if (this.effectFill) {
                 let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_FILLPARTID.toString());
 
-                // Compute the offset locations of the attributes in the vertexshader that will be mapped to the instance buffer data
-                if (!this.instancingFillAttributes) {
-                    this.instancingFillAttributes = this.loadInstancingAttributes(Shape2D.SHAPE2D_FILLPARTID, this.effectFill);
-                }
-
                 engine.enableEffect(this.effectFill);
                 engine.bindBuffers(this.fillVB, this.fillIB, [1], 4, this.effectFill);
-
-                engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
-
-                engine.draw(true, 0, this.fillIndicesCount, instanceInfo._instancesPartsData[partIndex].usedElementCount);
-
-                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingFillAttributes);
+                let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
+                if (instanceInfo._owner.owner.supportInstancedArray) {
+                    if (!this.instancingFillAttributes) {
+                        // Compute the offset locations of the attributes in the vertexshader that will be mapped to the instance buffer data
+                        this.instancingFillAttributes = this.loadInstancingAttributes(Shape2D.SHAPE2D_FILLPARTID, this.effectFill);
+                    }
+
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingFillAttributes);
+                } else {
+                    for (let i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.fillIndicesCount);                        
+                    }
+                }
             }
 
             if (this.effectBorder) {
                 let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_BORDERPARTID.toString());
 
-                // Compute the offset locations of the attributes in the vertexshader that will be mapped to the instance buffer data
-                if (!this.instancingBorderAttributes) {
-                    this.instancingBorderAttributes = this.loadInstancingAttributes(Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
-                }
                 engine.enableEffect(this.effectBorder);
                 engine.bindBuffers(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
-
-                engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
-
-                engine.draw(true, 0, this.borderIndicesCount, instanceInfo._instancesPartsData[partIndex].usedElementCount);
-
-                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingBorderAttributes);
+                let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
+                if (instanceInfo._owner.owner.supportInstancedArray) {
+                    if (!this.instancingBorderAttributes) {
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                    }
+
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingBorderAttributes);
+                } else {
+                    for (let i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.borderIndicesCount);
+                    }
+                }
             }
             return true;
         }
@@ -169,7 +179,9 @@
                 renderCache.fillIndicesCount = triCount * 3;
 
                 let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_FILLPARTID, ["index"]);
-                renderCache.effectFill = engine.createEffect({ vertex: "rect2d", fragment: "rect2d" }, ei.attributes, [], [], ei.defines);
+                renderCache.effectFill = engine.createEffect({ vertex: "rect2d", fragment: "rect2d" }, ei.attributes, ei.uniforms, [], ei.defines, null, e => {
+//                    renderCache.setupUniformsLocation(e, ei.uniforms, Shape2D.SHAPE2D_FILLPARTID);
+                });
             }
 
             // Need to create webgl resource for border part?
@@ -201,7 +213,9 @@
                 renderCache.borderIndicesCount = triCount * 3;
 
                 let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_BORDERPARTID, ["index"]);
-                renderCache.effectBorder = engine.createEffect({ vertex: "rect2d", fragment: "rect2d" }, ei.attributes, [], [], ei.defines);
+                renderCache.effectBorder = engine.createEffect({ vertex: "rect2d", fragment: "rect2d" }, ei.attributes, ei.uniforms, [], ei.defines, null, e => {
+//                    renderCache.setupUniformsLocation(e, ei.uniforms, Shape2D.SHAPE2D_BORDERPARTID);
+                });
             }
 
             return renderCache;

+ 44 - 26
src/Canvas2d/babylon.renderablePrim2d.ts

@@ -58,8 +58,8 @@
         }
 
         private _getBaseOffset(categories: string): number {
-            var curOffset = 0;
-            var curBase = this._baseInfo;
+            let curOffset = 0;
+            let curBase = this._baseInfo;
             while (curBase) {
                 curOffset += curBase._nextOffset.getOrAdd(categories, 0);
                 curBase = curBase._baseInfo;
@@ -80,6 +80,7 @@
         shaderOffset: number;
         instanceOffset: StringDictionary<number>;
         dataType: ShaderDataType;
+        //uniformLocation: WebGLUniformLocation;
 
         constructor() {
             this.instanceOffset = new StringDictionary<number>();
@@ -187,7 +188,7 @@
         return (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => {
 
             let dic = ClassTreeInfo.getOrRegister<InstanceClassInfo, InstancePropInfo>(target, (base) => new InstanceClassInfo(base));
-            var node = dic.getLevelOf(target);
+            let node = dic.getLevelOf(target);
             let instanceDataName = <string>propName;
             shaderAttributeName = shaderAttributeName || instanceDataName;
 
@@ -199,7 +200,7 @@
 
             info = new InstancePropInfo();
             info.attributeName = shaderAttributeName;
-            info.category = category;
+            info.category = category || null;
 
             node.levelContent.add(instanceDataName, info);
 
@@ -215,7 +216,7 @@
                     node.classContent.mapProperty(info, false);
                 }
 
-                var obj: InstanceDataBase = this;
+                let obj: InstanceDataBase = this;
                 if (obj.dataBuffer && obj.dataElements) {
                     let offset = obj.dataElements[obj.curElement].offset + info.instanceOffset.get(InstanceClassInfo._CurCategories);
                     info.writeData(obj.dataBuffer.buffer, offset, val);
@@ -263,7 +264,7 @@
         }
 
         allocElements() {
-            var res = new Array<DynamicFloatArrayElementInfo>(this.dataElementCount);
+            let res = new Array<DynamicFloatArrayElementInfo>(this.dataElementCount);
             for (let i = 0; i < this.dataElementCount; i++) {
                 res[i] = this.dataBuffer.allocElement();
             }
@@ -306,9 +307,12 @@
             // Need to create the model?
             let setupModelRenderCache = false;
             if (!this._modelRenderCache || this._modelDirty) {
-                this._modelRenderCache = SmartPropertyPrim.GetOrAddModelCache(this.modelKey, (key: string) => this.createModelRenderCache());
+                this._modelRenderCache = SmartPropertyPrim.GetOrAddModelCache(this.modelKey, (key: string) => {
+                    let mrc = this.createModelRenderCache();
+                    setupModelRenderCache = true;
+                    return mrc;
+                });
                 this._modelDirty = false;
-                setupModelRenderCache = true;
             }
 
             // Need to create the instance?
@@ -321,11 +325,12 @@
 
                 if (!this._modelRenderCache._partsDataStride) {
                     let ctiArray = new Array<ClassTreeInfo<InstanceClassInfo, InstancePropInfo>>();
-                    var dataStrides = new Array<number>();
-                    var usedCatList = new Array<string[]>();
-                    var partIdList = new Array<number>();
+                    let dataStrides = new Array<number>();
+                    let usedCatList = new Array<string[]>();
+                    let partIdList = new Array<number>();
+                    let joinedUsedCatList = new Array<string>();
 
-                    for (var dataPart of parts) {
+                    for (let dataPart of parts) {
                         let cat = this.getUsedShaderCategories(dataPart);
                         let cti = dataPart.getClassTreeInfo();
                         // Make sure the instance is visible other the properties won't be set and their size/offset wont be computed
@@ -333,11 +338,13 @@
                         this.isVisible = true;
                         // We manually trigger refreshInstanceData for the only sake of evaluating each isntance property size and offset in the instance data, this can only be made at runtime. Once it's done we have all the information to create the instance data buffer.
                         //console.log("Build Prop Layout for " + Tools.getClassName(this._instanceDataParts[0]));
-                        InstanceClassInfo._CurCategories = cat.join(";");
+                        let joinCat = cat.join(";");
+                        joinedUsedCatList.push(joinCat);
+                        InstanceClassInfo._CurCategories = joinCat;
                         this.refreshInstanceDataPart(dataPart);
                         this.isVisible = curVisible;
 
-                        var size = 0;
+                        let size = 0;
                         cti.fullContent.forEach((k, v) => {
                             if (!v.category || cat.indexOf(v.category) !== -1) {
                                 if (!v.size) {
@@ -354,17 +361,23 @@
                     }
                     this._modelRenderCache._partsDataStride = dataStrides;
                     this._modelRenderCache._partsUsedCategories = usedCatList;
+                    this._modelRenderCache._partsJoinedUsedCategories = joinedUsedCatList;
                     this._modelRenderCache._partsClassInfo = ctiArray;
                     this._modelRenderCache._partIdList = partIdList;
                 }
 
                 gii = this.renderGroup.groupRenderInfo.getOrAddWithFactory(this.modelKey, k => new GroupInstanceInfo(this.renderGroup, this._modelRenderCache));
 
+                // First time init of the GroupInstanceInfo
                 if (gii._instancesPartsData.length === 0) {
                     for (let j = 0; j < this._modelRenderCache._partsDataStride.length; j++) {
                         let stride = this._modelRenderCache._partsDataStride[j];
                         gii._instancesPartsData.push(new DynamicFloatArray(stride / 4, 50));
                         gii._partIndexFromId.add(this._modelRenderCache._partIdList[j].toString(), j);
+
+                        for (let part of this._instanceDataParts) {
+                            gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())] = this.getUsedShaderCategories(part).join(";");
+                        }
                     }
                 }
 
@@ -382,9 +395,13 @@
             }
 
             if (context.forceRefreshPrimitive || newInstance || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep)) {
+                if (!gii) {
+                    gii = this.renderGroup.groupRenderInfo.get(this.modelKey);
+                }
+
                 for (let part of this._instanceDataParts) {
                     let cat = this.getUsedShaderCategories(part);
-                    InstanceClassInfo._CurCategories = cat.join(";");
+                    InstanceClassInfo._CurCategories = gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())];
 
                     // Will return false if the instance should not be rendered (not visible or other any reasons)
                     if (!this.refreshInstanceDataPart(part)) {
@@ -396,27 +413,28 @@
                 }
                 this._instanceDirtyFlags = 0;
 
-                if (!gii) {
-                    gii = this.renderGroup.groupRenderInfo.get(this.modelKey);
-                }
-
                 gii._dirtyInstancesData = true;
             }
         }
 
-        protected getDataPartEffectInfo(dataPartId: number, vertexBufferAttributes: string[]): {attributes: string[], defines: string} {
-            var dataPart = Tools.first(this._instanceDataParts, i => i.id === dataPartId);
+        protected getDataPartEffectInfo(dataPartId: number, vertexBufferAttributes: string[]): { attributes: string[], uniforms: string[], defines: string} {
+            let dataPart = Tools.first(this._instanceDataParts, i => i.id === dataPartId);
             if (!dataPart) {
                 return null;
             }
 
-            var cti = dataPart.getClassTreeInfo();
-            var categories = this.getUsedShaderCategories(dataPart);
-            var attributes = vertexBufferAttributes.concat(cti.classContent.getShaderAttributes(categories));
-            var defines = "";
+            let instancedArray = this.owner.supportInstancedArray;
+
+            let cti = dataPart.getClassTreeInfo();
+            let categories = this.getUsedShaderCategories(dataPart);
+            let att = cti.classContent.getShaderAttributes(categories);
+            let defines = "";
             categories.forEach(c => { defines += `#define ${c}\n`});
+            if (instancedArray) {
+                defines += "#define Instanced\n";
+            }
 
-            return { attributes: attributes, defines: defines };
+            return { attributes: instancedArray ? vertexBufferAttributes.concat(att) : vertexBufferAttributes, uniforms: instancedArray ? [] : att, defines: defines };
         }
 
         public get isTransparent(): boolean {

+ 18 - 7
src/Canvas2d/babylon.sprite2d.ts

@@ -16,22 +16,31 @@
             }
 
             // Compute the offset locations of the attributes in the vertexshader that will be mapped to the instance buffer data
-            if (!this.instancingAttributes) {
-                this.instancingAttributes = this.loadInstancingAttributes(Sprite2D.SPRITE2D_MAINPARTID, this.effect);
-            }
             var engine = instanceInfo._owner.owner.engine;
 
             engine.enableEffect(this.effect);
             this.effect.setTexture("diffuseSampler", this.texture);
             engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
 
-            engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
             var cur = engine.getAlphaMode();
             engine.setAlphaMode(Engine.ALPHA_COMBINE);
-            engine.draw(true, 0, 6, instanceInfo._instancesPartsData[0].usedElementCount);
+            let count = instanceInfo._instancesPartsData[0].usedElementCount;
+            if (instanceInfo._owner.owner.supportInstancedArray) {
+                if (!this.instancingAttributes) {
+                    this.instancingAttributes = this.loadInstancingAttributes(Sprite2D.SPRITE2D_MAINPARTID, this.effect);
+                }
+                engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
+                engine.draw(true, 0, 6, count);
+                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
+            } else {
+                for (let i = 0; i < count; i++) {
+                    this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);
+                    engine.draw(true, 0, 6);
+                }
+            }
+
             engine.setAlphaMode(cur);
 
-            engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
 
             return true;
         }
@@ -175,7 +184,9 @@
             renderCache.texture = this.texture;
 
             var ei = this.getDataPartEffectInfo(Sprite2D.SPRITE2D_MAINPARTID, ["index"]);
-            renderCache.effect = engine.createEffect({ vertex: "sprite2d", fragment: "sprite2d" }, ei.attributes, [], ["diffuseSampler"], ei.defines);
+            renderCache.effect = engine.createEffect({ vertex: "sprite2d", fragment: "sprite2d" }, ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null, e => {
+//                renderCache.setupUniformsLocation(e, ei.uniforms, Sprite2D.SPRITE2D_MAINPARTID);
+            });
 
             return renderCache;
         }

+ 15 - 4
src/Canvas2d/babylon.text2d.ts

@@ -26,13 +26,22 @@
             this.effect.setTexture("diffuseSampler", this.fontTexture);
             engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
 
-            engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
             var cur = engine.getAlphaMode();
             engine.setAlphaMode(Engine.ALPHA_COMBINE);
-            engine.draw(true, 0, 6, instanceInfo._instancesPartsData[0].usedElementCount);
+            let count = instanceInfo._instancesPartsData[0].usedElementCount;
+            if (instanceInfo._owner.owner.supportInstancedArray) {
+                engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
+                engine.draw(true, 0, 6, count);
+                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
+            } else {
+                for (let i = 0; i < count; i++) {
+                    this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);
+                    engine.draw(true, 0, 6);
+                }
+            }
+
             engine.setAlphaMode(cur);
 
-            engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
 
             return true;
         }
@@ -216,7 +225,9 @@
 
             // Effects
             let ei = this.getDataPartEffectInfo(Text2D.TEXT2D_MAINPARTID, ["index"]);
-            renderCache.effect = engine.createEffect("text2d", ei.attributes, [], ["diffuseSampler"], ei.defines);
+            renderCache.effect = engine.createEffect("text2d", ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null, e => {
+//                renderCache.setupUniformsLocation(e, ei.uniforms, Text2D.TEXT2D_MAINPARTID);
+            });
 
             return renderCache;
         }

+ 21 - 15
src/Shaders/rect2d.vertex.fx

@@ -1,36 +1,42 @@
-// Attributes
+// based on if Instanced Array are supported or not, declare the field either as attribute or uniform
+#ifdef Instanced
+#define att attribute
+#else
+#define att uniform
+#endif
+
 attribute float index;
-attribute vec2 zBias;
-attribute vec4 transformX;
-attribute vec4 transformY;
-attribute vec2 origin;
+att vec2 zBias;
+att vec4 transformX;
+att vec4 transformY;
+att vec2 origin;
 
 #ifdef Border
-attribute float borderThickness;
+att float borderThickness;
 #endif
 
 #ifdef FillSolid
-attribute vec4 fillSolidColor;
+att vec4 fillSolidColor;
 #endif
 
 #ifdef BorderSolid
-attribute vec4 borderSolidColor;
+att vec4 borderSolidColor;
 #endif
 
 #ifdef FillGradient
-attribute vec4 fillGradientColor1;
-attribute vec4 fillGradientColor2;
-attribute vec4 fillGradientTY;
+att vec4 fillGradientColor1;
+att vec4 fillGradientColor2;
+att vec4 fillGradientTY;
 #endif
 
 #ifdef BorderGradient
-attribute vec4 borderGradientColor1;
-attribute vec4 borderGradientColor2;
-attribute vec4 borderGradientTY;
+att vec4 borderGradientColor1;
+att vec4 borderGradientColor2;
+att vec4 borderGradientTY;
 #endif
 
 // xyzw are: width, height, roundRadius (0.0 for simple rectangle with four vertices)
-attribute vec3 properties;
+att vec3 properties;
 
 // First index is the center, then there's four sections of 16 subdivisions
 

+ 17 - 11
src/Shaders/sprite2d.vertex.fx

@@ -1,16 +1,22 @@
-// Attributes
-attribute float index;
-attribute vec2 zBias;
+// based on if Instanced Array are supported or not, declare the field either as attribute or uniform
+#ifdef Instanced
+#define att attribute
+#else
+#define att uniform
+#endif
 
-attribute vec4 transformX;
-attribute vec4 transformY;
+// Attributes
+attribute float index;
 
-attribute vec2 topLeftUV;
-attribute vec2 sizeUV;
-attribute vec2 origin;
-attribute vec2 textureSize;
-attribute float frame;
-attribute float invertY;
+att vec2 topLeftUV;
+att vec2 sizeUV;
+att vec2 origin;
+att vec2 textureSize;
+att float frame;
+att float invertY;
+att vec2 zBias;
+att vec4 transformX;
+att vec4 transformY;
 
 // Uniforms
 

+ 15 - 10
src/Shaders/text2d.vertex.fx

@@ -1,16 +1,21 @@
-// Attributes
+// based on if Instanced Array are supported or not, declare the field either as attribute or uniform
+#ifdef Instanced
+#define att attribute
+#else
+#define att uniform
+#endif
+
+// Attributes
 attribute float index;
-attribute vec2 zBias;
+att vec2 zBias;
 
-attribute vec4 transformX;
-attribute vec4 transformY;
+att vec4 transformX;
+att vec4 transformY;
 
-attribute vec2 topLeftUV;
-attribute vec2 sizeUV;
-attribute vec2 origin;
-attribute vec2 textureSize;
-
-// Uniforms
+att vec2 topLeftUV;
+att vec2 sizeUV;
+att vec2 origin;
+att vec2 textureSize;
 
 // Output
 varying vec2 vUV;