1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2012
6 * All rights reserved
7 *
8 * This file is part of GPAC / Scene Compositor sub-project
9 *
10 * GPAC is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * GPAC is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26
27
28 #include "nodes_stacks.h"
29 #include "visual_manager.h"
30
31 #ifndef GPAC_DISABLE_VRML
32
ifs2d_check_changes(GF_Node * node,Drawable * stack,GF_TraverseState * tr_state)33 static void ifs2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
34 {
35 u32 i;
36 SFVec2f *pts;
37 u32 ci_count, c_count;
38 Bool started;
39 M_IndexedFaceSet2D *ifs2D;
40 M_Coordinate2D *coord;
41
42 if (! gf_node_dirty_get(node)) return;
43
44 ifs2D = (M_IndexedFaceSet2D *)node;
45 coord = (M_Coordinate2D *)ifs2D->coord;
46 drawable_reset_path(stack);
47 gf_node_dirty_clear(node, 0);
48 drawable_mark_modified(stack, tr_state);
49
50
51 c_count = coord->point.count;
52 ci_count = ifs2D->coordIndex.count;
53 pts = coord->point.vals;
54
55 if (ci_count > 0) {
56 started = 0;
57 for (i=0; i < ci_count; i++) {
58 if (ifs2D->coordIndex.vals[i] == -1) {
59 gf_path_close(stack->path);
60 started = 0;
61 } else if (!started) {
62 started = 1;
63 gf_path_add_move_to_vec(stack->path, &pts[ifs2D->coordIndex.vals[i]]);
64 } else {
65 gf_path_add_line_to_vec(stack->path, &pts[ifs2D->coordIndex.vals[i]]);
66 }
67 }
68 if (started) gf_path_close(stack->path);
69 } else if (c_count) {
70 gf_path_add_move_to_vec(stack->path, &pts[0]);
71 for (i=1; i < c_count; i++) {
72 gf_path_add_line_to_vec(stack->path, &pts[i]);
73 }
74 gf_path_close(stack->path);
75 }
76 }
77
78
IFS2D_Draw(GF_Node * node,GF_TraverseState * tr_state)79 static void IFS2D_Draw(GF_Node *node, GF_TraverseState *tr_state)
80 {
81 u32 i, count, ci_count;
82 #if 0 //unused
83 u32 j, ind_col, num_col;
84 SFVec2f center, end;
85 SFColor col_cen;
86 GF_EVGStencil *grad;
87 u32 *colors;
88 #endif
89 SFVec2f start;
90 SFVec2f *pts;
91 SFColor col;
92 Fixed alpha;
93 DrawableContext *ctx = tr_state->ctx;
94 M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node;
95 M_Coordinate2D *coord = (M_Coordinate2D*) ifs2D->coord;
96 M_Color *color = (M_Color *) ifs2D->color;
97
98 col.red = col.green = col.blue = 0;
99 /*simple case, no color specified*/
100 if (!ifs2D->color) {
101 visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state);
102 visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
103 return;
104 }
105
106 /*if default face use first color*/
107 ci_count = ifs2D->coordIndex.count;
108 pts = coord->point.vals;
109
110 if (ci_count == 0) {
111 col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[0]] : color->color.vals[0];
112
113 alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255;
114 if (!alpha || !ctx->aspect.pen_props.width) {
115 alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255;
116 ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
117 } else {
118 ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
119 }
120 visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state);
121 visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
122 return;
123 }
124
125 /*we have color per faces so we need N path :(*/
126 if (! ifs2D->colorPerVertex) {
127 GF_Path *path = gf_path_new();
128
129 count = 0;
130 i = 0;
131 while (1) {
132 gf_path_reset(path);
133 start = pts[ifs2D->coordIndex.vals[i]];
134 gf_path_add_move_to(path, start.x, start.y);
135 i++;
136
137 while (ifs2D->coordIndex.vals[i] != -1) {
138 start = pts[ifs2D->coordIndex.vals[i]];
139 gf_path_add_line_to(path, start.x, start.y);
140 i++;
141 if (i >= ci_count) break;
142 }
143 /*close in ALL cases because even if the start/end points are the same the line join needs to be present*/
144 gf_path_close(path);
145
146 col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[count]] : color->color.vals[count];
147
148 alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255;
149 if (!alpha) {
150 alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255;
151 ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
152 } else {
153 ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
154 }
155
156 visual_2d_texture_path(tr_state->visual, path, ctx, tr_state);
157 visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state);
158 count++;
159 i++;
160 if (i >= ci_count) break;
161 ctx->flags &= ~CTX_PATH_FILLED;
162 ctx->flags &= ~CTX_PATH_STROKE;
163 }
164 gf_path_del(path);
165 return;
166 }
167
168 /*final case, color per vertex means gradient fill/strike*/
169 /*not supported, fill default*/
170 visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state);
171 visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
172 return;
173
174
175 #if 0 //deprecated
176 path = gf_path_new();
177
178 ind_col = 0;
179 i = 0;
180 while (1) {
181 gf_path_reset(path);
182 start = pts[ifs2D->coordIndex.vals[i]];
183 center = start;
184 gf_path_add_move_to(path, start.x, start.y);
185 num_col = 1;
186 i+=1;
187 while (ifs2D->coordIndex.vals[i] != -1) {
188 end = pts[ifs2D->coordIndex.vals[i]];
189 gf_path_add_line_to(path, end.x, end.y);
190 i++;
191 center.x += end.x;
192 center.y += end.y;
193 num_col ++;
194 if (i >= ci_count) break;
195 }
196 gf_path_close(path);
197 num_col++;
198
199 alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color) ) / 255;
200
201 colors = (u32*)gf_malloc(sizeof(u32) * num_col);
202 col_cen.blue = col_cen.red = col_cen.green = 0;
203 for (j=0; j<num_col-1; j++) {
204 if (ifs2D->colorIndex.count > ind_col + j) {
205 col = color->color.vals[ifs2D->colorIndex.vals[ind_col + j]];
206 } else if (ci_count > ind_col + j) {
207 col = color->color.vals[ifs2D->coordIndex.vals[ind_col + j]];
208 }
209 colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
210 col_cen.blue += col.blue;
211 col_cen.green += col.green;
212 col_cen.red += col.red;
213 }
214 colors[num_col-1] = colors[0];
215
216 if (ifs2D->colorIndex.count > ind_col) {
217 col = color->color.vals[ifs2D->colorIndex.vals[ind_col]];
218 } else if (ci_count > ind_col) {
219 col = color->color.vals[ifs2D->coordIndex.vals[ind_col]];
220 }
221 col_cen.blue += col.blue;
222 col_cen.green += col.green;
223 col_cen.red += col.red;
224
225 gf_evg_stencil_set_vertex_path(grad, path);
226 gf_evg_stencil_set_vertex_colors(grad, colors, num_col);
227
228 gf_free(colors);
229
230 col_cen.blue /= num_col;
231 col_cen.green /= num_col;
232 col_cen.red /= num_col;
233 center.x /= num_col;
234 center.y /= num_col;
235 gf_evg_stencil_set_vertex_center(grad, center.x, center.y, GF_COL_ARGB_FIXED(alpha, col_cen.red, col_cen.green, col_cen.blue) );
236
237 gf_evg_stencil_set_matrix(grad, &ctx->transform);
238
239 /*draw*/
240 visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, grad, grad, tr_state);
241
242 gf_evg_stencil_delete(grad);
243
244 //goto next point
245 i++;
246 ind_col += num_col + 1;
247 if (i >= ci_count) break;
248 grad = gf_evg_stencil_new(GF_STENCIL_VERTEX_GRADIENT);
249 ctx->flags &= ~CTX_PATH_FILLED;
250 ctx->flags &= ~CTX_PATH_STROKE;
251 }
252 gf_path_del(path);
253 #endif
254
255
256 }
257
TraverseIFS2D(GF_Node * node,void * rs,Bool is_destroy)258 static void TraverseIFS2D(GF_Node *node, void *rs, Bool is_destroy)
259 {
260 DrawableContext *ctx;
261 M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node;
262 Drawable *stack = (Drawable *)gf_node_get_private(node);
263 GF_TraverseState *tr_state = (GF_TraverseState *)rs;
264
265 if (is_destroy) {
266 drawable_node_del(node);
267 return;
268 }
269 if (!ifs2D->coord) return;
270
271 ifs2d_check_changes(node, stack, tr_state);
272
273 switch (tr_state->traversing_mode) {
274 case TRAVERSE_DRAW_2D:
275 IFS2D_Draw(node, tr_state);
276 return;
277 #ifndef GPAC_DISABLE_3D
278 case TRAVERSE_DRAW_3D:
279 {
280 DrawAspect2D asp;
281
282 if (!stack->mesh) {
283 stack->mesh = new_mesh();
284 mesh_new_ifs2d(stack->mesh, node);
285 }
286
287 memset(&asp, 0, sizeof(DrawAspect2D));
288 drawable_get_aspect_2d_mpeg4(node, &asp, tr_state);
289 if (ifs2D->color && !GF_COL_A(asp.fill_color) ) {
290 /*use special func to disable outline recompute and handle recompute ourselves*/
291 StrikeInfo2D *si = drawable_get_strikeinfo(tr_state->visual->compositor, stack, &asp, tr_state->appear, NULL, 0, tr_state);
292 if (!si->mesh_outline) {
293 si->mesh_outline = new_mesh();
294 mesh_new_ils(si->mesh_outline, ifs2D->coord, &ifs2D->coordIndex, ifs2D->color, &ifs2D->colorIndex, ifs2D->colorPerVertex, 1);
295 }
296 visual_3d_mesh_strike(tr_state, si->mesh_outline, asp.pen_props.width, asp.line_scale, asp.pen_props.dash);
297 } else {
298 visual_3d_draw_2d_with_aspect(stack, tr_state, &asp);
299 }
300 return;
301 }
302 #endif
303 case TRAVERSE_PICK:
304 vrml_drawable_pick(stack, tr_state);
305 return;
306 case TRAVERSE_GET_BOUNDS:
307 gf_path_get_bounds(stack->path, &tr_state->bounds);
308 return;
309 case TRAVERSE_SORT:
310 #ifndef GPAC_DISABLE_3D
311 if (tr_state->visual->type_3d) return;
312 #endif
313
314 ctx = drawable_init_context_mpeg4(stack, tr_state);
315 if (!ctx) return;
316 drawable_finalize_sort(ctx, tr_state, NULL);
317 return;
318 }
319 }
320
IFS2D_SetColorIndex(GF_Node * node,GF_Route * route)321 static void IFS2D_SetColorIndex(GF_Node *node, GF_Route *route)
322 {
323 M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node;
324 if (node) {
325 gf_sg_vrml_field_copy(&ifs2D->colorIndex, &ifs2D->set_colorIndex, GF_SG_VRML_MFINT32);
326 gf_sg_vrml_mf_reset(&ifs2D->set_colorIndex, GF_SG_VRML_MFINT32);
327 }
328 }
329
IFS2D_SetCoordIndex(GF_Node * node,GF_Route * route)330 static void IFS2D_SetCoordIndex(GF_Node *node, GF_Route *route)
331 {
332 M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node;
333 if (node) {
334 gf_sg_vrml_field_copy(&ifs2D->coordIndex, &ifs2D->set_coordIndex, GF_SG_VRML_MFINT32);
335 gf_sg_vrml_mf_reset(&ifs2D->set_coordIndex, GF_SG_VRML_MFINT32);
336 }
337 }
338
compositor_init_indexed_face_set2d(GF_Compositor * compositor,GF_Node * node)339 void compositor_init_indexed_face_set2d(GF_Compositor *compositor, GF_Node *node)
340 {
341 M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node;
342 Drawable *stack = drawable_stack_new(compositor, node);
343 stack->flags = DRAWABLE_USE_TRAVERSE_DRAW;
344 gf_node_set_callback_function(node, TraverseIFS2D);
345 ifs2D->on_set_colorIndex = IFS2D_SetColorIndex;
346 ifs2D->on_set_coordIndex = IFS2D_SetCoordIndex;
347
348 #ifdef GPAC_ENABLE_COVERAGE
349 if (gf_sys_is_cov_mode()) {
350 IFS2D_SetCoordIndex(NULL, NULL);
351 IFS2D_SetColorIndex(NULL, NULL);
352 }
353 #endif
354
355 }
356
357 #endif /*GPAC_DISABLE_VRML*/
358