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 
ils2d_check_changes(GF_Node * node,Drawable * stack,GF_TraverseState * tr_state)33 static void ils2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
34 {
35 	u32 i;
36 	Bool started;
37 	SFVec2f *pts;
38 	M_IndexedLineSet2D *ils2D;
39 	M_Coordinate2D *coord;
40 
41 	if (! gf_node_dirty_get(node)) return;
42 
43 	drawable_reset_path(stack);
44 	gf_node_dirty_clear(node, 0);
45 	drawable_mark_modified(stack, tr_state);
46 
47 	ils2D = (M_IndexedLineSet2D *)node;
48 	coord = (M_Coordinate2D *)ils2D->coord;
49 
50 	pts = coord->point.vals;
51 	if (ils2D->coordIndex.count > 0) {
52 		started = 0;
53 		for (i=0; i < ils2D->coordIndex.count; i++) {
54 			/*NO close on ILS2D*/
55 			if (ils2D->coordIndex.vals[i] == -1) {
56 				started = 0;
57 			} else if (!started) {
58 				started = 1;
59 				gf_path_add_move_to(stack->path, pts[ils2D->coordIndex.vals[i]].x, pts[ils2D->coordIndex.vals[i]].y);
60 			} else {
61 				gf_path_add_line_to(stack->path, pts[ils2D->coordIndex.vals[i]].x, pts[ils2D->coordIndex.vals[i]].y);
62 			}
63 		}
64 	} else if (coord->point.count) {
65 		gf_path_add_move_to(stack->path, pts[0].x, pts[0].y);
66 		for (i=1; i < coord->point.count; i++) {
67 			gf_path_add_line_to(stack->path, pts[i].x, pts[i].y);
68 		}
69 	}
70 	stack->path->flags |= GF_PATH_FILL_ZERO_NONZERO;
71 }
72 
ILS2D_Draw(GF_Node * node,GF_TraverseState * tr_state)73 static void ILS2D_Draw(GF_Node *node, GF_TraverseState *tr_state)
74 {
75 	GF_Path *path;
76 	SFVec2f *pts;
77 	SFColor col;
78 	Fixed alpha;
79 	u32 i, count, col_ind, ind, end_at;
80 	u32 linear[2];
81 #if 0 //unused
82 	u32 *colors, j;
83 #endif
84 	SFVec2f start, end;
85 	u32 num_col;
86 	GF_EVGStencil *grad;
87 	DrawableContext *ctx = tr_state->ctx;
88 	M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node;
89 	M_Coordinate2D *coord = (M_Coordinate2D*) ils2D->coord;
90 	M_Color *color = (M_Color *) ils2D->color;
91 
92 	end.x = end.y = 0;
93 	if (!coord->point.count) return;
94 
95 	if (! ils2D->color) {
96 		/*no texturing*/
97 		visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
98 		return;
99 	}
100 
101 	alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255;
102 	pts = coord->point.vals;
103 
104 	if (!ils2D->colorPerVertex || (color->color.count<2) ) {
105 		count = 0;
106 		end_at = ils2D->coordIndex.count;
107 		if (!end_at) end_at = coord->point.count;
108 		ind = ils2D->coordIndex.count ? ils2D->coordIndex.vals[0] : 0;
109 		i=1;
110 		path = gf_path_new();
111 		gf_path_add_move_to(path, pts[ind].x, pts[ind].y);
112 
113 		for (; i<=end_at; i++) {
114 			if ((i==end_at) || (ils2D->coordIndex.count && ils2D->coordIndex.vals[i] == -1)) {
115 
116 				/*draw current*/
117 				col_ind = (ils2D->colorIndex.count && (ils2D->colorIndex.vals[count]>=0) ) ? (u32) ils2D->colorIndex.vals[count] : count;
118 				if (col_ind>=color->color.count) col_ind=color->color.count-1;
119 				col = color->color.vals[col_ind];
120 				ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
121 
122 				visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state);
123 
124 				i++;
125 				if (i>=end_at) break;
126 				gf_path_reset(path);
127 
128 				ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i;
129 				gf_path_add_move_to(path, pts[ind].x, pts[ind].y);
130 
131 				if (ils2D->coordIndex.count) count++;
132 				continue;
133 			} else {
134 				ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0) ) ? (u32) ils2D->coordIndex.vals[i] : i;
135 				gf_path_add_line_to(path, pts[ind].x, pts[ind].y);
136 			}
137 		}
138 		gf_path_del(path);
139 		return;
140 	}
141 
142 	end_at = ils2D->coordIndex.count;
143 	if (!end_at) end_at = coord->point.count;
144 
145 	col_ind = 0;
146 	i=0;
147 	path = gf_path_new();
148 	while (1) {
149 		gf_path_reset(path);
150 		ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i;
151 		start = pts[ind];
152 		num_col = 1;
153 		i++;
154 		gf_path_add_move_to(path, start.x, start.y);
155 
156 		if (ils2D->coordIndex.count) {
157 			while (ils2D->coordIndex.vals[i] != -1) {
158 				end = pts[ils2D->coordIndex.vals[i]];
159 				gf_path_add_line_to(path, end.x, end.y);
160 				i++;
161 				num_col++;
162 				if (i >= ils2D->coordIndex.count) break;
163 			}
164 		} else {
165 			while (i<end_at) {
166 				end = pts[i];
167 				gf_path_add_line_to(path, end.x, end.y);
168 				i++;
169 				num_col++;
170 			}
171 		}
172 
173 		/*use linear gradient*/
174 		if (num_col==2) {
175 			Fixed pos[2];
176 			grad = gf_evg_stencil_new(GF_STENCIL_LINEAR_GRADIENT);
177 			if (ils2D->colorIndex.count) {
178 				col = color->color.vals[ils2D->colorIndex.vals[col_ind]];
179 				linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
180 				col = color->color.vals[ils2D->colorIndex.vals[col_ind+1]];
181 				linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
182 			} else if (ils2D->coordIndex.count) {
183 				col = color->color.vals[ils2D->coordIndex.vals[col_ind]];
184 				linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
185 				col = color->color.vals[ils2D->coordIndex.vals[col_ind+1]];
186 				linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
187 			} else {
188 				col = color->color.vals[col_ind];
189 				linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
190 				col = color->color.vals[col_ind+1];
191 				linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
192 			}
193 			pos[0] = 0;
194 			pos[1] = FIX_ONE;
195 			gf_evg_stencil_set_linear_gradient(grad, start.x, start.y, end.x, end.y);
196 			gf_evg_stencil_set_gradient_interpolation(grad, pos, linear, 2);
197 		} else {
198             grad = NULL;
199 #if 0 //unused
200 			grad = gf_evg_stencil_new(GF_STENCIL_VERTEX_GRADIENT);
201 			if (grad) {
202 				gf_evg_stencil_set_vertex_path(grad, path);
203 
204 				colors = (u32*)gf_malloc(sizeof(u32) * num_col);
205 				for (j=0; j<num_col; j++) {
206 					if (ils2D->colorIndex.count>0) {
207 						col = color->color.vals[ils2D->colorIndex.vals[col_ind+j]];
208 					} else if (ils2D->coordIndex.count) {
209 						col = color->color.vals[ils2D->coordIndex.vals[col_ind+j]];
210 					} else {
211 						col = color->color.vals[col_ind+j];
212 					}
213 					colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
214 				}
215 				gf_evg_stencil_set_vertex_colors(grad, colors, num_col);
216 				gf_free(colors);
217 			}
218 #endif
219 
220 		}
221 		gf_evg_stencil_set_matrix(grad, &ctx->transform);
222 		visual_2d_draw_path(tr_state->visual, path, ctx, NULL, grad, tr_state);
223 		if (grad) gf_evg_stencil_delete(grad);
224 
225 		i ++;
226 		col_ind += num_col + 1;
227 		if (i >= ils2D->coordIndex.count) break;
228 		ctx->flags &= ~CTX_PATH_STROKE;
229 	}
230 	gf_path_del(path);
231 }
232 
233 
TraverseILS2D(GF_Node * node,void * rs,Bool is_destroy)234 static void TraverseILS2D(GF_Node *node, void *rs, Bool is_destroy)
235 {
236 	DrawableContext *ctx;
237 	M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node;
238 	Drawable *stack = (Drawable *)gf_node_get_private(node);
239 	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
240 
241 	if (is_destroy) {
242 		drawable_node_del(node);
243 		return;
244 	}
245 
246 	if (!ils2D->coord) return;
247 
248 	ils2d_check_changes(node, stack, tr_state);
249 
250 	switch (tr_state->traversing_mode) {
251 	case TRAVERSE_DRAW_2D:
252 		ILS2D_Draw(node, tr_state);
253 		return;
254 #ifndef GPAC_DISABLE_3D
255 	case TRAVERSE_DRAW_3D:
256 		if (!stack->mesh) {
257 			stack->mesh = new_mesh();
258 			mesh_new_ils(stack->mesh, ils2D->coord, &ils2D->coordIndex, ils2D->color, &ils2D->colorIndex, ils2D->colorPerVertex, 0);
259 		}
260 		if (ils2D->color) {
261 			DrawAspect2D asp;
262 			memset(&asp, 0, sizeof(DrawAspect2D));
263 			drawable_get_aspect_2d_mpeg4(node, &asp, tr_state);
264 
265 			visual_3d_mesh_strike(tr_state, stack->mesh, asp.pen_props.width, asp.line_scale, asp.pen_props.dash);
266 		} else {
267 			visual_3d_draw_2d(stack, tr_state);
268 		}
269 		return;
270 #endif
271 	case TRAVERSE_PICK:
272 		vrml_drawable_pick(stack, tr_state);
273 		return;
274 	case TRAVERSE_GET_BOUNDS:
275 		gf_path_get_bounds(stack->path, &tr_state->bounds);
276 		return;
277 	case TRAVERSE_SORT:
278 #ifndef GPAC_DISABLE_3D
279 		if (tr_state->visual->type_3d) return;
280 #endif
281 
282 		ctx = drawable_init_context_mpeg4(stack, tr_state);
283 		if (!ctx) return;
284 		/*ILS2D are NEVER filled*/
285 		ctx->aspect.fill_color &= 0x00FFFFFF;
286 		drawable_finalize_sort(ctx, tr_state, NULL);
287 		return;
288 	default:
289 		return;
290 	}
291 }
292 
ILS2D_SetColorIndex(GF_Node * node,GF_Route * route)293 static void ILS2D_SetColorIndex(GF_Node *node, GF_Route *route)
294 {
295 	M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node;
296 	if (node) {
297 		gf_sg_vrml_field_copy(&ils2D->colorIndex, &ils2D->set_colorIndex, GF_SG_VRML_MFINT32);
298 		gf_sg_vrml_mf_reset(&ils2D->set_colorIndex, GF_SG_VRML_MFINT32);
299 	}
300 }
301 
ILS2D_SetCoordIndex(GF_Node * node,GF_Route * route)302 static void ILS2D_SetCoordIndex(GF_Node *node, GF_Route *route)
303 {
304 	M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node;
305 	if (node) {
306 		gf_sg_vrml_field_copy(&ils2D->coordIndex, &ils2D->set_coordIndex, GF_SG_VRML_MFINT32);
307 		gf_sg_vrml_mf_reset(&ils2D->set_coordIndex, GF_SG_VRML_MFINT32);
308 	}
309 }
310 
compositor_init_indexed_line_set2d(GF_Compositor * compositor,GF_Node * node)311 void compositor_init_indexed_line_set2d(GF_Compositor *compositor, GF_Node *node)
312 {
313 	M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node;
314 	Drawable *stack = drawable_stack_new(compositor, node);
315 	stack->flags = DRAWABLE_USE_TRAVERSE_DRAW;
316 	gf_node_set_callback_function(node, TraverseILS2D);
317 	ils2D->on_set_colorIndex = ILS2D_SetColorIndex;
318 	ils2D->on_set_coordIndex = ILS2D_SetCoordIndex;
319 
320 #ifdef GPAC_ENABLE_COVERAGE
321 	if (gf_sys_is_cov_mode()) {
322 		ILS2D_SetCoordIndex(NULL, NULL);
323 		ILS2D_SetColorIndex(NULL, NULL);
324 	}
325 #endif
326 
327 }
328 
329 #endif /*GPAC_DISABLE_VRML*/
330