📄 drawable.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / 2D rendering module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "drawable.h"#include "visualsurface2d.h"#include "stacks2d.h"#ifndef GPAC_DISABLE_SVG#include "svg_stacks.h"#endif/*default rendering routine*/void drawable_draw(RenderEffect2D *eff) { VS2D_TexturePath(eff->surface, eff->ctx->drawable->path, eff->ctx); VS2D_DrawPath(eff->surface, eff->ctx->drawable->path, eff->ctx, NULL, NULL);}/*default point_over routine*/void drawable_pick(RenderEffect2D *eff){ GF_Matrix2D inv; StrikeInfo2D *si; Fixed x, y; if (!eff->ctx || !eff->ctx->drawable->path) return; assert(eff->surface); gf_mx2d_copy(inv, eff->ctx->transform); gf_mx2d_inverse(&inv); x = eff->x; y = eff->y; gf_mx2d_apply_coords(&inv, &x, &y); if (eff->ctx->h_texture || (eff->pick_type<PICK_FULL) || GF_COL_A(eff->ctx->aspect.fill_color) || (eff->ctx->flags & CTX_SVG_PICK_PATH) ) { if (gf_path_point_over(eff->ctx->drawable->path, x, y)) { eff->is_over = 1; return; } } if (eff->ctx->aspect.pen_props.width || eff->ctx->aspect.line_texture || (eff->pick_type!=PICK_PATH) || (eff->ctx->flags & CTX_SVG_PICK_OUTLINE) ) { si = drawctx_get_strikeinfo(eff->surface->render, eff->ctx, NULL); if (si && si->outline && gf_path_point_over(si->outline, x, y)) { eff->is_over = 1; } }}Drawable *drawable_new(){ Drawable *tmp; GF_SAFEALLOC(tmp, Drawable) tmp->path = gf_path_new(); /*allocate a default surface container*/ GF_SAFEALLOC(tmp->dri, DRInfo); /*allocate a default bounds container*/ GF_SAFEALLOC(tmp->dri->current_bounds, BoundInfo); return tmp;}void drawable_reset_bounds(Drawable *dr, VisualSurface2D *surf){ DRInfo *dri; BoundInfo *bi, *_cur; dri = dr->dri; while (dri) { if (dri->surface != surf) { dri = dri->next; continue; } /*destroy previous bounds only, since current ones are always used during traversing*/ bi = dri->previous_bounds; while (bi) { _cur = bi; bi = bi->next; free(_cur); } dri->previous_bounds = NULL; return; }}void drawable_del_ex(Drawable *dr, Render2D *r2d){ StrikeInfo2D *si; Bool is_reg = 0; DRInfo *dri, *cur; BoundInfo *bi, *_cur; /*remove node from all surfaces it's on*/ dri = dr->dri; while (dri) { is_reg = R2D_IsSurfaceRegistered(r2d, dri->surface); bi = dri->current_bounds; while (bi) { _cur = bi; if (is_reg) ra_add(&dri->surface->to_redraw, &bi->clip); bi = bi->next; free(_cur); } bi = dri->previous_bounds; while (bi) { _cur = bi; if (is_reg) ra_add(&dri->surface->to_redraw, &bi->clip); bi = bi->next; free(_cur); } if (is_reg) VS2D_DrawableDeleted(dri->surface, dr); cur = dri; dri = dri->next; free(cur); } r2d->compositor->draw_next_frame = 1; /*remove path object*/ if (dr->path) gf_path_del(dr->path); si = dr->outline; while (si) { StrikeInfo2D *next = si->next; /*remove from main strike list*/ if (r2d) gf_list_del_item(r2d->strike_bank, si); delete_strikeinfo2d(si); si = next; } free(dr);}void drawable_del(Drawable *dr){ GF_Renderer *sr = gf_sr_get_renderer(dr->node); drawable_del_ex(dr, sr ? sr->visual_renderer->user_priv : NULL);}void DestroyDrawableNode(GF_Node *node){ drawable_del( (Drawable *)gf_node_get_private(node) );}Drawable *drawable_stack_new(Render2D *sr, GF_Node *node){ Drawable *stack = drawable_new(); stack->node = node; gf_node_set_private(node, stack); return stack;}static BoundInfo *drawable_check_alloc_bounds(struct _drawable_context *ctx, VisualSurface2D *surf){ DRInfo *dri, *prev; BoundInfo *bi, *_prev; /*get bounds info for this surface*/ prev = NULL; dri = ctx->drawable->dri; while (dri) { if (dri->surface == surf) break; if (!dri->surface) { dri->surface = surf; break; } prev = dri; dri = dri->next; } if (!dri) { GF_SAFEALLOC(dri, DRInfo); dri->surface = surf; if (prev) prev->next = dri; else ctx->drawable->dri = dri; } /*get available bound info slot*/ _prev = NULL; bi = dri->current_bounds; while (bi) { if (!bi->clip.width) break; _prev = bi; bi = bi->next; } if (!bi) { GF_SAFEALLOC(bi, BoundInfo); if (_prev) { assert(!_prev->next); _prev->next = bi; } else { assert(!dri->current_bounds); dri->current_bounds = bi; } GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Allocating new bound info for drawable %s\n", gf_node_get_class_name(ctx->drawable->node))); } /*reset next bound info*/ if (bi->next) bi->next->clip.width = 0; return bi;}/*move current bounds to previous bounds*/Bool drawable_flush_bounds(Drawable *drawable, struct _visual_surface_2D *on_surface, u32 render_mode){ Bool was_drawn; DRInfo *dri; BoundInfo *tmp; /*reset node modified flag*/ drawable->flags &= ~DRAWABLE_HAS_CHANGED; dri = drawable->dri; while (dri) { if (dri->surface == on_surface) break; dri = dri->next; } if (!dri) return 0; was_drawn = (dri->current_bounds && dri->current_bounds->clip.width) ? 1 : 0; if (render_mode) { /*permanent direct rendering, destroy previous bounds*/ if (render_mode==1) { if (dri->previous_bounds) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Destroying previous bounds info for drawable %s\n", gf_node_get_class_name(drawable->node))); while (dri->previous_bounds) { BoundInfo *bi = dri->previous_bounds; dri->previous_bounds = bi->next; free(bi); } } } } /*indirect rendering, flush bounds*/ else { tmp = dri->previous_bounds; dri->previous_bounds = dri->current_bounds; dri->current_bounds = tmp; } /*reset first allocated bound*/ if (dri->current_bounds) dri->current_bounds->clip.width = 0; drawable->flags &= ~DRAWABLE_DRAWN_ON_SURFACE; return was_drawn;} /* return 1 if same bound is found in previous list (and remove it from the list) return 0 otherwise*/Bool drawable_has_same_bounds(struct _drawable_context *ctx, struct _visual_surface_2D *surf){ DRInfo *dri; BoundInfo *bi; dri = ctx->drawable->dri; while (dri) { if (dri->surface == surf) break; dri = dri->next; } if (!dri) return 0; bi = dri->previous_bounds; while (bi) { if ( /*if 0, end of bounds used in the previous pass*/ bi->clip.width /*we need the same Appearance || parent <use>*/ && (bi->extra_check == ctx->appear) /*we need exact same cliper*/ && (bi->clip.x==ctx->bi->clip.x) && (bi->clip.y==ctx->bi->clip.y) && (bi->clip.width==ctx->bi->clip.width) && (bi->clip.height==ctx->bi->clip.height) /*only check x and y (if w or h have changed, object has changed -> bounds info has been reset*/ && (bi->unclip.x==ctx->bi->unclip.x) && (bi->unclip.y==ctx->bi->unclip.y) ) { /*remove*/ bi->clip.width = 0; return 1; } bi = bi->next; } return 0;}/* return any previous bounds related to the same surface in @rc if any if nothing found return 0*/Bool drawable_get_previous_bound(Drawable *drawable, GF_IRect *rc, struct _visual_surface_2D *surf){ DRInfo *dri; BoundInfo *bi; dri = drawable->dri; while (dri) { if (dri->surface == surf) break; dri = dri->next; } if (!dri) return 0; bi = dri->previous_bounds; while (bi) { if (bi->clip.width) { *rc = bi->clip; bi->clip.width = 0; return 1; } bi = bi->next; } return 0;}DrawableContext *NewDrawableContext(){ DrawableContext *tmp; GF_SAFEALLOC(tmp, DrawableContext); return tmp;}void DeleteDrawableContext(DrawableContext *ctx){ drawctx_reset(ctx); free(ctx);}void drawctx_reset(DrawableContext *ctx){ DrawableContext *next = ctx->next; drawctx_reset_sensors(ctx); if (ctx->col_mat) free(ctx->col_mat); memset(ctx, 0, sizeof(DrawableContext)); ctx->next = next; /*by default all nodes are transparent*/ ctx->flags |= CTX_IS_TRANSPARENT; /*BIFS has default value for 2D appearance ...*/ ctx->aspect.fill_color = 0xFFCCCCCC; ctx->aspect.line_color = 0xFFCCCCCC; ctx->aspect.pen_props.width = FIX_ONE; ctx->aspect.pen_props.cap = GF_LINE_CAP_FLAT; ctx->aspect.pen_props.join = GF_LINE_JOIN_BEVEL; ctx->aspect.pen_props.miterLimit = 4*FIX_ONE;}void drawctx_reset_sensors(DrawableContext *ctx){ SensorContext *sc = ctx->sensor; while (sc) { SensorContext *cur = sc; sc = sc->next; free(cur); } ctx->sensor = NULL;}static void drawctx_add_sensor(DrawableContext *ctx, SensorContext *handler){ SensorContext *sc = (SensorContext *)malloc(sizeof(SensorContext)); sc->h_node = handler->h_node; sc->next = NULL; gf_mx2d_copy(sc->matrix, handler->matrix); if (!ctx->sensor) { ctx->sensor = sc; } else { SensorContext *cur = ctx->sensor; while (cur->next) cur = cur->next; cur->next = sc; }}void drawctx_update_info(DrawableContext *ctx, struct _visual_surface_2D *surf){ DRInfo *dri; Bool moved, need_redraw, drawn; need_redraw = (ctx->flags & CTX_REDRAW_MASK) ? 1 : 0; drawn = 0; dri = ctx->drawable->dri; while (dri) { if (dri->surface==surf) { if (dri->current_bounds && dri->current_bounds->clip.width) drawn = 1; break; } dri = dri->next; } if (drawn) { ctx->drawable->flags |= DRAWABLE_DRAWN_ON_SURFACE; /*node has been modified, do not check bounds, just assumed it moved*/ if (ctx->drawable->flags & DRAWABLE_HAS_CHANGED) { moved = 1; } else { /*check if same bounds are used*/ moved = !drawable_has_same_bounds(ctx, surf); } if (need_redraw || moved) ctx->flags |= CTX_REDRAW_MASK; } /*in all cases reset dirty flag of appearance and its sub-nodes*/ //if (ctx->flags & CTX_HAS_APPEARANCE) gf_node_dirty_reset(ctx->appear);}static void setup_drawable_context(DrawableContext *ctx, RenderEffect2D *eff){ M_Material2D *m = NULL; M_LineProperties *LP; M_XLineProperties *XLP; if (ctx->appear == NULL) goto check_default; m = (M_Material2D *) ((M_Appearance *)ctx->appear)->material; if ( m == NULL) { ctx->aspect.fill_color &= 0x00FFFFFF; goto check_default; } if (gf_node_get_tag((GF_Node *) m) != TAG_MPEG4_Material2D) return; ctx->aspect.fill_color = GF_COL_ARGB_FIXED(FIX_ONE-m->transparency, m->emissiveColor.red, m->emissiveColor.green, m->emissiveColor.blue); if (ctx->col_mat) ctx->aspect.fill_color = gf_cmx_apply(ctx->col_mat, ctx->aspect.fill_color); ctx->aspect.line_color = ctx->aspect.fill_color; if (!m->filled) ctx->aspect.fill_color &= 0x00FFFFFF; ctx->aspect.pen_props.cap = GF_LINE_CAP_FLAT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -