void group_cache_setup(GroupCache *cache, GF_Rect *path_bounds, GF_IRect *pix_bounds, GF_Compositor *compositor, Bool for_gl) { /*setup texture */ cache->txh.compositor = compositor; cache->txh.height = pix_bounds->height; cache->txh.width = pix_bounds->width; cache->txh.stride = pix_bounds->width * 4; cache->txh.pixelformat = for_gl ? GF_PIXEL_RGBA : GF_PIXEL_ARGB; cache->txh.transparent = 1; if (cache->txh.data) gf_free(cache->txh.data); #ifdef CACHE_DEBUG_ALPHA cache->txh.stride = pix_bounds->width * 3; cache->txh.pixelformat = GF_PIXEL_RGB_24; cache->txh.transparent = 0; #endif cache->txh.data = (char *) gf_malloc (sizeof(char) * cache->txh.stride * cache->txh.height); memset(cache->txh.data, 0x0, sizeof(char) * cache->txh.stride * cache->txh.height); /*the path of drawable_cache is a rectangle one that is the the bound of the object*/ gf_path_reset(cache->drawable->path); /*set a rectangle to the path Attention, we want to center the cached bitmap at the center of the screen (main visual), so we use the local coordinate to parameterize the path*/ gf_path_add_rect_center(cache->drawable->path, path_bounds->x + path_bounds->width/2, path_bounds->y - path_bounds->height/2, path_bounds->width, path_bounds->height); }
static void PointSet2D_Draw(GF_Node *node, GF_TraverseState *tr_state) { GF_Path *path; Fixed alpha, w, h; u32 i; SFColor col; DrawableContext *ctx = tr_state->ctx; M_PointSet2D *ps2D = (M_PointSet2D *)node; M_Coordinate2D *coord = (M_Coordinate2D*) ps2D->coord; M_Color *color = (M_Color *) ps2D->color; /*never outline PS2D*/ ctx->flags |= CTX_PATH_STROKE; if (!color || color->color.count<coord->point.count) { /*no texturing*/ visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } get_point_size(&ctx->transform, &w, &h); path = gf_path_new(); alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; for (i = 0; i < coord->point.count; i++) { col = color->color.vals[i]; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); gf_path_add_rect_center(path, coord->point.vals[i].x, coord->point.vals[i].y, w, h); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state); gf_path_reset(path); ctx->flags &= ~CTX_PATH_FILLED; } gf_path_del(path); }
static void rectangle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { /*if modified update node - we don't update for other traversing mode in order not to mess up the dirty rect tracking (otherwise we would miss geometry changes with same bounds)*/ if (gf_node_dirty_get(node)) { drawable_reset_path(stack); gf_path_add_rect_center(stack->path, 0, 0, ((M_Rectangle *) node)->size.x, ((M_Rectangle *) node)->size.y); gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
static void DrawBackground2D_2D(DrawableContext *ctx, GF_TraverseState *tr_state) { Background2DStack *stack; if (!ctx || !ctx->drawable || !ctx->drawable->node) return; stack = (Background2DStack *) gf_node_get_private(ctx->drawable->node); if (!ctx->bi->clip.width || !ctx->bi->clip.height) return; stack->flags &= ~CTX_PATH_FILLED; if (back_use_texture((M_Background2D *)ctx->drawable->node)) { if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL)) { /*set target rect*/ gf_path_reset(stack->drawable->path); gf_path_add_rect_center(stack->drawable->path, ctx->bi->unclip.x + ctx->bi->unclip.width/2, ctx->bi->unclip.y - ctx->bi->unclip.height/2, ctx->bi->unclip.width, ctx->bi->unclip.height); /*draw texture*/ visual_2d_texture_path(tr_state->visual, stack->drawable->path, ctx, tr_state); } stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY); } else { /*direct drawing, draw without clippers */ if (tr_state->immediate_draw) { /*directly clear with specified color*/ tr_state->visual->ClearSurface(tr_state->visual, &ctx->bi->clip, ctx->aspect.fill_color); } else { u32 i; GF_IRect clip; for (i=0; i<tr_state->visual->to_redraw.count; i++) { /*there's an opaque region above, don't draw*/ #ifdef TRACK_OPAQUE_REGIONS if (tr_state->visual->draw_node_index<tr_state->visual->to_redraw.opaque_node_index[i]) continue; #endif clip = ctx->bi->clip; gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i]); if (clip.width && clip.height) { tr_state->visual->ClearSurface(tr_state->visual, &clip, ctx->aspect.fill_color); } } } stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY); } tr_state->visual->has_modif = 1; }
static void draw_clipper(VisualSurface2D *surf, struct _drawable_context *ctx) { GF_PenSettings clipset; GF_Path *clippath, *cliper; GF_Raster2D *r2d = surf->render->compositor->r2d; if (ctx->flags & CTX_IS_BACKGROUND) return; memset(&clipset, 0, sizeof(GF_PenSettings)); clipset.width = 2*FIX_ONE; clippath = gf_path_new(); gf_path_add_rect_center(clippath, ctx->bi->unclip.x + ctx->bi->unclip.width/2, ctx->bi->unclip.y - ctx->bi->unclip.height/2, ctx->bi->unclip.width, ctx->bi->unclip.height); cliper = gf_path_get_outline(clippath, clipset); gf_path_del(clippath); r2d->surface_set_matrix(surf->the_surface, NULL); r2d->surface_set_clipper(surf->the_surface, NULL); r2d->surface_set_path(surf->the_surface, cliper); r2d->stencil_set_brush_color(surf->the_pen, 0xFF000000); r2d->surface_fill(surf->the_surface, surf->the_pen); gf_path_del(cliper); }
static void draw_clipper(GF_VisualManager *visual, struct _drawable_context *ctx) { GF_PenSettings clipset; GF_Path *clippath, *cliper; GF_Raster2D *raster = visual->compositor->rasterizer; if (ctx->flags & CTX_IS_BACKGROUND) return; memset(&clipset, 0, sizeof(GF_PenSettings)); clipset.width = 2*FIX_ONE; clippath = gf_path_new(); gf_path_add_rect_center(clippath, ctx->bi->unclip.x + ctx->bi->unclip.width/2, ctx->bi->unclip.y - ctx->bi->unclip.height/2, ctx->bi->unclip.width, ctx->bi->unclip.height); cliper = gf_path_get_outline(clippath, clipset); gf_path_del(clippath); raster->surface_set_matrix(visual->raster_surface, NULL); raster->surface_set_clipper(visual->raster_surface, NULL); raster->surface_set_path(visual->raster_surface, cliper); raster->stencil_set_brush_color(visual->raster_brush, 0xFF000000); raster->surface_fill(visual->raster_surface, visual->raster_brush); gf_path_del(cliper); }
u32 layer3d_setup_offscreen(GF_Node *node, Layer3DStack *st, GF_TraverseState *tr_state, Fixed width, Fixed height) { GF_STENCIL stencil; u32 new_pixel_format, w, h; GF_Compositor *compositor = (GF_Compositor *)st->visual->compositor; if (st->unsupported) return 0; #ifndef GPAC_USE_TINYGL /*no support for offscreen rendering*/ if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN)) { st->unsupported = 1; return 0; } #endif /* if (tr_state->visual->compositor->recompute_ar) { gf_node_dirty_set(node, 0, 0); return 0; } */ new_pixel_format = GF_PIXEL_RGBA; #ifndef GPAC_USE_TINYGL // if (!compositor_background_transparent(gf_list_get(tr_state->backgrounds, 0)) ) // new_pixel_format = GF_PIXEL_RGB_24; /*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/ #ifdef GPAC_USE_OGL_ES new_pixel_format = GF_PIXEL_RGBA; #else /*no support for alpha in offscreen rendering*/ if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA)) new_pixel_format = GF_PIXEL_RGB_24; #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 w = (u32) FIX2INT(gf_ceil(width)); h = (u32) FIX2INT(gf_ceil(height)); /*1- some implementation of glReadPixel crash if w||h are not multiple of 4*/ /*2- some implementation of glReadPixel don't behave properly here when texture is not a power of 2*/ w = gf_get_next_pow2(w); if (w>1024) w = 1024; h = gf_get_next_pow2(h); if (h>1024) h = 1024; if (!w || !h) return 0; if (st->txh.tx_io && (new_pixel_format == st->txh.pixelformat) && (w == st->txh.width) && (h == st->txh.height) && (compositor->offscreen_width >= w) && (compositor->offscreen_height >= h) ) return 2; if (st->txh.tx_io) { #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx); #endif gf_sc_texture_release(&st->txh); if (st->txh.data) gf_free(st->txh.data); st->txh.data = NULL; } st->vp = gf_rect_center(INT2FIX(w), INT2FIX(h) ); st->txh.width = w; st->txh.height = h; gf_sc_texture_allocate(&st->txh); st->txh.pixelformat = new_pixel_format; if (new_pixel_format==GF_PIXEL_RGBA) { st->txh.stride = w * 4; st->txh.transparent = 1; } else if (new_pixel_format==GF_PIXEL_RGBDS) { st->txh.stride = w * 4; st->txh.transparent = 1; } else { st->txh.stride = w * 3; st->txh.transparent = 0; } st->visual->width = w; st->visual->height = h; stencil = compositor->rasterizer->stencil_new(compositor->rasterizer, GF_STENCIL_TEXTURE); #ifndef GPAC_USE_TINYGL /*create an offscreen window for OpenGL rendering*/ if ((compositor->offscreen_width < w) || (compositor->offscreen_height < h)) { GF_Err e; GF_Event evt; compositor->offscreen_width = MAX(compositor->offscreen_width, w); compositor->offscreen_height = MAX(compositor->offscreen_height, h); evt.type = GF_EVENT_VIDEO_SETUP; evt.setup.width = tr_state->visual->compositor->offscreen_width; evt.setup.height = tr_state->visual->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(&st->txh); st->unsupported = 1; return 0; } /*reload openGL ext*/ gf_sc_load_opengl_extensions(compositor, 1); } #endif st->txh.data = (char*)gf_malloc(sizeof(unsigned char) * st->txh.stride * st->txh.height); memset(st->txh.data, 0, sizeof(unsigned char) * st->txh.stride * st->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)*/ compositor->rasterizer->stencil_set_texture(stencil, st->txh.data, st->txh.width, st->txh.height, st->txh.stride, st->txh.pixelformat, st->txh.pixelformat, 0); #ifdef GPAC_USE_TINYGL /*create TinyGL offscreen context*/ st->tgl_ctx = ostgl_create_context(st->txh.width, st->txh.height, st->txh.transparent ? 32 : 24, &st->txh.data, 1); st->scale_x = st->scale_y = FIX_ONE; #else st->scale_x = INT2FIX(w) / tr_state->visual->compositor->offscreen_width; st->scale_y = INT2FIX(h) / tr_state->visual->compositor->offscreen_height; #endif gf_sc_texture_set_stencil(&st->txh, stencil); drawable_reset_path(st->drawable); gf_path_add_rect_center(st->drawable->path, 0, 0, st->clip.width, st->clip.height); return 1; }
/* This is a crude draft implementation of filter. The main drawback is that we don't cache any data. We should be able to check for changes in the sub-group or in the filter */ void svg_draw_filter(GF_Node *filter, GF_Node *node, GF_TraverseState *tr_state) { GF_IRect rc1, rc2; #ifndef GPAC_DISABLE_3D u32 type_3d; #endif u32 prev_flags; GF_IRect txrc; Fixed scale_x, scale_y, temp_x, temp_y; DrawableContext *ctx, *child_ctx; GF_SURFACE offscreen_surface, old_surf; GF_Rect bounds, local_bounds, rc; GF_Matrix2D backup; SVGAllAttributes all_atts; GF_FilterStack *st = gf_node_get_private(filter); assert(tr_state->traversing_mode==TRAVERSE_SORT); /*store the current transform matrix, create a new one for group_cache*/ gf_mx2d_copy(backup, tr_state->transform); gf_mx2d_init(tr_state->transform); gf_node_allow_cyclic_traverse(node); tr_state->traversing_mode = TRAVERSE_GET_BOUNDS; tr_state->bounds.width = tr_state->bounds.height = 0; gf_node_traverse(node, tr_state); local_bounds = bounds = tr_state->bounds; /*compute bounds in final coordinate system - this ensures that the cache has the correct anti aliasing*/ gf_mx2d_apply_rect(&backup, &bounds); txrc = gf_rect_pixelize(&bounds); if (txrc.width%2) txrc.width++; if (txrc.height%2) txrc.height++; bounds = gf_rect_ft(&txrc); tr_state->traversing_mode = TRAVERSE_SORT; gf_mx2d_copy(tr_state->transform, backup); if (!bounds.width || !bounds.height) { return; } /*create a context */ ctx = drawable_init_context_svg(st->drawable, tr_state); if (!ctx) return; /*setup texture */ st->txh.height = txrc.height; st->txh.width = txrc.width; st->txh.stride = txrc.width * 4; st->txh.pixelformat = GF_PIXEL_ARGB; #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) st->txh.pixelformat = GF_PIXEL_RGBA; #endif st->txh.transparent = 1; if (st->txh.stride * st->txh.height > st->alloc_size) { st->alloc_size = st->txh.stride * st->txh.height; st->data = (u8*)gf_realloc(st->data, sizeof(u8) * st->alloc_size); } memset(st->data, 0x0, sizeof(char) * st->txh.stride * st->txh.height); st->txh.data = (char *) st->data; /*setup geometry (rectangle matching the bounds of the object) Warning, we want to center the cached bitmap at the center of the screen (main visual)*/ gf_path_reset(st->drawable->path); gf_path_add_rect_center(st->drawable->path, bounds.x + bounds.width/2, bounds.y - bounds.height/2, bounds.width, bounds.height); old_surf = tr_state->visual->raster_surface; offscreen_surface = tr_state->visual->compositor->rasterizer->surface_new(tr_state->visual->compositor->rasterizer, tr_state->visual->center_coords); tr_state->visual->raster_surface = offscreen_surface; gf_mx2d_copy(backup, tr_state->transform); gf_mx2d_init(tr_state->transform); /*attach the buffer to visual*/ tr_state->visual->compositor->rasterizer->surface_attach_to_buffer(offscreen_surface, st->txh.data, st->txh.width, st->txh.height, 0, st->txh.stride, st->txh.pixelformat); prev_flags = tr_state->immediate_draw; tr_state->immediate_draw = 1; tr_state->traversing_mode = TRAVERSE_SORT; tr_state->in_svg_filter = 1; /*recompute the bounds with the final scaling used*/ scale_x = gf_divfix(bounds.width, local_bounds.width); scale_y = gf_divfix(bounds.height, local_bounds.height); gf_mx2d_init(tr_state->transform); gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y); rc = local_bounds; gf_mx2d_apply_rect(&tr_state->transform, &rc); /*centered the bitmap on the visual*/ if (tr_state->visual->center_coords) { temp_x = -rc.x - rc.width/2; temp_y = rc.height/2 - rc.y; } else { temp_x = -rc.x; temp_y = rc.height - rc.y; } gf_mx2d_add_translation(&tr_state->transform, temp_x, temp_y); rc1 = tr_state->visual->surf_rect; rc2 = tr_state->visual->top_clipper; tr_state->visual->surf_rect.width = st->txh.width; tr_state->visual->surf_rect.height = st->txh.height; if (tr_state->visual->center_coords) { tr_state->visual->surf_rect.y = st->txh.height/2; tr_state->visual->surf_rect.x = -1 * (s32) st->txh.width/2; } else { tr_state->visual->surf_rect.y = st->txh.height; tr_state->visual->surf_rect.x = 0; } tr_state->visual->top_clipper = tr_state->visual->surf_rect; #ifndef GPAC_DISABLE_3D type_3d = tr_state->visual->type_3d; tr_state->visual->type_3d=0; #endif if (prev_flags) gf_node_allow_cyclic_traverse(node); gf_node_traverse(node, tr_state); child_ctx = ctx->next; while (child_ctx && child_ctx->drawable) { drawable_reset_bounds(child_ctx->drawable, tr_state->visual); child_ctx->drawable = NULL; child_ctx = child_ctx->next; } tr_state->visual->cur_context = ctx; /*restore state and destroy whatever needs to be cleaned*/ tr_state->in_svg_filter = 0; tr_state->immediate_draw = prev_flags; tr_state->visual->compositor->rasterizer->surface_delete(offscreen_surface); tr_state->visual->raster_surface = old_surf; tr_state->traversing_mode = TRAVERSE_SORT; tr_state->visual->surf_rect = rc1; tr_state->visual->top_clipper = rc2; #ifndef GPAC_DISABLE_3D tr_state->visual->type_3d = type_3d ; #endif /*update texture*/ st->txh.transparent = 1; st->txh.flags |= GF_SR_TEXTURE_NO_GL_FLIP; gf_sc_texture_set_data(&st->txh); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) gf_sc_texture_push_image(&st->txh, 0, 0); else #endif gf_sc_texture_push_image(&st->txh, 0, 1); ctx->flags |= CTX_NO_ANTIALIAS; ctx->aspect.fill_color = 0; ctx->aspect.line_color = 0xFF000000; ctx->aspect.fill_texture = &st->txh; ctx->flags |= CTX_TEXTURE_DIRTY; /*get the filter region*/ bounds = local_bounds; gf_svg_flatten_attributes((SVG_Element *)filter, &all_atts); if (!all_atts.filterUnits || (*all_atts.filterUnits==SVG_GRADIENTUNITS_OBJECT)) { Fixed v; v = all_atts.x ? all_atts.x->value : INT2FIX(-10); bounds.x += gf_mulfix(v, bounds.width); v = all_atts.y ? all_atts.y->value : INT2FIX(-10); bounds.y += gf_mulfix(v, bounds.height); v = all_atts.width ? all_atts.width->value : INT2FIX(120); bounds.width = gf_mulfix(v, bounds.width); v = all_atts.height ? all_atts.height->value : INT2FIX(120); bounds.height = gf_mulfix(v, bounds.height); } else { bounds.x = all_atts.x ? all_atts.x->value : 0; bounds.y = all_atts.y ? all_atts.y->value : 0; bounds.width = all_atts.width ? all_atts.x->value : bounds.width; bounds.height = all_atts.x ? all_atts.x->value : 120; } gf_mx2d_apply_rect(&backup, &bounds); svg_filter_apply(filter, &st->txh, &bounds); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (!st->drawable->mesh) { st->drawable->mesh = new_mesh(); mesh_from_path(st->drawable->mesh, st->drawable->path); } visual_3d_draw_from_context(tr_state->ctx, tr_state); ctx->drawable = NULL; return; } #endif /*we computed the texture in final screen coordinate, so use the identity matrix for the context*/ gf_mx2d_init(tr_state->transform); drawable_finalize_sort(ctx, tr_state, NULL); gf_mx2d_copy(tr_state->transform, backup); }
static void SVG_Build_Bitmap_Graph(SVG_video_stack *stack, GF_TraverseState *tr_state) { u32 tag; GF_Rect rc, new_rc; Fixed x, y, width, height, txwidth, txheight; Fixed rectx, recty, rectwidth, rectheight; SVGAllAttributes atts; SVG_PreserveAspectRatio pAR; SVG_Element *e = (SVG_Element *)stack->graph->node; gf_svg_flatten_attributes(e, &atts); tag = gf_node_get_tag(stack->graph->node); switch (tag) { case TAG_SVG_image: case TAG_SVG_video: x = (atts.x ? atts.x->value : 0); y = (atts.y ? atts.y->value : 0); width = (atts.width ? atts.width->value : 0); height = (atts.height ? atts.height->value : 0); break; default: return; } if (!width || !height) return; txheight = INT2FIX(stack->txh.height); txwidth = INT2FIX(stack->txh.width); if (!txwidth || !txheight) return; if (!atts.preserveAspectRatio) { pAR.defer = GF_FALSE; pAR.meetOrSlice = SVG_MEETORSLICE_MEET; pAR.align = SVG_PRESERVEASPECTRATIO_XMIDYMID; } else { pAR = *atts.preserveAspectRatio; } if (pAR.defer) { /* TODO */ rectwidth = width; rectheight = height; rectx = x+rectwidth/2; recty = y+rectheight/2; } else { if (pAR.align==SVG_PRESERVEASPECTRATIO_NONE) { rectwidth = width; rectheight = height; rectx = x+rectwidth/2; recty = y+rectheight/2; } else { Fixed scale, scale_w, scale_h; scale_w = gf_divfix(width, txwidth); scale_h = gf_divfix(height, txheight); if (pAR.meetOrSlice==SVG_MEETORSLICE_MEET) { if (scale_w > scale_h) { scale = scale_h; rectwidth = gf_mulfix(txwidth, scale); rectheight = height; } else { scale = scale_w; rectwidth = width; rectheight = gf_mulfix(txheight, scale); } } else { if (scale_w < scale_h) { scale = scale_h; rectwidth = gf_mulfix(txwidth, scale); rectheight = height; } else { scale = scale_w; rectwidth = width; rectheight = gf_mulfix(txheight, scale); } } rectx = x + rectwidth/2; recty = y + rectheight/2; switch (pAR.align) { case SVG_PRESERVEASPECTRATIO_XMINYMIN: break; case SVG_PRESERVEASPECTRATIO_XMIDYMIN: rectx += (width - rectwidth)/ 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMIN: rectx += width - rectwidth; break; case SVG_PRESERVEASPECTRATIO_XMINYMID: recty += (height - rectheight)/ 2; break; case SVG_PRESERVEASPECTRATIO_XMIDYMID: rectx += (width - rectwidth)/ 2; recty += (height - rectheight) / 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMID: rectx += width - rectwidth; recty += ( txheight - rectheight) / 2; break; case SVG_PRESERVEASPECTRATIO_XMINYMAX: recty += height - rectheight; break; case SVG_PRESERVEASPECTRATIO_XMIDYMAX: rectx += (width - rectwidth)/ 2; recty += height - rectheight; break; case SVG_PRESERVEASPECTRATIO_XMAXYMAX: rectx += width - rectwidth; recty += height - rectheight; break; } } } gf_path_get_bounds(stack->graph->path, &rc); drawable_reset_path(stack->graph); gf_path_add_rect_center(stack->graph->path, rectx, recty, rectwidth, rectheight); gf_path_get_bounds(stack->graph->path, &new_rc); if (!gf_rect_equal(rc, new_rc)) drawable_mark_modified(stack->graph, tr_state); else if (stack->txh.flags & GF_SR_TEXTURE_PRIVATE_MEDIA) drawable_mark_modified(stack->graph, tr_state); gf_node_dirty_clear(stack->graph->node, GF_SG_SVG_GEOMETRY_DIRTY); }
static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) { Fixed cx, cy, angle; /*video stack is just an extension of image stack, type-casting is OK*/ SVG_video_stack *stack = (SVG_video_stack*)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGPropertiesPointers backup_props; u32 backup_flags; GF_Matrix2D backup_matrix; GF_Matrix mx_3d; DrawableContext *ctx; SVGAllAttributes all_atts; if (is_destroy) { gf_sc_texture_destroy(&stack->txh); gf_sg_mfurl_del(stack->txurl); drawable_del(stack->graph); if (stack->audio) { gf_node_unregister(stack->audio, NULL); } gf_free(stack); return; } /*TRAVERSE_DRAW is NEVER called in 3D mode*/ if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) { SVG_Draw_bitmap(tr_state); return; } else if (tr_state->traversing_mode==TRAVERSE_PICK) { svg_drawable_pick(node, stack->graph, tr_state); return; } /*flatten attributes and apply animations + inheritance*/ gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags)) return; if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) { gf_term_get_mfurl_from_xlink(node, &stack->txurl); stack->txh.width = stack->txh.height = 0; /*remove associated audio if any*/ if (stack->audio) { svg_audio_smil_evaluate_ex(NULL, 0, SMIL_TIMING_EVAL_REMOVE, stack->audio, stack->txh.owner); gf_node_unregister(stack->audio, NULL); stack->audio = NULL; } stack->audio_dirty = GF_TRUE; if (stack->txurl.count) svg_play_texture(stack, &all_atts); gf_node_dirty_clear(node, GF_SG_SVG_XLINK_HREF_DIRTY); } if (gf_node_dirty_get(node)) { /*do not clear dirty state until the image is loaded*/ if (stack->txh.width) { gf_node_dirty_clear(node, 0); SVG_Build_Bitmap_Graph((SVG_video_stack*)gf_node_get_private(node), tr_state); } } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { if (!compositor_svg_is_display_off(tr_state->svg_props)) { gf_path_get_bounds(stack->graph->path, &tr_state->bounds); compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { GF_Matrix2D mx; tr_state->bounds.width = INT2FIX(stack->txh.width); tr_state->bounds.height = INT2FIX(stack->txh.height); tr_state->bounds.x = cx - tr_state->bounds.width/2; tr_state->bounds.y = cy + tr_state->bounds.height/2; gf_mx2d_init(mx); gf_mx2d_add_rotation(&mx, 0, 0, angle); gf_mx2d_apply_rect(&mx, &tr_state->bounds); } else { gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } } else if (tr_state->traversing_mode == TRAVERSE_SORT) { if (!compositor_svg_is_display_off(tr_state->svg_props) && ( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) { GF_Matrix mx_bck; Bool restore_mx = GF_FALSE; compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); ctx = drawable_init_context_svg(stack->graph, tr_state); if (!ctx || !ctx->aspect.fill_texture ) return; if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { drawable_reset_path(stack->graph); gf_path_add_rect_center(stack->graph->path, cx, cy, INT2FIX(stack->txh.width), INT2FIX(stack->txh.height)); gf_mx2d_copy(mx_bck, tr_state->transform); restore_mx = GF_TRUE; gf_mx2d_init(tr_state->transform); gf_mx2d_add_rotation(&tr_state->transform, cx, cy, angle); } /*even if set this is not true*/ ctx->aspect.pen_props.width = 0; ctx->flags |= CTX_NO_ANTIALIAS; /*if rotation, transparent*/ ctx->flags &= ~CTX_IS_TRANSPARENT; if (ctx->transform.m[1] || ctx->transform.m[3]) { ctx->flags |= CTX_IS_TRANSPARENT; ctx->flags &= ~CTX_NO_ANTIALIAS; } else if (ctx->aspect.fill_texture->transparent) ctx->flags |= CTX_IS_TRANSPARENT; else if (tr_state->svg_props->opacity && (tr_state->svg_props->opacity->type==SVG_NUMBER_VALUE) && (tr_state->svg_props->opacity->value!=FIX_ONE)) { ctx->flags = CTX_IS_TRANSPARENT; ctx->aspect.fill_color = GF_COL_ARGB(FIX2INT(0xFF * tr_state->svg_props->opacity->value), 0, 0, 0); } #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (!stack->graph->mesh) { stack->graph->mesh = new_mesh(); mesh_from_path(stack->graph->mesh, stack->graph->path); } compositor_3d_draw_bitmap(stack->graph, &ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE); ctx->drawable = NULL; } else #endif { drawable_finalize_sort(ctx, tr_state, NULL); } if (restore_mx) gf_mx2d_copy(tr_state->transform, mx_bck); compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } } if (stack->audio) svg_traverse_audio_ex(stack->audio, rs, GF_FALSE, tr_state->svg_props); memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
static void DrawBackground2D_2D(DrawableContext *ctx, GF_TraverseState *tr_state) { Bool clear_all = GF_TRUE; u32 color; Bool use_texture; Bool is_offscreen = GF_FALSE; Background2DStack *stack; if (!ctx || !ctx->drawable || !ctx->drawable->node) return; stack = (Background2DStack *) gf_node_get_private(ctx->drawable->node); if (!ctx->bi->clip.width || !ctx->bi->clip.height) return; stack->flags &= ~CTX_PATH_FILLED; color = ctx->aspect.fill_color; use_texture = back_use_texture((M_Background2D *)ctx->drawable->node); if (!use_texture && !tr_state->visual->is_attached) { use_texture = 1; stack->txh.data = stack->col_tx; stack->txh.width = 2; stack->txh.height = 2; stack->txh.stride = 6; stack->txh.pixelformat = GF_PIXEL_RGB_24; } if (use_texture) { if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx)) { /*set target rect*/ gf_path_reset(stack->drawable->path); gf_path_add_rect_center(stack->drawable->path, ctx->bi->unclip.x + ctx->bi->unclip.width/2, ctx->bi->unclip.y - ctx->bi->unclip.height/2, ctx->bi->unclip.width, ctx->bi->unclip.height); /*draw texture*/ visual_2d_texture_path(tr_state->visual, stack->drawable->path, ctx, tr_state); } //a quick hack, if texture not ready return (we don't have direct notification of this through the above functions #ifndef GPAC_DISABLE_3D if (tr_state->visual->compositor->hybrid_opengl && !stack->txh.tx_io) return; #endif stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY); tr_state->visual->has_modif = 1; #ifndef GPAC_DISABLE_3D //in opengl auto mode we still have to clear the canvas if (!tr_state->immediate_draw && !tr_state->visual->offscreen && tr_state->visual->compositor->hybrid_opengl) { clear_all = GF_FALSE; is_offscreen = GF_TRUE; color &= 0x00FFFFFF; } else #endif return; } #ifndef GPAC_DISABLE_3D if (ctx->flags & CTX_BACKROUND_NOT_LAYER) { if (clear_all && !tr_state->visual->offscreen && tr_state->visual->compositor->hybrid_opengl) { compositor_2d_hybgl_clear_surface(tr_state->visual, NULL, color, GF_FALSE); is_offscreen = GF_TRUE; color &= 0x00FFFFFF; //we may need to clear the canvas for immediate mode } } else { is_offscreen = GF_TRUE; } #endif /*direct drawing, draw without clippers */ if (tr_state->immediate_draw ) { /*directly clear with specified color*/ if (clear_all) tr_state->visual->ClearSurface(tr_state->visual, &ctx->bi->clip, color, is_offscreen); } else { u32 i; GF_IRect clip; for (i=0; i<tr_state->visual->to_redraw.count; i++) { /*there's an opaque region above, don't draw*/ #ifdef TRACK_OPAQUE_REGIONS if (tr_state->visual->draw_node_index < tr_state->visual->to_redraw.list[i].opaque_node_index) continue; #endif clip = ctx->bi->clip; gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i].rect); if (clip.width && clip.height) { tr_state->visual->ClearSurface(tr_state->visual, &clip, color, is_offscreen); } } } stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY); tr_state->visual->has_modif = 1; }