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