1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2012
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / Scene Compositor sub-project
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 
27 
28 #include "nodes_stacks.h"
29 
30 #ifndef GPAC_DISABLE_VRML
31 
32 #ifndef GPAC_DISABLE_3D
33 
34 #include "texturing.h"
35 #include "visual_manager.h"
36 
37 /*for background textures - the offset is to prevent lines on cube map edges*/
38 #define PLANE_HSIZE		FLT2FIX(0.5025f)
39 #define PLANE_HSIZE_LOW		FLT2FIX(0.5f)
40 
41 
back_use_texture(MFURL * url)42 static Bool back_use_texture(MFURL *url)
43 {
44 	if (!url->count) return 0;
45 	if (url->vals[0].OD_ID > 0) return 1;
46 	if (url->vals[0].url && strlen(url->vals[0].url)) return 1;
47 	return 0;
48 }
49 
UpdateBackgroundTexture(GF_TextureHandler * txh)50 static void UpdateBackgroundTexture(GF_TextureHandler *txh)
51 {
52 	gf_sc_texture_update_frame(txh, 0);
53 	/*restart texture if needed (movie background controled by MediaControl)*/
54 	if (txh->stream_finished && gf_mo_get_loop(txh->stream, 0)) gf_sc_texture_restart(txh);
55 }
56 
57 
back_gf_sc_texture_enabled(MFURL * url,GF_TextureHandler * txh)58 static Bool back_gf_sc_texture_enabled(MFURL *url, GF_TextureHandler *txh)
59 {
60 	Bool use_texture = back_use_texture(url);
61 	if (use_texture) {
62 		/*texture not ready*/
63 		if (!txh->tx_io) {
64 			use_texture = 0;
65 			gf_sc_invalidate(txh->compositor, NULL);
66 		}
67 		gf_sc_texture_set_blend_mode(txh, gf_sc_texture_is_transparent(txh) ? TX_REPLACE : TX_DECAL);
68 	}
69 	return use_texture;
70 }
71 
back_check_gf_sc_texture_change(GF_TextureHandler * txh,MFURL * url)72 static void back_check_gf_sc_texture_change(GF_TextureHandler *txh, MFURL *url)
73 {
74 	/*if open and changed, stop and play*/
75 	if (txh->is_open) {
76 		if (! gf_sc_texture_check_url_change(txh, url)) return;
77 		gf_sc_texture_stop(txh);
78 		gf_sc_texture_play(txh, url);
79 		return;
80 	}
81 	/*if not open and changed play*/
82 	if (url->count) gf_sc_texture_play(txh, url);
83 }
84 
DestroyBackground(GF_Node * node)85 static void DestroyBackground(GF_Node *node)
86 {
87 	BackgroundStack *ptr = (BackgroundStack *) gf_node_get_private(node);
88 	PreDestroyBindable(node, ptr->reg_stacks);
89 	gf_list_del(ptr->reg_stacks);
90 
91 	if (ptr->sky_mesh) mesh_free(ptr->sky_mesh);
92 	if (ptr->ground_mesh) mesh_free(ptr->ground_mesh);
93 
94 	gf_sg_vrml_mf_reset(&ptr->ground_ang, GF_SG_VRML_MFFLOAT);
95 	gf_sg_vrml_mf_reset(&ptr->sky_ang, GF_SG_VRML_MFFLOAT);
96 	gf_sg_vrml_mf_reset(&ptr->ground_col, GF_SG_VRML_MFCOLOR);
97 	gf_sg_vrml_mf_reset(&ptr->sky_col, GF_SG_VRML_MFCOLOR);
98 
99 	mesh_free(ptr->front_mesh);
100 	mesh_free(ptr->back_mesh);
101 	mesh_free(ptr->top_mesh);
102 	mesh_free(ptr->bottom_mesh);
103 	mesh_free(ptr->left_mesh);
104 	mesh_free(ptr->right_mesh);
105 
106 
107 	gf_sc_texture_destroy(&ptr->txh_front);
108 	gf_sc_texture_destroy(&ptr->txh_back);
109 	gf_sc_texture_destroy(&ptr->txh_top);
110 	gf_sc_texture_destroy(&ptr->txh_bottom);
111 	gf_sc_texture_destroy(&ptr->txh_left);
112 	gf_sc_texture_destroy(&ptr->txh_right);
113 
114 	gf_free(ptr);
115 }
116 
117 #define COL_TO_RGBA(res, col) { res.red = col.red; res.green = col.green; res.blue = col.blue; res.alpha = FIX_ONE; }
118 
119 #define DOME_STEP_V	32
120 #define DOME_STEP_H	16
121 
back_build_dome(GF_Mesh * mesh,MFFloat * angles,MFColor * color,Bool ground_dome)122 static void back_build_dome(GF_Mesh *mesh, MFFloat *angles, MFColor *color, Bool ground_dome)
123 {
124 	u32 i, j, last_idx, ang_idx, new_idx;
125 	Bool pad;
126 	u32 step_div_h;
127 	GF_Vertex vx;
128 	SFColorRGBA start_col, end_col, fcol;
129 	Fixed start_angle, next_angle, angle, r, frac, first_angle;
130 
131 	start_angle = 0;
132 	mesh_reset(mesh);
133 
134 	start_col.red = start_col.green = start_col.blue = 0;
135 	start_col.alpha = FIX_ONE;
136 	end_col = start_col;
137 
138 	if (color->count) {
139 		COL_TO_RGBA(start_col, color->vals[0]);
140 		end_col = start_col;
141 		if (color->count>1) COL_TO_RGBA(end_col, color->vals[1]);
142 	}
143 
144 	vx.texcoords.x = vx.texcoords.y = 0;
145 	vx.color = MESH_MAKE_COL(start_col);
146 	vx.pos.x = vx.pos.z = 0;
147 	vx.pos.y = FIX_ONE;
148 	vx.normal.x = vx.normal.z = 0;
149 	vx.normal.y = -MESH_NORMAL_UNIT;
150 
151 	mesh_set_vertex_vx(mesh, &vx);
152 	last_idx = 0;
153 	ang_idx = 0;
154 
155 	pad = 1;
156 	next_angle = first_angle = 0;
157 	if (angles->count) {
158 		next_angle = angles->vals[0];
159 		first_angle = 7*next_angle/8;
160 		pad = 0;
161 	}
162 
163 	step_div_h = DOME_STEP_H;
164 	i=0;
165 	if (ground_dome) {
166 		step_div_h *= 2;
167 		i=1;
168 	}
169 
170 	for (; i<DOME_STEP_V; i++) {
171 		if (ground_dome) {
172 			angle = first_angle + (i * (GF_PI2-first_angle) / DOME_STEP_V);
173 		} else {
174 			angle = (i * GF_PI / DOME_STEP_V);
175 		}
176 
177 		/*switch cols*/
178 		if (angle >= next_angle) {
179 			if (ang_idx+1<=angles->count) {
180 				start_angle = next_angle;
181 				next_angle = angles->vals[ang_idx+1];
182 				if (next_angle>GF_PI) next_angle=GF_PI;
183 				start_col = end_col;
184 				ang_idx++;
185 				if (ang_idx+1<color->count) {
186 					COL_TO_RGBA(end_col, color->vals[ang_idx+1]);
187 				} else {
188 					pad = 1;
189 				}
190 			} else {
191 				if (ground_dome) break;
192 				pad = 1;
193 			}
194 		}
195 
196 		if (pad) {
197 			fcol = end_col;
198 		} else {
199 			frac = gf_divfix(angle - start_angle, next_angle - start_angle) ;
200 			fcol.red = gf_mulfix(end_col.red - start_col.red, frac) + start_col.red;
201 			fcol.green = gf_mulfix(end_col.green - start_col.green, frac) + start_col.green;
202 			fcol.blue = gf_mulfix(end_col.blue - start_col.blue, frac) + start_col.blue;
203 			fcol.alpha = FIX_ONE;
204 		}
205 		vx.color = MESH_MAKE_COL(fcol);
206 
207 		vx.pos.y = gf_sin(GF_PI2 - angle);
208 		r = gf_sqrt(FIX_ONE - gf_mulfix(vx.pos.y, vx.pos.y));
209 
210 		new_idx = mesh->v_count;
211 		for (j = 0; j < step_div_h; j++) {
212 			SFVec3f n;
213 			Fixed lon = 2 * GF_PI * j / step_div_h;
214 			vx.pos.x = gf_mulfix(gf_sin(lon), r);
215 			vx.pos.z = gf_mulfix(gf_cos(lon), r);
216 			n = gf_vec_scale(vx.pos, FIX_ONE /*-FIX_ONE*/);
217 			gf_vec_norm(&n);
218 			MESH_SET_NORMAL(vx, n);
219 			mesh_set_vertex_vx(mesh, &vx);
220 
221 			if (j) {
222 				if (i>1) {
223 					mesh_set_triangle(mesh, last_idx+j, new_idx+j, new_idx+j-1);
224 					mesh_set_triangle(mesh, last_idx+j, new_idx+j-1, last_idx+j-1);
225 				} else {
226 					mesh_set_triangle(mesh, 0, new_idx+j, new_idx+j-1);
227 				}
228 			}
229 		}
230 		if (i>1) {
231 			mesh_set_triangle(mesh, last_idx, new_idx, new_idx+step_div_h-1);
232 			mesh_set_triangle(mesh, last_idx, new_idx+step_div_h-1, last_idx+step_div_h-1);
233 		} else {
234 			mesh_set_triangle(mesh, 0, new_idx, new_idx+step_div_h-1);
235 		}
236 		last_idx = new_idx;
237 	}
238 
239 	if (!ground_dome) {
240 		new_idx = mesh->v_count;
241 		vx.pos.x = vx.pos.z = 0;
242 		vx.pos.y = -FIX_ONE;
243 		vx.normal.x = vx.normal.z = 0;
244 		vx.normal.y = MESH_NORMAL_UNIT;
245 		mesh_set_vertex_vx(mesh, &vx);
246 
247 		for (j=1; j < step_div_h; j++) {
248 			mesh_set_triangle(mesh, last_idx+j-1, last_idx+j, new_idx);
249 		}
250 		mesh_set_triangle(mesh, last_idx+step_div_h-1, last_idx, new_idx);
251 	}
252 
253 	mesh->flags |= MESH_HAS_COLOR | MESH_NO_TEXTURE;
254 	mesh_update_bounds(mesh);
255 }
256 
back_draw_texture(GF_TraverseState * tr_state,GF_TextureHandler * txh,GF_Mesh * mesh)257 static void back_draw_texture(GF_TraverseState *tr_state, GF_TextureHandler *txh, GF_Mesh *mesh)
258 {
259 	if (gf_sc_texture_enable(txh, NULL)) {
260 		tr_state->mesh_num_textures = 1;
261 		visual_3d_mesh_paint(tr_state, mesh);
262 		gf_sc_texture_disable(txh);
263 		tr_state->mesh_num_textures = 0;
264 	}
265 }
266 
TraverseBackground(GF_Node * node,void * rs,Bool is_destroy)267 static void TraverseBackground(GF_Node *node, void *rs, Bool is_destroy)
268 {
269 	M_Background *bck;
270 	BackgroundStack *st;
271 	SFVec4f res;
272 	Fixed scale;
273 	Bool has_sky, has_ground, front_tx, back_tx, top_tx, bottom_tx, right_tx, left_tx;
274 	GF_Matrix mx;
275 	GF_Compositor *compositor;
276 	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
277 
278 	if (is_destroy) {
279 		DestroyBackground(node);
280 		return;
281 	}
282 	if (tr_state->visual->compositor->noback)
283 		return;
284 
285 	gf_node_dirty_clear(node, 0);
286 	bck = (M_Background *)node;
287 	st = (BackgroundStack *) gf_node_get_private(node);
288 	compositor = (GF_Compositor*)st->compositor;
289 
290 
291 	/*may happen in get_bounds*/
292 	if (!tr_state->backgrounds) return;
293 
294 	/*first traverse, bound if needed*/
295 	if (gf_list_find(tr_state->backgrounds, node) < 0) {
296 		gf_list_add(tr_state->backgrounds, node);
297 		assert(gf_list_find(st->reg_stacks, tr_state->backgrounds)==-1);
298 		gf_list_add(st->reg_stacks, tr_state->backgrounds);
299 		/*only bound if we're on top*/
300 		if (gf_list_get(tr_state->backgrounds, 0) == bck) {
301 			if (!bck->isBound) Bindable_SetIsBound(node, 1);
302 		}
303 
304 		/*check streams*/
305 		if (back_use_texture(&bck->frontUrl) && !st->txh_front.is_open) gf_sc_texture_play(&st->txh_front, &bck->frontUrl);
306 		if (back_use_texture(&bck->bottomUrl) && !st->txh_bottom.is_open) gf_sc_texture_play(&st->txh_bottom, &bck->bottomUrl);
307 		if (back_use_texture(&bck->backUrl) && !st->txh_back.is_open) gf_sc_texture_play(&st->txh_back, &bck->backUrl);
308 		if (back_use_texture(&bck->topUrl) && !st->txh_top.is_open) gf_sc_texture_play(&st->txh_top, &bck->topUrl);
309 		if (back_use_texture(&bck->rightUrl) && !st->txh_right.is_open) gf_sc_texture_play(&st->txh_right, &bck->rightUrl);
310 		if (back_use_texture(&bck->leftUrl) && !st->txh_left.is_open) gf_sc_texture_play(&st->txh_left, &bck->leftUrl);
311 
312 		/*in any case don't draw the first time (since the background could have been declared last)*/
313 		gf_sc_invalidate(st->compositor, NULL);
314 		return;
315 	}
316 	if (!bck->isBound) return;
317 
318 	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
319 		if (tr_state->traversing_mode == TRAVERSE_SORT) {
320 			gf_mx_copy(st->current_mx, tr_state->model_matrix);
321 			if (!tr_state->pixel_metrics && tr_state->visual->compositor->inherit_type_3d) {
322 				Fixed pix_scale = gf_divfix(FIX_ONE, tr_state->min_hsize);
323 				gf_mx_add_scale(&st->current_mx, pix_scale, pix_scale, pix_scale);
324 
325 			}
326 		}
327 		return;
328 	}
329 
330 	front_tx = back_gf_sc_texture_enabled(&bck->frontUrl, &st->txh_front);
331 	back_tx = back_gf_sc_texture_enabled(&bck->backUrl, &st->txh_back);
332 	top_tx = back_gf_sc_texture_enabled(&bck->topUrl, &st->txh_top);
333 	bottom_tx = back_gf_sc_texture_enabled(&bck->bottomUrl, &st->txh_bottom);
334 	right_tx = back_gf_sc_texture_enabled(&bck->rightUrl, &st->txh_right);
335 	left_tx = back_gf_sc_texture_enabled(&bck->leftUrl, &st->txh_left);
336 
337 	has_sky = ((bck->skyColor.count>1) && bck->skyAngle.count) ? 1 : 0;
338 	has_ground = ((bck->groundColor.count>1) && bck->groundAngle.count) ? 1 : 0;
339 
340 	/*if we clear the main visual clear it entirely - ONLY IF NOT IN LAYER*/
341 	if ((tr_state->visual == compositor->visual) && (tr_state->visual->back_stack == tr_state->backgrounds)) {
342 		SFColor bcol;
343 		bcol.red = INT2FIX( GF_COL_R(tr_state->visual->compositor->back_color)) / 255;
344 		bcol.green = INT2FIX( GF_COL_G(tr_state->visual->compositor->back_color)) / 255;
345 		bcol.blue = INT2FIX( GF_COL_B(tr_state->visual->compositor->back_color)) / 255;
346 
347 		visual_3d_clear(tr_state->visual, bcol, FIX_ONE);
348 		if (!has_sky && !has_ground && !front_tx && !back_tx && !top_tx && !bottom_tx && !left_tx && !right_tx) {
349 			return;
350 		}
351 	}
352 
353 	/*undo translation*/
354 	res.x = res.y = res.z = 0;
355 	res.q = FIX_ONE;
356 	gf_mx_apply_vec_4x4(&tr_state->camera->unprojection, &res);
357 	assert(res.q);
358 	res.x = gf_divfix(res.x, res.q);
359 	res.y = gf_divfix(res.y, res.q);
360 	res.z = gf_divfix(res.z, res.q);
361 	/*NB: we don't support local rotation of the background ...*/
362 
363 	/*enable background state (turn off all quality options)*/
364 	visual_3d_set_background_state(tr_state->visual, 1);
365 
366 	if (has_sky) {
367 		GF_Matrix bck_mx;
368 		gf_mx_copy(bck_mx, tr_state->model_matrix);
369 		gf_mx_copy(tr_state->model_matrix, st->current_mx);
370 
371 		if (!st->sky_mesh) {
372 			st->sky_mesh = new_mesh();
373 			back_build_dome(st->sky_mesh, &bck->skyAngle, &bck->skyColor, 0);
374 		}
375 
376 		gf_mx_init(mx);
377 		gf_mx_add_translation(&mx, res.x, res.y, res.z);
378 
379 		/*CHECKME - not sure why, we need to scale less in fixed point otherwise z-far clipping occur - probably some
380 		rounding issues...*/
381 #ifdef GPAC_FIXED_POINT
382 		scale = (tr_state->camera->z_far/10)*8;
383 #else
384 		scale = 8*tr_state->camera->z_far/10;
385 #endif
386 		gf_mx_add_scale(&mx, scale, scale, scale);
387 
388 		gf_mx_add_matrix(&tr_state->model_matrix, &mx);
389 
390 		visual_3d_mesh_paint(tr_state, st->sky_mesh);
391 
392 		gf_mx_copy(tr_state->model_matrix, bck_mx);
393 	}
394 
395 	if (has_ground) {
396 		GF_Matrix bck_mx;
397 		gf_mx_copy(bck_mx, tr_state->model_matrix);
398 		gf_mx_copy(tr_state->model_matrix, st->current_mx);
399 
400 		if (!st->ground_mesh) {
401 			st->ground_mesh = new_mesh();
402 			back_build_dome(st->ground_mesh, &bck->groundAngle, &bck->groundColor, 1);
403 		}
404 
405 		gf_mx_init(mx);
406 		gf_mx_add_translation(&mx, res.x, res.y, res.z);
407 		/*cf above*/
408 #ifdef GPAC_FIXED_POINT
409 		scale = (tr_state->camera->z_far/100)*70;
410 #else
411 		scale = 70*tr_state->camera->z_far/100;
412 #endif
413 		gf_mx_add_scale(&mx, scale, -scale, scale);
414 
415 		gf_mx_add_matrix(&tr_state->model_matrix, &mx);
416 		visual_3d_mesh_paint(tr_state, st->ground_mesh);
417 		gf_mx_copy(tr_state->model_matrix, bck_mx);
418 	}
419 
420 	if (front_tx || back_tx || left_tx || right_tx || top_tx || bottom_tx) {
421 		GF_Matrix bck_mx;
422 		gf_mx_copy(bck_mx, tr_state->model_matrix);
423 		gf_mx_copy(tr_state->model_matrix, st->current_mx);
424 
425 		gf_mx_init(mx);
426 		gf_mx_add_translation(&mx, res.x, res.y, res.z);
427 #ifdef GPAC_FIXED_POINT
428 		scale = (tr_state->camera->z_far/100)*90;
429 #else
430 		scale = (tr_state->camera->z_far/100)*90;
431 #endif
432 		gf_mx_add_scale(&mx, scale, scale, scale);
433 
434 		visual_3d_enable_antialias(tr_state->visual, 1);
435 
436 		gf_mx_add_matrix(&tr_state->model_matrix, &mx);
437 
438 		if (front_tx) back_draw_texture(tr_state, &st->txh_front, st->front_mesh);
439 		if (back_tx) back_draw_texture(tr_state, &st->txh_back, st->back_mesh);
440 		if (top_tx) back_draw_texture(tr_state, &st->txh_top, st->top_mesh);
441 		if (bottom_tx) back_draw_texture(tr_state, &st->txh_bottom, st->bottom_mesh);
442 		if (left_tx) back_draw_texture(tr_state, &st->txh_left, st->left_mesh);
443 		if (right_tx) back_draw_texture(tr_state, &st->txh_right, st->right_mesh);
444 
445 		gf_mx_copy(tr_state->model_matrix, bck_mx);
446 	}
447 
448 	/*enable background state (turn off all quality options)*/
449 	visual_3d_set_background_state(tr_state->visual, 0);
450 }
451 
452 
back_set_bind(GF_Node * node,GF_Route * route)453 static void back_set_bind(GF_Node *node, GF_Route *route)
454 {
455 	BackgroundStack *st = (BackgroundStack *)gf_node_get_private(node);
456 	Bindable_OnSetBind(node, st->reg_stacks, NULL);
457 	/*and redraw scene*/
458 	gf_sc_invalidate(st->compositor, NULL);
459 }
460 
compositor_init_background(GF_Compositor * compositor,GF_Node * node)461 void compositor_init_background(GF_Compositor *compositor, GF_Node *node)
462 {
463 	BackgroundStack *ptr;
464 	GF_SAFEALLOC(ptr, BackgroundStack);
465 	if (!ptr) {
466 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate background stack\n"));
467 		return;
468 	}
469 
470 	ptr->compositor = compositor;
471 	ptr->reg_stacks = gf_list_new();
472 	((M_Background *)node)->on_set_bind = back_set_bind;
473 
474 	gf_mx_init(ptr->current_mx);
475 
476 	/*build texture cube*/
477 	ptr->front_mesh = new_mesh();
478 	mesh_set_vertex(ptr->front_mesh, -PLANE_HSIZE, -PLANE_HSIZE, -PLANE_HSIZE_LOW,  0,  0,  FIX_ONE, 0, 0);
479 	mesh_set_vertex(ptr->front_mesh,  PLANE_HSIZE, -PLANE_HSIZE, -PLANE_HSIZE_LOW,  0,  0,  FIX_ONE, FIX_ONE, 0);
480 	mesh_set_vertex(ptr->front_mesh,  PLANE_HSIZE,  PLANE_HSIZE, -PLANE_HSIZE_LOW,  0,  0,  FIX_ONE, FIX_ONE, FIX_ONE);
481 	mesh_set_vertex(ptr->front_mesh, -PLANE_HSIZE,  PLANE_HSIZE, -PLANE_HSIZE_LOW,  0,  0,  FIX_ONE, 0, FIX_ONE);
482 	mesh_set_triangle(ptr->front_mesh, 0, 1, 2);
483 	mesh_set_triangle(ptr->front_mesh, 0, 2, 3);
484 	mesh_update_bounds(ptr->front_mesh);
485 
486 	ptr->back_mesh = new_mesh();
487 	mesh_set_vertex(ptr->back_mesh, -PLANE_HSIZE, -PLANE_HSIZE,  PLANE_HSIZE_LOW,  0,  0,  -FIX_ONE, FIX_ONE, 0);
488 	mesh_set_vertex(ptr->back_mesh,  PLANE_HSIZE, -PLANE_HSIZE,  PLANE_HSIZE_LOW,  0,  0,  -FIX_ONE, 0, 0);
489 	mesh_set_vertex(ptr->back_mesh,  PLANE_HSIZE,  PLANE_HSIZE,  PLANE_HSIZE_LOW,  0,  0,  -FIX_ONE, 0, FIX_ONE);
490 	mesh_set_vertex(ptr->back_mesh, -PLANE_HSIZE,  PLANE_HSIZE,  PLANE_HSIZE_LOW,  0,  0,  -FIX_ONE, FIX_ONE, FIX_ONE);
491 	mesh_set_triangle(ptr->back_mesh, 0, 1, 2);
492 	mesh_set_triangle(ptr->back_mesh, 0, 2, 3);
493 	mesh_update_bounds(ptr->back_mesh);
494 
495 	ptr->top_mesh = new_mesh();
496 	mesh_set_vertex(ptr->top_mesh, -PLANE_HSIZE,  PLANE_HSIZE_LOW,  PLANE_HSIZE,  0,  -FIX_ONE,  0, 0, 0);
497 	mesh_set_vertex(ptr->top_mesh,  PLANE_HSIZE,  PLANE_HSIZE_LOW,  PLANE_HSIZE,  0,  -FIX_ONE,  0, 0, FIX_ONE);
498 	mesh_set_vertex(ptr->top_mesh,  PLANE_HSIZE,  PLANE_HSIZE_LOW, -PLANE_HSIZE,  0,  -FIX_ONE,  0, FIX_ONE, FIX_ONE);
499 	mesh_set_vertex(ptr->top_mesh, -PLANE_HSIZE,  PLANE_HSIZE_LOW, -PLANE_HSIZE,  0,  -FIX_ONE,  0, FIX_ONE, 0);
500 	mesh_set_triangle(ptr->top_mesh, 0, 1, 2);
501 	mesh_set_triangle(ptr->top_mesh, 0, 2, 3);
502 	mesh_update_bounds(ptr->top_mesh);
503 
504 	ptr->bottom_mesh = new_mesh();
505 	mesh_set_vertex(ptr->bottom_mesh, -PLANE_HSIZE, -PLANE_HSIZE_LOW, -PLANE_HSIZE,  0, FIX_ONE,  0, FIX_ONE, FIX_ONE);
506 	mesh_set_vertex(ptr->bottom_mesh,  PLANE_HSIZE, -PLANE_HSIZE_LOW, -PLANE_HSIZE,  0, FIX_ONE,  0, FIX_ONE, 0);
507 	mesh_set_vertex(ptr->bottom_mesh,  PLANE_HSIZE, -PLANE_HSIZE_LOW,  PLANE_HSIZE,  0, FIX_ONE,  0, 0, 0);
508 	mesh_set_vertex(ptr->bottom_mesh, -PLANE_HSIZE, -PLANE_HSIZE_LOW,  PLANE_HSIZE,  0, FIX_ONE,  0, 0, FIX_ONE);
509 	mesh_set_triangle(ptr->bottom_mesh, 0, 1, 2);
510 	mesh_set_triangle(ptr->bottom_mesh, 0, 2, 3);
511 	mesh_update_bounds(ptr->bottom_mesh);
512 
513 	ptr->left_mesh = new_mesh();
514 	mesh_set_vertex(ptr->left_mesh, -PLANE_HSIZE_LOW, -PLANE_HSIZE, -PLANE_HSIZE, FIX_ONE,  0,  0, FIX_ONE, 0);
515 	mesh_set_vertex(ptr->left_mesh, -PLANE_HSIZE_LOW, -PLANE_HSIZE,  PLANE_HSIZE, FIX_ONE,  0,  0, 0, 0);
516 	mesh_set_vertex(ptr->left_mesh, -PLANE_HSIZE_LOW,  PLANE_HSIZE,  PLANE_HSIZE, FIX_ONE,  0,  0, 0, FIX_ONE);
517 	mesh_set_vertex(ptr->left_mesh, -PLANE_HSIZE_LOW,  PLANE_HSIZE, -PLANE_HSIZE, FIX_ONE,  0,  0, FIX_ONE, FIX_ONE);
518 	mesh_set_triangle(ptr->left_mesh, 0, 1, 2);
519 	mesh_set_triangle(ptr->left_mesh, 0, 2, 3);
520 	mesh_update_bounds(ptr->left_mesh);
521 
522 	ptr->right_mesh = new_mesh();
523 	mesh_set_vertex(ptr->right_mesh,  PLANE_HSIZE_LOW, -PLANE_HSIZE,  PLANE_HSIZE, -FIX_ONE,  0,  0, FIX_ONE, 0);
524 	mesh_set_vertex(ptr->right_mesh,  PLANE_HSIZE_LOW, -PLANE_HSIZE, -PLANE_HSIZE, -FIX_ONE,  0,  0, 0, 0);
525 	mesh_set_vertex(ptr->right_mesh,  PLANE_HSIZE_LOW,  PLANE_HSIZE, -PLANE_HSIZE, -FIX_ONE,  0,  0, 0, FIX_ONE);
526 	mesh_set_vertex(ptr->right_mesh,  PLANE_HSIZE_LOW,  PLANE_HSIZE,  PLANE_HSIZE, -FIX_ONE,  0,  0, FIX_ONE, FIX_ONE);
527 	mesh_set_triangle(ptr->right_mesh, 0, 1, 2);
528 	mesh_set_triangle(ptr->right_mesh, 0, 2, 3);
529 	mesh_update_bounds(ptr->right_mesh);
530 
531 
532 	gf_sc_texture_setup(&ptr->txh_back, compositor, node);
533 	ptr->txh_back.update_texture_fcnt = UpdateBackgroundTexture;
534 	gf_sc_texture_setup(&ptr->txh_front, compositor, node);
535 	ptr->txh_front.update_texture_fcnt = UpdateBackgroundTexture;
536 	gf_sc_texture_setup(&ptr->txh_top, compositor, node);
537 	ptr->txh_top.update_texture_fcnt = UpdateBackgroundTexture;
538 	gf_sc_texture_setup(&ptr->txh_bottom, compositor, node);
539 	ptr->txh_bottom.update_texture_fcnt = UpdateBackgroundTexture;
540 	gf_sc_texture_setup(&ptr->txh_left, compositor, node);
541 	ptr->txh_left.update_texture_fcnt = UpdateBackgroundTexture;
542 	gf_sc_texture_setup(&ptr->txh_right, compositor, node);
543 	ptr->txh_right.update_texture_fcnt = UpdateBackgroundTexture;
544 
545 	gf_node_set_private(node, ptr);
546 	gf_node_set_callback_function(node, TraverseBackground);
547 
548 }
549 
compositor_background_modified(GF_Node * node)550 void compositor_background_modified(GF_Node *node)
551 {
552 	M_Background *bck = (M_Background *)node;
553 	BackgroundStack *st = (BackgroundStack *) gf_node_get_private(node);
554 	if (!st) return;
555 
556 	if (!gf_sg_vrml_field_equal(&bck->skyColor, &st->sky_col, GF_SG_VRML_MFCOLOR)
557 	        || !gf_sg_vrml_field_equal(&bck->skyAngle, &st->sky_ang, GF_SG_VRML_MFFLOAT)
558 	   ) {
559 
560 		if (st->sky_mesh) mesh_free(st->sky_mesh);
561 		st->sky_mesh = NULL;
562 		gf_sg_vrml_field_copy(&st->sky_col, &bck->skyColor, GF_SG_VRML_MFCOLOR);
563 		gf_sg_vrml_field_copy(&st->sky_ang, &bck->skyAngle, GF_SG_VRML_MFFLOAT);
564 	}
565 	if (!gf_sg_vrml_field_equal(&bck->groundColor, &st->ground_col, GF_SG_VRML_MFCOLOR)
566 	        || !gf_sg_vrml_field_equal(&bck->groundAngle, &st->ground_ang, GF_SG_VRML_MFFLOAT)
567 	   ) {
568 
569 		if (st->ground_mesh) mesh_free(st->ground_mesh);
570 		st->ground_mesh = NULL;
571 		gf_sg_vrml_field_copy(&st->ground_col, &bck->groundColor, GF_SG_VRML_MFCOLOR);
572 		gf_sg_vrml_field_copy(&st->ground_ang, &bck->groundAngle, GF_SG_VRML_MFFLOAT);
573 	}
574 
575 	back_check_gf_sc_texture_change(&st->txh_front, &bck->frontUrl);
576 	back_check_gf_sc_texture_change(&st->txh_back, &bck->backUrl);
577 	back_check_gf_sc_texture_change(&st->txh_top, &bck->topUrl);
578 	back_check_gf_sc_texture_change(&st->txh_bottom, &bck->bottomUrl);
579 	back_check_gf_sc_texture_change(&st->txh_left, &bck->leftUrl);
580 	back_check_gf_sc_texture_change(&st->txh_right, &bck->rightUrl);
581 
582 
583 	gf_sc_invalidate(st->compositor, NULL);
584 }
585 
586 #endif /*GPAC_DISABLE_3D*/
587 
588 #endif	/*GPAC_DISABLE_VRML*/
589