Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2020
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 <gpac/internal/scenegraph_dev.h>
29 :
30 : #include "nodes_stacks.h"
31 : #include "visual_manager.h"
32 : #include "texturing.h"
33 :
34 : #ifndef GPAC_DISABLE_VRML
35 :
36 : #ifdef GPAC_USE_TINYGL
37 : #include <GL/oscontext.h>
38 : #endif
39 :
40 : typedef struct
41 : {
42 : GF_TextureHandler txh;
43 : Fixed sx, sy;
44 : /*the visual object handling the texture*/
45 : GF_VisualManager *visual;
46 : Bool first, unsupported;
47 : GF_List *sensors, *previous_sensors, *temp_sensors, *temp_previous_sensors;
48 : GF_Node *prev_hit_appear;
49 :
50 : GF_TraverseState *tr_state;
51 :
52 : #ifdef GPAC_USE_TINYGL
53 : ostgl_context *tgl_ctx;
54 : #else
55 : Bool use_fbo;
56 : #endif
57 : } CompositeTextureStack;
58 :
59 :
60 0 : static Bool composite2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, struct _drawable_context *ctx)
61 : {
62 : u8 alpha = 0xFF;
63 : GF_VideoSurface offscreen_dst, video_src;
64 : GF_Window src_wnd, dst_wnd;
65 : Bool use_blit, has_scale;
66 : CompositeTextureStack *st;
67 :
68 0 : if (visual->compositor->disable_composite_blit) return 0;
69 :
70 0 : if (!ctx->aspect.fill_texture) return 1;
71 0 : if (ctx->transform.m[0]<0) return 0;
72 0 : if (ctx->transform.m[4]<0) {
73 0 : if (!(ctx->flags & CTX_FLIPED_COORDS)) return 0;
74 : } else {
75 0 : if (ctx->flags & CTX_FLIPED_COORDS) return 0;
76 : }
77 0 : if (ctx->transform.m[1] || ctx->transform.m[3]) return 0;
78 : #ifndef GPAC_DISABLE_VRML
79 0 : if ((ctx->flags & CTX_HAS_APPEARANCE) && ctx->appear && ((M_Appearance*)ctx->appear)->textureTransform)
80 : return 0;
81 : #endif
82 :
83 0 : alpha = GF_COL_A(ctx->aspect.fill_color);
84 : /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/
85 0 : if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
86 0 : if (!alpha) return 1;
87 :
88 0 : st = (CompositeTextureStack *) gf_node_get_private(visual->offscreen);
89 :
90 0 : if (!compositor_texture_rectangles(visual, ctx->aspect.fill_texture, &ctx->bi->clip, &ctx->bi->unclip, &src_wnd, &dst_wnd, &use_blit, &has_scale)) return 1;
91 :
92 : memset(&video_src, 0, sizeof(GF_VideoSurface));
93 0 : video_src.height = ctx->aspect.fill_texture->height;
94 0 : video_src.width = ctx->aspect.fill_texture->width;
95 : video_src.pitch_x = 0;
96 0 : video_src.pitch_y = ctx->aspect.fill_texture->stride;
97 0 : video_src.pixel_format = ctx->aspect.fill_texture->pixelformat;
98 : #ifdef GF_SR_USE_DEPTH
99 0 : if (ctx->aspect.fill_texture->pixelformat==GF_PIXEL_YUVD) video_src.pixel_format = GF_PIXEL_YUV;
100 : #endif
101 0 : video_src.video_buffer = ctx->aspect.fill_texture->data;
102 :
103 : memset(&offscreen_dst, 0, sizeof(GF_VideoSurface));
104 0 : offscreen_dst.width = st->txh.width;
105 0 : offscreen_dst.height = st->txh.height;
106 0 : offscreen_dst.pitch_y = st->txh.stride;
107 0 : offscreen_dst.pixel_format = st->txh.pixelformat;
108 0 : offscreen_dst.video_buffer = st->txh.data;
109 :
110 0 : gf_stretch_bits(&offscreen_dst, &video_src, &dst_wnd, &src_wnd, alpha, 0, tr_state->col_key, ctx->col_mat);
111 0 : return 1;
112 : }
113 :
114 2404 : static void composite_traverse(GF_Node *node, void *rs, Bool is_destroy)
115 : {
116 2404 : if (is_destroy) {
117 32 : u32 i=0;
118 : GF_VisualManager *a_visual;
119 32 : CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(node);
120 : /*unregister visual*/
121 32 : gf_sc_visual_unregister(st->visual->compositor, st->visual);
122 :
123 : /*We must make sure we don't keep pointers to this composite in the different visuals.
124 : - we must track Appearance nodes at the compositor level to undo the textureTransform while picking
125 : - but we clearly don't want to track destruction of all appearance nodes just to solve this texture delete
126 : => remove the entire compositeTexture appearance state - this may lead to small bugs in interaction logics, however they should
127 : not be too damageable
128 : */
129 32 : st->visual->compositor->hit_appear = NULL;
130 32 : st->visual->compositor->prev_hit_appear = NULL;
131 :
132 142 : while ( (a_visual = gf_list_enum(st->visual->compositor->visuals, &i))) {
133 78 : if (a_visual->offscreen) {
134 46 : CompositeTextureStack *a_st = (CompositeTextureStack *) gf_node_get_private(a_visual->offscreen);
135 46 : a_st->prev_hit_appear = NULL;
136 : }
137 : }
138 :
139 32 : visual_del(st->visual);
140 32 : if (st->txh.data) gf_free(st->txh.data);
141 : /*destroy texture*/
142 32 : gf_sc_texture_destroy(&st->txh);
143 : #ifdef GPAC_USE_TINYGL
144 : if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
145 : #endif
146 :
147 32 : gf_list_del(st->sensors);
148 32 : gf_list_del(st->previous_sensors);
149 :
150 32 : gf_list_del(st->tr_state->vrml_sensors);
151 32 : gf_free(st->tr_state);
152 :
153 32 : gf_free(st);
154 : } else {
155 2372 : gf_node_traverse_children(node, rs);
156 : }
157 2404 : }
158 :
159 2068 : static Bool composite_do_bindable(GF_Node *n, GF_TraverseState *tr_state, Bool force_check)
160 : {
161 : GF_Node *btop;
162 : Bool ret = 0;
163 2068 : switch (gf_node_get_tag(n)) {
164 : #ifndef GPAC_DISABLE_3D
165 304 : case TAG_MPEG4_CompositeTexture3D:
166 : {
167 : M_CompositeTexture3D*c3d = (M_CompositeTexture3D*)n;
168 304 : if (force_check || gf_node_dirty_get(c3d->background)) {
169 68 : gf_node_traverse(c3d->background, tr_state);
170 : ret = 1;
171 : }
172 304 : btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
173 304 : if (btop != c3d->background) {
174 2 : gf_node_unregister(c3d->background, n);
175 2 : gf_node_register(btop, n);
176 2 : c3d->background = btop;
177 2 : gf_node_event_out(n, 5/*"background"*/);
178 : ret = 1;
179 : }
180 304 : if (force_check || gf_node_dirty_get(c3d->viewpoint)) {
181 2 : gf_node_traverse(c3d->viewpoint, tr_state);
182 : ret = 1;
183 : }
184 304 : btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
185 304 : if (btop != c3d->viewpoint) {
186 0 : gf_node_unregister(c3d->viewpoint, n);
187 0 : gf_node_register(btop, n);
188 0 : c3d->viewpoint = btop;
189 0 : gf_node_event_out(n, 8/*"viewpoint"*/);
190 : ret = 1;
191 : }
192 :
193 304 : if (force_check || gf_node_dirty_get(c3d->fog)) {
194 2 : gf_node_traverse(c3d->fog, tr_state);
195 : ret = 1;
196 : }
197 304 : btop = (GF_Node*)gf_list_get(tr_state->fogs, 0);
198 304 : if (btop != c3d->fog) {
199 0 : gf_node_unregister(c3d->fog, n);
200 0 : gf_node_register(btop, n);
201 0 : c3d->fog = btop;
202 0 : gf_node_event_out(n, 6/*"fog"*/);
203 : ret = 1;
204 : }
205 :
206 304 : if (force_check || gf_node_dirty_get(c3d->navigationInfo)) {
207 2 : gf_node_traverse(c3d->navigationInfo, tr_state);
208 : ret = 1;
209 : }
210 304 : btop = (GF_Node*)gf_list_get(tr_state->navigations, 0);
211 304 : if (btop != c3d->navigationInfo) {
212 0 : gf_node_unregister(c3d->navigationInfo, n);
213 0 : gf_node_register(btop, n);
214 0 : c3d->navigationInfo = btop;
215 0 : gf_node_event_out(n, 7/*"navigationInfo"*/);
216 : ret = 1;
217 : }
218 : return ret;
219 : }
220 : #endif
221 1764 : case TAG_MPEG4_CompositeTexture2D:
222 : {
223 : M_CompositeTexture2D *c2d = (M_CompositeTexture2D*)n;
224 1764 : if (force_check || gf_node_dirty_get(c2d->background)) {
225 36 : gf_node_traverse(c2d->background, tr_state);
226 : ret = 1;
227 : }
228 1764 : btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
229 1764 : if (btop != c2d->background) {
230 9 : gf_node_unregister(c2d->background, n);
231 9 : gf_node_register(btop, n);
232 9 : c2d->background = btop;
233 9 : gf_node_event_out(n, 5/*"background"*/);
234 : ret = 1;
235 : }
236 :
237 1764 : if (force_check || gf_node_dirty_get(c2d->viewport)) {
238 30 : gf_node_traverse(c2d->viewport, tr_state);
239 : ret = 1;
240 : }
241 1764 : btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
242 1764 : if (btop != c2d->viewport) {
243 0 : gf_node_unregister(c2d->viewport, n);
244 0 : gf_node_register(btop, n);
245 0 : c2d->viewport = btop;
246 0 : gf_node_event_out(n, 6/*"viewport"*/);
247 : ret = 1;
248 : }
249 :
250 : return ret;
251 : }
252 : }
253 : return 0;
254 : }
255 :
256 2627 : static void composite_update(GF_TextureHandler *txh)
257 : {
258 : s32 w, h;
259 : GF_EVGStencil *stencil;
260 : #ifndef GPAC_USE_GLES1X
261 : M_Background2D *back;
262 : #endif
263 : GF_List *sensor_bck;
264 : Bool invalidate_all;
265 : u32 new_pixel_format;
266 2627 : GF_Compositor *compositor = (GF_Compositor *)txh->compositor;
267 2627 : CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(txh->owner);
268 :
269 2627 : if (st->unsupported) return;
270 :
271 : /*
272 : if (compositor->recompute_ar) {
273 : gf_node_dirty_set(txh->owner, 0, 0);
274 : return;
275 : }
276 : */
277 2627 : if (!compositor->rebuild_offscreen_textures && (!compositor->text_edit_changed || !st->visual->has_text_edit ) && !gf_node_dirty_get(txh->owner)) {
278 559 : txh->needs_refresh = 0;
279 559 : return;
280 : }
281 2068 : gf_node_dirty_clear(st->txh.owner, 0);
282 :
283 : /*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/
284 : #if defined(GPAC_USE_GLES1X)
285 : new_pixel_format = GF_PIXEL_RGBA;
286 :
287 : #else
288 :
289 2068 : back = gf_list_get(st->visual->back_stack, 0);
290 2068 : if (back && back->isBound) new_pixel_format = GF_PIXEL_RGB;
291 : else new_pixel_format = GF_PIXEL_RGBA;
292 :
293 : #ifdef GPAC_USE_TINYGL
294 : /*TinyGL pixel format is fixed at compile time, we cannot override it !*/
295 : if (st->visual->type_3d) new_pixel_format = GF_PIXEL_RGBA;
296 :
297 : #elif !defined(GPAC_DISABLE_3D)
298 : /*no alpha support in offscreen rendering*/
299 2068 : if (!compositor->visual->type_3d && !compositor->hybrid_opengl && !compositor->fbo_id && (st->visual->type_3d) && !(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA))
300 : new_pixel_format = GF_PIXEL_RGB;
301 : #endif
302 :
303 : #endif //GPAC_USE_GLES1X
304 :
305 : /*FIXME - we assume RGB+Depth+bitshape, we should check with the video out module*/
306 : #if defined(GF_SR_USE_DEPTH) && !defined(GPAC_DISABLE_3D)
307 2068 : if (st->visual->type_3d && (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_DEPTH) ) new_pixel_format = GF_PIXEL_RGBDS;
308 : #endif
309 :
310 :
311 : #ifndef GPAC_DISABLE_3D
312 2068 : if (st->visual->type_3d>1) {
313 302 : w = ((M_CompositeTexture3D*)txh->owner)->pixelWidth;
314 302 : h = ((M_CompositeTexture3D*)txh->owner)->pixelHeight;
315 : } else
316 : #endif
317 : {
318 1766 : w = ((M_CompositeTexture2D*)txh->owner)->pixelWidth;
319 1766 : h = ((M_CompositeTexture2D*)txh->owner)->pixelHeight;
320 : }
321 :
322 : /*internal GPAC hacks for testing color spaces*/
323 2068 : if (w<-1) {
324 0 : w = -w;
325 0 : if (h<0) {
326 0 : h = -h;
327 0 : if (new_pixel_format==GF_PIXEL_RGBA) {
328 : new_pixel_format=GF_PIXEL_ARGB;
329 : } else {
330 : new_pixel_format=GF_PIXEL_BGR;
331 : }
332 : } else {
333 0 : if (new_pixel_format==GF_PIXEL_RGB) {
334 : new_pixel_format=GF_PIXEL_RGBX;
335 : }
336 : }
337 : }
338 2068 : else if (h<-1) {
339 0 : h = -h;
340 0 : if (new_pixel_format==GF_PIXEL_RGB) {
341 : new_pixel_format=GF_PIXEL_RGBX;
342 : }
343 : }
344 :
345 2068 : if (w<0) w = 0;
346 2068 : if (h<0) h = 0;
347 :
348 :
349 2068 : if (!w || !h) {
350 0 : if (txh->tx_io) {
351 : #ifdef GPAC_USE_TINYGL
352 : if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
353 : #endif
354 0 : gf_sc_texture_release(txh);
355 0 : if (txh->data) gf_free(txh->data);
356 0 : txh->data = NULL;
357 0 : txh->width = txh->height = txh->stride = 0;
358 : }
359 : return;
360 : }
361 2068 : invalidate_all = compositor->rebuild_offscreen_textures;
362 :
363 : /*rebuild stencil*/
364 2068 : if (!txh->tx_io
365 2036 : || (w != (s32) txh->width) || ( h != (s32) txh->height)
366 2031 : || (new_pixel_format != txh->pixelformat)
367 : ) {
368 :
369 : Bool needs_stencil = 1;
370 52 : if (txh->tx_io) {
371 : #ifdef GPAC_USE_TINYGL
372 : if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
373 : #endif
374 20 : gf_sc_texture_release(txh);
375 20 : if (txh->data)
376 13 : gf_free(txh->data);
377 20 : txh->data = NULL;
378 : }
379 :
380 : /*we don't use rect ext because of no support for texture transforms*/
381 : if ((1)
382 : #ifndef GPAC_DISABLE_3D
383 : || compositor->gl_caps.npot_texture
384 : #endif
385 : ) {
386 52 : st->txh.width = w;
387 52 : st->txh.height = h;
388 52 : st->sx = st->sy = FIX_ONE;
389 : } else {
390 : st->txh.width = 2;
391 : while (st->txh.width<(u32)w) st->txh.width*=2;
392 : st->txh.height = 2;
393 : while (st->txh.height<(u32)h) st->txh.height*=2;
394 :
395 : st->sx = INT2FIX(st->txh.width) / w;
396 : st->sy = INT2FIX(st->txh.height) / h;
397 : }
398 :
399 52 : gf_sc_texture_allocate(txh);
400 52 : txh->pixelformat = new_pixel_format;
401 52 : switch (new_pixel_format) {
402 41 : case GF_PIXEL_RGBA:
403 : case GF_PIXEL_ARGB:
404 41 : txh->stride = txh->width * 4;
405 41 : txh->transparent = 1;
406 41 : break;
407 0 : case GF_PIXEL_RGB_565:
408 0 : txh->stride = txh->width * 2;
409 0 : txh->transparent = 0;
410 0 : break;
411 0 : case GF_PIXEL_RGBDS:
412 0 : txh->stride = txh->width * 4;
413 0 : txh->transparent = 1;
414 0 : break;
415 11 : case GF_PIXEL_RGB:
416 11 : txh->stride = txh->width * 3;
417 11 : txh->transparent = 0;
418 11 : break;
419 : }
420 :
421 52 : st->visual->width = txh->width;
422 52 : st->visual->height = txh->height;
423 52 : st->use_fbo = GF_FALSE;
424 :
425 52 : stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
426 :
427 : #ifndef GPAC_DISABLE_3D
428 52 : if (st->visual->type_3d) {
429 : /*figure out what to do if main visual (eg video out) is not in OpenGL ...*/
430 9 : if (!compositor->visual->type_3d && !compositor->hybrid_opengl) {
431 : /*create an offscreen window for OpenGL rendering*/
432 0 : if (!compositor->fbo_id
433 0 : && ((compositor->offscreen_width < st->txh.width) || (compositor->offscreen_height < st->txh.height))
434 : ) {
435 :
436 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Offscreen OpenGL is not possible if no openGL context is created - use hybridGL mode for compositor\n"));
437 0 : st->unsupported = GF_TRUE;
438 : }
439 : } else {
440 : needs_stencil = 0;
441 : }
442 : }
443 : #endif
444 :
445 : if (needs_stencil) {
446 43 : txh->data = (char*)gf_malloc(sizeof(unsigned char) * txh->stride * txh->height);
447 43 : memset(txh->data, 0, sizeof(unsigned char) * txh->stride * txh->height);
448 :
449 : /*set stencil texture - we don't check error as an image could not be supported by the rasterizer
450 : but still supported by the blitter (case of RGBD/RGBDS)*/
451 43 : gf_evg_stencil_set_texture(stencil, txh->data, txh->width, txh->height, txh->stride, txh->pixelformat);
452 :
453 : #ifdef GPAC_USE_TINYGL
454 : if (st->visual->type_3d && !compositor->visual->type_3d) {
455 : st->tgl_ctx = ostgl_create_context(txh->width, txh->height, txh->transparent ? 32 : 24, &txh->data, 1);
456 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Creating TinyGL Offscreen context %p (%d %d - pf %s)\n", st->tgl_ctx, txh->width, txh->width, gf_4cc_to_str(txh->pixelformat)));
457 : }
458 : #endif
459 : }
460 : #if !defined(GPAC_USE_TINYGL) && !defined(GPAC_DISABLE_3D)
461 9 : else if (compositor->gl_caps.fbo) {
462 9 : if (gf_sc_texture_setup_fbo(&st->txh)==GF_OK)
463 9 : st->use_fbo = GF_TRUE;
464 : }
465 : #endif
466 :
467 : invalidate_all = 1;
468 52 : gf_sc_texture_set_stencil(txh, stencil);
469 : }
470 2068 : if (!txh->tx_io) return;
471 :
472 : #ifndef GPAC_DISABLE_3D
473 2068 : if (st->visual->camera.is_3D) {
474 : #ifdef GPAC_USE_TINYGL
475 : st->visual->type_3d = 2;
476 : #else
477 304 : if (compositor->visual->type_3d) {
478 152 : st->visual->type_3d = 2;
479 152 : } else if (compositor->hybrid_opengl || compositor->fbo_id) {
480 152 : st->visual->type_3d = 2;
481 0 : } else if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN)) {
482 0 : st->visual->type_3d = 0;
483 : } else {
484 0 : st->visual->type_3d = 2;
485 : }
486 : #endif
487 : }
488 : #endif
489 :
490 2068 : stencil = gf_sc_texture_get_stencil(txh);
491 2068 : if (!stencil) return;
492 :
493 : #ifdef GPAC_USE_TINYGL
494 : if (st->tgl_ctx)
495 : ostgl_make_current(st->tgl_ctx, 0);
496 : #elif !defined(GPAC_DISABLE_3D)
497 2068 : if (st->use_fbo) {
498 302 : gf_sc_texture_enable_fbo(&st->txh, GF_TRUE);
499 : }
500 : #endif
501 :
502 2068 : sensor_bck = st->tr_state->vrml_sensors;
503 : memset(st->tr_state, 0, sizeof(GF_TraverseState));
504 2068 : st->tr_state->vrml_sensors = sensor_bck;
505 2068 : st->tr_state->visual = st->visual;
506 2068 : st->tr_state->invalidate_all = invalidate_all;
507 :
508 2068 : st->tr_state->immediate_draw = st->visual->compositor->traverse_state->immediate_draw;
509 :
510 4136 : gf_mx2d_init(st->tr_state->transform);
511 2068 : gf_cmx_init(&st->tr_state->color_mat);
512 :
513 2068 : st->tr_state->backgrounds = st->visual->back_stack;
514 2068 : st->tr_state->viewpoints = st->visual->view_stack;
515 2068 : st->tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner));
516 2068 : st->tr_state->min_hsize = INT2FIX( MIN(txh->width, txh->height) ) / 2;
517 2068 : st->tr_state->vp_size.x = INT2FIX(txh->width);
518 2068 : st->tr_state->vp_size.y = INT2FIX(txh->height);
519 :
520 2068 : composite_do_bindable(st->txh.owner, st->tr_state, st->first);
521 2068 : st->first = 0;
522 :
523 2068 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Entering draw cycle\n"));
524 :
525 2068 : txh->needs_refresh = visual_draw_frame(st->visual, st->txh.owner, st->tr_state, 0);
526 2068 : txh->transparent = (st->visual->last_had_back==2) ? 0 : 1;
527 :
528 2068 : if (!compositor->edited_text && st->visual->has_text_edit)
529 0 : st->visual->has_text_edit = 0;
530 :
531 :
532 : #if 0
533 : /*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/
534 : if (gf_list_count(st->visual->view_stack)) {
535 : M_Viewport *vp = (M_Viewport *)gf_list_get(st->visual->view_stack, 0);
536 :
537 : if (vp->isBound) {
538 : SFVec2f size = vp->size;
539 : if (size.x >=0 && size.y>=0) {
540 : /*FIXME - we need tracking of VP changes*/
541 : txh->needs_refresh = 1;
542 : }
543 : }
544 : }
545 : #endif
546 :
547 2068 : if (txh->needs_refresh) {
548 : #ifndef GPAC_DISABLE_3D
549 :
550 : #ifndef GPAC_USE_TINYGL
551 1296 : if (st->use_fbo) {
552 302 : gf_sc_texture_enable_fbo(&st->txh, GF_FALSE);
553 : } else
554 : #endif
555 : //no FBO, for composite 3D, store current buffer to texture
556 994 : if (st->visual->camera.is_3D && (st->visual->compositor->visual->type_3d || st->visual->compositor->hybrid_opengl)) {
557 : #ifndef GPAC_USE_TINYGL
558 2 : gf_sc_copy_to_texture(&st->txh);
559 : #endif
560 : }
561 992 : else if (st->visual->camera.is_3D) {
562 0 : if (st->visual->compositor->visual->type_3d) {
563 : #ifndef GPAC_USE_TINYGL
564 0 : gf_sc_copy_to_texture(&st->txh);
565 : #else
566 : /*in TinyGL we only need to push associated bitmap to the texture*/
567 : gf_sc_texture_push_image(&st->txh, 0, 0);
568 : #endif
569 : } else {
570 : #ifndef GPAC_USE_TINYGL
571 0 : gf_sc_copy_to_stencil(&st->txh);
572 : #else
573 : if (txh->pixelformat==GF_PIXEL_RGBDS)
574 : gf_get_tinygl_depth(&st->txh);
575 : #endif
576 : }
577 : } else
578 : #endif
579 : {
580 992 : gf_sc_texture_set_stencil(txh, stencil);
581 : }
582 1296 : gf_sc_invalidate(st->txh.compositor, NULL);
583 : }
584 2068 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Leaving draw cycle\n"));
585 : }
586 :
587 :
588 1764 : GF_Err composite_get_video_access(GF_VisualManager *visual)
589 : {
590 : GF_EVGStencil *stencil;
591 : GF_Err e;
592 1764 : CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(visual->offscreen);
593 :
594 1764 : if (!st->txh.tx_io || !visual->raster_surface) return GF_BAD_PARAM;
595 1764 : stencil = gf_sc_texture_get_stencil(&st->txh);
596 1764 : if (!stencil) return GF_BAD_PARAM;
597 1764 : e = gf_evg_surface_attach_to_texture(visual->raster_surface, stencil);
598 1764 : if (!e) visual->is_attached = 1;
599 : return e;
600 : }
601 :
602 1764 : void composite_release_video_access(GF_VisualManager *visual)
603 : {
604 1764 : }
605 :
606 5899 : Bool composite_check_visual_attached(GF_VisualManager *visual)
607 : {
608 5899 : return visual->is_attached;
609 : }
610 :
611 30 : void compositor_init_compositetexture2d(GF_Compositor *compositor, GF_Node *node)
612 : {
613 : M_CompositeTexture2D *c2d = (M_CompositeTexture2D *)node;
614 : CompositeTextureStack *st;
615 30 : GF_SAFEALLOC(st, CompositeTextureStack);
616 :
617 30 : if (!st) {
618 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture stack\n"));
619 : return;
620 : }
621 :
622 30 : GF_SAFEALLOC(st->tr_state, GF_TraverseState);
623 30 : if (!st->tr_state) {
624 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture state\n"));
625 : return;
626 : }
627 30 : st->tr_state->vrml_sensors = gf_list_new();
628 :
629 30 : st->sensors = gf_list_new();
630 30 : st->previous_sensors = gf_list_new();
631 30 : gf_sc_texture_setup(&st->txh, compositor, node);
632 : /*remove texture from compositor and add it at the end, so that any sub-textures are handled before*/
633 30 : gf_list_del_item(compositor->textures, &st->txh);
634 30 : gf_list_add(compositor->textures, &st->txh);
635 :
636 30 : st->txh.update_texture_fcnt = composite_update;
637 :
638 30 : if ((c2d->repeatSandT==1) || (c2d->repeatSandT==3) ) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
639 30 : if (c2d->repeatSandT>1) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
640 :
641 : /*create composite visual*/
642 30 : st->visual = visual_new(compositor);
643 30 : st->visual->offscreen = node;
644 30 : st->visual->GetSurfaceAccess = composite_get_video_access;
645 30 : st->visual->ReleaseSurfaceAccess = composite_release_video_access;
646 30 : st->visual->DrawBitmap = composite2d_draw_bitmap;
647 30 : st->visual->CheckAttached = composite_check_visual_attached;
648 :
649 30 : st->visual->raster_surface = gf_evg_surface_new(1);
650 :
651 :
652 30 : st->first = 1;
653 30 : st->visual->compositor = compositor;
654 30 : gf_node_set_private(node, st);
655 30 : gf_node_set_callback_function(node, composite_traverse);
656 30 : gf_sc_visual_register(compositor, st->visual);
657 : }
658 :
659 :
660 : #ifndef GPAC_DISABLE_3D
661 2 : void compositor_init_compositetexture3d(GF_Compositor *compositor, GF_Node *node)
662 : {
663 : M_CompositeTexture3D *c3d = (M_CompositeTexture3D *)node;
664 : CompositeTextureStack *st;
665 :
666 2 : if (!gf_sc_check_gl_support(compositor)) {
667 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] Driver disabled, cannot render 3D composite textures\n"));
668 : return;
669 : }
670 :
671 2 : GF_SAFEALLOC(st, CompositeTextureStack);
672 2 : if (!st) {
673 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture stack\n"));
674 : return;
675 : }
676 2 : GF_SAFEALLOC(st->tr_state, GF_TraverseState);
677 2 : if (!st->tr_state) {
678 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture state\n"));
679 : return;
680 : }
681 :
682 2 : st->tr_state->vrml_sensors = gf_list_new();
683 :
684 2 : st->sensors = gf_list_new();
685 2 : st->previous_sensors = gf_list_new();
686 2 : gf_sc_texture_setup(&st->txh, compositor, node);
687 : /*remove texture from compositor and add it at the end, so that any sub-textures are handled before*/
688 2 : gf_list_del_item(compositor->textures, &st->txh);
689 2 : gf_list_add(compositor->textures, &st->txh);
690 :
691 2 : st->txh.update_texture_fcnt = composite_update;
692 :
693 2 : if (c3d->repeatS) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
694 2 : if (c3d->repeatT) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
695 :
696 : /*create composite visual*/
697 2 : st->visual = visual_new(compositor);
698 2 : st->visual->offscreen = node;
699 2 : st->visual->GetSurfaceAccess = composite_get_video_access;
700 2 : st->visual->ReleaseSurfaceAccess = composite_release_video_access;
701 2 : st->visual->CheckAttached = composite_check_visual_attached;
702 :
703 2 : st->visual->camera.is_3D = 1;
704 2 : st->first = 1;
705 2 : st->visual->compositor = compositor;
706 2 : gf_node_set_private(node, st);
707 2 : gf_node_set_callback_function(node, composite_traverse);
708 2 : gf_sc_visual_register(compositor, st->visual);
709 :
710 2 : camera_invalidate(&st->visual->camera);
711 : }
712 : #endif
713 :
714 3307 : GF_TextureHandler *compositor_get_composite_texture(GF_Node *node)
715 : {
716 3307 : CompositeTextureStack *st = (CompositeTextureStack*) gf_node_get_private(node);
717 3307 : return &st->txh;
718 : }
719 :
720 70 : Bool compositor_compositetexture_handle_event(GF_Compositor *compositor, GF_Node *composite_appear, GF_Event *ev, Bool is_flush)
721 : {
722 : GF_Ray ray;
723 : Fixed dist;
724 : Bool had_text_sel=0;
725 : GF_Matrix mx;
726 : GF_ChildNodeItem *children, *l;
727 : Bool res;
728 : SFVec3f txcoord, loc_pt, world_pt;
729 : GF_Matrix l2w_mx, w2l_mx;
730 : CompositeTextureStack *stack;
731 : GF_Node *appear, *prev_appear;
732 : GF_List *sensor_bck;
733 : M_Appearance *ap = (M_Appearance *)composite_appear;
734 : assert(ap && ap->texture);
735 :
736 70 : if (ev->type > GF_EVENT_MOUSEMOVE) return 0;
737 70 : stack = gf_node_get_private(ap->texture);
738 70 : if (!stack->txh.tx_io) return 0;
739 :
740 : children = NULL;
741 :
742 :
743 70 : if (!is_flush) {
744 68 : txcoord.x = compositor->hit_texcoords.x;
745 68 : txcoord.y = compositor->hit_texcoords.y;
746 68 : txcoord.z = 0;
747 68 : if (gf_sc_texture_get_transform(&stack->txh, ap->textureTransform, &mx, 1)) {
748 : /*tx coords are inverted when mapping, thus applying directly the matrix will give us the
749 : untransformed coords*/
750 50 : gf_mx_apply_vec(&mx, &txcoord);
751 50 : while (txcoord.x<0) txcoord.x += FIX_ONE;
752 177 : while (txcoord.x>FIX_ONE) txcoord.x -= FIX_ONE;
753 0 : while (txcoord.y<0) txcoord.y += FIX_ONE;
754 64 : while (txcoord.y>FIX_ONE) txcoord.y -= FIX_ONE;
755 : }
756 :
757 : /*convert to tx space*/
758 68 : ev->mouse.x = FIX2INT( (txcoord.x - FIX_ONE/2) * stack->visual->width + FIX_ONE/2);
759 68 : ev->mouse.y = FIX2INT( (txcoord.y - FIX_ONE/2) * stack->visual->height + FIX_ONE/2);
760 :
761 68 : sensor_bck = stack->tr_state->vrml_sensors;
762 : memset(stack->tr_state, 0, sizeof(GF_TraverseState));
763 68 : stack->tr_state->vrml_sensors = sensor_bck;
764 :
765 68 : stack->tr_state->visual = stack->visual;
766 68 : stack->tr_state->traversing_mode = TRAVERSE_PICK;
767 68 : stack->tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(ap->texture));
768 68 : stack->tr_state->vp_size.x = INT2FIX(stack->txh.width);
769 68 : stack->tr_state->vp_size.y = INT2FIX(stack->txh.height);
770 68 : stack->tr_state->color_mat.identity = 1;
771 :
772 136 : gf_mx2d_init(stack->tr_state->transform);
773 : #ifndef GPAC_DISABLE_3D
774 136 : gf_mx_init(stack->tr_state->model_matrix);
775 : #endif
776 : /*collect sensors but not anchors*/
777 68 : l = children = ((M_CompositeTexture2D*)ap->texture)->children;
778 350 : while (l) {
779 214 : GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
780 214 : if (hsens) gf_list_add(stack->tr_state->vrml_sensors, hsens);
781 214 : l = l->next;
782 : }
783 : }
784 :
785 70 : stack->temp_sensors = compositor->sensors;
786 70 : stack->temp_previous_sensors = compositor->previous_sensors;
787 70 : compositor->sensors = stack->sensors;
788 70 : compositor->previous_sensors = stack->previous_sensors;
789 :
790 70 : ray = compositor->hit_world_ray;
791 70 : dist = compositor->hit_square_dist;
792 70 : prev_appear = compositor->prev_hit_appear;
793 :
794 : /*protect against destrucion in case of self-destroy*/
795 70 : if (prev_appear) {
796 65 : gf_node_register(prev_appear, NULL);
797 : }
798 70 : compositor->prev_hit_appear = stack->prev_hit_appear;
799 70 : appear = compositor->hit_appear;
800 70 : compositor->hit_appear = NULL;
801 :
802 : /*also backup current hit state in case we hit a node in the texture but don't consume the event*/
803 70 : loc_pt = compositor->hit_local_point;
804 70 : world_pt = compositor->hit_world_point;
805 70 : gf_mx_copy(l2w_mx, compositor->hit_local_to_world);
806 70 : gf_mx_copy(w2l_mx, compositor->hit_world_to_local);
807 :
808 70 : if (compositor->text_selection) had_text_sel=1;
809 :
810 70 : if (is_flush) {
811 : res = 0;
812 2 : gf_list_reset(stack->sensors);
813 2 : gf_sc_exec_event_vrml(compositor, ev);
814 : } else {
815 68 : res = visual_execute_event(stack->visual, stack->tr_state, ev, children);
816 : }
817 :
818 70 : if (!had_text_sel && compositor->edited_text) {
819 0 : stack->visual->has_text_edit = 1;
820 70 : } else if (!compositor->text_selection) {
821 70 : stack->visual->has_text_edit = 0;
822 : }
823 :
824 70 : if (!res) {
825 13 : compositor->hit_local_point = loc_pt;
826 : gf_mx_copy(compositor->hit_local_to_world, l2w_mx);
827 : gf_mx_copy(compositor->hit_world_to_local, w2l_mx);
828 : }
829 :
830 70 : compositor->hit_world_point = world_pt;
831 70 : compositor->hit_world_ray = ray;
832 70 : compositor->hit_square_dist = dist;
833 :
834 70 : stack->sensors = compositor->sensors;
835 70 : stack->previous_sensors = compositor->previous_sensors;
836 70 : compositor->sensors = stack->temp_sensors;
837 70 : stack->temp_sensors = NULL;
838 70 : compositor->previous_sensors = stack->temp_previous_sensors;
839 70 : stack->temp_previous_sensors = NULL;
840 :
841 :
842 70 : if (!is_flush) {
843 : #ifndef GPAC_DISABLE_3D
844 68 : if (stack->tr_state->layer3d) compositor->traverse_state->layer3d = stack->tr_state->layer3d;
845 : #endif
846 : }
847 :
848 70 : stack->prev_hit_appear = compositor->prev_hit_appear;
849 :
850 : //finally unregister the node, this may destroy the stack !
851 70 : if (prev_appear) {
852 65 : if (prev_appear->sgprivate->num_instances>1) {
853 65 : compositor->prev_hit_appear = prev_appear;
854 65 : compositor->hit_appear = appear;
855 : } else {
856 0 : compositor->prev_hit_appear = NULL;
857 0 : compositor->hit_appear = NULL;
858 : }
859 65 : gf_node_unregister(prev_appear, NULL);
860 : } else {
861 5 : compositor->prev_hit_appear = prev_appear;
862 5 : compositor->hit_appear = appear;
863 : }
864 :
865 : return res;
866 : }
867 :
868 170 : void compositor_compositetexture_sensor_delete(GF_Node *composite_appear, GF_SensorHandler *hdl)
869 : {
870 170 : CompositeTextureStack *stack = gf_node_get_private(composite_appear);
871 170 : gf_list_del_item(stack->previous_sensors, hdl);
872 170 : gf_list_del_item(stack->sensors, hdl);
873 170 : if (stack->temp_sensors)
874 0 : gf_list_del_item(stack->temp_sensors, hdl);
875 170 : if (stack->temp_previous_sensors)
876 0 : gf_list_del_item(stack->temp_previous_sensors, hdl);
877 170 : }
878 :
879 :
880 485 : void compositor_adjust_scale(GF_Node *node, Fixed *sx, Fixed *sy)
881 : {
882 485 : switch (gf_node_get_tag(node)) {
883 7 : case TAG_MPEG4_CompositeTexture2D:
884 : case TAG_MPEG4_CompositeTexture3D:
885 : {
886 7 : CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(node);
887 7 : (*sx) = gf_divfix(*sx, st->sx);
888 7 : (*sy) = gf_divfix(*sy, st->sy);
889 7 : break;
890 : }
891 : default:
892 : return;
893 : }
894 : }
895 :
896 2787 : Bool compositor_is_composite_texture(GF_Node *appear)
897 : {
898 : M_Appearance *ap = NULL;
899 : u32 tag;
900 2787 : if (!appear) return 0;
901 :
902 2785 : tag = gf_node_get_tag(appear);
903 2785 : if (tag==TAG_MPEG4_Appearance) ap = (M_Appearance *)appear;
904 : #ifndef GPAC_DISABLE_X3D
905 6 : else if (tag==TAG_X3D_Appearance) ap = (M_Appearance *)appear;
906 : #endif
907 : if (!ap) return 0;
908 2785 : if (!ap->texture) return 0;
909 897 : switch (gf_node_get_tag(((M_Appearance *)appear)->texture)) {
910 : case TAG_MPEG4_CompositeTexture2D:
911 : case TAG_MPEG4_CompositeTexture3D:
912 : return 1;
913 : }
914 829 : return 0;
915 : }
916 :
917 : #endif /*GPAC_DISABLE_VRML*/
|