<commit_before>/*
 *			GPAC - Multimedia Framework C SDK
 *
 *			Copyright (c) <NAME> 2000-2005
 *					All rights reserved
 *
 *  This file is part of GPAC / Scene Compositor sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */



#include "visual_manager.h"
#include "nodes_stacks.h"
#include <gpac/options.h>

#ifdef OPENGL_RASTER
#include "gl_inc.h"
#include "texturing.h"

static void c2d_gl_fill_no_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Color color)
{
#if defined(GPAC_USE_OGL_ES)
	GLfloat line[4];

	line[0] = FIX2FLT(x);
	line[1] = FIX2FLT(y);
	line[2] = FIX2FLT(x+run_h_len);
	line[3] = line[1];

	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), 0xFF);
	glVertexPointer(2, GL_FLOAT, 0, line);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDrawArrays(GL_LINES, 0, 2);
	glDisableClientState(GL_VERTEX_ARRAY);

#else
	glBegin(GL_LINES);
	glColor3ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color));
//	glColor3f(GF_COL_R(color)/255, GF_COL_G(color)/255, GF_COL_B(color)/255);
	glVertex2i(x,y);
	glVertex2i(x+run_h_len,y);
	glEnd();
#endif
}

static void c2d_gl_fill_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Color color, u8 alpha)
{
#if defined(GPAC_USE_OGL_ES)
	GLfloat line[4];

	line[0] = FIX2FLT(x);
	line[1] = FIX2FLT(y);
	line[2] = FIX2FLT(x+run_h_len);
	line[3] = line[1];

	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), (u8) alpha);

	glVertexPointer(2, GL_FLOAT, 0, line);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDrawArrays(GL_LINES, 0, 2);
	glDisableClientState(GL_VERTEX_ARRAY);

	glDisable(GL_BLEND);
#else
	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), (u8) alpha);
	glBegin(GL_LINES);
	glVertex2i(x,y);
	glVertex2i(x+run_h_len,y);
	glEnd();
	glDisable(GL_BLEND);
#endif
}

static void c2d_gl_fill_rect(void *cbk, u32 x, u32 y, u32 width, u32 height, GF_Color color)
{
#if defined(GPAC_USE_OGL_ES)
	GLfloat line[8];

	line[0] = FIX2FLT(x);
	line[1] = FIX2FLT(y);
	line[2] = FIX2FLT(x+width);
	line[3] = FIX2FLT(y);
	line[4] = FIX2FLT(x+width);
	line[5] = FIX2FLT(y+height);
	line[6] = FIX2FLT(x);
	line[7] = FIX2FLT(y+height);

	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), GF_COL_A(color));

	glVertexPointer(4, GL_FLOAT, 0, line);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDrawArrays(GL_TRIANGLE_FAN, 0, 2);
	glDisableClientState(GL_VERTEX_ARRAY);

	glDisable(GL_BLEND);
#else
	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), GF_COL_A(color));
	glBegin(GL_TRIANGLES);
	glVertex2i(x,y);
	glVertex2i(x+width,y);
	glVertex2i(x+width,y+height);
	glEnd();
	glBegin(GL_TRIANGLES);
	glVertex2i(x,y);
	glVertex2i(x+width,y+height);
	glVertex2i(x,y+height);
	glEnd();
	glDisable(GL_BLEND);
#endif
}


Bool c2d_gl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key)
{
	u8 alpha = GF_COL_A(ctx->aspect.fill_color);

	if (ctx->transform.m[1] || ctx->transform.m[3]) return 0;

	visual_3d_set_state(visual, V3D_STATE_LIGHT, 0);
	visual_3d_enable_antialias(visual, 0);
	if (alpha && (alpha != 0xFF)) {
		visual_3d_set_material_2d_argb(visual, ctx->aspect.fill_color);
		gf_sc_texture_set_blend_mode(ctx->aspect.fill_texture, TX_MODULATE);
	} else if (gf_sc_texture_is_transparent(ctx->aspect.fill_texture)) {
		gf_sc_texture_set_blend_mode(ctx->aspect.fill_texture, TX_REPLACE);
	} else {
		visual_3d_set_state(visual, V3D_STATE_BLEND, 0);
	}
	/*ignore texture transform for bitmap*/
	tr_state->mesh_num_textures = gf_sc_texture_enable(ctx->aspect.fill_texture, tr_state->appear ? ((M_Appearance *)tr_state->appear)->textureTransform : NULL);
	if (tr_state->mesh_num_textures) {
		SFVec2f size, orig;
		GF_Mesh *mesh;
		size.x = ctx->bi->unclip.width;
		size.y = ctx->bi->unclip.height;
		orig.x = ctx->bi->unclip.x + INT2FIX(visual->compositor->vp_width)/2;
		orig.y = INT2FIX(visual->compositor->vp_height)/2 - ctx->bi->unclip.y + ctx->bi->unclip.height;

		mesh = new_mesh();
		mesh_new_rectangle(mesh, size, &orig, 1);
		visual_3d_mesh_paint(tr_state, mesh);
		mesh_free(mesh);
		gf_sc_texture_disable(ctx->aspect.fill_texture);
		tr_state->mesh_num_textures = 0;
		return 1;
	}
	return 0;
}
#endif

GF_Err compositor_2d_get_video_access(GF_VisualManager *visual)
{
	GF_Err e;
	GF_Compositor *compositor = visual->compositor;


	if (!visual->raster_surface) return GF_BAD_PARAM;

#ifdef OPENGL_RASTER
	if (compositor->opengl_raster && compositor->rasterizer->surface_attach_to_callbacks) {
		GF_RasterCallback callbacks;
		callbacks.cbk = visual;
		callbacks.fill_run_alpha = c2d_gl_fill_alpha;
		callbacks.fill_run_no_alpha = c2d_gl_fill_no_alpha;
		callbacks.fill_rect = c2d_gl_fill_rect;

		visual->DrawBitmap = c2d_gl_draw_bitmap;

		e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &callbacks, compositor->vp_width, compositor->vp_height);
		if (e==GF_OK) {
			GF_Matrix mx;
			Fixed hh, hw;
			visual->is_attached = 2;

			visual_3d_setup(visual);
			glClear(GL_DEPTH_BUFFER_BIT);
			glViewport(0, 0, compositor->vp_width, compositor->vp_height);

			glClear(GL_COLOR_BUFFER_BIT);

			glLineWidth(1.0f);

#ifndef GPAC_USE_OGL_ES
			glDisable(GL_POLYGON_SMOOTH);
#endif
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);

			glDisable(GL_NORMALIZE);
			glDisable(GL_LINE_SMOOTH);
			glDisable(GL_DEPTH_TEST);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glDepthFunc(GL_LEQUAL);

			hw = INT2FIX(compositor->vp_width)/2;
			hh = INT2FIX(compositor->vp_height)/2;
			gf_mx_ortho(&mx, -hw, hw, -hh, hh, 50, -50);

			visual_3d_set_matrix_mode(visual, V3D_MATRIX_PROJECTION);
			visual_3d_matrix_load(visual, mx.m);

			visual_3d_set_matrix_mode(visual, V3D_MATRIX_MODELVIEW);
			gf_mx_init(mx);
			gf_mx_add_scale(&mx, 1, -1, 1);
			gf_mx_add_translation(&mx, -hw, -hh, 0);
			visual_3d_matrix_load(visual, mx.m);

			return GF_OK;
		}
	}
#endif


	compositor->hw_locked = 0;
	e = GF_IO_ERR;

	/*try from video memory handle (WIN32) if supported*/
	if ((compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_HWND_HDC)
		&& compositor->rasterizer->surface_attach_to_device
		&& compositor->video_out->LockOSContext
		) {
		compositor->hw_context = compositor->video_out->LockOSContext(compositor->video_out, 1);
		if (compositor->hw_context) {
			e = compositor->rasterizer->surface_attach_to_device(visual->raster_surface, compositor->hw_context, compositor->vp_width, compositor->vp_height);
			if (!e) {
				visual->is_attached = 1;
				GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface handle attached to raster\n"));
				return GF_OK;
			}
			compositor->video_out->LockOSContext(compositor->video_out, 0);
			GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface handle to raster: %s\n", gf_error_to_string(e) ));
		}
	}

	if (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_LINE_BLIT) {
		e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &compositor->raster_callbacks, compositor->vp_width, compositor->vp_height);
		if (!e) {
			visual->is_attached = 1;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface callbacks attached to raster\n"));
			return GF_OK;
		}
		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Failed to attach video surface callbacks to raster\n"));
	}

	e = GF_NOT_SUPPORTED;

	if (compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 1)==GF_OK) {
		compositor->hw_locked = 1;

		e = compositor->rasterizer->surface_attach_to_buffer(visual->raster_surface, compositor->hw_surface.video_buffer,
							compositor->hw_surface.width,
							compositor->hw_surface.height,
							compositor->hw_surface.pitch_x,
							compositor->hw_surface.pitch_y,
							(GF_PixelFormat) compositor->hw_surface.pixel_format);
		if (!e) {
			visual->is_attached = 1;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface memory attached to raster - w=%d h=%d pitch_x=%d pitch_y=%d\n", compositor->hw_surface.width, compositor->hw_surface.height, compositor->hw_surface.pitch_x, compositor->hw_surface.pitch_y));
			return GF_OK;
		}
		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface memory to raster: %s\n", gf_error_to_string(e) ));
		compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 0);
	}
	compositor->hw_locked = 0;
	visual->is_attached = 0;
	return e;
}

void compositor_2d_release_video_access(GF_VisualManager *visual)
{
	GF_Compositor *compositor = visual->compositor;
	if (visual->is_attached) {
		compositor->rasterizer->surface_detach(visual->raster_surface);
		visual->is_attached = 0;
	}
	if (compositor->hw_context) {
		compositor->video_out->LockOSContext(compositor->video_out, 0);
		compositor->hw_context = NULL;
	} else if (compositor->hw_locked) {
		compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 0);
		compositor->hw_locked = 0;
	}
}

Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler *txh, GF_IRect *clip, GF_Rect *unclip, GF_Window *src, GF_Window *dst, Bool *disable_blit, Bool *has_scale)
{
	Fixed w_scale, h_scale, tmp;
	u32 output_width, output_height;
	GF_IRect clipped_final = *clip;
	GF_Rect final = *unclip;
	Bool use_blit;

	src->w = src->h = 0;
	dst->w = dst->h = 0;
	if (disable_blit) *disable_blit = 0;
	if (has_scale) *has_scale = 0;

	/*this should never happen but we check for float rounding safety*/
	if (final.width<=0 || final.height <=0) return 0;


	w_scale = final.width / txh->width;
	h_scale = final.height / txh->height;

	if ((w_scale != FIX_ONE) || (h_scale!=FIX_ONE)) {
		if (has_scale) *has_scale = 1;
	}

	if (visual->offscreen) {
		output_width = visual->width;
		output_height = visual->height;
	} else {
		/*use entire video surface for un-centering coord system*/
		output_width = visual->compositor->vp_width;
		output_height = visual->compositor->vp_height;
	}
	/*take care of pixel rounding for odd width/height and make sure we strictly draw in the clipped bounds*/
	if (visual->center_coords) {
		clipped_final.x += output_width / 2;
		final.x += INT2FIX( output_width / 2 );

		clipped_final.y = output_height/ 2 - clipped_final.y;
		final.y = INT2FIX( output_height / 2) - final.y;

	} else {
		final.y -= final.height;
		clipped_final.y -= clipped_final.height;
	}

	/*make sure we lie in the final rect (this is needed for directdraw mode)*/
	if (clipped_final.x<0) {
		clipped_final.width += clipped_final.x;
		clipped_final.x = 0;
		if (clipped_final.width <= 0) return 0;
	}
	if (clipped_final.y<0) {
		clipped_final.height += clipped_final.y;
		clipped_final.y = 0;
		if (clipped_final.height <= 0) return 0;
	}
	if (clipped_final.x + clipped_final.width > (s32) output_width) {
		clipped_final.width = output_width - clipped_final.x;
		clipped_final.x = output_width - clipped_final.width;
	}
	if (clipped_final.y + clipped_final.height > (s32) output_height) {
		clipped_final.height = output_height - clipped_final.y;
		clipped_final.y = output_height - clipped_final.height;
	}
	/*needed in direct drawing since clipping is not performed*/
	if (clipped_final.width<=0 || clipped_final.height <=0)
		return 0;

	if (clipped_final.width-1>= FIX2INT(final.width) ) clipped_final.width = FIX2INT(final.width);
	if (clipped_final.height-1>= FIX2INT(final.height) ) clipped_final.height = FIX2INT(final.height);

	/*set dest window*/
	dst->x = (u32) clipped_final.x;
	dst->y = (u32) clipped_final.y;
	dst->w = (u32) clipped_final.width;
	dst->h = (u32) clipped_final.height;

	if (!dst->w || !dst->h) return 0;

#ifdef GPAC_FIXED_POINT
#define ROUND_FIX(_v)	\
	_v = FIX2INT(tmp);
#define CEILING(_v)	\
	_v = FIX2INT(tmp);	\
	if (INT2FIX(_v)!=tmp) _v++;
#else
#define ROUND_FIX(_v)	\
	_v = FIX2INT(tmp);	\
	tmp -= INT2FIX(_v);	\
	if (tmp>99*FIX_ONE/100) { _v++; tmp = 0; }	\
	if (ABS(tmp) > FIX_EPSILON) use_blit = 0;
#define CEILING(_v)	\
	_v = FIX2INT(tmp);	\
	tmp -= INT2FIX(_v);	\
	if (tmp>0) { _v++; tmp = 0; }	\
	if (ABS(tmp) > FIX_EPSILON) use_blit = 0;
#endif

	use_blit = 1;
	/*compute SRC window*/
	tmp = gf_divfix(INT2FIX(clipped_final.x) - final.x, w_scale);
	if (tmp<0) tmp=0;
	CEILING(src->x);

	tmp = gf_divfix(INT2FIX(clipped_final.y) - final.y, h_scale);
	if (tmp<0) tmp=0;
	CEILING(src->y);

	tmp = gf_divfix(INT2FIX(clip->width), w_scale);
	ROUND_FIX(src->w);

	tmp = gf_divfix(INT2FIX(clip->height), h_scale);
	ROUND_FIX(src->h);

#undef ROUND_FIX

	if (src->w>txh->width) src->w=txh->width;
	if (src->h>txh->height) src->h=txh->height;

	if (!src->w || !src->h) return 0;

	/*make sure we lie in src bounds*/
	if (src->x + src->w>txh->width) src->w = txh->width - src->x;
	if (src->y + src->h>txh->height) src->h = txh->height - src->y;

	if (disable_blit) *disable_blit = use_blit ? 0 : 1;
	return 1;
}

static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHandler *txh, DrawableContext *ctx, GF_IRect *clip, GF_Rect *unclip, u8 alpha, GF_ColorKey *col_key, GF_TraverseState *tr_state, Bool force_soft_blt)
{
	GF_VideoSurface video_src;
	GF_Err e;
	Bool use_soft_stretch, use_blit, flush_video, is_attached, has_scale;
	u32 overlay_type;
	GF_Window src_wnd, dst_wnd;
	u32 output_width, output_height, hw_caps;


	if (!txh->data) return 1;

	if (!visual->compositor->has_size_info && !(visual->compositor->msg_type & GF_SR_CFG_OVERRIDE_SIZE)
		&& (visual->compositor->override_size_flags & 1)
		&& !(visual->compositor->override_size_flags & 2)
		) {
		if ( (visual->compositor->scene_width < txh->width)
			|| (visual->compositor->scene_height < txh->height)) {
			visual->compositor->scene_width = txh->width;
			visual->compositor->scene_height = txh->height;
			visual->compositor->msg_type |= GF_SR_CFG_OVERRIDE_SIZE;
			return 1;
		}
	}

	if (!compositor_texture_rectangles(visual, txh, clip, unclip, &src_wnd, &dst_wnd, &use_blit, &has_scale)) return 1;

	/*can we use hardware blitter ?*/
	hw_caps = visual->compositor->video_out->hw_caps;
	overlay_type = 0;
	flush_video = 0;
	use_soft_stretch = 1;

	output_width = visual->compositor->vp_width;
	output_height = visual->compositor->vp_height;

	if (!(hw_caps & GF_VIDEO_HW_HAS_STRETCH)) {
		if (has_scale) force_soft_blt = 1;
	}
	if (visual->compositor->disable_hardware_blit) force_soft_blt = 1;

	if (!force_soft_blt) {

		/*avoid partial redraw that don't come close to src pixels with the bliter, this leads to ugly artefacts -
		fall back to rasterizer*/
//		if (!(ctx->flags & CTX_TEXTURE_DIRTY) && !use_blit && (src_wnd.x || src_wnd.y) )
//			return 0;

		switch (txh->pixelformat) {
		case GF_PIXEL_RGB_24:
		case GF_PIXEL_BGR_24:
		case GF_PIXEL_RGBS:
		case GF_PIXEL_RGBD:
		case GF_PIXEL_RGB_555:
		case GF_PIXEL_RGB_565:
			if (hw_caps & GF_VIDEO_HW_HAS_RGB)
				use_soft_stretch = 0;
			break;
		case GF_PIXEL_ARGB:
		case GF_PIXEL_RGBA:
		case GF_PIXEL_RGBAS:
		case GF_PIXEL_RGBDS:
			if (hw_caps & GF_VIDEO_HW_HAS_RGBA)
				use_soft_stretch = 0;
			break;
		case GF_PIXEL_YV12:
		case GF_PIXEL_IYUV:
		case GF_PIXEL_I420:
		case GF_PIXEL_YUVD:
			if (hw_caps & GF_VIDEO_HW_HAS_YUV) use_soft_stretch = 0;
			else if (hw_caps & GF_VIDEO_HW_HAS_YUV_OVERLAY) overlay_type = 1;
			break;
		default:
			break;
		}
		/*disable based on settings*/
		if (!visual->compositor->enable_yuv_hw
			|| (ctx->col_mat || (alpha!=0xFF) || !visual->compositor->video_out->Blit)
			) {
			use_soft_stretch = 1;
			overlay_type = 0;
		}
		if (visual->compositor->disable_partial_hw_blit && ((src_wnd.w!=txh->width) || (src_wnd.h!=txh->height) )) {
			use_soft_stretch = 1;
		}

		/*disable HW color keying - not compatible with MPEG-4 MaterialKey*/
		if (col_key) {
			use_soft_stretch = 1;
			overlay_type = 0;
		}

		if (overlay_type) {
			/*no more than one overlay is supported at the current time*/
			if (visual->overlays) {
				ctx->drawable->flags &= ~DRAWABLE_IS_OVERLAY;
				overlay_type = 0;
			}
			/*direct draw or not last context: we must queue the overlay*/
			else if (tr_state->immediate_draw || (ctx->next && ctx->next->drawable)) {
				overlay_type = 2;
			}
			/*OK we can overlay this video - if full display, don't flush*/
			if (overlay_type==1) {
				if (dst_wnd.w==visual->compositor->display_width) flush_video = 0;
				else if (dst_wnd.h==visual->compositor->display_height) flush_video = 0;
				else flush_video = visual->has_modif;
			}
			/*if no color keying, we cannot queue the overlay*/
			else if (!visual->compositor->video_out->overlay_color_key) {
				overlay_type = 0;
			}
		}

	}

	video_src.height = txh->height;
	video_src.width = txh->width;
	video_src.pitch_x = 0;
	video_src.pitch_y = txh->stride;
	video_src.pixel_format = txh->pixelformat;
#ifdef GF_SR_USE_DEPTH
	if (txh->pixelformat==GF_PIXEL_YUVD) video_src.pixel_format = GF_PIXEL_YV12;
#endif
	video_src.video_buffer = txh->data;
	if (overlay_type) {

		if (overlay_type==2) {
			GF_IRect o_rc;
			GF_OverlayStack *ol, *first;

			/*queue overlay in order*/
			GF_SAFEALLOC(ol, GF_OverlayStack);
			ol->ctx = ctx;
			ol->dst = dst_wnd;
			ol->src = src_wnd;
			first = visual->overlays;
			if (first) {
				while (first->next) first = first->next;
				first->next = ol;
			} else {
				visual->overlays = ol;
			}

			if (visual->center_coords) {
				o_rc.x = dst_wnd.x - output_width/2;
				o_rc.y = output_height/2- dst_wnd.y;
			} else {
				o_rc.x = dst_wnd.x;
				o_rc.y = dst_wnd.y + dst_wnd.h;
			}

			o_rc.width = dst_wnd.w;
			o_rc.height = dst_wnd.h;
			visual->ClearSurface(visual, &o_rc, visual->compositor->video_out->overlay_color_key);
			visual->has_overlays = 1;
			/*mark drawable as overlay*/
			ctx->drawable->flags |= DRAWABLE_IS_OVERLAY;

			/*prevents this context from being removed in direct draw mode by requesting a new one
			but not allocating it*/
			if (tr_state->immediate_draw)
				visual_2d_get_drawable_context(visual);
			return 1;
		}
		/*top level overlay*/
		if (flush_video) {
			GF_Window rc;
			rc.x = rc.y = 0;
			rc.w = visual->compositor->display_width;
			rc.h = visual->compositor->display_height;

			visual_2d_release_raster(visual);
			visual->compositor->video_out->Flush(visual->compositor->video_out, &rc);
			visual_2d_init_raster(visual);
		}
		visual->compositor->skip_flush = 1;

		e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 1);
		if (!e) {
			/*mark drawable as overlay*/
			ctx->drawable->flags |= DRAWABLE_IS_OVERLAY;
			visual->has_overlays = 1;
			return 1;
		}
		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Error during overlay blit - trying with soft one\n"));
		visual->compositor->skip_flush = 0;
	}

	/*most graphic cards can't perform bliting on locked surface - force unlock by releasing the hardware*/
	is_attached = visual->is_attached;
	if (is_attached) visual_2d_release_raster(visual);

	if (!use_soft_stretch) {
		e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 0);
		/*HW pb, try soft*/
		if (e) {
			use_soft_stretch = 1;
			if (visual->compositor->video_memory==1) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Error during hardware blit - will use soft one\n"));
				visual->compositor->video_memory = 2;
			}
			/*force a reconfigure of video output*/
			else {
				GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring video output to use video memory\n"));
				visual->compositor->request_video_memory = 1;
				visual->compositor->root_visual_setup = 0;
				gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
			}
		}
	}
	if (use_soft_stretch) {
		GF_VideoSurface backbuffer;
		e = visual->compositor->video_out->LockBackBuffer(visual->compositor->video_out, &backbuffer, 1);
		if (!e) {
			gf_stretch_bits(&backbuffer, &video_src, &dst_wnd, &src_wnd, alpha, 0, col_key, ctx->col_mat);
			e = visual->compositor->video_out->LockBackBuffer(visual->compositor->video_out, &backbuffer, 0);
		} else {
			GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot lock back buffer - Error %s\n", gf_error_to_string(e) ));
			if (is_attached) visual_2d_init_raster(visual);
			return 0;
		}
		if (!visual->compositor->video_memory) {
			GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring video output to use video memory\n"));
			visual->compositor->video_memory = 1;
			visual->compositor->root_visual_setup = 0;
			gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
		}
	}
	visual->has_modif = 1;
	if (is_attached) visual_2d_init_raster(visual);
	return 1;
}



Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key)
{
	u8 alpha = 0xFF;

	if (!ctx->aspect.fill_texture) return 1;
	/*check if texture is ready*/
	if (!ctx->aspect.fill_texture->data) return 0;
	if (ctx->transform.m[0]<0) return 0;
	/*check if the <0 value is due to a flip in he scene description or
	due to bifs<->svg... context switching*/
	if (ctx->transform.m[4]<0) {
		if (!(ctx->flags & CTX_FLIPED_COORDS)) return 0;
	} else {
		if (ctx->flags & CTX_FLIPED_COORDS) return 0;
	}
	if (ctx->transform.m[1] || ctx->transform.m[3]) return 0;
#ifndef GPAC_DISABLE_VRML
	if ((ctx->flags & CTX_HAS_APPEARANCE) && ctx->appear && ((M_Appearance*)ctx->appear)->textureTransform)
		return 0;
#endif

	alpha = GF_COL_A(ctx->aspect.fill_color);
	/*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/
	if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);

	if (!alpha) return 1;

	switch (ctx->aspect.fill_texture->pixelformat) {
	case GF_PIXEL_RGB_24:
	case GF_PIXEL_BGR_24:
	case GF_PIXEL_RGB_555:
	case GF_PIXEL_RGB_565:
	case GF_PIXEL_ARGB:
	case GF_PIXEL_RGBA:
	case GF_PIXEL_YV12:
	case GF_PIXEL_IYUV:
	case GF_PIXEL_I420:
	case GF_PIXEL_YUVA:
	case GF_PIXEL_RGBS:
	case GF_PIXEL_RGBAS:
		break;
	case GF_PIXEL_YUVD:
	case GF_PIXEL_RGBD:
	case GF_PIXEL_RGBDS:
#ifndef GPAC_DISABLE_3D
		/*using OpenGL to render depth images*/
		if (visual->compositor->depth_gl_type) {
			gf_sc_set_option(visual->compositor, GF_OPT_USE_OPENGL, 2);
			return 1;
		}
#endif
		break;
	/*the rest has to be displayed through brush for now, we only use YUV and RGB pool*/
	default:
		return 0;
	}

	/*direct drawing, no clippers */
	if (tr_state->immediate_draw) {
		if (visual->compositor->video_out->BlitTexture) {
			if (! visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, col_key
#ifdef GF_SR_USE_DEPTH
				, ctx->depth_offset, ctx->depth_gain
#else
				, 0, 0
#endif
				))
				return 0;
		} else {
			if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &ctx->bi->clip, &ctx->bi->unclip, alpha, col_key, tr_state, 0))
				return 0;
		}
	}
	/*draw bitmap for all dirty rects*/
	else {
		u32 i;
		GF_IRect clip;
		for (i=0; i<tr_state->visual->to_redraw.count; i++) {
			/*there's an opaque region above, don't draw*/
#ifdef TRACK_OPAQUE_REGIONS
			if (tr_state->visual->draw_node_index < tr_state->visual->to_redraw.opaque_node_index[i]) continue;
#endif
			clip = ctx->bi->clip;
			gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i]);
			if (clip.width && clip.height) {
				if (visual->compositor->video_out->BlitTexture) {
					if (!visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, col_key
#ifdef GF_SR_USE_DEPTH
						, ctx->depth_offset, ctx->depth_gain
#else
						, 0, 0
#endif
					))
					return 0;
				} else if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &clip, &ctx->bi->unclip, alpha, col_key, tr_state, 0)) {
					return 0;
				}
			}
		}
	}
	ctx->aspect.fill_texture->flags |= GF_SR_TEXTURE_USED;
	return 1;
}


GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor)
{
	Double ratio;
	GF_Event evt;
	GF_Err e;
	Fixed scaleX, scaleY;

	compositor->output_width = compositor->scene_width;
	compositor->output_height = compositor->scene_height;
	compositor->vp_x = compositor->vp_y = 0;
	scaleX = scaleY = FIX_ONE;

	/*force complete clean*/
	compositor->traverse_state->invalidate_all = 1;

	if (!compositor->has_size_info && !(compositor->override_size_flags & 2) ) {
		compositor->output_width = compositor->display_width;
		compositor->output_height = compositor->display_height;
		compositor->vp_width = compositor->visual->width = compositor->output_width;
		compositor->vp_height = compositor->visual->height = compositor->output_height;
	} else {
		if (compositor->rotate_mode % 2) {
			compositor->vp_height = compositor->display_width;
			compositor->vp_width = compositor->display_height;
		} else {
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = compositor->display_height;
		}

		switch (compositor->aspect_ratio) {
		case GF_ASPECT_RATIO_FILL_SCREEN:
			break;
		case GF_ASPECT_RATIO_16_9:
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = 9 * compositor->display_width / 16;
			if (compositor->vp_height>compositor->display_height) {
				compositor->vp_height = compositor->display_height;
				compositor->vp_width = 16 * compositor->display_height / 9;
			}
			break;
		case GF_ASPECT_RATIO_4_3:
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = 3 * compositor->display_width / 4;
			if (compositor->vp_height>compositor->display_height) {
				compositor->vp_height = compositor->display_height;
				compositor->vp_width = 4 * compositor->display_height / 3;
			}
			break;
		default:
			ratio = compositor->scene_height;
			ratio /= compositor->scene_width;
			if (compositor->vp_width * ratio > compositor->vp_height) {
				compositor->vp_width = compositor->vp_height * compositor->scene_width;
				compositor->vp_width /= compositor->scene_height;
			}
			else {
				compositor->vp_height = compositor->vp_width * compositor->scene_height;
				compositor->vp_height /= compositor->scene_width;
			}
			break;
		}
		compositor->vp_x = (compositor->display_width - compositor->vp_width) / 2;
		compositor->vp_y = (compositor->display_height - compositor->vp_height) / 2;

		scaleX = gf_divfix(INT2FIX(compositor->vp_width), INT2FIX(compositor->scene_width));
		if (!scaleX) scaleX = FIX_ONE;
		scaleY = gf_divfix(INT2FIX(compositor->vp_height), INT2FIX(compositor->scene_height));
		if (!scaleY) scaleY = FIX_ONE;

		if (!compositor->scalable_zoom) {
			compositor->output_width = compositor->scene_width;
			compositor->output_height = compositor->scene_height;
			compositor->vp_width = FIX2INT(gf_divfix(INT2FIX(compositor->display_width), scaleX));
			compositor->vp_height = FIX2INT(gf_divfix(INT2FIX(compositor->display_height), scaleY));

			compositor->vp_x = (compositor->vp_width - compositor->output_width) / 2;
			compositor->vp_y = (compositor->vp_height - compositor->output_height) / 2;

			scaleX = scaleY = FIX_ONE;
		} else {
/*
			compositor->output_width = compositor->vp_width;
			compositor->output_height = compositor->vp_height;
*/
			compositor->output_width = compositor->display_width;
			compositor->output_height = compositor->display_height;
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = compositor->display_height;
		}
		compositor->visual->width = compositor->output_width;
		compositor->visual->height = compositor->output_height;
	}

	/*resize hardware surface*/
	evt.type = GF_EVENT_VIDEO_SETUP;
	evt.setup.width = compositor->vp_width;
	evt.setup.height = compositor->vp_height;
	evt.setup.opengl_mode = 0;
	evt.setup.system_memory = (compositor->request_video_memory==1) ? 0 : 1;
	compositor->request_video_memory = 0;

#ifdef OPENGL_RASTER
	if (compositor->opengl_raster) {
		evt.setup.opengl_mode = 1;
		evt.setup.system_memory = 0;
		evt.setup.back_buffer = 1;
	}
#endif


	GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring display size %d x %d - opengl %s - use %s memory\n", evt.setup.width, evt.setup.height,
		(evt.setup.opengl_mode==2) ? "Offscreen" : (evt.setup.opengl_mode==1) ? "yes" : "no", evt.setup.system_memory ? "systems" : "video"
		));

	e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
	if (e) return e;

	if (compositor->has_size_info) {
		compositor->traverse_state->vp_size.x = INT2FIX(compositor->scene_width);
		compositor->traverse_state->vp_size.y = INT2FIX(compositor->scene_height);
	} else {
		compositor->traverse_state->vp_size.x = INT2FIX(compositor->output_width);
		compositor->traverse_state->vp_size.y = INT2FIX(compositor->output_height);
	}
	/*set scale factor*/
	compositor_set_ar_scale(compositor, scaleX, scaleY);
	return GF_OK;<commit_msg>Fixed bug in video/systems memory selection<commit_after>/*
 *			GPAC - Multimedia Framework C SDK
 *
 *			Copyright (c) <NAME> 2000-2005
 *					All rights reserved
 *
 *  This file is part of GPAC / Scene Compositor sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */



#include "visual_manager.h"
#include "nodes_stacks.h"
#include <gpac/options.h>

#ifdef OPENGL_RASTER
#include "gl_inc.h"
#include "texturing.h"

static void c2d_gl_fill_no_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Color color)
{
#if defined(GPAC_USE_OGL_ES)
	GLfloat line[4];

	line[0] = FIX2FLT(x);
	line[1] = FIX2FLT(y);
	line[2] = FIX2FLT(x+run_h_len);
	line[3] = line[1];

	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), 0xFF);
	glVertexPointer(2, GL_FLOAT, 0, line);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDrawArrays(GL_LINES, 0, 2);
	glDisableClientState(GL_VERTEX_ARRAY);

#else
	glBegin(GL_LINES);
	glColor3ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color));
//	glColor3f(GF_COL_R(color)/255, GF_COL_G(color)/255, GF_COL_B(color)/255);
	glVertex2i(x,y);
	glVertex2i(x+run_h_len,y);
	glEnd();
#endif
}

static void c2d_gl_fill_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Color color, u8 alpha)
{
#if defined(GPAC_USE_OGL_ES)
	GLfloat line[4];

	line[0] = FIX2FLT(x);
	line[1] = FIX2FLT(y);
	line[2] = FIX2FLT(x+run_h_len);
	line[3] = line[1];

	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), (u8) alpha);

	glVertexPointer(2, GL_FLOAT, 0, line);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDrawArrays(GL_LINES, 0, 2);
	glDisableClientState(GL_VERTEX_ARRAY);

	glDisable(GL_BLEND);
#else
	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), (u8) alpha);
	glBegin(GL_LINES);
	glVertex2i(x,y);
	glVertex2i(x+run_h_len,y);
	glEnd();
	glDisable(GL_BLEND);
#endif
}

static void c2d_gl_fill_rect(void *cbk, u32 x, u32 y, u32 width, u32 height, GF_Color color)
{
#if defined(GPAC_USE_OGL_ES)
	GLfloat line[8];

	line[0] = FIX2FLT(x);
	line[1] = FIX2FLT(y);
	line[2] = FIX2FLT(x+width);
	line[3] = FIX2FLT(y);
	line[4] = FIX2FLT(x+width);
	line[5] = FIX2FLT(y+height);
	line[6] = FIX2FLT(x);
	line[7] = FIX2FLT(y+height);

	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), GF_COL_A(color));

	glVertexPointer(4, GL_FLOAT, 0, line);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDrawArrays(GL_TRIANGLE_FAN, 0, 2);
	glDisableClientState(GL_VERTEX_ARRAY);

	glDisable(GL_BLEND);
#else
	glEnable(GL_BLEND);
	glColor4ub(GF_COL_R(color), GF_COL_G(color), GF_COL_B(color), GF_COL_A(color));
	glBegin(GL_TRIANGLES);
	glVertex2i(x,y);
	glVertex2i(x+width,y);
	glVertex2i(x+width,y+height);
	glEnd();
	glBegin(GL_TRIANGLES);
	glVertex2i(x,y);
	glVertex2i(x+width,y+height);
	glVertex2i(x,y+height);
	glEnd();
	glDisable(GL_BLEND);
#endif
}


Bool c2d_gl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key)
{
	u8 alpha = GF_COL_A(ctx->aspect.fill_color);

	if (ctx->transform.m[1] || ctx->transform.m[3]) return 0;

	visual_3d_set_state(visual, V3D_STATE_LIGHT, 0);
	visual_3d_enable_antialias(visual, 0);
	if (alpha && (alpha != 0xFF)) {
		visual_3d_set_material_2d_argb(visual, ctx->aspect.fill_color);
		gf_sc_texture_set_blend_mode(ctx->aspect.fill_texture, TX_MODULATE);
	} else if (gf_sc_texture_is_transparent(ctx->aspect.fill_texture)) {
		gf_sc_texture_set_blend_mode(ctx->aspect.fill_texture, TX_REPLACE);
	} else {
		visual_3d_set_state(visual, V3D_STATE_BLEND, 0);
	}
	/*ignore texture transform for bitmap*/
	tr_state->mesh_num_textures = gf_sc_texture_enable(ctx->aspect.fill_texture, tr_state->appear ? ((M_Appearance *)tr_state->appear)->textureTransform : NULL);
	if (tr_state->mesh_num_textures) {
		SFVec2f size, orig;
		GF_Mesh *mesh;
		size.x = ctx->bi->unclip.width;
		size.y = ctx->bi->unclip.height;
		orig.x = ctx->bi->unclip.x + INT2FIX(visual->compositor->vp_width)/2;
		orig.y = INT2FIX(visual->compositor->vp_height)/2 - ctx->bi->unclip.y + ctx->bi->unclip.height;

		mesh = new_mesh();
		mesh_new_rectangle(mesh, size, &orig, 1);
		visual_3d_mesh_paint(tr_state, mesh);
		mesh_free(mesh);
		gf_sc_texture_disable(ctx->aspect.fill_texture);
		tr_state->mesh_num_textures = 0;
		return 1;
	}
	return 0;
}
#endif

GF_Err compositor_2d_get_video_access(GF_VisualManager *visual)
{
	GF_Err e;
	GF_Compositor *compositor = visual->compositor;


	if (!visual->raster_surface) return GF_BAD_PARAM;

#ifdef OPENGL_RASTER
	if (compositor->opengl_raster && compositor->rasterizer->surface_attach_to_callbacks) {
		GF_RasterCallback callbacks;
		callbacks.cbk = visual;
		callbacks.fill_run_alpha = c2d_gl_fill_alpha;
		callbacks.fill_run_no_alpha = c2d_gl_fill_no_alpha;
		callbacks.fill_rect = c2d_gl_fill_rect;

		visual->DrawBitmap = c2d_gl_draw_bitmap;

		e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &callbacks, compositor->vp_width, compositor->vp_height);
		if (e==GF_OK) {
			GF_Matrix mx;
			Fixed hh, hw;
			visual->is_attached = 2;

			visual_3d_setup(visual);
			glClear(GL_DEPTH_BUFFER_BIT);
			glViewport(0, 0, compositor->vp_width, compositor->vp_height);

			glClear(GL_COLOR_BUFFER_BIT);

			glLineWidth(1.0f);

#ifndef GPAC_USE_OGL_ES
			glDisable(GL_POLYGON_SMOOTH);
#endif
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);

			glDisable(GL_NORMALIZE);
			glDisable(GL_LINE_SMOOTH);
			glDisable(GL_DEPTH_TEST);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glDepthFunc(GL_LEQUAL);

			hw = INT2FIX(compositor->vp_width)/2;
			hh = INT2FIX(compositor->vp_height)/2;
			gf_mx_ortho(&mx, -hw, hw, -hh, hh, 50, -50);

			visual_3d_set_matrix_mode(visual, V3D_MATRIX_PROJECTION);
			visual_3d_matrix_load(visual, mx.m);

			visual_3d_set_matrix_mode(visual, V3D_MATRIX_MODELVIEW);
			gf_mx_init(mx);
			gf_mx_add_scale(&mx, 1, -1, 1);
			gf_mx_add_translation(&mx, -hw, -hh, 0);
			visual_3d_matrix_load(visual, mx.m);

			return GF_OK;
		}
	}
#endif


	compositor->hw_locked = 0;
	e = GF_IO_ERR;

	/*try from video memory handle (WIN32) if supported*/
	if ((compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_HWND_HDC)
		&& compositor->rasterizer->surface_attach_to_device
		&& compositor->video_out->LockOSContext
		) {
		compositor->hw_context = compositor->video_out->LockOSContext(compositor->video_out, 1);
		if (compositor->hw_context) {
			e = compositor->rasterizer->surface_attach_to_device(visual->raster_surface, compositor->hw_context, compositor->vp_width, compositor->vp_height);
			if (!e) {
				visual->is_attached = 1;
				GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface handle attached to raster\n"));
				return GF_OK;
			}
			compositor->video_out->LockOSContext(compositor->video_out, 0);
			GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface handle to raster: %s\n", gf_error_to_string(e) ));
		}
	}

	if (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_LINE_BLIT) {
		e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &compositor->raster_callbacks, compositor->vp_width, compositor->vp_height);
		if (!e) {
			visual->is_attached = 1;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface callbacks attached to raster\n"));
			return GF_OK;
		}
		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Failed to attach video surface callbacks to raster\n"));
	}

	e = GF_NOT_SUPPORTED;

	if (compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 1)==GF_OK) {
		compositor->hw_locked = 1;

		e = compositor->rasterizer->surface_attach_to_buffer(visual->raster_surface, compositor->hw_surface.video_buffer,
							compositor->hw_surface.width,
							compositor->hw_surface.height,
							compositor->hw_surface.pitch_x,
							compositor->hw_surface.pitch_y,
							(GF_PixelFormat) compositor->hw_surface.pixel_format);
		if (!e) {
			visual->is_attached = 1;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface memory attached to raster - w=%d h=%d pitch_x=%d pitch_y=%d\n", compositor->hw_surface.width, compositor->hw_surface.height, compositor->hw_surface.pitch_x, compositor->hw_surface.pitch_y));
			return GF_OK;
		}
		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface memory to raster: %s\n", gf_error_to_string(e) ));
		compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 0);
	}
	compositor->hw_locked = 0;
	visual->is_attached = 0;
	return e;
}

void compositor_2d_release_video_access(GF_VisualManager *visual)
{
	GF_Compositor *compositor = visual->compositor;
	if (visual->is_attached) {
		compositor->rasterizer->surface_detach(visual->raster_surface);
		visual->is_attached = 0;
	}
	if (compositor->hw_context) {
		compositor->video_out->LockOSContext(compositor->video_out, 0);
		compositor->hw_context = NULL;
	} else if (compositor->hw_locked) {
		compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 0);
		compositor->hw_locked = 0;
	}
}

Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler *txh, GF_IRect *clip, GF_Rect *unclip, GF_Window *src, GF_Window *dst, Bool *disable_blit, Bool *has_scale)
{
	Fixed w_scale, h_scale, tmp;
	u32 output_width, output_height;
	GF_IRect clipped_final = *clip;
	GF_Rect final = *unclip;
	Bool use_blit;

	src->w = src->h = 0;
	dst->w = dst->h = 0;
	if (disable_blit) *disable_blit = 0;
	if (has_scale) *has_scale = 0;

	/*this should never happen but we check for float rounding safety*/
	if (final.width<=0 || final.height <=0) return 0;


	w_scale = final.width / txh->width;
	h_scale = final.height / txh->height;

	if ((w_scale != FIX_ONE) || (h_scale!=FIX_ONE)) {
		if (has_scale) *has_scale = 1;
	}

	if (visual->offscreen) {
		output_width = visual->width;
		output_height = visual->height;
	} else {
		/*use entire video surface for un-centering coord system*/
		output_width = visual->compositor->vp_width;
		output_height = visual->compositor->vp_height;
	}
	/*take care of pixel rounding for odd width/height and make sure we strictly draw in the clipped bounds*/
	if (visual->center_coords) {
		clipped_final.x += output_width / 2;
		final.x += INT2FIX( output_width / 2 );

		clipped_final.y = output_height/ 2 - clipped_final.y;
		final.y = INT2FIX( output_height / 2) - final.y;

	} else {
		final.y -= final.height;
		clipped_final.y -= clipped_final.height;
	}

	/*make sure we lie in the final rect (this is needed for directdraw mode)*/
	if (clipped_final.x<0) {
		clipped_final.width += clipped_final.x;
		clipped_final.x = 0;
		if (clipped_final.width <= 0) return 0;
	}
	if (clipped_final.y<0) {
		clipped_final.height += clipped_final.y;
		clipped_final.y = 0;
		if (clipped_final.height <= 0) return 0;
	}
	if (clipped_final.x + clipped_final.width > (s32) output_width) {
		clipped_final.width = output_width - clipped_final.x;
		clipped_final.x = output_width - clipped_final.width;
	}
	if (clipped_final.y + clipped_final.height > (s32) output_height) {
		clipped_final.height = output_height - clipped_final.y;
		clipped_final.y = output_height - clipped_final.height;
	}
	/*needed in direct drawing since clipping is not performed*/
	if (clipped_final.width<=0 || clipped_final.height <=0)
		return 0;

	if (clipped_final.width-1>= FIX2INT(final.width) ) clipped_final.width = FIX2INT(final.width);
	if (clipped_final.height-1>= FIX2INT(final.height) ) clipped_final.height = FIX2INT(final.height);

	/*set dest window*/
	dst->x = (u32) clipped_final.x;
	dst->y = (u32) clipped_final.y;
	dst->w = (u32) clipped_final.width;
	dst->h = (u32) clipped_final.height;

	if (!dst->w || !dst->h) return 0;

#ifdef GPAC_FIXED_POINT
#define ROUND_FIX(_v)	\
	_v = FIX2INT(tmp);
#define CEILING(_v)	\
	_v = FIX2INT(tmp);	\
	if (INT2FIX(_v)!=tmp) _v++;
#else
#define ROUND_FIX(_v)	\
	_v = FIX2INT(tmp);	\
	tmp -= INT2FIX(_v);	\
	if (tmp>99*FIX_ONE/100) { _v++; tmp = 0; }	\
	if (ABS(tmp) > FIX_EPSILON) use_blit = 0;
#define CEILING(_v)	\
	_v = FIX2INT(tmp);	\
	tmp -= INT2FIX(_v);	\
	if (tmp>0) { _v++; tmp = 0; }	\
	if (ABS(tmp) > FIX_EPSILON) use_blit = 0;
#endif

	use_blit = 1;
	/*compute SRC window*/
	tmp = gf_divfix(INT2FIX(clipped_final.x) - final.x, w_scale);
	if (tmp<0) tmp=0;
	CEILING(src->x);

	tmp = gf_divfix(INT2FIX(clipped_final.y) - final.y, h_scale);
	if (tmp<0) tmp=0;
	CEILING(src->y);

	tmp = gf_divfix(INT2FIX(clip->width), w_scale);
	ROUND_FIX(src->w);

	tmp = gf_divfix(INT2FIX(clip->height), h_scale);
	ROUND_FIX(src->h);

#undef ROUND_FIX

	if (src->w>txh->width) src->w=txh->width;
	if (src->h>txh->height) src->h=txh->height;

	if (!src->w || !src->h) return 0;

	/*make sure we lie in src bounds*/
	if (src->x + src->w>txh->width) src->w = txh->width - src->x;
	if (src->y + src->h>txh->height) src->h = txh->height - src->y;

	if (disable_blit) *disable_blit = use_blit ? 0 : 1;
	return 1;
}

static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHandler *txh, DrawableContext *ctx, GF_IRect *clip, GF_Rect *unclip, u8 alpha, GF_ColorKey *col_key, GF_TraverseState *tr_state, Bool force_soft_blt)
{
	GF_VideoSurface video_src;
	GF_Err e;
	Bool use_soft_stretch, use_blit, flush_video, is_attached, has_scale;
	u32 overlay_type;
	GF_Window src_wnd, dst_wnd;
	u32 output_width, output_height, hw_caps;


	if (!txh->data) return 1;

	if (!visual->compositor->has_size_info && !(visual->compositor->msg_type & GF_SR_CFG_OVERRIDE_SIZE)
		&& (visual->compositor->override_size_flags & 1)
		&& !(visual->compositor->override_size_flags & 2)
		) {
		if ( (visual->compositor->scene_width < txh->width)
			|| (visual->compositor->scene_height < txh->height)) {
			visual->compositor->scene_width = txh->width;
			visual->compositor->scene_height = txh->height;
			visual->compositor->msg_type |= GF_SR_CFG_OVERRIDE_SIZE;
			return 1;
		}
	}

	if (!compositor_texture_rectangles(visual, txh, clip, unclip, &src_wnd, &dst_wnd, &use_blit, &has_scale)) return 1;

	/*can we use hardware blitter ?*/
	hw_caps = visual->compositor->video_out->hw_caps;
	overlay_type = 0;
	flush_video = 0;
	use_soft_stretch = 1;

	output_width = visual->compositor->vp_width;
	output_height = visual->compositor->vp_height;

	if (!(hw_caps & GF_VIDEO_HW_HAS_STRETCH)) {
		if (has_scale) force_soft_blt = 1;
	}
	if (visual->compositor->disable_hardware_blit) force_soft_blt = 1;

	if (!force_soft_blt) {

		/*avoid partial redraw that don't come close to src pixels with the bliter, this leads to ugly artefacts -
		fall back to rasterizer*/
//		if (!(ctx->flags & CTX_TEXTURE_DIRTY) && !use_blit && (src_wnd.x || src_wnd.y) )
//			return 0;

		switch (txh->pixelformat) {
		case GF_PIXEL_RGB_24:
		case GF_PIXEL_BGR_24:
		case GF_PIXEL_RGBS:
		case GF_PIXEL_RGBD:
		case GF_PIXEL_RGB_555:
		case GF_PIXEL_RGB_565:
			if (hw_caps & GF_VIDEO_HW_HAS_RGB)
				use_soft_stretch = 0;
			break;
		case GF_PIXEL_ARGB:
		case GF_PIXEL_RGBA:
		case GF_PIXEL_RGBAS:
		case GF_PIXEL_RGBDS:
			if (hw_caps & GF_VIDEO_HW_HAS_RGBA)
				use_soft_stretch = 0;
			break;
		case GF_PIXEL_YV12:
		case GF_PIXEL_IYUV:
		case GF_PIXEL_I420:
		case GF_PIXEL_YUVD:
			if (hw_caps & GF_VIDEO_HW_HAS_YUV) use_soft_stretch = 0;
			else if (hw_caps & GF_VIDEO_HW_HAS_YUV_OVERLAY) overlay_type = 1;
			break;
		default:
			break;
		}
		/*disable based on settings*/
		if (!visual->compositor->enable_yuv_hw
			|| (ctx->col_mat || (alpha!=0xFF) || !visual->compositor->video_out->Blit)
			) {
			use_soft_stretch = 1;
			overlay_type = 0;
		}
		if (visual->compositor->disable_partial_hw_blit && ((src_wnd.w!=txh->width) || (src_wnd.h!=txh->height) )) {
			use_soft_stretch = 1;
		}

		/*disable HW color keying - not compatible with MPEG-4 MaterialKey*/
		if (col_key) {
			use_soft_stretch = 1;
			overlay_type = 0;
		}

		if (overlay_type) {
			/*no more than one overlay is supported at the current time*/
			if (visual->overlays) {
				ctx->drawable->flags &= ~DRAWABLE_IS_OVERLAY;
				overlay_type = 0;
			}
			/*direct draw or not last context: we must queue the overlay*/
			else if (tr_state->immediate_draw || (ctx->next && ctx->next->drawable)) {
				overlay_type = 2;
			}
			/*OK we can overlay this video - if full display, don't flush*/
			if (overlay_type==1) {
				if (dst_wnd.w==visual->compositor->display_width) flush_video = 0;
				else if (dst_wnd.h==visual->compositor->display_height) flush_video = 0;
				else flush_video = visual->has_modif;
			}
			/*if no color keying, we cannot queue the overlay*/
			else if (!visual->compositor->video_out->overlay_color_key) {
				overlay_type = 0;
			}
		}

	}

	video_src.height = txh->height;
	video_src.width = txh->width;
	video_src.pitch_x = 0;
	video_src.pitch_y = txh->stride;
	video_src.pixel_format = txh->pixelformat;
#ifdef GF_SR_USE_DEPTH
	if (txh->pixelformat==GF_PIXEL_YUVD) video_src.pixel_format = GF_PIXEL_YV12;
#endif
	video_src.video_buffer = txh->data;
	if (overlay_type) {

		if (overlay_type==2) {
			GF_IRect o_rc;
			GF_OverlayStack *ol, *first;

			/*queue overlay in order*/
			GF_SAFEALLOC(ol, GF_OverlayStack);
			ol->ctx = ctx;
			ol->dst = dst_wnd;
			ol->src = src_wnd;
			first = visual->overlays;
			if (first) {
				while (first->next) first = first->next;
				first->next = ol;
			} else {
				visual->overlays = ol;
			}

			if (visual->center_coords) {
				o_rc.x = dst_wnd.x - output_width/2;
				o_rc.y = output_height/2- dst_wnd.y;
			} else {
				o_rc.x = dst_wnd.x;
				o_rc.y = dst_wnd.y + dst_wnd.h;
			}

			o_rc.width = dst_wnd.w;
			o_rc.height = dst_wnd.h;
			visual->ClearSurface(visual, &o_rc, visual->compositor->video_out->overlay_color_key);
			visual->has_overlays = 1;
			/*mark drawable as overlay*/
			ctx->drawable->flags |= DRAWABLE_IS_OVERLAY;

			/*prevents this context from being removed in direct draw mode by requesting a new one
			but not allocating it*/
			if (tr_state->immediate_draw)
				visual_2d_get_drawable_context(visual);
			return 1;
		}
		/*top level overlay*/
		if (flush_video) {
			GF_Window rc;
			rc.x = rc.y = 0;
			rc.w = visual->compositor->display_width;
			rc.h = visual->compositor->display_height;

			visual_2d_release_raster(visual);
			visual->compositor->video_out->Flush(visual->compositor->video_out, &rc);
			visual_2d_init_raster(visual);
		}
		visual->compositor->skip_flush = 1;

		e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 1);
		if (!e) {
			/*mark drawable as overlay*/
			ctx->drawable->flags |= DRAWABLE_IS_OVERLAY;
			visual->has_overlays = 1;
			return 1;
		}
		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Error during overlay blit - trying with soft one\n"));
		visual->compositor->skip_flush = 0;
	}

	/*most graphic cards can't perform bliting on locked surface - force unlock by releasing the hardware*/
	is_attached = visual->is_attached;
	if (is_attached) visual_2d_release_raster(visual);

	if (!use_soft_stretch) {
		e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 0);
		/*HW pb, try soft*/
		if (e) {
			use_soft_stretch = 1;
			if (visual->compositor->video_memory==1) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Error during hardware blit - will use soft one\n"));
				visual->compositor->video_memory = 2;
			}
			/*force a reconfigure of video output*/
			else {
				GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring video output to use video memory\n"));
				visual->compositor->request_video_memory = 1;
				visual->compositor->root_visual_setup = 0;
				gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
			}
		}
	}
	if (use_soft_stretch) {
		GF_VideoSurface backbuffer;
		e = visual->compositor->video_out->LockBackBuffer(visual->compositor->video_out, &backbuffer, 1);
		if (!e) {
			gf_stretch_bits(&backbuffer, &video_src, &dst_wnd, &src_wnd, alpha, 0, col_key, ctx->col_mat);
			e = visual->compositor->video_out->LockBackBuffer(visual->compositor->video_out, &backbuffer, 0);
		} else {
			GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot lock back buffer - Error %s\n", gf_error_to_string(e) ));
			if (is_attached) visual_2d_init_raster(visual);
			return 0;
		}
		if (!visual->compositor->video_memory) {
			GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring video output to use video memory\n"));
			visual->compositor->video_memory = 1;
			visual->compositor->root_visual_setup = 0;
			gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
		}
	}
	visual->has_modif = 1;
	if (is_attached) visual_2d_init_raster(visual);
	return 1;
}



Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key)
{
	u8 alpha = 0xFF;

	if (!ctx->aspect.fill_texture) return 1;
	/*check if texture is ready*/
	if (!ctx->aspect.fill_texture->data) return 0;
	if (ctx->transform.m[0]<0) return 0;
	/*check if the <0 value is due to a flip in he scene description or
	due to bifs<->svg... context switching*/
	if (ctx->transform.m[4]<0) {
		if (!(ctx->flags & CTX_FLIPED_COORDS)) return 0;
	} else {
		if (ctx->flags & CTX_FLIPED_COORDS) return 0;
	}
	if (ctx->transform.m[1] || ctx->transform.m[3]) return 0;
#ifndef GPAC_DISABLE_VRML
	if ((ctx->flags & CTX_HAS_APPEARANCE) && ctx->appear && ((M_Appearance*)ctx->appear)->textureTransform)
		return 0;
#endif

	alpha = GF_COL_A(ctx->aspect.fill_color);
	/*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/
	if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);

	if (!alpha) return 1;

	switch (ctx->aspect.fill_texture->pixelformat) {
	case GF_PIXEL_RGB_24:
	case GF_PIXEL_BGR_24:
	case GF_PIXEL_RGB_555:
	case GF_PIXEL_RGB_565:
	case GF_PIXEL_ARGB:
	case GF_PIXEL_RGBA:
	case GF_PIXEL_YV12:
	case GF_PIXEL_IYUV:
	case GF_PIXEL_I420:
	case GF_PIXEL_YUVA:
	case GF_PIXEL_RGBS:
	case GF_PIXEL_RGBAS:
		break;
	case GF_PIXEL_YUVD:
	case GF_PIXEL_RGBD:
	case GF_PIXEL_RGBDS:
#ifndef GPAC_DISABLE_3D
		/*using OpenGL to render depth images*/
		if (visual->compositor->depth_gl_type) {
			gf_sc_set_option(visual->compositor, GF_OPT_USE_OPENGL, 2);
			return 1;
		}
#endif
		break;
	/*the rest has to be displayed through brush for now, we only use YUV and RGB pool*/
	default:
		return 0;
	}

	/*direct drawing, no clippers */
	if (tr_state->immediate_draw) {
		if (visual->compositor->video_out->BlitTexture) {
			if (! visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, col_key
#ifdef GF_SR_USE_DEPTH
				, ctx->depth_offset, ctx->depth_gain
#else
				, 0, 0
#endif
				))
				return 0;
		} else {
			if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &ctx->bi->clip, &ctx->bi->unclip, alpha, col_key, tr_state, 0))
				return 0;
		}
	}
	/*draw bitmap for all dirty rects*/
	else {
		u32 i;
		GF_IRect clip;
		for (i=0; i<tr_state->visual->to_redraw.count; i++) {
			/*there's an opaque region above, don't draw*/
#ifdef TRACK_OPAQUE_REGIONS
			if (tr_state->visual->draw_node_index < tr_state->visual->to_redraw.opaque_node_index[i]) continue;
#endif
			clip = ctx->bi->clip;
			gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i]);
			if (clip.width && clip.height) {
				if (visual->compositor->video_out->BlitTexture) {
					if (!visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, col_key
#ifdef GF_SR_USE_DEPTH
						, ctx->depth_offset, ctx->depth_gain
#else
						, 0, 0
#endif
					))
					return 0;
				} else if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &clip, &ctx->bi->unclip, alpha, col_key, tr_state, 0)) {
					return 0;
				}
			}
		}
	}
	ctx->aspect.fill_texture->flags |= GF_SR_TEXTURE_USED;
	return 1;
}


GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor)
{
	Double ratio;
	GF_Event evt;
	GF_Err e;
	Fixed scaleX, scaleY;

	compositor->output_width = compositor->scene_width;
	compositor->output_height = compositor->scene_height;
	compositor->vp_x = compositor->vp_y = 0;
	scaleX = scaleY = FIX_ONE;

	/*force complete clean*/
	compositor->traverse_state->invalidate_all = 1;

	if (!compositor->has_size_info && !(compositor->override_size_flags & 2) ) {
		compositor->output_width = compositor->display_width;
		compositor->output_height = compositor->display_height;
		compositor->vp_width = compositor->visual->width = compositor->output_width;
		compositor->vp_height = compositor->visual->height = compositor->output_height;
	} else {
		if (compositor->rotate_mode % 2) {
			compositor->vp_height = compositor->display_width;
			compositor->vp_width = compositor->display_height;
		} else {
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = compositor->display_height;
		}

		switch (compositor->aspect_ratio) {
		case GF_ASPECT_RATIO_FILL_SCREEN:
			break;
		case GF_ASPECT_RATIO_16_9:
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = 9 * compositor->display_width / 16;
			if (compositor->vp_height>compositor->display_height) {
				compositor->vp_height = compositor->display_height;
				compositor->vp_width = 16 * compositor->display_height / 9;
			}
			break;
		case GF_ASPECT_RATIO_4_3:
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = 3 * compositor->display_width / 4;
			if (compositor->vp_height>compositor->display_height) {
				compositor->vp_height = compositor->display_height;
				compositor->vp_width = 4 * compositor->display_height / 3;
			}
			break;
		default:
			ratio = compositor->scene_height;
			ratio /= compositor->scene_width;
			if (compositor->vp_width * ratio > compositor->vp_height) {
				compositor->vp_width = compositor->vp_height * compositor->scene_width;
				compositor->vp_width /= compositor->scene_height;
			}
			else {
				compositor->vp_height = compositor->vp_width * compositor->scene_height;
				compositor->vp_height /= compositor->scene_width;
			}
			break;
		}
		compositor->vp_x = (compositor->display_width - compositor->vp_width) / 2;
		compositor->vp_y = (compositor->display_height - compositor->vp_height) / 2;

		scaleX = gf_divfix(INT2FIX(compositor->vp_width), INT2FIX(compositor->scene_width));
		if (!scaleX) scaleX = FIX_ONE;
		scaleY = gf_divfix(INT2FIX(compositor->vp_height), INT2FIX(compositor->scene_height));
		if (!scaleY) scaleY = FIX_ONE;

		if (!compositor->scalable_zoom) {
			compositor->output_width = compositor->scene_width;
			compositor->output_height = compositor->scene_height;
			compositor->vp_width = FIX2INT(gf_divfix(INT2FIX(compositor->display_width), scaleX));
			compositor->vp_height = FIX2INT(gf_divfix(INT2FIX(compositor->display_height), scaleY));

			compositor->vp_x = (compositor->vp_width - compositor->output_width) / 2;
			compositor->vp_y = (compositor->vp_height - compositor->output_height) / 2;

			scaleX = scaleY = FIX_ONE;
		} else {
/*
			compositor->output_width = compositor->vp_width;
			compositor->output_height = compositor->vp_height;
*/
			compositor->output_width = compositor->display_width;
			compositor->output_height = compositor->display_height;
			compositor->vp_width = compositor->display_width;
			compositor->vp_height = compositor->display_height;
		}
		compositor->visual->width = compositor->output_width;
		compositor->visual->height = compositor->output_height;
	}

	/*resize hardware surface*/
	evt.type = GF_EVENT_VIDEO_SETUP;
	evt.setup.width = compositor->vp_width;
	evt.setup.height = compositor->vp_height;
	evt.setup.opengl_mode = 0;
	/*copy over settings*/
	evt.setup.system_memory = compositor->video_memory ? 0 : 1;
	if (compositor->request_video_memory) evt.setup.system_memory = 0;
	compositor->request_video_memory = 0;

#ifdef OPENGL_RASTER
	if (compositor->opengl_raster) {
		evt.setup.opengl_mode = 1;
		evt.setup.system_memory = 0;
		evt.setup.back_buffer = 1;
	}
#endif


	GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring display size %d x %d - opengl %s - use %s memory\n", evt.setup.width, evt.setup.height,
		(evt.setup.opengl_mode==2) ? "Offscreen" : (evt.setup.opengl_mode==1) ? "yes" : "no", evt.setup.system_memory ? "systems" : "video"
		));

	e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
	if (e) return e;

	if (compositor->has_size_info) {
		compositor->traverse_state->vp_size.x = INT2FIX(compositor->scene_width);
		compositor->traverse_state->vp_size.y = INT2FIX(compositor->scene_height);
	} else {
		compositor->traverse_state->vp_size.x = INT2FIX(compositor->output_width);
		compositor->traverse_state->vp_size.y = INT2FIX(compositor->output_height);
	}
	/*set scale factor*/
	compositor_set_ar_scale(compositor, scaleX, scaleY);
	return GF_OK;
{'fraction_non_alphanumeric': 0.13608285806156814, 'fraction_numerical': 0.015603581038772022, 'mean_word_length': 4.701466615206484, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 1044, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3843108', 'n_tokens_mistral': 25894, 'n_tokens_neox': 23463, 'n_words': 4337}