diff --git a/src/core/Geometry.js b/src/core/Geometry.js index dfffb61e..f6b45028 100644 --- a/src/core/Geometry.js +++ b/src/core/Geometry.js @@ -5,6 +5,7 @@ // instanced - default null. Pass divisor amount // type - gl enum default gl.UNSIGNED_SHORT for 'index', gl.FLOAT for others // normalized - boolean default false +// integer - boolean default false // buffer - gl buffer, if buffer exists, don't need to provide data - although needs position data for bounds calculation // stride - default 0 - for when passing in buffer @@ -65,6 +66,7 @@ export class Geometry { : attr.data.constructor === Uint16Array ? this.gl.UNSIGNED_SHORT : this.gl.UNSIGNED_INT); // Uint32Array + attr.integer = attr.integer || false; attr.target = key === 'index' ? this.gl.ELEMENT_ARRAY_BUFFER : this.gl.ARRAY_BUFFER; attr.normalized = attr.normalized || false; attr.stride = attr.stride || 0; @@ -153,7 +155,12 @@ export class Geometry { const offset = numLoc === 1 ? 0 : numLoc * 4; for (let i = 0; i < numLoc; i++) { - this.gl.vertexAttribPointer(location + i, size, attr.type, attr.normalized, attr.stride + stride, attr.offset + i * offset); + if(attr.integer && this.gl.renderer.isWebgl2){ + this.gl.vertexAttribIPointer(location + i, size, attr.type, attr.stride + stride, attr.offset + i * offset); + } + else{ + this.gl.vertexAttribPointer(location + i, size, attr.type, attr.normalized, attr.stride + stride, attr.offset + i * offset); + } this.gl.enableVertexAttribArray(location + i); // For instanced attributes, divisor needs to be set. diff --git a/src/core/Program.js b/src/core/Program.js index e8f0a84a..f0a23fe5 100644 --- a/src/core/Program.js +++ b/src/core/Program.js @@ -21,6 +21,8 @@ export class Program { depthTest = true, depthWrite = true, depthFunc = gl.LEQUAL, + blendFunc = {}, + blendEquation = {}, } = {} ) { if (!gl.canvas) console.error('gl not passed as first argument to Program'); @@ -38,8 +40,8 @@ export class Program { this.depthTest = depthTest; this.depthWrite = depthWrite; this.depthFunc = depthFunc; - this.blendFunc = {}; - this.blendEquation = {}; + this.blendFunc = blendFunc; + this.blendEquation = blendEquation; // set default blendFunc if transparent flagged if (this.transparent && !this.blendFunc.src) { @@ -113,16 +115,21 @@ export class Program { } setBlendFunc(src, dst, srcAlpha, dstAlpha) { - this.blendFunc.src = src; - this.blendFunc.dst = dst; - this.blendFunc.srcAlpha = srcAlpha; - this.blendFunc.dstAlpha = dstAlpha; + this.blendFunc = { src, dst, srcAlpha, dstAlpha }; if (src) this.transparent = true; } setBlendEquation(modeRGB, modeAlpha) { - this.blendEquation.modeRGB = modeRGB; - this.blendEquation.modeAlpha = modeAlpha; + this.blendEquation = { modeRGB, modeAlpha }; + } + + setBlendFuncArray(blendFuncs) { + this.blendFunc = blendFuncs.map(({ src, dst, srcAlpha, dstAlpha }) => ({ src, dst, srcAlpha, dstAlpha })); + this.transparent = true; + } + + setBlendEquationArray(blendEquations) { + this.blendEquation = blendEquations.map(({ modeRGB, modeAlpha }) => ({ modeRGB, modeAlpha })); } applyState() { @@ -132,15 +139,39 @@ export class Program { if (this.cullFace) this.gl.renderer.enable(this.gl.CULL_FACE); else this.gl.renderer.disable(this.gl.CULL_FACE); - if (this.blendFunc.src) this.gl.renderer.enable(this.gl.BLEND); - else this.gl.renderer.disable(this.gl.BLEND); + // if (this.blendFunc.src) this.gl.renderer.enable(this.gl.BLEND); + // else this.gl.renderer.disable(this.gl.BLEND); if (this.cullFace) this.gl.renderer.setCullFace(this.cullFace); this.gl.renderer.setFrontFace(this.frontFace); this.gl.renderer.setDepthMask(this.depthWrite); this.gl.renderer.setDepthFunc(this.depthFunc); - if (this.blendFunc.src) this.gl.renderer.setBlendFunc(this.blendFunc.src, this.blendFunc.dst, this.blendFunc.srcAlpha, this.blendFunc.dstAlpha); - this.gl.renderer.setBlendEquation(this.blendEquation.modeRGB, this.blendEquation.modeAlpha); + + if (Array.isArray(this.blendFunc)) { + if (this.blendFunc.length) { + this.blendFunc.forEach((blendFunc, i) => { + if (blendFunc?.src) { + this.gl.renderer.drawBuffersIndexed.enableiOES(this.gl.BLEND, i); + } else { + this.gl.renderer.drawBuffersIndexed.disableiOES(this.gl.BLEND, i); + } + }); + this.gl.renderer.setBlendFuncArray(this.blendFunc); + } else { + this.gl.renderer.disable(this.gl.BLEND); + } + } else if (this.blendFunc.src) { + this.gl.renderer.enable(this.gl.BLEND); + this.gl.renderer.setBlendFunc(this.blendFunc.src, this.blendFunc.dst, this.blendFunc.srcAlpha, this.blendFunc.dstAlpha); + } else { + this.gl.renderer.disable(this.gl.BLEND); + } + + if (Array.isArray(this.blendEquation)) { + this.gl.renderer.setBlendEquationArray(this.blendEquation); + } else { + this.gl.renderer.setBlendEquation(this.blendEquation.modeRGB, this.blendEquation.modeAlpha); + } } use({ flipFaces = false } = {}) { diff --git a/src/core/Renderer.js b/src/core/Renderer.js index 255bd49f..5e38e29f 100644 --- a/src/core/Renderer.js +++ b/src/core/Renderer.js @@ -103,6 +103,7 @@ export class Renderer { this.bindVertexArray = this.getExtension('OES_vertex_array_object', 'bindVertexArray', 'bindVertexArrayOES'); this.deleteVertexArray = this.getExtension('OES_vertex_array_object', 'deleteVertexArray', 'deleteVertexArrayOES'); this.drawBuffers = this.getExtension('WEBGL_draw_buffers', 'drawBuffers', 'drawBuffersWEBGL'); + this.drawBuffersIndexed = this.getExtension('OES_draw_buffers_indexed'); // Store device parameters this.parameters = {}; @@ -153,29 +154,85 @@ export class Renderer { setBlendFunc(src, dst, srcAlpha, dstAlpha) { if ( + !Array.isArray(this.state.blendFunc) && this.state.blendFunc.src === src && this.state.blendFunc.dst === dst && this.state.blendFunc.srcAlpha === srcAlpha && this.state.blendFunc.dstAlpha === dstAlpha ) return; - this.state.blendFunc.src = src; - this.state.blendFunc.dst = dst; - this.state.blendFunc.srcAlpha = srcAlpha; - this.state.blendFunc.dstAlpha = dstAlpha; + this.state.blendFunc = { src, dst, srcAlpha, dstAlpha }; if (srcAlpha !== undefined) this.gl.blendFuncSeparate(src, dst, srcAlpha, dstAlpha); else this.gl.blendFunc(src, dst); } setBlendEquation(modeRGB, modeAlpha) { modeRGB = modeRGB || this.gl.FUNC_ADD; - if (this.state.blendEquation.modeRGB === modeRGB && this.state.blendEquation.modeAlpha === modeAlpha) return; - this.state.blendEquation.modeRGB = modeRGB; - this.state.blendEquation.modeAlpha = modeAlpha; + if (!Array.isArray(this.state.blendEquation) && this.state.blendEquation.modeRGB === modeRGB && this.state.blendEquation.modeAlpha === modeAlpha) return; + this.state.blendEquation = { modeRGB, modeAlpha }; if (modeAlpha !== undefined) this.gl.blendEquationSeparate(modeRGB, modeAlpha); else this.gl.blendEquation(modeRGB); } + setBlendFuncArray(blendFuncs) { + if ( + Array.isArray(this.state.blendFunc) && + this.state.blendFunc.length === blendFuncs.length && + this.state.blendFunc.every((blendFunc, i) => { + const newBlendFunc = blendFuncs[i]; + if (blendFunc === null && newBlendFunc === null) { + return true; + } + return blendFunc.src === newBlendFunc.src && blendFunc.dst === newBlendFunc.dst && blendFunc.srcAlpha === newBlendFunc.srcAlpha && blendFunc.dstAlpha === newBlendFunc.dstAlpha; + }) + ) + return; + this.state.blendFunc = blendFuncs.map((blendFunc) => { + if (blendFunc) { + return { src: blendFunc.src, dst: blendFunc.dst, srcAlpha: blendFunc.srcAlpha, dstAlpha: blendFunc.dstAlpha }; + } + return null; + }); + + blendFuncs.forEach((blendFunc, i) => { + if (blendFunc === null) { + return; + } + if (blendFunc.srcAlpha !== undefined) { + this.drawBuffersIndexed.blendFuncSeparateiOES(i, blendFunc.src, blendFunc.dst, blendFunc.srcAlpha, blendFunc.dstAlpha); + } else { + this.drawBuffersIndexed.blendFunciOES(i, blendFunc.src, blendFunc.dst); + } + }); + } + + setBlendEquationArray(blendEquations) { + if ( + Array.isArray(this.state.blendEquation) && + this.state.blendEquation.length === blendEquations.length && + this.state.blendEquation.every((blendEquation, i) => { + const newBlendEquation = blendEquations[i]; + if (blendEquation === null && newBlendEquation === null) { + return true; + } + return blendEquation.modeRGB === newBlendEquation.modeRGB && blendEquation.modeAlpha === newBlendEquation.modeAlpha; + }) + ) + return; + this.state.blendEquation = blendEquations.map(({ modeRGB, modeAlpha }) => ({ modeRGB, modeAlpha })); + + blendEquations.forEach((blendEquation, i) => { + if (blendEquation === null) { + return; + } + if (blendEquation.modeAlpha !== undefined) { + this.drawBuffersIndexed.blendEquationSeparateiOES(i, blendEquation.modeRGB, blendEquation.modeAlpha); + } else { + this.drawBuffersIndexed.blendEquationiOES(i, blendEquation.modeRGB); + } + }); + } + setCullFace(value) { if (this.state.cullFace === value) return; this.state.cullFace = value; @@ -334,11 +391,7 @@ export class Renderer { this.enable(this.gl.DEPTH_TEST); this.setDepthMask(true); } - this.gl.clear( - (this.color ? this.gl.COLOR_BUFFER_BIT : 0) | - (this.depth ? this.gl.DEPTH_BUFFER_BIT : 0) | - (this.stencil ? this.gl.STENCIL_BUFFER_BIT : 0) - ); + this.gl.clear((this.color ? this.gl.COLOR_BUFFER_BIT : 0) | (this.depth ? this.gl.DEPTH_BUFFER_BIT : 0) | (this.stencil ? this.gl.STENCIL_BUFFER_BIT : 0)); } // updates all scene graph matrices diff --git a/types/core/Geometry.d.ts b/types/core/Geometry.d.ts index 5137b7f5..a1641ea6 100644 --- a/types/core/Geometry.d.ts +++ b/types/core/Geometry.d.ts @@ -13,6 +13,7 @@ export interface Attribute { instanced: null | number | boolean; type: GLenum; normalized: boolean; + integer: boolean; buffer: WebGLBuffer; stride: number; diff --git a/types/core/Program.d.ts b/types/core/Program.d.ts index 2c63999d..9edd1e4c 100644 --- a/types/core/Program.d.ts +++ b/types/core/Program.d.ts @@ -11,6 +11,8 @@ export interface ProgramOptions { depthTest: boolean; depthWrite: boolean; depthFunc: GLenum; + blendFunc: BlendFunc | (BlendFunc | null)[]; + blendEquation: BlendEquation | (BlendEquation | null)[]; } export interface UniformInfo extends WebGLActiveInfo { @@ -37,8 +39,8 @@ export class Program { depthTest: boolean; depthWrite: boolean; depthFunc: GLenum; - blendFunc: BlendFunc; - blendEquation: BlendEquation; + blendFunc: BlendFunc | (BlendFunc | null)[]; + blendEquation: BlendEquation | (BlendEquation | null)[]; vertexShader: WebGLShader; fragmentShader: WebGLShader; @@ -55,6 +57,10 @@ export class Program { setBlendEquation(modeRGB: GLenum, modeAlpha: GLenum): void; + setBlendFuncArray(blendFuncs: BlendFunc[]): void; + + setBlendEquationArray(blendEquations: BlendEquation[]): void; + applyState(): void; use(options?: { flipFaces?: boolean }): void; diff --git a/types/core/Renderer.d.ts b/types/core/Renderer.d.ts index 6612f7c7..d4cb8cae 100644 --- a/types/core/Renderer.d.ts +++ b/types/core/Renderer.d.ts @@ -49,8 +49,8 @@ export interface Viewport { } export interface RenderState { - blendFunc: BlendFunc; - blendEquation: BlendEquation; + blendFunc: BlendFunc | (BlendFunc | null)[]; + blendEquation: BlendEquation | (BlendEquation | null)[]; cullFace: GLenum | false | null; frontFace: number; depthMask: boolean; @@ -98,6 +98,7 @@ export class Renderer { bindVertexArray: Function; deleteVertexArray: Function; drawBuffers: Function; + drawBuffersIndexed: OES_draw_buffers_indexed parameters: DeviceParameters; @@ -118,10 +119,14 @@ export class Renderer { disable(id: GLenum): void; - setBlendFunc(src: GLenum, dst: GLenum, srcAlpha: GLenum, dstAlpha: GLenum): void; + setBlendFunc(src: GLenum, dst: GLenum, srcAlpha?: GLenum, dstAlpha?: GLenum): void; setBlendEquation(modeRGB: GLenum, modeAlpha: GLenum): void; + setBlendFuncArray(blendFuncs: (BlendFunc | null)[]): void; + + setBlendEquationArray(blendEquations: (BlendEquation | null)[]): void; + setCullFace(value: GLenum): void; setFrontFace(value: GLenum): void;