Spaces:
Running
Running
import { Camera } from "../../../cameras/Camera"; | |
import { Scene } from "../../../core/Scene"; | |
import { WebGLRenderer } from "../../WebGLRenderer"; | |
import { ShaderPass } from "../passes/ShaderPass"; | |
abstract class ShaderProgram { | |
private _renderer: WebGLRenderer; | |
private _program: WebGLProgram; | |
private _passes: ShaderPass[]; | |
protected _scene: Scene | null = null; | |
protected _camera: Camera | null = null; | |
protected _started: boolean = false; | |
protected _initialized: boolean = false; | |
protected abstract _initialize: () => void; | |
protected abstract _resize: () => void; | |
protected abstract _render: () => void; | |
protected abstract _dispose: () => void; | |
initialize: () => void; | |
resize: () => void; | |
render: (scene: Scene, camera: Camera) => void; | |
dispose: () => void; | |
constructor(renderer: WebGLRenderer, passes: ShaderPass[]) { | |
this._renderer = renderer; | |
const gl = renderer.gl; | |
this._program = gl.createProgram() as WebGLProgram; | |
this._passes = passes || []; | |
const vertexShader = gl.createShader(gl.VERTEX_SHADER) as WebGLShader; | |
gl.shaderSource(vertexShader, this._getVertexSource()); | |
gl.compileShader(vertexShader); | |
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { | |
console.error(gl.getShaderInfoLog(vertexShader)); | |
} | |
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) as WebGLShader; | |
gl.shaderSource(fragmentShader, this._getFragmentSource()); | |
gl.compileShader(fragmentShader); | |
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { | |
console.error(gl.getShaderInfoLog(fragmentShader)); | |
} | |
gl.attachShader(this.program, vertexShader); | |
gl.attachShader(this.program, fragmentShader); | |
gl.linkProgram(this.program); | |
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { | |
console.error(gl.getProgramInfoLog(this.program)); | |
} | |
this.resize = () => { | |
gl.useProgram(this._program); | |
this._resize(); | |
}; | |
this.initialize = () => { | |
console.assert(!this._initialized, "ShaderProgram already initialized"); | |
gl.useProgram(this._program); | |
this._initialize(); | |
for (const pass of this.passes) { | |
pass.initialize(this); | |
} | |
this._initialized = true; | |
this._started = true; | |
}; | |
this.render = (scene: Scene, camera: Camera) => { | |
gl.useProgram(this._program); | |
if (this._scene !== scene || this._camera !== camera) { | |
this.dispose(); | |
this._scene = scene; | |
this._camera = camera; | |
this.initialize(); | |
} | |
for (const pass of this.passes) { | |
pass.render(); | |
} | |
this._render(); | |
}; | |
this.dispose = () => { | |
if (!this._initialized) return; | |
gl.useProgram(this._program); | |
for (const pass of this.passes) { | |
pass.dispose(); | |
} | |
this._dispose(); | |
this._scene = null; | |
this._camera = null; | |
this._initialized = false; | |
}; | |
} | |
get renderer() { | |
return this._renderer; | |
} | |
get scene() { | |
return this._scene; | |
} | |
get camera() { | |
return this._camera; | |
} | |
get program() { | |
return this._program; | |
} | |
get passes() { | |
return this._passes; | |
} | |
get started() { | |
return this._started; | |
} | |
protected abstract _getVertexSource(): string; | |
protected abstract _getFragmentSource(): string; | |
} | |
export { ShaderProgram }; | |