This source file includes following definitions.
- gf_sc_load_opengl_extensions
 
- visual_3d_compile_shader
 
- visual_3d_shader_from_source_file
 
- visual_3d_shader_with_flags
 
- visual_3d_set_tx_planes
 
- visual_3d_init_stereo_shaders
 
- gf_glGetUniformLocation
 
- gf_glGetAttribLocation
 
- gf_glQueryProgram
 
- gf_glQueryUniform
 
- gf_glQueryAttrib
 
- gf_glQueryUniforms
 
- gf_glQueryAttributes
 
- visual_3d_init_generic_shaders
 
- visual_3d_init_shaders
 
- visual_3d_reset_graphics
 
- visual_3d_set_clipper_scissor
 
- visual_3d_load_matrix_shaders
 
- visual_3d_init_autostereo
 
- visual_3d_end_auto_stereo_pass
 
- visual_3d_setup_quality
 
- visual_3d_setup
 
- visual_3d_set_background_state
 
- visual_3d_enable_antialias
 
- visual_3d_enable_depth_buffer
 
- visual_3d_set_viewport
 
- visual_3d_set_scissor
 
- visual_3d_clear_depth
 
- visual_3d_draw_aabb_node
 
- visual_3d_matrix_load
 
- visual_3d_update_matrices
 
- visual_3d_set_clippers
 
- visual_3d_reset_clippers
 
- visual_3d_reset_lights
 
- visual_3d_set_lights
 
- visual_3d_enable_fog
 
- visual_3d_do_draw_mesh
 
- visual_3d_bind_buffer
 
- visual_3d_update_matrices_shaders
 
- visual_3d_set_lights_shaders
 
- visual_3d_set_fog_shaders
 
- visual_3d_set_clippers_shaders
 
- visual_3d_draw_mesh_shader_only
 
- visual_3d_draw_mesh
 
- visual_3d_set_debug_color
 
- visual_3d_draw_normals
 
- visual_3d_draw_aabb_nodeBounds
 
- visual_3d_draw_bbox_ex
 
- visual_3d_draw_bbox
 
- visual_3d_draw_bounds
 
- visual_3d_mesh_paint
 
- visual_3d_mesh_hatch
 
- visual_3d_mesh_strike
 
- visual_3d_clear
 
- visual_3d_fill_rect
 
- compositor_3d_get_screen_buffer
 
- compositor_3d_release_screen_buffer
 
- compositor_3d_get_offscreen_buffer
 
- visual_3d_point_sprite
 
#include "visual_manager.h"
#include "texturing.h"
#ifndef GPAC_DISABLE_3D
#include <gpac/options.h>
#include <gpac/nodes_mpeg4.h>
#include "gl_inc.h"
#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
# if defined(GPAC_USE_TINYGL)
#  pragma comment(lib, "TinyGL")
# elif defined(GPAC_USE_GLES1X)
#  if 0
#   pragma message("Using OpenGL-ES Common Lite Profile")
#   pragma comment(lib, "libGLES_CL")
#       define GL_ES_CL_PROFILE
#  else
#   pragma message("Using OpenGL-ES Common Profile")
#   pragma comment(lib, "libGLES_CM")
#  endif
# elif defined(GPAC_USE_GLES2)
#  pragma comment(lib, "libGLESv2")
# else
#  pragma comment(lib, "opengl32")
# endif
#ifdef GPAC_HAS_GLU
#  pragma comment(lib, "glu32")
#endif
#endif
#if defined(GL_MAX_CLIP_PLANES) && defined(__SYMBIAN32__)
#undef GL_MAX_CLIP_PLANES
#endif
#define CHECK_GL_EXT(name) ((strstr(ext, name) != NULL) ? 1 : 0)
#ifdef LOAD_GL_1_3
GLDECL_STATIC(glActiveTexture);
GLDECL_STATIC(glClientActiveTexture);
GLDECL_STATIC(glBlendEquation);
#endif 
#ifdef LOAD_GL_1_4
GLDECL_STATIC(glPointParameterf);
GLDECL_STATIC(glPointParameterfv);
#endif 
#ifdef LOAD_GL_1_5
GLDECL_STATIC(glGenBuffers);
GLDECL_STATIC(glDeleteBuffers);
GLDECL_STATIC(glBindBuffer);
GLDECL_STATIC(glBufferData);
GLDECL_STATIC(glBufferSubData);
GLDECL_STATIC(glMapBuffer);
GLDECL_STATIC(glUnmapBuffer);
#endif 
#ifdef LOAD_GL_2_0
GLDECL_STATIC(glCreateProgram);
GLDECL_STATIC(glDeleteProgram);
GLDECL_STATIC(glLinkProgram);
GLDECL_STATIC(glUseProgram);
GLDECL_STATIC(glCreateShader);
GLDECL_STATIC(glDeleteShader);
GLDECL_STATIC(glShaderSource);
GLDECL_STATIC(glCompileShader);
GLDECL_STATIC(glAttachShader);
GLDECL_STATIC(glDetachShader);
GLDECL_STATIC(glGetShaderiv);
GLDECL_STATIC(glGetInfoLogARB);
GLDECL_STATIC(glGetUniformLocation);
GLDECL_STATIC(glUniform1f);
GLDECL_STATIC(glUniform2f);
GLDECL_STATIC(glUniform3f);
GLDECL_STATIC(glUniform4f);
GLDECL_STATIC(glUniform1i);
GLDECL_STATIC(glUniform2i);
GLDECL_STATIC(glUniform3i);
GLDECL_STATIC(glUniform4i);
GLDECL_STATIC(glUniform1fv);
GLDECL_STATIC(glUniform2fv);
GLDECL_STATIC(glUniform3fv);
GLDECL_STATIC(glUniform4fv);
GLDECL_STATIC(glUniform1iv);
GLDECL_STATIC(glUniform2iv);
GLDECL_STATIC(glUniform3iv);
GLDECL_STATIC(glUniform4iv);
GLDECL_STATIC(glUniformMatrix2fv);
GLDECL_STATIC(glUniformMatrix3fv);
GLDECL_STATIC(glUniformMatrix4fv);
GLDECL_STATIC(glUniformMatrix2x3fv);
GLDECL_STATIC(glUniformMatrix3x2fv);
GLDECL_STATIC(glUniformMatrix2x4fv);
GLDECL_STATIC(glUniformMatrix4x2fv);
GLDECL_STATIC(glUniformMatrix3x4fv);
GLDECL_STATIC(glUniformMatrix4x3fv);
GLDECL_STATIC(glGetProgramiv);
GLDECL_STATIC(glGetProgramInfoLog);
GLDECL_STATIC(glGetAttribLocation);
#ifndef GPAC_ANDROID
GLDECL_STATIC(glEnableVertexAttribArray);
GLDECL_STATIC(glDisableVertexAttribArray);
GLDECL_STATIC(glVertexAttribPointer);
GLDECL_STATIC(glVertexAttribIPointer);
#endif
#endif 
void gf_sc_load_opengl_extensions(GF_Compositor *compositor, Bool has_gl_context)
{
#ifdef GPAC_USE_TINYGL
        
        compositor->gl_caps.rect_texture = 1;
        compositor->gl_caps.npot_texture = 1;
#else
        const char *ext = NULL;
        if (compositor->visual->type_3d || compositor->hybrid_opengl)
                ext = (const char *) glGetString(GL_EXTENSIONS);
        if (!ext) ext = gf_cfg_get_key(compositor->user->config, "Compositor", "OpenGLExtensions");
        
        else if (gf_cfg_get_key(compositor->user->config, "Compositor", "OpenGLExtensions")==NULL)
                gf_cfg_set_key(compositor->user->config, "Compositor", "OpenGLExtensions", ext ? ext : "None");
        if (!ext) return;
        memset(&compositor->gl_caps, 0, sizeof(GLCaps));
        if (CHECK_GL_EXT("GL_ARB_multisample") || CHECK_GL_EXT("GLX_ARB_multisample") || CHECK_GL_EXT("WGL_ARB_multisample"))
                compositor->gl_caps.multisample = 1;
        if (CHECK_GL_EXT("GL_ARB_texture_non_power_of_two"))
                compositor->gl_caps.npot_texture = 1;
        if (CHECK_GL_EXT("GL_EXT_abgr"))
                compositor->gl_caps.abgr_texture = 1;
        if (CHECK_GL_EXT("GL_EXT_bgra"))
                compositor->gl_caps.bgra_texture = 1;
        if (CHECK_GL_EXT("GL_ARB_point_parameters")) {
                compositor->gl_caps.point_sprite = 1;
                if (CHECK_GL_EXT("GL_ARB_point_sprite") || CHECK_GL_EXT("GL_NV_point_sprite")) {
                        compositor->gl_caps.point_sprite = 2;
                }
        }
#ifdef GPAC_USE_GLES2
        compositor->gl_caps.vbo = 1;
#else
        if (CHECK_GL_EXT("GL_ARB_vertex_buffer_object")) {
                compositor->gl_caps.vbo = 1;
        }
#endif
#ifndef GPAC_USE_GLES1X
        if (CHECK_GL_EXT("GL_EXT_texture_rectangle") || CHECK_GL_EXT("GL_NV_texture_rectangle")) {
                compositor->gl_caps.rect_texture = 1;
                if (CHECK_GL_EXT("GL_MESA_ycbcr_texture")) compositor->gl_caps.yuv_texture = YCBCR_MESA;
                else if (CHECK_GL_EXT("GL_APPLE_ycbcr_422")) compositor->gl_caps.yuv_texture = YCBCR_422_APPLE;
        }
#endif
        if (CHECK_GL_EXT("EXT_unpack_subimage") ) {
                compositor->gl_caps.gles2_unpack = 1;
        }
        
        if (!has_gl_context) return;
        
        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &compositor->gl_caps.max_texture_size);
#ifdef LOAD_GL_1_3
        if (CHECK_GL_EXT("GL_ARB_multitexture")) {
                GET_GLFUN(glActiveTexture);
                GET_GLFUN(glClientActiveTexture);
        }
        GET_GLFUN(glBlendEquation);
#endif
#ifdef LOAD_GL_1_4
        if (compositor->gl_caps.point_sprite) {
                GET_GLFUN(glPointParameterf);
                GET_GLFUN(glPointParameterfv);
        }
#endif
#ifdef LOAD_GL_1_5
        if (compositor->gl_caps.vbo) {
                GET_GLFUN(glGenBuffers);
                GET_GLFUN(glDeleteBuffers);
                GET_GLFUN(glBindBuffer);
                GET_GLFUN(glBufferData);
                GET_GLFUN(glBufferSubData);
        }
        if (CHECK_GL_EXT("GL_ARB_pixel_buffer_object")) {
                GET_GLFUN(glMapBuffer);
                GET_GLFUN(glUnmapBuffer);
                compositor->gl_caps.pbo=1;
        }
#endif
#ifdef LOAD_GL_2_0
        GET_GLFUN(glCreateProgram);
        if (glCreateProgram != NULL) {
                GET_GLFUN(glDeleteProgram);
                GET_GLFUN(glLinkProgram);
                GET_GLFUN(glUseProgram);
                GET_GLFUN(glCreateShader);
                GET_GLFUN(glDeleteShader);
                GET_GLFUN(glShaderSource);
                GET_GLFUN(glCompileShader);
                GET_GLFUN(glAttachShader);
                GET_GLFUN(glDetachShader);
                GET_GLFUN(glGetShaderiv);
                GET_GLFUN(glGetInfoLogARB);
                GET_GLFUN(glGetUniformLocation);
                GET_GLFUN(glUniform1f);
                GET_GLFUN(glUniform2f);
                GET_GLFUN(glUniform3f);
                GET_GLFUN(glUniform4f);
                GET_GLFUN(glUniform1i);
                GET_GLFUN(glUniform2i);
                GET_GLFUN(glUniform3i);
                GET_GLFUN(glUniform4i);
                GET_GLFUN(glUniform1fv);
                GET_GLFUN(glUniform2fv);
                GET_GLFUN(glUniform3fv);
                GET_GLFUN(glUniform4fv);
                GET_GLFUN(glUniform1iv);
                GET_GLFUN(glUniform2iv);
                GET_GLFUN(glUniform3iv);
                GET_GLFUN(glUniform4iv);
                GET_GLFUN(glUniformMatrix2fv);
                GET_GLFUN(glUniformMatrix3fv);
                GET_GLFUN(glUniformMatrix4fv);
                GET_GLFUN(glUniformMatrix2x3fv);
                GET_GLFUN(glUniformMatrix3x2fv);
                GET_GLFUN(glUniformMatrix2x4fv);
                GET_GLFUN(glUniformMatrix4x2fv);
                GET_GLFUN(glUniformMatrix3x4fv);
                GET_GLFUN(glUniformMatrix4x3fv);
                GET_GLFUN(glGetProgramiv);
                GET_GLFUN(glGetProgramInfoLog);
                compositor->gl_caps.has_shaders = 1;
#ifndef GPAC_ANDROID
                GET_GLFUN(glEnableVertexAttribArray);
                GET_GLFUN(glDisableVertexAttribArray);
                GET_GLFUN(glVertexAttribPointer);
                GET_GLFUN(glVertexAttribIPointer);
                GET_GLFUN(glGetAttribLocation);
                if (glGetAttribLocation != NULL) {
                        compositor->shader_only_mode = GF_TRUE;
                }
#endif
        } else {
                GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] OpenGL shaders not supported\n"));
        }
#endif 
#endif 
#ifdef GPAC_USE_GLES2
        compositor->gl_caps.has_shaders = GF_TRUE;
        compositor->shader_only_mode = GF_TRUE;
#elif defined (GL_VERSION_2_0)
        compositor->gl_caps.has_shaders = GF_TRUE;
        compositor->shader_only_mode = GF_TRUE;
#endif
        if (!compositor->gl_caps.has_shaders && (compositor->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER)) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] OpenGL shaders not supported - disabling auto-stereo output\n"));
                compositor->visual->nb_views=1;
                compositor->visual->autostereo_type = GF_3D_STEREO_NONE;
                compositor->visual->camera_layout = GF_3D_CAMERA_STRAIGHT;
        }
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
        if (compositor->shader_only_mode) {
                const char *shader = gf_cfg_get_key(compositor->user->config, "Compositor", "VertexShader");
                FILE *t = shader ? gf_fopen(shader, "rt") : NULL;
                if (!t) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] GLES Vertex shader not found, disabling shaders\n"));
                        compositor->shader_only_mode = GF_FALSE;
                }
                if (t) gf_fclose(t);
                shader = gf_cfg_get_key(compositor->user->config, "Compositor", "FragmentShader");
                t = shader ? gf_fopen(shader, "rt") : NULL;
                if (!t) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] GLES Fragment shader not found, disabling shaders\n"));
                        compositor->shader_only_mode = GF_FALSE;
                }
                if (t) gf_fclose(t);
        }
#endif
}
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
#ifdef GPAC_USE_GLES2
#define GLES_VERSION_STRING "#version 100 \n"
#else
#define GLES_VERSION_STRING "#version 120 \n"
#endif
#define GLSL_PREFIX GLES_VERSION_STRING \
        "#ifdef GL_ES\n"\
        "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"\
        "precision highp float;\n"\
        "#else\n"\
        "precision mediump float;\n"\
        "#endif\n" \
        "#endif\n"
static char *glsl_autostereo_vertex = GLSL_PREFIX "\
        attribute vec4 gfVertex;\
        attribute vec2 gfTextureCoordinates;\
        uniform mat4 gfProjectionMatrix;\
        varying vec2 TexCoord;\
        void main(void)\
        {\
                TexCoord = gfTextureCoordinates;\
                gl_Position = gfProjectionMatrix * gfVertex;\
        }";
static char *glsl_view_anaglyph = GLSL_PREFIX "\
        uniform sampler2D gfView1;\
        uniform sampler2D gfView2;\
        varying vec2 TexCoord;\
        void main(void)  \
        {\
                vec4 col1 = texture2D(gfView1, TexCoord.st); \
                vec4 col2 = texture2D(gfView2, TexCoord.st); \
                gl_FragColor.r = col1.r;\
                gl_FragColor.g = col2.g;\
                gl_FragColor.b = col2.b;\
        }";
#ifdef GPAC_UNUSED_FUNC
static char *glsl_view_anaglyph_optimize = GLSL_PREFIX "\
        uniform sampler2D gfView1;\
        uniform sampler2D gfView2;\
        varying vec2 TexCoord;\
        void main(void)  \
        {\
                vec4 col1 = texture2D(gfView1, TexCoord.st); \
                vec4 col2 = texture2D(gfView2, TexCoord.st); \
                gl_FragColor.r = 0.7*col1.g + 0.3*col1.b;\
                gl_FragColor.r = pow(gl_FragColor.r, 1.5);\
                gl_FragColor.g = col2.g;\
                gl_FragColor.b = col2.b;\
        }";
#endif 
static char *glsl_view_columns = GLSL_PREFIX "\
        uniform sampler2D gfView1;\
        uniform sampler2D gfView2;\
        varying vec2 TexCoord;\
        void main(void)  \
        {\
                if ( int( mod(gl_FragCoord.x, 2.0) ) == 0) \
                        gl_FragColor = texture2D(gfView1, TexCoord.st); \
                else \
                        gl_FragColor = texture2D(gfView2, TexCoord.st); \
        }";
static char *glsl_view_rows = GLSL_PREFIX "\
        uniform sampler2D gfView1;\
        uniform sampler2D gfView2;\
        varying vec2 TexCoord;\
        void main(void)  \
        {\
                if ( int( mod(gl_FragCoord.y, 2.0) ) == 0) \
                        gl_FragColor = texture2D(gfView1, TexCoord.st); \
                else \
                        gl_FragColor = texture2D(gfView2, TexCoord.st); \
        }";
static char *glsl_view_5VSP19 = GLSL_PREFIX "\
        uniform sampler2D gfView1;\
        uniform sampler2D gfView2;\
        uniform sampler2D gfView3;\
        uniform sampler2D gfView4;\
        uniform sampler2D gfView5;\
        varying vec2 TexCoord;\
        \
        void getTextureSample(in int texID, out vec4 color) { \
          if (texID == 0 ) color = texture2D(gfView1, TexCoord.st); \
          else if (texID == 1 ) color = texture2D(gfView2, TexCoord.st); \
          else if (texID == 2 ) color = texture2D(gfView3, TexCoord.st); \
          else if (texID == 3 ) color = texture2D(gfView4, TexCoord.st); \
          else if (texID == 4 ) color = texture2D(gfView5, TexCoord.st); \
        } \
        \
        void main(void) {\
                vec4 color;\
                float pitch = 5.0 + 1.0  - mod(gl_FragCoord.y , 5.0);\
                int col = int( mod(pitch + 3.0 * (gl_FragCoord.x), 5.0 ) );\
                int Vr = int(col);\
                int Vg = int(col) + 1;\
                int Vb = int(col) + 2;\
                if (Vg >= 5) Vg -= 5;\
                if (Vb >= 5) Vb -= 5;\
                getTextureSample(Vr, color); \
                gl_FragColor.r = color.r;\
                getTextureSample(Vg, color); \
                gl_FragColor.g = color.g;\
                getTextureSample(Vb, color); \
                gl_FragColor.b = color.b;\
        }";
static char *glsl_view_8VAlio = GLSL_PREFIX "\
        uniform sampler2D gfView1; \
        uniform sampler2D gfView2; \
        uniform sampler2D gfView3; \
        uniform sampler2D gfView4; \
        uniform sampler2D gfView5; \
        uniform sampler2D gfView6; \
        uniform sampler2D gfView7; \
        uniform sampler2D gfView8; \
        varying vec2 TexCoord;\
         \
        void getTextureSample(in int texID, out vec4 color) { \
          if (texID == 0 ) color = texture2D(gfView1, TexCoord.st); \
          else if (texID == 1 ) color = texture2D(gfView2, TexCoord.st); \
          else if (texID == 2 ) color = texture2D(gfView3, TexCoord.st); \
          else if (texID == 3 ) color = texture2D(gfView4, TexCoord.st); \
          else if (texID == 4 ) color = texture2D(gfView5, TexCoord.st); \
          else if (texID == 5 ) color = texture2D(gfView6, TexCoord.st); \
          else if (texID == 6 ) color = texture2D(gfView7, TexCoord.st); \
          else if (texID == 7 ) color = texture2D(gfView8, TexCoord.st); \
        } \
         \
        void main() \
        { \
          int x = int(gl_FragCoord.x + 0.5); \
          int y = int(gl_FragCoord.y + 0.5); \
          int modulox = x/8; \
          int moduloy = y/8; \
          modulox = x - 8 * modulox; \
          moduloy = y - 8 * moduloy; \
           \
          int viewLine = 7 - moduloy; \
          int viewPix = viewLine + 3 * modulox; \
          int viewR = viewPix - 8*(viewPix/8); \
          int viewG = viewPix + 1 - 8*((viewPix +1)/8); \
          int viewB = viewPix + 2 - 8*((viewPix +2)/8); \
           \
          vec4 color; \
          getTextureSample(viewR, color); \
          gl_FragColor.r = color.r; \
          getTextureSample(viewG, color);  \
          gl_FragColor.g = color.g; \
          getTextureSample(viewB, color); \
          gl_FragColor.b = color.b; \
        }";
Bool visual_3d_compile_shader(GF_SHADERID shader_id, const char *name, const char *source)
{
        GLint blen = 0;
        GLsizei slen = 0;
        s32 len;
        GLint is_compiled=0;
        if (!source || !shader_id) return 0;
        len = (u32) strlen(source);
        glShaderSource(shader_id, 1, &source, &len);
        glCompileShader(shader_id);
        glGetShaderiv(shader_id, GL_COMPILE_STATUS, &is_compiled);
        if (is_compiled == GL_TRUE) return GF_TRUE;
        glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH , &blen);
        if (blen > 1) {
                char* compiler_log = (char*) gf_malloc(blen);
#ifdef CONFIG_DARWIN_GL
                glGetInfoLogARB((GLhandleARB) shader_id, blen, &slen, compiler_log);
#elif defined(GPAC_USE_GLES2)
                glGetShaderInfoLog(shader_id, blen, &slen, compiler_log);
#else
                glGetInfoLogARB(shader_id, blen, &slen, compiler_log);
#endif
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[GLSL] Failed to compile %s shader: %s\n", name, compiler_log));
                GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[GLSL] ***** faulty shader code ****\n%s\n**********************\n", source));
                gf_free (compiler_log);
                return 0;
        }
        return 1;
}
static GF_SHADERID visual_3d_shader_from_source_file(const char *src_path, u32 shader_type)
{
        FILE *src = gf_fopen(src_path, "rt");
        GF_SHADERID shader = 0;
        if (src) {
                size_t size;
                char *shader_src;
                gf_fseek(src, 0, SEEK_END);
                size = (size_t) gf_ftell(src);
                gf_fseek(src, 0, SEEK_SET);
                shader_src = gf_malloc(sizeof(char)*(size+1));
                size = fread(shader_src, 1, size, src);
                gf_fclose(src);
                if (size != (size_t) -1) {
                        shader_src[size]=0;
                        shader = glCreateShader(shader_type);
                        if (visual_3d_compile_shader(shader, (shader_type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex", shader_src)==GF_FALSE) {
                                glDeleteShader(shader);
                                shader = 0;
                        }
                }
                gf_free(shader_src);
        } else {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to open shader file %s\n", src_path));
        }
        return shader;
}
#ifdef GPAC_IPHONE
#include <errno.h>
#include <sys/sysctl.h>
#endif
static GF_SHADERID visual_3d_shader_with_flags(const char *src_path, u32 shader_type, u32 flags) {
        FILE *src = gf_fopen(src_path, "rt");
        GF_SHADERID shader = 0;
        char *shader_src;
        char *defs, *tmp, szKey[100];
        size_t str_size;
        defs = (char *) gf_strdup(GLES_VERSION_STRING);
        str_size = strlen(defs) + 1; 
        if (flags & GF_GL_HAS_LIGHT) {
                sprintf(szKey, "#define GF_GL_HAS_LIGHT\n#define LIGHTS_MAX %d\n", GF_MAX_GL_LIGHTS);
                str_size += strlen(szKey);
                defs = (char *) gf_realloc(defs, sizeof(char)*str_size);
                strcat(defs, szKey);
        }
        if(flags & GF_GL_HAS_COLOR) {
                str_size += strlen("#define GF_GL_HAS_COLOR \n");
                defs = (char *) gf_realloc(defs, sizeof(char)*str_size);
                strcat(defs,"#define GF_GL_HAS_COLOR \n");
        }
        if(flags & GF_GL_HAS_TEXTURE) {
                str_size += strlen("#define GF_GL_HAS_TEXTURE \n");
                defs = (char *) gf_realloc(defs, sizeof(char)*str_size);
                strcat(defs,"#define GF_GL_HAS_TEXTURE \n");
        }
        if(flags & GF_GL_HAS_CLIP) {
                
                sprintf(szKey, "#define CLIPS_MAX %d\n#define GF_GL_HAS_CLIP\n", GF_MAX_GL_CLIPS);
                str_size += strlen(szKey);
                defs = (char *) gf_realloc(defs, sizeof(char)*str_size);
                strcat(defs, szKey);
        }
        if (shader_type==GL_FRAGMENT_SHADER) {
                if(flags & GF_GL_IS_YUV) {
                        str_size += strlen("#define GF_GL_IS_YUV \n");
                        defs = (char *) gf_realloc(defs, sizeof(char)*str_size);
                        strcat(defs,"#define GF_GL_IS_YUV \n");
                }
                if(flags & GF_GL_IS_ExternalOES) {
                        str_size += strlen("#define GF_GL_IS_ExternalOES \n");
                        defs = (char *) gf_realloc(defs, sizeof(char)*str_size);
                        strcat(defs,"#define GF_GL_IS_ExternalOES \n");
                }
        }
        if (src) {
                size_t size;
                gf_fseek(src, 0, SEEK_END);
                size = (size_t) gf_ftell(src);
                gf_fseek(src, 0, SEEK_SET);
                shader_src = gf_malloc(sizeof(char)*(size+1));
                size = fread(shader_src, 1, size, src);
                tmp = (char *) gf_malloc(sizeof(char)*(size+str_size+2));
                strcpy(tmp, defs);
                strncat(tmp, shader_src, (size));
                gf_fclose(src);
                if (size != (size_t) -1) {
                        tmp[size+str_size]=0;
                        shader = glCreateShader(shader_type);
                        if (visual_3d_compile_shader(shader, (shader_type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex", tmp)==GF_FALSE) {
                                glDeleteShader(shader);
                                shader = 0;
                        }
                }
                gf_free(shader_src);
                gf_free(tmp);
                gf_free(defs);
        } else {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to open shader file %s\n", src_path));
        }
        return shader;
}
static void visual_3d_set_tx_planes(GF_VisualManager *visual)
{
        GLint i,j, loc;
        for(i=0; i<GF_GL_NB_FRAG_SHADERS; i++) {
                if (! (i & GF_GL_HAS_TEXTURE))
                        continue;
                glUseProgram(visual->glsl_programs[i]);
                if (i & GF_GL_IS_YUV) {
                        for (j=0; j<3; j++) {
                                const char *txname = (j==0) ? "y_plane" : (j==1) ? "u_plane" : "v_plane";
                                loc = glGetUniformLocation(visual->glsl_programs[i], txname);
                                if (loc == -1) {
                                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate texture %s in YUV shader\n", txname));
                                        continue;
                                }
                                glUniform1i(loc, j);
                        }
                } else if (i & GF_GL_IS_ExternalOES)  {
                        loc = glGetUniformLocation(visual->glsl_programs[i], "imgOES");
                        if (loc == -1) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate texture imgOES in ExternalOES shader\n"));
                        }
                        glUniform1i(loc, 0);
                } else {
                        loc = glGetUniformLocation(visual->glsl_programs[i], "img");
                        if (loc == -1) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate texture img in RGB shader\n"));
                        }
                        glUniform1i(loc, 0);
                }
        }
}
void visual_3d_init_stereo_shaders(GF_VisualManager *visual)
{
        GLint linked;
        Bool res;
        if (!visual->compositor->gl_caps.has_shaders) return;
        if (visual->autostereo_glsl_program) return;
        visual->autostereo_glsl_program = glCreateProgram();
        res = GF_TRUE;
        if (!visual->base_glsl_vertex) {
                visual->base_glsl_vertex = glCreateShader(GL_VERTEX_SHADER);
                res = visual_3d_compile_shader(visual->base_glsl_vertex, "vertex", glsl_autostereo_vertex);
        }
        if (res) {
                switch (visual->autostereo_type) {
                case GF_3D_STEREO_COLUMNS:
                        visual->autostereo_glsl_fragment = glCreateShader(GL_FRAGMENT_SHADER);
                        res = visual_3d_compile_shader(visual->autostereo_glsl_fragment, "fragment", glsl_view_columns);
                        break;
                case GF_3D_STEREO_ROWS:
                        visual->autostereo_glsl_fragment = glCreateShader(GL_FRAGMENT_SHADER);
                        res = visual_3d_compile_shader(visual->autostereo_glsl_fragment, "fragment", glsl_view_rows);
                        break;
                case GF_3D_STEREO_ANAGLYPH:
                        visual->autostereo_glsl_fragment = glCreateShader(GL_FRAGMENT_SHADER);
                        res = visual_3d_compile_shader(visual->autostereo_glsl_fragment, "fragment", glsl_view_anaglyph);
                        break;
                case GF_3D_STEREO_5VSP19:
                        visual->autostereo_glsl_fragment = glCreateShader(GL_FRAGMENT_SHADER);
                        res = visual_3d_compile_shader(visual->autostereo_glsl_fragment, "fragment", glsl_view_5VSP19);
                        break;
                case GF_3D_STEREO_8VALIO:
                        visual->autostereo_glsl_fragment = glCreateShader(GL_FRAGMENT_SHADER);
                        res = visual_3d_compile_shader(visual->autostereo_glsl_fragment, "fragment", glsl_view_8VAlio);
                        break;
                case GF_3D_STEREO_CUSTOM:
                {
                        const char *sOpt = gf_cfg_get_key(visual->compositor->user->config, "Compositor", "InterleaverShader");
                        if (sOpt) {
                                visual->autostereo_glsl_fragment = visual_3d_shader_from_source_file(sOpt, GL_FRAGMENT_SHADER);
                                if (visual->autostereo_glsl_fragment) res = GF_TRUE;
                        }
                }
                break;
                }
        }
        if (res) {
                glAttachShader(visual->autostereo_glsl_program, visual->base_glsl_vertex);
                glAttachShader(visual->autostereo_glsl_program, visual->autostereo_glsl_fragment);
                glLinkProgram(visual->autostereo_glsl_program);
                glGetProgramiv(visual->autostereo_glsl_program, GL_LINK_STATUS, &linked);
                if (!linked) {
                        int i32CharsWritten, i32InfoLogLength;
                        char pszInfoLog[2048];
                        glGetProgramiv(visual->autostereo_glsl_program, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
                        glGetProgramInfoLog(visual->autostereo_glsl_program, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, (pszInfoLog));
                        res = GF_FALSE;
                }
                GL_CHECK_ERR
        }
        if (!res) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[V3D:GLSL] Autostereo vertex shader failed - disabling stereo support\n"));
                visual->autostereo_type = 0;
                visual->nb_views = 1;
        }
}
#define DEL_SHADER(_a) if (_a) { glDeleteShader(_a); _a = 0; }
#define DEL_PROGRAM(_a) if (_a) { glDeleteProgram(_a); _a = 0; }
static GLint gf_glGetUniformLocation(GF_SHADERID glsl_program, const char *uniform_name)
{
        GLint loc = glGetUniformLocation(glsl_program, uniform_name);
        if (loc<0) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[V3D:GLSL] Cannot find uniform \"%s\" in GLSL program\n", uniform_name));
        }
        return loc;
}
static GLint gf_glGetAttribLocation(GF_SHADERID glsl_program, const char *attrib_name)
{
        GLint loc = glGetAttribLocation(glsl_program, attrib_name);
        if (loc<0) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[V3D:GLSL] Cannot find attrib \"%s\" in GLSL program\n", attrib_name));
        }
        return loc;
}
#if 0
static void gf_glQueryProgram(GF_SHADERID progObj)
{
        GLint err_log = -10;
        GL_CHECK_ERR
        glValidateProgram(progObj);
        GL_CHECK_ERR
        glGetProgramiv(progObj, GL_VALIDATE_STATUS, &err_log);
        printf("GL_VALIDATE_STATUS: %d \n ",err_log);
        glGetProgramiv(progObj, GL_LINK_STATUS, &err_log);
        printf("GL_LINK_STATUS: %d \n ",err_log);
        glGetProgramiv(progObj, GL_ATTACHED_SHADERS, &err_log);
        printf("GL_ATTACHED_SHADERS: %d \n ",err_log);
        glGetProgramiv(progObj, GL_ACTIVE_UNIFORMS, &err_log);
        printf("GL_ACTIVE_UNIFORMS: %d \n ",err_log);
}
static void gf_glQueryUniform(GF_SHADERID progObj, const char *name, int index)
{
        GLint loc, i;
        GLfloat res[16];
        loc = gf_glGetUniformLocation(progObj, name);
        if(loc<0) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("failed to locate uniform. exiting\n"));
                return;
        }
        glGetUniformfv(progObj, loc, (GLfloat *) res);
        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("uniform %s has value of: ", name));
        for (i =0; i<index; i++)
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("%f ", res[i]));
}
static void gf_glQueryAttrib(GF_SHADERID progObj, const char *name, int index, GLenum param)
{
        GLint loc, i;
        GLfloat res[16];
        loc = gf_glGetAttribLocation(progObj, name);
        if (loc<0) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("failed to locate attribute. exiting\n"));
                return;
        }
        glGetVertexAttribfv(loc, param, (GLfloat *) res);
        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("attribute %s has value of: ", name));
        for( i =0; i<index; i++)
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("%f ", res[i]));
}
static void gf_glQueryUniforms(GF_SHADERID progObj)
{
        GLint maxUniformLen;
        GLint numUniforms;
        char *uniformName;
        GLint index;
        glGetProgramiv(progObj, GL_ACTIVE_UNIFORMS, &numUniforms);
        glGetProgramiv(progObj, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen);
        uniformName = malloc(sizeof(char) * maxUniformLen);
        for(index = 0; index < numUniforms; index++) {
                GLint size;
                GLenum type;
                GLint location;
                
                glGetActiveUniform(progObj, index, maxUniformLen, NULL, &size, &type, uniformName);
                
                location = glGetUniformLocation(progObj, uniformName);
                if(location) printf("uniform %s is: ",uniformName);
                switch(type) {
                case GL_FLOAT:
                        printf("float \n");
                        break;
                case GL_FLOAT_VEC2:
                        printf("floatvec2 \n");
                        break;
                case GL_FLOAT_VEC3:
                        printf("floatvec3 \n");
                        break;
                case GL_FLOAT_VEC4:
                        printf("floatvec4 \n");
                        break;
                case GL_INT:
                        printf("int \n");
                        break;
                case GL_INT_VEC2:
                case GL_INT_VEC3:
                case GL_INT_VEC4:
                        printf("intVec \n");
                        break;
                case GL_FLOAT_MAT2:
                case GL_FLOAT_MAT3:
                case GL_FLOAT_MAT4:
                        printf("fmat \n");
                        break;
                case GL_SAMPLER_2D:
                        printf("samp2D \n");
                        break;
                case GL_SAMPLER_CUBE:
                        printf("sampCube \n");
                        break;
                default:
                        printf("other \n");
                        break;
                }
        }
}
static void gf_glQueryAttributes(GF_SHADERID progObj)
{
        GLint maxAttributeLen;
        GLint numAttributes;
        char *attributeName;
        GLint index;
        printf("Listing Attribs... \n");
        glGetProgramiv(progObj, GL_ACTIVE_ATTRIBUTES, &numAttributes);
        glGetProgramiv(progObj, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeLen);
        attributeName = malloc(sizeof(char) * maxAttributeLen);
        for(index = 0; index < numAttributes; index++) {
                GLint size;
                GLenum type;
                GLint location;
                
                glGetActiveAttrib(progObj, index, maxAttributeLen, NULL, &size, &type, attributeName);
                
                location = glGetAttribLocation(progObj, attributeName);
                if(location) printf("attrib %s is: ",attributeName);
                switch(type) {
                case GL_FLOAT:
                        printf("float \n");
                        break;
                case GL_FLOAT_VEC2:
                        printf("floatvec2 \n");
                        break;
                case GL_FLOAT_VEC3:
                        printf("floatvec3 \n");
                        break;
                case GL_FLOAT_VEC4:
                        printf("floatvec4 \n");
                        break;
                case GL_INT:
                        printf("int \n");
                        break;
                case GL_INT_VEC2:
                case GL_INT_VEC3:
                case GL_INT_VEC4:
                        printf("intVec \n");
                        break;
                case GL_FLOAT_MAT2:
                case GL_FLOAT_MAT3:
                case GL_FLOAT_MAT4:
                        printf("fmat \n");
                        break;
                case GL_SAMPLER_2D:
                        printf("samp2D \n");
                        break;
                case GL_SAMPLER_CUBE:
                        printf("sampCube \n");
                        break;
                default:
                        printf("other \n");
                        break;
                }
        }
}
#endif
static Bool visual_3d_init_generic_shaders(GF_VisualManager *visual)
{
        u32 i;
        GLint err_log = -10;
        const char *shader_file;
        GF_Config *cfg = visual->compositor->user->config;
        
        glGetError();
        
        if (visual->glsl_programs[0]) {
                glGetProgramiv(visual->glsl_programs[0], GL_VALIDATE_STATUS, &err_log);
                if(err_log==-10) {
                        for (i=0; i<GF_GL_NB_VERT_SHADERS; i++) {
                                DEL_SHADER(visual->glsl_vertex_shaders[i]);
                        }
                        for (i=0; i<GF_GL_NB_FRAG_SHADERS; i++) {
                                DEL_SHADER(visual->glsl_fragment_shaders[i]);
                                DEL_PROGRAM(visual->glsl_programs[i]);
                        }
                        visual->glsl_has_shaders=0;
                        
                        glGetError();
                }
        } else {
                visual->glsl_has_shaders=0;
                GL_CHECK_ERR;
        }
        
        if (visual->glsl_has_shaders) {
                return GF_TRUE;
        }
        GL_CHECK_ERR
        
        for(i=0; i<GF_GL_NB_FRAG_SHADERS; i++) {
                visual->glsl_programs[i] = glCreateProgram();
        }
        visual->glsl_has_shaders = GF_TRUE;
        GL_CHECK_ERR
        shader_file =(char *) gf_cfg_get_key(cfg, "Compositor", "VertexShader");
        if (!shader_file) return GF_FALSE;
        for (i=0; i<GF_GL_NB_VERT_SHADERS; i++) {
                GL_CHECK_ERR;
                visual->glsl_vertex_shaders[i] = visual_3d_shader_with_flags(shader_file , GL_VERTEX_SHADER, i);
                if (!visual->glsl_vertex_shaders[i]) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to compile vertex shader\n"));
                        return GF_FALSE;
                }
        }
        shader_file =(char *) gf_cfg_get_key(cfg, "Compositor", "FragmentShader");
        if (!shader_file) return GF_FALSE;
        for (i=0; i<GF_GL_NB_FRAG_SHADERS; i++) {
                GLint linked;
                u32 vert_id;
                GL_CHECK_ERR;
                
                if ( (i& (GF_GL_IS_YUV | GF_GL_IS_ExternalOES)) && ! (i & GF_GL_HAS_TEXTURE)) {
                        DEL_PROGRAM(visual->glsl_programs[i]);
                        visual->glsl_programs[i]=0;
                        visual->glsl_fragment_shaders[i] = 0;
                        continue;
                }
                visual->glsl_fragment_shaders[i] = visual_3d_shader_with_flags(shader_file , GL_FRAGMENT_SHADER, i);
                if (!visual->glsl_fragment_shaders[i]) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to compile fragment shader\n"));
                        continue;
                }
                GL_CHECK_ERR;
                
                vert_id = i;
                if (i & (GF_GL_IS_YUV | GF_GL_IS_ExternalOES)) {
                        vert_id &= ~(GF_GL_IS_YUV | GF_GL_IS_ExternalOES);
                        vert_id |= GF_GL_HAS_TEXTURE;
                        assert(vert_id<GF_GL_NB_VERT_SHADERS);
                }
                glAttachShader(visual->glsl_programs[i], visual->glsl_vertex_shaders[vert_id]);
                GL_CHECK_ERR;
                glAttachShader(visual->glsl_programs[i], visual->glsl_fragment_shaders[i]);
                GL_CHECK_ERR;
                glLinkProgram(visual->glsl_programs[i]);
                GL_CHECK_ERR;
                glGetProgramiv(visual->glsl_programs[i], GL_LINK_STATUS, &linked);
                if (!linked) {
                        int i32CharsWritten, i32InfoLogLength;
                        char pszInfoLog[2048];
                        glGetProgramiv(visual->glsl_programs[i], GL_INFO_LOG_LENGTH, &i32InfoLogLength);
                        glGetProgramInfoLog(visual->glsl_programs[i], i32InfoLogLength, &i32CharsWritten, pszInfoLog);
                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, (pszInfoLog));
                }
                glUseProgram(visual->glsl_programs[i]);
                GL_CHECK_ERR;
        }
        
        visual_3d_set_tx_planes(visual);
        return GF_TRUE;
}
void visual_3d_init_shaders(GF_VisualManager *visual)
{
        if (visual->compositor->visual != visual)
                return;
        if (!visual->compositor->gl_caps.has_shaders)
                return;
        if (visual->compositor->shader_only_mode) {
                
                if (! visual_3d_init_generic_shaders(visual)) {
                        visual->compositor->hybrid_opengl = GF_FALSE;
                        visual->compositor->force_opengl_2d = GF_FALSE;
                        
                        visual->compositor->root_visual_setup = 0;
                        
                        gf_sc_reset_graphics(visual->compositor);
                        
                        gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
                }
        }
}
#endif 
void visual_3d_reset_graphics(GF_VisualManager *visual)
{
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
        u32 i;
        if (visual->compositor->visual != visual)
                return;
        DEL_SHADER(visual->base_glsl_vertex);
        DEL_SHADER(visual->autostereo_glsl_fragment);
        DEL_PROGRAM(visual->autostereo_glsl_program );
        if (visual->gl_textures) {
                glDeleteTextures(visual->nb_views, visual->gl_textures);
                gf_free(visual->gl_textures);
                visual->gl_textures = NULL;
        }
        if (visual->autostereo_mesh) {
                mesh_free(visual->autostereo_mesh);
                visual->autostereo_mesh = NULL;
        }
        for (i=0; i<GF_GL_NB_VERT_SHADERS; i++) {
                DEL_SHADER(visual->glsl_vertex_shaders[i]);
        }
        for (i=0; i<GF_GL_NB_FRAG_SHADERS; i++) {
                DEL_SHADER(visual->glsl_fragment_shaders[i]);
                DEL_PROGRAM(visual->glsl_programs[i]);
        }
        visual->glsl_has_shaders=0;
#endif
}
void visual_3d_set_clipper_scissor(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
#ifndef GPAC_USE_TINYGL
        if (visual->has_clipper_2d) {
                u32 x, y;
                u32 dw, dh;
                glEnable(GL_SCISSOR_TEST);
                if (visual->offscreen) {
                        dw = visual->width;
                        dh = visual->height;
                } else {
                        dw = visual->compositor->display_width;
                        dh = visual->compositor->display_height;
                }
                if (visual->center_coords) {
                        x = visual->clipper_2d.x + dw / 2;
                        y = dh / 2 + visual->clipper_2d.y - visual->clipper_2d.height;
                } else {
                        x = visual->clipper_2d.x;
                        y = dh - visual->clipper_2d.y;
                }
                glScissor(x, y, visual->clipper_2d.width, visual->clipper_2d.height);
        } else {
                glDisable(GL_SCISSOR_TEST);
        }
#endif
}
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
static void visual_3d_load_matrix_shaders(GF_SHADERID program, Fixed *mat, const char *name)
{
        GLint loc;
#ifdef GPAC_FIXED_POINT
        Float _mat[16];
        u32 i;
#endif
        loc = gf_glGetUniformLocation(program, name);
        if(loc<0) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("GL Error (file %s line %d): Invalid matrix name", __FILE__, __LINE__));
                return;
        }
        GL_CHECK_ERR
#ifdef GPAC_FIXED_POINT
        for (i=0; i<16; i++) _mat[i] = FIX2FLT(mat[i]);
        glUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat *) _mat);
#else
        glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
#endif
        GL_CHECK_ERR
}
#endif
GF_Err visual_3d_init_autostereo(GF_VisualManager *visual)
{
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
        u32 bw, bh;
        SFVec2f s;
        Bool use_npot = visual->compositor->gl_caps.npot_texture;
        if (visual->gl_textures) return GF_OK;
        visual->gl_textures = gf_malloc(sizeof(GLuint) * visual->nb_views);
        glGenTextures(visual->nb_views, visual->gl_textures);
        bw = visual->width;
        bh = visual->height;
        
        if (visual->compositor->visual==visual) {
                bw = visual->compositor->output_width;
                bh = visual->compositor->output_height;
        }
#ifdef GPAC_USE_GLES2
        use_npot = GF_TRUE;
#endif
        if (use_npot) {
                visual->auto_stereo_width = bw;
                visual->auto_stereo_height = bh;
        } else {
                visual->auto_stereo_width = 2;
                while (visual->auto_stereo_width < bw) visual->auto_stereo_width *= 2;
                visual->auto_stereo_height = 2;
                while (visual->auto_stereo_height < bh) visual->auto_stereo_height *= 2;
        }
        visual->autostereo_mesh = new_mesh();
        s.x = INT2FIX(bw);
        s.y = INT2FIX(bh);
        mesh_new_rectangle(visual->autostereo_mesh, s, NULL, 0);
        if (! use_npot) {
                u32 i;
                Fixed max_u = INT2FIX(bw) / visual->auto_stereo_width;
                Fixed max_v = INT2FIX(bh) / visual->auto_stereo_height;
                for (i=0; i<visual->autostereo_mesh->v_count; i++) {
                        if (visual->autostereo_mesh->vertices[i].texcoords.x == FIX_ONE) {
                                visual->autostereo_mesh->vertices[i].texcoords.x = max_u;
                        }
                        if (visual->autostereo_mesh->vertices[i].texcoords.y == FIX_ONE) {
                                visual->autostereo_mesh->vertices[i].texcoords.y = max_v;
                        }
                }
        }
        GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual3D] AutoStereo initialized - width %d height %d\n", visual->auto_stereo_width, visual->auto_stereo_height) );
        visual_3d_init_stereo_shaders(visual);
#endif 
        return GF_OK;
}
void visual_3d_end_auto_stereo_pass(GF_VisualManager *visual)
{
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
        u32 i;
        GLint loc, loc_vertex_attrib, loc_texcoord_attrib;
        char szTex[100];
        Fixed hw, hh;
        GF_Matrix mx;
        glFlush();
        GL_CHECK_ERR
#ifndef GPAC_USE_GLES2
        glEnable(GL_TEXTURE_2D);
#endif
        glBindTexture(GL_TEXTURE_2D, visual->gl_textures[visual->current_view]);
#ifndef GPAC_USE_GLES2
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
#else
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
#endif
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, visual->auto_stereo_width, visual->auto_stereo_height, 0);
        GL_CHECK_ERR
#ifndef GPAC_USE_GLES2
        glDisable(GL_TEXTURE_2D);
#endif
        glClear(GL_DEPTH_BUFFER_BIT);
        GL_CHECK_ERR
        if (visual->current_view+1<visual->nb_views) return;
        hw = INT2FIX(visual->width);
        hh = INT2FIX(visual->height);
        
        if (visual->compositor->visual==visual) {
                hw = INT2FIX(visual->compositor->output_width);
                hh = INT2FIX(visual->compositor->output_height);
        }
        glViewport(0, 0, (GLsizei) hw, (GLsizei) hh );
        hw /= 2;
        hh /= 2;
        
        glUseProgram(visual->autostereo_glsl_program);
        
        gf_mx_ortho(&mx, -hw, hw, -hh, hh, -10, 100);
        visual_3d_load_matrix_shaders(visual->autostereo_glsl_program, mx.m, "gfProjectionMatrix");
        
        
        loc = glGetUniformLocation(visual->autostereo_glsl_program, "gfViewCount");
        if (loc != -1) glUniform1i(loc, visual->nb_views);
        loc_texcoord_attrib = -1;
        
        loc_vertex_attrib = gf_glGetAttribLocation(visual->autostereo_glsl_program, "gfVertex");
        if (loc_vertex_attrib>=0) {
                glVertexAttribPointer(loc_vertex_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(GF_Vertex), &visual->autostereo_mesh->vertices[0].pos);
                glEnableVertexAttribArray(loc_vertex_attrib);
                GL_CHECK_ERR
                
                loc_texcoord_attrib = gf_glGetAttribLocation(visual->autostereo_glsl_program, "gfTextureCoordinates");
                if (loc_texcoord_attrib>=0) {
                        glVertexAttribPointer(loc_texcoord_attrib, 2, GL_FLOAT, GL_FALSE, sizeof(GF_Vertex), &visual->autostereo_mesh->vertices[0].texcoords);
                        glEnableVertexAttribArray(loc_texcoord_attrib);
                        GL_CHECK_ERR
                        
                        for (i=0; i<visual->nb_views; i++) {
                                sprintf(szTex, "gfView%d", i+1);
                                loc = glGetUniformLocation(visual->autostereo_glsl_program, szTex);
                                if (loc == -1) continue;
                                glActiveTexture(GL_TEXTURE0 + i);
#ifndef GPAC_USE_GLES2
                                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                                glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
#endif
                                GL_CHECK_ERR
                                glBindTexture(GL_TEXTURE_2D, visual->gl_textures[i]);
                                GL_CHECK_ERR
                                glUniform1i(loc, i);
                                GL_CHECK_ERR
                        }
                        
#if defined(GPAC_USE_GLES2)
                        glDrawElements(GL_TRIANGLES, visual->autostereo_mesh->i_count, GL_UNSIGNED_SHORT, visual->autostereo_mesh->indices);
#else
                        glDrawElements(GL_TRIANGLES, visual->autostereo_mesh->i_count, GL_UNSIGNED_INT, visual->autostereo_mesh->indices);
#endif
                        GL_CHECK_ERR
                }
        }
        if (loc_vertex_attrib>=0) glDisableVertexAttribArray(loc_vertex_attrib);
        if (loc_texcoord_attrib>=0) glDisableVertexAttribArray(loc_texcoord_attrib);
        GL_CHECK_ERR
        glUseProgram(0);
#ifndef GPAC_USE_GLES2
        
        glActiveTexture(GL_TEXTURE0);
        GL_CHECK_ERR
        glBindTexture(GL_TEXTURE_2D, 0);
        glDisable(GL_TEXTURE_2D);
#endif
        GL_CHECK_ERR
#endif 
}
static void visual_3d_setup_quality(GF_VisualManager *visual)
{
#ifndef GPAC_USE_GLES2
        if (visual->compositor->high_speed) {
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
                glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
#ifdef GL_POLYGON_SMOOTH_HINT
                glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
#endif
        } else {
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
                glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
#ifdef GL_POLYGON_SMOOTH_HINT
                glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
#endif
        }
        if (visual->compositor->antiAlias == GF_ANTIALIAS_FULL) {
                glEnable(GL_LINE_SMOOTH);
#ifndef GPAC_USE_GLES1X
                if (visual->compositor->poly_aa)
                        glEnable(GL_POLYGON_SMOOTH);
                else
                        glDisable(GL_POLYGON_SMOOTH);
#endif
        } else {
                glDisable(GL_LINE_SMOOTH);
#ifndef GPAC_USE_GLES1X
                glDisable(GL_POLYGON_SMOOTH);
#endif
        }
#endif
}
void visual_3d_setup(GF_VisualManager *visual)
{
        if (visual->gl_setup) {
                visual->has_fog = GF_FALSE;
                glClear(GL_DEPTH_BUFFER_BIT);
                return;
        }
#ifndef GPAC_USE_TINYGL
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDepthFunc(GL_LEQUAL);
#endif
        glEnable(GL_DEPTH_TEST);
        glFrontFace(GL_CCW);
        glCullFace(GL_BACK);
#ifdef GPAC_USE_GLES1X
        glClearDepthx(FIX_ONE);
        glLightModelx(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
        glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, FLT2FIX(0.2f * 128) );
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#elif defined(GPAC_USE_GLES2)
        glClearDepthf(1.0f);
#else
        glClearDepth(1.0f);
        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, (float) (0.2 * 128));
#endif
#ifndef GPAC_USE_GLES2
        glDisable(GL_TEXTURE_2D);
        glShadeModel(GL_SMOOTH);
        glGetIntegerv(GL_MAX_LIGHTS, (GLint*)&visual->max_lights);
        if (visual->max_lights>GF_MAX_GL_LIGHTS)
                visual->max_lights=GF_MAX_GL_LIGHTS;
#ifdef GL_MAX_CLIP_PLANES
        glGetIntegerv(GL_MAX_CLIP_PLANES, (GLint*)&visual->max_clips);
        if (visual->max_clips>GF_MAX_GL_CLIPS)
                visual->max_clips=GF_MAX_GL_CLIPS;
#endif
        glDisable(GL_POINT_SMOOTH);
        glDisable(GL_COLOR_MATERIAL);
        glDisable(GL_LIGHTING);
        glDisable(GL_BLEND);
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_CULL_FACE);
        glDisable(GL_FOG);
        
        glEnable(GL_NORMALIZE);
#endif 
        visual_3d_setup_quality(visual);
        glDisable(GL_BLEND);
        glDisable(GL_CULL_FACE);
        visual->has_fog = GF_FALSE;
        visual->max_lights=GF_MAX_GL_LIGHTS;
        visual->max_clips=GF_MAX_GL_CLIPS;
        visual->gl_setup = GF_TRUE;
        glClear(GL_DEPTH_BUFFER_BIT);
}
void visual_3d_set_background_state(GF_VisualManager *visual, Bool on)
{
#ifndef GPAC_USE_GLES2
        if (on) {
                glDisable(GL_LIGHTING);
                glDisable(GL_FOG);
                glDisable(GL_LINE_SMOOTH);
                glDisable(GL_BLEND);
#ifndef GPAC_USE_GLES1X
                glDisable(GL_POLYGON_SMOOTH);
#endif
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
        } else {
                visual_3d_setup_quality(visual);
        }
#endif
        visual_3d_enable_depth_buffer(visual, ! on);
}
void visual_3d_enable_antialias(GF_VisualManager *visual, Bool bOn)
{
#ifndef GPAC_USE_GLES2
        if (bOn) {
                glEnable(GL_LINE_SMOOTH);
#ifndef GPAC_USE_GLES1X
                if (visual->compositor->poly_aa)
                        glEnable(GL_POLYGON_SMOOTH);
                else
                        glDisable(GL_POLYGON_SMOOTH);
#endif
        } else {
                glDisable(GL_LINE_SMOOTH);
#ifndef GPAC_USE_GLES1X
                glDisable(GL_POLYGON_SMOOTH);
#endif
        }
#endif
}
void visual_3d_enable_depth_buffer(GF_VisualManager *visual, Bool on)
{
        if (on) glEnable(GL_DEPTH_TEST);
        else glDisable(GL_DEPTH_TEST);
}
void visual_3d_set_viewport(GF_VisualManager *visual, GF_Rect vp)
{
        glViewport(FIX2INT(vp.x), FIX2INT(vp.y), FIX2INT(vp.width), FIX2INT(vp.height));
}
void visual_3d_set_scissor(GF_VisualManager *visual, GF_Rect *vp)
{
#ifndef GPAC_USE_TINYGL
        if (vp) {
                glEnable(GL_SCISSOR_TEST);
                glScissor(FIX2INT(vp->x), FIX2INT(vp->y), FIX2INT(vp->width), FIX2INT(vp->height));
        } else {
                glDisable(GL_SCISSOR_TEST);
        }
#endif
}
void visual_3d_clear_depth(GF_VisualManager *visual)
{
        glClear(GL_DEPTH_BUFFER_BIT);
}
static void visual_3d_draw_aabb_node(GF_TraverseState *tr_state, GF_Mesh *mesh, u32 prim_type, GF_Plane *fplanes, u32 *p_indices, AABBNode *n, void *idx_addr)
{
        u32 i;
        
        if (n->pos) {
                u32 p_idx, cull;
                SFVec3f vertices[8];
                
                gf_bbox_get_vertices(n->min, n->max, vertices);
                cull = CULL_INSIDE;
                for (i=0; i<6; i++) {
                        p_idx = p_indices[i];
                        
                        if (gf_plane_get_distance(&fplanes[i], &vertices[p_idx])<0) {
                                cull = CULL_OUTSIDE;
                                break;
                        }
                        
                        if (gf_plane_get_distance(&fplanes[i], &vertices[7-p_idx])<0) {
                                cull = CULL_INTERSECTS;
                                break;
                        }
                }
                if (cull==CULL_OUTSIDE) return;
                if (cull==CULL_INTERSECTS) {
                        visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_indices, n->pos, idx_addr);
                        visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_indices, n->neg, idx_addr);
                        return;
                }
        }
        
        for (i=0; i<n->nb_idx; i++) {
                u32 idx = 3*n->indices[i];
                void *vbi_addr;
                if (!idx_addr) vbi_addr = (void *) PTR_TO_U_CAST ( sizeof(IDX_TYPE) * idx );
                else vbi_addr = &mesh->indices[idx];
#if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2)
                glDrawElements(prim_type, 3, GL_UNSIGNED_SHORT, vbi_addr);
#else
                glDrawElements(prim_type, 3, GL_UNSIGNED_INT, vbi_addr);
#endif
        }
}
#ifndef GPAC_USE_GLES2
static void visual_3d_matrix_load(GF_VisualManager *visual, Fixed *mat)
{
#if defined(GPAC_FIXED_POINT)
        Float _mat[16];
        u32 i;
#endif
        if (!mat) {
                glLoadIdentity();
                return;
        }
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
        glLoadMatrixx(mat);
#elif defined(GPAC_FIXED_POINT)
        for (i=0; i<16; i++) _mat[i] = FIX2FLT(mat[i]);
        glLoadMatrixf(_mat);
#else
        glLoadMatrixf(mat);
#endif
}
static void visual_3d_update_matrices(GF_TraverseState *tr_state)
{
        GF_Matrix mx;
        if (!tr_state || !tr_state->camera) return;
        if (tr_state->visual->needs_projection_matrix_reload) {
                tr_state->visual->needs_projection_matrix_reload = 0;
                glMatrixMode(GL_PROJECTION);
                visual_3d_matrix_load(tr_state->visual, tr_state->camera->projection.m);
                glMatrixMode(GL_MODELVIEW);
        }
        gf_mx_copy(mx, tr_state->camera->modelview.m);
        gf_mx_add_matrix(&mx, &tr_state->model_matrix);
        visual_3d_matrix_load(tr_state->visual, (Fixed *) &mx);
}
static void visual_3d_set_clippers(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
#ifdef GL_MAX_CLIP_PLANES
        u32 i;
        GF_Matrix inv_mx;
        gf_mx_copy(inv_mx, tr_state->model_matrix);
        gf_mx_inverse(&inv_mx);
        for (i=0; i<visual->num_clips; i++) {
                u32 idx = GL_CLIP_PLANE0 + i;
#ifdef GPAC_USE_GLES1X
                Fixed g[4];
#else
                Double g[4];
#endif
                GF_Matrix mx;
                GF_Plane p = visual->clippers[i].p;
                if (visual->clippers[i].is_2d_clip) {
                        visual_3d_matrix_load(tr_state->visual, tr_state->camera->modelview.m);
                } else {
                        gf_mx_copy(mx, inv_mx);
                        if (visual->clippers[i].mx_clipper != NULL) {
                                gf_mx_add_matrix(&mx, visual->clippers[i].mx_clipper);
                        }
                        gf_mx_apply_plane(&mx, &p);
                }
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
                g[0] = p.normal.x;
                g[1] = p.normal.y;
                g[2] = p.normal.z;
                g[3] = p.d;
                glClipPlanex(idx, g);
#else
                g[0] = FIX2FLT(p.normal.x);
                g[1] = FIX2FLT(p.normal.y);
                g[2] = FIX2FLT(p.normal.z);
                g[3] = FIX2FLT(p.d);
#if defined(GPAC_USE_GLES1X)
                glClipPlanef(idx, g);
#else
                glClipPlane(idx, g);
#endif
#endif
                glEnable(idx);
                if (visual->clippers[i].is_2d_clip) {
                        visual_3d_update_matrices(tr_state);
                }
        }
#endif
}
static void visual_3d_reset_clippers(GF_VisualManager *visual)
{
#ifdef GL_MAX_CLIP_PLANES
        u32 i;
        for (i=0; i<visual->num_clips; i++) {
                glDisable(GL_CLIP_PLANE0 + i);
        }
#endif
}
void visual_3d_reset_lights(GF_VisualManager *visual)
{
        u32 i;
        if (!visual->num_lights) return;
        for (i=0; i<visual->num_lights; i++) {
                glDisable(GL_LIGHT0 + i);
        }
        glDisable(GL_LIGHTING);
}
static void visual_3d_set_lights(GF_VisualManager *visual)
{
        u32 i;
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
        Fixed vals[4], exp;
#else
        Float vals[4], intensity, cutOffAngle, beamWidth, ambientIntensity, exp;
#endif
        if (!visual->num_lights) return;
        for (i=0; i<visual->num_lights; i++) {
                GF_Matrix mx;
                GF_LightInfo *li = &visual->lights[i];
                GLint iLight = GL_LIGHT0 + i;
                if(li->type==3) {
                        gf_mx_init(mx);
                } else {
                        gf_mx_copy(mx, visual->camera.modelview.m);
                        gf_mx_add_matrix(&mx, &li->light_mx);
                }
                visual_3d_matrix_load(visual, mx.m);
                glEnable(iLight);
                switch (li->type) {
                
                case 0:
                case 3:
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
                        vals[0] = -li->direction.x;
                        vals[1] = -li->direction.y;
                        vals[2] = -li->direction.z;
                        vals[3] = 0;
                        glLightxv(iLight, GL_POSITION, vals);
                        vals[0] = gf_mulfix(li->color.red, li->intensity);
                        vals[1] = gf_mulfix(li->color.green, li->intensity);
                        vals[2] = gf_mulfix(li->color.blue, li->intensity);
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_DIFFUSE, vals);
                        glLightxv(iLight, GL_SPECULAR, vals);
                        vals[0] = gf_mulfix(li->color.red, li->ambientIntensity);
                        vals[1] = gf_mulfix(li->color.green, li->ambientIntensity);
                        vals[2] = gf_mulfix(li->color.blue, li->ambientIntensity);
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_AMBIENT, vals);
                        glLightx(iLight, GL_CONSTANT_ATTENUATION, FIX_ONE);
                        glLightx(iLight, GL_LINEAR_ATTENUATION, 0);
                        glLightx(iLight, GL_QUADRATIC_ATTENUATION, 0);
                        glLightx(iLight, GL_SPOT_CUTOFF, INT2FIX(180) );
#else
                        ambientIntensity = FIX2FLT(li->ambientIntensity);
                        intensity = FIX2FLT(li->intensity);
                        vals[0] = -FIX2FLT(li->direction.x);
                        vals[1] = -FIX2FLT(li->direction.y);
                        vals[2] = -FIX2FLT(li->direction.z);
                        vals[3] = 0;
                        glLightfv(iLight, GL_POSITION, vals);
                        vals[0] = FIX2FLT(li->color.red)*intensity;
                        vals[1] = FIX2FLT(li->color.green)*intensity;
                        vals[2] = FIX2FLT(li->color.blue)*intensity;
                        vals[3] = 1;
                        glLightfv(iLight, GL_DIFFUSE, vals);
                        glLightfv(iLight, GL_SPECULAR, vals);
                        vals[0] = FIX2FLT(li->color.red)*ambientIntensity;
                        vals[1] = FIX2FLT(li->color.green)*ambientIntensity;
                        vals[2] = FIX2FLT(li->color.blue)*ambientIntensity;
                        vals[3] = 1;
                        glLightfv(iLight, GL_AMBIENT, vals);
                        glLightf(iLight, GL_CONSTANT_ATTENUATION, 1.0f);
                        glLightf(iLight, GL_LINEAR_ATTENUATION, 0);
                        glLightf(iLight, GL_QUADRATIC_ATTENUATION, 0);
                        glLightf(iLight, GL_SPOT_CUTOFF, 180);
#endif
                        break;
                
                case 1:
#ifndef GPAC_USE_GLES1X
                        ambientIntensity = FIX2FLT(li->ambientIntensity);
                        intensity = FIX2FLT(li->intensity);
                        cutOffAngle = FIX2FLT(li->cutOffAngle);
                        beamWidth = FIX2FLT(li->beamWidth);
#endif
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
                        vals[0] = li->direction.x;
                        vals[1] = li->direction.y;
                        vals[2] = li->direction.z;
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_SPOT_DIRECTION, vals);
                        vals[0] = li->position.x;
                        vals[1] = li->position.y;
                        vals[2] = li->position.z;
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_POSITION, vals);
                        glLightx(iLight, GL_CONSTANT_ATTENUATION, li->attenuation.x ? li->attenuation.x : FIX_ONE);
                        glLightx(iLight, GL_LINEAR_ATTENUATION, li->attenuation.y);
                        glLightx(iLight, GL_QUADRATIC_ATTENUATION, li->attenuation.z);
                        vals[0] = gf_mulfix(li->color.red, li->intensity);
                        vals[1] = gf_mulfix(li->color.green, li->intensity);
                        vals[2] = gf_mulfix(li->color.blue, li->intensity);
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_DIFFUSE, vals);
                        glLightxv(iLight, GL_SPECULAR, vals);
                        vals[0] = gf_mulfix(li->color.red, li->ambientIntensity);
                        vals[1] = gf_mulfix(li->color.green, li->ambientIntensity);
                        vals[2] = gf_mulfix(li->color.blue, li->ambientIntensity);
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_AMBIENT, vals);
                        if (!li->beamWidth) exp = FIX_ONE;
                        else if (li->beamWidth > li->cutOffAngle) exp = 0;
                        else {
                                exp = FIX_ONE - gf_cos(li->beamWidth);
                                if (exp>FIX_ONE) exp = FIX_ONE;
                        }
                        glLightx(iLight, GL_SPOT_EXPONENT,  exp*128);
                        glLightx(iLight, GL_SPOT_CUTOFF, gf_divfix(180*li->cutOffAngle, GF_PI) );
#else
                        vals[0] = FIX2FLT(li->direction.x);
                        vals[1] = FIX2FLT(li->direction.y);
                        vals[2] = FIX2FLT(li->direction.z);
                        vals[3] = 1;
                        glLightfv(iLight, GL_SPOT_DIRECTION, vals);
                        vals[0] = FIX2FLT(li->position.x);
                        vals[1] = FIX2FLT(li->position.y);
                        vals[2] = FIX2FLT(li->position.z);
                        vals[3] = 1;
                        glLightfv(iLight, GL_POSITION, vals);
                        glLightf(iLight, GL_CONSTANT_ATTENUATION, li->attenuation.x ? FIX2FLT(li->attenuation.x) : 1.0f);
                        glLightf(iLight, GL_LINEAR_ATTENUATION, FIX2FLT(li->attenuation.y));
                        glLightf(iLight, GL_QUADRATIC_ATTENUATION, FIX2FLT(li->attenuation.z));
                        vals[0] = FIX2FLT(li->color.red)*intensity;
                        vals[1] = FIX2FLT(li->color.green)*intensity;
                        vals[2] = FIX2FLT(li->color.blue)*intensity;
                        vals[3] = 1;
                        glLightfv(iLight, GL_DIFFUSE, vals);
                        glLightfv(iLight, GL_SPECULAR, vals);
                        vals[0] = FIX2FLT(li->color.red)*ambientIntensity;
                        vals[1] = FIX2FLT(li->color.green)*ambientIntensity;
                        vals[2] = FIX2FLT(li->color.blue)*ambientIntensity;
                        vals[3] = 1;
                        glLightfv(iLight, GL_AMBIENT, vals);
                        
                        if (!beamWidth) exp = 1;
                        else if (beamWidth>cutOffAngle) exp = 0;
                        else {
                                exp = 1.0f - (Float) cos(beamWidth);
                                if (exp>1) exp = 1;
                        }
                        glLightf(iLight, GL_SPOT_EXPONENT,  exp*128);
                        glLightf(iLight, GL_SPOT_CUTOFF, 180*cutOffAngle/FIX2FLT(GF_PI));
#endif
                        break;
                
                case 2:
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
                        vals[0] = li->position.x;
                        vals[1] = li->position.y;
                        vals[2] = li->position.z;
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_POSITION, vals);
                        glLightx(iLight, GL_CONSTANT_ATTENUATION, li->attenuation.x ? li->attenuation.x : FIX_ONE);
                        glLightx(iLight, GL_LINEAR_ATTENUATION, li->attenuation.y);
                        glLightx(iLight, GL_QUADRATIC_ATTENUATION, li->attenuation.z);
                        vals[0] = gf_mulfix(li->color.red, li->intensity);
                        vals[1] = gf_mulfix(li->color.green, li->intensity);
                        vals[2] = gf_mulfix(li->color.blue, li->intensity);
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_DIFFUSE, vals);
                        glLightxv(iLight, GL_SPECULAR, vals);
                        vals[0] = gf_mulfix(li->color.red, li->ambientIntensity);
                        vals[1] = gf_mulfix(li->color.green, li->ambientIntensity);
                        vals[2] = gf_mulfix(li->color.blue, li->ambientIntensity);
                        vals[3] = FIX_ONE;
                        glLightxv(iLight, GL_AMBIENT, vals);
                        glLightx(iLight, GL_SPOT_EXPONENT, 0);
                        glLightx(iLight, GL_SPOT_CUTOFF, INT2FIX(180) );
#else
                        ambientIntensity = FIX2FLT(li->ambientIntensity);
                        intensity = FIX2FLT(li->intensity);
                        vals[0] = FIX2FLT(li->position.x);
                        vals[1] = FIX2FLT(li->position.y);
                        vals[2] = FIX2FLT(li->position.z);
                        vals[3] = 1;
                        glLightfv(iLight, GL_POSITION, vals);
                        glLightf(iLight, GL_CONSTANT_ATTENUATION, li->attenuation.x ? FIX2FLT(li->attenuation.x) : 1.0f);
                        glLightf(iLight, GL_LINEAR_ATTENUATION, FIX2FLT(li->attenuation.y));
                        glLightf(iLight, GL_QUADRATIC_ATTENUATION, FIX2FLT(li->attenuation.z));
                        vals[0] = FIX2FLT(li->color.red)*intensity;
                        vals[1] = FIX2FLT(li->color.green)*intensity;
                        vals[2] = FIX2FLT(li->color.blue)*intensity;
                        vals[3] = 1;
                        glLightfv(iLight, GL_DIFFUSE, vals);
                        glLightfv(iLight, GL_SPECULAR, vals);
                        vals[0] = FIX2FLT(li->color.red)*ambientIntensity;
                        vals[1] = FIX2FLT(li->color.green)*ambientIntensity;
                        vals[2] = FIX2FLT(li->color.blue)*ambientIntensity;
                        vals[3] = 1;
                        glLightfv(iLight, GL_AMBIENT, vals);
                        glLightf(iLight, GL_SPOT_EXPONENT, 0);
                        glLightf(iLight, GL_SPOT_CUTOFF, 180);
#endif
                        break;
                }
        }
        glEnable(GL_LIGHTING);
}
void visual_3d_enable_fog(GF_VisualManager *visual)
{
#ifndef GPAC_USE_TINYGL
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
        Fixed vals[4];
        glEnable(GL_FOG);
        if (!visual->fog_type) glFogx(GL_FOG_MODE, GL_LINEAR);
        else if (visual->fog_type==1) glFogx(GL_FOG_MODE, GL_EXP);
        else if (visual->fog_type==2) glFogx(GL_FOG_MODE, GL_EXP2);
        glFogx(GL_FOG_DENSITY, visual->fog_density);
        glFogx(GL_FOG_START, 0);
        glFogx(GL_FOG_END, visual->fog_visibility);
        vals[0] = visual->fog_color.red;
        vals[1] = visual->fog_color.green;
        vals[2] = visual->fog_color.blue;
        vals[3] = FIX_ONE;
        glFogxv(GL_FOG_COLOR, vals);
        glHint(GL_FOG_HINT, visual->compositor->high_speed ? GL_FASTEST : GL_NICEST);
#else
        Float vals[4];
        glEnable(GL_FOG);
#if defined(GPAC_USE_GLES1X)
        if (!visual->fog_type) glFogf(GL_FOG_MODE, GL_LINEAR);
        else if (visual->fog_type==1) glFogf(GL_FOG_MODE, GL_EXP);
        else if (visual->fog_type==2) glFogf(GL_FOG_MODE, GL_EXP2);
#else
        if (!visual->fog_type) glFogi(GL_FOG_MODE, GL_LINEAR);
        else if (visual->fog_type==1) glFogi(GL_FOG_MODE, GL_EXP);
        else if (visual->fog_type==2) glFogi(GL_FOG_MODE, GL_EXP2);
#endif
        glFogf(GL_FOG_DENSITY, FIX2FLT(visual->fog_density));
        glFogf(GL_FOG_START, 0);
        glFogf(GL_FOG_END, FIX2FLT(visual->fog_visibility));
        vals[0] = FIX2FLT(visual->fog_color.red);
        vals[1] = FIX2FLT(visual->fog_color.green);
        vals[2] = FIX2FLT(visual->fog_color.blue);
        vals[3] = 1;
        glFogfv(GL_FOG_COLOR, vals);
        glHint(GL_FOG_HINT, visual->compositor->high_speed ? GL_FASTEST : GL_NICEST);
#endif
#endif
}
#endif 
static void visual_3d_do_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh)
{
        u32 prim_type;
        GF_Matrix mx;
        u32 i, p_idx[6];
        void *idx_addr = NULL;
        GF_Plane fplanes[6];
        switch (mesh->mesh_type) {
        case MESH_LINESET:
                prim_type = GL_LINES;
                break;
        case MESH_POINTSET:
                prim_type = GL_POINTS;
                break;
        default:
                prim_type = GL_TRIANGLES;
                break;
        }
        if (mesh->vbo_idx) {
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->vbo_idx);
        } else {
                idx_addr = mesh->indices;
        }
        
        if (tr_state->visual->compositor->disable_gl_cull || (tr_state->cull_flag==CULL_INSIDE) || !mesh->aabb_root || !mesh->aabb_root->pos)   {
#if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2)
                glDrawElements(prim_type, mesh->i_count, GL_UNSIGNED_SHORT, idx_addr);
#else
                glDrawElements(prim_type, mesh->i_count, GL_UNSIGNED_INT, idx_addr);
#endif
        } else {
                
                
                gf_mx_copy(mx, tr_state->model_matrix);
                gf_mx_inverse(&mx);
                for (i=0; i<6; i++) {
                        fplanes[i] = tr_state->camera->planes[i];
                        gf_mx_apply_plane(&mx, &fplanes[i]);
                        p_idx[i] = gf_plane_get_p_vertex_idx(&fplanes[i]);
                }
                
                visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_idx, mesh->aabb_root->pos, idx_addr);
                visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_idx, mesh->aabb_root->neg, idx_addr);
        }
        if (mesh->vbo_idx) {
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        }
}
static Bool visual_3d_bind_buffer(GF_Compositor *compositor, GF_Mesh *mesh, void **base_address)
{
        *base_address = NULL;
        if ((compositor->reset_graphics==2) && mesh->vbo) {
                
                mesh->vbo = 0;
                mesh->vbo_idx = 0;
        }
        
        if (!mesh->vbo && compositor->gl_caps.vbo
#ifndef GPAC_USE_GLES2
                && (mesh->v_count>4)
#endif
           ) {
                glGenBuffers(1, &mesh->vbo);
                if (mesh->vbo) {
                        glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
                        glBufferData(GL_ARRAY_BUFFER, mesh->v_count * sizeof(GF_Vertex) , mesh->vertices, (mesh->vbo_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
                        mesh->vbo_dirty = 0;
                } else {
                        return GF_FALSE;
                }
                glGenBuffers(1, &mesh->vbo_idx);
                if (mesh->vbo_idx) {
                        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->vbo_idx);
                        glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->i_count*sizeof(IDX_TYPE), mesh->indices, (mesh->vbo_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
                } else {
                        return GF_FALSE;
                }
        }
        if (mesh->vbo) {
                *base_address = NULL;
                glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
        } else {
                *base_address = &mesh->vertices[0].pos;
        }
        if (mesh->vbo_dirty) {
                glBufferSubData(GL_ARRAY_BUFFER, 0, mesh->v_count * sizeof(GF_Vertex) , mesh->vertices);
                if (mesh->vbo_idx) {
                        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->vbo_idx);
                        glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->i_count*sizeof(IDX_TYPE), mesh->indices, (mesh->vbo_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
                        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
                }
                mesh->vbo_dirty = 0;
        }
        return GF_TRUE;
}
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
static void visual_3d_update_matrices_shaders(GF_TraverseState *tr_state)
{
        GF_Matrix mx;
        if (tr_state->visual->needs_projection_matrix_reload) {
                tr_state->visual->needs_projection_matrix_reload = 0;
                visual_3d_load_matrix_shaders(tr_state->visual->glsl_program, (Fixed *) tr_state->camera->projection.m, "gfProjectionMatrix");
        }
        
        gf_mx_copy(mx, tr_state->camera->modelview);
        gf_mx_add_matrix(&mx, &tr_state->model_matrix);
        visual_3d_load_matrix_shaders(tr_state->visual->glsl_program, (Fixed *) &mx.m, "gfModelViewMatrix");
}
static void visual_3d_set_lights_shaders(GF_TraverseState *tr_state)
{
        u32 i;
        GF_LightInfo *li;
        GF_Vec pt;
        Float ambientIntensity, intensity, vals[4];
        GLint loc;
        GF_Matrix mx;
        GF_VisualManager *visual = tr_state->visual;
        char szName[100];
        loc = gf_glGetUniformLocation(visual->glsl_program, "gfNumLights");
        if (loc>=0)
                glUniform1i(loc, visual->num_lights);
        GL_CHECK_ERR
        
        loc = gf_glGetUniformLocation(visual->glsl_program, "gfLightTwoSide");
        if (loc>=0)
                glUniform1i(loc, 1);
        GL_CHECK_ERR
        li = &visual->lights[0];
        pt = li->direction;
        gf_vec_norm(&pt);
        vals[0] = -FIX2FLT(pt.x);
        vals[1] = -FIX2FLT(pt.y);
        vals[2] = -FIX2FLT(pt.z);
        vals[3] = 0;
        ambientIntensity = FIX2FLT(li->ambientIntensity);
        intensity = FIX2FLT(li->intensity);
        for (i = 0; i < (int) visual->num_lights; i++) {
                GF_Vec orig;
                li = &visual->lights[i];
                if (li->type==3) {      
                        gf_mx_init(mx);
                } else {
                        
                        gf_mx_copy(mx, visual->camera.modelview);
                        gf_mx_add_matrix(&mx, &li->light_mx);
                }
                sprintf(szName, "%s%d%s", "lights[", i, "].type");
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);            
                if (loc>=0) {
                        if (li->type==3) {
                                glUniform1i(loc, 0); 
                        } else {
                                glUniform1i(loc, (GLint) li->type); 
                        }
                }
                
                pt = li->direction;
                orig.x = orig.y = orig.z = 0;
                gf_mx_apply_vec(&mx, &pt);
                gf_mx_apply_vec(&mx, &orig);
                gf_vec_diff(pt, pt, orig);
                gf_vec_norm(&pt);
                vals[0] = -FIX2FLT(pt.x);
                vals[1] = -FIX2FLT(pt.y);
                vals[2] = -FIX2FLT(pt.z);
                vals[3] = 0;
                sprintf(szName, "%s%d%s", "lights[", i, "].direction");
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);
                if (loc>=0)
                        glUniform4fv(loc, 1, vals); 
                if ((li->type==0) || (li->type==3) ) {
                        pt = li->direction;
                        vals[0] = -FIX2FLT(pt.x);
                        vals[1] = -FIX2FLT(pt.y);
                        vals[2] = -FIX2FLT(pt.z);
                        vals[3] = 0;
                        pt = li->position;
                } else {        
                        pt = li->position;
                        gf_mx_apply_vec(&mx, &pt);
                        vals[0] = FIX2FLT(pt.x);
                        vals[1] = FIX2FLT(pt.y);
                        vals[2] = FIX2FLT(pt.z);
                        vals[3] = 1.0;
                }
                sprintf(szName, "%s%d%s", "lights[", i, "].position");
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);
                if (loc>=0)
                        glUniform4fv(loc, 1, vals);
                pt = li->attenuation;
                if (li->type && !li->attenuation.x) {
                        vals[0]=1.0;
                } else {
                        vals[0] = FIX2FLT(pt.x);
                }
                vals[1] = FIX2FLT(pt.y);
                vals[2] = FIX2FLT(pt.z);
                sprintf(szName, "%s%d%s", "lights[", i, "].attenuation");
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);
                if (loc>=0)
                        glUniform3fv(loc, 1, vals);
                vals[0] = FIX2FLT(li->color.red);
                vals[1] = FIX2FLT(li->color.green);
                vals[2] = FIX2FLT(li->color.blue);
                vals[3] = 0;
                sprintf(szName, "%s%d%s", "lights[", i, "].color");
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);
                if (loc>=0)
                        glUniform4fv(loc, 1, vals);
                sprintf(szName, "%s%d%s", "lights[", i, "].intensity");
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);
                if (loc>=0)
                        glUniform1f(loc, li->intensity);
                sprintf(szName, "%s%d%s", "lights[", i, "].cutOffAngle");
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);
                if (loc>=0)
                        glUniform1f(loc, li->cutOffAngle);
        }
        vals[0] = FIX2FLT(li->color.red)*intensity;
        vals[1] = FIX2FLT(li->color.green)*intensity;
        vals[2] = FIX2FLT(li->color.blue)*intensity;
        vals[3] = 1;
        loc = gf_glGetUniformLocation(visual->glsl_program, "gfLightDiffuse");
        if (loc>=0) glUniform4fv(loc, 1, vals);
        loc = gf_glGetUniformLocation(visual->glsl_program, "gfLightSpecular");
        if (loc>=0) glUniform4fv(loc, 1, vals);
        vals[0] = FIX2FLT(li->color.red)*ambientIntensity;
        vals[1] = FIX2FLT(li->color.green)*ambientIntensity;
        vals[2] = FIX2FLT(li->color.blue)*ambientIntensity;
        vals[3] = 1;
        loc = gf_glGetUniformLocation(visual->glsl_program, "gfLightAmbient");
        if (loc>=0) glUniform4fv(loc, 1, vals);
        GL_CHECK_ERR
}
static void visual_3d_set_fog_shaders(GF_VisualManager *visual)
{
        GLint loc;
        if (visual->has_fog) {
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfFogEnabled");
                if(loc>=0)
                        glUniform1i(loc, GL_TRUE);
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfFogColor");
                if(loc>=0)
                        glUniform3fv(loc, 1, (GLfloat *) &visual->fog_color);
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfFogDensity");
                if(loc>=0)
                        glUniform1f(loc, visual->fog_density );
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfFogType");
                if(loc>=0)
                        glUniform1i(loc, (GLuint) visual->fog_type );
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfFogVisibility");
                if(loc>=0)
                        glUniform1f(loc, visual->fog_visibility);
        } else {
                loc = glGetUniformLocation(visual->glsl_program, "gfFogEnabled");
                if(loc>=0)
                        glUniform1i(loc, GL_FALSE);
        }
        GL_CHECK_ERR
}
static void visual_3d_set_clippers_shaders(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
        Fixed vals[4];
        char szName[100];
        GLint loc;
        u32 i;
        GF_Matrix inv_mx, eye_mx;
        if (!visual->num_clips) return;
        gf_mx_copy(inv_mx, tr_state->model_matrix);
        gf_mx_inverse(&inv_mx);
        gf_mx_copy(eye_mx, tr_state->camera->modelview);
        gf_mx_add_matrix(&eye_mx, &tr_state->model_matrix);
        loc = gf_glGetUniformLocation(visual->glsl_program, "gfNumClippers");
        if (loc>=0)
                glUniform1i(loc, visual->num_clips);
        for (i = 0; i < visual->num_clips; i++) {
                GF_Matrix mx;
                GF_Plane p;
                p = visual->clippers[i].p;
                
                if (! visual->clippers[i].is_2d_clip) {
                        gf_mx_copy(mx, inv_mx);
                        if (visual->clippers[i].mx_clipper != NULL) {
                                gf_mx_add_matrix(&mx, visual->clippers[i].mx_clipper);
                        }
                        
                        gf_mx_apply_plane(&mx, &p);
                        
                        gf_mx_apply_plane(&eye_mx, &p);
                }
                sprintf(szName, "%s%d%s", "clipPlane[", i, "]");        
                loc = gf_glGetUniformLocation(visual->glsl_program, szName);
                if (loc>=0) {
                        vals[0] = p.normal.x;
                        vals[1] = p.normal.y;
                        vals[2] = p.normal.z;
                        vals[3] = p.d;
                        glUniform4fv(loc, 1, vals); 
                }
        }
}
static void visual_3d_draw_mesh_shader_only(GF_TraverseState *tr_state, GF_Mesh *mesh)
{
        void *vertex_buffer_address;
        GF_VisualManager *visual = tr_state->visual;
        GF_VisualManager *root_visual = visual->compositor->visual;
        GLint loc, loc_vertex_array, loc_color_array, loc_normal_array, loc_textcoord_array;
        u32 flags;
        u32 num_lights = visual->num_lights;
        
        flags = root_visual->glsl_flags;
        if (visual->has_material_2d) {
                num_lights = 0;
        }
        if (!tr_state->mesh_num_textures && (mesh->flags & MESH_HAS_COLOR)) {
                flags |= GF_GL_HAS_COLOR;
                visual->has_material_2d = GF_FALSE;
        }
        else if (tr_state->mesh_num_textures && (mesh->mesh_type==MESH_TRIANGLES) && !(mesh->flags & MESH_NO_TEXTURE)) {
                flags |= GF_GL_HAS_TEXTURE;
        } else {
                flags &= ~GF_GL_HAS_TEXTURE;
                flags &= ~GF_GL_IS_YUV;
                flags &= ~GF_GL_IS_ExternalOES;
        }
        if (num_lights) {
                flags |= GF_GL_HAS_LIGHT;
        } else {
                flags &= ~GF_GL_HAS_LIGHT;
        }
        if (visual->num_clips) {
                flags |= GF_GL_HAS_CLIP;
        } else {
                flags &= ~GF_GL_HAS_CLIP;
        }
        root_visual->glsl_flags = visual->glsl_flags = flags;
        
        if ((visual->glsl_program != root_visual->glsl_programs[visual->glsl_flags])
                || !root_visual->glsl_programs[visual->glsl_flags]) {
                tr_state->visual->needs_projection_matrix_reload = GF_TRUE;
        }
        GL_CHECK_ERR
        visual->glsl_program = root_visual->glsl_programs[visual->glsl_flags];
        glUseProgram(visual->glsl_program);
        GL_CHECK_ERR
        if (! visual_3d_bind_buffer(visual->compositor, mesh, &vertex_buffer_address)) {
                glUseProgram(0);
                return;
        }
        if (visual->state_blend_on)
                glEnable(GL_BLEND);
        visual_3d_update_matrices_shaders(tr_state);
        loc_color_array = loc_normal_array = loc_textcoord_array = -1;
        
        loc_vertex_array = gf_glGetAttribLocation(visual->glsl_program, "gfVertex");
        if (loc_vertex_array<0)
                return;
        glEnableVertexAttribArray(loc_vertex_array);
        GL_CHECK_ERR
#if defined(GPAC_FIXED_POINT)
        glVertexAttribPointer(loc_vertex_array, 3, GL_FIXED, GL_TRUE, sizeof(GF_Vertex), vertex_buffer_address);
#else
        glVertexAttribPointer(loc_vertex_array, 3, GL_FLOAT, GL_FALSE, sizeof(GF_Vertex), vertex_buffer_address);
#endif
        
        visual_3d_set_clipper_scissor(visual, tr_state);
        
        visual_3d_set_clippers_shaders(visual, tr_state);
        
        if (visual->has_material_2d) {
                
                if (flags & GF_GL_IS_YUV) {
                        loc = gf_glGetUniformLocation(visual->glsl_program, "alpha");
                        if(loc>=0)
                                glUniform1f(loc, FIX2FLT(visual->mat_2d.alpha));
                }
                
                else if (!tr_state->mesh_num_textures) {
                        if (visual->mat_2d.alpha < FIX_ONE) {
                                glEnable(GL_BLEND);
                        } else {
                                glDisable(GL_BLEND);
                        }
                }
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfEmissionColor");
                if (loc>=0)
                        glUniform4fv(loc, 1, (GLfloat *) & visual->mat_2d);
                GL_CHECK_ERR
                loc = gf_glGetUniformLocation(visual->glsl_program, "hasMaterial2D");
                if (loc>=0)
                        glUniform1i(loc, 1);
                GL_CHECK_ERR
        } else {
                loc = gf_glGetUniformLocation(visual->glsl_program, "hasMaterial2D");
                if (loc>=0)
                        glUniform1i(loc, 0);
                GL_CHECK_ERR
                
                if (flags & GF_GL_IS_YUV) {
                        loc = gf_glGetUniformLocation(visual->glsl_program, "alpha");
                        if(loc>=0)
                                glUniform1f(loc, 1.0);
                        GL_CHECK_ERR
                }
        }
        
        if ((flags & GF_GL_HAS_LIGHT) && visual->has_material && !visual->has_material_2d) {
                u32 i;
                for(i =0; i<4; i++) {
                        Fixed *rgba = (Fixed *) & visual->materials[i];
#if defined(GPAC_FIXED_POINT)
                        Float _rgba[4];
                        _rgba[0] = FIX2FLT(rgba[0]);
                        _rgba[1] = FIX2FLT(rgba[1]);
                        _rgba[2] = FIX2FLT(rgba[2]);
                        _rgba[3] = FIX2FLT(rgba[3]);
#elif defined(GPAC_USE_GLES1X)
                        Fixed *_rgba = (Fixed *) rgba;
#else
                        Float *_rgba = (Float *) rgba;
#endif
                        switch (i) {
                        case 0:
                                loc = gf_glGetUniformLocation(visual->glsl_program, "gfAmbientColor");
                                break;
                        case 1:
                                loc = gf_glGetUniformLocation(visual->glsl_program, "gfDiffuseColor");
                                break;
                        case 2:
                                loc = gf_glGetUniformLocation(visual->glsl_program, "gfSpecularColor");
                                break;
                        case 3:
                                loc = gf_glGetUniformLocation(visual->glsl_program, "gfEmissionColor");
                                break;
                        }
                        if (loc>=0)
                                glUniform4fv(loc, 1, _rgba);
                }
                
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfShininess");
                if (loc>=0)
                        glUniform1f(loc, FIX2FLT(visual->shininess));
                glDisable(GL_CULL_FACE);        
        }
        
        if (!tr_state->mesh_num_textures && (mesh->flags & MESH_HAS_COLOR)) {
                loc_color_array = gf_glGetAttribLocation(visual->glsl_program, "gfMeshColor");
                if (loc_color_array >= 0) {
                        
                        if (mesh->flags & MESH_HAS_ALPHA) {
                                glEnable(GL_BLEND);
                                tr_state->mesh_is_transparent = 1;
                                glVertexAttribPointer(loc_color_array, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GF_Vertex), ((char *)vertex_buffer_address + MESH_COLOR_OFFSET));
                        } else {
                                glVertexAttribPointer(loc_color_array, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GF_Vertex), ((char *)vertex_buffer_address + MESH_COLOR_OFFSET));
                        }
                        glEnableVertexAttribArray(loc_color_array);
                }
                GL_CHECK_ERR
        }
        if (flags & GF_GL_HAS_LIGHT) {
                visual_3d_set_fog_shaders(visual);
        }
        
        if (!visual->has_material_2d && num_lights && (mesh->mesh_type==MESH_TRIANGLES) ) {
                GF_Matrix normal_mx;
                assert(flags & GF_GL_HAS_LIGHT);
                gf_mx_copy(normal_mx, tr_state->camera->modelview);
                gf_mx_add_matrix(&normal_mx, &tr_state->model_matrix);
                normal_mx.m[12] = normal_mx.m[13] = normal_mx.m[14] = 0;
                gf_mx_inverse(&normal_mx);
                gf_mx_transpose(&normal_mx);
                visual_3d_load_matrix_shaders(tr_state->visual->glsl_program, (Fixed *) &normal_mx.m, "gfNormalMatrix");
                loc_normal_array = gf_glGetAttribLocation(visual->glsl_program, "gfNormal");
                if (loc_normal_array>=0) {
#ifdef MESH_USE_FIXED_NORMAL
                        glVertexAttribPointer(loc_normal_array, 3, GL_FLOAT, GL_FALSE, sizeof(GF_Vertex),  ((char *)vertex_buffer_address + MESH_NORMAL_OFFSET) );
#else
                        glVertexAttribPointer(loc_normal_array, 3, GL_BYTE, GL_FALSE, sizeof(GF_Vertex),  ((char *)vertex_buffer_address + MESH_NORMAL_OFFSET) );
#endif
                        glEnableVertexAttribArray(loc_normal_array);
                }
                GL_CHECK_ERR
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfNumLights");
                if (loc>=0)
                        glUniform1i(loc, num_lights);
                visual_3d_set_lights_shaders(tr_state);
                GL_CHECK_ERR
        }
        
        if (tr_state->mesh_num_textures && (mesh->mesh_type==MESH_TRIANGLES) && !(mesh->flags & MESH_NO_TEXTURE)) {
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfNumTextures");
                if (loc>=0) {
                        glUniform1i(loc, tr_state->mesh_num_textures);
                }
                GL_CHECK_ERR
                if (visual->has_tx_matrix) {
                        
                        loc = gf_glGetUniformLocation(visual->glsl_program, "gfTextureMatrix");
                        if (loc>=0)
                                glUniformMatrix4fv(loc, 1, GL_FALSE, visual->tx_matrix.m);
                        GL_CHECK_ERR
                        loc = gf_glGetUniformLocation(visual->glsl_program, "hasTextureMatrix");
                        if (loc>=0) glUniform1i(loc, 1);
                } else {
                        loc = gf_glGetUniformLocation(visual->glsl_program, "hasTextureMatrix");
                        if (loc>=0) glUniform1i(loc, 0);
                }
                
                loc_textcoord_array = gf_glGetAttribLocation(visual->glsl_program, "gfMultiTexCoord");
                if (loc_textcoord_array>=0) {
                        glVertexAttribPointer(loc_textcoord_array, 2, GL_FLOAT, GL_FALSE, sizeof(GF_Vertex), ((char *)vertex_buffer_address + MESH_TEX_OFFSET));
                        glEnableVertexAttribArray(loc_textcoord_array);
                        GL_CHECK_ERR
                }
                if (flags & GF_GL_IS_YUV) {
                        loc = gf_glGetUniformLocation(visual->glsl_program, "yuvPixelFormat");
                        if (loc>=0) {
                                int yuv_mode = 0;
                                if (visual->yuv_pixelformat_type == GF_PIXEL_NV21) yuv_mode = 1;
                                else if (visual->yuv_pixelformat_type == GF_PIXEL_NV12) yuv_mode = 2;
                        
                                glUniform1i(loc, yuv_mode);
                        }
                        GL_CHECK_ERR
                }
        }
        
        if (mesh->mesh_type != MESH_TRIANGLES) {
                
                if(flags & GF_GL_HAS_LIGHT) {
                        loc = gf_glGetUniformLocation(visual->glsl_program, "gfNumLights");
                        if (loc>=0)     glUniform1i(loc, 0);
                }
                glDisable(GL_CULL_FACE);
#if !defined(GPAC_USE_TINYGL) && !defined(GL_ES_CL_PROFILE)
                glLineWidth(1.0f);
#endif
        } else {
                if (visual->compositor->backcull
                        && (!tr_state->mesh_is_transparent || (visual->compositor->backcull ==GF_BACK_CULL_ALPHA) )
                        && (mesh->flags & MESH_IS_SOLID)) {
                        glEnable(GL_CULL_FACE);
                        glFrontFace((mesh->flags & MESH_IS_CW) ? GL_CW : GL_CCW);
                } else {
                        glDisable(GL_CULL_FACE);
                }
        }
        GL_CHECK_ERR
        
        if(!tr_state->color_mat.identity) {
                GF_Matrix toBeParsed;   
                Fixed translateV[4];    
                int row,col;
                gf_mx_init(toBeParsed);
                
                for(row=0; row<4; row++) {
                        for(col=0; col<4; col++) {
                                toBeParsed.m[col+(row*4)]=tr_state->color_mat.m[col+(row*5)];
                        }
                        translateV[row] = tr_state->color_mat.m[4+(row*5)];
                }
                
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfTranslationVector");
                if (loc>=0)
                        glUniform4fv(loc, 1, (GLfloat *) &translateV);
                GL_CHECK_ERR
                loc = glGetUniformLocation(visual->glsl_program, "hasColorMatrix");
                if(loc>=0) glUniform1i(loc, 1);
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfColorMatrix");
                if (loc>=0)
                        glUniformMatrix4fv(loc, 1, GL_FALSE, toBeParsed.m);
                GL_CHECK_ERR
        } else {
                loc = glGetUniformLocation(visual->glsl_program, "hasColorMatrix");
                if(loc>=0) glUniform1i(loc, 0);
        }
        
        if(tr_state->col_key) {
                Float vals[3];
                Float eightbit = 255;   
                glEnable(GL_BLEND);             
                loc = glGetUniformLocation(visual->glsl_program, "hasColorKey");
                if(loc>=0) glUniform1i(loc, 1);
                vals[0] = tr_state->col_key->r/eightbit;
                vals[1] = tr_state->col_key->g/eightbit;
                vals[2] = tr_state->col_key->b/eightbit;
                loc = glGetUniformLocation(visual->glsl_program, "gfKeyColor");
                if(loc>=0)glUniform3fv(loc, 1, vals);
                loc = glGetUniformLocation(visual->glsl_program, "gfKeyLow");
                if(loc>=0) glUniform1f(loc, tr_state->col_key->low/eightbit);
                loc = glGetUniformLocation(visual->glsl_program, "gfKeyHigh");
                if(loc>=0) glUniform1f(loc, tr_state->col_key->high/eightbit);
                loc = glGetUniformLocation(visual->glsl_program, "gfKeyAlpha");
                if(loc>=0) glUniform1f(loc, tr_state->col_key->alpha/eightbit);
        } else {
                loc = glGetUniformLocation(visual->glsl_program, "hasColorKey");
                if(loc>=0) glUniform1i(loc, 0);
        }
        visual_3d_do_draw_mesh(tr_state, mesh);
        GL_CHECK_ERR
        
        if (mesh->vbo)
                glBindBuffer(GL_ARRAY_BUFFER, 0);
        if (mesh->vbo)
                glBindBuffer(GL_ARRAY_BUFFER, 0);
        if (loc_vertex_array>=0) glDisableVertexAttribArray(loc_vertex_array);
        if (loc_color_array>=0) glDisableVertexAttribArray(loc_color_array);
        if (loc_normal_array>=0) glDisableVertexAttribArray(loc_normal_array);
        if (loc_textcoord_array>=0) glDisableVertexAttribArray(loc_textcoord_array);
        
        if(visual->compositor->visual->glsl_flags & GF_GL_HAS_LIGHT) {
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfNumLights");
                if (loc>=0)     glUniform1i(loc, 0);
                GL_CHECK_ERR
        }
        if (visual->has_clipper_2d) {
                glDisable(GL_SCISSOR_TEST);
        }
        visual->has_material_2d = 0;
        visual->glsl_flags = visual->compositor->visual->glsl_flags;
        root_visual->glsl_flags &= ~ (GF_GL_IS_ExternalOES | GF_GL_IS_YUV | GF_GL_HAS_COLOR);
        visual->has_material = 0;
        visual->state_color_on = 0;
        if (tr_state->mesh_is_transparent) glDisable(GL_BLEND);
        tr_state->mesh_is_transparent = 0;
        GL_CHECK_ERR
        glUseProgram(0);
        GL_CHECK_ERR
}
#endif 
static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh)
{
#ifndef GPAC_USE_GLES2
        GF_Compositor *compositor = tr_state->visual->compositor;
        GF_VisualManager *visual = tr_state->visual;
        Bool has_col, has_tx, has_norm;
        void *base_address = NULL;
#if defined(GPAC_FIXED_POINT) && !defined(GPAC_USE_GLES1X)
        Float *color_array = NULL;
        Float fix_scale = 1.0f;
        fix_scale /= FIX_ONE;
#endif
#endif
        GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[V3D] Drawing mesh %p\n", mesh));
        
        glGetError();
        GL_CHECK_ERR
#ifdef GPAC_USE_GLES2
        visual_3d_draw_mesh_shader_only(tr_state, mesh);
        return;
#else
#if !defined(GPAC_ANDROID) && !defined(GPAC_IPHONE) && !defined(GPAC_FIXED_POINT)
        if (visual->compositor->shader_only_mode) {
                visual_3d_draw_mesh_shader_only(tr_state, mesh);
                return;
        }
#endif
        if (! visual_3d_bind_buffer(compositor, mesh, &base_address)) {
#if! defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL)
                glUseProgram(0);
#endif
                return;
        }
        has_col = has_tx = has_norm = 0;
        
        visual_3d_set_lights(visual);
        visual_3d_update_matrices(tr_state);
        
        if (visual->has_fog) visual_3d_enable_fog(visual);
        if (visual->state_color_on) glEnable(GL_COLOR_MATERIAL);
        else glDisable(GL_COLOR_MATERIAL);
        if (visual->state_blend_on) glEnable(GL_BLEND);
        
        visual_3d_set_clipper_scissor(visual, tr_state);
        if (visual->num_clips)
                visual_3d_set_clippers(visual, tr_state);
        glEnableClientState(GL_VERTEX_ARRAY);
#if defined(GPAC_USE_GLES1X)
        glVertexPointer(3, GL_FIXED, sizeof(GF_Vertex),  base_address);
#elif defined(GPAC_FIXED_POINT)
        
        glPushMatrix();
        glScalef(fix_scale, fix_scale, fix_scale);
        glVertexPointer(3, GL_INT, sizeof(GF_Vertex), base_address);
#else
        glVertexPointer(3, GL_FLOAT, sizeof(GF_Vertex), base_address);
#endif
        
        if (visual->has_material_2d) {
                glDisable(GL_LIGHTING);
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL)
                if (visual->compositor->visual->current_texture_glsl_program) {
                        int loc = glGetUniformLocation(visual->compositor->visual->current_texture_glsl_program, "alpha");
                        if (loc == -1) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate uniform \"alpha\" in YUV shader\n"));
                        } else {
                                glUniform1f(loc, FIX2FLT(visual->mat_2d.alpha) );
                        }
                } else
#endif
                {
                        if (visual->mat_2d.alpha != FIX_ONE) {
                                glEnable(GL_BLEND);
                                visual_3d_enable_antialias(visual, 0);
                        } else {
                                
                                if (!tr_state->mesh_num_textures)
                                        glDisable(GL_BLEND);
                                visual_3d_enable_antialias(visual, visual->compositor->antiAlias ? 1 : 0);
                        }
#ifdef GPAC_USE_GLES1X
                        glColor4x( FIX2INT(visual->mat_2d.red * 255), FIX2INT(visual->mat_2d.green * 255), FIX2INT(visual->mat_2d.blue * 255), FIX2INT(visual->mat_2d.alpha * 255));
#elif defined(GPAC_FIXED_POINT)
                        glColor4f(FIX2FLT(visual->mat_2d.red), FIX2FLT(visual->mat_2d.green), FIX2FLT(visual->mat_2d.blue), FIX2FLT(visual->mat_2d.alpha));
#else
                        glColor4f(visual->mat_2d.red, visual->mat_2d.green, visual->mat_2d.blue, visual->mat_2d.alpha);
#endif
                }
        }
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL)
        else if (visual->compositor->visual->current_texture_glsl_program) {
                int loc = glGetUniformLocation(visual->compositor->visual->current_texture_glsl_program, "alpha");
                if (loc == -1) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate uniform \"alpha\" in YUV shader\n"));
                } else {
                        glUniform1f(loc, 1.0 );
                }
        }
#endif
        
        if (visual->has_material) {
                u32 i;
                GL_CHECK_ERR
                for (i=0; i<4; i++) {
                        GLenum mode;
                        Fixed *rgba = (Fixed *) & visual->materials[i];
#if defined(GPAC_USE_GLES1X)
                        Fixed *_rgba = (Fixed *) rgba;
#elif defined(GPAC_FIXED_POINT)
                        Float _rgba[4];
                        _rgba[0] = FIX2FLT(rgba[0]);
                        _rgba[1] = FIX2FLT(rgba[1]);
                        _rgba[2] = FIX2FLT(rgba[2]);
                        _rgba[3] = FIX2FLT(rgba[3]);
#else
                        Float *_rgba = (Float *) rgba;
#endif
                        switch (i) {
                        case 0:
                                mode = GL_AMBIENT;
                                break;
                        case 1:
                                mode = GL_DIFFUSE;
                                break;
                        case 2:
                                mode = GL_SPECULAR;
                                break;
                        default:
                                mode = GL_EMISSION;
                                break;
                        }
#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT)
                        glMaterialxv(GL_FRONT_AND_BACK, mode, _rgba);
#else
                        glMaterialfv(GL_FRONT_AND_BACK, mode, _rgba);
#endif
                        GL_CHECK_ERR
                }
#ifdef GPAC_USE_GLES1X
                glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, visual->shininess * 128);
#else
                glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, FIX2FLT(visual->shininess) * 128);
#endif
                GL_CHECK_ERR
        }
        
        if (!tr_state->mesh_num_textures && (mesh->flags & MESH_HAS_COLOR)) {
                glEnable(GL_COLOR_MATERIAL);
#if !defined (GPAC_USE_GLES1X)
                glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
#endif
                glEnableClientState(GL_COLOR_ARRAY);
                has_col = 1;
#if defined (GPAC_USE_GLES1X)
                if (mesh->flags & MESH_HAS_ALPHA) {
                        glEnable(GL_BLEND);
                        tr_state->mesh_is_transparent = 1;
                }
#ifdef MESH_USE_SFCOLOR
                
                glColorPointer(4, GL_FIXED, sizeof(GF_Vertex), ((char *)base_address + MESH_COLOR_OFFSET));
#else
                glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(GF_Vertex), ((char *)base_address + MESH_COLOR_OFFSET));
#endif  
#elif defined (GPAC_FIXED_POINT)
#ifdef MESH_USE_SFCOLOR
                
                if (mesh->flags & MESH_HAS_ALPHA) {
                        u32 i;
                        color_array = gf_malloc(sizeof(Float)*4*mesh->v_count);
                        for (i=0; i<mesh->v_count; i++) {
                                color_array[4*i] = FIX2FLT(mesh->vertices[i].color.red);
                                color_array[4*i+1] = FIX2FLT(mesh->vertices[i].color.green);
                                color_array[4*i+2] = FIX2FLT(mesh->vertices[i].color.blue);
                                color_array[4*i+3] = FIX2FLT(mesh->vertices[i].color.alpha);
                        }
                        glEnable(GL_BLEND);
                        glColorPointer(4, GL_FLOAT, 4*sizeof(Float), color_array);
                        tr_state->mesh_is_transparent = 1;
                } else {
                        color_array = gf_malloc(sizeof(Float)*3*mesh->v_count);
                        for (i=0; i<mesh->v_count; i++) {
                                color_array[3*i] = FIX2FLT(mesh->vertices[i].color.red);
                                color_array[3*i+1] = FIX2FLT(mesh->vertices[i].color.green);
                                color_array[3*i+2] = FIX2FLT(mesh->vertices[i].color.blue);
                        }
                        glColorPointer(3, GL_FLOAT, 3*sizeof(Float), color_array);
                }
#else
                glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(GF_Vertex), ((char *)base_address + MESH_COLOR_OFFSET));
#endif 
#else
#ifdef MESH_USE_SFCOLOR
                if (mesh->flags & MESH_HAS_ALPHA) {
                        glEnable(GL_BLEND);
                        glColorPointer(4, GL_FLOAT, sizeof(GF_Vertex), ((char *)base_address + MESH_COLOR_OFFSET));
                        tr_state->mesh_is_transparent = 1;
                } else {
                        glColorPointer(3, GL_FLOAT, sizeof(GF_Vertex), ((char *)base_address + MESH_COLOR_OFFSET));
                }
#else
                if (mesh->flags & MESH_HAS_ALPHA) {
                        glEnable(GL_BLEND);
                        tr_state->mesh_is_transparent = 1;
                        glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(GF_Vertex), ((char *)base_address + MESH_COLOR_OFFSET));
                } else {
                        glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(GF_Vertex), ((char *)base_address + MESH_COLOR_OFFSET));
                }
#endif 
#endif
        }
        if (tr_state->mesh_num_textures && (mesh->mesh_type==MESH_TRIANGLES) && !(mesh->flags & MESH_NO_TEXTURE)) {
                has_tx = 1;
                glMatrixMode(GL_TEXTURE);
                if (visual->has_tx_matrix) {
                        visual_3d_matrix_load(visual, visual->tx_matrix.m);
                } else {
                        glLoadIdentity();
                }
                glMatrixMode(GL_MODELVIEW);
#if defined(GPAC_USE_GLES1X)
                glTexCoordPointer(2, GL_FIXED, sizeof(GF_Vertex), ((char *)base_address + MESH_TEX_OFFSET));
                glEnableClientState(GL_TEXTURE_COORD_ARRAY );
#elif defined(GPAC_FIXED_POINT)
                glMatrixMode(GL_TEXTURE);
                glPushMatrix();
                glScalef(fix_scale, fix_scale, fix_scale);
                glMatrixMode(GL_MODELVIEW);
                glTexCoordPointer(2, GL_INT, sizeof(GF_Vertex), ((char *)base_address + MESH_TEX_OFFSET));
                glEnableClientState(GL_TEXTURE_COORD_ARRAY );
#else
#ifndef GPAC_USE_TINYGL
                if (tr_state->mesh_num_textures>1) {
                        u32 i;
                        for (i=0; i<tr_state->mesh_num_textures; i++) {
                                glClientActiveTexture(GL_TEXTURE0 + i);
                                glTexCoordPointer(2, GL_FLOAT, sizeof(GF_Vertex), ((char *)base_address + MESH_TEX_OFFSET));
                                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                        }
                } else
#endif 
                {
                        glTexCoordPointer(2, GL_FLOAT, sizeof(GF_Vertex), ((char *)base_address + MESH_TEX_OFFSET));
                        glEnableClientState(GL_TEXTURE_COORD_ARRAY );
                }
#endif
        }
        if (mesh->mesh_type != MESH_TRIANGLES) {
#ifdef GPAC_USE_GLES1X
                glNormal3x(0, 0, FIX_ONE);
#else
                glNormal3f(0, 0, 1.0f);
#endif
                glDisable(GL_CULL_FACE);
                glDisable(GL_LIGHTING);
                if (mesh->mesh_type==MESH_LINESET) glDisable(GL_LINE_SMOOTH);
                else glDisable(GL_POINT_SMOOTH);
#if !defined(GPAC_USE_TINYGL) && !defined(GL_ES_CL_PROFILE)
                glLineWidth(1.0f);
#endif
        } else {
                u32 normal_type = GL_FLOAT;
                has_norm = 1;
                glEnableClientState(GL_NORMAL_ARRAY );
#ifdef MESH_USE_FIXED_NORMAL
#if defined(GPAC_USE_GLES1X)
                normal_type = GL_FIXED;
#elif defined(GPAC_FIXED_POINT)
                normal_type = GL_INT;
#else
                normal_type = GL_FLOAT;
#endif
#else 
                
                normal_type = GL_BYTE;
#endif
                glNormalPointer(normal_type, sizeof(GF_Vertex), ((char *)base_address + MESH_NORMAL_OFFSET));
                if (mesh->mesh_type==MESH_TRIANGLES) {
                        if (compositor->backcull
                                && (!tr_state->mesh_is_transparent || (compositor->backcull ==GF_BACK_CULL_ALPHA) )
                                && (mesh->flags & MESH_IS_SOLID)) {
                                glEnable(GL_CULL_FACE);
                                glFrontFace((mesh->flags & MESH_IS_CW) ? GL_CW : GL_CCW);
                        } else {
                                glDisable(GL_CULL_FACE);
                        }
                }
        }
        GL_CHECK_ERR
        visual_3d_do_draw_mesh(tr_state, mesh);
        GL_CHECK_ERR
        glDisableClientState(GL_VERTEX_ARRAY);
        if (has_col) glDisableClientState(GL_COLOR_ARRAY);
        glDisable(GL_COLOR_MATERIAL);
        if (has_tx) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        if (has_norm) glDisableClientState(GL_NORMAL_ARRAY);
        if (mesh->vbo)
                glBindBuffer(GL_ARRAY_BUFFER, 0);
#if defined(GPAC_FIXED_POINT) && !defined(GPAC_USE_GLES1X)
        if (color_array) gf_free(color_array);
        if (tr_state->mesh_num_textures && (mesh->mesh_type==MESH_TRIANGLES) && !(mesh->flags & MESH_NO_TEXTURE)) {
                glMatrixMode(GL_TEXTURE);
                glPopMatrix();
                glMatrixMode(GL_MODELVIEW);
        }
        glPopMatrix();
#endif
        if (visual->has_clipper_2d) {
                glDisable(GL_SCISSOR_TEST);
        }
        visual_3d_reset_lights(visual);
        glDisable(GL_COLOR_MATERIAL);
        
        if (visual->num_clips)
                visual_3d_reset_clippers(visual);
        visual->has_material_2d = 0;
        visual->has_material = 0;
        visual->state_color_on = 0;
        if (tr_state->mesh_is_transparent) glDisable(GL_BLEND);
        tr_state->mesh_is_transparent = 0;
        GL_CHECK_ERR
#endif
}
static void visual_3d_set_debug_color(u32 col)
{
#ifndef GPAC_USE_GLES2
#ifdef GPAC_USE_GLES1X
        glColor4x( (col ? GF_COL_R(col) : 255) , (col ? GF_COL_G(col) : 0) , (col ? GF_COL_B(col) : 255), 255);
#else
        glColor4f(col ? GF_COL_R(col)/255.0f : 1, col ? GF_COL_G(col)/255.0f : 0, col ? GF_COL_B(col)/255.0f : 1, 1);
#endif
#endif 
}
static void visual_3d_draw_normals(GF_TraverseState *tr_state, GF_Mesh *mesh)
{
#if !defined( GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES2)
        GF_Vec pt, end;
        u32 i, j;
        Fixed scale = mesh->bounds.radius / 4;
#ifdef GPAC_USE_GLES1X
        GF_Vec va[2];
        u16 indices[2];
        glEnableClientState(GL_VERTEX_ARRAY);
#endif
        visual_3d_set_debug_color(0);
        if (tr_state->visual->compositor->draw_normals==GF_NORMALS_VERTEX) {
                IDX_TYPE *idx = mesh->indices;
                for (i=0; i<mesh->i_count; i+=3) {
                        for (j=0; j<3; j++) {
                                pt = mesh->vertices[idx[j]].pos;
                                MESH_GET_NORMAL(end, mesh->vertices[idx[j]]);
                                end = gf_vec_scale(end, scale);
                                gf_vec_add(end, pt, end);
#ifdef GPAC_USE_GLES1X
                                va[0] = pt;
                                va[1] = end;
                                indices[0] = 0;
                                indices[1] = 1;
                                glVertexPointer(3, GL_FIXED, 0, va);
                                glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, indices);
#else
                                glBegin(GL_LINES);
                                glVertex3f(FIX2FLT(pt.x), FIX2FLT(pt.y), FIX2FLT(pt.z));
                                glVertex3f(FIX2FLT(end.x), FIX2FLT(end.y), FIX2FLT(end.z));
                                glEnd();
#endif
                        }
                        idx+=3;
                }
        } else {
                IDX_TYPE *idx = mesh->indices;
                for (i=0; i<mesh->i_count; i+=3) {
                        gf_vec_add(pt, mesh->vertices[idx[0]].pos, mesh->vertices[idx[1]].pos);
                        gf_vec_add(pt, pt, mesh->vertices[idx[2]].pos);
                        pt = gf_vec_scale(pt, FIX_ONE/3);
                        MESH_GET_NORMAL(end, mesh->vertices[idx[0]]);
                        end = gf_vec_scale(end, scale);
                        gf_vec_add(end, pt, end);
#ifdef GPAC_USE_GLES1X
                        va[0] = pt;
                        va[1] = end;
                        indices[0] = 0;
                        indices[1] = 1;
                        glVertexPointer(3, GL_FIXED, 0, va);
                        glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, indices);
#else
                        glBegin(GL_LINES);
                        glVertex3f(FIX2FLT(pt.x), FIX2FLT(pt.y), FIX2FLT(pt.z));
                        glVertex3f(FIX2FLT(end.x), FIX2FLT(end.y), FIX2FLT(end.z));
                        glEnd();
#endif
                        idx += 3;
                }
        }
#ifdef GPAC_USE_GLES1X
        glDisableClientState(GL_VERTEX_ARRAY);
#endif
#endif  
}
void visual_3d_draw_aabb_nodeBounds(GF_TraverseState *tr_state, AABBNode *node)
{
        if (node->pos) {
                visual_3d_draw_aabb_nodeBounds(tr_state, node->pos);
                visual_3d_draw_aabb_nodeBounds(tr_state, node->neg);
        } else {
                GF_Matrix mx;
                SFVec3f c, s;
                gf_vec_diff(s, node->max, node->min);
                c = gf_vec_scale(s, FIX_ONE/2);
                gf_vec_add(c, node->min, c);
                gf_mx_copy(mx, tr_state->model_matrix);
                gf_mx_add_translation(&tr_state->model_matrix, c.x, c.y, c.z);
                gf_mx_add_scale(&tr_state->model_matrix, s.x, s.y, s.z);
                visual_3d_draw_mesh(tr_state, tr_state->visual->compositor->unit_bbox);
                gf_mx_copy(tr_state->model_matrix, mx);
        }
}
void visual_3d_draw_bbox_ex(GF_TraverseState *tr_state, GF_BBox *box, Bool is_debug)
{
        GF_Matrix mx;
        SFVec3f c, s;
        if (! is_debug) {
                visual_3d_set_debug_color(tr_state->visual->compositor->highlight_stroke);
        }
        gf_vec_diff(s, box->max_edge, box->min_edge);
        c.x = box->min_edge.x + s.x/2;
        c.y = box->min_edge.y + s.y/2;
        c.z = box->min_edge.z + s.z/2;
        gf_mx_copy(mx, tr_state->model_matrix);
        gf_mx_add_translation(&tr_state->model_matrix, c.x, c.y, c.z);
        gf_mx_add_scale(&tr_state->model_matrix, s.x, s.y, s.z);
        visual_3d_draw_mesh(tr_state, tr_state->visual->compositor->unit_bbox);
        gf_mx_copy(tr_state->model_matrix, mx);
}
void visual_3d_draw_bbox(GF_TraverseState *tr_state, GF_BBox *box)
{
        visual_3d_draw_bbox_ex(tr_state, box, 0);
}
static void visual_3d_draw_bounds(GF_TraverseState *tr_state, GF_Mesh *mesh)
{
        visual_3d_set_debug_color(0);
        if (mesh->aabb_root && (tr_state->visual->compositor->draw_bvol==GF_BOUNDS_AABB)) {
                visual_3d_draw_aabb_nodeBounds(tr_state, mesh->aabb_root);
        } else {
                visual_3d_draw_bbox_ex(tr_state, &mesh->bounds, 1);
        }
}
void visual_3d_mesh_paint(GF_TraverseState *tr_state, GF_Mesh *mesh)
{
#if !defined(GPAC_USE_GLES2)
        Bool mesh_drawn = 0;
#endif
        GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[V3D] Drawing mesh %p\n", mesh));
        if (tr_state->visual->compositor->wiremode != GF_WIREFRAME_ONLY) {
                visual_3d_draw_mesh(tr_state, mesh);
#if !defined(GPAC_USE_GLES2)
                mesh_drawn = 1;
#endif
        }
#if !defined(GPAC_USE_GLES2)
        if (tr_state->visual->compositor->draw_normals) {
                if (!mesh_drawn) {
                        visual_3d_update_matrices(tr_state);
                        mesh_drawn=1;
                }
                visual_3d_draw_normals(tr_state, mesh);
        }
        if ((mesh->mesh_type==MESH_TRIANGLES) && (tr_state->visual->compositor->wiremode != GF_WIREFRAME_NONE)) {
                glDisable(GL_LIGHTING);
                visual_3d_set_debug_color(0xFFFFFFFF);
                if (!mesh_drawn)
                        visual_3d_update_matrices(tr_state);
                glEnableClientState(GL_VERTEX_ARRAY);
#ifdef GPAC_USE_GLES1X
                glVertexPointer(3, GL_FIXED, sizeof(GF_Vertex),  &mesh->vertices[0].pos);
                glDrawElements(GL_LINES, mesh->i_count, GL_UNSIGNED_SHORT, mesh->indices);
#else
                glVertexPointer(3, GL_FLOAT, sizeof(GF_Vertex),  &mesh->vertices[0].pos);
                glDrawElements(GL_LINES, mesh->i_count, GL_UNSIGNED_INT, mesh->indices);
#endif
                glDisableClientState(GL_VERTEX_ARRAY);
        }
#endif
        if (tr_state->visual->compositor->draw_bvol)
                visual_3d_draw_bounds(tr_state, mesh);
        GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[V3D] Done drawing mesh %p\n", mesh));
}
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES2)
static GLubyte hatch_horiz[] = {
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
};
static GLubyte hatch_vert[] = {
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
};
static GLubyte hatch_up[] = {
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03,
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03,
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03,
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03,
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03,
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03,
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03,
        0xc0, 0xc0, 0xc0, 0xc0, 0x30, 0x30, 0x30, 0x30,
        0x0c, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x03
};
static GLubyte hatch_down[] = {
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0,
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0,
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0,
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0,
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0,
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0,
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0,
        0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x0c,
        0x30, 0x30, 0x30, 0x30, 0xc0, 0xc0, 0xc0, 0xc0
};
static GLubyte hatch_cross[] = {
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c
};
void visual_3d_mesh_hatch(GF_TraverseState *tr_state, GF_Mesh *mesh, u32 hatchStyle, SFColor hatchColor)
{
        if (mesh->mesh_type != MESH_TRIANGLES) return;
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, sizeof(GF_Vertex),  &mesh->vertices[0].pos);
        if (mesh->flags & MESH_IS_2D) {
                glDisableClientState(GL_NORMAL_ARRAY);
                glNormal3f(0, 0, 1.0f);
                glDisable(GL_CULL_FACE);
        } else {
                glEnableClientState(GL_NORMAL_ARRAY );
                glNormalPointer(GL_FLOAT, sizeof(GF_Vertex), &mesh->vertices[0].normal);
                
                if (!tr_state->mesh_is_transparent && (mesh->flags & MESH_IS_SOLID)) {
                        glEnable(GL_CULL_FACE);
                        glFrontFace((mesh->flags & MESH_IS_CW) ? GL_CW : GL_CCW);
                } else {
                        glDisable(GL_CULL_FACE);
                }
        }
        glEnable(GL_POLYGON_STIPPLE);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        
        switch (hatchStyle) {
        case 5:
                glPolygonStipple(hatch_cross);
                break;
        case 4:
                glPolygonStipple(hatch_up);
                break;
        case 3:
                glPolygonStipple(hatch_down);
                break;
        case 2:
                glPolygonStipple(hatch_vert);
                break;
        case 1:
                glPolygonStipple(hatch_horiz);
                break;
        default:
                glDisable(GL_POLYGON_STIPPLE);
                break;
        }
        glColor3f(FIX2FLT(hatchColor.red), FIX2FLT(hatchColor.green), FIX2FLT(hatchColor.blue));
        glDrawElements(GL_TRIANGLES, mesh->i_count, GL_UNSIGNED_INT, mesh->indices);
        glDisable(GL_POLYGON_STIPPLE);
}
#endif
void visual_3d_mesh_strike(GF_TraverseState *tr_state, GF_Mesh *mesh, Fixed width, Fixed line_scale, u32 dash_style)
{
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES2)
        u16 style;
#endif
        if (mesh->mesh_type != MESH_LINESET) return;
        if (line_scale) width = gf_mulfix(width, line_scale);
        width/=2;
#if !defined(GPAC_USE_TINYGL) && !defined(GL_ES_CL_PROFILE)
        glLineWidth( FIX2FLT(width));
#endif
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES2)
        switch (dash_style) {
        case GF_DASH_STYLE_DASH:
                style = 0x1F1F;
                break;
        case GF_DASH_STYLE_DOT:
                style = 0x3333;
                break;
        case GF_DASH_STYLE_DASH_DOT:
                style = 0x6767;
                break;
        case GF_DASH_STYLE_DASH_DASH_DOT:
                style = 0x33CF;
                break;
        case GF_DASH_STYLE_DASH_DOT_DOT:
                style = 0x330F;
                break;
        default:
                style = 0;
                break;
        }
        if (style) {
                u32 factor = FIX2INT(width);
                if (!factor) factor = 1;
                glEnable(GL_LINE_STIPPLE);
                glLineStipple(factor, style);
                visual_3d_mesh_paint(tr_state, mesh);
                glDisable (GL_LINE_STIPPLE);
        } else
#endif
                visual_3d_mesh_paint(tr_state, mesh);
}
void visual_3d_clear(GF_VisualManager *visual, SFColor color, Fixed alpha)
{
#ifdef GPAC_USE_GLES1X
        glClearColorx(color.red, color.green, color.blue, alpha);
#else
        glClearColor(FIX2FLT(color.red), FIX2FLT(color.green), FIX2FLT(color.blue), FIX2FLT(alpha));
#endif
        glClear(GL_COLOR_BUFFER_BIT);
}
void visual_3d_fill_rect(GF_VisualManager *visual, GF_Rect rc, SFColorRGBA color)
{
        
#ifdef GPAC_USE_GLES2
#else
        glDisable(GL_BLEND | GL_LIGHTING | GL_TEXTURE_2D);
#if defined(GPAC_USE_GLES1X)
        glNormal3x(0, 0, FIX_ONE);
        if (color.alpha!=FIX_ONE) glEnable(GL_BLEND);
        glColor4x(color.red, color.green, color.blue, color.alpha);
        {
                Fixed v[8];
                u16 indices[3];
                indices[0] = 0;
                indices[1] = 1;
                indices[2] = 2;
                v[0] = rc.x;
                v[1] = rc.y;
                v[2] = rc.x+rc.width;
                v[3] = rc.y-rc.height;
                v[4] = rc.x+rc.width;
                v[5] = rc.y;
                glEnableClientState(GL_VERTEX_ARRAY);
                glVertexPointer(2, GL_FIXED, 0, v);
                glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
                v[4] = rc.x;
                v[5] = rc.y-rc.height;
                glVertexPointer(2, GL_FIXED, 0, v);
                glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
                glDisableClientState(GL_VERTEX_ARRAY);
        }
#else
        glNormal3f(0, 0, 1);
        if (color.alpha!=FIX_ONE) {
                glEnable(GL_BLEND);
                glColor4f(FIX2FLT(color.red), FIX2FLT(color.green), FIX2FLT(color.blue), FIX2FLT(color.alpha));
        } else {
                glColor3f(FIX2FLT(color.red), FIX2FLT(color.green), FIX2FLT(color.blue));
        }
        glBegin(GL_QUADS);
        glVertex3f(FIX2FLT(rc.x), FIX2FLT(rc.y), 0);
        glVertex3f(FIX2FLT(rc.x), FIX2FLT(rc.y-rc.height), 0);
        glVertex3f(FIX2FLT(rc.x+rc.width), FIX2FLT(rc.y-rc.height), 0);
        glVertex3f(FIX2FLT(rc.x+rc.width), FIX2FLT(rc.y), 0);
        glEnd();
        glDisable(GL_COLOR_MATERIAL | GL_COLOR_MATERIAL_FACE);
#endif
        glDisable(GL_BLEND);
#endif
}
GF_Err compositor_3d_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *fb, u32 depth_dump_mode)
{
        
        u32 i;
#ifndef GPAC_USE_TINYGL
        char*tmp;
        u32 hy;
#endif 
        fb->width = compositor->display_width;
        fb->height = compositor->display_height;
        
        if (depth_dump_mode==1) {
                
#ifdef GPAC_USE_GLES1X
                return GF_NOT_SUPPORTED;
#else
                Float *depthp;
                Float zFar, zNear;
                fb->pitch_x = 0;
                fb->pitch_y = compositor->vp_width;
                if (compositor->screen_buffer_alloc_size < fb->pitch_y * fb->height) {
                        compositor->screen_buffer_alloc_size = fb->pitch_y * fb->height;
                        compositor->screen_buffer = gf_realloc(compositor->screen_buffer, compositor->screen_buffer_alloc_size);
                }
                fb->video_buffer = compositor->screen_buffer;
                
                depthp = (Float*)gf_malloc(sizeof(Float)* fb->pitch_y * fb->height);
                fb->pixel_format = GF_PIXEL_GREYSCALE;
#ifndef GPAC_USE_TINYGL
                
                
#endif
                glReadPixels(compositor->vp_x, compositor->vp_y, fb->width, fb->height, GL_DEPTH_COMPONENT, GL_FLOAT, depthp);
                
                zFar = FIX2FLT(compositor->visual->camera.z_far);
                zNear = FIX2FLT(compositor->visual->camera.z_near);
                for (i=0; i<fb->height*fb->width; i++) {
                        Float res = ( (2.0f * zNear) / (zFar + zNear - depthp[i] * (zFar - zNear)) ) ;
                        fb->video_buffer[i] = (u8) ( 255.0 * (1.0 - res));
                }
                gf_free(depthp);
#endif  
        }
        
        else if (depth_dump_mode==2 || depth_dump_mode==3) {
#ifdef GPAC_USE_GLES1X
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor]: RGB+Depth format not implemented in OpenGL ES\n"));
                return GF_NOT_SUPPORTED;
#else
                char *depth_data=NULL;
                u32 size;
                fb->pitch_x = 4;
                fb->pitch_y = compositor->vp_width*4; 
#ifndef GPAC_USE_TINYGL
                size = fb->pitch_y * fb->height;
#else
                size = 2 * fb->pitch_y * fb->height;
#endif
                if (compositor->screen_buffer_alloc_size < size) {
                        compositor->screen_buffer_alloc_size = size;
                        compositor->screen_buffer = gf_realloc(compositor->screen_buffer, compositor->screen_buffer_alloc_size);
                }
                fb->video_buffer = compositor->screen_buffer;
#ifndef GPAC_USE_TINYGL
                glReadPixels(0, 0, fb->width, fb->height, GL_RGBA, GL_UNSIGNED_BYTE, fb->video_buffer);
                
                depth_data = (char*) gf_malloc(sizeof(char)*fb->width*fb->height);
                glReadPixels(0, 0, fb->width, fb->height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, depth_data);
                if (depth_dump_mode==2) {
                        u32 i;
                        fb->pixel_format = GF_PIXEL_RGBDS;
                        
                        for (i=0; i<fb->height*fb->width; i++) {
                                u8 ds;
                                
                                u8 depth = depth_data[i] & 0xfe;
                                
                                ds = (fb->video_buffer[i*4 + 3]);
                                
                                if (ds & 0x80) depth |= 0x01;
                                fb->video_buffer[i*4+3] = depth; 
                        }
                        
                } else if (depth_dump_mode==3) {
                        u32 i;
                        fb->pixel_format = GF_PIXEL_RGBD;
                        for (i=0; i<fb->height*fb->width; i++)
                                fb->video_buffer[i*4+3] = depth_data[i];
                }
#else
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor]: RGB+Depth format not implemented in TinyGL\n"));
                return GF_NOT_SUPPORTED;
#endif
#endif 
        } else { 
                u32 size;
                fb->pitch_x = 4;
                fb->pitch_y = 4*compositor->vp_width;
                size = fb->pitch_y * fb->height;
                if (compositor->screen_buffer_alloc_size < size) {
                        compositor->screen_buffer_alloc_size = size;
                        compositor->screen_buffer = gf_realloc(compositor->screen_buffer, compositor->screen_buffer_alloc_size);
                }
                fb->video_buffer = compositor->screen_buffer;
                fb->pixel_format = GF_PIXEL_RGBA;
                glReadPixels(0, 0, fb->width, fb->height, GL_RGBA, GL_UNSIGNED_BYTE, fb->video_buffer);
                
        }
#ifndef GPAC_USE_TINYGL
        
        tmp = (char*)gf_malloc(sizeof(char)*fb->pitch_y);
        hy = fb->height/2;
        for (i=0; i<hy; i++) {
                memcpy(tmp, fb->video_buffer+ i*fb->pitch_y, fb->pitch_y);
                memcpy(fb->video_buffer + i*fb->pitch_y, fb->video_buffer + (fb->height - 1 - i) * fb->pitch_y, fb->pitch_y);
                memcpy(fb->video_buffer + (fb->height - 1 - i) * fb->pitch_y, tmp, fb->pitch_y);
        }
        gf_free(tmp);
#endif
        return GF_OK;
}
GF_Err compositor_3d_release_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer)
{
        framebuffer->video_buffer = 0;
        return GF_OK;
}
GF_Err compositor_3d_get_offscreen_buffer(GF_Compositor *compositor, GF_VideoSurface *fb, u32 view_idx, u32 depth_dump_mode)
{
        
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES2)
        char *tmp;
        u32 hy, i;
        
        if (depth_dump_mode) return GF_NOT_SUPPORTED;
        if (view_idx>=compositor->visual->nb_views) return GF_BAD_PARAM;
        fb->width = compositor->visual->auto_stereo_width;
        fb->height = compositor->visual->auto_stereo_height;
        fb->pixel_format = GF_PIXEL_RGB_24;
        fb->pitch_y = 3*fb->width;
        fb->video_buffer = gf_malloc(sizeof(char)*3*fb->width*fb->height);
        if (!fb->video_buffer) return GF_OUT_OF_MEM;
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, compositor->visual->gl_textures[view_idx]);
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, fb->video_buffer);
        glDisable(GL_TEXTURE_2D);
        
        tmp = (char*)gf_malloc(sizeof(char)*fb->pitch_y);
        hy = fb->height/2;
        for (i=0; i<hy; i++) {
                memcpy(tmp, fb->video_buffer+ i*fb->pitch_y, fb->pitch_y);
                memcpy(fb->video_buffer + i*fb->pitch_y, fb->video_buffer + (fb->height - 1 - i) * fb->pitch_y, fb->pitch_y);
                memcpy(fb->video_buffer + (fb->height - 1 - i) * fb->pitch_y, tmp, fb->pitch_y);
        }
        gf_free(tmp);
        return GF_OK;
#else
        return GF_NOT_SUPPORTED;
#endif
}
void visual_3d_point_sprite(GF_VisualManager *visual, Drawable *stack, GF_TextureHandler *txh, GF_TraverseState *tr_state)
{
        
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES2)
        u32 w, h;
        u32 pixel_format, stride;
        u8 *data;
        Float r, g, b;
        Fixed x, y;
        Float inc, scale;
        Bool in_strip;
        Float delta = 0;
        Bool first_pass = 2;
        GF_Node *txtrans = NULL;
        if ((visual->compositor->depth_gl_type==GF_SC_DEPTH_GL_POINTS) && visual->compositor->gl_caps.point_sprite) {
                Float z;
                static GLfloat none[3] = { 1.0f, 0, 0 };
                data = (u8 *) gf_sc_texture_get_data(txh, &pixel_format);
                if (!data) return;
                if (pixel_format!=GF_PIXEL_RGBD) return;
                stride = txh->stride;
                if (txh->pixelformat==GF_PIXEL_YUVD) stride *= 4;
                glPointSize(1.0f * visual->compositor->zoom);
                glDepthMask(GL_FALSE);
                glPointParameterfv(GL_DISTANCE_ATTENUATION_EXT, none);
                glPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 0.0);
                glEnable(GL_POINT_SMOOTH);
                glDisable(GL_LIGHTING);
                inc = 1;
                if (!tr_state->pixel_metrics) inc /= FIX2FLT(tr_state->min_hsize);
                y = 1;
                y = gf_mulfix(y, INT2FIX(txh->height/2));
                if (!tr_state->pixel_metrics) y = gf_divfix(y, tr_state->min_hsize);
                glBegin(GL_POINTS);
                for (h=0; h<txh->height; h++) {
                        x = -1;
                        x = gf_mulfix(x, INT2FIX(txh->width/2));
                        if (!tr_state->pixel_metrics) x = gf_divfix(x, tr_state->min_hsize);
                        for (w=0; w<txh->width; w++) {
                                u8 *p = data + h*stride + w*4;
                                r = p[0];
                                r /= 255;
                                g = p[1];
                                g /= 255;
                                b = p[2];
                                b /= 255;
                                z = p[3];
                                z = z / 255;
                                glColor4f(r, g, b, 1.0);
                                glVertex3f(FIX2FLT(x), FIX2FLT(y), FIX2FLT(-z)*60);
                                x += FLT2FIX(inc);
                        }
                        y -= FLT2FIX(inc);
                }
                glEnd();
                glDepthMask(GL_TRUE);
                return;
        }
        if (visual->compositor->depth_gl_type==GF_SC_DEPTH_GL_STRIPS) {
                delta = FIX2FLT(visual->compositor->depth_gl_strips_filter);
                if (!delta) first_pass = 2;
                else first_pass = 1;
                data = (u8 *) gf_sc_texture_get_data(txh, &pixel_format);
                if (!data) return;
                if (pixel_format!=GF_PIXEL_RGBD) return;
                stride = txh->stride;
                if (txh->pixelformat==GF_PIXEL_YUVD) stride *= 4;
                glDepthMask(GL_FALSE);
                glDisable(GL_TEXTURE_2D);
                glDisable(GL_LIGHTING);
                glDisable(GL_BLEND);
                glDisable(GL_CULL_FACE);
                glDisable(GL_POINT_SMOOTH);
                glDisable(GL_FOG);
restart:
                scale = FIX2FLT(visual->compositor->depth_gl_scale);
                inc = 1;
                if (!tr_state->pixel_metrics) inc /= FIX2FLT(tr_state->min_hsize);
                y = 1;
                y = gf_mulfix(y, INT2FIX(txh->height/2));;
                if (!tr_state->pixel_metrics) y = gf_divfix(y, tr_state->min_hsize);
                in_strip = 0;
                for (h=0; h<txh->height - 1; h++) {
                        u8 *src = data + h*stride;
                        x = -1;
                        x = gf_mulfix(x, INT2FIX(txh->width/2));
                        if (!tr_state->pixel_metrics) x  = gf_divfix(x, tr_state->min_hsize);
                        for (w=0; w<txh->width; w++) {
                                u8 *p1 = src + w*4;
                                u8 *p2 = src + w*4 + stride;
                                Float z1 = p1[3];
                                Float z2 = p2[3];
                                if (first_pass==1) {
                                        if ((z1>delta) || (z2>delta))
                                        {
                                                if (0 && in_strip) {
                                                        glEnd();
                                                        in_strip = 0;
                                                }
                                                x += FLT2FIX(inc);
                                                continue;
                                        }
                                } else if (first_pass==0) {
                                        if ((z1<=delta) || (z2<=delta))
                                        {
                                                if (in_strip) {
                                                        glEnd();
                                                        in_strip = 0;
                                                }
                                                x += FLT2FIX(inc);
                                                continue;
                                        }
                                }
                                z1 = z1 / 255;
                                z2 = z2 / 255;
                                r = p1[0];
                                r /= 255;
                                g = p1[1];
                                g /= 255;
                                b = p1[2];
                                b /= 255;
                                if (!in_strip) {
                                        glBegin(GL_TRIANGLE_STRIP);
                                        in_strip = 1;
                                }
                                glColor3f(r, g, b);
                                glVertex3f(FIX2FLT(x), FIX2FLT(y), FIX2FLT(z1)*scale);
                                r = p2[0];
                                r /= 255;
                                g = p2[1];
                                g /= 255;
                                b = p2[2];
                                b /= 255;
                                glColor3f(r, g, b);
                                glVertex3f(FIX2FLT(x), FIX2FLT(y)-inc, FIX2FLT(z2)*scale);
                                x += FLT2FIX(inc);
                        }
                        if (in_strip) {
                                glEnd();
                                in_strip = 0;
                        }
                        y -= FLT2FIX(inc);
                }
                if (first_pass==1) {
                        first_pass = 0;
                        goto restart;
                }
                return;
        }
        glColor3f(1.0, 0.0, 0.0);
        
        if (!stack->mesh) {
                stack->mesh = new_mesh();
                stack->mesh->vbo_dynamic = 1;
                inc = 1;
                if (!tr_state->pixel_metrics) inc /= FIX2FLT(tr_state->min_hsize);
                y = 1;
                y = gf_mulfix(y, FLT2FIX(txh->height/2));
                if (!tr_state->pixel_metrics) y = gf_divfix(y, tr_state->min_hsize);
                if (txh->width>1 && txh->height>1) {
                        for (h=0; h<txh->height; h++) {
                                u32 idx_offset = h ? ((h-1)*txh->width) : 0;
                                x = -1;
                                x = gf_mulfix(x, FLT2FIX(txh->width/2));
                                if (tr_state->min_hsize && !tr_state->pixel_metrics) x = gf_divfix(x, tr_state->min_hsize);
                                for (w=0; w<txh->width; w++) {
                                        mesh_set_vertex(stack->mesh, x, y, 0, 0, 0, -FIX_ONE, INT2FIX(w / (txh->width-1)), INT2FIX((txh->height - h  -1) / (txh->height-1)) );
                                        x += FLT2FIX(inc);
                                        
                                        if (h && w) {
                                                u32 first_idx = idx_offset + w - 1;
                                                mesh_set_triangle(stack->mesh, first_idx, first_idx+1, txh->width + first_idx +1);
                                                mesh_set_triangle(stack->mesh, first_idx, txh->width + first_idx, txh->width + first_idx +1);
                                        }
                                }
                                y -= FLT2FIX(inc);
                        }
                        
                        txh->needs_refresh = 1;
                }
        }
        
        if (txh->needs_refresh) {
                Fixed f_scale = FLT2FIX(visual->compositor->depth_gl_scale);
                txh->needs_refresh = 0;
                data = (u8 *) gf_sc_texture_get_data(txh, &pixel_format);
                if (!data) return;
                if (pixel_format!=GF_PIXEL_RGB_24_DEPTH) return;
                data += txh->height*txh->width*3;
                for (h=0; h<txh->height; h++) {
                        u8 *src = data + h * txh->width;
                        for (w=0; w<txh->width; w++) {
                                u8 d = src[w];
                                Fixed z = INT2FIX(d);
                                z = gf_mulfix(z / 255, f_scale);
                                stack->mesh->vertices[w + h*txh->width].pos.z = z;
                        }
                }
                stack->mesh->vbo_dirty = 1;
        }
#ifndef GPAC_DISABLE_VRML
        if (tr_state->appear) txtrans = ((M_Appearance *)tr_state->appear)->textureTransform;
#endif
        tr_state->mesh_num_textures = gf_sc_texture_enable(txh, txtrans);
        visual_3d_draw_mesh(tr_state, stack->mesh);
        visual_3d_disable_texture(tr_state);
#endif 
}
#endif