/*this is ugly but we have no choice, we need to clone the conditional stack because of externProto*/ void BIFS_SetupConditionalClone(GF_Node *node, GF_Node *orig) { M_Conditional *ptr; u32 i; ConditionalStack *priv_orig, *priv; priv_orig = (ConditionalStack*)gf_node_get_private(orig); /*looks we're not in BIFS*/ if (!priv_orig) { GF_Command *ori_com; M_Conditional *c_orig, *c_dest; c_orig = (M_Conditional *)orig; c_dest = (M_Conditional *)node; gf_node_init(node); /*and clone all commands*/ i=0; while ((ori_com = (GF_Command*)gf_list_enum(c_orig->buffer.commandList, &i))) { GF_Command *dest_com = gf_sg_command_clone(ori_com, gf_node_get_graph(node)); if (dest_com) gf_list_add(c_dest->buffer.commandList, dest_com); } return; } priv = (ConditionalStack*)malloc(sizeof(ConditionalStack)); priv->codec = priv_orig->codec; priv->info = priv_orig->info; gf_node_set_callback_function(node, Conditional_PreDestroy); gf_node_set_private(node, priv); ptr = (M_Conditional *)node; ptr->on_activate = Conditional_OnActivate; ptr->on_reverseActivate = Conditional_OnReverseActivate; }
static void mpeg4_sensor_created(GF_Compositor *compositor, GF_Node *node) { compositor->interaction_sensors--; #ifndef GPAC_DISABLE_SVG gf_sg_register_event_type(gf_node_get_graph(node), GF_DOM_EVENT_MOUSE|GF_DOM_EVENT_KEY); #endif }
void MC_Modified(GF_Node *node) { MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node); if (!stack) return; if (stack->changed!=2) { /*check URL*/ if (MC_URLChanged(&stack->url, &stack->control->url)) stack->changed = 2; /*check speed (play/pause)*/ else if (stack->media_speed != stack->control->mediaSpeed) stack->changed = 1; /*check mediaStartTime (seek)*/ else if (stack->media_start != stack->control->mediaStartTime) { /*do not reevaluate if mediaStartTime is reset to -1 (current time)*/ if (stack->control->mediaStartTime!=-1.0) stack->changed = 2; /*check mediaStopTime <0 (timeshift buffer control)*/ } else if (stack->media_stop != stack->control->mediaStopTime) { if (stack->control->mediaStopTime<=0) stack->changed = 2; } // else stack->changed = 1; } gf_node_dirty_set( gf_sg_get_root_node(gf_node_get_graph(node)), 0, 1); /*invalidate scene, we recompute MC state in render*/ gf_term_invalidate_compositor(stack->parent->root_od->term); }
GF_EXPORT Bool gf_inline_is_default_viewpoint(GF_Node *node) { const char *nname, *seg_name; GF_SceneGraph *sg = gf_node_get_graph(node); GF_Scene *scene = sg ? (GF_Scene *) gf_sg_get_private(sg) : NULL; if (!scene) return 0; nname = gf_node_get_name(node); if (!nname) return 0; /*check any viewpoint*/ seg_name = strrchr(scene->root_od->net_service->url, '#'); /*check the URL of the parent*/ if (!seg_name && scene->current_url) { if (scene->current_url->count && scene->current_url->vals[0].url) seg_name = strrchr(scene->current_url->vals[0].url, '#'); } else if (!seg_name && scene->root_od->mo && scene->root_od->mo->URLs.count && scene->root_od->mo->URLs.vals[0].url) { seg_name = strrchr(scene->root_od->mo->URLs.vals[0].url, '#'); } if (!seg_name) return 0; seg_name += 1; /*look for a media segment with this name - if none found, this is a viewpoint name*/ if (gf_odm_find_segment(scene->root_od, (char *) seg_name) != NULL) return 0; return (!strcmp(nname, seg_name)); }
static Bool svg_font_uri_check(GF_Node *node, FontURIStack *st) { GF_Font *font; GF_Node *font_elt; SVGAllAttributes atts; gf_svg_flatten_attributes((SVG_Element*)node, &atts); if (!atts.xlink_href) return 0; if (atts.xlink_href->type == XMLRI_ELEMENTID) { if (!atts.xlink_href->target) atts.xlink_href->target = gf_sg_find_node_by_name(gf_node_get_graph(node), atts.xlink_href->string+1); } else { GF_SceneGraph *ext_sg; char *font_name = strchr(atts.xlink_href->string, '#'); if (!font_name) return 0; if (!st->mo) { st->mo = gf_mo_load_xlink_resource(node, 0, 0, -1); if (!st->mo) return 0; } ext_sg = gf_mo_get_scenegraph(st->mo); if (!ext_sg) return 0; atts.xlink_href->target = gf_sg_find_node_by_name(ext_sg, font_name+1); if (!atts.xlink_href->target) return 0; } font_elt = atts.xlink_href->target; if (gf_node_get_tag(font_elt) != TAG_SVG_font) return 0; font = gf_node_get_private(font_elt); if (!font) return 0; st->alias = font; gf_mo_is_done(st->mo); font->not_loaded = 0; return 1; }
static void Conditional_execute(M_Conditional *node) { char *buffer; u32 len; GF_BitStream *bs; GF_BifsDecoder *codec; GF_Proto *prevproto; GF_SceneGraph *prev_graph; ConditionalStack *priv = (ConditionalStack*)gf_node_get_private((GF_Node*)node); if (!priv) return; /*set the codec working graph to the node one (to handle conditional in protos)*/ prev_graph = priv->codec->current_graph; priv->codec->current_graph = gf_node_get_graph((GF_Node*)node); assert(priv->codec->current_graph); priv->codec->info = priv->info; prevproto = priv->codec->pCurrentProto; priv->codec->pCurrentProto = NULL; if (priv->codec->current_graph->pOwningProto) priv->codec->pCurrentProto = priv->codec->current_graph->pOwningProto->proto_interface; /*set isActive - to clarify in the specs*/ node->isActive = 1; gf_node_event_out((GF_Node *)node, 3/*"isActive"*/); if (!node->buffer.bufferSize) return; /*we may replace ourselves*/ buffer = (char*)node->buffer.buffer; len = node->buffer.bufferSize; node->buffer.buffer = NULL; node->buffer.bufferSize = 0; bs = gf_bs_new(buffer, len, GF_BITSTREAM_READ); codec = priv->codec; codec->cts_offset = gf_node_get_scene_time((GF_Node*)node); /*a conditional may destroy/replace itself - to prevent that, protect node by a register/unregister ...*/ gf_node_register((GF_Node*)node, NULL); #ifdef GF_SELF_REPLACE_ENABLE /*and a conditional may destroy the entire scene!*/ cur_graph->graph_has_been_reset = 0; #endif gf_bifs_dec_command(codec, bs); gf_bs_del(bs); #ifdef GF_SELF_REPLACE_ENABLE if (cur_graph->graph_has_been_reset) { return; } #endif if (node->buffer.buffer) { gf_free(buffer); } else { node->buffer.buffer = (u8*)buffer; node->buffer.bufferSize = len; } //set isActive - to clarify in the specs // node->isActive = 0; gf_node_unregister((GF_Node*)node, NULL); codec->cts_offset = 0; codec->pCurrentProto = prevproto; codec->current_graph = prev_graph; }
GF_Err gf_bifs_flush_command_list(GF_BifsDecoder *codec) { GF_BitStream *bs; GF_Err e; CommandBufferItem *cbi; u32 NbPass = gf_list_count(codec->command_buffers); GF_List *nextPass = gf_list_new(); while (NbPass) { while (gf_list_count(codec->command_buffers)) { cbi = (CommandBufferItem *)gf_list_get(codec->command_buffers, 0); gf_list_rem(codec->command_buffers, 0); codec->current_graph = gf_node_get_graph(cbi->node); e = GF_OK; if (cbi->cb->bufferSize) { bs = gf_bs_new((char*)cbi->cb->buffer, cbi->cb->bufferSize, GF_BITSTREAM_READ); gf_bs_set_eos_callback(bs, BM_EndOfStream, codec); e = BM_ParseCommand(codec, bs, cbi->cb->commandList); gf_bs_del(bs); } if (!e) { gf_free(cbi); continue; } /*this may be an error or a dependency pb - reset coimmand list and move to next pass*/ while (gf_list_count(cbi->cb->commandList)) { u32 i; GF_CommandField *cf; GF_Command *com = (GF_Command *)gf_list_get(cbi->cb->commandList, 0); gf_list_rem(cbi->cb->commandList, 0); cf = (GF_CommandField *) gf_list_get(com->command_fields, 0); if (cf && cf->fieldType==GF_SG_VRML_SFCOMMANDBUFFER) { for (i=0; i<gf_list_count(codec->command_buffers); i++) { CommandBufferItem *cbi2 = (CommandBufferItem *)gf_list_get(codec->command_buffers, i); if (cbi2->cb == cf->field_ptr) { gf_free(cbi2); gf_list_rem(codec->command_buffers, i); i--; } } } gf_sg_command_del(com); } gf_list_add(nextPass, cbi); } if (!gf_list_count(nextPass)) break; /*prepare next pass*/ while (gf_list_count(nextPass)) { cbi = (CommandBufferItem *)gf_list_get(nextPass, 0); gf_list_rem(nextPass, 0); gf_list_add(codec->command_buffers, cbi); } NbPass --; if (NbPass > gf_list_count(codec->command_buffers)) NbPass = gf_list_count(codec->command_buffers); codec->LastError = GF_OK; } gf_list_del(nextPass); return GF_OK; }
static void OnAnchor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info) { GF_Event evt; MFURL *url; AnchorStack *st = (AnchorStack *) gf_node_get_private(sh->owner); if ((ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) st->active = 1; else if (st->active && (ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT) ) { u32 i; if (gf_node_get_tag(sh->owner)==TAG_MPEG4_Anchor) { url = & ((M_Anchor *)sh->owner)->url; evt.navigate.param_count = ((M_Anchor *)sh->owner)->parameter.count; evt.navigate.parameters = (const char **) ((M_Anchor *)sh->owner)->parameter.vals; } else { url = & ((X_Anchor *)sh->owner)->url; evt.navigate.param_count = ((X_Anchor *)sh->owner)->parameter.count; evt.navigate.parameters = (const char **) ((X_Anchor *)sh->owner)->parameter.vals; } evt.type = GF_EVENT_NAVIGATE; i=0; while (i<url->count) { evt.navigate.to_url = url->vals[i].url; if (!evt.navigate.to_url) break; /*current scene navigation*/ if (evt.navigate.to_url[0] == '#') { GF_Node *bindable; evt.navigate.to_url++; bindable = gf_sg_find_node_by_name(gf_node_get_graph(sh->owner), (char *) evt.navigate.to_url); if (bindable) { Bindable_SetSetBind(bindable, 1); break; } } else if (st->compositor->term) { if (gf_is_process_anchor(sh->owner, &evt)) break; } else if (st->compositor->user->EventProc) { if (st->compositor->user->EventProc(st->compositor->user->opaque, &evt)) break; } i++; } } else if (ev->type==GF_EVENT_MOUSEMOVE) { if (st->compositor->user->EventProc) { evt.type = GF_EVENT_NAVIGATE_INFO; if (gf_node_get_tag(sh->owner)==TAG_MPEG4_Anchor) { evt.navigate.to_url = ((M_Anchor *)sh->owner)->description.buffer; url = & ((M_Anchor *)sh->owner)->url; } else { evt.navigate.to_url = ((X_Anchor *)sh->owner)->description.buffer; url = & ((X_Anchor *)sh->owner)->url; } if (!evt.navigate.to_url || !strlen(evt.navigate.to_url)) evt.navigate.to_url = url->vals[0].url; st->compositor->user->EventProc(st->compositor->user->opaque, &evt); } } }
static void svg_a_set_view(GF_Node *handler, GF_Compositor *compositor, const char *url) { gf_scene_set_fragment_uri(handler, url); /*force recompute viewbox of root SVG - FIXME in full this should be the parent svg*/ gf_node_dirty_set(gf_sg_get_root_node(gf_node_get_graph(handler)), 0, 0); compositor->trans_x = compositor->trans_y = 0; compositor->rotation = 0; compositor->zoom = FIX_ONE; compositor_2d_set_user_transform(compositor, FIX_ONE, 0, 0, 0); gf_sc_invalidate(compositor, NULL); }
GF_EXPORT void gf_mse_mediasource_open(GF_HTML_MediaSource *ms, struct _mediaobj *mo) { if (!ms) return; if (!mo) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[MSE] Cannot open media source without a media object\n")); return; } ms->readyState = MEDIA_SOURCE_READYSTATE_OPEN; /* getting the Scene Tree node attached to this media source */ ms->node = (GF_Node *)gf_event_target_get_node(gf_mo_event_target_get(mo, 0)); ms->sg = gf_node_get_graph(ms->node); gf_mse_fire_event(ms->evt_target, GF_EVENT_HTML_MSE_SOURCE_OPEN); }
/* Creates a subscene from the xlink:href */ static GF_Scene *gf_svg_get_subscene(GF_Node *elt, XLinkAttributesPointers *xlinkp, SMILSyncAttributesPointers *syncp, Bool use_sync, Bool primary_resource) { MFURL url; Bool lock_timelines = 0; GF_MediaObject *mo; GF_SceneGraph *graph = gf_node_get_graph(elt); GF_Scene *scene = (GF_Scene *)gf_sg_get_private(graph); if (!scene) return NULL; if (use_sync && syncp) { switch ((syncp->syncBehavior?*syncp->syncBehavior:SMIL_SYNCBEHAVIOR_DEFAULT)) { case SMIL_SYNCBEHAVIOR_LOCKED: case SMIL_SYNCBEHAVIOR_CANSLIP: lock_timelines = 1; break; case SMIL_SYNCBEHAVIOR_DEFAULT: { #if 0 if (svg && syncp) { switch ((syncp->syncBehaviorDefault ? *syncp->syncBehaviorDefault : SMIL_SYNCBEHAVIOR_LOCKED)) { case SMIL_SYNCBEHAVIOR_LOCKED: case SMIL_SYNCBEHAVIOR_CANSLIP: lock_timelines = 1; break; default: break; } } #endif } default: break; } } memset(&url, 0, sizeof(MFURL)); if (!xlinkp->href) return NULL; gf_term_get_mfurl_from_xlink(elt, &url); while (scene->secondary_resource && scene->root_od->parentscene) scene = scene->root_od->parentscene; mo = gf_scene_get_media_object_ex(scene, &url, GF_MEDIA_OBJECT_SCENE, lock_timelines, NULL, primary_resource, elt); gf_sg_vrml_mf_reset(&url, GF_SG_VRML_MFURL); if (!mo || !mo->odm) return NULL; mo->odm->subscene->secondary_resource = primary_resource ? 0 : 1; return mo->odm->subscene; }
void compositor_init_svg_svg(GF_Compositor *compositor, GF_Node *node) { GF_Node *root; SVGsvgStack *stack; GF_SAFEALLOC(stack, SVGsvgStack); root = gf_sg_get_root_node(gf_node_get_graph(node)); stack->root_svg = (root==node) ? 1 : 0; if (stack->root_svg) { GF_SAFEALLOC(stack->svg_props, SVGPropertiesPointers); gf_svg_properties_init_pointers(stack->svg_props); } gf_mx2d_init(stack->viewbox_mx); gf_node_set_private(node, stack); gf_node_set_callback_function(node, svg_traverse_svg); }
static void RenderInputSensor(GF_Node *node, void *rs, Bool is_destroy) { ISStack *st = (ISStack*)gf_node_get_private(node); M_InputSensor *is = (M_InputSensor *)node; if (is_destroy) { GF_InlineScene *is; if (st->registered) IS_Unregister(st); is = (GF_InlineScene*)gf_sg_get_private(gf_node_get_graph(node)); gf_term_rem_render_node(is->root_od->term, node); free(st); } else { /*get decoder object */ if (!st->mo) st->mo = gf_mo_find(node, &is->url, 0); /*register with decoder*/ if (st->mo && !st->registered) IS_Register(node); } }
static void seng_exec_conditional(M_Conditional *c, GF_SceneGraph *scene) { GF_List *clist = c->buffer.commandList; c->buffer.commandList = NULL; gf_sg_command_apply_list(gf_node_get_graph((GF_Node*)c), clist, 0.0); if (c->buffer.commandList != NULL) { while (gf_list_count(clist)) { GF_Command *sub_com = (GF_Command *)gf_list_get(clist, 0); gf_sg_command_del(sub_com); gf_list_rem(clist, 0); } gf_list_del(clist); } else { c->buffer.commandList = clist; } }
static void TraverseInputSensor(GF_Node *node, void *rs, Bool is_destroy) { ISStack *st = (ISStack*)gf_node_get_private(node); M_InputSensor *is = (M_InputSensor *)node; if (is_destroy) { GF_Scene *scene; if (st->registered) IS_Unregister(node, st); scene = (GF_Scene*)gf_sg_get_private(gf_node_get_graph(node)); gf_term_unqueue_node_traverse(scene->root_od->term, node); gf_free(st); } else { /*get decoder object */ if (!st->mo) st->mo = gf_mo_register(node, &is->url, 0, 0); /*register with decoder*/ if (st->mo && !st->registered) IS_Register(node); } }
static void mpeg4_sensor_deleted(GF_Node *node, GF_SensorHandler *hdl) { GF_Compositor *compositor = gf_sc_get_compositor(node); if (compositor) { GF_VisualManager *visual; u32 i=0; gf_list_del_item(compositor->sensors, hdl); gf_list_del_item(compositor->previous_sensors, hdl); if (compositor->interaction_sensors) compositor->interaction_sensors--; while ( (visual=gf_list_enum(compositor->visuals, &i)) ) { if (visual->offscreen) compositor_compositetexture_sensor_delete(visual->offscreen, hdl); } #ifndef GPAC_DISABLE_SVG gf_sg_unregister_event_type(gf_node_get_graph(node), GF_DOM_EVENT_MOUSE|GF_DOM_EVENT_KEY); #endif } }
void compositor_init_imagetexture(GF_Compositor *compositor, GF_Node *node) { GF_TextureHandler *txh; GF_SAFEALLOC(txh, GF_TextureHandler); gf_sc_texture_setup(txh, compositor, node); txh->update_texture_fcnt = imagetexture_update; gf_node_set_private(node, txh); gf_node_set_callback_function(node, imagetexture_destroy); txh->flags = 0; if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) { if (((M_ImageTexture*)node)->repeatS) txh->flags |= GF_SR_TEXTURE_REPEAT_S; if (((M_ImageTexture*)node)->repeatT) txh->flags |= GF_SR_TEXTURE_REPEAT_T; } else { const char *url; u32 i, count; M_CacheTexture*ct = (M_CacheTexture*)node; if (!ct->image.buffer) return; if (ct->repeatS) txh->flags |= GF_SR_TEXTURE_REPEAT_S; if (ct->repeatT) txh->flags |= GF_SR_TEXTURE_REPEAT_T; /*locate existing cache*/ url = gf_scene_get_service_url( gf_node_get_graph(node) ); count = gf_cfg_get_section_count(compositor->user->config); for (i=0; i<count; i++) { const char *opt; const char *name = gf_cfg_get_section_name(compositor->user->config, i); if (strncmp(name, "@cache=", 7)) continue; opt = gf_cfg_get_key(compositor->user->config, name, "serviceURL"); if (!opt || stricmp(opt, url)) continue; opt = gf_cfg_get_key(compositor->user->config, name, "cacheName"); if (opt && ct->cacheURL.buffer && !stricmp(opt, ct->cacheURL.buffer)) { opt = gf_cfg_get_key(compositor->user->config, name, "cacheFile"); if (opt) gf_delete_file((char*)opt); gf_cfg_del_section(compositor->user->config, name); break; } } } }
static void anchor_activation(GF_Node *node, AnchorStack *st, GF_Compositor *compositor) { GF_Event evt; u32 i; MFURL *url = NULL; switch (gf_node_get_tag(node)) { case TAG_MPEG4_Anchor: url = & ((M_Anchor *)node)->url; evt.navigate.param_count = ((M_Anchor *)node)->parameter.count; evt.navigate.parameters = (const char **) ((M_Anchor *)node)->parameter.vals; break; #ifndef GPAC_DISABLE_X3D case TAG_X3D_Anchor: url = & ((X_Anchor *)node)->url; evt.navigate.param_count = ((X_Anchor *)node)->parameter.count; evt.navigate.parameters = (const char **) ((X_Anchor *)node)->parameter.vals; break; #endif } evt.type = GF_EVENT_NAVIGATE; i=0; while (url && i<url->count) { evt.navigate.to_url = url->vals[i].url; if (!evt.navigate.to_url) break; /*current scene navigation*/ if (evt.navigate.to_url[0] == '#') { GF_Node *bindable; evt.navigate.to_url++; bindable = gf_sg_find_node_by_name(gf_node_get_graph(node), (char *) evt.navigate.to_url); if (bindable) { Bindable_SetSetBind(bindable, 1); break; } } else if (compositor->term) { if (gf_scene_process_anchor(node, &evt)) break; } else if (gf_term_send_event(compositor->term, &evt)) { break; } i++; } }
static Bool gf_inline_set_scene(M_Inline *root) { GF_MediaObject *mo; GF_Scene *parent; GF_SceneGraph *graph = gf_node_get_graph((GF_Node *) root); parent = (GF_Scene *)gf_sg_get_private(graph); if (!parent) return 0; mo = gf_scene_get_media_object_ex(parent, &root->url, GF_MEDIA_OBJECT_SCENE, 0, NULL, 0, (GF_Node*)root); if (!mo || !mo->odm) return 0; if (!mo->odm->subscene) { gf_term_invalidate_compositor(parent->root_od->term); return 0; } /*assign inline scene as private stack of inline node, and remember inline node for event propagation*/ gf_node_set_private((GF_Node *)root, mo->odm->subscene); /*play*/ gf_mo_play(mo, 0, -1, 0); return 1; }
char *gf_term_resolve_xlink(GF_Node *node, char *the_url) { char *url; GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node)); if (!scene) return NULL; url = gf_strdup(the_url); /*apply XML:base*/ while (node) { GF_FieldInfo info; if (gf_node_get_attribute_by_tag(node, TAG_XML_ATT_base, 0, 0, &info)==GF_OK) { char *new_url = gf_url_concatenate( ((XMLRI*)info.far_ptr)->string, url); if (new_url) { gf_free(url); url = new_url; } } node = gf_node_get_parent(node, 0); } /*if this is a fragment and no XML:BASE was found, this is a fragment of the current document*/ if (url[0]=='#') return url; if (scene) { char *the_url; if (scene->redirect_xml_base) { the_url = gf_url_concatenate(scene->redirect_xml_base, url); } else { // the_url = gf_url_concatenate(is->root_od->net_service->url, url); /*the root url of a document should be "." if not specified, so that the final URL resolve happens only once at the service level*/ the_url = gf_strdup(url); } gf_free(url); return the_url; } return url; }
GF_EXPORT GF_Err gf_term_get_mfurl_from_xlink(GF_Node *node, MFURL *mfurl) { u32 stream_id = 0; GF_Err e = GF_OK; SFURL *sfurl = NULL; GF_FieldInfo info; XMLRI *iri; GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node)); if (!scene) return GF_BAD_PARAM; gf_sg_vrml_mf_reset(mfurl, GF_SG_VRML_MFURL); e = gf_node_get_attribute_by_tag(node, TAG_XLINK_ATT_href, 0, 0, &info); if (e) return e; iri = (XMLRI*)info.far_ptr; if (iri->type==XMLRI_STREAMID) { stream_id = iri->lsr_stream_id; } else if (!iri->string) return GF_OK; mfurl->count = 1; GF_SAFEALLOC(mfurl->vals, SFURL) sfurl = mfurl->vals; sfurl->OD_ID = stream_id; if (stream_id) return GF_OK; if (!strncmp(iri->string, "data:", 5)) { const char *cache_dir = gf_cfg_get_key(scene->root_od->term->user->config, "General", "CacheDirectory"); e = gf_node_store_embedded_data(iri, cache_dir, "embedded_"); if (e) return e; sfurl->url = gf_strdup(iri->string); return GF_OK; } sfurl->url = gf_term_resolve_xlink(node, iri->string); return e; }
GF_MediaObject *gf_mo_load_xlink_resource(GF_Node *node, Bool primary_resource, Double clipBegin, Double clipEnd) { GF_Scene *new_resource; SVGAllAttributes all_atts; XLinkAttributesPointers xlinkp; SMILSyncAttributesPointers syncp; GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node)); if (!scene) return NULL; gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); xlinkp.actuate = all_atts.xlink_actuate; xlinkp.arcrole = all_atts.xlink_arcrole; xlinkp.href = all_atts.xlink_href; xlinkp.role = all_atts.xlink_role; xlinkp.show = all_atts.xlink_show; xlinkp.title = all_atts.xlink_title; xlinkp.type = all_atts.xlink_type; syncp.syncBehavior = all_atts.syncBehavior; syncp.syncBehaviorDefault = all_atts.syncBehaviorDefault; syncp.syncMaster = all_atts.syncMaster; syncp.syncReference = all_atts.syncReference; syncp.syncTolerance = all_atts.syncTolerance; syncp.syncToleranceDefault = all_atts.syncToleranceDefault; if (!xlinkp.href) return NULL; if (xlinkp.href->type == XMLRI_ELEMENTID) return NULL; // else if (xlinkp.href->string && (xlinkp.href->string[0]=='#')) return NULL; new_resource = gf_svg_get_subscene(node, &xlinkp, &syncp, primary_resource ? 1 : 0, primary_resource); if (!new_resource) return NULL; /*play*/ gf_mo_play(new_resource->root_od->mo, 0, -1, 0); return new_resource->root_od->mo; }
Bool compositor_compositetexture_handle_event(GF_Compositor *compositor, GF_Node *composite_appear, GF_Event *ev, Bool is_flush) { GF_Ray ray; Fixed dist; Bool had_text_sel=0; GF_Matrix mx; GF_TraverseState *tr_state; GF_ChildNodeItem *children, *l; Bool res; SFVec3f txcoord, loc_pt, world_pt; GF_Matrix l2w_mx, w2l_mx; CompositeTextureStack *stack; GF_Node *appear, *prev_appear; M_Appearance *ap = (M_Appearance *)composite_appear; assert(ap && ap->texture); if (ev->type > GF_EVENT_MOUSEMOVE) return 0; stack = gf_node_get_private(ap->texture); if (!stack->txh.tx_io) return 0; tr_state = NULL; children = NULL; if (!is_flush) { txcoord.x = compositor->hit_texcoords.x; txcoord.y = compositor->hit_texcoords.y; txcoord.z = 0; if (gf_sc_texture_get_transform(&stack->txh, ap->textureTransform, &mx, 1)) { /*tx coords are inverted when mapping, thus applying directly the matrix will give us the untransformed coords*/ gf_mx_apply_vec(&mx, &txcoord); while (txcoord.x<0) txcoord.x += FIX_ONE; while (txcoord.x>FIX_ONE) txcoord.x -= FIX_ONE; while (txcoord.y<0) txcoord.y += FIX_ONE; while (txcoord.y>FIX_ONE) txcoord.y -= FIX_ONE; } /*convert to tx space*/ ev->mouse.x = FIX2INT( (txcoord.x - FIX_ONE/2) * stack->visual->width + FIX_ONE/2); ev->mouse.y = FIX2INT( (txcoord.y - FIX_ONE/2) * stack->visual->height + FIX_ONE/2); GF_SAFEALLOC(tr_state, GF_TraverseState); tr_state->vrml_sensors = gf_list_new(); tr_state->visual = stack->visual; tr_state->traversing_mode = TRAVERSE_PICK; tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(ap->texture)); tr_state->vp_size.x = INT2FIX(stack->txh.width); tr_state->vp_size.y = INT2FIX(stack->txh.height); tr_state->color_mat.identity = 1; gf_mx2d_init(tr_state->transform); #ifndef GPAC_DISABLE_3D gf_mx_init(tr_state->model_matrix); #endif /*collect sensors*/ l = children = ((M_CompositeTexture2D*)ap->texture)->children; while (l) { GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler(l->node); if (hsens) gf_list_add(tr_state->vrml_sensors, hsens); l = l->next; } } stack->temp_sensors = compositor->sensors; stack->temp_previous_sensors = compositor->previous_sensors; compositor->sensors = stack->sensors; compositor->previous_sensors = stack->previous_sensors; ray = compositor->hit_world_ray; dist = compositor->hit_square_dist; prev_appear = compositor->prev_hit_appear; /*protect against destrucion in case of self-destroy*/ if (prev_appear) { gf_node_register(prev_appear, NULL); } compositor->prev_hit_appear = stack->prev_hit_appear; appear = compositor->hit_appear; compositor->hit_appear = NULL; /*also backup current hit state in case we hit a node in the texture but don't consume the event*/ loc_pt = compositor->hit_local_point; world_pt = compositor->hit_world_point; gf_mx_copy(l2w_mx, compositor->hit_local_to_world); gf_mx_copy(w2l_mx, compositor->hit_world_to_local); if (compositor->text_selection) had_text_sel=1; if (is_flush) { res = 0; gf_list_reset(stack->sensors); gf_sc_exec_event_vrml(compositor, ev); } else { res = visual_execute_event(stack->visual, tr_state, ev, children); } if (!had_text_sel && compositor->edited_text) { stack->visual->has_text_edit = 1; } else if (!compositor->text_selection) { stack->visual->has_text_edit = 0; } if (!res) { compositor->hit_local_point = loc_pt; gf_mx_copy(compositor->hit_local_to_world, l2w_mx); gf_mx_copy(compositor->hit_world_to_local, w2l_mx); } stack->prev_hit_appear = compositor->prev_hit_appear; if (prev_appear) { if (prev_appear->sgprivate->num_instances>1) { compositor->prev_hit_appear = prev_appear; compositor->hit_appear = appear; } else { compositor->prev_hit_appear = NULL; compositor->hit_appear = NULL; } gf_node_unregister(prev_appear, NULL); } else { compositor->prev_hit_appear = prev_appear; compositor->hit_appear = appear; } compositor->hit_world_point = world_pt; compositor->hit_world_ray = ray; compositor->hit_square_dist = dist; stack->sensors = compositor->sensors; stack->previous_sensors = compositor->previous_sensors; compositor->sensors = stack->temp_sensors; stack->temp_sensors = NULL; compositor->previous_sensors = stack->temp_previous_sensors; stack->temp_previous_sensors = NULL; if (!is_flush) { gf_list_del(tr_state->vrml_sensors); #ifndef GPAC_DISABLE_3D if (tr_state->layer3d) compositor->traverse_state->layer3d = tr_state->layer3d; #endif gf_free(tr_state); } return res; }
static void composite_update(GF_TextureHandler *txh) { s32 w, h; GF_STENCIL stencil; M_Background2D *back; GF_TraverseState *tr_state; Bool invalidate_all; u32 new_pixel_format; GF_Compositor *compositor = (GF_Compositor *)txh->compositor; CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(txh->owner); GF_Raster2D *raster = st->visual->compositor->rasterizer; if (st->unsupported) return; /* if (compositor->recompute_ar) { gf_node_dirty_set(txh->owner, 0, 0); return; } */ if (!compositor->rebuild_offscreen_textures && (!compositor->text_edit_changed || !st->visual->has_text_edit ) && !gf_node_dirty_get(txh->owner)) { txh->needs_refresh = 0; return; } gf_node_dirty_clear(st->txh.owner, 0); new_pixel_format = 0; back = gf_list_get(st->visual->back_stack, 0); if (back && back->isBound) new_pixel_format = GF_PIXEL_RGB_24; else new_pixel_format = GF_PIXEL_RGBA; #ifdef GPAC_USE_TINYGL /*TinyGL pixel format is fixed at compile time, we cannot override it !*/ if (st->visual->type_3d) new_pixel_format = GF_PIXEL_RGBA; #else #ifndef GPAC_DISABLE_3D /*no alpha support in offscreen rendering*/ if ( (st->visual->type_3d) && !(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA)) new_pixel_format = GF_PIXEL_RGB_24; #endif /*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/ #ifdef GPAC_USE_OGL_ES new_pixel_format = GF_PIXEL_RGBA; #endif #endif /*FIXME - we assume RGB+Depth+bitshape, we should check with the video out module*/ #if defined(GF_SR_USE_DEPTH) && !defined(GPAC_DISABLE_3D) if (st->visual->type_3d && (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_DEPTH) ) new_pixel_format = GF_PIXEL_RGBDS; #endif #ifndef GPAC_DISABLE_3D if (st->visual->type_3d>1) { w = ((M_CompositeTexture3D*)txh->owner)->pixelWidth; h = ((M_CompositeTexture3D*)txh->owner)->pixelHeight; } else #endif { w = ((M_CompositeTexture2D*)txh->owner)->pixelWidth; h = ((M_CompositeTexture2D*)txh->owner)->pixelHeight; } /*internal GPAC hacks for testing color spaces*/ if (w<-1) { w = -w; if (h<0) { h = -h; if (new_pixel_format==GF_PIXEL_RGBA) { new_pixel_format=GF_PIXEL_ARGB; } else { new_pixel_format=GF_PIXEL_BGR_24; } } else { if (new_pixel_format==GF_PIXEL_RGB_24) { new_pixel_format=GF_PIXEL_RGB_32; } } } else if (h<-1) { h = -h; if (new_pixel_format==GF_PIXEL_RGB_24) { new_pixel_format=GF_PIXEL_RGB_32; } } if (w<0) w = 0; if (h<0) h = 0; if (!w || !h) { if (txh->tx_io) { #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx); #endif gf_sc_texture_release(txh); if (txh->data) gf_free(txh->data); txh->data = NULL; txh->width = txh->height = txh->stride = 0; } return; } invalidate_all = compositor->rebuild_offscreen_textures; /*rebuild stencil*/ if (!txh->tx_io || (w != (s32) txh->width) || ( h != (s32) txh->height) || (new_pixel_format != txh->pixelformat) ) { Bool needs_stencil = 1; if (txh->tx_io) { #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx); #endif gf_sc_texture_release(txh); if (txh->data) gf_free(txh->data); txh->data = NULL; } /*we don't use rect ext because of no support for texture transforms*/ if (1 #ifndef GPAC_DISABLE_3D || compositor->gl_caps.npot_texture #endif ) { st->txh.width = w; st->txh.height = h; st->sx = st->sy = FIX_ONE; } else { st->txh.width = 2; while (st->txh.width<(u32)w) st->txh.width*=2; st->txh.height = 2; while (st->txh.height<(u32)h) st->txh.height*=2; st->sx = INT2FIX(st->txh.width) / w; st->sy = INT2FIX(st->txh.height) / h; } gf_sc_texture_allocate(txh); txh->pixelformat = new_pixel_format; switch (new_pixel_format) { case GF_PIXEL_RGBA: case GF_PIXEL_ARGB: txh->stride = txh->width * 4; txh->transparent = 1; break; case GF_PIXEL_RGB_565: txh->stride = txh->width * 2; txh->transparent = 0; break; case GF_PIXEL_RGBDS: txh->stride = txh->width * 4; txh->transparent = 1; break; case GF_PIXEL_RGB_24: txh->stride = txh->width * 3; txh->transparent = 0; break; } st->visual->width = txh->width; st->visual->height = txh->height; stencil = raster->stencil_new(raster, GF_STENCIL_TEXTURE); /*TODO - add support for compositeTexture3D when root is 2D visual*/ #ifndef GPAC_DISABLE_3D if (st->visual->type_3d) { GF_Compositor *compositor = st->visual->compositor; /*figure out what to do if main visual (eg video out) is not in OpenGL ...*/ if (!compositor->visual->type_3d) { /*create an offscreen window for OpenGL rendering*/ if ((compositor->offscreen_width < st->txh.width) || (compositor->offscreen_height < st->txh.height)) { #ifndef GPAC_USE_TINYGL GF_Err e; GF_Event evt; compositor->offscreen_width = MAX(compositor->offscreen_width, st->txh.width); compositor->offscreen_height = MAX(compositor->offscreen_height, st->txh.height); evt.type = GF_EVENT_VIDEO_SETUP; evt.setup.width = compositor->offscreen_width; evt.setup.height = compositor->offscreen_height; evt.setup.back_buffer = 0; evt.setup.opengl_mode = 2; e = compositor->video_out->ProcessEvent(compositor->video_out, &evt); if (e) { gf_sc_texture_release(txh); st->unsupported = 1; return; } /*reload openGL ext*/ gf_sc_load_opengl_extensions(compositor, 1); #endif } } else { needs_stencil = 0; } } #endif if (needs_stencil) { txh->data = (char*)gf_malloc(sizeof(unsigned char) * txh->stride * txh->height); memset(txh->data, 0, sizeof(unsigned char) * txh->stride * txh->height); /*set stencil texture - we don't check error as an image could not be supported by the rasterizer but still supported by the blitter (case of RGBD/RGBDS)*/ raster->stencil_set_texture(stencil, txh->data, txh->width, txh->height, txh->stride, txh->pixelformat, txh->pixelformat, 0); #ifdef GPAC_USE_TINYGL if (st->visual->type_3d && !compositor->visual->type_3d) { st->tgl_ctx = ostgl_create_context(txh->width, txh->height, txh->transparent ? 32 : 24, &txh->data, 1); GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Creating TinyGL Offscreen context %p (%d %d - pf %s)\n", st->tgl_ctx, txh->width, txh->width, gf_4cc_to_str(txh->pixelformat))); } #endif } invalidate_all = 1; gf_sc_texture_set_stencil(txh, stencil); } if (!txh->tx_io) return; stencil = gf_sc_texture_get_stencil(txh); if (!stencil) return; #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_make_current(st->tgl_ctx, 0); #endif GF_SAFEALLOC(tr_state, GF_TraverseState); tr_state->vrml_sensors = gf_list_new(); tr_state->visual = st->visual; tr_state->invalidate_all = invalidate_all; tr_state->immediate_draw = st->visual->compositor->traverse_state->immediate_draw; gf_mx2d_init(tr_state->transform); gf_cmx_init(&tr_state->color_mat); tr_state->backgrounds = st->visual->back_stack; tr_state->viewpoints = st->visual->view_stack; tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner)); tr_state->min_hsize = INT2FIX( MIN(txh->width, txh->height) ) / 2; tr_state->vp_size.x = INT2FIX(txh->width); tr_state->vp_size.y = INT2FIX(txh->height); composite_do_bindable(st->txh.owner, tr_state, st->first); st->first = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Entering draw cycle\n")); txh->needs_refresh = visual_draw_frame(st->visual, st->txh.owner, tr_state, 0); txh->transparent = (st->visual->last_had_back==2) ? 0 : 1; if (!compositor->edited_text && st->visual->has_text_edit) st->visual->has_text_edit = 0; /*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/ if (0 && gf_list_count(st->visual->view_stack)) { M_Viewport *vp = (M_Viewport *)gf_list_get(st->visual->view_stack, 0); if (vp->isBound) { SFVec2f size = vp->size; if (size.x >=0 && size.y>=0) { /*FIXME - we need tracking of VP changes*/ txh->needs_refresh = 1; } } } if (txh->needs_refresh) { #ifndef GPAC_DISABLE_3D if (st->visual->camera.is_3D) { if (st->visual->compositor->visual->type_3d) { #ifndef GPAC_USE_TINYGL gf_sc_copy_to_texture(&st->txh); #else /*in TinyGL we only need to push associated bitmap to the texture*/ gf_sc_texture_push_image(&st->txh, 0, 0); #endif } else { #ifndef GPAC_USE_TINYGL gf_sc_copy_to_stencil(&st->txh); #else if (txh->pixelformat==GF_PIXEL_RGBDS) gf_get_tinygl_depth(&st->txh); #endif } } else #endif { if (raster->stencil_texture_modified) raster->stencil_texture_modified(stencil); gf_sc_texture_set_stencil(txh, stencil); } gf_sc_invalidate(st->txh.compositor, NULL); } gf_list_del(tr_state->vrml_sensors); gf_free(tr_state); GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Leaving draw cycle\n")); }
static Bool OnAnchor(SensorHandler *sh, GF_Event *evt, DrawableContext *ctx, GF_Matrix2D *sensor_matrix) { u32 i; GF_Event event; AnchorStack *st = (AnchorStack *) gf_node_get_private(sh->owner); M_Anchor *an = (M_Anchor *) sh->owner; if (ctx==NULL) { event.type = GF_EVENT_NAVIGATE_INFO; event.navigate.to_url = ""; st->compositor->user->EventProc(st->compositor->user->opaque, &event); st->is_over = 0; return 0; } if (evt->type == GF_EVENT_MOUSEMOVE) { if (!st->is_over && st->compositor->user->EventProc) { event.type = GF_EVENT_NAVIGATE_INFO; event.navigate.to_url = an->description.buffer; if (!event.navigate.to_url || !strlen(event.navigate.to_url)) event.navigate.to_url = an->url.vals[0].url; st->compositor->user->EventProc(st->compositor->user->opaque, &event); } st->is_over = 1; return 0; } if ((evt->type != GF_EVENT_MOUSEUP) || (evt->mouse.button != GF_MOUSE_LEFT)) return 0; event.type = GF_EVENT_NAVIGATE; event.navigate.param_count = an->parameter.count; event.navigate.parameters = (const char **) an->parameter.vals; i=0; while (i<an->url.count) { event.navigate.to_url = an->url.vals[i].url; if (!event.navigate.to_url) break; /*current scene navigation*/ if (event.navigate.to_url[0] == '#') { GF_Node *n; event.navigate.to_url++; n = gf_sg_find_node_by_name(gf_node_get_graph(sh->owner), (char *) event.navigate.to_url); if (n) { switch (gf_node_get_tag(n)) { case TAG_MPEG4_Viewport: ((M_Viewport *)n)->set_bind = 1; ((M_Viewport *)n)->on_set_bind(n); break; } break; } } else if (st->compositor->term) { if (gf_is_process_anchor(sh->owner, &event)) break; } else if (st->compositor->user->EventProc) { if (st->compositor->user->EventProc(st->compositor->user->opaque, &event)) break; } i++; } return 0; }
static void gf_inline_traverse(GF_Node *n, void *rs, Bool is_destroy) { MFURL *current_url; GF_Scene *scene = (GF_Scene *)gf_node_get_private(n); if (is_destroy) { GF_MediaObject *mo; if (!scene) return; mo = scene->root_od ? scene->root_od->mo : NULL; gf_scene_notify_event(scene, GF_EVENT_UNLOAD, n, NULL, GF_OK); if (!mo) return; gf_list_del_item(mo->nodes, n); /*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/ if (mo->num_open) { mo->num_open --; if (!mo->num_open) { gf_term_lock_media_queue(scene->root_od->term, 1); /*this is unspecified in the spec: whenever an inline not using the OD framework is destroyed, destroy the associated resource*/ if (mo->OD_ID == GF_MEDIA_EXTERNAL_ID) { /*get parent scene and remove MediaObject in case the ressource gets re-requested later on*/ GF_Scene *parent_scene = (GF_Scene *)gf_sg_get_private(gf_node_get_graph((GF_Node *) n) ); if (gf_list_del_item(parent_scene->scene_objects, mo)>=0) { gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL); gf_list_del(mo->nodes); if (mo->odm) mo->odm->mo = NULL; gf_free(mo); } scene->root_od->action_type = GF_ODM_ACTION_DELETE; gf_list_add(scene->root_od->term->media_queue, scene->root_od); } else { scene->root_od->action_type = GF_ODM_ACTION_SCENE_DISCONNECT; gf_list_add(scene->root_od->term->media_queue, scene->root_od); } gf_term_lock_media_queue(scene->root_od->term, 0); } } return; } //if no private scene is associated get the node parent graph, retrieve the IS and find the OD if (!scene) { M_Inline *inl = (M_Inline *)n; gf_inline_set_scene(inl); scene = (GF_Scene *)gf_node_get_private(n); if (!scene) { /*just like protos, we must invalidate parent graph until attached*/ if (inl->url.count) { if (!inl->url.vals[0].OD_ID && (!inl->url.vals[0].url || !strlen(inl->url.vals[0].url) ) ) { gf_sg_vrml_mf_reset(&inl->url, GF_SG_VRML_MFURL); } else { gf_node_dirty_set(n, 0, 1); } } return; } } gf_inline_check_restart(scene); /*if we need to restart, shutdown graph and do it*/ if (scene->needs_restart) { /*special case: scene change*/ if (scene->needs_restart==2) { scene->needs_restart = 0; gf_inline_on_modified(n); return; } scene->needs_restart = 0; gf_term_lock_media_queue(scene->root_od->term, 1); scene->root_od->action_type = GF_ODM_ACTION_SCENE_INLINE_RESTART; gf_list_add(scene->root_od->term->media_queue, scene->root_od); gf_term_lock_media_queue(scene->root_od->term, 0); gf_node_dirty_set(n, 0, 1); return; } /*if not attached return (attaching the graph cannot be done in render since render is not called while unattached :) */ if (!scene->graph_attached) { /*just like protos, we must invalidate parent graph until attached*/ gf_node_dirty_set(n, 0, 1); return; } /*clear dirty flags for any sub-inlines, bitmaps or protos*/ gf_node_dirty_clear(n, 0); current_url = scene->current_url; scene->current_url = & ((M_Inline*)n)->url; gf_sc_traverse_subscene(scene->root_od->term->compositor, n, scene->graph, rs); scene->current_url = current_url; }
static void imagetexture_update(GF_TextureHandler *txh) { if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) { MFURL url = ((M_ImageTexture *) txh->owner)->url; /*setup texture if needed*/ if (!txh->is_open && url.count) { gf_sc_texture_play(txh, &url); } gf_sc_texture_update_frame(txh, 0); if ( /*URL is present but not opened - redraw till fetch*/ /* (txh->stream && !txh->tx_io) && */ /*image has been updated*/ txh->needs_refresh) { /*mark all subtrees using this image as dirty*/ gf_node_dirty_parents(txh->owner); gf_sc_invalidate(txh->compositor, NULL); } return; } /*cache texture case*/ else { M_CacheTexture *ct = (M_CacheTexture *) txh->owner; /*decode cacheTexture data */ if ((ct->data || ct->image.buffer) && !txh->data) { #ifndef GPAC_DISABLE_AV_PARSERS u32 out_size; GF_Err e; /*BT/XMT playback: load to memory*/ if (ct->image.buffer) { char *par = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) ); char *src_url = gf_url_concatenate(par, ct->image.buffer); FILE *test = gf_fopen( src_url ? src_url : ct->image.buffer, "rb"); if (test) { fseek(test, 0, SEEK_END); ct->data_len = (u32) gf_ftell(test); ct->data = gf_malloc(sizeof(char)*ct->data_len); fseek(test, 0, SEEK_SET); if (ct->data_len != fread(ct->data, 1, ct->data_len, test)) { GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: IO err\n", src_url ? src_url : ct->image.buffer ) ); gf_free(ct->data); ct->data = NULL; ct->data_len = 0; } gf_fclose(test); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: not found\n", src_url ? src_url : ct->image.buffer ) ); } ct->image.buffer = NULL; if (src_url) gf_free(src_url); } /*BIFS decoded playback*/ switch (ct->objectTypeIndication) { case GPAC_OTI_IMAGE_JPEG: out_size = 0; e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3); if (e==GF_BUFFER_TOO_SMALL) { u32 BPP; txh->data = gf_malloc(sizeof(char) * out_size); if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1; else BPP = 3; e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP); if (e==GF_OK) { gf_sc_texture_allocate(txh); gf_sc_texture_set_data(txh); txh->needs_refresh = 1; txh->stride = out_size / txh->height; } } break; case GPAC_OTI_IMAGE_PNG: out_size = 0; e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size); if (e==GF_BUFFER_TOO_SMALL) { txh->data = gf_malloc(sizeof(char) * out_size); e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size); if (e==GF_OK) { gf_sc_texture_allocate(txh); gf_sc_texture_set_data(txh); txh->needs_refresh = 1; txh->stride = out_size / txh->height; } } break; } #endif // GPAC_DISABLE_AV_PARSERS /*cacheURL is specified, store the image*/ if (ct->cacheURL.buffer) { u32 i; u8 hash[20]; FILE *cached_texture; char szExtractName[GF_MAX_PATH], section[64], *opt, *src_url; opt = (char *) gf_cfg_get_key(txh->compositor->user->config, "General", "CacheDirectory"); if (opt) { strcpy(szExtractName, opt); } else { opt = gf_get_default_cache_directory(); strcpy(szExtractName, opt); gf_free(opt); } strcat(szExtractName, "/"); src_url = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) ); gf_sha1_csum((u8 *)src_url, (u32) strlen(src_url), hash); for (i=0; i<20; i++) { char t[3]; t[2] = 0; sprintf(t, "%02X", hash[i]); strcat(szExtractName, t); } strcat(szExtractName, "_"); strcat(szExtractName, ct->cacheURL.buffer); cached_texture = gf_fopen(szExtractName, "wb"); if (cached_texture) { gf_fwrite(ct->data, 1, ct->data_len, cached_texture); gf_fclose(cached_texture); } /*and write cache info*/ if (ct->expirationDate!=0) { sprintf(section, "@cache=%p", ct); gf_cfg_set_key(txh->compositor->user->config, section, "serviceURL", src_url); gf_cfg_set_key(txh->compositor->user->config, section, "cacheFile", szExtractName); gf_cfg_set_key(txh->compositor->user->config, section, "cacheName", ct->cacheURL.buffer); if (ct->expirationDate>0) { char exp[50]; u32 sec, frac; gf_net_get_ntp(&sec, &frac); sec += ct->expirationDate; sprintf(exp, "%u", sec); gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", exp); } else { gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", "0"); } } } /*done with image, destroy buffer*/ if (ct->data) gf_free(ct->data); ct->data = NULL; ct->data_len = 0; } } }
static Bool compositor_handle_navigation_3d(GF_Compositor *compositor, GF_Event *ev) { Fixed x, y, trans_scale; Fixed dx, dy, key_trans, key_pan, key_exam; s32 key_inv; u32 keys; #ifdef SCALE_NAV Bool is_pixel_metrics; #endif GF_Camera *cam; Fixed zoom = compositor->zoom; cam = NULL; #ifndef GPAC_DISABLE_VRML if (compositor->active_layer) { cam = compositor_layer3d_get_camera(compositor->active_layer); #ifdef SCALE_NAV is_pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(compositor->active_layer)); #endif } #endif if (!cam) { cam = &compositor->visual->camera; assert(compositor); assert(compositor->scene); #ifdef SCALE_NAV is_pixel_metrics = compositor->traverse_state->pixel_metrics; #endif } if (!cam || (cam->navigate_mode==GF_NAVIGATE_NONE)) return 0; keys = compositor->key_states; if (!cam->navigate_mode && !(keys & GF_KEY_MOD_ALT) ) return 0; x = y = 0; /*renorm between -1, 1*/ if (ev->type<=GF_EVENT_MOUSEWHEEL) { x = gf_divfix( INT2FIX(ev->mouse.x - (s32) compositor->visual->width/2), INT2FIX(compositor->visual->width)); y = gf_divfix( INT2FIX(ev->mouse.y - (s32) compositor->visual->height/2), INT2FIX(compositor->visual->height)); } dx = (x - compositor->grab_x); dy = (compositor->grab_y - y); #ifdef SCALE_NAV trans_scale = is_pixel_metrics ? cam->width/2 : INT2FIX(10); key_trans = is_pixel_metrics ? INT2FIX(10) : cam->avatar_size.x; #else trans_scale = cam->width/20; key_trans = cam->avatar_size.x/2; //if default VP is quite far from center use larger dz/dy moves if (cam->vp_dist>100) trans_scale *= 10; #endif if (cam->world_bbox.is_set && (key_trans*5 > cam->world_bbox.radius)) { key_trans = cam->world_bbox.radius / 100; } key_pan = FIX_ONE/25; key_exam = FIX_ONE/20; key_inv = 1; if (keys & GF_KEY_MOD_SHIFT) { dx *= 4; dy *= 4; key_pan *= 4; key_exam *= 4; key_trans*=4; } switch (ev->type) { case GF_EVENT_MOUSEDOWN: /*left*/ if (ev->mouse.button==GF_MOUSE_LEFT) { compositor->grab_x = x; compositor->grab_y = y; compositor->navigation_state = 1; /*change vp and examine center to current location*/ if ((keys & GF_KEY_MOD_CTRL) && compositor->hit_square_dist) { cam->vp_position = cam->position; cam->vp_orientation = camera_get_orientation(cam->position, cam->target, cam->up); cam->vp_fov = cam->fieldOfView; cam->examine_center = compositor->hit_world_point; camera_changed(compositor, cam); return 1; } } /*right*/ else if (ev->mouse.button==GF_MOUSE_RIGHT) { if (compositor->navigation_state && (cam->navigate_mode==GF_NAVIGATE_WALK)) { camera_jump(cam); gf_sc_invalidate(compositor, NULL); return 1; } else if (keys & GF_KEY_MOD_CTRL) gf_sc_fit_world_to_screen(compositor); } break; /* note: shortcuts are mostly the same as blaxxun contact, I don't feel like remembering 2 sets...*/ case GF_EVENT_MOUSEMOVE: if (!compositor->navigation_state) { if (cam->navigate_mode==GF_NAVIGATE_GAME) { /*init mode*/ compositor->grab_x = x; compositor->grab_y = y; compositor->navigation_state = 1; } return 0; } compositor->navigation_state++; switch (cam->navigate_mode) { /*FIXME- we'll likely need a "step" value for walk at some point*/ case GF_NAVIGATE_WALK: case GF_NAVIGATE_FLY: view_pan_x(compositor, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_pan_y(compositor, cam, dy); else view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); break; case GF_NAVIGATE_VR: view_pan_x(compositor, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_zoom(compositor, cam, dy); else view_pan_y(compositor, cam, dy); break; case GF_NAVIGATE_PAN: view_pan_x(compositor, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); else view_pan_y(compositor, cam, dy); break; case GF_NAVIGATE_SLIDE: view_translate_x(compositor, cam, gf_mulfix(dx, trans_scale)); if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); else view_translate_y(compositor, cam, gf_mulfix(dy, trans_scale)); break; case GF_NAVIGATE_EXAMINE: if (keys & GF_KEY_MOD_CTRL) { view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); view_roll(compositor, cam, gf_mulfix(dx, trans_scale)); } else { if (ABS(dx) > ABS(dy)) { view_exam_x(compositor, cam, -gf_mulfix(GF_PI, dx)); } else { view_exam_y(compositor, cam, gf_mulfix(GF_PI, dy)); } } break; case GF_NAVIGATE_ORBIT: if (keys & GF_KEY_MOD_CTRL) { view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); } else { view_orbit_x(compositor, cam, -gf_mulfix(GF_PI, dx)); view_orbit_y(compositor, cam, gf_mulfix(GF_PI, dy)); } break; case GF_NAVIGATE_GAME: view_pan_x(compositor, cam, -dx); view_pan_y(compositor, cam, dy); break; } compositor->grab_x = x; compositor->grab_y = y; return 1; case GF_EVENT_MOUSEWHEEL: switch (cam->navigate_mode) { /*FIXME- we'll likely need a "step" value for walk at some point*/ case GF_NAVIGATE_WALK: case GF_NAVIGATE_FLY: view_pan_y(compositor, cam, gf_mulfix(key_pan, ev->mouse.wheel_pos)); break; case GF_NAVIGATE_VR: view_zoom(compositor, cam, gf_mulfix(key_pan, ev->mouse.wheel_pos)); break; case GF_NAVIGATE_SLIDE: case GF_NAVIGATE_EXAMINE: case GF_NAVIGATE_ORBIT: case GF_NAVIGATE_PAN: if (cam->is_3D) { view_translate_z(compositor, cam, gf_mulfix(trans_scale, ev->mouse.wheel_pos) * ((keys & GF_KEY_MOD_SHIFT) ? 4 : 1)); } else { nav_set_zoom_trans_2d(compositor->visual, zoom + INT2FIX(ev->mouse.wheel_pos)/10, 0, 0); } } return 1; case GF_EVENT_MOUSEUP: if (ev->mouse.button==GF_MOUSE_LEFT) compositor->navigation_state = 0; break; case GF_EVENT_KEYDOWN: switch (ev->key.key_code) { case GF_KEY_BACKSPACE: gf_sc_reset_graphics(compositor); return 1; case GF_KEY_C: compositor->collide_mode = compositor->collide_mode ? GF_COLLISION_NONE : GF_COLLISION_DISPLACEMENT; return 1; case GF_KEY_J: if (cam->navigate_mode==GF_NAVIGATE_WALK) { camera_jump(cam); gf_sc_invalidate(compositor, NULL); return 1; } break; case GF_KEY_HOME: if (!compositor->navigation_state) { compositor->visual->camera.start_zoom = compositor->zoom; compositor->zoom = FIX_ONE; compositor->interoccular_offset = 0; compositor->focus_distance = 0; compositor->interoccular_offset = 0; compositor->focus_distance = 0; compositor_3d_reset_camera(compositor); } break; case GF_KEY_END: if (cam->navigate_mode==GF_NAVIGATE_GAME) { cam->navigate_mode = GF_NAVIGATE_WALK; compositor->navigation_state = 0; return 1; } break; case GF_KEY_LEFT: key_inv = -1; case GF_KEY_RIGHT: if (keys & GF_KEY_MOD_ALT) { if ( (keys & GF_KEY_MOD_SHIFT) && (compositor->visual->nb_views > 1) ) { /*+ or - 10 cm*/ compositor->focus_distance += INT2FIX(key_inv); cam->flags |= CAM_IS_DIRTY; fprintf(stderr, "AutoStereo view distance %f - focus %f\n", FIX2FLT(compositor->video_out->view_distance)/100, FIX2FLT(compositor->focus_distance)/100); gf_sc_invalidate(compositor, NULL); return 1; } return 0; } switch (cam->navigate_mode) { case GF_NAVIGATE_SLIDE: if (keys & GF_KEY_MOD_CTRL) view_pan_x(compositor, cam, key_inv * key_pan); else view_translate_x(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_EXAMINE: if (keys & GF_KEY_MOD_CTRL) view_roll(compositor, cam, gf_mulfix(dx, trans_scale)); else view_exam_x(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_ORBIT: if (keys & GF_KEY_MOD_CTRL) view_translate_x(compositor, cam, key_inv * key_trans); else view_orbit_x(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_GAME: view_translate_x(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_VR: view_pan_x(compositor, cam, -key_inv * key_pan); break; /*walk/fly/pan*/ default: if (keys & GF_KEY_MOD_CTRL) view_translate_x(compositor, cam, key_inv * key_trans); else view_pan_x(compositor, cam, -key_inv * key_pan); break; } return 1; case GF_KEY_DOWN: key_inv = -1; case GF_KEY_UP: if (keys & GF_KEY_MOD_ALT) { if ( (keys & GF_KEY_MOD_SHIFT) && (compositor->visual->nb_views > 1) ) { compositor->interoccular_offset += FLT2FIX(0.5) * key_inv; fprintf(stderr, "AutoStereo interoccular distance %f\n", FIX2FLT(compositor->interoccular_distance + compositor->interoccular_offset)); cam->flags |= CAM_IS_DIRTY; gf_sc_invalidate(compositor, NULL); return 1; } return 0; } switch (cam->navigate_mode) { case GF_NAVIGATE_SLIDE: if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, key_inv * key_trans); else view_translate_y(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_EXAMINE: if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, key_inv * key_trans); else view_exam_y(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_ORBIT: if (keys & GF_KEY_MOD_CTRL) view_translate_y(compositor, cam, key_inv * key_trans); else view_orbit_y(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_PAN: if (keys & GF_KEY_MOD_CTRL) view_translate_y(compositor, cam, key_inv * key_trans); else view_pan_y(compositor, cam, key_inv * key_pan); break; case GF_NAVIGATE_GAME: view_translate_z(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_VR: if (keys & GF_KEY_MOD_CTRL) view_zoom(compositor, cam, key_inv * key_pan); else view_pan_y(compositor, cam, key_inv * key_pan); break; /*walk/fly*/ default: if (keys & GF_KEY_MOD_CTRL) view_pan_y(compositor, cam, key_inv * key_pan); else view_translate_z(compositor, cam, key_inv * key_trans); break; } return 1; case GF_KEY_PAGEDOWN: if (keys & GF_KEY_MOD_CTRL) { view_zoom(compositor, cam, FIX_ONE/10); return 1; } break; case GF_KEY_PAGEUP: if (keys & GF_KEY_MOD_CTRL) { view_zoom(compositor, cam, -FIX_ONE/10); return 1; } break; } break; } return 0; }
GF_EXPORT GF_MediaObject *gf_mo_register(GF_Node *node, MFURL *url, Bool lock_timelines, Bool force_new_res) { u32 obj_type; #ifndef GPAC_DISABLE_SVG Bool post_pone; GF_FieldInfo info; #endif GF_Scene *scene; GF_MediaObject *res, *syncRef; GF_SceneGraph *sg = gf_node_get_graph(node); if (!sg) return NULL; scene = (GF_Scene*)gf_sg_get_private(sg); if (!scene) return NULL; syncRef = NULL; /*keep track of the kind of object expected if URL is not using OD scheme*/ switch (gf_node_get_tag(node)) { #ifndef GPAC_DISABLE_VRML /*MPEG-4 / VRML / X3D only*/ case TAG_MPEG4_AudioClip: case TAG_MPEG4_AudioSource: #ifndef GPAC_DISABLE_X3D case TAG_X3D_AudioClip: #endif obj_type = GF_MEDIA_OBJECT_AUDIO; break; case TAG_MPEG4_SBVCAnimation: case TAG_MPEG4_AnimationStream: obj_type = GF_MEDIA_OBJECT_UPDATES; break; case TAG_MPEG4_BitWrapper: obj_type = GF_MEDIA_OBJECT_SCENE; break; case TAG_MPEG4_InputSensor: obj_type = GF_MEDIA_OBJECT_INTERACT; break; case TAG_MPEG4_Background2D: case TAG_MPEG4_Background: case TAG_MPEG4_ImageTexture: case TAG_MPEG4_CacheTexture: case TAG_MPEG4_MovieTexture: #ifndef GPAC_DISABLE_X3D case TAG_X3D_Background: case TAG_X3D_ImageTexture: case TAG_X3D_MovieTexture: #endif obj_type = GF_MEDIA_OBJECT_VIDEO; break; case TAG_MPEG4_Inline: #ifndef GPAC_DISABLE_X3D case TAG_X3D_Inline: #endif obj_type = GF_MEDIA_OBJECT_SCENE; break; #endif /*GPAC_DISABLE_VRML*/ /*SVG*/ #ifndef GPAC_DISABLE_SVG case TAG_SVG_audio: obj_type = GF_MEDIA_OBJECT_AUDIO; if (gf_node_get_attribute_by_tag(node, TAG_SVG_ATT_syncReference, GF_FALSE, GF_FALSE, &info)==GF_OK) { syncRef = get_sync_reference(scene, (XMLRI *)info.far_ptr, GF_MEDIA_OBJECT_UNDEF, node, &post_pone); /*syncRef is specified but doesn't exist yet, post-pone*/ if (post_pone) return NULL; } break; case TAG_SVG_video: obj_type = GF_MEDIA_OBJECT_VIDEO; if (gf_node_get_attribute_by_tag(node, TAG_SVG_ATT_syncReference, GF_FALSE, GF_FALSE, &info)==GF_OK) { syncRef = get_sync_reference(scene, (XMLRI *)info.far_ptr, GF_MEDIA_OBJECT_UNDEF, node, &post_pone); /*syncRef is specified but doesn't exist yet, post-pone*/ if (post_pone) return NULL; } break; case TAG_SVG_image: obj_type = GF_MEDIA_OBJECT_VIDEO; break; case TAG_SVG_foreignObject: case TAG_SVG_animation: obj_type = GF_MEDIA_OBJECT_SCENE; break; case TAG_LSR_updates: obj_type = GF_MEDIA_OBJECT_UPDATES; break; #endif default: obj_type = GF_MEDIA_OBJECT_UNDEF; break; } /*move to primary resource handler*/ while (scene->secondary_resource && scene->root_od->parentscene) scene = scene->root_od->parentscene; res = gf_scene_get_media_object_ex(scene, url, obj_type, lock_timelines, syncRef, force_new_res, node); return res; }
static void UpdateComposite2D(GF_TextureHandler *txh) { GF_Err e; u32 i; SensorHandler *hsens; RenderEffect2D *eff; M_CompositeTexture2D *ct2D = (M_CompositeTexture2D *)txh->owner; Composite2DStack *st = (Composite2DStack *) gf_node_get_private(txh->owner); GF_Raster2D *r2d = st->surf->render->compositor->r2d; if (!gf_node_dirty_get(txh->owner)) { txh->needs_refresh = 0; return; } /*rebuild stencil*/ if (!st->surf->the_surface || !txh->hwtx || ((s32) st->width != ct2D->pixelWidth) || ( (s32) st->height != ct2D->pixelHeight) ) { if (txh->hwtx) r2d->stencil_delete(txh->hwtx); txh->hwtx = NULL; if (ct2D->pixelWidth<=0) return; if (ct2D->pixelHeight<=0) return; st->width = ct2D->pixelWidth; st->height = ct2D->pixelHeight; txh->hwtx = r2d->stencil_new(r2d, GF_STENCIL_TEXTURE); e = r2d->stencil_create_texture(txh->hwtx, st->width, st->height, GF_PIXEL_ARGB); if (e) { if (txh->hwtx) r2d->stencil_delete(txh->hwtx); txh->hwtx = NULL; } } if (!txh->hwtx) return; GF_SAFEALLOC(eff, RenderEffect2D); eff->sensors = gf_list_new(); eff->surface = st->surf; if (st->surf->render->top_effect->trav_flags & TF_RENDER_DIRECT) { eff->trav_flags = TF_RENDER_DIRECT; } gf_mx2d_init(eff->transform); gf_cmx_init(&eff->color_mat); st->surf->width = st->width; st->surf->height = st->height; eff->back_stack = st->surf->back_stack; eff->view_stack = st->surf->view_stack; eff->is_pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner)); eff->min_hsize = INT2FIX( MIN(st->width, st->height) ) / 2; Composite_CheckBindables(st->txh.owner, eff, st->first); st->first = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Entering CompositeTexture2D Render Cycle\n")); e = VS2D_InitDraw(st->surf, eff); if (e) { effect_delete(eff); return; } /*render children*/ if (gf_node_dirty_get(st->txh.owner) & GF_SG_NODE_DIRTY) { GF_ChildNodeItem *l = ct2D->children; /*rebuild sensor list */ if (gf_list_count(st->sensors)) { gf_list_del(st->sensors); st->sensors = gf_list_new(); } while (l) { if (l->node && is_sensor_node(l->node) ) { hsens = get_sensor_handler(l->node); if (hsens) gf_list_add(st->sensors, hsens); } l = l->next; } /*if we have an active sensor at this level discard all sensors in current render context (cf VRML)*/ if (gf_list_count(st->sensors)) { effect_reset_sensors(eff); } } /*add sensor to effects*/ i=0; while ((hsens = (SensorHandler*)gf_list_enum(st->sensors, &i))) { effect_add_sensor(eff, hsens, &eff->transform); } gf_node_dirty_clear(st->txh.owner, 0); /*render*/ gf_node_render_children(st->txh.owner, eff); /*finalize draw*/ txh->needs_refresh = VS2D_TerminateDraw(st->surf, eff); st->txh.transparent = st->surf->last_had_back ? 0 : 1; /* st->txh.active_window.x = 0; st->txh.active_window.y = 0; st->txh.active_window.width = st->width; st->txh.active_window.height = st->height; */ st->txh.width = st->width; st->txh.height = st->height; /*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/ if (gf_list_count(st->surf->view_stack)) { M_Viewport *vp = (M_Viewport *)gf_list_get(st->surf->view_stack, 0); if (vp->isBound) { SFVec2f size = vp->size; if (size.x >=0 && size.y>=0) { /* st->txh.active_window.width = size.x; st->txh.active_window.height = size.y; st->txh.active_window.x = (st->width - size.x) / 2; st->txh.active_window.y = (st->height - size.y) / 2; */ /*FIXME - we need tracking of VP changes*/ txh->needs_refresh = 1; } } } if (txh->needs_refresh) { if (r2d->stencil_texture_modified) r2d->stencil_texture_modified(st->txh.hwtx); gf_sr_invalidate(st->txh.compositor, NULL); } effect_delete(eff); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Leaving CompositeTexture2D Render Cycle\n")); }