#ifndef __PARRAY_H__
#define __PARRAY_H__

// Number of polydata entries in the context.  Must be at least 32.
// It includes room for the polyarray entry and others.
// It's currently based on POLYDATA_BUFFER_SIZE+1 vertices of size 128
// fitting in 64K, which yields 511
#define POLYDATA_BUFFER_SIZE     511
// DrawElements expects at least this many vertices in the vertex buffer.
// It is the sum of the following (currently sum is 278):
//    Number of vertex entries in a batch
//    Number of entries used for index map
//    An extra vertex entry to prevent calling PolyArrayFlushPartialPrimitive
//        in the Vertex routines.
//    An entry for POLYARRAY
//    4 spare entries to be safe
// It is given by
//    VA_DRAWELEM_MAP_SIZE +
//    (VA_DRAWELEM_INDEX_SIZE + sizeof(POLYDATA) - 1) / sizeof(POLYDATA) +
//    1 + 1 + 4
#define MINIMUM_POLYDATA_BUFFER_SIZE    300

// Minimun number of polydata entries required before processing a primitive.
// Must be at least 16.
#define MIN_POLYDATA_BATCH_SIZE  68

#if !((MIN_POLYDATA_BATCH_SIZE <= MINIMUM_POLYDATA_BUFFER_SIZE) && \
      (MINIMUM_POLYDATA_BUFFER_SIZE <= POLYDATA_BUFFER_SIZE)       \
     )
#error "bad sizes\n"
#endif

// Maximun number of vertices handled by the polygon decomposer.
// It allocates stack space based on this constant.  It must be at least 6.
#define __GL_MAX_POLYGON_CLIP_SIZE   256

// The POLYMATERIAL structure contains an index to the next available
// __GLmatChange structure, an array of pointers to __GLmatChange arrays,
// and a pointer to an array of PDMATERIAL structures each containing
// pointers to the front and back material changes for each POLYDATA
// elements in vertex buffer.
//
// The __GLmatChange structures are used to record material changes to
// vertices in the vertex buffer.  Since there can be up to two material
// changes per vertex, we need up to (POLYDATA_BUFFER_SIZE * 2) material
// changes per rendering thread.
//
// The PDMATERIAL array is part of the POLYMATERIAL structure and follows
// the aMat field immediately.  Its elements correspond to the POLYDATA
// elements in the vertex buffer.
//
// To reduce memory requirement, the POLYMATERIAL structure keeps an array
// of pointers to __GLmatChange arrays.  Each __GLmatChange array of up to
// 4K size is allocated as needed.
//
// An iMat index is used to keep track of the next free __GLmatChange
// entry.  When the poly array buffer is flushed in glsbAttention, iMat
// is reset to 0.
//
// The POLYMATERIAL structure and its __GLmatChange arrays are part of
// a thread local storage and are freed when the thread exits.

#define POLYMATERIAL_ARRAY_SIZE       (4096 / sizeof(__GLmatChange))

typedef struct __GLmatChangeRec {
    GLuint dirtyBits;
    __GLcolor ambient;
    __GLcolor diffuse;
    __GLcolor specular;
    __GLcolor emissive;
    __GLfloat shininess;
    __GLfloat cmapa, cmapd, cmaps;
} __GLmatChange;

// Pointers to front and back material change structures.  They are
// valid only when the POLYDATA_MATERIAL_FRONT or POLYDATA_MATERIAL_BACK
// flag of the corresponding POLYDATA in the vertex buffer is set.
typedef struct {
    __GLmatChange *front;	// pointer to the front material changes
    __GLmatChange *back;	// pointer to the back material changes
} PDMATERIAL;

typedef struct _POLYMATERIAL {
    GLuint iMat;  // next available material structure for this command batch
    PDMATERIAL *pdMaterial0;	// pointer to the PDMATERIAL array
    GLuint aMatSize;		// number of aMat entries
    __GLmatChange *aMat[1];	// array of array of __GLmatChange structures
} POLYMATERIAL;

/*
** Vertex structure.  Each vertex contains enough state to properly
** render the active primitive.  It is used by the front-end geometry
** and back-end rasterization pipelines.
**
** NOTE: Same as __GLvertex structure!
** NOTE: This structure is used by RasterPos and evaluator too!
**
** To minimize storage requirement, some front-end storage (e.g. obj and normal)
** is shared with back-end storage (e.g. rxVertex).
*/
typedef struct _POLYDATA {
    /*
    ** Keep this data structure aligned: have all vectors start on 
    ** 4-word boundary, and sizeof this struct should be kept at 
    ** a multiple of 4 words. Also helps to bunch together most
    ** frequently used items, helps cache.
    */

    /*
    ** Bits are set in this indicating which fields of the vertex are
    ** valid.  This field is shared with the back-end has field!
    */
    GLuint flags;

    /*
    ** Moved up here to keep GLcoords aligned. 
    */
    __GLcolor *color;

    /*
    ** Clipping code mask.  One bit is set for each clipping plane that
    ** the vertex is out on.
    */
    GLuint clipCode;

    /*
    ** Fog value for the vertex.  This is only filled when doing cheap
    ** fogging.
    */
    __GLfloat fog;

    /*
    ** Coordinates straight from client. These fields may not be
    ** set depending on the active modes.  The normal and texture
    ** coordinate are used by lighting and texturing.  These cells
    ** may be overwritten by the eyeNormal and the generated texture
    ** coordinate, depending on the active modes.
    */
    /*
    ** Projected eye coodinate.  This field is filled in when the users
    ** eye coordinate has been multiplied by the projection matrix.
    */
    union
    {
        __GLcoord obj;
        __GLcoord clip;
    };

    /*
    ** Window coordinate. This field is filled in when the eye coordinate
    ** is converted to a drawing surface relative "window" coordinate.
    ** NOTE: the window.w coordinate contains 1/clip.w.
    */
    __GLcoord window;

    __GLcoord texture;

    __GLcoord normal;

    /*
    ** Colors.  colors[0] is the "front" color, colors[1] is the "back" color.
    ** The color pointer points to which color is current for this
    ** vertex.  Verticies can have more than one color when two sided
    ** lighting is enabled. (note color pointer moved up top).
    */
    __GLcolor colors[2];

    /*
    ** Eye coordinate. This field is filled in when the object coordinate
    ** has been multiplied by the model-view matrix.  If no eye coordinate
    ** was needed then this field contains undefined values.
    */
    __GLcoord eye;
} POLYDATA;

// This structure is used by RasterPos and evaluator too!
// This structure is also in the TEB!
typedef struct _POLYARRAY {
    // Flags for this batch.  Keep it first!
    GLuint flags;

    // Pointer to the next vertex in this batch.
    POLYDATA *pdNextVertex;

    // Pointer to the last vertex modifying the current color, RGBA or CI
    // depending on color mode, in this batch.
    POLYDATA *pdCurColor;

    // Pointer to the last vertex modifying normal coordinates in this batch.
    POLYDATA *pdCurNormal;

    // Pointer to the last vertex modifying texture coordinates in this batch.
    POLYDATA *pdCurTexture;

    // Pointer to the last vertex modifying edge flag in this batch.
    POLYDATA *pdCurEdgeFlag;

    // Pointer to the first vertex of this batch.
    // (pd0-1) points to this batch's POLYARRAY structure.
    POLYDATA *pd0;

    // Pointer to the flush vertex of this batch.
    POLYDATA *pdFlush;

    // Pointer to the vertex buffer entry in the gc for the next batch.
    POLYDATA *pdBufferNext;

    // Pointer to the first vertex buffer entry in the gc.
    POLYDATA *pdBuffer0;

    // Pointer to the last vertex buffer entry in the gc.
    POLYDATA *pdBufferMax;

    // In RGBA mode, otherColor.r is the last modified color index value in
    // this batch.  In CI mode, otherColor is the last modified RGBA color in
    // this batch.  Keep this field aligned!
    __GLcolor    otherColor;

    // Primitive type.
    GLenum primType;

    // Or result of all vertex clipCode's in this batch.
    GLuint  orClipCodes;

    // Pointer to the next message offset in the batching command buffer.
    // We use this offset to determine if 2 POLYARRAY's can be linked in
    // a DrawPolyArray command.
    ULONG        nextMsgOffset;

    // Linear pointer to this thread's TEB POLYARRAY, kept here
    // so the current POLYARRAY pointer can be retrieved from the
    // TEB with a single instruction
    struct _POLYARRAY *paTeb;

    // This is used to form a linked list of POLYARRAY data to be
    // processed in the DrawPolyArray command.
    struct _POLYARRAY *paNext;

    // Number of vertices in this primitive.
    GLint   nIndices;

    // Index map array defining vertex drawing order.  If NULL, the
    // vertex order starts from pd0 through (pdNextVertex-1).
    GLubyte *aIndices;

    // Fast pointer access to the shared command message buffer.
    PVOID   pMsgBatchInfo;

    // MCD Driver-private texture handle, or key
    DWORD textureKey;

    // And result of all vertex clipCode's in this batch.
    GLuint  andClipCodes;

    // Currently unused but space is reserved in the TEB for it
    ULONG ulUnused[1];
} POLYARRAY;

/*
** Edge tag.  When POLYDATA_EDGEFLAG_BOUNDARY is set, this vertex and the next
** form a boundary edge on the primitive (polygon, tstrip, tfan, qstrip).
*/
#define POLYDATA_EDGEFLAG_BOUNDARY    	0x00000001 // must be 1, same as
						   // __GL_HAS_EDGEFLAG_BOUNDARY
#define POLYDATA_EDGEFLAG_VALID       	0x00000002
#define POLYDATA_COLOR_VALID        	0x00000004
#define POLYDATA_NORMAL_VALID       	0x00000008
#define POLYDATA_TEXTURE_VALID       	0x00000010
#define POLYDATA_VERTEX2           	0x00000020 // same as POLYARRAY_
#define POLYDATA_VERTEX3           	0x00000040 // same as POLYARRAY_
#define POLYDATA_VERTEX4           	0x00000080 // same as POLYARRAY_
#define POLYDATA_EVALCOORD1          	0x00000100 // same as POLYARRAY_
#define POLYDATA_EVALCOORD2          	0x00000200 // same as POLYARRAY_
#define POLYDATA_EVALPOINT1          	0x00000400 // same as POLYARRAY_
#define POLYDATA_EVALPOINT2          	0x00000800 // same as POLYARRAY_
#define POLYDATA_DLIST_COLOR_4	    	0x00002000 // client side dlist flag
#define POLYDATA_FOG_VALID	        0x00004000 // same as __GL_HAS_FOG
                                    //  0x00008000 // reserved
#define POLYDATA_DLIST_TEXTURE1       	0x00100000 // client side dlist flag
#define POLYDATA_DLIST_TEXTURE2       	0x00200000 // client side dlist flag
#define POLYDATA_DLIST_TEXTURE3       	0x00400000 // client side dlist flag
#define POLYDATA_DLIST_TEXTURE4       	0x00800000 // client side dlist flag
#define POLYDATA_MATERIAL_FRONT    	0x10000000 // same as POLYARRAY_
#define POLYDATA_MATERIAL_BACK    	0x20000000 // same as POLYARRAY_

#define POLYARRAY_IN_BEGIN          	0x00000001
#define POLYARRAY_EYE_PROCESSED     	0x00000002
#define POLYARRAY_OTHER_COLOR          	0x00000004
#define POLYARRAY_PARTIAL_BEGIN        	0x00000008
#define POLYARRAY_PARTIAL_END          	0x00000010
#define POLYARRAY_VERTEX2           	0x00000020 // same as POLYDATA_
#define POLYARRAY_VERTEX3           	0x00000040 // same as POLYDATA_
#define POLYARRAY_VERTEX4           	0x00000080 // same as POLYDATA_
#define POLYARRAY_EVALCOORD1	   	0x00000100 // same as POLYDATA_
#define POLYARRAY_EVALCOORD2	   	0x00000200 // same as POLYDATA_
#define POLYARRAY_EVALPOINT1          	0x00000400 // same as POLYDATA_
#define POLYARRAY_EVALPOINT2          	0x00000800 // same as POLYDATA_
#define POLYARRAY_REMOVE_PRIMITIVE  	0x00001000
#define POLYARRAY_RESET_STIPPLE	    	0x00004000
#define POLYARRAY_RENDER_PRIMITIVE  	0x00008000
#define POLYARRAY_SAME_POLYDATA_TYPE 	0x00010000
#define POLYARRAY_RASTERPOS          	0x00020000
#define POLYARRAY_SAME_COLOR_DATA	0x00040000
#define POLYARRAY_TEXTURE1          	0x00100000 // same as POLYDATA_DLIST_
#define POLYARRAY_TEXTURE2          	0x00200000 // same as POLYDATA_DLIST_
#define POLYARRAY_TEXTURE3          	0x00400000 // same as POLYDATA_DLIST_
#define POLYARRAY_TEXTURE4          	0x00800000 // same as POLYDATA_DLIST_
//#define POLYARRAY_RESTORE_COLOR_POINTER	0x01000000 // no longer needed
#define POLYARRAY_MATERIAL_FRONT    	0x10000000 // same as POLYDATA_
#define POLYARRAY_MATERIAL_BACK    	0x20000000 // same as POLYDATA_
#define POLYARRAY_CLAMP_COLOR        	0x80000000 // must be 0x80000000

/************************************************************************/

GLuint FASTCALL PAClipCheckFrustum(__GLcontext *gc, POLYDATA *pd);
GLuint FASTCALL PAClipCheckFrustum2D(__GLcontext *gc, POLYDATA *pd);
GLuint FASTCALL PAClipCheckAll(__GLcontext *gc, POLYDATA *pd);
void   FASTCALL PADoEval2(__GLcontext *gc, POLYARRAY *pa, POLYDATA *pd, BOOL bScaleColor);

typedef void (FASTCALL *PFN_POLYARRAYCALCCOLORSKIP)
    (__GLcontext *, POLYARRAY *, GLint);
typedef void (FASTCALL *PFN_POLYARRAYCALCCOLOR)
    (__GLcontext *, GLint, POLYARRAY *, POLYDATA *, POLYDATA *);
typedef void (FASTCALL *PFN_POLYARRAYAPPLYCHEAPFOG)
    (__GLcontext *gc, POLYARRAY *pa);

void FASTCALL PolyArrayFillIndex0(__GLcontext *gc, POLYARRAY *pa, GLint face);
void FASTCALL PolyArrayFillColor0(__GLcontext *gc, POLYARRAY *pa, GLint face);
void FASTCALL PolyArrayCalcRGBColor(__GLcontext *gc, GLint face,
	POLYARRAY *pa, POLYDATA *pd1, POLYDATA *pd2);
void FASTCALL PolyArrayFastCalcRGBColor(__GLcontext *gc, GLint face,
	POLYARRAY *pa, POLYDATA *pd1, POLYDATA *pd2);
void FASTCALL PolyArrayZippyCalcRGBColor(__GLcontext *gc, GLint face,
	POLYARRAY *pa, POLYDATA *pd1, POLYDATA *pd2);
void FASTCALL PolyArrayCalcCIColor(__GLcontext *gc, GLint face,
	POLYARRAY *pa, POLYDATA *pd1, POLYDATA *pd2);
void FASTCALL PolyArrayFastCalcCIColor(__GLcontext *gc, GLint face,
	POLYARRAY *pa, POLYDATA *pd1, POLYDATA *pd2);
void FASTCALL PolyArrayCheapFogRGBColor(__GLcontext *gc, POLYARRAY *pa);
void FASTCALL PolyArrayCheapFogCIColor(__GLcontext *gc, POLYARRAY *pa);
void FASTCALL PolyArrayFlushPartialPrimitive(void);
__GLmatChange * FASTCALL PAMatAlloc(void);
void FASTCALL FreePolyMaterial(void);
GLboolean FASTCALL PolyArrayAllocBuffer(__GLcontext *gc, GLuint nVertices);
GLvoid    FASTCALL PolyArrayFreeBuffer(__GLcontext *gc);
GLvoid    FASTCALL PolyArrayResetBuffer(__GLcontext *gc);
GLvoid    FASTCALL PolyArrayRestoreColorPointer(POLYARRAY *pa);

#endif /* __PARRAY_H__ */