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 #include "texturing.h"
27
28 #include <gpac/network.h>
29 #include <gpac/nodes_mpeg4.h>
30 #include <gpac/nodes_x3d.h>
31
32 #ifndef GPAC_DISABLE_VRML
33
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37
38 /*for cache texture decode and hash*/
39 #include <gpac/avparse.h>
40 #include <gpac/crypt.h>
41 #include "nodes_stacks.h"
42
43
44 typedef struct
45 {
46 GF_TextureHandler txh;
47
48 GF_TimeNode time_handle;
49 Bool fetch_first_frame, first_frame_fetched, is_x3d;
50 Double start_time;
51 } MovieTextureStack;
52
movietexture_destroy(GF_Node * node,void * rs,Bool is_destroy)53 static void movietexture_destroy(GF_Node *node, void *rs, Bool is_destroy)
54 {
55 if (is_destroy) {
56 MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(node);
57 gf_sc_texture_destroy(&st->txh);
58 if (st->time_handle.is_registered) gf_sc_unregister_time_node(st->txh.compositor, &st->time_handle);
59 gf_free(st);
60 }
61 }
movietexture_get_speed(MovieTextureStack * stack,M_MovieTexture * mt)62 static Fixed movietexture_get_speed(MovieTextureStack *stack, M_MovieTexture *mt)
63 {
64 return gf_mo_get_speed(stack->txh.stream, mt->speed);
65 }
movietexture_get_loop(MovieTextureStack * stack,M_MovieTexture * mt)66 static Bool movietexture_get_loop(MovieTextureStack *stack, M_MovieTexture *mt)
67 {
68 return gf_mo_get_loop(stack->txh.stream, mt->loop);
69 }
movietexture_activate(MovieTextureStack * stack,M_MovieTexture * mt,Double scene_time)70 static void movietexture_activate(MovieTextureStack *stack, M_MovieTexture *mt, Double scene_time)
71 {
72 mt->isActive = 1;
73 gf_node_event_out((GF_Node*)mt, 8/*"isActive"*/);
74 if (!stack->txh.is_open) {
75 scene_time -= mt->startTime;
76 gf_sc_texture_play_from_to(&stack->txh, &mt->url, scene_time, -1, gf_mo_get_loop(stack->txh.stream, mt->loop), 0);
77 } else if (stack->first_frame_fetched) {
78 gf_mo_resume(stack->txh.stream);
79 }
80 gf_mo_set_speed(stack->txh.stream, mt->speed);
81 }
movietexture_deactivate(MovieTextureStack * stack,M_MovieTexture * mt)82 static void movietexture_deactivate(MovieTextureStack *stack, M_MovieTexture *mt)
83 {
84 mt->isActive = 0;
85 gf_node_event_out((GF_Node*)mt, 8/*"isActive"*/);
86 stack->time_handle.needs_unregister = 1;
87
88 if (stack->txh.is_open) {
89 gf_sc_texture_stop_no_unregister(&stack->txh);
90 }
91 }
movietexture_update(GF_TextureHandler * txh)92 static void movietexture_update(GF_TextureHandler *txh)
93 {
94 M_MovieTexture *txnode = (M_MovieTexture *) txh->owner;
95 MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(txh->owner);
96
97 /*setup texture if needed*/
98 if (!txh->is_open) return;
99 if (!txnode->isActive && st->first_frame_fetched) return;
100
101 /*when fetching the first frame disable resync*/
102 gf_sc_texture_update_frame(txh, 0);
103
104 if (txh->stream_finished) {
105 if (movietexture_get_loop(st, txnode)) {
106 gf_sc_texture_restart(txh);
107 }
108 /*if active deactivate*/
109 else if (txnode->isActive && gf_mo_should_deactivate(st->txh.stream) ) {
110 movietexture_deactivate(st, txnode);
111 }
112 }
113 /*first frame is fetched*/
114 if (!st->first_frame_fetched && (txh->needs_refresh) ) {
115 st->first_frame_fetched = 1;
116 txnode->duration_changed = gf_mo_get_duration(txh->stream);
117 gf_node_event_out(txh->owner, 7/*"duration_changed"*/);
118 /*stop stream if needed*/
119 if (!txnode->isActive && txh->is_open) {
120 gf_mo_pause(txh->stream);
121 /*make sure the refresh flag is not cleared*/
122 txh->needs_refresh = 1;
123 gf_sc_invalidate(txh->compositor, NULL);
124 }
125 }
126 if (txh->needs_refresh) {
127 /*mark all subtrees using this image as dirty*/
128 gf_node_dirty_parents(txh->owner);
129 }
130 }
131
movietexture_update_time(GF_TimeNode * st)132 static void movietexture_update_time(GF_TimeNode *st)
133 {
134 Double time;
135 M_MovieTexture *mt = (M_MovieTexture *)st->udta;
136 MovieTextureStack *stack = (MovieTextureStack *)gf_node_get_private(st->udta);
137
138 /*not active, store start time and speed*/
139 if ( ! mt->isActive) {
140 stack->start_time = mt->startTime;
141 }
142 time = gf_node_get_scene_time(st->udta);
143
144 if (time < stack->start_time ||
145 /*special case if we're getting active AFTER stoptime */
146 (!mt->isActive && (mt->stopTime > stack->start_time) && (time>=mt->stopTime))
147 // || (!stack->start_time && !stack->is_x3d && !mt->loop)
148 ) {
149 /*opens stream only at first access to fetch first frame*/
150 if (stack->fetch_first_frame) {
151 stack->fetch_first_frame = 0;
152 if (!stack->txh.is_open)
153 gf_sc_texture_play(&stack->txh, &mt->url);
154 else
155 gf_mo_resume(stack->txh.stream);
156 }
157 return;
158 }
159
160 if (movietexture_get_speed(stack, mt) && mt->isActive) {
161 /*if stoptime is reached (>startTime) deactivate*/
162 if ((mt->stopTime > stack->start_time) && (time >= mt->stopTime) ) {
163 movietexture_deactivate(stack, mt);
164 return;
165 }
166 }
167
168 /*we're (about to be) active: VRML:
169 "A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or
170 equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active */
171
172 if (! mt->isActive) movietexture_activate(stack, mt, time);
173 stack->txh.stream_finished = GF_FALSE;
174 if (!mt->url.count)
175 stack->txh.stream_finished = GF_TRUE;
176 }
177
compositor_init_movietexture(GF_Compositor * compositor,GF_Node * node)178 void compositor_init_movietexture(GF_Compositor *compositor, GF_Node *node)
179 {
180 MovieTextureStack *st;
181 GF_SAFEALLOC(st, MovieTextureStack);
182 if (!st) {
183 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate movie texture stack\n"));
184 return;
185 }
186 gf_sc_texture_setup(&st->txh, compositor, node);
187 st->txh.update_texture_fcnt = movietexture_update;
188 st->time_handle.UpdateTimeNode = movietexture_update_time;
189 st->time_handle.udta = node;
190 st->fetch_first_frame = 1;
191 st->txh.flags = 0;
192 if (((M_MovieTexture*)node)->repeatS) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
193 if (((M_MovieTexture*)node)->repeatT) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
194
195 #ifndef GPAC_DISABLE_X3D
196 st->is_x3d = (gf_node_get_tag(node)==TAG_X3D_MovieTexture) ? 1 : 0;
197 #endif
198
199 gf_node_set_private(node, st);
200 gf_node_set_callback_function(node, movietexture_destroy);
201
202 gf_sc_register_time_node(compositor, &st->time_handle);
203 }
204
mt_get_texture(GF_Node * node)205 GF_TextureHandler *mt_get_texture(GF_Node *node)
206 {
207 MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(node);
208 return &st->txh;
209 }
210
compositor_movietexture_modified(GF_Node * node)211 void compositor_movietexture_modified(GF_Node *node)
212 {
213 M_MovieTexture *mt = (M_MovieTexture *)node;
214 MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(node);
215 if (!st) return;
216
217 /*if open and changed, stop and play*/
218 if (gf_sc_texture_check_url_change(&st->txh, &mt->url)) {
219 if (st->txh.is_open) gf_sc_texture_stop(&st->txh);
220 if (mt->isActive) gf_sc_texture_play(&st->txh, &mt->url);
221 }
222 /*update state if we're active*/
223 else if (mt->isActive) {
224 movietexture_update_time(&st->time_handle);
225 if (!mt->isActive) return;
226 }
227 /*reregister if needed*/
228 st->time_handle.needs_unregister = 0;
229 if (!st->time_handle.is_registered) gf_sc_register_time_node(st->txh.compositor, &st->time_handle);
230 }
231
imagetexture_destroy(GF_Node * node,void * rs,Bool is_destroy)232 static void imagetexture_destroy(GF_Node *node, void *rs, Bool is_destroy)
233 {
234 if (is_destroy) {
235 GF_TextureHandler *txh = (GF_TextureHandler *) gf_node_get_private(node);
236
237 /*cleanup cache if needed*/
238 if (gf_node_get_tag(node)==TAG_MPEG4_CacheTexture) {
239 char section[64];
240 const char *opt, *file;
241 Bool delete_file = GF_TRUE;
242 M_CacheTexture *ct = (M_CacheTexture*)node;
243
244 sprintf(section, "@cache=%p", ct);
245 file = gf_opts_get_key(section, "cacheFile");
246 opt = gf_opts_get_key(section, "expireAfterNTP");
247
248 if (opt) {
249 u32 sec, frac, exp;
250 sscanf(opt, "%u", &exp);
251 gf_net_get_ntp(&sec, &frac);
252 if (!exp || (exp>sec)) delete_file=GF_FALSE;
253 }
254 if (delete_file) {
255 if (file) gf_file_delete((char*)file);
256 gf_opts_del_section(section);
257 }
258
259 if (txh->data) gf_free(txh->data);
260 txh->data = NULL;
261 }
262 gf_sc_texture_destroy(txh);
263 gf_free(txh);
264 }
265 }
266
imagetexture_update(GF_TextureHandler * txh)267 static void imagetexture_update(GF_TextureHandler *txh)
268 {
269 if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) {
270 MFURL url = ((M_ImageTexture *) txh->owner)->url;
271
272 /*setup texture if needed*/
273 if (!txh->is_open && url.count) {
274 gf_sc_texture_play(txh, &url);
275 }
276 gf_sc_texture_update_frame(txh, 0);
277
278 if (
279 /*URL is present but not opened - redraw till fetch*/
280 /* (txh->stream && !txh->tx_io) && */
281 /*image has been updated*/
282 txh->needs_refresh) {
283 /*mark all subtrees using this image as dirty*/
284 gf_node_dirty_parents(txh->owner);
285 gf_sc_invalidate(txh->compositor, NULL);
286 }
287 return;
288 }
289 /*cache texture case*/
290 else {
291 M_CacheTexture *ct = (M_CacheTexture *) txh->owner;
292
293 /*decode cacheTexture data */
294 if ((ct->data || ct->image.buffer) && !txh->data) {
295 #ifndef GPAC_DISABLE_AV_PARSERS
296 u32 out_size;
297 GF_Err e;
298
299 /*BT/XMT playback: load to memory*/
300 if (ct->image.buffer) {
301 char *par = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) );
302 char *src_url = gf_url_concatenate(par, ct->image.buffer);
303
304 if (ct->data) gf_free(ct->data);
305 ct->data = NULL;
306 ct->data_len = 0;
307
308 e = gf_file_load_data(src_url ? src_url : ct->image.buffer, &ct->data, &ct->data_len);
309 if (e) {
310 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: %s\n", src_url ? src_url : ct->image.buffer, gf_error_to_string(e) ) );
311 }
312 if (ct->image.buffer) gf_free(ct->image.buffer);
313 ct->image.buffer = NULL;
314 if (src_url) gf_free(src_url);
315 }
316
317 /*BIFS decoded playback*/
318 switch (ct->objectTypeIndication) {
319 case GF_CODECID_JPEG:
320 out_size = 0;
321 e = gf_img_jpeg_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3);
322 if (e==GF_BUFFER_TOO_SMALL) {
323 u32 BPP;
324 txh->data = gf_malloc(sizeof(char) * out_size);
325 if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1;
326 else BPP = 3;
327
328 e = gf_img_jpeg_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP);
329 if (e==GF_OK) {
330 gf_sc_texture_allocate(txh);
331 gf_sc_texture_set_data(txh);
332 txh->needs_refresh = 1;
333 txh->stride = out_size / txh->height;
334 }
335 }
336 break;
337 case GF_CODECID_PNG:
338 out_size = 0;
339 e = gf_img_png_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size);
340 if (e==GF_BUFFER_TOO_SMALL) {
341 txh->data = gf_malloc(sizeof(char) * out_size);
342 e = gf_img_png_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size);
343 if (e==GF_OK) {
344 gf_sc_texture_allocate(txh);
345 gf_sc_texture_set_data(txh);
346 txh->needs_refresh = 1;
347 txh->stride = out_size / txh->height;
348 }
349 }
350 break;
351 }
352
353 #endif // GPAC_DISABLE_AV_PARSERS
354
355 /*cacheURL is specified, store the image*/
356 if (ct->cacheURL.buffer) {
357 u32 i;
358 u8 hash[20];
359 FILE *cached_texture;
360 char szExtractName[GF_MAX_PATH], *opt, *src_url;
361 opt = (char *) gf_opts_get_key("core", "cache");
362 if (opt) {
363 strcpy(szExtractName, opt);
364 } else {
365 strcpy(szExtractName, gf_get_default_cache_directory());
366 }
367 strcat(szExtractName, "/");
368 src_url = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) );
369
370 gf_sha1_csum((u8 *)src_url, (u32) strlen(src_url), hash);
371 for (i=0; i<20; i++) {
372 char t[3];
373 t[2] = 0;
374 sprintf(t, "%02X", hash[i]);
375 strcat(szExtractName, t);
376 }
377 strcat(szExtractName, "_");
378
379 strcat(szExtractName, ct->cacheURL.buffer);
380 cached_texture = gf_fopen(szExtractName, "wb");
381 if (cached_texture) {
382 gf_fwrite(ct->data, ct->data_len, cached_texture);
383 gf_fclose(cached_texture);
384 }
385
386 /*and write cache info*/
387 if (ct->expirationDate!=0) {
388 char section[64];
389 sprintf(section, "@cache=%p", ct);
390 gf_opts_set_key(section, "serviceURL", src_url);
391 gf_opts_set_key(section, "cacheFile", szExtractName);
392 gf_opts_set_key(section, "cacheName", ct->cacheURL.buffer);
393
394 if (ct->expirationDate>0) {
395 char exp[50];
396 u32 sec, frac;
397 gf_net_get_ntp(&sec, &frac);
398 sec += ct->expirationDate;
399 sprintf(exp, "%u", sec);
400 gf_opts_set_key(section, "expireAfterNTP", exp);
401 } else {
402 gf_opts_set_key(section, "expireAfterNTP", "0");
403 }
404 }
405 }
406
407 /*done with image, destroy buffer*/
408 if (ct->data) gf_free(ct->data);
409 ct->data = NULL;
410 ct->data_len = 0;
411 }
412 }
413 }
414
compositor_init_imagetexture(GF_Compositor * compositor,GF_Node * node)415 void compositor_init_imagetexture(GF_Compositor *compositor, GF_Node *node)
416 {
417 GF_TextureHandler *txh;
418 GF_SAFEALLOC(txh, GF_TextureHandler);
419 if (!txh) {
420 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate image texture stack\n"));
421 return;
422 }
423 gf_sc_texture_setup(txh, compositor, node);
424 txh->update_texture_fcnt = imagetexture_update;
425 gf_node_set_private(node, txh);
426 gf_node_set_callback_function(node, imagetexture_destroy);
427 txh->flags = 0;
428
429 if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) {
430 if (((M_ImageTexture*)node)->repeatS) txh->flags |= GF_SR_TEXTURE_REPEAT_S;
431 if (((M_ImageTexture*)node)->repeatT) txh->flags |= GF_SR_TEXTURE_REPEAT_T;
432 } else {
433 const char *url;
434 u32 i, count;
435 M_CacheTexture*ct = (M_CacheTexture*)node;
436 if (!ct->image.buffer) return;
437
438 if (ct->repeatS) txh->flags |= GF_SR_TEXTURE_REPEAT_S;
439 if (ct->repeatT) txh->flags |= GF_SR_TEXTURE_REPEAT_T;
440
441 /*locate existing cache*/
442 url = gf_scene_get_service_url( gf_node_get_graph(node) );
443 count = gf_opts_get_section_count();
444 for (i=0; i<count; i++) {
445 const char *opt;
446 const char *name = gf_opts_get_section_name(i);
447 if (strncmp(name, "@cache=", 7)) continue;
448 opt = gf_opts_get_key(name, "serviceURL");
449 if (!opt || stricmp(opt, url)) continue;
450 opt = gf_opts_get_key(name, "cacheName");
451 if (opt && ct->cacheURL.buffer && !stricmp(opt, ct->cacheURL.buffer)) {
452 opt = gf_opts_get_key(name, "cacheFile");
453 if (opt) gf_file_delete((char*)opt);
454 gf_opts_del_section(name);
455 break;
456 }
457 }
458
459 }
460 }
461
it_get_texture(GF_Node * node)462 GF_TextureHandler *it_get_texture(GF_Node *node)
463 {
464 return gf_node_get_private(node);
465 }
compositor_imagetexture_modified(GF_Node * node)466 void compositor_imagetexture_modified(GF_Node *node)
467 {
468 MFURL url;
469 SFURL sfurl;
470 GF_TextureHandler *txh = (GF_TextureHandler *) gf_node_get_private(node);
471 if (!txh) return;
472
473 if (gf_node_get_tag(node)!=TAG_MPEG4_CacheTexture) {
474 url = ((M_ImageTexture *) node)->url;
475 } else {
476 url.count = 1;
477 sfurl.OD_ID=GF_MEDIA_EXTERNAL_ID;
478 sfurl.url = ((M_CacheTexture *) node)->image.buffer;
479 url.vals = &sfurl;
480 }
481
482 /*if open and changed, stop and play*/
483 if (txh->is_open) {
484 if (! gf_sc_texture_check_url_change(txh, &url)) return;
485 gf_sc_texture_stop(txh);
486 gf_sc_texture_play(txh, &url);
487 return;
488 }
489 /*if not open and changed play*/
490 if (url.count)
491 gf_sc_texture_play(txh, &url);
492 }
493
494
495
496 typedef struct
497 {
498 GF_TextureHandler txh;
499 char *pixels;
500 } PixelTextureStack;
501
pixeltexture_destroy(GF_Node * node,void * rs,Bool is_destroy)502 static void pixeltexture_destroy(GF_Node *node, void *rs, Bool is_destroy)
503 {
504 if (is_destroy) {
505 PixelTextureStack *st = (PixelTextureStack *) gf_node_get_private(node);
506 if (st->pixels) gf_free(st->pixels);
507 gf_sc_texture_destroy(&st->txh);
508 gf_free(st);
509 }
510 }
pixeltexture_update(GF_TextureHandler * txh)511 static void pixeltexture_update(GF_TextureHandler *txh)
512 {
513 u32 pix_format, stride, i;
514 M_PixelTexture *pt = (M_PixelTexture *) txh->owner;
515 PixelTextureStack *st = (PixelTextureStack *) gf_node_get_private(txh->owner);
516
517 if (!gf_node_dirty_get(txh->owner)) return;
518 gf_node_dirty_clear(txh->owner, 0);
519
520
521 /*pixel texture doesn not use any media object but has data in the content.
522 However we still use the same texture object, just be carefull not to use media funtcions*/
523 txh->transparent = 0;
524 stride = pt->image.width;
525 /*num_components are as in VRML (1->4) not as in BIFS bitstream (0->3)*/
526 switch (pt->image.numComponents) {
527 case 1:
528 pix_format = GF_PIXEL_GREYSCALE;
529 break;
530 case 2:
531 pix_format = GF_PIXEL_ALPHAGREY;
532 txh->transparent = 1;
533 stride *= 2;
534 break;
535 case 3:
536 pix_format = GF_PIXEL_RGB;
537 txh->transparent = 0;
538 stride *= 3;
539 break;
540 case 4:
541 pix_format = GF_PIXEL_RGBA;
542 txh->transparent = 1;
543 stride *= 4;
544 break;
545 default:
546 return;
547 }
548
549 if (!txh->tx_io) {
550 gf_sc_texture_allocate(txh);
551 if (!txh->tx_io) return;
552 }
553
554 if (st->pixels) gf_free(st->pixels);
555 st->pixels = (char*)gf_malloc(sizeof(char) * stride * pt->image.height);
556 /*FIXME FOR OPENGL !!*/
557 #if 0
558 for (i=0; i<pt->image.height; i++) {
559 memcpy(st->pixels + i * stride, pt->image.pixels + i * stride, stride);
560 }
561 #else
562 /*revert pixel ordering...*/
563 for (i=0; i<pt->image.height; i++) {
564 memcpy(st->pixels + i * stride, pt->image.pixels + (pt->image.height - 1 - i) * stride, stride);
565 }
566 #endif
567
568 txh->width = pt->image.width;
569 txh->height = pt->image.height;
570 txh->stride = stride;
571 txh->pixelformat = pix_format;
572 txh->data = st->pixels;
573
574 gf_sc_texture_set_data(txh);
575 }
576
compositor_init_pixeltexture(GF_Compositor * compositor,GF_Node * node)577 void compositor_init_pixeltexture(GF_Compositor *compositor, GF_Node *node)
578 {
579 PixelTextureStack *st;
580 GF_SAFEALLOC(st, PixelTextureStack);
581 if (!st) {
582 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate pixel texture stack\n"));
583 return;
584 }
585 gf_sc_texture_setup(&st->txh, compositor, node);
586 st->pixels = NULL;
587 st->txh.update_texture_fcnt = pixeltexture_update;
588
589 gf_node_set_private(node, st);
590 gf_node_set_callback_function(node, pixeltexture_destroy);
591 st->txh.flags = 0;
592 if (((M_PixelTexture*)node)->repeatS) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
593 if (((M_PixelTexture*)node)->repeatT) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
594 }
595
pt_get_texture(GF_Node * node)596 GF_TextureHandler *pt_get_texture(GF_Node *node)
597 {
598 PixelTextureStack *st = (PixelTextureStack *) gf_node_get_private(node);
599 return &st->txh;
600 }
601
matte_update(GF_TextureHandler * txh)602 static void matte_update(GF_TextureHandler *txh)
603 {
604 /*nothing to do*/
605 }
606
compositor_init_mattetexture(GF_Compositor * compositor,GF_Node * node)607 void compositor_init_mattetexture(GF_Compositor *compositor, GF_Node *node)
608 {
609 GF_TextureHandler *txh;
610 GF_SAFEALLOC(txh, GF_TextureHandler);
611 if (!txh) {
612 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate matte texture stack\n"));
613 return;
614 }
615 gf_sc_texture_setup(txh, compositor, node);
616 txh->flags = GF_SR_TEXTURE_MATTE;
617 txh->update_texture_fcnt = matte_update;
618 gf_node_set_private(node, txh);
619 gf_node_set_callback_function(node, imagetexture_destroy);
620 }
621
gf_sc_mo_destroyed(GF_Node * n)622 void gf_sc_mo_destroyed(GF_Node *n)
623 {
624 void *st = gf_node_get_private(n);
625 if (!st) return;
626
627 switch (gf_node_get_tag(n)) {
628 case TAG_MPEG4_Background2D:
629 ((Background2DStack *)st)->txh.stream = NULL;
630 break;
631 case TAG_MPEG4_Background:
632 case TAG_X3D_Background:
633 #ifndef GPAC_DISABLE_3D
634 ((BackgroundStack *)st)->txh_back.stream = NULL;
635 ((BackgroundStack *)st)->txh_front.stream = NULL;
636 ((BackgroundStack *)st)->txh_left.stream = NULL;
637 ((BackgroundStack *)st)->txh_right.stream = NULL;
638 ((BackgroundStack *)st)->txh_top.stream = NULL;
639 ((BackgroundStack *)st)->txh_bottom.stream = NULL;
640 #endif
641 break;
642 case TAG_MPEG4_ImageTexture:
643 case TAG_X3D_ImageTexture:
644 ((GF_TextureHandler *)st)->stream = NULL;
645 break;
646 case TAG_MPEG4_MovieTexture:
647 case TAG_X3D_MovieTexture:
648 ((MovieTextureStack *)st)->txh.stream = NULL;
649 break;
650 case TAG_MPEG4_MediaSensor:
651 ((MediaSensorStack *)st)->stream = NULL;
652 break;
653 case TAG_MPEG4_MediaControl:
654 ((MediaControlStack *)st)->stream = NULL;
655 break;
656 case TAG_MPEG4_AudioSource:
657 ((AudioSourceStack *)st)->input.stream = NULL;
658 break;
659 case TAG_MPEG4_AudioClip:
660 case TAG_X3D_AudioClip:
661 ((AudioClipStack *)st)->input.stream = NULL;
662 break;
663 #ifndef GPAC_DISABLE_SVG
664 case TAG_SVG_video:
665 case TAG_SVG_image:
666 ((SVG_video_stack *)st)->txh.stream = NULL;
667 break;
668 case TAG_SVG_audio:
669 ((SVG_audio_stack *)st)->input.stream = NULL;
670 break;
671 #endif
672 default:
673 break;
674 }
675 }
676
677 #ifdef __cplusplus
678 }
679 #endif
680 #endif /*GPAC_DISABLE_VRML*/
681