void compositor_svg_apply_local_transformation(GF_TraverseState *tr_state, SVGAllAttributes *atts, GF_Matrix2D *backup_matrix_2d, GF_Matrix *backup_matrix) { #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d && backup_matrix) { GF_Matrix tmp; Bool is_draw = (tr_state->traversing_mode==TRAVERSE_SORT) ? 1 : 0; gf_mx_copy(*backup_matrix, tr_state->model_matrix); if (is_draw) visual_3d_matrix_push(tr_state->visual); if (atts->transform && atts->transform->is_ref) { gf_mx_from_mx2d(&tr_state->model_matrix, &tr_state->vb_transform); if (is_draw) { GF_Matrix tmp; gf_mx_init(tmp); gf_mx_add_translation(&tmp, -tr_state->camera->width/2, tr_state->camera->height/2, 0); gf_mx_add_scale(&tmp, FIX_ONE, -FIX_ONE, FIX_ONE); gf_mx_add_matrix(&tmp, &tr_state->model_matrix); visual_3d_matrix_load(tr_state->visual, tmp.m); } } if (atts->motionTransform) { if (is_draw) { gf_mx_from_mx2d(&tmp, atts->motionTransform); visual_3d_matrix_add(tr_state->visual, tmp.m); } else { gf_mx_add_matrix_2d(&tr_state->model_matrix, atts->motionTransform); } } if (atts->transform) { if (is_draw) { gf_mx_from_mx2d(&tmp, &atts->transform->mat); visual_3d_matrix_add(tr_state->visual, tmp.m); } else { gf_mx_add_matrix_2d(&tr_state->model_matrix, &atts->transform->mat); } } return; } #endif gf_mx2d_copy(*backup_matrix_2d, tr_state->transform); if (atts->transform && atts->transform->is_ref) gf_mx2d_copy(tr_state->transform, tr_state->vb_transform); if (atts->motionTransform) gf_mx2d_pre_multiply(&tr_state->transform, atts->motionTransform); if (atts->transform) gf_mx2d_pre_multiply(&tr_state->transform, &atts->transform->mat); }
static void traverse_transform(GF_Node *node, Transform2DStack *stack, GF_TraverseState *tr_state) { if (stack->is_null) return; /*note we don't clear dirty flag, this is done in traversing*/ if (stack->is_identity) { group_2d_traverse(node, (GroupingNode2D *)stack, tr_state); } #ifndef GPAC_DISABLE_3D else if (tr_state->visual->type_3d) { GF_Matrix mx_bckup; gf_mx_copy(mx_bckup, tr_state->model_matrix); gf_mx_add_matrix_2d(&tr_state->model_matrix, &stack->mat); if (tr_state->traversing_mode == TRAVERSE_SORT) { GF_Matrix tmp; gf_mx_from_mx2d(&tmp, &stack->mat); visual_3d_matrix_push(tr_state->visual); visual_3d_matrix_add(tr_state->visual, tmp.m); group_2d_traverse(node, (GroupingNode2D *)stack, tr_state); visual_3d_matrix_pop(tr_state->visual); } else { group_2d_traverse(node, (GroupingNode2D *)stack, tr_state); } gf_mx_copy(tr_state->model_matrix, mx_bckup); } #endif else { GF_Matrix2D bckup; gf_mx2d_copy(bckup, tr_state->transform); gf_mx2d_pre_multiply(&tr_state->transform, &stack->mat); group_2d_traverse(node, (GroupingNode2D *)stack, tr_state); gf_mx2d_copy(tr_state->transform, bckup); } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_mx2d_apply_rect(&stack->mat, &tr_state->bounds); } }
static void TraverseSpotLight(GF_Node *n, void *rs, Bool is_destroy) { M_SpotLight *sl = (M_SpotLight *)n; GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { Bool *vis = gf_node_get_private(n); gf_free(vis); return; } if (!sl->on) return; /*store local bounds for culling*/ if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { GF_BBox b; SFVec3f size; Bool *visible = gf_node_get_private(n); size.x = size.y = size.z = sl->radius; gf_vec_add(b.max_edge, sl->location, size); gf_vec_diff(b.min_edge, sl->location, size); gf_bbox_refresh(&b); *visible = visual_3d_node_cull(tr_state, &b, 0); /*if visible, disable culling on our parent branch - this is not very efficient but we only store one bound per grouping node, and we don't want the lights to interfere with it*/ if (*visible) tr_state->disable_cull = 1; return; } else if (tr_state->traversing_mode == TRAVERSE_LIGHTING) { Bool *visible = gf_node_get_private(n); if (*visible) { visual_3d_matrix_push(tr_state->visual); visual_3d_matrix_add(tr_state->visual, tr_state->model_matrix.m); visual_3d_add_spot_light(tr_state->visual, sl->ambientIntensity, sl->attenuation, sl->beamWidth, sl->color, sl->cutOffAngle, sl->direction, sl->intensity, sl->location); visual_3d_matrix_pop(tr_state->visual); } } }
static void TraversePointLight(GF_Node *n, void *rs, Bool is_destroy) { M_PointLight *pl = (M_PointLight *)n; GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { Bool *vis = gf_node_get_private(n); gf_free(vis); return; } if (!pl->on) return; /*store local bounds for culling*/ if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { SFVec3f size; GF_BBox b; Bool *visible = gf_node_get_private(n); size.x = size.y = size.z = pl->radius; gf_vec_add(b.max_edge, pl->location, size); gf_vec_diff(b.min_edge, pl->location, size); gf_bbox_refresh(&b); *visible = visual_3d_node_cull(tr_state, &b, 0); /*if visible, disable culling on our parent branch*/ if (*visible) tr_state->disable_cull = 1; return; } else if (tr_state->traversing_mode == TRAVERSE_LIGHTING) { Bool *visible = gf_node_get_private(n); if (*visible) { visual_3d_matrix_push(tr_state->visual); visual_3d_matrix_add(tr_state->visual, tr_state->model_matrix.m); visual_3d_add_point_light(tr_state->visual, pl->ambientIntensity, pl->attenuation, pl->color, pl->intensity, pl->location); visual_3d_matrix_pop(tr_state->visual); } } }
static void DrawBackground2D_3D(M_Background2D *bck, Background2DStack *st, GF_TraverseState *tr_state) { GF_Matrix mx; Bool use_texture; use_texture = back_texture_enabled(bck, &st->txh); visual_3d_set_background_state(tr_state->visual, 1); visual_3d_matrix_push(tr_state->visual); /* visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_TEXTURE); gf_sc_texture_get_transform(&st->txh, NULL, &mx, 0); visual_3d_matrix_load(tr_state->visual, mx.m); */ visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_MODELVIEW); /*little opt: if we clear the main visual clear it entirely */ if (! tr_state->is_layer) { visual_3d_clear(tr_state->visual, bck->backColor, FIX_ONE); if (!use_texture) { visual_3d_matrix_pop(tr_state->visual); visual_3d_set_background_state(tr_state->visual, 0); return; } /*we need a hack here because main vp is always traversed before main background, and in the case of a 2D viewport it modifies the modelview matrix, which we don't want ...*/ visual_3d_matrix_reset(tr_state->visual); } if (!use_texture || (!tr_state->is_layer && st->txh.transparent) ) visual_3d_set_material_2d(tr_state->visual, bck->backColor, FIX_ONE); if (use_texture) { visual_3d_set_state(tr_state->visual, V3D_STATE_COLOR, ! tr_state->is_layer); tr_state->mesh_num_textures = gf_sc_texture_enable(&st->txh, NULL); if (!tr_state->mesh_num_textures) visual_3d_set_material_2d(tr_state->visual, bck->backColor, FIX_ONE); } /*create mesh object if needed*/ if (!st->mesh) { st->mesh = new_mesh(); mesh_set_vertex(st->mesh, -B2D_PLANE_HSIZE, -B2D_PLANE_HSIZE, 0, 0, 0, FIX_ONE, 0, 0); mesh_set_vertex(st->mesh, B2D_PLANE_HSIZE, -B2D_PLANE_HSIZE, 0, 0, 0, FIX_ONE, FIX_ONE, 0); mesh_set_vertex(st->mesh, B2D_PLANE_HSIZE, B2D_PLANE_HSIZE, 0, 0, 0, FIX_ONE, FIX_ONE, FIX_ONE); mesh_set_vertex(st->mesh, -B2D_PLANE_HSIZE, B2D_PLANE_HSIZE, 0, 0, 0, FIX_ONE, 0, FIX_ONE); mesh_set_triangle(st->mesh, 0, 1, 2); mesh_set_triangle(st->mesh, 0, 2, 3); st->mesh->flags |= MESH_IS_2D; } gf_mx_init(mx); if (tr_state->camera->is_3D) { Fixed sx, sy; /*reset matrix*/ visual_3d_matrix_reset(tr_state->visual); sx = sy = 2 * gf_mulfix(gf_tan(tr_state->camera->fieldOfView/2), tr_state->camera->z_far); if (tr_state->camera->width > tr_state->camera->height) { sx = gf_muldiv(sx, tr_state->camera->width, tr_state->camera->height); } else { sy = gf_muldiv(sy, tr_state->camera->height, tr_state->camera->width); } gf_mx_add_scale(&mx, sx, sy, FIX_ONE); #ifdef GPAC_FIXED_POINT gf_mx_add_translation(&mx, 0, 0, - (tr_state->camera->z_far/100)*99); #else gf_mx_add_translation(&mx, 0, 0, -0.995f*tr_state->camera->z_far); #endif } else { gf_mx_add_scale(&mx, tr_state->bbox.max_edge.x - tr_state->bbox.min_edge.x, tr_state->bbox.max_edge.y - tr_state->bbox.min_edge.y, FIX_ONE); /*when in layer2D, DON'T MOVE BACKGROUND TO ZFAR*/ if (!tr_state->is_layer) { Fixed tr; #ifdef GPAC_FIXED_POINT tr = -(tr_state->camera->z_far/100)*99; #else tr = -0.999f*tr_state->camera->z_far; #endif if (!tr_state->camera->is_3D) tr = -tr; gf_mx_add_translation(&mx, 0, 0, tr); } } visual_3d_matrix_add(tr_state->visual, mx.m); visual_3d_mesh_paint(tr_state, st->mesh); if (tr_state->mesh_num_textures) { gf_sc_texture_disable(&st->txh); tr_state->mesh_num_textures = 0; } visual_3d_matrix_pop(tr_state->visual); visual_3d_set_background_state(tr_state->visual, 0); }
static void TraverseDepthGroup(GF_Node *node, void *rs, Bool is_destroy) { #ifdef GF_SR_USE_DEPTH Fixed depth_gain, depth_offset; #endif DepthGroupStack *stack = (DepthGroupStack *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { gf_free(stack); return; } if (tr_state->traversing_mode==TRAVERSE_SORT) { if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { gf_node_dirty_clear(node, GF_SG_NODE_DIRTY); /*flag is not set for PROTO*/ gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, 0); } } DepthGroup_GetNode(node, &stack->dg); #ifdef GF_SR_USE_DEPTH depth_gain = tr_state->depth_gain; depth_offset = tr_state->depth_offset; // new offset is multiplied by parent gain and added to parent offset tr_state->depth_offset = gf_mulfix(stack->dg.depth_offset, tr_state->depth_gain) + tr_state->depth_offset; // gain is multiplied by parent gain tr_state->depth_gain = gf_mulfix(tr_state->depth_gain, stack->dg.depth_gain); #endif #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { GF_Matrix mx_bckup, mx; gf_mx_copy(mx_bckup, tr_state->model_matrix); gf_mx_init(mx); mx.m[14] = gf_mulfix(stack->dg.depth_offset, tr_state->visual->compositor->depth_gl_scale); gf_mx_add_matrix(&tr_state->model_matrix, &mx); if (tr_state->traversing_mode == TRAVERSE_SORT) { visual_3d_matrix_push(tr_state->visual); visual_3d_matrix_add(tr_state->visual, mx.m); group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state); visual_3d_matrix_pop(tr_state->visual); } else { group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state); } gf_mx_copy(tr_state->model_matrix, mx_bckup); } else #endif { group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state); } #ifdef GF_SR_USE_DEPTH tr_state->depth_gain = depth_gain; tr_state->depth_offset = depth_offset; #endif }
static void TraverseLayer2D(GF_Node *node, void *rs, Bool is_destroy) { GF_List *oldb, *oldv; GF_Node *viewport; GF_Node *back; Bool prev_layer; GF_Matrix2D backup; SFVec2f prev_vp; #ifndef GPAC_DISABLE_3D GF_Matrix mx3d; GF_List *oldf, *oldn; GF_List *node_list_backup; GF_Rect prev_clipper; Bool had_clip; #endif M_Layer2D *l = (M_Layer2D *)node; Layer2DStack *st = (Layer2DStack *) gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { gf_list_del(st->backs); gf_list_del(st->views); group_2d_destroy(node, (GroupingNode2D*)st); gf_free(st); return; } /*layers can only be used in a 2D context*/ #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d && tr_state->camera->is_3D) return; #endif /*layer2D maintains its own stacks*/ oldb = tr_state->backgrounds; oldv = tr_state->viewpoints; tr_state->backgrounds = st->backs; tr_state->viewpoints = st->views; prev_layer = tr_state->is_layer; tr_state->is_layer = 1; #ifndef GPAC_DISABLE_3D oldf = tr_state->fogs; oldn = tr_state->navigations; tr_state->fogs = tr_state->navigations = NULL; #endif l2d_CheckBindables(node, tr_state, st->first); back = (GF_Node*)gf_list_get(st->backs, 0); viewport = (GF_Node*)gf_list_get(st->views, 0); if ((tr_state->traversing_mode == TRAVERSE_SORT) || (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS)) { /*override group bounds*/ visual_get_size_info(tr_state, &st->clip.width, &st->clip.height); /*setup bounds in local coord system*/ if (l->size.x>=0) st->clip.width = l->size.x; if (l->size.y>=0) st->clip.height = l->size.y; st->clip = gf_rect_center(st->clip.width, st->clip.height); st->bounds = st->clip; } prev_vp = tr_state->vp_size; tr_state->vp_size.x = st->clip.width; tr_state->vp_size.y = st->clip.height; switch (tr_state->traversing_mode) { case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { tr_state->layer_clipper = compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, 1); visual_3d_matrix_push(tr_state->visual); gf_mx_copy(mx3d, tr_state->model_matrix); /*setup clipping*/ visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper); /*apply background BEFORE viewport*/ if (back) { tr_state->traversing_mode = TRAVERSE_BINDABLE; gf_bbox_from_rect(&tr_state->bbox, &st->clip); gf_node_traverse(back, tr_state); } /*sort all children without transform, and use current transform when flushing contexts*/ gf_mx_init(tr_state->model_matrix); /*apply viewport*/ if (viewport) { tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); visual_3d_matrix_add(tr_state->visual, tr_state->model_matrix.m); } node_list_backup = tr_state->visual->alpha_nodes_to_draw; tr_state->visual->alpha_nodes_to_draw = gf_list_new(); tr_state->traversing_mode = TRAVERSE_SORT; /*reset cull flag*/ tr_state->cull_flag = 0; group_2d_traverse(node, (GroupingNode2D *)st, tr_state); visual_3d_flush_contexts(tr_state->visual, tr_state); tr_state->traversing_mode = TRAVERSE_SORT; assert(!gf_list_count(tr_state->visual->alpha_nodes_to_draw)); gf_list_del(tr_state->visual->alpha_nodes_to_draw); tr_state->visual->alpha_nodes_to_draw = node_list_backup; visual_3d_matrix_pop(tr_state->visual); gf_mx_copy(tr_state->model_matrix, mx3d); visual_3d_reset_clipper_2d(tr_state->visual); tr_state->has_layer_clip = had_clip; if (had_clip) { tr_state->layer_clipper = prev_clipper; visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper); } } else #endif { GF_IRect prev_clip; GF_Rect rc; gf_mx2d_copy(backup, tr_state->transform); prev_clip = tr_state->visual->top_clipper; rc = st->clip; /*get clipper in world coordinate*/ gf_mx2d_apply_rect(&tr_state->transform, &rc); if (viewport) { tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); #if VIEWPORT_CLIPS /*move viewport box in world coordinate*/ gf_mx2d_apply_rect(&backup, &tr_state->bounds); /*and intersect with layer clipper*/ rect_intersect(&rc, &tr_state->bounds); #endif } tr_state->visual->top_clipper = gf_rect_pixelize(&rc); gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip); tr_state->traversing_mode = TRAVERSE_SORT; if (tr_state->visual->top_clipper.width && tr_state->visual->top_clipper.height) { if (back && Bindable_GetIsBound(back) ) { DrawableContext *ctx; ctx = b2d_get_context((M_Background2D*) back, st->backs); gf_mx2d_init(ctx->transform); ctx->bi->clip = tr_state->visual->top_clipper; ctx->bi->unclip = rc; if (tr_state->immediate_draw) { tr_state->ctx = ctx; tr_state->traversing_mode = TRAVERSE_DRAW_2D; gf_node_traverse(back, tr_state); tr_state->traversing_mode = TRAVERSE_SORT; tr_state->ctx = NULL; } else { DrawableContext *back_ctx = visual_2d_get_drawable_context(tr_state->visual); gf_node_traverse(back, tr_state); back_ctx->flags = ctx->flags; back_ctx->flags &= ~CTX_IS_TRANSPARENT; back_ctx->flags |= CTX_IS_BACKGROUND; back_ctx->aspect = ctx->aspect; back_ctx->drawable = ctx->drawable; drawable_check_bounds(back_ctx, tr_state->visual); back_ctx->bi->clip = ctx->bi->clip; back_ctx->bi->unclip = ctx->bi->unclip; } /*keep track of node drawn*/ if (!(ctx->drawable->flags & DRAWABLE_REGISTERED_WITH_VISUAL) ) { struct _drawable_store *it; GF_SAFEALLOC(it, struct _drawable_store); it->drawable = ctx->drawable; if (tr_state->visual->last_prev_entry) { tr_state->visual->last_prev_entry->next = it; tr_state->visual->last_prev_entry = it; } else { tr_state->visual->prev_nodes = tr_state->visual->last_prev_entry = it; } GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer2D] Registering new drawn node %s on visual\n", gf_node_get_class_name(it->drawable->node))); ctx->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL; } } group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } tr_state->visual->top_clipper = prev_clip; gf_mx2d_copy(tr_state->transform, backup); } break; /*check picking - we must fall in our 2D clipper*/ case TRAVERSE_PICK: if (gf_sc_pick_in_clipper(tr_state, &st->clip)) { #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { /*apply viewport*/ if (viewport) { gf_mx_copy(mx3d, tr_state->model_matrix); tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); tr_state->traversing_mode = TRAVERSE_PICK; group_2d_traverse(node, (GroupingNode2D *)st, tr_state); gf_mx_copy(tr_state->model_matrix, mx3d); } else { group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } } else #endif { if (viewport) { gf_mx2d_copy(backup, tr_state->transform); tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); tr_state->traversing_mode = TRAVERSE_PICK; group_2d_traverse(node, (GroupingNode2D *)st, tr_state); gf_mx2d_copy(tr_state->transform, backup); } else { group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } } } break; case TRAVERSE_GET_BOUNDS: if (tr_state->for_node) { group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } else { tr_state->bounds = st->clip; #ifndef GPAC_DISABLE_3D gf_bbox_from_rect(&tr_state->bbox, &st->clip); #endif } break; case TRAVERSE_DRAW_2D: group_2d_traverse(node, (GroupingNode2D *)st, tr_state); break; #ifndef GPAC_DISABLE_3D /*drawing a layer means drawing all sub-elements as a whole (no depth sorting with parents)*/ case TRAVERSE_DRAW_3D: assert(0); break; #endif } /*restore traversing state*/ tr_state->vp_size = prev_vp; tr_state->backgrounds = oldb; tr_state->viewpoints = oldv; tr_state->is_layer = prev_layer; #ifndef GPAC_DISABLE_3D tr_state->fogs = oldf; tr_state->navigations = oldn; #endif /*in case we missed bindables*/ if (st->first) { st->first = 0; gf_sc_invalidate(tr_state->visual->compositor, NULL); } }
void compositor_3d_draw_bitmap(Drawable *stack, DrawAspect2D *asp, GF_TraverseState *tr_state, Fixed width, Fixed height, Fixed bmp_scale_x, Fixed bmp_scale_y) { u8 alpha; #if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) Fixed x, y; Fixed sx, sy; char *data; u32 format; #endif GF_TextureHandler *txh; GF_Compositor *compositor = tr_state->visual->compositor; Bool use_texture = !compositor->bitmap_use_pixels; if (!asp->fill_texture) return; txh = asp->fill_texture; if (!txh || !txh->tx_io || !txh->width || !txh->height) return; if (((txh->pixelformat==GF_PIXEL_RGBD) || (txh->pixelformat==GF_PIXEL_YUVD))) { if (compositor->depth_gl_type) { if (txh->data && gf_sc_texture_convert(txh) ) visual_3d_point_sprite(tr_state->visual, stack, txh, tr_state); return; } else { use_texture = 1; } } alpha = GF_COL_A(asp->fill_color); /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/ if (!alpha) alpha = GF_COL_A(asp->line_color); /*texture is available in hw, use it - if blending, force using texture*/ if (!gf_sc_texture_needs_reload(txh) || (alpha != 0xFF) || use_texture #ifdef GF_SR_USE_DEPTH || tr_state->depth_offset #endif ) { visual_3d_set_state(tr_state->visual, V3D_STATE_LIGHT, 0); visual_3d_enable_antialias(tr_state->visual, 0); if (alpha && (alpha != 0xFF)) { visual_3d_set_material_2d_argb(tr_state->visual, GF_COL_ARGB(alpha, 0xFF, 0xFF, 0xFF)); gf_sc_texture_set_blend_mode(txh, TX_MODULATE); } else if (gf_sc_texture_is_transparent(txh)) { gf_sc_texture_set_blend_mode(txh, TX_REPLACE); } else { visual_3d_set_state(tr_state->visual, V3D_STATE_BLEND, 0); } /*ignore texture transform for bitmap*/ tr_state->mesh_num_textures = gf_sc_texture_enable(txh, NULL); if (tr_state->mesh_num_textures) { /*we must check the w & h passed are correct because of bitmap node initialization*/ if (width && height) { if (!stack->mesh) { SFVec2f size; size.x = width; size.y = height; stack->mesh = new_mesh(); mesh_new_rectangle(stack->mesh, size, NULL, 0); } } if (stack->mesh) { #ifdef GF_SR_USE_DEPTH if (tr_state->depth_offset) { GF_Matrix mx; Fixed offset; Fixed disp_depth = (compositor->display_depth<0) ? INT2FIX(tr_state->visual->height) : INT2FIX(compositor->display_depth); if (disp_depth) { if (!tr_state->pixel_metrics) disp_depth = gf_divfix(disp_depth, tr_state->min_hsize); gf_mx_init(mx); /*add recalibration by the scene*/ offset = tr_state->depth_offset; if (tr_state->visual->depth_vp_range) { offset = gf_divfix(offset, tr_state->visual->depth_vp_range/2); } gf_mx_add_translation(&mx, 0, 0, gf_mulfix(offset, disp_depth/2) ); visual_3d_matrix_push(tr_state->visual); visual_3d_matrix_add(tr_state->visual, mx.m); visual_3d_mesh_paint(tr_state, stack->mesh); visual_3d_matrix_pop(tr_state->visual); } else { visual_3d_mesh_paint(tr_state, stack->mesh); } } else #endif visual_3d_mesh_paint(tr_state, stack->mesh); } gf_sc_texture_disable(txh); tr_state->mesh_num_textures = 0; return; } } /*otherwise use glDrawPixels*/ #if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) data = gf_sc_texture_get_data(txh, &format); if (!data) return; x = INT2FIX(txh->width) / -2; y = INT2FIX(txh->height) / 2; { Fixed g[16]; sx = bmp_scale_x; if (sx<0) sx = FIX_ONE; sy = bmp_scale_y; if (sy<0) sy = FIX_ONE; #ifndef GPAC_DISABLE_VRML compositor_adjust_scale(txh->owner, &sx, &sy); #endif /*add top level scale if any*/ sx = gf_mulfix(sx, compositor->scale_x); sy = gf_mulfix(sy, compositor->scale_y); /*get & apply current transform scale*/ visual_3d_matrix_get(tr_state->visual, V3D_MATRIX_MODELVIEW, g); if (g[0]<0) g[0] *= -FIX_ONE; if (g[5]<0) g[5] *= -FIX_ONE; sx = gf_mulfix(sx, g[0]); sy = gf_mulfix(sy, g[5]); x = gf_mulfix(x, sx); y = gf_mulfix(y, sy); } visual_3d_draw_image(tr_state->visual, x, y, txh->width, txh->height, format, data, sx, sy); #endif }
static void svg_traverse_resource(GF_Node *node, void *rs, Bool is_destroy, Bool is_foreign_object) { GF_Matrix2D backup_matrix; GF_Matrix mx_3d; GF_Matrix2D translate; SVGPropertiesPointers backup_props; u32 backup_flags, dirty; Bool is_fragment; GF_Node *used_node; GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGAllAttributes all_atts; SVGlinkStack *stack = gf_node_get_private(node); SFVec2f prev_vp; SVG_Number *prev_opacity; if (is_destroy) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); gf_free(stack); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!all_atts.xlink_href) return; if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; dirty = gf_node_dirty_get(node); if (dirty & GF_SG_CHILD_DIRTY) drawable_reset_group_highlight(tr_state, node); if (dirty & GF_SG_SVG_XLINK_HREF_DIRTY) { stack->fragment_id = NULL; stack->inline_sg = NULL; if (all_atts.xlink_href->string && (all_atts.xlink_href->string[0]=='#')) { stack->fragment_id = all_atts.xlink_href->string; stack->inline_sg = gf_node_get_graph(node); } else { GF_MediaObject *new_res = gf_mo_load_xlink_resource(node, is_foreign_object, 0, -1); if (new_res != stack->resource) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); stack->resource = new_res; } } } gf_node_dirty_clear(node, 0); /*locate the used node - this is done at each step to handle progressive loading*/ is_fragment = 0; used_node = NULL; if (!stack->inline_sg && !stack->fragment_id && all_atts.xlink_href) { if (all_atts.xlink_href->type == XMLRI_ELEMENTID) { used_node = all_atts.xlink_href->target; is_fragment = 1; } else if (stack->resource) { stack->inline_sg = gf_mo_get_scenegraph(stack->resource); if (!is_foreign_object) { stack->fragment_id = strchr(all_atts.xlink_href->string, '#'); } } } if (!used_node && stack->inline_sg) { if (stack->fragment_id) { used_node = gf_sg_find_node_by_name(stack->inline_sg, (char *) stack->fragment_id+1); is_fragment = 1; } else if (is_foreign_object) { used_node = gf_sg_get_root_node(stack->inline_sg); } } if (!used_node) goto end; /*stack use nodes for picking*/ gf_list_add(tr_state->use_stack, used_node); gf_list_add(tr_state->use_stack, node); gf_mx2d_init(translate); translate.m[2] = (all_atts.x ? all_atts.x->value : 0); translate.m[5] = (all_atts.y ? all_atts.y->value : 0); /*update VP size (SVG 1.1)*/ prev_vp = tr_state->vp_size; if (all_atts.width && all_atts.height) { tr_state->vp_size.x = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.width); tr_state->vp_size.y = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.height); } prev_opacity = tr_state->parent_use_opacity; tr_state->parent_use_opacity = all_atts.opacity; if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (!compositor_svg_is_display_off(tr_state->svg_props)) { gf_node_traverse(used_node, tr_state); gf_mx2d_apply_rect(&translate, &tr_state->bounds); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } /*SORT mode and visible, traverse*/ else if (!compositor_svg_is_display_off(tr_state->svg_props) && (*(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN)) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { gf_mx_add_matrix_2d(&tr_state->model_matrix, &translate); if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix tmp; gf_mx_from_mx2d(&tmp, &translate); visual_3d_matrix_add(tr_state->visual, tmp.m); } } else #endif gf_mx2d_pre_multiply(&tr_state->transform, &translate); drawable_check_focus_highlight(node, tr_state, NULL); if (is_fragment) { gf_node_traverse(used_node, tr_state); } else { gf_sc_traverse_subscene(tr_state->visual->compositor, node, stack->inline_sg, tr_state); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } gf_list_rem_last(tr_state->use_stack); gf_list_rem_last(tr_state->use_stack); tr_state->vp_size = prev_vp; tr_state->parent_use_opacity = prev_opacity; end: memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
static void svg_traverse_svg(GF_Node *node, void *rs, Bool is_destroy) { Bool rootmost_svg, send_resize; u32 viewport_color; SVGsvgStack *stack; GF_Matrix2D backup_matrix, vb_bck; #ifndef GPAC_DISABLE_3D GF_Matrix bck_mx; #endif Bool is_dirty; GF_IRect top_clip; SFVec2f prev_vp; SVGPropertiesPointers backup_props, *prev_props; u32 backup_flags; Bool invalidate_flag; u32 styling_size = sizeof(SVGPropertiesPointers); GF_TraverseState *tr_state = (GF_TraverseState *) rs; SVGAllAttributes all_atts; stack = gf_node_get_private(node); if (is_destroy) { if (stack->svg_props) { gf_svg_properties_reset_pointers(stack->svg_props); gf_free(stack->svg_props); } gf_sc_check_focus_upon_destroy(node); if (stack->vp_fill) drawable_del(stack->vp_fill); gf_free(stack); return; } prev_props = tr_state->svg_props; /*SVG props not set: we are either the root-most <svg> of the compositor or an <svg> inside an <animation>*/ if (!tr_state->svg_props) { tr_state->svg_props = stack->svg_props; if (!tr_state->svg_props) return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) { tr_state->svg_props = prev_props; return; } /*enable or disable navigation*/ tr_state->visual->compositor->navigation_disabled = (all_atts.zoomAndPan && *all_atts.zoomAndPan == SVG_ZOOMANDPAN_DISABLE) ? 1 : 0; if (compositor_svg_is_display_off(tr_state->svg_props)) { memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; return; } top_clip = tr_state->visual->top_clipper; gf_mx2d_copy(backup_matrix, tr_state->transform); gf_mx2d_copy(vb_bck, tr_state->vb_transform); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) gf_mx_copy(bck_mx, tr_state->model_matrix); #endif invalidate_flag = tr_state->invalidate_all; is_dirty = gf_node_dirty_get(node); if (is_dirty & GF_SG_CHILD_DIRTY) drawable_reset_group_highlight(tr_state, node); gf_node_dirty_clear(node, 0); send_resize = 0; if ((stack->parent_vp.x != tr_state->vp_size.x) || (stack->parent_vp.y != tr_state->vp_size.y)) { is_dirty = 1; send_resize = 1; } if (is_dirty || tr_state->visual->compositor->recompute_ar) { svg_recompute_viewport_transformation(node, stack, tr_state, &all_atts); } gf_mx2d_copy(tr_state->vb_transform, stack->viewbox_mx); rootmost_svg = (stack->root_svg && !tr_state->parent_anim_atts) ? 1 : 0; if (tr_state->traversing_mode == TRAVERSE_SORT) { SVG_Paint *vp_fill = NULL; Fixed vp_opacity; if (tr_state->parent_anim_atts) { vp_fill = tr_state->parent_anim_atts->viewport_fill; vp_opacity = tr_state->parent_anim_atts->viewport_fill_opacity ? tr_state->parent_anim_atts->viewport_fill_opacity->value : FIX_ONE; } else { vp_fill = tr_state->svg_props->viewport_fill; vp_opacity = tr_state->svg_props->viewport_fill_opacity ? tr_state->svg_props->viewport_fill_opacity->value : FIX_ONE; } if (vp_fill && (vp_fill->type != SVG_PAINT_NONE) && vp_opacity) { Bool col_dirty = 0; viewport_color = GF_COL_ARGB_FIXED(vp_opacity, vp_fill->color.red, vp_fill->color.green, vp_fill->color.blue); if (stack->prev_color != viewport_color) { stack->prev_color = viewport_color; col_dirty = 1; } if (!rootmost_svg) { DrawableContext *ctx; Fixed width = tr_state->parent_anim_atts->width->value; Fixed height = tr_state->parent_anim_atts->height->value; if (!stack->vp_fill) { stack->vp_fill = drawable_new(); stack->vp_fill->node = node; } if ((width != stack->vp_fill->path->bbox.width) || (height != stack->vp_fill->path->bbox.height)) { drawable_reset_path(stack->vp_fill); gf_path_add_rect(stack->vp_fill->path, 0, 0, width, -height); } ctx = drawable_init_context_svg(stack->vp_fill, tr_state); if (ctx) { ctx->flags &= ~CTX_IS_TRANSPARENT; ctx->aspect.pen_props.width = 0; ctx->aspect.fill_color = viewport_color; ctx->aspect.fill_texture = NULL; if (col_dirty) ctx->flags |= CTX_APP_DIRTY; drawable_finalize_sort(ctx, tr_state, NULL); } } else if (col_dirty) { tr_state->visual->compositor->back_color = viewport_color; /*invalidate the entire visual*/ tr_state->invalidate_all = 1; } } } if (!stack->root_svg && (all_atts.x || all_atts.y)) gf_mx2d_add_translation(&tr_state->vb_transform, all_atts.x->value, all_atts.y->value); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix tmp; visual_3d_matrix_push(tr_state->visual); gf_mx_from_mx2d(&tmp, &tr_state->vb_transform); visual_3d_matrix_add(tr_state->visual, tmp.m); } else { gf_mx_add_matrix_2d(&tr_state->model_matrix, &tr_state->vb_transform); } } else #endif { gf_mx2d_pre_multiply(&tr_state->transform, &tr_state->vb_transform); } /*store VP and move it to current VP (eg, the one used to compute the vb_transform)*/ prev_vp = tr_state->vp_size; tr_state->vp_size = stack->vp; /*the event may trigger scripts which may delete nodes / modify the scene. We therefore send the resize event before traversing the scene*/ if (send_resize) { GF_DOM_Event evt; memset(&evt, 0, sizeof(GF_DOM_Event)); evt.bubbles = 1; evt.type = GF_EVENT_RESIZE; gf_dom_event_fire(node, &evt); } if ((stack->vp.x != prev_vp.x) || (stack->vp.y != prev_vp.y)) { GF_Scene *scene = node->sgprivate->scenegraph->userpriv; if (scene) { GF_DOM_Event evt; memset(&evt, 0, sizeof(GF_DOM_Event)); evt.bubbles = 0; evt.screen_rect.width = stack->vpw; evt.screen_rect.height = stack->vph; evt.screen_rect.x = stack->dx; evt.screen_rect.y = stack->dy; evt.prev_translate.x = stack->vp.x; evt.prev_translate.y = stack->vp.y; evt.type = GF_EVENT_VP_RESIZE; gf_scene_notify_event(scene, 0, NULL, &evt, GF_OK); } } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_sc_get_nodes_bounds(node, ((SVG_Element *)node)->children, tr_state, NULL); } else { compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); } tr_state->vp_size = prev_vp; #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (tr_state->traversing_mode==TRAVERSE_SORT) visual_3d_matrix_pop(tr_state->visual); gf_mx_copy(tr_state->model_matrix, bck_mx); } #endif gf_mx2d_copy(tr_state->transform, backup_matrix); gf_mx2d_copy(tr_state->vb_transform, vb_bck); memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; tr_state->visual->top_clipper = top_clip; if (!stack->root_svg) { tr_state->invalidate_all = invalidate_flag; } tr_state->svg_props = prev_props; }
static void svg_traverse_animation(GF_Node *node, void *rs, Bool is_destroy) { SVGAllAttributes all_atts; GF_Matrix2D backup_matrix; GF_Matrix backup_matrix3d; SVGPropertiesPointers backup_props; u32 backup_flags; SFVec2f prev_vp; GF_Rect rc; GF_IRect clip, prev_clip; SVGAllAttributes *prev_vp_atts; GF_TraverseState *tr_state = (GF_TraverseState*)rs; GF_Matrix2D translate; SVGPropertiesPointers *old_props; SVGlinkStack *stack = gf_node_get_private(node); if (is_destroy) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); gf_free(stack); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!stack->inline_sg && !stack->resource) { if (!stack->init_vis_state) { if (all_atts.initialVisibility && (*all_atts.initialVisibility==SVG_INITIALVISIBILTY_ALWAYS)) { stack->init_vis_state = 2; svg_animation_smil_update(node, stack, 0); } else { stack->init_vis_state = 1; } } if (!stack->inline_sg && !stack->resource) return; } if (!all_atts.width || !all_atts.height) return; if (!all_atts.width->value || !all_atts.height->value) return; if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; if (compositor_svg_is_display_off(tr_state->svg_props) || *(tr_state->svg_props->visibility) == SVG_VISIBILITY_HIDDEN) { goto end; } compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &backup_matrix3d); /*add x/y translation*/ gf_mx2d_init(translate); translate.m[2] = (all_atts.x ? all_atts.x->value : 0); translate.m[5] = (all_atts.y ? all_atts.y->value : 0); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { gf_mx_add_matrix_2d(&tr_state->model_matrix, &translate); if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix tmp; gf_mx_from_mx2d(&tmp, &translate); visual_3d_matrix_add(tr_state->visual, tmp.m); } } else #endif gf_mx2d_pre_multiply(&tr_state->transform, &translate); /*reset SVG props to reload a new inheritance context*/ old_props = tr_state->svg_props; tr_state->svg_props = NULL; /*store this node's attribute to compute PAR/ViewBox of the child <svg>*/ prev_vp_atts = tr_state->parent_anim_atts; tr_state->parent_anim_atts = &all_atts; /*update VP size*/ prev_vp = tr_state->vp_size; tr_state->vp_size.x = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.width); tr_state->vp_size.y = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.height); /*setup new clipper*/ rc.width = tr_state->vp_size.x; rc.height = tr_state->vp_size.y; rc.x = 0; rc.y = tr_state->vp_size.y; gf_mx2d_apply_rect(&tr_state->transform, &rc); prev_clip = tr_state->visual->top_clipper; clip = gf_rect_pixelize(&rc); // gf_irect_intersect(&tr_state->visual->top_clipper, &clip); if (!stack->inline_sg && stack->resource) { stack->inline_sg = gf_mo_get_scenegraph(stack->resource); } if (stack->inline_sg) { gf_sc_traverse_subscene(tr_state->visual->compositor, node, stack->inline_sg, tr_state); } if (stack->init_vis_state == 2) { stack->init_vis_state = 3; gf_mo_pause(stack->resource); } tr_state->svg_props = old_props; tr_state->visual->top_clipper = prev_clip; tr_state->parent_anim_atts = prev_vp_atts; tr_state->vp_size = prev_vp; compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &backup_matrix3d); end: memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }