Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2019
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / JavaScript WebGL bindings
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : /*
28 : ANY CHANGE TO THE API MUST BE REFLECTED IN THE DOCUMENTATION IN gpac/share/doc/idl/webgl.idl
29 : (no way to define inline JS doc with doxygen)
30 : */
31 :
32 : #include <gpac/setup.h>
33 : #ifdef GPAC_HAS_QJS
34 :
35 : #if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
36 :
37 : #include "webgl.h"
38 :
39 : JSClassID WebGLRenderingContextBase_class_id;
40 :
41 3 : static void webgl_finalize(JSRuntime *rt, JSValue obj)
42 : {
43 : u32 i, count;
44 3 : GF_WebGLContext *glctx = JS_GetOpaque(obj, WebGLRenderingContextBase_class_id);
45 3 : if (!glctx) return;
46 : JS_FreeValueRT(rt, glctx->canvas);
47 : JS_FreeValueRT(rt, glctx->tex_frame_flush);
48 : JS_FreeValueRT(rt, glctx->depth_frame_flush);
49 :
50 3 : count = gf_list_count(glctx->all_objects);
51 32 : for (i=0; i<count; i++) {
52 29 : GF_WebGLObject *glo = gf_list_get(glctx->all_objects, i);
53 29 : glo->par_ctx = NULL;
54 58 : if (!JS_IsUndefined(glo->obj))
55 : JS_FreeValueRT(rt, glo->obj);
56 : }
57 3 : gf_list_del(glctx->all_objects);
58 3 : count = gf_list_count(glctx->named_textures);
59 3 : for (i=0; i<count; i++) {
60 0 : GF_WebGLNamedTexture *named_tx = gf_list_get(glctx->named_textures, i);
61 0 : named_tx->par_ctx = NULL;
62 : }
63 3 : gf_list_del(glctx->named_textures);
64 :
65 3 : glDeleteTextures(1, &glctx->tex_id);
66 3 : glDeleteRenderbuffers(1, &glctx->depth_id);
67 3 : glDeleteFramebuffers(1, &glctx->fbo_id);
68 3 : gf_free(glctx);
69 : }
70 2 : static void webgl_gc_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
71 : {
72 : u32 i, count;
73 2 : GF_WebGLContext *glctx = JS_GetOpaque(val, WebGLRenderingContextBase_class_id);
74 2 : if (!glctx) return;
75 4 : if (!JS_IsUndefined(glctx->tex_frame_flush))
76 0 : JS_MarkValue(rt, glctx->depth_frame_flush, mark_func);
77 4 : if (!JS_IsUndefined(glctx->depth_frame_flush))
78 0 : JS_MarkValue(rt, glctx->tex_frame_flush, mark_func);
79 4 : if (!JS_IsUndefined(glctx->canvas))
80 2 : JS_MarkValue(rt, glctx->canvas, mark_func);
81 2 : count = gf_list_count(glctx->all_objects);
82 8 : for (i=0; i<count; i++) {
83 6 : GF_WebGLObject *glo = gf_list_get(glctx->all_objects, i);
84 12 : if (!JS_IsUndefined(glo->obj))
85 6 : JS_MarkValue(rt, glo->obj, mark_func);
86 : }
87 : }
88 : JSClassDef WebGLRenderingContextBase_class =
89 : {
90 : .class_name = "WebGLContext",
91 : .finalizer = webgl_finalize,
92 : .gc_mark = webgl_gc_mark,
93 : };
94 :
95 : JSClassID WebGLProgram_class_id;
96 : JSClassID WebGLShader_class_id;
97 : JSClassID WebGLBuffer_class_id;
98 : JSClassID WebGLFramebuffer_class_id;
99 : JSClassID WebGLRenderbuffer_class_id;
100 : JSClassID WebGLTexture_class_id;
101 : JSClassID WebGLUniformLocation_class_id;
102 : JSClassID NamedTexture_class_id;
103 :
104 : #define DEF_WGLOBJ_CLASS1(_name, _destr) \
105 : static void _name##_finalize(JSRuntime *rt, JSValue obj)\
106 : {\
107 : GF_WebGLObject *glo = JS_GetOpaque(obj, _name##_class_id);\
108 : if (!glo) return;\
109 : if (glo->gl_id) _destr(glo->gl_id);\
110 : if (glo->par_ctx) gf_list_del_item(glo->par_ctx->all_objects, glo);\
111 : gf_free(glo);\
112 : }\
113 : JSClassDef _name##_class =\
114 : {\
115 : .class_name = "#_name",\
116 : .finalizer = _name##_finalize,\
117 : };
118 :
119 : #define DEF_WGLOBJ_CLASS2(_name, _destr) \
120 : static void _name##_finalize(JSRuntime *rt, JSValue obj)\
121 : {\
122 : GF_WebGLObject *glo = JS_GetOpaque(obj, _name##_class_id);\
123 : if (!glo) return;\
124 : if (glo->gl_id) _destr(1, &glo->gl_id);\
125 : gf_free(glo);\
126 : }\
127 : JSClassDef _name##_class =\
128 : {\
129 : .class_name = "#_name",\
130 : .finalizer = _name##_finalize,\
131 : };
132 :
133 : #define DEF_WGLOBJ_CLASS3(_name) \
134 : static void _name##_finalize(JSRuntime *rt, JSValue obj)\
135 : {\
136 : GF_WebGLObject *glo = JS_GetOpaque(obj, _name##_class_id);\
137 : if (!glo) return;\
138 : gf_free(glo);\
139 : }\
140 : JSClassDef _name##_class =\
141 : {\
142 : .class_name = "#_name",\
143 : .finalizer = _name##_finalize,\
144 : };
145 :
146 :
147 3 : DEF_WGLOBJ_CLASS1(WebGLProgram, glDeleteProgram)
148 6 : DEF_WGLOBJ_CLASS1(WebGLShader, glDeleteShader)
149 9 : DEF_WGLOBJ_CLASS2(WebGLBuffer, glDeleteBuffers)
150 1 : DEF_WGLOBJ_CLASS2(WebGLFramebuffer, glDeleteFramebuffers)
151 1 : DEF_WGLOBJ_CLASS2(WebGLRenderbuffer, glDeleteRenderbuffers)
152 1 : DEF_WGLOBJ_CLASS2(WebGLTexture, glDeleteTextures)
153 10 : DEF_WGLOBJ_CLASS3(WebGLUniformLocation)
154 :
155 :
156 : #undef DEF_WGLOBJ_CLASS1
157 : #undef DEF_WGLOBJ_CLASS2
158 : #undef DEF_WGLOBJ_CLASS3
159 :
160 4 : static void NamedTexture_finalize(JSRuntime *rt, JSValue obj)
161 : {
162 4 : GF_WebGLNamedTexture *named_tx = JS_GetOpaque(obj, NamedTexture_class_id);
163 4 : if (!named_tx) return;
164 4 : if (named_tx->par_ctx)
165 4 : gf_list_del_item(named_tx->par_ctx->named_textures, named_tx);
166 :
167 4 : if (named_tx->tx.nb_textures) glDeleteTextures(named_tx->tx.nb_textures, named_tx->tx.textures);
168 4 : if (named_tx->tx_name) gf_free(named_tx->tx_name);
169 4 : gf_free(named_tx);
170 : }
171 : JSClassDef NamedTexture_class =
172 : {
173 : .class_name = "NamedTexture",
174 : .finalizer = NamedTexture_finalize
175 : };
176 :
177 :
178 :
179 101 : Bool WGL_LOAD_INT32_VEC(JSContext *ctx, JSValue val, s32 **values, u32 *v_size, u32 dim)
180 : {
181 : JSValue v;
182 : int res;
183 : u32 i, len;
184 101 : if (!JS_IsArray(ctx, val)) return GF_FALSE;
185 101 : v = JS_GetPropertyStr(ctx, val, "length");
186 101 : res = JS_ToInt32(ctx, &len, v);
187 : JS_FreeValue(ctx, v);
188 101 : if (res) return GF_FALSE;
189 :
190 101 : if (! *values) {
191 101 : *values = gf_malloc(sizeof(s32) * len);
192 101 : *v_size = len;
193 : } else {
194 0 : if (len>dim) len=dim;
195 : }
196 101 : for (i=0; i<len; i++) {
197 101 : v = JS_GetPropertyUint32(ctx, val, i);
198 101 : res = JS_ToInt32(ctx, & ( (*values)[i]), v);
199 : JS_FreeValue(ctx, v);
200 101 : if (res) return GF_FALSE;
201 : }
202 :
203 : return GF_TRUE;
204 : }
205 :
206 1210 : Bool WGL_LOAD_FLOAT_VEC(JSContext *ctx, JSValue val, Float **values, u32 *v_size, u32 dim, Bool is_matrix)
207 : {
208 : JSValue v;
209 : int res;
210 : u32 i, len;
211 1210 : if (!JS_IsArray(ctx, val)) return GF_FALSE;
212 1210 : v = JS_GetPropertyStr(ctx, val, "length");
213 1210 : res = JS_ToInt32(ctx, &len, v);
214 : JS_FreeValue(ctx, v);
215 1210 : if (res) return GF_FALSE;
216 :
217 1210 : if (! *values) {
218 1210 : *values = gf_malloc(sizeof(Float) * len);
219 1210 : if (is_matrix)
220 1210 : *v_size = len/dim/dim;
221 : else
222 0 : *v_size = len/dim;
223 : } else {
224 0 : if (len>dim) len = dim;
225 : }
226 19360 : for (i=0; i<len; i++) {
227 : Double aval;
228 19360 : v = JS_GetPropertyUint32(ctx, val, i);
229 19360 : res = JS_ToFloat64(ctx, &aval, v);
230 : JS_FreeValue(ctx, v);
231 19360 : if (res) return GF_FALSE;
232 19360 : (*values) [i] = (Float) aval;
233 : }
234 : return GF_TRUE;
235 : }
236 :
237 10 : uint8_t *wgl_GetArrayBuffer(JSContext *ctx, u32 *size, JSValueConst obj)
238 : {
239 : JSValue v;
240 : /*ArrayBuffer*/
241 : size_t psize;
242 10 : uint8_t *res = JS_GetArrayBuffer(ctx, &psize, obj);
243 10 : if (res) {
244 1 : *size = (u32) psize;
245 1 : return res;
246 : }
247 : /*ArrayView*/
248 9 : v = JS_GetPropertyStr(ctx, obj, "buffer");
249 9 : if (JS_IsUndefined(v)) return NULL;
250 9 : res = JS_GetArrayBuffer(ctx, &psize, v);
251 : JS_FreeValue(ctx, v);
252 9 : *size = (u32) psize;
253 9 : return res;
254 : }
255 :
256 1 : static JSValue WebGLRenderingContextBase_getProperty(JSContext *ctx, JSValueConst obj, int magic)
257 : {
258 1 : GF_WebGLContext *glc = JS_GetOpaque(obj, WebGLRenderingContextBase_class_id);
259 1 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
260 :
261 1 : switch (magic) {
262 0 : case WebGLRenderingContextBase_PROP_canvas:
263 : return JS_DupValue(ctx, glc->canvas);
264 1 : case WebGLRenderingContextBase_PROP_drawingBufferWidth:
265 1 : return JS_NewInt32(ctx, glc->width);
266 0 : case WebGLRenderingContextBase_PROP_drawingBufferHeight:
267 0 : return JS_NewInt32(ctx, glc->height);
268 : }
269 0 : return JS_UNDEFINED;
270 : }
271 :
272 202 : static JSValue webgl_getActiveAttribOrUniform(JSContext *ctx, GLuint program, u32 index, Bool is_attr)
273 : {
274 : char szAttName[1001];
275 202 : GLint size, att_len=0;
276 : GLenum type;
277 : JSValue info;
278 202 : if (is_attr) {
279 101 : glGetActiveAttrib(program, index, 1000, &att_len, &size, &type, szAttName);
280 : } else {
281 101 : glGetActiveUniform(program, index, 1000, &att_len, &size, &type, szAttName);
282 : }
283 202 : if (att_len>1000) return js_throw_err(ctx, WGL_INVALID_VALUE);
284 202 : szAttName[att_len] = 0;
285 202 : info = JS_NewObject(ctx);
286 404 : JS_SetPropertyStr(ctx, info, "size", JS_NewInt32(ctx, size));
287 404 : JS_SetPropertyStr(ctx, info, "type", JS_NewInt32(ctx, type));
288 202 : JS_SetPropertyStr(ctx, info, "name", JS_NewString(ctx, szAttName));
289 202 : return info;
290 : }
291 0 : JSValue webgl_getActiveAttrib(JSContext *ctx, GLuint program, u32 index)
292 : {
293 101 : return webgl_getActiveAttribOrUniform(ctx, program, index, GF_TRUE);
294 : }
295 0 : JSValue webgl_getActiveUniform(JSContext *ctx, GLuint program, u32 index)
296 : {
297 101 : return webgl_getActiveAttribOrUniform(ctx, program, index, GF_FALSE);
298 : }
299 1 : JSValue webgl_getAttachedShaders(JSContext *ctx, GF_WebGLContext *glc, GLuint program)
300 : {
301 : JSValue ret;
302 : GLuint shaders[20];
303 1 : u32 i, scount=0;
304 1 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
305 :
306 1 : glGetAttachedShaders(program, 20, &scount, shaders);
307 1 : if (!scount) return JS_NULL;
308 1 : ret = JS_NewArray(ctx);
309 3 : for (i=0; i<scount; i++) {
310 2 : u32 j, count = gf_list_count(glc->all_objects);
311 3 : for (j=0; j<count; j++) {
312 3 : GF_WebGLObject *glo = gf_list_get(glc->all_objects, j);
313 3 : if (glo->class_id != WebGLShader_class_id) continue;
314 3 : if (glo->gl_id == shaders[i]) {
315 2 : JS_SetPropertyUint32(ctx, ret, i, JS_DupValue(ctx, glo->obj) );
316 2 : break;
317 : }
318 : }
319 : }
320 1 : return ret;
321 : }
322 :
323 : /*WebGL 1.0 autogen code*/
324 : #include "WebGLRenderingContextBase.c"
325 :
326 :
327 1 : static JSValue wgl_getContextAttributes(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
328 : {
329 : JSValue ret;
330 1 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
331 1 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
332 :
333 1 : ret = JS_NewObject(ctx);
334 2 : JS_SetPropertyStr(ctx, ret, "alpha", JS_NewBool(ctx, glc->actual_attrs.alpha));
335 1 : if (glc->actual_attrs.depth== WGL_DEPTH_TEXTURE) {
336 0 : JS_SetPropertyStr(ctx, ret, "depth", JS_NewString(ctx, "texture"));
337 : } else {
338 1 : JS_SetPropertyStr(ctx, ret, "depth", JS_NewBool(ctx, glc->actual_attrs.depth));
339 : }
340 2 : JS_SetPropertyStr(ctx, ret, "stencil", JS_NewBool(ctx, glc->actual_attrs.stencil));
341 2 : JS_SetPropertyStr(ctx, ret, "antialias", JS_NewBool(ctx, glc->actual_attrs.antialias));
342 2 : JS_SetPropertyStr(ctx, ret, "premultipliedAlpha", JS_NewBool(ctx, glc->actual_attrs.premultipliedAlpha));
343 2 : JS_SetPropertyStr(ctx, ret, "preserveDrawingBuffer", JS_NewBool(ctx, glc->actual_attrs.preserveDrawingBuffer));
344 2 : JS_SetPropertyStr(ctx, ret, "failIfMajorPerformanceCaveat", JS_NewBool(ctx, glc->actual_attrs.failIfMajorPerformanceCaveat));
345 2 : JS_SetPropertyStr(ctx, ret, "desynchronized", JS_NewBool(ctx, glc->actual_attrs.desynchronized));
346 1 : return ret;
347 : }
348 :
349 1 : static JSValue wgl_isContextLost(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
350 : {
351 1 : return JS_FALSE;
352 : }
353 1 : static JSValue wgl_getSupportedExtensions(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
354 : {
355 : char *gl_exts;
356 1 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
357 1 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
358 1 : if (argc && JS_ToBool(ctx, argv[0])) {
359 : JSValue res;
360 : u32 idx=0;
361 0 : gl_exts = (char *) glGetString(GL_EXTENSIONS);
362 0 : res = JS_NewArray(ctx);
363 0 : while (gl_exts) {
364 0 : char *sep = strchr(gl_exts, ' ');
365 0 : if (sep) sep[0] = 0;
366 0 : JS_SetPropertyUint32(ctx, res, idx, JS_NewString(ctx, gl_exts));
367 0 : idx++;
368 0 : if (!sep) break;
369 0 : if (sep) sep[0] = ' ';
370 0 : gl_exts = sep+1;
371 : }
372 0 : JS_SetPropertyStr(ctx, res, "length", JS_NewInt32(ctx, idx));
373 0 : return res;
374 : }
375 1 : return JS_NewArray(ctx);
376 : }
377 :
378 1 : static JSValue wgl_getExtension(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
379 : {
380 : const char *gl_exts, *ext;
381 : Bool found = GF_FALSE;
382 1 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
383 1 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
384 1 : if (!argc) return js_throw_err(ctx, WGL_INVALID_VALUE);
385 : ext = JS_ToCString(ctx, argv[0]);
386 :
387 1 : gl_exts = (const char *) glGetString(GL_EXTENSIONS);
388 1 : if (strstr(gl_exts, ext)) {
389 : found = GF_TRUE;
390 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[WebGL] getExtension not yet implemented, cannot fetch extension for %s\n", ext));
391 : }
392 :
393 1 : JS_FreeCString(ctx, ext);
394 1 : if (!found) return JS_NULL;
395 0 : return JS_NULL;
396 : }
397 :
398 1 : static JSValue wgl_getBufferParameter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
399 : {
400 1 : u32 target = 0;
401 1 : u32 pname = 0;
402 : GLint params;
403 1 : WGL_CHECK_CONTEXT
404 1 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
405 1 : WGL_GET_U32(target, argv[0]);
406 1 : WGL_GET_U32(pname, argv[1]);
407 1 : glGetBufferParameteriv(target, pname, ¶ms);
408 1 : return JS_NewInt32(ctx, params);
409 : }
410 1 : static JSValue wgl_getParameter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
411 : {
412 : s32 ints[4];
413 : u32 i, count;
414 : JSValue ret;
415 : Float floats[4];
416 : GLboolean bools[4];
417 1 : u32 pname = 0;
418 : u32 nb_floats = 0;
419 : u32 nb_ints = 0;
420 : u32 nb_bools = 0;
421 : const char *str;
422 1 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
423 1 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
424 1 : if (argc<1) return js_throw_err(ctx, WGL_INVALID_VALUE);
425 1 : WGL_GET_U32(pname, argv[0]);
426 :
427 1 : switch (pname) {
428 : //Floatx2
429 0 : case GL_ALIASED_LINE_WIDTH_RANGE:
430 : case GL_ALIASED_POINT_SIZE_RANGE:
431 : case GL_DEPTH_RANGE:
432 0 : glGetFloatv(pname, floats);
433 : nb_floats = 2;
434 0 : break;
435 : //WebGLBuffer
436 0 : case GL_ARRAY_BUFFER_BINDING:
437 : case GL_ELEMENT_ARRAY_BUFFER_BINDING:
438 0 : glGetIntegerv(pname, ints);
439 0 : if (!ints[0]) return JS_NULL;
440 0 : count = gf_list_count(glc->all_objects);
441 0 : for (i=0; i<count; i++) {
442 0 : GF_WebGLObject *ob = gf_list_get(glc->all_objects, i);
443 0 : if (ob->class_id==WebGLBuffer_class_id) {
444 0 : if (ob->gl_id==ints[0]) return JS_DupValue(ctx, ob->obj);
445 : }
446 : }
447 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
448 :
449 : //Floatx4
450 0 : case GL_BLEND_COLOR:
451 : case GL_COLOR_CLEAR_VALUE:
452 0 : glGetFloatv(pname, floats);
453 : nb_floats = 4;
454 0 : break;
455 : //boolx4
456 0 : case GL_COLOR_WRITEMASK:
457 0 : glGetBooleanv(pname, bools);
458 : nb_bools = 4;
459 0 : break;
460 :
461 : //uint array
462 0 : case GL_COMPRESSED_TEXTURE_FORMATS:
463 : {
464 0 : glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, ints);
465 0 : s32 *tx_ints = gf_malloc(sizeof(s32)*ints[0]);
466 0 : glGetIntegerv(pname, tx_ints);
467 0 : ret = JS_NewArray(ctx);
468 0 : for (i=0; (s32)i<ints[0]; i++) {
469 0 : JS_SetPropertyUint32(ctx, ret, i, JS_NewInt32(ctx, tx_ints[i]));
470 : }
471 0 : gf_free(ints);
472 0 : return ret;
473 : }
474 : break;
475 : //WebGLProgram
476 0 : case GL_CURRENT_PROGRAM:
477 0 : glGetIntegerv(pname, ints);
478 0 : if (!ints[0]) return JS_NULL;
479 0 : count = gf_list_count(glc->all_objects);
480 0 : for (i=0; i<count; i++) {
481 0 : GF_WebGLObject *ob = gf_list_get(glc->all_objects, i);
482 0 : if (ob->class_id==WebGLProgram_class_id) {
483 0 : if (ob->gl_id==ints[0]) return JS_DupValue(ctx, ob->obj);
484 : }
485 : }
486 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
487 :
488 : //WebGLFramebuffer
489 0 : case GL_FRAMEBUFFER_BINDING:
490 0 : glGetIntegerv(pname, ints);
491 0 : if (!ints[0]) return JS_NULL;
492 0 : count = gf_list_count(glc->all_objects);
493 0 : for (i=0; i<count; i++) {
494 0 : GF_WebGLObject *ob = gf_list_get(glc->all_objects, i);
495 0 : if (ob->class_id==WebGLFramebuffer_class_id) {
496 0 : if (ob->gl_id==ints[0]) return JS_DupValue(ctx, ob->obj);
497 : }
498 : }
499 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
500 :
501 : //WebGLRenderbuffer
502 0 : case GL_RENDERBUFFER_BINDING:
503 0 : glGetIntegerv(pname, ints);
504 0 : if (!ints[0]) return JS_NULL;
505 0 : count = gf_list_count(glc->all_objects);
506 0 : for (i=0; i<count; i++) {
507 0 : GF_WebGLObject *ob = gf_list_get(glc->all_objects, i);
508 0 : if (ob->class_id==WebGLRenderbuffer_class_id) {
509 0 : if (ob->gl_id==ints[0]) return JS_DupValue(ctx, ob->obj);
510 : }
511 : }
512 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
513 :
514 : //WebGLTexture
515 0 : case GL_TEXTURE_BINDING_2D:
516 : case GL_TEXTURE_BINDING_CUBE_MAP:
517 0 : glGetIntegerv(pname, ints);
518 0 : if (!ints[0]) return JS_NULL;
519 0 : count = gf_list_count(glc->all_objects);
520 0 : for (i=0; i<count; i++) {
521 0 : GF_WebGLObject *ob = gf_list_get(glc->all_objects, i);
522 0 : if (ob->class_id==WebGLTexture_class_id) {
523 0 : if (ob->gl_id==ints[0]) return JS_DupValue(ctx, ob->obj);
524 : }
525 : }
526 : //todo: do we want to expose
527 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
528 :
529 : //bool
530 0 : case GL_BLEND:
531 : case GL_CULL_FACE:
532 : case GL_DEPTH_TEST:
533 : case GL_DEPTH_WRITEMASK:
534 : case GL_DITHER:
535 : case GL_POLYGON_OFFSET_FILL:
536 : case GL_SAMPLE_ALPHA_TO_COVERAGE:
537 : case GL_SAMPLE_COVERAGE:
538 : case GL_SAMPLE_COVERAGE_INVERT:
539 : case GL_SCISSOR_TEST:
540 : case GL_STENCIL_TEST:
541 : #if 0
542 : case GL_UNPACK_FLIP_Y_WEBGL:
543 : case GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
544 : #endif
545 0 : glGetBooleanv(pname, bools);
546 0 : return bools[0] ? JS_TRUE : JS_FALSE;
547 :
548 : //floats
549 0 : case GL_DEPTH_CLEAR_VALUE:
550 : case GL_LINE_WIDTH:
551 : case GL_POLYGON_OFFSET_FACTOR:
552 : case GL_POLYGON_OFFSET_UNITS:
553 : case GL_SAMPLE_COVERAGE_VALUE:
554 0 : glGetFloatv(pname, floats);
555 0 : return JS_NewFloat64(ctx, floats[0]);
556 : //intx2
557 0 : case GL_MAX_VIEWPORT_DIMS:
558 0 : glGetIntegerv(pname, ints);
559 : nb_ints = 2;
560 0 : break;
561 : //intx4
562 0 : case GL_SCISSOR_BOX:
563 : case GL_VIEWPORT:
564 0 : glGetIntegerv(pname, ints);
565 : nb_ints = 4;
566 0 : break;
567 : //strings
568 0 : case GL_RENDERER:
569 : case GL_SHADING_LANGUAGE_VERSION:
570 : case GL_VENDOR:
571 : case GL_VERSION:
572 0 : str = glGetString(pname);
573 0 : return JS_NewString(ctx, str ? str : "");
574 :
575 : //all the rest is enum or int
576 1 : default:
577 1 : glGetIntegerv(pname, ints);
578 1 : return JS_NewInt32(ctx, ints[0]);
579 : break;
580 : }
581 :
582 0 : if (nb_floats) {
583 0 : ret = JS_NewArray(ctx);
584 0 : for (i=0; i<nb_floats; i++) {
585 0 : JS_SetPropertyUint32(ctx, ret, i, JS_NewFloat64(ctx, floats[i]));
586 : }
587 0 : return ret;
588 : }
589 :
590 0 : if (nb_ints) {
591 0 : ret = JS_NewArray(ctx);
592 0 : for (i=0; i<nb_ints; i++) {
593 0 : JS_SetPropertyUint32(ctx, ret, i, JS_NewInt32(ctx, ints[i]));
594 : }
595 0 : return ret;
596 : }
597 :
598 0 : if (nb_bools) {
599 0 : ret = JS_NewArray(ctx);
600 0 : for (i=0; i<nb_bools; i++) {
601 0 : JS_SetPropertyUint32(ctx, ret, i, JS_NewBool(ctx, bools[i]));
602 : }
603 0 : return ret;
604 : }
605 0 : return JS_UNDEFINED;
606 : }
607 :
608 1 : static JSValue wgl_getFramebufferAttachmentParameter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
609 : {
610 1 : u32 target = 0;
611 1 : u32 attachment = 0;
612 1 : u32 pname = 0;
613 : GLint params;
614 1 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
615 1 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
616 1 : if (argc<3) return js_throw_err(ctx, WGL_INVALID_VALUE);
617 1 : WGL_GET_U32(target, argv[0]);
618 1 : WGL_GET_U32(attachment, argv[1]);
619 1 : WGL_GET_U32(pname, argv[2]);
620 1 : glGetFramebufferAttachmentParameteriv (target, attachment, pname, ¶ms);
621 1 : if (pname==GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
622 : u32 i, count;
623 0 : if (!params) return JS_NULL;
624 0 : count = gf_list_count(glc->all_objects);
625 0 : for (i=0; i<count; i++) {
626 0 : GF_WebGLObject *ob = gf_list_get(glc->all_objects, i);
627 0 : if (ob->class_id==WebGLTexture_class_id) {
628 0 : if (ob->gl_id == params) return JS_DupValue(ctx, ob->obj);
629 0 : } else if (ob->class_id==WebGLRenderbuffer_class_id) {
630 0 : if (ob->gl_id == params) return JS_DupValue(ctx, ob->obj);
631 : }
632 : }
633 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
634 : }
635 1 : return JS_NewInt32(ctx, params);
636 : }
637 3 : static JSValue wgl_getProgramParameter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
638 : {
639 : GLint program=0;
640 3 : u32 pname = 0;
641 : GLint params;
642 3 : WGL_CHECK_CONTEXT
643 3 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
644 6 : WGL_GET_GLID(program, argv[0], WebGLProgram_class_id);
645 3 : WGL_GET_U32(pname, argv[1]);
646 3 : glGetProgramiv(program, pname, ¶ms);
647 3 : switch (pname) {
648 3 : case GL_DELETE_STATUS:
649 : case GL_LINK_STATUS:
650 : case GL_VALIDATE_STATUS:
651 3 : return params ? JS_TRUE : JS_FALSE;
652 : default:
653 : break;
654 : }
655 0 : return JS_NewInt32(ctx, params);
656 : }
657 1 : static JSValue wgl_getRenderbufferParameter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
658 : {
659 1 : u32 target = 0;
660 1 : u32 pname = 0;
661 : GLint params;
662 1 : WGL_CHECK_CONTEXT
663 1 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
664 1 : WGL_GET_U32(target, argv[0]);
665 1 : WGL_GET_U32(pname, argv[1]);
666 1 : glGetRenderbufferParameteriv(target, pname, ¶ms);
667 1 : return JS_NewInt32(ctx, params);
668 : }
669 6 : static JSValue wgl_getShaderParameter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
670 : {
671 : GLint shader=0;
672 6 : u32 pname = 0;
673 : GLint params;
674 6 : WGL_CHECK_CONTEXT
675 6 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
676 12 : WGL_GET_GLID(shader, argv[0], WebGLShader_class_id);
677 6 : WGL_GET_U32(pname, argv[1]);
678 6 : glGetShaderiv(shader, pname, ¶ms);
679 6 : switch (pname) {
680 6 : case GL_DELETE_STATUS:
681 : case GL_COMPILE_STATUS:
682 6 : return params ? JS_TRUE : JS_FALSE;
683 : default:
684 : break;
685 : }
686 0 : return JS_NewInt32(ctx, params);
687 : }
688 1 : static JSValue wgl_getShaderPrecisionFormat(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
689 : {
690 : JSValue ret;
691 1 : u32 shader_type = 0;
692 1 : u32 prec_type = 0;
693 : GLint range[2];
694 : GLint precision;
695 1 : WGL_CHECK_CONTEXT
696 1 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
697 1 : WGL_GET_U32(shader_type, argv[0]);
698 1 : WGL_GET_U32(prec_type, argv[1]);
699 :
700 : #if defined(GPAC_USE_GLES2)
701 : glGetShaderPrecisionFormat(shader_type, prec_type, range, &precision);
702 : #else
703 : range[0] = 0;
704 : range[1] = 128;
705 : precision = 128;
706 : #endif
707 1 : ret = JS_NewObject(ctx);
708 1 : JS_SetPropertyStr(ctx, ret, "rangeMin", JS_NewInt32(ctx, range[0]));
709 1 : JS_SetPropertyStr(ctx, ret, "rangeMax", JS_NewInt32(ctx, range[1]));
710 1 : JS_SetPropertyStr(ctx, ret, "precision", JS_NewInt32(ctx, precision));
711 1 : return ret;
712 : }
713 5 : static JSValue wgl_getInfoLog(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, u32 type)
714 : {
715 : JSValue ret;
716 : int info_length;
717 : char *info;
718 : GLint program_shader=0;
719 5 : WGL_CHECK_CONTEXT
720 5 : if (argc<1) return js_throw_err(ctx, WGL_INVALID_VALUE);
721 5 : if (type==0) {
722 2 : WGL_GET_GLID(program_shader, argv[0], WebGLProgram_class_id);
723 1 : glGetProgramiv(program_shader, GL_INFO_LOG_LENGTH, &info_length);
724 : } else {
725 8 : WGL_GET_GLID(program_shader, argv[0], WebGLShader_class_id);
726 4 : if (type==1) {
727 2 : glGetShaderiv(program_shader, GL_INFO_LOG_LENGTH, &info_length);
728 : } else {
729 2 : glGetShaderiv(program_shader, GL_SHADER_SOURCE_LENGTH, &info_length);
730 : }
731 : }
732 5 : info = gf_malloc(sizeof(char)*(info_length+1));
733 5 : if (type==0) {
734 1 : glGetProgramInfoLog(program_shader, info_length, &info_length, info);
735 4 : } else if (type==1) {
736 2 : glGetShaderInfoLog(program_shader, info_length, &info_length, info);
737 : } else {
738 2 : glGetShaderSource(program_shader, info_length, &info_length, info);
739 : }
740 5 : info[info_length] = 0;
741 5 : ret = JS_NewString(ctx, info);
742 5 : gf_free(info);
743 5 : return ret;
744 : }
745 :
746 1 : static JSValue wgl_getProgramInfoLog(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
747 : {
748 1 : return wgl_getInfoLog(ctx, this_val, argc, argv, 0);
749 : }
750 2 : static JSValue wgl_getShaderInfoLog(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
751 : {
752 2 : return wgl_getInfoLog(ctx, this_val, argc, argv, 1);
753 : }
754 2 : static JSValue wgl_getShaderSource(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
755 : {
756 2 : return wgl_getInfoLog(ctx, this_val, argc, argv, 2);
757 : }
758 1 : static JSValue wgl_getTexParameter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
759 : {
760 1 : u32 target = 0;
761 1 : u32 pname = 0;
762 : GLint params;
763 1 : WGL_CHECK_CONTEXT
764 1 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
765 1 : WGL_GET_U32(target, argv[0]);
766 1 : WGL_GET_U32(pname, argv[1]);
767 1 : glGetTexParameteriv(target, pname, ¶ms);
768 1 : return JS_NewInt32(ctx, params);
769 : }
770 101 : static JSValue wgl_getUniform(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
771 : {
772 : GLint program_shader=0;
773 : GLint location=0;
774 101 : GLint i, j, activeUniforms=0;
775 : GLsizei len;
776 : GLint size, length;
777 : GLenum type, base_type;
778 : Bool found = GF_FALSE;
779 : GLfloat values_f[16];
780 : GLint values_i[4];
781 : GLuint values_ui[4];
782 : JSValue res;
783 : char name[1024], sname[1150];
784 :
785 101 : WGL_CHECK_CONTEXT
786 101 : if (argc<1) return js_throw_err(ctx, WGL_INVALID_VALUE);
787 202 : WGL_GET_GLID(program_shader, argv[0], WebGLProgram_class_id);
788 202 : WGL_GET_GLID(location, argv[1], WebGLUniformLocation_class_id);
789 :
790 : //openGL doesn't provide a way to get a uniform type from its location
791 : //we need to browse all active uniforms by name in the program
792 : //then look for the location of each uniform and check against the desired location
793 :
794 101 : glGetProgramiv(program_shader, GL_ACTIVE_UNIFORMS, &activeUniforms);
795 202 : for (i=0; i<activeUniforms; i++) {
796 202 : glGetActiveUniform(program_shader, i, 1024, &len, &size, &type, name);
797 202 : if ((len>3) && !strcmp(name+len-3, "[0]")) {
798 0 : len -= 3;
799 0 : name[len] = 0;
800 : }
801 :
802 101 : for (j=0; j<size; j++) {
803 : strcpy(sname, name);
804 202 : if ((size > 1) && (j >= 1)) {
805 : char szIdx[100];
806 : sprintf(szIdx, "[%d]", j);
807 : strcat(sname, szIdx);
808 : }
809 202 : GLint loc = glGetUniformLocation(program_shader, sname);
810 202 : if (loc == location) {
811 : found = GF_TRUE;
812 : break;
813 : }
814 : }
815 202 : if (found) break;
816 : }
817 101 : if (!found) {
818 0 : return js_throw_err_msg(ctx, WGL_INVALID_VALUE, "[WebGL] uniform not found");
819 : }
820 101 : switch (type) {
821 : case GL_BOOL: base_type = GL_BOOL; length = 1; break;
822 : case GL_BOOL_VEC2: base_type = GL_BOOL; length = 2; break;
823 : case GL_BOOL_VEC3: base_type = GL_BOOL; length = 3; break;
824 : case GL_BOOL_VEC4: base_type = GL_BOOL; length = 4; break;
825 : case GL_INT: base_type = GL_INT; length = 1; break;
826 : case GL_INT_VEC2: base_type = GL_INT; length = 2; break;
827 : case GL_INT_VEC3: base_type = GL_INT; length = 3; break;
828 : case GL_INT_VEC4: base_type = GL_INT; length = 4; break;
829 : case GL_FLOAT: base_type = GL_FLOAT; length = 1; break;
830 : case GL_FLOAT_VEC2: base_type = GL_FLOAT; length = 2; break;
831 : case GL_FLOAT_VEC3: base_type = GL_FLOAT; length = 3; break;
832 : case GL_FLOAT_VEC4: base_type = GL_FLOAT; length = 4; break;
833 : case GL_FLOAT_MAT2: base_type = GL_FLOAT; length = 4; break;
834 : case GL_FLOAT_MAT3: base_type = GL_FLOAT; length = 9; break;
835 : case GL_FLOAT_MAT4: base_type = GL_FLOAT; length = 16; break;
836 : case GL_SAMPLER_2D:
837 : case GL_SAMPLER_CUBE:
838 : base_type = GL_INT;
839 : length = 1;
840 : break;
841 0 : default:
842 0 : return js_throw_err_msg(ctx, WGL_INVALID_VALUE, "[WebGL] uniform type not supported");
843 : }
844 :
845 : #define RETURN_SINGLE_OR_ARRAY(__fun, __arr) \
846 : if (length == 1) return __fun(ctx, __arr[0]);\
847 : res = JS_NewArray(ctx);\
848 : JS_SetPropertyStr(ctx, res, "length", JS_NewInt32(ctx, length));\
849 : for (i=0; i<length; i++)\
850 : JS_SetPropertyUint32(ctx, res, i, __fun(ctx, __arr[i]) );\
851 : return res;
852 :
853 : switch (base_type) {
854 101 : case GL_FLOAT:
855 101 : glGetUniformfv(program_shader, location, values_f);
856 1919 : RETURN_SINGLE_OR_ARRAY(JS_NewFloat64, values_f);
857 :
858 0 : case GL_INT:
859 0 : glGetUniformiv(program_shader, location, values_i);
860 0 : RETURN_SINGLE_OR_ARRAY(JS_NewInt32, values_i);
861 :
862 : case GL_UNSIGNED_INT:
863 : //TODO - support for GLES3 is needed for this one, for now use the integer version
864 : glGetUniformiv(program_shader, location, values_ui);
865 : RETURN_SINGLE_OR_ARRAY(JS_NewInt64, values_ui);
866 :
867 0 : case GL_BOOL:
868 0 : glGetUniformiv(program_shader, location, values_i);
869 0 : RETURN_SINGLE_OR_ARRAY(JS_NewBool, values_i);
870 :
871 : default:
872 : break;
873 : }
874 :
875 : #undef RETURN_GLANY_SINGLE_OR_ARRAY
876 :
877 : return js_throw_err_msg(ctx, WGL_INVALID_VALUE, "[WebGL] uniform type not supported");
878 : }
879 :
880 101 : static JSValue wgl_getVertexAttrib(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
881 : {
882 : JSValue ret;
883 : u32 i, count;
884 101 : u32 index = 0;
885 101 : u32 pname = 0;
886 : Float floats[4];
887 : s32 ints[4];
888 101 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
889 101 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
890 101 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
891 101 : WGL_GET_U32(index, argv[0]);
892 101 : WGL_GET_U32(pname, argv[1]);
893 101 : switch (pname) {
894 0 : case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
895 0 : glGetVertexAttribiv(index, pname, ints);
896 0 : if (!ints[0]) return JS_NULL;
897 0 : count = gf_list_count(glc->all_objects);
898 0 : for (i=0; i<count; i++) {
899 0 : GF_WebGLObject *ob = gf_list_get(glc->all_objects, i);
900 0 : if (ob->class_id==WebGLBuffer_class_id) {
901 0 : if (ob->gl_id==ints[0]) return JS_DupValue(ctx, ob->obj);
902 : }
903 : }
904 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
905 0 : case GL_CURRENT_VERTEX_ATTRIB:
906 0 : glGetVertexAttribfv(index, pname, floats);
907 0 : ret = JS_NewArray(ctx);
908 0 : for (i=0; i<4; i++)
909 0 : JS_SetPropertyUint32(ctx, ret, i, JS_NewFloat64(ctx, floats[i]));
910 0 : return ret;
911 0 : case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
912 : case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
913 0 : glGetVertexAttribiv(index, pname, ints);
914 0 : return ints[0] ? JS_TRUE : JS_FALSE;
915 101 : case GL_VERTEX_ATTRIB_ARRAY_SIZE:
916 : case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
917 : case GL_VERTEX_ATTRIB_ARRAY_TYPE:
918 101 : glGetVertexAttribiv(index, pname, ints);
919 101 : return JS_NewInt32(ctx, ints[0]);
920 : }
921 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
922 : }
923 101 : static JSValue wgl_getVertexAttribOffset(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
924 : {
925 101 : u32 index = 0;
926 101 : u32 pname = 0;
927 101 : void *ptr = NULL;
928 101 : WGL_CHECK_CONTEXT
929 101 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
930 101 : WGL_GET_U32(index, argv[0]);
931 101 : WGL_GET_U32(pname, argv[1]);
932 101 : glGetVertexAttribPointerv(index, pname, &ptr);
933 : #ifdef GPAC_64_BITS
934 101 : return JS_NewInt64(ctx, (u64) ptr);
935 : #else
936 : return JS_NewInt64(ctx, (u32) ptr);
937 : #endif
938 : }
939 1 : static JSValue wgl_readPixels(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
940 : {
941 1 : s32 x = 0;
942 1 : s32 y = 0;
943 1 : u32 width = 0;
944 1 : u32 height = 0;
945 1 : u32 format = 0;
946 1 : u32 type = 0;
947 : u32 req_size=0;
948 : u8 *ab;
949 : u32 ab_size;
950 1 : WGL_CHECK_CONTEXT
951 1 : if (argc<7) return js_throw_err(ctx, WGL_INVALID_VALUE);
952 1 : WGL_GET_S32(x, argv[0]);
953 1 : WGL_GET_S32(y, argv[1]);
954 1 : WGL_GET_U32(width, argv[2]);
955 1 : WGL_GET_U32(height, argv[3]);
956 1 : WGL_GET_U32(format, argv[4]);
957 1 : WGL_GET_U32(type, argv[5]);
958 1 : ab = wgl_GetArrayBuffer(ctx, &ab_size, argv[6]);
959 1 : if (!ab) return js_throw_err(ctx, WGL_INVALID_VALUE);
960 :
961 1 : req_size = width * height;
962 1 : if (format==GL_RGB) {
963 1 : req_size *= 3;
964 0 : } else if (format==GL_RGBA) {
965 0 : req_size *= 4;
966 : } else {
967 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
968 : }
969 1 : if (type==GL_UNSIGNED_BYTE) {
970 0 : } else if (type==GL_UNSIGNED_SHORT) {
971 0 : req_size *= 2;
972 0 : } else if (type==GL_FLOAT) {
973 0 : req_size *= 4;
974 : } else {
975 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
976 : }
977 1 : if (req_size>ab_size) {
978 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
979 : }
980 1 : glReadPixels(x, y, width, height, format, type, ab);
981 :
982 1 : return JS_UNDEFINED;
983 : }
984 :
985 12 : GF_WebGLNamedTexture *wgl_locate_named_tx(GF_WebGLContext *glc, char *name)
986 : {
987 12 : u32 i, count = gf_list_count(glc->named_textures);
988 30 : for (i=0; i<count; i++) {
989 22 : GF_WebGLNamedTexture *tx = gf_list_get(glc->named_textures, i);
990 22 : if (!strcmp(tx->tx_name, name)) return tx;
991 : }
992 : return NULL;
993 : }
994 :
995 6 : static JSValue wgl_shaderSource(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
996 : {
997 : GLint shader=0;
998 : Bool has_gptx=GF_FALSE;
999 6 : char *source, *gf_source=NULL;
1000 : const char *final_source;
1001 6 : u32 len = 0;
1002 : u32 count, i;
1003 6 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1004 6 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1005 6 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
1006 12 : WGL_GET_GLID(shader, argv[0], WebGLShader_class_id);
1007 : source = (char *) JS_ToCString(ctx, argv[1]);
1008 6 : if (!source) return js_throw_err(ctx, WGL_INVALID_VALUE);
1009 :
1010 6 : count = gf_list_count(glc->named_textures);
1011 10 : for (i=0; i<count; i++) {
1012 : u32 namelen;
1013 6 : GF_WebGLNamedTexture *named_tx = gf_list_get(glc->named_textures, i);
1014 : char *a_source = source;
1015 6 : namelen = (u32) strlen(named_tx->tx_name);
1016 :
1017 12 : while (a_source) {
1018 6 : char *loc = strstr(a_source, "texture2D");
1019 6 : if (!loc) break;
1020 2 : loc += 9;
1021 2 : while (loc[0] && strchr(" (\n\t", loc[0])) loc++;
1022 2 : if (strchr(" ,)\n\t", loc[namelen])) {
1023 : has_gptx = GF_TRUE;
1024 : break;
1025 : }
1026 : a_source = loc;
1027 : }
1028 6 : if (has_gptx) break;
1029 : }
1030 :
1031 6 : if (has_gptx) {
1032 : char *o_src, *start;
1033 2 : char *gf_source_pass1 = NULL;
1034 :
1035 : //first pass, strip all sample2D declarations for GPACTextures, replace with our own
1036 : o_src = source;
1037 8 : while (o_src) {
1038 : char c;
1039 : GF_WebGLNamedTexture *named_tx=NULL;
1040 : Bool found = GF_FALSE;
1041 6 : char *sep, *start = strstr(o_src, "uniform sampler2D ");
1042 6 : if (!start) {
1043 2 : gf_dynstrcat(&gf_source_pass1, o_src, NULL);
1044 2 : break;
1045 : }
1046 4 : sep = start + strlen("uniform sampler2D ");
1047 6 : for (i=0; i<count; i++) {
1048 : u32 namelen;
1049 6 : named_tx = gf_list_get(glc->named_textures, i);
1050 6 : namelen = (u32) strlen(named_tx->tx_name);
1051 6 : if (strncmp(sep, named_tx->tx_name, namelen)) continue;
1052 :
1053 4 : if (strchr(" \n\t;", sep[namelen])) {
1054 : sep += namelen;
1055 4 : while (sep[0] && strchr(" ;", sep[0])) sep++;
1056 4 : start[0] = 0;
1057 4 : gf_dynstrcat(&gf_source_pass1, o_src, NULL);
1058 4 : start[0] = 'u';
1059 : o_src = sep;
1060 : found = GF_TRUE;
1061 4 : break;
1062 : }
1063 : }
1064 4 : if (found) {
1065 : //named texture but unknown pixel format, cannot create shader
1066 4 : if (!named_tx->tx.pix_fmt) {
1067 0 : JSValue ret = js_throw_err_msg(ctx, WGL_INVALID_VALUE, "NamedTexture %s pixel format undefined, cannot create shader", named_tx->tx_name);
1068 0 : JS_FreeCString(ctx, source);
1069 0 : gf_free(gf_source);
1070 0 : return ret;
1071 : }
1072 : //insert our uniform declaration and code
1073 4 : if (gf_gl_txw_insert_fragment_shader(named_tx->tx.pix_fmt, named_tx->tx_name, &gf_source_pass1))
1074 4 : named_tx->shader_attached = GF_TRUE;
1075 4 : continue;
1076 : }
1077 0 : c = sep[0];
1078 0 : sep[0] = 0;
1079 0 : gf_dynstrcat(&gf_source_pass1, o_src, NULL);
1080 0 : sep[0] = c;
1081 : o_src = sep;
1082 : }
1083 : //second pass, replace all texture2D(NamedTX, ..) with our calls
1084 2 : start = gf_source_pass1;
1085 16 : while (start && start[0]) {
1086 : char c;
1087 : char *next;
1088 : GF_WebGLNamedTexture *named_tx;
1089 : char *end_gfTx;
1090 14 : char *has_gfTx = strstr(start, "texture2D");
1091 14 : if (!has_gfTx) {
1092 2 : gf_dynstrcat(&gf_source, start, NULL);
1093 2 : break;
1094 : }
1095 :
1096 12 : end_gfTx = has_gfTx + strlen("texture2D");
1097 36 : while (end_gfTx[0] && strchr(" (\n", end_gfTx[0]))
1098 12 : end_gfTx++;
1099 : next = end_gfTx;
1100 120 : while (next[0] && !strchr(" (,)\n", next[0]))
1101 108 : next++;
1102 :
1103 : c = next[0];
1104 12 : next[0] = 0;
1105 12 : named_tx = wgl_locate_named_tx(glc, end_gfTx);
1106 :
1107 : //not a named texture, do not replace code
1108 12 : if (!named_tx) {
1109 8 : next[0] = c;
1110 8 : has_gfTx[0] = 0;
1111 8 : gf_dynstrcat(&gf_source, start, NULL);
1112 8 : has_gfTx[0] = 't';
1113 8 : gf_dynstrcat(&gf_source, "texture2D", NULL);
1114 : start = has_gfTx + 9;
1115 8 : continue;
1116 : }
1117 4 : next[0] = c;
1118 :
1119 4 : has_gfTx[0] = 0;
1120 4 : gf_dynstrcat(&gf_source, start, NULL);
1121 4 : has_gfTx[0] = 't';
1122 :
1123 4 : gf_dynstrcat(&gf_source, named_tx->tx_name, NULL);
1124 4 : gf_dynstrcat(&gf_source, "_sample(", NULL);
1125 16 : while (next[0] && strchr(" ,", next[0]))
1126 8 : next++;
1127 :
1128 : start = next;
1129 : }
1130 2 : gf_free(gf_source_pass1);
1131 2 : final_source = gf_source;
1132 : } else {
1133 4 : final_source = source;
1134 : }
1135 :
1136 6 : if (!final_source) {
1137 0 : JS_FreeCString(ctx, source);
1138 0 : return js_throw_err_msg(ctx, WGL_INVALID_VALUE, "Failed to rewrite shader");
1139 : }
1140 :
1141 6 : len = (u32) strlen(final_source);
1142 6 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONSOLE, ("[WebGL] Shader rewritten as\n%s", final_source));
1143 :
1144 6 : glShaderSource(shader, 1, &final_source, &len);
1145 :
1146 6 : JS_FreeCString(ctx, source);
1147 6 : if (gf_source) gf_free(gf_source);
1148 6 : return JS_UNDEFINED;
1149 : }
1150 :
1151 : const GF_FilterPacket *jsf_get_packet(JSContext *c, JSValue obj);
1152 :
1153 506 : static JSValue wgl_named_texture_upload(JSContext *c, JSValueConst pck_obj, GF_WebGLNamedTexture *named_tx)
1154 : {
1155 : GF_FilterPacket *pck = NULL;
1156 : GF_FilterFrameInterface *frame_ifce = NULL;
1157 506 : const u8 *data=NULL;
1158 :
1159 : /*try GF_FilterPacket*/
1160 506 : if (jsf_is_packet(c, pck_obj)) {
1161 504 : pck = (GF_FilterPacket *) jsf_get_packet(c, pck_obj);
1162 504 : if (!pck) return js_throw_err(c, WGL_INVALID_VALUE);
1163 :
1164 504 : frame_ifce = gf_filter_pck_get_frame_interface(pck);
1165 : }
1166 : /*try evg Texture*/
1167 2 : else if (js_evg_is_texture(c, pck_obj)) {
1168 : } else {
1169 0 : return js_throw_err(c, WGL_INVALID_VALUE);
1170 : }
1171 :
1172 : //setup texture
1173 506 : if (!named_tx->tx.pix_fmt) {
1174 4 : u32 pix_fmt=0, width=0, height=0, stride=0, uv_stride=0;
1175 4 : if (pck) {
1176 2 : jsf_get_filter_packet_planes(c, pck_obj, &width, &height, &pix_fmt, &stride, &uv_stride, NULL, NULL, NULL, NULL);
1177 : } else {
1178 2 : js_evg_get_texture_info(c, pck_obj, &width, &height, &pix_fmt, NULL, &stride, NULL, NULL, &uv_stride, NULL);
1179 : }
1180 :
1181 4 : if (!gf_gl_txw_setup(&named_tx->tx, pix_fmt, width, height, stride, uv_stride, GF_FALSE, frame_ifce, named_tx->tx.fullrange, named_tx->tx.mx_cicp)) {
1182 0 : return js_throw_err_msg(c, WGL_INVALID_VALUE, "[WebGL] Pixel format %s unknown, cannot setup NamedTexture\n", gf_4cc_to_str(pix_fmt));
1183 : }
1184 : }
1185 :
1186 : //fetch data
1187 506 : if (!frame_ifce) {
1188 506 : u32 size=0;
1189 506 : if (pck) {
1190 504 : data = gf_filter_pck_get_data(pck, &size);
1191 504 : if (!data)
1192 0 : return js_throw_err_msg(c, WGL_INVALID_VALUE, "[WebGL] Unable to fetch packet data, cannot setup NamedTexture\n");
1193 : } else {
1194 2 : js_evg_get_texture_info(c, pck_obj, NULL, NULL, NULL, (u8 **) &data, NULL, NULL, NULL, NULL, NULL);
1195 2 : if (!data)
1196 0 : return js_throw_err_msg(c, WGL_INVALID_VALUE, "[WebGL] Unable to fetch EVG texture data, cannot setup NamedTexture\n");
1197 : }
1198 : }
1199 :
1200 506 : gf_gl_txw_upload(&named_tx->tx, data, frame_ifce);
1201 :
1202 506 : return JS_UNDEFINED;
1203 : }
1204 :
1205 505 : static JSValue wgl_texImage2D(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1206 : {
1207 505 : u32 target = 0;
1208 505 : s32 level = 0;
1209 505 : s32 internalformat = 0;
1210 505 : u32 width = 0;
1211 505 : u32 height = 0;
1212 505 : s32 border = 0;
1213 505 : u32 format = 0;
1214 505 : u32 type = 0;
1215 : u32 pixfmt;
1216 : u32 stride;
1217 : u32 stride_uv;
1218 : u8 *p_u, *p_v, *p_a;
1219 : u8 *pix_buf;
1220 505 : u32 pix_buf_size=0;
1221 :
1222 505 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1223 505 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1224 :
1225 505 : if (argc<6) return js_throw_err(ctx, WGL_INVALID_VALUE);
1226 :
1227 505 : WGL_GET_U32(target, argv[0]);
1228 505 : WGL_GET_S32(level, argv[1]);
1229 505 : WGL_GET_S32(internalformat, argv[2]);
1230 : /*from texture object*/
1231 1010 : if (JS_IsObject(argv[5])) {
1232 :
1233 505 : WGL_GET_U32(format, argv[3]);
1234 505 : WGL_GET_U32(type, argv[4]);
1235 : }
1236 : /*from array buffer*/
1237 : else {
1238 0 : if (argc==8) {
1239 :
1240 0 : } else if ((argc<9) || (!JS_IsObject(argv[8]) && !JS_IsNull(argv[8]))) {
1241 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
1242 : }
1243 :
1244 0 : WGL_GET_U32(width, argv[3]);
1245 0 : WGL_GET_U32(height, argv[4]);
1246 0 : WGL_GET_S32(border, argv[5]);
1247 0 : WGL_GET_U32(format, argv[6]);
1248 0 : WGL_GET_U32(type, argv[7]);
1249 0 : pix_buf = wgl_GetArrayBuffer(ctx, &pix_buf_size, argv[8]);
1250 :
1251 0 : glTexImage2D(target, level, internalformat, width, height, border, format, type, pix_buf);
1252 0 : return JS_UNDEFINED;
1253 : }
1254 :
1255 : /*bound texture is a named texture, use tx.upload() */
1256 505 : if (glc->bound_named_texture) {
1257 504 : return wgl_named_texture_upload(ctx, argv[5], glc->bound_named_texture);
1258 : }
1259 :
1260 : /*check if this is an EVG texture*/
1261 1 : if (js_evg_get_texture_info(ctx, argv[5], &width, &height, &pixfmt, &pix_buf, &stride, &p_u, &p_v, &stride_uv, &p_a)) {
1262 1 : switch (pixfmt) {
1263 0 : case GF_PIXEL_GREYSCALE:
1264 0 : format = GL_LUMINANCE;
1265 0 : type = GL_TEXTURE_2D;
1266 0 : break;
1267 0 : case GF_PIXEL_ALPHAGREY:
1268 : case GF_PIXEL_GREYALPHA:
1269 0 : format = GL_LUMINANCE_ALPHA;
1270 0 : type = GL_UNSIGNED_BYTE;
1271 0 : break;
1272 1 : case GF_PIXEL_RGB:
1273 1 : format = GL_RGB;
1274 1 : type = GL_UNSIGNED_BYTE;
1275 1 : break;
1276 0 : case GF_PIXEL_RGBA:
1277 0 : format = GL_RGBA;
1278 0 : type = GL_UNSIGNED_BYTE;
1279 0 : break;
1280 0 : default:
1281 0 : return js_throw_err_msg(ctx, WGL_INVALID_ENUM, "[WebGL] Pixel format %s not yet mapped to texImage2D", gf_pixel_fmt_name(pixfmt) );
1282 : }
1283 1 : internalformat = GL_RGBA;
1284 1 : target = GL_TEXTURE_2D;
1285 1 : glTexImage2D(target, level, internalformat, width, height, border, format, type, pix_buf);
1286 1 : return JS_UNDEFINED;
1287 : }
1288 : /*otherwise not supported*/
1289 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
1290 : }
1291 :
1292 1 : static JSValue wgl_texSubImage2D(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1293 : {
1294 1 : u32 target = 0;
1295 1 : s32 level = 0;
1296 1 : s32 xoffset = 0;
1297 1 : s32 yoffset = 0;
1298 1 : u32 width = 0;
1299 1 : u32 height = 0;
1300 1 : u32 format = 0;
1301 1 : u32 type = 0;
1302 : u32 pixfmt, stride, stride_uv;
1303 : u8 *pix_buf, *p_u, *p_v, *p_a;
1304 1 : u32 pix_buf_size=0;
1305 1 : WGL_CHECK_CONTEXT
1306 1 : if (argc<7) return js_throw_err(ctx, WGL_INVALID_VALUE);
1307 :
1308 1 : WGL_GET_U32(target, argv[0]);
1309 1 : WGL_GET_S32(level, argv[1]);
1310 1 : WGL_GET_S32(xoffset, argv[2]);
1311 1 : WGL_GET_S32(yoffset, argv[3]);
1312 : /*from texture object*/
1313 2 : if (JS_IsObject(argv[6])) {
1314 :
1315 1 : WGL_GET_U32(format, argv[4]);
1316 1 : WGL_GET_U32(type, argv[5]);
1317 : }
1318 : /*from array buffer*/
1319 : else {
1320 0 : if ((argc<9) || !JS_IsObject(argv[8])) {
1321 0 : return js_throw_err(ctx, WGL_INVALID_VALUE);
1322 : }
1323 :
1324 0 : WGL_GET_U32(width, argv[4]);
1325 0 : WGL_GET_U32(height, argv[5]);
1326 0 : WGL_GET_U32(format, argv[6]);
1327 0 : WGL_GET_U32(type, argv[7]);
1328 0 : pix_buf = wgl_GetArrayBuffer(ctx, &pix_buf_size, argv[8]);
1329 0 : if (!pix_buf) return js_throw_err(ctx, WGL_INVALID_VALUE);
1330 :
1331 0 : glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pix_buf);
1332 0 : return JS_UNDEFINED;
1333 : }
1334 :
1335 : /*check if this is an EVG texture*/
1336 1 : if (js_evg_get_texture_info(ctx, argv[6], &width, &height, &pixfmt, &pix_buf, &stride, &p_u, &p_v, &stride_uv, &p_a)) {
1337 1 : switch (pixfmt) {
1338 0 : case GF_PIXEL_GREYSCALE:
1339 0 : format = GL_LUMINANCE;
1340 0 : type = GL_TEXTURE_2D;
1341 0 : break;
1342 0 : case GF_PIXEL_ALPHAGREY:
1343 : case GF_PIXEL_GREYALPHA:
1344 0 : format = GL_LUMINANCE_ALPHA;
1345 0 : type = GL_UNSIGNED_BYTE;
1346 0 : break;
1347 1 : case GF_PIXEL_RGB:
1348 1 : format = GL_RGB;
1349 1 : type = GL_UNSIGNED_BYTE;
1350 1 : break;
1351 0 : case GF_PIXEL_RGBA:
1352 0 : format = GL_RGBA;
1353 0 : type = GL_UNSIGNED_BYTE;
1354 0 : break;
1355 0 : default:
1356 0 : return js_throw_err_msg(ctx, WGL_INVALID_ENUM, "[WebGL] Pixel format %s not yet mapped to texImage2D", gf_pixel_fmt_name(pixfmt) );
1357 : }
1358 1 : glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pix_buf);
1359 1 : return JS_UNDEFINED;
1360 : }
1361 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
1362 : }
1363 :
1364 605 : static JSValue wgl_useProgram(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1365 : {
1366 605 : JSValue ret_val_js = JS_UNDEFINED;
1367 : GLuint program = 0;
1368 605 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1369 605 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1370 605 : if (argc<1) return js_throw_err(ctx, WGL_INVALID_VALUE);
1371 1210 : WGL_GET_GLID(program, argv[0], WebGLProgram_class_id);
1372 605 : glUseProgram(program);
1373 605 : glc->active_program = program;
1374 605 : return ret_val_js;
1375 : }
1376 1109 : static JSValue wgl_activeTexture(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1377 : {
1378 1109 : JSValue ret_val_js = JS_UNDEFINED;
1379 1109 : u32 texture = 0;
1380 1109 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1381 1109 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1382 1109 : if (argc<1) return js_throw_err(ctx, WGL_INVALID_VALUE);
1383 1109 : WGL_GET_U32(texture, argv[0]);
1384 1109 : glActiveTexture(texture);
1385 1109 : glc->active_texture = texture;
1386 1109 : return ret_val_js;
1387 : }
1388 :
1389 5 : static JSValue wgl_createTexture(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1390 : {
1391 : JSValue ret_val_js;
1392 5 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1393 5 : if (!glc) return js_throw_err(ctx, WGL_INVALID_VALUE);
1394 :
1395 9 : if (argc && JS_IsString(argv[0])) {
1396 : GF_WebGLNamedTexture *named_tx;
1397 : const char *tx_name;
1398 : tx_name = JS_ToCString(ctx, argv[0]);
1399 4 : if (!tx_name) return js_throw_err(ctx, WGL_INVALID_VALUE);
1400 :
1401 4 : GF_SAFEALLOC(named_tx, GF_WebGLNamedTexture);
1402 4 : if (!named_tx) return js_throw_err(ctx, WGL_OUT_OF_MEMORY);
1403 4 : named_tx->par_ctx = glc;
1404 4 : named_tx->tx_name = gf_strdup(tx_name);
1405 4 : JS_FreeCString(ctx, tx_name);
1406 4 : ret_val_js = JS_NewObjectClass(ctx, NamedTexture_class_id);
1407 4 : JS_SetOpaque(ret_val_js, named_tx);
1408 4 : gf_list_add(glc->named_textures, named_tx);
1409 :
1410 4 : if ((argc>1) && JS_IsObject(argv[1])) {
1411 0 : JSValue v = JS_GetPropertyStr(ctx, argv[1], "fullrange");
1412 0 : if (JS_IsBool(v) && JS_ToBool(ctx, v))
1413 0 : named_tx->tx.fullrange = GF_TRUE;
1414 :
1415 0 : v = JS_GetPropertyStr(ctx, argv[1], "matrix");
1416 0 : if (JS_IsInteger(v)) {
1417 0 : JS_ToInt32(ctx, &named_tx->tx.mx_cicp, v);
1418 0 : } else if (JS_IsString(v)) {
1419 : const char *cicp = JS_ToCString(ctx, v);
1420 0 : named_tx->tx.mx_cicp = gf_cicp_parse_color_matrix(cicp);
1421 0 : JS_FreeCString(ctx, cicp);
1422 : }
1423 : }
1424 : } else {
1425 : GF_WebGLObject *wglo;
1426 1 : GF_SAFEALLOC(wglo, GF_WebGLObject);
1427 1 : if (!wglo) return js_throw_err(ctx, WGL_OUT_OF_MEMORY);
1428 1 : wglo->par_ctx = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1429 1 : glGenTextures(1, &wglo->gl_id);
1430 1 : ret_val_js = JS_NewObjectClass(ctx, WebGLTexture_class_id);
1431 1 : JS_SetOpaque(ret_val_js, wglo);
1432 1 : wglo->obj = JS_DupValue(ctx, ret_val_js);
1433 1 : wglo->class_id = WebGLTexture_class_id;
1434 1 : gf_list_add(wglo->par_ctx->all_objects, wglo);
1435 : }
1436 5 : return ret_val_js;
1437 : }
1438 :
1439 :
1440 1614 : static JSValue wgl_bindTexture(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1441 : {
1442 : GF_WebGLObject *tx = NULL;
1443 : GF_WebGLNamedTexture *named_tx = NULL;
1444 1614 : JSValue ret_val_js = JS_UNDEFINED;
1445 1614 : u32 target = 0;
1446 1614 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1447 1614 : if (!glc|| (argc<2)) return js_throw_err(ctx, WGL_INVALID_VALUE);
1448 1614 : glc->bound_named_texture = NULL;
1449 :
1450 1614 : WGL_GET_U32(target, argv[0]);
1451 1614 : tx = JS_GetOpaque(argv[1], WebGLTexture_class_id);
1452 1614 : if (!tx)
1453 1512 : named_tx = JS_GetOpaque(argv[1], NamedTexture_class_id);
1454 1614 : if (!tx && !named_tx) {
1455 0 : glBindTexture(target, 0);
1456 0 : return ret_val_js;
1457 : }
1458 1614 : if (tx) {
1459 102 : glBindTexture(target, tx->gl_id);
1460 102 : return ret_val_js;
1461 : }
1462 1512 : glc->bound_named_texture = named_tx;
1463 :
1464 : GL_CHECK_ERR()
1465 :
1466 : /*this happens when using regular calls instead of pck_tx.upload(ipck):
1467 : gl.bindTexture(gl.TEXTURE_2D, pck_tx);
1468 : gl.texImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, ipck);
1469 :
1470 : in this case, the shader is not yet created but we do not throw an error for the sake of compatibility with usual GL programming
1471 : */
1472 1512 : if (!named_tx->shader_attached || !glc->active_program)
1473 504 : return JS_UNDEFINED;
1474 :
1475 1008 : if (!gf_gl_txw_bind(&named_tx->tx, named_tx->tx_name, glc->active_program, glc->active_texture)) {
1476 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
1477 : }
1478 1008 : return JS_UNDEFINED;
1479 : }
1480 :
1481 10 : static JSValue wgl_getUniformLocation(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1482 : {
1483 : JSValue ret_val_js;
1484 : GLuint program = 0;
1485 : GLint uni_loc=0;
1486 : const char * name = 0;
1487 10 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1488 10 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1489 10 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
1490 20 : WGL_GET_GLID(program, argv[0], WebGLProgram_class_id);
1491 : WGL_GET_STRING(name, argv[1]);
1492 : GF_WebGLObject *wglo;
1493 :
1494 10 : uni_loc = glGetUniformLocation(program, name);
1495 10 : if (uni_loc<0) {
1496 2 : u32 i, count = gf_list_count(glc->named_textures);
1497 : uni_loc = -1;
1498 2 : for (i=0; i<count; i++) {
1499 2 : GF_WebGLNamedTexture *named_tx = gf_list_get(glc->named_textures, i);
1500 2 : if (!strcmp(named_tx->tx_name, name)) {
1501 : uni_loc = -2;
1502 : break;
1503 : }
1504 : }
1505 2 : if (uni_loc==-1)
1506 0 : return JS_NULL;
1507 : }
1508 10 : GF_SAFEALLOC(wglo, GF_WebGLObject);
1509 10 : if (!wglo) return js_throw_err(ctx, WGL_OUT_OF_MEMORY);
1510 10 : wglo->par_ctx = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1511 10 : wglo->gl_id = uni_loc;
1512 :
1513 10 : ret_val_js = JS_NewObjectClass(ctx, WebGLUniformLocation_class_id);
1514 10 : JS_SetOpaque(ret_val_js, wglo);
1515 10 : wglo->obj = JS_DupValue(ctx, ret_val_js);
1516 10 : wglo->class_id = WebGLUniformLocation_class_id;
1517 10 : gf_list_add(wglo->par_ctx->all_objects, wglo);
1518 10 : JS_FreeCString(ctx, name);
1519 10 : return ret_val_js;
1520 : }
1521 :
1522 0 : JSValue wgl_bindFramebuffer(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1523 : {
1524 0 : JSValue ret_val_js = JS_UNDEFINED;
1525 0 : u32 target = 0;
1526 : GLuint framebuffer = 0;
1527 0 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1528 0 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1529 :
1530 0 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
1531 0 : WGL_GET_U32(target, argv[0]);
1532 0 : WGL_GET_GLID(framebuffer, argv[1], WebGLFramebuffer_class_id);
1533 0 : if (framebuffer)
1534 0 : glBindFramebuffer(target, framebuffer);
1535 : else
1536 0 : glBindFramebuffer(target, glc->fbo_id);
1537 0 : return ret_val_js;
1538 : }
1539 :
1540 :
1541 605 : void webgl_pck_tex_depth_del(GF_Filter *filter, GF_FilterPid *PID, GF_FilterPacket *pck, Bool is_depth)
1542 : {
1543 : JSValue *fun = NULL;
1544 605 : GF_FilterFrameInterface *f_ifce = gf_filter_pck_get_frame_interface(pck);
1545 605 : if (!f_ifce) return;
1546 605 : GF_WebGLContext *glc = (GF_WebGLContext *)f_ifce->user_data;
1547 605 : if (!glc) return;
1548 :
1549 605 : if (is_depth)
1550 252 : fun = &glc->depth_frame_flush;
1551 : else
1552 353 : fun = &glc->tex_frame_flush;
1553 :
1554 1210 : if (!JS_IsUndefined(*fun)) {
1555 605 : JSValue ret = JS_Call(glc->ctx, *fun, JS_UNDEFINED, 0, NULL);
1556 605 : JS_FreeValue(glc->ctx, ret);
1557 :
1558 605 : JS_FreeValue(glc->ctx, *fun);
1559 605 : *fun = JS_UNDEFINED;
1560 : }
1561 : }
1562 353 : void webgl_pck_tex_del(GF_Filter *filter, GF_FilterPid *PID, GF_FilterPacket *pck)
1563 : {
1564 353 : webgl_pck_tex_depth_del(filter, PID, pck, GF_FALSE);
1565 353 : }
1566 :
1567 252 : void webgl_pck_depth_del(GF_Filter *filter, GF_FilterPid *PID, GF_FilterPacket *pck)
1568 : {
1569 252 : webgl_pck_tex_depth_del(filter, PID, pck, GF_TRUE);
1570 252 : }
1571 :
1572 605 : JSValue webgl_get_frame_interface(JSContext *ctx, int argc, JSValueConst *argv, gf_fsess_packet_destructor *pck_del, GF_FilterFrameInterface **f_ifce)
1573 : {
1574 : JSValue *frame_flush_fun = NULL;
1575 : GF_WebGLContext *glc;
1576 605 : if (argc<2) return js_throw_err(ctx, WGL_INVALID_VALUE);
1577 605 : if (!JS_IsFunction(ctx, argv[1])) return js_throw_err(ctx, WGL_INVALID_VALUE);
1578 :
1579 605 : glc = JS_GetOpaque(argv[0], WebGLRenderingContextBase_class_id);
1580 605 : if (!glc) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1581 :
1582 605 : if ((argc>2) && JS_ToBool(ctx, argv[2]) ) {
1583 252 : if (glc->actual_attrs.depth != WGL_DEPTH_TEXTURE)
1584 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
1585 :
1586 252 : *pck_del = webgl_pck_depth_del;
1587 252 : frame_flush_fun = &glc->depth_frame_flush;
1588 252 : *f_ifce = &glc->depth_f_ifce;
1589 : } else {
1590 353 : *pck_del = webgl_pck_tex_del;
1591 353 : frame_flush_fun = &glc->tex_frame_flush;
1592 353 : *f_ifce = &glc->tex_f_ifce;
1593 : }
1594 1210 : if (!JS_IsUndefined(*frame_flush_fun))
1595 0 : return js_throw_err(ctx, WGL_INVALID_OPERATION);
1596 :
1597 : JS_FreeValue(ctx, *frame_flush_fun);
1598 605 : glc->tex_frame_flush = JS_UNDEFINED;
1599 605 : if (JS_IsFunction(ctx, argv[1])) {
1600 605 : *frame_flush_fun = JS_DupValue(ctx, argv[1]);
1601 : }
1602 605 : return JS_TRUE;
1603 : }
1604 :
1605 706 : static GF_Err webgl_get_texture(GF_FilterFrameInterface *ifce, u32 plane_idx, u32 *gl_tex_format, u32 *gl_tex_id, GF_Matrix *texcoordmatrix)
1606 : {
1607 706 : GF_WebGLContext *glc = ifce->user_data;
1608 706 : if (!glc) return GF_BAD_PARAM;
1609 706 : if (plane_idx) return GF_BAD_PARAM;
1610 353 : *gl_tex_id = glc->tex_id;
1611 353 : *gl_tex_format = GL_TEXTURE_2D;
1612 353 : if (texcoordmatrix)
1613 353 : gf_mx_add_scale(texcoordmatrix, FIX_ONE, -FIX_ONE, FIX_ONE);
1614 : return GF_OK;
1615 : }
1616 504 : static GF_Err webgl_get_depth(GF_FilterFrameInterface *ifce, u32 plane_idx, u32 *gl_tex_format, u32 *gl_tex_id, GF_Matrix *texcoordmatrix)
1617 : {
1618 504 : GF_WebGLContext *glc = ifce->user_data;
1619 504 : if (!glc) return GF_BAD_PARAM;
1620 504 : if (plane_idx) return GF_BAD_PARAM;
1621 252 : *gl_tex_id = glc->depth_id;
1622 252 : *gl_tex_format = GL_TEXTURE_2D;
1623 252 : if (texcoordmatrix)
1624 252 : gf_mx_add_scale(texcoordmatrix, FIX_ONE, -FIX_ONE, FIX_ONE);
1625 : return GF_OK;
1626 : }
1627 5 : static JSValue webgl_setup_fbo(JSContext *ctx, GF_WebGLContext *glc, u32 width, u32 height)
1628 : {
1629 5 : glc->width = width;
1630 5 : glc->height = height;
1631 :
1632 5 : if (glc->creation_attrs.primary) {
1633 0 : return JS_UNDEFINED;
1634 : }
1635 : /*create fbo*/
1636 5 : glGenTextures(1, &glc->tex_id);
1637 5 : if (!glc->tex_id) {
1638 0 : gf_free(glc);
1639 0 : return js_throw_err_msg(ctx, GF_IO_ERR, "Failed to create OpenGL texture %d", glGetError() );
1640 : }
1641 5 : glBindTexture(GL_TEXTURE_2D, glc->tex_id);
1642 5 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1643 5 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1644 5 : glTexImage2D(GL_TEXTURE_2D, 0, glc->actual_attrs.alpha ? GL_RGBA : GL_RGB, width, height, 0, glc->actual_attrs.alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, NULL);
1645 :
1646 5 : glGenFramebuffers(1, &glc->fbo_id);
1647 5 : if (!glc->fbo_id) {
1648 0 : glDeleteTextures(1, &glc->tex_id);
1649 0 : gf_free(glc);
1650 0 : return js_throw_err_msg(ctx, GF_IO_ERR, "Failed to create OpenGL Framebuffer %d", glGetError() );
1651 : }
1652 5 : glBindFramebuffer(GL_FRAMEBUFFER, glc->fbo_id);
1653 5 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glc->tex_id, 0);
1654 :
1655 5 : if (glc->actual_attrs.depth != WGL_DEPTH_NO) {
1656 5 : if (glc->actual_attrs.depth==WGL_DEPTH_TEXTURE) {
1657 2 : glGenTextures(1, &glc->depth_id);
1658 2 : if (!glc->depth_id) {
1659 0 : glDeleteTextures(1, &glc->tex_id);
1660 0 : glDeleteFramebuffers(1, &glc->fbo_id);
1661 0 : gf_free(glc);
1662 0 : return js_throw_err_msg(ctx, GF_IO_ERR, "Failed to create OpenGL depth texture %d", glGetError() );
1663 : }
1664 2 : glBindTexture(GL_TEXTURE_2D, glc->depth_id);
1665 2 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1666 2 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1667 2 : glTexImage2D(GL_TEXTURE_2D, 0,
1668 : #if defined(GPAC_CONFIG_IOS) || defined(GPAC_CONFIG_ANDROID)
1669 : GL_DEPTH_COMPONENT16,
1670 : #else
1671 : GL_DEPTH_COMPONENT24,
1672 : #endif
1673 : width, height, 0, GL_DEPTH_COMPONENT, GL_INT, NULL);
1674 :
1675 2 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, glc->depth_id, 0);
1676 :
1677 : } else {
1678 3 : glGenRenderbuffers(1, &glc->depth_id);
1679 3 : if (!glc->depth_id) {
1680 0 : glDeleteTextures(1, &glc->tex_id);
1681 0 : glDeleteFramebuffers(1, &glc->fbo_id);
1682 0 : gf_free(glc);
1683 0 : return js_throw_err_msg(ctx, GF_IO_ERR, "Failed to create OpenGL depth renderbuffer %d", glGetError() );
1684 : }
1685 :
1686 3 : glBindRenderbuffer(GL_RENDERBUFFER, glc->depth_id);
1687 : #if defined(GPAC_CONFIG_IOS) || defined(GPAC_CONFIG_ANDROID)
1688 : glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
1689 : #else
1690 3 : glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
1691 : #endif
1692 3 : glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, glc->depth_id);
1693 : }
1694 : }
1695 5 : GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1696 5 : switch (status) {
1697 : case GL_FRAMEBUFFER_COMPLETE:
1698 : break;
1699 0 : default:
1700 0 : glDeleteTextures(1, &glc->tex_id);
1701 0 : glDeleteRenderbuffers(1, &glc->depth_id);
1702 0 : glDeleteFramebuffers(1, &glc->fbo_id);
1703 0 : gf_free(glc);
1704 0 : return js_throw_err_msg(ctx, GF_IO_ERR, "Failed to initialize OpenGL FBO: %08x", status );
1705 : }
1706 :
1707 5 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
1708 5 : return JS_UNDEFINED;
1709 : }
1710 3 : static JSValue webgl_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
1711 : {
1712 : JSValue res;
1713 : u32 idx=0;
1714 3 : u32 width = 0;
1715 3 : u32 height = 0;
1716 : GF_Err e;
1717 : GF_WebGLContext *glc;
1718 : JSValue v;
1719 : Bool fake_canvas = GF_FALSE;
1720 :
1721 6 : if (argc && JS_IsObject(argv[0])) {
1722 0 : v = JS_GetPropertyStr(ctx, argv[0], "width");
1723 0 : JS_ToInt32(ctx, &width, v);
1724 : JS_FreeValue(ctx, v);
1725 :
1726 0 : v = JS_GetPropertyStr(ctx, argv[0], "height");
1727 0 : JS_ToInt32(ctx, &height, v);
1728 : JS_FreeValue(ctx, v);
1729 : idx=1;
1730 : fake_canvas = GF_TRUE;
1731 3 : } else if (argc>=2) {
1732 3 : WGL_GET_S32(width, argv[0]);
1733 3 : WGL_GET_S32(height, argv[1]);
1734 : idx=2;
1735 : }
1736 3 : if (!width || !height) {
1737 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "Invalid width/height %dx%d while creating OpenGL context", width, height);
1738 : }
1739 :
1740 3 : e = jsf_request_opengl(ctx);
1741 3 : if (e) return js_throw_err_msg(ctx, e, "Failed to load OpenGL");
1742 3 : GF_SAFEALLOC(glc, GF_WebGLContext);
1743 3 : if (!glc) return js_throw_err_msg(ctx, GF_OUT_OF_MEM, "Failed to allocate OpenGL context");
1744 3 : glc->creation_attrs.alpha = GF_TRUE;
1745 3 : glc->creation_attrs.depth = WGL_DEPTH_YES;
1746 3 : glc->creation_attrs.antialias = GF_TRUE;
1747 3 : glc->creation_attrs.premultipliedAlpha = GF_TRUE;
1748 5 : if ((argc>(s32)idx) && JS_IsObject(argv[idx])) {
1749 : #define GET_BOOL(_opt)\
1750 : v = JS_GetPropertyStr(ctx, argv[idx], #_opt);\
1751 : if (!JS_IsUndefined(v)) glc->creation_attrs._opt = JS_ToBool(ctx, v);\
1752 : JS_FreeValue(ctx, v);\
1753 :
1754 4 : GET_BOOL(alpha)
1755 4 : GET_BOOL(stencil)
1756 4 : GET_BOOL(antialias)
1757 4 : GET_BOOL(premultipliedAlpha)
1758 4 : GET_BOOL(preserveDrawingBuffer)
1759 4 : GET_BOOL(failIfMajorPerformanceCaveat)
1760 4 : GET_BOOL(desynchronized)
1761 4 : GET_BOOL(primary)
1762 : #undef GET_BOOL
1763 :
1764 2 : v = JS_GetPropertyStr(ctx, argv[idx], "depth");
1765 2 : if (!JS_IsUndefined(v)) {
1766 2 : if (JS_IsString(v)) {
1767 : const char *depth_mode = JS_ToCString(ctx, v);
1768 1 : if (!strcmp(depth_mode, "false") || !strcmp(depth_mode, "no"))
1769 0 : glc->creation_attrs.depth = WGL_DEPTH_NO;
1770 1 : else if (!strcmp(depth_mode, "true") || !strcmp(depth_mode, "yes"))
1771 0 : glc->creation_attrs.depth = WGL_DEPTH_YES;
1772 1 : else if (!strcmp(depth_mode, "texture"))
1773 1 : glc->creation_attrs.depth = WGL_DEPTH_TEXTURE;
1774 1 : JS_FreeCString(ctx, depth_mode);
1775 : } else {
1776 1 : glc->creation_attrs.depth = JS_ToBool(ctx, v) ? WGL_DEPTH_YES : WGL_DEPTH_NO;
1777 : }
1778 : }
1779 : JS_FreeValue(ctx, v);
1780 :
1781 2 : if (glc->creation_attrs.primary && (glc->creation_attrs.depth == WGL_DEPTH_TEXTURE)) {
1782 0 : gf_free(glc);
1783 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "Cannot setup WebGL context as primary and output depth texture at the same time");
1784 : }
1785 :
1786 2 : v = JS_GetPropertyStr(ctx, argv[idx], "powerPreference");
1787 2 : if (!JS_IsUndefined(v)) {
1788 : const char *str = JS_ToCString(ctx, v);
1789 0 : if (str && !strcmp(str, "low-power")) glc->creation_attrs.powerPreference = WGL_POWER_LOWPOWER;
1790 0 : else if (str && !strcmp(str, "high-performance")) glc->creation_attrs.powerPreference = WGL_POWER_HIGHPERF;
1791 : }
1792 : JS_FreeValue(ctx, v);
1793 : }
1794 3 : glc->actual_attrs = glc->creation_attrs;
1795 :
1796 3 : res = webgl_setup_fbo(ctx, glc, width, height);
1797 3 : if (!JS_IsUndefined(res)) return res;
1798 :
1799 : //not supported
1800 3 : glc->actual_attrs.preserveDrawingBuffer = GF_FALSE;
1801 :
1802 3 : v = JS_NewObjectClass(ctx, WebGLRenderingContextBase_class_id);
1803 3 : JS_SetOpaque(v, glc);
1804 :
1805 3 : glc->tex_f_ifce.flags = GF_FRAME_IFCE_BLOCKING;
1806 3 : if (glc->creation_attrs.primary)
1807 0 : glc->tex_f_ifce.flags |= GF_FRAME_IFCE_MAIN_GLFB;
1808 3 : glc->tex_f_ifce.get_gl_texture = webgl_get_texture;
1809 3 : glc->tex_f_ifce.user_data = glc;
1810 3 : glc->tex_frame_flush = JS_UNDEFINED;
1811 :
1812 3 : glc->depth_f_ifce.flags = GF_FRAME_IFCE_BLOCKING;
1813 3 : glc->depth_f_ifce.get_gl_texture = webgl_get_depth;
1814 3 : glc->depth_f_ifce.user_data = glc;
1815 3 : glc->depth_frame_flush = JS_UNDEFINED;
1816 :
1817 3 : if (fake_canvas) {
1818 0 : glc->canvas = JS_DupValue(ctx, argv[0]);
1819 : } else {
1820 3 : glc->canvas = JS_NewObject(ctx);
1821 6 : JS_SetPropertyStr(ctx, glc->canvas, "width", JS_NewInt32(ctx, width));
1822 6 : JS_SetPropertyStr(ctx, glc->canvas, "height", JS_NewInt32(ctx, height));
1823 : }
1824 6 : JS_SetPropertyStr(ctx, glc->canvas, "clientWidth", JS_NewInt32(ctx, width));
1825 6 : JS_SetPropertyStr(ctx, glc->canvas, "clientHeight", JS_NewInt32(ctx, height));
1826 3 : glc->ctx = ctx;
1827 3 : glc->all_objects = gf_list_new();
1828 3 : glc->named_textures = gf_list_new();
1829 :
1830 3 : return v;
1831 : }
1832 :
1833 1214 : static JSValue wgl_activate_gl(JSContext *ctx, GF_WebGLContext *glc, Bool activate)
1834 : {
1835 1214 : if (activate) {
1836 : u32 i, count;
1837 : //clear error
1838 607 : glGetError();
1839 607 : jsf_set_gl_active(ctx);
1840 :
1841 607 : if (glc->creation_attrs.primary) {
1842 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
1843 : } else {
1844 607 : glBindFramebuffer(GL_FRAMEBUFFER, glc->fbo_id);
1845 :
1846 607 : GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1847 607 : switch (status) {
1848 : case GL_FRAMEBUFFER_COMPLETE:
1849 : break;
1850 0 : default:
1851 0 : return js_throw_err_msg(ctx, GF_IO_ERR, "Failed to bind OpenGL FBO: %X", status );
1852 : }
1853 : }
1854 :
1855 607 : count = gf_list_count(glc->named_textures);
1856 1619 : for (i=0; i<count; i++) {
1857 1012 : GF_WebGLNamedTexture *named_tx = gf_list_get(glc->named_textures, i);
1858 1012 : named_tx->tx.frame_ifce = NULL;
1859 : }
1860 607 : glc->active_texture = 0;
1861 607 : glc->active_program = 0;
1862 607 : glc->bound_named_texture = NULL;
1863 : } else {
1864 : #if!defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2)
1865 607 : glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
1866 : #endif
1867 607 : glBindBuffer(GL_ARRAY_BUFFER, 0);
1868 607 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1869 607 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
1870 :
1871 607 : glActiveTexture(GL_TEXTURE0);
1872 607 : glBindTexture(GL_TEXTURE_2D, 0);
1873 607 : glDisable(GL_TEXTURE_2D);
1874 : //clear error
1875 607 : glGetError();
1876 : }
1877 1214 : return JS_UNDEFINED;
1878 : }
1879 1210 : static JSValue wgl_activate(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1880 : {
1881 : Bool activate;
1882 1210 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1883 1210 : if (!glc|| (argc<1)) return js_throw_err(ctx, WGL_INVALID_VALUE);
1884 1210 : WGL_GET_BOOL(activate, argv[0]);
1885 1210 : return wgl_activate_gl(ctx, glc, activate);
1886 : }
1887 :
1888 2 : static JSValue wgl_resize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1889 : {
1890 : JSValue res;
1891 : u32 width, height;
1892 2 : GF_WebGLContext *glc = JS_GetOpaque(this_val, WebGLRenderingContextBase_class_id);
1893 2 : if (!glc|| (argc<2)) return js_throw_err(ctx, WGL_INVALID_VALUE);
1894 2 : WGL_GET_U32(width, argv[0]);
1895 2 : WGL_GET_U32(height, argv[1]);
1896 2 : if (!width || !height) return js_throw_err(ctx, WGL_INVALID_VALUE);
1897 :
1898 2 : res = wgl_activate_gl(ctx, glc, GF_FALSE);
1899 2 : if (!JS_IsUndefined(res)) return res;
1900 :
1901 2 : glDeleteTextures(1, &glc->tex_id);
1902 2 : glc->tex_id = 0;
1903 2 : glDeleteRenderbuffers(1, &glc->depth_id);
1904 2 : glc->depth_id = 0;
1905 2 : glDeleteFramebuffers(1, &glc->fbo_id);
1906 2 : glc->fbo_id = 0;
1907 :
1908 2 : res = webgl_setup_fbo(ctx, glc, width, height);
1909 2 : if (!JS_IsUndefined(res)) return res;
1910 :
1911 2 : return wgl_activate_gl(ctx, glc, GF_TRUE);
1912 : }
1913 :
1914 :
1915 :
1916 2 : static JSValue wgl_named_tx_upload(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1917 : {
1918 2 : GF_WebGLNamedTexture *named_tx = JS_GetOpaque(this_val, NamedTexture_class_id);
1919 2 : if (!named_tx|| (argc<1)) return js_throw_err(ctx, WGL_INVALID_VALUE);
1920 2 : return wgl_named_texture_upload(ctx, argv[0], named_tx);
1921 : }
1922 2 : static JSValue wgl_named_tx_reconfigure(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1923 : {
1924 2 : GF_WebGLNamedTexture *named_tx = JS_GetOpaque(this_val, NamedTexture_class_id);
1925 2 : if (!named_tx) return js_throw_err(ctx, WGL_INVALID_VALUE);
1926 :
1927 2 : gf_gl_txw_reset(&named_tx->tx);
1928 :
1929 2 : named_tx->shader_attached = GF_FALSE;
1930 2 : return JS_UNDEFINED;
1931 : }
1932 :
1933 :
1934 : /*GPAC extensions*/
1935 : static const JSCFunctionListEntry webgl_funcs[] =
1936 : {
1937 : JS_CFUNC_DEF("activate", 0, wgl_activate),
1938 : JS_CFUNC_DEF("resize", 0, wgl_resize),
1939 : };
1940 :
1941 : enum
1942 : {
1943 : WGL_GPTX_NB_TEXTURES = 0,
1944 : WGL_GPTX_GLTX_IN,
1945 : WGL_GPTX_NAME,
1946 : WGL_GPTX_PBO,
1947 : };
1948 :
1949 504 : static JSValue wgl_named_tx_getProperty(JSContext *ctx, JSValueConst obj, int magic)
1950 : {
1951 504 : GF_WebGLNamedTexture *named_tx = JS_GetOpaque(obj, NamedTexture_class_id);
1952 504 : if (!named_tx) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1953 :
1954 504 : switch (magic) {
1955 504 : case WGL_GPTX_NB_TEXTURES:
1956 504 : return JS_NewInt32(ctx, named_tx->tx.nb_textures);
1957 0 : case WGL_GPTX_GLTX_IN:
1958 0 : return named_tx->tx.internal_textures ? JS_FALSE : JS_TRUE;
1959 0 : case WGL_GPTX_NAME:
1960 0 : return JS_NewString(ctx, named_tx->tx_name);
1961 0 : case WGL_GPTX_PBO:
1962 0 : return (named_tx->tx.pbo_state>GF_GL_PBO_NONE) ? JS_TRUE : JS_FALSE;
1963 : }
1964 0 : return JS_UNDEFINED;
1965 : }
1966 :
1967 2 : static JSValue wgl_named_tx_setProperty(JSContext *ctx, JSValueConst obj, JSValueConst value, int magic)
1968 : {
1969 2 : GF_WebGLNamedTexture *named_tx = JS_GetOpaque(obj, NamedTexture_class_id);
1970 2 : if (!named_tx) return js_throw_err(ctx, WGL_INVALID_OPERATION);
1971 :
1972 2 : switch (magic) {
1973 2 : case WGL_GPTX_PBO:
1974 2 : named_tx->tx.pbo_state = JS_ToBool(ctx, value) ? GF_GL_PBO_BOTH : GF_GL_PBO_NONE;
1975 2 : break;
1976 : }
1977 2 : return JS_UNDEFINED;
1978 : }
1979 : /*GPAC extensions*/
1980 : static const JSCFunctionListEntry webgl_named_tx_funcs[] =
1981 : {
1982 : JS_CGETSET_MAGIC_DEF("nb_textures", wgl_named_tx_getProperty, NULL, WGL_GPTX_NB_TEXTURES),
1983 : JS_CGETSET_MAGIC_DEF("is_gl_input", wgl_named_tx_getProperty, wgl_named_tx_setProperty, WGL_GPTX_GLTX_IN),
1984 : JS_CGETSET_MAGIC_DEF("name", wgl_named_tx_getProperty, wgl_named_tx_setProperty, WGL_GPTX_NAME),
1985 : JS_CGETSET_MAGIC_DEF("pbo", wgl_named_tx_getProperty, wgl_named_tx_setProperty, WGL_GPTX_PBO),
1986 : JS_CFUNC_DEF("reconfigure", 0, wgl_named_tx_reconfigure),
1987 : JS_CFUNC_DEF("upload", 0, wgl_named_tx_upload),
1988 : };
1989 :
1990 :
1991 3 : static int js_webgl_load_module(JSContext *c, JSModuleDef *m)
1992 : {
1993 : JSValue ctor;
1994 : JSValue proto;
1995 3 : JSRuntime *rt = JS_GetRuntime(c);
1996 :
1997 3 : if (!WebGLRenderingContextBase_class_id) {
1998 : #define INITCLASS(_name)\
1999 : JS_NewClassID(& _name##_class_id);\
2000 : JS_NewClass(rt, _name##_class_id, & _name##_class);\
2001 :
2002 3 : INITCLASS(WebGLRenderingContextBase)
2003 3 : INITCLASS(WebGLProgram)
2004 3 : INITCLASS(WebGLShader)
2005 3 : INITCLASS(WebGLBuffer)
2006 3 : INITCLASS(WebGLFramebuffer)
2007 3 : INITCLASS(WebGLRenderbuffer)
2008 3 : INITCLASS(WebGLTexture)
2009 3 : INITCLASS(WebGLUniformLocation)
2010 3 : INITCLASS(NamedTexture)
2011 : #undef INITCLASS
2012 :
2013 : }
2014 3 : proto = JS_NewObject(c);
2015 3 : JS_SetPropertyFunctionList(c, proto, webgl_funcs, countof(webgl_funcs));
2016 3 : JS_SetPropertyFunctionList(c, proto, WebGLRenderingContextBase_funcs, countof(WebGLRenderingContextBase_funcs));
2017 3 : JS_SetClassProto(c, WebGLRenderingContextBase_class_id, proto);
2018 :
2019 3 : proto = JS_NewObject(c);
2020 3 : JS_SetPropertyFunctionList(c, proto, webgl_named_tx_funcs, countof(webgl_named_tx_funcs));
2021 3 : JS_SetClassProto(c, NamedTexture_class_id, proto);
2022 :
2023 : /*export constructors*/
2024 3 : ctor = JS_NewCFunction2(c, webgl_constructor, "WebGLContext", 1, JS_CFUNC_constructor, 0);
2025 3 : JS_SetModuleExport(c, m, "WebGLContext", ctor);
2026 3 : return 0;
2027 : }
2028 :
2029 64 : void qjs_module_init_webgl(JSContext *ctx)
2030 : {
2031 : JSModuleDef *m;
2032 64 : m = JS_NewCModule(ctx, "webgl", js_webgl_load_module);
2033 64 : if (!m) return;
2034 :
2035 64 : JS_AddModuleExport(ctx, m, "WebGLContext");
2036 : }
2037 :
2038 : #else
2039 : #include "../scenegraph/qjs_common.h"
2040 : void qjs_module_init_webgl(JSContext *ctx)
2041 : {
2042 : }
2043 : #endif // !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
2044 :
2045 :
2046 : #endif //GPAC_HAS_QJS
2047 :
|