This source file includes following definitions.
- gf_irect_overlaps
- gf_irect_intersect
- gf_rect_ft
- visual_2d_get_drawable_context
- visual_2d_remove_last_context
- visual_2d_drawable_delete
- visual_2d_node_cull
- visual_2d_setup_projection
- visual_2d_init_draw
- gf_irect_inside
- gf_irect_union
- ra_union_rect
- gf_irect_relation
- ra_refresh
- register_context_rect
- register_dirty_rect
- visual_2d_terminate_draw
- visual_2d_draw_frame
- visual_2d_pick_node
#include "visual_manager.h"
#include "nodes_stacks.h"
Bool gf_irect_overlaps(GF_IRect *rc1, GF_IRect *rc2)
{
if (! rc2->height || !rc2->width || !rc1->height || !rc1->width) return 0;
if (rc2->x+rc2->width<=rc1->x) return 0;
if (rc2->x>=rc1->x+rc1->width) return 0;
if (rc2->y-rc2->height>=rc1->y) return 0;
if (rc2->y<=rc1->y-rc1->height) return 0;
return 1;
}
void gf_irect_intersect(GF_IRect *rc1, GF_IRect *rc2)
{
if (! gf_irect_overlaps(rc1, rc2)) {
rc1->width = rc1->height = 0;
return;
}
if (rc2->x > rc1->x) {
rc1->width -= rc2->x - rc1->x;
rc1->x = rc2->x;
}
if (rc2->x + rc2->width < rc1->x + rc1->width) {
rc1->width = rc2->width + rc2->x - rc1->x;
}
if (rc2->y < rc1->y) {
rc1->height -= rc1->y - rc2->y;
rc1->y = rc2->y;
}
if (rc2->y - rc2->height > rc1->y - rc1->height) {
rc1->height = rc1->y - rc2->y + rc2->height;
}
}
GF_Rect gf_rect_ft(GF_IRect *rc)
{
GF_Rect rcft;
rcft.x = INT2FIX(rc->x);
rcft.y = INT2FIX(rc->y);
rcft.width = INT2FIX(rc->width);
rcft.height = INT2FIX(rc->height);
return rcft;
}
DrawableContext *visual_2d_get_drawable_context(GF_VisualManager *visual)
{
#ifdef SKIP_CONTEXT
return NULL;
#endif
if (!visual->context) {
visual->context = NewDrawableContext();
visual->cur_context = visual->context;
drawctx_reset(visual->context);
visual->num_nodes_current_frame ++;
return visual->context;
}
if (!visual->cur_context->drawable) {
if (visual->cur_context->next) visual->cur_context->next->drawable = NULL;
drawctx_reset(visual->cur_context);
return visual->cur_context;
}
if (visual->cur_context->next) {
visual->cur_context = visual->cur_context->next;
if (visual->cur_context->next) visual->cur_context->next->drawable = NULL;
drawctx_reset(visual->cur_context);
visual->num_nodes_current_frame ++;
return visual->cur_context;
}
visual->cur_context->next = NewDrawableContext();
visual->cur_context = visual->cur_context->next;
drawctx_reset(visual->cur_context);
visual->num_nodes_current_frame ++;
#if 0
{
u32 i;
DrawableContext *last = visual->cur_context;
for (i=0; i<50; i++) {
last->next = gf_malloc(sizeof(DrawableContext));
last = last->next;
last->drawable = NULL;
last->col_mat = NULL;
}
last->next = NULL;
}
#endif
return visual->cur_context;
}
void visual_2d_remove_last_context(GF_VisualManager *visual)
{
assert(visual->cur_context);
visual->cur_context->drawable = NULL;
}
void visual_2d_drawable_delete(GF_VisualManager *visual, struct _drawable *drawable)
{
DrawableContext *ctx;
struct _drawable_store *it = visual->prev_nodes;
struct _drawable_store *prev = NULL;
while (it) {
if (it->drawable != drawable) {
prev = it;
it = prev->next;
continue;
}
if (prev) prev->next = it->next;
else visual->prev_nodes = it->next;
if (!it->next) visual->last_prev_entry = prev;
gf_free(it);
break;
}
ctx = visual->context;
while (ctx && ctx->drawable) {
if (ctx->drawable == drawable) {
ctx->flags = 0;
ctx->drawable = NULL;
}
ctx = ctx->next;
}
if (drawable->flags & DRAWABLE_IS_OVERLAY) {
visual->compositor->video_out->Blit(visual->compositor->video_out, NULL, NULL, NULL, 1);
}
}
Bool visual_2d_node_cull(GF_TraverseState *tr_state, GF_Rect *bounds)
{
GF_Rect rc;
GF_IRect i_rc;
rc = *bounds;
gf_mx2d_apply_rect(&tr_state->transform, &rc);
i_rc = gf_rect_pixelize(&rc);
if (gf_irect_overlaps(&tr_state->visual->top_clipper, &i_rc)) return 1;
return 0;
}
void visual_2d_setup_projection(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
GF_Rect rc;
tr_state->visual = visual;
#ifndef GPAC_DISABLE_VRML
tr_state->backgrounds = visual->back_stack;
tr_state->viewpoints = visual->view_stack;
#endif
if (visual->center_coords) {
if (!visual->offscreen) {
if (visual->compositor->scalable_zoom)
rc = gf_rect_center(INT2FIX(visual->compositor->display_width), INT2FIX(visual->compositor->display_height));
else
rc = gf_rect_center(INT2FIX(visual->compositor->output_width + 2*visual->compositor->vp_x), INT2FIX(visual->compositor->output_height + 2*visual->compositor->vp_y));
} else {
rc = gf_rect_center(INT2FIX(visual->width), INT2FIX(visual->height));
}
} else {
rc.x = 0;
rc.width = INT2FIX(visual->width);
rc.y = rc.height = INT2FIX(visual->height);
}
if (!tr_state->pixel_metrics) gf_mx2d_add_scale(&tr_state->transform, tr_state->min_hsize, tr_state->min_hsize);
visual->surf_rect = gf_rect_pixelize(&rc);
if (visual->center_coords) {
rc = gf_rect_center(INT2FIX(visual->width), INT2FIX(visual->height));
} else {
rc.width = INT2FIX(visual->width);
rc.height = INT2FIX(visual->height);
rc.x = 0;
rc.y = rc.height;
if (visual->compositor->visual==visual) {
rc.x += INT2FIX(visual->compositor->vp_x);
rc.y += INT2FIX(visual->compositor->vp_y);
}
}
#ifndef GPAC_DISABLE_VRML
if (gf_list_count(visual->view_stack)) {
tr_state->traversing_mode = TRAVERSE_BINDABLE;
tr_state->bounds = rc;
gf_node_traverse((GF_Node *) gf_list_get(visual->view_stack, 0), tr_state);
}
#endif
#ifndef GPAC_DISABLE_3D
gf_mx_init(tr_state->model_matrix);
if (tr_state->camera && (visual->compositor->visual==visual)) {
tr_state->camera->vp.width = INT2FIX(visual->compositor->output_width);
tr_state->camera->vp.height = INT2FIX(visual->compositor->output_height);
}
#endif
visual->top_clipper = gf_rect_pixelize(&rc);
tr_state->clipper = rc;
}
GF_Err visual_2d_init_draw(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
GF_Err e;
u32 rem, count;
struct _drawable_store *it, *prev;
#ifndef GPAC_DISABLE_VRML
DrawableContext *ctx;
M_Background2D *bck;
#endif
u32 draw_mode;
visual->cur_context = visual->context;
if (visual->context) visual->context->drawable = NULL;
visual->has_modif = 0;
visual->has_overlays = 0;
visual_2d_setup_projection(visual, tr_state);
if (!visual->top_clipper.width || !visual->top_clipper.height)
return GF_OK;
tr_state->traversing_mode = TRAVERSE_SORT;
visual->num_nodes_current_frame = 0;
e = visual_2d_init_raster(visual);
if (e)
return e;
tr_state->immediate_for_defer = GF_FALSE;
draw_mode = 0;
if (tr_state->immediate_draw) {
draw_mode = 1;
}
else if (tr_state->invalidate_all) {
tr_state->immediate_draw = 1;
tr_state->immediate_for_defer = GF_TRUE;
draw_mode = 2;
}
tr_state->invalidate_all = 0;
rem = count = 0;
prev = NULL;
it = visual->prev_nodes;
while (it) {
if (!drawable_flush_bounds(it->drawable, visual, draw_mode)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Unregistering previously drawn node %s from visual\n", gf_node_get_class_name(it->drawable->node)));
drawable_reset_bounds(it->drawable, visual);
if (prev) prev->next = it->next;
else visual->prev_nodes = it->next;
if (!it->next) visual->last_prev_entry = prev;
rem++;
gf_free(it);
it = prev ? prev->next : visual->prev_nodes;
} else {
it->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL;
prev = it;
it = it->next;
count++;
}
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Top visual initialized - %d nodes registered and %d removed - using %s rendering\n", count, rem, draw_mode ? "direct" : "dirty-rect"));
if (!draw_mode) return GF_OK;
#ifndef GPAC_DISABLE_VRML
bck = (M_Background2D*) gf_list_get(visual->back_stack, 0);
if (bck && bck->isBound) {
ctx = b2d_get_context(bck, visual->back_stack);
if (ctx) {
if (ctx->aspect.fill_texture &&ctx->aspect.fill_texture->stream) {
ctx->bi->clip = visual->top_clipper;
} else {
ctx->bi->clip = visual->surf_rect;
}
ctx->bi->unclip = gf_rect_ft(&ctx->bi->clip);
tr_state->traversing_mode = TRAVERSE_BINDABLE;
ctx->flags |= CTX_BACKROUND_NOT_LAYER;
gf_node_traverse((GF_Node *) bck, tr_state);
tr_state->traversing_mode = TRAVERSE_SORT;
ctx->flags &= ~CTX_BACKROUND_NOT_LAYER;
} else {
visual->ClearSurface(visual, NULL, 0, 0);
}
} else
#endif
{
visual->ClearSurface(visual, NULL, 0, 0);
#ifndef GPAC_DISABLE_3D
if (visual->compositor->hybrid_opengl) {
visual->ClearSurface(visual, NULL, 0, GF_TRUE);
}
#endif
}
return GF_OK;
}
Bool gf_irect_inside(GF_IRect *rc1, GF_IRect *rc2)
{
if (!rc1->width || !rc1->height) return 0;
if ( (rc1->x <= rc2->x) && (rc1->y >= rc2->y) && (rc1->x + rc1->width >= rc2->x + rc2->width) && (rc1->y - rc1->height <= rc2->y - rc2->height) )
return 1;
return 0;
}
#define ra_clear(ra) { (ra)->count = 0; }
#define ra_is_empty(ra) (!((ra)->count))
void gf_irect_union(GF_IRect *rc1, GF_IRect *rc2)
{
if (!rc1->width || !rc1->height) {
*rc1=*rc2;
return;
}
if (rc2->x < rc1->x) {
rc1->width += rc1->x - rc2->x;
rc1->x = rc2->x;
}
if (rc2->x + rc2->width > rc1->x+rc1->width) rc1->width = rc2->x + rc2->width - rc1->x;
if (rc2->y > rc1->y) {
rc1->height += rc2->y - rc1->y;
rc1->y = rc2->y;
}
if (rc2->y - rc2->height < rc1->y - rc1->height) rc1->height = rc1->y - rc2->y + rc2->height;
}
void ra_union_rect(GF_RectArray *ra, GF_IRect *rc)
{
u32 i;
assert(rc->width && rc->height);
for (i=0; i<ra->count; i++) {
if (gf_irect_overlaps(&ra->list[i].rect, rc)) {
gf_irect_union(&ra->list[i].rect, rc);
return;
}
}
ra_add(ra, rc);
}
static u32 gf_irect_relation(GF_IRect *rc1, GF_IRect *rc2)
{
if (! rc2->height || !rc2->width || !rc1->height || !rc1->width) return 0;
if (rc2->x+rc2->width<=rc1->x) return 0;
if (rc2->x>=rc1->x+rc1->width) return 0;
if (rc2->y-rc2->height>=rc1->y) return 0;
if (rc2->y<=rc1->y-rc1->height) return 0;
if ( (rc2->x <= rc1->x) && (rc2->y >= rc1->y) && (rc2->x + rc2->width >= rc1->x + rc1->width) && (rc2->y - rc2->height <= rc1->y - rc1->height) )
return 2;
return 1;
}
void ra_refresh(GF_RectArray *ra)
{
u32 i, j, k;
restart:
for (i=0; i<ra->count; i++) {
for (j=i+1; j<ra->count; j++) {
switch (gf_irect_relation(&ra->list[j].rect, &ra->list[i].rect)) {
case 1:
gf_irect_union(&ra->list[i].rect, &ra->list[j].rect);
#ifdef TRACK_OPAQUE_REGIONS
ra->list[i].opaque_node_index = 0;
#endif
case 2:
k = ra->count - j - 1;
if (k) {
memmove(&ra->list[j], & ra->list[j+1], sizeof(GF_IRect)*k);
}
ra->count--;
if (ra->count>=2)
goto restart;
return;
default:
break;
}
}
}
}
static u32 register_context_rect(GF_RectArray *ra, DrawableContext *ctx, u32 ctx_idx, DrawableContext **first_opaque)
{
u32 i;
Bool needs_redraw;
#ifdef TRACK_OPAQUE_REGIONS
Bool is_transparent = 1;
#endif
GF_IRect *rc = &ctx->bi->clip;
assert(rc->width && rc->height);
needs_redraw = (ctx->flags & CTX_REDRAW_MASK) ? 1 : 0;
if ((ctx->flags & CTX_NO_ANTIALIAS) && !(ctx->flags & CTX_IS_TRANSPARENT) ) {
#ifdef TRACK_OPAQUE_REGIONS
is_transparent = 0;
#endif
if ((*first_opaque==NULL) && needs_redraw) *first_opaque = ctx;
}
#ifndef GPAC_DISABLE_3D
if (ctx->flags & CTX_HYBOGL_NO_CLEAR) {
return 2;
}
#endif
for (i=0; i<ra->count; i++) {
if (needs_redraw) {
switch (gf_irect_relation(&ra->list[i].rect, rc)) {
case 1:
gf_irect_union(&ra->list[i].rect, rc);
#ifdef TRACK_OPAQUE_REGIONS
ra->list[i].opaque_node_index = 0;
#endif
return 1;
case 2:
ra->list[i].rect= *rc;
#ifdef TRACK_OPAQUE_REGIONS
ra->list[i].opaque_node_index = is_transparent ? 0 : ctx_idx;
#endif
return 1;
}
}
#ifdef TRACK_OPAQUE_REGIONS
else if (!is_transparent && gf_irect_inside(rc, &ra->list[i].rect)) {
u32 k = ra->count - i - 1;
if (k) {
memmove(&ra->list[i], & ra->list[i+1], sizeof(GF_RectArrayEntry)*k);
}
ra->count--;
i--;
}
#endif
}
if (needs_redraw) {
ra_add(ra, rc);
#ifdef TRACK_OPAQUE_REGIONS
ra->list[ra->count-1].opaque_node_index = is_transparent ? 0 : ctx_idx;
#endif
}
return 1;
}
static void register_dirty_rect(GF_RectArray *ra, GF_IRect *rc)
{
if (!rc->width || !rc->height) return;
#if 0
#ifdef TRACK_OPAQUE_REGIONS
u32 i;
for (i=0; i<ra->count; i++) {
switch (gf_irect_relation(rc, &ra->list[i].rect)) {
case 1:
gf_irect_union(&ra->list[i].rect, rc);
ra->list[i].opaque_node_index = 0;
return;
case 2:
return;
}
}
#endif
ra_add(ra, rc);
#ifdef TRACK_OPAQUE_REGIONS
ra->list[ra->count-1].opaque_node_index = 0;
#endif
#else
ra_add(ra, rc);
#ifdef TRACK_OPAQUE_REGIONS
ra->list[ra->count-1].opaque_node_index = 0;
#endif
#endif
}
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;
u32 hyb_force_background = 0;
#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;
if (tr_state->immediate_draw) {
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;
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
#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_background = 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;
}
if (!redraw_all_on_background_change)
hyb_force_background = 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_background = 1;
} else if (!redraw_all_on_background_change) {
hyb_force_background = 1;
}
num_nodes = 0;
ctx = visual->context;
while (ctx && ctx->drawable) {
num_nodes++;
drawctx_update_info(ctx, visual);
if (!redraw_all) {
u32 res;
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;
}
prev = NULL;
it = visual->prev_nodes;
while (it) {
while (drawable_get_previous_bound(it->drawable, &refreshRect, visual)) {
if (!redraw_all) {
gf_irect_intersect(&refreshRect, &visual->top_clipper);
register_dirty_rect(&visual->to_redraw, &refreshRect);
has_clear=1;
}
}
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)));
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, 0);
}
}
if (ra_is_empty(&visual->to_redraw) ) {
if (!hyb_force_redraw && !hyb_force_background) {
#ifndef GPAC_DISABLE_3D
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;
}
if (hyb_force_redraw) {
hyb_force_background = 2;
ra_add(&visual->to_redraw, &visual->surf_rect);
}
}
has_changed = 1;
tr_state->traversing_mode = TRAVERSE_DRAW_2D;
if (!visual->compositor->hybrid_opengl && !hyb_force_redraw && !hyb_force_background && 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;
}
#ifndef GPAC_DISABLE_VRML
if (bck_ctx) {
drawable_check_bounds(bck_ctx, visual);
tr_state->ctx = bck_ctx;
tr_state->appear = NULL;
visual->draw_node_index = 0;
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;
if (hyb_force_background==2)
bck_ctx->flags |= CTX_BACKROUND_NO_CLEAR;
gf_node_traverse(bck_ctx->drawable->node, tr_state);
bck_ctx->flags &= ~CTX_BACKROUND_NOT_LAYER;
bck_ctx->flags &= ~CTX_BACKROUND_NO_CLEAR;
} else
#endif
{
#ifndef GPAC_DISABLE_3D
if (visual->compositor->hybrid_opengl) {
compositor_2d_hybgl_clear_surface(tr_state->visual, NULL, 0, GF_FALSE);
}
#endif
count = visual->to_redraw.count;
for (k=0; k<count; k++) {
GF_IRect rc;
#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, 1);
}
}
if (!visual->to_redraw.count) {
visual->has_modif=0;
#ifndef GPAC_DISABLE_3D
visual->nb_objects_on_canvas_since_last_ogl_flush = 1;
#endif
goto exit;
}
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 (! 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;
}
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:
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;
}
Bool visual_2d_draw_frame(GF_VisualManager *visual, GF_Node *root, GF_TraverseState *tr_state, Bool is_root_visual)
{
GF_SceneGraph *sg;
GF_Matrix2D backup;
u32 i;
Bool res;
GF_Err e;
#ifndef GPAC_DISABLE_LOG
u32 itime, time = gf_sys_clock();
#endif
gf_mx2d_copy(backup, tr_state->transform);
visual->bounds_tracker_modif_flag = DRAWABLE_HAS_CHANGED;
e = visual_2d_init_draw(visual, tr_state);
if (e) {
gf_mx2d_copy(tr_state->transform, backup);
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Visual2D] Cannot init draw phase: %s\n", gf_error_to_string(e)));
return 0;
}
#ifndef GPAC_DISABLE_LOG
itime = gf_sys_clock();
visual->compositor->traverse_setup_time = itime - time;
time = itime;
#endif
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Traversing scene subtree (root node %s)\n", root ? gf_node_get_class_name(root) : "none"));
if (is_root_visual) {
gf_node_traverse(root, tr_state);
i=0;
while ((sg = (GF_SceneGraph*)gf_list_enum(visual->compositor->extra_scenes, &i))) {
gf_sc_traverse_subscene(visual->compositor, root, sg, tr_state);
}
} else {
gf_node_traverse(root, tr_state);
}
#ifndef GPAC_DISABLE_LOG
itime = gf_sys_clock();
visual->compositor->traverse_and_direct_draw_time = itime - time;
time = itime;
#endif
gf_mx2d_copy(tr_state->transform, backup);
res = visual_2d_terminate_draw(visual, tr_state);
#ifndef GPAC_DISABLE_LOG
if (!tr_state->immediate_draw) {
visual->compositor->indirect_draw_time = gf_sys_clock() - time;
}
#endif
return res;
}
void visual_2d_pick_node(GF_VisualManager *visual, GF_TraverseState *tr_state, GF_Event *ev, GF_ChildNodeItem *children)
{
GF_Matrix2D backup;
visual->bounds_tracker_modif_flag = DRAWABLE_HAS_CHANGED_IN_LAST_TRAVERSE;
gf_mx2d_copy(backup, tr_state->transform);
visual_2d_setup_projection(visual, tr_state);
visual->compositor->hit_node = NULL;
tr_state->ray.orig.x = INT2FIX(ev->mouse.x);
tr_state->ray.orig.y = INT2FIX(ev->mouse.y);
tr_state->ray.orig.z = 0;
tr_state->ray.dir.x = 0;
tr_state->ray.dir.y = 0;
tr_state->ray.dir.z = -FIX_ONE;
visual->compositor->hit_world_point = tr_state->ray.orig;
visual->compositor->hit_world_ray = tr_state->ray;
visual->compositor->hit_square_dist = 0;
gf_list_reset(visual->compositor->sensors);
tr_state->traversing_mode = TRAVERSE_PICK;
if (visual->compositor->visual != visual) {
while (children) {
gf_node_traverse(children->node, tr_state);
children = children->next;
}
} else {
u32 i = 0;
GF_SceneGraph *sg = visual->compositor->scene;
GF_Node *root = gf_sg_get_root_node(sg);
gf_node_traverse(root, tr_state);
while ((sg = (GF_SceneGraph*)gf_list_enum(visual->compositor->extra_scenes, &i))) {
gf_sc_traverse_subscene(visual->compositor, root, sg, tr_state);
}
}
gf_mx2d_copy(tr_state->transform, backup);
}