static void VS2D_DoFill(VisualSurface2D *surf, DrawableContext *ctx, GF_STENCIL stencil) { GF_IRect clip; GF_Raster2D *r2d = surf->render->compositor->r2d; /*background rendering - direct rendering: use ctx clip*/ if ((ctx->flags & CTX_IS_BACKGROUND) || (surf->render->top_effect->trav_flags & TF_RENDER_DIRECT)) { if (ctx->bi->clip.width && ctx->bi->clip.height) { r2d->surface_set_clipper(surf->the_surface, &ctx->bi->clip); r2d->surface_fill(surf->the_surface, stencil); } } /*indirect rendering, draw path in all dirty areas*/ else { u32 i; for (i=0; i<surf->to_redraw.count; i++) { /*there's an opaque region above, don't draw*/ #ifdef TRACK_OPAQUE_REGIONS if (surf->draw_node_index<surf->to_redraw.opaque_node_index[i]) continue; #endif clip = ctx->bi->clip; gf_irect_intersect(&clip, &surf->to_redraw.list[i]); if (clip.width && clip.height) { r2d->surface_set_clipper(surf->the_surface, &clip); r2d->surface_fill(surf->the_surface, stencil); // } else { // fprintf(stdout, "node outside clipper\n"); } } } }
static void visual_2d_fill_path(GF_VisualManager *visual, DrawableContext *ctx, GF_STENCIL stencil, GF_TraverseState *tr_state, Bool is_erase) { Bool has_modif = GF_FALSE; GF_IRect clip; GF_Raster2D *raster = visual->compositor->rasterizer; /*background & direct drawing : use ctx clip*/ if ((ctx->flags & CTX_IS_BACKGROUND) || tr_state->immediate_draw) { if (ctx->bi->clip.width && ctx->bi->clip.height) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Redrawing node %s[%s] (direct draw)\n", gf_node_get_log_name(ctx->drawable->node), gf_node_get_class_name(ctx->drawable->node) )); if (stencil) { raster->surface_set_clipper(visual->raster_surface, &ctx->bi->clip); raster->surface_fill(visual->raster_surface, stencil); } else { raster->surface_clear(visual->raster_surface, &ctx->bi->clip, 0); } has_modif = GF_TRUE; } } /*indirect drawing, draw path in all dirty areas*/ else { u32 i; for (i=0; i<visual->to_redraw.count; i++) { /*there's an opaque region above, don't draw*/ #ifdef TRACK_OPAQUE_REGIONS if (!is_erase && (visual->draw_node_index<visual->to_redraw.list[i].opaque_node_index)) continue; #endif clip = ctx->bi->clip; gf_irect_intersect(&clip, &visual->to_redraw.list[i].rect); if (clip.width && clip.height) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Redrawing node %s[%s] (indirect draw @ dirty rect idx %d)\n", gf_node_get_log_name(ctx->drawable->node), gf_node_get_class_name(ctx->drawable->node), i)); if (stencil) { raster->surface_set_clipper(visual->raster_surface, &clip); raster->surface_fill(visual->raster_surface, stencil); } else { raster->surface_clear(visual->raster_surface, &clip, 0); } has_modif = 1; } } } #ifndef GPAC_DISABLE_3D if (!is_erase) visual->nb_objects_on_canvas_since_last_ogl_flush++; #endif if (has_modif) { visual->has_modif = 1; #ifndef GPAC_DISABLE_3D if (!visual->offscreen && visual->compositor->hybrid_opengl && !is_erase) ra_union_rect(&visual->hybgl_drawn, &ctx->bi->clip); #endif } }
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 visual_2d_fill_path(GF_VisualManager *visual, DrawableContext *ctx, GF_STENCIL stencil, GF_TraverseState *tr_state) { GF_IRect clip; GF_Raster2D *raster = visual->compositor->rasterizer; /*background & direct drawing : use ctx clip*/ if ((ctx->flags & CTX_IS_BACKGROUND) || tr_state->immediate_draw) { if (ctx->bi->clip.width && ctx->bi->clip.height) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Redrawing node %s[%s] (direct draw)\n", gf_node_get_log_name(ctx->drawable->node), gf_node_get_class_name(ctx->drawable->node) )); if (stencil) { raster->surface_set_clipper(visual->raster_surface, &ctx->bi->clip); raster->surface_fill(visual->raster_surface, stencil); } else { raster->surface_clear(visual->raster_surface, &ctx->bi->clip, 0); } visual->has_modif = 1; } } /*indirect drawing, draw path in all dirty areas*/ else { u32 i; for (i=0; i<visual->to_redraw.count; i++) { /*there's an opaque region above, don't draw*/ #ifdef TRACK_OPAQUE_REGIONS if (visual->draw_node_index<visual->to_redraw.opaque_node_index[i]) continue; #endif clip = ctx->bi->clip; gf_irect_intersect(&clip, &visual->to_redraw.list[i]); if (clip.width && clip.height) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Redrawing node %s[%s] (indirect draw @ dirty rect idx %d)\n", gf_node_get_log_name(ctx->drawable->node), gf_node_get_class_name(ctx->drawable->node), i)); if (stencil) { raster->surface_set_clipper(visual->raster_surface, &clip); raster->surface_fill(visual->raster_surface, stencil); } else { raster->surface_clear(visual->raster_surface, &clip, 0); } visual->has_modif = 1; } } } }
static void compositor_2d_draw_rectangle(GF_TraverseState *tr_state) { DrawableContext *ctx = tr_state->ctx; if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->data #ifndef GPAC_DISABLE_3D && !tr_state->visual->compositor->hybrid_opengl #endif ) { Bool res; /*get image size WITHOUT line size or antialias margin*/ if ( !(ctx->flags & CTX_NO_ANTIALIAS) ) { GF_Rect orig_unclip; GF_IRect orig_clip; orig_unclip = ctx->bi->unclip; orig_clip = ctx->bi->clip; gf_path_get_bounds(ctx->drawable->path, &ctx->bi->unclip); gf_mx2d_apply_rect(&ctx->transform, &ctx->bi->unclip); ctx->bi->clip = gf_rect_pixelize(&ctx->bi->unclip); gf_irect_intersect(&ctx->bi->clip, &orig_clip); res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL); /*strike path*/ ctx->bi->unclip = orig_unclip; ctx->bi->clip = orig_clip; if (res) { ctx->flags |= CTX_PATH_FILLED; visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); } } else { res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL); } /*if failure retry with raster*/ if (res) return; } visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); }
Bool visual_2d_terminate_draw(GF_VisualManager *visual, GF_TraverseState *tr_state) { u32 k, i, count, num_nodes, num_changed; GF_IRect refreshRect; Bool redraw_all; Bool hyb_force_redraw=GF_FALSE; #ifndef GPAC_DISABLE_VRML M_Background2D *bck = NULL; DrawableContext *bck_ctx = NULL; #endif DrawableContext *ctx; struct _drawable_store *it, *prev; DrawableContext *first_opaque = NULL; Bool has_clear = 0; Bool has_changed = 0; Bool redraw_all_on_background_change = GF_TRUE; /*in direct mode the visual is always redrawn*/ if (tr_state->immediate_draw) { /*flush pending contexts due to overlays*/ visual_2d_flush_overlay_areas(visual, tr_state); visual_2d_release_raster(visual); visual_clean_contexts(visual); visual->num_nodes_prev_frame = visual->num_nodes_current_frame; return 1; } num_changed = 0; /*if the aspect ratio has changed redraw everything*/ redraw_all = tr_state->invalidate_all; #ifndef GPAC_DISABLE_3D if (visual->compositor->hybrid_opengl && !visual->offscreen) redraw_all_on_background_change = GF_FALSE; #endif /*check for background changes for transparent nodes*/ #ifndef GPAC_DISABLE_VRML bck = (M_Background2D*)gf_list_get(visual->back_stack, 0); if (bck) { if (!bck->isBound) { if (visual->last_had_back) { if (redraw_all_on_background_change) redraw_all = 1; else hyb_force_redraw = 1; } visual->last_had_back = 0; } else { bck_ctx = b2d_get_context(bck, visual->back_stack); if (!visual->last_had_back || (bck_ctx->flags & CTX_REDRAW_MASK) ) { if (redraw_all_on_background_change) redraw_all = 1; else hyb_force_redraw = 1; } visual->last_had_back = (bck_ctx->aspect.fill_texture && !bck_ctx->aspect.fill_texture->transparent) ? 2 : 1; } } else #endif if (visual->last_had_back) { visual->last_had_back = 0; if (redraw_all_on_background_change) redraw_all = 1; else hyb_force_redraw = 1; } num_nodes = 0; ctx = visual->context; while (ctx && ctx->drawable) { num_nodes++; drawctx_update_info(ctx, visual); if (!redraw_all) { u32 res; assert( gf_irect_inside(&visual->top_clipper, &ctx->bi->clip) ); res = register_context_rect(&visual->to_redraw, ctx, num_nodes, &first_opaque); if (res) { num_changed ++; if (res==2) hyb_force_redraw=GF_TRUE; } } ctx = ctx->next; } /*garbage collection*/ /*clear all remaining bounds since last frames (the ones that moved or that are not drawn this frame)*/ prev = NULL; it = visual->prev_nodes; while (it) { while (drawable_get_previous_bound(it->drawable, &refreshRect, visual)) { if (!redraw_all) { //assert( gf_irect_inside(&visual->top_clipper, &refreshRect) ); gf_irect_intersect(&refreshRect, &visual->top_clipper); register_dirty_rect(&visual->to_redraw, &refreshRect); has_clear=1; } } /*if node is marked as undrawn, remove from visual*/ if (!(it->drawable->flags & DRAWABLE_DRAWN_ON_VISUAL)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Node %s no longer on visual - unregistering it\n", gf_node_get_class_name(it->drawable->node))); /*remove all bounds info related to this visual and unreg node */ drawable_reset_bounds(it->drawable, visual); it->drawable->flags &= ~DRAWABLE_REGISTERED_WITH_VISUAL; if (it->drawable->flags & DRAWABLE_IS_OVERLAY) { visual->compositor->video_out->Blit(visual->compositor->video_out, NULL, NULL, NULL, 1); } if (prev) prev->next = it->next; else visual->prev_nodes = it->next; if (!it->next) visual->last_prev_entry = prev; gf_free(it); it = prev ? prev->next : visual->prev_nodes; } else { prev = it; it = it->next; } } if (redraw_all) { ra_clear(&visual->to_redraw); ra_add(&visual->to_redraw, &visual->surf_rect); #ifdef TRACK_OPAQUE_REGIONS visual->to_redraw.list[0].opaque_node_index=0; #endif } else { ra_refresh(&visual->to_redraw); if (visual->compositor->debug_defer) { visual->ClearSurface(visual, &visual->top_clipper, 0); } } /*nothing to redraw*/ if (!hyb_force_redraw && ra_is_empty(&visual->to_redraw) ) { #ifndef GPAC_DISABLE_3D //force canvas draw visual->nb_objects_on_canvas_since_last_ogl_flush = 1; #endif GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] No changes found since last frame - skipping redraw\n")); goto exit; } has_changed = 1; tr_state->traversing_mode = TRAVERSE_DRAW_2D; if (first_opaque && (visual->to_redraw.count==1) && gf_rect_equal(first_opaque->bi->clip, visual->to_redraw.list[0].rect)) { visual->has_modif=0; goto skip_background; } /*redraw everything*/ #ifndef GPAC_DISABLE_VRML if (bck_ctx) { drawable_check_bounds(bck_ctx, visual); tr_state->ctx = bck_ctx; visual->draw_node_index = 0; /*force clearing entire zone, not just viewport, when using color. If texture, we MUST use the VP clipper in order to compute offsets when blitting bitmaps*/ if (bck_ctx->aspect.fill_texture && bck_ctx->aspect.fill_texture->stream) { bck_ctx->bi->clip = visual->top_clipper; } else { bck_ctx->bi->clip = visual->surf_rect; } bck_ctx->bi->unclip = gf_rect_ft(&bck_ctx->bi->clip); bck_ctx->next = visual->context; bck_ctx->flags |= CTX_BACKROUND_NOT_LAYER; gf_node_traverse(bck_ctx->drawable->node, tr_state); bck_ctx->flags &= ~CTX_BACKROUND_NOT_LAYER; } else #endif /*GPAC_DISABLE_VRML*/ { count = visual->to_redraw.count; for (k=0; k<count; k++) { GF_IRect rc; /*opaque area, skip*/ #ifdef TRACK_OPAQUE_REGIONS if (visual->to_redraw.list[k].opaque_node_index > 0) continue; #endif rc = visual->to_redraw.list[k].rect; visual->ClearSurface(visual, &rc, 0); } #ifndef GPAC_DISABLE_3D if (!count && hyb_force_redraw) { compositor_2d_hybgl_clear_surface_ex(tr_state->visual, NULL, 0, GF_FALSE); } #endif } if (!redraw_all && !has_clear) visual->has_modif=0; skip_background: #ifndef GPAC_DISABLE_LOG if (gf_log_tool_level_on(GF_LOG_COMPOSE, GF_LOG_INFO)) { GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Visual2D] Redraw %d / %d nodes (all: %s - %d dirty rects\n)", num_changed, num_nodes, redraw_all ? "yes" : "no", visual->to_redraw.count)); if (visual->to_redraw.count>1) GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("\n")); for (i=0; i<visual->to_redraw.count; i++) { GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("\tDirtyRect #%d: %d:%d@%dx%d\n", i+1, visual->to_redraw.list[i].rect.x, visual->to_redraw.list[i].rect.y, visual->to_redraw.list[i].rect.width, visual->to_redraw.list[i].rect.height)); assert(visual->to_redraw.list[i].rect.width); } } #endif visual->draw_node_index = 0; ctx = visual->context; while (ctx && ctx->drawable) { visual->draw_node_index ++; tr_state->ctx = ctx; /*if overlay we cannot remove the context and cannot draw directly*/ if (! visual_2d_overlaps_overlay(tr_state->visual, ctx, tr_state)) { if (ctx->drawable->flags & DRAWABLE_USE_TRAVERSE_DRAW) { gf_node_traverse(ctx->drawable->node, tr_state); } else { drawable_draw(ctx->drawable, tr_state); } } ctx = ctx->next; } /*flush pending contexts due to overlays*/ visual_2d_flush_overlay_areas(visual, tr_state); #ifndef GPAC_DISABLE_VRML if (bck_ctx) bck_ctx->next = NULL; #endif if (visual->direct_flush) { GF_DirtyRectangles dr; u32 i; dr.count = visual->to_redraw.count; dr.list = gf_malloc(sizeof(GF_IRect)*dr.count); for (i=0; i<dr.count; i++) { dr.list[i] = visual->to_redraw.list[i].rect; } visual->compositor->video_out->FlushRectangles(visual->compositor->video_out, &dr); visual->compositor->skip_flush=1; gf_free(dr.list); } exit: /*clear dirty rects*/ ra_clear(&visual->to_redraw); visual_2d_release_raster(visual); visual_clean_contexts(visual); visual->num_nodes_prev_frame = visual->num_nodes_current_frame; return has_changed; }
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); } }
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; }
void visual_2d_flush_hybgl_canvas(GF_VisualManager *visual, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_TraverseState *tr_state) { Bool line_texture = GF_FALSE; u32 i; u32 prev_color; Bool transparent, had_flush = 0; u32 nb_obj_left_on_canvas = visual->nb_objects_on_canvas_since_last_ogl_flush; u8 alpha; if (! visual->hybgl_drawn.count) return; //we have drawn things on the canvas before this object, flush canvas to GPU if (txh && (txh==ctx->aspect.line_texture)) { line_texture = GF_TRUE; alpha = GF_COL_A(ctx->aspect.line_color); prev_color = ctx->aspect.line_color; ctx->aspect.line_texture = NULL; ctx->aspect.line_color = 0; } else { alpha = GF_COL_A(ctx->aspect.fill_color); if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color); prev_color = ctx->aspect.fill_color; ctx->aspect.fill_texture = NULL; ctx->aspect.fill_color = 0; } transparent = txh ? (txh->transparent || (alpha!=0xFF)) : GF_TRUE; //clear wherever we have overlap for (i=0; i<visual->hybgl_drawn.count; i++) { GF_IRect rc = ctx->bi->clip; gf_irect_intersect(&ctx->bi->clip, &visual->hybgl_drawn.list[i].rect); if (ctx->bi->clip.width && ctx->bi->clip.height) { //if something behind this, flush canvas to gpu if (transparent) { if (!had_flush) { //flush the complete area below this object, regardless of intersections compositor_2d_hybgl_flush_video(visual->compositor, tr_state->immediate_draw ? NULL : &rc); had_flush = 1; } //if object was not completely in the flush region we will need to flush the canvas if (gf_irect_inside(&rc, &visual->hybgl_drawn.list[i].rect)) { assert(nb_obj_left_on_canvas); nb_obj_left_on_canvas--; } } //erase all part of the canvas below us if (txh) { visual_2d_draw_path_extended(visual, ctx->drawable->path, ctx, NULL, NULL, tr_state, NULL, NULL, GF_TRUE); } else { visual->compositor->rasterizer->surface_clear(visual->raster_surface, &ctx->bi->clip, 0); } } ctx->bi->clip = rc; } if (line_texture) { ctx->aspect.line_color = prev_color; ctx->aspect.line_texture = txh; } else { ctx->aspect.fill_color = prev_color; ctx->aspect.fill_texture = txh; } if (had_flush) { visual->nb_objects_on_canvas_since_last_ogl_flush = nb_obj_left_on_canvas; } }