/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Jean Le Feuvre 2000-2005
 *					All rights reserved
 *
 *  This file is part of GPAC / plugins interfaces
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU 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 General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */


#ifndef M4_RASTER_2D_H
#define M4_RASTER_2D_H

#ifdef __cplusplus
extern "C" {
#endif

#include <gpac/m4_math.h>
#include <gpac/m4_tools.h>


/*
	Path object manipulation	
*/

/*point tags*/
enum
{
	/*point is on curve (moveTo, lineTo, end of splines)*/
	M4_PATH_CURVE_ON = 1,
	/*point is a subpath close*/
	M4_PATH_CLOSE	= 5,
	/*point is conic control point*/
	M4_PATH_CURVE_CONIC = 0,
	/*point is cubic control point*/
	M4_PATH_CURVE_CUBIC = 2,
};


/*path flags*/
enum
{
	/*zero-nonzero rule - if not set, uses odd/even rule*/
	M4_PATH_FILL_ZERO_NONZERO = 1,
	/*when set bbox must be recomputed - used to avoid wasting time on bounds calculation*/
	M4_PATH_BBOX_DIRTY = 2,
	/*nidicates path has been flattened*/
	M4_PATH_FLATTENED = 4,
};

typedef struct _m4_path
{
	/*number of subpath*/
	u32 n_contours;
	/*number of points in path and alloc size*/
	u32 n_points, n_alloc_points;
	/*points */
	M4Point2D *points;
	/*point tags (one per point)*/
	u8 *tags;
	/*subpath end points*/
	u32 *contours;
	/*path bbox - NEVER USE WITHOUT FIRST CALLING m4_path_get_bounds*/
	M4Rect bbox;
	/* path flags*/
	s32 flags;
	/*fineness to use whenever flattening the path - default is FIX_ONE*/
	Fixed fineness;
} M4Path;


M4Path *m4_path_new();
void m4_path_delete(M4Path *gp);
void m4_path_reset(M4Path *gp);
M4Path *m4_path_clone(M4Path *gp);
M4Err m4_path_close(M4Path *gp);
M4Err m4_path_add_move_to(M4Path *gp, Fixed x, Fixed y);
M4Err m4_path_add_move_to_vec(M4Path *gp, M4Point2D *pt);
M4Err m4_path_add_line_to(M4Path *gp, Fixed x, Fixed y);
M4Err m4_path_add_line_to_vec(M4Path *gp, M4Point2D *pt);
M4Err m4_path_add_cubic_to(M4Path *gp, Fixed c1_x, Fixed c1_y, Fixed c2_x, Fixed c2_y, Fixed x, Fixed y);
M4Err m4_path_add_cubic_to_vec(M4Path *gp, M4Point2D *c1, M4Point2D *c2, M4Point2D *pt);
M4Err m4_path_add_quadratic_to(M4Path *gp, Fixed c_x, Fixed c_y, Fixed x, Fixed y);
M4Err m4_path_add_quadratic_to_vec(M4Path *gp, M4Point2D *c, M4Point2D *pt);
M4Err m4_path_add_rect_center(M4Path *gp, Fixed cx, Fixed cy, Fixed w, Fixed h);
M4Err m4_path_add_rect(M4Path *gp, Fixed ox, Fixed oy, Fixed w, Fixed h);
M4Err m4_path_add_ellipse(M4Path *gp, Fixed cx, Fixed cy, Fixed a_axis, Fixed b_axis);
/*add N-bezier to path - path.fineness must be set before*/
M4Err m4_path_add_bezier(M4Path *gp, M4Point2D *pts, u32 nbPoints);
M4Err m4_path_add_arc_to(M4Path *gp, Fixed end_x, Fixed end_y, Fixed fa_x, Fixed fa_y, Fixed fb_x, Fixed fb_y, Bool cw);
M4Err m4_path_add_arc(M4Path *gp, Fixed radius, Fixed start_angle, Fixed end_angle, u32 close_type);
M4Err m4_path_get_control_bounds(M4Path *gp, M4Rect *rc);
M4Err m4_path_get_bounds(M4Path *gp, M4Rect *rc);
M4Path *m4_path_flatten(M4Path *gp);
Bool m4_path_point_over(M4Path *gp, Fixed x, Fixed y);

typedef struct _path_iterator M4PathIterator;

/*inits path iteration*/
M4PathIterator *m4_path_new_iterator(M4Path *gp);
void m4_path_delete_iterator(M4PathIterator *it);

Fixed m4_pathiterator_get_length(M4PathIterator *it);
/*gets transformation matrix at given point (offset) 
the transform is so that a local system is translated to the given point, its x-axis tangent to the path and in 
the same direction (path direction is from first point to last point)
@offset: length on the path in local system unit
@follow_tangent: indicates if transformation shall be computed if @offset indicates a point outside 
the path (<0 or >path_length). In which case the path shall be virtually extended by the tangent at 
origin (@offset <0) or at end (@offset>path_length). Otherwise the transformation is not computed 
and 0 is returned
@mat: matrix to be transformed (transformation shall be appended) - the matrix shall not be initialized
@smooth_edges: indicates if discontinuities shall be smoothed. 
	If not set, the rotation angle THETA is
the slope (DX/DY) of the current segment found.
	if set, the amount of the object that lies on next segment shall be computed according to 
@length_after_point . let:
	len_last: length of current checked segment
	len1: length of all previous segments so that len1 + len_last >= offset
then if (offset + length_after_point > len1 + len_last) {
		ratio = (len1 + len_last - offset) / length_after_point;

	then THETA = ratio * slope(L1) + (1-ratio) * slope(L2)
(of course care must be taken for PI/2 angles & the like)

returns 1 if matrix has been updated, 0 otherwise (fail or point out of path without tangent extension)
*/
Bool m4_pathiterator_get_transform_at_offset(M4PathIterator *it, Fixed offset, Bool follow_tangent, M4Matrix2D *mat, Bool smooth_edges, Fixed length_after_point);


/* 2D Polygon convexity checking */
enum
{
	/*complex/unknown*/
	M4_POLYGON_COMPLEX,
	/*counter-clockwise convex*/
	M4_POLYGON_CONVEX_CCW,
	/*clockwise convex*/
	M4_POLYGON_CONVEX_CW,
	/*convex line (degenerated path - all segments aligned)*/
	M4_POLYGON_CONVEX_LINE
};
/*get convexity info for this 2D polygon*/
u32 m4_get_poly2D_convexity(M4Point2D *pts, u32 nb_pts);




/*YUV->RGB routines*/
void m4_yuv_to_rgb_555(unsigned char *dst, s32 dst_stride,
				 unsigned char *y_src, unsigned char * u_src, unsigned char * v_src,
				 s32 y_stride, s32 uv_stride, s32 width, s32 height);
void m4_yuv_to_rgb_565(unsigned char * dst, s32 dst_stride,
				 unsigned char* y_src, unsigned char* u_src, unsigned char* v_src,
				 s32 y_stride, s32 uv_stride, s32 width, s32 height);
void m4_yuv_to_bgr_24(unsigned char *dst, s32 dststride, 
				unsigned char *y_src, unsigned char *u_src, unsigned char * v_src, 
				s32 y_stride, s32 uv_stride, s32 width, s32 height);
void m4_yuv_to_rgb_24(unsigned char *dst, s32 dststride, unsigned char *y_src, unsigned char *u_src, unsigned char * v_src, 
				 s32 y_stride, s32 uv_stride, s32 width, s32 height);
void m4_yuv_to_rgb_32(unsigned char *dst, s32 dststride, 
				unsigned char *y_src, unsigned char *v_src, unsigned char * u_src,
				s32 y_stride, s32 uv_stride, s32 width, s32 height);
void m4_yuva_to_rgb_32(unsigned char *dst, s32 dststride, 
				 unsigned char *y_src, unsigned char *v_src, unsigned char * u_src, unsigned char *a_src,
				 s32 y_stride, s32 uv_stride, s32 width, s32 height);

/*for openGL texturing*/
void m4_yuv_to_rgb_24_flip(unsigned char *dst, s32 dststride, unsigned char *y_src, unsigned char *u_src, unsigned char * v_src, 
				 s32 y_stride, s32 uv_stride, s32 width, s32 height);



/*stencil alignment*/
typedef enum
{	
	/*line is centered on path (-width/2, +width/2)*/
	M4_PATH_LINE_CENTER = 0,
	/*line is inside path*/
	M4_PATH_LINE_INSIDE,
	/*line is outside path*/
	M4_PATH_LINE_OUTSIDE,
} M4LineAlignement;

/*line cap*/
typedef enum
{
	/*end of line is flat*/
	M4_LINE_CAP_FLAT = 0,
	/*end of line is round*/
	M4_LINE_CAP_ROUND,
	/*end of line is square*/
	M4_LINE_CAP_SQUARE,
	/*end of line is triangle*/
	M4_LINE_CAP_TRIANGLE,
} M4LineCap;

/*line join - match XLineProperties values*/
typedef enum
{
	/*miter join*/
	M4_LINE_JOIN_MITER = 0,
	/*round join*/
	M4_LINE_JOIN_ROUND,
	/*bevel join*/
	M4_LINE_JOIN_BEVEL,
} M4LineJoin;

/*dash styles*/
typedef enum
{
	/*no dash - default*/
	M4_DASHSTYLE_PLAIN = 0,
	M4_DASHSTYLE_DASH,
	M4_DASHSTYLE_DOT,
	M4_DASHSTYLE_DASH_DOT,
	M4_DASHSTYLE_DASH_DASH_DOT,
	M4_DASHSTYLE_DASH_DOT_DOT,
	M4_DASHSTYLE_CUSTOM,
} M4DashStyle;

/*when dash style is custom, structure indicates dash pattern */
typedef struct
{
	u32 num_dash;
	Fixed *dashes;
} M4DashSettings;

typedef struct
{
	Fixed width;
	M4LineCap cap;
	M4LineJoin join;
	M4LineAlignement align;
	Fixed miterLimit;
	M4DashStyle dash;
	Fixed dash_offset;
	/*valid only when dash style is M4_DASHSTYLE_CUSTOM*/
	M4DashSettings *dash_set;
} M4PenSettings;

M4Path *m4_path_get_outline(M4Path *path, M4PenSettings pen);




/*stencil types*/
typedef enum
{
	/*solid color stencil*/
	M4_STENCIL_SOLID = 0,
	/*linear color gradient stencil*/
	M4_STENCIL_LINEAR_GRADIENT,
	/*radial color gradient stencil*/
	M4_STENCIL_RADIAL_GRADIENT,
	/*texture stencil*/
	M4_STENCIL_VERTEX_GRADIENT,
	/*texture stencil*/
	M4_STENCIL_TEXTURE,
} M4StencilType;


/*gradient filling modes*/
typedef enum
{
	/*edge colors are repeated until path is filled*/
	M4_GRADIENT_MODE_PAD,
	/*pattern is inversed each time it's repeated*/
	M4_GRADIENT_MODE_SPREAD,
	/*pattern is repeated to fill path*/
	M4_GRADIENT_MODE_REPEAT
} M4GradientMode;


/*texture modes*/
typedef enum
{
	/*texture is tiled across the path - this is the default mode if not specified*/
	M4_TEXTURE_TILE_BASE = 0,
	/*tiling with X-fliping at each repeat*/
	M4_TEXTURE_TILE_FLIP_X,
	/*tiling with Y-fliping at each repeat*/
	M4_TEXTURE_TILE_FLIP_Y,
	/*tiling with X and Y-fliping at each repeat*/
	M4_TEXTURE_TILE_FLIP_XY
} M4TextureTiling;

/*filter levels for texturing - up to the graphics engine but the following levels are used by
the client*/
typedef enum
{
	/*high speed mapping (ex, no filtering applied)*/
	M4_TEXTURE_FILTER_HIGH_SPEED,
	/*compromise between speed and quality (ex, filter to nearest pixel)*/
	M4_TEXTURE_FILTER_MID,
	/*high quality mapping (ex, bi-linear/bi-cubic interpolation)*/
	M4_TEXTURE_FILTER_HIGH_QUALITY
} M4TextureFilter;

/* rasterizer antialiasing depending on the graphics engine*/
typedef enum
{
	/*raster should use fastest mode possible (eg, no antialiasing)*/
	M4_RASTER_HIGH_SPEED,
	/*raster should use fast mode and good quality if possible*/
	M4_RASTER_MID,
	/*raster should use antialiasing*/
	M4_RASTER_HIGH_QUALITY
} M4RasterLevel;


/*user routines for raserizer. common syntaxes:
	@cbk: user defined callback
	@x, y: first pixel position of the run, in device memory (top-left) coordinates
	@run_h_len: number of pixels to fill on line
	@color: color to fill pixel with. USER MUST IGNORE THE ALPHA COMPONENT OF THIS COLOR, the final 
		alpha is computed by the lib
	@alpha: blending amount (0->0xFF) for the pixels
*/
typedef struct
{
	void *cbk;
	/*fills line pixels without any blending operation*/
	void (*fill_run_no_alpha)(void *cbk, u32 x, u32 y, u32 run_h_len, M4Color color);
	/*fills line pixels without blending operation - alpha combines both fill color and anti-aliasing blending*/
	void (*fill_run_alpha)(void *cbk, u32 x, u32 y, u32 run_h_len, M4Color color, u32 alpha);
} M4RasterCallback;



/*opaque handler for all stencils*/
typedef void * LPM4STENCIL;

/*visual surface handler*/
typedef void *LPM4SURFACE;

/*interface name for video driver*/
#define M4_RASTER_2D_INTERFACE		FOUR_CHAR_INT('M','R','2','D')

/*graphics driver*/
typedef struct _raster2d_interface
{
	/* interface declaration*/
	M4_DECL_PLUGIN_INTERFACE

	LPM4STENCIL (*stencil_new) (struct _raster2d_interface *, M4StencilType type);
	/*common destructor for all stencils*/
	void (*stencil_delete) (LPM4STENCIL _this);
	/*set stencil transformation matrix*/
	M4Err (*stencil_set_matrix) (LPM4STENCIL _this, M4Matrix2D *mat);
	/*solid brush - set brush color*/
	M4Err (*stencil_set_brush_color) (LPM4STENCIL _this, M4Color c);
	/*gradient brushes*/
	/*sets gradient repeat mode - return M4NotSupported if driver doesn't support this to let the app compute repeat patterns
	this may be called before the gradient is setup*/
	M4Err (*stencil_set_gradient_mode) (LPM4STENCIL _this, M4GradientMode mode);
	/*set linear gradient.  line is defined by start and end, and you can give interpolation colors at specified positions*/
	M4Err (*stencil_set_linear_gradient) (LPM4STENCIL _this, Fixed start_x, Fixed start_y, Fixed end_x, Fixed end_y, M4Color start_col, M4Color end_col);
	/*radial gradient brush center point, focal point and radius - colors can only be set through set_interpolation */
	M4Err (*stencil_set_radial_gradient) (LPM4STENCIL _this, Fixed cx, Fixed cy, Fixed fx, Fixed fy, Fixed x_radius, Fixed y_radius);
	/*radial and linear gradient (not used with vertex) - set color interpolation at given points, 
		@pos[i]: distance from (center for radial, start for linear) expressed between 0 and 1 (1 being the gradient bounds)
		@col[i]: associated color
	NOTE 1: the colors at 0 and 1.0 MUST be provided
	NOTE 2: colors shall be fed in order from 0 to 1
	NOTE 3: this overrides the colors provided for linear gradient
	*/
	M4Err (*stencil_set_gradient_interpolation) (LPM4STENCIL _this, Fixed *pos, M4Color *col, u32 count);

	/*vertex gradient : set limit path */
	M4Err (*stencil_set_vertex_path) (LPM4STENCIL _this, M4Path *path);
	/*set the center of the gradient*/
	M4Err (*stencil_set_vertex_center) (LPM4STENCIL _this, Fixed cx, Fixed cy, u32 color);
	/*set the center of the gradient*/
	M4Err (*stencil_set_vertex_colors) (LPM4STENCIL _this, u32 *colors, u32 nbCol);
	
	
	/*set stencil texture
		@pixels: texture data, from top to bottom
		@width, @height: texture size
		@stride: texture horizontal pitch (bytes to skip to get to next row)
		@pixelFormat: texture pixel format as defined in file m4_tools.h
		@destination_format_hint: this is the current pixel format of the destination surface, and is given
		as a hint in case the texture needs to be converted by the stencil
		@no_copy: if set, specifies the texture data shall not be cached by the plugin (eg it must be able
		to directly modify the given memory
	NOTE: this stencil acts as a data wrapper, the pixel data is not required to be locally copied
	data is not required to be available for texturing until the stencil is used in a draw operation
	*/
	M4Err (*stencil_set_texture) (LPM4STENCIL _this, unsigned char *pixels, u32 width, u32 height, u32 stride, M4PixelFormat pixelFormat, M4PixelFormat destination_format_hint, Bool no_copy);
	/*creates internal texture - pixel data is owned by texture brush - set to NULL if not supported - this is used to 
	cope with engines that don't support random strides (ex: Gdiplus needs stride to be a multiple of 4) 
	if not set the renderer will create its own mem texture and pass it through set_texture - pixel format shall 
	be respected as far as Alpha is concerned (eg alpha info shall be kept and used in blit) */
	M4Err (*stencil_create_texture) (LPM4STENCIL _this, u32 width, u32 height, M4PixelFormat pixelFormat);
	/*signals the texture has been modified (internal texture only)*/
	void (*stencil_texture_modified) (LPM4STENCIL _this);

	/*sets alpha blending level for texture - the alpha channel shall be combined with the color matrix if any*/
	M4Err (*stencil_set_texture_alpha) (LPM4STENCIL _this, u8 alpha);
	/*sets texture tile mode*/
	M4Err (*stencil_set_tiling) (LPM4STENCIL _this, M4TextureTiling mode);
	/*sets texture filtering mode*/
	M4Err (*stencil_set_filter) (LPM4STENCIL _this, M4TextureFilter filter_mode);
	/*set stencil color matrix - texture stencils only*/
	M4Err (*stencil_set_color_matrix) (LPM4STENCIL _this, M4ColorMatrix *cmat);
	/*reset stencil color matrix - texture stencils only*/
	M4Err (*stencil_reset_color_matrix) (LPM4STENCIL _this);

	/*creates surface object*/
	/* @center_coords: true indicates mathematical-like coord system, 
					   false indicates computer-like coord system */
	LPM4SURFACE (*surface_new) (struct _raster2d_interface *, Bool center_coords);
	/* delete surface object */
	void (*surface_delete) (LPM4SURFACE _this);

	/* attach surface object to device object (Win32: HDC) width and height are target surface size*/
	M4Err (*surface_attach_to_device) (LPM4SURFACE _this, void *os_handle, u32 width, u32 height);
	/* attach surface object to stencil object*/
	M4Err (*surface_attach_to_texture) (LPM4SURFACE _this, LPM4STENCIL sten);
	/* attach surface object to memory buffer if supported
		@pixels: texture data
		@width, @height: texture size
		@stride: texture horizontal pitch (bytes to skip to get to next row)
		@pixelFormat: texture pixel format
	*/
	M4Err (*surface_attach_to_buffer) (LPM4SURFACE _this, unsigned char *pixels, u32 width, u32 height, u32 stride, M4PixelFormat pixelFormat);

	M4Err (*surface_attach_to_callbacks) (LPM4SURFACE _this, M4RasterCallback *callbacks, u32 width, u32 height);

	/* detach surface object */
	void (*surface_detach) (LPM4SURFACE _this);

	/*sets rasterizer precision */
	M4Err (*surface_set_raster_level) (LPM4SURFACE _this, M4RasterLevel RasterSetting);
	/* set the given matrix as the current transformations for all drawn paths
	if NULL reset the current transformation */
	M4Err (*surface_set_matrix) (LPM4SURFACE _this, M4Matrix2D *mat);
	/* set the given rectangle as a clipper - nothing will be drawn outside this clipper
	if the clipper is NULL then no clipper is set
	NB: the clipper is not affected by the surface matrix and is given in pixels
	CF ABOVE NOTE ON CLIPPERS*/
	M4Err (*surface_set_clipper) (LPM4SURFACE _this, M4IRect *rc);

	/*sets the given path as the current one for drawing - the surface transform is NEVER changed between
	setting the path and filling, only the clipper may change*/
	M4Err (*surface_set_path) (LPM4SURFACE _this, M4Path *path);
	/*fills the current path using the given stencil - can be called several times with the same current path*/
	M4Err (*surface_fill) (LPM4SURFACE _this, LPM4STENCIL stencil);

	/*flushes to surface*/
	M4Err (*surface_flush) (LPM4SURFACE _this);

	/*clears given pixel rect on the surface with the given color - REQUIRED
	the given rect is formatted as a clipper - CF ABOVE NOTE ON CLIPPERS*/
	M4Err (*surface_clear)(LPM4SURFACE _this, M4IRect *rc, M4Color col);

/*private:*/
	void *internal;
} Raster2D;


#define M4_FONT_RASTER_INTERFACE		FOUR_CHAR_INT('M','F','N','T')

typedef struct _font_raster
{
	/* interface declaration*/
	M4_DECL_PLUGIN_INTERFACE

	/*inits font engine.*/
	M4Err (*init_font_engine)(struct _font_raster*dr);
	/*shutdown font engine*/
	M4Err (*shutdown_font_engine)(struct _font_raster*dr);

	/*set active font . @styles indicates font styles (PLAIN, BOLD, ITALIC, 
	BOLDITALIC and UNDERLINED, STRIKEOUT)*/
	M4Err (*set_font)(struct _font_raster*dr, const char *fontName, const char *styles);
	/*set active font pixel size*/
	M4Err (*set_font_size)(struct _font_raster*dr, Fixed pixel_size);
	/*gets font metrics*/
	M4Err (*get_font_metrics)(struct _font_raster*dr, Fixed *ascent, Fixed *descent, Fixed *lineSpacing);
	/*gets size of the given string (wide char)*/
	M4Err (*get_text_size)(struct _font_raster*dr, const unsigned short *string, Fixed *width, Fixed *height);

	/*add text to path - graphics driver may be changed at any time, therefore the font engine shall not 
	cache graphics data
		@path: target path
		x and y scaling: string display length control by the renderer, to apply to the text string
		left and top: top-left corner where to place the string (top alignment)
		ascent: offset between @top and baseline - may be needed by some fonts engine
		bounds: output bounds of the added text including white space
		flipText: true = BIFS, false = SVG
	*/
	M4Err (*add_text_to_path)(struct _font_raster*dr, M4Path *path, Bool flipText,
					const unsigned short* string, Fixed left, Fixed top, Fixed x_scaling, Fixed y_scaling, 
					Fixed ascent, M4Rect *bounds);
/*private*/
	void *priv;
} FontRaster;


#ifdef __cplusplus
}
#endif


#endif	/*M4_RASTER_2D_H*/

