Line data Source code
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 1008 : Bool compositor_get_2d_plane_intersection(GF_Ray *ray, SFVec3f *res)
32 : {
33 : GF_Plane p;
34 : Fixed t, t2;
35 1008 : if (!ray->dir.x && !ray->dir.y) {
36 553 : res->x = ray->orig.x;
37 553 : res->y = ray->orig.y;
38 553 : res->z = 0;
39 553 : return 1;
40 : }
41 455 : p.normal.x = p.normal.y = 0;
42 455 : p.normal.z = FIX_ONE;
43 : p.d = 0;
44 455 : t2 = gf_vec_dot(p.normal, ray->dir);
45 455 : if (t2 == 0) return 0;
46 455 : t = - gf_divfix(gf_vec_dot(p.normal, ray->orig) + p.d, t2);
47 455 : if (t<0) return 0;
48 455 : *res = gf_vec_scale(ray->dir, t);
49 455 : gf_vec_add(*res, ray->orig, *res);
50 455 : return 1;
51 : }
52 :
53 : #ifndef GPAC_DISABLE_VRML
54 :
55 : /*
56 : Shape
57 : */
58 308794 : static void TraverseShape(GF_Node *node, void *rs, Bool is_destroy)
59 : {
60 : GF_TraverseState *tr_state;
61 : M_Shape *shape;
62 308794 : if (is_destroy ) return;
63 :
64 : tr_state = (GF_TraverseState *)rs;
65 : #ifndef GPAC_DISABLE_3D
66 304137 : if (tr_state->traversing_mode==TRAVERSE_LIGHTING) return;
67 : #endif
68 :
69 : shape = (M_Shape *) node;
70 289306 : if (!shape->geometry) return;
71 :
72 : /*reset this node dirty flag (because bitmap may trigger bounds invalidation on the fly)*/
73 283534 : gf_node_dirty_clear(node, 0);
74 :
75 :
76 : /*check traverse mode, and take care of switch-off flag*/
77 283534 : if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
78 4805 : tr_state->appear = (GF_Node *) shape->appearance;
79 :
80 : /*this is done regardless of switch flag*/
81 4805 : gf_node_traverse((GF_Node *) shape->geometry, tr_state);
82 :
83 4805 : if (tr_state->appear) {
84 : /*apply line width*/
85 4731 : GF_Node *m = ((M_Appearance *)tr_state->appear)->material;
86 4731 : if (m && (gf_node_get_tag(m)==TAG_MPEG4_Material2D) ) {
87 : DrawAspect2D asp;
88 : Fixed width = 0;
89 2190 : asp.line_scale = FIX_ONE;
90 2190 : m = ((M_Material2D *)m)->lineProps;
91 2190 : if (m) {
92 11 : switch (gf_node_get_tag(m)) {
93 11 : case TAG_MPEG4_LineProperties:
94 11 : width = ((M_LineProperties *) m)->width;
95 11 : drawable_compute_line_scale(tr_state, &asp);
96 11 : break;
97 0 : case TAG_MPEG4_XLineProperties:
98 0 : if ( ((M_XLineProperties *) m)->isCenterAligned)
99 0 : width = ((M_XLineProperties *) m)->width;
100 0 : if ( ((M_XLineProperties *) m)->isScalable)
101 0 : drawable_compute_line_scale(tr_state, &asp);
102 : break;
103 : }
104 11 : width = gf_mulfix(width, asp.line_scale);
105 11 : tr_state->bounds.width += width;
106 11 : tr_state->bounds.height += width;
107 11 : tr_state->bounds.y += width/2;
108 11 : tr_state->bounds.x -= width/2;
109 : }
110 : }
111 4731 : tr_state->appear = NULL;
112 : }
113 : } else {
114 278729 : if (tr_state->switched_off) return;
115 :
116 277695 : tr_state->appear = (GF_Node *) shape->appearance;
117 :
118 277695 : switch (tr_state->traversing_mode) {
119 175772 : case TRAVERSE_SORT:
120 : #ifndef GPAC_DISABLE_3D
121 175772 : if (tr_state->visual->type_3d)
122 23665 : visual_3d_register_context(tr_state, shape->geometry);
123 : else
124 : #endif
125 152107 : gf_node_traverse((GF_Node *) shape->geometry, tr_state);
126 : break;
127 96995 : case TRAVERSE_PICK:
128 96995 : gf_node_traverse((GF_Node *) shape->geometry, tr_state);
129 96995 : break;
130 : #ifndef GPAC_DISABLE_3D
131 : /*if we're here we passed culler already*/
132 0 : case TRAVERSE_DRAW_3D:
133 0 : if (!tr_state->visual->type_3d && tr_state->visual->compositor->hybrid_opengl) {
134 0 : tr_state->visual->compositor->root_visual_setup=0;
135 0 : tr_state->visual->compositor->force_type_3d=1;
136 : }
137 0 : gf_node_traverse((GF_Node *) shape->geometry, tr_state);
138 0 : break;
139 4928 : case TRAVERSE_COLLIDE:
140 4928 : visual_3d_vrml_drawable_collide(shape->geometry, tr_state);
141 4928 : break;
142 : #endif
143 : }
144 :
145 277695 : tr_state->appear = NULL;
146 : }
147 : }
148 :
149 4657 : void compositor_init_shape(GF_Compositor *compositor, GF_Node *node)
150 : {
151 4657 : gf_node_set_callback_function(node, TraverseShape);
152 4657 : }
153 :
154 123482 : static void circle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
155 : {
156 123482 : if (gf_node_dirty_get(node)) {
157 1788 : Fixed a = ((M_Circle *) node)->radius * 2;
158 1788 : drawable_reset_path(stack);
159 1788 : gf_path_add_ellipse(stack->path, 0, 0, a, a);
160 1788 : gf_node_dirty_clear(node, 0);
161 1788 : drawable_mark_modified(stack, tr_state);
162 : }
163 123482 : }
164 124386 : static void TraverseCircle(GF_Node *node, void *rs, Bool is_destroy)
165 : {
166 : DrawableContext *ctx;
167 124386 : Drawable *stack = (Drawable *)gf_node_get_private(node);
168 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
169 :
170 124386 : if (is_destroy) {
171 904 : drawable_node_del(node);
172 904 : return;
173 : }
174 :
175 123482 : circle_check_changes(node, stack, tr_state);
176 :
177 123482 : switch (tr_state->traversing_mode) {
178 : #ifndef GPAC_DISABLE_3D
179 1007 : case TRAVERSE_DRAW_3D:
180 1007 : if (!stack->mesh) {
181 181 : Fixed a = ((M_Circle *) node)->radius * 2;
182 181 : stack->mesh = new_mesh();
183 181 : mesh_new_ellipse(stack->mesh, a, a, tr_state->visual->compositor->fast);
184 : }
185 1007 : visual_3d_draw_2d(stack, tr_state);
186 1007 : return;
187 : #endif
188 193 : case TRAVERSE_GET_BOUNDS:
189 193 : gf_path_get_bounds(stack->path, &tr_state->bounds);
190 193 : return;
191 71242 : case TRAVERSE_PICK:
192 71242 : vrml_drawable_pick(stack, tr_state);
193 71242 : return;
194 51040 : case TRAVERSE_SORT:
195 : #ifndef GPAC_DISABLE_3D
196 51040 : if (tr_state->visual->type_3d) return;
197 : #endif
198 51040 : ctx = drawable_init_context_mpeg4(stack, tr_state);
199 51040 : if (!ctx) return;
200 16882 : drawable_finalize_sort(ctx, tr_state, NULL);
201 16882 : return;
202 : }
203 : }
204 :
205 904 : void compositor_init_circle(GF_Compositor *compositor, GF_Node *node)
206 : {
207 904 : drawable_stack_new(compositor, node);
208 904 : gf_node_set_callback_function(node, TraverseCircle);
209 904 : }
210 :
211 104 : static void ellipse_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
212 : {
213 104 : if (gf_node_dirty_get(node)) {
214 4 : drawable_reset_path(stack);
215 4 : gf_path_add_ellipse(stack->path, 0, 0, ((M_Ellipse *) node)->radius.x*2, ((M_Ellipse *) node)->radius.y*2);
216 4 : gf_node_dirty_clear(node, 0);
217 4 : drawable_mark_modified(stack, tr_state);
218 : }
219 104 : }
220 108 : static void TraverseEllipse(GF_Node *node, void *rs, Bool is_destroy)
221 : {
222 : DrawableContext *ctx;
223 108 : Drawable *stack = (Drawable *)gf_node_get_private(node);
224 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
225 :
226 108 : if (is_destroy) {
227 4 : drawable_node_del(node);
228 4 : return;
229 : }
230 :
231 104 : ellipse_check_changes(node, stack, tr_state);
232 :
233 104 : switch (tr_state->traversing_mode) {
234 : #ifndef GPAC_DISABLE_3D
235 0 : case TRAVERSE_DRAW_3D:
236 0 : if (!stack->mesh) {
237 0 : stack->mesh = new_mesh();
238 0 : mesh_new_ellipse(stack->mesh, ((M_Ellipse *) node)->radius.x * 2, ((M_Ellipse *) node)->radius.y * 2, tr_state->visual->compositor->fast);
239 : }
240 0 : visual_3d_draw_2d(stack, tr_state);
241 0 : return;
242 : #endif
243 11 : case TRAVERSE_PICK:
244 11 : vrml_drawable_pick(stack, tr_state);
245 11 : return;
246 4 : case TRAVERSE_GET_BOUNDS:
247 4 : gf_path_get_bounds(stack->path, &tr_state->bounds);
248 4 : return;
249 89 : case TRAVERSE_SORT:
250 : #ifndef GPAC_DISABLE_3D
251 89 : if (tr_state->visual->type_3d) return;
252 : #endif
253 89 : ctx = drawable_init_context_mpeg4(stack, tr_state);
254 89 : if (!ctx) return;
255 89 : drawable_finalize_sort(ctx, tr_state, NULL);
256 89 : break;
257 : }
258 : }
259 :
260 4 : void compositor_init_ellipse(GF_Compositor *compositor, GF_Node *node)
261 : {
262 4 : drawable_stack_new(compositor, node);
263 4 : gf_node_set_callback_function(node, TraverseEllipse);
264 4 : }
265 :
266 23668 : static void compositor_2d_draw_rectangle(GF_TraverseState *tr_state)
267 : {
268 23668 : DrawableContext *ctx = tr_state->ctx;
269 :
270 23668 : if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->data
271 : #ifndef GPAC_DISABLE_3D
272 2982 : && !tr_state->visual->compositor->hybrid_opengl
273 : #endif
274 : ) {
275 : Bool res;
276 :
277 : /*get image size WITHOUT line size or antialias margin*/
278 2742 : if ( !(ctx->flags & CTX_NO_ANTIALIAS) ) {
279 : GF_Rect orig_unclip;
280 : GF_IRect orig_clip;
281 2435 : orig_unclip = ctx->bi->unclip;
282 2435 : orig_clip = ctx->bi->clip;
283 :
284 2435 : gf_path_get_bounds(ctx->drawable->path, &ctx->bi->unclip);
285 2435 : gf_mx2d_apply_rect(&ctx->transform, &ctx->bi->unclip);
286 2435 : ctx->bi->clip = gf_rect_pixelize(&ctx->bi->unclip);
287 2435 : gf_irect_intersect(&ctx->bi->clip, &orig_clip);
288 :
289 2435 : res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx);
290 :
291 : /*strike path*/
292 2435 : ctx->bi->unclip = orig_unclip;
293 2435 : ctx->bi->clip = orig_clip;
294 2435 : if (res) {
295 682 : ctx->flags |= CTX_PATH_FILLED;
296 682 : visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
297 : }
298 : } else {
299 307 : res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx);
300 : }
301 : /*if failure retry with raster*/
302 2742 : if (res) return;
303 : }
304 :
305 22689 : visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state);
306 22689 : visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
307 : }
308 :
309 71030 : static void rectangle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
310 : {
311 : /*if modified update node - we don't update for other traversing mode in order not to mess up the dirty
312 : rect tracking (otherwise we would miss geometry changes with same bounds)*/
313 71030 : if (gf_node_dirty_get(node)) {
314 382 : drawable_reset_path(stack);
315 382 : gf_path_add_rect_center(stack->path, 0, 0, ((M_Rectangle *) node)->size.x, ((M_Rectangle *) node)->size.y);
316 382 : gf_node_dirty_clear(node, 0);
317 382 : drawable_mark_modified(stack, tr_state);
318 : }
319 71030 : }
320 :
321 85682 : Bool rectangle_check_adaptation(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
322 : {
323 : GF_TextureHandler *txh;
324 : GF_MediaObjectVRInfo vrinfo;
325 : s32 gaze_x, gaze_y;
326 : Bool is_visible = GF_FALSE;
327 85682 : if (! tr_state->visual->compositor->gazer_enabled)
328 : return GF_TRUE;
329 :
330 0 : if (!tr_state->appear || ! ((M_Appearance *)tr_state->appear)->texture)
331 : return GF_TRUE;
332 :
333 0 : txh = gf_sc_texture_get_handler( ((M_Appearance *) tr_state->appear)->texture );
334 0 : if (!txh->stream) return GF_TRUE;
335 :
336 0 : if (! gf_mo_get_srd_info(txh->stream, &vrinfo))
337 : return GF_TRUE;
338 :
339 0 : if (!vrinfo.srd_w && !vrinfo.srd_h && vrinfo.is_tiled_srd) {
340 0 : if (txh->stream->srd_full_w && txh->stream->srd_full_h) {
341 0 : gaze_x = tr_state->visual->compositor->gaze_x;
342 0 : gaze_x *= txh->stream->srd_full_w;
343 0 : gaze_x /= tr_state->visual->width;
344 :
345 0 : gaze_y = tr_state->visual->compositor->gaze_y;
346 0 : gaze_y *= txh->stream->srd_full_h;
347 0 : gaze_y /= tr_state->visual->height;
348 :
349 0 : gf_mo_hint_gaze(txh->stream, gaze_x, gaze_y);
350 : }
351 :
352 : return GF_TRUE;
353 : }
354 :
355 0 : gaze_x = tr_state->visual->compositor->gaze_x;
356 0 : gaze_x *= vrinfo.srd_max_x;
357 0 : gaze_x /= tr_state->visual->width;
358 :
359 0 : gaze_y = tr_state->visual->compositor->gaze_y;
360 0 : gaze_y *= vrinfo.srd_max_y;
361 0 : gaze_y /= tr_state->visual->height;
362 :
363 : //simple test condition: only keep the first row
364 0 : if ((gaze_x>=vrinfo.srd_x) && (gaze_x<=vrinfo.srd_x+vrinfo.srd_w) && (gaze_y>=vrinfo.srd_y) && (gaze_y<=vrinfo.srd_y+vrinfo.srd_h)) {
365 :
366 0 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %d Partial plane is under gaze coord %d %d\n", txh->stream->OD_ID, tr_state->visual->compositor->gaze_x, tr_state->visual->compositor->gaze_y));
367 : is_visible = GF_TRUE;
368 : }
369 :
370 0 : if (vrinfo.has_full_coverage) {
371 0 : if (is_visible) {
372 0 : if (!txh->is_open) {
373 0 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %d stoped on visible partial plane - starting it\n", txh->stream->OD_ID));
374 : assert(txh->stream && txh->stream->odm);
375 0 : txh->stream->odm->disable_buffer_at_next_play = GF_TRUE;
376 :
377 0 : gf_sc_texture_play(txh, NULL);
378 : }
379 0 : if (! txh->data) return GF_FALSE;
380 0 : return GF_TRUE;
381 : } else {
382 0 : if (txh->is_open) {
383 0 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texure %d playing on hidden partial plane - stopping it\n", txh->stream->OD_ID));
384 0 : gf_sc_texture_stop_no_unregister(txh);
385 : }
386 : return GF_FALSE;
387 : }
388 : } else {
389 0 : if (is_visible) {
390 0 : gf_mo_hint_quality_degradation(txh->stream, 0);
391 0 : if (! txh->data) return GF_FALSE;
392 : } else {
393 0 : gf_mo_hint_quality_degradation(txh->stream, 100);
394 : }
395 : }
396 : return GF_TRUE;
397 : }
398 :
399 71421 : static void TraverseRectangle(GF_Node *node, void *rs, Bool is_destroy)
400 : {
401 : DrawableContext *ctx;
402 71421 : Drawable *stack = (Drawable *)gf_node_get_private(node);
403 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
404 :
405 71421 : if (is_destroy) {
406 391 : drawable_node_del(node);
407 391 : return;
408 : }
409 :
410 71030 : rectangle_check_changes(node, stack, tr_state);
411 :
412 71030 : if (! rectangle_check_adaptation(node, stack, tr_state))
413 : return;
414 :
415 71030 : switch (tr_state->traversing_mode) {
416 23668 : case TRAVERSE_DRAW_2D:
417 23668 : compositor_2d_draw_rectangle(tr_state);
418 23668 : return;
419 : #ifndef GPAC_DISABLE_3D
420 3604 : case TRAVERSE_DRAW_3D:
421 3604 : if (!stack->mesh) {
422 62 : stack->mesh = new_mesh();
423 62 : mesh_new_rectangle(stack->mesh, ((M_Rectangle *) node)->size, NULL, 0);
424 : }
425 3604 : visual_3d_draw_2d(stack, tr_state);
426 3604 : return;
427 : #endif
428 15552 : case TRAVERSE_PICK:
429 15552 : vrml_drawable_pick(stack, tr_state);
430 15552 : return;
431 1157 : case TRAVERSE_GET_BOUNDS:
432 1157 : gf_path_get_bounds(stack->path, &tr_state->bounds);
433 1157 : return;
434 27049 : case TRAVERSE_SORT:
435 : #ifndef GPAC_DISABLE_3D
436 27049 : if (tr_state->visual->type_3d) return;
437 : #endif
438 : break;
439 : default:
440 : return;
441 : }
442 :
443 27049 : ctx = drawable_init_context_mpeg4(stack, tr_state);
444 27049 : if (!ctx) return;
445 :
446 : /*if rotated, object is transparent (doesn't fill bounds) and antialias must be used*/
447 26629 : if (tr_state->transform.m[1] || tr_state->transform.m[3]) {
448 : }
449 : else {
450 :
451 : /*if alpha or not filled, transparent*/
452 23970 : if (ctx->aspect.fill_color && (GF_COL_A(ctx->aspect.fill_color) != 0xFF)) {
453 : }
454 : /*if texture transparent, transparent*/
455 20386 : else if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->transparent) {
456 : }
457 : /*TODO check matrix for alpha*/
458 20374 : else if (!tr_state->color_mat.identity) {
459 : }
460 : /*otherwise, not transparent*/
461 : else {
462 20366 : ctx->flags &= ~CTX_IS_TRANSPARENT;
463 : }
464 : /*if no line width, we skip antialiasing*/
465 23970 : if (!ctx->aspect.pen_props.width) ctx->flags |= CTX_NO_ANTIALIAS;
466 : }
467 26629 : drawable_finalize_sort(ctx, tr_state, NULL);
468 : }
469 :
470 391 : void compositor_init_rectangle(GF_Compositor *compositor, GF_Node *node)
471 : {
472 391 : Drawable *stack = drawable_stack_new(compositor, node);
473 391 : stack->flags = DRAWABLE_USE_TRAVERSE_DRAW;
474 391 : gf_node_set_callback_function(node, TraverseRectangle);
475 391 : }
476 :
477 :
478 : #define CHECK_VALID_C2D(nbPts) if (!idx && cur_index+nbPts>=pt_count) { gf_path_reset(stack->path); return; }
479 : //#define CHECK_VALID_C2D(nbPts)
480 : #define GET_IDX(_i) ((idx && (idx->count>_i) && (idx->vals[_i]>=0) ) ? (u32) idx->vals[_i] : _i)
481 :
482 961 : void curve2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state, MFInt32 *idx)
483 : {
484 : M_Curve2D *c2D;
485 : SFVec2f orig, ct_orig, ct_end, end;
486 : u32 cur_index, i, remain, type_count, pt_count;
487 : SFVec2f *pts;
488 : M_Coordinate2D *coord;
489 :
490 : c2D = (M_Curve2D *)node;
491 961 : coord = (M_Coordinate2D *)c2D->point;
492 961 : drawable_reset_path(stack);
493 961 : if (!coord) return;
494 :
495 961 : stack->path->fineness = c2D->fineness;
496 961 : if (tr_state->visual->compositor->fast) stack->path->fineness /= 2;
497 :
498 :
499 961 : pts = coord->point.vals;
500 961 : if (!pts)
501 : return;
502 :
503 953 : cur_index = c2D->type.count ? 1 : 0;
504 : /*if the first type is a moveTo skip initial moveTo*/
505 : i=0;
506 953 : if (cur_index) {
507 0 : while (c2D->type.vals[i]==0) i++;
508 : }
509 953 : ct_orig = orig = pts[ GET_IDX(i) ];
510 :
511 953 : gf_path_add_move_to(stack->path, orig.x, orig.y);
512 :
513 953 : pt_count = coord->point.count;
514 953 : type_count = c2D->type.count;
515 15050 : for (; i<type_count; i++) {
516 :
517 14097 : switch (c2D->type.vals[i]) {
518 : /*moveTo, 1 point*/
519 328 : case 0:
520 328 : CHECK_VALID_C2D(0);
521 328 : orig = pts[ GET_IDX(cur_index) ];
522 328 : if (i) gf_path_add_move_to(stack->path, orig.x, orig.y);
523 328 : cur_index += 1;
524 328 : break;
525 : /*lineTo, 1 point*/
526 6997 : case 1:
527 6997 : CHECK_VALID_C2D(0);
528 6997 : end = pts[ GET_IDX(cur_index) ];
529 6997 : gf_path_add_line_to(stack->path, end.x, end.y);
530 : orig = end;
531 6997 : cur_index += 1;
532 6997 : break;
533 : /*curveTo, 3 points*/
534 3415 : case 2:
535 3415 : CHECK_VALID_C2D(2);
536 3415 : ct_orig = pts[ GET_IDX(cur_index) ];
537 3415 : ct_end = pts[ GET_IDX(cur_index+1) ];
538 3415 : end = pts[ GET_IDX(cur_index+2) ];
539 3415 : gf_path_add_cubic_to(stack->path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
540 3415 : cur_index += 3;
541 : ct_orig = ct_end;
542 : orig = end;
543 3415 : break;
544 : /*nextCurveTo, 2 points (cf spec)*/
545 18 : case 3:
546 18 : CHECK_VALID_C2D(1);
547 18 : ct_orig.x = 2*orig.x - ct_orig.x;
548 18 : ct_orig.y = 2*orig.y - ct_orig.y;
549 18 : ct_end = pts[ GET_IDX(cur_index) ];
550 18 : end = pts[ GET_IDX(cur_index+1) ];
551 18 : gf_path_add_cubic_to(stack->path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
552 18 : cur_index += 2;
553 : ct_orig = ct_end;
554 : orig = end;
555 18 : break;
556 :
557 : /*all XCurve2D specific*/
558 :
559 : /*CW and CCW ArcTo*/
560 9 : case 4:
561 : case 5:
562 9 : CHECK_VALID_C2D(2);
563 9 : ct_orig = pts[ GET_IDX(cur_index) ];
564 9 : ct_end = pts[ GET_IDX(cur_index+1) ];
565 9 : end = pts[ GET_IDX(cur_index+2) ];
566 9 : gf_path_add_arc_to(stack->path, end.x, end.y, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, (c2D->type.vals[i]==5) ? 1 : 0);
567 9 : cur_index += 3;
568 : ct_orig = ct_end;
569 : orig = end;
570 9 : break;
571 : /*ClosePath*/
572 251 : case 6:
573 251 : gf_path_close(stack->path);
574 251 : break;
575 : /*quadratic CurveTo, 2 points*/
576 3079 : case 7:
577 3079 : CHECK_VALID_C2D(1);
578 3079 : ct_end = pts[ GET_IDX(cur_index) ];
579 3079 : end = pts[ GET_IDX(cur_index+1) ];
580 3079 : gf_path_add_quadratic_to(stack->path, ct_end.x, ct_end.y, end.x, end.y);
581 3079 : cur_index += 2;
582 : ct_orig = ct_end;
583 : orig = end;
584 3079 : break;
585 : }
586 : }
587 :
588 : /*what's left is an N-bezier spline*/
589 953 : if (!idx && (pt_count > cur_index) ) {
590 : /*first moveto*/
591 49 : if (!cur_index) cur_index++;
592 :
593 49 : remain = pt_count - cur_index;
594 :
595 49 : if (remain>1)
596 33 : gf_path_add_bezier(stack->path, &pts[cur_index], remain);
597 : }
598 :
599 953 : gf_node_dirty_clear(node, 0);
600 953 : drawable_mark_modified(stack, tr_state);
601 : }
602 :
603 25446 : static void TraverseCurve2D(GF_Node *node, void *rs, Bool is_destroy)
604 : {
605 : DrawableContext *ctx;
606 25446 : Drawable *stack = (Drawable *)gf_node_get_private(node);
607 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
608 :
609 25446 : if (is_destroy) {
610 579 : drawable_node_del(node);
611 579 : return;
612 : }
613 24867 : if (gf_node_dirty_get(node)) {
614 698 : curve2d_check_changes(node, stack, tr_state, NULL);
615 : }
616 :
617 24867 : switch (tr_state->traversing_mode) {
618 : #ifndef GPAC_DISABLE_3D
619 320 : case TRAVERSE_DRAW_3D:
620 320 : if (!stack->mesh) {
621 37 : stack->mesh = new_mesh();
622 37 : mesh_from_path(stack->mesh, stack->path);
623 : }
624 320 : visual_3d_draw_2d(stack, tr_state);
625 320 : return;
626 : #endif
627 37 : case TRAVERSE_PICK:
628 37 : vrml_drawable_pick(stack, tr_state);
629 37 : return;
630 341 : case TRAVERSE_GET_BOUNDS:
631 341 : gf_path_get_bounds(stack->path, &tr_state->bounds);
632 341 : return;
633 24169 : case TRAVERSE_SORT:
634 : #ifndef GPAC_DISABLE_3D
635 24169 : if (tr_state->visual->type_3d) return;
636 : #endif
637 24169 : ctx = drawable_init_context_mpeg4(stack, tr_state);
638 24169 : if (!ctx) return;
639 22560 : drawable_finalize_sort(ctx, tr_state, NULL);
640 22560 : return;
641 : }
642 : }
643 :
644 579 : void compositor_init_curve2d(GF_Compositor *compositor, GF_Node *node)
645 : {
646 579 : drawable_stack_new(compositor, node);
647 579 : gf_node_set_callback_function(node, TraverseCurve2D);
648 579 : }
649 :
650 :
651 :
652 : /*
653 : Note on point set 2D: this is a very bad node and should be avoided in DEF/USE, since the size
654 : of the rectangle representing the pixel shall always be 1 pixel w/h, therefore
655 : the path object is likely not the same depending on transformation context...
656 :
657 : */
658 :
659 18 : static void get_point_size(GF_Matrix2D *mat, Fixed *w, Fixed *h)
660 : {
661 : GF_Point2D pt;
662 18 : pt.x = mat->m[0] + mat->m[1];
663 18 : pt.y = mat->m[3] + mat->m[4];
664 18 : *w = *h = gf_divfix(FLT2FIX(1.41421356f) , gf_v2d_len(&pt));
665 18 : }
666 :
667 442 : static void pointset2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
668 : {
669 : u32 i;
670 : Fixed w, h;
671 : M_Coordinate2D *coord;
672 :
673 866 : if (!gf_node_dirty_get(node)) return;
674 18 : coord = (M_Coordinate2D *) ((M_PointSet2D *)node)->coord;
675 :
676 18 : drawable_reset_path(stack);
677 :
678 18 : get_point_size(&tr_state->transform, &w, &h);
679 : /*for PS2D don't add to avoid too much antialiasing, just try to fill the given pixel*/
680 90 : for (i=0; i < coord->point.count; i++)
681 72 : gf_path_add_rect(stack->path, coord->point.vals[i].x, coord->point.vals[i].y, w, h);
682 :
683 18 : stack->path->flags |= GF_PATH_FILL_ZERO_NONZERO;
684 :
685 18 : gf_node_dirty_clear(node, 0);
686 18 : drawable_mark_modified(stack, tr_state);
687 : }
688 :
689 146 : static void PointSet2D_Draw(GF_Node *node, GF_TraverseState *tr_state)
690 : {
691 : GF_Path *path;
692 : Fixed alpha, w, h;
693 : u32 i;
694 : SFColor col;
695 146 : DrawableContext *ctx = tr_state->ctx;
696 : M_PointSet2D *ps2D = (M_PointSet2D *)node;
697 146 : M_Coordinate2D *coord = (M_Coordinate2D*) ps2D->coord;
698 146 : M_Color *color = (M_Color *) ps2D->color;
699 :
700 : /*never outline PS2D*/
701 146 : ctx->flags |= CTX_PATH_STROKE;
702 146 : if (!color || color->color.count<coord->point.count) {
703 : /*no texturing*/
704 146 : visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
705 146 : return;
706 : }
707 :
708 0 : get_point_size(&ctx->transform, &w, &h);
709 :
710 0 : path = gf_path_new();
711 0 : alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255;
712 0 : for (i = 0; i < coord->point.count; i++) {
713 0 : col = color->color.vals[i];
714 0 : ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
715 0 : gf_path_add_rect_center(path, coord->point.vals[i].x, coord->point.vals[i].y, w, h);
716 0 : visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state);
717 0 : gf_path_reset(path);
718 0 : ctx->flags &= ~CTX_PATH_FILLED;
719 : }
720 0 : gf_path_del(path);
721 : }
722 :
723 460 : static void TraversePointSet2D(GF_Node *node, void *rs, Bool is_destroy)
724 : {
725 : DrawableContext *ctx;
726 : M_PointSet2D *ps2D = (M_PointSet2D *)node;
727 460 : Drawable *stack = (Drawable *)gf_node_get_private(node);
728 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
729 :
730 460 : if (is_destroy) {
731 18 : drawable_node_del(node);
732 18 : return;
733 : }
734 :
735 442 : if (!ps2D->coord) return;
736 :
737 442 : pointset2d_check_changes(node, stack, tr_state);
738 :
739 442 : switch (tr_state->traversing_mode) {
740 146 : case TRAVERSE_DRAW_2D:
741 146 : PointSet2D_Draw(node, tr_state);
742 146 : return;
743 : #ifndef GPAC_DISABLE_3D
744 144 : case TRAVERSE_DRAW_3D:
745 : {
746 : DrawAspect2D asp;
747 144 : if (!stack->mesh) {
748 9 : stack->mesh = new_mesh();
749 9 : mesh_new_ps(stack->mesh, ps2D->coord, ps2D->color);
750 : }
751 : memset(&asp, 0, sizeof(DrawAspect2D));
752 144 : drawable_get_aspect_2d_mpeg4(node, &asp, tr_state);
753 144 : visual_3d_set_material_2d_argb(tr_state->visual, asp.fill_color);
754 144 : visual_3d_mesh_paint(tr_state, stack->mesh);
755 : return;
756 : }
757 : #endif
758 0 : case TRAVERSE_GET_BOUNDS:
759 0 : gf_path_get_bounds(stack->path, &tr_state->bounds);
760 0 : return;
761 : case TRAVERSE_PICK:
762 : return;
763 152 : case TRAVERSE_SORT:
764 : #ifndef GPAC_DISABLE_3D
765 152 : if (tr_state->visual->type_3d) return;
766 : #endif
767 152 : ctx = drawable_init_context_mpeg4(stack, tr_state);
768 152 : if (!ctx) return;
769 152 : drawable_finalize_sort(ctx, tr_state, NULL);
770 152 : break;
771 : default:
772 : return;
773 : }
774 : }
775 :
776 :
777 18 : void compositor_init_pointset2d(GF_Compositor *compositor, GF_Node *node)
778 : {
779 18 : Drawable *stack = drawable_stack_new(compositor, node);
780 18 : stack->flags = DRAWABLE_USE_TRAVERSE_DRAW;
781 18 : gf_node_set_callback_function(node, TraversePointSet2D);
782 18 : }
783 :
784 0 : static void TraverseBitWrapper(GF_Node *node, void *rs, Bool is_destroy)
785 : {
786 : GF_TraverseState *tr_state;
787 : M_BitWrapper *bitWrap;
788 :
789 0 : if (is_destroy) {
790 0 : gf_node_set_private(node, NULL);
791 0 : return;
792 : }
793 : #ifdef GPAC_ENABLE_COVERAGE
794 0 : if (!rs) return;
795 : #endif
796 :
797 : tr_state = (GF_TraverseState *)rs;
798 : // Traverse the node here
799 : bitWrap = (M_BitWrapper *)node;
800 0 : gf_node_traverse(bitWrap->node, tr_state);
801 : }
802 :
803 6 : void compositor_init_bitwrapper(GF_Compositor *compositor, GF_Node *node)
804 : {
805 : M_BitWrapper *bit;
806 : bit = (M_BitWrapper *)node;
807 6 : if (!bit->node) return;
808 0 : gf_node_set_private(node, gf_node_get_private(bit->node));
809 0 : gf_node_set_callback_function(node, TraverseBitWrapper);
810 :
811 : #ifdef GPAC_ENABLE_COVERAGE
812 0 : if (gf_sys_is_cov_mode()) {
813 : TraverseBitWrapper(node, NULL, GF_FALSE);
814 : }
815 : #endif
816 : }
817 :
818 :
819 : #endif /*GPAC_DISABLE_VRML*/
|