static void DrawBackground(DrawableContext *ctx) { Background2DStack *bcks = (Background2DStack *) Node_GetPrivate(ctx->node->owner); if (m4_rect_is_empty(ctx->clip) ) return; ctx->path_filled = 0; if ( back_use_texture(b2D_getnode(bcks)) ) { if (!ctx->surface->DrawBitmap) { /*set target rect*/ m4_path_reset(bcks->node->path); m4_path_add_rectangle(bcks->node->path, ctx->unclip.x + ctx->unclip.width/2, ctx->unclip.y - ctx->unclip.height/2, ctx->unclip.width, ctx->unclip.height); ctx->original = ctx->unclip; /*draw texture*/ VS2D_TexturePath(ctx->surface, bcks->node->path, ctx); } else { ctx->original = ctx->unclip; ctx->clip = m4_rect_pixelize(&ctx->unclip); /*direct rendering, render without clippers */ if (ctx->surface->render->top_effect->trav_flags & TF_RENDER_DIRECT) { ctx->surface->DrawBitmap(ctx->surface, ctx->h_texture, &ctx->clip, &ctx->unclip); } /*render bitmap for all dirty rects*/ else { u32 i; M4IRect clip; for (i=0; i<ctx->surface->to_redraw.count; i++) { /*there's an opaque region above, don't draw*/ if (ctx->surface->draw_node_index<ctx->surface->to_redraw.opaque_node_index[i]) continue; clip = ctx->clip; m4_irect_intersect(&clip, &ctx->surface->to_redraw.list[i]); if (clip.width && clip.height) { ctx->surface->DrawBitmap(ctx->surface, ctx->h_texture, &clip, &ctx->unclip); } } } } ctx->redraw_flags = bcks->txh.hwtx ? 0 : CTX_APP_DIRTY; } else { /*directly clear with specified color*/ VS2D_Clear(ctx->surface, &ctx->clip, ctx->aspect.fill_color); ctx->redraw_flags = 0; } }
static Bool back_texture_enabled(M_Background2D *bck, GF_TextureHandler *txh) { Bool use_texture = back_use_texture(bck); if (use_texture) { /*texture not ready*/ if (!txh->tx_io) { use_texture = 0; gf_sc_invalidate(txh->compositor, NULL); } gf_sc_texture_set_blend_mode(txh, gf_sc_texture_is_transparent(txh) ? TX_REPLACE : TX_DECAL); } return use_texture; }
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 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 RenderBackground2D(SFNode *node, void *rs) { u32 col; BackgroundStatus *status; M_Background2D *bck; Background2DStack *bcks = (Background2DStack *) Node_GetPrivate(node); RenderEffect2D *eff = (RenderEffect2D *)rs; status = b2D_GetStatus(bcks, eff); if (!status) return; status->ctx.redraw_flags = 0; if (Node_GetDirty(node)) { status->ctx.redraw_flags = CTX_APP_DIRTY; Node_ClearDirty(node); } bck = b2D_getnode(bcks); if (bcks->first_render) { bcks->first_render = 0; if (ChainGetEntry(status->bind_stack, 0) == node) { if (!bck->isBound) { bck->isBound = 1; Node_OnEventOutSTR((SFNode *)bck, "isBound"); } } /*open the stream if any*/ if (back_use_texture(bck) && !bcks->txh.is_open) { texture_play(&bcks->txh, &bck->url); } /*we're in direct rendering and we missed background drawing - reset*/ if (bck->isBound && (eff->trav_flags & TF_RENDER_DIRECT) && !eff->draw_background) { SR_Invalidate(bcks->compositor, NULL); return; } } if (!bck->isBound) return; if (!eff->draw_background && (eff->trav_flags & TF_RENDER_DIRECT)) return; /*background context bounds are always setup by parent group/surface*/ if (back_use_texture(bck) ) { if (bcks->txh.hwtx) { if (!status->ctx.redraw_flags && bcks->txh.needs_refresh) status->ctx.redraw_flags |= CTX_TEXTURE_DIRTY; } else { SR_Invalidate(bcks->compositor, NULL); status->ctx.redraw_flags = CTX_APP_DIRTY; } } else { col = MAKE_ARGB_FLOAT(1.0, bck->backColor.red, bck->backColor.green, bck->backColor.blue); if (col != status->ctx.aspect.fill_color) { status->ctx.aspect.fill_color = col; status->ctx.redraw_flags = CTX_APP_DIRTY; } } if (!eff->draw_background) return; if (eff->back_stack == eff->surface->back_stack) eff->surface->render->back_color = MAKE_ARGB_FLOAT(1.0, bck->backColor.red, bck->backColor.green, bck->backColor.blue); if (eff->parent) { group2d_add_to_context_list(eff->parent, &status->ctx); } else if (eff->trav_flags & TF_RENDER_DIRECT) { bcks->node->Draw(&status->ctx); } }
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; }
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); }