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