This source file includes following definitions.
- clean_paths
- new_fs_item
- build_shape
- fs_traverse
- compositor_init_hc_flashshape
#include "nodes_stacks.h"
#include "visual_manager.h"
#ifndef GPAC_DISABLE_3D
#include <gpac/internal/mesh.h>
#endif
typedef struct
{
GF_Path *path;
Fixed width;
u32 fill_col, line_col;
#ifndef GPAC_DISABLE_3D
GF_Mesh *mesh;
#endif
} FSItem;
typedef struct
{
GF_Compositor *compositor;
Drawable *drawable;
GF_Rect bounds;
GF_List *items;
Fixed max_width;
} FSStack;
static void clean_paths(FSStack *stack)
{
while (gf_list_count(stack->items)) {
FSItem *it = (FSItem*)gf_list_get(stack->items, 0);
gf_list_rem(stack->items, 0);
if (it->path) gf_path_del(it->path);
#ifndef GPAC_DISABLE_3D
if (it->mesh) mesh_free(it->mesh);
#endif
gf_free(it);
}
}
static FSItem *new_fs_item(FSStack *st, u32 line_col, u32 fill_col, Fixed width)
{
FSItem *item;
GF_SAFEALLOC(item, FSItem);
if (!item) return NULL;
gf_list_add(st->items, item);
item->fill_col = fill_col;
item->width = width;
item->line_col = line_col;
item->path = gf_path_new();
return item;
}
#define SFCOL_MAKE_ARGB(c) GF_COL_ARGB_FIXED(FIX_ONE, c.red, c.green, c.blue);
static void build_shape(FSStack *st, GF_Node *node)
{
GF_FieldInfo field;
MFVec2f *coords;
MFInt32 *com, *widthIndex, *lineIndex, *fillIndex, *coordIndex;
MFFloat *widths;
MFColor *colors;
u32 wi, li, fi, ci, command, i, has_ci;
FSItem *fill_item, *line_item;
Fixed w;
SFVec2f cur, pt, ct1= {0,0}, ct2, *pts;
GF_Rect rc;
u32 line_col, fill_col;
Bool need_line, need_fill;
gf_node_get_field(node, 0, &field);
coords = (MFVec2f*)field.far_ptr;
gf_node_get_field(node, 1, &field);
com = (MFInt32*)field.far_ptr;
gf_node_get_field(node, 2, &field);
widths = (MFFloat*)field.far_ptr;
gf_node_get_field(node, 3, &field);
colors = (MFColor*)field.far_ptr;
gf_node_get_field(node, 4, &field);
widthIndex = (MFInt32*)field.far_ptr;
gf_node_get_field(node, 5, &field);
lineIndex = (MFInt32*)field.far_ptr;
gf_node_get_field(node, 6, &field);
fillIndex = (MFInt32*)field.far_ptr;
gf_node_get_field(node, 7, &field);
coordIndex = (MFInt32*)field.far_ptr;
wi = li = fi = ci = 0;
w = 0;
st->max_width = 0;
cur.x = cur.y = 0;
fill_item = line_item = NULL;
need_line = need_fill = GF_FALSE;
cur.x = cur.y = 0;
has_ci = coordIndex->count ? 1 : 0;
pts = coords->vals;
line_col = fill_col = 0;
for (command=0; command<com->count; command++) {
switch (com->vals[command]) {
case 0:
if (wi >= widthIndex->count) return;
w = (widthIndex->vals[wi]==-1) ? 0 : widths->vals[widthIndex->vals[wi]];
if (!w)
line_item = NULL;
else {
need_line = GF_TRUE;
if (st->max_width<w) st->max_width = w;
}
wi++;
break;
case 1:
if (li > lineIndex->count) return;
if (w) {
line_col = SFCOL_MAKE_ARGB(colors->vals[lineIndex->vals[li]]);
need_line = GF_TRUE;
}
li++;
break;
case 2:
if (fi >= fillIndex->count) return;
if (fillIndex->vals[fi]==-1) {
fill_col = 0;
fill_item = NULL;
} else {
fill_col = SFCOL_MAKE_ARGB(colors->vals[fillIndex->vals[fi]]);
need_fill = GF_TRUE;
}
fi++;
break;
case 3:
if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return;
if (need_fill) {
fill_item = new_fs_item(st, 0, fill_col, 0);
need_fill = GF_FALSE;
}
if (need_line) {
line_item = new_fs_item(st, line_col, 0, w);
need_line = GF_FALSE;
}
if (has_ci) {
pt = pts[coordIndex->vals[ci]];
} else {
pt = pts[ci];
}
if (fill_item) gf_path_add_move_to(fill_item->path, pt.x, pt.y);
if (line_item) gf_path_add_move_to(line_item->path, pt.x, pt.y);
ct1 = pt;
cur = pt;
ci++;
break;
case 4:
if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return;
if (need_fill) {
fill_item = new_fs_item(st, 0, fill_col, 0);
gf_path_add_move_to(fill_item->path, cur.x, cur.y);
need_fill = GF_FALSE;
}
if (need_line) {
line_item = new_fs_item(st, line_col, 0, w);
gf_path_add_move_to(line_item->path, cur.x, cur.y);
need_line = GF_FALSE;
}
if (has_ci) {
pt = pts[coordIndex->vals[ci]];
} else {
pt = pts[ci];
}
if (fill_item) gf_path_add_line_to(fill_item->path, pt.x, pt.y);
if (line_item) gf_path_add_line_to(line_item->path, pt.x, pt.y);
cur = pt;
ci++;
break;
case 5:
if ((has_ci && ci + 2 >= coordIndex->count) || (!has_ci && ci + 2>= coords->count) ) return;
if (need_fill) {
fill_item = new_fs_item(st, 0, fill_col, 0);
gf_path_add_move_to(fill_item->path, cur.x, cur.y);
need_fill = GF_FALSE;
}
if (need_line) {
line_item = new_fs_item(st, line_col, 0, w);
gf_path_add_move_to(line_item->path, cur.x, cur.y);
need_line = GF_FALSE;
}
if (has_ci) {
ct1 = pts[coordIndex->vals[ci]];
ct2 = pts[coordIndex->vals[ci+1]];
pt = pts[coordIndex->vals[ci+2]];
} else {
ct1 = pts[ci];
ct2 = pts[ci+1];
pt = pts[ci+2];
}
if (fill_item) gf_path_add_cubic_to(fill_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y);
if (line_item) gf_path_add_cubic_to(line_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y);
ct1 = ct2;
cur = pt;
ci += 3;
break;
case 6:
if ((has_ci && ci + 1 >= coordIndex->count) || (!has_ci && ci + 1>= coords->count) ) return;
if (need_fill) {
fill_item = new_fs_item(st, 0, fill_col, 0);
gf_path_add_move_to(fill_item->path, cur.x, cur.y);
need_fill = GF_FALSE;
}
if (need_line) {
line_item = new_fs_item(st, line_col, 0, w);
gf_path_add_move_to(line_item->path, cur.x, cur.y);
need_line = GF_FALSE;
}
ct1.x = 2*cur.x - ct1.x;
ct1.y = 2*cur.y - ct1.y;
if (has_ci) {
ct2 = pts[coordIndex->vals[ci]];
pt = pts[coordIndex->vals[ci+1]];
} else {
ct2 = pts[ci];
pt = pts[ci+1];
}
if (fill_item) gf_path_add_cubic_to(fill_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y);
if (line_item) gf_path_add_cubic_to(line_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y);
ct1 = ct2;
cur = pt;
ci += 2;
break;
case 7:
if ((has_ci && ci + 1 >= coordIndex->count) || (!has_ci && ci + 1>= coords->count) ) return;
if (need_fill) {
fill_item = new_fs_item(st, 0, fill_col, 0);
gf_path_add_move_to(fill_item->path, cur.x, cur.y);
need_fill = GF_FALSE;
}
if (need_line) {
line_item = new_fs_item(st, line_col, 0, w);
gf_path_add_move_to(line_item->path, cur.x, cur.y);
need_line = GF_FALSE;
}
if (has_ci) {
ct1 = pts[coordIndex->vals[ci]];
pt = pts[coordIndex->vals[ci+1]];
} else {
ct1 = pts[ci];
pt = pts[ci+1];
}
if (fill_item) gf_path_add_quadratic_to(fill_item->path, ct1.x, ct1.y, pt.x, pt.y);
if (line_item) gf_path_add_quadratic_to(line_item->path, ct1.x, ct1.y, pt.x, pt.y);
cur = pt;
ci += 2;
break;
case 8:
if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return;
if (need_fill) {
fill_item = new_fs_item(st, 0, fill_col, 0);
gf_path_add_move_to(fill_item->path, cur.x, cur.y);
need_fill = GF_FALSE;
}
if (need_line) {
line_item = new_fs_item(st, line_col, 0, w);
gf_path_add_move_to(line_item->path, cur.x, cur.y);
need_line = GF_FALSE;
}
ct1.x = 2*cur.x - ct1.x;
ct1.y = 2*cur.y - ct1.y;
if (has_ci) {
pt = pts[coordIndex->vals[ci]];
} else {
pt = pts[ci];
}
if (fill_item) gf_path_add_quadratic_to(fill_item->path, ct1.x, ct1.y, pt.x, pt.y);
if (line_item) gf_path_add_quadratic_to(line_item->path, ct1.x, ct1.y, pt.x, pt.y);
cur = pt;
ci += 2;
break;
case 9:
if (fill_item) gf_path_close(fill_item->path);
if (line_item) gf_path_close(line_item->path);
break;
}
}
st->bounds.width = st->bounds.height = 0;
for (i=0; i<gf_list_count(st->items); i++) {
line_item = (FSItem*)gf_list_get(st->items, i);
gf_path_get_bounds(line_item->path, &rc);
gf_rect_union(&st->bounds, &rc);
}
}
static void fs_traverse(GF_Node *node, void *rs, Bool is_destroy)
{
u32 i;
DrawableContext *ctx;
FSStack *st = (FSStack *) gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState*)rs;
if (is_destroy) {
clean_paths(st);
drawable_del(st->drawable);
gf_list_del(st->items);
gf_free(st);
return;
}
if (gf_node_dirty_get(node)) {
gf_node_dirty_clear(node, 0);
clean_paths(st);
build_shape(st, node);
}
switch (tr_state->traversing_mode) {
case TRAVERSE_DRAW_2D:
ctx = tr_state->ctx;
for (i=0; i<gf_list_count(st->items); i++) {
FSItem *item = (FSItem*)gf_list_get(st->items, i);
ctx->flags &= ~(CTX_PATH_FILLED | CTX_PATH_STROKE);
memset(&ctx->aspect, 0, sizeof(DrawAspect2D));
if (item->fill_col) {
ctx->aspect.fill_color = item->fill_col;
}
if (item->width) {
ctx->aspect.line_color = item->line_col;
ctx->aspect.pen_props.width = item->width;
}
visual_2d_draw_path(tr_state->visual, item->path, ctx, NULL, NULL, tr_state);
}
return;
#ifndef GPAC_DISABLE_3D
case TRAVERSE_DRAW_3D:
ctx = tr_state->ctx;
for (i=0; i<gf_list_count(st->items); i++) {
FSItem *item = (FSItem*)gf_list_get(st->items, i);
memset(&ctx->aspect, 0, sizeof(DrawAspect2D));
if (item->fill_col) {
ctx->aspect.fill_color = item->fill_col;
}
if (item->width) {
ctx->aspect.line_color = item->line_col;
ctx->aspect.pen_props.width = item->width;
}
if (!item->mesh) {
item->mesh = new_mesh();
mesh_from_path(item->mesh, item->path);
}
st->drawable->mesh = item->mesh;
visual_3d_draw_2d_with_aspect(st->drawable, tr_state, &ctx->aspect);
st->drawable->mesh = NULL;
}
return;
#endif
case TRAVERSE_PICK:
return;
case TRAVERSE_GET_BOUNDS:
tr_state->bounds = st->bounds;
return;
case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) return;
#endif
#ifndef GPAC_DISABLE_VRML
ctx = drawable_init_context_mpeg4(st->drawable, tr_state);
#else
ctx = NULL;
#endif
if (!ctx) return;
if (st->max_width) {
ctx->aspect.pen_props.width = st->max_width;
}
drawable_finalize_sort(ctx, tr_state, &st->bounds);
break;
}
}
void compositor_init_hc_flashshape(GF_Compositor *compositor, GF_Node *node)
{
FSStack *stack;
GF_SAFEALLOC(stack, FSStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate flashshape proto stack\n"));
return;
}
stack->drawable = drawable_new();
stack->drawable->node = node;
stack->drawable->flags = DRAWABLE_USE_TRAVERSE_DRAW;
stack->items = gf_list_new();
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, fs_traverse);
}