gl_js.go raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 package gl
4
5 import (
6 "errors"
7 "strings"
8 "syscall/js"
9 )
10
11 type Functions struct {
12 Ctx js.Value
13 EXT_disjoint_timer_query js.Value
14 EXT_disjoint_timer_query_webgl2 js.Value
15
16 // Cached reference to the Uint8Array JS type.
17 uint8Array js.Value
18
19 // Cached JS arrays.
20 arrayBuf js.Value
21 int32Buf js.Value
22 }
23
24 type Context js.Value
25
26 func NewFunctions(ctx Context) (*Functions, error) {
27 f := &Functions{
28 Ctx: js.Value(ctx),
29 uint8Array: js.Global().Get("Uint8Array"),
30 }
31 if err := f.Init(); err != nil {
32 return nil, err
33 }
34 return f, nil
35 }
36
37 func (f *Functions) Init() error {
38 webgl2Class := js.Global().Get("WebGL2RenderingContext")
39 iswebgl2 := !webgl2Class.IsUndefined() && f.Ctx.InstanceOf(webgl2Class)
40 if !iswebgl2 {
41 f.EXT_disjoint_timer_query = f.getExtension("EXT_disjoint_timer_query")
42 if f.getExtension("OES_texture_half_float").IsNull() && f.getExtension("OES_texture_float").IsNull() {
43 return errors.New("gl: no support for neither OES_texture_half_float nor OES_texture_float")
44 }
45 if f.getExtension("EXT_sRGB").IsNull() {
46 return errors.New("gl: EXT_sRGB not supported")
47 }
48 } else {
49 // WebGL2 extensions.
50 f.EXT_disjoint_timer_query_webgl2 = f.getExtension("EXT_disjoint_timer_query_webgl2")
51 if f.getExtension("EXT_color_buffer_half_float").IsNull() && f.getExtension("EXT_color_buffer_float").IsNull() {
52 return errors.New("gl: no support for neither EXT_color_buffer_half_float nor EXT_color_buffer_float")
53 }
54 }
55 return nil
56 }
57
58 func (f *Functions) getExtension(name string) js.Value {
59 return f.Ctx.Call("getExtension", name)
60 }
61
62 func (f *Functions) ActiveTexture(t Enum) {
63 f.Ctx.Call("activeTexture", int(t))
64 }
65 func (f *Functions) AttachShader(p Program, s Shader) {
66 f.Ctx.Call("attachShader", js.Value(p), js.Value(s))
67 }
68 func (f *Functions) BeginQuery(target Enum, query Query) {
69 if !f.EXT_disjoint_timer_query_webgl2.IsNull() {
70 f.Ctx.Call("beginQuery", int(target), js.Value(query))
71 } else {
72 f.EXT_disjoint_timer_query.Call("beginQueryEXT", int(target), js.Value(query))
73 }
74 }
75 func (f *Functions) BindAttribLocation(p Program, a Attrib, name string) {
76 f.Ctx.Call("bindAttribLocation", js.Value(p), int(a), name)
77 }
78 func (f *Functions) BindBuffer(target Enum, b Buffer) {
79 f.Ctx.Call("bindBuffer", int(target), js.Value(b))
80 }
81 func (f *Functions) BindBufferBase(target Enum, index int, b Buffer) {
82 f.Ctx.Call("bindBufferBase", int(target), index, js.Value(b))
83 }
84 func (f *Functions) BindFramebuffer(target Enum, fb Framebuffer) {
85 f.Ctx.Call("bindFramebuffer", int(target), js.Value(fb))
86 }
87 func (f *Functions) BindRenderbuffer(target Enum, rb Renderbuffer) {
88 f.Ctx.Call("bindRenderbuffer", int(target), js.Value(rb))
89 }
90 func (f *Functions) BindTexture(target Enum, t Texture) {
91 f.Ctx.Call("bindTexture", int(target), js.Value(t))
92 }
93 func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) {
94 panic("not implemented")
95 }
96 func (f *Functions) BlendEquation(mode Enum) {
97 f.Ctx.Call("blendEquation", int(mode))
98 }
99 func (f *Functions) BlendFunc(sfactor, dfactor Enum) {
100 f.Ctx.Call("blendFunc", int(sfactor), int(dfactor))
101 }
102 func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) {
103 panic("not implemented")
104 }
105 func (f *Functions) BufferData(target Enum, size int, usage Enum) {
106 f.Ctx.Call("bufferData", int(target), size, int(usage))
107 }
108 func (f *Functions) BufferSubData(target Enum, offset int, src []byte) {
109 f.Ctx.Call("bufferSubData", int(target), offset, f.byteArrayOf(src))
110 }
111 func (f *Functions) CheckFramebufferStatus(target Enum) Enum {
112 return Enum(f.Ctx.Call("checkFramebufferStatus", int(target)).Int())
113 }
114 func (f *Functions) Clear(mask Enum) {
115 f.Ctx.Call("clear", int(mask))
116 }
117 func (f *Functions) ClearColor(red, green, blue, alpha float32) {
118 f.Ctx.Call("clearColor", red, green, blue, alpha)
119 }
120 func (f *Functions) ClearDepthf(d float32) {
121 f.Ctx.Call("clearDepth", d)
122 }
123 func (f *Functions) CompileShader(s Shader) {
124 f.Ctx.Call("compileShader", js.Value(s))
125 }
126 func (f *Functions) CreateBuffer() Buffer {
127 return Buffer(f.Ctx.Call("createBuffer"))
128 }
129 func (f *Functions) CreateFramebuffer() Framebuffer {
130 return Framebuffer(f.Ctx.Call("createFramebuffer"))
131 }
132 func (f *Functions) CreateProgram() Program {
133 return Program(f.Ctx.Call("createProgram"))
134 }
135 func (f *Functions) CreateQuery() Query {
136 return Query(f.Ctx.Call("createQuery"))
137 }
138 func (f *Functions) CreateRenderbuffer() Renderbuffer {
139 return Renderbuffer(f.Ctx.Call("createRenderbuffer"))
140 }
141 func (f *Functions) CreateShader(ty Enum) Shader {
142 return Shader(f.Ctx.Call("createShader", int(ty)))
143 }
144 func (f *Functions) CreateTexture() Texture {
145 return Texture(f.Ctx.Call("createTexture"))
146 }
147 func (f *Functions) DeleteBuffer(v Buffer) {
148 f.Ctx.Call("deleteBuffer", js.Value(v))
149 }
150 func (f *Functions) DeleteFramebuffer(v Framebuffer) {
151 f.Ctx.Call("deleteFramebuffer", js.Value(v))
152 }
153 func (f *Functions) DeleteProgram(p Program) {
154 f.Ctx.Call("deleteProgram", js.Value(p))
155 }
156 func (f *Functions) DeleteQuery(query Query) {
157 if !f.EXT_disjoint_timer_query_webgl2.IsNull() {
158 f.Ctx.Call("deleteQuery", js.Value(query))
159 } else {
160 f.EXT_disjoint_timer_query.Call("deleteQueryEXT", js.Value(query))
161 }
162 }
163 func (f *Functions) DeleteShader(s Shader) {
164 f.Ctx.Call("deleteShader", js.Value(s))
165 }
166 func (f *Functions) DeleteRenderbuffer(v Renderbuffer) {
167 f.Ctx.Call("deleteRenderbuffer", js.Value(v))
168 }
169 func (f *Functions) DeleteTexture(v Texture) {
170 f.Ctx.Call("deleteTexture", js.Value(v))
171 }
172 func (f *Functions) DepthFunc(fn Enum) {
173 f.Ctx.Call("depthFunc", int(fn))
174 }
175 func (f *Functions) DepthMask(mask bool) {
176 f.Ctx.Call("depthMask", mask)
177 }
178 func (f *Functions) DisableVertexAttribArray(a Attrib) {
179 f.Ctx.Call("disableVertexAttribArray", int(a))
180 }
181 func (f *Functions) Disable(cap Enum) {
182 f.Ctx.Call("disable", int(cap))
183 }
184 func (f *Functions) DrawArrays(mode Enum, first, count int) {
185 f.Ctx.Call("drawArrays", int(mode), first, count)
186 }
187 func (f *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) {
188 f.Ctx.Call("drawElements", int(mode), count, int(ty), offset)
189 }
190 func (f *Functions) DispatchCompute(x, y, z int) {
191 panic("not implemented")
192 }
193 func (f *Functions) Enable(cap Enum) {
194 f.Ctx.Call("enable", int(cap))
195 }
196 func (f *Functions) EnableVertexAttribArray(a Attrib) {
197 f.Ctx.Call("enableVertexAttribArray", int(a))
198 }
199 func (f *Functions) EndQuery(target Enum) {
200 if !f.EXT_disjoint_timer_query_webgl2.IsNull() {
201 f.Ctx.Call("endQuery", int(target))
202 } else {
203 f.EXT_disjoint_timer_query.Call("endQueryEXT", int(target))
204 }
205 }
206 func (f *Functions) Finish() {
207 f.Ctx.Call("finish")
208 }
209 func (f *Functions) FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer Renderbuffer) {
210 f.Ctx.Call("framebufferRenderbuffer", int(target), int(attachment), int(renderbuffertarget), js.Value(renderbuffer))
211 }
212 func (f *Functions) FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int) {
213 f.Ctx.Call("framebufferTexture2D", int(target), int(attachment), int(texTarget), js.Value(t), level)
214 }
215 func (f *Functions) GetError() Enum {
216 // Avoid slow getError calls. See gio#179.
217 return 0
218 }
219 func (f *Functions) GetRenderbufferParameteri(target, pname Enum) int {
220 return paramVal(f.Ctx.Call("getRenderbufferParameteri", int(pname)))
221 }
222 func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname Enum) int {
223 return paramVal(f.Ctx.Call("getFramebufferAttachmentParameter", int(target), int(attachment), int(pname)))
224 }
225 func (f *Functions) GetBinding(pname Enum) Object {
226 return Object(f.Ctx.Call("getParameter", int(pname)))
227 }
228 func (f *Functions) GetInteger(pname Enum) int {
229 return paramVal(f.Ctx.Call("getParameter", int(pname)))
230 }
231 func (f *Functions) GetProgrami(p Program, pname Enum) int {
232 return paramVal(f.Ctx.Call("getProgramParameter", js.Value(p), int(pname)))
233 }
234 func (f *Functions) GetProgramInfoLog(p Program) string {
235 return f.Ctx.Call("getProgramInfoLog", js.Value(p)).String()
236 }
237 func (f *Functions) GetQueryObjectuiv(query Query, pname Enum) uint {
238 if !f.EXT_disjoint_timer_query_webgl2.IsNull() {
239 return uint(paramVal(f.Ctx.Call("getQueryParameter", js.Value(query), int(pname))))
240 } else {
241 return uint(paramVal(f.EXT_disjoint_timer_query.Call("getQueryObjectEXT", js.Value(query), int(pname))))
242 }
243 }
244 func (f *Functions) GetShaderi(s Shader, pname Enum) int {
245 return paramVal(f.Ctx.Call("getShaderParameter", js.Value(s), int(pname)))
246 }
247 func (f *Functions) GetShaderInfoLog(s Shader) string {
248 return f.Ctx.Call("getShaderInfoLog", js.Value(s)).String()
249 }
250 func (f *Functions) GetString(pname Enum) string {
251 switch pname {
252 case EXTENSIONS:
253 extsjs := f.Ctx.Call("getSupportedExtensions")
254 var exts []string
255 for i := 0; i < extsjs.Length(); i++ {
256 exts = append(exts, "GL_"+extsjs.Index(i).String())
257 }
258 return strings.Join(exts, " ")
259 default:
260 return f.Ctx.Call("getParameter", int(pname)).String()
261 }
262 }
263 func (f *Functions) GetUniformBlockIndex(p Program, name string) uint {
264 return uint(paramVal(f.Ctx.Call("getUniformBlockIndex", js.Value(p), name)))
265 }
266 func (f *Functions) GetUniformLocation(p Program, name string) Uniform {
267 return Uniform(f.Ctx.Call("getUniformLocation", js.Value(p), name))
268 }
269 func (f *Functions) InvalidateFramebuffer(target, attachment Enum) {
270 fn := f.Ctx.Get("invalidateFramebuffer")
271 if !fn.IsUndefined() {
272 if f.int32Buf.IsUndefined() {
273 f.int32Buf = js.Global().Get("Int32Array").New(1)
274 }
275 f.int32Buf.SetIndex(0, int32(attachment))
276 f.Ctx.Call("invalidateFramebuffer", int(target), f.int32Buf)
277 }
278 }
279 func (f *Functions) LinkProgram(p Program) {
280 f.Ctx.Call("linkProgram", js.Value(p))
281 }
282 func (f *Functions) PixelStorei(pname Enum, param int32) {
283 f.Ctx.Call("pixelStorei", int(pname), param)
284 }
285 func (f *Functions) MemoryBarrier(barriers Enum) {
286 panic("not implemented")
287 }
288 func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte {
289 panic("not implemented")
290 }
291 func (f *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) {
292 f.Ctx.Call("renderbufferStorage", int(target), int(internalformat), width, height)
293 }
294 func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) {
295 ba := f.byteArrayOf(data)
296 f.Ctx.Call("readPixels", x, y, width, height, int(format), int(ty), ba)
297 js.CopyBytesToGo(data, ba)
298 }
299 func (f *Functions) Scissor(x, y, width, height int32) {
300 f.Ctx.Call("scissor", x, y, width, height)
301 }
302 func (f *Functions) ShaderSource(s Shader, src string) {
303 f.Ctx.Call("shaderSource", js.Value(s), src)
304 }
305 func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width, height int, format, ty Enum) {
306 f.Ctx.Call("texImage2D", int(target), int(level), int(internalFormat), int(width), int(height), 0, int(format), int(ty), nil)
307 }
308 func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) {
309 f.Ctx.Call("texStorage2D", int(target), levels, int(internalFormat), width, height)
310 }
311 func (f *Functions) TexSubImage2D(target Enum, level int, x, y, width, height int, format, ty Enum, data []byte) {
312 f.Ctx.Call("texSubImage2D", int(target), level, x, y, width, height, int(format), int(ty), f.byteArrayOf(data))
313 }
314 func (f *Functions) TexParameteri(target, pname Enum, param int) {
315 f.Ctx.Call("texParameteri", int(target), int(pname), int(param))
316 }
317 func (f *Functions) UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint) {
318 f.Ctx.Call("uniformBlockBinding", js.Value(p), int(uniformBlockIndex), int(uniformBlockBinding))
319 }
320 func (f *Functions) Uniform1f(dst Uniform, v float32) {
321 f.Ctx.Call("uniform1f", js.Value(dst), v)
322 }
323 func (f *Functions) Uniform1i(dst Uniform, v int) {
324 f.Ctx.Call("uniform1i", js.Value(dst), v)
325 }
326 func (f *Functions) Uniform2f(dst Uniform, v0, v1 float32) {
327 f.Ctx.Call("uniform2f", js.Value(dst), v0, v1)
328 }
329 func (f *Functions) Uniform3f(dst Uniform, v0, v1, v2 float32) {
330 f.Ctx.Call("uniform3f", js.Value(dst), v0, v1, v2)
331 }
332 func (f *Functions) Uniform4f(dst Uniform, v0, v1, v2, v3 float32) {
333 f.Ctx.Call("uniform4f", js.Value(dst), v0, v1, v2, v3)
334 }
335 func (f *Functions) UseProgram(p Program) {
336 f.Ctx.Call("useProgram", js.Value(p))
337 }
338 func (f *Functions) UnmapBuffer(target Enum) bool {
339 panic("not implemented")
340 }
341 func (f *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int) {
342 f.Ctx.Call("vertexAttribPointer", int(dst), size, int(ty), normalized, stride, offset)
343 }
344 func (f *Functions) Viewport(x, y, width, height int) {
345 f.Ctx.Call("viewport", x, y, width, height)
346 }
347
348 func (f *Functions) byteArrayOf(data []byte) js.Value {
349 if len(data) == 0 {
350 return js.Null()
351 }
352 f.resizeByteBuffer(len(data))
353 ba := f.uint8Array.New(f.arrayBuf, int(0), int(len(data)))
354 js.CopyBytesToJS(ba, data)
355 return ba
356 }
357
358 func (f *Functions) resizeByteBuffer(n int) {
359 if n == 0 {
360 return
361 }
362 if !f.arrayBuf.IsUndefined() && f.arrayBuf.Length() >= n {
363 return
364 }
365 f.arrayBuf = js.Global().Get("ArrayBuffer").New(n)
366 }
367
368 func paramVal(v js.Value) int {
369 switch v.Type() {
370 case js.TypeBoolean:
371 if b := v.Bool(); b {
372 return 1
373 } else {
374 return 0
375 }
376 case js.TypeNumber:
377 return v.Int()
378 default:
379 panic("unknown parameter type")
380 }
381 }
382