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 
composite2d_draw_bitmap(GF_VisualManager * visual,GF_TraverseState * tr_state,struct _drawable_context * ctx)60 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 	if (visual->compositor->disable_composite_blit) return 0;
69 
70 	if (!ctx->aspect.fill_texture) return 1;
71 	if (ctx->transform.m[0]<0) return 0;
72 	if (ctx->transform.m[4]<0) {
73 		if (!(ctx->flags & CTX_FLIPED_COORDS)) return 0;
74 	} else {
75 		if (ctx->flags & CTX_FLIPED_COORDS) return 0;
76 	}
77 	if (ctx->transform.m[1] || ctx->transform.m[3]) return 0;
78 #ifndef GPAC_DISABLE_VRML
79 	if ((ctx->flags & CTX_HAS_APPEARANCE) && ctx->appear && ((M_Appearance*)ctx->appear)->textureTransform)
80 		return 0;
81 #endif
82 
83 	alpha = GF_COL_A(ctx->aspect.fill_color);
84 	/*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/
85 	if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
86 	if (!alpha) return 1;
87 
88 	st = (CompositeTextureStack *) gf_node_get_private(visual->offscreen);
89 
90 	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 	video_src.height = ctx->aspect.fill_texture->height;
94 	video_src.width = ctx->aspect.fill_texture->width;
95 	video_src.pitch_x = 0;
96 	video_src.pitch_y = ctx->aspect.fill_texture->stride;
97 	video_src.pixel_format = ctx->aspect.fill_texture->pixelformat;
98 #ifdef GF_SR_USE_DEPTH
99 	if (ctx->aspect.fill_texture->pixelformat==GF_PIXEL_YUVD) video_src.pixel_format = GF_PIXEL_YUV;
100 #endif
101 	video_src.video_buffer = ctx->aspect.fill_texture->data;
102 
103 	memset(&offscreen_dst, 0, sizeof(GF_VideoSurface));
104 	offscreen_dst.width = st->txh.width;
105 	offscreen_dst.height = st->txh.height;
106 	offscreen_dst.pitch_y = st->txh.stride;
107 	offscreen_dst.pixel_format = st->txh.pixelformat;
108 	offscreen_dst.video_buffer = st->txh.data;
109 
110 	gf_stretch_bits(&offscreen_dst, &video_src, &dst_wnd, &src_wnd, alpha, 0, tr_state->col_key, ctx->col_mat);
111 	return 1;
112 }
113 
composite_traverse(GF_Node * node,void * rs,Bool is_destroy)114 static void composite_traverse(GF_Node *node, void *rs, Bool is_destroy)
115 {
116 	if (is_destroy) {
117 		u32 i=0;
118 		GF_VisualManager *a_visual;
119 		CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(node);
120 		/*unregister visual*/
121 		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 		st->visual->compositor->hit_appear = NULL;
130 		st->visual->compositor->prev_hit_appear = NULL;
131 
132 		while ( (a_visual = gf_list_enum(st->visual->compositor->visuals, &i))) {
133 			if (a_visual->offscreen) {
134 				CompositeTextureStack *a_st = (CompositeTextureStack *) gf_node_get_private(a_visual->offscreen);
135 				a_st->prev_hit_appear = NULL;
136 			}
137 		}
138 
139 		visual_del(st->visual);
140 		if (st->txh.data) gf_free(st->txh.data);
141 		/*destroy texture*/
142 		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 		gf_list_del(st->sensors);
148 		gf_list_del(st->previous_sensors);
149 
150 		gf_list_del(st->tr_state->vrml_sensors);
151 		gf_free(st->tr_state);
152 
153 		gf_free(st);
154 	} else {
155 		gf_node_traverse_children(node, rs);
156 	}
157 }
158 
composite_do_bindable(GF_Node * n,GF_TraverseState * tr_state,Bool force_check)159 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 	switch (gf_node_get_tag(n)) {
164 #ifndef GPAC_DISABLE_3D
165 	case TAG_MPEG4_CompositeTexture3D:
166 	{
167 		M_CompositeTexture3D*c3d = (M_CompositeTexture3D*)n;
168 		if (force_check || gf_node_dirty_get(c3d->background)) {
169 			gf_node_traverse(c3d->background, tr_state);
170 			ret = 1;
171 		}
172 		btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
173 		if (btop != c3d->background) {
174 			gf_node_unregister(c3d->background, n);
175 			gf_node_register(btop, n);
176 			c3d->background = btop;
177 			gf_node_event_out(n, 5/*"background"*/);
178 			ret = 1;
179 		}
180 		if (force_check || gf_node_dirty_get(c3d->viewpoint)) {
181 			gf_node_traverse(c3d->viewpoint, tr_state);
182 			ret = 1;
183 		}
184 		btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
185 		if (btop != c3d->viewpoint) {
186 			gf_node_unregister(c3d->viewpoint, n);
187 			gf_node_register(btop, n);
188 			c3d->viewpoint = btop;
189 			gf_node_event_out(n, 8/*"viewpoint"*/);
190 			ret = 1;
191 		}
192 
193 		if (force_check || gf_node_dirty_get(c3d->fog)) {
194 			gf_node_traverse(c3d->fog, tr_state);
195 			ret = 1;
196 		}
197 		btop = (GF_Node*)gf_list_get(tr_state->fogs, 0);
198 		if (btop != c3d->fog) {
199 			gf_node_unregister(c3d->fog, n);
200 			gf_node_register(btop, n);
201 			c3d->fog = btop;
202 			gf_node_event_out(n, 6/*"fog"*/);
203 			ret = 1;
204 		}
205 
206 		if (force_check || gf_node_dirty_get(c3d->navigationInfo)) {
207 			gf_node_traverse(c3d->navigationInfo, tr_state);
208 			ret = 1;
209 		}
210 		btop = (GF_Node*)gf_list_get(tr_state->navigations, 0);
211 		if (btop != c3d->navigationInfo) {
212 			gf_node_unregister(c3d->navigationInfo, n);
213 			gf_node_register(btop, n);
214 			c3d->navigationInfo = btop;
215 			gf_node_event_out(n, 7/*"navigationInfo"*/);
216 			ret = 1;
217 		}
218 		return ret;
219 	}
220 #endif
221 	case TAG_MPEG4_CompositeTexture2D:
222 	{
223 		M_CompositeTexture2D *c2d = (M_CompositeTexture2D*)n;
224 		if (force_check || gf_node_dirty_get(c2d->background)) {
225 			gf_node_traverse(c2d->background, tr_state);
226 			ret = 1;
227 		}
228 		btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
229 		if (btop != c2d->background) {
230 			gf_node_unregister(c2d->background, n);
231 			gf_node_register(btop, n);
232 			c2d->background = btop;
233 			gf_node_event_out(n, 5/*"background"*/);
234 			ret = 1;
235 		}
236 
237 		if (force_check || gf_node_dirty_get(c2d->viewport)) {
238 			gf_node_traverse(c2d->viewport, tr_state);
239 			ret = 1;
240 		}
241 		btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
242 		if (btop != c2d->viewport) {
243 			gf_node_unregister(c2d->viewport, n);
244 			gf_node_register(btop, n);
245 			c2d->viewport = btop;
246 			gf_node_event_out(n, 6/*"viewport"*/);
247 			ret = 1;
248 		}
249 
250 		return ret;
251 	}
252 	}
253 	return 0;
254 }
255 
composite_update(GF_TextureHandler * txh)256 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 	GF_Compositor *compositor = (GF_Compositor *)txh->compositor;
267 	CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(txh->owner);
268 
269 	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 	if (!compositor->rebuild_offscreen_textures && (!compositor->text_edit_changed || !st->visual->has_text_edit ) && !gf_node_dirty_get(txh->owner)) {
278 		txh->needs_refresh = 0;
279 		return;
280 	}
281 	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 	back = gf_list_get(st->visual->back_stack, 0);
290 	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 	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 	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 	if (st->visual->type_3d>1) {
313 		w = ((M_CompositeTexture3D*)txh->owner)->pixelWidth;
314 		h = ((M_CompositeTexture3D*)txh->owner)->pixelHeight;
315 	} else
316 #endif
317 	{
318 		w = ((M_CompositeTexture2D*)txh->owner)->pixelWidth;
319 		h = ((M_CompositeTexture2D*)txh->owner)->pixelHeight;
320 	}
321 
322 	/*internal GPAC hacks for testing color spaces*/
323 	if (w<-1) {
324 		w = -w;
325 		if (h<0) {
326 			h = -h;
327 			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 			if (new_pixel_format==GF_PIXEL_RGB) {
334 				new_pixel_format=GF_PIXEL_RGBX;
335 			}
336 		}
337 	}
338 	else if (h<-1) {
339 		h = -h;
340 		if (new_pixel_format==GF_PIXEL_RGB) {
341 			new_pixel_format=GF_PIXEL_RGBX;
342 		}
343 	}
344 
345 	if (w<0) w = 0;
346 	if (h<0) h = 0;
347 
348 
349 	if (!w || !h) {
350 		if (txh->tx_io) {
351 #ifdef GPAC_USE_TINYGL
352 			if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
353 #endif
354 			gf_sc_texture_release(txh);
355 			if (txh->data) gf_free(txh->data);
356 			txh->data = NULL;
357 			txh->width = txh->height = txh->stride = 0;
358 		}
359 		return;
360 	}
361 	invalidate_all = compositor->rebuild_offscreen_textures;
362 
363 	/*rebuild stencil*/
364 	if (!txh->tx_io
365 	        || (w != (s32) txh->width) || ( h != (s32) txh->height)
366 	        || (new_pixel_format != txh->pixelformat)
367 	   ) {
368 
369 		Bool needs_stencil = 1;
370 		if (txh->tx_io) {
371 #ifdef GPAC_USE_TINYGL
372 			if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
373 #endif
374 			gf_sc_texture_release(txh);
375 			if (txh->data)
376 				gf_free(txh->data);
377 			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 			st->txh.width = w;
387 			st->txh.height = h;
388 			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 		gf_sc_texture_allocate(txh);
400 		txh->pixelformat = new_pixel_format;
401 		switch (new_pixel_format) {
402 		case GF_PIXEL_RGBA:
403 		case GF_PIXEL_ARGB:
404 			txh->stride = txh->width * 4;
405 			txh->transparent = 1;
406 			break;
407 		case GF_PIXEL_RGB_565:
408 			txh->stride = txh->width * 2;
409 			txh->transparent = 0;
410 			break;
411 		case GF_PIXEL_RGBDS:
412 			txh->stride = txh->width * 4;
413 			txh->transparent = 1;
414 			break;
415 		case GF_PIXEL_RGB:
416 			txh->stride = txh->width * 3;
417 			txh->transparent = 0;
418 			break;
419 		}
420 
421 		st->visual->width = txh->width;
422 		st->visual->height = txh->height;
423 		st->use_fbo = GF_FALSE;
424 
425 		stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
426 
427 #ifndef GPAC_DISABLE_3D
428 		if (st->visual->type_3d) {
429 			/*figure out what to do if main visual (eg video out) is not in OpenGL ...*/
430 			if (!compositor->visual->type_3d && !compositor->hybrid_opengl) {
431 				/*create an offscreen window for OpenGL rendering*/
432 				if (!compositor->fbo_id
433 					&& ((compositor->offscreen_width < st->txh.width) || (compositor->offscreen_height < st->txh.height))
434 				) {
435 
436 					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 					st->unsupported = GF_TRUE;
438 				}
439 			} else {
440 				needs_stencil = 0;
441 			}
442 		}
443 #endif
444 
445 		if (needs_stencil) {
446 			txh->data = (char*)gf_malloc(sizeof(unsigned char) * txh->stride * txh->height);
447 			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 			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 		else if (compositor->gl_caps.fbo) {
462 			if (gf_sc_texture_setup_fbo(&st->txh)==GF_OK)
463 				st->use_fbo = GF_TRUE;
464 		}
465 #endif
466 
467 		invalidate_all = 1;
468 		gf_sc_texture_set_stencil(txh, stencil);
469 	}
470 	if (!txh->tx_io) return;
471 
472 #ifndef GPAC_DISABLE_3D
473 	if (st->visual->camera.is_3D) {
474 #ifdef GPAC_USE_TINYGL
475 		st->visual->type_3d = 2;
476 #else
477 		if (compositor->visual->type_3d) {
478 			st->visual->type_3d = 2;
479 		} else if (compositor->hybrid_opengl || compositor->fbo_id) {
480 			st->visual->type_3d = 2;
481 		} else if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN)) {
482 			st->visual->type_3d = 0;
483 		} else {
484 			st->visual->type_3d = 2;
485 		}
486 #endif
487 	}
488 #endif
489 
490 	stencil = gf_sc_texture_get_stencil(txh);
491 	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 	if (st->use_fbo) {
498 		gf_sc_texture_enable_fbo(&st->txh, GF_TRUE);
499 	}
500 #endif
501 
502 	sensor_bck = st->tr_state->vrml_sensors;
503 	memset(st->tr_state, 0, sizeof(GF_TraverseState));
504 	st->tr_state->vrml_sensors = sensor_bck;
505 	st->tr_state->visual = st->visual;
506 	st->tr_state->invalidate_all = invalidate_all;
507 
508 	st->tr_state->immediate_draw = st->visual->compositor->traverse_state->immediate_draw;
509 
510 	gf_mx2d_init(st->tr_state->transform);
511 	gf_cmx_init(&st->tr_state->color_mat);
512 
513 	st->tr_state->backgrounds = st->visual->back_stack;
514 	st->tr_state->viewpoints = st->visual->view_stack;
515 	st->tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner));
516 	st->tr_state->min_hsize = INT2FIX( MIN(txh->width, txh->height) ) / 2;
517 	st->tr_state->vp_size.x = INT2FIX(txh->width);
518 	st->tr_state->vp_size.y = INT2FIX(txh->height);
519 
520 	composite_do_bindable(st->txh.owner, st->tr_state, st->first);
521 	st->first = 0;
522 
523 	GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Entering draw cycle\n"));
524 
525 	txh->needs_refresh = visual_draw_frame(st->visual, st->txh.owner, st->tr_state, 0);
526 	txh->transparent = (st->visual->last_had_back==2) ? 0 : 1;
527 
528 	if (!compositor->edited_text && st->visual->has_text_edit)
529 		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 	if (txh->needs_refresh) {
548 #ifndef GPAC_DISABLE_3D
549 
550 #ifndef GPAC_USE_TINYGL
551 		if (st->use_fbo) {
552 			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 		if (st->visual->camera.is_3D && (st->visual->compositor->visual->type_3d || st->visual->compositor->hybrid_opengl)) {
557 #ifndef GPAC_USE_TINYGL
558 			gf_sc_copy_to_texture(&st->txh);
559 #endif
560 		}
561 		else if (st->visual->camera.is_3D) {
562 			if (st->visual->compositor->visual->type_3d) {
563 #ifndef GPAC_USE_TINYGL
564 				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 				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 			gf_sc_texture_set_stencil(txh, stencil);
581 		}
582 		gf_sc_invalidate(st->txh.compositor, NULL);
583 	}
584 	GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Leaving draw cycle\n"));
585 }
586 
587 
composite_get_video_access(GF_VisualManager * visual)588 GF_Err composite_get_video_access(GF_VisualManager *visual)
589 {
590 	GF_EVGStencil *stencil;
591 	GF_Err e;
592 	CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(visual->offscreen);
593 
594 	if (!st->txh.tx_io || !visual->raster_surface) return GF_BAD_PARAM;
595 	stencil = gf_sc_texture_get_stencil(&st->txh);
596 	if (!stencil) return GF_BAD_PARAM;
597 	e = gf_evg_surface_attach_to_texture(visual->raster_surface, stencil);
598 	if (!e) visual->is_attached = 1;
599 	return e;
600 }
601 
composite_release_video_access(GF_VisualManager * visual)602 void composite_release_video_access(GF_VisualManager *visual)
603 {
604 }
605 
composite_check_visual_attached(GF_VisualManager * visual)606 Bool composite_check_visual_attached(GF_VisualManager *visual)
607 {
608 	return visual->is_attached;
609 }
610 
compositor_init_compositetexture2d(GF_Compositor * compositor,GF_Node * node)611 void compositor_init_compositetexture2d(GF_Compositor *compositor, GF_Node *node)
612 {
613 	M_CompositeTexture2D *c2d = (M_CompositeTexture2D *)node;
614 	CompositeTextureStack *st;
615 	GF_SAFEALLOC(st, CompositeTextureStack);
616 
617 	if (!st) {
618 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture stack\n"));
619 		return;
620 	}
621 
622 	GF_SAFEALLOC(st->tr_state, GF_TraverseState);
623 	if (!st->tr_state) {
624 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture state\n"));
625 		return;
626 	}
627 	st->tr_state->vrml_sensors = gf_list_new();
628 
629 	st->sensors = gf_list_new();
630 	st->previous_sensors = gf_list_new();
631 	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 	gf_list_del_item(compositor->textures, &st->txh);
634 	gf_list_add(compositor->textures, &st->txh);
635 
636 	st->txh.update_texture_fcnt = composite_update;
637 
638 	if ((c2d->repeatSandT==1) || (c2d->repeatSandT==3) ) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
639 	if (c2d->repeatSandT>1) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
640 
641 	/*create composite visual*/
642 	st->visual = visual_new(compositor);
643 	st->visual->offscreen = node;
644 	st->visual->GetSurfaceAccess = composite_get_video_access;
645 	st->visual->ReleaseSurfaceAccess = composite_release_video_access;
646 	st->visual->DrawBitmap = composite2d_draw_bitmap;
647 	st->visual->CheckAttached = composite_check_visual_attached;
648 
649 	st->visual->raster_surface = gf_evg_surface_new(1);
650 
651 
652 	st->first = 1;
653 	st->visual->compositor = compositor;
654 	gf_node_set_private(node, st);
655 	gf_node_set_callback_function(node, composite_traverse);
656 	gf_sc_visual_register(compositor, st->visual);
657 }
658 
659 
660 #ifndef GPAC_DISABLE_3D
compositor_init_compositetexture3d(GF_Compositor * compositor,GF_Node * node)661 void compositor_init_compositetexture3d(GF_Compositor *compositor, GF_Node *node)
662 {
663 	M_CompositeTexture3D *c3d = (M_CompositeTexture3D *)node;
664 	CompositeTextureStack *st;
665 
666 	if (!gf_sc_check_gl_support(compositor)) {
667 		GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] Driver disabled, cannot render 3D composite textures\n"));
668 		return;
669 	}
670 
671 	GF_SAFEALLOC(st, CompositeTextureStack);
672 	if (!st) {
673 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture stack\n"));
674 		return;
675 	}
676 	GF_SAFEALLOC(st->tr_state, GF_TraverseState);
677 	if (!st->tr_state) {
678 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture state\n"));
679 		return;
680 	}
681 
682 	st->tr_state->vrml_sensors = gf_list_new();
683 
684 	st->sensors = gf_list_new();
685 	st->previous_sensors = gf_list_new();
686 	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 	gf_list_del_item(compositor->textures, &st->txh);
689 	gf_list_add(compositor->textures, &st->txh);
690 
691 	st->txh.update_texture_fcnt = composite_update;
692 
693 	if (c3d->repeatS) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
694 	if (c3d->repeatT) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
695 
696 	/*create composite visual*/
697 	st->visual = visual_new(compositor);
698 	st->visual->offscreen = node;
699 	st->visual->GetSurfaceAccess = composite_get_video_access;
700 	st->visual->ReleaseSurfaceAccess = composite_release_video_access;
701 	st->visual->CheckAttached = composite_check_visual_attached;
702 
703 	st->visual->camera.is_3D = 1;
704 	st->first = 1;
705 	st->visual->compositor = compositor;
706 	gf_node_set_private(node, st);
707 	gf_node_set_callback_function(node, composite_traverse);
708 	gf_sc_visual_register(compositor, st->visual);
709 
710 	camera_invalidate(&st->visual->camera);
711 }
712 #endif
713 
compositor_get_composite_texture(GF_Node * node)714 GF_TextureHandler *compositor_get_composite_texture(GF_Node *node)
715 {
716 	CompositeTextureStack *st = (CompositeTextureStack*) gf_node_get_private(node);
717 	return &st->txh;
718 }
719 
compositor_compositetexture_handle_event(GF_Compositor * compositor,GF_Node * composite_appear,GF_Event * ev,Bool is_flush)720 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 	if (ev->type > GF_EVENT_MOUSEMOVE) return 0;
737 	stack = gf_node_get_private(ap->texture);
738 	if (!stack->txh.tx_io) return 0;
739 
740 	children = NULL;
741 
742 
743 	if (!is_flush) {
744 		txcoord.x = compositor->hit_texcoords.x;
745 		txcoord.y = compositor->hit_texcoords.y;
746 		txcoord.z = 0;
747 		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 			gf_mx_apply_vec(&mx, &txcoord);
751 			while (txcoord.x<0) txcoord.x += FIX_ONE;
752 			while (txcoord.x>FIX_ONE) txcoord.x -= FIX_ONE;
753 			while (txcoord.y<0) txcoord.y += FIX_ONE;
754 			while (txcoord.y>FIX_ONE) txcoord.y -= FIX_ONE;
755 		}
756 
757 		/*convert to tx space*/
758 		ev->mouse.x = FIX2INT( (txcoord.x - FIX_ONE/2) * stack->visual->width + FIX_ONE/2);
759 		ev->mouse.y = FIX2INT( (txcoord.y - FIX_ONE/2) * stack->visual->height + FIX_ONE/2);
760 
761 		sensor_bck = stack->tr_state->vrml_sensors;
762 		memset(stack->tr_state, 0, sizeof(GF_TraverseState));
763 		stack->tr_state->vrml_sensors = sensor_bck;
764 
765 		stack->tr_state->visual = stack->visual;
766 		stack->tr_state->traversing_mode = TRAVERSE_PICK;
767 		stack->tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(ap->texture));
768 		stack->tr_state->vp_size.x = INT2FIX(stack->txh.width);
769 		stack->tr_state->vp_size.y = INT2FIX(stack->txh.height);
770 		stack->tr_state->color_mat.identity = 1;
771 
772 		gf_mx2d_init(stack->tr_state->transform);
773 #ifndef GPAC_DISABLE_3D
774 		gf_mx_init(stack->tr_state->model_matrix);
775 #endif
776 		/*collect sensors but not anchors*/
777 		l = children = ((M_CompositeTexture2D*)ap->texture)->children;
778 		while (l) {
779 			GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
780 			if (hsens) gf_list_add(stack->tr_state->vrml_sensors, hsens);
781 			l = l->next;
782 		}
783 	}
784 
785 	stack->temp_sensors = compositor->sensors;
786 	stack->temp_previous_sensors = compositor->previous_sensors;
787 	compositor->sensors = stack->sensors;
788 	compositor->previous_sensors = stack->previous_sensors;
789 
790 	ray = compositor->hit_world_ray;
791 	dist = compositor->hit_square_dist;
792 	prev_appear = compositor->prev_hit_appear;
793 
794 	/*protect against destrucion in case of self-destroy*/
795 	if (prev_appear) {
796 		gf_node_register(prev_appear, NULL);
797 	}
798 	compositor->prev_hit_appear = stack->prev_hit_appear;
799 	appear = compositor->hit_appear;
800 	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 	loc_pt = compositor->hit_local_point;
804 	world_pt = compositor->hit_world_point;
805 	gf_mx_copy(l2w_mx, compositor->hit_local_to_world);
806 	gf_mx_copy(w2l_mx, compositor->hit_world_to_local);
807 
808 	if (compositor->text_selection) had_text_sel=1;
809 
810 	if (is_flush) {
811 		res = 0;
812 		gf_list_reset(stack->sensors);
813 		gf_sc_exec_event_vrml(compositor, ev);
814 	} else {
815 		res = visual_execute_event(stack->visual, stack->tr_state, ev, children);
816 	}
817 
818 	if (!had_text_sel && compositor->edited_text) {
819 		stack->visual->has_text_edit = 1;
820 	} else if (!compositor->text_selection) {
821 		stack->visual->has_text_edit = 0;
822 	}
823 
824 	if (!res) {
825 		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 	compositor->hit_world_point = world_pt;
831 	compositor->hit_world_ray = ray;
832 	compositor->hit_square_dist = dist;
833 
834 	stack->sensors = compositor->sensors;
835 	stack->previous_sensors = compositor->previous_sensors;
836 	compositor->sensors = stack->temp_sensors;
837 	stack->temp_sensors = NULL;
838 	compositor->previous_sensors = stack->temp_previous_sensors;
839 	stack->temp_previous_sensors = NULL;
840 
841 
842 	if (!is_flush) {
843 #ifndef GPAC_DISABLE_3D
844 		if (stack->tr_state->layer3d) compositor->traverse_state->layer3d = stack->tr_state->layer3d;
845 #endif
846 	}
847 
848 	stack->prev_hit_appear = compositor->prev_hit_appear;
849 
850 	//finally unregister the node, this may destroy the stack !
851 	if (prev_appear) {
852 		if (prev_appear->sgprivate->num_instances>1) {
853 			compositor->prev_hit_appear = prev_appear;
854 			compositor->hit_appear = appear;
855 		} else {
856 			compositor->prev_hit_appear = NULL;
857 			compositor->hit_appear = NULL;
858 		}
859 		gf_node_unregister(prev_appear, NULL);
860 	} else {
861 		compositor->prev_hit_appear = prev_appear;
862 		compositor->hit_appear = appear;
863 	}
864 
865 	return res;
866 }
867 
compositor_compositetexture_sensor_delete(GF_Node * composite_appear,GF_SensorHandler * hdl)868 void compositor_compositetexture_sensor_delete(GF_Node *composite_appear, GF_SensorHandler *hdl)
869 {
870 	CompositeTextureStack *stack = gf_node_get_private(composite_appear);
871 	gf_list_del_item(stack->previous_sensors, hdl);
872 	gf_list_del_item(stack->sensors, hdl);
873 	if (stack->temp_sensors)
874 		gf_list_del_item(stack->temp_sensors, hdl);
875 	if (stack->temp_previous_sensors)
876 		gf_list_del_item(stack->temp_previous_sensors, hdl);
877 }
878 
879 
compositor_adjust_scale(GF_Node * node,Fixed * sx,Fixed * sy)880 void compositor_adjust_scale(GF_Node *node, Fixed *sx, Fixed *sy)
881 {
882 	switch (gf_node_get_tag(node)) {
883 	case TAG_MPEG4_CompositeTexture2D:
884 	case TAG_MPEG4_CompositeTexture3D:
885 	{
886 		CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(node);
887 		(*sx) = gf_divfix(*sx, st->sx);
888 		(*sy) = gf_divfix(*sy, st->sy);
889 		break;
890 	}
891 	default:
892 		return;
893 	}
894 }
895 
compositor_is_composite_texture(GF_Node * appear)896 Bool compositor_is_composite_texture(GF_Node *appear)
897 {
898 	M_Appearance *ap = NULL;
899 	u32 tag;
900 	if (!appear) return 0;
901 
902 	tag = gf_node_get_tag(appear);
903 	if (tag==TAG_MPEG4_Appearance) ap = (M_Appearance *)appear;
904 #ifndef GPAC_DISABLE_X3D
905 	else if (tag==TAG_X3D_Appearance) ap = (M_Appearance *)appear;
906 #endif
907 	if (!ap) return 0;
908 	if (!ap->texture) return 0;
909 	switch (gf_node_get_tag(((M_Appearance *)appear)->texture)) {
910 	case TAG_MPEG4_CompositeTexture2D:
911 	case TAG_MPEG4_CompositeTexture3D:
912 		return 1;
913 	}
914 	return 0;
915 }
916 
917 #endif /*GPAC_DISABLE_VRML*/
918