Ejemplo n.º 1
0
GF_EXPORT
void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
{
	u32 size, ts;

	/*already refreshed*/
	if (txh->needs_refresh) return;

	if (!txh->stream) {
		txh->data = NULL;
		return;
	}

	/*should never happen!!*/
	if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);

	/*check init flag*/
	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		/*if we had a texture this means the object has changed - delete texture and force next frame 
		composition (this will take care of OD reuse)*/
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
			txh->data = NULL;
			txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
			return;
		}
		if (gf_mo_is_private_media(txh->stream)) {
			setup_texture_object(txh, 1);
			gf_node_dirty_set(txh->owner, 0, 0);
		}
	}
	txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size);

	/*if no frame or muted don't draw*/
	if (!txh->data || !size) {
		/*TODO - check if this is needed */
		if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
			//txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
		}
		return;
	}

	/*if setup and same frame return*/
	if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) {
		gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
		txh->needs_release = 0;
		return;
	}
	txh->needs_release = 1; 
	txh->last_frame_time = ts;
	if (gf_mo_is_muted(txh->stream)) return;

	if (!txh->tx_io) {
		setup_texture_object(txh, 0);
	}

	/*try to push texture on graphics but don't complain if failure*/
	gf_sc_texture_set_data(txh);

	txh->needs_refresh = 1;
	gf_sc_invalidate(txh->compositor, NULL);
}
Ejemplo n.º 2
0
GF_EXPORT
void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
{
	Bool needs_reload = 0;
	u32 size, ts;
	s32 ms_until_pres, ms_until_next;

	/*already refreshed*/
	if (txh->needs_refresh) return;

	if (!txh->stream) {
		txh->data = NULL;
		return;
	}

	/*should never happen!!*/
	if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);

	/*check init flag*/
	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		needs_reload = 1;
		txh->data = NULL;
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
		}
	}
	txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size, &ms_until_pres, &ms_until_next);

	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		needs_reload = 1;
	} else if (size && txh->size && (size != txh->size)) {
		needs_reload = 1;
	}

	if (needs_reload) {
		/*if we had a texture this means the object has changed - delete texture and resetup. Do not skip
		texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
			txh->needs_refresh = 1;
		}
		if (gf_mo_is_private_media(txh->stream)) {
			setup_texture_object(txh, 1);
			gf_node_dirty_set(txh->owner, 0, 0);
		}
	}

	/*if no frame or muted don't draw*/
	if (!txh->data || !size) {
		GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("|Visual Texture] No output frame available \n"));
		/*TODO - check if this is needed */
		if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
			//txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
		}
		return;
	}

	/*if setup and same frame return*/
	if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) {
		gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
		txh->needs_release = 0;
		if (!txh->stream_finished) {
			if (ms_until_next>0 && (txh->compositor->next_frame_delay > (u32) ms_until_next))
				txh->compositor->next_frame_delay = ms_until_next;
		}
		return;
	}
	txh->needs_release = 1;
	txh->last_frame_time = ts;
	txh->size = size;
	if (txh->raw_memory) {
		gf_mo_get_raw_image_planes(txh->stream, (u8 **) &txh->data, (u8 **) &txh->pU, (u8 **) &txh->pV);
	}
	if (gf_mo_is_muted(txh->stream)) return;


	if (txh->nb_frames) {
		s32 push_delay = txh->upload_time / txh->nb_frames;
		if (push_delay > ms_until_pres) ms_until_pres = 0;
		else ms_until_pres -= push_delay;
	}

	if (txh->compositor->frame_delay < ms_until_pres)
		txh->compositor->frame_delay = ms_until_pres;

	txh->compositor->next_frame_delay = 1;

	if (!txh->tx_io) {
		setup_texture_object(txh, 0);
	}

	/*try to push texture on graphics but don't complain if failure*/
	gf_sc_texture_set_data(txh);

	txh->needs_refresh = 1;
	gf_sc_invalidate(txh->compositor, NULL);
}
Ejemplo n.º 3
0
static void pixeltexture_update(GF_TextureHandler *txh)
{
	u32 pix_format, stride, i;
	M_PixelTexture *pt = (M_PixelTexture *) txh->owner;
	PixelTextureStack *st = (PixelTextureStack *) gf_node_get_private(txh->owner);

	if (!gf_node_dirty_get(txh->owner)) return;
	gf_node_dirty_clear(txh->owner, 0);


	/*pixel texture doesn not use any media object but has data in the content.
	However we still use the same texture object, just be carefull not to use media funtcions*/
	txh->transparent = 0;
	stride = pt->image.width;
	/*num_components are as in VRML (1->4) not as in BIFS bitstream (0->3)*/
	switch (pt->image.numComponents) {
	case 1:
		pix_format = GF_PIXEL_GREYSCALE;
		break;
	case 2:
		pix_format = GF_PIXEL_ALPHAGREY;
		txh->transparent = 1;
		stride *= 2;
		break;
	case 3:
		pix_format = GF_PIXEL_RGB_24;
		txh->transparent = 0;
		stride *= 3;
		break;
	case 4:
		pix_format = GF_PIXEL_RGBA;
		txh->transparent = 1;
		stride *= 4;
		break;
	default:
		return;
	}

	if (!txh->tx_io) {
		gf_sc_texture_allocate(txh);
		if (!txh->tx_io) return;
	}

	if (st->pixels) gf_free(st->pixels);
	st->pixels = (char*)gf_malloc(sizeof(char) * stride * pt->image.height);
	/*FIXME FOR OPENGL !!*/
	if (0) {
		for (i=0; i<pt->image.height; i++) {
			memcpy(st->pixels + i * stride, pt->image.pixels + i * stride, stride);
		}
	}
	/*revert pixel ordering...*/
	else {
		for (i=0; i<pt->image.height; i++) {
			memcpy(st->pixels + i * stride, pt->image.pixels + (pt->image.height - 1 - i) * stride, stride);
		}
	}

	txh->width = pt->image.width;
	txh->height = pt->image.height;
	txh->stride = stride;
	txh->pixelformat = pix_format;
	txh->data = st->pixels;

	gf_sc_texture_set_data(txh);
}
Ejemplo n.º 4
0
static void imagetexture_update(GF_TextureHandler *txh)
{
	if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) {
		MFURL url = ((M_ImageTexture *) txh->owner)->url;

		/*setup texture if needed*/
		if (!txh->is_open && url.count) {
			gf_sc_texture_play(txh, &url);
		}
		gf_sc_texture_update_frame(txh, 0);

		if (
		    /*URL is present but not opened - redraw till fetch*/
		    /* (txh->stream && !txh->tx_io) && */
		    /*image has been updated*/
		    txh->needs_refresh) {
			/*mark all subtrees using this image as dirty*/
			gf_node_dirty_parents(txh->owner);
			gf_sc_invalidate(txh->compositor, NULL);
		}
		return;
	}
	/*cache texture case*/
	else {
		M_CacheTexture *ct = (M_CacheTexture *) txh->owner;

		/*decode cacheTexture data */
		if ((ct->data || ct->image.buffer) && !txh->data) {
#ifndef GPAC_DISABLE_AV_PARSERS
			u32 out_size;
			GF_Err e;

			/*BT/XMT playback: load to memory*/
			if (ct->image.buffer) {
				char *par = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) );
				char *src_url = gf_url_concatenate(par, ct->image.buffer);
				FILE *test = gf_fopen( src_url ? src_url : ct->image.buffer, "rb");
				if (test) {
					fseek(test, 0, SEEK_END);
					ct->data_len = (u32) gf_ftell(test);
					ct->data = gf_malloc(sizeof(char)*ct->data_len);
					fseek(test, 0, SEEK_SET);
					if (ct->data_len != fread(ct->data, 1, ct->data_len, test)) {
						GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: IO err\n", src_url ? src_url : ct->image.buffer ) );
						gf_free(ct->data);
						ct->data = NULL;
						ct->data_len = 0;
					}
					gf_fclose(test);
				} else {
					GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: not found\n", src_url ? src_url : ct->image.buffer ) );
				}
				ct->image.buffer = NULL;
				if (src_url) gf_free(src_url);
			}

			/*BIFS decoded playback*/
			switch (ct->objectTypeIndication) {
			case GPAC_OTI_IMAGE_JPEG:
				out_size = 0;
				e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3);
				if (e==GF_BUFFER_TOO_SMALL) {
					u32 BPP;
					txh->data = gf_malloc(sizeof(char) * out_size);
					if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1;
					else BPP = 3;

					e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP);
					if (e==GF_OK) {
						gf_sc_texture_allocate(txh);
						gf_sc_texture_set_data(txh);
						txh->needs_refresh = 1;
						txh->stride = out_size / txh->height;
					}
				}
				break;
			case GPAC_OTI_IMAGE_PNG:
				out_size = 0;
				e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size);
				if (e==GF_BUFFER_TOO_SMALL) {
					txh->data = gf_malloc(sizeof(char) * out_size);
					e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size);
					if (e==GF_OK) {
						gf_sc_texture_allocate(txh);
						gf_sc_texture_set_data(txh);
						txh->needs_refresh = 1;
						txh->stride = out_size / txh->height;
					}
				}
				break;
			}

#endif // GPAC_DISABLE_AV_PARSERS

			/*cacheURL is specified, store the image*/
			if (ct->cacheURL.buffer) {
				u32 i;
				u8 hash[20];
				FILE *cached_texture;
				char szExtractName[GF_MAX_PATH], section[64], *opt, *src_url;
				opt = (char *) gf_cfg_get_key(txh->compositor->user->config, "General", "CacheDirectory");
				if (opt) {
					strcpy(szExtractName, opt);
				} else {
					opt = gf_get_default_cache_directory();
					strcpy(szExtractName, opt);
					gf_free(opt);
				}
				strcat(szExtractName, "/");
				src_url = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) );

				gf_sha1_csum((u8 *)src_url, (u32) strlen(src_url), hash);
				for (i=0; i<20; i++) {
					char t[3];
					t[2] = 0;
					sprintf(t, "%02X", hash[i]);
					strcat(szExtractName, t);
				}
				strcat(szExtractName, "_");

				strcat(szExtractName, ct->cacheURL.buffer);
				cached_texture = gf_fopen(szExtractName, "wb");
				if (cached_texture) {
					gf_fwrite(ct->data, 1, ct->data_len, cached_texture);
					gf_fclose(cached_texture);
				}

				/*and write cache info*/
				if (ct->expirationDate!=0) {
					sprintf(section, "@cache=%p", ct);
					gf_cfg_set_key(txh->compositor->user->config, section, "serviceURL", src_url);
					gf_cfg_set_key(txh->compositor->user->config, section, "cacheFile", szExtractName);
					gf_cfg_set_key(txh->compositor->user->config, section, "cacheName", ct->cacheURL.buffer);

					if (ct->expirationDate>0) {
						char exp[50];
						u32 sec, frac;
						gf_net_get_ntp(&sec, &frac);
						sec += ct->expirationDate;
						sprintf(exp, "%u", sec);
						gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", exp);
					} else {
						gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", "0");
					}
				}
			}

			/*done with image, destroy buffer*/
			if (ct->data) gf_free(ct->data);
			ct->data = NULL;
			ct->data_len = 0;
		}
	}
}
Ejemplo n.º 5
0
GF_EXPORT
void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
{
	u32 size, ts;

	/*already refreshed*/
	if (txh->needs_refresh) return;

	if (!txh->stream) {
		txh->data = NULL;
		return;
	}

	/*should never happen!!*/
	if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);

	/*check init flag*/
	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		/*if we had a texture this means the object has changed - delete texture and resetup. Do not skip
		texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
			txh->data = NULL;
			txh->needs_refresh = 1;
		}
		if (gf_mo_is_private_media(txh->stream)) {
			setup_texture_object(txh, 1);
			gf_node_dirty_set(txh->owner, 0, 0);
		}
	}
	txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size);

	/*if no frame or muted don't draw*/
	if (!txh->data || !size) {
		GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("No output frame available\n"));
		/*TODO - check if this is needed */
		if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
			//txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
		}
		return;
	}

	/*if setup and same frame return*/
	if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) {
		gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
		txh->needs_release = 0;
		return;
	}
	txh->needs_release = 1;
	txh->last_frame_time = ts;
	if (gf_mo_is_muted(txh->stream)) return;

	if (!txh->tx_io) {
		setup_texture_object(txh, 0);
	}

	/*try to push texture on graphics but don't complain if failure*/
	gf_sc_texture_set_data(txh);

	txh->needs_refresh = 1;
	gf_sc_invalidate(txh->compositor, NULL);
}
Ejemplo n.º 6
0
/*
	This is a crude draft implementation of filter. The main drawback is that we don't cache any data.
	We should be able to check for changes in the sub-group or in the filter
*/
void svg_draw_filter(GF_Node *filter, GF_Node *node, GF_TraverseState *tr_state)
{
	GF_IRect rc1, rc2;

#ifndef GPAC_DISABLE_3D
	u32 type_3d;
#endif
	u32 prev_flags;
	GF_IRect txrc;
	Fixed scale_x, scale_y, temp_x, temp_y;
	DrawableContext *ctx, *child_ctx;
	GF_SURFACE offscreen_surface, old_surf;
	GF_Rect bounds, local_bounds, rc;
	GF_Matrix2D backup;
	SVGAllAttributes all_atts;
	GF_FilterStack *st = gf_node_get_private(filter);
	assert(tr_state->traversing_mode==TRAVERSE_SORT);

	/*store the current transform matrix, create a new one for group_cache*/
	gf_mx2d_copy(backup, tr_state->transform);
	gf_mx2d_init(tr_state->transform);

	gf_node_allow_cyclic_traverse(node);
	tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
	tr_state->bounds.width = tr_state->bounds.height = 0;
	gf_node_traverse(node, tr_state);

	local_bounds = bounds = tr_state->bounds;
	/*compute bounds in final coordinate system - this ensures that the cache has the correct anti aliasing*/
	gf_mx2d_apply_rect(&backup, &bounds);
	txrc = gf_rect_pixelize(&bounds);
	if (txrc.width%2) txrc.width++;
	if (txrc.height%2) txrc.height++;
	bounds = gf_rect_ft(&txrc);

	tr_state->traversing_mode = TRAVERSE_SORT;

	gf_mx2d_copy(tr_state->transform, backup);

	if (!bounds.width || !bounds.height) {
		return;
	}

	/*create a context */
	ctx = drawable_init_context_svg(st->drawable, tr_state);
	if (!ctx) return;

	/*setup texture */
	st->txh.height = txrc.height;
	st->txh.width = txrc.width;

	st->txh.stride = txrc.width * 4;
	st->txh.pixelformat = GF_PIXEL_ARGB;
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) st->txh.pixelformat = GF_PIXEL_RGBA;
#endif
	st->txh.transparent = 1;

	if (st->txh.stride * st->txh.height > st->alloc_size) {
		st->alloc_size = st->txh.stride * st->txh.height;
		st->data = (u8*)gf_realloc(st->data, sizeof(u8) * st->alloc_size);
	}
	memset(st->data, 0x0, sizeof(char) * st->txh.stride * st->txh.height);
	st->txh.data = (char *) st->data;
	/*setup geometry (rectangle matching the bounds of the object)
	Warning, we want to center the cached bitmap at the center of the screen (main visual)*/
	gf_path_reset(st->drawable->path);

	gf_path_add_rect_center(st->drawable->path,
	                        bounds.x + bounds.width/2,
	                        bounds.y - bounds.height/2,
	                        bounds.width,
	                        bounds.height);


	old_surf = tr_state->visual->raster_surface;
	offscreen_surface = tr_state->visual->compositor->rasterizer->surface_new(tr_state->visual->compositor->rasterizer, tr_state->visual->center_coords);
	tr_state->visual->raster_surface = offscreen_surface;

	gf_mx2d_copy(backup, tr_state->transform);
	gf_mx2d_init(tr_state->transform);

	/*attach the buffer to visual*/
	tr_state->visual->compositor->rasterizer->surface_attach_to_buffer(offscreen_surface, st->txh.data,
	        st->txh.width,
	        st->txh.height,
	        0,
	        st->txh.stride,
	        st->txh.pixelformat);

	prev_flags = tr_state->immediate_draw;
	tr_state->immediate_draw = 1;
	tr_state->traversing_mode = TRAVERSE_SORT;
	tr_state->in_svg_filter = 1;

	/*recompute the bounds with the final scaling used*/
	scale_x = gf_divfix(bounds.width, local_bounds.width);
	scale_y = gf_divfix(bounds.height, local_bounds.height);
	gf_mx2d_init(tr_state->transform);
	gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y);

	rc = local_bounds;
	gf_mx2d_apply_rect(&tr_state->transform, &rc);

	/*centered the bitmap on the visual*/
	if (tr_state->visual->center_coords) {
		temp_x = -rc.x - rc.width/2;
		temp_y = rc.height/2 - rc.y;
	} else {
		temp_x = -rc.x;
		temp_y = rc.height - rc.y;
	}
	gf_mx2d_add_translation(&tr_state->transform, temp_x, temp_y);


	rc1 = tr_state->visual->surf_rect;
	rc2 = tr_state->visual->top_clipper;
	tr_state->visual->surf_rect.width = st->txh.width;
	tr_state->visual->surf_rect.height = st->txh.height;
	if (tr_state->visual->center_coords) {
		tr_state->visual->surf_rect.y = st->txh.height/2;
		tr_state->visual->surf_rect.x = -1 * (s32) st->txh.width/2;
	} else {
		tr_state->visual->surf_rect.y = st->txh.height;
		tr_state->visual->surf_rect.x = 0;
	}
	tr_state->visual->top_clipper = tr_state->visual->surf_rect;


#ifndef GPAC_DISABLE_3D
	type_3d = tr_state->visual->type_3d;
	tr_state->visual->type_3d=0;
#endif

	if (prev_flags) gf_node_allow_cyclic_traverse(node);
	gf_node_traverse(node, tr_state);

	child_ctx = ctx->next;
	while (child_ctx && child_ctx->drawable) {
		drawable_reset_bounds(child_ctx->drawable, tr_state->visual);
		child_ctx->drawable = NULL;
		child_ctx = child_ctx->next;
	}
	tr_state->visual->cur_context = ctx;


	/*restore state and destroy whatever needs to be cleaned*/
	tr_state->in_svg_filter = 0;
	tr_state->immediate_draw = prev_flags;
	tr_state->visual->compositor->rasterizer->surface_delete(offscreen_surface);
	tr_state->visual->raster_surface = old_surf;
	tr_state->traversing_mode = TRAVERSE_SORT;
	tr_state->visual->surf_rect = rc1;
	tr_state->visual->top_clipper = rc2;
#ifndef GPAC_DISABLE_3D
	tr_state->visual->type_3d = type_3d ;
#endif

	/*update texture*/
	st->txh.transparent = 1;
	st->txh.flags |= GF_SR_TEXTURE_NO_GL_FLIP;
	gf_sc_texture_set_data(&st->txh);
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d)
		gf_sc_texture_push_image(&st->txh, 0, 0);
	else
#endif
		gf_sc_texture_push_image(&st->txh, 0, 1);

	ctx->flags |= CTX_NO_ANTIALIAS;
	ctx->aspect.fill_color = 0;
	ctx->aspect.line_color = 0xFF000000;
	ctx->aspect.fill_texture = &st->txh;
	ctx->flags |= CTX_TEXTURE_DIRTY;

	/*get the filter region*/
	bounds = local_bounds;
	gf_svg_flatten_attributes((SVG_Element *)filter, &all_atts);
	if (!all_atts.filterUnits || (*all_atts.filterUnits==SVG_GRADIENTUNITS_OBJECT)) {
		Fixed v;
		v = all_atts.x ? all_atts.x->value : INT2FIX(-10);
		bounds.x += gf_mulfix(v, bounds.width);
		v = all_atts.y ? all_atts.y->value : INT2FIX(-10);
		bounds.y += gf_mulfix(v, bounds.height);
		v = all_atts.width ? all_atts.width->value : INT2FIX(120);
		bounds.width = gf_mulfix(v, bounds.width);
		v = all_atts.height ? all_atts.height->value : INT2FIX(120);
		bounds.height = gf_mulfix(v, bounds.height);
	} else {
		bounds.x = all_atts.x ? all_atts.x->value : 0;
		bounds.y = all_atts.y ? all_atts.y->value : 0;
		bounds.width = all_atts.width ? all_atts.x->value : bounds.width;
		bounds.height = all_atts.x ? all_atts.x->value : 120;
	}
	gf_mx2d_apply_rect(&backup, &bounds);

	svg_filter_apply(filter, &st->txh, &bounds);


#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		if (!st->drawable->mesh) {
			st->drawable->mesh = new_mesh();
			mesh_from_path(st->drawable->mesh, st->drawable->path);
		}
		visual_3d_draw_from_context(tr_state->ctx, tr_state);
		ctx->drawable = NULL;
		return;
	}
#endif

	/*we computed the texture in final screen coordinate, so use the identity matrix for the context*/
	gf_mx2d_init(tr_state->transform);
	drawable_finalize_sort(ctx, tr_state, NULL);
	gf_mx2d_copy(tr_state->transform, backup);
}
Ejemplo n.º 7
0
Bool group_cache_traverse(GF_Node *node, GroupCache *cache, GF_TraverseState *tr_state, Bool force_recompute, Bool is_mpeg4, Bool auto_fit_vp)
{
	GF_Matrix2D backup;
	DrawableContext *group_ctx = NULL;
	GF_ChildNodeItem *l;

	if (!cache) return 0;

	/*do we need to recompute the cache*/
	if (cache->force_recompute) {
		force_recompute = 1;
		cache->force_recompute = 0;
	}
	else if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) {
		force_recompute = 1;
	}

	/*we need to redraw the group in an offscreen visual*/
	if (force_recompute) {
		GF_Matrix2D backup;
		GF_IRect rc1, rc2;
		u32 type_3d;
		u32 prev_flags;
		GF_Rect cache_bounds;
		GF_SURFACE offscreen_surface, old_surf;
		GF_Raster2D *r2d = tr_state->visual->compositor->rasterizer;
		DrawableContext *child_ctx;
		Fixed temp_x, temp_y, scale_x, scale_y;

		GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Recomputing cache for subtree %s\n", gf_node_get_log_name(node)));
		/*step 1 : store current state and indicate children should not be cached*/
		tr_state->in_group_cache = 1;
		prev_flags = tr_state->immediate_draw;
		/*store the current transform matrix, create a new one for group_cache*/
		gf_mx2d_copy(backup, tr_state->transform);
		gf_mx2d_init(tr_state->transform);

		type_3d = 0;
#ifndef GPAC_DISABLE_3D
		/*force 2D rendering*/
		type_3d = tr_state->visual->type_3d;
		tr_state->visual->type_3d = 0;
#endif

		/*step 2: collect the bounds of all children*/
		tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
		cache_bounds.width = cache_bounds.height = 0;
		l = ((GF_ParentNode*)node)->children;
		while (l) {
			tr_state->bounds.width = tr_state->bounds.height = 0;
			gf_node_traverse(l->node, tr_state);
			l = l->next;
			gf_rect_union(&cache_bounds, &tr_state->bounds);
		}
		tr_state->traversing_mode = TRAVERSE_SORT;

		if (!cache_bounds.width || !cache_bounds.height) {
			tr_state->in_group_cache = 0;
			tr_state->immediate_draw = prev_flags;
			gf_mx2d_copy(tr_state->transform, backup);
#ifndef GPAC_DISABLE_3D
			tr_state->visual->type_3d = type_3d;
#endif
			return 0;
		}

		/*step 3: insert a DrawableContext for this group in the display list*/
		if (is_mpeg4) {
#ifndef GPAC_DISABLE_VRML
			group_ctx = drawable_init_context_mpeg4(cache->drawable, tr_state);
#endif
		} else {
#ifndef GPAC_DISABLE_SVG
			group_ctx = drawable_init_context_svg(cache->drawable, tr_state);
#endif
		}
		if (!group_ctx) return 0;

		/*step 4: now we have the bounds:
			allocate the offscreen memory
			create temp raster visual & attach to buffer
			override the tr_state->visual->the_surface with the temp raster
			add translation (shape is not always centered)
			setup top clipers
		*/
		old_surf = tr_state->visual->raster_surface;
		offscreen_surface = r2d->surface_new(r2d, tr_state->visual->center_coords);	/*a new temp raster visual*/
		tr_state->visual->raster_surface = offscreen_surface;

		/*use current surface coordinate scaling to compute the cache*/
#ifdef GF_SR_USE_VIDEO_CACHE
		scale_x = tr_state->visual->compositor->cache_scale * backup.m[0] / 100;
		scale_y = tr_state->visual->compositor->cache_scale * backup.m[4] / 100;
#else
		scale_x = backup.m[0];
		scale_y = backup.m[4];
#endif

		if (scale_x<0) scale_x = -scale_x;
		if (scale_y<0) scale_y = -scale_y;

		cache->scale = MAX(scale_x, scale_y);
		tr_state->bounds = cache_bounds;
		gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y);
		gf_mx2d_apply_rect(&tr_state->transform, &cache_bounds);

		rc1 = gf_rect_pixelize(&cache_bounds);
		if (rc1.width % 2) rc1.width++;
		if (rc1.height%2) rc1.height++;

		/* Initialize the group cache with the scaled pixelized bounds for texture but the original bounds for path*/
		group_cache_setup(cache, &tr_state->bounds, &rc1, tr_state->visual->compositor, type_3d);


		/*attach the buffer to visual*/
		r2d->surface_attach_to_buffer(offscreen_surface, cache->txh.data,
										cache->txh.width,
										cache->txh.height,
										0,
										cache->txh.stride,
										cache->txh.pixelformat);


		/*recompute the bounds with the final scaling used*/
		scale_x = gf_divfix(INT2FIX(rc1.width), tr_state->bounds.width);
		scale_y = gf_divfix(INT2FIX(rc1.height), tr_state->bounds.height);
		gf_mx2d_init(tr_state->transform);
		gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y);
		cache_bounds = tr_state->bounds;
		gf_mx2d_apply_rect(&tr_state->transform, &cache_bounds);

		/*centered the bitmap on the visual*/
		temp_x = -cache_bounds.x;
		temp_y = -cache_bounds.y;
		if (tr_state->visual->center_coords) {
			temp_x -= cache_bounds.width/2;
			temp_y += cache_bounds.height/2;
		} else {
			temp_y += cache_bounds.height;
		}
		gf_mx2d_add_translation(&tr_state->transform, temp_x, temp_y);

		/*override top clippers*/
		rc1 = tr_state->visual->surf_rect;
		rc2 = tr_state->visual->top_clipper;
		tr_state->visual->surf_rect.width = cache->txh.width;
		tr_state->visual->surf_rect.height = cache->txh.height;
		if (tr_state->visual->center_coords) {
			tr_state->visual->surf_rect.y = cache->txh.height/2;
			tr_state->visual->surf_rect.x = -1 * (s32) cache->txh.width/2;
		} else {
			tr_state->visual->surf_rect.y = cache->txh.height;
			tr_state->visual->surf_rect.x = 0;
		}
		tr_state->visual->top_clipper = tr_state->visual->surf_rect;


		/*step 5: traverse subtree in direct draw mode*/
		tr_state->immediate_draw = 1;
		group_ctx->flags &= ~CTX_NO_ANTIALIAS;

		l = ((GF_ParentNode*)node)->children;
		while (l) {
			gf_node_traverse(l->node, tr_state);
			l = l->next;
		}
		/*step 6: reset all contexts after the current group one*/
		child_ctx = group_ctx->next;
		while (child_ctx && child_ctx->drawable) {
			drawable_reset_bounds(child_ctx->drawable, tr_state->visual);
			child_ctx->drawable = NULL;
			child_ctx = child_ctx->next;
		}

		/*and set ourselves as the last context on the main visual*/
		tr_state->visual->cur_context = group_ctx;

		/*restore state and destroy whatever needs to be cleaned*/
		gf_mx2d_copy(tr_state->transform, backup);
		tr_state->in_group_cache = 0;
		tr_state->immediate_draw = prev_flags;
		r2d->surface_delete(offscreen_surface);
		tr_state->visual->raster_surface = old_surf;
		tr_state->traversing_mode = TRAVERSE_SORT;

#ifndef GPAC_DISABLE_3D
		tr_state->visual->type_3d = type_3d;
#endif
		tr_state->visual->surf_rect = rc1;
		tr_state->visual->top_clipper = rc2;

		/*update texture*/
		cache->txh.transparent = 1;
		cache->txh.flags |= GF_SR_TEXTURE_NO_GL_FLIP;
		gf_sc_texture_set_data(&cache->txh);
		gf_sc_texture_push_image(&cache->txh, 0, type_3d ? 0 : 1);

		cache->orig_vp = tr_state->vp_size;
	}
	/*just setup the context*/
	else {
		if (is_mpeg4) {
#ifndef GPAC_DISABLE_VRML
			group_ctx = drawable_init_context_mpeg4(cache->drawable, tr_state);
#endif
		} else {
#ifndef GPAC_DISABLE_SVG
			group_ctx = drawable_init_context_svg(cache->drawable, tr_state);
#endif
		}
	}
	if (!group_ctx) return 0;
	group_ctx->flags |= CTX_NO_ANTIALIAS;
	if (cache->opacity != FIX_ONE)
		group_ctx->aspect.fill_color = GF_COL_ARGB_FIXED(cache->opacity, FIX_ONE, FIX_ONE, FIX_ONE);
	else
		group_ctx->aspect.fill_color = 0;
	group_ctx->aspect.fill_texture = &cache->txh;

	if (!cache->opacity) {
		group_ctx->drawable = NULL;
		return 0;
	}

	if (gf_node_dirty_get(node)) group_ctx->flags |= CTX_TEXTURE_DIRTY;

#ifdef CACHE_DEBUG_CENTER
	gf_mx2d_copy(backup, tr_state->transform);
	gf_mx2d_init(tr_state->transform);
#else
	gf_mx2d_copy(backup, tr_state->transform);
	if (auto_fit_vp) {
		if ((tr_state->vp_size.x != cache->orig_vp.x) || (tr_state->vp_size.y != cache->orig_vp.y)) {
			GF_Matrix2D m;
			gf_mx2d_init(m);
			gf_mx2d_copy(backup, tr_state->transform);
			gf_mx2d_add_scale(&m, gf_divfix(tr_state->vp_size.x, cache->orig_vp.x), gf_divfix(tr_state->vp_size.y, cache->orig_vp.y) );
			gf_mx2d_pre_multiply(&tr_state->transform, &m);
		} else {
			auto_fit_vp = 0;
		}
	}
#endif

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		if (!cache->drawable->mesh) {
			cache->drawable->mesh = new_mesh();
			mesh_from_path(cache->drawable->mesh, cache->drawable->path);
		}
		visual_3d_draw_from_context(group_ctx, tr_state);
		group_ctx->drawable = NULL;
	} else
#endif
		drawable_finalize_sort(group_ctx, tr_state, NULL);

#ifndef CACHE_DEBUG_CENTER
	if (auto_fit_vp)
#endif
	{
		gf_mx2d_copy(tr_state->transform, backup);
	}
	return (force_recompute==1);
}