Allow different max texture sizes for 1/2D, 3D and cube maps.
[mesa.git] / src / mesa / tnl / t_imm_eval.c
index 1207a9ab158353a5a64c6d9f9c7755f89b061194..f6d33dfa1a4c8055f63b2c5b618941deafda8d1a 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: t_imm_eval.c,v 1.5 2001/02/20 18:28:52 keithw Exp $ */
+/* $Id: t_imm_eval.c,v 1.13 2001/05/14 09:00:51 keithw Exp $ */
 
 /*
  * Mesa 3-D graphics library
  * Version:  3.5
  *
- * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2001  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"),
  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Keith Whitwell <keithw@valinux.com>
+ *
  */
 
 
 #include "math/m_eval.h"
 
 #include "t_context.h"
+#include "t_imm_debug.h"
 #include "t_imm_eval.h"
 #include "t_imm_exec.h"
 #include "t_imm_fixup.h"
+#include "t_imm_alloc.h"
 
 
 static void eval_points1( GLfloat outcoord[][4],
@@ -84,10 +90,10 @@ static const GLubyte dirty_flags[5] = {
 
 
 static void eval1_4f( GLvector4f *dest,
-                            GLfloat coord[][4],
-                            const GLuint *flags,
-                            GLuint dimension,
-                            struct gl_1d_map *map )
+                     GLfloat coord[][4],
+                     const GLuint *flags,
+                     GLuint dimension,
+                     struct gl_1d_map *map )
 {
    const GLfloat u1 = map->u1;
    const GLfloat du = map->du;
@@ -98,7 +104,7 @@ static void eval1_4f( GLvector4f *dest,
       if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
         GLfloat u = (coord[i][0] - u1) * du;
         ASSIGN_4V(to[i], 0,0,0,1);
-        _math_horner_bezier_curve(map->Points, to[i], u, 
+        _math_horner_bezier_curve(map->Points, to[i], u,
                                   dimension, map->Order);
       }
 
@@ -106,6 +112,31 @@ static void eval1_4f( GLvector4f *dest,
    dest->flags |= dirty_flags[dimension];
 }
 
+static void eval1_4f_ca( struct gl_client_array *dest,
+                        GLfloat coord[][4],
+                        const GLuint *flags,
+                        GLuint dimension,
+                        struct gl_1d_map *map )
+{
+   const GLfloat u1 = map->u1;
+   const GLfloat du = map->du;
+   GLfloat (*to)[4] = (GLfloat (*)[4])dest->Ptr;
+   GLuint i;
+
+   ASSERT(dest->Type == GL_FLOAT);
+   ASSERT(dest->StrideB == 4 * sizeof(GLfloat));
+
+   for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+      if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
+        GLfloat u = (coord[i][0] - u1) * du;
+        ASSIGN_4V(to[i], 0,0,0,1);
+        _math_horner_bezier_curve(map->Points, to[i], u,
+                                  dimension, map->Order);
+      }
+
+   dest->Size = MAX2(dest->Size, (GLint) dimension);
+}
+
 
 static void eval1_1ui( GLvector1ui *dest,
                       GLfloat coord[][4],
@@ -129,7 +160,7 @@ static void eval1_1ui( GLvector1ui *dest,
 
 static void eval1_norm( GLvector3f *dest,
                        GLfloat coord[][4],
-                       const GLuint *flags, 
+                       const GLuint *flags,
                        struct gl_1d_map *map )
 {
    const GLfloat u1 = map->u1;
@@ -144,25 +175,6 @@ static void eval1_norm( GLvector3f *dest,
       }
 }
 
-static void eval1_color( GLvector4chan *dest,
-                        GLfloat coord[][4],
-                        const GLuint *flags,
-                        struct gl_1d_map *map )
-{
-   const GLfloat u1 = map->u1;
-   const GLfloat du = map->du;
-   GLchan (*to)[4] = dest->data;
-   GLuint i;
-
-   for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
-      if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
-        GLfloat u = (coord[i][0] - u1) * du;
-        GLfloat fcolor[4];
-        _math_horner_bezier_curve(map->Points, fcolor, u, 4, map->Order);
-         UNCLAMPED_FLOAT_TO_RGBA_CHAN(to[i], fcolor);
-      }
-   }
-}
 
 
 
@@ -182,6 +194,8 @@ static void eval2_obj_norm( GLvector4f *obj_ptr,
    GLfloat (*normal)[3] = norm_ptr->data;
    GLuint i;
 
+/*     fprintf(stderr, "%s\n", __FUNCTION__); */
+
    for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
       if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
         GLfloat u = (coord[i][0] - u1) * du;
@@ -218,6 +232,8 @@ static void eval2_4f( GLvector4f *dest,
       if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
         GLfloat u = (coord[i][0] - u1) * du;
         GLfloat v = (coord[i][1] - v1) * dv;
+/*      fprintf(stderr, "coord %d: %f %f\n", i, coord[i][0], coord[i][1]); */
+
         _math_horner_bezier_surf(map->Points, to[i], u, v, dimension,
                                  map->Uorder, map->Vorder);
       }
@@ -226,6 +242,33 @@ static void eval2_4f( GLvector4f *dest,
    dest->flags |= dirty_flags[dimension];
 }
 
+static void eval2_4f_ca( struct gl_client_array *dest,
+                        GLfloat coord[][4],
+                        const GLuint *flags,
+                        GLuint dimension,
+                        struct gl_2d_map *map )
+{
+   const GLfloat u1 = map->u1;
+   const GLfloat du = map->du;
+   const GLfloat v1 = map->v1;
+   const GLfloat dv = map->dv;
+   GLfloat (*to)[4] = (GLfloat (*)[4])dest->Ptr;
+   GLuint i;
+
+   ASSERT(dest->Type == GL_FLOAT);
+   ASSERT(dest->StrideB == 4 * sizeof(GLfloat));
+
+   for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+      if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
+        GLfloat u = (coord[i][0] - u1) * du;
+        GLfloat v = (coord[i][1] - v1) * dv;
+        _math_horner_bezier_surf(map->Points, to[i], u, v, dimension,
+                                 map->Uorder, map->Vorder);
+      }
+
+   dest->Size = MAX2(dest->Size, (GLint) dimension);
+}
+
 
 static void eval2_norm( GLvector3f *dest,
                        GLfloat coord[][4],
@@ -276,50 +319,37 @@ static void eval2_1ui( GLvector1ui *dest,
 
 
 
-static void eval2_color( GLvector4chan *dest,
-                        GLfloat coord[][4],
-                        GLuint *flags,
-                        struct gl_2d_map *map )
-{
-   const GLfloat u1 = map->u1;
-   const GLfloat du = map->du;
-   const GLfloat v1 = map->v1;
-   const GLfloat dv = map->dv;
-   GLchan (*to)[4] = dest->data;
-   GLuint i;
-
-   for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
-      if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
-        GLfloat u = (coord[i][0] - u1) * du;
-        GLfloat v = (coord[i][1] - v1) * dv;
-        GLfloat fcolor[4];
-        _math_horner_bezier_surf(map->Points, fcolor, u, v, 4,
-                                 map->Uorder, map->Vorder);
-         UNCLAMPED_FLOAT_TO_RGBA_CHAN(to[i], fcolor);
-      }
-   }
-}
 
 
 
 static void copy_4f( GLfloat to[][4], GLfloat from[][4], GLuint count )
 {
-   MEMCPY( to, from, count * sizeof(to[0])); 
+   MEMCPY( to, from, count * sizeof(to[0]));
 }
 
-static void copy_3f( GLfloat to[][3], GLfloat from[][3], GLuint count )
+static void copy_4f_stride( GLfloat to[][4], GLfloat *from, 
+                           GLuint stride, GLuint count )
 {
-   MEMCPY( to, from, (count) * sizeof(to[0])); 
+   if (stride == 4 * sizeof(GLfloat))
+      MEMCPY( to, from, count * sizeof(to[0]));
+   else {
+      GLuint i;
+/*        fprintf(stderr, "%s stride %d count %d\n", __FUNCTION__, */
+/*           stride, count); */
+      for (i = 0 ; i < count ; i++, STRIDE_F(from, stride))
+        COPY_4FV( to[i], from );
+   }
 }
 
-static void copy_4chan( GLchan to[][4], GLchan from[][4], GLuint count )
+static void copy_3f( GLfloat to[][3], GLfloat from[][3], GLuint count )
 {
-   MEMCPY( to, from, (count) * sizeof(to[0])); 
+   MEMCPY( to, from, (count) * sizeof(to[0]));
 }
 
+
 static void copy_1ui( GLuint to[], GLuint from[], GLuint count )
 {
-   MEMCPY( to, from, (count) * sizeof(to[0])); 
+   MEMCPY( to, from, (count) * sizeof(to[0]));
 }
 
 
@@ -368,13 +398,13 @@ static void update_eval( GLcontext *ctx )
       eval1 |= VERT_OBJ_23;
 
    if (ctx->Eval.Map2Vertex4) {
-      if (ctx->Eval.AutoNormal) 
+      if (ctx->Eval.AutoNormal)
         eval2 |= VERT_OBJ_234 | VERT_NORM;
       else
         eval2 |= VERT_OBJ_234;
    }
    else if (ctx->Eval.Map2Vertex3) {
-      if (ctx->Eval.AutoNormal) 
+      if (ctx->Eval.AutoNormal)
         eval2 |= VERT_OBJ_23 | VERT_NORM;
       else
         eval2 |= VERT_OBJ_23;
@@ -388,129 +418,180 @@ static void update_eval( GLcontext *ctx )
 
 /* This looks a lot like a pipeline stage, but for various reasons is
  * better handled outside the pipeline, and considered the final stage
- * of fixing up an immediate struct for execution.  
+ * of fixing up an immediate struct for execution.
  *
  * Really want to cache the results of this function in display lists,
- * at least for EvalMesh commands.  
+ * at least for EvalMesh commands.
  */
-void _tnl_eval_vb( GLcontext *ctx, 
-                  GLfloat (*coord)[4],
-                  GLuint orflag, 
-                  GLuint andflag )
+void _tnl_eval_immediate( GLcontext *ctx, struct immediate *IM )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_arrays *tmp = &tnl->imm_inputs;
-   struct tnl_eval_store *store = &tnl->eval;
-   GLuint *flags = tnl->vb.Flag;
-   GLuint count = tnl->vb.Count;
+   struct immediate *store = tnl->eval.im;
+   GLuint *flags = IM->Flag + IM->CopyStart;
+   GLuint copycount;
+   GLuint orflag = IM->OrFlag;
    GLuint any_eval1 = orflag & (VERT_EVAL_C1|VERT_EVAL_P1);
    GLuint any_eval2 = orflag & (VERT_EVAL_C2|VERT_EVAL_P2);
-   GLuint all_eval = andflag & VERT_EVAL_ANY; /* may have false negatives */
    GLuint req = 0;
    GLuint purge_flags = 0;
+   GLfloat (*coord)[4] = IM->Obj + IM->CopyStart;
+
+   if (IM->AndFlag & VERT_EVAL_ANY)
+      copycount = IM->Start - IM->CopyStart; /* just copy copied vertices */
+   else
+      copycount = IM->Count - IM->CopyStart; /* copy all vertices */
+
+/*     fprintf(stderr, "%s copystart %d start %d count %d copycount %d\n", */
+/*        __FUNCTION__, IM->CopyStart, IM->Start, IM->Count, copycount); */
+
+   if (!store)
+      store = tnl->eval.im = _tnl_alloc_immediate( ctx );
 
    if (tnl->eval.EvalNewState & _NEW_EVAL)
       update_eval( ctx );
 
-   /* Handle the degenerate cases.
-    */
-   if (any_eval1 && !ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3)
-      purge_flags = (VERT_EVAL_P1|VERT_EVAL_C1);
+   if (any_eval1) {
+      req |= tnl->pipeline.inputs & tnl->eval.EvalMap1Flags;
 
-   if (any_eval2 && !ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3) 
-      purge_flags |= (VERT_EVAL_P1|VERT_EVAL_C1);
+      if (!ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3)
+        purge_flags = (VERT_EVAL_P1|VERT_EVAL_C1);
 
-   if (any_eval1) 
-      req |= tnl->pipeline.inputs & tnl->eval.EvalMap1Flags;
+      if (orflag & VERT_EVAL_P1) {
+        eval_points1( store->Obj + IM->CopyStart, 
+                      coord, flags,
+                      ctx->Eval.MapGrid1du,
+                      ctx->Eval.MapGrid1u1);
+        
+        coord = store->Obj + IM->CopyStart;
+      }
+   }
 
-   if (any_eval2) 
+   if (any_eval2) {
       req |= tnl->pipeline.inputs & tnl->eval.EvalMap2Flags;
 
-   
-   /* Translate points into coords.  Use store->Coord to hold the
-    * new data.  
-    */
-   if (any_eval1 && (orflag & VERT_EVAL_P1))
-   {
-      eval_points1( store->Coord, coord, flags,
-                   ctx->Eval.MapGrid1du,
-                   ctx->Eval.MapGrid1u1);
+      if (!ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3)
+        purge_flags |= (VERT_EVAL_P2|VERT_EVAL_C2);
 
-      coord = store->Coord;
-   }
-
-   if (any_eval2 && (orflag & VERT_EVAL_P2))
-   {
-      eval_points2( store->Coord, coord, flags,
-                   ctx->Eval.MapGrid2du,
-                   ctx->Eval.MapGrid2u1,
-                   ctx->Eval.MapGrid2dv,
-                   ctx->Eval.MapGrid2v1 );
+      if (orflag & VERT_EVAL_P2) {
+        eval_points2( store->Obj + IM->CopyStart, 
+                      coord, flags,
+                      ctx->Eval.MapGrid2du,
+                      ctx->Eval.MapGrid2u1,
+                      ctx->Eval.MapGrid2dv,
+                      ctx->Eval.MapGrid2v1 );
 
-      coord = store->Coord;
+        coord = store->Obj + IM->CopyStart;
+      }
    }
 
 
+/*     _tnl_print_vert_flags(__FUNCTION__, req); */
+
    /* Perform the evaluations on active data elements.
     */
    if (req & VERT_INDEX)
    {
-      if (!all_eval) 
-        copy_1ui( store->Index, tmp->Index.data, count );
+      GLuint generated = 0;
+
+      if (copycount)
+        copy_1ui( store->Index + IM->CopyStart, tmp->Index.data, copycount );
 
-      tmp->Index.data = store->Index;
-      tmp->Index.start = store->Index;
+      tmp->Index.data = store->Index + IM->CopyStart;
+      tmp->Index.start = store->Index + IM->CopyStart;
 
-      if (ctx->Eval.Map1Index && any_eval1) 
+      if (ctx->Eval.Map1Index && any_eval1) {
         eval1_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map1Index );
+        generated |= VERT_EVAL_C1|VERT_EVAL_P1;
+      }
 
-      if (ctx->Eval.Map2Index && any_eval2)
+      if (ctx->Eval.Map2Index && any_eval2) {
         eval2_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map2Index );
+        generated |= VERT_EVAL_C2|VERT_EVAL_P2;
+      }
 
+      /* Propogate values to generate correct vertices when vertex
+       * maps are disabled.
+       */
+      if (purge_flags & generated)
+        _tnl_fixup_1ui( tmp->Index.data, flags, 0, 
+                        VERT_INDEX|
+                        VERT_OBJ|
+                        generated|
+                        (VERT_EVAL_ANY&~purge_flags) );
    }
 
    if (req & VERT_RGBA)
    {
-      if (!all_eval)
-        copy_4chan( store->Color, tmp->Color.data, count );
-
-      tmp->Color.data = store->Color;
-      tmp->Color.start = (GLchan *) store->Color;
+      GLuint generated = 0;
+
+      if (copycount) 
+        copy_4f_stride( store->Color + IM->CopyStart, 
+                        (GLfloat *)tmp->Color.Ptr, 
+                        tmp->Color.StrideB,
+                        copycount );
+
+      tmp->Color.Ptr = store->Color + IM->CopyStart;
+      tmp->Color.StrideB = 4 * sizeof(GLfloat);
+      tmp->Color.Flags = 0;
+      tnl->vb.importable_data &= ~VERT_RGBA;
+
+      if (ctx->Eval.Map1Color4 && any_eval1) {
+        eval1_4f_ca( &tmp->Color, coord, flags, 4, &ctx->EvalMap.Map1Color4 );
+        generated |= VERT_EVAL_C1|VERT_EVAL_P1;
+      }
 
-      if (ctx->Eval.Map1Color4 && any_eval1)
-        eval1_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map1Color4 );
+      if (ctx->Eval.Map2Color4 && any_eval2) {
+        eval2_4f_ca( &tmp->Color, coord, flags, 4, &ctx->EvalMap.Map2Color4 );
+        generated |= VERT_EVAL_C2|VERT_EVAL_P2;
+      }
 
-      if (ctx->Eval.Map2Color4 && any_eval2)
-        eval2_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map2Color4 );
+      /* Propogate values to generate correct vertices when vertex
+       * maps are disabled.
+       */
+      if (purge_flags & generated)
+        _tnl_fixup_4f( store->Color + IM->CopyStart, 
+                       flags, 0, 
+                       VERT_RGBA|
+                       VERT_OBJ|
+                       generated|
+                       (VERT_EVAL_ANY&~purge_flags) );
    }
 
 
    if (req & VERT_TEX(0))
    {
-      if (!all_eval) 
-        copy_4f( store->TexCoord, tmp->TexCoord[0].data, count );
-      else 
+      GLuint generated = 0;
+
+      if (copycount)
+        copy_4f( store->TexCoord[0] + IM->CopyStart, 
+                 tmp->TexCoord[0].data, copycount );
+      else
         tmp->TexCoord[0].size = 0;
-        
-      tmp->TexCoord[0].data = store->TexCoord;
-      tmp->TexCoord[0].start = (GLfloat *)store->TexCoord;
+
+      tmp->TexCoord[0].data = store->TexCoord[0] + IM->CopyStart;
+      tmp->TexCoord[0].start = (GLfloat *)tmp->TexCoord[0].data;
 
       if (any_eval1) {
         if (ctx->Eval.Map1TextureCoord4) {
            eval1_4f( &tmp->TexCoord[0], coord, flags, 4,
                      &ctx->EvalMap.Map1Texture4 );
+           generated |= VERT_EVAL_C1|VERT_EVAL_P1;
         }
         else if (ctx->Eval.Map1TextureCoord3) {
            eval1_4f( &tmp->TexCoord[0], coord, flags, 3,
                      &ctx->EvalMap.Map1Texture3 );
+           generated |= VERT_EVAL_C1|VERT_EVAL_P1;
         }
         else if (ctx->Eval.Map1TextureCoord2) {
            eval1_4f( &tmp->TexCoord[0], coord, flags, 2,
                      &ctx->EvalMap.Map1Texture2 );
-        } 
+           generated |= VERT_EVAL_C1|VERT_EVAL_P1;
+        }
         else if (ctx->Eval.Map1TextureCoord1) {
            eval1_4f( &tmp->TexCoord[0], coord, flags, 1,
                      &ctx->EvalMap.Map1Texture1 );
+           generated |= VERT_EVAL_C1|VERT_EVAL_P1;
         }
       }
 
@@ -518,38 +599,71 @@ void _tnl_eval_vb( GLcontext *ctx,
         if (ctx->Eval.Map2TextureCoord4) {
            eval2_4f( &tmp->TexCoord[0], coord, flags, 4,
                      &ctx->EvalMap.Map2Texture4 );
+           generated |= VERT_EVAL_C2|VERT_EVAL_P2;
         }
         else if (ctx->Eval.Map2TextureCoord3) {
-           eval2_4f( &tmp->TexCoord[0], coord, flags, 3, 
+           eval2_4f( &tmp->TexCoord[0], coord, flags, 3,
                      &ctx->EvalMap.Map2Texture3 );
+           generated |= VERT_EVAL_C2|VERT_EVAL_P2;
         }
         else if (ctx->Eval.Map2TextureCoord2) {
            eval2_4f( &tmp->TexCoord[0], coord, flags, 2,
                      &ctx->EvalMap.Map2Texture2 );
+           generated |= VERT_EVAL_C2|VERT_EVAL_P2;
         }
         else if (ctx->Eval.Map2TextureCoord1) {
            eval2_4f( &tmp->TexCoord[0], coord, flags, 1,
                      &ctx->EvalMap.Map2Texture1 );
+           generated |= VERT_EVAL_C2|VERT_EVAL_P2;
         }
       }
+
+      /* Propogate values to generate correct vertices when vertex
+       * maps are disabled.
+       */
+      if (purge_flags & generated)
+        _tnl_fixup_4f( tmp->TexCoord[0].data, flags, 0, 
+                       VERT_TEX0|
+                       VERT_OBJ|
+                       generated|
+                       (VERT_EVAL_ANY&~purge_flags) );
    }
 
 
    if (req & VERT_NORM)
    {
-      if (!all_eval)
-        copy_3f( store->Normal, tmp->Normal.data, count );
+      GLuint generated = 0;
 
-      tmp->Normal.data = store->Normal;
-      tmp->Normal.start = (GLfloat *)store->Normal;
+      if (copycount) {
+/*      fprintf(stderr, "%s: Copy normals\n", __FUNCTION__); */
+        copy_3f( store->Normal + IM->CopyStart, tmp->Normal.data, 
+                 copycount );
+      }
 
-      if (ctx->Eval.Map1Normal && any_eval1)
+      tmp->Normal.data = store->Normal + IM->CopyStart;
+      tmp->Normal.start = (GLfloat *)tmp->Normal.data;
+
+      if (ctx->Eval.Map1Normal && any_eval1) {
         eval1_norm( &tmp->Normal, coord, flags,
                     &ctx->EvalMap.Map1Normal );
+        generated |= VERT_EVAL_C1|VERT_EVAL_P1;
+      }
 
-      if (ctx->Eval.Map2Normal && any_eval2)
+      if (ctx->Eval.Map2Normal && any_eval2) {
         eval2_norm( &tmp->Normal, coord, flags,
                     &ctx->EvalMap.Map2Normal );
+        generated |= VERT_EVAL_C2|VERT_EVAL_P2;
+      }
+
+      /* Propogate values to generate correct vertices when vertex
+       * maps are disabled.
+       */
+      if (purge_flags & generated)
+        _tnl_fixup_3f( tmp->Normal.data, flags, 0, 
+                       VERT_NORM|
+                       VERT_OBJ|
+                       generated|
+                       (VERT_EVAL_ANY&~purge_flags) );
    }
 
 
@@ -559,17 +673,24 @@ void _tnl_eval_vb( GLcontext *ctx,
     */
    if (req & VERT_OBJ)
    {
-      if (!all_eval) {
-        copy_4f( store->Obj, tmp->Obj.data, count );
+      if (copycount) {
+        /* This copy may already have occurred when eliminating
+         * glEvalPoint calls:
+         */
+        if  (coord != store->Obj + IM->CopyStart)
+           copy_4f( store->Obj + IM->CopyStart, tmp->Obj.data, copycount );
       } else
         tmp->Obj.size = 0;
 
-      tmp->Obj.data = store->Obj;
-      tmp->Obj.start = (GLfloat *)store->Obj;
+      tmp->Obj.data = store->Obj + IM->CopyStart;
+      tmp->Obj.start = (GLfloat *)tmp->Obj.data;
+
+      /* Note: Normal data is already prepared above.
+       */
 
       if (any_eval1) {
         if (ctx->Eval.Map1Vertex4) {
-           eval1_4f( &tmp->Obj, coord, flags, 4, 
+           eval1_4f( &tmp->Obj, coord, flags, 4,
                      &ctx->EvalMap.Map1Vertex4 );
         }
         else if (ctx->Eval.Map1Vertex3) {
@@ -581,16 +702,16 @@ void _tnl_eval_vb( GLcontext *ctx,
       if (any_eval2) {
         if (ctx->Eval.Map2Vertex4)
         {
-           if (ctx->Eval.AutoNormal && (req & VERT_NORM)) 
-              eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 4, 
+           if (ctx->Eval.AutoNormal && (req & VERT_NORM))
+              eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 4,
                               &ctx->EvalMap.Map2Vertex4 );
            else
-              eval2_4f( &tmp->Obj, coord, flags, 4, 
+              eval2_4f( &tmp->Obj, coord, flags, 4,
                         &ctx->EvalMap.Map2Vertex4 );
         }
         else if (ctx->Eval.Map2Vertex3)
         {
-           if (ctx->Eval.AutoNormal && (req & VERT_NORM)) 
+           if (ctx->Eval.AutoNormal && (req & VERT_NORM))
               eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 3,
                               &ctx->EvalMap.Map2Vertex3 );
            else
@@ -601,24 +722,47 @@ void _tnl_eval_vb( GLcontext *ctx,
    }
 
 
+   /* Calculate new IM->Elts, IM->Primitive, IM->PrimitiveLength for
+    * the case where vertex maps are not enabled for some received eval
+    * coordinates.
+    */
+   if (purge_flags) {
+      GLuint vertex = VERT_OBJ|(VERT_EVAL_ANY & ~purge_flags);
+      GLuint last_new_prim = 0;
+      GLuint new_prim_length = 0;
+      GLuint next_old_prim = 0;
+      struct vertex_buffer *VB = &tnl->vb;
+      GLuint i,j,count = VB->Count;
+
+/*        fprintf(stderr, "PURGING\n"); */
+
+      for (i = 0, j = 0 ; i < count ; i++) {
+        if (flags[i] & vertex) {
+           store->Elt[j++] = i;
+           new_prim_length++;
+        }
+        if (i == next_old_prim) {
+           next_old_prim += VB->PrimitiveLength[i];
+           VB->PrimitiveLength[last_new_prim] = new_prim_length;
+           VB->Primitive[j] = VB->Primitive[i];
+           last_new_prim = j;
+        }
+      }
+      
+      VB->Elts = store->Elt;
+      _tnl_get_purged_copy_verts( ctx, store );
+   }
+
+   /* Produce new flags array:
+    */
    {
       GLuint i;
+      GLuint count = tnl->vb.Count + 1;
+
       copy_1ui( store->Flag, flags, count );
       tnl->vb.Flag = store->Flag;
-      
-      /* This is overkill, but correct as fixup will have copied the
-       * values to all vertices in the VB - we may be falsely stating
-       * that some repeated values are new, but doing so is fairly
-       * harmless.
-       */
       for (i = 0 ; i < count ; i++)
         store->Flag[i] |= req;
+      IM->CopyOrFlag |= req;   /* hack for copying. */
    }
 }
-
-
-
-
-
-
-