UNPKG

meta-next

Version:

182 lines (156 loc) 4.54 kB
import Engine from "../Engine" import Vector3 from "../math/Vector3" import Vector4 from "../math/Vector4" import Matrix4 from "../math/Matrix4" import Texture from "../resources/Texture" import DrawCommand from "./DrawCommand" let activeMaterial = null const emptyVector3 = new Vector3() const emptyVector4 = new Vector4() const emptyMatrix = new Matrix4() let emptyTexture = null let emptyPropsCreated = false class Renderer { constructor() { Engine.on("setup", this.setup.bind(this)) } setup() { if(!emptyPropsCreated) { emptyPropsCreated = true emptyTexture = new Texture() emptyTexture.loadEmpty() } } render(drawCommand) { const gl = Engine.gl const mesh = drawCommand.mesh this.useMaterial(drawCommand.material) this.updateAttribs(drawCommand) this.updateUniforms(drawCommand) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indices) gl.drawElements(drawCommand.mode, mesh.numElements, gl.UNSIGNED_SHORT, 0) } useMaterial(material) { if(activeMaterial === material) { return } const gl = Engine.gl gl.useProgram(material.program) const currNumAttribs = this.activeMaterial ? this.activeMaterial.numAttribs : 0 const newNumAttribs = material.numAttribs if(currNumAttribs < newNumAttribs) { for(let n = currNumAttribs; n < newNumAttribs; n++) { gl.enableVertexAttribArray(n) } } else { for(let n = newNumAttribs; n < currNumAttribs; n++) { gl.disableVertexAttribArray(n) } } activeMaterial = material } updateAttribs(drawCommand) { const gl = Engine.gl const mesh = drawCommand.mesh const attribData = drawCommand.material.attribData for(let n = 0; n < attribData.length; n++) { const attrib = attribData[n] switch(attrib.name) { case "position": gl.bindBuffer(gl.ARRAY_BUFFER, mesh.buffer) gl.vertexAttribPointer(attrib.loc, 2, gl.FLOAT, false, mesh.stride, 0) break case "uv": gl.bindBuffer(gl.ARRAY_BUFFER, mesh.buffer); gl.vertexAttribPointer(attrib.loc, 2, gl.FLOAT, false, mesh.stride, 8) break } } } updateUniforms(drawCommand) { let numSamplers = 0 const gl = Engine.gl const material = drawCommand.material const uniforms = drawCommand.uniforms const uniformData = material.uniformData for(let n = 0; n < uniformData.length; n++) { const uniform = uniformData[n] switch(uniform.type) { case gl.FLOAT_MAT4: { let matrix switch(uniform.name) { case "matrixProjection": matrix = Engine.camera.projectionTransform break case "matrixView": matrix = Engine.camera.transform break case "matrixModel": matrix = drawCommand.transform break default: matrix = material.uniforms[uniform.name] break } if(matrix) { gl.uniformMatrix4fv(uniform.loc, false, matrix.m) } else { gl.uniformMatrix4fv(uniform.loc, false, emptyMatrix.m) console.warn(`(Renderer.updateUniforms) Empty FLOAT_MAT4 uniform used for: ${uniform.name}`) } } break case gl.FLOAT_VEC3: { const vec = uniforms[uniform.name] if(vec) { gl.uniform3fv(uniform.loc, vec.toFloat32Array()) } else { gl.uniform3fv(uniform.loc, emptyVector3.toFloat32Array()) console.warn(`(Renderer.updateUniforms) Empty FLOAT_VEC3 uniform used for: ${uniform.name}`) } } break case gl.FLOAT_VEC4: { const vec = uniforms[uniform.name] if(vec) { gl.uniform4fv(uniform.loc, vec.toFloat32Array()) } else { gl.uniform4fv(uniform.loc, emptyVector4.toFloat32Array()) console.warn(`(Renderer.updateUniforms) Empty FLOAT_VEC4 uniform used for: ${uniform.name}`) } } break case gl.SAMPLER_2D: { const texture = uniforms[uniform.name] gl.activeTexture(gl.TEXTURE0 + numSamplers) if(texture) { gl.bindTexture(gl.TEXTURE_2D, texture) } else { gl.bindTexture(gl.TEXTURE_2D, emptyTexture.instance) console.warn(`(Renderer.updateUniforms) Empty SAMPLER_2D uniform used for: ${uniform.name}`) } gl.uniform1i(uniform.loc, numSamplers++) } break case gl.FLOAT: { const float = uniforms[uniform.name] gl.uniform1f(uniform.loc, float || 0) } break } } } } export default Renderer