root/src/compositor/visual_manager_3d_gl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gf_sc_load_opengl_extensions
  2. visual_3d_compile_shader
  3. visual_3d_shader_from_source_file
  4. visual_3d_shader_with_flags
  5. visual_3d_set_tx_planes
  6. visual_3d_init_stereo_shaders
  7. gf_glGetUniformLocation
  8. gf_glGetAttribLocation
  9. gf_glQueryProgram
  10. gf_glQueryUniform
  11. gf_glQueryAttrib
  12. gf_glQueryUniforms
  13. gf_glQueryAttributes
  14. visual_3d_init_generic_shaders
  15. visual_3d_init_shaders
  16. visual_3d_reset_graphics
  17. visual_3d_set_clipper_scissor
  18. visual_3d_load_matrix_shaders
  19. visual_3d_init_autostereo
  20. visual_3d_end_auto_stereo_pass
  21. visual_3d_setup_quality
  22. visual_3d_setup
  23. visual_3d_set_background_state
  24. visual_3d_enable_antialias
  25. visual_3d_enable_depth_buffer
  26. visual_3d_set_viewport
  27. visual_3d_set_scissor
  28. visual_3d_clear_depth
  29. visual_3d_draw_aabb_node
  30. visual_3d_matrix_load
  31. visual_3d_update_matrices
  32. visual_3d_set_clippers
  33. visual_3d_reset_clippers
  34. visual_3d_reset_lights
  35. visual_3d_set_lights
  36. visual_3d_enable_fog
  37. visual_3d_do_draw_mesh
  38. visual_3d_bind_buffer
  39. visual_3d_update_matrices_shaders
  40. visual_3d_set_lights_shaders
  41. visual_3d_set_fog_shaders
  42. visual_3d_set_clippers_shaders
  43. visual_3d_draw_mesh_shader_only
  44. visual_3d_draw_mesh
  45. visual_3d_set_debug_color
  46. visual_3d_draw_normals
  47. visual_3d_draw_aabb_nodeBounds
  48. visual_3d_draw_bbox_ex
  49. visual_3d_draw_bbox
  50. visual_3d_draw_bounds
  51. visual_3d_mesh_paint
  52. visual_3d_mesh_hatch
  53. visual_3d_mesh_strike
  54. visual_3d_clear
  55. visual_3d_fill_rect
  56. compositor_3d_get_screen_buffer
  57. compositor_3d_release_screen_buffer
  58. compositor_3d_get_offscreen_buffer
  59. visual_3d_point_sprite

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / Scene Compositor sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#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

/*!! HORRIBLE HACK, but on my test devices, it seems that glClipPlanex is missing on the device but not in the SDK lib !!*/
#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 //LOAD_GL_1_3

#ifdef LOAD_GL_1_4

GLDECL_STATIC(glPointParameterf);
GLDECL_STATIC(glPointParameterfv);

#endif //LOAD_GL_1_4


#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 //LOAD_GL_1_5

#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 //LOAD_GL_2_0

void gf_sc_load_opengl_extensions(GF_Compositor *compositor, Bool has_gl_context)
{
#ifdef GPAC_USE_TINYGL
        /*let TGL handle texturing*/
        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");
        /*store OGL extension to config for app usage*/
        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;


        /*we have a GL context, init the rest (proc addresses & co)*/
        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 //LOAD_GL_FUNCS

#endif //GPAC_USE_TINYGL

#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 /*GPAC_UNUSED_FUNC*/

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; \
        }";


/**
 parses (glShaderSource) and compiles (glCompileShader) shader source
 \return GF_TRUE if successful
 */
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; //+1 for trailing \0

        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) {
                /*clipping is always enabled*/
                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;
}

//The following functions were used for shader testing [in ES2.0]
#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]));
}

//same here
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;
                // Get the Uniform Info
                glGetActiveUniform(progObj, index, maxUniformLen, NULL, &size, &type, uniformName);
                // Get the uniform location
                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;
                // Get the Attribute Info
                glGetActiveAttrib(progObj, index, maxAttributeLen, NULL, &size, &type, attributeName);
                // Get the attribute location
                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;

        //FIXME: Clear error log - for Android we will always have an GL_INVALID_VALUE error
        glGetError();

        /* test if programs exist (by using flags 0)
         *  this check was introduced due to losing program objects when switching rasterization modes
         *  (hit '3' in runtime to recreate issue)
         *  the program objects were not deleted though
         */
        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;
                        //Clear error log (if the program is lost we will always have an GL_INVALID_VALUE error)
                        glGetError();
                }
        } else {
                visual->glsl_has_shaders=0;
                GL_CHECK_ERR;
        }

        //nothing to do
        if (visual->glsl_has_shaders) {
                return GF_TRUE;
        }

        GL_CHECK_ERR
        //Creating Program for the shaders
        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;
                //discard unused flags combination (ie YUV with no texture)
                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;

                //compute vertex shader for this fragment: all YUV frag shaders are texture vert shaders
                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;
        }

        /* Set texture planes*/
        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 we fail to configure shaders, force 2D mode
                if (! visual_3d_init_generic_shaders(visual)) {
                        visual->compositor->hybrid_opengl = GF_FALSE;
                        visual->compositor->force_opengl_2d = GF_FALSE;
                        /*force resetup*/
                        visual->compositor->root_visual_setup = 0;
                        /*force texture setup when switching to OpenGL*/
                        gf_sc_reset_graphics(visual->compositor);
                        /*force redraw*/
                        gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
                }
        }
}

#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)


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;
        /*main (not offscreen) visual*/
        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 // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)

        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);
        /*main (not offscreen) visual*/
        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;

        /*use our program*/
        glUseProgram(visual->autostereo_glsl_program);

        //load projection
        gf_mx_ortho(&mx, -hw, hw, -hh, hh, -10, 100);
        visual_3d_load_matrix_shaders(visual->autostereo_glsl_program, mx.m, "gfProjectionMatrix");

        //no need for modelview (identifty)

        /*push number of views if shader uses it*/
        loc = glGetUniformLocation(visual->autostereo_glsl_program, "gfViewCount");
        if (loc != -1) glUniform1i(loc, visual->nb_views);

        loc_texcoord_attrib = -1;
        //setup vertex attrib
        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
                //setup texcoord location
                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

                        /*bind all our textures*/
                        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
                        }

                        //draw
#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
        /*not sure why this is needed but it prevents a texturing bug on XP on parallels*/
        glActiveTexture(GL_TEXTURE0);
        GL_CHECK_ERR

        glBindTexture(GL_TEXTURE_2D, 0);
        glDisable(GL_TEXTURE_2D);
#endif

        GL_CHECK_ERR
#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)

}


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);
        /*Note: we cannot enable/disable normalization on the fly, because we have no clue when the GL implementation
        will actually compute the related fragments. Since a typical world always use scaling, we always turn normalization on
        to avoid tracking scale*/
        glEnable(GL_NORMALIZE);
#endif //GLES2

        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

/*              glDisable(GL_DITHER);
                glDisable(GL_POINT_SMOOTH);
                glHint(GL_POINT_SMOOTH, GL_DONT_CARE);
                glHint(GL_LINE_SMOOTH, GL_DONT_CARE);
                glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
        
                glDisable( GL_MULTISAMPLE_ARB);
*/
        }

#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 not leaf do cull*/
        if (n->pos) {
                u32 p_idx, cull;
                SFVec3f vertices[8];
                /*get box vertices*/
                gf_bbox_get_vertices(n->min, n->max, vertices);
                cull = CULL_INSIDE;
                for (i=0; i<6; i++) {
                        p_idx = p_indices[i];
                        /*check p-vertex: if not in plane, we're out (since p-vertex is the closest point to the plane)*/
                        if (gf_plane_get_distance(&fplanes[i], &vertices[p_idx])<0) {
                                cull = CULL_OUTSIDE;
                                break;
                        }
                        /*check n-vertex: if not in plane, we're intersecting*/
                        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;
                }
        }

        /*the good thing about the structure of the aabb tree is that the primitive idx is valid for both
        leaf and non-leaf nodes, so we can use it as soon as we have a CULL_INSIDE.
        However we must push triangles one by one since primitive order may have been swapped when
        building the AABB tree*/
        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) {
                //directionnal light
                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;


                //spot light
                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);

                        //glLightf(iLight, GL_SPOT_EXPONENT, 0.5f * (beamWidth+0.001f) /*(Float) (0.5 * log(0.5) / log(cos(beamWidth)) ) */);
                        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;


                //point light
                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 // ! GPAC_USE_GLES2


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 inside or no aabb for the mesh draw vertex array*/
        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 {

                /*otherwise cull aabb against frustum - after some testing it appears (as usual) that there must
                 be a compromise: we're slowing down the compositor here, however the gain is really appreciable for
                 large meshes, especially terrains/elevation grids*/

                /*first get transformed frustum in local space*/
                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]);
                }
                /*then recursively cull & draw AABB tree*/
                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) {
                /*we lost OpenGL context at previous frame, recreate VBO*/
                mesh->vbo = 0;
                mesh->vbo_idx = 0;
        }
        /*rebuild VBO for large ojects only (we basically filter quads out)*/
        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");
        }

        //calculate ModelView matix (camera.view * model)
        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

        /*
         * Equivalent to glLightModel(GL_LIGHTMODEL_TWO_SIDE, GL_TRUE);
         */
        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) {      //we have a headlight
                        gf_mx_init(mx);
                } else {
                        //update mx according to the light mx
                        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);            //Uniform name lights[i].type
                if (loc>=0) {
                        if (li->type==3) {
                                glUniform1i(loc, 0); //headlight; Set type 0-directional
                        } else {
                                glUniform1i(loc, (GLint) li->type); //Set type 0-directional 1-spot 2-point
                        }
                }

                //set for light direction (assuming origin = 0,0,0)
                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); //Set direction

                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 {        //we have a spot or point light
                        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;
                //compute clip plane in eye coordinates
                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);
                        }
                        //plane in local coordinates
                        gf_mx_apply_plane(&mx, &p);
                        //plane in eye coordinates
                        gf_mx_apply_plane(&eye_mx, &p);
                }

                sprintf(szName, "%s%d%s", "clipPlane[", i, "]");        //parse plane values
                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); //Set Plane (w = distance)
                }
        }
}

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;

        //check if we are using a different program than last time, if so force matrices updates
        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;

        //setup vertext array location (always true)
        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

        //setup scissor
        visual_3d_set_clipper_scissor(visual, tr_state);

        //setup clippers
        visual_3d_set_clippers_shaders(visual, tr_state);

        /* Material2D does not have any lights, color used is "gfEmissionColor" uniform */
        if (visual->has_material_2d) {
                //for YUV manually set alpha
                if (flags & GF_GL_IS_YUV) {
                        loc = gf_glGetUniformLocation(visual->glsl_program, "alpha");
                        if(loc>=0)
                                glUniform1f(loc, FIX2FLT(visual->mat_2d.alpha));
                }
                //otherwise handle alpha with blend if no texture
                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

                //for YUV manually set alpha
                if (flags & GF_GL_IS_YUV) {
                        loc = gf_glGetUniformLocation(visual->glsl_program, "alpha");
                        if(loc>=0)
                                glUniform1f(loc, 1.0);
                        GL_CHECK_ERR
                }
        }

        /* if lighting is on, setup material */
        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);
                }
                //TO CHECK:  if this does not work as it is supposed to, try: visual->shininess * 128
                loc = gf_glGetUniformLocation(visual->glsl_program, "gfShininess");
                if (loc>=0)
                        glUniform1f(loc, FIX2FLT(visual->shininess));

                glDisable(GL_CULL_FACE);        //Enable for performance; if so, check glFrontFace()
        }

        //setup mesh color vertex attribute - only available for some shaders
        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) {

                        //for now colors are 8bit/comp RGB(A), so used GL_UNSIGNED_BYTE and GL_TRUE for normalizing values
                        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);
        }

        //setup mesh normal vertex attribute - only available for some shaders
        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
        }

        //setup mesh normal vertex attribute - only available for some shaders
        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) {
                        //parsing texture 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);
                }

                //parsing texture coordinates
                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) {
                //According to the spec we should pass a 0,0,1 Normal and disable lights. we just disable lights
                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

        //We have a Colour Matrix to be applied
        if(!tr_state->color_mat.identity) {
                GF_Matrix toBeParsed;   //4x4 RGBA Color Matrix
                Fixed translateV[4];    //Vec4 holding translation property of color_mat
                int row,col;

                gf_mx_init(toBeParsed);

                //Copy values from Color Matrix
                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)];
                }

                //the rest of the values form the translation vector
                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);
        }


        //We have a Colour Key to be applied
        if(tr_state->col_key) {

                Float vals[3];
                Float eightbit = 255;   //used for mapping values between 0.0 and 1.0

                glEnable(GL_BLEND);             //normally we shouldn have to need this, but we do

                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
        //We drawn, now we Reset

        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);

        //instead of visual_3d_reset_lights(visual);
        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 // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)

//#endif //GPAC_USE_GLES2


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));
        //clear error
        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;

        //set lights before pushing modelview matrix
        visual_3d_set_lights(visual);

        visual_3d_update_matrices(tr_state);

        /*enable states*/
        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);

        //setup scissor
        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)
        /*scale modelview matrix*/
        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


        /*
        *       Enable colors:
        if mat2d is set, use mat2d and no lighting
        */
        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 {
                                //disable blending only if no texture !
                                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


        //setup material color
        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
        }

        //otherwise setup mesh color
        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
                /*glES only accepts full RGBA colors*/
                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  /*MESH_USE_SFCOLOR*/

#elif defined (GPAC_FIXED_POINT)


#ifdef MESH_USE_SFCOLOR
                /*this is a real pain: we cannot "scale" colors through openGL, and our components are 16.16 (32 bytes) ranging
                from [0 to 65536] mapping to [0, 1.0], but openGL assumes for s32 a range from [-2^31 2^31] mapping to [0, 1.0]
                we must thus rebuild a dedicated array...*/
                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 /*MESH_USE_SFCOLOR*/

#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 /*MESH_USE_SFCOLOR*/

#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 //GPAC_USE_TINYGL
                {
                        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 /*MESH_USE_FIXED_NORMAL*/
                /*normals are stored on signed bytes*/
                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);

        //reset all our states
        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 //GPAC_USE_GLES2
}


/*note we don't perform any culling for normal drawing...*/
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  /*GPAC_USE_TINYGL*/
}


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 mesh is transparent DON'T CULL*/
                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);
        /*can't access ISO International Register of Graphical Items www site :)*/
        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

/*only used for ILS/ILS2D or IFS2D outline*/
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)
{
        //TODOk - code this for GLES2 ?
#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)
{
        /*FIXME*/
        u32 i;
#ifndef GPAC_USE_TINYGL
        char*tmp;
        u32 hy;
#endif //GPAC_USE_TINYGL

        fb->width = compositor->display_width;
        fb->height = compositor->display_height;

        /*depthmap-only dump*/
        if (depth_dump_mode==1) {
                //depth reading not supported on gles <= 1.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;

                //read as float
                depthp = (Float*)gf_malloc(sizeof(Float)* fb->pitch_y * fb->height);
                fb->pixel_format = GF_PIXEL_GREYSCALE;

#ifndef GPAC_USE_TINYGL
                //glPixelTransferf(GL_DEPTH_SCALE, FIX2FLT(compositor->OGLDepthGain) );
                //glPixelTransferf(GL_DEPTH_BIAS, FIX2FLT(compositor->OGLDepthOffset) );
#endif

                glReadPixels(compositor->vp_x, compositor->vp_y, fb->width, fb->height, GL_DEPTH_COMPONENT, GL_FLOAT, depthp);

                //linearize z buffer, from 0 (zfar) to 1 (znear)
                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  /*GPAC_USE_GLES1X*/
        }

        /* RGBDS or RGBD dump*/
        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; /* 4 bytes for each rgbds pixel */

#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);

                /*
                glPixelTransferf(GL_DEPTH_SCALE, FIX2FLT(compositor->OGLDepthGain));
                glPixelTransferf(GL_DEPTH_BIAS, FIX2FLT(compositor->OGLDepthOffset));
                */

                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;

                        /*this corresponds to the RGBDS ordering*/
                        for (i=0; i<fb->height*fb->width; i++) {
                                u8 ds;
                                /* erase lowest-weighted depth bit */
                                u8 depth = depth_data[i] & 0xfe;
                                /*get alpha*/
                                ds = (fb->video_buffer[i*4 + 3]);
                                /* if heaviest-weighted alpha bit is set (>128) , turn on shape bit*/
                                if (ds & 0x80) depth |= 0x01;
                                fb->video_buffer[i*4+3] = depth; /*insert depth onto alpha*/
                        }
                        /*this corresponds to RGBD ordering*/
                } 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 /*GPAC_USE_GLES1X*/
        } else { /*if (compositor->user && (compositor->user->init_flags & GF_TERM_WINDOW_TRANSPARENT))*/
                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);
                /*      } else {
                                fb->pitch_x = 3;
                                fb->pitch_y = 3*compositor->vp_width;
                                fb->video_buffer = (char*)gf_malloc(sizeof(char) * fb->pitch_y * fb->height);
                                fb->pixel_format = GF_PIXEL_RGB_24;

                                glReadPixels(compositor->vp_x, compositor->vp_y, fb->width, fb->height, GL_RGB, GL_UNSIGNED_BYTE, fb->video_buffer);
                */
        }

#ifndef GPAC_USE_TINYGL
        /*flip image (openGL always handle image data bottom to top) */
        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)
{
        //TODOk - habdle offscreen buffers through frameBuffer objects, no read back j
#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES2)
        char *tmp;
        u32 hy, i;
        /*not implemented yet*/
        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);

        /*flip image (openGL always handle image data bottom to top) */
        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)
{
        //todo - allow point sprites for GLES2 ?
#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);

//              scale = FIX2FLT(visual->compositor->depth_gl_scale);
                inc = 1;
                if (!tr_state->pixel_metrics) inc /= FIX2FLT(tr_state->min_hsize);
//              x = 0;
                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);
//              x = 0;
                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);
        /*render using vertex array*/
        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);
//              x = 0;
                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);

                                        /*set triangle*/
                                        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);
                        }
                        /*force recompute of Z*/
                        txh->needs_refresh = 1;
                }
        }

        /*texture has been updated, recompute Z*/
        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 //GPAC_USE_GLES1X

}

#endif // GPAC_DISABLE_3D

/* [<][>][^][v][top][bottom][index][help] */