/******************************Module*Header*******************************\
* Module Name: glcltgs.c
*
* Routines to batch function calls and primitives
*
* Copyright (c) 1993-1996 Microsoft Corporation
\**************************************************************************/
/*
** Copyright 1991-1993, Silicon Graphics, Inc.
** All Rights Reserved.
** 
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
** 
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
*/


/*
 * AUTOMATICALLY UPDATED OR GENERATED BY SGI: DO NOT EDIT
 * IF YOU MUST MODIFY THIS FILE, PLEASE CONTACT ptar@sgi.com 415-390-1483
 */

#include "precomp.h"
#pragma hdrstop

/* Generic OpenGL Client using subbatching. */
#include <string.h>

#include "imports.h"
#include "types.h"

#include "glsbmsg.h"
#include "glsbmsgh.h"
#include "glsrvspt.h"

#include "subbatch.h"
#include "batchinf.h"
#include "glteb.h"
#include "glsbcltu.h"
#include "glclt.h"
#include "compsize.h"
#include "context.h"
#include "global.h"
#include "parray.h"
#include "glarray.h"
#include "lighting.h"
#include "imfuncs.h"
#include "..\dlist\dlistopt.h"

#ifdef NEW_PARTIAL_PRIM

// Vertex flags that should be propagated to polyarray flags
//
#define VERTEX_FLAGS_FOR_POLYARRAY (POLYDATA_VERTEX2 | POLYDATA_VERTEX3 | \
                                    POLYDATA_VERTEX4)

#define VERTEX_MATERIAL(pm, pa, pd) (pm->pdMaterial0[pd - pa->pdBuffer0])

PDMATERIAL* FASTCALL GetVertexMaterial(POLYARRAY *pa, POLYDATA *pd)
{
    POLYMATERIAL *pm = GLTEB_CLTPOLYMATERIAL();
    if (!pm)
    {
        PAMatAlloc();
        pm = GLTEB_CLTPOLYMATERIAL();
        if (!pm)
            return NULL;
    }
    return &VERTEX_MATERIAL(pm, pa, pd);
}
//------------------------------------------------------------------------
// Assumes that POLYMATERIAL structure is valid
//
PDMATERIAL* FASTCALL GetVertexMaterialSafe(POLYARRAY *pa, POLYDATA *pd)
{
    POLYMATERIAL *pm = GLTEB_CLTPOLYMATERIAL();
    return &VERTEX_MATERIAL(pm, pa, pd);
}
//------------------------------------------------------------------------
// Copy material changes from src to pd material
//
void FASTCALL SetVertexMaterial(POLYARRAY *pa, 
                                POLYDATA *pd, 
                                __GLmatChange *src, 
                                GLint faceOrientation)
{
    __GLmatChange *pdMat;
    PDMATERIAL    *mat;

   // Get POLYMATERIAL pointer after PAMatAlloc!
    mat = GetVertexMaterial(pa, pd);
    if (!mat) 
        return;
    if (faceOrientation == __GL_FRONTFACE)
    {
       mat->front = PAMatAlloc();
       if (!mat->front)
           return;
       pdMat = mat->front;
    }
    else
    {
       mat->back = PAMatAlloc();
       pdMat = mat->back;
    }
    if (pdMat)
        *pdMat = *src;
}
//-----------------------------------------------------------------------------
// Save shared vertex for a partial primitive
//
// We have to save all data applicapable for vertex (all data that can be inside 
// BEGIN END brackets): flags, color, texture, normal, coordinate, material, edge flag. 
// We do not save evaluator data, because it was processed earlier.
//
void SaveSharedVertex(SAVEREGION *dst, POLYDATA *src, POLYARRAY *pa)
{                
    dst->pd.flags = src->flags;       
    dst->pd.obj = src->obj;         
    if (src->flags & POLYDATA_TEXTURE_VALID)  
        dst->pd.texture = src->texture;    
    if (src->flags & POLYDATA_NORMAL_VALID)   
        dst->pd.normal = src->normal;     
    if (src->flags & POLYDATA_COLOR_VALID)    
        dst->pd.colors[0] = src->colors[0];
    if (src->flags & POLYDATA_MATERIAL_FRONT)
        dst->front = *(GetVertexMaterial(pa, src)->front);
    if (src->flags & POLYDATA_MATERIAL_BACK)
        dst->back = *(GetVertexMaterial(pa, src)->back);
}
//
// dst  - POLYDATA
// src  - SAVEREGION
// pa   - POLYARRAY
//
#define RESTOREMATERIAL(dst, src, pa)                                   \
    if (dst->flags & POLYDATA_MATERIAL_FRONT)                           \
    {                                                                   \
        SetVertexMaterial(pa, dst, &src->front, __GL_FRONTFACE);        \
    }                                                                   \
    if (dst->flags & POLYDATA_MATERIAL_BACK)                            \
    {                                                                   \
        SetVertexMaterial(pa, dst, &src->back, __GL_BACKFACE);          \
    }
// Restore shared vertex for a partial primitive
//
// We have to restore all data applicapable for vertex (all data that can be inside 
// BEGIN END brackets): flags, color, texture, normal, coordinate, material, edge flag. 
// We do not restore evaluator data, because it was processed earlier.
// We must update POLYARRAY flags and current color, normal, edge flag, texture pointers.
// We also must intitialize flags for a next vertex.
//
void RestoreSharedVertex(POLYDATA *dst, SAVEREGION *src, POLYARRAY *pa)               
{
    dst->flags = src->pd.flags;            
    dst->obj = src->pd.obj;              
    if (dst->flags & POLYDATA_TEXTURE_VALID)   
    {                                            
        dst->texture = src->pd.texture;      
        if (src->pd.flags & POLYDATA_EVAL_TEXCOORD)
            pa->pdLastEvalTexture = dst;
        else
            pa->pdCurTexture = dst;                
    }                                            
    if (dst->flags & POLYDATA_NORMAL_VALID)    
    {                                            
        dst->normal = src->pd.normal;       
        if (src->pd.flags & POLYDATA_EVAL_NORMAL)
            pa->pdLastEvalNormal = dst;
        else
            pa->pdCurNormal = dst;               
    }                                            
    if (dst->flags & POLYDATA_COLOR_VALID)     
    {                                            
        dst->colors[0] = src->pd.colors[0];    
        if (src->pd.flags & POLYDATA_EVAL_COLOR)
            pa->pdLastEvalColor = dst;
        else
            pa->pdCurColor = dst;                  
    }                                            
    if (dst->flags & POLYDATA_EDGEFLAG_VALID)  
        pa->pdCurEdgeFlag = dst;               

    RESTOREMATERIAL(dst, src, pa);
    
    pa->flags |= (dst->flags & VERTEX_FLAGS_FOR_POLYARRAY);
    (dst+1)->flags = 0;     // Initialize flag for a next vertex
}
//------------------------------------------------------------------------------
// Copy data from Graphics Context
//
void FASTCALL CopyColorFromGC(__GLcontext *gc, POLYARRAY *pa, POLYDATA *pd)
{
    __GLcolor scaledUserColor;

    pd->flags |= POLYDATA_COLOR_VALID;
    if (!gc->modes.colorIndexMode) 
    {
        __GL_SCALE_AND_CHECK_CLAMP_RGBA(scaledUserColor.r,
                                        scaledUserColor.g,
                                        scaledUserColor.b,
                                        scaledUserColor.a,
                                        gc, pa->flags,
                                        gc->state.current.userColor.r,
                                        gc->state.current.userColor.g,
                                        gc->state.current.userColor.b,
                                        gc->state.current.userColor.a);
    } 
    else 
    {
        __GL_CHECK_CLAMP_CI(scaledUserColor.r, gc, pa->flags, 
                            gc->state.current.userColorIndex);
    }
    pd->colors[0] = scaledUserColor;
}

void FASTCALL CopyTextureFromGC(__GLcontext *gc, POLYARRAY *pa, POLYDATA *pd)
{
    pd->flags |= POLYDATA_TEXTURE_VALID;
    pd->texture = gc->state.current.texture;

    if (__GL_FLOAT_COMPARE_PONE(pd->texture.w, !=))
        pa->flags |= POLYARRAY_TEXTURE4;
    else if (__GL_FLOAT_NEZ(pd->texture.z))
        pa->flags |= POLYARRAY_TEXTURE3;
    else if (__GL_FLOAT_NEZ(pd->texture.y))
        pa->flags |= POLYARRAY_TEXTURE2;
    else
        pa->flags |= POLYARRAY_TEXTURE1;
}

void FASTCALL CopyEdgeFlagFromGC(__GLcontext *gc, POLYDATA *pd)
{
    pd->flags |= POLYDATA_EDGEFLAG_VALID;
    if (gc->state.current.edgeTag)
        pd->flags |= POLYDATA_EDGEFLAG_BOUNDARY;
}

void FASTCALL CopyNormalFromGC(__GLcontext *gc, POLYDATA *pd)
{
    pd->flags |= POLYDATA_NORMAL_VALID;
    pd->normal = gc->state.current.normal;
}
//-------------------------------------------------------------------------------
// Copy material state corresponding to changeBits from GC to mat.
// face defines front or back material to use.
//
void FASTCALL CopyMaterialFromGC(__GLcontext *gc, __GLmatChange *mat, 
                                 GLuint changeBits, GLint face)
{
    __GLmaterialState *ms;

    ms = &gc->state.light.front;
    if (face != __GL_FRONTFACE)
        ms = &gc->state.light.back;
     
    // Take data from graphics context

    if (changeBits & __GL_MATERIAL_AMBIENT)
        mat->ambient = ms->ambient;

    if (changeBits & __GL_MATERIAL_DIFFUSE)
        mat->diffuse = ms->diffuse;

    if (changeBits & __GL_MATERIAL_SPECULAR)
        mat->specular = ms->specular;

    if (changeBits & __GL_MATERIAL_EMISSIVE)
    {
        mat->emissive.r = ms->emissive.r * gc->oneOverRedVertexScale;   
        mat->emissive.g = ms->emissive.g * gc->oneOverGreenVertexScale;   
        mat->emissive.b = ms->emissive.b * gc->oneOverBlueVertexScale;    
        mat->emissive.a = ms->emissive.a * gc->oneOverAlphaVertexScale;   
    }

    if (changeBits & __GL_MATERIAL_SHININESS)
         mat->shininess = ms->specularExponent;

    if (changeBits & __GL_MATERIAL_COLORINDEXES)
    {
        mat->cmapa = ms->cmapa;
        mat->cmapd = ms->cmapd;
        mat->cmaps = ms->cmaps;
    }
}
//-------------------------------------------------------------------------------
// Compute complete vertex state to restore state modified by pdLast vertex.
//
// We have to preserve the following state for a vertex:
// - normal
// - texture
// - color
// - edge flag
// - material
//
// Input:
//  dst     - where to copy vertex state
//  pdStart - we go from this vertex to the beginning of a polyarray to find 
//            material changes
//  pdLast  - we have to update vertex state only if the state is changed by 
//            this vertex
//
void FASTCALL UpdateVertexState(__GLcontext *gc, 
                                POLYARRAY   *pa, 
                                SAVEREGION  *dst, 
                                POLYDATA    *pdStart,
                                POLYDATA    *pdLast)
{
    GLuint flags = dst->pd.flags;
    GLuint flagsLast = pdLast ? pdLast->flags : 0xFFFFFFFF;
    POLYDATA *pd0 = pa->pd0;

    ASSERTOPENGL(pdStart >= pd0, "Infinite loop possible!");

    // If last vertex changes normal we have to find nearest previous normal
    // and propagate it to the dst
    if (flagsLast & POLYDATA_NORMAL_VALID && !(flags & POLYDATA_NORMAL_VALID))
    {
        POLYDATA *pd;
        // Find nearest normal
        for (pd = pdStart; pd >= pd0; pd--)
        {
            if (pd->flags & POLYDATA_NORMAL_VALID && 
                !(pd->flags & POLYDATA_EVAL_NORMAL))
                break;
        }
        flags |= POLYDATA_NORMAL_VALID;
        if (pd < pd0)
            //  We have not found any normal, so take value from graphics state
            CopyNormalFromGC(gc, &dst->pd);
        else
            dst->pd.normal = pd->normal;
    }

    // If last vertex changes texture we have to find nearest previous texture
    // and propagate it to the dst
    if (flagsLast & POLYDATA_TEXTURE_VALID && !(flags & POLYDATA_TEXTURE_VALID))
    {
        POLYDATA *pd;
        // Find latest texture
        for (pd = pdStart; pd >= pd0; pd--)
        {
            if (pd->flags & POLYDATA_TEXTURE_VALID && 
                !(pd->flags & POLYDATA_EVAL_TEXCOORD))
                break;
        }
        flags |= POLYDATA_TEXTURE_VALID;
        if (pd < pd0)
            //  We have not found any vertex, so take value from graphics state
            CopyTextureFromGC(gc, pa, &dst->pd);
        else
            dst->pd.texture = pd->texture;
    }

    // If last vertex changes color we have to find nearest previous color
    // and propagate it to the dst
    if (flagsLast & POLYDATA_COLOR_VALID && !(flags & POLYDATA_COLOR_VALID))
    {
        POLYDATA *pd;
        // Find latest color
        for (pd = pdStart; pd >= pd0; pd--)
        {
            if (pd->flags & POLYDATA_COLOR_VALID && 
                !(pd->flags & POLYDATA_EVAL_COLOR))
                break;
        }
        flags |= POLYDATA_COLOR_VALID;
        if (pd < pd0)
            //  We have not found any vertex, so take value from graphics state
            CopyColorFromGC(gc, pa, &dst->pd);
        else
            dst->pd.colors[0] = pd->colors[0];
    }

    if (flagsLast & POLYDATA_EDGEFLAG_VALID && !(flags & POLYDATA_EDGEFLAG_VALID))
    {
        POLYDATA *pd;
        // Find latest edge flag
        for (pd = pdStart; pd >= pd0; pd--)
        {
            if (pd->flags & POLYDATA_EDGEFLAG_VALID)
                break;
        }
        flags |= POLYDATA_EDGEFLAG_VALID;
        if (pd < pd0)
        { 
            //  We have not found any vertex, so take value from graphics state
            if (gc->state.current.edgeTag)
                flags |= POLYDATA_EDGEFLAG_BOUNDARY;
        }
        else
            flags |= (pd->flags & POLYDATA_EDGEFLAG_BOUNDARY);
    }

    dst->pd.flags |= flags;

    // Now we have to update material state

    if (pdLast->flags & (POLYARRAY_MATERIAL_FRONT | POLYARRAY_MATERIAL_BACK))
    {
        // We have to compute material state for pdLast1, because after the primitive is
        // processed, current material state will have changes from pdLast2 vertex.

        __GLmatChange *mat;
        __GLmatChange *pdMatLast;
        POLYDATA      *pd;
        GLint         face;
        GLuint        matMask;
        GLuint        changeBits;

        for (face = __GL_BACKFACE, matMask = POLYARRAY_MATERIAL_BACK;
              face >= 0;
              face--, matMask = POLYARRAY_MATERIAL_FRONT
             )
        {
            if (!(pa->flags & matMask))
                continue;

            // Only reset material data changed by pdLast
            if (face == __GL_FRONTFACE)
            {
                pdMatLast = GetVertexMaterial(pa, pdLast)->front;
                changeBits = pdMatLast->dirtyBits;
                mat  = &dst->front;
                // Don't modify color materials if they are in effect!
                changeBits &= ~gc->light.front.colorMaterialChange;
            }
            else
            {
                pdMatLast = GetVertexMaterial(pa, pdLast)->back;
                changeBits = pdMatLast->dirtyBits;
                mat  = &dst->back;
                // Don't modify color materials if they are in effect!
                changeBits &= ~gc->light.back.colorMaterialChange;
            }

            // Don't modify material settings used by this vertex
            changeBits &= ~mat->dirtyBits;

            if (!changeBits) 
                continue;   

            mat->dirtyBits |= changeBits;

            // Apply changes from vertices
            // We go backwards and apply the latest change
            for (pd = pdStart; pd >= pd0; pd--)
            {
                __GLmatChange *pdMat;
                GLuint dirtyBits;
                if (pd->flags & matMask)
                {
                    GLuint dirtyBits;
              
                    pdMat = GetVertexMaterial(pa, pd)->front + face;
                    dirtyBits  = pdMat->dirtyBits & changeBits;

                    if (!dirtyBits) 
                        continue;

                    if (dirtyBits & __GL_MATERIAL_AMBIENT)
                    {
                        mat->ambient = pdMat->ambient;
                    }
              
                    if (dirtyBits & __GL_MATERIAL_DIFFUSE)
                    {
                        mat->diffuse = pdMat->diffuse;
                    }

                    if (dirtyBits & __GL_MATERIAL_SPECULAR)
                    {
                        mat->specular = pdMat->specular;
                    }
              
                    if (dirtyBits & __GL_MATERIAL_EMISSIVE)
                    {
                        mat->emissive = pdMat->emissive;
                    }
              
                    if (dirtyBits & __GL_MATERIAL_SHININESS)
                    {
                        mat->shininess = pdMat->shininess;
                    }

                    if (dirtyBits & __GL_MATERIAL_COLORINDEXES)
                    {
                        mat->cmapa = pdMat->cmapa;
                        mat->cmapd = pdMat->cmapd;
                        mat->cmaps = pdMat->cmaps;
                    }

                    // Clear processed bits
                    changeBits &= ~dirtyBits;

                    if (!changeBits)
                        break;
                }
            }

            if (changeBits)
                CopyMaterialFromGC (gc, mat, changeBits, face);

            dst->pd.flags |= matMask;
        }
    }
}
//-------------------------------------------------------------------------------------
// Propagate vertex state from GC to the vertex.
//
// Already set vertex data should be preserved.
//
void FASTCALL UpdateVertexStateUsingGC(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *dst)
{ 
    POLYDATA * const pd = &dst->pd;
    if (!(pd->flags & POLYDATA_NORMAL_VALID))
        CopyNormalFromGC(gc, pd);

    if (!(pd->flags & POLYDATA_TEXTURE_VALID))
        CopyTextureFromGC(gc, pa, pd);

    if (!(pd->flags & POLYDATA_COLOR_VALID))
        CopyColorFromGC(gc, pa, pd);

    if (!(pd->flags & POLYDATA_EDGEFLAG_VALID))
        CopyEdgeFlagFromGC(gc, pd);

    if (pa->flags & (POLYARRAY_MATERIAL_FRONT | POLYARRAY_MATERIAL_BACK))
    {
        // Compute material state for the vertex, using GC
        // Do not override material changes in the vertex

        __GLmatChange *mat;
        GLint         face;
        GLuint        matMask;
        GLuint        changeBits;

        for (face = __GL_BACKFACE, matMask = POLYARRAY_MATERIAL_BACK;
              face >= 0;
              face--, matMask = POLYARRAY_MATERIAL_FRONT
             )
        {
            GLuint  dirtyBits;
            if (!(pa->flags & matMask))
                continue;

            // Don't modify color materials if they are in effect or if they are set 
            // by pdFirst!

            changeBits = 0xFFFFFFFF;
            if (face == __GL_FRONTFACE)
            {
                if (pd->flags & matMask)
                    changeBits &= ~dst->front.dirtyBits;

                changeBits &= ~gc->light.front.colorMaterialChange;
                mat = &dst->front;
            }
            else
            {
                if (pd->flags & matMask)
                    changeBits &= ~dst->back.dirtyBits;
                changeBits  = ~gc->light.back.colorMaterialChange;
                mat = &dst->back;
            }

            // Apply changes from vertices
            // We go backwards and remember the latest change

            if (changeBits)
            {
                CopyMaterialFromGC (gc, mat, changeBits, face);
                // Update changes for the vertex
                pd->flags |= matMask;
                mat->dirtyBits |= changeBits;
            }

        }
    }
}
#endif // NEW_PARTIAL_PRIM

//
// extension apis these are not exported
//

void APIENTRY
glAddSwapHintRectWIN(IN GLint x, IN GLint y, IN GLint width, IN GLint height)
{
    PLRC plrc = GLTEB_CLTCURRENTRC();

    if (plrc == NULL || plrc->dhrc != 0) {
        // this api should only be called if there is a generic rc
        // currently selected.
        return;
    }

    GLCLIENT_BEGIN( AddSwapHintRectWIN, ADDSWAPHINTRECTWIN )
        pMsg->xs = x;
        pMsg->ys = y;
        pMsg->xe = x + width;
        pMsg->ye = y + height;
    return;
    GLCLIENT_END
}

#ifdef PRIMITIVE_TRACK
static ULONG prim_entries;
static ULONG prim_total = 0;
static ULONG prim_count = 0;
#endif

// Polyarray begin flags.  Reset line stipple for new line loop,
// line strip, and polygon.
// Assume that all vertices have the same color.
GLuint aPolyArrayBeginFlags[] =
{
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA, // GL_POINTS
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA, // GL_LINES
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA | POLYARRAY_RESET_STIPPLE, // GL_LINE_LOOP
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA | POLYARRAY_RESET_STIPPLE, // GL_LINE_STRIP
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA, // GL_TRIANGLES
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA, // GL_TRIANGLE_STRIP
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA, // GL_TRIANGLE_FAN
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA, // GL_QUADS
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA, // GL_QUAD_STRIP
    POLYARRAY_IN_BEGIN | POLYARRAY_SAME_COLOR_DATA | POLYARRAY_RESET_STIPPLE  // GL_POLYGON
};

// If you modify this function, you need to also modify VA_DrawElementsBegin.
void APIENTRY
glcltBegin ( IN GLenum mode )
{
    POLYARRAY *pa;
    POLYDATA  *pd0, *pdFlush;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;
    __GL_SETUP();
    DWORD flags = GET_EVALSTATE (gc);


    // The invalid functions within begin/end are detected in glsbAttention.

    pa = GLTEB_CLTPOLYARRAY();

    // The vertex buffer is used as follows.  The first entry contains the
    // POLYARRAY structure.  The incoming vertices will be saved beginning
    // at a following entry.  As an optimization, the POLYARRAY structure is
    // kept in the TEB.  When glEnd is called, it will be copied to the
    // vertex buffer.

#ifndef _WIN95_
    ASSERTOPENGL(sizeof(POLYARRAY) <= sizeof(NtCurrentTeb()->glReserved1),
       "POLYARRAY and TEB sizes mismatch!");
#endif

    ASSERTOPENGL(sizeof(POLYDATA) == sizeof(__GLvertex),
       "POLYDATA and __GLvertex sizes mismatch!");

    ASSERTOPENGL(sizeof(POLYARRAY) <= sizeof(POLYDATA),
       "POLYARRAY and POLYDATA sizes mismatch!");

    // Keep vertex structure a multiple of 4 bytes (or 8 bytes).
    // The vertex buffer must be 4-byte aligned.

    ASSERTOPENGL(!(sizeof(POLYDATA) & 0x3), "bad POLYDATA size!");
    ASSERTOPENGL(!((ULONG_PTR)pa->pdBuffer0 & 0x3), "POLYDATA should be aligned!\n");

    // If we are already in the begin/end bracket, return an error.

    if (pa->flags & POLYARRAY_IN_BEGIN)
    {
        GLSETERROR(GL_INVALID_OPERATION);
        return;
    }

    if ((GLuint) mode > GL_POLYGON)
    {
        GLSETERROR(GL_INVALID_ENUM);
        return;
    }

	// if there are any pending API calls that affect the Evaluator state
    // then flush the message buffer

    if (flags & (__EVALS_AFFECTS_ALL_EVAL|
                 __EVALS_AFFECTS_1D_EVAL|
                 __EVALS_AFFECTS_2D_EVAL))
        glsbAttention ();

    // Flush the command buffer if the vertex buffer is nearly full.
    // Otherwise, just continue with the next available vertex buffer entry.

    if (pa->pdBufferNext > pa->pdBufferMax - MIN_POLYDATA_BATCH_SIZE)
    {
#ifdef PRIMITIVE_TRACK
        DbgPrint("* Min-not-present flush\n");
#endif
        glsbAttention();	// it resets pdBufferNext pointer too

        ASSERTOPENGL(pa->nextMsgOffset == PA_nextMsgOffset_RESET_VALUE, 
                 "bad nextMsgOffset\n");
    }

    // Batch POLYARRAY command in the command buffer.
    // We want to leave enough room to accomodate at least one invalid command
    // that may be batched in the begin/end bracket.  When glsbAttention,
    // glsbAttentionAlt, or glcltEnd is called, we will remove these invalid
    // commands.
    //
    // Combine adjacent DrawPolyArray commands into one command.

    // request DRAWPOLYARRAY_LARGE structure to make room for invalid commands
    GLCLIENT_BEGIN(DrawPolyArray, DRAWPOLYARRAY_LARGE)
    // need msg pointer to update pa later
    pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *) pMsg;

	if (pa->nextMsgOffset == CurrentOffset)
	{
	    // rewind command buffer pointer
	    pMsgBatchInfo->NextOffset = CurrentOffset;
	    ((BYTE *) pMsgDrawPolyArray) -= 
		 GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY));

	    // chain adjacent DrawPolyArray commands
	    ((POLYARRAY *) pMsgDrawPolyArray->paLast)->paNext
		= (POLYARRAY *) pa->pdBufferNext;
	    ((POLYARRAY *) pMsgDrawPolyArray->paLast)
		= (POLYARRAY *) pa->pdBufferNext;
	}
	else
	{
	    // resize the msg to the real size
	    pMsgBatchInfo->NextOffset = CurrentOffset
		+ GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY));

	    // remember the end of the primitive command
	    pa->nextMsgOffset = pMsgBatchInfo->NextOffset;

	    // start of a new chain
	    pMsgDrawPolyArray->pa0    =
	    pMsgDrawPolyArray->paLast = (PVOID) pa->pdBufferNext;
	}
    GLCLIENT_END


// Compute the start of the primitive.  A new primitive always begins with a
// POLYARRAY entry immediately followed by vertex entries.

    pd0 = pa->pdBufferNext + 1;

    // Initialize first polydata.

    pd0->flags = 0;

    ASSERTOPENGL(pd0->color == &pd0->colors[__GL_FRONTFACE],
                 "bad color pointer!\n");
    
    // Initialize the polyarray structure in the TEB.

    pa->flags         = aPolyArrayBeginFlags[mode];
    pa->pdNextVertex  =
    pa->pd0           = pd0;
    pa->primType      = mode;
    pa->pdCurColor    =	
    pa->pdCurNormal   =	
    pa->pdCurTexture  =	
    pa->pdCurEdgeFlag =	NULL;
    pa->paNext        = NULL;
    pa->nIndices      = 0;
    pa->aIndices      = NULL;	// identity mapping
    pa->pdLastEvalColor   =
    pa->pdLastEvalNormal  =
    pa->pdLastEvalTexture = NULL;
           
    // Compute the flush vertex for this primitive.  When the flush vertex is
    // reached, we will have accumulated enough vertices to render a partially
    // composed primitive.

    pdFlush = pa->pdBufferMax;
    switch (mode)
    {
      case GL_POINTS:
      case GL_LINE_STRIP:
      case GL_TRIANGLE_FAN:
        break;
      case GL_LINE_LOOP:
        // Line loop reserves an additional end vertex to close the loop.
        pdFlush--;
        break;
      case GL_POLYGON:
        // The polygon decomposer can only handle up to
        // __GL_MAX_POLYGON_CLIP_SIZE vertices.
        if (pdFlush > pd0 + __GL_MAX_POLYGON_CLIP_SIZE - 1)
	    pdFlush = pd0 + __GL_MAX_POLYGON_CLIP_SIZE - 1;
        break;
      case GL_LINES:
      case GL_TRIANGLE_STRIP:
      case GL_QUAD_STRIP:
        // number of vertices must be a multiple of 2
        if ((pdFlush - pd0 + 1) % 2)
            pdFlush--;
        break;
      case GL_TRIANGLES:
        // number of vertices must be a multiple of 3
        switch ((pdFlush - pd0 + 1) % 3)
        {
          case 2: pdFlush--;        // fall through
          case 1: pdFlush--;
        }
        break;
      case GL_QUADS:
        // number of vertices must be a multiple of 4
        switch ((pdFlush - pd0 + 1) % 4)
        {
          case 3: pdFlush--;        // fall through
          case 2: pdFlush--;        // fall through
          case 1: pdFlush--;
        }
        break;
    }
    pa->pdFlush = pdFlush;

#ifdef PRIMITIVE_TRACK
    DbgPrint("glcltBegin with %3d space left\n", pdFlush-pd0+1);
    prim_entries = 0;
#endif
}

// Special version of Begin for DrawElements.
// If you modify this function, you need to also modify glcltBegin.
void FASTCALL VA_DrawElementsBegin(POLYARRAY *pa, GLenum mode, GLsizei count)
{
    POLYDATA  *pd0;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;
    GLint     maxVertexCount;

    // The vertex buffer is used as follows.  The first entry contains the
    // POLYARRAY structure.  The incoming vertices will be saved beginning
    // at a following entry.  As an optimization, the POLYARRAY structure is
    // kept in the TEB.  When VA_DrawElementsEnd is called, it will be copied
    // to the vertex buffer.

    // We don't handle Points, Line Loop, and Polygon here.  They should
    // have been sent to Begin/End.

    ASSERTOPENGL(mode != GL_POINTS && mode != GL_LINE_LOOP && mode != GL_POLYGON,
    "Primitive type not handled\n");

    // Flush the command buffer if the vertex buffer will overflow.
    // Otherwise, just continue with the next available vertex buffer entry.

    // Maximum number of vertex entries that we will handle in next batch
    maxVertexCount = min(count,VA_DRAWELEM_MAP_SIZE)
    // Add maximum number of entries used for index map
    + (VA_DRAWELEM_INDEX_SIZE + sizeof(POLYDATA) - 1) / sizeof(POLYDATA)
    // Reserve an extra vertex entry to prevent calling
    // PolyArrayFlushPartialPrimitive in the Vertex routines.
    // It should call VA_DrawElementsFlushPartialPrimitive instead.
    + 1
    // Add an entry for POLYARRAY
    + 1
    // Add a few more entries to be safe
    + 4;

    if (pa->pdBufferNext > pa->pdBufferMax - maxVertexCount + 1)
    {
#ifdef PRIMITIVE_TRACK
        DbgPrint("* Min-not-present flush\n");
#endif
        glsbAttention();    // it resets pdBufferNext pointer too

        ASSERTOPENGL(pa->nextMsgOffset == PA_nextMsgOffset_RESET_VALUE, 
                     "bad nextMsgOffset\n");
    }

    // The vertex buffer must have at least maxVertexCount (currently <= 277)
    // entries.
    ASSERTOPENGL(maxVertexCount <= pa->pdBufferMax - pa->pdBuffer0 + 1,
    "vertex buffer is too small!\n");

    // Batch POLYARRAY command in the command buffer.
    // Combine adjacent DrawPolyArray commands into one command.

    GLCLIENT_BEGIN(DrawPolyArray, DRAWPOLYARRAY)
    // need msg pointer to update pa later
    pMsgDrawPolyArray = pMsg;

    if (pa->nextMsgOffset == CurrentOffset)
    {
        // rewind command buffer pointer
        pMsgBatchInfo->NextOffset = CurrentOffset;
        ((BYTE *) pMsgDrawPolyArray) -= 
         GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY));

        // chain adjacent DrawPolyArray commands
        ((POLYARRAY *) pMsgDrawPolyArray->paLast)->paNext
        = (POLYARRAY *) pa->pdBufferNext;
        ((POLYARRAY *) pMsgDrawPolyArray->paLast)
        = (POLYARRAY *) pa->pdBufferNext;
    }
    else
    {
        // remember the end of the primitive command
        pa->nextMsgOffset = pMsgBatchInfo->NextOffset;

        // start of a new chain
        pMsgDrawPolyArray->pa0    =
        pMsgDrawPolyArray->paLast = (PVOID) pa->pdBufferNext;
    }
    GLCLIENT_END


// Compute the start of the primitive.  A new primitive always begins with a
// POLYARRAY entry immediately followed by vertex entries.

    pd0 = pa->pdBufferNext + 1;

    // Initialize first polydata.

    pd0->flags = 0;
    
    ASSERTOPENGL(pd0->color == &pd0->colors[__GL_FRONTFACE],
                 "bad color pointer!\n");
    
    // Initialize the polyarray structure in the TEB.

    pa->flags         = aPolyArrayBeginFlags[mode] | POLYARRAY_SAME_POLYDATA_TYPE;
    pa->pdNextVertex  =
    pa->pd0           = pd0;
    pa->primType      = mode;
    pa->pdCurColor    =
    pa->pdCurNormal   =
    pa->pdCurTexture  =
    pa->pdCurEdgeFlag = NULL;
    pa->paNext        = NULL;
    pa->nIndices      = 0;
    pa->aIndices      = PA_aIndices_INITIAL_VALUE; // this is updated in End

    // For consistency
    pa->pdLastEvalColor    =
    pa->pdLastEvalNormal   =
    pa->pdLastEvalTexture  = NULL;

// The flush vertex for this primitive should never be reached.  We have
// reserved enough room for a vertex batch.  Set it to maximum and assert
// that we never reach the vertex in PolyArrayFlushPartialPrimitive!

    pa->pdFlush = pa->pdBufferMax;

#ifdef PRIMITIVE_TRACK
    DbgPrint("VA_DrawElementsBegin with %3d space left\n", pa->pdBufferMax-pd0+1);
#endif
    return;
}

void APIENTRY
glcltEnd ( void )
{
    POLYARRAY *pa;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;

#ifdef NEW_PARTIAL_PRIM
    __GL_SETUP();
    pa = gc->paTeb;
#else
    pa = GLTEB_CLTPOLYARRAY();
#endif

// Flush invalid commands accumulated in the command buffer if there is any.

    glsbAttention();

    // If we are not in the begin/end bracket, return an error.

    if (!(pa->flags & POLYARRAY_IN_BEGIN))
    {
        GLSETERROR(GL_INVALID_OPERATION);
        return;
    }

    // Clear the POLYARRAY_IN_BEGIN flag in the TEB.  We are now out of
    // the begin/end bracket.

    pa->flags &= ~POLYARRAY_IN_BEGIN;

    // Clear POLYARRAY_SAME_COLOR_DATA flag if the primitive uses more than
    // one color.  Also clear the flag if an evaluator is used.  We cannot
    // tell if an evaluator modifies the color on the client side.

    // If there are evaluator calls in this polyarray that also generate
    // color, then too, remove the POLYARRAY_SAME_COLOR_DATA flag

    if ((pa->pdCurColor != pa->pd0) ||
        ((pa->pd0->flags & POLYDATA_COLOR_VALID) &&
         (pa->flags & POLYARRAY_PARTIAL_BEGIN)) || 
        (pa->pdLastEvalColor != NULL))
        pa->flags &= ~POLYARRAY_SAME_COLOR_DATA;

    // Compute nIndices.  It is the final number of vertices passed to the low
    // level render routines and is different from the number of polydata's
    // accumulated.  The final number includes the reserved vertices and the
    // accumulated vertices.

    pa->nIndices += (GLint)((ULONG_PTR)(pa->pdNextVertex - pa->pd0));
    /*
    // If there are no vertices and no attributes to propagate to a next 
    // primitive, we can remove this polyarray from the batch
    if (pa->nIndices == 0 && pa->pdNextVertex->flags == 0)
        return;
        */

#ifdef NEW_PARTIAL_PRIM
    if (pa->primType == GL_LINE_LOOP)
    {
        if (pa->nIndices > 1)
        {
        // We have to add an additional vertex at the end. It could be
        //   - saved vertex if primitive is partial begin OR 
        //   - first vertex
        // We will change primitive type to GL_LINE_STRIP after we update 
        // current color, normal, texture, edge flag in __glim_DrawPolyArray
        //
            POLYDATA   *pd = pa->pdNextVertex++;
            SAVEREGION firstVertex;
            SAVEREGION lastVertex;
            SAVEREGION *reg;
            // We have to propagate vertex state for next primitive before we 
            // insert the vertex.

            pa->nIndices++;  
            if (pa->flags & POLYARRAY_PARTIAL_BEGIN)
            { // This is partial primitive
                reg = &gc->vertex.regSaved;
            }
            else
            { // This is non partial primitive
                SaveSharedVertex(&firstVertex, pa->pd0, pa);
                reg = &firstVertex;
            }
            // Save pdNextVertex before we override it
            SaveSharedVertex(&lastVertex, pd, pa);      
            // Insert first vertex at the end
            RestoreSharedVertex(pd, reg, pa); 
            // Compute state for last vertex, because we have to override 
            // changes made by first vertex.
            UpdateVertexState(gc, pa, &lastVertex, pd-1, pd);
            // pdNextVertex will have state for a next primitive
            RestoreSharedVertex(pa->pdNextVertex, &lastVertex, pa);
        }

        pa->primType = GL_LINE_STRIP;
    }
#else // NEW_PARTIAL_PRIM
    if (pa->primType == GL_LINE_LOOP)
        pa->nIndices++;     // add one extra vertex when a line loop is closed.
                            // It's okay not to advance pdBufferNext since we
                            // don't need attributes after they've been
                            // processed.
#endif // NEWFLUSH

    // Save the POLYARRAY structure in the batch.

    pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
    ((BYTE *) pa->pMsgBatchInfo + pa->nextMsgOffset -
         GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
    *(POLYARRAY *) pMsgDrawPolyArray->paLast = *pa;

#ifdef PRIMITIVE_TRACK
    prim_entries += pa->pdNextVertex-pa->pd0;
    prim_total += prim_entries;
    prim_count++;
    DbgPrint("glcltEnd   with %3d polydata entries, %3d now, avg %d\n",
         prim_entries, pa->pdNextVertex-pa->pd0, prim_total/prim_count);
#endif

// Advance polyarray batch pointer.
// Skip a vertex because it may contain attributes for the current batch.

    pa->pdBufferNext = pa->pdNextVertex + 1;
}

void FASTCALL VA_DrawElementsEnd(POLYARRAY *pa)
{
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;

    ASSERTOPENGL(pa->flags & POLYARRAY_IN_BEGIN, "not in begin\n");
    ASSERTOPENGL(pa->aIndices && (pa->aIndices != PA_aIndices_INITIAL_VALUE),
	"no output index array!\n");

// Clear the POLYARRAY_IN_BEGIN flag in the TEB.  We are now out of
// the begin/end bracket.

    pa->flags &= ~POLYARRAY_IN_BEGIN;

// Clear POLYARRAY_SAME_COLOR_DATA flag if the primitive uses more than
// one color.

    if (pa->pdCurColor != pa->pd0)
	pa->flags &= ~POLYARRAY_SAME_COLOR_DATA;

// Save the POLYARRAY structure in the batch.

    pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
	((BYTE *) pa->pMsgBatchInfo + pa->nextMsgOffset -
         GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
    *(POLYARRAY *) pMsgDrawPolyArray->paLast = *pa;

#ifdef PRIMITIVE_TRACK
    prim_count++;
    DbgPrint("VA_DrawElementsEnd called\n");
#endif

// Advance polyarray batch pointer.

    pa->pdBufferNext = (POLYDATA *) (pa->aIndices +
	(pa->nIndices + sizeof(POLYDATA) - 1) / sizeof(POLYDATA) * sizeof(POLYDATA));
}

#ifdef NEW_PARTIAL_PRIM

typedef void (*PFNSAVERESTORE)(__GLcontext*, POLYARRAY*, SAVEREGION*);

void FASTCALL SaveFirstVertex(__GLcontext* gc, POLYARRAY* pa)
{
    if (!(pa->flags & POLYARRAY_PARTIAL_BEGIN))
    {
        GLuint  flags = pa->flags & (POLYARRAY_MATERIAL_FRONT | POLYARRAY_MATERIAL_BACK);
        SaveSharedVertex(&gc->vertex.regSaved, pa->pd0, pa);
        // Save vertex state to restore it later
        pa->flags |= (POLYARRAY_MATERIAL_FRONT | POLYARRAY_MATERIAL_BACK);
        UpdateVertexStateUsingGC(gc, pa, &gc->vertex.regSaved);
        // Restore pa flags
        pa->flags &= ~(POLYARRAY_MATERIAL_FRONT | POLYARRAY_MATERIAL_BACK);
        pa->flags |= flags;
    }
}

// This function is used by GL_POINTS, GL_LINES, GL_TRIANGLES, GL_QUADS, 
// because for these cases parts of broken primitive are not connected. 
// We also clear POLYARRAY_PARTIAL_END flag, because in DrawPolyArray we 
// can remove this partial primitive if it is clipped out (we do not have
// to preserve line stipple for these primitives).
//
void SaveEmpty(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    pa->flags &= ~POLYARRAY_PARTIAL_END;
}

// A line loop is the same as a line strip except that a final segment is
// added from the final specified vertex to the first vertex.  We convert 
// the line loop into a strip here. We have to save first vertex of line 
// loop only if the primitive is not partial begin (i.e. it is not a middle 
// part of a line loop broken into more than two polyarrays). 
// We do not clear POLYARRAY_PARTIAL_END flag, because in DrawPolyArray we 
// can not remove this partial primitive if it is clipped out to preserve 
// line stipple. 
// Index mapping is always indentity for GL_LINE_LOOP.
// We save first vertex in graphics state, because it will be restored in glcltEnd.
// We change line loop to line strip here.
//
// When the first vertex is saved we have preserve its state to restore it in the next part
// of partial primitive.
//
void SaveLineLoop(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    POLYDATA*  pd;

    SaveFirstVertex(gc, pa);

    pd = pa->pdNextVertex-1;
    SaveSharedVertex(r, pd, pa);
    pa->primType = GL_LINE_STRIP;
}

// For GL_LINE_STRIP we save last vertex. We do not clear POLYARRAY_PARTIAL_END flag,
// because in DrawPolyArray we can not remove this partial primitive if it is clipped
// out to preserve line stipple.
// We do not preserve index because it is assumed to be 0 for the next part
// of the primitive.
//
void SaveLineStrip(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    POLYDATA *pd;
    if (pa->aIndices)
        pd = &pa->pd0[pa->aIndices[pa->nIndices-1]];
    else
        pd = pa->pdNextVertex-1;
    SaveSharedVertex(r, pd, pa);
}

// For GL_TRIANLE_FAN we save first and last vertices. Line stipple is reset for every 
// triangle in a fan, so we can clear POLYARRAY_PARTIAL_END flag
// We do not preserve indices because they are assumed to be 0 and 1 for the next part
// of the primitive.
//
// When we restore first vertex it must have the same state as when we saved it.
// But this state should no affect vertex last vertex.
// So we have to compute vertex state for the first when we save it and compute
// vertex state for the lase vertex when we restore it.
// First vertex and its state should be computed only once, even if a primitive is broken 
// several times.
//
void SaveTFan(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    if (pa->aIndices)
    {
        POLYDATA *pd;
        GLubyte  *aIndices = pa->aIndices;

        pd = &pa->pd0[aIndices[0]];
        SaveSharedVertex(&gc->vertex.regSaved, pd, pa);

        pd = &pa->pd0[aIndices[pa->nIndices-1]];
        SaveSharedVertex(r, pd, pa);
    }
    else
    {
        POLYDATA *pd;
        // Compute state for the first vertex only for the very first part
        // of partial primitive
        SaveFirstVertex(gc, pa);

        pd = pa->pdNextVertex-1;
        SaveSharedVertex(r, pd, pa);
    }
    pa->flags &= ~POLYARRAY_PARTIAL_END;
}

// This function handles GL_TRIANGLE_STRIP and GL_QUAD_STRIP.
// We save two last vertices.
// Line stipple is reset for every triangle (quad) in a strip, so we can clear 
// POLYARRAY_PARTIAL_END flag.
// We do not preserve indices because they are assumed to be 0 and 1 for the 
// next part of the primitive.
//
// We have to save 2 last vertices: v1 and v2 (last vertex).
// Next part of partial primitive will start with vertex v1.
// v2 could change vertex state, so we have to compute vertex state for v1 and
// restore it. This should be done only for non indexed case.
//
void SaveTStrip(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    if (pa->aIndices)
    {
        POLYDATA *pd;
        GLint     nIndices = pa->nIndices;
        GLubyte  *aIndices = pa->aIndices;

        pd = &pa->pd0[aIndices[nIndices-2]];
        SaveSharedVertex(r, pd, pa);
        pd = &pa->pd0[aIndices[nIndices-1]];
        SaveSharedVertex(r+1, pd, pa);
    }
    else
    {
        POLYDATA *pd = pa->pdNextVertex-2;

        SaveSharedVertex(r, pd, pa);
        // Compute vertex state, changed by vertex pd+1
        UpdateVertexState(gc, pa, r, pd-1, pd+1);
        pd++;
        SaveSharedVertex(r+1, pd, pa);
    }
    pa->flags &= ~POLYARRAY_PARTIAL_END;
}

// For GL_POLYGON we first and last two vertices, because we do not know 
// if the last vertex of this part is the last vertex for the primitive. We need this
// information to compute edge flag for the last vertex.
// We remove last vertex from the primitive. It will be processed in the next part of 
// the primitive.
// We need POLYARRAY_PARTIAL_END flag when we compute edge flag in DrawPolyArray.
//
void SavePolygon(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    POLYDATA *pd;
    // Compute state for the first vertex only for the very first part
    // of partial primitive
    SaveFirstVertex(gc, pa);

    pd = pa->pdNextVertex-2;
    SaveSharedVertex(r, pd, pa);

    r++;
    pd = pa->pdNextVertex-1;
    SaveSharedVertex(r, pd, pa);

// Remove last vertex from the primitive
    pa->nIndices--;
    pa->pdNextVertex--;
}

PFNSAVERESTORE  pfnSaveFunc[] =
{
    SaveEmpty,      // GL_POINTS
    SaveEmpty,      // GL_LINES
    SaveLineLoop,   // GL_LINE_LOOP
    SaveLineStrip,  // GL_LINE_STRIP
    SaveEmpty,      // GL_TRIANGLES
    SaveTStrip,     // GL_TRIANGLE_STRIP
    SaveTFan,       // GL_TRIANGLE_FAN
    SaveEmpty,      // GL_QUADS
    SaveTStrip,     // GL_QUAD_STRIP
    SavePolygon     // GL_POLYGON
};

// This function is used by GL_POINTS, GL_LINES, GL_TRIANGLES, GL_QUADS, 
// because for these cases parts of broken primitive are not connected. We 
// also clear POLYARRAY_PARTIAL_BEGIN flag, because in DrawPolyArray we can 
// remove this partial primitive if it is clipped out (we do not have to 
// preserve line stipple for these primitives).
//
void RestoreEmpty(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    pa->flags &= ~POLYARRAY_PARTIAL_BEGIN;
}

// For GL_LINE_LOOP and GL_LINE_STRIP last vertex from previous part will be the first.
// We will convert line loop into line strip in glcltEnd or PolyArrayFlushPartialPrimitive
// To preserve line stipple we need POLYARRAY_PARTIAL_BEGIN flag.
//
void RestoreLineStrip(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    POLYDATA *pd = pa->pdNextVertex++;

    RestoreSharedVertex(pd, r, pa);
}

// For GL_TRIANGLE_STRIP and GL_QUAD_STRIP we have to add two saved
// vertices at the beginning of primitive.
// We do not to preserve line stipple, so we clear POLYARRAY_PARTIAL_BEGIN flag.
//
void RestoreTStrip(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    POLYDATA *pd = pa->pdNextVertex++;

    RestoreSharedVertex(pd, r, pa);
                 
    r++;
    pd = pa->pdNextVertex++;
    RestoreSharedVertex(pd, r, pa);

    pa->flags &= ~POLYARRAY_PARTIAL_BEGIN;
}

// For GL_TRIANGLE_FAN we have to add two saved vertices at the beginning 
// of primitive. Last vertex should have a state, not modified by previous vertex.
// We do not to preserve line stipple, so we clear POLYARRAY_PARTIAL_BEGIN flag.
//
void RestoreTFan(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    POLYDATA *pd = pa->pdNextVertex++;

    RestoreSharedVertex(pd, &gc->vertex.regSaved, pa);

    pd = pa->pdNextVertex++;
    if (!pa->aIndices)
        // Compute state for last vertex, because it could be modified 
        // by first vertex
        UpdateVertexStateUsingGC(gc, pa, r);
    RestoreSharedVertex(pd, r, pa);
}

// For GL_POLYGON we have to add three saved vertices at the beginning of primitive.
// We need POLYARRAY_PARTIAL_BEGIN flag to compute edge flag in DrawPolyArray.
//
void RestorePolygon(__GLcontext *gc, POLYARRAY *pa, SAVEREGION *r)
{
    POLYDATA *pd = pa->pdNextVertex++;

    RestoreSharedVertex(pd, &gc->vertex.regSaved, pa);
                 
    // Compute state for this vertex, because it could be modified 
    // by first vertex
    UpdateVertexStateUsingGC(gc, pa, r);
    pd = pa->pdNextVertex++;
    RestoreSharedVertex(pd, r, pa);

    r++;
    pd = pa->pdNextVertex++;
    RestoreSharedVertex(pd, r, pa);
}

PFNSAVERESTORE  pfnRestoreFunc[] =
{
    RestoreEmpty,      // GL_POINTS
    RestoreEmpty,      // GL_LINES
    RestoreLineStrip,  // GL_LINE_LOOP
    RestoreLineStrip,  // GL_LINE_STRIP
    RestoreEmpty,      // GL_TRIANGLES
    RestoreTStrip,     // GL_TRIANGLE_STRIP
    RestoreTFan,       // GL_TRIANGLE_FAN
    RestoreEmpty,      // GL_QUADS
    RestoreTStrip,     // GL_QUAD_STRIP
    RestorePolygon     // GL_POLYGON
};               

#endif // NEW_PARTIAL_PRIM

// Number of reserved vertices for partial Begin.
GLint nReservedIndicesPartialBegin[] =
{
    0, // GL_POINTS
    0, // GL_LINES
    1, // GL_LINE_LOOP
    1, // GL_LINE_STRIP
    0, // GL_TRIANGLES
    2, // GL_TRIANGLE_STRIP
    2, // GL_TRIANGLE_FAN
    0, // GL_QUADS
    2, // GL_QUAD_STRIP
    3  // GL_POLYGON
};

// If you modify this function, you need to also modify
// VA_DrawElementsFlushPartialPrimitive.
void FASTCALL PolyArrayFlushPartialPrimitive()
{
    POLYARRAY *pa;
    POLYDATA  *pd0, *pdFlush;
    GLenum    mode;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;
    GLuint    paFlags;
#ifdef NEW_PARTIAL_PRIM
    SAVEREGION savereg[3];     // Temporary storage for vertices, shared between
#endif // NEW_PARTIAL_PRIM     // parts of decomposed primitive                 
    __GL_SETUP();

    pa = gc->paTeb;

#ifdef PRIMITIVE_TRACK
    prim_entries += pa->pdNextVertex-pa->pd0;
    DbgPrint("* Flush partial primitive with %d polydata entries\n",
          pa->pdNextVertex-pa->pd0);
#endif

    ASSERTOPENGL(pa->flags & POLYARRAY_IN_BEGIN, "not in begin\n");
    ASSERTOPENGL(!pa->aIndices || (pa->aIndices == PA_aIndices_INITIAL_VALUE),
                 "Flushing DrawElements unexpected!\n");

// Flush invalid commands accumulated in the command buffer if there is any.

    glsbAttention();

    // Clear the POLYARRAY_IN_BEGIN flag in the TEB.  We are now out of
    // the begin/end bracket temporarily.  glsbAttention does not flush
    // unless the flag is clear.

    pa->flags &= ~POLYARRAY_IN_BEGIN;

    // Mark it as a partially completed primitive batch.

    pa->flags |= POLYARRAY_PARTIAL_END;

    // Clear POLYARRAY_SAME_COLOR_DATA flag if the primitive uses more than
    // one color.  Also clear the flag if an evaluator is used.  We cannot
    // tell if an evaluator modifies the color on the client side.

    if ((pa->pdCurColor != pa->pd0) ||
        ((pa->pd0->flags & POLYDATA_COLOR_VALID) &&
         (pa->flags & POLYARRAY_PARTIAL_BEGIN)) ||
        (pa->pdLastEvalColor != pa->pd0))
        pa->flags &= ~POLYARRAY_SAME_COLOR_DATA;

    // Save some pa flags for next partial primitive.
    // Need to preserve POLYARRAY_CLAMP_COLOR flag in dlist playback.

#ifdef NEW_PARTIAL_PRIM
    // We have to preserve material flags to handle first vertex
    //
    paFlags = pa->flags & (POLYARRAY_SAME_POLYDATA_TYPE |
                           POLYARRAY_SAME_COLOR_DATA |
                           POLYARRAY_TEXTURE1 |
                           POLYARRAY_TEXTURE2 |
                           POLYARRAY_TEXTURE3 |
                           POLYARRAY_TEXTURE4 |
                           POLYARRAY_VERTEX2  |
                           POLYARRAY_VERTEX3  |
                           POLYARRAY_VERTEX4  |
                           POLYDATA_MATERIAL_FRONT | 
                           POLYDATA_MATERIAL_BACK  |
                           POLYARRAY_CLAMP_COLOR);
#else
    paFlags = pa->flags & (POLYARRAY_SAME_POLYDATA_TYPE |
                           POLYARRAY_SAME_COLOR_DATA |
                           POLYARRAY_CLAMP_COLOR);
#endif
    // Compute nIndices.  It is the final number of vertices passed to the low
    // level render routines and is different from the number of polydata's
    // accumulated.  The final number includes the reserved vertices and the
    // accumulated vertices.

    pa->nIndices += (GLint)((ULONG_PTR)(pa->pdNextVertex - pa->pd0));

    // Save states before flushing the batch.

    mode = pa->primType;

#ifdef NEW_PARTIAL_PRIM
    // Save shared vertices for the next part of the partial primitive

    pfnSaveFunc[mode](gc, pa, savereg);
#endif // NEW_PARTIAL_PRIM

    // Save the POLYARRAY structure in the batch.

    pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
    
    ((BYTE *) pa->pMsgBatchInfo + pa->nextMsgOffset -
       GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
    *(POLYARRAY *) pMsgDrawPolyArray->paLast = *pa;


    // Flush the command buffer and reset pointer for the next batch.
    // If we are compiling poly array primitive in dlist, record the last poly
    // data record.

    if (gc->dlist.beginRec)
    {
        // Record the poly data.
        __glDlistCompilePolyData(gc, GL_FALSE);

        // We just recorded this vertex, don't record it in the compile
        // code again!
        gc->dlist.skipPolyData = GL_TRUE;

        if (gc->dlist.mode == GL_COMPILE_AND_EXECUTE)
            glsbAttention();    // reset pdBufferNext pointer too!
        else
            glsbResetBuffers(TRUE); // reset pointers but no execution
    }
    else
    {
        glsbAttention();    // reset pdBufferNext pointer too!
    }

    ASSERTOPENGL(pa->nextMsgOffset == PA_nextMsgOffset_RESET_VALUE, 
                 "bad nextMsgOffset\n");

    // Batch new POLYARRAY command in the command buffer.
    
    GLCLIENT_BEGIN(DrawPolyArray, DRAWPOLYARRAY)
    // need msg pointer to update pa later
    pMsgDrawPolyArray = pMsg;

    // start of a new chain
    pMsgDrawPolyArray->pa0    =
    pMsgDrawPolyArray->paLast = (PVOID) pa->pdBufferNext;

    // remember the end of the primitive command
    pa->nextMsgOffset = pMsgBatchInfo->NextOffset;
    GLCLIENT_END

#ifdef NEW_PARTIAL_PRIM
// Compute the start of the PARTIAL primitive.  A partial primitive begins
// with a POLYARRAY entry followed by vertex entries.  We DO NOT not need to
// reserve additional vertex entries at the beginning for connectivity
// between decomposed primitives. Because we just add them at the beginning

    pd0 = pa->pdBufferNext + 1;
#else
// Compute the start of the PARTIAL primitive.  A partial primitive begins
// with a POLYARRAY entry followed by vertex entries.  We need to
// reserve additional vertex entries at the beginning for connectivity
// between decomposed primitives.

    pd0 = pa->pdBufferNext + 1 + nReservedIndicesPartialBegin[mode];

#endif // NEW_PARTIAL_PRIM

    // Initialize first polydata.

    pd0->flags = 0;
    
    ASSERTOPENGL(pd0->color == &pd0->colors[__GL_FRONTFACE],
                 "bad color pointer!\n");
    
    // Initialize the polyarray structure in the TEB.

    pa->flags         = POLYARRAY_IN_BEGIN | POLYARRAY_PARTIAL_BEGIN | paFlags;
    pa->pdNextVertex  =
    pa->pd0           = pd0;
    pa->primType      = mode;
    pa->paNext        = NULL;
#ifdef NEW_PARTIAL_PRIM
    pa->nIndices      = 0;          // WE do not reserve any vertices
#else
    pa->nIndices      = nReservedIndicesPartialBegin[mode];
#endif // NEW_PARTIAL_PRIM
    pa->aIndices      = NULL;   // identity mapping
    pa->pdCurColor    =
    pa->pdCurNormal   =
    pa->pdCurTexture  =
    pa->pdCurEdgeFlag =
    pa->pdLastEvalColor    =
    pa->pdLastEvalNormal   =
    pa->pdLastEvalTexture  = NULL;


    // Compute the flush vertex for this primitive.  When the flush vertex is
    // reached, we will have accumulated enough vertices to render a partially
    // composed primitive.

    pdFlush = pa->pdBufferMax;
    switch (mode)
    {
      case GL_POINTS:
      case GL_LINE_STRIP:
      case GL_TRIANGLE_FAN:
        break;
      case GL_LINE_LOOP:
        // Line loop reserves an additional end vertex to close the loop.
        pdFlush--;
        break;
      case GL_POLYGON:
        // The polygon decomposer can only handle up to
        // __GL_MAX_POLYGON_CLIP_SIZE vertices.  We also need to give
        // allowance for 3 vertices in the decomposed polygons.
        if (pdFlush > (pd0 - 3) + __GL_MAX_POLYGON_CLIP_SIZE - 1)
            pdFlush = (pd0 - 3) + __GL_MAX_POLYGON_CLIP_SIZE - 1;
        ASSERTOPENGL(nReservedIndicesPartialBegin[GL_POLYGON] == 3,
                     "bad reserved size!\n");
        break;
      case GL_LINES:
      case GL_TRIANGLE_STRIP:
      case GL_QUAD_STRIP:
        // number of vertices must be a multiple of 2
        if ((pdFlush - pd0 + 1) % 2)
            pdFlush--;
        break;
      case GL_TRIANGLES:
        // number of vertices must be a multiple of 3
        switch ((pdFlush - pd0 + 1) % 3)
        {
          case 2: pdFlush--;        // fall through
          case 1: pdFlush--;
        }
        break;
      case GL_QUADS:
        // number of vertices must be a multiple of 4
        switch ((pdFlush - pd0 + 1) % 4)
        {
          case 3: pdFlush--;        // fall through
          case 2: pdFlush--;        // fall through
          case 1: pdFlush--;
        }
        break;
    }
    pa->pdFlush = pdFlush;

#ifdef NEW_PARTIAL_PRIM
    // Add saved vertices into the new part of the primitive

    pfnRestoreFunc[mode](gc, pa, savereg);

#endif // NEW_PARTIAL_PRIM
}

// Special version of Flush for DrawElements.
// If you modify this function, you need to also modify
// PolyArrayFlushPartialPrimitive.
void FASTCALL VA_DrawElementsFlushPartialPrimitive(POLYARRAY *pa, GLenum mode)
{
    POLYDATA  *pd0;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;
    GLuint    paFlags;
#ifdef NEW_PARTIAL_PRIM
    SAVEREGION  savereg[3];     // Temporary storage for vertices, shared between
#endif // NEW_PARTIAL_PRIM             // parts of decomposed primitive                 
    __GL_SETUP();

#ifdef PRIMITIVE_TRACK
    DbgPrint("VA_DrawElementsFlushPartialPrimitive called\n");
#endif

    // We don't handle Points, Line Loop, and Polygon here.  They should
    // have been sent to Begin/End.

    ASSERTOPENGL(mode != GL_POINTS && mode != GL_LINE_LOOP && mode != GL_POLYGON,
                 "Primitive type not handled\n");

    ASSERTOPENGL(pa->flags & POLYARRAY_IN_BEGIN, "not in begin\n");
    ASSERTOPENGL(pa->aIndices && (pa->aIndices != PA_aIndices_INITIAL_VALUE),
	"no output index array!\n");

    // Clear the POLYARRAY_IN_BEGIN flag in the TEB.  We are now out of
    // the begin/end bracket temporarily.  glsbAttention does not flush
    // unless the flag is clear.

    pa->flags &= ~POLYARRAY_IN_BEGIN;

    // Mark it as a partially completed primitive batch.

    pa->flags |= POLYARRAY_PARTIAL_END;

    // Clear POLYARRAY_SAME_COLOR_DATA flag if the primitive uses more than
    // one color.

    if (pa->pdCurColor != pa->pd0)
        pa->flags &= ~POLYARRAY_SAME_COLOR_DATA;

    // Save some pa flags for next partial primitive.

    paFlags = pa->flags & (POLYARRAY_SAME_COLOR_DATA |
                           POLYARRAY_TEXTURE1 |
                           POLYARRAY_TEXTURE2 |
                           POLYARRAY_TEXTURE3 |
                           POLYARRAY_TEXTURE4 |
                           POLYARRAY_VERTEX2  |
                           POLYARRAY_VERTEX3  |
                           POLYARRAY_VERTEX4  |
                           POLYARRAY_CLAMP_COLOR);

#ifdef NEW_PARTIAL_PRIM
    // Save shared vertices for the next part of partial primitive

    pfnSaveFunc[mode](gc, pa, savereg);

#endif // NEW_PARTIAL_PRIM

    // Save the POLYARRAY structure in the batch.

    pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
      ((BYTE *) pa->pMsgBatchInfo + pa->nextMsgOffset -
       GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
    *(POLYARRAY *) pMsgDrawPolyArray->paLast = *pa;

    // Flush the command buffer and reset pointer for the next batch.

    ASSERTOPENGL(!gc->dlist.beginRec
                 || gc->dlist.mode == GL_COMPILE_AND_EXECUTE,
                 "dlist complilation unexpected!\n");
    glsbAttention();    // reset pdBufferNext pointer too!

    ASSERTOPENGL(pa->nextMsgOffset == PA_nextMsgOffset_RESET_VALUE, 
                 "bad nextMsgOffset\n");

    // Batch new POLYARRAY command in the command buffer.

    GLCLIENT_BEGIN(DrawPolyArray, DRAWPOLYARRAY)
    // need msg pointer to update pa later
    pMsgDrawPolyArray = pMsg;

    // start of a new chain
    pMsgDrawPolyArray->pa0    =
    pMsgDrawPolyArray->paLast = (PVOID) pa->pdBufferNext;

    // remember the end of the primitive command
    pa->nextMsgOffset = pMsgBatchInfo->NextOffset;
    GLCLIENT_END

#ifdef NEW_PARTIAL_PRIM
// Compute the start of the PARTIAL primitive.  A partial primitive begins
// with a POLYARRAY entry followed by vertex entries.  We DO NOT need to
// reserve additional vertex entries at the beginning for connectivity
// between decomposed primitives.

    pd0 = pa->pdBufferNext + 1;
#else
// Compute the start of the PARTIAL primitive.  A partial primitive begins
// with a POLYARRAY entry followed by vertex entries.  We need to
// reserve additional vertex entries at the beginning for connectivity
// between decomposed primitives.

    pd0 = pa->pdBufferNext + 1 + nReservedIndicesPartialBegin[mode];
#endif

    // Initialize first polydata.

    pd0->flags = 0;
    
    ASSERTOPENGL(pd0->color == &pd0->colors[__GL_FRONTFACE],
                 "bad color pointer!\n");
    
    // Initialize the polyarray structure in the TEB.

    pa->flags         = POLYARRAY_IN_BEGIN | POLYARRAY_PARTIAL_BEGIN |
      POLYARRAY_SAME_POLYDATA_TYPE | paFlags;
    pa->pdNextVertex  =
    pa->pd0           = pd0;
    pa->primType      = mode;
    pa->pdCurColor    =
    pa->pdCurNormal   =
    pa->pdCurTexture  =
    pa->pdCurEdgeFlag = NULL;
    pa->paNext        = NULL;
#ifdef NEW_PARTIAL_PRIM
    pa->nIndices      = 0;
#else
    pa->nIndices      = nReservedIndicesPartialBegin[mode];
#endif // NEW_PARTIAL_PRIM
    pa->aIndices      = PA_aIndices_INITIAL_VALUE;  // this is updated in End
    
// The flush vertex for this primitive should never be reached.  The call
// to glsbAttention in this function has left enough room for a vertex batch.
// Set it to maximum and assert that we never reach the vertex in
// PolyArrayFlushPartialPrimitive!

    pa->pdFlush = pa->pdBufferMax;

#ifdef NEW_PARTIAL_PRIM
    // Add saved vertices into the new part of the primitive

    pfnRestoreFunc[mode](gc, pa, savereg);

#endif // NEW_PARTIAL_PRIM
}

// The vertex functions are called in begin/end only.
#define PA_VERTEX2(x1,y1)					\
								\
    POLYARRAY *pa;						\
    POLYDATA  *pd;						\
								\
    pa = GLTEB_CLTPOLYARRAY();					\
								\
    if (pa->flags & POLYARRAY_IN_BEGIN)				\
    {								\
	pa->flags |= POLYARRAY_VERTEX2;				\
								\
	pd = pa->pdNextVertex++;				\
	pd->flags |= POLYDATA_VERTEX2;				\
	pd->obj.x = x1;						\
	pd->obj.y = y1;						\
	pd->obj.z = __glZero;					\
	pd->obj.w = __glOne;					\
								\
	pd[1].flags = 0;					\
								\
	if (pd >= pa->pdFlush)            			\
	    PolyArrayFlushPartialPrimitive(); 			\
    }      

#define PA_VERTEX3(x1,y1,z1)				\
{								            \
    GLfloat t1;							    \
    POLYARRAY *pa;							\
    POLYDATA  *pd, *pd1;					\
    ULONG	flag1, flag2, flag3;			\
    register GLfloat tone;					\
                                            \
    pa = GLTEB_CLTPOLYARRAY();				\
    tone = 1.0;                             \
                                            \
    pd1 = pa->pdFlush;						\
    flag1 = pa->flags;						\
    pd = pa->pdNextVertex;					\
                                            \
    if (flag1 & POLYARRAY_IN_BEGIN)         \
    {                                       \
        flag3 = pd->flags;                  \
        pa->pdNextVertex++;                 \
        flag2 = flag1 | POLYARRAY_VERTEX3;  \
        flag3 = flag3 | POLYDATA_VERTEX3;   \
                                            \
        pd->obj.x = x1;						\
        pd->obj.y = y1;						\
        pd->obj.z = z1;						\
        pd->obj.w = tone;					\
        pa->flags = flag2;					\
        pd->flags = flag3;					    \
								                \
        pd[1].flags = 0;					    \
								                \
        if (pd >= pd1)		            		\
	        PolyArrayFlushPartialPrimitive();   \
    }                                           \
}

#define PA_VERTEX4(x1,y1,z1,w1)					\
								\
    POLYARRAY *pa;						\
    POLYDATA  *pd;						\
								\
    pa = GLTEB_CLTPOLYARRAY();					\
								\
    if (pa->flags & POLYARRAY_IN_BEGIN)				\
    {								\
	pa->flags |= POLYARRAY_VERTEX4;				\
								\
	pd = pa->pdNextVertex++;				\
	pd->flags |= POLYDATA_VERTEX4;				\
	pd->obj.x = x1;						\
	pd->obj.y = y1;						\
	pd->obj.z = z1;						\
	pd->obj.w = w1;						\
								\
	pd[1].flags = 0;					\
								\
	if (pd >= pa->pdFlush)            			\
	    PolyArrayFlushPartialPrimitive(); 			\
    }

#define PA_COLOR_IN_RGBA_NO_CLAMP1(red,green,blue)		            \
    POLYARRAY *pa;						            \
    POLYDATA  *pd;						            \
    __GL_SETUP();                                                           \
								            \
    pa = gc->paTeb;							    \
								            \
    if (pa->flags & POLYARRAY_IN_BEGIN)				            \
    {								            \
	pd = pa->pdNextVertex;					            \
	pa->pdCurColor = pd;					            \
                                                                            \
        __GL_SCALE_RGB(pd->colors[0].r, pd->colors[0].g, pd->colors[0].b,   \
                       gc, red, green, blue);    	                    \
        pd->colors[0].a = gc->alphaVertexScale;                             \
                                                                            \
	pd->flags |= POLYDATA_COLOR_VALID;				    \
    }								            \
    else							            \
    {								            \
	glcltColor4f_InRGBA_NotInBegin(gc, pa,				    \
	  POLYDATA_COLOR_VALID, red, green, blue, __glOne);		    \
    }

#define PA_COLOR_IN_RGBA_NO_CLAMP(red,green,blue,alpha)		            \
    POLYARRAY *pa;						            \
    POLYDATA  *pd;						            \
    __GL_SETUP();                                                           \
								            \
    pa = gc->paTeb;							    \
								            \
    if (pa->flags & POLYARRAY_IN_BEGIN)				            \
    {								            \
	pd = pa->pdNextVertex;					            \
	pa->pdCurColor = pd;					            \
                                                                            \
        __GL_SCALE_RGBA(pd->colors[0].r,                                    \
                        pd->colors[0].g,                                    \
                        pd->colors[0].b,                                    \
                        pd->colors[0].a,                                    \
                        gc, red, green, blue, alpha);                       \
                                                                            \
	pd->flags |= POLYDATA_COLOR_VALID | POLYDATA_DLIST_COLOR_4;	    \
    }								            \
    else							            \
    {								            \
	glcltColor4f_InRGBA_NotInBegin(gc, pa,				    \
	  POLYDATA_COLOR_VALID | POLYDATA_DLIST_COLOR_4, red, green, blue, alpha);\
    }

#define PA_COLOR_IN_RGB1(red,green,blue)			            \
    POLYARRAY *pa;						            \
    POLYDATA  *pd;						            \
    __GL_SETUP();                                                           \
								            \
    pa = gc->paTeb;						            \
								            \
    if (pa->flags & POLYARRAY_IN_BEGIN)				            \
    {								            \
	pd = pa->pdNextVertex;					            \
	pa->pdCurColor = pd;					            \
                                                                            \
        __GL_SCALE_AND_CHECK_CLAMP_RGB(pd->colors[0].r,                     \
                                       pd->colors[0].g,                     \
                                       pd->colors[0].b,                     \
                                       gc, pa->flags,                       \
                                       red, green, blue);                   \
        pd->colors[0].a = gc->alphaVertexScale;                             \
                                                                            \
	pd->flags |= POLYDATA_COLOR_VALID;			            \
    }								            \
    else							            \
    {								            \
	glcltColor4f_InRGBA_NotInBegin(gc, pa,				    \
	  POLYDATA_COLOR_VALID, red, green, blue, __glOne);		    \
    }

#define PA_COLOR_IN_RGB2(red, green, blue)      \
{                                               \
    POLYARRAY *pa;                              \
    POLYDATA  *pd;                              \
    GLfloat sr, sg, sb;                         \
    ULONG f1, f2, f3, f4, f5, f6;               \
    LONG t1, t2, t3;                            \
                                                \
    __GL_SETUP();                               \
                                                \
    pa = gc->paTeb;                             \
                                                \
    if (pa->flags & POLYARRAY_IN_BEGIN)			\
    {                                           \
                                                \
        t1 = (LONG) (CASTINT(gc->redVertexScale));      \
        t2 = (LONG) (CASTINT(gc->greenVertexScale));	\
        t3 = (LONG) (CASTINT(gc->blueVertexScale));		\
                                                \
        pd = pa->pdNextVertex;                  \
        pa->pdCurColor = pd;                    \
                                                \
        sr = red *  gc->redVertexScale;         \
        sg = green * gc->greenVertexScale;      \
        sb = blue * gc->blueVertexScale;        \
                                                \
        f1 = (ULONG) (CASTINT(sr));             \
        f2 = (ULONG) (CASTINT(sg));             \
        f3 = (ULONG) (CASTINT(sb));             \
							                    \
        f4 = (ULONG) (t1 - CASTINT(sr));		\
        f5 = (ULONG) (t2 - CASTINT(sg));		\
        f6 = (ULONG) (t3 - CASTINT(sb));		\
                                                \
        f1 = f1 | f2;                           \
        f3 = f3 | f4;                           \
        f5 = f5 | f6;                           \
                                                \
        pd->colors[0].r = sr;					\
        pd->colors[0].g = sg;					\
        pd->colors[0].b = sb;					\
                                                \
        f1 = f1 | f3 | f5;                      \
                                                \
        pa->flags |= (f1 & 0x80000000);         \
                                                \
        pd->colors[0].a = gc->alphaVertexScale; \
                             				    \
        pd->flags |= POLYDATA_COLOR_VALID;		\
    }	                                        \
    else                                        \
    {	                                        \
        glcltColor4f_InRGBA_NotInBegin(gc, pa,              \
          POLYDATA_COLOR_VALID, red, green, blue, __glOne);	\
    }								                        \
}

#define PA_COLOR_IN_RGBA(red,green,blue,alpha)			            \
    POLYARRAY *pa;						            \
    POLYDATA  *pd;						            \
    __GL_SETUP();                                                           \
								            \
    pa = gc->paTeb;							    \
								            \
    if (pa->flags & POLYARRAY_IN_BEGIN)				            \
    {								            \
	pd = pa->pdNextVertex;					            \
	pa->pdCurColor = pd;					            \
                                                                            \
        __GL_SCALE_AND_CHECK_CLAMP_RGBA(pd->colors[0].r,                    \
                                        pd->colors[0].g,                    \
                                        pd->colors[0].b,                    \
                                        pd->colors[0].a,                    \
                                        gc, pa->flags,                      \
                                        red, green, blue, alpha);           \
                                                                            \
	pd->flags |= POLYDATA_COLOR_VALID | POLYDATA_DLIST_COLOR_4;	    \
    }								            \
    else							            \
    {								            \
	glcltColor4f_InRGBA_NotInBegin(gc, pa,				    \
	  POLYDATA_COLOR_VALID | POLYDATA_DLIST_COLOR_4, red, green, blue, alpha);\
    }

#define PA_COLOR_IN_CI(red,green,blue,alpha)			\
								\
    POLYARRAY *pa;						\
								\
    pa = GLTEB_CLTPOLYARRAY();					\
								\
    if (pa->flags & POLYARRAY_IN_BEGIN)				\
    {								\
	pa->flags |= POLYARRAY_OTHER_COLOR;			\
	/* need only record the latest values */		\
	/* otherColor in the TEB may not be aligned at 16-byte boundary */ \
	pa->otherColor.r = red;					\
	pa->otherColor.g = green;				\
	pa->otherColor.b = blue;				\
	pa->otherColor.a = alpha;				\
    }								\
    else							\
    {								\
	glcltColor4f_NotInBegin(red, green, blue, alpha);	\
    }

void FASTCALL glcltColor4f_NotInBegin(GLfloat red, GLfloat green,
    GLfloat blue, GLfloat alpha)
{
    GLCLIENT_BEGIN( Color4fv, COLOR4FV )
        pMsg->v[0] = red;
        pMsg->v[1] = green;
        pMsg->v[2] = blue;
        pMsg->v[3] = alpha;
    GLCLIENT_END
}

void FASTCALL glcltColor4f_InRGBA_NotInBegin(__GLcontext *gc, POLYARRAY *pa,
    GLuint pdFlags, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
{
    POLYDATA  *pd;
    GLMSGBATCHINFO *pMsgBatchInfo;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;

    pMsgBatchInfo = (GLMSGBATCHINFO *) pa->pMsgBatchInfo;

    // If the last command is DrawPolyArray, add it to the command.
    // This allows us to chain primitives separated by the attribute.
    if (pMsgBatchInfo->NextOffset == pa->nextMsgOffset)
    {
	pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
	    ((BYTE *) pMsgBatchInfo + pMsgBatchInfo->NextOffset -
	     GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
        pa = (POLYARRAY *) pMsgDrawPolyArray->paLast;

	pd = pa->pdNextVertex;
	pa->pdCurColor = pd;

        __GL_SCALE_AND_CHECK_CLAMP_RGBA(pd->colors[0].r,
                                        pd->colors[0].g,
                                        pd->colors[0].b,
                                        pd->colors[0].a,
                                        gc, pa->flags,
                                        red, green, blue, alpha);

	pd->flags |= pdFlags;
    }
    else
    {
	glcltColor4f_NotInBegin(red, green, blue, alpha);
    }
}

#define PA_INDEX_IN_RGBA(i)					\
								\
    POLYARRAY *pa;						\
								\
    pa = GLTEB_CLTPOLYARRAY();					\
								\
    if (pa->flags & POLYARRAY_IN_BEGIN)				\
    {								\
	pa->flags |= POLYARRAY_OTHER_COLOR;			\
	/* need only record the latest value */			\
	pa->otherColor.r = i;					\
    }								\
    else							\
    {								\
	glcltIndexf_NotInBegin(i);				\
    }

#define PA_INDEX_IN_CI(i)					\
								\
    POLYARRAY *pa;						\
    POLYDATA  *pd;						\
    __GL_SETUP();                                               \
								\
    pa = gc->paTeb;					        \
								\
    if (pa->flags & POLYARRAY_IN_BEGIN)				\
    {								\
	pd = pa->pdNextVertex;					\
	pa->pdCurColor = pd;					\
        __GL_CHECK_CLAMP_CI(pd->colors[0].r, gc, pa->flags, i);	\
	pd->flags |= POLYDATA_COLOR_VALID;			\
    }								\
    else							\
    {								\
	glcltIndexf_InCI_NotInBegin(gc, pa, i);			\
    }

void FASTCALL glcltIndexf_NotInBegin(GLfloat c)
{
    GLCLIENT_BEGIN( Indexf, INDEXF )
	pMsg->c = c;
    GLCLIENT_END
}

void FASTCALL glcltIndexf_InCI_NotInBegin(__GLcontext *gc, POLYARRAY *pa, GLfloat c)
{
    POLYDATA  *pd;
    GLMSGBATCHINFO *pMsgBatchInfo;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;

    pMsgBatchInfo = (GLMSGBATCHINFO *) pa->pMsgBatchInfo;

    // If the last command is DrawPolyArray, add it to the command.
    // This allows us to chain primitives separated by the attribute.
    if (pMsgBatchInfo->NextOffset == pa->nextMsgOffset)
    {
	pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
	    ((BYTE *) pMsgBatchInfo + pMsgBatchInfo->NextOffset -
	     GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
        pa = (POLYARRAY *) pMsgDrawPolyArray->paLast;

	pd = pa->pdNextVertex;
	pa->pdCurColor = pd;
        __GL_CHECK_CLAMP_CI(pd->colors[0].r, gc, pa->flags, c);
	pd->flags |= POLYDATA_COLOR_VALID;
    }
    else
    {
	glcltIndexf_NotInBegin(c);
    }
}

#define PA_TEXTURE1(s1)							\
									\
    POLYARRAY *pa;							\
    POLYDATA  *pd;							\
									\
    pa = GLTEB_CLTPOLYARRAY();						\
									\
    if (pa->flags & POLYARRAY_IN_BEGIN)					\
    {									\
	pa->flags |= POLYARRAY_TEXTURE1;				\
									\
	pd = pa->pdNextVertex;						\
	pa->pdCurTexture = pd;						\
	pd->flags |= POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE1;	\
	pd->texture.x = s1;						\
	pd->texture.y = __glZero;					\
	pd->texture.z = __glZero;					\
	pd->texture.w = __glOne;					\
    }									\
    else								\
    {									\
	glcltTexCoord4f_NotInBegin(pa, POLYARRAY_TEXTURE1,		\
	    s1, __glZero, __glZero, __glOne);				\
    }

#define PA_TEXTURE2(s1,t1)						\
									\
    POLYARRAY *pa;							\
    POLYDATA  *pd;							\
									\
    pa = GLTEB_CLTPOLYARRAY();						\
									\
    if (pa->flags & POLYARRAY_IN_BEGIN)					\
    {									\
	pa->flags |= POLYARRAY_TEXTURE2;				\
									\
	pd = pa->pdNextVertex;						\
	pa->pdCurTexture = pd;						\
	pd->flags |= POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE2;	\
	pd->texture.x = s1;						\
	pd->texture.y = t1;						\
	pd->texture.z = __glZero;					\
	pd->texture.w = __glOne;					\
    }									\
    else								\
    {									\
	glcltTexCoord4f_NotInBegin(pa, POLYARRAY_TEXTURE2,		\
	    s1, t1, __glZero, __glOne);					\
    }

#define PA_TEXTURE3(s1,t1,r1)						\
									\
    POLYARRAY *pa;							\
    POLYDATA  *pd;							\
									\
    pa = GLTEB_CLTPOLYARRAY();						\
									\
    if (pa->flags & POLYARRAY_IN_BEGIN)					\
    {									\
	pa->flags |= POLYARRAY_TEXTURE3;				\
									\
	pd = pa->pdNextVertex;						\
	pa->pdCurTexture = pd;						\
	pd->flags |= POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE3;	\
	pd->texture.x = s1;						\
	pd->texture.y = t1;						\
	pd->texture.z = r1;						\
	pd->texture.w = __glOne;					\
    }									\
    else								\
    {									\
	glcltTexCoord4f_NotInBegin(pa, POLYARRAY_TEXTURE3,		\
	    s1, t1, r1, __glOne);					\
    }

#define PA_TEXTURE4(s1,t1,r1,q1)					\
									\
    POLYARRAY *pa;							\
    POLYDATA  *pd;							\
									\
    pa = GLTEB_CLTPOLYARRAY();						\
									\
    if (pa->flags & POLYARRAY_IN_BEGIN)					\
    {									\
	pa->flags |= POLYARRAY_TEXTURE4;				\
									\
	pd = pa->pdNextVertex;						\
	pa->pdCurTexture = pd;						\
	pd->flags |= POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE4;	\
	pd->texture.x = s1;						\
	pd->texture.y = t1;						\
	pd->texture.z = r1;						\
	pd->texture.w = q1;						\
    }									\
    else								\
    {									\
	glcltTexCoord4f_NotInBegin(pa, POLYARRAY_TEXTURE4,		\
	    s1, t1, r1, q1);						\
    }

void FASTCALL glcltTexCoord4f_NotInBegin(POLYARRAY *pa, GLuint paFlags,
    GLfloat s, GLfloat t, GLfloat r, GLfloat q)
{
    POLYDATA  *pd;
    GLMSGBATCHINFO *pMsgBatchInfo;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;

    pMsgBatchInfo = (GLMSGBATCHINFO *) pa->pMsgBatchInfo;

    // If the last command is DrawPolyArray, add it to the command.
    // This allows us to chain primitives separated by the attribute.
    if (pMsgBatchInfo->NextOffset == pa->nextMsgOffset)
    {
	pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
	    ((BYTE *) pMsgBatchInfo + pMsgBatchInfo->NextOffset -
	     GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
        pa = (POLYARRAY *) pMsgDrawPolyArray->paLast;

	pa->flags |= paFlags;
	pd = pa->pdNextVertex;
	pa->pdCurTexture = pd;
	pd->flags |= POLYDATA_TEXTURE_VALID | paFlags;
	pd->texture.x = s;
	pd->texture.y = t;
	pd->texture.z = r;
	pd->texture.w = q;
    }
    else
    {
	GLCLIENT_BEGIN( TexCoord4fv, TEXCOORD4FV )
	    pMsg->v[0] = s;
	    pMsg->v[1] = t;
	    pMsg->v[2] = r;
	    pMsg->v[3] = q;
	GLCLIENT_END
    }
}

#define PA_NORMAL(x1, y1, z1)					\
{								\
    POLYARRAY *pa;						\
    POLYDATA  *pd;						\
    ULONG flag1, flag2;						\
								\
    pa = GLTEB_CLTPOLYARRAY();					\
								\
    pd = pa->pdNextVertex;					\
    flag1 = pa->flags;						\
								\
    if (flag1 & POLYARRAY_IN_BEGIN)         \
    {                                       \
        flag2 = pd->flags;					\
        flag2 |= POLYDATA_NORMAL_VALID;	    \
        pa->pdCurNormal = pd;				\
        pd->normal.x = x1;					\
        pd->normal.y = y1;					\
        pd->normal.z = z1;					\
        pd->flags = flag2;					\
    }								\
    else							\
    {								\
        glcltNormal3f_NotInBegin(pa, x1, y1, z1);		\
    }								\
								\
}

void FASTCALL glcltNormal3f_NotInBegin(POLYARRAY *pa, GLfloat nx, GLfloat ny, GLfloat nz)
{
    POLYDATA  *pd;
    GLMSGBATCHINFO *pMsgBatchInfo;
    GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray;

    pMsgBatchInfo = (GLMSGBATCHINFO *) pa->pMsgBatchInfo;

    // If the last command is DrawPolyArray, add it to the command.
    // This allows us to chain primitives separated by the attribute.
    if (pMsgBatchInfo->NextOffset == pa->nextMsgOffset)
    {
	pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *)
	    ((BYTE *) pMsgBatchInfo + pMsgBatchInfo->NextOffset -
	     GLMSG_ALIGN(sizeof(GLMSG_DRAWPOLYARRAY)));
        pa = (POLYARRAY *) pMsgDrawPolyArray->paLast;

	pd = pa->pdNextVertex;
	pa->pdCurNormal = pd;
	pd->flags |= POLYDATA_NORMAL_VALID;
	pd->normal.x = nx;
	pd->normal.y = ny;
	pd->normal.z = nz;
    }
    else
    {
	GLCLIENT_BEGIN( Normal3fv, NORMAL3FV )
	    pMsg->v[ 0] = nx;
	    pMsg->v[ 1] = ny;
	    pMsg->v[ 2] = nz;
	GLCLIENT_END
    }
}

#define PA_EDGEFLAG(edgeflag)						    \
									    \
    POLYARRAY *pa;							    \
    POLYDATA  *pd;							    \
									    \
    pa = GLTEB_CLTPOLYARRAY();						    \
									    \
    if (pa->flags & POLYARRAY_IN_BEGIN)					    \
    {									    \
	pd = pa->pdNextVertex;						    \
	pa->pdCurEdgeFlag = pd;						    \
	if (edgeflag)							    \
	    pd->flags |= POLYDATA_EDGEFLAG_VALID|POLYDATA_EDGEFLAG_BOUNDARY;\
	else								    \
	{								    \
	    /* must clear POLYDATA_EDGEFLAG_BOUNDARY flag here since    */  \
	    /* there may have been a previous edge flag for this same   */  \
	    /* vertex!                                                  */  \
	    pd->flags &= ~POLYDATA_EDGEFLAG_BOUNDARY;			    \
	    pd->flags |= POLYDATA_EDGEFLAG_VALID;			    \
	}								    \
    }									    \
    else								    \
    {									    \
	glcltEdgeFlag_NotInBegin(edgeflag);				    \
    }

void FASTCALL glcltEdgeFlag_NotInBegin(GLboolean flag)
{
    GLCLIENT_BEGIN( EdgeFlag, EDGEFLAG )
	pMsg->flag  = flag;
    GLCLIENT_END
}

void APIENTRY
glcltColor3b_InRGBA ( IN GLbyte red, IN GLbyte green, IN GLbyte blue )
{
    PA_COLOR_IN_RGB1(__GL_B_TO_FLOAT(red), __GL_B_TO_FLOAT(green),
	             __GL_B_TO_FLOAT(blue));
}

void APIENTRY
glcltColor3bv_InRGBA ( IN const GLbyte v[3] )
{
    PA_COLOR_IN_RGB1(__GL_B_TO_FLOAT(v[0]), __GL_B_TO_FLOAT(v[1]),
	             __GL_B_TO_FLOAT(v[2]));
}

void APIENTRY
glcltColor3d_InRGBA ( IN GLdouble red, IN GLdouble green, IN GLdouble blue )
{
    PA_COLOR_IN_RGB1((GLfloat) red, (GLfloat) green,
		     (GLfloat) blue);
}

void APIENTRY
glcltColor3dv_InRGBA ( IN const GLdouble v[3] )
{
    PA_COLOR_IN_RGB1((GLfloat) v[0], (GLfloat) v[1],
		     (GLfloat) v[2]);
}

#ifndef __GL_ASM_GLCLTCOLOR3F_INRGBA
void APIENTRY
glcltColor3f_InRGBA ( IN GLfloat red, IN GLfloat green, IN GLfloat blue )
{
    PA_COLOR_IN_RGB2(red, green, blue);
}
#endif // __GL_ASM_GLCLTCOLOR3F_INRGBA

#ifndef __GL_ASM_GLCLTCOLOR3FV_INRGBA
void APIENTRY
glcltColor3fv_InRGBA ( IN const GLfloat v[3] )
{
    GLfloat red, green, blue;

    red = (GLfloat) v[0];
    green = (GLfloat) v[1];
    blue = (GLfloat) v[2];

    PA_COLOR_IN_RGB2(red, green, blue);
}
#endif // __GL_ASM_GLCLTCOLOR3FV_INRGBA

void APIENTRY
glcltColor3i_InRGBA ( IN GLint red, IN GLint green, IN GLint blue )
{
    PA_COLOR_IN_RGB1(__GL_I_TO_FLOAT(red), __GL_I_TO_FLOAT(green),
	             __GL_I_TO_FLOAT(blue));
}

void APIENTRY
glcltColor3iv_InRGBA ( IN const GLint v[3] )
{
    PA_COLOR_IN_RGB1(__GL_I_TO_FLOAT(v[0]), __GL_I_TO_FLOAT(v[1]),
	             __GL_I_TO_FLOAT(v[2]));
}

void APIENTRY
glcltColor3s_InRGBA ( IN GLshort red, IN GLshort green, IN GLshort blue )
{
    PA_COLOR_IN_RGB1(__GL_S_TO_FLOAT(red), __GL_S_TO_FLOAT(green),
	             __GL_S_TO_FLOAT(blue));
}

void APIENTRY
glcltColor3sv_InRGBA ( IN const GLshort v[3] )
{
    PA_COLOR_IN_RGB1(__GL_S_TO_FLOAT(v[0]), __GL_S_TO_FLOAT(v[1]),
	             __GL_S_TO_FLOAT(v[2]));
}

void APIENTRY
glcltColor3ub_InRGBA ( IN GLubyte red, IN GLubyte green, IN GLubyte blue )
{
    PA_COLOR_IN_RGBA_NO_CLAMP1(__GL_UB_TO_FLOAT(red), __GL_UB_TO_FLOAT(green),
	             __GL_UB_TO_FLOAT(blue));
}

void APIENTRY
glcltColor3ubv_InRGBA ( IN const GLubyte v[3] )
{
    PA_COLOR_IN_RGBA_NO_CLAMP1(__GL_UB_TO_FLOAT(v[0]), __GL_UB_TO_FLOAT(v[1]),
	             __GL_UB_TO_FLOAT(v[2]));
}

void APIENTRY
glcltColor3ui_InRGBA ( IN GLuint red, IN GLuint green, IN GLuint blue )
{
    PA_COLOR_IN_RGB1(__GL_UI_TO_FLOAT(red), __GL_UI_TO_FLOAT(green),
	             __GL_UI_TO_FLOAT(blue));
}

void APIENTRY
glcltColor3uiv_InRGBA ( IN const GLuint v[3] )
{
    PA_COLOR_IN_RGB1(__GL_UI_TO_FLOAT(v[0]), __GL_UI_TO_FLOAT(v[1]),
	             __GL_UI_TO_FLOAT(v[2]));
}

void APIENTRY
glcltColor3us_InRGBA ( IN GLushort red, IN GLushort green, IN GLushort blue )
{
    PA_COLOR_IN_RGBA_NO_CLAMP1(__GL_US_TO_FLOAT(red), __GL_US_TO_FLOAT(green),
	             __GL_US_TO_FLOAT(blue));
}

void APIENTRY
glcltColor3usv_InRGBA ( IN const GLushort v[3] )
{
    PA_COLOR_IN_RGBA_NO_CLAMP1(__GL_US_TO_FLOAT(v[0]), __GL_US_TO_FLOAT(v[1]),
	             __GL_US_TO_FLOAT(v[2]));
}

void APIENTRY
glcltColor4b_InRGBA ( IN GLbyte red, IN GLbyte green, IN GLbyte blue, IN GLbyte alpha )
{
    PA_COLOR_IN_RGBA(__GL_B_TO_FLOAT(red), __GL_B_TO_FLOAT(green),
	             __GL_B_TO_FLOAT(blue), __GL_B_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4bv_InRGBA ( IN const GLbyte v[4] )
{
    PA_COLOR_IN_RGBA(__GL_B_TO_FLOAT(v[0]), __GL_B_TO_FLOAT(v[1]),
	             __GL_B_TO_FLOAT(v[2]), __GL_B_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4d_InRGBA ( IN GLdouble red, IN GLdouble green, IN GLdouble blue, IN GLdouble alpha )
{
    PA_COLOR_IN_RGBA((GLfloat) red, (GLfloat) green,
		     (GLfloat) blue, (GLfloat) alpha);
}

void APIENTRY
glcltColor4dv_InRGBA ( IN const GLdouble v[4] )
{
    PA_COLOR_IN_RGBA((GLfloat) v[0], (GLfloat) v[1],
		     (GLfloat) v[2], (GLfloat) v[3]);
}

#ifndef __GL_ASM_GLCLTCOLOR4F_INRGBA
void APIENTRY
glcltColor4f_InRGBA ( IN GLfloat red, IN GLfloat green, IN GLfloat blue, IN GLfloat alpha )
{
    PA_COLOR_IN_RGBA(red, green, blue, alpha);
}
#endif // __GL_ASM_GLCLTCOLOR4F_INRGBA

#ifndef __GL_ASM_GLCLTCOLOR4FV_INRGBA
void APIENTRY
glcltColor4fv_InRGBA ( IN const GLfloat v[4] )
{
    PA_COLOR_IN_RGBA(v[0], v[1], v[2], v[3]);
}
#endif // __GL_ASM_GLCLTCOLOR4FV_INRGBA

void APIENTRY
glcltColor4i_InRGBA ( IN GLint red, IN GLint green, IN GLint blue, IN GLint alpha )
{
    PA_COLOR_IN_RGBA(__GL_I_TO_FLOAT(red), __GL_I_TO_FLOAT(green),
	             __GL_I_TO_FLOAT(blue), __GL_I_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4iv_InRGBA ( IN const GLint v[4] )
{
    PA_COLOR_IN_RGBA(__GL_I_TO_FLOAT(v[0]), __GL_I_TO_FLOAT(v[1]),
	             __GL_I_TO_FLOAT(v[2]), __GL_I_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4s_InRGBA ( IN GLshort red, IN GLshort green, IN GLshort blue, IN GLshort alpha )
{
    PA_COLOR_IN_RGBA(__GL_S_TO_FLOAT(red), __GL_S_TO_FLOAT(green),
	             __GL_S_TO_FLOAT(blue), __GL_S_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4sv_InRGBA ( IN const GLshort v[4] )
{
    PA_COLOR_IN_RGBA(__GL_S_TO_FLOAT(v[0]), __GL_S_TO_FLOAT(v[1]),
	             __GL_S_TO_FLOAT(v[2]), __GL_S_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4ub_InRGBA ( IN GLubyte red, IN GLubyte green, IN GLubyte blue, IN GLubyte alpha )
{
    PA_COLOR_IN_RGBA_NO_CLAMP(__GL_UB_TO_FLOAT(red), __GL_UB_TO_FLOAT(green),
	             __GL_UB_TO_FLOAT(blue), __GL_UB_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4ubv_InRGBA ( IN const GLubyte v[4] )
{
    PA_COLOR_IN_RGBA_NO_CLAMP(__GL_UB_TO_FLOAT(v[0]), __GL_UB_TO_FLOAT(v[1]),
	             __GL_UB_TO_FLOAT(v[2]), __GL_UB_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4ui_InRGBA ( IN GLuint red, IN GLuint green, IN GLuint blue, IN GLuint alpha )
{
    PA_COLOR_IN_RGBA(__GL_UI_TO_FLOAT(red), __GL_UI_TO_FLOAT(green),
	             __GL_UI_TO_FLOAT(blue), __GL_UI_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4uiv_InRGBA ( IN const GLuint v[4] )
{
    PA_COLOR_IN_RGBA(__GL_UI_TO_FLOAT(v[0]), __GL_UI_TO_FLOAT(v[1]),
	             __GL_UI_TO_FLOAT(v[2]), __GL_UI_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4us_InRGBA ( IN GLushort red, IN GLushort green, IN GLushort blue, IN GLushort alpha )
{
    PA_COLOR_IN_RGBA_NO_CLAMP(__GL_US_TO_FLOAT(red), __GL_US_TO_FLOAT(green),
	             __GL_US_TO_FLOAT(blue), __GL_US_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4usv_InRGBA ( IN const GLushort v[4] )
{
    PA_COLOR_IN_RGBA_NO_CLAMP(__GL_US_TO_FLOAT(v[0]), __GL_US_TO_FLOAT(v[1]),
	             __GL_US_TO_FLOAT(v[2]), __GL_US_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor3b_InCI ( IN GLbyte red, IN GLbyte green, IN GLbyte blue )
{
    PA_COLOR_IN_CI(__GL_B_TO_FLOAT(red), __GL_B_TO_FLOAT(green),
	             __GL_B_TO_FLOAT(blue), __glOne);
}

void APIENTRY
glcltColor3bv_InCI ( IN const GLbyte v[3] )
{
    PA_COLOR_IN_CI(__GL_B_TO_FLOAT(v[0]), __GL_B_TO_FLOAT(v[1]),
	             __GL_B_TO_FLOAT(v[2]), __glOne);
}

void APIENTRY
glcltColor3d_InCI ( IN GLdouble red, IN GLdouble green, IN GLdouble blue )
{
    PA_COLOR_IN_CI((GLfloat) red, (GLfloat) green,
		     (GLfloat) blue, __glOne);
}

void APIENTRY
glcltColor3dv_InCI ( IN const GLdouble v[3] )
{
    PA_COLOR_IN_CI((GLfloat) v[0], (GLfloat) v[1],
		     (GLfloat) v[2], __glOne);
}

void APIENTRY
glcltColor3f_InCI ( IN GLfloat red, IN GLfloat green, IN GLfloat blue )
{
    PA_COLOR_IN_CI(red, green, blue, __glOne);
}

void APIENTRY
glcltColor3fv_InCI ( IN const GLfloat v[3] )
{
    PA_COLOR_IN_CI(v[0], v[1], v[2], __glOne);
}

void APIENTRY
glcltColor3i_InCI ( IN GLint red, IN GLint green, IN GLint blue )
{
    PA_COLOR_IN_CI(__GL_I_TO_FLOAT(red), __GL_I_TO_FLOAT(green),
	             __GL_I_TO_FLOAT(blue), __glOne);
}

void APIENTRY
glcltColor3iv_InCI ( IN const GLint v[3] )
{
    PA_COLOR_IN_CI(__GL_I_TO_FLOAT(v[0]), __GL_I_TO_FLOAT(v[1]),
	             __GL_I_TO_FLOAT(v[2]), __glOne);
}

void APIENTRY
glcltColor3s_InCI ( IN GLshort red, IN GLshort green, IN GLshort blue )
{
    PA_COLOR_IN_CI(__GL_S_TO_FLOAT(red), __GL_S_TO_FLOAT(green),
	             __GL_S_TO_FLOAT(blue), __glOne);
}

void APIENTRY
glcltColor3sv_InCI ( IN const GLshort v[3] )
{
    PA_COLOR_IN_CI(__GL_S_TO_FLOAT(v[0]), __GL_S_TO_FLOAT(v[1]),
	             __GL_S_TO_FLOAT(v[2]), __glOne);
}

void APIENTRY
glcltColor3ub_InCI ( IN GLubyte red, IN GLubyte green, IN GLubyte blue )
{
    PA_COLOR_IN_CI(__GL_UB_TO_FLOAT(red), __GL_UB_TO_FLOAT(green),
	             __GL_UB_TO_FLOAT(blue), __glOne);
}

void APIENTRY
glcltColor3ubv_InCI ( IN const GLubyte v[3] )
{
    PA_COLOR_IN_CI(__GL_UB_TO_FLOAT(v[0]), __GL_UB_TO_FLOAT(v[1]),
	             __GL_UB_TO_FLOAT(v[2]), __glOne);
}

void APIENTRY
glcltColor3ui_InCI ( IN GLuint red, IN GLuint green, IN GLuint blue )
{
    PA_COLOR_IN_CI(__GL_UI_TO_FLOAT(red), __GL_UI_TO_FLOAT(green),
	             __GL_UI_TO_FLOAT(blue), __glOne);
}

void APIENTRY
glcltColor3uiv_InCI ( IN const GLuint v[3] )
{
    PA_COLOR_IN_CI(__GL_UI_TO_FLOAT(v[0]), __GL_UI_TO_FLOAT(v[1]),
	             __GL_UI_TO_FLOAT(v[2]), __glOne);
}

void APIENTRY
glcltColor3us_InCI ( IN GLushort red, IN GLushort green, IN GLushort blue )
{
    PA_COLOR_IN_CI(__GL_US_TO_FLOAT(red), __GL_US_TO_FLOAT(green),
	             __GL_US_TO_FLOAT(blue), __glOne);
}

void APIENTRY
glcltColor3usv_InCI ( IN const GLushort v[3] )
{
    PA_COLOR_IN_CI(__GL_US_TO_FLOAT(v[0]), __GL_US_TO_FLOAT(v[1]),
	             __GL_US_TO_FLOAT(v[2]), __glOne);
}

void APIENTRY
glcltColor4b_InCI ( IN GLbyte red, IN GLbyte green, IN GLbyte blue, IN GLbyte alpha )
{
    PA_COLOR_IN_CI(__GL_B_TO_FLOAT(red), __GL_B_TO_FLOAT(green),
	             __GL_B_TO_FLOAT(blue), __GL_B_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4bv_InCI ( IN const GLbyte v[4] )
{
    PA_COLOR_IN_CI(__GL_B_TO_FLOAT(v[0]), __GL_B_TO_FLOAT(v[1]),
	             __GL_B_TO_FLOAT(v[2]), __GL_B_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4d_InCI ( IN GLdouble red, IN GLdouble green, IN GLdouble blue, IN GLdouble alpha )
{
    PA_COLOR_IN_CI((GLfloat) red, (GLfloat) green,
		     (GLfloat) blue, (GLfloat) alpha);
}

void APIENTRY
glcltColor4dv_InCI ( IN const GLdouble v[4] )
{
    PA_COLOR_IN_CI((GLfloat) v[0], (GLfloat) v[1],
		     (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltColor4f_InCI ( IN GLfloat red, IN GLfloat green, IN GLfloat blue, IN GLfloat alpha )
{
    PA_COLOR_IN_CI(red, green, blue, alpha);
}

void APIENTRY
glcltColor4fv_InCI ( IN const GLfloat v[4] )
{
    PA_COLOR_IN_CI(v[0], v[1], v[2], v[3]);
}

void APIENTRY
glcltColor4i_InCI ( IN GLint red, IN GLint green, IN GLint blue, IN GLint alpha )
{
    PA_COLOR_IN_CI(__GL_I_TO_FLOAT(red), __GL_I_TO_FLOAT(green),
	             __GL_I_TO_FLOAT(blue), __GL_I_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4iv_InCI ( IN const GLint v[4] )
{
    PA_COLOR_IN_CI(__GL_I_TO_FLOAT(v[0]), __GL_I_TO_FLOAT(v[1]),
	             __GL_I_TO_FLOAT(v[2]), __GL_I_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4s_InCI ( IN GLshort red, IN GLshort green, IN GLshort blue, IN GLshort alpha )
{
    PA_COLOR_IN_CI(__GL_S_TO_FLOAT(red), __GL_S_TO_FLOAT(green),
	             __GL_S_TO_FLOAT(blue), __GL_S_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4sv_InCI ( IN const GLshort v[4] )
{
    PA_COLOR_IN_CI(__GL_S_TO_FLOAT(v[0]), __GL_S_TO_FLOAT(v[1]),
	             __GL_S_TO_FLOAT(v[2]), __GL_S_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4ub_InCI ( IN GLubyte red, IN GLubyte green, IN GLubyte blue, IN GLubyte alpha )
{
    PA_COLOR_IN_CI(__GL_UB_TO_FLOAT(red), __GL_UB_TO_FLOAT(green),
	             __GL_UB_TO_FLOAT(blue), __GL_UB_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4ubv_InCI ( IN const GLubyte v[4] )
{
    PA_COLOR_IN_CI(__GL_UB_TO_FLOAT(v[0]), __GL_UB_TO_FLOAT(v[1]),
	             __GL_UB_TO_FLOAT(v[2]), __GL_UB_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4ui_InCI ( IN GLuint red, IN GLuint green, IN GLuint blue, IN GLuint alpha )
{
    PA_COLOR_IN_CI(__GL_UI_TO_FLOAT(red), __GL_UI_TO_FLOAT(green),
	             __GL_UI_TO_FLOAT(blue), __GL_UI_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4uiv_InCI ( IN const GLuint v[4] )
{
    PA_COLOR_IN_CI(__GL_UI_TO_FLOAT(v[0]), __GL_UI_TO_FLOAT(v[1]),
	             __GL_UI_TO_FLOAT(v[2]), __GL_UI_TO_FLOAT(v[3]));
}

void APIENTRY
glcltColor4us_InCI ( IN GLushort red, IN GLushort green, IN GLushort blue, IN GLushort alpha )
{
    PA_COLOR_IN_CI(__GL_US_TO_FLOAT(red), __GL_US_TO_FLOAT(green),
	             __GL_US_TO_FLOAT(blue), __GL_US_TO_FLOAT(alpha));
}

void APIENTRY
glcltColor4usv_InCI ( IN const GLushort v[4] )
{
    PA_COLOR_IN_CI(__GL_US_TO_FLOAT(v[0]), __GL_US_TO_FLOAT(v[1]),
	             __GL_US_TO_FLOAT(v[2]), __GL_US_TO_FLOAT(v[3]));
}

// Allocate a __GLmatChange structure.
//
// The POLYMATERIAL structure contains pointers to __GLmatChange arrays.
// These __GLmatChange structures are used to record material changes to
// vertices in the vertex buffer.
//
// To reduce memory requirement, the POLYMATERIAL structure keeps an array
// of pointers to __GLmatChange arrays.  Each __GLmatChange array 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.

__GLmatChange * FASTCALL PAMatAlloc()
{
    POLYMATERIAL *pm;
    GLuint iArray, iMat;
#if DBG
    __GL_SETUP();
#endif

    pm = GLTEB_CLTPOLYMATERIAL();

// Allocate a POLYMATERIAL structure for this thread if one does not exist.

    if (!pm)
    {
        GLuint nv, aMatSize;
        __GL_SETUP();

        nv       = gc->vertex.pdBufSize;
        aMatSize = nv * 2 / POLYMATERIAL_ARRAY_SIZE + 1;

	if (!(pm = (POLYMATERIAL *) ALLOCZ(
		// Base size
		sizeof(POLYMATERIAL) - sizeof(__GLmatChange *) +
		// array of pointers to __GLmatChange arrays
		aMatSize * sizeof(__GLmatChange *) +
		// the PDMATERIAL array
		nv * sizeof(PDMATERIAL))))
	{
	    GLSETERROR(GL_OUT_OF_MEMORY);
	    return NULL;
	}

        pm->aMatSize = aMatSize;
        // Initialize pointer to the PDMATERIAL array
        pm->pdMaterial0 = (PDMATERIAL *) &pm->aMat[aMatSize];

        GLTEB_SET_CLTPOLYMATERIAL(pm);
    }

// Sanity check that pdBufSize has not changed.

    ASSERTOPENGL
    (
	pm->aMatSize == gc->vertex.pdBufSize * 2 / POLYMATERIAL_ARRAY_SIZE + 1,
	"vertex buffer size has changed!\n"
    );

// Find the material array from which to allocate the material change structure.

    iMat = pm->iMat;
    iArray = iMat / POLYMATERIAL_ARRAY_SIZE;
    iMat   = iMat % POLYMATERIAL_ARRAY_SIZE;

    ASSERTOPENGL(iArray < pm->aMatSize, "iArray exceeds range!\n");

// Allocate the material array if it has not been allocated.

    if (!(pm->aMat[iArray]))
    {
	if (!(pm->aMat[iArray] = (__GLmatChange *) ALLOC(
		sizeof(__GLmatChange) * POLYMATERIAL_ARRAY_SIZE)))
	{
	    GLSETERROR(GL_OUT_OF_MEMORY);
	    return NULL;
	}
    }

// Advance next available material pointer.

    pm->iMat++;
    ASSERTOPENGL(pm->iMat <= gc->vertex.pdBufSize * 2,
	"too many material changes!\n");

// Return the material change.

    return (&pm->aMat[iArray][iMat]);
}

// Free polymaterial for current thread.
void FASTCALL FreePolyMaterial(void)
{
    POLYMATERIAL *pm = GLTEB_CLTPOLYMATERIAL();
    GLuint i;

    if (pm)
    {
	for (i = 0; i < pm->aMatSize && pm->aMat[i]; i++)
	{
	    FREE(pm->aMat[i]);
	}
	FREE(pm);

	GLTEB_SET_CLTPOLYMATERIAL(NULL);
    }
}

#if !((POLYARRAY_MATERIAL_FRONT == POLYDATA_MATERIAL_FRONT)      \
   && (POLYARRAY_MATERIAL_BACK  == POLYDATA_MATERIAL_BACK))
#error "bad material mask\n"
#endif

void APIENTRY
glcltMaterialfv ( IN GLenum face, IN GLenum pname, IN const GLfloat params[] )
{
    POLYARRAY *pa;
    POLYDATA  *pd;
    GLuint    i, pdFlags, dirtyBits, matMask;
    POLYMATERIAL *pm;

    pa = GLTEB_CLTPOLYARRAY();

    if (pa->flags & POLYARRAY_IN_BEGIN)
    {
        switch (pname)
        {
          case GL_SHININESS:
            if (params[0] < (GLfloat) 0 || params[0] > (GLfloat) 128)
            {
                GLSETERROR(GL_INVALID_VALUE);
                return;
            }
            dirtyBits = __GL_MATERIAL_SHININESS;
            break;
          case GL_EMISSION:
            dirtyBits = __GL_MATERIAL_EMISSIVE;
            break;
          case GL_AMBIENT:
            dirtyBits = __GL_MATERIAL_AMBIENT;
            break;
          case GL_DIFFUSE:
            dirtyBits = __GL_MATERIAL_DIFFUSE;
            break;
          case GL_SPECULAR:
            dirtyBits = __GL_MATERIAL_SPECULAR;
            break;
          case GL_AMBIENT_AND_DIFFUSE:
            dirtyBits = __GL_MATERIAL_AMBIENT | __GL_MATERIAL_DIFFUSE;
            break;
          case GL_COLOR_INDEXES:
            dirtyBits = __GL_MATERIAL_COLORINDEXES;
            break;
          default:
            GLSETERROR(GL_INVALID_ENUM);
            return;
        }

        switch (face)
        {
          case GL_FRONT:
            pdFlags = POLYDATA_MATERIAL_FRONT;
            break;
          case GL_BACK:
            pdFlags = POLYDATA_MATERIAL_BACK;
            break;
          case GL_FRONT_AND_BACK:
            pdFlags = POLYDATA_MATERIAL_FRONT | POLYDATA_MATERIAL_BACK;
            break;
          default:
            GLSETERROR(GL_INVALID_ENUM);
            return;
        }

// Update pa flags POLYARRAY_MATERIAL_FRONT and POLYARRAY_MATERIAL_BACK.

        pa->flags |= pdFlags;

// Do front and back material for this vertex
// Overwrite the previous material changes for this vertex if they exist since
// only the last material changes matter.

        pd = pa->pdNextVertex;

        for (i = 0, matMask = POLYDATA_MATERIAL_FRONT;
             i < 2;
             i++,   matMask = POLYDATA_MATERIAL_BACK)
        {
            __GLmatChange *pdMat;

            if (!(pdFlags & matMask))
                continue;

            // allocate __GLmatChange structure if this vertex hasn't got one
            if (!(pd->flags & matMask))
            {
                if (!(pdMat = PAMatAlloc()))
                    return;

                // Get POLYMATERIAL pointer after PAMatAlloc!
                pm = GLTEB_CLTPOLYMATERIAL();
                if (matMask == POLYDATA_MATERIAL_FRONT)
                    pm->pdMaterial0[pd - pa->pdBuffer0].front = pdMat;
                else
                    pm->pdMaterial0[pd - pa->pdBuffer0].back  = pdMat;

                pdMat->dirtyBits = dirtyBits;
            }
            else
            {
                pm = GLTEB_CLTPOLYMATERIAL();
                if (matMask == POLYDATA_MATERIAL_FRONT)
                    pdMat = pm->pdMaterial0[pd - pa->pdBuffer0].front;
                else
                    pdMat = pm->pdMaterial0[pd - pa->pdBuffer0].back;

                pdMat->dirtyBits |= dirtyBits;
            }

            if (dirtyBits & __GL_MATERIAL_SHININESS)
            {
                pdMat->shininess = params[0];
            }
            else if (dirtyBits & __GL_MATERIAL_COLORINDEXES)
            {
                pdMat->cmapa = params[0];
                pdMat->cmapd = params[1];
                pdMat->cmaps = params[2];
            }
            else if (dirtyBits & __GL_MATERIAL_EMISSIVE)
            {
                pdMat->emissive.r = params[0];
                pdMat->emissive.g = params[1];
                pdMat->emissive.b = params[2];
                pdMat->emissive.a = params[3];
            }
            else if (dirtyBits & __GL_MATERIAL_SPECULAR)
            {
                pdMat->specular.r = params[0];
                pdMat->specular.g = params[1];
                pdMat->specular.b = params[2];
                pdMat->specular.a = params[3];
            }
            else
            {
                // ambient and/or diffuse
                if (dirtyBits & __GL_MATERIAL_AMBIENT)
                {
                    pdMat->ambient.r = params[0];
                    pdMat->ambient.g = params[1];
                    pdMat->ambient.b = params[2];
                    pdMat->ambient.a = params[3];
                }
                if (dirtyBits & __GL_MATERIAL_DIFFUSE)
                {
                    pdMat->diffuse.r = params[0];
                    pdMat->diffuse.g = params[1];
                    pdMat->diffuse.b = params[2];
                    pdMat->diffuse.a = params[3];
                }
            }
        }
        
        // Finally, update pd flags

        pd->flags |= pdFlags;
    }
    else
    {
        int cArgs;

        switch (pname)
        {
          case GL_SHININESS:
            if (params[0] < (GLfloat) 0 || params[0] > (GLfloat) 128)
            {
                GLSETERROR(GL_INVALID_VALUE);
                return;
            }
            cArgs = 1;
            break;
          case GL_EMISSION:
          case GL_AMBIENT:
          case GL_DIFFUSE:
          case GL_SPECULAR:
          case GL_AMBIENT_AND_DIFFUSE:
            cArgs = 4;
            break;
          case GL_COLOR_INDEXES:
            cArgs = 3;
            break;
          default:
            GLSETERROR(GL_INVALID_ENUM);
            return;
        }

        switch (face)
        {
          case GL_FRONT:
          case GL_BACK:
          case GL_FRONT_AND_BACK:
            break;
          default:
            GLSETERROR(GL_INVALID_ENUM);
            return;
        }
        
        GLCLIENT_BEGIN( Materialfv, MATERIALFV )
          pMsg->face      = face;
          pMsg->pname     = pname;
          while (--cArgs >= 0)
              pMsg->params[cArgs] = params[cArgs];
        GLCLIENT_END
    }
}

void APIENTRY
glcltMaterialf ( IN GLenum face, IN GLenum pname, IN GLfloat param )
{
    if (pname != GL_SHININESS)
    {
        GLSETERROR(GL_INVALID_ENUM);
        return;
    }

    glcltMaterialfv(face, pname, &param);
}

void APIENTRY
glcltMateriali ( IN GLenum face, IN GLenum pname, IN GLint param )
{
    GLfloat fParams[1];

    if (pname != GL_SHININESS)
    {
        GLSETERROR(GL_INVALID_ENUM);
        return;
    }

    fParams[0] = (GLfloat) param;
    glcltMaterialfv(face, pname, fParams);
}

void APIENTRY
glcltMaterialiv ( IN GLenum face, IN GLenum pname, IN const GLint params[] )
{
    GLfloat fParams[4];

    switch (pname)
    {
      case GL_EMISSION:
      case GL_AMBIENT:
      case GL_DIFFUSE:
      case GL_SPECULAR:
      case GL_AMBIENT_AND_DIFFUSE:
	fParams[0] = __GL_I_TO_FLOAT(params[0]);
	fParams[1] = __GL_I_TO_FLOAT(params[1]);
	fParams[2] = __GL_I_TO_FLOAT(params[2]);
	fParams[3] = __GL_I_TO_FLOAT(params[3]);
        break;
      case GL_COLOR_INDEXES:
	fParams[2] = (GLfloat) params[2];
	fParams[1] = (GLfloat) params[1];
      case GL_SHININESS:
	fParams[0] = (GLfloat) params[0];
        break;
    }

    glcltMaterialfv(face, pname, fParams);
}

void APIENTRY
glcltEdgeFlag ( IN GLboolean flag )
{
    PA_EDGEFLAG(flag);
}

void APIENTRY
glcltEdgeFlagv ( IN const GLboolean flag[1] )
{
    PA_EDGEFLAG(flag[0]);
}

void APIENTRY
glcltIndexd_InCI ( IN GLdouble c )
{
    PA_INDEX_IN_CI((GLfloat) c);
}

void APIENTRY
glcltIndexdv_InCI ( IN const GLdouble c[1] )
{
    PA_INDEX_IN_CI((GLfloat) c[0]);
}

void APIENTRY
glcltIndexf_InCI ( IN GLfloat c )
{
    PA_INDEX_IN_CI((GLfloat) c);
}

void APIENTRY
glcltIndexfv_InCI ( IN const GLfloat c[1] )
{
    PA_INDEX_IN_CI((GLfloat) c[0]);
}

void APIENTRY
glcltIndexi_InCI ( IN GLint c )
{
    PA_INDEX_IN_CI((GLfloat) c);
}

void APIENTRY
glcltIndexiv_InCI ( IN const GLint c[1] )
{
    PA_INDEX_IN_CI((GLfloat) c[0]);
}

void APIENTRY
glcltIndexs_InCI ( IN GLshort c )
{
    PA_INDEX_IN_CI((GLfloat) c);
}

void APIENTRY
glcltIndexsv_InCI ( IN const GLshort c[1] )
{
    PA_INDEX_IN_CI((GLfloat) c[0]);
}

void APIENTRY
glcltIndexub_InCI ( IN GLubyte c )
{
    PA_INDEX_IN_CI((GLfloat) c);
}

void APIENTRY
glcltIndexubv_InCI ( IN const GLubyte c[1] )
{
    PA_INDEX_IN_CI((GLfloat) c[0]);
}

void APIENTRY
glcltIndexd_InRGBA ( IN GLdouble c )
{
    PA_INDEX_IN_RGBA((GLfloat) c);
}

void APIENTRY
glcltIndexdv_InRGBA ( IN const GLdouble c[1] )
{
    PA_INDEX_IN_RGBA((GLfloat) c[0]);
}

void APIENTRY
glcltIndexf_InRGBA ( IN GLfloat c )
{
    PA_INDEX_IN_RGBA((GLfloat) c);
}

void APIENTRY
glcltIndexfv_InRGBA ( IN const GLfloat c[1] )
{
    PA_INDEX_IN_RGBA((GLfloat) c[0]);
}

void APIENTRY
glcltIndexi_InRGBA ( IN GLint c )
{
    PA_INDEX_IN_RGBA((GLfloat) c);
}

void APIENTRY
glcltIndexiv_InRGBA ( IN const GLint c[1] )
{
    PA_INDEX_IN_RGBA((GLfloat) c[0]);
}

void APIENTRY
glcltIndexs_InRGBA ( IN GLshort c )
{
    PA_INDEX_IN_RGBA((GLfloat) c);
}

void APIENTRY
glcltIndexsv_InRGBA ( IN const GLshort c[1] )
{
    PA_INDEX_IN_RGBA((GLfloat) c[0]);
}

void APIENTRY
glcltIndexub_InRGBA ( IN GLubyte c )
{
    PA_INDEX_IN_RGBA((GLfloat) c);
}

void APIENTRY
glcltIndexubv_InRGBA ( IN const GLubyte c[1] )
{
    PA_INDEX_IN_RGBA((GLfloat) c[0]);
}

/******************************************************************/
void APIENTRY
glcltNormal3b ( IN GLbyte nx, IN GLbyte ny, IN GLbyte nz )
{
    PA_NORMAL(__GL_B_TO_FLOAT(nx), __GL_B_TO_FLOAT(ny), __GL_B_TO_FLOAT(nz));
}

void APIENTRY
glcltNormal3bv ( IN const GLbyte v[3] )
{
    PA_NORMAL(__GL_B_TO_FLOAT(v[0]), __GL_B_TO_FLOAT(v[1]), __GL_B_TO_FLOAT(v[2]));
}

void APIENTRY
glcltNormal3d ( IN GLdouble nx, IN GLdouble ny, IN GLdouble nz )
{
    PA_NORMAL((GLfloat) nx, (GLfloat) ny, (GLfloat) nz);
}

void APIENTRY
glcltNormal3dv ( IN const GLdouble v[3] )
{
    PA_NORMAL((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}

#ifndef __GL_ASM_GLCLTNORMAL3F
void APIENTRY
glcltNormal3f ( IN GLfloat x, IN GLfloat y, IN GLfloat z )
{
    PA_NORMAL(x, y, z);
}
#endif //__GL_ASM_GLCLTNORMAL3F

#ifndef __GL_ASM_GLCLTNORMAL3FV
void APIENTRY
glcltNormal3fv ( IN const GLfloat v[3] )
{
    GLfloat x, y, z;

    x = v[0];
    y = v[1];
    z = v[2];

    PA_NORMAL(x, y, z);
}
#endif //__GL_ASM_GLCLTNORMAL3FV

void APIENTRY
glcltNormal3i ( IN GLint nx, IN GLint ny, IN GLint nz )
{
    PA_NORMAL(__GL_I_TO_FLOAT(nx), __GL_I_TO_FLOAT(ny), __GL_I_TO_FLOAT(nz));
}

void APIENTRY
glcltNormal3iv ( IN const GLint v[3] )
{
    PA_NORMAL(__GL_I_TO_FLOAT(v[0]), __GL_I_TO_FLOAT(v[1]), __GL_I_TO_FLOAT(v[2]));
}

void APIENTRY
glcltNormal3s ( IN GLshort nx, IN GLshort ny, IN GLshort nz )
{
    PA_NORMAL(__GL_S_TO_FLOAT(nx), __GL_S_TO_FLOAT(ny), __GL_S_TO_FLOAT(nz));
}

void APIENTRY
glcltNormal3sv ( IN const GLshort v[3] )
{
    PA_NORMAL(__GL_S_TO_FLOAT(v[0]), __GL_S_TO_FLOAT(v[1]), __GL_S_TO_FLOAT(v[2]));
}

void APIENTRY
glcltRasterPos2d ( IN GLdouble x, IN GLdouble y )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos2dv ( IN const GLdouble v[2] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos2f ( IN GLfloat x, IN GLfloat y )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos2fv ( IN const GLfloat v[2] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos2i ( IN GLint x, IN GLint y )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos2iv ( IN const GLint v[2] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos2s ( IN GLshort x, IN GLshort y )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos2sv ( IN const GLshort v[2] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) 0.0, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3d ( IN GLdouble x, IN GLdouble y, IN GLdouble z )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3dv ( IN const GLdouble v[3] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3f ( IN GLfloat x, IN GLfloat y, IN GLfloat z )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3fv ( IN const GLfloat v[3] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3i ( IN GLint x, IN GLint y, IN GLint z )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3iv ( IN const GLint v[3] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3s ( IN GLshort x, IN GLshort y, IN GLshort z )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos3sv ( IN const GLshort v[3] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) 1.0);
}

void APIENTRY
glcltRasterPos4d ( IN GLdouble x, IN GLdouble y, IN GLdouble z, IN GLdouble w )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
}

void APIENTRY
glcltRasterPos4dv ( IN const GLdouble v[4] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltRasterPos4f ( IN GLfloat x, IN GLfloat y, IN GLfloat z, IN GLfloat w )
{
    GLCLIENT_BEGIN( RasterPos4fv, RASTERPOS4FV )
        pMsg->v[0] = x;
        pMsg->v[1] = y;
        pMsg->v[2] = z;
        pMsg->v[3] = w;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltRasterPos4fv ( IN const GLfloat v[4] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltRasterPos4i ( IN GLint x, IN GLint y, IN GLint z, IN GLint w )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
}

void APIENTRY
glcltRasterPos4iv ( IN const GLint v[4] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltRasterPos4s ( IN GLshort x, IN GLshort y, IN GLshort z, IN GLshort w )
{
    glcltRasterPos4f((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
}

void APIENTRY
glcltRasterPos4sv ( IN const GLshort v[4] )
{
    glcltRasterPos4f((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltRectd ( IN GLdouble x1, IN GLdouble y1, IN GLdouble x2, IN GLdouble y2 )
{
    glcltRectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
}

void APIENTRY
glcltRectdv ( IN const GLdouble v1[2], IN const GLdouble v2[2] )
{
    glcltRectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
}

void APIENTRY
glcltRectf ( IN GLfloat x1, IN GLfloat y1, IN GLfloat x2, IN GLfloat y2 )
{
    POLYARRAY *pa;

// Not allowed in begin/end.

    pa = GLTEB_CLTPOLYARRAY();
    if (pa->flags & POLYARRAY_IN_BEGIN)
    {
	GLSETERROR(GL_INVALID_OPERATION);
	return;
    }

// Call Begin/End to do polyarray correctly.  Note that by calling these
// functions, we allow poly array to be batched correctly.
// Note also that we use quad strip instead of quad to force edge flag to be on.

    //!!! Conformance fails if we use QUAD_STRIP!
    //glcltBegin(GL_QUAD_STRIP);
    glcltBegin(GL_QUADS);
    pa->flags |= POLYARRAY_SAME_POLYDATA_TYPE;
    glcltVertex2f(x1, y1);
    glcltVertex2f(x2, y1);
    glcltVertex2f(x2, y2);
    glcltVertex2f(x1, y2);
    glcltEnd();
}

void APIENTRY
glcltRectfv ( IN const GLfloat v1[2], IN const GLfloat v2[2] )
{
    glcltRectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
}

void APIENTRY
glcltRecti ( IN GLint x1, IN GLint y1, IN GLint x2, IN GLint y2 )
{
    glcltRectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
}

void APIENTRY
glcltRectiv ( IN const GLint v1[2], IN const GLint v2[2] )
{
    glcltRectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
}

void APIENTRY
glcltRects ( IN GLshort x1, IN GLshort y1, IN GLshort x2, IN GLshort y2 )
{
    glcltRectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
}

void APIENTRY
glcltRectsv ( IN const GLshort v1[2], IN const GLshort v2[2] )
{
    glcltRectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
}

void APIENTRY
glcltTexCoord1d ( IN GLdouble s )
{
    PA_TEXTURE1((GLfloat) s);
}

void APIENTRY
glcltTexCoord1dv ( IN const GLdouble v[1] )
{
    PA_TEXTURE1((GLfloat) v[0]);
}

void APIENTRY
glcltTexCoord1f ( IN GLfloat s )
{
    PA_TEXTURE1((GLfloat) s);
}

void APIENTRY
glcltTexCoord1fv ( IN const GLfloat v[1] )
{
    PA_TEXTURE1((GLfloat) v[0]);
}

void APIENTRY
glcltTexCoord1i ( IN GLint s )
{
    PA_TEXTURE1((GLfloat) s);
}

void APIENTRY
glcltTexCoord1iv ( IN const GLint v[1] )
{
    PA_TEXTURE1((GLfloat) v[0]);
}

void APIENTRY
glcltTexCoord1s ( IN GLshort s )
{
    PA_TEXTURE1((GLfloat) s);
}

void APIENTRY
glcltTexCoord1sv ( IN const GLshort v[1] )
{
    PA_TEXTURE1((GLfloat) v[0]);
}

void APIENTRY
glcltTexCoord2d ( IN GLdouble s, IN GLdouble t )
{
    PA_TEXTURE2((GLfloat) s, (GLfloat) t);
}

void APIENTRY
glcltTexCoord2dv ( IN const GLdouble v[2] )
{
    PA_TEXTURE2((GLfloat) v[0], (GLfloat) v[1]);
}

#ifndef __GL_ASM_GLCLTTEXCOORD2F
void APIENTRY
glcltTexCoord2f ( IN GLfloat s, IN GLfloat t )
{
    PA_TEXTURE2((GLfloat) s, (GLfloat) t);
}
#endif //__GL_ASM_GLCLTTEXCOORD2F

#ifndef __GL_ASM_GLCLTTEXCOORD2FV
void APIENTRY
glcltTexCoord2fv ( IN const GLfloat v[2] )
{
    PA_TEXTURE2((GLfloat) v[0], (GLfloat) v[1]);
}
#endif //__GL_ASM_GLCLTTEXCOORD2FV

void APIENTRY
glcltTexCoord2i ( IN GLint s, IN GLint t )
{
    PA_TEXTURE2((GLfloat) s, (GLfloat) t);
}

void APIENTRY
glcltTexCoord2iv ( IN const GLint v[2] )
{
    PA_TEXTURE2((GLfloat) v[0], (GLfloat) v[1]);
}

void APIENTRY
glcltTexCoord2s ( IN GLshort s, IN GLshort t )
{
    PA_TEXTURE2((GLfloat) s, (GLfloat) t);
}

void APIENTRY
glcltTexCoord2sv ( IN const GLshort v[2] )
{
    PA_TEXTURE2((GLfloat) v[0], (GLfloat) v[1]);
}

void APIENTRY
glcltTexCoord3d ( IN GLdouble s, IN GLdouble t, IN GLdouble r )
{
    PA_TEXTURE3((GLfloat) s, (GLfloat) t, (GLfloat) r);
}

void APIENTRY
glcltTexCoord3dv ( IN const GLdouble v[3] )
{
    PA_TEXTURE3((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}

#ifndef __GL_ASM_GLCLTTEXCOORD3F
void APIENTRY
glcltTexCoord3f ( IN GLfloat s, IN GLfloat t, IN GLfloat r )
{
    PA_TEXTURE3((GLfloat) s, (GLfloat) t, (GLfloat) r);
}
#endif //__GL_ASM_GLCLTTEXCOORD3F

#ifndef __GL_ASM_GLCLTTEXCOORD3FV
void APIENTRY
glcltTexCoord3fv ( IN const GLfloat v[3] )
{
    PA_TEXTURE3((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}
#endif //__GL_ASM_GLCLTTEXCOORD3FV

void APIENTRY
glcltTexCoord3i ( IN GLint s, IN GLint t, IN GLint r )
{
    PA_TEXTURE3((GLfloat) s, (GLfloat) t, (GLfloat) r);
}

void APIENTRY
glcltTexCoord3iv ( IN const GLint v[3] )
{
    PA_TEXTURE3((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}

void APIENTRY
glcltTexCoord3s ( IN GLshort s, IN GLshort t, IN GLshort r )
{
    PA_TEXTURE3((GLfloat) s, (GLfloat) t, (GLfloat) r);
}

void APIENTRY
glcltTexCoord3sv ( IN const GLshort v[3] )
{
    PA_TEXTURE3((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}

void APIENTRY
glcltTexCoord4d ( IN GLdouble s, IN GLdouble t, IN GLdouble r, IN GLdouble q )
{
    PA_TEXTURE4((GLfloat) s, (GLfloat) t, (GLfloat) r, (GLfloat) q);
}

void APIENTRY
glcltTexCoord4dv ( IN const GLdouble v[4] )
{
    PA_TEXTURE4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltTexCoord4f ( IN GLfloat s, IN GLfloat t, IN GLfloat r, IN GLfloat q )
{
    PA_TEXTURE4((GLfloat) s, (GLfloat) t, (GLfloat) r, (GLfloat) q);
}

void APIENTRY
glcltTexCoord4fv ( IN const GLfloat v[4] )
{
    PA_TEXTURE4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltTexCoord4i ( IN GLint s, IN GLint t, IN GLint r, IN GLint q )
{
    PA_TEXTURE4((GLfloat) s, (GLfloat) t, (GLfloat) r, (GLfloat) q);
}

void APIENTRY
glcltTexCoord4iv ( IN const GLint v[4] )
{
    PA_TEXTURE4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltTexCoord4s ( IN GLshort s, IN GLshort t, IN GLshort r, IN GLshort q )
{
    PA_TEXTURE4((GLfloat) s, (GLfloat) t, (GLfloat) r, (GLfloat) q);
}

void APIENTRY
glcltTexCoord4sv ( IN const GLshort v[4] )
{
    PA_TEXTURE4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

#ifdef GL_WIN_multiple_textures
void APIENTRY glcltMultiTexCoord1dWIN
    (GLbitfield mask, GLdouble s)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord1dvWIN
    (GLbitfield mask, const GLdouble *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord1fWIN
    (GLbitfield mask, GLfloat s)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord1fvWIN
    (GLbitfield mask, const GLfloat *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord1iWIN
    (GLbitfield mask, GLint s)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord1ivWIN
    (GLbitfield mask, const GLint *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord1sWIN
    (GLbitfield mask, GLshort s)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord1svWIN
    (GLbitfield mask, const GLshort *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2dWIN
    (GLbitfield mask, GLdouble s, GLdouble t)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2dvWIN
    (GLbitfield mask, const GLdouble *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2fWIN
    (GLbitfield mask, GLfloat s, GLfloat t)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2fvWIN
    (GLbitfield mask, const GLfloat *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2iWIN
    (GLbitfield mask, GLint s, GLint t)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2ivWIN
    (GLbitfield mask, const GLint *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2sWIN
    (GLbitfield mask, GLshort s, GLshort t)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord2svWIN
    (GLbitfield mask, const GLshort *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3dWIN
    (GLbitfield mask, GLdouble s, GLdouble t, GLdouble r)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3dvWIN
    (GLbitfield mask, const GLdouble *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3fWIN
    (GLbitfield mask, GLfloat s, GLfloat t, GLfloat r)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3fvWIN
    (GLbitfield mask, const GLfloat *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3iWIN
    (GLbitfield mask, GLint s, GLint t, GLint r)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3ivWIN
    (GLbitfield mask, const GLint *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3sWIN
    (GLbitfield mask, GLshort s, GLshort t, GLshort r)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord3svWIN
    (GLbitfield mask, const GLshort *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4dWIN
    (GLbitfield mask, GLdouble s, GLdouble t, GLdouble r, GLdouble q)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4dvWIN
    (GLbitfield mask, const GLdouble *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4fWIN
    (GLbitfield mask, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4fvWIN
    (GLbitfield mask, const GLfloat *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4iWIN
    (GLbitfield mask, GLint s, GLint t, GLint r, GLint q)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4ivWIN
    (GLbitfield mask, const GLint *v)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4sWIN
    (GLbitfield mask, GLshort s, GLshort t, GLshort r, GLshort q)
{
    // ATTENTION
}

void APIENTRY glcltMultiTexCoord4svWIN
    (GLbitfield mask, const GLshort *v)
{
    // ATTENTION
}
#endif // GL_WIN_multiple_textures

void APIENTRY
glcltVertex2d ( IN GLdouble x, IN GLdouble y )
{
    PA_VERTEX2((GLfloat) x, (GLfloat) y);
}

void APIENTRY
glcltVertex2dv ( IN const GLdouble v[2] )
{
    PA_VERTEX2((GLfloat) v[0], (GLfloat) v[1]);
}

#ifndef __GL_ASM_GLCLTVERTEX2F
void APIENTRY
glcltVertex2f ( IN GLfloat x, IN GLfloat y )
{
    PA_VERTEX2((GLfloat) x, (GLfloat) y);
}
#endif //__GL_ASM_GLCLTVERTEX2F

#ifndef __GL_ASM_GLCLTVERTEX2FV
void APIENTRY
glcltVertex2fv ( IN const GLfloat v[2] )
{
    PA_VERTEX2((GLfloat) v[0], (GLfloat) v[1]);
}
#endif //__GL_ASM_GLCLTVERTEX2FV

void APIENTRY
glcltVertex2i ( IN GLint x, IN GLint y )
{
    PA_VERTEX2((GLfloat) x, (GLfloat) y);
}

void APIENTRY
glcltVertex2iv ( IN const GLint v[2] )
{
    PA_VERTEX2((GLfloat) v[0], (GLfloat) v[1]);
}

void APIENTRY
glcltVertex2s ( IN GLshort x, IN GLshort y )
{
    PA_VERTEX2((GLfloat) x, (GLfloat) y);
}

void APIENTRY
glcltVertex2sv ( IN const GLshort v[2] )
{
    PA_VERTEX2((GLfloat) v[0], (GLfloat) v[1]);
}

void APIENTRY
glcltVertex3d ( IN GLdouble x, IN GLdouble y, IN GLdouble z )
{
    PA_VERTEX3((GLfloat) x, (GLfloat) y, (GLfloat) z);
}

void APIENTRY
glcltVertex3dv ( IN const GLdouble v[3] )
{
    PA_VERTEX3((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}

#ifndef __GL_ASM_GLCLTVERTEX3F
void APIENTRY
glcltVertex3f ( IN GLfloat x, IN GLfloat y, IN GLfloat z )
{
    PA_VERTEX3((GLfloat) x, (GLfloat) y, (GLfloat) z);
}
#endif //__GL_ASM_GLCLTVERTEX3F

#ifndef __GL_ASM_GLCLTVERTEX3FV
void APIENTRY
glcltVertex3fv ( IN const GLfloat v[3] )
{
    GLfloat x1, y1, z1;

    x1 = (GLfloat) v[0];
    y1 = (GLfloat) v[1];
    z1 = (GLfloat) v[2];

    PA_VERTEX3(x1, y1, z1);

}
#endif //__GL_ASM_GLCLTVERTEX3FV

void APIENTRY
glcltVertex3i ( IN GLint x, IN GLint y, IN GLint z )
{
    PA_VERTEX3((GLfloat) x, (GLfloat) y, (GLfloat) z);
}

void APIENTRY
glcltVertex3iv ( IN const GLint v[3] )
{
    PA_VERTEX3((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}

void APIENTRY
glcltVertex3s ( IN GLshort x, IN GLshort y, IN GLshort z )
{
    PA_VERTEX3((GLfloat) x, (GLfloat) y, (GLfloat) z);
}

void APIENTRY
glcltVertex3sv ( IN const GLshort v[3] )
{
    PA_VERTEX3((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
}

void APIENTRY
glcltVertex4d ( IN GLdouble x, IN GLdouble y, IN GLdouble z, IN GLdouble w )
{
    PA_VERTEX4((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
}

void APIENTRY
glcltVertex4dv ( IN const GLdouble v[4] )
{
    PA_VERTEX4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltVertex4f ( IN GLfloat x, IN GLfloat y, IN GLfloat z, IN GLfloat w )
{
    PA_VERTEX4((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
}

void APIENTRY
glcltVertex4fv ( IN const GLfloat v[4] )
{
    PA_VERTEX4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltVertex4i ( IN GLint x, IN GLint y, IN GLint z, IN GLint w )
{
    PA_VERTEX4((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
}

void APIENTRY
glcltVertex4iv ( IN const GLint v[4] )
{
    PA_VERTEX4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltVertex4s ( IN GLshort x, IN GLshort y, IN GLshort z, IN GLshort w )
{
    PA_VERTEX4((GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
}

void APIENTRY
glcltVertex4sv ( IN const GLshort v[4] )
{
    PA_VERTEX4((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2], (GLfloat) v[3]);
}

void APIENTRY
glcltClipPlane ( IN GLenum plane, IN const GLdouble equation[4] )
{
    GLCLIENT_BEGIN( ClipPlane, CLIPPLANE )
        pMsg->plane    = plane   ;
        pMsg->equation[ 0] = equation[ 0];
        pMsg->equation[ 1] = equation[ 1];
        pMsg->equation[ 2] = equation[ 2];
        pMsg->equation[ 3] = equation[ 3];
    return;
    GLCLIENT_END
}

void APIENTRY
glcltColorMaterial ( IN GLenum face, IN GLenum mode )
{
    GLCLIENT_BEGIN( ColorMaterial, COLORMATERIAL )
        pMsg->face     = face    ;
        pMsg->mode     = mode    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltCullFace ( IN GLenum mode )
{
    GLCLIENT_BEGIN( CullFace, CULLFACE )
        pMsg->mode     = mode    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltFrontFace ( IN GLenum mode )
{
    GLCLIENT_BEGIN( FrontFace, FRONTFACE )
        pMsg->mode     = mode    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltHint ( IN GLenum target, IN GLenum mode )
{
    GLCLIENT_BEGIN( Hint, HINT )
        pMsg->target   = target  ;
        pMsg->mode     = mode    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltLineStipple ( IN GLint factor, IN GLushort pattern )
{
    GLCLIENT_BEGIN( LineStipple, LINESTIPPLE )
        pMsg->factor   = factor  ;
        pMsg->pattern  = pattern ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltLineWidth ( IN GLfloat width )
{
    GLCLIENT_BEGIN( LineWidth, LINEWIDTH )
        pMsg->width    = width   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPointSize ( IN GLfloat size )
{
    GLCLIENT_BEGIN( PointSize, POINTSIZE )
        pMsg->size     = size    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPolygonMode ( IN GLenum face, IN GLenum mode )
{
    GLCLIENT_BEGIN( PolygonMode, POLYGONMODE )
        pMsg->face     = face    ;
        pMsg->mode     = mode    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltScissor ( IN GLint x, IN GLint y, IN GLsizei width, IN GLsizei height )
{
    GLCLIENT_BEGIN( Scissor, SCISSOR )
        pMsg->x        = x       ;
        pMsg->y        = y       ;
        pMsg->width    = width   ;
        pMsg->height   = height  ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltShadeModel ( IN GLenum mode )
{
    GLCLIENT_BEGIN( ShadeModel, SHADEMODEL )
        pMsg->mode     = mode    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltInitNames ( void )
{
    GLCLIENT_BEGIN( InitNames, INITNAMES )
    return;
    GLCLIENT_END
}

void APIENTRY
glcltLoadName ( IN GLuint name )
{
    GLCLIENT_BEGIN( LoadName, LOADNAME )
        pMsg->name     = name    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPassThrough ( IN GLfloat token )
{
    GLCLIENT_BEGIN( PassThrough, PASSTHROUGH )
        pMsg->token    = token   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPopName ( void )
{
    GLCLIENT_BEGIN( PopName, POPNAME )
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPushName ( IN GLuint name )
{
    GLCLIENT_BEGIN( PushName, PUSHNAME )
        pMsg->name     = name    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltDrawBuffer ( IN GLenum mode )
{
// We're doing something special here.  By doing a glsbAttention after
// putting a glDrawBuffer in the batch, we are guaranteeing that all
// drawing done in the batch is in the same drawing mode and that the
// drawing mode cannot change until the end of the batch.  This allows
// the server to sample the current drawing mode at the beginning of
// batch and to assume that it is constant for the entire batch.
//
// The server might be able to take advantage of the fact, for example,
// that all drawing in a batch is only to the back buffer.

    GLCLIENT_BEGIN( DrawBuffer, DRAWBUFFER )
        pMsg->mode     = mode    ;
        glsbAttention();
    return;
    GLCLIENT_END
}

void APIENTRY
glcltClear ( IN GLbitfield mask )
{
    GLCLIENT_BEGIN( Clear, CLEAR )
        pMsg->mask     = mask    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltClearAccum ( IN GLfloat red, IN GLfloat green, IN GLfloat blue, IN GLfloat alpha )
{
    GLCLIENT_BEGIN( ClearAccum, CLEARACCUM )
        pMsg->red      = red     ;
        pMsg->green    = green   ;
        pMsg->blue     = blue    ;
        pMsg->alpha    = alpha   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltClearIndex ( IN GLfloat c )
{
    GLCLIENT_BEGIN( ClearIndex, CLEARINDEX )
        pMsg->c        = c       ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltClearColor ( IN GLclampf red, IN GLclampf green, IN GLclampf blue, IN GLclampf alpha )
{
    GLCLIENT_BEGIN( ClearColor, CLEARCOLOR )
        pMsg->red      = red     ;
        pMsg->green    = green   ;
        pMsg->blue     = blue    ;
        pMsg->alpha    = alpha   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltClearStencil ( IN GLint s )
{
    GLCLIENT_BEGIN( ClearStencil, CLEARSTENCIL )
        pMsg->s        = s       ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltClearDepth ( IN GLclampd depth )
{
    GLCLIENT_BEGIN( ClearDepth, CLEARDEPTH )
        pMsg->depth    = depth   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltStencilMask ( IN GLuint mask )
{
    GLCLIENT_BEGIN( StencilMask, STENCILMASK )
        pMsg->mask     = mask    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltColorMask ( IN GLboolean red, IN GLboolean green, IN GLboolean blue, IN GLboolean alpha )
{
    GLCLIENT_BEGIN( ColorMask, COLORMASK )
        pMsg->red      = red     ;
        pMsg->green    = green   ;
        pMsg->blue     = blue    ;
        pMsg->alpha    = alpha   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltDepthMask ( IN GLboolean flag )
{
    GLCLIENT_BEGIN( DepthMask, DEPTHMASK )
        pMsg->flag     = flag    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltIndexMask ( IN GLuint mask )
{
    GLCLIENT_BEGIN( IndexMask, INDEXMASK )
        pMsg->mask     = mask    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltAccum ( IN GLenum op, IN GLfloat value )
{
    GLCLIENT_BEGIN( Accum, ACCUM )
        pMsg->op       = op      ;
        pMsg->value    = value   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltDisable ( IN GLenum cap )
{
    __GL_SETUP();

    GLCLIENT_BEGIN( Disable, DISABLE )
        pMsg->cap      = cap     ;

	    // Set the enable flags for the evaluators
	    switch (cap)
        {
        case GL_MAP1_COLOR_4:
        case GL_MAP1_INDEX:
        case GL_MAP1_NORMAL:
        case GL_MAP1_TEXTURE_COORD_1:
        case GL_MAP1_TEXTURE_COORD_2:
        case GL_MAP1_TEXTURE_COORD_3:
        case GL_MAP1_TEXTURE_COORD_4:
        case GL_MAP1_VERTEX_3:
        case GL_MAP1_VERTEX_4:
            gc->eval.evalStateFlags |= __EVALS_AFFECTS_1D_EVAL;
            break;
        case GL_MAP2_COLOR_4:
        case GL_MAP2_INDEX:
        case GL_MAP2_NORMAL:
        case GL_MAP2_TEXTURE_COORD_1:
        case GL_MAP2_TEXTURE_COORD_2:
        case GL_MAP2_TEXTURE_COORD_3:
        case GL_MAP2_TEXTURE_COORD_4:
        case GL_MAP2_VERTEX_3:
        case GL_MAP2_VERTEX_4:
        case GL_NORMALIZE:
        case GL_AUTO_NORMAL:
            gc->eval.evalStateFlags |= __EVALS_AFFECTS_2D_EVAL;
            break;
        case GL_LIGHTING:
            gc->eval.evalStateFlags |= __EVALS_AFFECTS_ALL_EVAL;
            break;
        }
    return;
    GLCLIENT_END
}

void APIENTRY
glcltEnable ( IN GLenum cap )
{
    __GL_SETUP();
  
    GLCLIENT_BEGIN( Enable, ENABLE )
        pMsg->cap      = cap     ;

    // Set the enable flags for the evaluators
    switch (cap)
    {
    case GL_MAP1_COLOR_4:
    case GL_MAP1_INDEX:
    case GL_MAP1_NORMAL:
    case GL_MAP1_TEXTURE_COORD_1:
    case GL_MAP1_TEXTURE_COORD_2:
    case GL_MAP1_TEXTURE_COORD_3:
    case GL_MAP1_TEXTURE_COORD_4:
    case GL_MAP1_VERTEX_3:
    case GL_MAP1_VERTEX_4:
        gc->eval.evalStateFlags |= __EVALS_AFFECTS_1D_EVAL;
        break;
    case GL_MAP2_COLOR_4:
    case GL_MAP2_INDEX:
    case GL_MAP2_NORMAL:
    case GL_MAP2_TEXTURE_COORD_1:
    case GL_MAP2_TEXTURE_COORD_2:
    case GL_MAP2_TEXTURE_COORD_3:
    case GL_MAP2_TEXTURE_COORD_4:
    case GL_MAP2_VERTEX_3:
    case GL_MAP2_VERTEX_4:
    case GL_NORMALIZE:
    case GL_AUTO_NORMAL:
        gc->eval.evalStateFlags |= __EVALS_AFFECTS_2D_EVAL;
        break;
    case GL_LIGHTING:
        gc->eval.evalStateFlags |= __EVALS_AFFECTS_ALL_EVAL;
        break;
    }
    return;
    GLCLIENT_END
}

void APIENTRY
glcltFinish ( void )
{
// This function is invalid between glBegin and glEnd.
// This is detected in glsbAttention.

    glsbAttention();
}

void APIENTRY
glcltFlush ( void )
{
// This function is invalid between glBegin and glEnd.
// This is detected in glsbAttention.

    glsbAttention();
}

void APIENTRY
glcltPopAttrib ( void )
{
    __GL_SETUP();

    GLCLIENT_BEGIN( PopAttrib, POPATTRIB )
    if (gc->eval.evalStackState & 0x1)
    {
        gc->eval.evalStateFlags = gc->eval.evalStateFlags |
                                  __EVALS_AFFECTS_ALL_EVAL |
                                  __EVALS_POP_EVAL_ATTRIB;
    }
    gc->eval.evalStackState = (gc->eval.evalStackState) >> 1;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPushAttrib ( IN GLbitfield mask )
{
    __GL_SETUP ();
  
    // Assert that the stack size is always less than 31 since the
    // bitfield is a DWORD. 
    ASSERTOPENGL (gc->constants.maxAttribStackDepth < 31, "Attrib state stack is greater than the size of the bitfield used to track it\n");
    
    GLCLIENT_BEGIN( PushAttrib, PUSHATTRIB )
        pMsg->mask     = mask    ;
        gc->eval.evalStackState = (gc->eval.evalStackState) << 1;
        if (mask & GL_EVAL_BIT)
    	{
    	    gc->eval.evalStateFlags = gc->eval.evalStateFlags | 
                                      __EVALS_AFFECTS_ALL_EVAL |
                                      __EVALS_PUSH_EVAL_ATTRIB;
    		gc->eval.evalStackState = (gc->eval.evalStackState) | 0x1;
        }
    return;
    GLCLIENT_END
}




void APIENTRY
glcltAlphaFunc ( IN GLenum func, IN GLclampf ref )
{
    GLCLIENT_BEGIN( AlphaFunc, ALPHAFUNC )
        pMsg->func     = func    ;
        pMsg->ref      = ref     ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltBlendFunc ( IN GLenum sfactor, IN GLenum dfactor )
{
    GLCLIENT_BEGIN( BlendFunc, BLENDFUNC )
        pMsg->sfactor  = sfactor ;
        pMsg->dfactor  = dfactor ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltLogicOp ( IN GLenum opcode )
{
    GLCLIENT_BEGIN( LogicOp, LOGICOP )
        pMsg->opcode   = opcode  ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltStencilFunc ( IN GLenum func, IN GLint ref, IN GLuint mask )
{
    GLCLIENT_BEGIN( StencilFunc, STENCILFUNC )
        pMsg->func     = func    ;
        pMsg->ref      = ref     ;
        pMsg->mask     = mask    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltStencilOp ( IN GLenum fail, IN GLenum zfail, IN GLenum zpass )
{
    GLCLIENT_BEGIN( StencilOp, STENCILOP )
        pMsg->fail     = fail    ;
        pMsg->zfail    = zfail   ;
        pMsg->zpass    = zpass   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltDepthFunc ( IN GLenum func )
{
    GLCLIENT_BEGIN( DepthFunc, DEPTHFUNC )
        pMsg->func     = func    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPixelZoom ( IN GLfloat xfactor, IN GLfloat yfactor )
{
    GLCLIENT_BEGIN( PixelZoom, PIXELZOOM )
        pMsg->xfactor  = xfactor ;
        pMsg->yfactor  = yfactor ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPixelTransferf ( IN GLenum pname, IN GLfloat param )
{
    GLCLIENT_BEGIN( PixelTransferf, PIXELTRANSFERF )
        pMsg->pname    = pname   ;
        pMsg->param    = param   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPixelTransferi ( IN GLenum pname, IN GLint param )
{
    GLCLIENT_BEGIN( PixelTransferi, PIXELTRANSFERI )
        pMsg->pname    = pname   ;
        pMsg->param    = param   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPixelStoref ( IN GLenum pname, IN GLfloat param )
{
    GLCLIENT_BEGIN( PixelStoref, PIXELSTOREF )
        pMsg->pname    = pname   ;
        pMsg->param    = param   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPixelStorei ( IN GLenum pname, IN GLint param )
{
    GLCLIENT_BEGIN( PixelStorei, PIXELSTOREI )
        pMsg->pname    = pname   ;
        pMsg->param    = param   ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPixelMapfv ( IN GLenum map, IN GLint mapsize, IN const GLfloat values[] )
{
    GLCLIENT_BEGIN_LARGE_SET( PixelMapfv, PIXELMAPFV, values, ulSize, valuesOff )
        pMsg->map      = map     ;
        pMsg->mapsize  = mapsize ;
    GLCLIENT_END_LARGE_SET
    return;
}

void APIENTRY
glcltPixelMapuiv ( IN GLenum map, IN GLint mapsize, IN const GLuint values[] )
{
    GLCLIENT_BEGIN_LARGE_SET( PixelMapuiv, PIXELMAPUIV, values, ulSize, valuesOff )
        pMsg->map      = map     ;
        pMsg->mapsize  = mapsize ;
    GLCLIENT_END_LARGE_SET
    return;
}

void APIENTRY
glcltPixelMapusv ( IN GLenum map, IN GLint mapsize, IN const GLushort values[] )
{
    GLCLIENT_BEGIN_LARGE_SET( PixelMapusv, PIXELMAPUSV, values, ulSize, valuesOff )
        pMsg->map      = map     ;
        pMsg->mapsize  = mapsize ;
    GLCLIENT_END_LARGE_SET
    return;
}

void APIENTRY
glcltReadBuffer ( IN GLenum mode )
{
    GLCLIENT_BEGIN( ReadBuffer, READBUFFER )
        pMsg->mode     = mode    ;
        glsbAttention();
    return;
    GLCLIENT_END
}

void APIENTRY
glcltCopyPixels ( IN GLint x, IN GLint y, IN GLsizei width, IN GLsizei height, IN GLenum type )
{
    GLCLIENT_BEGIN( CopyPixels, COPYPIXELS )
        pMsg->x        = x       ;
        pMsg->y        = y       ;
        pMsg->width    = width   ;
        pMsg->height   = height  ;
        pMsg->type     = type    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltGetClipPlane ( IN GLenum plane, OUT GLdouble equation[4] )
{
    GLCLIENT_BEGIN( GetClipPlane, GETCLIPPLANE )
        pMsg->plane    = plane   ;
        pMsg->equation = equation;
        glsbAttention();
    return;
    GLCLIENT_END
}

GLenum APIENTRY
glcltGetError ( void )
{
    GLCLIENT_BEGIN( GetError, GETERROR )
        GLTEB_RETURNVALUE()  = GL_INVALID_OPERATION;   // assume error
        glsbAttention();
    return((GLenum)GLTEB_RETURNVALUE());
    GLCLIENT_END
}

void APIENTRY
glcltGetMapdv ( IN GLenum target, IN GLenum query, OUT GLdouble v[] )
{
    GLCLIENT_BEGIN_LARGE_GET( GetMapdv, GETMAPDV, v, ulSize, vOff )
        pMsg->target   = target  ;
        pMsg->query    = query   ;
    GLCLIENT_END_LARGE_GET
    return;
}

void APIENTRY
glcltGetMapfv ( IN GLenum target, IN GLenum query, OUT GLfloat v[] )
{
    GLCLIENT_BEGIN_LARGE_GET( GetMapfv, GETMAPFV, v, ulSize, vOff )
        pMsg->target   = target  ;
        pMsg->query    = query   ;
    GLCLIENT_END_LARGE_GET
    return;
}

void APIENTRY
glcltGetMapiv ( IN GLenum target, IN GLenum query, OUT GLint v[] )
{
    GLCLIENT_BEGIN_LARGE_GET( GetMapiv, GETMAPIV, v, ulSize, vOff )
        pMsg->target   = target  ;
        pMsg->query    = query   ;
    GLCLIENT_END_LARGE_GET
    return;
}

void APIENTRY
glcltGetPixelMapfv ( IN GLenum map, OUT GLfloat values[] )
{
    GLCLIENT_BEGIN_LARGE_GET( GetPixelMapfv, GETPIXELMAPFV, values, ulSize, valuesOff )
        pMsg->map      = map     ;
    GLCLIENT_END_LARGE_GET
    return;
}

void APIENTRY
glcltGetPixelMapuiv ( IN GLenum map, OUT GLuint values[] )
{
    GLCLIENT_BEGIN_LARGE_GET( GetPixelMapuiv, GETPIXELMAPUIV, values, ulSize, valuesOff )
        pMsg->map      = map     ;
    GLCLIENT_END_LARGE_GET
    return;
}

void APIENTRY
glcltGetPixelMapusv ( IN GLenum map, OUT GLushort values[] )
{
    GLCLIENT_BEGIN_LARGE_GET( GetPixelMapusv, GETPIXELMAPUSV, values, ulSize, valuesOff )
        pMsg->map      = map     ;
    GLCLIENT_END_LARGE_GET
    return;
}

GLboolean APIENTRY
glcltIsEnabled ( IN GLenum cap )
{
    GLCLIENT_BEGIN( IsEnabled, ISENABLED )
        pMsg->cap      = cap     ;
        GLTEB_RETURNVALUE()  = 0;              // assume error
        glsbAttention();
    return((GLboolean)GLTEB_RETURNVALUE());
    GLCLIENT_END
}

void APIENTRY
glcltDepthRange ( IN GLclampd zNear, IN GLclampd zFar )
{
    GLCLIENT_BEGIN( DepthRange, DEPTHRANGE )
        pMsg->zNear    = zNear   ;
        pMsg->zFar     = zFar    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltFrustum ( IN GLdouble left, IN GLdouble right, IN GLdouble bottom, IN GLdouble top, IN GLdouble zNear, IN GLdouble zFar )
{
    GLCLIENT_BEGIN( Frustum, FRUSTUM )
        pMsg->left     = left    ;
        pMsg->right    = right   ;
        pMsg->bottom   = bottom  ;
        pMsg->top      = top     ;
        pMsg->zNear    = zNear   ;
        pMsg->zFar     = zFar    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltLoadIdentity ( void )
{
    GLCLIENT_BEGIN( LoadIdentity, LOADIDENTITY )
    return;
    GLCLIENT_END
}

void APIENTRY
glcltLoadMatrixf ( IN const GLfloat m[16] )
{
    GLCLIENT_BEGIN( LoadMatrixf, LOADMATRIXF )
        pMsg->m[ 0] = m[ 0];
        pMsg->m[ 1] = m[ 1];
        pMsg->m[ 2] = m[ 2];
        pMsg->m[ 3] = m[ 3];
        pMsg->m[ 4] = m[ 4];
        pMsg->m[ 5] = m[ 5];
        pMsg->m[ 6] = m[ 6];
        pMsg->m[ 7] = m[ 7];
        pMsg->m[ 8] = m[ 8];
        pMsg->m[ 9] = m[ 9];
        pMsg->m[10] = m[10];
        pMsg->m[11] = m[11];
        pMsg->m[12] = m[12];
        pMsg->m[13] = m[13];
        pMsg->m[14] = m[14];
        pMsg->m[15] = m[15];
    return;
    GLCLIENT_END
}

void APIENTRY
glcltLoadMatrixd ( IN const GLdouble m[16] )
{
// Call LoadMatrixf instead

    GLCLIENT_BEGIN( LoadMatrixf, LOADMATRIXF )
        pMsg->m[ 0] = (GLfloat) m[ 0];
        pMsg->m[ 1] = (GLfloat) m[ 1];
        pMsg->m[ 2] = (GLfloat) m[ 2];
        pMsg->m[ 3] = (GLfloat) m[ 3];
        pMsg->m[ 4] = (GLfloat) m[ 4];
        pMsg->m[ 5] = (GLfloat) m[ 5];
        pMsg->m[ 6] = (GLfloat) m[ 6];
        pMsg->m[ 7] = (GLfloat) m[ 7];
        pMsg->m[ 8] = (GLfloat) m[ 8];
        pMsg->m[ 9] = (GLfloat) m[ 9];
        pMsg->m[10] = (GLfloat) m[10];
        pMsg->m[11] = (GLfloat) m[11];
        pMsg->m[12] = (GLfloat) m[12];
        pMsg->m[13] = (GLfloat) m[13];
        pMsg->m[14] = (GLfloat) m[14];
        pMsg->m[15] = (GLfloat) m[15];
    return;
    GLCLIENT_END
}

void APIENTRY
glcltMatrixMode ( IN GLenum mode )
{
    GLCLIENT_BEGIN( MatrixMode, MATRIXMODE )
        pMsg->mode     = mode    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltMultMatrixf ( IN const GLfloat m[16] )
{
    GLCLIENT_BEGIN( MultMatrixf, MULTMATRIXF )
        pMsg->m[ 0] = m[ 0];
        pMsg->m[ 1] = m[ 1];
        pMsg->m[ 2] = m[ 2];
        pMsg->m[ 3] = m[ 3];
        pMsg->m[ 4] = m[ 4];
        pMsg->m[ 5] = m[ 5];
        pMsg->m[ 6] = m[ 6];
        pMsg->m[ 7] = m[ 7];
        pMsg->m[ 8] = m[ 8];
        pMsg->m[ 9] = m[ 9];
        pMsg->m[10] = m[10];
        pMsg->m[11] = m[11];
        pMsg->m[12] = m[12];
        pMsg->m[13] = m[13];
        pMsg->m[14] = m[14];
        pMsg->m[15] = m[15];
    return;
    GLCLIENT_END
}

void APIENTRY
glcltMultMatrixd ( IN const GLdouble m[16] )
{
// Call MultMatrixf instead

    GLCLIENT_BEGIN( MultMatrixf, MULTMATRIXF )
        pMsg->m[ 0] = (GLfloat) m[ 0];
        pMsg->m[ 1] = (GLfloat) m[ 1];
        pMsg->m[ 2] = (GLfloat) m[ 2];
        pMsg->m[ 3] = (GLfloat) m[ 3];
        pMsg->m[ 4] = (GLfloat) m[ 4];
        pMsg->m[ 5] = (GLfloat) m[ 5];
        pMsg->m[ 6] = (GLfloat) m[ 6];
        pMsg->m[ 7] = (GLfloat) m[ 7];
        pMsg->m[ 8] = (GLfloat) m[ 8];
        pMsg->m[ 9] = (GLfloat) m[ 9];
        pMsg->m[10] = (GLfloat) m[10];
        pMsg->m[11] = (GLfloat) m[11];
        pMsg->m[12] = (GLfloat) m[12];
        pMsg->m[13] = (GLfloat) m[13];
        pMsg->m[14] = (GLfloat) m[14];
        pMsg->m[15] = (GLfloat) m[15];
    return;
    GLCLIENT_END
}

void APIENTRY
glcltOrtho ( IN GLdouble left, IN GLdouble right, IN GLdouble bottom, IN GLdouble top, IN GLdouble zNear, IN GLdouble zFar )
{
    GLCLIENT_BEGIN( Ortho, ORTHO )
        pMsg->left     = left    ;
        pMsg->right    = right   ;
        pMsg->bottom   = bottom  ;
        pMsg->top      = top     ;
        pMsg->zNear    = zNear   ;
        pMsg->zFar     = zFar    ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPopMatrix ( void )
{
    GLCLIENT_BEGIN( PopMatrix, POPMATRIX )
    return;
    GLCLIENT_END
}

void APIENTRY
glcltPushMatrix ( void )
{
    GLCLIENT_BEGIN( PushMatrix, PUSHMATRIX )
    return;
    GLCLIENT_END
}

void APIENTRY
glcltRotated ( IN GLdouble angle, IN GLdouble x, IN GLdouble y, IN GLdouble z )
{
// Call Rotatef instead

    glcltRotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z);
}

void APIENTRY
glcltRotatef ( IN GLfloat angle, IN GLfloat x, IN GLfloat y, IN GLfloat z )
{
    GLCLIENT_BEGIN( Rotatef, ROTATEF )
        pMsg->angle    = angle   ;
        pMsg->x        = x       ;
        pMsg->y        = y       ;
        pMsg->z        = z       ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltScaled ( IN GLdouble x, IN GLdouble y, IN GLdouble z )
{
// Call Scalef instead

    glcltScalef((GLfloat) x, (GLfloat) y, (GLfloat) z);
}

void APIENTRY
glcltScalef ( IN GLfloat x, IN GLfloat y, IN GLfloat z )
{
    GLCLIENT_BEGIN( Scalef, SCALEF )
        pMsg->x        = x       ;
        pMsg->y        = y       ;
        pMsg->z        = z       ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltTranslated ( IN GLdouble x, IN GLdouble y, IN GLdouble z )
{
// Call Translatef instead

    glcltTranslatef((GLfloat) x, (GLfloat) y, (GLfloat) z);
}

void APIENTRY
glcltTranslatef ( IN GLfloat x, IN GLfloat y, IN GLfloat z )
{
    GLCLIENT_BEGIN( Translatef, TRANSLATEF )
        pMsg->x        = x       ;
        pMsg->y        = y       ;
        pMsg->z        = z       ;
    return;
    GLCLIENT_END
}

void APIENTRY
glcltViewport ( IN GLint x, IN GLint y, IN GLsizei width, IN GLsizei height )
{
    GLCLIENT_BEGIN( Viewport, VIEWPORT )
        pMsg->x        = x       ;
        pMsg->y        = y       ;
        pMsg->width    = width   ;
        pMsg->height   = height  ;
    return;
    GLCLIENT_END
}
