Minor clean-up of polygon offset logic. Properly compute _MRD field.
[mesa.git] / src / mesa / main / varray.c
index 96b15c27f071a6b1708799dab0070c08ba158347..fe4a7c684f6344bd84aa8cb94324de71e3953419 100644 (file)
@@ -1,21 +1,19 @@
-/* $Id: varray.c,v 1.29 2000/10/30 18:50:42 keithw Exp $ */
-
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
- * 
- * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
- * 
+ * Version:  6.5.1
+ *
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
- * 
+ *
  * The above copyright notice and this permission notice shall be included
  * in all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef PC_HEADER
-#include "all.h"
-#else
+
 #include "glheader.h"
+#include "imports.h"
+#include "bufferobj.h"
 #include "context.h"
-#include "cva.h"
 #include "enable.h"
 #include "enums.h"
-#include "dlist.h"
-#include "light.h"
-#include "macros.h"
-#include "mmath.h"
-#include "pipeline.h"
-#include "state.h"
-#include "texstate.h"
-#include "translate.h"
-#include "types.h"
+#include "mtypes.h"
 #include "varray.h"
-#include "vb.h"
-#include "vbfill.h"
-#include "vbrender.h"
-#include "vbindirect.h"
-#include "vbxform.h"
-#include "xform.h"
+#include "arrayobj.h"
+#include "glapi/dispatch.h"
+
+
+/**
+ * Update the fields of a vertex array object.
+ * We need to do a few special things for arrays that live in
+ * vertex buffer objects.
+ *
+ * \param array  the array to update
+ * \param dirtyBit  which bit to set in ctx->Array.NewState for this array
+ * \param elementSize  size of each array element, in bytes
+ * \param size  components per element (1, 2, 3 or 4)
+ * \param type  datatype of each component (GL_FLOAT, GL_INT, etc)
+ * \param stride  stride between elements, in elements
+ * \param normalized  are integer types converted to floats in [-1, 1]?
+ * \param ptr  the address (or offset inside VBO) of the array data
+ */
+static void
+update_array(GLcontext *ctx, struct gl_client_array *array,
+             GLbitfield dirtyBit, GLsizei elementSize,
+             GLint size, GLenum type,
+             GLsizei stride, GLboolean normalized, const GLvoid *ptr)
+{
+   array->Size = size;
+   array->Type = type;
+   array->Stride = stride;
+   array->StrideB = stride ? stride : elementSize;
+   array->Normalized = normalized;
+   array->Ptr = (const GLubyte *) ptr;
+#if FEATURE_ARB_vertex_buffer_object
+   array->BufferObj->RefCount--;
+   if (array->BufferObj->RefCount <= 0) {
+      ASSERT(array->BufferObj->Name);
+      _mesa_remove_buffer_object( ctx, array->BufferObj );
+      (*ctx->Driver.DeleteBuffer)( ctx, array->BufferObj );
+   }
+   array->BufferObj = ctx->Array.ArrayBufferObj;
+   array->BufferObj->RefCount++;
+   /* Compute the index of the last array element that's inside the buffer.
+    * Later in glDrawArrays we'll check if start + count > _MaxElement to
+    * be sure we won't go out of bounds.
+    */
+   if (ctx->Array.ArrayBufferObj->Name)
+      array->_MaxElement = ((GLsizeiptrARB) ctx->Array.ArrayBufferObj->Size
+                            - (GLsizeiptrARB) array->Ptr + array->StrideB
+                            - elementSize) / array->StrideB;
+   else
 #endif
+      array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
 
+   ctx->NewState |= _NEW_ARRAY;
+   ctx->Array.NewState |= dirtyBit;
+}
 
 
-void
+void GLAPIENTRY
 _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
 {
+   GLsizei elementSize;
    GET_CURRENT_CONTEXT(ctx);
-   
-   if (size<2 || size>4) {
-      gl_error( ctx, GL_INVALID_VALUE, "glVertexPointer(size)" );
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (size < 2 || size > 4) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glVertexPointer(size)" );
       return;
    }
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glVertexPointer(stride)" );
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glVertexPointer(stride)" );
       return;
    }
-   
+
    if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
-      fprintf(stderr, "glVertexPointer( sz %d type %s stride %d )\n", size, 
-             gl_lookup_enum_by_nr( type ),
-             stride);
+      _mesa_debug(ctx, "glVertexPointer( sz %d type %s stride %d )\n", size,
+                  _mesa_lookup_enum_by_nr( type ), stride);
 
-   ctx->Array.Vertex.StrideB = stride;
-   if (!stride) {
-      switch (type) {
+   /* always need to check that <type> is legal */
+   switch (type) {
       case GL_SHORT:
-         ctx->Array.Vertex.StrideB =  size*sizeof(GLshort);
+         elementSize = size * sizeof(GLshort);
          break;
       case GL_INT:
-         ctx->Array.Vertex.StrideB =  size*sizeof(GLint);
+         elementSize = size * sizeof(GLint);
          break;
       case GL_FLOAT:
-         ctx->Array.Vertex.StrideB =  size*sizeof(GLfloat);
+         elementSize = size * sizeof(GLfloat);
          break;
       case GL_DOUBLE:
-         ctx->Array.Vertex.StrideB =  size*sizeof(GLdouble);
+         elementSize = size * sizeof(GLdouble);
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glVertexPointer(type)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glVertexPointer(type)" );
          return;
-      }
    }
-   ctx->Array.Vertex.Size = size;
-   ctx->Array.Vertex.Type = type;
-   ctx->Array.Vertex.Stride = stride;
-   ctx->Array.Vertex.Ptr = (void *) ptr;
-   ctx->Array.VertexFunc = gl_trans_4f_tab[size][TYPE_IDX(type)];
-   ctx->Array.VertexEltFunc = gl_trans_elt_4f_tab[size][TYPE_IDX(type)];
-   ctx->Array.NewArrayState |= VERT_OBJ_ANY;
-   ctx->NewState |= _NEW_ARRAY;
-}
 
+   update_array(ctx, &ctx->Array.ArrayObj->Vertex, _NEW_ARRAY_VERTEX,
+                elementSize, size, type, stride, GL_FALSE, ptr);
 
+   if (ctx->Driver.VertexPointer)
+      ctx->Driver.VertexPointer( ctx, size, type, stride, ptr );
+}
 
 
-void
+void GLAPIENTRY
 _mesa_NormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr )
 {
+   GLsizei elementSize;
    GET_CURRENT_CONTEXT(ctx);
-   
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glNormalPointer(stride)" );
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glNormalPointer(stride)" );
       return;
    }
 
    if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
-      fprintf(stderr, "glNormalPointer( type %s stride %d )\n", 
-             gl_lookup_enum_by_nr( type ),
-             stride);
+      _mesa_debug(ctx, "glNormalPointer( type %s stride %d )\n",
+                  _mesa_lookup_enum_by_nr( type ), stride);
 
-   ctx->Array.Normal.StrideB = stride;
-   if (!stride) {
-      switch (type) {
+   switch (type) {
       case GL_BYTE:
-         ctx->Array.Normal.StrideB =  3*sizeof(GLbyte);
+         elementSize = 3 * sizeof(GLbyte);
          break;
       case GL_SHORT:
-         ctx->Array.Normal.StrideB =  3*sizeof(GLshort);
+         elementSize = 3 * sizeof(GLshort);
          break;
       case GL_INT:
-         ctx->Array.Normal.StrideB =  3*sizeof(GLint);
+         elementSize = 3 * sizeof(GLint);
          break;
       case GL_FLOAT:
-         ctx->Array.Normal.StrideB =  3*sizeof(GLfloat);
+         elementSize = 3 * sizeof(GLfloat);
          break;
       case GL_DOUBLE:
-         ctx->Array.Normal.StrideB =  3*sizeof(GLdouble);
+         elementSize = 3 * sizeof(GLdouble);
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glNormalPointer(type)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glNormalPointer(type)" );
          return;
-      }
    }
-   ctx->Array.Normal.Type = type;
-   ctx->Array.Normal.Stride = stride;
-   ctx->Array.Normal.Ptr = (void *) ptr;
-   ctx->Array.NormalFunc = gl_trans_3f_tab[TYPE_IDX(type)];
-   ctx->Array.NormalEltFunc = gl_trans_elt_3f_tab[TYPE_IDX(type)];
-   ctx->Array.NewArrayState |= VERT_NORM;
-   ctx->NewState |= _NEW_ARRAY;
-}
 
+   update_array(ctx, &ctx->Array.ArrayObj->Normal, _NEW_ARRAY_NORMAL,
+                elementSize, 3, type, stride, GL_TRUE, ptr);
 
+   if (ctx->Driver.NormalPointer)
+      ctx->Driver.NormalPointer( ctx, type, stride, ptr );
+}
 
-void
+
+void GLAPIENTRY
 _mesa_ColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
 {
+   GLsizei elementSize;
    GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   if (size<3 || size>4) {
-      gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(size)" );
+   if (size < 3 || size > 4) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glColorPointer(size)" );
       return;
    }
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(stride)" );
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glColorPointer(stride)" );
       return;
    }
 
    if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
-      fprintf(stderr, "glColorPointer( sz %d type %s stride %d )\n", size, 
-         gl_lookup_enum_by_nr( type ),
-         stride);
+      _mesa_debug(ctx, "glColorPointer( sz %d type %s stride %d )\n", size,
+                  _mesa_lookup_enum_by_nr( type ), stride);
 
-   ctx->Array.Color.StrideB = stride;
-   if (!stride) {
-      switch (type) {
+   switch (type) {
       case GL_BYTE:
-         ctx->Array.Color.StrideB =  size*sizeof(GLbyte);
+         elementSize = size * sizeof(GLbyte);
          break;
       case GL_UNSIGNED_BYTE:
-         ctx->Array.Color.StrideB =  size*sizeof(GLubyte);
+         elementSize = size * sizeof(GLubyte);
          break;
       case GL_SHORT:
-         ctx->Array.Color.StrideB =  size*sizeof(GLshort);
+         elementSize = size * sizeof(GLshort);
          break;
       case GL_UNSIGNED_SHORT:
-         ctx->Array.Color.StrideB =  size*sizeof(GLushort);
+         elementSize = size * sizeof(GLushort);
          break;
       case GL_INT:
-         ctx->Array.Color.StrideB =  size*sizeof(GLint);
+         elementSize = size * sizeof(GLint);
          break;
       case GL_UNSIGNED_INT:
-         ctx->Array.Color.StrideB =  size*sizeof(GLuint);
+         elementSize = size * sizeof(GLuint);
          break;
       case GL_FLOAT:
-         ctx->Array.Color.StrideB =  size*sizeof(GLfloat);
+         elementSize = size * sizeof(GLfloat);
          break;
       case GL_DOUBLE:
-         ctx->Array.Color.StrideB =  size*sizeof(GLdouble);
+         elementSize = size * sizeof(GLdouble);
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glColorPointer(type)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glColorPointer(type)" );
          return;
-      }
    }
-   ctx->Array.Color.Size = size;
-   ctx->Array.Color.Type = type;
-   ctx->Array.Color.Stride = stride;
-   ctx->Array.Color.Ptr = (void *) ptr;
-   ctx->Array.ColorFunc = gl_trans_4ub_tab[size][TYPE_IDX(type)];
-   ctx->Array.ColorEltFunc = gl_trans_elt_4ub_tab[size][TYPE_IDX(type)];
-   ctx->Array.NewArrayState |= VERT_RGBA;
-   ctx->NewState |= _NEW_ARRAY;
-}
 
+   update_array(ctx, &ctx->Array.ArrayObj->Color, _NEW_ARRAY_COLOR0,
+                elementSize, size, type, stride, GL_TRUE, ptr);
+
+   if (ctx->Driver.ColorPointer)
+      ctx->Driver.ColorPointer( ctx, size, type, stride, ptr );
+}
 
 
-void
+void GLAPIENTRY
 _mesa_FogCoordPointerEXT(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
+   GLint elementSize;
    GET_CURRENT_CONTEXT(ctx);
-   
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glFogCoordPointer(stride)" );
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glFogCoordPointer(stride)" );
       return;
    }
 
-   ctx->Array.FogCoord.StrideB = stride;
-   if (!stride) {
-      switch (type) {
+   switch (type) {
       case GL_FLOAT:
-         ctx->Array.FogCoord.StrideB =  sizeof(GLfloat);
+         elementSize = sizeof(GLfloat);
          break;
       case GL_DOUBLE:
-         ctx->Array.FogCoord.StrideB =  sizeof(GLdouble);
+         elementSize = sizeof(GLdouble);
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glFogCoordPointer(type)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glFogCoordPointer(type)" );
          return;
-      }
    }
-   ctx->Array.FogCoord.Type = type;
-   ctx->Array.FogCoord.Stride = stride;
-   ctx->Array.FogCoord.Ptr = (void *) ptr;
-   ctx->Array.FogCoordFunc = gl_trans_1f_tab[TYPE_IDX(type)];
-   ctx->Array.FogCoordEltFunc = gl_trans_elt_1f_tab[TYPE_IDX(type)];
-   ctx->Array.NewArrayState |= VERT_FOG_COORD;
-   ctx->NewState |= _NEW_ARRAY;
+
+   update_array(ctx, &ctx->Array.ArrayObj->FogCoord, _NEW_ARRAY_FOGCOORD,
+                elementSize, 1, type, stride, GL_FALSE, ptr);
+
+   if (ctx->Driver.FogCoordPointer)
+      ctx->Driver.FogCoordPointer( ctx, type, stride, ptr );
 }
 
 
-void
+void GLAPIENTRY
 _mesa_IndexPointer(GLenum type, GLsizei stride, const GLvoid *ptr)
 {
+   GLsizei elementSize;
    GET_CURRENT_CONTEXT(ctx);
-   
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glIndexPointer(stride)" );
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glIndexPointer(stride)" );
       return;
    }
 
-   ctx->Array.Index.StrideB = stride;
-   if (!stride) {
-      switch (type) {
+   switch (type) {
       case GL_UNSIGNED_BYTE:
-         ctx->Array.Index.StrideB =  sizeof(GLubyte);
+         elementSize = sizeof(GLubyte);
          break;
       case GL_SHORT:
-         ctx->Array.Index.StrideB =  sizeof(GLshort);
+         elementSize = sizeof(GLshort);
          break;
       case GL_INT:
-         ctx->Array.Index.StrideB =  sizeof(GLint);
+         elementSize = sizeof(GLint);
          break;
       case GL_FLOAT:
-         ctx->Array.Index.StrideB =  sizeof(GLfloat);
+         elementSize = sizeof(GLfloat);
          break;
       case GL_DOUBLE:
-         ctx->Array.Index.StrideB =  sizeof(GLdouble);
+         elementSize = sizeof(GLdouble);
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glIndexPointer(type)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glIndexPointer(type)" );
          return;
-      }
    }
-   ctx->Array.Index.Type = type;
-   ctx->Array.Index.Stride = stride;
-   ctx->Array.Index.Ptr = (void *) ptr;
-   ctx->Array.IndexFunc = gl_trans_1ui_tab[TYPE_IDX(type)];
-   ctx->Array.IndexEltFunc = gl_trans_elt_1ui_tab[TYPE_IDX(type)];
-   ctx->Array.NewArrayState |= VERT_INDEX;
-   ctx->NewState |= _NEW_ARRAY;
+
+   update_array(ctx, &ctx->Array.ArrayObj->Index, _NEW_ARRAY_INDEX,
+                elementSize, 1, type, stride, GL_FALSE, ptr);
+
+   if (ctx->Driver.IndexPointer)
+      ctx->Driver.IndexPointer( ctx, type, stride, ptr );
 }
 
 
-void
-_mesa_SecondaryColorPointerEXT(GLint size, GLenum type, 
+void GLAPIENTRY
+_mesa_SecondaryColorPointerEXT(GLint size, GLenum type,
                               GLsizei stride, const GLvoid *ptr)
 {
+   GLsizei elementSize;
    GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    if (size != 3 && size != 4) {
-      gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(size)" );
+      _mesa_error( ctx, GL_INVALID_VALUE, "glSecondaryColorPointer(size)" );
       return;
    }
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(stride)" );
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glSecondaryColorPointer(stride)" );
       return;
    }
 
    if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
-      fprintf(stderr, "glColorPointer( sz %d type %s stride %d )\n", size, 
-         gl_lookup_enum_by_nr( type ),
-         stride);
+      _mesa_debug(ctx, "glSecondaryColorPointer( sz %d type %s stride %d )\n",
+                  size, _mesa_lookup_enum_by_nr( type ), stride);
 
-   ctx->Array.SecondaryColor.StrideB = stride;
-   if (!stride) {
-      switch (type) {
+   switch (type) {
       case GL_BYTE:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLbyte);
+         elementSize = size * sizeof(GLbyte);
          break;
       case GL_UNSIGNED_BYTE:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLubyte);
+         elementSize = size * sizeof(GLubyte);
          break;
       case GL_SHORT:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLshort);
+         elementSize = size * sizeof(GLshort);
          break;
       case GL_UNSIGNED_SHORT:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLushort);
+         elementSize = size * sizeof(GLushort);
          break;
       case GL_INT:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLint);
+         elementSize = size * sizeof(GLint);
          break;
       case GL_UNSIGNED_INT:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLuint);
+         elementSize = size * sizeof(GLuint);
          break;
       case GL_FLOAT:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLfloat);
+         elementSize = size * sizeof(GLfloat);
          break;
       case GL_DOUBLE:
-         ctx->Array.SecondaryColor.StrideB =  size*sizeof(GLdouble);
+         elementSize = size * sizeof(GLdouble);
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glSecondaryColorPointer(type)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glSecondaryColorPointer(type)" );
          return;
-      }
    }
-   ctx->Array.SecondaryColor.Size = 3; /* hardwire */
-   ctx->Array.SecondaryColor.Type = type;
-   ctx->Array.SecondaryColor.Stride = stride;
-   ctx->Array.SecondaryColor.Ptr = (void *) ptr;
-   ctx->Array.SecondaryColorFunc = gl_trans_4ub_tab[size][TYPE_IDX(type)];
-   ctx->Array.SecondaryColorEltFunc = gl_trans_elt_4ub_tab[size][TYPE_IDX(type)];
-   ctx->Array.NewArrayState |= VERT_SPEC_RGB;
-   ctx->NewState |= _NEW_ARRAY;
-}
 
+   update_array(ctx, &ctx->Array.ArrayObj->SecondaryColor, _NEW_ARRAY_COLOR1,
+                elementSize, size, type, stride, GL_TRUE, ptr);
 
+   if (ctx->Driver.SecondaryColorPointer)
+      ctx->Driver.SecondaryColorPointer( ctx, size, type, stride, ptr );
+}
 
-void
-_mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
+
+void GLAPIENTRY
+_mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride,
+                      const GLvoid *ptr)
 {
+   GLint elementSize;
    GET_CURRENT_CONTEXT(ctx);
-   GLuint texUnit;
-   
-   texUnit = ctx->Array.ActiveTexture;
+   const GLuint unit = ctx->Array.ActiveTexture;
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   if (size<1 || size>4) {
-      gl_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(size)" );
+   if (size < 1 || size > 4) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(size)" );
       return;
    }
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(stride)" );
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(stride)" );
       return;
    }
 
    if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
-      fprintf(stderr, "glTexCoordPointer( unit %u sz %d type %s stride %d )\n", 
-         texUnit,
-         size, 
-         gl_lookup_enum_by_nr( type ),
-         stride);
-
-   ctx->Array.TexCoord[texUnit].StrideB = stride;
-   if (!stride) {
-      switch (type) {
+      _mesa_debug(ctx, "glTexCoordPointer(unit %u sz %d type %s stride %d)\n",
+                  unit, size, _mesa_lookup_enum_by_nr( type ), stride);
+
+   /* always need to check that <type> is legal */
+   switch (type) {
       case GL_SHORT:
-         ctx->Array.TexCoord[texUnit].StrideB =  size*sizeof(GLshort);
+         elementSize = size * sizeof(GLshort);
          break;
       case GL_INT:
-         ctx->Array.TexCoord[texUnit].StrideB =  size*sizeof(GLint);
+         elementSize = size * sizeof(GLint);
          break;
       case GL_FLOAT:
-         ctx->Array.TexCoord[texUnit].StrideB =  size*sizeof(GLfloat);
+         elementSize = size * sizeof(GLfloat);
          break;
       case GL_DOUBLE:
-         ctx->Array.TexCoord[texUnit].StrideB =  size*sizeof(GLdouble);
+         elementSize = size * sizeof(GLdouble);
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glTexCoordPointer(type)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glTexCoordPointer(type)" );
          return;
-      }
    }
-   ctx->Array.TexCoord[texUnit].Size = size;
-   ctx->Array.TexCoord[texUnit].Type = type;
-   ctx->Array.TexCoord[texUnit].Stride = stride;
-   ctx->Array.TexCoord[texUnit].Ptr = (void *) ptr;
-
-   ctx->Array.TexCoordFunc[texUnit] = gl_trans_4f_tab[size][TYPE_IDX(type)];
-   ctx->Array.TexCoordEltFunc[texUnit] = gl_trans_elt_4f_tab[size][TYPE_IDX(type)];
-   ctx->Array.NewArrayState |= VERT_TEX_ANY(texUnit);
-   ctx->NewState |= _NEW_ARRAY;
+
+   update_array(ctx, &ctx->Array.ArrayObj->TexCoord[unit],
+                _NEW_ARRAY_TEXCOORD(unit),
+                elementSize, size, type, stride, GL_FALSE, ptr);
+
+   if (ctx->Driver.TexCoordPointer)
+      ctx->Driver.TexCoordPointer( ctx, size, type, stride, ptr );
 }
 
 
+void GLAPIENTRY
+_mesa_EdgeFlagPointer(GLsizei stride, const GLvoid *ptr)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glEdgeFlagPointer(stride)" );
+      return;
+   }
 
+   update_array(ctx, &ctx->Array.ArrayObj->EdgeFlag, _NEW_ARRAY_EDGEFLAG,
+                sizeof(GLboolean), 1, GL_UNSIGNED_BYTE, stride, GL_FALSE, ptr);
 
-void
-_mesa_EdgeFlagPointer(GLsizei stride, const void *vptr)
+   if (ctx->Driver.EdgeFlagPointer)
+      ctx->Driver.EdgeFlagPointer( ctx, stride, ptr );
+}
+
+
+#if FEATURE_NV_vertex_program
+void GLAPIENTRY
+_mesa_VertexAttribPointerNV(GLuint index, GLint size, GLenum type,
+                            GLsizei stride, const GLvoid *ptr)
 {
+   const GLboolean normalized = GL_FALSE;
+   GLsizei elementSize;
    GET_CURRENT_CONTEXT(ctx);
-   const GLboolean *ptr = (GLboolean *)vptr;
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
 
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glEdgeFlagPointer(stride)" );
+   if (index >= MAX_VERTEX_PROGRAM_ATTRIBS) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(index)");
       return;
    }
-   ctx->Array.EdgeFlag.Stride = stride;
-   ctx->Array.EdgeFlag.StrideB = stride ? stride : sizeof(GLboolean);
-   ctx->Array.EdgeFlag.Ptr = (GLboolean *) ptr;
-   if (stride != sizeof(GLboolean)) {
-      ctx->Array.EdgeFlagFunc = gl_trans_1ub_tab[TYPE_IDX(GL_UNSIGNED_BYTE)];
-   } else {
-      ctx->Array.EdgeFlagFunc = 0;
+
+   if (size < 1 || size > 4) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(size)");
+      return;
    }
-   ctx->Array.EdgeFlagEltFunc = gl_trans_elt_1ub_tab[TYPE_IDX(GL_UNSIGNED_BYTE)];
-   ctx->Array.NewArrayState |= VERT_EDGE;
-   ctx->NewState |= _NEW_ARRAY;
+
+   if (stride < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(stride)");
+      return;
+   }
+
+   if (type == GL_UNSIGNED_BYTE && size != 4) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(size!=4)");
+      return;
+   }
+
+   /* check for valid 'type' and compute StrideB right away */
+   switch (type) {
+      case GL_UNSIGNED_BYTE:
+         elementSize = size * sizeof(GLubyte);
+         break;
+      case GL_SHORT:
+         elementSize = size * sizeof(GLshort);
+         break;
+      case GL_FLOAT:
+         elementSize = size * sizeof(GLfloat);
+         break;
+      case GL_DOUBLE:
+         elementSize = size * sizeof(GLdouble);
+         break;
+      default:
+         _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttribPointerNV(type)" );
+         return;
+   }
+
+   update_array(ctx, &ctx->Array.ArrayObj->VertexAttrib[index],
+                _NEW_ARRAY_ATTRIB(index),
+                elementSize, size, type, stride, normalized, ptr);
+
+   if (ctx->Driver.VertexAttribPointer)
+      ctx->Driver.VertexAttribPointer( ctx, index, size, type, stride, ptr );
 }
+#endif
+
 
+#if FEATURE_ARB_vertex_program
+void GLAPIENTRY
+_mesa_VertexAttribPointerARB(GLuint index, GLint size, GLenum type,
+                             GLboolean normalized,
+                             GLsizei stride, const GLvoid *ptr)
+{
+   GLsizei elementSize;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (index >= ctx->Const.VertexProgram.MaxAttribs) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(index)");
+      return;
+   }
+
+   if (size < 1 || size > 4) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(size)");
+      return;
+   }
+
+   if (stride < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(stride)");
+      return;
+   }
+
+   if (type == GL_UNSIGNED_BYTE && size != 4) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(size!=4)");
+      return;
+   }
+
+   /* check for valid 'type' and compute StrideB right away */
+   /* NOTE: more types are supported here than in the NV extension */
+   switch (type) {
+      case GL_BYTE:
+         elementSize = size * sizeof(GLbyte);
+         break;
+      case GL_UNSIGNED_BYTE:
+         elementSize = size * sizeof(GLubyte);
+         break;
+      case GL_SHORT:
+         elementSize = size * sizeof(GLshort);
+         break;
+      case GL_UNSIGNED_SHORT:
+         elementSize = size * sizeof(GLushort);
+         break;
+      case GL_INT:
+         elementSize = size * sizeof(GLint);
+         break;
+      case GL_UNSIGNED_INT:
+         elementSize = size * sizeof(GLuint);
+         break;
+      case GL_FLOAT:
+         elementSize = size * sizeof(GLfloat);
+         break;
+      case GL_DOUBLE:
+         elementSize = size * sizeof(GLdouble);
+         break;
+      default:
+         _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttribPointerARB(type)" );
+         return;
+   }
 
+   update_array(ctx, &ctx->Array.ArrayObj->VertexAttrib[index],
+                _NEW_ARRAY_ATTRIB(index),
+                elementSize, size, type, stride, normalized, ptr);
 
+   if (ctx->Driver.VertexAttribPointer)
+      ctx->Driver.VertexAttribPointer(ctx, index, size, type, stride, ptr);
+}
+#endif
 
 
-void
+void GLAPIENTRY
 _mesa_VertexPointerEXT(GLint size, GLenum type, GLsizei stride,
                        GLsizei count, const GLvoid *ptr)
 {
@@ -451,7 +578,7 @@ _mesa_VertexPointerEXT(GLint size, GLenum type, GLsizei stride,
 }
 
 
-void
+void GLAPIENTRY
 _mesa_NormalPointerEXT(GLenum type, GLsizei stride, GLsizei count,
                        const GLvoid *ptr)
 {
@@ -460,7 +587,7 @@ _mesa_NormalPointerEXT(GLenum type, GLsizei stride, GLsizei count,
 }
 
 
-void
+void GLAPIENTRY
 _mesa_ColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count,
                       const GLvoid *ptr)
 {
@@ -469,7 +596,7 @@ _mesa_ColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count,
 }
 
 
-void
+void GLAPIENTRY
 _mesa_IndexPointerEXT(GLenum type, GLsizei stride, GLsizei count,
                       const GLvoid *ptr)
 {
@@ -478,7 +605,7 @@ _mesa_IndexPointerEXT(GLenum type, GLsizei stride, GLsizei count,
 }
 
 
-void
+void GLAPIENTRY
 _mesa_TexCoordPointerEXT(GLint size, GLenum type, GLsizei stride,
                          GLsizei count, const GLvoid *ptr)
 {
@@ -487,7 +614,7 @@ _mesa_TexCoordPointerEXT(GLint size, GLenum type, GLsizei stride,
 }
 
 
-void
+void GLAPIENTRY
 _mesa_EdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *ptr)
 {
    (void) count;
@@ -495,640 +622,25 @@ _mesa_EdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *ptr)
 }
 
 
-
-
-
-/* KW: Batch function to exec all the array elements in the input
- *     buffer prior to transform.  Done only the first time a vertex
- *     buffer is executed or compiled.
- *
- * KW: Have to do this after each glEnd if cva isn't active.  (also
- *     have to do it after each full buffer)
- */
-void gl_exec_array_elements( GLcontext *ctx, struct immediate *IM,
-                            GLuint start, 
-                            GLuint count)
-{
-   GLuint *flags = IM->Flag;
-   GLuint *elts = IM->Elt;
-   GLuint translate = ctx->Array.Flags;
-   GLuint i;
-
-   if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
-      fprintf(stderr, "exec_array_elements %d .. %d\n", start, count);
-   
-   if (translate & VERT_OBJ_ANY) 
-      (ctx->Array.VertexEltFunc)( IM->Obj, 
-                                 &ctx->Array.Vertex, 
-                                 flags, elts, (VERT_ELT|VERT_OBJ_ANY),
-                                 start, count);
-   
-   if (translate & VERT_NORM) 
-      (ctx->Array.NormalEltFunc)( IM->Normal, 
-                                 &ctx->Array.Normal, 
-                                 flags, elts, (VERT_ELT|VERT_NORM),
-                                 start, count);
-
-   if (translate & VERT_EDGE) 
-      (ctx->Array.EdgeFlagEltFunc)( IM->EdgeFlag, 
-                                   &ctx->Array.EdgeFlag, 
-                                   flags, elts, (VERT_ELT|VERT_EDGE),
-                                   start, count);
-   
-   if (translate & VERT_RGBA)
-      (ctx->Array.ColorEltFunc)( IM->Color, 
-                                &ctx->Array.Color, 
-                                flags, elts, (VERT_ELT|VERT_RGBA),
-                                start, count);
-
-
-   if (translate & VERT_SPEC_RGB)
-      (ctx->Array.SecondaryColorEltFunc)( IM->SecondaryColor, 
-                                         &ctx->Array.SecondaryColor, 
-                                         flags, elts, (VERT_ELT|VERT_SPEC_RGB),
-                                         start, count);
-
-   if (translate & VERT_FOG_COORD)
-      (ctx->Array.FogCoordEltFunc)( IM->FogCoord, 
-                                   &ctx->Array.FogCoord, 
-                                   flags, elts, (VERT_ELT|VERT_FOG_COORD),
-                                   start, count);
-
-   if (translate & VERT_INDEX)
-      (ctx->Array.IndexEltFunc)( IM->Index, 
-                                &ctx->Array.Index, 
-                                flags, elts, (VERT_ELT|VERT_INDEX),
-                                start, count);
-
-   if (translate & VERT_TEX0_ANY)
-      (ctx->Array.TexCoordEltFunc[0])( IM->TexCoord[0], 
-                                      &ctx->Array.TexCoord[0], 
-                                      flags, elts, (VERT_ELT|VERT_TEX0_ANY),
-                                      start, count);
-
-   if (translate & VERT_TEX1_ANY)
-      (ctx->Array.TexCoordEltFunc[1])( IM->TexCoord[1], 
-                                      &ctx->Array.TexCoord[1], 
-                                      flags, elts, (VERT_ELT|VERT_TEX1_ANY),
-                                      start, count);
-
-#if MAX_TEXTURE_UNITS > 2
-   if (translate & VERT_TEX2_ANY)
-      (ctx->Array.TexCoordEltFunc[2])( IM->TexCoord[2], 
-                                      &ctx->Array.TexCoord[2], 
-                                      flags, elts, (VERT_ELT|VERT_TEX2_ANY),
-                                      start, count);
-#endif
-#if MAX_TEXTURE_UNITS > 3
-   if (translate & VERT_TEX3_ANY)
-      (ctx->Array.TexCoordEltFunc[3])( IM->TexCoord[3], 
-                                      &ctx->Array.TexCoord[3], 
-                                      flags, elts, (VERT_ELT|VERT_TEX3_ANY),
-                                      start, count);
-#endif
-
-   for (i = start ; i < count ; i++) 
-      if (flags[i] & VERT_ELT) 
-        flags[i] |= translate;
-
-}
-
-
-
-/* Enough funny business going on in here it might be quicker to use a
- * function pointer.
- */
-#define ARRAY_ELT( IM, i )                                     \
-{                                                              \
-   GLuint count = IM->Count;                                   \
-   IM->Elt[count] = i;                                         \
-   IM->Flag[count] = ((IM->Flag[count] & IM->ArrayAndFlags) |  \
-                     VERT_ELT);                                \
-   IM->FlushElt |= IM->ArrayEltFlush;                          \
-   IM->Count = count += IM->ArrayIncr;                         \
-   if (count == VB_MAX)                                                \
-      _mesa_maybe_transform_vb( IM );                          \
-}
-
-
-void
-_mesa_ArrayElement( GLint i )
-{
-   GET_IMMEDIATE;
-   ARRAY_ELT( IM, i );
-}
-
-
-static void
-gl_ArrayElement( GLcontext *CC, GLint i )
-{
-   struct immediate *im = CC->input;
-   ARRAY_ELT( im, i );
-}
-
-
-
-void
-_mesa_DrawArrays(GLenum mode, GLint start, GLsizei count)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   struct vertex_buffer *VB = ctx->VB;
-   GLint i;
-
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawArrays");
-
-   if (count<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
-      return;
-   }
-
-   if (!ctx->CompileFlag && ctx->Array.Vertex.Enabled) {
-      GLint remaining = count;
-      GLint i;
-      struct gl_client_array *Normal;
-      struct gl_client_array *Color;
-      struct gl_client_array *SecondaryColor;
-      struct gl_client_array *FogCoord;
-      struct gl_client_array *Index;
-      struct gl_client_array *TexCoord[MAX_TEXTURE_UNITS];
-      struct gl_client_array *EdgeFlag;
-      struct immediate *IM = VB->IM;
-      struct gl_pipeline *elt = &ctx->CVA.elt;
-      GLboolean relock;
-      GLuint fallback, required;
-
-      if (ctx->NewState)
-        gl_update_state( ctx );        
-
-      /* Just turn off cva on this path.  Could be useful for multipass
-       * rendering to keep it turned on.
-       */
-      relock = ctx->CompileCVAFlag;
-
-      if (relock) {
-        ctx->CompileCVAFlag = 0;
-        elt->pipeline_valid = 0;
-      }
-
-      if (!elt->pipeline_valid)
-        gl_build_immediate_pipeline( ctx );
-
-      required = elt->inputs;
-      fallback = (elt->inputs & ~ctx->Array.Summary);
-
-      /* The translate function doesn't do anything about size.  It
-       * just ensures that type and stride come out right.
-       */
-      IM->v.Obj.size = ctx->Array.Vertex.Size;
-
-      if (required & VERT_RGBA) {
-        Color = &ctx->Array.Color;
-        if (fallback & VERT_RGBA) {
-           Color = &ctx->Fallback.Color;
-           ctx->Array.ColorFunc = 
-              gl_trans_4ub_tab[4][TYPE_IDX(GL_UNSIGNED_BYTE)];
-        }
-      }
-
-      if (required & VERT_SPEC_RGB) 
-      {
-        SecondaryColor = &ctx->Array.SecondaryColor;
-        if (fallback & VERT_SPEC_RGB) {
-           SecondaryColor = &ctx->Fallback.SecondaryColor;
-           ctx->Array.SecondaryColorFunc = 
-              gl_trans_4ub_tab[4][TYPE_IDX(GL_UNSIGNED_BYTE)];
-        }
-      }
-
-      if (required & VERT_FOG_COORD) 
-      {
-        FogCoord = &ctx->Array.FogCoord;
-        if (fallback & VERT_FOG_COORD) {
-           FogCoord = &ctx->Fallback.FogCoord;
-           ctx->Array.FogCoordFunc = 
-              gl_trans_1f_tab[TYPE_IDX(GL_FLOAT)];
-        }
-      }
-   
-      if (required & VERT_INDEX) {
-        Index = &ctx->Array.Index;
-        if (fallback & VERT_INDEX) {
-           Index = &ctx->Fallback.Index;
-           ctx->Array.IndexFunc = gl_trans_1ui_tab[TYPE_IDX(GL_UNSIGNED_INT)];
-        }
-      }
-
-      for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)  {
-        GLuint flag = VERT_TEX_ANY(i);
-
-        if (required & flag) {
-           TexCoord[i] = &ctx->Array.TexCoord[i];
-
-           if (fallback & flag) {
-              TexCoord[i] = &ctx->Fallback.TexCoord[i];
-              TexCoord[i]->Size = gl_texcoord_size( ctx->Current.Flag, i );
-
-              ctx->Array.TexCoordFunc[i] = 
-                 gl_trans_4f_tab[TexCoord[i]->Size][TYPE_IDX(GL_FLOAT)];
-           }
-        }
-      }
-
-      if (ctx->Array.Flags != ctx->Array.Flag[0]) {
-        for (i = 0 ; i < VB_MAX ; i++) 
-           ctx->Array.Flag[i] = ctx->Array.Flags;
-      }
-
-      if (required & VERT_NORM)  {
-        Normal = &ctx->Array.Normal;
-        if (fallback & VERT_NORM) {
-           Normal = &ctx->Fallback.Normal;
-           ctx->Array.NormalFunc = gl_trans_3f_tab[TYPE_IDX(GL_FLOAT)];
-        }
-      }
-
-      if ( required & VERT_EDGE ) {
-        if (mode == GL_TRIANGLES || 
-            mode == GL_QUADS || 
-            mode == GL_POLYGON) {
-           EdgeFlag = &ctx->Array.EdgeFlag;
-           if (fallback & VERT_EDGE) {
-              EdgeFlag = &ctx->Fallback.EdgeFlag;
-              ctx->Array.EdgeFlagFunc = 
-                 gl_trans_1ub_tab[TYPE_IDX(GL_UNSIGNED_BYTE)];
-           }
-        }
-        else
-           required &= ~VERT_EDGE;
-      }
-
-      VB->Primitive = IM->Primitive; 
-      VB->NextPrimitive = IM->NextPrimitive; 
-      VB->MaterialMask = IM->MaterialMask;
-      VB->Material = IM->Material;
-      VB->BoundsPtr = 0;
-
-      while (remaining > 0) {
-         GLint vbspace = VB_MAX - VB_START;
-        GLuint count, n;
-        
-        if (vbspace >= remaining) {
-           n = remaining;
-           VB->LastPrimitive = VB_START + n;
-        }
-         else {
-           n = vbspace;
-           VB->LastPrimitive = VB_START;
-        }
-        
-        VB->CullMode = 0;
-        
-        ctx->Array.VertexFunc( IM->Obj + VB_START, 
-                               &ctx->Array.Vertex, start, n );
-        
-        if (required & VERT_NORM) {
-           ctx->Array.NormalFunc( IM->Normal + VB_START, 
-                                  Normal, start, n );
-        }
-        
-        if (required & VERT_EDGE) {
-           ctx->Array.EdgeFlagFunc( IM->EdgeFlag + VB_START, 
-                                    EdgeFlag, start, n );
-        }
-        
-        if (required & VERT_RGBA) {
-           ctx->Array.ColorFunc( IM->Color + VB_START, 
-                                 Color, start, n );
-        }
-
-        if (required & VERT_SPEC_RGB) {
-           ctx->Array.SecondaryColorFunc( IM->SecondaryColor + VB_START, 
-                                          SecondaryColor, start, n );
-        }
-
-        if (required & VERT_FOG_COORD) {
-           ctx->Array.FogCoordFunc( IM->FogCoord + VB_START, 
-                                    FogCoord, start, n );
-        }
-        
-        if (required & VERT_INDEX) {
-           ctx->Array.IndexFunc( IM->Index + VB_START, 
-                                 Index, start, n );
-        }
-        
-        if (required & VERT_TEX0_ANY) {
-           IM->v.TexCoord[0].size = TexCoord[0]->Size;
-           ctx->Array.TexCoordFunc[0]( IM->TexCoord[0] + VB_START, 
-                                       TexCoord[0], start, n );
-        }
-        
-        if (required & VERT_TEX1_ANY) {
-           IM->v.TexCoord[1].size = TexCoord[1]->Size;
-           ctx->Array.TexCoordFunc[1]( IM->TexCoord[1] + VB_START, 
-                                       TexCoord[1], start, n );
-        }
-#if MAX_TEXTURE_UNITS > 2
-        if (required & VERT_TEX2_ANY) {
-           IM->v.TexCoord[2].size = TexCoord[2]->Size;
-           ctx->Array.TexCoordFunc[2]( IM->TexCoord[2] + VB_START, 
-                                       TexCoord[2], start, n );
-        }
-#endif
-#if MAX_TEXTURE_UNITS > 3
-        if (required & VERT_TEX3_ANY) {
-           IM->v.TexCoord[3].size = TexCoord[3]->Size;
-           ctx->Array.TexCoordFunc[3]( IM->TexCoord[3] + VB_START, 
-                                       TexCoord[3], start, n );
-        }
-#endif
-
-        VB->ObjPtr = &IM->v.Obj;
-        VB->NormalPtr = &IM->v.Normal;
-        VB->ColorPtr = &IM->v.Color;
-        VB->Color[0] = VB->Color[1] = VB->ColorPtr;
-        VB->IndexPtr = &IM->v.Index;
-        VB->EdgeFlagPtr = &IM->v.EdgeFlag;
-        VB->SecondaryColorPtr = &IM->v.SecondaryColor;
-        VB->FogCoordPtr = &IM->v.FogCoord;
-         for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
-            VB->TexCoordPtr[i] = &IM->v.TexCoord[i];
-         }
-
-        VB->Flag = ctx->Array.Flag;
-        VB->OrFlag = ctx->Array.Flags;
-
-        VB->Start = IM->Start = VB_START;
-        count = VB->Count = IM->Count = VB_START + n;
-
-#define RESET_VEC(v, t, s, c) (v.start = t v.data[s], v.count = c)  
-
-        RESET_VEC(IM->v.Obj, (GLfloat *), VB_START, count);
-        RESET_VEC(IM->v.Normal, (GLfloat *), VB_START, count);
-         for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
-            RESET_VEC(IM->v.TexCoord[i], (GLfloat *), VB_START, count);
-         }
-        RESET_VEC(IM->v.Index, &, VB_START, count);
-        RESET_VEC(IM->v.Elt, &, VB_START, count);
-        RESET_VEC(IM->v.EdgeFlag, &, VB_START, count);
-        RESET_VEC(IM->v.Color, (GLubyte *), VB_START, count);
-        RESET_VEC(VB->Clip, (GLfloat *), VB_START, count);
-        RESET_VEC(VB->Eye, (GLfloat *), VB_START, count);
-        RESET_VEC(VB->Win, (GLfloat *), VB_START, count);
-        RESET_VEC(VB->BColor, (GLubyte *), VB_START, count); 
-        RESET_VEC(VB->BIndex, &, VB_START, count);
-
-        VB->NextPrimitive[VB->CopyStart] = VB->Count;
-        VB->Primitive[VB->CopyStart] = mode;
-        ctx->Array.Flag[count] |= VERT_END_VB;
-
-         /* Transform and render.
-         */
-         gl_run_pipeline( VB );
-        gl_reset_vb( VB );
-
-        ctx->Array.Flag[count] = ctx->Array.Flags;
-        ctx->Array.Flag[VB_START] = ctx->Array.Flags;
-
-         start += n;
-         remaining -= n;
-      }
-
-      gl_reset_input( ctx );
-
-      if (relock) {
-        ctx->CompileCVAFlag = relock;
-        elt->pipeline_valid = 0;
-      }
-   }
-   else if (ctx->Array.Vertex.Enabled) 
-   {
-      /* The GL_COMPILE and GL_COMPILE_AND_EXECUTE cases.  These
-       * could be handled by the above code, but it gets a little
-       * complex.  The generated list is still of good quality
-       * this way.
-       */
-      gl_Begin( ctx, mode );
-      for (i=0;i<count;i++) {
-         gl_ArrayElement( ctx, start+i );
-      }
-      gl_End( ctx );
-   }
-   else
-   {
-      /* The degenerate case where vertices are not enabled - only
-       * need to process the very final array element, as all of the
-       * preceding ones would be overwritten anyway. 
-       */
-      gl_Begin( ctx, mode );
-      gl_ArrayElement( ctx, start+count );
-      gl_End( ctx );
-   }
-}
-
-
-
-/* KW: Exactly fakes the effects of calling glArrayElement multiple times.
- */
-#if 1
-#define DRAW_ELT(FUNC, TYPE)                           \
-static void FUNC( GLcontext *ctx, GLenum mode,         \
-                 TYPE *indices, GLuint count )         \
-{                                                      \
-   GLuint i,j;                                         \
-                                                       \
-   gl_Begin( ctx, mode );                              \
-                                                       \
-   for (j = 0 ; j < count ; ) {                                \
-      struct immediate *IM = ctx->input;               \
-      GLuint start = IM->Start;                                \
-      GLuint nr = MIN2( VB_MAX, count - j + start );   \
-      GLuint sf = IM->Flag[start];                     \
-      IM->FlushElt |= IM->ArrayEltFlush;               \
-                                                       \
-      for (i = start ; i < nr ; i++) {                 \
-        IM->Elt[i] = (GLuint) *indices++;              \
-        IM->Flag[i] = VERT_ELT;                        \
-      }                                                        \
-                                                       \
-      if (j == 0) IM->Flag[start] |= sf;               \
-                                                       \
-      IM->Count = nr;                                  \
-      j += nr - start;                                 \
-                                                       \
-      if (j == count)                                  \
-         gl_End( ctx );                                        \
-      _mesa_maybe_transform_vb( IM );                  \
-   }                                                   \
-}
-#else 
-#define DRAW_ELT(FUNC, TYPE)                           \
-static void FUNC( GLcontext *ctx, GLenum mode,         \
-                  TYPE *indices, GLuint count )        \
-{                                                      \
-  int i;                                               \
-  glBegin(mode);                                       \
-  for (i = 0 ; i < count ; i++)                                \
-    glArrayElement( indices[i] );                      \
-  glEnd();                                             \
-}
-#endif
-       
-
-DRAW_ELT( draw_elt_ubyte, GLubyte )
-DRAW_ELT( draw_elt_ushort, GLushort )
-DRAW_ELT( draw_elt_uint, GLuint )
-
-
-static GLuint natural_stride[0x10] = 
-{
-   sizeof(GLbyte),             /* 0 */
-   sizeof(GLubyte),            /* 1 */
-   sizeof(GLshort),            /* 2 */
-   sizeof(GLushort),           /* 3 */
-   sizeof(GLint),              /* 4 */
-   sizeof(GLuint),             /* 5 */
-   sizeof(GLfloat),            /* 6 */
-   2 * sizeof(GLbyte),         /* 7 */
-   3 * sizeof(GLbyte),         /* 8 */
-   4 * sizeof(GLbyte),         /* 9 */
-   sizeof(GLdouble),           /* a */
-   0,                          /* b */
-   0,                          /* c */
-   0,                          /* d */
-   0,                          /* e */
-   0                           /* f */
-};
-
-
-void
-_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   struct gl_cva *cva;
-      
-   cva = &ctx->CVA;
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawElements");
-
-   if (count <= 0) {
-      if (count < 0)
-        gl_error( ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
-      return;
-   }
-
-   if (mode < 0 || mode > GL_POLYGON) {
-      gl_error( ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
-      return;
-   }
-   
-   if (type != GL_UNSIGNED_INT && type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT)
-   {
-       gl_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
-       return;
-   }
-
-   if (ctx->NewState)
-      gl_update_state(ctx);
-
-   if (ctx->CompileCVAFlag) 
-   {
-      /* Treat VERT_ELT like a special client array.
-       */
-      ctx->Array.NewArrayState |= VERT_ELT;
-      ctx->Array.Summary |= VERT_ELT;
-      ctx->Array.Flags |= VERT_ELT;
-
-      cva->elt_mode = mode;
-      cva->elt_count = count;
-      cva->Elt.Type = type;
-      cva->Elt.Ptr = (void *) indices;
-      cva->Elt.StrideB = natural_stride[TYPE_IDX(type)];
-      cva->EltFunc = gl_trans_1ui_tab[TYPE_IDX(type)];
-
-      if (!cva->pre.pipeline_valid) 
-        gl_build_precalc_pipeline( ctx );
-      else if (MESA_VERBOSE & VERBOSE_PIPELINE)
-        fprintf(stderr, ": dont rebuild\n");
-
-      gl_cva_force_precalc( ctx );
-
-      /* Did we 'precalculate' the render op?
-       */
-      if (ctx->CVA.pre.ops & PIPE_OP_RENDER) {
-        ctx->Array.NewArrayState |= VERT_ELT;
-        ctx->Array.Summary &= ~VERT_ELT;
-        ctx->Array.Flags &= ~VERT_ELT;
-        return;
-      } 
-
-      if ( (MESA_VERBOSE&VERBOSE_VARRAY) )
-        printf("using immediate\n");
-   }
-
-
-   /* Otherwise, have to use the immediate path to render.
-    */
-   switch (type) {
-   case GL_UNSIGNED_BYTE:
-   {
-      GLubyte *ub_indices = (GLubyte *) indices;
-      if (ctx->Array.Summary & VERT_OBJ_ANY) {
-        draw_elt_ubyte( ctx, mode, ub_indices, count );
-      } else {
-        gl_ArrayElement( ctx, (GLuint) ub_indices[count-1] );
-      }
-   }
-   break;
-   case GL_UNSIGNED_SHORT:
-   {
-      GLushort *us_indices = (GLushort *) indices;
-      if (ctx->Array.Summary & VERT_OBJ_ANY) {
-        draw_elt_ushort( ctx, mode, us_indices, count );
-      } else {
-        gl_ArrayElement( ctx, (GLuint) us_indices[count-1] );
-      }
-   }
-   break;
-   case GL_UNSIGNED_INT:
-   {
-      GLuint *ui_indices = (GLuint *) indices;
-      if (ctx->Array.Summary & VERT_OBJ_ANY) {
-        draw_elt_uint( ctx, mode, ui_indices, count );
-      } else {
-        gl_ArrayElement( ctx, ui_indices[count-1] );
-      }
-   }
-   break;
-   default:
-      gl_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
-      break;
-   }
-
-   if (ctx->CompileCVAFlag) {
-      ctx->Array.NewArrayState |= VERT_ELT;
-      ctx->Array.Summary &= ~VERT_ELT;
-   }
-}
-
-
-
-void
+void GLAPIENTRY
 _mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
 {
    GET_CURRENT_CONTEXT(ctx);
    GLboolean tflag, cflag, nflag;  /* enable/disable flags */
    GLint tcomps, ccomps, vcomps;   /* components per texcoord, color, vertex */
-
-   GLenum ctype;                   /* color type */
-   GLint coffset, noffset, voffset;/* color, normal, vertex offsets */
+   GLenum ctype = 0;               /* color type */
+   GLint coffset = 0, noffset = 0, voffset;/* color, normal, vertex offsets */
+   const GLint toffset = 0;        /* always zero */
    GLint defstride;                /* default stride */
    GLint c, f;
-   GLint coordUnitSave;
-   
+
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
    f = sizeof(GLfloat);
-   c = f * ((4*sizeof(GLubyte) + (f-1)) / f);
+   c = f * ((4 * sizeof(GLubyte) + (f - 1)) / f);
 
-   if (stride<0) {
-      gl_error( ctx, GL_INVALID_VALUE, "glInterleavedArrays(stride)" );
+   if (stride < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glInterleavedArrays(stride)" );
       return;
    }
 
@@ -1239,7 +751,7 @@ _mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
          defstride = 15*f;
          break;
       default:
-         gl_error( ctx, GL_INVALID_ENUM, "glInterleavedArrays(format)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glInterleavedArrays(format)" );
          return;
    }
 
@@ -1249,39 +761,23 @@ _mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
 
    _mesa_DisableClientState( GL_EDGE_FLAG_ARRAY );
    _mesa_DisableClientState( GL_INDEX_ARRAY );
+   /* XXX also disable secondary color and generic arrays? */
 
    /* Texcoords */
-   coordUnitSave = ctx->Array.ActiveTexture;
    if (tflag) {
-      GLint i;
-      GLint factor = ctx->Array.TexCoordInterleaveFactor;
-      for (i = 0; i < factor; i++) {
-         _mesa_ClientActiveTextureARB( (GLenum) (GL_TEXTURE0_ARB + i) );
-         _mesa_EnableClientState( GL_TEXTURE_COORD_ARRAY );
-         glTexCoordPointer( tcomps, GL_FLOAT, stride,
-                             (GLubyte *) pointer + i * coffset );
-      }
-      for (i = factor; i < ctx->Const.MaxTextureUnits; i++) {
-         _mesa_ClientActiveTextureARB( (GLenum) (GL_TEXTURE0_ARB + i) );
-         _mesa_DisableClientState( GL_TEXTURE_COORD_ARRAY );
-      }
+      _mesa_EnableClientState( GL_TEXTURE_COORD_ARRAY );
+      _mesa_TexCoordPointer( tcomps, GL_FLOAT, stride,
+                             (GLubyte *) pointer + toffset );
    }
    else {
-      GLint i;
-      for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
-         _mesa_ClientActiveTextureARB( (GLenum) (GL_TEXTURE0_ARB + i) );
-         _mesa_DisableClientState( GL_TEXTURE_COORD_ARRAY );
-      }
+      _mesa_DisableClientState( GL_TEXTURE_COORD_ARRAY );
    }
-   /* Restore texture coordinate unit index */
-   _mesa_ClientActiveTextureARB( (GLenum) (GL_TEXTURE0_ARB + coordUnitSave) );
-
 
    /* Color */
    if (cflag) {
       _mesa_EnableClientState( GL_COLOR_ARRAY );
-      glColorPointer( ccomps, ctype, stride,
-                       (GLubyte*) pointer + coffset );
+      _mesa_ColorPointer( ccomps, ctype, stride,
+                         (GLubyte *) pointer + coffset );
    }
    else {
       _mesa_DisableClientState( GL_COLOR_ARRAY );
@@ -1291,95 +787,152 @@ _mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
    /* Normals */
    if (nflag) {
       _mesa_EnableClientState( GL_NORMAL_ARRAY );
-      glNormalPointer( GL_FLOAT, stride,
-                        (GLubyte*) pointer + noffset );
+      _mesa_NormalPointer( GL_FLOAT, stride, (GLubyte *) pointer + noffset );
    }
    else {
       _mesa_DisableClientState( GL_NORMAL_ARRAY );
    }
 
+   /* Vertices */
    _mesa_EnableClientState( GL_VERTEX_ARRAY );
-   glVertexPointer( vcomps, GL_FLOAT, stride,
-                     (GLubyte *) pointer + voffset );
+   _mesa_VertexPointer( vcomps, GL_FLOAT, stride,
+                       (GLubyte *) pointer + voffset );
 }
 
 
-
-void
-_mesa_DrawRangeElements(GLenum mode, GLuint start,
-                        GLuint end, GLsizei count,
-                        GLenum type, const GLvoid *indices)
+void GLAPIENTRY
+_mesa_LockArraysEXT(GLint first, GLsizei count)
 {
    GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   if (end < start) {
-      gl_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements( end < start )");
-      return;
-   }
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glLockArrays %d %d\n", first, count);
 
-#if 0
-   /*
-    * XXX something in locked arrays is broken!  If start = 0,
-    * end = 1 and count = 2 we'll take the LockArrays path and
-    * get incorrect results.  See Scott McMillan's bug of 3 Jan 2000.
-    * For now, don't use locked arrays.
-    */
-   if (!ctx->Array.LockCount && 2*count > (GLint) 3*(end-start)) {
-      glLockArraysEXT( start, end );
-      glDrawElements( mode, count, type, indices );
-      glUnlockArraysEXT();
-   } else {
-      glDrawElements( mode, count, type, indices );
+   if (first == 0 && count > 0 &&
+       count <= (GLint) ctx->Const.MaxArrayLockSize) {
+      ctx->Array.LockFirst = first;
+      ctx->Array.LockCount = count;
    }
-#else
-   glDrawElements( mode, count, type, indices );
-#endif
+   else {
+      ctx->Array.LockFirst = 0;
+      ctx->Array.LockCount = 0;
+   }
+
+   ctx->NewState |= _NEW_ARRAY;
+   ctx->Array.NewState |= _NEW_ARRAY_ALL;
+
+   if (ctx->Driver.LockArraysEXT)
+      ctx->Driver.LockArraysEXT( ctx, first, count );
+}
+
+
+void GLAPIENTRY
+_mesa_UnlockArraysEXT( void )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glUnlockArrays\n");
+
+   ctx->Array.LockFirst = 0;
+   ctx->Array.LockCount = 0;
+   ctx->NewState |= _NEW_ARRAY;
+   ctx->Array.NewState |= _NEW_ARRAY_ALL;
+
+   if (ctx->Driver.UnlockArraysEXT)
+      ctx->Driver.UnlockArraysEXT( ctx );
 }
 
 
+/* GL_EXT_multi_draw_arrays */
+/* Somebody forgot to spec the first and count parameters as const! <sigh> */
+void GLAPIENTRY
+_mesa_MultiDrawArraysEXT( GLenum mode, GLint *first,
+                          GLsizei *count, GLsizei primcount )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   for (i = 0; i < primcount; i++) {
+      if (count[i] > 0) {
+         CALL_DrawArrays(ctx->Exec, (mode, first[i], count[i]));
+      }
+   }
+}
 
-void gl_update_client_state( GLcontext *ctx )
+
+/* GL_EXT_multi_draw_arrays */
+void GLAPIENTRY
+_mesa_MultiDrawElementsEXT( GLenum mode, const GLsizei *count, GLenum type,
+                            const GLvoid **indices, GLsizei primcount )
 {
-   static const GLuint sz_flags[5] = {
-      0, 
-      0,
-      VERT_OBJ_2, 
-      VERT_OBJ_23, 
-      VERT_OBJ_234
-   };
-   static const GLuint tc_flags[5] = {
-      0, 
-      VERT_TEX0_12, 
-      VERT_TEX0_12, 
-      VERT_TEX0_123, 
-      VERT_TEX0_1234
-   };
+   GET_CURRENT_CONTEXT(ctx);
    GLint i;
 
-   ctx->Array.Flags = 0;
-   ctx->Array.Summary = 0;
-   ctx->input->ArrayIncr = 0;
-   
-   if (ctx->Array.Normal.Enabled)         ctx->Array.Flags |= VERT_NORM;
-   if (ctx->Array.Color.Enabled)          ctx->Array.Flags |= VERT_RGBA;
-   if (ctx->Array.SecondaryColor.Enabled) ctx->Array.Flags |= VERT_SPEC_RGB;
-   if (ctx->Array.FogCoord.Enabled)       ctx->Array.Flags |= VERT_FOG_COORD;
-   if (ctx->Array.Index.Enabled)          ctx->Array.Flags |= VERT_INDEX;
-   if (ctx->Array.EdgeFlag.Enabled)       ctx->Array.Flags |= VERT_EDGE;
-   if (ctx->Array.Vertex.Enabled) {
-      ctx->Array.Flags |= sz_flags[ctx->Array.Vertex.Size];
-      ctx->input->ArrayIncr = 1;
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   for (i = 0; i < primcount; i++) {
+      if (count[i] > 0) {
+         CALL_DrawElements(ctx->Exec, (mode, count[i], type, indices[i]));
+      }
    }
-   for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
-      if (ctx->Array.TexCoord[i].Enabled) {
-         ctx->Array.Flags |= (tc_flags[ctx->Array.TexCoord[i].Size] << (i * NR_TEXSIZE_BITS));
+}
+
+
+/* GL_IBM_multimode_draw_arrays */
+void GLAPIENTRY
+_mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
+                             const GLsizei * count,
+                             GLsizei primcount, GLint modestride )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   for ( i = 0 ; i < primcount ; i++ ) {
+      if ( count[i] > 0 ) {
+         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
+        CALL_DrawArrays(ctx->Exec, ( m, first[i], count[i] ));
       }
    }
+}
 
-   /* Not really important any more:
-    */
-   ctx->Array.Summary = ctx->Array.Flags & VERT_DATA;
-   ctx->input->ArrayAndFlags = ~ctx->Array.Flags;
-   ctx->input->ArrayEltFlush = !(ctx->CompileCVAFlag);
+
+/* GL_IBM_multimode_draw_arrays */
+void GLAPIENTRY
+_mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
+                               GLenum type, const GLvoid * const * indices,
+                               GLsizei primcount, GLint modestride )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   /* XXX not sure about ARB_vertex_buffer_object handling here */
+
+   for ( i = 0 ; i < primcount ; i++ ) {
+      if ( count[i] > 0 ) {
+         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
+        CALL_DrawElements(ctx->Exec, ( m, count[i], type, indices[i] ));
+      }
+   }
 }
 
+
+/**
+ * Initialize vertex array state for given context.
+ */
+void 
+_mesa_init_varray(GLcontext *ctx)
+{
+   ctx->Array.DefaultArrayObj = _mesa_new_array_object(ctx, 0);
+   ctx->Array.ArrayObj = ctx->Array.DefaultArrayObj;
+
+   ctx->Array.ActiveTexture = 0;   /* GL_ARB_multitexture */
+}