void compositor_imagetexture_modified(GF_Node *node) { MFURL url; SFURL sfurl; GF_TextureHandler *txh = (GF_TextureHandler *) gf_node_get_private(node); if (!txh) return; if (gf_node_get_tag(node)!=TAG_MPEG4_CacheTexture) { url = ((M_ImageTexture *) node)->url; } else { url.count = 1; sfurl.OD_ID=GF_MEDIA_EXTERNAL_ID; sfurl.url = ((M_CacheTexture *) node)->image.buffer; url.vals = &sfurl; } /*if open and changed, stop and play*/ if (txh->is_open) { if (! gf_sc_texture_check_url_change(txh, &url)) return; gf_sc_texture_stop(txh); gf_sc_texture_play(txh, &url); return; } /*if not open and changed play*/ if (url.count) gf_sc_texture_play(txh, &url); }
static void back_check_gf_sc_texture_change(GF_TextureHandler *txh, MFURL *url) { /*if open and changed, stop and play*/ if (txh->is_open) { if (! gf_sc_texture_check_url_change(txh, url)) return; gf_sc_texture_stop(txh); gf_sc_texture_play(txh, url); return; } /*if not open and changed play*/ if (url->count) gf_sc_texture_play(txh, url); }
void compositor_background2d_modified(GF_Node *node) { M_Background2D *bck = (M_Background2D *)node; Background2DStack *st = (Background2DStack *) gf_node_get_private(node); if (!st) return; /*dirty node and parents in order to trigger parent visual redraw*/ gf_node_dirty_set(node, 0, 1); /*if open and changed, stop and play*/ if (st->txh.is_open) { if (! gf_sc_texture_check_url_change(&st->txh, &bck->url)) return; gf_sc_texture_stop(&st->txh); gf_sc_texture_play(&st->txh, &bck->url); return; } /*if not open and changed play*/ if (bck->url.count) gf_sc_texture_play(&st->txh, &bck->url); gf_sc_invalidate(st->txh.compositor, NULL); }
static void movietexture_update_time(GF_TimeNode *st) { Double time; M_MovieTexture *mt = (M_MovieTexture *)st->udta; MovieTextureStack *stack = (MovieTextureStack *)gf_node_get_private(st->udta); /*not active, store start time and speed*/ if ( ! mt->isActive) { stack->start_time = mt->startTime; } time = gf_node_get_scene_time(st->udta); if (time < stack->start_time || /*special case if we're getting active AFTER stoptime */ (!mt->isActive && (mt->stopTime > stack->start_time) && (time>=mt->stopTime)) // || (!stack->start_time && !stack->is_x3d && !mt->loop) ) { /*opens stream only at first access to fetch first frame*/ if (stack->fetch_first_frame) { stack->fetch_first_frame = 0; if (!stack->txh.is_open) gf_sc_texture_play(&stack->txh, &mt->url); else gf_mo_resume(stack->txh.stream); } return; } if (movietexture_get_speed(stack, mt) && mt->isActive) { /*if stoptime is reached (>startTime) deactivate*/ if ((mt->stopTime > stack->start_time) && (time >= mt->stopTime) ) { movietexture_deactivate(stack, mt); return; } } /*we're (about to be) active: VRML: "A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active */ if (! mt->isActive) movietexture_activate(stack, mt, time); stack->txh.stream_finished = GF_FALSE; }
void compositor_movietexture_modified(GF_Node *node) { M_MovieTexture *mt = (M_MovieTexture *)node; MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(node); if (!st) return; /*if open and changed, stop and play*/ if (gf_sc_texture_check_url_change(&st->txh, &mt->url)) { if (st->txh.is_open) gf_sc_texture_stop(&st->txh); if (mt->isActive) gf_sc_texture_play(&st->txh, &mt->url); } /*update state if we're active*/ else if (mt->isActive) { movietexture_update_time(&st->time_handle); if (!mt->isActive) return; } /*reregister if needed*/ st->time_handle.needs_unregister = 0; if (!st->time_handle.is_registered) gf_sc_register_time_node(st->txh.compositor, &st->time_handle); }
static void TraverseBackground2D(GF_Node *node, void *rs, Bool is_destroy) { u32 col; BackgroundStatus *status; M_Background2D *bck; Background2DStack *stack = (Background2DStack *) gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { DestroyBackground2D(node); return; } bck = (M_Background2D *)node; /*special case for background in Layer2D: the background is seen as a regular drawable, so RENDER_BINDABLE is not used*/ switch (tr_state->traversing_mode) { case TRAVERSE_DRAW_2D: DrawBackground2D_2D(tr_state->ctx, tr_state); return; case TRAVERSE_PICK: case TRAVERSE_GET_BOUNDS: return; } /*first traverse, bound if needed*/ if (gf_list_find(tr_state->backgrounds, node) < 0) { M_Background2D *top_bck = (M_Background2D *)node; gf_list_add(tr_state->backgrounds, node); assert(gf_list_find(stack->reg_stacks, tr_state->backgrounds)==-1); gf_list_add(stack->reg_stacks, tr_state->backgrounds); b2D_new_status(stack, bck); /*only bound if we're on top*/ top_bck = gf_list_get(tr_state->backgrounds, 0); if (!bck->isBound) { if (top_bck== bck) { Bindable_SetIsBound(node, 1); } else if (!top_bck->isBound) { bck->set_bind = 1; bck->on_set_bind(node, NULL); } } /*open the stream if any*/ if (back_use_texture(bck) && !stack->txh.is_open) gf_sc_texture_play(&stack->txh, &bck->url); /*in any case don't draw the first time (since the background could have been declared last)*/ gf_sc_invalidate(stack->txh.compositor, NULL); return; } if (!bck->isBound) return; status = b2d_get_status(stack, tr_state->backgrounds); if (!status) return; if (gf_node_dirty_get(node)) { stack->flags |= CTX_APP_DIRTY; gf_node_dirty_clear(node, 0); col = GF_COL_ARGB_FIXED(FIX_ONE, bck->backColor.red, bck->backColor.green, bck->backColor.blue); if (col != status->ctx.aspect.fill_color) { status->ctx.aspect.fill_color = col; stack->flags |= CTX_APP_DIRTY; } } if (back_use_texture(bck) ) { if (stack->txh.tx_io && !(status->ctx.flags & CTX_APP_DIRTY) && stack->txh.needs_refresh) stack->flags |= CTX_TEXTURE_DIRTY; } status->ctx.flags = stack->flags; if (tr_state->traversing_mode != TRAVERSE_BINDABLE) return; /*3D mode*/ #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { DrawBackground2D_3D(bck, stack, tr_state); } else #endif DrawBackground2D_2D(&status->ctx, tr_state); }
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 void TraverseBackground(GF_Node *node, void *rs, Bool is_destroy) { M_Background *bck; BackgroundStack *st; SFColor bcol; SFVec4f res; Fixed scale; Bool has_sky, has_ground, front_tx, back_tx, top_tx, bottom_tx, right_tx, left_tx; GF_Matrix mx; GF_Compositor *compositor; GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { DestroyBackground(node); return; } gf_node_dirty_clear(node, 0); bck = (M_Background *)node; st = (BackgroundStack *) gf_node_get_private(node); compositor = (GF_Compositor*)st->compositor; /*may happen in get_bounds*/ if (!tr_state->backgrounds) return; /*first traverse, bound if needed*/ if (gf_list_find(tr_state->backgrounds, node) < 0) { gf_list_add(tr_state->backgrounds, node); assert(gf_list_find(st->reg_stacks, tr_state->backgrounds)==-1); gf_list_add(st->reg_stacks, tr_state->backgrounds); /*only bound if we're on top*/ if (gf_list_get(tr_state->backgrounds, 0) == bck) { if (!bck->isBound) Bindable_SetIsBound(node, 1); } /*check streams*/ if (back_use_texture(&bck->frontUrl) && !st->txh_front.is_open) gf_sc_texture_play(&st->txh_front, &bck->frontUrl); if (back_use_texture(&bck->bottomUrl) && !st->txh_bottom.is_open) gf_sc_texture_play(&st->txh_bottom, &bck->bottomUrl); if (back_use_texture(&bck->backUrl) && !st->txh_back.is_open) gf_sc_texture_play(&st->txh_back, &bck->backUrl); if (back_use_texture(&bck->topUrl) && !st->txh_top.is_open) gf_sc_texture_play(&st->txh_top, &bck->topUrl); if (back_use_texture(&bck->rightUrl) && !st->txh_right.is_open) gf_sc_texture_play(&st->txh_right, &bck->rightUrl); if (back_use_texture(&bck->leftUrl) && !st->txh_left.is_open) gf_sc_texture_play(&st->txh_left, &bck->leftUrl); /*in any case don't draw the first time (since the background could have been declared last)*/ gf_sc_invalidate(st->compositor, NULL); return; } if (!bck->isBound) return; if (tr_state->traversing_mode != TRAVERSE_BINDABLE) { if (tr_state->traversing_mode == TRAVERSE_SORT) { gf_mx_copy(st->current_mx, tr_state->model_matrix); } return; } front_tx = back_gf_sc_texture_enabled(&bck->frontUrl, &st->txh_front); back_tx = back_gf_sc_texture_enabled(&bck->backUrl, &st->txh_back); top_tx = back_gf_sc_texture_enabled(&bck->topUrl, &st->txh_top); bottom_tx = back_gf_sc_texture_enabled(&bck->bottomUrl, &st->txh_bottom); right_tx = back_gf_sc_texture_enabled(&bck->rightUrl, &st->txh_right); left_tx = back_gf_sc_texture_enabled(&bck->leftUrl, &st->txh_left); has_sky = ((bck->skyColor.count>1) && bck->skyAngle.count) ? 1 : 0; has_ground = ((bck->groundColor.count>1) && bck->groundAngle.count) ? 1 : 0; bcol.red = bcol.green = bcol.blue = 0; if (bck->skyColor.count) bcol = bck->skyColor.vals[0]; /*if we clear the main visual clear it entirely - ONLY IF NOT IN LAYER*/ if ((tr_state->visual == compositor->visual) && (tr_state->visual->back_stack == tr_state->backgrounds)) { visual_3d_clear(tr_state->visual, bcol, FIX_ONE); if (!has_sky && !has_ground && !front_tx && !back_tx && !top_tx && !bottom_tx && !left_tx && !right_tx) { return; } } /*undo translation*/ res.x = res.y = res.z = 0; res.q = FIX_ONE; gf_mx_apply_vec_4x4(&tr_state->camera->unprojection, &res); assert(res.q); res.x = gf_divfix(res.x, res.q); res.y = gf_divfix(res.y, res.q); res.z = gf_divfix(res.z, res.q); /*NB: we don't support local rotation of the background ...*/ /*enable background state (turn off all quality options)*/ visual_3d_set_background_state(tr_state->visual, 1); if (has_sky) { GF_Matrix bck_mx; gf_mx_copy(bck_mx, tr_state->model_matrix); gf_mx_copy(tr_state->model_matrix, st->current_mx); if (!st->sky_mesh) { st->sky_mesh = new_mesh(); back_build_dome(st->sky_mesh, &bck->skyAngle, &bck->skyColor, 0); } gf_mx_init(mx); gf_mx_add_translation(&mx, res.x, res.y, res.z); /*CHECKME - not sure why, we need to scale less in fixed point otherwise z-far clipping occur - probably some rounding issues...*/ #ifdef GPAC_FIXED_POINT scale = (tr_state->camera->z_far/10)*8; #else scale = 9*tr_state->camera->z_far/10; #endif gf_mx_add_scale(&mx, scale, scale, scale); gf_mx_add_matrix(&tr_state->model_matrix, &mx); visual_3d_mesh_paint(tr_state, st->sky_mesh); gf_mx_copy(tr_state->model_matrix, bck_mx); } if (has_ground) { GF_Matrix bck_mx; gf_mx_copy(bck_mx, tr_state->model_matrix); gf_mx_copy(tr_state->model_matrix, st->current_mx); if (!st->ground_mesh) { st->ground_mesh = new_mesh(); back_build_dome(st->ground_mesh, &bck->groundAngle, &bck->groundColor, 1); } gf_mx_init(mx); gf_mx_add_translation(&mx, res.x, res.y, res.z); /*cf above*/ #ifdef GPAC_FIXED_POINT scale = (tr_state->camera->z_far/100)*70; #else scale = 85*tr_state->camera->z_far/100; #endif gf_mx_add_scale(&mx, scale, -scale, scale); gf_mx_add_matrix(&tr_state->model_matrix, &mx); visual_3d_mesh_paint(tr_state, st->ground_mesh); gf_mx_copy(tr_state->model_matrix, bck_mx); } if (front_tx || back_tx || left_tx || right_tx || top_tx || bottom_tx) { GF_Matrix bck_mx; gf_mx_copy(bck_mx, tr_state->model_matrix); gf_mx_copy(tr_state->model_matrix, st->current_mx); gf_mx_init(mx); gf_mx_add_translation(&mx, res.x, res.y, res.z); #ifdef GPAC_FIXED_POINT scale = (tr_state->camera->z_far/100)*99; gf_mx_add_scale(&mx, scale, scale, scale); #else gf_mx_add_scale(&mx, tr_state->camera->z_far, tr_state->camera->z_far, tr_state->camera->z_far); #endif visual_3d_enable_antialias(tr_state->visual, 1); gf_mx_add_matrix(&tr_state->model_matrix, &mx); if (front_tx) back_draw_texture(tr_state, &st->txh_front, st->front_mesh); if (back_tx) back_draw_texture(tr_state, &st->txh_back, st->back_mesh); if (top_tx) back_draw_texture(tr_state, &st->txh_top, st->top_mesh); if (bottom_tx) back_draw_texture(tr_state, &st->txh_bottom, st->bottom_mesh); if (left_tx) back_draw_texture(tr_state, &st->txh_left, st->left_mesh); if (right_tx) back_draw_texture(tr_state, &st->txh_right, st->right_mesh); gf_mx_copy(tr_state->model_matrix, bck_mx); } /*enable background state (turn off all quality options)*/ visual_3d_set_background_state(tr_state->visual, 0); }