/* @(#)shape.h 9.4 88/01/19 SMI	 */

/*
 * Copyright (c) 1985 by Sun Microsystems, Inc. 
 */

/*-
	Definitions for shapes

	shape.h, Thu Jun 27 09:38:35 1985

		James Gosling,
		Sun Microsystems
 */

#ifndef sh_decref
#ifndef major
#ifdef SUN
#include <sys/types.h>
#endif
#endif
#ifndef pr_width
#include <pixrect/pixrect.h>
#endif
#ifndef FRACT
#include "fract.h"
#endif

/*
 * A path is a set of infinitly thin, possibly curved, lines.  It can be
 * used as the trajectory of a pen or as the boundary of a region. 
 */
struct path {
    short       size,		/* The amount of space available in the
				 * path */
                used;		/* The amount of space used by the path */
    int         straight:1;	/* True iff all elements of the path are
				 * straight */
    int         eorule:1;	/* true iff the boundary specifies a
				 * region using the even/odd winding
				 * number rule. False implies the nonzero
				 * winding number rule */
    short       bottompos;	/* The bottom position in the path element
				 * list that is usable -- this get changed
				 * by gsave/grestore */
    short       startpos;	/* The position in the path element list
				 * where the first entry in the path
				 * starts. This can be different from
				 * bottompos if a gsave is done when the
				 * current path is non-empty */
    struct path_element *element;	/* The array of path elements */
};


/*
 * A shape is a possibly discretized version of a path.  Besides
 * containing a path, it contains many alternate representations for the
 * path 
 */
struct shape {
    struct spoint pos;		/* position of bbox */
    struct spoint size;		/* size of bbox; size.x<0 => bbox not
				 * known */
    short       refcnt;		/* The number of references to this shape */
    short       is_rect:1;	/* true iff this shape is rectangular, and
				 * hence only the bbox is valid */
    struct shape_trapezon *trapset;	/* The set of trapezons that
					 * define this shape (optional) */
#ifdef undef
    struct spoint pix_off;	/* The coordinates of the upper left hand
				 * corner of the pixrect */
    struct pixrect *pixrect;	/* The pixrect that defines this shape
				 * (optional) */
    struct shape_dcurve *curve;	/* The unit-width stroke representation */
    struct path path;		/* The path that defines this shape
				 * (optional) */
#endif
};

#define sh_decref(sh) (--(sh)->refcnt <= 0 ? sh_freeshape(sh) : 0)
#define sh_incref(sh) ((sh)->refcnt++)
#define STATIC_OBJ (-0xfff)


/* A segment in a trapezon */
struct shape_trapseg {
    short       y;		/* Y coordinate of segment */
    short       x1;		/* X start of row */
    short       x2;		/* X end of row - this pixel isnt to be
				 * set - ie. the width is x2-x1 */
};

struct shape_trapezon {		/* A trapezon describes a region that has
				 * a flat top and bottom, but whose sides
				 * may be curved -- they are are allowed
				 * to be vertically concave -- for each
				 * edge, there is a single x for each y */
    struct shape_trapezon *next;
    short       refcnt;		/* The number of references to this
				 * trapezon */
    short       top,		/* Y coordinates of the top and bottom of
				 * the trapezon */
                bottom, left, right;
    short       used,		/* The number of segments used */
                size;		/* The number of segments for which space
				 * is allocated */
    struct shape_trapseg segs[1];	/* The scanlines that make up this
					 * trapezon */
};

struct shape_arc {		/* A conic arc from point A to point C
				 * drawn towards point B with sharpness sh */
    struct shape_arc *next;
    struct fpoint A, B, C;
    fract       sh;
};


struct shape_dcurve {		/* A discrete representation of a curve. A
				 * curve starts at point x0,y0 and ends at
				 * point x1,y1.  For each of the y1-y0+1
				 * rows there is exactly one x value,
				 * contained in the x array. y0<=y1 */
    short       x0, y0, x1, y1;
    short       left,		/* The left and right edges of the bbox */
                right;
    struct shape_dcurve *next;
    char        direction;	/* 1=>down, -1=>up */
    short	refcnt;
    short       *x;
};

struct path_element {
    fract       variation;
    struct fpoint pos;		/* The transformed point */
};

#define MOVE_TO_FLAG (1<<31)	/* In a path_element, if variation equals
				 * MOVE_TO_FLAG then that element is the
				 * first point in a new loop */
#define CLOSEPATH_FLAG ((1<<31)+1)	/* If a path_element has a
					 * variation of CLOSEPATH_FLAG
					 * then it closes off a path
					 * segment and its x&y are
					 * meaningless */

#define has_current_pos(path) ((path)->used > (path)->startpos)
#define current_pos(path) ((path)->element[(path)->used-1].pos)

/*
 * A fast test for the important special case of the current path being a
 * rectangle 
 */
#define IS_RECT(path) (((path)->used - (path)->startpos == 4 \
			|| (path)->used - (path)->startpos == 5 && \
			   (path)->element[4].variation == CLOSEPATH_FLAG) \
			&& (path)->straight && \
	    (((path)->element[0].pos.x == (path)->element[1].pos.x && \
	      (path)->element[2].pos.x == (path)->element[3].pos.x && \
	      (path)->element[0].pos.y == (path)->element[3].pos.y && \
	      (path)->element[1].pos.y == (path)->element[2].pos.y) \
	     || ((path)->element[0].pos.y == (path)->element[1].pos.y && \
		 (path)->element[2].pos.y == (path)->element[3].pos.y && \
		 (path)->element[0].pos.x == (path)->element[3].pos.x && \
		 (path)->element[1].pos.x == (path)->element[2].pos.x)))



typedef fract FMATRIX[3][2];
typedef float FLMATRIX[3][2];

enum TransformOpt {		/* The kinds of transformation optimizations */
    tro_none,			/* No optimization */
    tro_check,			/* No opt, overflow possible */
    tro_unit,			/* [1 0 0 1 x y] */
    tro_neg,			/* [1 0 0 -1 x y] */
    tro_scale,			/* [a 0 0 b x y] */
    tro_scalecheck,		/* [a 0 0 b x y], overflow possible */
};

/* A transformation matrix: pt = xfact*x+yfact*y+offset */
struct transform {
    char        well_behaved;	/* true iff it maps a "small" range into
				 * display coordinates */
    char        rigid;		/* true iff this is a rigid transform, ie.
				 * it consists of only rotations,
				 * translations and scaling */
    enum TransformOpt kind:8;	/* 1=>matrix==[1 0 0 1 x y] (unit scaling)
				 * -1=>matrix==[1 0 0 -1 x y] (unit scaling,
				 * y inversion */
    char        floatexists;	/* true iff the floating point form of the
				 * transform exists */
    char	simplescale;	/* true iff matrix==[s 0 0 -s x y] */
    fract	checklimit;	/* Maximum input value that can be
				   transformed without overflow */
    int		revision;	/* The "revision level" of this matrix.
				   Incremented each time the matrix is
				   changed */
    FMATRIX     matrix;
    double      rmatrix[3][2];
};

struct color {
    unsigned char
		red, green, blue, /* The color components */
                hint;		  /* lookup hint */
};

enum cs_linejoin {
    cs_miterjoin,
    cs_roundjoin,
    cs_beveljoin,
};

enum cs_linecap {
    cs_buttcap,
    cs_roundcap,
    cs_squarecap,
};

/* A graphics context */
struct graphics_context {
    struct pixrect *canvas;	/* The current output canvas */
    struct path path;		/* The current path */
    struct shape *shape;	/* The discrete form of the current path */
    struct shape *clip;		/* The clipping boundary */
    fract       linewidth;	/* The width of a line */
    short	trlinewidth;	/* Transformed line width */
    char	newwidth;	/* True iff the line width has changed */
    enum cs_linecap linecap:8;	/* The style used to cap lines.  0=Butt,
				 * 1=round, 2=projecting square cap */
    enum cs_linejoin linejoin:8;/* The style used to join lines.  0=Miter,
				 * 1=round, 2=bevel */
    char	hascurrentpoint;/* True if the currentpoint is valid */
    char	printermatch;	/* True if printer font matching should be
				   done */
    char	strokequality;	/* 0->64 improving quality; -ve implies width
				   is so narrow that quality doesn't matter */
    char	flatness;	/* maximum acceptable pixel error in
				   converting curves to straight lines */
    fract       miterlimit;	/* limit for switching from mitered to
				 * beveled line joins */
    fract       texture[5];	/* Line dash pattern */
    fract	offset;		/* The offset into the dash pattern */
    int		textrevision;	/* The transformation revision for which the
				   texture has been revised */
    fract	ttexture[5];	/* Transformed texture */
    fract	toffset;	/* Transformed texture offset */
    struct psfont *font;	/* The current text font */
    struct color color;		/* The current color */
    struct fpoint currentpoint;	/* The last point moved or drawn to */
    struct graphics_context *gsaves;	/* The set of graphics states in the gsave
					 * stack */
    short       gsave_used;	/* The number of stacked gsaves */
    short       gsave_size;	/* The amount of space allocated in gsaves */
    struct transform transform;	/* The transformation to be applied to
				 * points being added to the current path */
    short       func;		/* The technique for applying the color.
				 * Its actually the rasterop function
				 * code. The useful values are PIX_SRC
				 * |,&,^ PIX_DST.  It may have a color
				 * mixed in. */
    struct pixrect *pattern;	/* The pattern to be applied.  NULL
				 * implies the uniform pattern, in which
				 * case func will be either PIX_SET or
				 * PIX_CLR */
};

extern struct fpoint shape_point; /* The transformation & path building
				   * operators sometimes communicate via
				   * shape_point */
extern struct rpoint shape_rpoint; /* ditto here if the results are real */

struct fcorner_bbox {		/* A bounding box specified by its corners */
    struct fpoint ur,		/* upper right */
		  ll;		/* lower left */
};

/* Maps for converting from RGB colors to colormap indicies */
extern unsigned char red_inverse[];
extern unsigned char green_inverse[];
extern unsigned char blue_inverse[];
extern unsigned char grey_inverse[];
extern unsigned char grey_opcode[];
#define sh_colorhint(color) ((color)->red == (color)->green && (color)->green == (color)->blue \
			     ? grey_inverse[(color)->green] \
			     : red_inverse[(color)->red] + green_inverse[(color)->green] \
				 + blue_inverse[(color)->blue])
#define pixrectopcode(pr,color) \
    ((pr)==0 ? PIX_SET \
	 : (pr)->pr_depth==1 \
		? grey_opcode[(color)->hint] \
		: PIX_SRC | PIX_COLOR((color)->hint))
extern struct color black_color, white_color;
struct color cs_frrgbcolor();
struct graphics_context *cs_newcontext();
struct color cs_frhsbcolor();
struct spoint cs_abscanvaslocation();
struct shape *sh_difference();
struct shape *sh_intersect();
struct shape *sh_copy();
struct shape *sh_translate();
struct shape *cv_pathtoshape(/*gc,mask*/);
struct shape_arc *path_to_arc();
struct shape_trapezon *looptotrap();
struct pixrect *fake_bw2_make();

extern struct shape InfiniteShape;
extern struct shape InvalidShape;
extern struct graphics_context *temp_context;

#define TOP(p) ((p)->pos.y)
#define LEFT(p) ((p)->pos.x)
#define BOTTOM(p) ((p)->pos.y+(p)->size.y)
#define RIGHT(p) ((p)->pos.x+(p)->size.x)
#define SETBOTTOM(p,b) ((p)->size.y = (b) - (p)->pos.y)
#define SETRIGHT(p,b) ((p)->size.x = (b) - (p)->pos.x)
#define SETTOP(p,t) ((p)->pos.y = (t))
#define SETLEFT(p,l) ((p)->pos.x = (l))

extern int ovl_state;			/* -1=>overlay exists, but down;
				   0=>no overlay
				   1=>overlay exists and is up */
#define OVERLAYDOWN() (ovl_state>0 ? ovl_overlaydown() : 0)
#define OVERLAYUP() (ovl_state<0 ? ovl_overlayup() : 0)

#ifndef assert
#ifdef DEBUG
#define assert(x) (!(x) ? fprintf(stderr,"Assertion failed x  [file %s, line %d]\n", __FILE__, __LINE__),abort(1) : 0)
#else
#define assert(x) (0)
#endif
#endif
#ifndef abs
#define abs(v) ((v)<0 ? -(v) : (v))
#endif
#ifndef min
#define min(a,b) ((a)<(b) ? (a) : (b))
#define max(a,b) ((a)>(b) ? (a) : (b))
#define sadd(a,b) ((short)(((short)(a))+((short)(b))))
#define ssub(a,b) ((short)(((short)(a))-((short)(b))))
#endif
#endif