/* $Id: t_context.h,v 1.36 2002/01/06 03:54:12 brianp Exp $ */

/*
 * Mesa 3-D graphics library
 * Version:  4.1
 *
 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Author:
 *    Keith Whitwell <keithw@valinux.com>
 */

#ifndef _T_CONTEXT_H
#define _T_CONTEXT_H

#include "glheader.h"
#include "mtypes.h"

#include "math/m_matrix.h"
#include "math/m_vector.h"
#include "math/m_xform.h"


#define MAX_PIPELINE_STAGES     30


/* Numbers for sizing immediate structs.
 */
#define IMM_MAX_COPIED_VERTS  3
#define IMM_MAXDATA          (216 + IMM_MAX_COPIED_VERTS)
#define IMM_SIZE             (IMM_MAXDATA + MAX_CLIPPED_VERTICES)


/* Values for IM->BeginState
 */
#define VERT_BEGIN_0    0x1	   /* glBegin (if initially inside beg/end) */
#define VERT_BEGIN_1    0x2	   /* glBegin (if initially outside beg/end) */
#define VERT_ERROR_0    0x4	   /* invalid_operation in initial state 0 */
#define VERT_ERROR_1    0x8        /* invalid_operation in initial state 1 */


/* Flags to be added to the primitive enum in VB->Primitive.
 */
#define PRIM_MODE_MASK  0xff    /* Extract the actual primitive */
#define PRIM_BEGIN      0x100	/* The prim starts here (not wrapped) */
#define PRIM_END        0x200	/* The prim ends in this VB (does not wrap) */
#define PRIM_PARITY     0x400	/* The prim wrapped on an odd number of verts */
#define PRIM_LAST       0x800   /* No more prims in the VB */


/* Flags that describe the inputs and outputs of pipeline stages, and
 * the contents of a vertex-cassette.
 *
 * 5 spare flags, rearrangement of eval flags can secure at least 3
 * more.
 */
#define VERT_OBJ_BIT         _NEW_ARRAY_VERTEX
#define VERT_WEIGHT_BIT      _NEW_ARRAY_WEIGHT  /* unused */
#define VERT_NORMAL_BIT      _NEW_ARRAY_NORMAL
#define VERT_COLOR0_BIT      _NEW_ARRAY_COLOR0
#define VERT_COLOR1_BIT      _NEW_ARRAY_COLOR1
#define VERT_FOG_BIT         _NEW_ARRAY_FOGCOORD
#define VERT_INDEX_BIT       _NEW_ARRAY_INDEX
#define VERT_EDGEFLAG_BIT    _NEW_ARRAY_EDGEFLAG
#define VERT_TEX0_BIT        _NEW_ARRAY_TEXCOORD_0
#define VERT_TEX1_BIT        _NEW_ARRAY_TEXCOORD_1
#define VERT_TEX2_BIT        _NEW_ARRAY_TEXCOORD_2
#define VERT_TEX3_BIT        _NEW_ARRAY_TEXCOORD_3
#define VERT_TEX4_BIT        _NEW_ARRAY_TEXCOORD_4
#define VERT_TEX5_BIT        _NEW_ARRAY_TEXCOORD_5
#define VERT_TEX6_BIT        _NEW_ARRAY_TEXCOORD_6
#define VERT_TEX7_BIT        _NEW_ARRAY_TEXCOORD_7
#define VERT_EVAL_C1         0x10000    /* imm only */
#define VERT_EVAL_C2         0x20000    /* imm only */
#define VERT_EVAL_P1         0x40000    /* imm only */
#define VERT_EVAL_P2         0x80000    /* imm only */
#define VERT_OBJ_3           0x100000   /* imm only */
#define VERT_OBJ_4           0x200000   /* imm only */
#define VERT_MATERIAL        0x400000   /* imm only, but tested in vb code */
#define VERT_ELT             0x800000   /* imm only */
#define VERT_BEGIN           0x1000000  /* imm only, but tested in vb code */
#define VERT_END             0x2000000  /* imm only, but tested in vb code */
#define VERT_END_VB          0x4000000  /* imm only, but tested in vb code */
#define VERT_POINT_SIZE      0x8000000  /* vb only, could reuse a bit */
#define VERT_EYE             VERT_BEGIN /* vb only, reuse imm bit */
#define VERT_CLIP            VERT_END   /* vb only, reuse imm bit*/



/* Flags for IM->TexCoordSize.  Enough flags for 16 units.
 */
#define TEX_0_SIZE_3          0x1
#define TEX_0_SIZE_4          0x10001
#define TEX_SIZE_3(unit)      (TEX_0_SIZE_3 << (unit))
#define TEX_SIZE_4(unit)      (TEX_0_SIZE_4 << (unit))


/* Shorthands.
 */
#define VERT_EVAL_ANY      (VERT_EVAL_C1 | VERT_EVAL_P1 | \
                            VERT_EVAL_C2 | VERT_EVAL_P2)

#define VERT_OBJ_23        (VERT_OBJ_3 | VERT_OBJ_BIT)
#define VERT_OBJ_234       (VERT_OBJ_4 | VERT_OBJ_23)

#define VERT_TEX0_BIT_SHIFT 11

#define VERT_TEX(i)        (VERT_TEX0_BIT << (i))

#define VERT_TEX_ANY       (VERT_TEX0_BIT |		\
                            VERT_TEX1_BIT |		\
                            VERT_TEX2_BIT |		\
                            VERT_TEX3_BIT |		\
                            VERT_TEX4_BIT |		\
                            VERT_TEX5_BIT |		\
                            VERT_TEX6_BIT |		\
                            VERT_TEX7_BIT)

#define VERT_FIXUP        (VERT_TEX_ANY |		\
                           VERT_COLOR0_BIT |		\
                           VERT_COLOR1_BIT |		\
                           VERT_FOG_BIT |		\
			   VERT_INDEX_BIT |		\
                           VERT_EDGEFLAG_BIT |		\
                           VERT_NORMAL_BIT)

#define VERT_CURRENT_DATA  (VERT_FIXUP |		\
			    VERT_MATERIAL)

#define VERT_DATA          (VERT_TEX_ANY |		\
			    VERT_COLOR0_BIT |		\
			    VERT_COLOR1_BIT |		\
			    VERT_FOG_BIT |		\
                            VERT_INDEX_BIT |		\
                            VERT_EDGEFLAG_BIT |		\
                            VERT_NORMAL_BIT |		\
	                    VERT_OBJ_BIT |		\
                            VERT_MATERIAL |		\
                            VERT_ELT |			\
	                    VERT_EVAL_ANY)


/* KW: Represents everything that can take place between a begin and
 * end, and can represent multiple begin/end pairs.  Can be used to
 * losslessly encode this information in display lists.
 */
struct immediate
{
   struct __GLcontextRec *backref;
   GLuint id, ref_count;

   /* This must be saved when immediates are shared in display lists.
    */
   GLuint CopyStart, Start, Count;
   GLuint LastData;		/* count or count+1 */
   GLuint AndFlag, OrFlag;
   GLuint TexSize;		/* keep track of texcoord sizes */
   GLuint BeginState, SavedBeginState;
   GLuint LastPrimitive;

   GLuint ArrayEltFlags;	/* precalc'ed for glArrayElt */
   GLuint ArrayEltIncr;
   GLuint ArrayEltFlush;

#define FLUSH_ELT_EAGER 0x1
#define FLUSH_ELT_LAZY 0x2
   GLuint FlushElt;

   GLuint MaxTextureUnits;	/* precalc'ed for glMultiTexCoordARB */

   /* Temporary values created when vertices are copied into the
    * first 3 slots of the struct:
    */
   GLuint CopyOrFlag;
   GLuint CopyAndFlag;
   GLuint CopyTexSize;
   GLuint Evaluated;


   /* allocate storage for these on demand:
    */
   struct gl_material (*Material)[2];
   GLuint *MaterialMask;
   GLuint LastMaterial;
   GLuint MaterialOrMask;
   GLuint MaterialAndMask;

   GLuint  Primitive[IMM_SIZE];	    /* BEGIN/END */
   GLuint  PrimitiveLength[IMM_SIZE]; /* BEGIN/END */
   GLuint  Flag[IMM_SIZE];	    /* VERT_* flags */

   /* All vertex attributes (position, normal, color, secondary color,
    * texcoords, fog coord) are stored in the Attrib[] arrays instead
    * of individual arrays as we did prior to Mesa 4.1.
    *
    * XXX may need to use 32-byte aligned allocation for this!!!
    */
   GLfloat Attrib[VERT_ATTRIB_MAX][IMM_SIZE][4];  /* GL_NV_vertex_program */

   GLfloat *NormalLengthPtr; /* length of normal vectors (display list only) */

   GLuint  Elt[IMM_SIZE];
   GLubyte EdgeFlag[IMM_SIZE];
   GLuint  Index[IMM_SIZE];
};


struct vertex_arrays
{
   GLvector4f  Obj;
   GLvector4f  Normal;
   struct gl_client_array Color;
   struct gl_client_array SecondaryColor;
   GLvector1ui Index;
   GLvector1ub EdgeFlag;
   GLvector4f  TexCoord[MAX_TEXTURE_UNITS];
   GLvector1ui Elt;
   GLvector4f  FogCoord;
   GLvector4f  Attribs[VERT_ATTRIB_MAX];
};


typedef struct gl_material GLmaterial;

/* Contains the current state of a running pipeline.
 */
typedef struct vertex_buffer
{
   /* Constant over life of the vertex_buffer.
    */
   GLuint Size;

   /* Constant over the pipeline.
    */
   GLuint     Count;		              /* for everything except Elts */
   GLuint     FirstClipped;	              /* temp verts for clipping */
   GLuint     FirstPrimitive;	              /* usually zero */

   /* Pointers to current data.
    */
   GLuint      *Elts;		                /* VERT_ELT */
   GLvector4f  *ObjPtr;		                /* VERT_OBJ_BIT */
   GLvector4f  *EyePtr;		                /* VERT_EYE */
   GLvector4f  *ClipPtr;	                /* VERT_CLIP */
   GLvector4f  *NdcPtr;                         /* VERT_CLIP (2) */
   GLubyte     ClipOrMask;	                /* VERT_CLIP (3) */
   GLubyte     *ClipMask;		        /* VERT_CLIP (4) */
   GLvector4f  *NormalPtr;	                /* VERT_NORMAL_BIT */
   GLfloat     *NormalLengthPtr;	        /* VERT_NORMAL_BIT */
   GLboolean   *EdgeFlag;	                /* VERT_EDGEFLAG_BIT */
   GLvector4f  *TexCoordPtr[MAX_TEXTURE_UNITS];	/* VERT_TEX_0..n */
   GLvector1ui *IndexPtr[2];	                /* VERT_INDEX_BIT */
   struct gl_client_array *ColorPtr[2];	        /* VERT_COLOR0_BIT */
   struct gl_client_array *SecondaryColorPtr[2];/* VERT_COLOR1_BIT */
   GLvector4f  *PointSizePtr;	                /* VERT_POINT_SIZE */
   GLvector4f  *FogCoordPtr;	                /* VERT_FOG_BIT */
   GLmaterial (*Material)[2];                   /* VERT_MATERIAL, optional */
   GLuint      *MaterialMask;	                /* VERT_MATERIAL, optional */
   GLuint      *Flag;		                /* VERT_* flags, optional */
   GLuint      *Primitive;	                /* GL_(mode)|PRIM_* flags */
   GLuint      *PrimitiveLength;	        /* integers */

   /* Inputs to the vertex program stage */
   GLvector4f *AttribPtr[VERT_ATTRIB_MAX];      /* GL_NV_vertex_program */

   GLuint importable_data;
   void *import_source;
   void (*import_data)( GLcontext *ctx, GLuint flags, GLuint vecflags );
   /* Callback to the provider of the untransformed input for the
    * render stage (or other stages) to call if they need to write into
    * write-protected arrays, or fixup the stride on input arrays.
    *
    * This is currently only necessary for client arrays that make it
    * as far down the pipeline as the render stage.
    */

   GLuint LastClipped;
   /* Private data from _tnl_render_stage that has no business being
    * in this struct.
    */

} TNLvertexbuffer;



/* Describes an individual operation on the pipeline.
 */
struct gl_pipeline_stage {
   const char *name;
   GLuint check_state;		/* All state referenced in check() --
				 * When is the pipeline_stage struct
				 * itself invalidated?  Must be
				 * constant.
				 */

   /* Usually constant or set by the 'check' callback:
    */
   GLuint run_state;		/* All state referenced in run() --
				 * When is the cached output of the
				 * stage invalidated?
				 */

   GLboolean active;		/* True if runnable in current state */
   GLuint inputs;		/* VERT_* inputs to the stage */
   GLuint outputs;		/* VERT_* outputs of the stage */

   /* Set in _tnl_run_pipeline():
    */
   GLuint changed_inputs;	/* Generated value -- inputs to the
				 * stage that have changed since last
				 * call to 'run'.
				 */

   /* Private data for the pipeline stage:
    */
   void *privatePtr;

   /* Free private data.  May not be null.
    */
   void (*destroy)( struct gl_pipeline_stage * );

   /* Called from _tnl_validate_pipeline().  Must update all fields in
    * the pipeline_stage struct for the current state.
    */
   void (*check)( GLcontext *ctx, struct gl_pipeline_stage * );

   /* Called from _tnl_run_pipeline().  The stage.changed_inputs value
    * encodes all inputs to thee struct which have changed.  If
    * non-zero, recompute all affected outputs of the stage, otherwise
    * execute any 'sideeffects' of the stage.
    *
    * Return value: GL_TRUE - keep going
    *               GL_FALSE - finished pipeline
    */
   GLboolean (*run)( GLcontext *ctx, struct gl_pipeline_stage * );
};


struct gl_pipeline {
   GLuint build_state_trigger;	  /* state changes which require build */
   GLuint build_state_changes;    /* state changes since last build */
   GLuint run_state_changes;	  /* state changes since last run */
   GLuint run_input_changes;	  /* VERT_* changes since last run */
   GLuint inputs;		  /* VERT_* inputs to pipeline */
   struct gl_pipeline_stage stages[MAX_PIPELINE_STAGES+1];
   GLuint nr_stages;
};


struct tnl_eval_store {
   GLuint EvalMap1Flags;
   GLuint EvalMap2Flags;
   GLuint EvalNewState;
   struct immediate *im;	/* used for temporary data */
};


typedef void (*points_func)( GLcontext *ctx, GLuint first, GLuint last );
typedef void (*line_func)( GLcontext *ctx, GLuint v1, GLuint v2 );
typedef void (*triangle_func)( GLcontext *ctx,
                               GLuint v1, GLuint v2, GLuint v3 );
typedef void (*quad_func)( GLcontext *ctx, GLuint v1, GLuint v2,
                           GLuint v3, GLuint v4 );
typedef void (*render_func)( GLcontext *ctx, GLuint start, GLuint count,
			     GLuint flags );
typedef void (*interp_func)( GLcontext *ctx,
			     GLfloat t, GLuint dst, GLuint out, GLuint in,
			     GLboolean force_boundary );
typedef void (*copy_pv_func)( GLcontext *ctx, GLuint dst, GLuint src );
typedef void (*setup_func)( GLcontext *ctx,
			    GLuint start, GLuint end,
			    GLuint new_inputs);


struct tnl_device_driver {
   /***
    *** TNL Pipeline
    ***/

   void (*RunPipeline)(GLcontext *ctx);
   /* Replaces PipelineStart/PipelineFinish -- intended to allow
    * drivers to wrap _tnl_run_pipeline() with code to validate state
    * and grab/release hardware locks.  
    */

   /***
    *** Rendering -- These functions called only from t_vb_render.c
    ***/
   struct {
      void (*Start)(GLcontext *ctx);
      void (*Finish)(GLcontext *ctx);
      /* Called before and after all rendering operations, including DrawPixels,
       * ReadPixels, Bitmap, span functions, and CopyTexImage, etc commands.
       * These are a suitable place for grabbing/releasing hardware locks.
       */

      void (*PrimitiveNotify)(GLcontext *ctx, GLenum mode);
      /* Called between RenderStart() and RenderFinish() to indicate the
       * type of primitive we're about to draw.  Mode will be one of the
       * modes accepted by glBegin().
       */

      interp_func Interp;
      /* The interp function is called by the clipping routines when we need
       * to generate an interpolated vertex.  All pertinant vertex ancilliary
       * data should be computed by interpolating between the 'in' and 'out'
       * vertices.
       */

      copy_pv_func CopyPV;
      /* The copy function is used to make a copy of a vertex.  All pertinant
       * vertex attributes should be copied.
       */

      void (*ClippedPolygon)( GLcontext *ctx, const GLuint *elts, GLuint n );
      /* Render a polygon with <n> vertices whose indexes are in the <elts>
       * array.
       */

      void (*ClippedLine)( GLcontext *ctx, GLuint v0, GLuint v1 );
      /* Render a line between the two vertices given by indexes v0 and v1. */

      points_func           Points; /* must now respect vb->elts */
      line_func             Line;
      triangle_func         Triangle;
      quad_func             Quad;
      /* These functions are called in order to render points, lines,
       * triangles and quads.  These are only called via the T&L module.
       */

      render_func          *PrimTabVerts;
      render_func          *PrimTabElts;
      /* Render whole unclipped primitives (points, lines, linestrips,
       * lineloops, etc).  The tables are indexed by the GL enum of the
       * primitive to be rendered.  RenderTabVerts is used for non-indexed
       * arrays of vertices.  RenderTabElts is used for indexed arrays of
       * vertices.
       */

      void (*ResetLineStipple)( GLcontext *ctx );
      /* Reset the hardware's line stipple counter.
       */

      setup_func BuildVertices;
      /* This function is called whenever new vertices are required for
       * rendering.  The vertices in question are those n such that start
       * <= n < end.  The new_inputs parameter indicates those fields of
       * the vertex which need to be updated, if only a partial repair of
       * the vertex is required.
       *
       * This function is called only from _tnl_render_stage in tnl/t_render.c.
       */
      

      GLboolean (*Multipass)( GLcontext *ctx, GLuint passno );
      /* Driver may request additional render passes by returning GL_TRUE
       * when this function is called.  This function will be called
       * after the first pass, and passes will be made until the function
       * returns GL_FALSE.  If no function is registered, only one pass
       * is made.
       *
       * This function will be first invoked with passno == 1.
       */
   } Render;
};
   

typedef struct {

   /* Driver interface.
    */
   struct tnl_device_driver Driver;

   /* Track whether the module is active.
    */
   GLboolean bound_exec;

   /* Display list extensions
    */
   GLuint opcode_vertex_cassette;

   /* Pipeline
    */
   struct gl_pipeline pipeline;
   struct vertex_buffer vb;

   /* GLvectors for binding to vb:
    */
   struct vertex_arrays imm_inputs;
   struct vertex_arrays array_inputs;
   GLuint *tmp_primitive;
   GLuint *tmp_primitive_length;

   /* Set when executing an internally generated begin/end object.  If
    * such an object is encountered in a display list, it will be
    * replayed only if the list is outside any existing begin/end
    * objects.  
    */
   GLboolean ReplayHardBeginEnd;

   /* Note which vertices need copying over succesive immediates.
    * Will add save versions to precompute vertex copying where
    * possible.
    */
   struct immediate *ExecCopySource;
   GLuint ExecCopyCount;
   GLuint ExecCopyElts[IMM_MAX_COPIED_VERTS];
   GLuint ExecCopyTexSize;
   GLuint ExecParity;

   GLuint DlistPrimitive;
   GLuint DlistPrimitiveLength;
   GLuint DlistLastPrimitive;

   /* Cache a single free immediate (refcount == 0)
    */
   struct immediate *freed_immediate;   

   /* Probably need a better configuration mechanism:
    */
   GLboolean NeedNdcCoords;
   GLboolean LoopbackDListCassettes;
   GLboolean CalcDListNormalLengths;

   /* Derived state and storage for _tnl_eval_vb:
    */
   struct tnl_eval_store eval;

   /* Functions to be plugged into dispatch when tnl is active.
    */
   GLvertexformat vtxfmt;

} TNLcontext;



#define TNL_CONTEXT(ctx) ((TNLcontext *)(ctx->swtnl_context))
#define TNL_CURRENT_IM(ctx) ((struct immediate *)(ctx->swtnl_im))


#define TYPE_IDX(t) ((t) & 0xf)
#define MAX_TYPES TYPE_IDX(GL_DOUBLE)+1      /* 0xa + 1 */

extern void _tnl_MakeCurrent( GLcontext *ctx,
			      GLframebuffer *drawBuffer,
			      GLframebuffer *readBuffer );


/*
 * Macros for fetching current input buffer.
 */
#ifdef THREADS
#define GET_IMMEDIATE  struct immediate *IM = TNL_CURRENT_IM(((GLcontext *) (_glapi_Context ? _glapi_Context : _glapi_get_context())))
#define SET_IMMEDIATE(ctx, im)  ctx->swtnl_im = (void *)im
#else
extern struct immediate *_tnl_CurrentInput;
#define GET_IMMEDIATE struct immediate *IM = _tnl_CurrentInput
#define SET_IMMEDIATE(ctx, im)			\
do {						\
   ctx->swtnl_im = (void *)im;			\
   _tnl_CurrentInput = im;			\
} while (0)
#endif


#endif