|
import Attribute from './Attribute.js'; |
|
|
|
export default class Material { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gl; |
|
|
|
uniformInstances = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(minigl, vertexShaders, fragments, uniforms = {}, properties = {}) { |
|
|
|
|
|
Object.assign(this, properties); |
|
|
|
|
|
this.gl = minigl; |
|
this.uniforms = uniforms; |
|
|
|
const context = this.gl.getContext(); |
|
|
|
const prefix = ` |
|
precision highp float; |
|
`; |
|
|
|
this.vertexSource = ` |
|
${prefix} |
|
attribute vec4 position; |
|
attribute vec2 uv; |
|
attribute vec2 uvNorm; |
|
${this._getUniformVariableDeclarations(this.gl.commonUniforms,"vertex")} |
|
${this._getUniformVariableDeclarations(uniforms,"vertex")} |
|
${vertexShaders} |
|
`; |
|
|
|
this.Source = ` |
|
${prefix} |
|
${this._getUniformVariableDeclarations(this.gl.commonUniforms,"fragment")} |
|
${this._getUniformVariableDeclarations(uniforms,"fragment")} |
|
${fragments} |
|
`; |
|
|
|
this.vertexShader = this._getShaderByType(context.VERTEX_SHADER, this.vertexSource); |
|
this.fragmentShader = this._getShaderByType(context.FRAGMENT_SHADER, this.Source); |
|
this.program = context.createProgram(); |
|
|
|
context.attachShader(this.program, this.vertexShader); |
|
context.attachShader(this.program, this.fragmentShader); |
|
context.linkProgram(this.program); |
|
context.getProgramParameter(this.program, context.LINK_STATUS) || console.error(context.getProgramInfoLog(this.program)); |
|
context.useProgram(this.program); |
|
|
|
this.attachUniforms(void 0, this.gl.commonUniforms); |
|
this.attachUniforms(void 0, this.uniforms); |
|
|
|
} |
|
|
|
_getShaderByType(type, source) { |
|
const context = this.gl.getContext(); |
|
const shader = context.createShader(type); |
|
context.shaderSource(shader, source); |
|
context.compileShader(shader); |
|
|
|
if (!context.getShaderParameter(shader, context.COMPILE_STATUS)) { |
|
console.error(context.getShaderInfoLog(shader)); |
|
} |
|
|
|
return shader; |
|
} |
|
|
|
_getUniformVariableDeclarations(uniforms, type) { |
|
return Object.entries(uniforms).map(([uniform, value]) => { |
|
return value.getDeclaration(uniform, type); |
|
}).join("\n"); |
|
} |
|
|
|
attachUniforms(name, uniforms) { |
|
if (!name) { |
|
Object.entries(uniforms).forEach(([name, uniform]) => { |
|
this.attachUniforms(name, uniform); |
|
}); |
|
} else if (uniforms.type === 'array') { |
|
uniforms.value.forEach((uniform, i) => { |
|
this.attachUniforms(`${name}[${i}]`, uniform); |
|
}); |
|
} else if (uniforms.type === 'struct') { |
|
Object.entries(uniforms.value).forEach(([uniform, i]) => { |
|
this.attachUniforms(`${name}.${uniform}`, i); |
|
}); |
|
} else { |
|
this.uniformInstances.push({ |
|
uniform: uniforms, |
|
location: this.gl.getContext().getUniformLocation(this.program, name) |
|
}); |
|
} |
|
} |
|
|
|
} |
|
|