/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>




/* TeX starts here. Do not remove this comment. */

/*
\section{Rendering}
This section describes the internal routines and data structures
associated with rendering.

/*
\paragraph{Xfield}  The {\tt xfield} data structure contains information
extracted from a field.  Extracting this information once avoids a lot
of overhead.  The {\tt tile} structure contains tiling parameters relevant
to the field.  We declare it as a separate structure, because we use it
later on to pass down tiling parameters as we traverse the structure.
*/

struct tile {		/* tiling parameters */
    int ignore;		/* don't get new parameters - e.g. w/in comp field */
    int fast_exp;	/* use fast exponent in volume rendering */
    int flat_x;		/* flat x in volume rendering */
    int flat_y;		/* flat y in volume rendering */
    int flat_z;		/* flat z in volume rendering */
    int skip;		/* skip faces at random in volume rendering */
    int patch_size;	/* volume rendering patch size */
    float color_multiplier;	/* multiplier for volume colors */
    float opacity_multiplier;	/* multiplier for volume opacities */
    int if_group;	/* in interference group */
    int if_object;	/* in interference object */
    int perspective;	/* do perspective for this field? */
    enum approx {
	approx_none,	/* no approximation */
	approx_flat,	/* flat shading - NOT IMPLEMENTED */
	approx_lines,	/* line rendering - NOT IMPLEMENTED */
	approx_dots,	/* dots */
	approx_box	/* box */
    } approx;
};

Error _dxf_approx(Object o, enum approx *approx);


#define MAXLIGHTS 100

struct lightList
{
    int      na;
    int      nl;
    RGBColor ambient;
    Light    lights[MAXLIGHTS];
    Vector   h[MAXLIGHTS];
};

typedef struct lightList *LightList;

typedef enum {
	dep_positions,
	dep_connections,
	dep_polylines
} dependency;

struct xfield {

    Point *box;			/* bounding box */
    int nbox;
    float nearPlane;			/* near plane for perspective clipping */

    /* positions and typically point-dependent data */
    Point *positions;		/* control points */
    Pointer fcolors, bcolors;	/* front/back colors or byte data */
    RGBColor *cmap;		/* color map iff above is byte data */
    Pointer opacities;		/* opacities or byte data */
    float *omap;		/* opacity map iff above is byte data */
    Vector *normals;		/* normals */

    /* counts */
    int npositions;		/* number of positions */
    int ncolors;		/* number of colors, normals, opacities */

    /* dependencies */
    dependency colors_dep, normals_dep;

    /* standard connections */
    enum ct {			/* type of connections */
	ct_none,		/* none specified */
	ct_lines,		/* line segments */
	ct_polylines,		/* line segments */
	ct_triangles,		/* triangles */
	ct_quads,		/* quads */
	ct_tetrahedra,		/* tetrahedra */
	ct_cubes		/* cubes */
    } ct;
    union {			/* data array for the irregular ones only */
	Line *lines;
	Triangle *triangles;
	Tetrahedron *tetrahedra;
	Quadrilateral *quads;
	Cube *cubes;
	int *i;
    } c;
    int volume;			/* whether it is a volume connection */
    int nconnections;		/* number of connection elements */
    Pointer neighbors;		/* neighbors data */

    int *polylines, npolylines;	/* polylines are handled separately since */
    int *edges, nedges;         /* they require an indirection through an */
				/* "edges" component			  */

    /* information about regular partition */
    Point o;			/* back corner of partition */
    Vector d[3];		/* axes of partition box, relative to o */
    int n;			/* point id of back corner of partition */
    int k[3], s[3];		/* counts, strides in each direction */
    int cn;			/* point id of back corner of partition */
    int ck[3], cs[3];		/* counts, strides in each direction */

    /* tiling options applicable to this field */
    struct tile tile;

    /* the arrays */
    Array box_array;
    Array positions_array;
    Array neighbors_array;
    Array fcolors_array;
    Array bcolors_array;
    Array opacities_array;
    Array normals_array;
    Array faces_array;
    Array polylines_array;
    Array loops_array;
    Array edges_array;
    Array inner_array;
    Array connections_array;
    Array cmap_array;
    Array omap_array;

    /* flags to indicate whether data is local */
    char box_local;
    char positions_local;
    char neighbors_local;
    char opacities_local;
    char fcolors_local;
    char bcolors_local;
    char normals_local;
    char surface_local;
    char inner_local;
    char faces_local;
    char polylines_local;
    char loops_local;
    char edges_local;
    char cmap_local;
    char omap_local;
    char volAlg;

    InvalidComponentHandle iElts, iPts;

    /*
     * lighting parameters for delayed lighting
     */
    LightList lights;
    float kaf, kdf, ksf;
    int   kspf;
    float kab, kdb, ksb;
    int   kspb;

    int   *indices;

    /*
     * The following has been added to support constant normals and colors
     * components without expansion.  If the components are constant, the 
     * following buffers will contain the component value and the cst flags
     * will be set.
     */
    Point    nbuf;
    RGBColor fbuf, bbuf;
    float    obuf;
    char     fcst, bcst, ncst, ocst;
    char     fbyte, bbyte, obyte;

};

enum xr {
    XR_OPTIONAL=0,
    XR_REQUIRED=1
};

enum xd {
    XD_NONE,
    XD_GLOBAL,
    XD_LOCAL
};

typedef enum
{
    INV_UNKNOWN,
    INV_VALID,
    INV_INVALID
} inv_stat;

void _dxf_XZero(struct xfield *xf);
Error _dxf_XBox(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XPositions(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XConnections(Field f, struct xfield *xf, enum xr required);
Error _dxf_XNeighbors(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XColors(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XNormals(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XOpacities(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XSurface(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XInner(Field f, struct xfield *xf, enum xr required, enum xd xd);
Error _dxf_XLighting(Field f, struct xfield *xf);
/**
These routines extract various components.  The {\tt xr} parameter
indicates whether the component is required, i.e. whether it is an
error for it not to be present.  The {\tt xd} parameter tells us
whether to get the data, and if so whether to copy it to local memory.
This is an issue because getting the data from a regular array
potentially involves expanding a compact representation.
**/

Error _dxf_XFreeLocal(struct xfield *xf);
/**
Frees the local data for all the arrays in {\tt *xf} that were copied
to local memory.
**/

/*
\paragraph{Rendering Buffer}  The rendering buffer data structure contains
information relevant to rendering a particular screen patch, including a
pointer to the pixels themselves (in local memory).  This section describes
the rendering buffer and a set of low-level routines for rendering primitives
into the buffer.
*/

struct rgbo {
    float r, g, b, o;
};

struct buffer {
    int width, height;			/* size */
    int ox, oy;				/* origin */
    int merged;				/* have back and z been merged? */
    Point min, max;			/* for bbox check */
    Point omin, omax;			/* object size for interference */
    Point fmin, fmax;			/* face size */

    union {
	struct big {
	    RGBColor c;			/* accumulated color */
	    struct rgbo co;		/* 1) volume interp 2) face color */
	    float z;			/* last rendered z */
	    float front, back;		/* front/back clip surfaces */
	    int in;			/* in/out of 1) volume 2) face */
	} *big;				/* buffer */
	struct fast {
	    RGBColor c;			/* color */
	    float z;			/* z value */
	} *fast;			/* fast buffer */
	struct zbuf {
	    float z;			/* z value */
	} *zbuf;
    } u;				/* possibly aligned buffer */
    enum pix_type {
	pix_big,
	pix_fast,
	pix_zbuf
    } pix_type;				/* buffer pixel type */
    Pointer buffer;			/* the buffer for freeing */
    
    int iwidth;				/* image width */
    union {
	struct fbpixel *fb;		/* image is fb pixels */
	struct RGBColor *rgb;		/* image is float colors */
	unsigned char *x;		/* image is x byte image */
    } img;
    enum img_type {
	img_fb,				/* image is fb pixels */
	img_rgb,			/* image is float colors */
	img_x				/* image is x byte image */
    } img_type;

    int init;				/* init method to use */
    int showpatches;			/* whether to show patch outline */
    int notriangles;			/* return at beginning of Triangle */
    int setuponly;			/* return after triangle setup */
    int tri;				/* triangle method to use */
    int irregular;			/* force irregular */
    char *vol;				/* regular volume method to use */
    int triangles;			/* return count */
    int pixels;				/* return count */
};

Error _dxf_InitBuffer(struct buffer *b, enum pix_type pix_type,
		  int width, int height, int ox, int oy, RGBColor c);
/**
Initialize a rendering buffer structure.
**/

Error _dxf_CopyBufferToImage(struct buffer *b, Field i, int xoff, int yoff);
Error _dxf_CopyBufferToFBImage(struct buffer *b, Field i, int xoff, int yoff);
Error _dxf_CopyBufferToXImage(struct buffer *b, Field i, int xoff, int yoff);
/**
Copies rendering buffer {\tt b} to image {\tt i} at the specified offset
in the image.  Returns {\tt b} or null to indicate an error.
**/

Error _dxf_BeginClipping(struct buffer *b);
/**
Initialize the buffer for clipping.
**/

Error _dxf_EndClipping(struct buffer *b);
/**
Restore the buffer after clipping.
**/

Error _dxfCapClipping(struct buffer *b, float);
/**
If in perspective, may need to cap the clipping volume
(eg. if part of the front surface was clipped away by the
Z clip).
**/

Error _dxf_Triangle(struct buffer *b, struct xfield *xf, int n,
		Triangle *tri, int *indices,
		int surface, int clip_status, inv_stat invalid_status);
Error _dxf_Quad(struct buffer *b, struct xfield *xf, int n,
		Quadrilateral *quad, int *indices,
		int surface, int clip_status, inv_stat invalid_status);
/**
Renders face {\tt tri} from field {\tt xf} into rendering buffer
{\tt b}, treating it as a surface face or an inner face according to
{\tt surface}.  Returns {\tt b} or null to indicate an error.
(Question: should we include {\tt clip\_status} as an argument to
allow selection of clipped/non-clipped algorithm, for performance?)
**/

Error _dxf_TriangleFlat(struct buffer *b, struct xfield *xf, int n,
		    Triangle *tri, int *indices,
		    Pointer front, Pointer back, Pointer o,
		    int surface, int clip_status, inv_stat invalid_status);
Error _dxf_QuadFlat(struct buffer *b, struct xfield *xf, int n,
		    Quadrilateral *quad, int *indices,
		    Pointer front, Pointer back, Pointer o,
		    int surface, int clip_status, inv_stat invalid_status);
/**
Renders face {\tt tri} from field {\tt xf} into rendering buffer
{\tt b}, treating it as a surface face or an inner face according to
{\tt surface}.  Uses flat shading with specified color and opacity.
Returns {\tt b} or null to indicate an error.
**/

Error _dxf_TriangleClipping(struct buffer *b, struct xfield *xf,
			    int n, Triangle *tri, int *indices);
Error _dxf_QuadClipping(struct buffer *b, struct xfield *xf,
			int n, Quadrilateral *quad, int *indices);
/**
Renders face {\tt tri} from field {\tt xf} as a clipping triangle.
**/

static Error _dxf_TriangleComposite(struct buffer *b, struct xfield *xf, int n,
				   Triangle *tri, int *indices,
			 	   int clip_status, inv_stat invalid_status);
static Error _dxf_QuadComposite(struct buffer *b, struct xfield *xf, int n,
			 	Quadrilateral *quad, int *indices,
			 	int clip_status, inv_stat invalid_status);
/**
Composites a triangle or a quad.
**/

Error _dxf_TriangleCompositeFlat(struct buffer *b, struct xfield *xf, int n,
			     Triangle *tri, int *indices, Pointer colors,
			     Pointer op, int clip_status, inv_stat invalid_status);
Error _dxf_QuadCompositeFlat(struct buffer *b, struct xfield *xf, int n,
			     Quadrilateral *quad, int *indices, Pointer colors,
			     Pointer op, int clip_status, inv_stat invalid_status);

Error _dxf_Polyline(struct buffer *b, struct xfield *xf, int n, int *line,
	    int *indices, int clip_status, inv_stat invalid_status);
Error _dxf_PolylineFlat(struct buffer *b, struct xfield *xf, int n, int *line,
		int *indices,
		Pointer colors, Pointer opacities, int clip_status, inv_stat invalid_status);

Error _dxf_Line(struct buffer *b, struct xfield *xf, int n, Line *line,
	    int *indices, int clip_status, inv_stat invalid_status);
Error _dxf_LineFlat(struct buffer *b, struct xfield *xf, int n, Line *line,
		int *indices,
		Pointer colors, Pointer opacities, int clip_status, inv_stat invalid_status);

Error _dxf_Points(struct buffer *b, struct xfield *xf);
Error _dxf_Point(struct buffer *b, struct xfield *xf, int i);
/**
DXRender all the positions of field {\tt xf} as points in buffer {\tt b}, or
render one translucent point.
**/

#define ALL8(b,op,m,x) ( \
    b[0].x op m.x && b[1].x op m.x && b[2].x op m.x && b[3].x op m.x && \
    b[4].x op m.x && b[5].x op m.x && b[6].x op m.x && b[7].x op m.x )
#define CULLBOX(b,min,max) \
    (ALL8(b,<,min,x)|| ALL8(b,<,min,y)||ALL8(b,>=,max,x)||ALL8(b,>=,max,y))


/*
\paragraph{Object traversal}  The following routines traverse entire objects.
In general, they are called from Tile.
*/

/* clip_status values */
#define CLIPPING (-1)			/* this is a clipping object */
#define UNCLIPPED 0			/* this is an unclipped object */
#define CLIPPED(x) ((x)>0)		/* this is a clipped object */
#define NEST(x) ((x)+1)			/* nested clipping */

Object _dxfPaint(Object o, struct buffer *b, int clip_status, struct tile *tile);
/**
Adds the opaque parts of the {\tt Object} to the rendering buffer.
The {\tt clip} argument specifies whether we are rendering an unclipped
object, rendering a clipped object, or rendering the object that does
the clipping.  Returns {\tt b} or null to indicate an error.
**/

struct count {
    lock_type DXlock;		/* for parallel update */
    int nx, ny;			/* input number of screen patches */
    int width, height;		/* size of image */
    int irregular;		/* number of irregular (vol/surf) fields */
    int volume;			/* number of volume fields */
    int regular;		/* number of regular volume fields */
    int fast;			/* whether fast small fb can be used */
    struct pcount {		/* patch count */
	int nconnections;	/* number of connections for work estimate */
	int tfields;		/* number of translucent fields */
	int nbytes;		/* number of bytes for sort array */
    } *pcount;
};

#define SORT_POINT	    1	/* index into point connections component */
#define SORT_LINE	    2	/* index into line connections component */
#define SORT_POLYLINE	    3	/* index into line connections component */
#define SORT_TRI	    4	/* index into triangle connections component */
#define SORT_QUAD	    5	/* index into quads connections component */
#define SORT_TRI_PTS	    6	/* three point indices forming a triangle */
#define SORT_QUAD_PTS	    7	/* four point indices forming a quad */
#define SORT_TRI_FLAT	    8	/* three point indices plus color index */
#define SORT_QUAD_FLAT	    9	/* four point indices plus color index */

/*
 * For volume elements that we a) sort and b) have to render even if
 * invalid, determine the validity type.
 */
#define SORT_INV_TRI_PTS   10	/* three point indices forming a triangle */
#define SORT_INV_QUAD_PTS  11	/* four point indices forming a quad */
#define SORT_INV_TRI_FLAT  12	/* three point indices plus color index */
#define SORT_INV_QUAD_FLAT 13	/* four point indices plus color index */

struct sort {
    short field;		/* index into gather->xfields array */
    char type;			/* type (one of the SORT_... constants) */
    char surface;		/* whether it's a surface face */
};

struct sortindex {
    struct sort *sort;
    float z;
};

struct gather {
    int cull;			/* do/don't cull (e.g. perspective) XXX */
    Point min, max;		/* bounds to cull clip against */
    struct sort *sort;		/* beginning of sort array */
    struct sort *current;	/* current position in sort array */
    int nthings;		/* number of triangles, etc. seen */
    int nfields;		/* number of fields seen */
    struct xfield *fields;	/* array of xfield data structures */
    Object clipping;		/* clipping object for translucent surfaces */
};

Object _dxfGather(Object o, struct gather *gather, struct tile *tile);
/**
Gathers all the translucent faces from {\tt r} into {\tt
sort} that are visible in the box specified by {\tt min} and {\tt
max}, and adds the count of the number of faces gathered to {\tt
nfaces}.  The faces can then be sorted by $z$ and rendered.
(Question: sort by $z$ is only approximately correct; this is ok for
small faces in volume rendering, but what about translucent surfaces?)
The clipping object, if any, is returned in {\tt clipping}; all
volumes and translucent faces in the scene must have the same clipping
object.
**/

Error _dxf_VolumeIrregular(struct buffer *b, struct gather *gather, int clip);
/**
DXRender the volume and translucent faces gathered in {\tt gather} into
buffer {\tt b}, using the irregular face algorithm.
**/

Error _dxf_VolumeRegular(struct buffer *b, struct gather *gather, int clip);
/**
DXRender the volumes gathered in {\tt gather} into buffer {\tt b},
using a regular volume rendering algorithm.
**/

Error
_dxf_CompositePlane(struct buffer *b, float osx, float osy, float osz, int clip,
		float ux, float uy, float uz, float vx, float vy, float vz,
		Pointer ic, char cstcolors, RGBColor *cmap,
		Pointer io, char cstopacities, float *omap,
		float cmul, float omul,
		int idx, int idy, int inx, int iny);
/**
Composite a plane of quads.
**/

Error
_dxf_MergeBackIntoZ(struct buffer *b);
/**
Merge the back and z buffers; needed for the irregular face algorithm.
**/

#define IN_FACE	        1
#define IF_OBJECT       2
#define IF_UNION        4
#define IF_INTERSECTION 8

#define D_POS 1
#define D_CON 2

Error _dxf_CopyFace(struct buffer *b, int if_object);
Error _dxf_InterferenceObject(struct buffer *buf);
Private   _dxfGetLights(Object, Camera);
Error     _dxfFreeLightList(LightList);
Error     _dxfInitApplyLights(float, float, float, int,
			      float, float, float, int,
			      Pointer, Pointer, RGBColor *,
			      Vector *, LightList, dependency, dependency,
			      RGBColor *, RGBColor *, int,
			      char, char, char, char, char);
Error     _dxfApplyLights(int *, int *, int);

#define FRONTFACING 1
#define BACKFACING  2

int _dxf_zclip_triangles(struct xfield *, int *,
			    int, int *, int, struct xfield *, inv_stat);
int _dxf_zclip_quads(struct xfield *, int *,
			    int, int *, int, struct xfield *, inv_stat);

extern float _dxd_ubyteToFloat[256];
void  _dxf_initUbyteToFloat();


