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 : #include "nodes_stacks.h"
27 : #include "mpeg4_grouping.h"
28 : #include "visual_manager.h"
29 :
30 : #ifndef GPAC_DISABLE_VRML
31 :
32 : typedef struct
33 : {
34 : s32 last_switch;
35 : } SwitchStack;
36 :
37 28748 : static void TraverseSwitch(GF_Node *node, void *rs, Bool is_destroy)
38 : {
39 : GF_ChildNodeItem *l;
40 : u32 i;
41 : Bool prev_switch;
42 : GF_ChildNodeItem *children;
43 : s32 whichChoice;
44 : GF_Node *child;
45 28748 : SwitchStack *st = (SwitchStack *)gf_node_get_private(node);
46 : GF_TraverseState *tr_state;
47 : tr_state = (GF_TraverseState *)rs;
48 : children = NULL;
49 :
50 : whichChoice = -1;
51 28748 : if (is_destroy) {
52 431 : gf_sc_check_focus_upon_destroy(node);
53 431 : gf_free(st);
54 431 : return;
55 : }
56 : /*WARNING: X3D/MPEG4 NOT COMPATIBLE*/
57 28317 : switch (gf_node_get_tag(node)) {
58 28317 : case TAG_MPEG4_Switch:
59 28317 : children = ((M_Switch *)node)->choice;
60 28317 : whichChoice = ((M_Switch *)node)->whichChoice;
61 28317 : break;
62 : #ifndef GPAC_DISABLE_X3D
63 0 : case TAG_X3D_Switch:
64 0 : children = ((X_Switch *)node)->children;
65 0 : whichChoice = ((X_Switch *)node)->whichChoice;
66 0 : break;
67 : #endif
68 : }
69 :
70 28317 : if (tr_state->traversing_mode!=TRAVERSE_GET_BOUNDS) {
71 28272 : prev_switch = tr_state->switched_off;
72 : /*check changes in choice field*/
73 28272 : if ((gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) || (st->last_switch != whichChoice) ) {
74 739 : tr_state->switched_off = 1;
75 : i=0;
76 : l = children;
77 4427 : while (l) {
78 : // if ((s32) i!=whichChoice) gf_node_traverse(l->node, tr_state);
79 2949 : if ((s32) i == st->last_switch) gf_node_traverse(l->node, tr_state);
80 2949 : l = l->next;
81 2949 : i++;
82 : }
83 739 : tr_state->switched_off = 0;
84 739 : st->last_switch = whichChoice;
85 : }
86 :
87 28272 : gf_node_dirty_clear(node, 0);
88 :
89 : /*no need to check for sensors since a sensor is active for the whole parent group, that is for switch itself
90 : CSQ: switch cannot be used to switch sensors, too bad...*/
91 28272 : tr_state->switched_off = prev_switch;
92 : }
93 :
94 28317 : if (!children) return;
95 28175 : if (whichChoice==-2) {
96 : #ifndef GPAC_DISABLE_3D
97 0 : if (tr_state->visual->autostereo_type) {
98 : u32 idx;
99 0 : u32 count = gf_node_list_get_count(children);
100 : /*this should be a bit more subtle (reusing views if missing, ...)...*/
101 0 : idx = tr_state->visual->current_view % count;
102 :
103 0 : child = (GF_Node*)gf_node_list_get_child(children, idx);
104 0 : gf_node_traverse(child, tr_state);
105 0 : return;
106 : } else
107 : #endif //GPAC_DISABLE_3D
108 : {
109 : /*fallback to first view*/
110 : whichChoice=0;
111 : }
112 : }
113 28175 : if (whichChoice>=0) {
114 26902 : child = (GF_Node*)gf_node_list_get_child(children, whichChoice);
115 26902 : gf_node_traverse(child, tr_state);
116 : }
117 : }
118 :
119 431 : void compositor_init_switch(GF_Compositor *compositor, GF_Node *node)
120 : {
121 431 : SwitchStack *st = (SwitchStack *)gf_malloc(sizeof(SwitchStack));
122 431 : st->last_switch = -1;
123 431 : gf_node_set_private(node, st);
124 431 : gf_node_set_callback_function(node, TraverseSwitch);
125 431 : }
126 :
127 :
128 : /*transform2D*/
129 : typedef struct
130 : {
131 : GROUPING_MPEG4_STACK_2D
132 : GF_Matrix2D mat;
133 : u8 is_identity;
134 : u8 is_null;
135 : } Transform2DStack;
136 :
137 301981 : static void traverse_transform(GF_Node *node, Transform2DStack *stack, GF_TraverseState *tr_state)
138 : {
139 301981 : if (stack->is_null) return;
140 :
141 : /*note we don't clear dirty flag, this is done in traversing*/
142 299995 : if (stack->is_identity) {
143 111123 : group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
144 : }
145 : #ifndef GPAC_DISABLE_3D
146 188872 : else if (tr_state->visual->type_3d) {
147 : GF_Matrix mx_bckup;
148 5005 : gf_mx_copy(mx_bckup, tr_state->model_matrix);
149 :
150 5005 : gf_mx_add_matrix_2d(&tr_state->model_matrix, &stack->mat);
151 5005 : group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
152 : gf_mx_copy(tr_state->model_matrix, mx_bckup);
153 : }
154 : #endif
155 : else {
156 : GF_Matrix2D bckup;
157 183867 : gf_mx2d_copy(bckup, tr_state->transform);
158 183867 : gf_mx2d_pre_multiply(&tr_state->transform, &stack->mat);
159 :
160 183867 : group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
161 :
162 : gf_mx2d_copy(tr_state->transform, bckup);
163 : }
164 :
165 299995 : if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
166 1563 : gf_mx2d_apply_rect(&stack->mat, &tr_state->bounds);
167 : }
168 : }
169 :
170 :
171 296364 : static void TraverseTransform2D(GF_Node *node, void *rs, Bool is_destroy)
172 : {
173 : M_Transform2D *tr = (M_Transform2D *)node;
174 296364 : Transform2DStack *ptr = (Transform2DStack *)gf_node_get_private(node);
175 : GF_TraverseState *tr_state;
176 :
177 296364 : if (is_destroy) {
178 4753 : gf_sc_check_focus_upon_destroy(node);
179 4753 : group_2d_destroy(node, (GroupingNode2D*)ptr);
180 4753 : gf_free(ptr);
181 4753 : return;
182 : }
183 :
184 : tr_state = (GF_TraverseState *) rs;
185 :
186 291611 : if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
187 19738 : gf_mx2d_init(ptr->mat);
188 9869 : ptr->is_identity = 1;
189 9869 : if ((tr->scale.x != FIX_ONE) || (tr->scale.y != FIX_ONE)) {
190 2540 : gf_mx2d_add_scale_at(&ptr->mat, tr->scale.x, tr->scale.y, 0, 0, tr->scaleOrientation);
191 2540 : ptr->is_identity = 0;
192 : }
193 9869 : if (tr->rotationAngle) {
194 886 : gf_mx2d_add_rotation(&ptr->mat, tr->center.x, tr->center.y, tr->rotationAngle);
195 886 : ptr->is_identity = 0;
196 : }
197 9869 : if (tr->translation.x || tr->translation.y) {
198 7001 : ptr->is_identity = 0;
199 7001 : gf_mx2d_add_translation(&ptr->mat, tr->translation.x, tr->translation.y);
200 : }
201 9869 : gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
202 9869 : ptr->is_null = (!tr->scale.x || !tr->scale.y) ? 1 : 0;
203 : }
204 291611 : traverse_transform(node, ptr, tr_state);
205 : }
206 :
207 4753 : void compositor_init_transform2d(GF_Compositor *compositor, GF_Node *node)
208 : {
209 : Transform2DStack *stack;
210 4753 : GF_SAFEALLOC(stack, Transform2DStack);
211 4753 : if (!stack) {
212 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate transform2d stack\n"));
213 : return;
214 : }
215 :
216 9506 : gf_mx2d_init(stack->mat);
217 4753 : stack->is_identity = 1;
218 4753 : gf_node_set_private(node, stack);
219 4753 : gf_node_set_callback_function(node, TraverseTransform2D);
220 : }
221 :
222 1929 : void tr_mx2d_get_matrix(GF_Node *n, GF_Matrix2D *mat)
223 : {
224 : M_TransformMatrix2D *tr = (M_TransformMatrix2D*)n;
225 3858 : gf_mx2d_init(*mat);
226 1929 : mat->m[0] = tr->mxx;
227 1929 : mat->m[1] = tr->mxy;
228 1929 : mat->m[2] = tr->tx;
229 1929 : mat->m[3] = tr->myx;
230 1929 : mat->m[4] = tr->myy;
231 1929 : mat->m[5] = tr->ty;
232 1929 : }
233 :
234 :
235 : /*TransformMatrix2D*/
236 11239 : static void TraverseTransformMatrix2D(GF_Node *node, void *rs, Bool is_destroy)
237 : {
238 11239 : Transform2DStack *ptr = (Transform2DStack *) gf_node_get_private(node);
239 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
240 :
241 11239 : if (is_destroy) {
242 869 : gf_sc_check_focus_upon_destroy(node);
243 869 : group_2d_destroy(node, (GroupingNode2D*)ptr);
244 869 : gf_free(ptr);
245 869 : return;
246 : }
247 :
248 10370 : if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
249 : M_TransformMatrix2D *tr = (M_TransformMatrix2D*)node;
250 1047 : tr_mx2d_get_matrix(node, &ptr->mat);
251 1047 : if ((tr->mxx==FIX_ONE) && (tr->mxy==0) && (tr->tx==0)
252 17 : && (tr->myx==0) && (tr->myy==FIX_ONE) && (tr->ty==0) )
253 17 : ptr->is_identity = 1;
254 : else
255 1030 : ptr->is_identity = 0;
256 :
257 1047 : ptr->is_null = ( (!ptr->mat.m[0] && !ptr->mat.m[1]) || (!ptr->mat.m[3] && !ptr->mat.m[4]) ) ? 1 : 0;
258 1047 : gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
259 : }
260 10370 : traverse_transform(node, ptr, tr_state);
261 : }
262 :
263 :
264 869 : void compositor_init_transformmatrix2d(GF_Compositor *compositor, GF_Node *node)
265 : {
266 : Transform2DStack *stack;
267 869 : GF_SAFEALLOC(stack, Transform2DStack);
268 869 : if (!stack) return;
269 :
270 1738 : gf_mx2d_init(stack->mat);
271 869 : gf_node_set_private(node, stack);
272 869 : gf_node_set_callback_function(node, TraverseTransformMatrix2D);
273 : }
274 :
275 :
276 : typedef struct
277 : {
278 : GROUPING_MPEG4_STACK_2D
279 : GF_ColorMatrix cmat;
280 : } ColorTransformStack;
281 :
282 : /*ColorTransform*/
283 24496 : static void TraverseColorTransform(GF_Node *node, void *rs, Bool is_destroy)
284 : {
285 : Bool c_changed;
286 : M_ColorTransform *tr = (M_ColorTransform *)node;
287 24496 : ColorTransformStack *ptr = (ColorTransformStack *)gf_node_get_private(node);
288 : GF_TraverseState *tr_state = (GF_TraverseState *) rs;
289 : Bool prev_inv;
290 :
291 24496 : if (is_destroy) {
292 430 : gf_sc_check_focus_upon_destroy(node);
293 430 : group_2d_destroy(node, (GroupingNode2D*)ptr);
294 430 : gf_free(ptr);
295 430 : return;
296 : }
297 24066 : if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
298 0 : group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
299 0 : return;
300 : }
301 :
302 24066 : prev_inv = tr_state->invalidate_all;
303 : c_changed = 0;
304 24066 : if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
305 1048 : gf_cmx_set(&ptr->cmat,
306 : tr->mrr , tr->mrg, tr->mrb, tr->mra, tr->tr,
307 : tr->mgr , tr->mgg, tr->mgb, tr->mga, tr->tg,
308 : tr->mbr, tr->mbg, tr->mbb, tr->mba, tr->tb,
309 : tr->mar, tr->mag, tr->mab, tr->maa, tr->ta);
310 : c_changed = 1;
311 1048 : gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
312 : }
313 :
314 24066 : if ((tr_state->traversing_mode==TRAVERSE_SORT)
315 5111 : && !tr->maa && !tr->mar && !tr->mag && !tr->mab && !tr->ta)
316 : return;
317 :
318 : /*if modified redraw all nodes*/
319 24058 : if (c_changed) tr_state->invalidate_all = 1;
320 :
321 : /*note we don't clear dirty flag, this is done in traversing*/
322 24058 : if (ptr->cmat.identity) {
323 0 : group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
324 : } else {
325 : GF_ColorMatrix gf_cmx_bck;
326 24058 : gf_cmx_copy(&gf_cmx_bck, &tr_state->color_mat);
327 24058 : gf_cmx_multiply(&tr_state->color_mat, &ptr->cmat);
328 :
329 :
330 24058 : group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
331 : /*restore traversing state*/
332 24058 : gf_cmx_copy(&tr_state->color_mat, &gf_cmx_bck);
333 : }
334 24058 : tr_state->invalidate_all = prev_inv;
335 : }
336 :
337 430 : void compositor_init_colortransform(GF_Compositor *compositor, GF_Node *node)
338 : {
339 : ColorTransformStack *stack;
340 430 : GF_SAFEALLOC(stack, ColorTransformStack);
341 430 : if (!stack) return;
342 :
343 430 : gf_cmx_init(&stack->cmat);
344 430 : gf_node_set_private(node, stack);
345 430 : gf_node_set_callback_function(node, TraverseColorTransform);
346 : }
347 :
348 :
349 : struct og_pos
350 : {
351 : Fixed priority;
352 : u32 position;
353 : };
354 : typedef struct
355 : {
356 : GROUPING_MPEG4_STACK_2D
357 : u32 *positions;
358 : } OrderedGroupStack;
359 :
360 :
361 13 : static s32 compare_priority(const void* elem1, const void* elem2)
362 : {
363 : struct og_pos *p1, *p2;
364 : p1 = (struct og_pos *)elem1;
365 : p2 = (struct og_pos *)elem2;
366 13 : if (p1->priority < p2->priority) return -1;
367 13 : if (p1->priority > p2->priority) return 1;
368 5 : return 0;
369 : }
370 :
371 :
372 29695 : static void TraverseOrderedGroup(GF_Node *node, void *rs, Bool is_destroy)
373 : {
374 : u32 i, count;
375 : struct og_pos *priorities;
376 : Bool invalidate_backup;
377 29695 : OrderedGroupStack *stack = (OrderedGroupStack *) gf_node_get_private(node);
378 : M_OrderedGroup *og = (M_OrderedGroup *) node;
379 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
380 :
381 29695 : if (is_destroy) {
382 672 : gf_sc_check_focus_upon_destroy(node);
383 672 : group_2d_destroy(node, (GroupingNode2D*)stack);
384 672 : if (stack->positions) gf_free(stack->positions);
385 672 : gf_free(stack);
386 672 : return;
387 : }
388 :
389 29023 : if (!og->order.count || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
390 28989 : gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
391 28989 : group_2d_traverse(node, (GroupingNode2D*)stack, tr_state);
392 28989 : return;
393 : }
394 :
395 34 : invalidate_backup = tr_state->invalidate_all;
396 : /*check whether the OrderedGroup node has changed*/
397 34 : if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
398 5 : if (stack->positions) gf_free(stack->positions);
399 5 : count = gf_node_list_get_count(og->children);
400 5 : priorities = (struct og_pos*)gf_malloc(sizeof(struct og_pos)*count);
401 20 : for (i=0; i<count; i++) {
402 15 : priorities[i].position = i;
403 15 : priorities[i].priority = (i<og->order.count) ? og->order.vals[i] : 0;
404 : }
405 5 : qsort(priorities, count, sizeof(struct og_pos), compare_priority);
406 :
407 5 : stack->positions = (u32*)gf_malloc(sizeof(u32) * count);
408 5 : for (i=0; i<count; i++) stack->positions[i] = priorities[i].position;
409 5 : gf_free(priorities);
410 :
411 5 : tr_state->invalidate_all = 1;
412 5 : gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
413 : }
414 34 : group_2d_traverse_with_order(node, (GroupingNode2D*)stack, tr_state, stack->positions);
415 34 : tr_state->invalidate_all = invalidate_backup;
416 : }
417 :
418 672 : void compositor_init_orderedgroup(GF_Compositor *compositor, GF_Node *node)
419 : {
420 : OrderedGroupStack *ptr;
421 672 : GF_SAFEALLOC(ptr, OrderedGroupStack);
422 672 : if (!ptr) return;
423 :
424 672 : gf_node_set_private(node, ptr);
425 672 : gf_node_set_callback_function(node, TraverseOrderedGroup);
426 : }
427 :
428 : #endif /*GPAC_DISABLE_VRML*/
429 :
|