-/* $Id: t_imm_dlist.c,v 1.10 2001/03/03 20:33:31 brianp Exp $ */
+/* $Id: t_imm_dlist.c,v 1.43 2002/10/24 23:57:25 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 3.5
- *
- * Copyright (C) 1999 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"),
* 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
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
- * Author:
- * Keith Whitwell <keithw@valinux.com>
+ * Authors:
+ * Keith Whitwell <keithw@valinux.com>
*/
#include "dlist.h"
#include "debug.h"
#include "mmath.h"
-#include "mem.h"
+#include "imports.h"
#include "state.h"
#include "t_context.h"
GLuint LastPrimitive;
GLuint LastMaterial;
GLuint MaterialOrMask;
+ GLuint MaterialAndMask;
} TNLvertexcassette;
static void execute_compiled_cassette( GLcontext *ctx, void *data );
+static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM );
+
+
+static void build_normal_lengths( struct immediate *IM )
+{
+ GLuint i;
+ GLfloat len;
+ GLfloat (*data)[4] = IM->Attrib[VERT_ATTRIB_NORMAL] + IM->Start;
+ GLfloat *dest = IM->NormalLengthPtr;
+ GLuint *flags = IM->Flag + IM->Start;
+ GLuint count = IM->Count - IM->Start;
+
+ if (!dest) {
+ dest = IM->NormalLengthPtr = (GLfloat *) ALIGN_MALLOC( IMM_SIZE*sizeof(GLfloat), 32 );
+ if (!dest) return;
+ }
+ dest += IM->Start;
+
+ len = (GLfloat) LEN_3FV( data[0] );
+ if (len > 0.0F) len = 1.0F / len;
+
+ for (i = 0 ; i < count ; ) {
+ dest[i] = len;
+ if (flags[++i] & VERT_BIT_NORMAL) {
+ len = (GLfloat) LEN_3FV( data[i] );
+ if (len > 0.0F) len = 1.0F / len;
+ }
+ }
+}
+
+static void fixup_normal_lengths( struct immediate *IM )
+{
+ GLuint i;
+ GLfloat len = 1.0F; /* just to silence warnings */
+ GLfloat (*data)[4] = IM->Attrib[VERT_ATTRIB_NORMAL];
+ GLfloat *dest = IM->NormalLengthPtr;
+ GLuint *flags = IM->Flag;
+
+ for (i = IM->CopyStart ; i <= IM->Start ; i++) {
+ len = (GLfloat) LEN_3FV( data[i] );
+ if (len > 0.0F) len = 1.0F / len;
+ dest[i] = len;
+ }
+
+ if (i < IM->Count) {
+ while (!(flags[i] & (VERT_BIT_NORMAL|VERT_BIT_END_VB))) {
+ dest[i] = len;
+ i++;
+ }
+ }
+}
+
/* Insert the active immediate struct onto the display list currently
* being built.
*/
-void
+void
_tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
{
struct immediate *im = TNL_CURRENT_IM(ctx);
TNLvertexcassette *node;
GLuint new_beginstate;
+ if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST)
+ _mesa_debug(ctx, "_tnl_compiled_cassette IM: %d\n", IM->id);
- _tnl_compute_orflag( IM );
-
- IM->CopyStart = IM->Start;
-
- if (IM->OrFlag & VERT_ELT) {
- GLuint andflag = ~0;
- GLuint i;
- GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
- _tnl_translate_array_elts( ctx, IM, start, IM->Count );
-
- /* Need to recompute andflag.
- */
- if (IM->AndFlag & VERT_ELT)
- IM->CopyAndFlag = IM->AndFlag |= ctx->Array._Enabled;
- else {
- for (i = IM->CopyStart ; i < IM->Count ; i++)
- andflag &= IM->Flag[i];
- IM->CopyAndFlag = IM->AndFlag = andflag;
- }
+ if (IM->FlushElt) {
+ ASSERT (IM->FlushElt == FLUSH_ELT_LAZY);
+ _tnl_translate_array_elts( ctx, IM, IM->Start, IM->Count );
}
- _tnl_fixup_input( ctx, IM );
+ _tnl_compute_orflag( IM, IM->Start );
- /* Mark the last primitive:
+ /* Need to clear this flag, or fixup gets confused. (The
+ * array-elements have been translated away by now, so it's ok to
+ * remove it.)
*/
- IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive;
- ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
+ IM->OrFlag &= ~VERT_BIT_ELT;
+ IM->AndFlag &= ~VERT_BIT_ELT;
-
- node = (TNLvertexcassette *)
- _mesa_alloc_instruction(ctx,
+ _tnl_fixup_input( ctx, IM );
+
+ node = (TNLvertexcassette *)
+ _mesa_alloc_instruction(ctx,
tnl->opcode_vertex_cassette,
sizeof(TNLvertexcassette));
- if (!node)
+ if (!node)
return;
-
+
node->IM = im; im->ref_count++;
node->Start = im->Start;
node->Count = im->Count;
node->LastPrimitive = im->LastPrimitive;
node->LastMaterial = im->LastMaterial;
node->MaterialOrMask = im->MaterialOrMask;
+ node->MaterialAndMask = im->MaterialAndMask;
+
+ if (tnl->CalcDListNormalLengths) {
+ build_normal_lengths( im );
+ }
if (ctx->ExecuteFlag) {
execute_compiled_cassette( ctx, (void *)node );
}
-
-
+
/* Discard any errors raised in the last cassette.
*/
new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
if (im->Count > IMM_MAXDATA - 16) {
/* Call it full...
*/
- struct immediate *new_im = _tnl_alloc_immediate(ctx);
- if (!new_im) return;
+ struct immediate *new_im = _tnl_alloc_immediate(ctx);
new_im->ref_count++;
- im->ref_count--; /* remove CURRENT_IM reference */
- ASSERT(im->ref_count > 0);
+ im->ref_count--; /* remove CURRENT_IM reference */
+ ASSERT(im->ref_count > 0); /* it is compiled into a display list */
SET_IMMEDIATE( ctx, new_im );
- _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS,
- new_beginstate, node->SavedBeginState );
+ _tnl_reset_compile_input( ctx, IMM_MAX_COPIED_VERTS,
+ new_beginstate, node->SavedBeginState );
} else {
/* Still some room in the current immediate.
*/
- _tnl_reset_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
+ _tnl_reset_compile_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
new_beginstate, node->SavedBeginState);
- }
+ }
}
-static void
+static void fixup_compiled_primitives( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* Can potentially overwrite primitive details - need to save the
+ * first slot:
+ */
+ 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->BeginState & VERT_ERROR_1)
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
+
+ for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
+ if (IM->Flag[i] & (VERT_BIT_BEGIN|VERT_BIT_END_VB))
+ break;
+
+ /* 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->Flag[IM->Start] & VERT_BIT_BEGIN)) {
+ IM->Primitive[IM->CopyStart] = GL_POLYGON+1;
+ IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
+ if (IM->Flag[i] & VERT_BIT_END_VB) {
+ IM->Primitive[IM->CopyStart] |= PRIM_LAST;
+ IM->LastPrimitive = IM->CopyStart;
+ }
+ }
+ } else {
+ GLuint i;
+
+ if (IM->BeginState & VERT_ERROR_0)
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
+
+ if (IM->CopyStart == IM->Start &&
+ IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB))
+ {
+ }
+ else
+ {
+ IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
+ if (tnl->ExecParity)
+ IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
+
+ /* one of these should be true, else we'll be in an infinite loop
+ */
+ ASSERT(IM->PrimitiveLength[IM->Start] > 0 ||
+ IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB));
+
+ for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
+ if (IM->Flag[i] & (VERT_BIT_END | VERT_BIT_END_VB)) {
+ IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
+ if (IM->Flag[i] & VERT_BIT_END_VB) {
+ IM->Primitive[IM->CopyStart] |= PRIM_LAST;
+ IM->LastPrimitive = IM->CopyStart;
+ }
+ if (IM->Flag[i] & VERT_BIT_END) {
+ IM->Primitive[IM->CopyStart] |= PRIM_END;
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* Undo any changes potentially made to the immediate in the range
+ * IM->Start..IM->Count above.
+ */
+static void restore_compiled_primitives( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ IM->Primitive[IM->Start] = tnl->DlistPrimitive;
+ IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength;
+}
+
+
+
+static void
execute_compiled_cassette( GLcontext *ctx, void *data )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
TNLvertexcassette *node = (TNLvertexcassette *)data;
struct immediate *IM = node->IM;
- if (ctx->NewState)
- _mesa_update_state(ctx);
+/* _mesa_debug("%s\n", __FUNCTION__); */
- if (tnl->pipeline.build_state_changes)
- _tnl_validate_pipeline( ctx );
-
IM->Start = node->Start;
IM->CopyStart = node->Start;
IM->Count = node->Count;
IM->BeginState = node->BeginState;
- IM->SavedBeginState = node->SavedBeginState;
+ IM->SavedBeginState = node->SavedBeginState;
IM->OrFlag = node->OrFlag;
- IM->TexSize = node->TexSize;
+ IM->TexSize = node->TexSize;
IM->AndFlag = node->AndFlag;
IM->LastData = node->LastData;
IM->LastPrimitive = node->LastPrimitive;
IM->LastMaterial = node->LastMaterial;
IM->MaterialOrMask = node->MaterialOrMask;
+ IM->MaterialAndMask = node->MaterialAndMask;
if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
(MESA_VERBOSE & VERBOSE_IMMEDIATE))
_tnl_print_cassette( IM );
if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
- fprintf(stderr, "Run cassette %d, rows %d..%d, beginstate %x ",
- IM->id,
- IM->Start, IM->Count, IM->BeginState);
+ _mesa_debug(ctx, "Run cassette %d, rows %d..%d, beginstate %x ",
+ IM->id, IM->Start, IM->Count, IM->BeginState);
_tnl_print_vert_flags("orflag", IM->OrFlag);
}
- if (IM->Count == IM->Start) {
- _tnl_copy_to_current( ctx, IM, IM->OrFlag );
- return;
- }
+ /* Need to respect 'HardBeginEnd' even if the commands are looped
+ * back to a driver tnl module.
+ */
if (IM->SavedBeginState) {
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
tnl->ReplayHardBeginEnd = 1;
}
}
- _tnl_fixup_compiled_cassette( ctx, IM );
- _tnl_get_exec_copy_verts( ctx, IM );
- _tnl_run_cassette( ctx, IM );
- _tnl_restore_compiled_cassette( ctx, IM );
+ if (tnl->LoopbackDListCassettes) {
+/* (tnl->IsolateMaterials && (IM->OrFlag & VERT_MATERIAL)) ) { */
+ fixup_compiled_primitives( ctx, IM );
+ loopback_compiled_cassette( ctx, IM );
+ restore_compiled_primitives( ctx, IM );
+ }
+ else {
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ _tnl_fixup_compiled_cassette( ctx, IM );
+ fixup_compiled_primitives( ctx, IM );
+
+ if (IM->Primitive[IM->LastPrimitive] & PRIM_END)
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+ else if ((IM->Primitive[IM->LastPrimitive] & PRIM_BEGIN) ||
+ (IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK) ==
+ PRIM_OUTSIDE_BEGIN_END) {
+ ctx->Driver.CurrentExecPrimitive =
+ IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK;
+ }
+
+ _tnl_get_exec_copy_verts( ctx, IM );
+
+ if (IM->NormalLengthPtr)
+ fixup_normal_lengths( IM );
+
+ if (IM->Count == IM->Start)
+ _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
+ else {
+/* _tnl_print_cassette( IM ); */
+ _tnl_run_cassette( ctx, IM );
+ }
+
+ restore_compiled_primitives( ctx, IM );
+ }
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
tnl->ReplayHardBeginEnd = 0;
TNLvertexcassette *node = (TNLvertexcassette *)data;
if ( --node->IM->ref_count == 0 )
- _tnl_free_immediate( node->IM );
+ _tnl_free_immediate( ctx, node->IM );
}
-static void
+static void
print_compiled_cassette( GLcontext *ctx, void *data )
{
TNLvertexcassette *node = (TNLvertexcassette *)data;
struct immediate *IM = node->IM;
- fprintf(stderr, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
- node->IM->id, node->Start, node->Count);
+ _mesa_debug(ctx, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
+ node->IM->id, node->Start, node->Count);
IM->Start = node->Start;
+ IM->CopyStart = node->Start;
IM->Count = node->Count;
IM->BeginState = node->BeginState;
IM->OrFlag = node->OrFlag;
IM->LastPrimitive = node->LastPrimitive;
IM->LastMaterial = node->LastMaterial;
IM->MaterialOrMask = node->MaterialOrMask;
+ IM->MaterialAndMask = node->MaterialAndMask;
_tnl_print_cassette( node->IM );
}
}
-/* Called at the tail of a CallList. Copy vertices out of the display
- * list if necessary.
+/* Called at the tail of a CallList. Make current immediate aware of
+ * any new to-be-copied vertices.
*/
void
_tnl_EndCallList( GLcontext *ctx )
{
- /* May have to copy vertices from a dangling begin/end inside the
- * list to the current immediate.
- */
- if (ctx->CallDepth == 0) {
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct immediate *IM = TNL_CURRENT_IM(ctx);
+ GLuint beginstate = 0;
- if (tnl->ExecCopySource != IM)
- _tnl_copy_immediate_vertices( ctx, IM );
- }
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
+ beginstate = VERT_BEGIN_0|VERT_BEGIN_1;
+
+ _tnl_reset_exec_input( ctx, TNL_CURRENT_IM(ctx)->Start, beginstate, 0 );
}
-void
+void
_tnl_EndList( GLcontext *ctx )
{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
struct immediate *IM = TNL_CURRENT_IM(ctx);
ctx->swtnl_im = 0;
IM->ref_count--;
- if (IM == tnl->ExecCopySource) {
- IM->ref_count--;
- } else {
- if ( --tnl->ExecCopySource->ref_count == 0 )
- _tnl_free_immediate( tnl->ExecCopySource );
- }
+
+ /* outside begin/end, even in COMPILE_AND_EXEC,
+ * so no vertices to copy, right?
+ */
+ ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
/* If this one isn't free, get a clean one. (Otherwise we'll be
* using one that's already half full).
ASSERT(IM->ref_count == 0);
- tnl->ExecCopySource = IM;
- IM->ref_count++;
-
SET_IMMEDIATE( ctx, IM );
IM->ref_count++;
- _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
-
- /* outside begin/end, even in COMPILE_AND_EXEC,
- * so no vertices to copy, right?
- */
- ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
+ _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
}
-void
+void
_tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
{
struct immediate *IM = TNL_CURRENT_IM(ctx);
}
-void
+void
_tnl_dlist_init( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
- tnl->opcode_vertex_cassette =
+ tnl->opcode_vertex_cassette =
_mesa_alloc_opcode( ctx,
sizeof(TNLvertexcassette),
execute_compiled_cassette,
print_compiled_cassette );
}
+
+static void emit_material( struct gl_material *src, GLuint bitmask )
+{
+ if (bitmask & FRONT_EMISSION_BIT)
+ glMaterialfv( GL_FRONT, GL_EMISSION, src[0].Emission );
+
+ if (bitmask & BACK_EMISSION_BIT)
+ glMaterialfv( GL_BACK, GL_EMISSION, src[1].Emission );
+
+ if (bitmask & FRONT_AMBIENT_BIT)
+ glMaterialfv( GL_FRONT, GL_AMBIENT, src[0].Ambient );
+
+ if (bitmask & BACK_AMBIENT_BIT)
+ glMaterialfv( GL_BACK, GL_AMBIENT, src[1].Ambient );
+
+ if (bitmask & FRONT_DIFFUSE_BIT)
+ glMaterialfv( GL_FRONT, GL_DIFFUSE, src[0].Diffuse );
+
+ if (bitmask & BACK_DIFFUSE_BIT)
+ glMaterialfv( GL_BACK, GL_DIFFUSE, src[1].Diffuse );
+
+ if (bitmask & FRONT_SPECULAR_BIT)
+ glMaterialfv( GL_FRONT, GL_SPECULAR, src[0].Specular );
+
+ if (bitmask & BACK_SPECULAR_BIT)
+ glMaterialfv( GL_BACK, GL_SPECULAR, src[1].Specular );
+
+ if (bitmask & FRONT_SHININESS_BIT)
+ glMaterialfv( GL_FRONT, GL_SHININESS, &src[0].Shininess );
+
+ if (bitmask & BACK_SHININESS_BIT)
+ glMaterialfv( GL_BACK, GL_SHININESS, &src[1].Shininess );
+
+ if (bitmask & FRONT_INDEXES_BIT) {
+ GLfloat ind[3];
+ ind[0] = src[0].AmbientIndex;
+ ind[1] = src[0].DiffuseIndex;
+ ind[2] = src[0].SpecularIndex;
+ glMaterialfv( GL_FRONT, GL_COLOR_INDEXES, ind );
+ }
+
+ if (bitmask & BACK_INDEXES_BIT) {
+ GLfloat ind[3];
+ ind[0] = src[1].AmbientIndex;
+ ind[1] = src[1].DiffuseIndex;
+ ind[2] = src[1].SpecularIndex;
+ glMaterialfv( GL_BACK, GL_COLOR_INDEXES, ind );
+ }
+}
+
+
+/* Low-performance helper function to allow driver-supplied tnl
+ * modules to process tnl display lists. This is primarily supplied
+ * to avoid fallbacks if CallList is invoked inside a Begin/End pair.
+ * For higher performance, drivers should fallback to tnl (if outside
+ * begin/end), or (for tnl hardware) implement their own display list
+ * mechanism.
+ */
+static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ GLuint i;
+ GLuint *flags = IM->Flag;
+ GLuint orflag = IM->OrFlag;
+ GLuint j;
+ void (GLAPIENTRY *vertex)( const GLfloat * );
+ void (GLAPIENTRY *texcoordfv[MAX_TEXTURE_UNITS])( GLenum, const GLfloat * );
+ GLuint maxtex = 0;
+ GLuint p, length, prim = 0;
+
+ if (orflag & VERT_BITS_OBJ_234)
+ vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex4fv;
+ else
+ vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex3fv;
+
+ if (orflag & VERT_BITS_TEX_ANY) {
+ for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) {
+ if (orflag & VERT_BIT_TEX(j)) {
+ maxtex = j+1;
+ if ((IM->TexSize & TEX_SIZE_4(j)) == TEX_SIZE_4(j))
+ texcoordfv[j] = glMultiTexCoord4fvARB;
+ else if (IM->TexSize & TEX_SIZE_3(j))
+ texcoordfv[j] = glMultiTexCoord3fvARB;
+ else
+ texcoordfv[j] = glMultiTexCoord2fvARB;
+ }
+ }
+ }
+
+ for (p = IM->Start ; !(prim & PRIM_LAST) ; p += length)
+ {
+ prim = IM->Primitive[p];
+ length= IM->PrimitiveLength[p];
+ ASSERT(length || (prim & PRIM_LAST));
+ ASSERT((prim & PRIM_MODE_MASK) <= GL_POLYGON+1);
+
+ if (prim & PRIM_BEGIN) {
+ glBegin(prim & PRIM_MODE_MASK);
+ }
+
+ for ( i = p ; i <= p+length ; i++) {
+ if (flags[i] & VERT_BITS_TEX_ANY) {
+ GLuint k;
+ for (k = 0 ; k < maxtex ; k++) {
+ if (flags[i] & VERT_BIT_TEX(k)) {
+ texcoordfv[k]( GL_TEXTURE0_ARB + k,
+ IM->Attrib[VERT_ATTRIB_TEX0 + k][i] );
+ }
+ }
+ }
+
+ if (flags[i] & VERT_BIT_NORMAL)
+ glNormal3fv(IM->Attrib[VERT_ATTRIB_NORMAL][i]);
+
+ if (flags[i] & VERT_BIT_COLOR0)
+ glColor4fv( IM->Attrib[VERT_ATTRIB_COLOR0][i] );
+
+ if (flags[i] & VERT_BIT_COLOR1)
+ _glapi_Dispatch->SecondaryColor3fvEXT( IM->Attrib[VERT_ATTRIB_COLOR1][i] );
+
+ if (flags[i] & VERT_BIT_FOG)
+ _glapi_Dispatch->FogCoordfEXT( IM->Attrib[VERT_ATTRIB_FOG][i][0] );
+
+ if (flags[i] & VERT_BIT_INDEX)
+ glIndexi( IM->Index[i] );
+
+ if (flags[i] & VERT_BIT_EDGEFLAG)
+ glEdgeFlag( IM->EdgeFlag[i] );
+
+ if (flags[i] & VERT_BIT_MATERIAL)
+ emit_material( IM->Material[i], IM->MaterialMask[i] );
+
+ if (flags[i]&VERT_BITS_OBJ_234)
+ vertex( IM->Attrib[VERT_ATTRIB_POS][i] );
+ else if (flags[i] & VERT_BIT_EVAL_C1)
+ glEvalCoord1f( IM->Attrib[VERT_ATTRIB_POS][i][0] );
+ else if (flags[i] & VERT_BIT_EVAL_P1)
+ glEvalPoint1( (GLint) IM->Attrib[VERT_ATTRIB_POS][i][0] );
+ else if (flags[i] & VERT_BIT_EVAL_C2)
+ glEvalCoord2f( IM->Attrib[VERT_ATTRIB_POS][i][0],
+ IM->Attrib[VERT_ATTRIB_POS][i][1] );
+ else if (flags[i] & VERT_BIT_EVAL_P2)
+ glEvalPoint2( (GLint) IM->Attrib[VERT_ATTRIB_POS][i][0],
+ (GLint) IM->Attrib[VERT_ATTRIB_POS][i][1] );
+ }
+
+ if (prim & PRIM_END) {
+ glEnd();
+ }
+ }
+}