1
- import { shaderArgs , UniformValue , ShaderHook } from "../types" ;
2
- import { domHandler , MethodName } from "./base" ;
1
+ import { Shader } from './shader'
2
+ import { domHandler , MethodName } from './domHandler'
3
3
4
4
5
- /** Shader Class
6
- * @export
7
- * @class Shader
8
- * @extends {domHandler }
9
- *
10
- */
11
- export class Shader extends domHandler {
12
- private hooks : Record < string , ShaderHook [ ] > = { } ;
13
- private gl : WebGLRenderingContext ;
14
- private shaderProgram : WebGLProgram ;
15
- private vertexBuffer : WebGLBuffer ;
16
- private uniforms : Array < UniformValue > | undefined
17
-
18
- constructor ( container : HTMLCanvasElement , args : shaderArgs ) {
19
- super ( container ) ;
20
- this . gl = container . getContext ( 'webgl' ) as WebGLRenderingContext ;
21
- this . shaderProgram = this . initializeShader ( args . vertShader , args . fragShader ) ;
22
- this . vertexBuffer = this . initBuffers ( ) ;
23
- this . uniforms = args . uniforms
24
- // Initialize custom logic if provided
25
- args . hooks ?. forEach ( ( hook ) => {
26
- this . addHook ( hook . methodName , hook . hook )
27
- } )
28
- }
29
-
30
- public init ( ) {
31
- super . init ( ) ;
32
- this . runHooks ( MethodName . INIT ) ;
33
-
34
- this . resize ( )
35
- this . startLoop ( 60 ) ;
36
-
37
- this . uniforms ?. forEach ( ( uniform ) => {
38
- this . setUniform ( uniform )
39
- } )
40
- }
41
-
42
- public addHook ( methodName : MethodName , hook : ShaderHook ) : void {
43
- if ( ! this . hooks [ methodName ] ) this . hooks [ methodName ] = [ ] ;
44
- this . hooks [ methodName ] . push ( hook ) ;
45
- }
46
-
47
- protected runHooks ( method : MethodName , ...args : any [ ] ) {
48
- if ( this . hooks [ method ] ) {
49
- this . hooks [ method ] . forEach ( ( hook ) => hook ( this , ...args ) ) ;
50
- }
51
- }
52
-
53
- private initBuffers ( ) : WebGLBuffer {
54
- const vertices = new Float32Array ( [
55
- - 1.0 , 1.0 , // Top-left
56
- - 1.0 , - 1.0 , // Bottom-left
57
- 1.0 , - 1.0 , // Bottom-right
58
-
59
- - 1.0 , 1.0 , // Top-left
60
- 1.0 , - 1.0 , // Bottom-right
61
- 1.0 , 1.0 // Top-right
62
- ] ) ;
63
-
64
- const vertexBuffer = this . gl . createBuffer ( ) ;
65
- if ( ! vertexBuffer ) throw new Error ( 'Failed to create vertex buffer' ) ;
66
-
67
- this . gl . bindBuffer ( this . gl . ARRAY_BUFFER , vertexBuffer ) ;
68
- this . gl . bufferData ( this . gl . ARRAY_BUFFER , vertices , this . gl . STATIC_DRAW ) ;
69
-
70
- return vertexBuffer ;
71
- }
72
-
73
- private loadShader ( gl : WebGLRenderingContext , type : GLenum , source : string = '' ) : WebGLShader | null {
74
- const shader = gl . createShader ( type ) ;
75
- if ( ! shader ) return null ;
76
-
77
- gl . shaderSource ( shader , source ) ;
78
- gl . compileShader ( shader ) ;
79
-
80
- if ( ! gl . getShaderParameter ( shader , gl . COMPILE_STATUS ) ) {
81
- console . error ( 'Shader compilation error:' , gl . getShaderInfoLog ( shader ) ) ;
82
- gl . deleteShader ( shader ) ;
83
- return null ;
84
- }
85
-
86
- return shader ;
87
- }
88
-
89
- private initializeShader ( vertShader ?: string , fragShader ?: string ) : WebGLProgram {
90
- const vertexShader = this . loadShader ( this . gl , this . gl . VERTEX_SHADER , vertShader ) ;
91
- const fragmentShader = this . loadShader ( this . gl , this . gl . FRAGMENT_SHADER , fragShader ) ;
92
- if ( ! vertexShader || ! fragmentShader ) throw new Error ( 'Shader compilation failed' ) ;
93
-
94
- const shaderProgram = this . gl . createProgram ( ) ;
95
- if ( ! shaderProgram ) throw new Error ( 'Failed to create shader program' ) ;
96
-
97
- this . gl . attachShader ( shaderProgram , vertexShader ) ;
98
- this . gl . attachShader ( shaderProgram , fragmentShader ) ;
99
- this . gl . linkProgram ( shaderProgram ) ;
100
-
101
- if ( ! this . gl . getProgramParameter ( shaderProgram , this . gl . LINK_STATUS ) ) {
102
- console . error ( 'Shader program link error:' , this . gl . getProgramInfoLog ( shaderProgram ) ) ;
103
- throw new Error ( 'Unable to initialize the shader program' ) ;
104
- }
105
- return shaderProgram ;
106
- }
107
-
108
- // Main render loop
109
- protected loop ( ) : void {
110
- super . loop ( ) ;
111
- this . runHooks ( MethodName . LOOP ) ;
112
- this . render ( ) ;
113
- }
114
-
115
- protected render ( ) : void {
116
- const gl = this . gl ;
117
- this . runHooks ( MethodName . RENDER ) ;
118
-
119
- gl . clear ( gl . COLOR_BUFFER_BIT ) ;
120
- gl . clear ( gl . DEPTH_BUFFER_BIT ) ;
121
- gl . clear ( gl . STENCIL_BUFFER_BIT ) ;
122
-
123
- const vertexPosition = gl . getAttribLocation ( this . shaderProgram , 'a_position' ) ;
124
- gl . bindBuffer ( gl . ARRAY_BUFFER , this . vertexBuffer ) ;
125
- gl . vertexAttribPointer ( vertexPosition , 2 , gl . FLOAT , false , 0 , 0 ) ;
126
- gl . enableVertexAttribArray ( vertexPosition ) ;
127
-
128
- gl . useProgram ( this . shaderProgram ) ;
129
- gl . drawArrays ( gl . TRIANGLES , 0 , 6 ) ;
130
- }
131
-
132
- /** Gets a uniform value from the shader */
133
- public getUniform ( name : string ) : UniformValue | undefined {
134
- const uLoc = this . gl . getUniformLocation ( this . shaderProgram , name ) ;
135
- if ( ! uLoc ) {
136
- console . error ( `Uniform ${ name } not found.` ) ;
137
- return ;
138
- }
139
-
140
- return this . gl . getUniform ( this . shaderProgram , uLoc )
141
- }
142
-
143
- /** Sets a uniform value for the shader */
144
- public setUniform ( uniform : UniformValue ) : void {
145
- const { name, type, value } = uniform
146
- const uLoc = this . gl . getUniformLocation ( this . shaderProgram , name ) ;
147
-
148
- if ( ! uLoc ) {
149
- console . error ( `Uniform ${ name } not found.` ) ;
150
- return ;
151
- }
152
-
153
- switch ( type ) {
154
- case "float" :
155
- this . gl . uniform1f ( uLoc , value as number ) ;
156
- break ;
157
- case "vec2" :
158
- this . gl . uniform2fv ( uLoc , value as Float32Array ) ;
159
- break ;
160
- case "vec3" :
161
- this . gl . uniform3fv ( uLoc , value as Float32Array ) ;
162
- break ;
163
- case "vec4" :
164
- this . gl . uniform4fv ( uLoc , value as Float32Array ) ;
165
- break ;
166
- case "int" :
167
- this . gl . uniform1i ( uLoc , value as number ) ;
168
- break ;
169
- case "ivec2" :
170
- this . gl . uniform2iv ( uLoc , value as Int32Array ) ;
171
- break ;
172
- case "ivec3" :
173
- this . gl . uniform3iv ( uLoc , value as Int32Array ) ;
174
- break ;
175
- case "ivec4" :
176
- this . gl . uniform4iv ( uLoc , value as Int32Array ) ;
177
- break ;
178
- case "mat2" :
179
- this . gl . uniformMatrix2fv ( uLoc , false , value as Float32Array ) ;
180
- break ;
181
- case "mat3" :
182
- this . gl . uniformMatrix3fv ( uLoc , false , value as Float32Array ) ;
183
- break ;
184
- case "mat4" :
185
- this . gl . uniformMatrix4fv ( uLoc , false , value as Float32Array ) ;
186
- break ;
187
- default :
188
- console . error ( `Unsupported uniform type: ${ type } ` ) ;
189
- }
190
- }
191
-
192
- // Resize handler
193
- protected resize ( e ?: Event ) : void {
194
- super . resize ( e ) ;
195
- const { width, height } = this . container . getBoundingClientRect ( ) ;
196
- this . container . width = width ;
197
- this . container . height = height ;
198
- this . gl . viewport ( 0 , 0 , width , height ) ;
199
- this . runHooks ( MethodName . RESIZE ) ;
200
-
201
- this . render ( ) ; // Render immediately on resize to avoid jitter waiting for render call
202
- }
203
-
204
- // Handles input events
205
- protected handleInput ( e : Event ) : void {
206
- super . handleInput ( e ) ;
207
- this . runHooks ( MethodName . INPUT ) ;
208
-
209
- }
210
-
211
- // Handles touch start events
212
- protected touchStart ( e : Event ) : void {
213
- super . touchStart ( e ) ;
214
- this . runHooks ( MethodName . TOUCH ) ;
215
-
216
-
217
- }
218
- }
5
+ export { Shader , domHandler , MethodName }
0 commit comments