LCOV - code coverage report
Current view: top level - jsmods - webgl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 810 1117 72.5 %
Date: 2021-04-29 23:48:07 Functions: 63 66 95.5 %

          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, &params);
     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, &params);
     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, &params);
     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, &params);
     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, &params);
     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, &params);
     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             : 

Generated by: LCOV version 1.13