Allow different max texture sizes for 1/2D, 3D and cube maps.
[mesa.git] / src / mesa / tnl / t_imm_fixup.c
index 5da75db53bf138220734e69c483ff1b12967a570..fdfeff566a144d5e987930b218274b4c016e6964 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: t_imm_fixup.c,v 1.2 2000/12/28 22:11:05 keithw Exp $ */
+/* $Id: t_imm_fixup.c,v 1.20 2001/06/04 16:09:28 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"),
@@ -26,7 +26,7 @@
 
 /*
  * Authors:
- *   Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keithw@valinux.com>
  */
 
 
 #include "context.h"
 #include "enums.h"
 #include "dlist.h"
+#include "colormac.h"
+#include "light.h"
 #include "macros.h"
 #include "mem.h"
 #include "mmath.h"
 #include "state.h"
-#include "texture.h"
 #include "mtypes.h"
 
 #include "math/m_matrix.h"
 #include "t_context.h"
 #include "t_imm_alloc.h"
 #include "t_imm_debug.h"
+#include "t_imm_elt.h"
 #include "t_imm_fixup.h"
 #include "t_pipeline.h"
 
 
+static const GLuint increment[GL_POLYGON+2] = { 1,2,1,1,3,1,1,4,2,1,1 };
+static const GLuint intro[GL_POLYGON+2]     = { 0,0,2,2,0,2,2,0,2,2,0 };
 
-static void
-fixup_4f( GLfloat data[][4], GLuint flag[], GLuint start, GLuint match )
+void
+_tnl_fixup_4f( GLfloat data[][4], GLuint flag[], GLuint start, GLuint match )
 {
    GLuint i = start;
 
@@ -65,8 +69,8 @@ fixup_4f( GLfloat data[][4], GLuint flag[], GLuint start, GLuint match )
    }
 }
 
-static void
-fixup_3f( float data[][3], GLuint flag[], GLuint start, GLuint match )
+void
+_tnl_fixup_3f( float data[][3], GLuint flag[], GLuint start, GLuint match )
 {
    GLuint i = start;
 
@@ -79,8 +83,8 @@ fixup_3f( float data[][3], GLuint flag[], GLuint start, GLuint match )
 }
 
 
-static void
-fixup_1ui( GLuint *data, GLuint flag[], GLuint start, GLuint match )
+void
+_tnl_fixup_1ui( GLuint *data, GLuint flag[], GLuint start, GLuint match )
 {
    GLuint i = start;
 
@@ -94,8 +98,8 @@ fixup_1ui( GLuint *data, GLuint flag[], GLuint start, GLuint match )
 }
 
 
-static void
-fixup_1f( GLfloat *data, GLuint flag[], GLuint start, GLuint match )
+void
+_tnl_fixup_1f( GLfloat *data, GLuint flag[], GLuint start, GLuint match )
 {
    GLuint i = start;
 
@@ -108,8 +112,8 @@ fixup_1f( GLfloat *data, GLuint flag[], GLuint start, GLuint match )
    flag[i] |= match;
 }
 
-static void
-fixup_1ub( GLubyte *data, GLuint flag[], GLuint start, GLuint match )
+void
+_tnl_fixup_1ub( GLubyte *data, GLuint flag[], GLuint start, GLuint match )
 {
    GLuint i = start;
 
@@ -123,21 +127,6 @@ fixup_1ub( GLubyte *data, GLuint flag[], GLuint start, GLuint match )
 }
 
 
-static void
-fixup_4ub( GLubyte data[][4], GLuint flag[], GLuint start, GLuint match )
-{
-   GLuint i = start;
-
-   for (;;) {
-      if ((flag[++i] & match) == 0) {
-        COPY_4UBV(data[i], data[i-1]);
-        if (flag[i] & VERT_END_VB) break;
-      }
-   }
-   flag[i] |= match;
-}
-
-
 static void
 fixup_first_4f( GLfloat data[][4], GLuint flag[], GLuint match,
                GLuint start, GLfloat *dflt )
@@ -196,18 +185,6 @@ fixup_first_1ub( GLubyte data[], GLuint flag[], GLuint match,
 }
 
 
-static void
-fixup_first_4ub( GLubyte data[][4], GLuint flag[], GLuint match,
-                GLuint start, GLubyte dflt[4] )
-{
-   GLuint i = start-1;
-   match |= VERT_END_VB;
-
-   while ((flag[++i]&match) == 0)
-      COPY_4UBV(data[i], dflt);
-}
-
-
 void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
@@ -226,7 +203,7 @@ void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM )
 
    fixup = ~andflag & VERT_FIXUP;
 
-   if (!ctx->CompileFlag) 
+   if (!ctx->CompileFlag)
       fixup &= tnl->pipeline.inputs;
 
    if (!ctx->ExecuteFlag)
@@ -238,30 +215,32 @@ void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM )
    if (fixup) {
       GLuint copy = fixup & ~IM->Flag[start];
 
-        
+
       /* Equivalent to a lazy copy-from-current when setting up the
        * immediate.
        */
       if (ctx->ExecuteFlag && copy) {
-/*      _tnl_print_vert_flags("copy from current", copy); */
+
+        if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
+           _tnl_print_vert_flags("copy from current", copy); 
 
         if (copy & VERT_NORM) {
            COPY_3V( IM->Normal[start], ctx->Current.Normal );
         }
 
         if (copy & VERT_RGBA) {
-           COPY_4UBV( IM->Color[start], ctx->Current.Color);
+           COPY_4FV( IM->Color[start], ctx->Current.Color);
         }
 
         if (copy & VERT_SPEC_RGB)
-           COPY_4UBV( IM->SecondaryColor[start], ctx->Current.SecondaryColor);
+           COPY_4FV( IM->SecondaryColor[start], ctx->Current.SecondaryColor);
 
         if (copy & VERT_FOG_COORD)
            IM->FogCoord[start] = ctx->Current.FogCoord;
 
         if (copy & VERT_INDEX)
            IM->Index[start] = ctx->Current.Index;
-       
+
         if (copy & VERT_EDGE)
            IM->EdgeFlag[start] = ctx->Current.EdgeFlag;
 
@@ -275,73 +254,97 @@ void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM )
       }
 
       if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
-/*      _tnl_print_vert_flags("fixup", fixup); */
+        _tnl_print_vert_flags("fixup", fixup); 
 
       if (fixup & VERT_TEX_ANY) {
         GLuint i;
         for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
            if (fixup & VERT_TEX(i)) {
-              if (orflag & VERT_TEX(i)) 
-                 fixup_4f( IM->TexCoord[i], IM->Flag, start, VERT_TEX(i) );
+              if (orflag & VERT_TEX(i))
+                 _tnl_fixup_4f( IM->TexCoord[i], IM->Flag, start,
+                                VERT_TEX(i) );
               else
                  fixup_first_4f( IM->TexCoord[i], IM->Flag, VERT_END_VB, start,
                                  IM->TexCoord[i][start]);
            }
         }
       }
-   }
-
-   if (fixup & VERT_EDGE) {
-      if (orflag & VERT_EDGE)
-        fixup_1ub( IM->EdgeFlag, IM->Flag, start, VERT_EDGE );
-      else
-        fixup_first_1ub( IM->EdgeFlag, IM->Flag, VERT_END_VB, start,
-                         IM->EdgeFlag[start] );
-   }
-
-   if (fixup & VERT_INDEX) {
-      if (orflag & VERT_INDEX)
-        fixup_1ui( IM->Index, IM->Flag, start, VERT_INDEX );
-      else
-        fixup_first_1ui( IM->Index, IM->Flag, VERT_END_VB, start, IM->Index[start] );
-   }
+   
 
-   if (fixup & VERT_RGBA) {
-      if (orflag & VERT_RGBA)
-        fixup_4ub( IM->Color, IM->Flag, start, VERT_RGBA );
-      else
-        fixup_first_4ub( IM->Color, IM->Flag, VERT_END_VB, start, IM->Color[start] );
-   }
+      if (fixup & VERT_EDGE) {
+        if (orflag & VERT_EDGE)
+           _tnl_fixup_1ub( IM->EdgeFlag, IM->Flag, start, VERT_EDGE );
+        else
+           fixup_first_1ub( IM->EdgeFlag, IM->Flag, VERT_END_VB, start,
+                            IM->EdgeFlag[start] );
+      }
 
-   if (fixup & VERT_SPEC_RGB) {
-      if (orflag & VERT_SPEC_RGB)
-        fixup_4ub( IM->SecondaryColor, IM->Flag, start, VERT_SPEC_RGB );
-      else
-        fixup_first_4ub( IM->SecondaryColor, IM->Flag, VERT_END_VB, start,
-                         IM->SecondaryColor[start] );
-   }
+      if (fixup & VERT_INDEX) {
+        if (orflag & VERT_INDEX)
+           _tnl_fixup_1ui( IM->Index, IM->Flag, start, VERT_INDEX );
+        else
+           fixup_first_1ui( IM->Index, IM->Flag, VERT_END_VB, start, 
+                            IM->Index[start] );
+      }
 
-   if (fixup & VERT_FOG_COORD) {
-      if (orflag & VERT_FOG_COORD)
-        fixup_1f( IM->FogCoord, IM->Flag, start, VERT_FOG_COORD );
-      else
-        fixup_first_1f( IM->FogCoord, IM->Flag, VERT_END_VB, start,
-                        IM->FogCoord[start] );
-   }
+      if (fixup & VERT_RGBA) {
+        if (orflag & VERT_RGBA)
+           _tnl_fixup_4f( IM->Color, IM->Flag, start, VERT_RGBA );
+        /* No need for else case as the drivers understand stride
+         * zero here.  (TODO - propogate this)
+         */
+      }
+      
+      if (fixup & VERT_SPEC_RGB) {
+        if (orflag & VERT_SPEC_RGB)
+           _tnl_fixup_4f( IM->SecondaryColor, IM->Flag, start, 
+                          VERT_SPEC_RGB );
+        else
+           fixup_first_4f( IM->SecondaryColor, IM->Flag, VERT_END_VB, start,
+                           IM->SecondaryColor[start] );
+      }
+      
+      if (fixup & VERT_FOG_COORD) {
+        if (orflag & VERT_FOG_COORD)
+           _tnl_fixup_1f( IM->FogCoord, IM->Flag, start, VERT_FOG_COORD );
+        else
+           fixup_first_1f( IM->FogCoord, IM->Flag, VERT_END_VB, start,
+                           IM->FogCoord[start] );
+      }
 
-   if (fixup & VERT_NORM) {
-      if (orflag & VERT_NORM)
-        fixup_3f( IM->Normal, IM->Flag, start, VERT_NORM );
-      else
-        fixup_first_3f( IM->Normal, IM->Flag, VERT_END_VB, start,
-                        IM->Normal[start] );
+      if (fixup & VERT_NORM) {
+        if (orflag & VERT_NORM)
+           _tnl_fixup_3f( IM->Normal, IM->Flag, start, VERT_NORM );
+        else
+           fixup_first_3f( IM->Normal, IM->Flag, VERT_END_VB, start,
+                           IM->Normal[start] );
+      }
    }
-
+      
    /* Prune possible half-filled slot.
     */
    IM->Flag[IM->LastData+1] &= ~VERT_END_VB;
    IM->Flag[IM->Count] |= VERT_END_VB;
 
+
+   /* Materials:
+    */
+   if (IM->MaterialOrMask & ~IM->MaterialAndMask) {
+      GLuint vulnerable = IM->MaterialOrMask;
+      GLuint i = IM->Start;
+
+      do {
+        while (!(IM->Flag[i] & VERT_MATERIAL))
+           i++;
+
+        vulnerable &= ~IM->MaterialMask[i];
+        _mesa_copy_material_pairs( IM->Material[i],
+                                   ctx->Light.Material,
+                                   vulnerable );
+
+
+      } while (vulnerable);
+   }
 }
 
 
@@ -356,11 +359,23 @@ static void copy_material( struct immediate *next,
                                                   IMM_SIZE * 2 );
       next->MaterialMask = (GLuint *) MALLOC( sizeof(GLuint) * IMM_SIZE );
    }
-   
-   next->MaterialMask[dst] = prev->MaterialMask[src];
+
+   next->MaterialMask[dst] = prev->MaterialOrMask;
    MEMCPY(next->Material[dst], prev->Material[src], 2*sizeof(GLmaterial));
 }
 
+static GLboolean is_fan_like[GL_POLYGON+1] = {
+   GL_FALSE,
+   GL_FALSE,
+   GL_TRUE,                    /* line loop */
+   GL_FALSE,
+   GL_FALSE,
+   GL_FALSE,
+   GL_TRUE,                    /* tri fan */
+   GL_FALSE,
+   GL_FALSE,
+   GL_TRUE                     /* polygon */
+};
 
 
 /* Copy the untransformed data from the shared vertices of a primitive
@@ -370,124 +385,123 @@ static void copy_material( struct immediate *next,
  * primitives.
  *
  * Have to be careful with the transitions between display list
- * replay, compile and normal execute modes.  
+ * replay, compile and normal execute modes.
  */
-static void copy_vertices( GLcontext *ctx,
-                          struct immediate *next,
-                          struct immediate *prev,
-                          GLuint count,
-                          GLuint *elts )
+void _tnl_copy_immediate_vertices( GLcontext *ctx, struct immediate *next )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct immediate *prev = tnl->ExecCopySource;
+   struct vertex_arrays *inputs = &tnl->imm_inputs;
+   GLuint count = tnl->ExecCopyCount;
+   GLuint *elts = tnl->ExecCopyElts;
    GLuint offset = IMM_MAX_COPIED_VERTS - count;
    GLuint i;
 
-   next->CopyStart = next->Start - count; 
-
-   /* Copy the vertices
-    */
-   for (i = 0 ; i < count ; i++)
-   {
-      GLuint src = elts[i+offset];
-      GLuint dst = next->CopyStart+i;
+   if (!prev) {
+      ASSERT(tnl->ExecCopyCount == 0);
+      return;
+   }
 
-      COPY_4FV( next->Obj[dst], prev->Obj[src] );
-      COPY_3FV( next->Normal[dst], prev->Normal[src] );      
-      COPY_4UBV( next->Color[dst], prev->Color[src] );
+   next->CopyStart = next->Start - count;
 
-      if (prev->OrFlag & VERT_TEX_ANY) {
-        GLuint i;
-        for (i = 0 ; i < prev->MaxTextureUnits ; i++) {
-           if (prev->OrFlag & VERT_TEX(i))
-              COPY_4FV( next->TexCoord[i][dst], prev->TexCoord[i][src] );
-        }
+   if ((prev->CopyOrFlag & VERT_DATA) == VERT_ELT &&
+       ctx->Array.LockCount &&
+       ctx->Array.Vertex.Enabled)
+   {
+      /* Copy Elt values only
+       */
+      for (i = 0 ; i < count ; i++)
+      {
+        GLuint src = elts[i+offset];
+        GLuint dst = next->CopyStart+i;
+        next->Elt[dst] = prev->Elt[src];
+        next->Flag[dst] = VERT_ELT;
       }
-
-      if (prev->Flag[src] & VERT_MATERIAL)
-        copy_material(next, prev, dst, src);
-
-      next->Elt[dst] = prev->Elt[src];
-      next->EdgeFlag[dst] = prev->EdgeFlag[src];
-      next->Index[dst] = prev->Index[src];
-      COPY_4UBV( next->SecondaryColor[dst], prev->SecondaryColor[src] );
-      next->FogCoord[dst] = prev->FogCoord[src];
-      next->Flag[dst] = (prev->CopyOrFlag & VERT_FIXUP);
-      next->CopyOrFlag |= prev->Flag[src];  /* redundant for current_im */
-      next->CopyAndFlag &= prev->Flag[src]; /* redundant for current_im */
+      next->CopyOrFlag |= VERT_ELT;
+      next->CopyAndFlag &= VERT_ELT;
    }
-   
-   /* Only needed when copying to a compiled cassette
-    */
-   if (next->NormalLengths) {
+   else {
+      /* prev->CopyOrFlag is hacked to include values generated by eval:
+       */
+      GLuint copy = tnl->pipeline.inputs & prev->CopyOrFlag;
+      GLuint flag;
+
+      if (is_fan_like[ctx->Driver.CurrentExecPrimitive]) {
+        next->TexSize |= tnl->ExecCopyTexSize;
+        next->CopyOrFlag |= (prev->CopyOrFlag & VERT_FIXUP);
+        next->CopyAndFlag &= (prev->CopyOrFlag & VERT_FIXUP);
+        flag = (prev->CopyOrFlag & VERT_FIXUP);
+      } 
+      else {
+        /* Don't let an early 'glColor', etc. poison the elt path.
+         */
+        next->CopyAndFlag &= (prev->OrFlag & VERT_FIXUP);
+        flag = (prev->OrFlag & VERT_FIXUP);
+      }
+        
+
+      /* Copy whole vertices
+       */
       for (i = 0 ; i < count ; i++)
       {
         GLuint src = elts[i+offset];
+        GLuint isrc = src - prev->CopyStart;
         GLuint dst = next->CopyStart+i;
 
-        if (prev->NormalLengths) 
-           next->NormalLengths[dst] = prev->NormalLengths[src];
-        else
-           next->NormalLengths[dst] = 1.0/LEN_3FV(prev->Normal[src]);
-      }
-   }
+        /* Values subject to eval must be copied out of the 'inputs'
+         * struct.  (Copied rows should not be evaluated twice).
+         *
+         * Note these pointers are null when inactive.
+         */
+        COPY_4FV( next->Obj[dst], inputs->Obj.data[isrc] );
 
-   ASSERT(prev == tnl->ExecCopySource);
+        if (copy & VERT_NORM) 
+           COPY_3FV( next->Normal[dst], inputs->Normal.data[isrc] );
 
-/*     fprintf(stderr, "%s id %d refcount %d\n", __FUNCTION__,  */
-/*        tnl->ExecCopySource->id, tnl->ExecCopySource->ref_count-1); */
+        if (copy & VERT_RGBA)
+           COPY_4FV( next->Color[dst], 
+                     ((GLfloat (*)[4])inputs->Color.Ptr)[isrc] );
 
-   if (--tnl->ExecCopySource->ref_count == 0)
-      _tnl_free_immediate( tnl->ExecCopySource );
-   
-   next->ref_count++;
-   tnl->ExecCopySource = next;
-/*     fprintf(stderr, "%s id %d refcount %d\n", __FUNCTION__,  */
-/*        next->id, next->ref_count); */
-   tnl->ExecCopyElts[0] = next->Start-3;
-   tnl->ExecCopyElts[1] = next->Start-2;
-   tnl->ExecCopyElts[2] = next->Start-1;
-}
+        if (copy & VERT_INDEX)
+           next->Index[dst] = inputs->Index.data[isrc];
 
-/* Copy vertices to an empty immediate struct.
- */
-void _tnl_copy_immediate_vertices( GLcontext *ctx, struct immediate *IM )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
+        if (copy & VERT_TEX_ANY) {
+           GLuint i;
+           for (i = 0 ; i < prev->MaxTextureUnits ; i++) {
+              if (copy & VERT_TEX(i))
+                 COPY_4FV( next->TexCoord[i][dst], 
+                           inputs->TexCoord[i].data[isrc] );
+           }
+        }
 
-   ASSERT(IM == TNL_CURRENT_IM(ctx));
-   ASSERT(IM->Count == IM->Start);
+        /* Remaining values should be the same in the 'input' struct and the
+         * original immediate.
+         */
+        if (copy & (VERT_ELT|VERT_EDGE|VERT_SPEC_RGB|VERT_FOG_COORD|
+                    VERT_MATERIAL)) {
 
-   /* Need to push this in now as it won't be computed anywhere else/
-    */
-   IM->TexSize = tnl->ExecCopyTexSize;
-   
-   /* A wrapped primitive.  We may be copying into a revived
-    * display list immediate, or onto the front of a new execute-mode
-    * immediate.
-    */
-   copy_vertices( ctx, IM, 
-                 tnl->ExecCopySource, 
-                 tnl->ExecCopyCount,
-                 tnl->ExecCopyElts );
-   
-   if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
-      /* Immediates are built by default to be correct in this state,
-       * and copying to the first slots of an immediate doesn't remove
-       * this property.
-       */
-      ASSERT(tnl->ExecCopyTexSize == 0);
-      ASSERT(tnl->ExecCopyCount == 0);
-      ASSERT(IM->CopyStart == IM->Start);
+           if (prev->Flag[src] & VERT_MATERIAL)
+              copy_material(next, prev, dst, src);
+
+           next->Elt[dst] = prev->Elt[src];
+           next->EdgeFlag[dst] = prev->EdgeFlag[src];
+           COPY_4FV( next->SecondaryColor[dst], prev->SecondaryColor[src] );
+           next->FogCoord[dst] = prev->FogCoord[src];
+        }
+
+        next->Flag[dst] = flag;
+        next->OrFlag |= prev->Flag[src]; /* for non-fanlike prims, 
+                                            otherwise redundant */
+      }
    }
 
-   /* Copy the primitive information: 
-    */
-   IM->Primitive[IM->CopyStart] = (ctx->Driver.CurrentExecPrimitive | PRIM_LAST);
-   IM->LastPrimitive = IM->CopyStart;
-   if (tnl->ExecParity)
-      IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
+   if (--tnl->ExecCopySource->ref_count == 0)
+      _tnl_free_immediate( tnl->ExecCopySource );
+
+   tnl->ExecCopySource = 0;
+   tnl->ExecCopyCount = 0;
 }
-                        
+
 
 /* Revive a compiled immediate struct - propogate new 'Current'
  * values.  Often this is redundant because the current values were
@@ -503,21 +517,24 @@ void _tnl_fixup_compiled_cassette( GLcontext *ctx, struct immediate *IM )
    if (count == start)
       return;
 
-   IM->CopyOrFlag = IM->OrFlag;          /* redundant for current_im */
-   IM->CopyAndFlag = IM->AndFlag; /* redundant for current_im */
+   IM->CopyOrFlag = IM->OrFlag;          
+   IM->CopyAndFlag = IM->AndFlag; 
    IM->CopyTexSize = IM->TexSize | tnl->ExecCopyTexSize;
 
-   copy_vertices( ctx, IM, 
-                 tnl->ExecCopySource, 
-                 tnl->ExecCopyCount,
-                 tnl->ExecCopyElts );
+   _tnl_copy_immediate_vertices( ctx, IM );
 
    if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
-      ASSERT(tnl->ExecCopyTexSize == 0);
-      ASSERT(tnl->ExecCopyCount == 0);
       ASSERT(IM->CopyStart == IM->Start);
    }
 
+   /* Naked array elements can be copied into the first cassette in a
+    * display list.  Need to translate them away:
+    */
+   if (IM->CopyOrFlag & VERT_ELT) {
+      ASSERT(IM->CopyStart < IM->Start);
+      _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->Start );
+   }
+
    fixup = tnl->pipeline.inputs & ~IM->Flag[start] & VERT_FIXUP;
 
    if (fixup) {
@@ -539,12 +556,13 @@ void _tnl_fixup_compiled_cassette( GLcontext *ctx, struct immediate *IM )
                         ctx->Current.Index );
 
       if (fixup & VERT_RGBA)
-        fixup_first_4ub(IM->Color, IM->Flag, VERT_RGBA, start,
-                        ctx->Current.Color );
+        if (IM->CopyOrFlag & VERT_RGBA)
+           fixup_first_4f(IM->Color, IM->Flag, VERT_RGBA, start,
+                          ctx->Current.Color );
 
       if (fixup & VERT_SPEC_RGB)
-        fixup_first_4ub(IM->SecondaryColor, IM->Flag, VERT_SPEC_RGB, start,
-                        ctx->Current.SecondaryColor );
+        fixup_first_4f(IM->SecondaryColor, IM->Flag, VERT_SPEC_RGB, start,
+                       ctx->Current.SecondaryColor );
 
       if (fixup & VERT_FOG_COORD)
         fixup_first_1f(IM->FogCoord, IM->Flag, VERT_FOG_COORD, start,
@@ -553,103 +571,33 @@ void _tnl_fixup_compiled_cassette( GLcontext *ctx, struct immediate *IM )
       if (fixup & VERT_NORM) {
         fixup_first_3f(IM->Normal, IM->Flag, VERT_NORM, start,
                        ctx->Current.Normal );
-        if (IM->NormalLengths)
-           fixup_first_1f(IM->NormalLengths, IM->Flag, VERT_NORM, start,
-                          1.0F / (GLfloat) LEN_3FV(ctx->Current.Normal) );
       }
    }
 
-
-   /* Can potentially overwrite primitive details - need to save the
-    * first slot: 
+   /* Materials:
     */
-   tnl->DlistPrimitive = IM->Primitive[IM->Start];
-   tnl->DlistPrimitiveLength = IM->PrimitiveLength[IM->Start];
-   tnl->DlistLastPrimitive = IM->LastPrimitive;
-
-   /* The first primitive may be different from what was recorded in
-    * the immediate struct.  Consider an immediate that starts with a
-    * glBegin, compiled in a display list, which is called from within
-    * an existing Begin/End object.
-    */
-   if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
-      GLuint i;
+   if (IM->MaterialOrMask & ~IM->MaterialAndMask) {
+      GLuint vulnerable = IM->MaterialOrMask;
+      GLuint i = IM->Start;
 
-      if (IM->BeginState & VERT_ERROR_1) 
-        gl_error( ctx, GL_INVALID_OPERATION, "begin/end");
+      do {
+        while (!(IM->Flag[i] & VERT_MATERIAL))
+           i++;
 
-      for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
-        if (IM->Flag[i] & (VERT_BEGIN|VERT_END_VB)) 
-           break;
+        vulnerable &= ~IM->MaterialMask[i];
+        _mesa_copy_material_pairs( IM->Material[i],
+                                   ctx->Light.Material,
+                                   vulnerable );
 
-      /* Would like to just ignore vertices upto this point.  Can't
-       * set copystart because it might skip materials? 
-       */
-      ASSERT(IM->Start == IM->CopyStart);
-      if (i > IM->CopyStart) {
-        IM->Primitive[IM->CopyStart] = GL_POLYGON+1;
-        IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
-        if (IM->Flag[i] & VERT_END_VB) {
-           IM->Primitive[IM->CopyStart] |= PRIM_LAST;
-           IM->LastPrimitive = IM->CopyStart;
-        }
-      }
-      /* Shouldn't immediates be set up to have this structure *by default*?
-       */
-   } else {
-      GLuint i;
 
-      if (IM->BeginState & VERT_ERROR_0) 
-        gl_error( ctx, GL_INVALID_OPERATION, "begin/end");
-      
-      if (IM->CopyStart == IM->Start &&
-         IM->Flag[IM->Start] & (VERT_END|VERT_END_VB))
-      {
-      }
-      else 
-      {
-        IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
-        if (tnl->ExecParity) 
-           IM->Primitive[IM->CopyStart] |= PRIM_PARITY;      
-      
-      
-        for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
-           if (IM->Flag[i] & (VERT_END|VERT_END_VB)) {
-              IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
-              if (IM->Flag[i] & VERT_END_VB) {
-                 IM->Primitive[IM->CopyStart] |= PRIM_LAST;        
-                 IM->LastPrimitive = IM->CopyStart;
-              }
-              if (IM->Flag[i] & VERT_END) {
-                 IM->Primitive[IM->CopyStart] |= PRIM_END;
-              }
-              break;
-           }
-      }
+      } while (vulnerable);
    }
-
-   if (IM->Primitive[IM->LastPrimitive] & PRIM_END)
-      ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
-   else
-      ctx->Driver.CurrentExecPrimitive = 
-        IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK;
 }
 
 
-/* Undo any changes potentially made to the immediate in the range
- * IM->Start..IM->Count above.
- */
-void _tnl_restore_compiled_cassette( GLcontext *ctx, struct immediate *IM )
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   IM->Primitive[IM->Start] = tnl->DlistPrimitive;
-   IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength;
-}
 
 
-                        
 
-                        
 
 static void copy_none( TNLcontext *tnl, GLuint start, GLuint count, GLuint ovf)
 {
@@ -715,13 +663,11 @@ static copy_func copy_tab[GL_POLYGON+2] =
 
 
 
-/* Figure out what vertices need to be copied next time. 
+/* Figure out what vertices need to be copied next time.
  */
 void
 _tnl_get_exec_copy_verts( GLcontext *ctx, struct immediate *IM )
 {
-   static const GLuint increment[GL_POLYGON+2] = { 1,2,1,1,3,1,1,4,2,1,1 };
-   static const GLuint intro[GL_POLYGON+2]     = { 0,0,2,2,0,2,2,0,2,2,0 };
 
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    GLuint last = IM->LastPrimitive;
@@ -729,93 +675,91 @@ _tnl_get_exec_copy_verts( GLcontext *ctx, struct immediate *IM )
    GLuint pincr = increment[prim];
    GLuint pintro = intro[prim];
    GLuint ovf = 0;
-   
 
-   if (tnl->ExecCopySource != IM) {
-/*        fprintf(stderr, "%s id %d refcount %d\n", __FUNCTION__,  */
-/*           tnl->ExecCopySource->id, tnl->ExecCopySource->ref_count-1); */
-      if (--tnl->ExecCopySource->ref_count == 0)
-        _tnl_free_immediate( tnl->ExecCopySource );
-      IM->ref_count++;
-      tnl->ExecCopySource = IM;
-/*        fprintf(stderr, "%s id %d refcount %d\n", __FUNCTION__,  */
-/*           tnl->ExecCopySource->id, tnl->ExecCopySource->ref_count); */
-   }
+/*     fprintf(stderr, "_tnl_get_exec_copy_verts %s\n",  */
+/*        _mesa_lookup_enum_by_nr(prim)); */
+
+   ASSERT(tnl->ExecCopySource == 0);
 
    if (prim == GL_POLYGON+1) {
       tnl->ExecCopyCount = 0;
       tnl->ExecCopyTexSize = 0;
       tnl->ExecParity = 0;
    } else {
+      /* Remember this immediate as the one to copy from.
+       */
+      IM->ref_count++;
+      tnl->ExecCopySource = IM;
       tnl->ExecCopyCount = 0;
       tnl->ExecCopyTexSize = IM->CopyTexSize;
       tnl->ExecParity = IM->PrimitiveLength[IM->LastPrimitive] & 1;
 
       if (pincr != 1 && (IM->Count - last - pintro))
         ovf = (IM->Count - last - pintro) % pincr;
-   
+
       if (last < IM->Count)
         copy_tab[prim]( tnl, last, IM->Count, ovf );
    }
 }
 
 
-/* If we receive evalcoords in an immediate struct for maps which
- * don't have a vertex enabled, need to do an additional fixup, as
- * those rows containing evalcoords must now be ignored.  The
- * evalcoords may still generate colors, normals, etc, so have to
- * respect the relative order between calls to EvalCoord and Normal
- * etc.
- *
- * Generate the index list that will be used to render this immediate
- * struct.  
- *
- * Finally, generate a new primitives list for rendering the indices.
+/* Recalculate ExecCopyElts, ExecParity, etc.  
  */
-#if 0
-void _tnl_fixup_purged_eval( GLcontext *ctx,
-                            GLuint fixup, GLuint purge )
+void 
+_tnl_get_purged_copy_verts( GLcontext *ctx, struct immediate *IM ) 
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct tnl_eval_store *store = &tnl->eval;
-   GLuint *flags = tnl->vb.Flag;
-   GLuint i, j, nextprim;
-   GLuint fixup_fence = purge|VERT_OBJ;
-   GLuint good_index = (VERT_EVAL_ANY & ~purge)|VERT_OBJ;
-   GLuint prim_length = 0, lastprim = 0, nextprim = 0;
 
-   if (fixup & VERT_TEX0) 
-      fixup_4f( store->TexCoord, flags, 0, VERT_TEX0|fixup_fence );
+   if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+      GLuint last = IM->LastPrimitive;
+      GLenum prim = IM->Primitive[last];
+      GLuint pincr = increment[prim];
+      GLuint pintro = intro[prim];
+      GLuint ovf = 0, i;
 
-   if (fixup & VERT_INDEX) 
-      fixup_1ui( store->Index, flags, 0, VERT_INDEX|fixup_fence );
+      tnl->ExecCopyCount = 0;
+      tnl->ExecParity = IM->PrimitiveLength[last] & 1;
 
-   if (fixup & VERT_RGBA) 
-      fixup_4ub( store->Color, flags, 0, VERT_RGBA|fixup_fence );
+      if (pincr != 1 && (IM->Count - last - pintro))
+        ovf = (IM->Count - last - pintro) % pincr;
 
-   if (fixup & VERT_NORM) 
-      fixup_3f( store->Normal, flags, 0, VERT_NORM|fixup_fence );
+      if (last < IM->Count)
+        copy_tab[prim]( tnl, last, IM->Count, ovf );
 
-   for (i = 0, j = 0 ; i < tnl->vb.Count ; i++) {
-      if (flags[i] & good_index) {
-        store->Elts[j++] = i;
-        prim_length++;
-      }
-      if (i == nextprim) {
-        VB->PrimitiveLength[lastprim] = prim_length;
-        VB->Primitive[j] = VB->Primitive[i];
-        nextprim += lastprimlen;
-        lastprim = i;
-        lastprimlen = VB->PrimitiveLength[i];
-      }
+      for (i = 0 ; i < tnl->ExecCopyCount ; i++)
+        tnl->ExecCopyElts[i] = IM->Elt[tnl->ExecCopyElts[i]];
    }
-   VB->Elts = store->Elts;
+}
 
-   /* What about copying???  No immediate exists with the right
-    * vertices in place...
-    */
-   if (tnl->CurrentPrimitive != GL_POLYGON+1) {
+
+void _tnl_upgrade_current_data( GLcontext *ctx,
+                               GLuint required,
+                               GLuint flags )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct vertex_buffer *VB = &tnl->vb;
+   struct immediate *IM = (struct immediate *)VB->import_source;
+
+   ASSERT(IM);
+
+/*     _tnl_print_vert_flags("_tnl_upgrade_client_data", required); */
+
+   if ((required & VERT_RGBA) && (VB->ColorPtr[0]->Flags & CA_CLIENT_DATA)) {
+      struct gl_client_array *tmp = &tnl->imm_inputs.Color;
+      GLuint start = IM->CopyStart;
+
+      tmp->Ptr = IM->Color + start;
+      tmp->StrideB = 4 * sizeof(GLfloat);
+      tmp->Flags = 0;
+
+      COPY_4FV( IM->Color[start], ctx->Current.Color);   
+
+      ASSERT(IM->Flag[IM->LastData+1] & VERT_END_VB);
+
+      fixup_first_4f( IM->Color, IM->Flag, VERT_END_VB, start, 
+                     IM->Color[start] );
+
+      VB->importable_data &= ~VERT_RGBA;
    }
 }
-#endif