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 "visual_manager.h"
29 : #include "nodes_stacks.h"
30 :
31 : //#define SKIP_CONTEXT
32 :
33 1403938 : Bool gf_irect_overlaps(GF_IRect *rc1, GF_IRect *rc2)
34 : {
35 1403938 : if (! rc2->height || !rc2->width || !rc1->height || !rc1->width) return 0;
36 1398984 : if (rc2->x+rc2->width<=rc1->x) return 0;
37 1078119 : if (rc2->x>=rc1->x+rc1->width) return 0;
38 893925 : if (rc2->y-rc2->height>=rc1->y) return 0;
39 586076 : if (rc2->y<=rc1->y-rc1->height) return 0;
40 440306 : return 1;
41 : }
42 :
43 : /*intersects @rc1 with @rc2 - the new @rc1 is the intersection*/
44 1381985 : void gf_irect_intersect(GF_IRect *rc1, GF_IRect *rc2)
45 : {
46 1381985 : if (! gf_irect_overlaps(rc1, rc2)) {
47 963072 : rc1->width = rc1->height = 0;
48 963072 : return;
49 : }
50 418913 : if (rc2->x > rc1->x) {
51 50241 : rc1->width -= rc2->x - rc1->x;
52 50241 : rc1->x = rc2->x;
53 : }
54 418913 : if (rc2->x + rc2->width < rc1->x + rc1->width) {
55 52838 : rc1->width = rc2->width + rc2->x - rc1->x;
56 : }
57 418913 : if (rc2->y < rc1->y) {
58 39619 : rc1->height -= rc1->y - rc2->y;
59 39619 : rc1->y = rc2->y;
60 : }
61 418913 : if (rc2->y - rc2->height > rc1->y - rc1->height) {
62 54009 : rc1->height = rc1->y - rc2->y + rc2->height;
63 : }
64 : }
65 :
66 :
67 0 : GF_Rect gf_rect_ft(GF_IRect *rc)
68 : {
69 : GF_Rect rcft;
70 13372 : rcft.x = INT2FIX(rc->x);
71 13372 : rcft.y = INT2FIX(rc->y);
72 13372 : rcft.width = INT2FIX(rc->width);
73 13372 : rcft.height = INT2FIX(rc->height);
74 0 : return rcft;
75 : }
76 :
77 178666 : DrawableContext *visual_2d_get_drawable_context(GF_VisualManager *visual)
78 : {
79 : #ifdef SKIP_CONTEXT
80 : return NULL;
81 : #endif
82 :
83 178666 : if (!visual->context) {
84 523 : visual->context = NewDrawableContext();
85 523 : visual->cur_context = visual->context;
86 523 : drawctx_reset(visual->context);
87 523 : visual->num_nodes_current_frame ++;
88 523 : return visual->context;
89 : }
90 : // assert(visual->cur_context);
91 : /*current context is OK*/
92 178143 : if (!visual->cur_context->drawable) {
93 : /*reset next context in display list for next call*/
94 59164 : if (visual->cur_context->next) visual->cur_context->next->drawable = NULL;
95 59164 : drawctx_reset(visual->cur_context);
96 59164 : return visual->cur_context;
97 : }
98 : /*need a new context and next one is OK*/
99 118979 : if (visual->cur_context->next) {
100 113960 : visual->cur_context = visual->cur_context->next;
101 : // assert(visual->cur_context->drawable == NULL);
102 : /*reset next context in display list for next call*/
103 113960 : if (visual->cur_context->next) visual->cur_context->next->drawable = NULL;
104 113960 : drawctx_reset(visual->cur_context);
105 113960 : visual->num_nodes_current_frame ++;
106 113960 : return visual->cur_context;
107 : }
108 : /*need to create a new context*/
109 5019 : visual->cur_context->next = NewDrawableContext();
110 5019 : visual->cur_context = visual->cur_context->next;
111 5019 : drawctx_reset(visual->cur_context);
112 5019 : visual->num_nodes_current_frame ++;
113 :
114 : //pre-allocate some contexts
115 : #if 0
116 : {
117 : u32 i;
118 : DrawableContext *last = visual->cur_context;
119 : for (i=0; i<50; i++) {
120 : last->next = gf_malloc(sizeof(DrawableContext));
121 : last = last->next;
122 : last->drawable = NULL;
123 : last->col_mat = NULL;
124 : }
125 : last->next = NULL;
126 : }
127 : #endif
128 :
129 5019 : return visual->cur_context;
130 : }
131 :
132 36214 : void visual_2d_remove_last_context(GF_VisualManager *visual)
133 : {
134 : assert(visual->cur_context);
135 36214 : visual->cur_context->drawable = NULL;
136 36214 : }
137 :
138 :
139 3955 : void visual_2d_drawable_delete(GF_VisualManager *visual, struct _drawable *drawable)
140 : {
141 : DrawableContext *ctx;
142 : /*remove drawable from visual list*/
143 3955 : struct _drawable_store *it = visual->prev_nodes;
144 : struct _drawable_store *prev = NULL;
145 8470 : while (it) {
146 692 : if (it->drawable != drawable) {
147 : prev = it;
148 560 : it = prev->next;
149 560 : continue;
150 : }
151 132 : if (prev) prev->next = it->next;
152 74 : else visual->prev_nodes = it->next;
153 132 : if (!it->next) visual->last_prev_entry = prev;
154 132 : gf_free(it);
155 132 : break;
156 : }
157 :
158 3955 : ctx = visual->context;
159 8644 : while (ctx && ctx->drawable) {
160 : /*remove visual registration flag*/
161 734 : if (ctx->drawable == drawable) {
162 83 : ctx->flags = 0;
163 83 : ctx->drawable = NULL;
164 : }
165 734 : ctx = ctx->next;
166 : }
167 3955 : if (drawable->flags & DRAWABLE_IS_OVERLAY) {
168 0 : visual->compositor->video_out->Blit(visual->compositor->video_out, NULL, NULL, NULL, 1);
169 : }
170 3955 : }
171 :
172 : #if 0 //unused
173 : Bool visual_2d_node_cull(GF_TraverseState *tr_state, GF_Rect *bounds)
174 : {
175 : GF_Rect rc;
176 : GF_IRect i_rc;
177 : rc = *bounds;
178 : gf_mx2d_apply_rect(&tr_state->transform, &rc);
179 : i_rc = gf_rect_pixelize(&rc);
180 : if (gf_irect_overlaps(&tr_state->visual->top_clipper, &i_rc)) return 1;
181 : return 0;
182 : }
183 : #endif
184 :
185 24879 : void visual_2d_setup_projection(GF_VisualManager *visual, GF_TraverseState *tr_state)
186 : {
187 : GF_Rect rc;
188 :
189 24879 : tr_state->visual = visual;
190 : #ifndef GPAC_DISABLE_VRML
191 24879 : tr_state->backgrounds = visual->back_stack;
192 24879 : tr_state->viewpoints = visual->view_stack;
193 : #endif
194 :
195 : /*setup clipper*/
196 24879 : if (visual->center_coords) {
197 24019 : if (!visual->offscreen) {
198 22205 : if (visual->compositor->sz)
199 22205 : rc = gf_rect_center(INT2FIX(visual->compositor->display_width), INT2FIX(visual->compositor->display_height));
200 : else
201 0 : rc = gf_rect_center(INT2FIX(visual->compositor->output_width + 2*visual->compositor->vp_x), INT2FIX(visual->compositor->output_height + 2*visual->compositor->vp_y));
202 : } else {
203 1814 : rc = gf_rect_center(INT2FIX(visual->width), INT2FIX(visual->height));
204 : }
205 : } else {
206 860 : rc.x = 0;
207 860 : rc.width = INT2FIX(visual->width);
208 860 : rc.y = rc.height = INT2FIX(visual->height);
209 : }
210 : /*set top-transform to pixelMetrics*/
211 24879 : if (!tr_state->pixel_metrics) gf_mx2d_add_scale(&tr_state->transform, tr_state->min_hsize, tr_state->min_hsize);
212 :
213 24879 : visual->surf_rect = gf_rect_pixelize(&rc);
214 :
215 : // GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] output rectangle setup - width %d height %d\n", visual->surf_rect.width, visual->surf_rect.height));
216 :
217 : /*setup top clipper*/
218 24879 : if (visual->center_coords) {
219 24019 : rc = gf_rect_center(INT2FIX(visual->width), INT2FIX(visual->height));
220 : } else {
221 860 : rc.width = INT2FIX(visual->width);
222 860 : rc.height = INT2FIX(visual->height);
223 860 : rc.x = 0;
224 860 : rc.y = rc.height;
225 860 : if (visual->compositor->visual==visual) {
226 860 : rc.x += INT2FIX(visual->compositor->vp_x);
227 860 : rc.y += INT2FIX(visual->compositor->vp_y);
228 : }
229 : }
230 :
231 : /*setup viewport*/
232 : #ifndef GPAC_DISABLE_VRML
233 24879 : if (gf_list_count(visual->view_stack)) {
234 364 : tr_state->traversing_mode = TRAVERSE_BINDABLE;
235 364 : tr_state->bounds = rc;
236 364 : gf_node_traverse((GF_Node *) gf_list_get(visual->view_stack, 0), tr_state);
237 : }
238 : #endif
239 :
240 : #ifndef GPAC_DISABLE_3D
241 49758 : gf_mx_init(tr_state->model_matrix);
242 24879 : if (tr_state->camera && (visual->compositor->visual==visual)) {
243 1128 : tr_state->camera->vp.width = INT2FIX(visual->compositor->output_width);
244 1128 : tr_state->camera->vp.height = INT2FIX(visual->compositor->output_height);
245 : }
246 : #endif
247 :
248 24879 : visual->top_clipper = gf_rect_pixelize(&rc);
249 24879 : tr_state->clipper = rc;
250 : // GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Cliper setup - %d:%d@%dx%d\n", visual->top_clipper.x, visual->top_clipper.y, visual->top_clipper.width, visual->top_clipper.height));
251 24879 : }
252 :
253 21466 : GF_Err visual_2d_init_draw(GF_VisualManager *visual, GF_TraverseState *tr_state)
254 : {
255 : GF_Err e;
256 : u32 rem, count;
257 : struct _drawable_store *it, *prev;
258 : #ifndef GPAC_DISABLE_VRML
259 : DrawableContext *ctx;
260 : M_Background2D *bck;
261 : #endif
262 : u32 mode2d;
263 :
264 : /*reset display list*/
265 21466 : visual->cur_context = visual->context;
266 21466 : if (visual->context) visual->context->drawable = NULL;
267 21466 : visual->has_modif = 0;
268 21466 : visual->has_overlays = 0;
269 :
270 21466 : visual_2d_setup_projection(visual, tr_state);
271 21466 : if (!visual->top_clipper.width || !visual->top_clipper.height)
272 : return GF_OK;
273 :
274 21466 : tr_state->traversing_mode = TRAVERSE_SORT;
275 21466 : visual->num_nodes_current_frame = 0;
276 :
277 : /*setup raster surface, brush and pen */
278 21466 : e = visual_2d_init_raster(visual);
279 21466 : if (e)
280 : return e;
281 :
282 21466 : tr_state->immediate_for_defer = GF_FALSE;
283 : mode2d = 0;
284 21466 : if (tr_state->immediate_draw) {
285 : mode2d = 1;
286 : }
287 : /*if we're requested to invalidate everything, switch to direct drawing but don't reset bounds*/
288 21185 : else if (tr_state->invalidate_all) {
289 595 : tr_state->immediate_draw = 1;
290 595 : tr_state->immediate_for_defer = GF_TRUE;
291 : mode2d = 2;
292 : }
293 21466 : tr_state->invalidate_all = 0;
294 :
295 : /*reset prev nodes if any (previous traverse was indirect)*/
296 : rem = count = 0;
297 : prev = NULL;
298 21466 : it = visual->prev_nodes;
299 146150 : while (it) {
300 : /*node was not drawn on this visual*/
301 103218 : if (!drawable_flush_bounds(it->drawable, visual, mode2d)) {
302 6 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Unregistering previously drawn node %s from visual\n", gf_node_get_class_name(it->drawable->node)));
303 :
304 : /*remove all bounds info related to this visual and unreg node */
305 6 : drawable_reset_bounds(it->drawable, visual);
306 :
307 6 : if (prev) prev->next = it->next;
308 4 : else visual->prev_nodes = it->next;
309 6 : if (!it->next) visual->last_prev_entry = prev;
310 6 : rem++;
311 6 : gf_free(it);
312 6 : it = prev ? prev->next : visual->prev_nodes;
313 : } else {
314 : /*mark drawable as already registered with visual*/
315 103212 : it->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL;
316 : prev = it;
317 103212 : it = it->next;
318 103212 : count++;
319 : }
320 : }
321 21466 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Top visual initialized - %d nodes registered and %d removed - using %s rendering\n", count, rem, mode2d ? "direct" : "dirty-rect"));
322 21466 : if (!mode2d) return GF_OK;
323 :
324 : #ifndef GPAC_DISABLE_VRML
325 : /*direct mode, draw background*/
326 876 : bck = (M_Background2D*) gf_list_get(visual->back_stack, 0);
327 876 : if (bck && bck->isBound) {
328 96 : ctx = b2d_get_context(bck, visual->back_stack);
329 96 : if (ctx) {
330 : /*force clearing entire zone, not just viewport, when using color. If texture, we MUST
331 : use the VP clipper in order to compute offsets when blitting bitmaps*/
332 96 : if (ctx->aspect.fill_texture &&ctx->aspect.fill_texture->stream) {
333 29 : ctx->bi->clip = visual->top_clipper;
334 : } else {
335 67 : ctx->bi->clip = visual->surf_rect;
336 : }
337 192 : ctx->bi->unclip = gf_rect_ft(&ctx->bi->clip);
338 96 : tr_state->traversing_mode = TRAVERSE_BINDABLE;
339 96 : ctx->flags |= CTX_BACKROUND_NOT_LAYER;
340 96 : gf_node_traverse((GF_Node *) bck, tr_state);
341 96 : tr_state->traversing_mode = TRAVERSE_SORT;
342 96 : ctx->flags &= ~CTX_BACKROUND_NOT_LAYER;
343 : } else {
344 0 : visual->ClearSurface(visual, NULL, 0, 0);
345 : }
346 : } else
347 : #endif
348 : {
349 780 : visual->ClearSurface(visual, NULL, 0, 0);
350 : #ifndef GPAC_DISABLE_3D
351 780 : if (visual->compositor->hybrid_opengl) {
352 170 : visual->ClearSurface(visual, NULL, 0, GF_TRUE);
353 : }
354 : #endif
355 : }
356 : return GF_OK;
357 : }
358 :
359 :
360 :
361 : /*@rc2 fully contained in @rc1*/
362 901 : Bool gf_irect_inside(GF_IRect *rc1, GF_IRect *rc2)
363 : {
364 901 : if (!rc1->width || !rc1->height) return 0;
365 901 : if ( (rc1->x <= rc2->x) && (rc1->y >= rc2->y) && (rc1->x + rc1->width >= rc2->x + rc2->width) && (rc1->y - rc1->height <= rc2->y - rc2->height) )
366 : return 1;
367 564 : return 0;
368 : }
369 :
370 :
371 : /*clears list*/
372 : #define ra_clear(ra) { (ra)->count = 0; }
373 :
374 : /*is list empty*/
375 : #define ra_is_empty(ra) (!((ra)->count))
376 :
377 : /*adds @rc2 to @rc1 - the new @rc1 contains the old @rc1 and @rc2*/
378 36420 : void gf_irect_union(GF_IRect *rc1, GF_IRect *rc2)
379 : {
380 36420 : if (!rc1->width || !rc1->height) {
381 0 : *rc1=*rc2;
382 0 : return;
383 : }
384 :
385 36420 : if (rc2->x < rc1->x) {
386 4425 : rc1->width += rc1->x - rc2->x;
387 4425 : rc1->x = rc2->x;
388 : }
389 36420 : if (rc2->x + rc2->width > rc1->x+rc1->width) rc1->width = rc2->x + rc2->width - rc1->x;
390 36420 : if (rc2->y > rc1->y) {
391 5072 : rc1->height += rc2->y - rc1->y;
392 5072 : rc1->y = rc2->y;
393 : }
394 36420 : if (rc2->y - rc2->height < rc1->y - rc1->height) rc1->height = rc1->y - rc2->y + rc2->height;
395 : }
396 :
397 :
398 : /*adds rectangle to the list performing union test*/
399 22409 : void ra_union_rect(GF_RectArray *ra, GF_IRect *rc)
400 : {
401 : u32 i;
402 :
403 : assert(rc->width && rc->height);
404 :
405 22969 : for (i=0; i<ra->count; i++) {
406 21953 : if (gf_irect_overlaps(&ra->list[i].rect, rc)) {
407 21393 : gf_irect_union(&ra->list[i].rect, rc);
408 21393 : return;
409 : }
410 : }
411 1016 : ra_add(ra, rc);
412 : }
413 :
414 : /*returns relation between rc1 and rc2:
415 : 0: rectangles are disjoint
416 : 1: rectangles overlap
417 : 2: rc2 completely covers rc1
418 :
419 : */
420 83652 : static u32 gf_irect_relation(GF_IRect *rc1, GF_IRect *rc2)
421 : {
422 83652 : if (! rc2->height || !rc2->width || !rc1->height || !rc1->width) return 0;
423 83652 : if (rc2->x+rc2->width<=rc1->x) return 0;
424 63120 : if (rc2->x>=rc1->x+rc1->width) return 0;
425 41141 : if (rc2->y-rc2->height>=rc1->y) return 0;
426 33476 : if (rc2->y<=rc1->y-rc1->height) return 0;
427 :
428 27657 : if ( (rc2->x <= rc1->x) && (rc2->y >= rc1->y) && (rc2->x + rc2->width >= rc1->x + rc1->width) && (rc2->y - rc2->height <= rc1->y - rc1->height) )
429 : return 2;
430 :
431 15027 : return 1;
432 : }
433 :
434 : /*refreshes the content of the array to have only non-overlapping rects*/
435 19725 : void ra_refresh(GF_RectArray *ra)
436 : {
437 : u32 i, j, k;
438 44487 : restart:
439 82041 : for (i=0; i<ra->count; i++) {
440 80040 : for (j=i+1; j<ra->count; j++) {
441 62211 : switch (gf_irect_relation(&ra->list[j].rect, &ra->list[i].rect)) {
442 :
443 : /*both rectangles overlap, merge them and remove opaque node info*/
444 6330 : case 1:
445 6330 : gf_irect_union(&ra->list[i].rect, &ra->list[j].rect);
446 : #ifdef TRACK_OPAQUE_REGIONS
447 : /*current dirty rect is no longer opaque*/
448 : ra->list[i].opaque_node_index = 0;
449 : #endif
450 : /*FALLTHROUGH*/
451 : /*first rectangle covers second, just remove*/
452 18325 : case 2:
453 : /*remove rect*/
454 18325 : k = ra->count - j - 1;
455 18325 : if (k) {
456 9559 : memmove(&ra->list[j], & ra->list[j+1], sizeof(GF_IRect)*k);
457 : }
458 18325 : ra->count--;
459 18325 : if (ra->count>=2)
460 : goto restart;
461 : return;
462 : default:
463 : break;
464 : }
465 : }
466 : }
467 : }
468 :
469 126079 : static u32 register_context_rect(GF_RectArray *ra, DrawableContext *ctx, u32 ctx_idx, DrawableContext **first_opaque)
470 : {
471 : u32 i;
472 : Bool needs_redraw;
473 : #ifdef TRACK_OPAQUE_REGIONS
474 : Bool is_transparent = 1;
475 : #endif
476 126079 : GF_IRect *rc = &ctx->bi->clip;
477 : assert(rc->width && rc->height);
478 :
479 : /*node is modified*/
480 126079 : needs_redraw = (ctx->flags & CTX_REDRAW_MASK) ? 1 : 0;
481 :
482 : /*node is not transparent*/
483 126079 : if ((ctx->flags & CTX_NO_ANTIALIAS) && !(ctx->flags & CTX_IS_TRANSPARENT) ) {
484 : #ifdef TRACK_OPAQUE_REGIONS
485 : is_transparent = 0;
486 : #endif
487 20175 : if ((*first_opaque==NULL) && needs_redraw) *first_opaque = ctx;
488 : }
489 :
490 : #ifndef GPAC_DISABLE_3D
491 126079 : if (ctx->flags & CTX_HYBOGL_NO_CLEAR) {
492 : return 2;
493 : }
494 : #endif
495 :
496 84534 : for (i=0; i<ra->count; i++) {
497 93866 : if (needs_redraw) {
498 21441 : switch (gf_irect_relation(&ra->list[i].rect, rc)) {
499 : /*context intersects an existing rectangle, merge them and remove opaque idx info*/
500 8697 : case 1:
501 8697 : gf_irect_union(&ra->list[i].rect, rc);
502 : #ifdef TRACK_OPAQUE_REGIONS
503 : ra->list[i].opaque_node_index = 0;
504 : #endif
505 : return 1;
506 : /*context covers an existing rectangle, replace rect and add opaque idx info*/
507 635 : case 2:
508 635 : ra->list[i].rect= *rc;
509 : #ifdef TRACK_OPAQUE_REGIONS
510 : ra->list[i].opaque_node_index = is_transparent ? 0 : ctx_idx;
511 : #endif
512 : return 1;
513 : }
514 : }
515 : #ifdef TRACK_OPAQUE_REGIONS
516 : /*context unchanged coverring an entire area*/
517 : else if (!is_transparent && gf_irect_inside(rc, &ra->list[i].rect)) {
518 : /*remove rect*/
519 : u32 k = ra->count - i - 1;
520 : if (k) {
521 : memmove(&ra->list[i], & ra->list[i+1], sizeof(GF_RectArrayEntry)*k);
522 : }
523 : ra->count--;
524 : i--;
525 : }
526 : #endif
527 : }
528 : /*not found, add rect*/
529 116545 : if (needs_redraw) {
530 19158 : ra_add(ra, rc);
531 : #ifdef TRACK_OPAQUE_REGIONS
532 : ra->list[ra->count-1].opaque_node_index = is_transparent ? 0 : ctx_idx;
533 : #endif
534 : }
535 : return 1;
536 : }
537 :
538 :
539 18238 : static void register_dirty_rect(GF_RectArray *ra, GF_IRect *rc)
540 : {
541 18238 : if (!rc->width || !rc->height) return;
542 :
543 : /*technically this is correct however the gain is not that big*/
544 : #if 0
545 :
546 : #ifdef TRACK_OPAQUE_REGIONS
547 : u32 i;
548 : for (i=0; i<ra->count; i++) {
549 : switch (gf_irect_relation(rc, &ra->list[i].rect)) {
550 : /*dirty area intersects this dirty rectangle, merge them and remove opaque idx info*/
551 : case 1:
552 : gf_irect_union(&ra->list[i].rect, rc);
553 : ra->list[i].opaque_node_index = 0;
554 : return;
555 : /*dirty area is covered by this dirty rectangle, nothing to do*/
556 : case 2:
557 : return;
558 : }
559 : }
560 : #endif
561 : /*not found, add rect*/
562 : ra_add(ra, rc);
563 : #ifdef TRACK_OPAQUE_REGIONS
564 : ra->list[ra->count-1].opaque_node_index = 0;
565 : #endif
566 :
567 : #else
568 :
569 18238 : ra_add(ra, rc);
570 :
571 : #ifdef TRACK_OPAQUE_REGIONS
572 : ra->list[ra->count-1].opaque_node_index = 0;
573 : #endif
574 :
575 : #endif
576 : }
577 :
578 :
579 21466 : Bool visual_2d_terminate_draw(GF_VisualManager *visual, GF_TraverseState *tr_state)
580 : {
581 : u32 k, i, count, num_nodes, num_changed;
582 : GF_IRect refreshRect;
583 : Bool redraw_all;
584 : Bool hyb_force_redraw=GF_FALSE;
585 : u32 hyb_force_background = 0;
586 : #ifndef GPAC_DISABLE_VRML
587 : M_Background2D *bck = NULL;
588 : DrawableContext *bck_ctx = NULL;
589 : #endif
590 : DrawableContext *ctx;
591 : struct _drawable_store *it, *prev;
592 21466 : DrawableContext *first_opaque = NULL;
593 : Bool has_clear = 0;
594 : Bool has_changed = 0;
595 : Bool redraw_all_on_background_change = GF_TRUE;
596 :
597 : /*in direct mode the visual is always redrawn*/
598 21466 : if (tr_state->immediate_draw) {
599 : /*flush pending contexts due to overlays*/
600 876 : visual_2d_flush_overlay_areas(visual, tr_state);
601 :
602 876 : visual_2d_release_raster(visual);
603 876 : visual_clean_contexts(visual);
604 876 : visual->num_nodes_prev_frame = visual->num_nodes_current_frame;
605 876 : return 1;
606 : }
607 :
608 : num_changed = 0;
609 :
610 : /*if the aspect ratio has changed redraw everything*/
611 20590 : redraw_all = tr_state->invalidate_all;
612 :
613 : #ifndef GPAC_DISABLE_3D
614 20590 : if (visual->compositor->hybrid_opengl && !visual->offscreen) redraw_all_on_background_change = GF_FALSE;
615 : #endif
616 : /*check for background changes for transparent nodes*/
617 : #ifndef GPAC_DISABLE_VRML
618 20590 : bck = (M_Background2D*)gf_list_get(visual->back_stack, 0);
619 20590 : if (bck) {
620 17907 : if (!bck->isBound) {
621 0 : if (visual->last_had_back) {
622 0 : if (redraw_all_on_background_change) redraw_all = 1;
623 : else hyb_force_background = 1;
624 : }
625 0 : visual->last_had_back = 0;
626 : } else {
627 17907 : bck_ctx = b2d_get_context(bck, visual->back_stack);
628 17907 : if (!visual->last_had_back || (bck_ctx->flags & CTX_REDRAW_MASK) ) {
629 1019 : if (redraw_all_on_background_change) redraw_all = 1;
630 : }
631 : /*in hybridGL we will have to force background draw even if no change, since backbuffer GL is not persistent*/
632 17907 : if (!redraw_all_on_background_change)
633 : hyb_force_background = 1;
634 :
635 17907 : visual->last_had_back = (bck_ctx->aspect.fill_texture && !bck_ctx->aspect.fill_texture->transparent) ? 2 : 1;
636 : }
637 : } else
638 : #endif
639 2683 : if (visual->last_had_back) {
640 0 : visual->last_had_back = 0;
641 0 : if (redraw_all_on_background_change) redraw_all = 1;
642 : else hyb_force_background = 1;
643 2683 : } else if (!redraw_all_on_background_change) {
644 : hyb_force_background = 1;
645 : }
646 :
647 : num_nodes = 0;
648 20590 : ctx = visual->context;
649 172104 : while (ctx && ctx->drawable) {
650 130924 : num_nodes++;
651 :
652 130924 : drawctx_update_info(ctx, visual);
653 130924 : if (!redraw_all) {
654 : u32 res;
655 : // assert( gf_irect_inside(&visual->top_clipper, &ctx->bi->clip) );
656 126079 : res = register_context_rect(&visual->to_redraw, ctx, num_nodes, &first_opaque);
657 126079 : if (res) {
658 126079 : num_changed ++;
659 126079 : if (res==2)
660 : hyb_force_redraw=GF_TRUE;
661 : }
662 :
663 : }
664 130924 : ctx = ctx->next;
665 : }
666 :
667 : /*garbage collection*/
668 :
669 : /*clear all remaining bounds since last frames (the ones that moved or that are not drawn this frame)*/
670 : prev = NULL;
671 20590 : it = visual->prev_nodes;
672 146157 : while (it) {
673 123456 : while (drawable_get_previous_bound(it->drawable, &refreshRect, visual)) {
674 18479 : if (!redraw_all) {
675 : //assert( gf_irect_inside(&visual->top_clipper, &refreshRect) );
676 18238 : gf_irect_intersect(&refreshRect, &visual->top_clipper);
677 18238 : register_dirty_rect(&visual->to_redraw, &refreshRect);
678 : has_clear=1;
679 : }
680 : }
681 : /*if node is marked as undrawn, remove from visual*/
682 104977 : if (!(it->drawable->flags & DRAWABLE_DRAWN_ON_VISUAL)) {
683 1767 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Node %s no longer on visual - unregistering it\n", gf_node_get_class_name(it->drawable->node)));
684 :
685 : /*remove all bounds info related to this visual and unreg node */
686 1767 : drawable_reset_bounds(it->drawable, visual);
687 :
688 1767 : it->drawable->flags &= ~DRAWABLE_REGISTERED_WITH_VISUAL;
689 :
690 1767 : if (it->drawable->flags & DRAWABLE_IS_OVERLAY) {
691 0 : visual->compositor->video_out->Blit(visual->compositor->video_out, NULL, NULL, NULL, 1);
692 : }
693 :
694 1767 : if (prev) prev->next = it->next;
695 70 : else visual->prev_nodes = it->next;
696 1767 : if (!it->next) visual->last_prev_entry = prev;
697 1767 : gf_free(it);
698 1767 : it = prev ? prev->next : visual->prev_nodes;
699 : } else {
700 : prev = it;
701 103210 : it = it->next;
702 : }
703 : }
704 :
705 20590 : if (redraw_all) {
706 865 : ra_clear(&visual->to_redraw);
707 865 : ra_add(&visual->to_redraw, &visual->surf_rect);
708 : #ifdef TRACK_OPAQUE_REGIONS
709 : visual->to_redraw.list[0].opaque_node_index=0;
710 : #endif
711 : } else {
712 19725 : ra_refresh(&visual->to_redraw);
713 :
714 19725 : if (visual->compositor->debug_defer) {
715 248 : visual->ClearSurface(visual, &visual->top_clipper, 0, 0);
716 : }
717 : }
718 :
719 : /*nothing to redraw*/
720 20590 : if (ra_is_empty(&visual->to_redraw) ) {
721 5655 : if (!hyb_force_redraw && !hyb_force_background) {
722 : #ifndef GPAC_DISABLE_3D
723 : //force canvas draw
724 5611 : visual->nb_objects_on_canvas_since_last_ogl_flush = 1;
725 : #endif
726 5611 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] No changes found since last frame - skipping redraw\n"));
727 : goto exit;
728 : }
729 :
730 : //openGL, force redraw of complete scene but signal we shoud only draw the background, not clear the canvas (nothing to redraw except GL textures)
731 44 : if (hyb_force_redraw) {
732 : hyb_force_background = 2;
733 0 : ra_add(&visual->to_redraw, &visual->surf_rect);
734 : }
735 : }
736 : has_changed = 1;
737 14979 : tr_state->traversing_mode = TRAVERSE_DRAW_2D;
738 :
739 : //if only one opaque object has changed and not moved, skip background unless hybgl mode
740 14979 : if (!visual->compositor->hybrid_opengl && !hyb_force_redraw && !hyb_force_background && first_opaque && (visual->to_redraw.count==1) && irect_rect_equal(&first_opaque->bi->clip, &visual->to_redraw.list[0].rect)) {
741 0 : visual->has_modif=0;
742 0 : goto skip_background;
743 : }
744 :
745 : /*redraw everything*/
746 : #ifndef GPAC_DISABLE_VRML
747 14979 : if (bck_ctx) {
748 13276 : drawable_check_bounds(bck_ctx, visual);
749 13276 : tr_state->ctx = bck_ctx;
750 13276 : tr_state->appear = NULL;
751 13276 : visual->draw_node_index = 0;
752 :
753 : /*force clearing entire zone, not just viewport, when using color. If texture, we MUST
754 : use the VP clipper in order to compute offsets when blitting bitmaps*/
755 13276 : if (bck_ctx->aspect.fill_texture && bck_ctx->aspect.fill_texture->stream) {
756 839 : bck_ctx->bi->clip = visual->top_clipper;
757 : } else {
758 12437 : bck_ctx->bi->clip = visual->surf_rect;
759 : }
760 26552 : bck_ctx->bi->unclip = gf_rect_ft(&bck_ctx->bi->clip);
761 13276 : bck_ctx->next = visual->context;
762 13276 : bck_ctx->flags |= CTX_BACKROUND_NOT_LAYER;
763 :
764 : //for hybrid openGL, only redraw background but do not erase canvas
765 13276 : if (hyb_force_background==2)
766 0 : bck_ctx->flags |= CTX_BACKROUND_NO_CLEAR;
767 :
768 13276 : gf_node_traverse(bck_ctx->drawable->node, tr_state);
769 :
770 13276 : bck_ctx->flags &= ~CTX_BACKROUND_NOT_LAYER;
771 13276 : bck_ctx->flags &= ~CTX_BACKROUND_NO_CLEAR;
772 : } else
773 : #endif /*GPAC_DISABLE_VRML*/
774 : {
775 :
776 : #ifndef GPAC_DISABLE_3D
777 : //cleanup openGL screen
778 1703 : if (visual->compositor->hybrid_opengl) {
779 351 : compositor_2d_hybgl_clear_surface(tr_state->visual, NULL, 0, GF_FALSE);
780 : }
781 : #endif
782 :
783 : //and clean dirty rect - for hybrid openGL this will clear the canvas, otherwise the 2D backbuffer
784 1703 : count = visual->to_redraw.count;
785 3597 : for (k=0; k<count; k++) {
786 : GF_IRect rc;
787 : /*opaque area, skip*/
788 : #ifdef TRACK_OPAQUE_REGIONS
789 : if (visual->to_redraw.list[k].opaque_node_index > 0) continue;
790 : #endif
791 1894 : rc = visual->to_redraw.list[k].rect;
792 1894 : visual->ClearSurface(visual, &rc, 0, 1);
793 : }
794 : }
795 14979 : if (!visual->to_redraw.count) {
796 44 : visual->has_modif=0;
797 : #ifndef GPAC_DISABLE_3D
798 : //force canvas flush
799 44 : visual->nb_objects_on_canvas_since_last_ogl_flush = 1;
800 : #endif
801 44 : goto exit;
802 : }
803 :
804 20457 : if (!redraw_all && !has_clear) visual->has_modif=0;
805 :
806 24348 : skip_background:
807 :
808 : #ifndef GPAC_DISABLE_LOG
809 14935 : if (gf_log_tool_level_on(GF_LOG_COMPOSE, GF_LOG_DEBUG)) {
810 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Redraw %d / %d nodes (all: %s - %d dirty rects\n)", num_changed, num_nodes, redraw_all ? "yes" : "no", visual->to_redraw.count));
811 0 : if (visual->to_redraw.count>1) GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("\n"));
812 :
813 0 : for (i=0; i<visual->to_redraw.count; i++) {
814 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("\tDirtyRect #%d: %d:%d@%dx%d\n", i+1, visual->to_redraw.list[i].rect.x, visual->to_redraw.list[i].rect.y, visual->to_redraw.list[i].rect.width, visual->to_redraw.list[i].rect.height));
815 : assert(visual->to_redraw.list[i].rect.width);
816 : }
817 : }
818 : #endif
819 :
820 14935 : visual->draw_node_index = 0;
821 :
822 14935 : ctx = visual->context;
823 142357 : while (ctx && ctx->drawable) {
824 :
825 112487 : visual->draw_node_index ++;
826 112487 : tr_state->ctx = ctx;
827 :
828 : /*if overlay we cannot remove the context and cannot draw directly*/
829 112487 : if (! visual_2d_overlaps_overlay(tr_state->visual, ctx, tr_state)) {
830 :
831 112487 : if (ctx->drawable->flags & DRAWABLE_USE_TRAVERSE_DRAW) {
832 66286 : gf_node_traverse(ctx->drawable->node, tr_state);
833 : } else {
834 46201 : drawable_draw(ctx->drawable, tr_state);
835 : }
836 : }
837 112487 : ctx = ctx->next;
838 : }
839 : /*flush pending contexts due to overlays*/
840 14935 : visual_2d_flush_overlay_areas(visual, tr_state);
841 : #ifndef GPAC_DISABLE_VRML
842 14935 : if (bck_ctx) bck_ctx->next = NULL;
843 : #endif
844 :
845 14935 : if (visual->direct_flush) {
846 : GF_DirtyRectangles dr;
847 0 : dr.count = visual->to_redraw.count;
848 0 : dr.list = gf_malloc(sizeof(GF_IRect)*dr.count);
849 0 : for (i=0; i<dr.count; i++) {
850 0 : dr.list[i] = visual->to_redraw.list[i].rect;
851 : }
852 0 : visual->compositor->video_out->FlushRectangles(visual->compositor->video_out, &dr);
853 0 : visual->compositor->skip_flush = 1;
854 0 : gf_free(dr.list);
855 : }
856 :
857 35525 : exit:
858 : /*clear dirty rects*/
859 20590 : ra_clear(&visual->to_redraw);
860 20590 : visual_2d_release_raster(visual);
861 20590 : visual_clean_contexts(visual);
862 20590 : visual->num_nodes_prev_frame = visual->num_nodes_current_frame;
863 20590 : return has_changed;
864 : }
865 :
866 21466 : Bool visual_2d_draw_frame(GF_VisualManager *visual, GF_Node *root, GF_TraverseState *tr_state, Bool is_root_visual)
867 : {
868 : GF_Matrix2D backup;
869 : u32 i;
870 : Bool res;
871 : GF_Err e;
872 : #ifndef GPAC_DISABLE_LOG
873 21466 : u32 itime, time = gf_sys_clock();
874 : #endif
875 :
876 21466 : gf_mx2d_copy(backup, tr_state->transform);
877 21466 : visual->bounds_tracker_modif_flag = DRAWABLE_HAS_CHANGED;
878 :
879 : #ifndef GPAC_DISABLE_3D
880 21466 : if (visual->compositor->hybrid_opengl && visual->compositor->fbo_id) {
881 876 : compositor_3d_enable_fbo(visual->compositor, GF_TRUE);
882 : }
883 : #endif
884 :
885 21466 : e = visual_2d_init_draw(visual, tr_state);
886 21466 : if (e) {
887 : gf_mx2d_copy(tr_state->transform, backup);
888 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Visual2D] Cannot init draw phase: %s\n", gf_error_to_string(e)));
889 : #ifndef GPAC_DISABLE_3D
890 0 : if (visual->compositor->hybrid_opengl && visual->compositor->fbo_id) {
891 0 : compositor_3d_enable_fbo(visual->compositor, GF_FALSE);
892 : }
893 : #endif
894 : return 0;
895 : }
896 :
897 : #ifndef GPAC_DISABLE_LOG
898 21466 : itime = gf_sys_clock();
899 21466 : visual->compositor->traverse_setup_time = itime - time;
900 : time = itime;
901 : #endif
902 :
903 21466 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Traversing scene subtree (root node %s)\n", root ? gf_node_get_class_name(root) : "none"));
904 :
905 21466 : if (is_root_visual) {
906 : GF_SceneGraph *sg;
907 19702 : gf_node_traverse(root, tr_state);
908 :
909 19702 : i=0;
910 39519 : while ((sg = (GF_SceneGraph*)gf_list_enum(visual->compositor->extra_scenes, &i))) {
911 115 : gf_sc_traverse_subscene(visual->compositor, root, sg, tr_state);
912 : }
913 : } else {
914 1764 : gf_node_traverse(root, tr_state);
915 : }
916 :
917 : #ifndef GPAC_DISABLE_LOG
918 21466 : itime = gf_sys_clock();
919 21466 : visual->compositor->traverse_and_direct_draw_time = itime - time;
920 : time = itime;
921 : #endif
922 :
923 : gf_mx2d_copy(tr_state->transform, backup);
924 21466 : res = visual_2d_terminate_draw(visual, tr_state);
925 :
926 : #ifndef GPAC_DISABLE_LOG
927 21466 : if (!tr_state->immediate_draw) {
928 20590 : visual->compositor->indirect_draw_time = gf_sys_clock() - time;
929 : }
930 : #endif
931 :
932 : #ifndef GPAC_DISABLE_3D
933 21466 : if (visual->compositor->hybrid_opengl && visual->compositor->fbo_id) {
934 876 : compositor_3d_enable_fbo(visual->compositor, GF_FALSE);
935 : }
936 : #endif
937 : return res;
938 : }
939 :
940 :
941 3413 : void visual_2d_pick_node(GF_VisualManager *visual, GF_TraverseState *tr_state, GF_Event *ev, GF_ChildNodeItem *children)
942 : {
943 : GF_Matrix2D backup;
944 3413 : visual->bounds_tracker_modif_flag = DRAWABLE_HAS_CHANGED_IN_LAST_TRAVERSE;
945 :
946 3413 : gf_mx2d_copy(backup, tr_state->transform);
947 :
948 3413 : visual_2d_setup_projection(visual, tr_state);
949 :
950 3413 : visual->compositor->hit_node = NULL;
951 3413 : tr_state->ray.orig.x = INT2FIX(ev->mouse.x);
952 3413 : tr_state->ray.orig.y = INT2FIX(ev->mouse.y);
953 3413 : tr_state->ray.orig.z = 0;
954 3413 : tr_state->ray.dir.x = 0;
955 3413 : tr_state->ray.dir.y = 0;
956 3413 : tr_state->ray.dir.z = -FIX_ONE;
957 :
958 3413 : visual->compositor->hit_world_point = tr_state->ray.orig;
959 3413 : visual->compositor->hit_world_ray = tr_state->ray;
960 3413 : visual->compositor->hit_square_dist = 0;
961 :
962 3413 : gf_list_reset(visual->compositor->sensors);
963 3413 : tr_state->traversing_mode = TRAVERSE_PICK;
964 :
965 : /*not the root scene, use children list*/
966 3413 : if (visual->compositor->visual != visual) {
967 228 : while (children) {
968 178 : gf_node_traverse(children->node, tr_state);
969 178 : children = children->next;
970 : }
971 : } else {
972 3363 : u32 i = 0;
973 3363 : GF_SceneGraph *sg = visual->compositor->scene;
974 3363 : GF_Node *root = gf_sg_get_root_node(sg);
975 3363 : gf_node_traverse(root, tr_state);
976 6756 : while ((sg = (GF_SceneGraph*)gf_list_enum(visual->compositor->extra_scenes, &i))) {
977 30 : gf_sc_traverse_subscene(visual->compositor, root, sg, tr_state);
978 : }
979 : }
980 : gf_mx2d_copy(tr_state->transform, backup);
981 3413 : }
982 :
|