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 }; | |