This source file includes following definitions.
- gf_sc_next_frame_state
- gf_sc_set_fullscreen
- gf_sc_reconfig_task
- gf_sc_draw_frame
- gf_sc_reset_graphics
- gf_sc_reset_framerate
- gf_sc_set_check_raster2d
- gf_sc_load
- gf_sc_create
- gf_sc_proc
- gf_sc_new
- gf_sc_del
- gf_sc_set_fps
- gf_sc_get_audio_buffer_length
- gf_sc_set_play_state
- gf_sc_get_clock
- gf_sc_set_scene_size
- gf_sc_get_size
- gf_sc_svg_convert_length_to_display
- compositor_set_ar_scale
- gf_sc_reset
- gf_sc_set_scene
- gf_sc_lock_audio
- gf_sc_lock
- gf_sc_set_size
- gf_sc_reload_config
- gf_sc_set_option
- gf_sc_is_over
- gf_sc_get_option
- gf_sc_map_point
- gf_sc_get_screen_buffer
- gf_sc_get_offscreen_buffer
- gf_sc_release_screen_buffer
- gf_sc_get_fps
- gf_sc_register_time_node
- gf_sc_unregister_time_node
- gf_sc_pick_node
- gf_sc_recompute_ar
- gf_sc_setup_root_visual
- gf_sc_draw_scene
- compositor_release_textures
- gf_sc_flush_video
- gf_sc_render_frame
- gf_sc_visual_is_registered
- gf_sc_visual_register
- gf_sc_visual_unregister
- gf_sc_traverse_subscene_ex
- gf_sc_handle_event_intern
- gf_sc_traverse_subscene
- gf_sc_on_event_ex
- gf_sc_on_event
- gf_sc_user_event
- gf_sc_register_extra_graph
- gf_sc_get_audio_delay
- gf_sc_script_action
- gf_sc_pick_in_clipper
- gf_sc_has_text_selection
- gf_sc_get_selected_text
- gf_sc_check_focus_upon_destroy
- gf_sc_add_video_listener
- gf_sc_remove_video_listener
- gf_sc_use_raw_texture
- gf_sc_get_av_caps
- gf_sc_set_system_pending_frame
- gf_sc_set_video_pending_frame
- gf_sc_queue_event
- gf_sc_queue_dom_event
- gf_sc_queue_dom_event_on_target
- sc_cleanup_event_queue
- gf_sc_node_destroy
- gf_sc_navigation_supported
- gf_sc_use_3d
#include <gpac/internal/compositor_dev.h>
#include <gpac/internal/terminal_dev.h>
#include <gpac/options.h>
#include <gpac/utf.h>
#include <gpac/modules/hardcoded_proto.h>
#include "nodes_stacks.h"
#include "visual_manager.h"
#include "texturing.h"
#define SC_DEF_WIDTH 320
#define SC_DEF_HEIGHT 240
void gf_sc_next_frame_state(GF_Compositor *compositor, u32 state)
{
if (state==GF_SC_DRAW_FLUSH) {
if (!compositor->skip_flush)
compositor->skip_flush = 2;
if (!compositor->frame_draw_type
#ifndef GPAC_DISABLE_3D
&& !compositor->visual->type_3d && !compositor->hybrid_opengl
#endif
) {
compositor->frame_draw_type = state;
}
} else {
compositor->frame_draw_type = state;
}
}
static void gf_sc_set_fullscreen(GF_Compositor *compositor)
{
GF_Err e;
if (!compositor->video_out->SetFullScreen) return;
GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Switching fullscreen %s\n", compositor->fullscreen ? "off" : "on"));
compositor->fullscreen = !compositor->fullscreen;
gf_mx_v(compositor->mx);
if (compositor->fullscreen && (compositor->scene_width>=compositor->scene_height)
#ifndef GPAC_DISABLE_3D
&& !compositor->visual->type_3d
#endif
) {
e = compositor->video_out->SetFullScreen(compositor->video_out, 2, &compositor->display_width, &compositor->display_height);
} else {
e = compositor->video_out->SetFullScreen(compositor->video_out, compositor->fullscreen, &compositor->display_width, &compositor->display_height);
}
gf_mx_p(compositor->mx);
if (e) {
GF_Event evt;
memset(&evt, 0, sizeof(GF_Event));
evt.type = GF_EVENT_MESSAGE;
evt.message.message = "Cannot switch to fullscreen";
evt.message.error = e;
gf_term_send_event(compositor->term, &evt);
compositor->fullscreen = 0;
compositor->video_out->SetFullScreen(compositor->video_out, 0, &compositor->display_width, &compositor->display_height);
}
GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] recomputing aspect ratio\n"));
compositor->recompute_ar = 1;
if (!compositor->reset_graphics) gf_sc_reset_graphics(compositor);
}
static void gf_sc_reconfig_task(GF_Compositor *compositor)
{
GF_Event evt;
Bool notif_size=GF_FALSE;
u32 width,height;
if (compositor->audio_renderer && !compositor->audio_renderer->th) gf_sc_ar_reconfig(compositor->audio_renderer);
if (compositor->msg_type) {
compositor->msg_type |= GF_SR_IN_RECONFIG;
if (compositor->msg_type & GF_SR_CFG_INITIAL_RESIZE) {
GF_Event evt;
memset(&evt, 0, sizeof(GF_Event));
evt.type = GF_EVENT_VIDEO_SETUP;
evt.setup.width = compositor->new_width;
evt.setup.height = compositor->new_height;
evt.setup.system_memory = compositor->video_memory ? GF_FALSE : GF_TRUE;
#ifdef OPENGL_RASTER
if (compositor->opengl_raster) {
evt.setup.opengl_mode = 1;
evt.setup.system_memory = GF_FALSE;
evt.setup.back_buffer = GF_TRUE;
}
#endif
#ifndef GPAC_DISABLE_3D
if (compositor->hybrid_opengl || compositor->force_opengl_2d) {
evt.setup.opengl_mode = 1;
evt.setup.system_memory = GF_FALSE;
evt.setup.back_buffer = GF_TRUE;
}
#endif
compositor->video_out->ProcessEvent(compositor->video_out, &evt);
compositor->msg_type &= ~GF_SR_CFG_INITIAL_RESIZE;
}
if (compositor->msg_type & GF_SR_CFG_OVERRIDE_SIZE) {
GF_Event evt;
assert(!(compositor->override_size_flags & 2));
compositor->msg_type &= ~GF_SR_CFG_OVERRIDE_SIZE;
compositor->override_size_flags |= 2;
width = compositor->scene_width;
height = compositor->scene_height;
compositor->has_size_info = 1;
gf_sc_set_size(compositor, width, height);
evt.type = GF_EVENT_SIZE;
evt.size.width = width;
evt.size.height = height;
gf_term_send_event(compositor->term, &evt);
}
if (compositor->msg_type & GF_SR_CFG_SET_SIZE) {
u32 fs_width, fs_height;
Bool restore_fs = compositor->fullscreen;
GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Changing display size to %d x %d\n", compositor->new_width, compositor->new_height));
fs_width = fs_height = 0;
if (restore_fs) {
if ((compositor->new_width>compositor->display_width) || (compositor->new_height>compositor->display_height)) {
u32 w = compositor->display_width;
compositor->display_width = compositor->display_height;
compositor->display_height = w;
compositor->recompute_ar = 1;
}
fs_width = compositor->display_width;
fs_height = compositor->display_height;
}
evt.type = GF_EVENT_SIZE;
evt.size.width = compositor->new_width;
evt.size.height = compositor->new_height;
if ( !(compositor->msg_type & GF_SR_CFG_WINDOWSIZE_NOTIF)) {
compositor->video_out->ProcessEvent(compositor->video_out, &evt);
}
compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
if (restore_fs) {
if ((compositor->display_width != fs_width) || (compositor->display_height != fs_height)) {
compositor->display_width = fs_width;
compositor->display_height = fs_height;
compositor->recompute_ar = 1;
}
} else {
compositor->display_width = evt.size.width;
compositor->display_height = evt.size.height;
compositor->recompute_ar = 1;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
}
notif_size=1;
compositor->new_width = compositor->new_height = 0;
compositor->msg_type &= ~GF_SR_CFG_SET_SIZE;
GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Display size changed to %d x %d\n", compositor->new_width, compositor->new_height));
}
if (compositor->msg_type & GF_SR_CFG_AR) {
compositor->msg_type &= ~GF_SR_CFG_AR;
compositor->recompute_ar = 1;
}
if (compositor->msg_type & GF_SR_CFG_FULLSCREEN) {
compositor->msg_type &= ~GF_SR_CFG_FULLSCREEN;
if (compositor->recompute_ar) {
compositor->fullscreen_postponed = 1;
} else {
gf_sc_set_fullscreen(compositor);
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
notif_size=1;
}
}
compositor->msg_type &= ~GF_SR_IN_RECONFIG;
}
if (notif_size && compositor->video_listeners) {
u32 k=0;
GF_VideoListener *l;
while ((l = gf_list_enum(compositor->video_listeners, &k))) {
if ( compositor->user && (compositor->user->init_flags & GF_TERM_WINDOW_TRANSPARENT) )
l->on_video_reconfig(l->udta, compositor->display_width, compositor->display_height, 4);
else
l->on_video_reconfig(l->udta, compositor->display_width, compositor->display_height, 3);
}
}
if (compositor->reset_graphics) {
#ifndef GPAC_DISABLE_3D
compositor->offscreen_width = compositor->offscreen_height = 0;
#endif
gf_sc_lock(compositor, 0);
evt.type = GF_EVENT_SYS_COLORS;
if (compositor->video_out->ProcessEvent(compositor->video_out, &evt) ) {
u32 i;
for (i=0; i<28; i++) {
compositor->sys_colors[i] = evt.sys_cols.sys_colors[i] & 0x00FFFFFF;
}
}
gf_sc_lock(compositor, 1);
}
}
GF_EXPORT
Bool gf_sc_draw_frame(GF_Compositor *compositor, Bool no_flush, s32 *ms_till_next)
{
Bool ret = GF_FALSE;
if (no_flush)
compositor->skip_flush=1;
gf_sc_render_frame(compositor);
if (ms_till_next) {
if ( compositor->ms_until_next_frame == GF_INT_MAX)
*ms_till_next = compositor->frame_duration;
else
*ms_till_next = compositor->ms_until_next_frame;
}
if (compositor->ms_until_next_frame < 0) ret = GF_TRUE;
else if (compositor->frame_draw_type) ret = GF_TRUE;
else if (compositor->fonts_pending) ret = GF_TRUE;
return ret;
}
GF_EXPORT
void gf_sc_reset_graphics(GF_Compositor *compositor)
{
if (compositor) {
Bool locked = gf_mx_try_lock(compositor->mx);
compositor->reset_graphics = 1;
if (locked) gf_mx_v(compositor->mx);
}
}
static void gf_sc_reset_framerate(GF_Compositor *compositor)
{
u32 i;
for (i=0; i<GF_SR_FPS_COMPUTE_SIZE; i++) compositor->frame_time[i] = compositor->frame_dur[i] = 0;
compositor->current_frame = 0;
}
static Bool gf_sc_on_event(void *cbck, GF_Event *event);
static Bool gf_sc_set_check_raster2d(GF_Compositor *compositor, GF_Raster2D *ifce)
{
if (!ifce->stencil_new || !ifce->surface_new) return 0;
if (!ifce->surface_clear || !ifce->surface_set_path || !ifce->surface_fill) return 0;
if (ifce->surface_attach_to_buffer) return 1;
return GF_FALSE;
}
static GF_Err gf_sc_load(GF_Compositor *compositor)
{
compositor->strike_bank = gf_list_new();
compositor->visuals = gf_list_new();
GF_SAFEALLOC(compositor->traverse_state, GF_TraverseState);
if (!compositor->traverse_state) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to initilaize compositor\n"));
return GF_OUT_OF_MEM;
}
compositor->traverse_state->vrml_sensors = gf_list_new();
compositor->traverse_state->use_stack = gf_list_new();
#ifndef GPAC_DISABLE_3D
compositor->traverse_state->local_lights = gf_list_new();
#endif
compositor->sensors = gf_list_new();
compositor->previous_sensors = gf_list_new();
compositor->hit_use_stack = gf_list_new();
compositor->prev_hit_use_stack = gf_list_new();
compositor->focus_ancestors = gf_list_new();
compositor->focus_use_stack = gf_list_new();
compositor->env_tests = gf_list_new();
compositor->visual = visual_new(compositor);
compositor->visual->GetSurfaceAccess = compositor_2d_get_video_access;
compositor->visual->ReleaseSurfaceAccess = compositor_2d_release_video_access;
compositor->visual->CheckAttached = compositor_2d_check_attached;
compositor->visual->ClearSurface = compositor_2d_clear_surface;
if (compositor->video_out->FlushRectangles)
compositor->visual->direct_flush = GF_TRUE;
compositor_2d_init_callbacks(compositor);
#ifdef GF_SR_USE_DEPTH
compositor->traverse_state->depth_gain = FIX_ONE;
#endif
gf_list_add(compositor->visuals, compositor->visual);
compositor->zoom = compositor->scale_x = compositor->scale_y = FIX_ONE;
compositor->focus_highlight = drawable_new();
compositor->focus_highlight->node = gf_node_new(NULL, TAG_UndefinedNode);
gf_node_register(compositor->focus_highlight->node, NULL);
gf_node_set_callback_function(compositor->focus_highlight->node, drawable_traverse_focus);
#ifndef GPAC_DISABLE_3D
compositor->collide_mode = GF_COLLISION_DISPLACEMENT;
compositor->gravity_on = GF_TRUE;
compositor->unit_bbox = new_mesh();
mesh_new_unit_bbox(compositor->unit_bbox);
gf_mx_init(compositor->traverse_state->model_matrix);
#endif
compositor->was_system_memory=1;
return GF_OK;
}
static GF_Err gf_sc_create(GF_Compositor *compositor)
{
const char *sOpt;
sOpt = gf_cfg_get_key(compositor->user->config, "Video", "DriverName");
if (sOpt) {
compositor->video_out = (GF_VideoOutput *) gf_modules_load_interface_by_name(compositor->user->modules, sOpt, GF_VIDEO_OUTPUT_INTERFACE);
if (compositor->video_out) {
compositor->video_out->evt_cbk_hdl = compositor;
compositor->video_out->on_event = gf_sc_on_event;
if (!compositor->video_out->Setup || compositor->video_out->Setup(compositor->video_out, compositor->user->os_window_handler, compositor->user->os_display, compositor->user->init_flags) != GF_OK) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Failed to Setup Video Driver %s!\n", sOpt));
gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
compositor->video_out = NULL;
}
}
}
if (!compositor->video_out) {
GF_VideoOutput *raw_out = NULL;
u32 i, count = gf_modules_get_count(compositor->user->modules);
GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Trying to find a suitable video driver amongst %d modules...\n", count));
for (i=0; i<count; i++) {
compositor->video_out = (GF_VideoOutput *) gf_modules_load_interface(compositor->user->modules, i, GF_VIDEO_OUTPUT_INTERFACE);
if (!compositor->video_out) continue;
compositor->video_out->evt_cbk_hdl = compositor;
compositor->video_out->on_event = gf_sc_on_event;
if (!stricmp(compositor->video_out->module_name, "Raw Video Output")) {
raw_out = compositor->video_out;
compositor->video_out = NULL;
continue;
}
if (compositor->video_out->Setup && compositor->video_out->Setup(compositor->video_out, compositor->user->os_window_handler, compositor->user->os_display, compositor->user->init_flags)==GF_OK) {
gf_cfg_set_key(compositor->user->config, "Video", "DriverName", compositor->video_out->module_name);
break;
}
gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
compositor->video_out = NULL;
}
if (raw_out) {
if (compositor->video_out) gf_modules_close_interface((GF_BaseInterface *)raw_out);
else {
compositor->video_out = raw_out;
compositor->video_out ->Setup(compositor->video_out, compositor->user->os_window_handler, compositor->user->os_display, compositor->user->init_flags);
}
}
}
if (!compositor->video_out ) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Failed to create compositor->video_out, did not find any suitable driver.\n"));
return GF_IO_ERR;
}
sOpt = gf_cfg_get_key(compositor->user->config, "Video", "DPI");
if (sOpt) {
compositor->video_out->dpi_x = compositor->video_out->dpi_y = atoi(sOpt);
}
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "Raster2D");
if (sOpt) {
compositor->rasterizer = (GF_Raster2D *) gf_modules_load_interface_by_name(compositor->user->modules, sOpt, GF_RASTER_2D_INTERFACE);
if (!compositor->rasterizer) {
sOpt = NULL;
} else if (!gf_sc_set_check_raster2d(compositor, compositor->rasterizer)) {
gf_modules_close_interface((GF_BaseInterface *)compositor->rasterizer);
compositor->rasterizer = NULL;
sOpt = NULL;
}
}
if (!compositor->rasterizer) {
u32 i, count;
count = gf_modules_get_count(compositor->user->modules);
for (i=0; i<count; i++) {
compositor->rasterizer = (GF_Raster2D *) gf_modules_load_interface(compositor->user->modules, i, GF_RASTER_2D_INTERFACE);
if (!compositor->rasterizer) continue;
if (gf_sc_set_check_raster2d(compositor, compositor->rasterizer)) break;
gf_modules_close_interface((GF_BaseInterface *)compositor->rasterizer);
compositor->rasterizer = NULL;
}
if (compositor->rasterizer) gf_cfg_set_key(compositor->user->config, "Compositor", "Raster2D", compositor->rasterizer->module_name);
}
if (!compositor->rasterizer) {
if (compositor->video_out->Shutdown) compositor->video_out->Shutdown(compositor->video_out);
gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
compositor->video_out = NULL;
return GF_IO_ERR;
}
if (gf_sc_load(compositor) != GF_OK) {
gf_modules_close_interface((GF_BaseInterface *)compositor->rasterizer);
compositor->rasterizer = NULL;
compositor->video_out->Shutdown(compositor->video_out);
gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
compositor->video_out = NULL;
return GF_IO_ERR;
}
compositor->textures = gf_list_new();
compositor->textures_gc = gf_list_new();
compositor->frame_rate = 30.0;
compositor->frame_duration = 33;
compositor->time_nodes = gf_list_new();
compositor->event_queue = gf_list_new();
compositor->event_queue_back = gf_list_new();
compositor->evq_mx = gf_mx_new("EventQueue");
#ifdef GF_SR_USE_VIDEO_CACHE
compositor->cached_groups = gf_list_new();
compositor->cached_groups_queue = gf_list_new();
#endif
if (!compositor->audio_renderer)
compositor->audio_renderer = gf_sc_ar_load(compositor->user);
gf_sc_reset_framerate(compositor);
compositor->font_manager = gf_font_manager_new(compositor->user);
compositor->extra_scenes = gf_list_new();
compositor->interaction_level = GF_INTERACT_NORMAL | GF_INTERACT_INPUT_SENSOR | GF_INTERACT_NAVIGATION;
compositor->scene_sampled_clock = 0;
compositor->video_th_id = gf_th_id();
return GF_OK;
}
enum
{
GF_COMPOSITOR_THREAD_START = 0,
GF_COMPOSITOR_THREAD_RUN,
GF_COMPOSITOR_THREAD_ABORTING,
GF_COMPOSITOR_THREAD_DONE,
GF_COMPOSITOR_THREAD_INIT_FAILED,
};
static u32 gf_sc_proc(void *par)
{
GF_Err e;
GF_Compositor *compositor = (GF_Compositor *) par;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Compositor] Entering thread ID %d\n", gf_th_id() ));
compositor->video_th_state = GF_COMPOSITOR_THREAD_START;
e = gf_sc_create(compositor);
if (e != GF_OK) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] Failed to initialize compositor: %s\n", gf_error_to_string(e) ));
compositor->video_th_state = GF_COMPOSITOR_THREAD_INIT_FAILED;
return 1;
}
compositor->video_th_state = GF_COMPOSITOR_THREAD_RUN;
while (compositor->video_th_state == GF_COMPOSITOR_THREAD_RUN) {
gf_sc_render_frame(compositor);
}
#ifndef GPAC_DISABLE_3D
visual_3d_reset_graphics(compositor->visual);
compositor_2d_reset_gl_auto(compositor);
#endif
gf_sc_texture_cleanup_hw(compositor);
compositor->video_out->Shutdown(compositor->video_out);
gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
compositor->video_out = NULL;
compositor->video_th_state = GF_COMPOSITOR_THREAD_DONE;
return 0;
}
GF_Compositor *gf_sc_new(GF_User *user, Bool self_threaded, GF_Terminal *term)
{
GF_Err e;
GF_Compositor *tmp;
GF_SAFEALLOC(tmp, GF_Compositor);
if (!tmp) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Failed to allocate compositor : OUT OF MEMORY!\n"));
return NULL;
}
tmp->user = user;
tmp->term = term;
tmp->mx = gf_mx_new("Compositor");
if (user) {
u32 i;
tmp->proto_modules = gf_list_new();
for (i=0; i< gf_modules_get_count(user->modules); i++) {
GF_HardcodedProto *ifce = (GF_HardcodedProto *) gf_modules_load_interface(user->modules, i, GF_HARDCODED_PROTO_INTERFACE);
if (ifce) gf_list_add(tmp->proto_modules, ifce);
}
}
tmp->msg_type |= GF_SR_CFG_INITIAL_RESIZE;
if (tmp->user && !tmp->user->os_window_handler) {
const char *opt;
tmp->new_width = SC_DEF_WIDTH;
tmp->new_height = SC_DEF_HEIGHT;
opt = gf_cfg_get_key(user->config, "Compositor", "DefaultWidth");
if (opt) tmp->new_width = atoi(opt);
opt = gf_cfg_get_key(user->config, "Compositor", "DefaultHeight");
if (opt) tmp->new_height = atoi(opt);
tmp->msg_type |= GF_SR_CFG_SET_SIZE;
}
if (self_threaded) {
tmp->VisualThread = gf_th_new("Compositor");
gf_th_run(tmp->VisualThread, gf_sc_proc, tmp);
while (tmp->video_th_state < GF_COMPOSITOR_THREAD_RUN) {
gf_sleep(1);
}
if (tmp->video_th_state == GF_COMPOSITOR_THREAD_INIT_FAILED) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("GF_COMPOSITOR_THREAD_INIT_FAILED : Deleting compositor.\n"));
gf_sc_del(tmp);
return NULL;
}
} else {
e = gf_sc_create(tmp);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error while calling gf_sc_create() : %s, deleting compositor.\n", gf_error_to_string(e)));
gf_sc_del(tmp);
return NULL;
}
}
if ((tmp->user->init_flags & GF_TERM_NO_REGULATION) || !tmp->VisualThread)
tmp->no_regulation = GF_TRUE;
#ifndef GPAC_DISABLE_3D
gf_sc_load_opengl_extensions(tmp, GF_FALSE);
#endif
GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI]\tCompositor Cycle Log\tNetworks\tDecoders\tFrame\tDirect Draw\tVisual Config\tEvent\tRoute\tSMIL Timing\tTime node\tTexture\tSMIL Anim\tTraverse setup\tTraverse (and direct Draw)\tTraverse (and direct Draw) without anim\tIndirect Draw\tTraverse And Draw (Indirect or Not)\tFlush\tCycle\n"));
return tmp;
}
void gf_sc_del(GF_Compositor *compositor)
{
if (!compositor) return;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Destroying\n"));
gf_sc_lock(compositor, GF_TRUE);
if (compositor->VisualThread) {
if (compositor->video_th_state == GF_COMPOSITOR_THREAD_RUN) {
compositor->video_th_state = GF_COMPOSITOR_THREAD_ABORTING;
while (compositor->video_th_state != GF_COMPOSITOR_THREAD_DONE) {
gf_sc_lock(compositor, GF_FALSE);
gf_sleep(1);
gf_sc_lock(compositor, GF_TRUE);
}
}
gf_th_del(compositor->VisualThread);
} else {
#ifndef GPAC_DISABLE_3D
compositor_2d_reset_gl_auto(compositor);
#endif
gf_sc_texture_cleanup_hw(compositor);
}
if (compositor->video_out) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Closing video output\n"));
compositor->video_out->Shutdown(compositor->video_out);
gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Closing visual compositor\n"));
if (compositor->focus_highlight) {
gf_node_unregister(compositor->focus_highlight->node, NULL);
drawable_del_ex(compositor->focus_highlight, compositor);
}
if (compositor->selected_text) gf_free(compositor->selected_text);
if (compositor->sel_buffer) gf_free(compositor->sel_buffer);
if (compositor->visual) visual_del(compositor->visual);
if (compositor->sensors) gf_list_del(compositor->sensors);
if (compositor->previous_sensors) gf_list_del(compositor->previous_sensors);
if (compositor->visuals) gf_list_del(compositor->visuals);
if (compositor->strike_bank) gf_list_del(compositor->strike_bank);
if (compositor->hit_use_stack) gf_list_del(compositor->hit_use_stack);
if (compositor->prev_hit_use_stack) gf_list_del(compositor->prev_hit_use_stack);
if (compositor->focus_ancestors) gf_list_del(compositor->focus_ancestors);
if (compositor->focus_use_stack) gf_list_del(compositor->focus_use_stack);
if (compositor->env_tests) gf_list_del(compositor->env_tests);
if (compositor->traverse_state) {
gf_list_del(compositor->traverse_state->vrml_sensors);
gf_list_del(compositor->traverse_state->use_stack);
#ifndef GPAC_DISABLE_3D
gf_list_del(compositor->traverse_state->local_lights);
#endif
gf_free(compositor->traverse_state);
}
#ifndef GPAC_DISABLE_3D
if (compositor->unit_bbox) mesh_free(compositor->unit_bbox);
if (compositor->screen_buffer) gf_free(compositor->screen_buffer);
#endif
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unloading visual compositor module\n"));
if (compositor->audio_renderer) gf_sc_ar_del(compositor->audio_renderer);
compositor->audio_renderer = NULL;
if (compositor->proto_modules) {
u32 i;
for (i=0; i< gf_list_count(compositor->proto_modules); i++) {
GF_HardcodedProto *ifce = gf_list_get(compositor->proto_modules, i);
gf_modules_close_interface((GF_BaseInterface *) ifce);
}
gf_list_del(compositor->proto_modules);
}
if (compositor->evq_mx) gf_mx_p(compositor->evq_mx);
while (gf_list_count(compositor->event_queue)) {
GF_QueuedEvent *qev = (GF_QueuedEvent *)gf_list_get(compositor->event_queue, 0);
gf_list_rem(compositor->event_queue, 0);
gf_free(qev);
}
while (gf_list_count(compositor->event_queue_back)) {
GF_QueuedEvent *qev = (GF_QueuedEvent *)gf_list_get(compositor->event_queue_back, 0);
gf_list_rem(compositor->event_queue, 0);
gf_free(qev);
}
if (compositor->evq_mx) gf_mx_v(compositor->evq_mx);
if (compositor->evq_mx) gf_mx_del(compositor->evq_mx);
gf_list_del(compositor->event_queue);
gf_list_del(compositor->event_queue_back);
if (compositor->font_manager) gf_font_manager_del(compositor->font_manager);
#ifdef GF_SR_USE_VIDEO_CACHE
gf_list_del(compositor->cached_groups);
gf_list_del(compositor->cached_groups_queue);
#endif
if (compositor->textures) gf_list_del(compositor->textures);
if (compositor->textures_gc) gf_list_del(compositor->textures_gc);
if (compositor->time_nodes) gf_list_del(compositor->time_nodes);
if (compositor->extra_scenes) gf_list_del(compositor->extra_scenes);
if (compositor->video_listeners) gf_list_del(compositor->video_listeners);
gf_sc_lock(compositor, GF_FALSE);
gf_mx_del(compositor->mx);
gf_free(compositor);
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Destroyed\n"));
}
void gf_sc_set_fps(GF_Compositor *compositor, Double fps)
{
if (fps) {
compositor->frame_rate = fps;
compositor->frame_duration = (u32) (1000 / fps);
gf_sc_reset_framerate(compositor);
}
}
u32 gf_sc_get_audio_buffer_length(GF_Compositor *compositor)
{
if (!compositor || !compositor->audio_renderer || !compositor->audio_renderer->audio_out) return 0;
return compositor->audio_renderer->audio_out->GetTotalBufferTime(compositor->audio_renderer->audio_out);
}
static void gf_sc_set_play_state(GF_Compositor *compositor, u32 PlayState)
{
if (!compositor || !compositor->audio_renderer) return;
if (!compositor->paused && !PlayState) return;
if (compositor->paused && (PlayState==GF_STATE_PAUSED)) return;
if (PlayState==GF_STATE_STEP_PAUSE) {
compositor->step_mode = GF_TRUE;
gf_sc_flush_next_audio(compositor);
compositor->paused = 1;
} else {
compositor->step_mode = GF_FALSE;
if (compositor->audio_renderer) gf_sc_ar_control(compositor->audio_renderer, (compositor->paused && (PlayState==0xFF)) ? GF_SC_AR_RESET_HW_AND_PLAY : (compositor->paused ? GF_SC_AR_RESUME : GF_SC_AR_PAUSE) );
compositor->paused = (PlayState==GF_STATE_PAUSED) ? 1 : 0;
}
}
u32 gf_sc_get_clock(GF_Compositor *compositor)
{
if (!compositor->bench_mode) {
return gf_sc_ar_get_clock(compositor->audio_renderer);
}
return compositor->scene_sampled_clock;
}
GF_Err gf_sc_set_scene_size(GF_Compositor *compositor, u32 Width, u32 Height, Bool force_size)
{
if (!Width || !Height) {
if (compositor->override_size_flags) {
compositor->scene_height = SC_DEF_HEIGHT;
compositor->scene_width = SC_DEF_WIDTH;
} else {
compositor->scene_width = compositor->new_width ? compositor->new_width : compositor->display_width;
compositor->scene_height = compositor->new_height ? compositor->new_height : compositor->display_height;
}
} else {
compositor->scene_height = Height;
compositor->scene_width = Width;
}
if (force_size)
compositor->has_size_info = 1;
return GF_OK;
}
Bool gf_sc_get_size(GF_Compositor *compositor, u32 *Width, u32 *Height)
{
*Height = compositor->scene_height;
*Width = compositor->scene_width;
return 1;
}
#ifndef GPAC_DISABLE_SVG
GF_EXPORT
Fixed gf_sc_svg_convert_length_to_display(GF_Compositor *compositor, SVG_Length *length)
{
u32 dpi = 90;
if (!length) return 0;
switch (length->type) {
case SVG_NUMBER_PERCENTAGE:
break;
case SVG_NUMBER_EMS:
break;
case SVG_NUMBER_EXS:
break;
case SVG_NUMBER_VALUE:
break;
case SVG_NUMBER_PX:
return length->value;
case SVG_NUMBER_CM:
return gf_mulfix(length->value, dpi*FLT2FIX(0.39));
break;
case SVG_NUMBER_MM:
return gf_mulfix(length->value, dpi*FLT2FIX(0.039));
case SVG_NUMBER_IN:
return length->value * dpi;
case SVG_NUMBER_PT:
return (dpi * length->value) / 12;
case SVG_NUMBER_PC:
return (dpi*length->value) / 6;
case SVG_NUMBER_INHERIT:
break;
}
return length->value;
}
#endif
void compositor_set_ar_scale(GF_Compositor *compositor, Fixed scaleX, Fixed scaleY)
{
compositor->trans_x = gf_muldiv(compositor->trans_x, scaleX, compositor->scale_x);
compositor->trans_y = gf_muldiv(compositor->trans_y, scaleY, compositor->scale_y);
compositor->zoom_changed = 1;
compositor->scale_x = scaleX;
compositor->scale_y = scaleY;
compositor_2d_set_user_transform(compositor, compositor->zoom, compositor->trans_x, compositor->trans_y, 1);
}
static void gf_sc_reset(GF_Compositor *compositor, Bool has_scene)
{
Bool draw_mode;
GF_VisualManager *visual;
u32 i=0;
while ((visual = (GF_VisualManager *)gf_list_enum(compositor->visuals, &i))) {
visual->cur_context = visual->context;
if (visual->cur_context) visual->cur_context->drawable = NULL;
while (visual->prev_nodes) {
struct _drawable_store *cur = visual->prev_nodes;
visual->prev_nodes = cur->next;
gf_free(cur);
}
visual->last_prev_entry = NULL;
visual->to_redraw.count = 0;
if (visual->raster_surface) compositor->rasterizer->surface_delete(visual->raster_surface);
visual->raster_surface = NULL;
}
gf_list_reset(compositor->sensors);
gf_list_reset(compositor->previous_sensors);
draw_mode = compositor->traverse_state->immediate_draw;
gf_list_del(compositor->traverse_state->vrml_sensors);
gf_list_del(compositor->traverse_state->use_stack);
#ifndef GPAC_DISABLE_3D
gf_list_del(compositor->traverse_state->local_lights);
#endif
memset(compositor->traverse_state, 0, sizeof(GF_TraverseState));
compositor->traverse_state->vrml_sensors = gf_list_new();
compositor->traverse_state->use_stack = gf_list_new();
#ifndef GPAC_DISABLE_3D
compositor->traverse_state->local_lights = gf_list_new();
#endif
gf_mx2d_init(compositor->traverse_state->transform);
gf_cmx_init(&compositor->traverse_state->color_mat);
compositor->traverse_state->immediate_draw = draw_mode;
#ifdef GF_SR_USE_DEPTH
compositor->traverse_state->depth_gain = FIX_ONE;
compositor->traverse_state->depth_offset = 0;
#endif
#ifndef GPAC_DISABLE_3D
if (has_scene && compositor->hybgl_txh) {
compositor->hybgl_txh->width = compositor->hybgl_txh->height = 0;
}
#endif
assert(!compositor->visual->overlays);
compositor->reset_graphics = 0;
compositor->trans_x = compositor->trans_y = 0;
compositor->zoom = FIX_ONE;
compositor->grab_node = NULL;
compositor->grab_use = NULL;
compositor->focus_node = NULL;
compositor->focus_text_type = 0;
compositor->frame_number = 0;
compositor->video_memory = compositor->was_system_memory ? 0 : 1;
compositor->rotation = 0;
gf_list_reset(compositor->focus_ancestors);
gf_list_reset(compositor->focus_use_stack);
#ifdef GF_SR_USE_VIDEO_CACHE
gf_list_reset(compositor->cached_groups);
compositor->video_cache_current_size = 0;
gf_list_reset(compositor->cached_groups_queue);
#endif
compositor->root_visual_setup = 0;
compositor_set_ar_scale(compositor, compositor->scale_x, compositor->scale_x);
}
GF_Err gf_sc_set_scene(GF_Compositor *compositor, GF_SceneGraph *scene_graph)
{
u32 width, height;
Bool do_notif;
if (!compositor) return GF_BAD_PARAM;
gf_sc_lock(compositor, 1);
GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, (scene_graph ? "[Compositor] Attaching new scene\n" : "[Compositor] Detaching scene\n"));
if (compositor->audio_renderer && (compositor->scene != scene_graph)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting audio compositor\n"));
gf_sc_ar_reset(compositor->audio_renderer);
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting event queue\n"));
gf_mx_p(compositor->evq_mx);
while (gf_list_count(compositor->event_queue)) {
GF_QueuedEvent *qev = (GF_QueuedEvent*)gf_list_get(compositor->event_queue, 0);
gf_list_rem(compositor->event_queue, 0);
gf_free(qev);
}
gf_mx_v(compositor->evq_mx);
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting compositor module\n"));
gf_sc_reset(compositor, scene_graph ? 1 : 0);
compositor->scene = scene_graph;
do_notif = GF_FALSE;
if (scene_graph) {
#ifndef GPAC_DISABLE_SVG
SVG_Length *w, *h;
SVG_ViewBox *vb;
Bool is_svg = GF_FALSE;
u32 tag;
GF_Node *top_node;
#endif
const char *opt;
Bool had_size_info = compositor->has_size_info;
gf_sg_get_scene_size_info(compositor->scene, &width, &height);
compositor->has_size_info = (width && height) ? 1 : 0;
if (compositor->has_size_info != had_size_info) compositor->scene_width = compositor->scene_height = 0;
compositor->video_memory = gf_scene_is_dynamic_scene(scene_graph);
#ifndef GPAC_DISABLE_3D
compositor->visual->camera.world_bbox.is_set = 0;
#endif
if (! (compositor->user->init_flags & GF_TERM_WINDOWLESS)) {
if (compositor->default_back_color) {
compositor->back_color = compositor->default_back_color;
} else {
compositor->back_color = 0xFF000000;
}
}
#ifndef GPAC_DISABLE_SVG
top_node = gf_sg_get_root_node(compositor->scene);
tag = 0;
if (top_node) tag = gf_node_get_tag(top_node);
w = h = NULL;
vb = NULL;
if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) {
GF_FieldInfo info;
is_svg = 1;
if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_width, 0, 0, &info)==GF_OK)
w = info.far_ptr;
if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_height, 0, 0, &info)==GF_OK)
h = info.far_ptr;
if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_viewBox, 0, 0, &info)==GF_OK)
vb = info.far_ptr;
}
if (is_svg && ! (compositor->user->init_flags & GF_TERM_WINDOWLESS)) compositor->back_color = 0xFFFFFFFF;
if (!compositor->has_size_info && w && h && vb) {
do_notif = 1;
if (w->type!=SVG_NUMBER_PERCENTAGE) {
width = FIX2INT(gf_sc_svg_convert_length_to_display(compositor, w) );
} else if ((u32) FIX2INT(vb->width)<compositor->video_out->max_screen_width) {
width = FIX2INT(vb->width);
} else {
width = SC_DEF_WIDTH;
do_notif = 0;
}
if (h->type!=SVG_NUMBER_PERCENTAGE) {
height = FIX2INT(gf_sc_svg_convert_length_to_display(compositor, h) );
} else if ((u32) FIX2INT(vb->height)<compositor->video_out->max_screen_height) {
height = FIX2INT(vb->height);
} else {
height = SC_DEF_HEIGHT;
do_notif = 0;
}
}
if (is_svg) {
compositor->has_size_info = 0;
gf_sc_focus_switch_ring(compositor, 0, NULL, 0);
} else
#endif
{
GF_Node *keynav = gf_scene_get_keynav(compositor->scene, NULL);
if (keynav) gf_sc_change_key_navigator(compositor, keynav);
}
if (compositor->user->init_flags & GF_TERM_WINDOWLESS) {
opt = gf_cfg_get_key(compositor->user->config, "Compositor", "ColorKey");
if (opt) {
u32 r, g, b, a;
sscanf(opt, "%02X%02X%02X%02X", &a, &r, &g, &b);
compositor->back_color = GF_COL_ARGB(0xFF, r, g, b);
}
}
if ( !width || (compositor->scene_width!=width) || !height || (compositor->scene_height!=height)) {
do_notif = do_notif || compositor->has_size_info || (!compositor->scene_width && !compositor->scene_height);
gf_sc_set_scene_size(compositor, width, height, 0);
width = compositor->scene_width;
height = compositor->scene_height;
opt = gf_cfg_get_key(compositor->user->config, "Compositor", "ScreenWidth");
if (opt) width = atoi(opt);
opt = gf_cfg_get_key(compositor->user->config, "Compositor", "ScreenHeight");
if (opt) height = atoi(opt);
if (!compositor->user->os_window_handler) {
if (compositor->video_out->max_screen_width && (width > compositor->video_out->max_screen_width))
width = compositor->video_out->max_screen_width;
if (compositor->video_out->max_screen_height && (height > compositor->video_out->max_screen_height))
height = compositor->video_out->max_screen_height;
gf_sc_set_size(compositor,width, height);
}
}
}
gf_sc_reset_framerate(compositor);
gf_sc_lock(compositor, 0);
if (scene_graph)
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
if (do_notif) {
GF_Event evt;
evt.type = GF_EVENT_SCENE_SIZE;
evt.size.width = width;
evt.size.height = height;
gf_term_send_event(compositor->term, &evt);
}
return GF_OK;
}
void gf_sc_lock_audio(GF_Compositor *compositor, Bool doLock)
{
if (compositor->audio_renderer) {
gf_mixer_lock(compositor->audio_renderer->mixer, doLock);
}
}
GF_EXPORT
void gf_sc_lock(GF_Compositor *compositor, Bool doLock)
{
if (doLock)
gf_mx_p(compositor->mx);
else {
gf_mx_v(compositor->mx);
}
}
GF_EXPORT
GF_Err gf_sc_set_size(GF_Compositor *compositor, u32 NewWidth, u32 NewHeight)
{
Bool lock_ok;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("sc_set_size %dx%d\n", NewWidth, NewHeight));
if ((compositor->display_width == NewWidth) && (compositor->display_height == NewHeight))
return GF_OK;
if (!NewWidth || !NewHeight) {
compositor->override_size_flags &= ~2;
compositor->msg_type |= GF_SR_CFG_AR;
return GF_OK;
}
lock_ok = gf_mx_try_lock(compositor->mx);
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("line %d lock_ok %d\n", __LINE__, lock_ok));
compositor->new_width = NewWidth;
compositor->new_height = NewHeight;
compositor->msg_type |= GF_SR_CFG_SET_SIZE;
assert(compositor->new_width);
compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
if ((compositor->display_width == NewWidth) && (compositor->display_height == NewHeight) ) {
compositor->msg_type |= GF_SR_CFG_WINDOWSIZE_NOTIF;
}
if (lock_ok) gf_sc_lock(compositor, 0);
{
GF_Event evt;
evt.type = GF_EVENT_SCENE_SIZE;
evt.size.width = NewWidth;
evt.size.height = NewHeight;
gf_term_send_event(compositor->term, &evt);
}
return GF_OK;
}
GF_EXPORT
void gf_sc_reload_config(GF_Compositor *compositor)
{
const char *sOpt;
gf_sc_lock(compositor, 1);
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "FrameRate");
if (!sOpt) {
sOpt = "30.0";
gf_cfg_set_key(compositor->user->config, "Compositor", "FrameRate", "30.0");
}
gf_sc_set_fps(compositor, atof(sOpt));
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "ForceSceneSize");
if (sOpt && ! stricmp(sOpt, "yes")) {
compositor->override_size_flags = 1;
} else {
compositor->override_size_flags = 0;
}
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "AntiAlias");
if (sOpt) {
if (! stricmp(sOpt, "None")) gf_sc_set_option(compositor, GF_OPT_ANTIALIAS, GF_ANTIALIAS_NONE);
else if (! stricmp(sOpt, "Text")) gf_sc_set_option(compositor, GF_OPT_ANTIALIAS, GF_ANTIALIAS_TEXT);
else gf_sc_set_option(compositor, GF_OPT_ANTIALIAS, GF_ANTIALIAS_FULL);
} else {
gf_cfg_set_key(compositor->user->config, "Compositor", "AntiAlias", "All");
gf_sc_set_option(compositor, GF_OPT_ANTIALIAS, GF_ANTIALIAS_FULL);
}
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "FocusHighlightFill");
if (sOpt) sscanf(sOpt, "%x", &compositor->highlight_fill);
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "FocusHighlightStroke");
if (sOpt) sscanf(sOpt, "%x", &compositor->highlight_stroke);
else compositor->highlight_stroke = 0xFF000000;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "FocusHighlightStrokeWidth");
if (sOpt) {
Float v;
sscanf(sOpt, "%f", &v);
compositor->highlight_stroke_width = FLT2FIX(v);
}
else compositor->highlight_stroke_width = FIX_ONE;
compositor->text_sel_color = 0xFFAAAAFF;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "TextSelectHighlight");
if (sOpt) sscanf(sOpt, "%x", &compositor->text_sel_color);
if (!compositor->text_sel_color) compositor->text_sel_color = 0xFFAAAAFF;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "ScalableZoom");
compositor->scalable_zoom = (!sOpt || !stricmp(sOpt, "yes") ) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DisableYUV");
compositor->enable_yuv_hw = (sOpt && !stricmp(sOpt, "yes") ) ? 0 : 1;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DisablePartialHardwareBlit");
compositor->disable_partial_hw_blit = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "StressMode");
gf_sc_set_option(compositor, GF_OPT_STRESS_MODE, (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0);
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "HighSpeed");
gf_sc_set_option(compositor, GF_OPT_HIGHSPEED, (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0);
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "BoundingVolume");
if (sOpt) {
if (! stricmp(sOpt, "Box")) gf_sc_set_option(compositor, GF_OPT_DRAW_BOUNDS, GF_BOUNDS_BOX);
else if (! stricmp(sOpt, "AABB")) gf_sc_set_option(compositor, GF_OPT_DRAW_BOUNDS, GF_BOUNDS_AABB);
else gf_sc_set_option(compositor, GF_OPT_DRAW_BOUNDS, GF_BOUNDS_NONE);
} else {
gf_cfg_set_key(compositor->user->config, "Compositor", "BoundingVolume", "None");
gf_sc_set_option(compositor, GF_OPT_DRAW_BOUNDS, GF_BOUNDS_NONE);
}
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "TextureTextMode");
if (sOpt && !stricmp(sOpt, "Always")) compositor->texture_text_mode = GF_TEXTURE_TEXT_ALWAYS;
else if (sOpt && !stricmp(sOpt, "Never")) compositor->texture_text_mode = GF_TEXTURE_TEXT_NEVER;
else compositor->texture_text_mode = GF_TEXTURE_TEXT_DEFAULT;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "Output8bit");
if (!sOpt) {
sOpt = (compositor->video_out->max_screen_bpp > 8) ? "no" : "yes";
gf_cfg_set_key(compositor->user->config, "Compositor", "Output8bit", sOpt);
}
if (sOpt && !strcmp(sOpt, "yes")) compositor->output_as_8bit = GF_TRUE;
if (compositor->audio_renderer) {
sOpt = gf_cfg_get_key(compositor->user->config, "Audio", "NoResync");
compositor->audio_renderer->disable_resync = (sOpt && !stricmp(sOpt, "yes")) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Audio", "DisableMultiChannel");
compositor->audio_renderer->disable_multichannel = (sOpt && !stricmp(sOpt, "yes")) ? 1 : 0;
}
#ifdef GF_SR_USE_VIDEO_CACHE
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "VideoCacheSize");
compositor->video_cache_max_size = sOpt ? atoi(sOpt) : 0;
compositor->video_cache_max_size *= 1024;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "CacheScale");
compositor->cache_scale = sOpt ? atoi(sOpt) : 100;
if (!compositor->cache_scale) compositor->cache_scale = 100;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "CacheTolerance");
compositor->cache_tolerance = sOpt ? atoi(sOpt) : 30;
#endif
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "TextureFromDecoderMemory");
compositor->texture_from_decoder_memory = (sOpt && !strcmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE;
if (!sOpt)
gf_cfg_set_key(compositor->user->config, "Compositor", "TextureFromDecoderMemory", "no");
#ifndef GPAC_DISABLE_3D
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "OpenGLMode");
if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL)) {
if (sOpt && strcmp(sOpt, "disable")) {
GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] OpenGL mode %s requested but no opengl-capable output - disabling openGL\n", sOpt));
}
compositor->force_opengl_2d = 0;
compositor->autoconfig_opengl = 0;
compositor->hybrid_opengl = 0;
} else {
compositor->force_opengl_2d = (sOpt && !strcmp(sOpt, "always")) ? 1 : 0;
if (!sOpt) {
compositor->recompute_ar = 1;
compositor->autoconfig_opengl = 1;
} else {
compositor->hybrid_opengl = !strcmp(sOpt, "hybrid") ? 1 : 0;
#ifdef OPENGL_RASTER
compositor->opengl_raster = !strcmp(sOpt, "raster") ? 1 : 0;
if (compositor->opengl_raster) compositor->traverse_state->immediate_draw = GF_TRUE;
#endif
}
}
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "EnablePBO");
if (!sOpt) gf_cfg_set_key(compositor->user->config, "Compositor", "EnablePBO", "no");
compositor->enable_pbo = (sOpt && !strcmp(sOpt, "yes")) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DefaultNavigationMode");
if (sOpt && !strcmp(sOpt, "Walk")) compositor->default_navigation_mode = GF_NAVIGATE_WALK;
else if (sOpt && !strcmp(sOpt, "Examine")) compositor->default_navigation_mode = GF_NAVIGATE_EXAMINE;
else if (sOpt && !strcmp(sOpt, "Fly")) compositor->default_navigation_mode = GF_NAVIGATE_FLY;
#ifdef GPAC_HAS_GLU
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "RasterOutlines");
compositor->raster_outlines = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
#endif
#ifndef GPAC_USE_GLES1X
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "EmulatePOW2");
compositor->emul_pow2 = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
#else
compositor->raster_outlines = 1;
compositor->emul_pow2 = 1;
#endif
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "PolygonAA");
compositor->poly_aa = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "BackFaceCulling");
if (sOpt && !stricmp(sOpt, "Off")) compositor->backcull = GF_BACK_CULL_OFF;
else if (sOpt && !stricmp(sOpt, "Alpha")) compositor->backcull = GF_BACK_CULL_ALPHA;
else compositor->backcull = GF_BACK_CULL_ON;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "Wireframe");
if (sOpt && !stricmp(sOpt, "WireOnly")) compositor->wiremode = GF_WIREFRAME_ONLY;
else if (sOpt && !stricmp(sOpt, "WireOnSolid")) compositor->wiremode = GF_WIREFRAME_SOLID;
else compositor->wiremode = GF_WIREFRAME_NONE;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DrawNormals");
if (sOpt && !stricmp(sOpt, "PerFace")) compositor->draw_normals = GF_NORMALS_FACE;
else if (sOpt && !stricmp(sOpt, "PerVertex")) compositor->draw_normals = GF_NORMALS_VERTEX;
else compositor->draw_normals = GF_NORMALS_NONE;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DisableGLUScale");
compositor->disable_glu_scale = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DisableRectExt");
compositor->disable_rect_ext = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DisableGLCulling");
compositor->disable_gl_cull = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DisableYUVGL");
compositor->disable_yuvgl = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DepthScale");
if (!sOpt) {
sOpt = "100";
gf_cfg_set_key(compositor->user->config, "Compositor", "DepthScale", sOpt);
}
compositor->depth_gl_scale = FLT2FIX( (Float) atof(sOpt) );
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DepthType");
if (!sOpt) {
sOpt = "VertexArray";
gf_cfg_set_key(compositor->user->config, "Compositor", "DepthType", sOpt);
}
if (sOpt && !strcmp(sOpt, "Points")) compositor->depth_gl_type = GF_SC_DEPTH_GL_POINTS;
else if (sOpt && !strnicmp(sOpt, "Strips", 6)) {
compositor->depth_gl_type = GF_SC_DEPTH_GL_STRIPS;
compositor->depth_gl_strips_filter = 0;
if (strlen(sOpt)>7) compositor->depth_gl_strips_filter = FLT2FIX( (Float) atof(sOpt+7) );
}
else if (sOpt && !strcmp(sOpt, "VertexArray")) compositor->depth_gl_type = GF_SC_DEPTH_GL_VBO;
else compositor->depth_gl_type = GF_SC_DEPTH_GL_NONE;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "NumViews");
if (!sOpt) {
sOpt = "1";
gf_cfg_set_key(compositor->user->config, "Compositor", "NumViews", "1");
}
compositor->visual->nb_views = atoi(sOpt);
if (!compositor->visual->nb_views) compositor->visual->nb_views = 1;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "StereoType");
if (!sOpt) {
sOpt = "none";
gf_cfg_set_key(compositor->user->config, "Compositor", "StereoType", "none");
}
if (!strcmp(sOpt, "SideBySide")) compositor->visual->autostereo_type = GF_3D_STEREO_SIDE;
else if (!strcmp(sOpt, "TopToBottom")) compositor->visual->autostereo_type = GF_3D_STEREO_TOP;
else if (!strcmp(sOpt, "Custom")) compositor->visual->autostereo_type = GF_3D_STEREO_CUSTOM;
else if (!strcmp(sOpt, "Anaglyph")) compositor->visual->autostereo_type = GF_3D_STEREO_ANAGLYPH;
else if (!strcmp(sOpt, "Columns")) compositor->visual->autostereo_type = GF_3D_STEREO_COLUMNS;
else if (!strcmp(sOpt, "Rows")) compositor->visual->autostereo_type = GF_3D_STEREO_ROWS;
else if (!strcmp(sOpt, "SPV19")) {
compositor->visual->autostereo_type = GF_3D_STEREO_5VSP19;
if (compositor->visual->nb_views != 5) {
GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] SPV19 interleaving used but only %d views indicated - adjusting to 5 view\n", compositor->visual->nb_views ));
compositor->visual->nb_views = 5;
gf_cfg_set_key(compositor->user->config, "Compositor", "NumViews", "5");
}
}
else if (!strcmp(sOpt, "ALIO")) {
compositor->visual->autostereo_type = GF_3D_STEREO_8VALIO;
if (compositor->visual->nb_views != 8) {
GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] ALIO interleaving used but only %d views indicated - adjusting to 8 view\n", compositor->visual->nb_views ));
compositor->visual->nb_views = 8;
gf_cfg_set_key(compositor->user->config, "Compositor", "NumViews", "8");
}
}
else if (!strcmp(sOpt, "StereoHeadset")) compositor->visual->autostereo_type = GF_3D_STEREO_HEADSET;
else {
compositor->visual->autostereo_type = GF_3D_STEREO_NONE;
compositor->visual->nb_views = 1;
gf_cfg_set_key(compositor->user->config, "Compositor", "NumViews", "1");
}
if ((compositor->visual->autostereo_type!=GF_3D_STEREO_NONE) && (compositor->visual->autostereo_type <= GF_3D_STEREO_HEADSET)) {
compositor->visual->nb_views = 2;
}
if (compositor->visual->autostereo_type)
compositor->force_opengl_2d = 1;
switch (compositor->visual->autostereo_type) {
case GF_3D_STEREO_ANAGLYPH:
case GF_3D_STEREO_COLUMNS:
case GF_3D_STEREO_ROWS:
if (compositor->visual->nb_views != 2) {
GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] Stereo interleaving used but %d views indicated - adjusting to 2 view\n", compositor->visual->nb_views ));
compositor->visual->nb_views = 2;
gf_cfg_set_key(compositor->user->config, "Compositor", "NumViews", "2");
}
break;
}
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "FramePacking");
if (!sOpt) {
sOpt = "None";
gf_cfg_set_key(compositor->user->config, "Compositor", "FramePacking", "None");
}
if (!strcmp(sOpt, "Side")) compositor->frame_packing = GF_3D_STEREO_SIDE;
else if (!strcmp(sOpt, "Top")) compositor->frame_packing = GF_3D_STEREO_TOP;
else compositor->frame_packing = GF_3D_STEREO_NONE;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "CameraLayout");
if (!sOpt) {
sOpt = "Straight";
gf_cfg_set_key(compositor->user->config, "Compositor", "CameraLayout", "Straight");
}
if (!strcmp(sOpt, "Linear")) compositor->visual->camera_layout = GF_3D_CAMERA_LINEAR;
else if (!strcmp(sOpt, "Circular")) compositor->visual->camera_layout = GF_3D_CAMERA_CIRCULAR;
else if (!strcmp(sOpt, "OffAxis")) compositor->visual->camera_layout = GF_3D_CAMERA_OFFAXIS;
else compositor->visual->camera_layout = GF_3D_CAMERA_STRAIGHT;
compositor->interoccular_distance = FLT2FIX(6.3f);
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "EyeSeparation");
if (sOpt) compositor->interoccular_distance = FLT2FIX( atof(sOpt)) ;
else gf_cfg_set_key(compositor->user->config, "Compositor", "EyeSeparation", "6.3");
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "ReverseViews");
if (sOpt && !strcmp(sOpt, "yes")) compositor->visual->reverse_views = 1;
#endif
if (!compositor->hybrid_opengl && compositor->video_out->hw_caps & GF_VIDEO_HW_DIRECT_ONLY) {
compositor->traverse_state->immediate_draw = 1;
} else {
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DrawMode");
if (!sOpt) {
sOpt = "defer";
gf_cfg_set_key(compositor->user->config, "Compositor", "DrawMode", sOpt);
}
if (!strcmp(sOpt, "immediate")) compositor->traverse_state->immediate_draw = 1;
else if (!strcmp(sOpt, "defer-debug")) {
compositor->traverse_state->immediate_draw = 0;
compositor->debug_defer = 1;
}
else compositor->traverse_state->immediate_draw = 0;
}
#ifdef GF_SR_USE_DEPTH
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "AutoStereoCalibration");
compositor->auto_calibration = (sOpt && !strcmp(sOpt, "yes")) ? 1 : 0;
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "DisplayDepth");
compositor->display_depth = sOpt ? (!strcmp(sOpt, "auto") ? -1 : atoi(sOpt)) : 0;
#ifndef GPAC_DISABLE_3D
if (compositor->visual->autostereo_type && !compositor->display_depth) {
compositor->display_depth = -1;
}
#endif
if (!compositor->video_out->view_distance) {
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "ViewDistance");
compositor->video_out->view_distance = FLT2FIX( sOpt ? (Float) atof(sOpt) : 50.0f );
}
#ifndef GPAC_DISABLE_3D
sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "FocusDistance");
compositor->focus_distance = 0;
if (sOpt)
compositor->focus_distance = FLT2FIX( atof(sOpt) );
else
gf_cfg_set_key(compositor->user->config, "Compositor", "FocusDistance", "0");
#endif
#endif
gf_sc_reset_graphics(compositor);
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
gf_sc_lock(compositor, 0);
}
GF_EXPORT
GF_Err gf_sc_set_option(GF_Compositor *compositor, u32 type, u32 value)
{
GF_Err e;
gf_sc_lock(compositor, 1);
e = GF_OK;
switch (type) {
case GF_OPT_PLAY_STATE:
gf_sc_set_play_state(compositor, value);
break;
case GF_OPT_AUDIO_VOLUME:
gf_sc_ar_set_volume(compositor->audio_renderer, value);
break;
case GF_OPT_AUDIO_PAN:
gf_sc_ar_set_pan(compositor->audio_renderer, value);
break;
case GF_OPT_AUDIO_MUTE:
gf_sc_ar_mute(compositor->audio_renderer, value);
break;
case GF_OPT_OVERRIDE_SIZE:
compositor->override_size_flags = value ? 1 : 0;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_STRESS_MODE:
compositor->stress_mode = value;
break;
case GF_OPT_ANTIALIAS:
compositor->antiAlias = value;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_HIGHSPEED:
compositor->high_speed = value;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_DRAW_BOUNDS:
compositor->draw_bvol = value;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_TEXTURE_TEXT:
compositor->texture_text_mode = value;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_ASPECT_RATIO:
compositor->aspect_ratio = value;
compositor->msg_type |= GF_SR_CFG_AR;
break;
case GF_OPT_INTERACTION_LEVEL:
compositor->interaction_level = value;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_REFRESH:
gf_sc_reset_graphics(compositor);
compositor->traverse_state->invalidate_all = 1;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_FULLSCREEN:
if (compositor->fullscreen != value) compositor->msg_type |= GF_SR_CFG_FULLSCREEN;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_ORIGINAL_VIEW:
compositor_2d_set_user_transform(compositor, FIX_ONE, 0, 0, 0);
gf_sc_set_size(compositor, compositor->scene_width, compositor->scene_height);
break;
case GF_OPT_VISIBLE:
compositor->is_hidden = !value;
if (compositor->video_out->ProcessEvent) {
GF_Event evt;
evt.type = GF_EVENT_SHOWHIDE;
evt.show.show_type = value ? 1 : 0;
e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
}
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_FREEZE_DISPLAY:
compositor->freeze_display = value;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_FORCE_AUDIO_CONFIG:
if (value) {
compositor->audio_renderer->config_forced++;
} else if (compositor->audio_renderer->config_forced) {
compositor->audio_renderer->config_forced --;
}
break;
case GF_OPT_RELOAD_CONFIG:
gf_sc_reload_config(compositor);
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_DRAW_MODE:
if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_DIRECT_ONLY)) {
compositor->traverse_state->immediate_draw = (value==GF_DRAW_MODE_IMMEDIATE) ? 1 : 0;
compositor->debug_defer = (value==GF_DRAW_MODE_DEFER_DEBUG) ? 1 : 0;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
}
break;
case GF_OPT_SCALABLE_ZOOM:
compositor->scalable_zoom = value;
compositor->msg_type |= GF_SR_CFG_AR;
break;
case GF_OPT_USE_OPENGL:
if (compositor->force_opengl_2d != value) {
compositor->force_opengl_2d = value;
compositor->root_visual_setup = 0;
if (value) gf_sc_reset_graphics(compositor);
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
}
break;
case GF_OPT_VIDEO_BENCH:
compositor->bench_mode = value ? GF_TRUE : GF_FALSE;
break;
case GF_OPT_YUV_HARDWARE:
compositor->enable_yuv_hw = value;
break;
case GF_OPT_NAVIGATION_TYPE:
compositor->rotation = 0;
compositor_2d_set_user_transform(compositor, FIX_ONE, 0, 0, 0);
#ifndef GPAC_DISABLE_3D
compositor_3d_reset_camera(compositor);
#endif
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
break;
case GF_OPT_NAVIGATION:
if (! gf_sc_navigation_supported(compositor, value)) {
e = GF_NOT_SUPPORTED;
}
#ifndef GPAC_DISABLE_3D
else if (compositor->visual->type_3d || compositor->active_layer) {
GF_Camera *cam = compositor_3d_get_camera(compositor);
cam->navigate_mode = value;
}
#endif
else {
compositor->navigate_mode = value;
}
break;
case GF_OPT_HEADLIGHT:
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d || compositor->active_layer) {
GF_Camera *cam = compositor_3d_get_camera(compositor);
if (cam->navigation_flags & NAV_ANY) {
if (value)
cam->navigation_flags |= NAV_HEADLIGHT;
else
cam->navigation_flags &= ~NAV_HEADLIGHT;
break;
}
}
#endif
e = GF_NOT_SUPPORTED;
break;
#ifndef GPAC_DISABLE_3D
case GF_OPT_EMULATE_POW2:
compositor->emul_pow2 = value;
break;
case GF_OPT_POLYGON_ANTIALIAS:
compositor->poly_aa = value;
break;
case GF_OPT_BACK_CULL:
compositor->backcull = value;
break;
case GF_OPT_WIREFRAME:
compositor->wiremode = value;
break;
case GF_OPT_NORMALS:
compositor->draw_normals = value;
break;
#ifdef GPAC_HAS_GLU
case GF_OPT_RASTER_OUTLINES:
compositor->raster_outlines = value;
break;
#endif
case GF_OPT_NO_RECT_TEXTURE:
if (value != compositor->disable_rect_ext) {
compositor->disable_rect_ext = value;
gf_sc_reset_graphics(compositor);
}
break;
case GF_OPT_COLLISION:
compositor->collide_mode = value;
break;
case GF_OPT_GRAVITY:
{
GF_Camera *cam = compositor_3d_get_camera(compositor);
compositor->gravity_on = value;
cam->last_pos.z -= 1;
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
}
break;
#endif
case GF_OPT_VIDEO_CACHE_SIZE:
#ifdef GF_SR_USE_VIDEO_CACHE
compositor_set_cache_memory(compositor, 1024*value);
#else
e = GF_NOT_SUPPORTED;
#endif
break;
default:
e = GF_BAD_PARAM;
break;
}
gf_sc_lock(compositor, 0);
return e;
}
GF_EXPORT
Bool gf_sc_is_over(GF_Compositor *compositor, GF_SceneGraph *scene_graph)
{
u32 i, count;
count = gf_list_count(compositor->time_nodes);
for (i=0; i<count; i++) {
GF_TimeNode *tn = (GF_TimeNode *)gf_list_get(compositor->time_nodes, i);
if (tn->needs_unregister) continue;
if (scene_graph && (gf_node_get_graph((GF_Node *)tn->udta) != scene_graph))
continue;
switch (gf_node_get_tag((GF_Node *)tn->udta)) {
#ifndef GPAC_DISABLE_VRML
case TAG_MPEG4_TimeSensor:
#endif
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_TimeSensor:
#endif
return 0;
#ifndef GPAC_DISABLE_VRML
case TAG_MPEG4_MovieTexture:
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_MovieTexture:
#endif
if (((M_MovieTexture *)tn->udta)->loop) return 0;
break;
case TAG_MPEG4_AudioClip:
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_AudioClip:
#endif
if (((M_AudioClip*)tn->udta)->loop) return 0;
break;
case TAG_MPEG4_AnimationStream:
if (((M_AnimationStream*)tn->udta)->loop) return 0;
break;
#endif
}
}
return 1;
}
u32 gf_sc_get_option(GF_Compositor *compositor, u32 type)
{
switch (type) {
case GF_OPT_PLAY_STATE:
return compositor->paused ? 1 : 0;
case GF_OPT_OVERRIDE_SIZE:
return (compositor->override_size_flags & 1) ? 1 : 0;
case GF_OPT_IS_FINISHED:
if (compositor->interaction_sensors) return 0;
case GF_OPT_IS_OVER:
return gf_sc_is_over(compositor, NULL);
case GF_OPT_STRESS_MODE:
return compositor->stress_mode;
case GF_OPT_AUDIO_VOLUME:
return compositor->audio_renderer->volume;
case GF_OPT_AUDIO_PAN:
return compositor->audio_renderer->pan;
case GF_OPT_AUDIO_MUTE:
return compositor->audio_renderer->mute;
case GF_OPT_ANTIALIAS:
return compositor->antiAlias;
case GF_OPT_HIGHSPEED:
return compositor->high_speed;
case GF_OPT_ASPECT_RATIO:
return compositor->aspect_ratio;
case GF_OPT_FULLSCREEN:
return compositor->fullscreen;
case GF_OPT_INTERACTION_LEVEL:
return compositor->interaction_level;
case GF_OPT_VISIBLE:
return !compositor->is_hidden;
case GF_OPT_FREEZE_DISPLAY:
return compositor->freeze_display;
case GF_OPT_TEXTURE_TEXT:
return compositor->texture_text_mode;
case GF_OPT_USE_OPENGL:
return compositor->force_opengl_2d;
case GF_OPT_DRAW_MODE:
if (compositor->traverse_state->immediate_draw) return GF_DRAW_MODE_IMMEDIATE;
if (compositor->debug_defer) return GF_DRAW_MODE_DEFER_DEBUG;
return GF_DRAW_MODE_DEFER;
case GF_OPT_SCALABLE_ZOOM:
return compositor->scalable_zoom;
case GF_OPT_YUV_HARDWARE:
return compositor->enable_yuv_hw;
case GF_OPT_YUV_FORMAT:
return compositor->enable_yuv_hw ? compositor->video_out->yuv_pixel_format : 0;
case GF_OPT_NAVIGATION_TYPE:
#ifndef GPAC_DISABLE_3D
if (compositor->navigation_disabled) return GF_NAVIGATE_TYPE_NONE;
if (compositor->visual->type_3d || compositor->active_layer) {
GF_Camera *cam = compositor_3d_get_camera(compositor);
if ((cam->navigation_flags & NAV_SELECTABLE)) return GF_NAVIGATE_TYPE_3D;
if (!(cam->navigation_flags & NAV_ANY)) return GF_NAVIGATE_TYPE_NONE;
return GF_NAVIGATE_TYPE_3D;
} else
#endif
{
return GF_NAVIGATE_TYPE_2D;
}
case GF_OPT_NAVIGATION:
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d || compositor->active_layer) {
GF_Camera *cam = compositor_3d_get_camera(compositor);
return cam->navigate_mode;
}
#endif
return compositor->navigate_mode;
case GF_OPT_HEADLIGHT:
return 0;
case GF_OPT_COLLISION:
return GF_COLLISION_NONE;
case GF_OPT_GRAVITY:
return 0;
case GF_OPT_VIDEO_CACHE_SIZE:
#ifdef GF_SR_USE_VIDEO_CACHE
return compositor->video_cache_max_size/1024;
#else
return 0;
#endif
break;
case GF_OPT_NUM_STEREO_VIEWS:
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d) {
if (compositor->visual->nb_views && compositor->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER)
return compositor->visual->nb_views;
}
#endif
return 1;
default:
return 0;
}
}
void gf_sc_map_point(GF_Compositor *compositor, s32 X, s32 Y, Fixed *bifsX, Fixed *bifsY)
{
X = X - compositor->display_width/2;
Y = compositor->display_height/2 - Y;
*bifsX = INT2FIX(X);
*bifsY = INT2FIX(Y);
}
GF_EXPORT
GF_Err gf_sc_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer, u32 depth_dump_mode)
{
GF_Err e;
if (!compositor || !framebuffer) return GF_BAD_PARAM;
gf_mx_p(compositor->mx);
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d || compositor->hybrid_opengl)
e = compositor_3d_get_screen_buffer(compositor, framebuffer, depth_dump_mode);
else
#endif
if (depth_dump_mode) e = GF_NOT_SUPPORTED;
else e = compositor->video_out->LockBackBuffer(compositor->video_out, framebuffer, 1);
if (e != GF_OK) gf_mx_v(compositor->mx);
return e;
}
GF_Err gf_sc_get_offscreen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer, u32 view_idx, u32 depth_dump_mode)
{
if (!compositor || !framebuffer) return GF_BAD_PARAM;
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d && compositor->visual->nb_views && (compositor->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER)) {
GF_Err e;
gf_mx_p(compositor->mx);
e = compositor_3d_get_offscreen_buffer(compositor, framebuffer, view_idx, depth_dump_mode);
if (e != GF_OK) gf_mx_v(compositor->mx);
return e;
}
#endif
return GF_BAD_PARAM;
}
GF_EXPORT
GF_Err gf_sc_release_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer)
{
GF_Err e;
if (!compositor || !framebuffer) return GF_BAD_PARAM;
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d || compositor->hybrid_opengl)
e = compositor_3d_release_screen_buffer(compositor, framebuffer);
else
#endif
e = compositor->video_out->LockBackBuffer(compositor->video_out, framebuffer, 0);
gf_mx_v(compositor->mx);
return e;
}
GF_EXPORT
Double gf_sc_get_fps(GF_Compositor *compositor, Bool absoluteFPS)
{
Double fps;
u32 fidx, num, frames, run_time;
gf_mx_p(compositor->mx);
if (absoluteFPS) {
fidx = compositor->current_frame;
frames = 0;
run_time = compositor->frame_dur[fidx];
for (num=0; num<GF_SR_FPS_COMPUTE_SIZE; num++) {
run_time += compositor->frame_dur[fidx];
frames++;
if (frames==GF_SR_FPS_COMPUTE_SIZE) break;
if (!fidx) {
fidx = GF_SR_FPS_COMPUTE_SIZE-1;
} else {
fidx--;
}
}
} else {
fidx = compositor->current_frame;
run_time = compositor->frame_time[fidx];
fidx = (fidx+1)% GF_SR_FPS_COMPUTE_SIZE;
assert(run_time >= compositor->frame_time[fidx]);
run_time -= compositor->frame_time[fidx];
frames = GF_SR_FPS_COMPUTE_SIZE-1;
}
gf_mx_v(compositor->mx);
if (!run_time) return (Double) compositor->frame_rate;
fps = 1000*frames;
fps /= run_time;
return fps;
}
void gf_sc_register_time_node(GF_Compositor *compositor, GF_TimeNode *tn)
{
if (tn->is_registered) return;
if (tn->needs_unregister) return;
gf_list_add(compositor->time_nodes, tn);
tn->is_registered = 1;
}
void gf_sc_unregister_time_node(GF_Compositor *compositor, GF_TimeNode *tn)
{
gf_list_del_item(compositor->time_nodes, tn);
}
GF_Node *gf_sc_pick_node(GF_Compositor *compositor, s32 X, s32 Y)
{
return NULL;
}
static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node)
{
Bool force_pause;
force_pause = GF_FALSE;
#ifndef GPAC_DISABLE_LOG
compositor->visual_config_time = 0;
#endif
if (compositor->recompute_ar) {
#ifndef GPAC_DISABLE_3D
u32 prev_type_3d = compositor->visual->type_3d;
#endif
#ifndef GPAC_DISABLE_LOG
u32 time=0;
if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
time = gf_sys_clock();
}
#endif
if (force_pause)
gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_PAUSE);
#ifndef GPAC_DISABLE_3D
if (compositor->autoconfig_opengl) {
compositor->visual->type_3d = 1;
}
if (compositor->visual->type_3d) {
compositor_3d_set_aspect_ratio(compositor);
gf_sc_load_opengl_extensions(compositor, compositor->visual->type_3d);
#ifndef GPAC_USE_GLES1X
visual_3d_init_shaders(compositor->visual);
#endif
if (compositor->autoconfig_opengl) {
compositor->autoconfig_opengl = 0;
compositor->force_opengl_2d = 0;
compositor->visual->type_3d = prev_type_3d;
#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
if (compositor->visual->compositor->shader_only_mode) {
gf_cfg_set_key(compositor->user->config, "Compositor", "OpenGLMode", "hybrid");
compositor->hybrid_opengl = 1;
} else {
gf_cfg_set_key(compositor->user->config, "Compositor", "OpenGLMode", "disable");
}
#endif
}
}
if (!compositor->visual->type_3d)
#endif
{
compositor_2d_set_aspect_ratio(compositor);
#ifndef GPAC_DISABLE_3D
if (compositor->hybrid_opengl) {
gf_sc_load_opengl_extensions(compositor, GF_TRUE);
#ifndef GPAC_USE_GLES1X
visual_3d_init_shaders(compositor->visual);
#endif
if (!compositor->visual->hybgl_drawn.list) {
ra_init(&compositor->visual->hybgl_drawn);
}
}
#endif
}
if (force_pause )
gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_RESUME);
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
compositor->visual_config_time = gf_sys_clock() - time;
}
#endif
#ifndef GPAC_DISABLE_VRML
compositor_evaluate_envtests(compositor, 0);
#endif
if (compositor->fullscreen_postponed) {
compositor->fullscreen_postponed = 0;
compositor->msg_type |= GF_SR_CFG_FULLSCREEN;
}
}
}
static void gf_sc_setup_root_visual(GF_Compositor *compositor, GF_Node *top_node)
{
if (top_node && !compositor->root_visual_setup) {
GF_SceneGraph *scene = compositor->scene;
u32 node_tag;
#ifndef GPAC_DISABLE_3D
Bool force_navigate=0;
Bool was_3d = compositor->visual->type_3d;
#endif
compositor->root_visual_setup = 1;
compositor->visual->center_coords = 1;
compositor->traverse_state->pixel_metrics = 1;
compositor->traverse_state->min_hsize = INT2FIX(MIN(compositor->scene_width, compositor->scene_height)) / 2;
node_tag = gf_node_get_tag(top_node);
switch (node_tag) {
#ifndef GPAC_DISABLE_VRML
case TAG_MPEG4_OrderedGroup:
case TAG_MPEG4_Layer2D:
#ifndef GPAC_DISABLE_3D
#ifdef GF_SR_USE_DEPTH
if (compositor->display_depth) {
compositor->visual->type_3d = 0;
compositor->visual->camera.is_3D = 0;
} else
#endif
{
compositor->visual->type_3d = 0;
compositor->visual->camera.is_3D = 0;
}
#endif
compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
break;
case TAG_MPEG4_Group:
case TAG_MPEG4_Layer3D:
#ifndef GPAC_DISABLE_3D
compositor->visual->type_3d = 2;
compositor->visual->camera.is_3D = 1;
#endif
compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
break;
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_Group:
#ifndef GPAC_DISABLE_3D
compositor->visual->type_3d = 3;
#endif
compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
break;
#endif
#endif
#ifndef GPAC_DISABLE_SVG
case TAG_SVG_svg:
#ifndef GPAC_DISABLE_3D
#ifdef GF_SR_USE_DEPTH
if (compositor->display_depth) {
compositor->visual->type_3d = 2;
compositor->visual->camera.is_3D = 1;
} else
#endif
{
compositor->visual->type_3d = 0;
compositor->visual->camera.is_3D = 0;
}
#endif
compositor->visual->center_coords = 0;
compositor->root_visual_setup = 2;
break;
#endif
}
#ifndef GPAC_DISABLE_3D
if (compositor->inherit_type_3d && !compositor->visual->type_3d) {
compositor->visual->type_3d = 2;
compositor->visual->camera.is_3D = 1;
}
else if ( (compositor->force_opengl_2d && !compositor->visual->type_3d)
|| (compositor->hybrid_opengl && compositor->force_type_3d)) {
compositor->force_type_3d=0;
compositor->visual->type_3d = 1;
if (compositor->force_opengl_2d==2) force_navigate=1;
}
if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL)) {
compositor->visual->type_3d = 0;
compositor->visual->camera.is_3D = 0;
}
compositor->visual->camera.is_3D = (compositor->visual->type_3d>1) ? 1 : 0;
if (!compositor->visual->camera.is_3D)
camera_set_2d(&compositor->visual->camera);
camera_invalidate(&compositor->visual->camera);
if (force_navigate) {
compositor->visual->camera.navigate_mode = GF_NAVIGATE_EXAMINE;
compositor->visual->camera.had_nav_info = 0;
}
#endif
GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Main scene setup - pixel metrics %d - center coords %d\n", compositor->traverse_state->pixel_metrics, compositor->visual->center_coords));
compositor->recompute_ar = 1;
#ifndef GPAC_DISABLE_3D
if (was_3d != compositor->visual->type_3d) compositor->recompute_ar = was_3d ? 1 : 2;
#endif
}
}
static void gf_sc_draw_scene(GF_Compositor *compositor)
{
u32 flags;
GF_Node *top_node = gf_sg_get_root_node(compositor->scene);
if (!top_node && !compositor->visual->last_had_back && !compositor->visual->cur_context) {
compositor->skip_flush = 1;
return;
}
#ifdef GF_SR_USE_VIDEO_CACHE
if (!compositor->video_cache_max_size)
compositor->traverse_state->in_group_cache = 1;
#endif
flags = compositor->traverse_state->immediate_draw;
if (compositor->video_setup_failed) {
compositor->skip_flush = 1;
}
else if (! visual_draw_frame(compositor->visual, top_node, compositor->traverse_state, 1)) {
#ifdef GPAC_ANDROID
compositor->skip_flush = 0;
#else
if (compositor->skip_flush==2) {
compositor->skip_flush = 0;
} else {
compositor->skip_flush = 1;
}
#endif
}
compositor->traverse_state->immediate_draw = flags;
#ifdef GF_SR_USE_VIDEO_CACHE
gf_list_reset(compositor->cached_groups_queue);
#endif
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Frame %d - drawing done\n", compositor->frame_number));
if (compositor->recompute_ar) {
compositor_send_resize_event(compositor, NULL, 0, 0, 0, 1);
compositor->recompute_ar = 0;
}
compositor->zoom_changed = 0;
}
#ifndef GPAC_DISABLE_LOG
extern u32 time_spent_in_anim;
#endif
static void compositor_release_textures(GF_Compositor *compositor, Bool frame_drawn)
{
u32 i, count;
count = gf_list_count(compositor->textures);
for (i=0; i<count; i++) {
GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
gf_sc_texture_release_stream(txh);
if (frame_drawn && txh->tx_io && !(txh->flags & GF_SR_TEXTURE_USED))
gf_sc_texture_reset(txh);
txh->flags &= ~GF_SR_TEXTURE_USED;
}
}
void gf_sc_flush_video(GF_Compositor *compositor)
{
GF_Window rc;
gf_sc_lock(compositor, 0);
rc.x = rc.y = 0;
rc.w = compositor->display_width;
rc.h = compositor->display_height;
compositor->video_out->Flush(compositor->video_out, &rc);
gf_sc_lock(compositor, 1);
}
void gf_sc_render_frame(GF_Compositor *compositor)
{
#ifndef GPAC_DISABLE_SCENEGRAPH
GF_SceneGraph *sg;
#endif
GF_List *temp_queue;
u32 in_time, end_time, i, count, frame_duration;
Bool frame_drawn, has_timed_nodes=GF_FALSE, all_tx_done=GF_TRUE;
#ifndef GPAC_DISABLE_LOG
s32 event_time, route_time, smil_timing_time=0, time_node_time, texture_time, traverse_time, flush_time, txtime;
#endif
gf_sc_lock(compositor, 1);
in_time = gf_sys_clock();
gf_sc_texture_cleanup_hw(compositor);
compositor->video_out->ProcessEvent(compositor->video_out, NULL);
if (compositor->freeze_display) {
gf_sc_lock(compositor, 0);
if (!compositor->bench_mode) {
compositor->scene_sampled_clock = gf_sc_ar_get_clock(compositor->audio_renderer);
}
if (!compositor->no_regulation) gf_sleep(compositor->frame_duration);
return;
}
gf_sc_reconfig_task(compositor);
if (!compositor->scene && !gf_list_count(compositor->extra_scenes) ) {
gf_sc_draw_scene(compositor);
if (compositor->bench_mode && (compositor->force_bench_frame==1)) {
compositor->scene_sampled_clock += compositor->frame_duration;
}
gf_sc_lock(compositor, 0);
if (!compositor->no_regulation) {
gf_sleep(compositor->bench_mode ? 2 : compositor->frame_duration);
}
compositor->force_bench_frame=0;
compositor->frame_draw_type = 0;
return;
}
if (compositor->reset_graphics) {
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
visual_reset_graphics(compositor->visual);
}
#ifndef GPAC_DISABLE_LOG
event_time = gf_sys_clock();
#endif
gf_mx_p(compositor->evq_mx);
temp_queue = compositor->event_queue;
compositor->event_queue = compositor->event_queue_back;
compositor->event_queue_back = temp_queue;
gf_mx_v(compositor->evq_mx);
while (gf_list_count(compositor->event_queue_back)) {
GF_QueuedEvent *qev = (GF_QueuedEvent*)gf_list_get(compositor->event_queue_back, 0);
gf_list_rem(compositor->event_queue_back, 0);
if (qev->target) {
#ifndef GPAC_DISABLE_SVG
gf_sg_fire_dom_event(qev->target, &qev->dom_evt, qev->sg, NULL);
#endif
} else if (qev->node) {
#ifndef GPAC_DISABLE_SVG
gf_dom_event_fire(qev->node, &qev->dom_evt);
#endif
} else {
gf_sc_exec_event(compositor, &qev->evt);
}
gf_free(qev);
}
#ifndef GPAC_DISABLE_LOG
event_time = gf_sys_clock() - event_time;
#endif
if (!compositor->bench_mode) {
compositor->scene_sampled_clock = gf_sc_ar_get_clock(compositor->audio_renderer);
} else {
if (compositor->force_bench_frame==1) {
compositor->scene_sampled_clock += compositor->frame_duration;
}
compositor->force_bench_frame = 0;
}
compositor->frame_delay = 0;
compositor->ms_until_next_frame = GF_INT_MAX;
frame_duration = compositor->frame_duration;
#ifndef GPAC_DISABLE_LOG
texture_time = gf_sys_clock();
#endif
count = gf_list_count(compositor->textures);
for (i=0; i<count; i++) {
GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
if (!txh) break;
if (! txh->stream) continue;
if (compositor->reset_graphics && txh->tx_io) gf_sc_texture_reset(txh);
txh->update_texture_fcnt(txh);
if (!txh->stream_finished) {
u32 d = gf_mo_get_min_frame_dur(txh->stream);
if (d && (d < frame_duration)) frame_duration = d;
all_tx_done=0;
}
}
if (compositor->msg_type) {
gf_sc_lock(compositor, 0);
return;
}
#ifndef GPAC_DISABLE_LOG
texture_time = gf_sys_clock() - texture_time;
#endif
#ifndef GPAC_DISABLE_SVG
#ifndef GPAC_DISABLE_LOG
smil_timing_time = gf_sys_clock();
#endif
if (gf_smil_notify_timed_elements(compositor->scene)) {
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
}
#ifndef GPAC_DISABLE_SCENEGRAPH
i = 0;
while ((sg = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) {
if (gf_smil_notify_timed_elements(sg)) {
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
}
}
#endif
#ifndef GPAC_DISABLE_LOG
smil_timing_time = gf_sys_clock() - smil_timing_time;
#endif
#endif
#ifndef GPAC_DISABLE_LOG
time_node_time = gf_sys_clock();
#endif
count = gf_list_count(compositor->time_nodes);
for (i=0; i<count; i++) {
GF_TimeNode *tn = (GF_TimeNode *)gf_list_get(compositor->time_nodes, i);
if (!tn->needs_unregister) tn->UpdateTimeNode(tn);
if (tn->needs_unregister) {
tn->is_registered = 0;
tn->needs_unregister = 0;
gf_list_rem(compositor->time_nodes, i);
i--;
count--;
continue;
}
has_timed_nodes = GF_TRUE;
}
#ifndef GPAC_DISABLE_LOG
time_node_time = gf_sys_clock() - time_node_time;
#endif
if (compositor->focus_text_type) {
if (!compositor->caret_next_draw_time) {
compositor->caret_next_draw_time = gf_sys_clock();
compositor->show_caret = 1;
}
if (compositor->caret_next_draw_time <= compositor->last_frame_time) {
compositor->frame_draw_type=GF_SC_DRAW_FRAME;
compositor->caret_next_draw_time+=500;
compositor->show_caret = !compositor->show_caret;
compositor->text_edit_changed = 1;
}
}
#ifndef GPAC_DISABLE_VRML
#ifndef GPAC_DISABLE_LOG
route_time = gf_sys_clock();
#endif
gf_sg_activate_routes(compositor->scene);
#ifndef GPAC_DISABLE_SCENEGRAPH
i = 0;
while ((sg = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) {
gf_sg_activate_routes(sg);
}
#endif
#ifndef GPAC_DISABLE_LOG
route_time = gf_sys_clock() - route_time;
#endif
#else
#ifndef GPAC_DISABLE_LOG
route_time = 0;
#endif
#endif
gf_sc_setup_root_visual(compositor, gf_sg_get_root_node(compositor->scene));
gf_sc_recompute_ar(compositor, gf_sg_get_root_node(compositor->scene) );
if (compositor->video_setup_failed) {
gf_sc_lock(compositor, 0);
return;
}
#ifndef GPAC_DISABLE_LOG
txtime = gf_sys_clock();
#endif
compositor->texture_inserted = GF_FALSE;
count = gf_list_count(compositor->textures);
for (i=0; i<count; i++) {
GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
if (!txh) break;
if (txh->stream) continue;
if (compositor->reset_graphics && txh->tx_io) gf_sc_texture_reset(txh);
txh->update_texture_fcnt(txh);
if (compositor->texture_inserted) {
compositor->texture_inserted = GF_FALSE;
count = gf_list_count(compositor->textures);
i = gf_list_find(compositor->textures, txh);
}
}
if (compositor->msg_type) {
compositor->recompute_ar = 0;
gf_sc_lock(compositor, 0);
return;
}
#ifndef GPAC_DISABLE_LOG
texture_time += gf_sys_clock() - txtime;
#endif
compositor->text_edit_changed = 0;
compositor->rebuild_offscreen_textures = 0;
if (compositor->force_next_frame_redraw) {
compositor->force_next_frame_redraw=0;
compositor->frame_draw_type=GF_SC_DRAW_FRAME;
}
if (compositor->is_hidden && !compositor->video_listeners) {
compositor->frame_draw_type = 0;
}
frame_drawn = (compositor->frame_draw_type==GF_SC_DRAW_FRAME) ? 1 : 0;
if (compositor->frame_draw_type) {
Bool textures_released = 0;
#ifndef GPAC_DISABLE_LOG
traverse_time = gf_sys_clock();
time_spent_in_anim = 0;
#endif
if (compositor->traverse_state->immediate_draw) {
compositor->frame_draw_type = GF_SC_DRAW_FRAME;
}
if (compositor->frame_draw_type==GF_SC_DRAW_FLUSH) {
compositor->frame_draw_type = 0;
}
else {
compositor->frame_draw_type = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Redrawing scene - STB %d\n", compositor->scene_sampled_clock));
gf_sc_draw_scene(compositor);
#ifndef GPAC_DISABLE_LOG
traverse_time = gf_sys_clock() - traverse_time;
#endif
if (compositor->video_listeners && compositor->skip_flush!=1) {
u32 k=0;
GF_VideoListener *l;
while ((l = gf_list_enum(compositor->video_listeners, &k))) {
l->on_video_frame(l->udta, gf_sc_ar_get_clock(compositor->audio_renderer) );
}
}
}
#ifndef GPAC_DISABLE_LOG
flush_time = gf_sys_clock();
#endif
if(compositor->user->init_flags & GF_TERM_INIT_HIDE)
compositor->skip_flush = 1;
if (!compositor->visual->has_overlays) {
compositor_release_textures(compositor, frame_drawn);
textures_released = 1;
}
if (compositor->skip_flush!=1) {
gf_sc_flush_video(compositor);
} else {
compositor->skip_flush = 0;
}
#ifndef GPAC_DISABLE_LOG
flush_time = gf_sys_clock() - flush_time;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Compositor] done flushing frame in %d ms\n", flush_time));
#endif
visual_2d_draw_overlays(compositor->visual);
compositor->last_had_overlays = compositor->visual->has_overlays;
if (!textures_released) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Compositor] Releasing textures after flush\n" ));
compositor_release_textures(compositor, frame_drawn);
}
if (compositor->stress_mode) {
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
gf_sc_reset_graphics(compositor);
}
compositor->reset_fonts = 0;
} else {
compositor_release_textures(compositor, frame_drawn);
#ifndef GPAC_DISABLE_LOG
traverse_time = 0;
time_spent_in_anim = 0;
flush_time = 0;
compositor->traverse_setup_time = 0;
compositor->traverse_and_direct_draw_time = 0;
compositor->indirect_draw_time = 0;
#endif
}
compositor->reset_graphics = 0;
compositor->last_frame_time = gf_sys_clock();
end_time = compositor->last_frame_time - in_time;
GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI]\tCompositor Cycle Log\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
compositor->networks_time,
compositor->decoders_time,
compositor->frame_number,
compositor->traverse_state->immediate_draw,
compositor->visual_config_time,
event_time,
route_time,
smil_timing_time,
time_node_time,
texture_time,
time_spent_in_anim,
compositor->traverse_setup_time,
compositor->traverse_and_direct_draw_time,
compositor->traverse_and_direct_draw_time - time_spent_in_anim,
compositor->indirect_draw_time,
traverse_time,
flush_time,
end_time));
if (frame_drawn) {
compositor->current_frame = (compositor->current_frame+1) % GF_SR_FPS_COMPUTE_SIZE;
compositor->frame_dur[compositor->current_frame] = end_time;
compositor->frame_time[compositor->current_frame] = compositor->last_frame_time;
compositor->frame_number++;
}
if (compositor->bench_mode && (frame_drawn || (has_timed_nodes&&all_tx_done) )) {
compositor->scene_sampled_clock += frame_duration;
}
compositor->video_frame_pending=0;
gf_sc_lock(compositor, 0);
if (frame_drawn) compositor->step_mode = GF_FALSE;
if (compositor->no_regulation)
return;
if (compositor->bench_mode) {
gf_sleep(0);
return;
}
if (compositor->ms_until_next_frame != GF_INT_MAX) {
compositor->ms_until_next_frame -= end_time;
if (compositor->ms_until_next_frame<=0) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame already due (%d ms late) - not going to sleep\n", - compositor->ms_until_next_frame));
compositor->ms_until_next_frame=0;
return;
}
compositor->ms_until_next_frame = MIN(compositor->ms_until_next_frame, (s32) frame_duration );
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame due in %d ms\n", compositor->ms_until_next_frame));
if (compositor->ms_until_next_frame > 2) {
u64 start = gf_sys_clock_high_res();
u64 diff=0;
u64 wait_for = 1000 * (u64) compositor->ms_until_next_frame;
while (! compositor->msg_type && ! compositor->video_frame_pending) {
gf_sleep(1);
diff = gf_sys_clock_high_res() - start;
if (diff >= wait_for)
break;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept %d ms until next frame (msg type %d - frame pending %d)\n", diff/1000, compositor->msg_type, compositor->video_frame_pending));
}
return;
}
if (end_time > frame_duration) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor did not go to sleep\n"));
return;
}
end_time %= frame_duration;
gf_sleep(frame_duration - end_time);
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept for %d ms\n", frame_duration - end_time));
}
Bool gf_sc_visual_is_registered(GF_Compositor *compositor, GF_VisualManager *visual)
{
GF_VisualManager *tmp;
u32 i = 0;
while ((tmp = (GF_VisualManager *)gf_list_enum(compositor->visuals, &i))) {
if (tmp == visual) return 1;
}
return 0;
}
void gf_sc_visual_register(GF_Compositor *compositor, GF_VisualManager *visual)
{
if (gf_sc_visual_is_registered(compositor, visual)) return;
gf_list_add(compositor->visuals, visual);
}
void gf_sc_visual_unregister(GF_Compositor *compositor, GF_VisualManager *visual)
{
gf_list_del_item(compositor->visuals, visual);
}
void gf_sc_traverse_subscene_ex(GF_Compositor *compositor, GF_Node *inline_parent, GF_SceneGraph *subscene, void *rs)
{
Fixed min_hsize, vp_scale;
Bool use_pm, prev_pm, prev_coord;
SFVec2f prev_vp;
s32 flip_coords;
u32 h, w, tag;
GF_Matrix2D transf;
GF_SceneGraph *in_scene;
GF_Node *inline_root;
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
if (!compositor->root_visual_setup) return;
inline_root = gf_sg_get_root_node(subscene);
if (!inline_root) return;
if (!gf_scene_is_over(subscene))
tr_state->subscene_not_over ++;
flip_coords = 0;
in_scene = gf_node_get_graph(inline_root);
w = h = 0;
tag = gf_node_get_tag(inline_root);
if (tag < GF_NODE_RANGE_LAST_VRML) {
#ifndef GPAC_DISABLE_VRML
u32 new_tag = 0;
use_pm = gf_sg_use_pixel_metrics(in_scene);
if (gf_node_get_tag(inline_parent)>GF_NODE_RANGE_LAST_VRML) {
flip_coords = 1;
if (tag==TAG_MPEG4_OrderedGroup) {
new_tag = TAG_MPEG4_Layer2D;
} else if (tag==TAG_MPEG4_Group) {
new_tag = TAG_MPEG4_Layer3D;
}
#ifndef GPAC_DISABLE_X3D
else if (tag==TAG_X3D_Group) {
new_tag = TAG_MPEG4_Layer3D;
}
#endif
}
#if !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_3D)
else if (!tr_state->visual->type_3d && ((tag==TAG_MPEG4_Group) || (tag==TAG_X3D_Group))) {
new_tag = TAG_MPEG4_Layer3D;
}
#endif
if (new_tag) {
GF_SceneGraph *sg = gf_node_get_graph(inline_root);
GF_Node *new_root = gf_node_new(sg, new_tag);
gf_node_register(new_root, NULL);
gf_sg_set_root_node(sg, new_root);
gf_node_list_add_child(& ((GF_ParentNode*)new_root)->children, inline_root);
gf_node_register(inline_root, new_root);
gf_node_unregister(inline_root, NULL);
inline_root = new_root;
gf_node_init(new_root);
}
#endif
gf_sg_get_scene_size_info(in_scene, &w, &h);
} else {
use_pm = 1;
if (gf_node_get_tag(inline_parent)<GF_NODE_RANGE_LAST_VRML) {
flip_coords = -1;
}
}
min_hsize = tr_state->min_hsize;
prev_pm = tr_state->pixel_metrics;
prev_vp = tr_state->vp_size;
prev_coord = tr_state->fliped_coords;
vp_scale = FIX_ONE;
gf_mx2d_init(transf);
if (flip_coords)
gf_mx2d_add_scale(&transf, FIX_ONE, -FIX_ONE);
if (w && h) {
if ((compositor->scene_width != tr_state->vp_size.x) || (compositor->scene_height != tr_state->vp_size.y)) {
Fixed scale_w = tr_state->vp_size.x/w;
Fixed scale_h = tr_state->vp_size.y/h;
vp_scale = MIN(scale_w, scale_h);
gf_mx2d_add_scale(&transf, vp_scale, vp_scale);
}
}
if (flip_coords) {
gf_mx2d_add_translation(&transf, flip_coords * tr_state->vp_size.x/2, tr_state->vp_size.y/2);
tr_state->fliped_coords = !tr_state->fliped_coords;
}
if (w && h) {
tr_state->vp_size.x = gf_divfix(tr_state->vp_size.x, vp_scale);
tr_state->vp_size.y = gf_divfix(tr_state->vp_size.y, vp_scale);
}
if (use_pm != tr_state->pixel_metrics) {
if (w && h) {
Fixed scale = INT2FIX( MIN(w, h) / 2);
if (scale) tr_state->min_hsize = scale;
}
if (!use_pm) {
gf_mx2d_add_scale(&transf, tr_state->min_hsize, tr_state->min_hsize);
} else {
Fixed inv_scale = gf_invfix(tr_state->min_hsize);
gf_mx2d_add_scale(&transf, inv_scale, inv_scale);
}
tr_state->pixel_metrics = use_pm;
}
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
GF_Matrix mx_bck, mx;
gf_mx_copy(mx_bck, tr_state->model_matrix);
gf_mx_from_mx2d(&mx, &transf);
mx.m[10] = mx.m[5];
gf_mx_add_matrix(&tr_state->model_matrix, &mx);
gf_node_traverse(inline_root, rs);
gf_mx_copy(tr_state->model_matrix, mx_bck);
} else
#endif
{
GF_Matrix2D mx_bck;
gf_mx2d_copy(mx_bck, tr_state->transform);
gf_mx2d_pre_multiply(&tr_state->transform, &transf);
gf_node_traverse(inline_root, rs);
gf_mx2d_copy(tr_state->transform, mx_bck);
}
tr_state->pixel_metrics = prev_pm;
tr_state->min_hsize = min_hsize;
tr_state->vp_size = prev_vp;
tr_state->fliped_coords = prev_coord;
}
static Bool gf_sc_handle_event_intern(GF_Compositor *compositor, GF_Event *event, Bool from_user)
{
Bool ret;
if (compositor->term && (compositor->interaction_level & GF_INTERACT_INPUT_SENSOR) && (event->type<=GF_EVENT_MOUSEWHEEL)) {
GF_Event evt = *event;
gf_term_mouse_input(compositor->term, &evt.mouse);
}
gf_mx_p(compositor->mx);
ret = gf_sc_exec_event(compositor, event);
gf_sc_lock(compositor, GF_FALSE);
return ret;
}
void gf_sc_traverse_subscene(GF_Compositor *compositor, GF_Node *inline_parent, GF_SceneGraph *subscene, void *rs)
{
u32 i=0;
GF_SceneGraph *subsg;
gf_sc_traverse_subscene_ex(compositor, inline_parent, subscene, rs);
while ( (subsg = gf_scene_enum_extra_scene(subscene, &i)))
gf_sc_traverse_subscene_ex(compositor, inline_parent, subsg, rs);
}
static Bool gf_sc_on_event_ex(GF_Compositor *compositor , GF_Event *event, Bool from_user)
{
if (!compositor || !compositor->visual) return GF_FALSE;
if (compositor->msg_type & GF_SR_IN_RECONFIG) {
if (event->type==GF_EVENT_VIDEO_SETUP) {
if (event->setup.hw_reset)
gf_sc_reset_graphics(compositor);
if (event->setup.back_buffer)
compositor->recompute_ar = 1;
}
return GF_FALSE;
}
switch (event->type) {
case GF_EVENT_SHOWHIDE:
case GF_EVENT_SET_CAPTION:
case GF_EVENT_MOVE:
compositor->video_out->ProcessEvent(compositor->video_out, event);
break;
case GF_EVENT_MOVE_NOTIF:
if (compositor->last_had_overlays) {
gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
}
break;
case GF_EVENT_REFRESH:
gf_sc_next_frame_state(compositor, compositor->last_had_overlays ? GF_SC_DRAW_FRAME : GF_SC_DRAW_FLUSH);
break;
case GF_EVENT_VIDEO_SETUP:
{
Bool locked = gf_mx_try_lock(compositor->mx);
if (event->setup.hw_reset) {
gf_sc_reset_graphics(compositor);
compositor->reset_graphics = 2;
}
if (event->setup.back_buffer)
compositor->recompute_ar = 1;
if (locked) gf_mx_v(compositor->mx);
}
break;
case GF_EVENT_SIZE:
if ( gf_term_send_event(compositor->term, event) )
return GF_TRUE;
if (!compositor->user->os_window_handler) {
Bool lock_ok = gf_mx_try_lock(compositor->mx);
if ((compositor->display_width!=event->size.width)
|| (compositor->display_height!=event->size.height)
|| (compositor->new_width && (compositor->new_width!=event->size.width))
|| (compositor->new_width && (compositor->new_height!=event->size.height))
) {
#if defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_IPHONE)
if (compositor->display_width==event->size.width) {
if (compositor->display_height > 2*event->size.height) {
event->size.width = compositor->display_width * event->size.height / compositor->display_height;
}
}
#endif
compositor->new_width = event->size.width;
compositor->new_height = event->size.height;
compositor->msg_type |= GF_SR_CFG_SET_SIZE;
if (from_user) compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
} else {
compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
}
if (lock_ok) gf_sc_lock(compositor, GF_FALSE);
}
return GF_FALSE;
case GF_EVENT_KEYDOWN:
case GF_EVENT_KEYUP:
{
Bool ret;
switch (event->key.key_code) {
case GF_KEY_SHIFT:
if (event->type==GF_EVENT_KEYDOWN) {
compositor->key_states |= GF_KEY_MOD_SHIFT;
} else {
compositor->key_states &= ~GF_KEY_MOD_SHIFT;
}
break;
case GF_KEY_CONTROL:
if (event->type==GF_EVENT_KEYDOWN) {
compositor->key_states |= GF_KEY_MOD_CTRL;
} else {
compositor->key_states &= ~GF_KEY_MOD_CTRL;
}
break;
case GF_KEY_ALT:
if (event->type==GF_EVENT_KEYDOWN) {
compositor->key_states |= GF_KEY_MOD_ALT;
} else {
compositor->key_states &= ~GF_KEY_MOD_ALT;
}
break;
}
ret = GF_FALSE;
event->key.flags |= compositor->key_states;
if (compositor->term && (compositor->interaction_level & GF_INTERACT_INPUT_SENSOR) ) {
ret = gf_term_keyboard_input(compositor->term, event->key.key_code, event->key.hw_code, (event->type==GF_EVENT_KEYUP) ? GF_TRUE : GF_FALSE);
}
ret += gf_sc_handle_event_intern(compositor, event, from_user);
return ret;
}
case GF_EVENT_TEXTINPUT:
if (compositor->term && (compositor->interaction_level & GF_INTERACT_INPUT_SENSOR) )
gf_term_string_input(compositor->term , event->character.unicode_char);
return gf_sc_handle_event_intern(compositor, event, from_user);
case GF_EVENT_SHOWHIDE_NOTIF:
compositor->is_hidden = event->show.show_type ? GF_FALSE : GF_TRUE;
break;
case GF_EVENT_MOUSEMOVE:
event->mouse.button = 0;
case GF_EVENT_MOUSEDOWN:
case GF_EVENT_MOUSEUP:
case GF_EVENT_MOUSEWHEEL:
event->mouse.key_states = compositor->key_states;
case GF_EVENT_SENSOR_ORIENTATION:
return gf_sc_handle_event_intern(compositor, event, from_user);
case GF_EVENT_PASTE_TEXT:
gf_sc_paste_text(compositor, event->message.message);
break;
case GF_EVENT_COPY_TEXT:
if (gf_sc_has_text_selection(compositor)) {
event->message.message = gf_sc_get_selected_text(compositor);
} else {
event->message.message = NULL;
}
break;
default:
return gf_term_send_event(compositor->term, event);
}
return GF_TRUE;
}
static Bool gf_sc_on_event(void *cbck, GF_Event *event)
{
return gf_sc_on_event_ex((GF_Compositor *)cbck, event, GF_FALSE);
}
Bool gf_sc_user_event(GF_Compositor *compositor, GF_Event *event)
{
switch (event->type) {
case GF_EVENT_SHOWHIDE:
case GF_EVENT_MOVE:
case GF_EVENT_SET_CAPTION:
compositor->video_out->ProcessEvent(compositor->video_out, event);
return GF_FALSE;
default:
return gf_sc_on_event_ex(compositor, event, GF_TRUE);
}
}
GF_EXPORT
void gf_sc_register_extra_graph(GF_Compositor *compositor, GF_SceneGraph *extra_scene, Bool do_remove)
{
gf_sc_lock(compositor, GF_TRUE);
if (do_remove) gf_list_del_item(compositor->extra_scenes, extra_scene);
else if (gf_list_find(compositor->extra_scenes, extra_scene)<0) gf_list_add(compositor->extra_scenes, extra_scene);
gf_sc_lock(compositor, GF_FALSE);
}
u32 gf_sc_get_audio_delay(GF_Compositor *compositor)
{
return compositor->audio_renderer ? compositor->audio_renderer->audio_delay : 0;
}
Bool gf_sc_script_action(GF_Compositor *compositor, u32 type, GF_Node *n, GF_JSAPIParam *param)
{
switch (type) {
case GF_JSAPI_OP_GET_SCALE:
param->val = compositor->zoom;
return GF_TRUE;
case GF_JSAPI_OP_SET_SCALE:
compositor_2d_set_user_transform(compositor, param->val, compositor->trans_x, compositor->trans_y, GF_FALSE);
return GF_TRUE;
case GF_JSAPI_OP_GET_ROTATION:
param->val = gf_divfix(180*compositor->rotation, GF_PI);
return GF_TRUE;
case GF_JSAPI_OP_SET_ROTATION:
compositor->rotation = gf_mulfix(GF_PI, param->val/180);
compositor_2d_set_user_transform(compositor, compositor->zoom, compositor->trans_x, compositor->trans_y, GF_FALSE);
return GF_TRUE;
case GF_JSAPI_OP_GET_TRANSLATE:
param->pt.x = compositor->trans_x;
param->pt.y = compositor->trans_y;
return GF_TRUE;
case GF_JSAPI_OP_SET_TRANSLATE:
compositor_2d_set_user_transform(compositor, compositor->zoom, param->pt.x, param->pt.y, GF_FALSE);
return GF_TRUE;
case GF_JSAPI_OP_GET_TIME:
param->time = gf_node_get_scene_time(n);
return GF_TRUE;
case GF_JSAPI_OP_SET_TIME:
return GF_FALSE;
case GF_JSAPI_OP_GET_VIEWPORT:
#ifndef GPAC_DISABLE_SVG
if (compositor_svg_get_viewport(n, ¶m->rc)) return GF_TRUE;
#endif
param->rc = gf_rect_center(compositor->traverse_state->vp_size.x, compositor->traverse_state->vp_size.y);
if (!compositor->visual->center_coords) {
param->rc.x = 0;
param->rc.y = 0;
}
return GF_TRUE;
case GF_JSAPI_OP_SET_FOCUS:
compositor->focus_node = param->node;
return GF_TRUE;
case GF_JSAPI_OP_GET_FOCUS:
param->node = compositor->focus_node;
return GF_TRUE;
case GF_JSAPI_OP_GET_LOCAL_BBOX:
case GF_JSAPI_OP_GET_SCREEN_BBOX:
case GF_JSAPI_OP_GET_TRANSFORM:
{
GF_TraverseState tr_state;
memset(&tr_state, 0, sizeof(tr_state));
tr_state.traversing_mode = TRAVERSE_GET_BOUNDS;
tr_state.visual = compositor->visual;
tr_state.vp_size = compositor->traverse_state->vp_size;
tr_state.for_node = n;
tr_state.ignore_strike = GF_TRUE;
tr_state.min_hsize = compositor->traverse_state->min_hsize;
tr_state.pixel_metrics = compositor->traverse_state->pixel_metrics;
gf_mx2d_init(tr_state.transform);
gf_mx2d_init(tr_state.mx_at_node);
if (type==GF_JSAPI_OP_GET_LOCAL_BBOX) {
#ifndef GPAC_DISABLE_SVG
GF_SAFEALLOC(tr_state.svg_props, SVGPropertiesPointers);
gf_svg_properties_init_pointers(tr_state.svg_props);
tr_state.abort_bounds_traverse = GF_TRUE;
gf_node_traverse(n, &tr_state);
gf_svg_properties_reset_pointers(tr_state.svg_props);
gf_free(tr_state.svg_props);
#endif
} else {
gf_node_traverse(gf_sg_get_root_node(compositor->scene), &tr_state);
}
if (!tr_state.bounds.height && !tr_state.bounds.width && !tr_state.bounds.x && !tr_state.bounds.y)
tr_state.abort_bounds_traverse = GF_FALSE;
gf_mx2d_pre_multiply(&tr_state.mx_at_node, &compositor->traverse_state->transform);
if (type==GF_JSAPI_OP_GET_LOCAL_BBOX) {
gf_bbox_from_rect(¶m->bbox, &tr_state.bounds);
} else if (type==GF_JSAPI_OP_GET_TRANSFORM) {
gf_mx_from_mx2d(¶m->mx, &tr_state.mx_at_node);
} else {
gf_mx2d_apply_rect(&tr_state.mx_at_node, &tr_state.bounds);
gf_bbox_from_rect(¶m->bbox, &tr_state.bounds);
}
if (!tr_state.abort_bounds_traverse) param->bbox.is_set = GF_FALSE;
}
return GF_TRUE;
case GF_JSAPI_OP_LOAD_URL:
{
#ifndef GPAC_DISABLE_VRML
GF_Node *target;
char *sub_url = strrchr(param->uri.url, '#');
if (!sub_url) return GF_FALSE;
target = gf_sg_find_node_by_name(gf_node_get_graph(n), sub_url+1);
if (target && (gf_node_get_tag(target)==TAG_MPEG4_Viewport) ) {
((M_Viewport *)target)->set_bind = 1;
((M_Viewport *)target)->on_set_bind(n, NULL);
return GF_TRUE;
}
#endif
return GF_FALSE;
}
case GF_JSAPI_OP_GET_FPS:
param->time = gf_sc_get_fps(compositor, GF_FALSE);
return GF_TRUE;
case GF_JSAPI_OP_GET_SPEED:
param->time = 0;
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d==2) {
param->time = FIX2FLT(compositor->visual->camera.speed);
}
#endif
return GF_TRUE;
case GF_JSAPI_OP_PAUSE_SVG:
if (n) {
u32 tag = gf_node_get_tag(n);
switch(tag) {
#ifndef GPAC_DISABLE_SVG
case TAG_SVG_audio:
svg_pause_audio(n, GF_TRUE);
break;
case TAG_SVG_video:
svg_pause_video(n, GF_TRUE);
break;
case TAG_SVG_animation:
svg_pause_animation(n, GF_TRUE);
break;
#endif
}
} else {
return GF_FALSE;
}
return GF_TRUE;
case GF_JSAPI_OP_RESUME_SVG:
{
u32 tag = gf_node_get_tag(n);
switch(tag) {
#ifndef GPAC_DISABLE_SVG
case TAG_SVG_audio:
svg_pause_audio(n, GF_FALSE);
break;
case TAG_SVG_video:
svg_pause_video(n, GF_FALSE);
break;
case TAG_SVG_animation:
svg_pause_animation(n, GF_FALSE);
break;
#endif
}
}
return GF_TRUE;
case GF_JSAPI_OP_GET_DPI_X:
param->opt = compositor->video_out->dpi_x;
return GF_TRUE;
case GF_JSAPI_OP_GET_DPI_Y:
param->opt = compositor->video_out->dpi_y;
return GF_TRUE;
}
return GF_FALSE;
}
Bool gf_sc_pick_in_clipper(GF_TraverseState *tr_state, GF_Rect *clip)
{
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
SFVec3f pos;
GF_Matrix mx;
GF_Ray r;
gf_mx_copy(mx, tr_state->model_matrix);
gf_mx_inverse(&mx);
r = tr_state->ray;
gf_mx_apply_ray(&mx, &r);
if (!compositor_get_2d_plane_intersection(&r, &pos)) return GF_FALSE;
if ( (pos.x < clip->x) || (pos.y > clip->y)
|| (pos.x > clip->x + clip->width) || (pos.y < clip->y - clip->height) ) return GF_FALSE;
} else
#endif
{
GF_Rect rc = *clip;
GF_Point2D pt;
gf_mx2d_apply_rect(&tr_state->transform, &rc);
pt.x = tr_state->ray.orig.x;
pt.y = tr_state->ray.orig.y;
if ( (pt.x < rc.x) || (pt.y > rc.y)
|| (pt.x > rc.x + rc.width) || (pt.y < rc.y - rc.height) ) return GF_FALSE;
}
return GF_TRUE;
}
Bool gf_sc_has_text_selection(GF_Compositor *compositor)
{
return (compositor->store_text_state==GF_SC_TSEL_FROZEN) ? GF_TRUE : GF_FALSE;
}
const char *gf_sc_get_selected_text(GF_Compositor *compositor)
{
const u16 *srcp;
size_t len;
if (compositor->store_text_state != GF_SC_TSEL_FROZEN) return NULL;
gf_sc_lock(compositor, GF_TRUE);
compositor->traverse_state->traversing_mode = TRAVERSE_GET_TEXT;
if (compositor->sel_buffer) {
gf_free(compositor->sel_buffer);
compositor->sel_buffer = NULL;
}
compositor->sel_buffer_len = 0;
compositor->sel_buffer_alloc = 0;
gf_node_traverse(compositor->text_selection, compositor->traverse_state);
compositor->traverse_state->traversing_mode = 0;
if (compositor->sel_buffer) compositor->sel_buffer[compositor->sel_buffer_len]=0;
srcp = compositor->sel_buffer;
if (compositor->selected_text) gf_free(compositor->selected_text);
compositor->selected_text = gf_malloc(sizeof(char)*2*compositor->sel_buffer_len);
len = gf_utf8_wcstombs((char *) compositor->selected_text, 2*compositor->sel_buffer_len, &srcp);
if ((s32)len<0) len = 0;
compositor->selected_text[len] = 0;
gf_sc_lock(compositor, GF_FALSE);
return (const char *) compositor->selected_text;
}
void gf_sc_check_focus_upon_destroy(GF_Node *n)
{
GF_Compositor *compositor = gf_sc_get_compositor(n);
if (!compositor) return;
if (compositor->focus_node==n) {
compositor->focus_node = NULL;
compositor->focus_text_type = 0;
compositor->focus_uses_dom_events = GF_FALSE;
gf_list_reset(compositor->focus_ancestors);
gf_list_reset(compositor->focus_use_stack);
}
if (compositor->hit_node==n) compositor->hit_node = NULL;
if (compositor->hit_text==n) compositor->hit_text = NULL;
}
GF_EXPORT
GF_Err gf_sc_add_video_listener(GF_Compositor *sc, GF_VideoListener *vl)
{
if (!sc|| !vl || !vl->on_video_frame || !vl->on_video_reconfig) return GF_BAD_PARAM;
gf_sc_lock(sc, GF_TRUE);
if (!sc->video_listeners) sc->video_listeners = gf_list_new();
gf_list_add(sc->video_listeners, vl);
gf_sc_lock(sc, GF_FALSE);
return GF_OK;
}
GF_EXPORT
GF_Err gf_sc_remove_video_listener(GF_Compositor *sc, GF_VideoListener *vl)
{
if (!sc|| !vl) return GF_BAD_PARAM;
gf_sc_lock(sc, GF_TRUE);
gf_list_del_item(sc->video_listeners, vl);
if (!gf_list_count(sc->video_listeners)) {
gf_list_del(sc->video_listeners);
sc->video_listeners = NULL;
}
gf_sc_lock(sc, GF_FALSE);
return GF_OK;
}
Bool gf_sc_use_raw_texture(GF_Compositor *compositor)
{
if (!compositor) return 0;
return compositor->texture_from_decoder_memory;
}
void gf_sc_get_av_caps(GF_Compositor *compositor, u32 *width, u32 *height, u32 *display_bit_depth, u32 *audio_bpp, u32 *channels, u32 *sample_rate)
{
if (width) *width = compositor->video_out->max_screen_width;
if (height) *height = compositor->video_out->max_screen_height;
if (display_bit_depth) *display_bit_depth = compositor->video_out->max_screen_bpp ? compositor->video_out->max_screen_bpp : 8;
if (audio_bpp) *audio_bpp = 8;
if (channels) *channels = 0;
if (sample_rate) *sample_rate = 48000;
}
void gf_sc_set_system_pending_frame(GF_Compositor *compositor, Bool frame_pending)
{
if (frame_pending) {
if (!compositor->force_bench_frame)
compositor->force_bench_frame = 1;
} else {
compositor->force_bench_frame = 2;
}
}
void gf_sc_set_video_pending_frame(GF_Compositor *compositor)
{
compositor->video_frame_pending = GF_TRUE;
}
void gf_sc_queue_event(GF_Compositor *compositor, GF_Event *evt)
{
u32 i, count;
GF_QueuedEvent *qev;
gf_mx_p(compositor->evq_mx);
count = gf_list_count(compositor->event_queue);
for (i=0; i<count; i++) {
qev = gf_list_get(compositor->event_queue, i);
if (!qev->node && (qev->evt.type==evt->type)) {
qev->evt = *evt;
gf_mx_v(compositor->evq_mx);
return;
}
}
GF_SAFEALLOC(qev, GF_QueuedEvent);
if (!qev) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
} else {
qev->evt = *evt;
gf_list_add(compositor->event_queue, qev);
}
gf_mx_v(compositor->evq_mx);
}
void gf_sc_queue_dom_event(GF_Compositor *compositor, GF_Node *node, GF_DOM_Event *evt)
{
u32 i, count;
GF_QueuedEvent *qev;
gf_mx_p(compositor->evq_mx);
count = gf_list_count(compositor->event_queue);
for (i=0; i<count; i++) {
qev = gf_list_get(compositor->event_queue, i);
if ((qev->node==node) && (qev->dom_evt.type==evt->type)) {
qev->dom_evt = *evt;
gf_mx_v(compositor->evq_mx);
return;
}
}
GF_SAFEALLOC(qev, GF_QueuedEvent);
if (!qev) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
} else {
qev->node = node;
qev->dom_evt = *evt;
gf_list_add(compositor->event_queue, qev);
}
gf_mx_v(compositor->evq_mx);
}
void gf_sc_queue_dom_event_on_target(GF_Compositor *compositor, GF_DOM_Event *evt, GF_DOMEventTarget *target, GF_SceneGraph *sg)
{
u32 i, count;
GF_QueuedEvent *qev;
gf_mx_p(compositor->evq_mx);
count = gf_list_count(compositor->event_queue);
for (i=0; i<count; i++) {
qev = gf_list_get(compositor->event_queue, i);
if ((qev->target==target) && (qev->dom_evt.type==evt->type) && (qev->sg==sg) ) {
qev->dom_evt = *evt;
gf_mx_v(compositor->evq_mx);
return;
}
}
GF_SAFEALLOC(qev, GF_QueuedEvent);
if (!qev) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
} else {
qev->sg = sg;
qev->target = target;
qev->dom_evt = *evt;
gf_list_add(compositor->event_queue, qev);
}
gf_mx_v(compositor->evq_mx);
}
static void sc_cleanup_event_queue(GF_List *evq, GF_Node *node, GF_SceneGraph *sg)
{
u32 i, count = gf_list_count(evq);
for (i=0; i<count; i++) {
Bool del = 0;
GF_QueuedEvent *qev = gf_list_get(evq, i);
if (qev->node) {
if (node == qev->node)
del = 1;
if (sg && (gf_node_get_graph(qev->node)==sg))
del = 1;
}
if (qev->sg && (qev->sg==sg))
del = 1;
else if (qev->target && (qev->target->ptr_type == GF_DOM_EVENT_TARGET_NODE)) {
if (node && ((GF_Node *)qev->target->ptr==node))
del = 1;
if (sg && (gf_node_get_graph((GF_Node *)qev->target->ptr)==sg))
del = 1;
}
if (del) {
gf_list_rem(evq, i);
i--;
count--;
gf_free(qev);
}
}
}
void gf_sc_node_destroy(GF_Compositor *compositor, GF_Node *node, GF_SceneGraph *sg)
{
gf_mx_p(compositor->evq_mx);
sc_cleanup_event_queue(compositor->event_queue, node, sg);
sc_cleanup_event_queue(compositor->event_queue_back, node, sg);
gf_mx_v(compositor->evq_mx);
}
GF_EXPORT
Bool gf_sc_navigation_supported(GF_Compositor *compositor, u32 type)
{
if (compositor->navigation_disabled ) return GF_FALSE;
#ifndef GPAC_DISABLE_3D
if (compositor->visual->type_3d || compositor->active_layer) {
GF_Camera *cam = compositor_3d_get_camera(compositor);
if (cam->navigation_flags & NAV_ANY) {
return GF_TRUE;
} else {
#ifndef GPAC_DISABLE_VRML
M_NavigationInfo *ni = (M_NavigationInfo *)gf_list_get(compositor->visual->navigation_stack, 0);
if (ni) {
u32 i;
for (i=0; i<ni->type.count; i++) {
if (!ni->type.vals[i]) continue;
if (!stricmp(ni->type.vals[i], "WALK") && (type==GF_NAVIGATE_WALK)) return GF_TRUE;
else if (!stricmp(ni->type.vals[i], "NONE") && (type==GF_NAVIGATE_NONE)) return GF_TRUE;
else if (!stricmp(ni->type.vals[i], "EXAMINE") && (type==GF_NAVIGATE_EXAMINE)) return GF_TRUE;
else if (!stricmp(ni->type.vals[i], "FLY") && (type==GF_NAVIGATE_FLY)) return GF_TRUE;
else if (!stricmp(ni->type.vals[i], "VR") && (type==GF_NAVIGATE_VR)) return GF_TRUE;
else if (!stricmp(ni->type.vals[i], "GAME") && (type==GF_NAVIGATE_GAME)) return GF_TRUE;
else if (!stricmp(ni->type.vals[i], "ORBIT") && (type==GF_NAVIGATE_ORBIT)) return GF_TRUE;
}
}
#endif
return GF_FALSE;
}
} else
#endif
if ((type!=GF_NAVIGATE_NONE) && (type!=GF_NAVIGATE_SLIDE) && (type!=GF_NAVIGATE_EXAMINE)) {
return GF_FALSE;
}
return GF_TRUE;
}
Bool gf_sc_use_3d(GF_Compositor *compositor)
{
#ifndef GPAC_DISABLE_3D
return (compositor->visual->type_3d || compositor->hybrid_opengl) ? 1 : 0;
#else
return 0;
#endif
}