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 "mpeg4_grouping.h"
30 : #include "visual_manager.h"
31 :
32 : #ifndef GPAC_DISABLE_VRML
33 :
34 :
35 : typedef struct
36 : {
37 : GROUPING_MPEG4_STACK_2D
38 : GF_List *backs;
39 : GF_List *views;
40 : Bool first;
41 : GF_Rect clip;
42 : } Layer2DStack;
43 :
44 :
45 :
46 5371 : static void l2d_CheckBindables(GF_Node *n, GF_TraverseState *tr_state, Bool force_traverse)
47 : {
48 : GF_Node *btop;
49 : M_Layer2D *l2d;
50 : l2d = (M_Layer2D *)n;
51 5371 : if (force_traverse) gf_node_traverse(l2d->background, tr_state);
52 5371 : btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
53 5371 : if (btop != l2d->background) {
54 1 : gf_node_unregister(l2d->background, n);
55 1 : gf_node_register(btop, n);
56 1 : l2d->background = btop;
57 1 : gf_node_event_out(n, 4/*"background"*/);
58 : }
59 5371 : if (force_traverse) gf_node_traverse(l2d->viewport, tr_state);
60 5371 : btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
61 5371 : if (btop != l2d->viewport) {
62 0 : gf_node_unregister(l2d->viewport, n);
63 0 : gf_node_register(btop, n);
64 0 : l2d->viewport = btop;
65 0 : gf_node_event_out(n, 5/*"viewport"*/);
66 : }
67 5371 : }
68 :
69 :
70 : #if VIEWPORT_CLIPS
71 : static void rect_intersect(GF_Rect *rc1, GF_Rect *rc2)
72 : {
73 : if (! gf_rect_overlaps(*rc1, *rc2)) {
74 : rc1->width = rc1->height = 0;
75 : return;
76 : }
77 : if (rc2->x > rc1->x) {
78 : rc1->width -= rc2->x - rc1->x;
79 : rc1->x = rc2->x;
80 : }
81 : if (rc2->x + rc2->width < rc1->x + rc1->width) {
82 : rc1->width = rc2->width + rc2->x - rc1->x;
83 : }
84 : if (rc2->y < rc1->y) {
85 : rc1->height -= rc1->y - rc2->y;
86 : rc1->y = rc2->y;
87 : }
88 : if (rc2->y - rc2->height > rc1->y - rc1->height) {
89 : rc1->height = rc1->y - rc2->y + rc2->height;
90 : }
91 : }
92 : #endif
93 :
94 5755 : static void TraverseLayer2D(GF_Node *node, void *rs, Bool is_destroy)
95 : {
96 : GF_List *oldb, *oldv;
97 : GF_Node *viewport;
98 : GF_Node *back;
99 : Bool prev_layer;
100 : GF_Matrix2D backup;
101 : GF_IRect prev_clip;
102 : GF_Rect rc;
103 : SFVec2f prev_vp;
104 :
105 : #ifndef GPAC_DISABLE_3D
106 : GF_Matrix mx3d, prev_layer_mx;
107 : GF_List *oldf, *oldn;
108 : GF_List *node_list_backup;
109 : GF_Rect prev_clipper;
110 : Bool had_clip;
111 : #endif
112 :
113 : M_Layer2D *l = (M_Layer2D *)node;
114 5755 : Layer2DStack *st = (Layer2DStack *) gf_node_get_private(node);
115 : GF_TraverseState *tr_state = (GF_TraverseState *) rs;
116 :
117 5755 : if (is_destroy) {
118 384 : BindableStackDelete(st->backs);
119 384 : BindableStackDelete(st->views);
120 384 : group_2d_destroy(node, (GroupingNode2D*)st);
121 384 : gf_free(st);
122 384 : return;
123 : }
124 :
125 : /*layers can only be used in a 2D context*/
126 : #ifndef GPAC_DISABLE_3D
127 5371 : if (tr_state->visual->type_3d && tr_state->camera && tr_state->camera->is_3D) return;
128 : #endif
129 :
130 : /*layer2D maintains its own stacks*/
131 5371 : oldb = tr_state->backgrounds;
132 5371 : oldv = tr_state->viewpoints;
133 5371 : tr_state->backgrounds = st->backs;
134 5371 : tr_state->viewpoints = st->views;
135 5371 : prev_layer = tr_state->is_layer;
136 5371 : tr_state->is_layer = 1;
137 : #ifndef GPAC_DISABLE_3D
138 5371 : oldf = tr_state->fogs;
139 5371 : oldn = tr_state->navigations;
140 5371 : tr_state->fogs = tr_state->navigations = NULL;
141 : #endif
142 :
143 5371 : l2d_CheckBindables(node, tr_state, st->first);
144 :
145 5371 : back = (GF_Node*)gf_list_get(st->backs, 0);
146 :
147 5371 : viewport = (GF_Node*)gf_list_get(st->views, 0);
148 :
149 5371 : if ((tr_state->traversing_mode == TRAVERSE_SORT) || (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS)) {
150 : /*override group bounds*/
151 5195 : visual_get_size_info(tr_state, &st->clip.width, &st->clip.height);
152 : /*setup bounds in local coord system*/
153 5195 : if (l->size.x>=0) st->clip.width = l->size.x;
154 5195 : if (l->size.y>=0) st->clip.height = l->size.y;
155 5195 : st->clip = gf_rect_center(st->clip.width, st->clip.height);
156 5195 : st->bounds = st->clip;
157 : }
158 :
159 5371 : prev_vp = tr_state->vp_size;
160 5371 : tr_state->vp_size.x = st->clip.width;
161 5371 : tr_state->vp_size.y = st->clip.height;
162 :
163 5371 : switch (tr_state->traversing_mode) {
164 5148 : case TRAVERSE_SORT:
165 : #ifndef GPAC_DISABLE_3D
166 5148 : if (tr_state->visual->type_3d) {
167 805 : gf_mx_copy(prev_layer_mx, tr_state->layer_matrix);
168 805 : tr_state->layer_clipper = compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, 1);
169 :
170 805 : gf_mx_copy(mx3d, tr_state->model_matrix);
171 :
172 : /*setup clipping*/
173 805 : if (had_clip) {
174 157 : visual_3d_reset_clipper_2d(tr_state->visual);
175 : }
176 805 : visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper, &mx3d);
177 :
178 : /*apply background BEFORE viewport*/
179 805 : if (back) {
180 471 : tr_state->traversing_mode = TRAVERSE_BINDABLE;
181 471 : gf_bbox_from_rect(&tr_state->bbox, &st->clip);
182 471 : gf_node_traverse(back, tr_state);
183 : }
184 :
185 : /*apply viewport*/
186 805 : if (viewport) {
187 28 : tr_state->traversing_mode = TRAVERSE_BINDABLE;
188 28 : tr_state->bounds = st->clip;
189 28 : gf_node_traverse(viewport, tr_state);
190 : }
191 :
192 :
193 805 : node_list_backup = tr_state->visual->alpha_nodes_to_draw;
194 805 : tr_state->visual->alpha_nodes_to_draw = gf_list_new();
195 805 : tr_state->traversing_mode = TRAVERSE_SORT;
196 : /*reset cull flag*/
197 805 : tr_state->cull_flag = 0;
198 805 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
199 :
200 805 : visual_3d_flush_contexts(tr_state->visual, tr_state);
201 805 : tr_state->traversing_mode = TRAVERSE_SORT;
202 :
203 : assert(!gf_list_count(tr_state->visual->alpha_nodes_to_draw));
204 805 : gf_list_del(tr_state->visual->alpha_nodes_to_draw);
205 805 : tr_state->visual->alpha_nodes_to_draw = node_list_backup;
206 :
207 : gf_mx_copy(tr_state->model_matrix, mx3d);
208 :
209 805 : visual_3d_reset_clipper_2d(tr_state->visual);
210 :
211 805 : tr_state->has_layer_clip = had_clip;
212 805 : if (had_clip) {
213 157 : tr_state->layer_clipper = prev_clipper;
214 : gf_mx_copy(tr_state->layer_matrix, prev_layer_mx);
215 157 : visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper, &prev_layer_mx);
216 : }
217 : } else
218 : #endif
219 : {
220 4343 : gf_mx2d_copy(backup, tr_state->transform);
221 :
222 4343 : prev_clip = tr_state->visual->top_clipper;
223 4343 : rc = st->clip;
224 :
225 : /*get clipper in world coordinate*/
226 4343 : gf_mx2d_apply_rect(&tr_state->transform, &rc);
227 :
228 4343 : if (viewport) {
229 56 : tr_state->traversing_mode = TRAVERSE_BINDABLE;
230 56 : tr_state->bounds = st->clip;
231 56 : gf_node_traverse(viewport, tr_state);
232 : #if VIEWPORT_CLIPS
233 : /*move viewport box in world coordinate*/
234 : gf_mx2d_apply_rect(&backup, &tr_state->bounds);
235 : /*and intersect with layer clipper*/
236 : rect_intersect(&rc, &tr_state->bounds);
237 : #endif
238 : }
239 :
240 4343 : rc.x -= FIX_ONE;
241 4343 : rc.width += 2*FIX_ONE;
242 4343 : rc.y += FIX_ONE;
243 4343 : rc.height += 2*FIX_ONE;
244 4343 : tr_state->visual->top_clipper = gf_rect_pixelize(&rc);
245 4343 : gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip);
246 4343 : tr_state->traversing_mode = TRAVERSE_SORT;
247 :
248 4343 : if (tr_state->visual->top_clipper.width && tr_state->visual->top_clipper.height) {
249 4201 : if (back && Bindable_GetIsBound(back) ) {
250 : DrawableContext *ctx;
251 :
252 860 : ctx = b2d_get_context((M_Background2D*) back, st->backs);
253 1720 : gf_mx2d_init(ctx->transform);
254 860 : ctx->bi->clip = tr_state->visual->top_clipper;
255 860 : ctx->bi->unclip = rc;
256 :
257 860 : if (tr_state->immediate_draw) {
258 6 : tr_state->ctx = ctx;
259 6 : tr_state->traversing_mode = TRAVERSE_DRAW_2D;
260 6 : gf_node_traverse(back, tr_state);
261 6 : tr_state->traversing_mode = TRAVERSE_SORT;
262 6 : tr_state->ctx = NULL;
263 : } else {
264 854 : DrawableContext *back_ctx = visual_2d_get_drawable_context(tr_state->visual);
265 :
266 854 : gf_node_traverse(back, tr_state);
267 :
268 854 : back_ctx->flags = ctx->flags;
269 854 : back_ctx->flags &= ~CTX_IS_TRANSPARENT;
270 854 : back_ctx->flags |= CTX_IS_BACKGROUND;
271 854 : back_ctx->aspect = ctx->aspect;
272 854 : back_ctx->drawable = ctx->drawable;
273 854 : drawable_check_bounds(back_ctx, tr_state->visual);
274 854 : back_ctx->bi->clip = ctx->bi->clip;
275 854 : back_ctx->bi->unclip = ctx->bi->unclip;
276 : }
277 : /*keep track of node drawn*/
278 860 : if (!(ctx->drawable->flags & DRAWABLE_REGISTERED_WITH_VISUAL) ) {
279 : struct _drawable_store *it;
280 17 : GF_SAFEALLOC(it, struct _drawable_store);
281 17 : if (!it) {
282 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Layer2D] Failed to allocate drawable store\n"));
283 : } else {
284 17 : it->drawable = ctx->drawable;
285 17 : if (tr_state->visual->last_prev_entry) {
286 13 : tr_state->visual->last_prev_entry->next = it;
287 13 : tr_state->visual->last_prev_entry = it;
288 : } else {
289 4 : tr_state->visual->prev_nodes = tr_state->visual->last_prev_entry = it;
290 : }
291 17 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer2D] Registering new drawn node %s on visual\n", gf_node_get_class_name(it->drawable->node)));
292 17 : ctx->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL;
293 : }
294 : }
295 : }
296 :
297 4201 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
298 : }
299 4343 : tr_state->visual->top_clipper = prev_clip;
300 : gf_mx2d_copy(tr_state->transform, backup);
301 : }
302 : break;
303 :
304 : /*check picking - we must fall in our 2D clipper*/
305 176 : case TRAVERSE_PICK:
306 176 : if (gf_sc_pick_in_clipper(tr_state, &st->clip)) {
307 :
308 : #ifndef GPAC_DISABLE_3D
309 135 : if (tr_state->visual->type_3d) {
310 : /*apply viewport*/
311 0 : if (viewport) {
312 0 : gf_mx_copy(mx3d, tr_state->model_matrix);
313 0 : tr_state->traversing_mode = TRAVERSE_BINDABLE;
314 0 : tr_state->bounds = st->clip;
315 0 : gf_node_traverse(viewport, tr_state);
316 0 : tr_state->traversing_mode = TRAVERSE_PICK;
317 0 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
318 : gf_mx_copy(tr_state->model_matrix, mx3d);
319 : } else {
320 0 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
321 : }
322 : } else
323 : #endif
324 : {
325 135 : if (viewport) {
326 0 : gf_mx2d_copy(backup, tr_state->transform);
327 0 : tr_state->traversing_mode = TRAVERSE_BINDABLE;
328 0 : tr_state->bounds = st->clip;
329 0 : gf_node_traverse(viewport, tr_state);
330 0 : tr_state->traversing_mode = TRAVERSE_PICK;
331 0 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
332 : gf_mx2d_copy(tr_state->transform, backup);
333 : } else {
334 135 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
335 : }
336 : }
337 : }
338 : break;
339 47 : case TRAVERSE_GET_BOUNDS:
340 47 : if (tr_state->for_node) {
341 0 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
342 : } else {
343 47 : tr_state->bounds = st->clip;
344 : #ifndef GPAC_DISABLE_3D
345 47 : gf_bbox_from_rect(&tr_state->bbox, &st->clip);
346 : #endif
347 : }
348 : break;
349 :
350 0 : case TRAVERSE_DRAW_2D:
351 0 : group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
352 0 : break;
353 :
354 : #ifndef GPAC_DISABLE_3D
355 : /*drawing a layer means drawing all sub-elements as a whole (no depth sorting with parents)*/
356 : case TRAVERSE_DRAW_3D:
357 : assert(0);
358 : break;
359 : #endif
360 : }
361 :
362 : /*restore traversing state*/
363 5371 : tr_state->vp_size = prev_vp;
364 5371 : tr_state->backgrounds = oldb;
365 5371 : tr_state->viewpoints = oldv;
366 5371 : tr_state->is_layer = prev_layer;
367 : #ifndef GPAC_DISABLE_3D
368 5371 : tr_state->fogs = oldf;
369 5371 : tr_state->navigations = oldn;
370 : #endif
371 :
372 : /*in case we missed bindables*/
373 5371 : if (st->first) {
374 319 : st->first = 0;
375 319 : gf_sc_invalidate(tr_state->visual->compositor, NULL);
376 : }
377 : }
378 :
379 384 : void compositor_init_layer2d(GF_Compositor *compositor, GF_Node *node)
380 : {
381 : Layer2DStack *stack;
382 384 : GF_SAFEALLOC(stack, Layer2DStack);
383 384 : if (!stack) {
384 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate layer2d stack\n"));
385 : return;
386 : }
387 :
388 384 : stack->backs = gf_list_new();
389 384 : stack->views = gf_list_new();
390 384 : stack->first = 1;
391 :
392 384 : gf_node_set_private(node, stack);
393 384 : gf_node_set_callback_function(node, TraverseLayer2D);
394 : }
395 :
396 :
397 : #endif /*GPAC_DISABLE_VRML*/
|