1 /* $Id: t_imm_dlist.c,v 1.44 2002/10/29 20:29:02 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Keith Whitwell <keith@tungstengraphics.com>
39 #include "t_context.h"
40 #include "t_imm_api.h"
41 #include "t_imm_elt.h"
42 #include "t_imm_alloc.h"
43 #include "t_imm_dlist.h"
44 #include "t_imm_debug.h"
45 #include "t_imm_exec.h"
46 #include "t_imm_fixup.h"
47 #include "t_pipeline.h"
54 GLuint SavedBeginState
;
61 GLuint MaterialOrMask
;
62 GLuint MaterialAndMask
;
65 static void execute_compiled_cassette( GLcontext
*ctx
, void *data
);
66 static void loopback_compiled_cassette( GLcontext
*ctx
, struct immediate
*IM
);
69 static void build_normal_lengths( struct immediate
*IM
)
73 GLfloat (*data
)[4] = IM
->Attrib
[VERT_ATTRIB_NORMAL
] + IM
->Start
;
74 GLfloat
*dest
= IM
->NormalLengthPtr
;
75 GLuint
*flags
= IM
->Flag
+ IM
->Start
;
76 GLuint count
= IM
->Count
- IM
->Start
;
79 dest
= IM
->NormalLengthPtr
= (GLfloat
*) ALIGN_MALLOC( IMM_SIZE
*sizeof(GLfloat
), 32 );
84 len
= (GLfloat
) LEN_3FV( data
[0] );
85 if (len
> 0.0F
) len
= 1.0F
/ len
;
87 for (i
= 0 ; i
< count
; ) {
89 if (flags
[++i
] & VERT_BIT_NORMAL
) {
90 len
= (GLfloat
) LEN_3FV( data
[i
] );
91 if (len
> 0.0F
) len
= 1.0F
/ len
;
96 static void fixup_normal_lengths( struct immediate
*IM
)
99 GLfloat len
= 1.0F
; /* just to silence warnings */
100 GLfloat (*data
)[4] = IM
->Attrib
[VERT_ATTRIB_NORMAL
];
101 GLfloat
*dest
= IM
->NormalLengthPtr
;
102 GLuint
*flags
= IM
->Flag
;
104 for (i
= IM
->CopyStart
; i
<= IM
->Start
; i
++) {
105 len
= (GLfloat
) LEN_3FV( data
[i
] );
106 if (len
> 0.0F
) len
= 1.0F
/ len
;
111 while (!(flags
[i
] & (VERT_BIT_NORMAL
|VERT_BIT_END_VB
))) {
120 /* Insert the active immediate struct onto the display list currently
124 _tnl_compile_cassette( GLcontext
*ctx
, struct immediate
*IM
)
126 struct immediate
*im
= TNL_CURRENT_IM(ctx
);
127 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
128 TNLvertexcassette
*node
;
129 GLuint new_beginstate
;
131 if (MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
)
132 _mesa_debug(ctx
, "_tnl_compiled_cassette IM: %d\n", IM
->id
);
135 ASSERT (IM
->FlushElt
== FLUSH_ELT_LAZY
);
136 _tnl_translate_array_elts( ctx
, IM
, IM
->Start
, IM
->Count
);
139 _tnl_compute_orflag( IM
, IM
->Start
);
141 /* Need to clear this flag, or fixup gets confused. (The
142 * array-elements have been translated away by now, so it's ok to
145 IM
->OrFlag
&= ~VERT_BIT_ELT
;
146 IM
->AndFlag
&= ~VERT_BIT_ELT
;
148 _tnl_fixup_input( ctx
, IM
);
150 node
= (TNLvertexcassette
*)
151 _mesa_alloc_instruction(ctx
,
152 tnl
->opcode_vertex_cassette
,
153 sizeof(TNLvertexcassette
));
157 node
->IM
= im
; im
->ref_count
++;
158 node
->Start
= im
->Start
;
159 node
->Count
= im
->Count
;
160 node
->BeginState
= im
->BeginState
;
161 node
->SavedBeginState
= im
->SavedBeginState
;
162 node
->OrFlag
= im
->OrFlag
;
163 node
->TexSize
= im
->TexSize
;
164 node
->AndFlag
= im
->AndFlag
;
165 node
->LastData
= im
->LastData
;
166 node
->LastPrimitive
= im
->LastPrimitive
;
167 node
->LastMaterial
= im
->LastMaterial
;
168 node
->MaterialOrMask
= im
->MaterialOrMask
;
169 node
->MaterialAndMask
= im
->MaterialAndMask
;
171 if (tnl
->CalcDListNormalLengths
) {
172 build_normal_lengths( im
);
175 if (ctx
->ExecuteFlag
) {
176 execute_compiled_cassette( ctx
, (void *)node
);
179 /* Discard any errors raised in the last cassette.
181 new_beginstate
= node
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
);
183 /* Decide whether this immediate struct is full, or can be used for
184 * the next batch of vertices as well.
186 if (im
->Count
> IMM_MAXDATA
- 16) {
189 struct immediate
*new_im
= _tnl_alloc_immediate(ctx
);
191 im
->ref_count
--; /* remove CURRENT_IM reference */
192 ASSERT(im
->ref_count
> 0); /* it is compiled into a display list */
193 SET_IMMEDIATE( ctx
, new_im
);
194 _tnl_reset_compile_input( ctx
, IMM_MAX_COPIED_VERTS
,
195 new_beginstate
, node
->SavedBeginState
);
197 /* Still some room in the current immediate.
199 _tnl_reset_compile_input( ctx
, im
->Count
+1+IMM_MAX_COPIED_VERTS
,
200 new_beginstate
, node
->SavedBeginState
);
205 static void fixup_compiled_primitives( GLcontext
*ctx
, struct immediate
*IM
)
207 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
209 /* Can potentially overwrite primitive details - need to save the
212 tnl
->DlistPrimitive
= IM
->Primitive
[IM
->Start
];
213 tnl
->DlistPrimitiveLength
= IM
->PrimitiveLength
[IM
->Start
];
214 tnl
->DlistLastPrimitive
= IM
->LastPrimitive
;
216 /* The first primitive may be different from what was recorded in
217 * the immediate struct. Consider an immediate that starts with a
218 * glBegin, compiled in a display list, which is called from within
219 * an existing Begin/End object.
221 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
224 if (IM
->BeginState
& VERT_ERROR_1
)
225 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin/glEnd");
227 for (i
= IM
->Start
; i
<= IM
->Count
; i
+= IM
->PrimitiveLength
[i
])
228 if (IM
->Flag
[i
] & (VERT_BIT_BEGIN
|VERT_BIT_END_VB
))
231 /* Would like to just ignore vertices upto this point. Can't
232 * set copystart because it might skip materials?
234 ASSERT(IM
->Start
== IM
->CopyStart
);
235 if (i
> IM
->CopyStart
|| !(IM
->Flag
[IM
->Start
] & VERT_BIT_BEGIN
)) {
236 IM
->Primitive
[IM
->CopyStart
] = GL_POLYGON
+1;
237 IM
->PrimitiveLength
[IM
->CopyStart
] = i
- IM
->CopyStart
;
238 if (IM
->Flag
[i
] & VERT_BIT_END_VB
) {
239 IM
->Primitive
[IM
->CopyStart
] |= PRIM_LAST
;
240 IM
->LastPrimitive
= IM
->CopyStart
;
246 if (IM
->BeginState
& VERT_ERROR_0
)
247 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin/glEnd");
249 if (IM
->CopyStart
== IM
->Start
&&
250 IM
->Flag
[IM
->Start
] & (VERT_BIT_END
| VERT_BIT_END_VB
))
255 IM
->Primitive
[IM
->CopyStart
] = ctx
->Driver
.CurrentExecPrimitive
;
257 IM
->Primitive
[IM
->CopyStart
] |= PRIM_PARITY
;
259 /* one of these should be true, else we'll be in an infinite loop
261 ASSERT(IM
->PrimitiveLength
[IM
->Start
] > 0 ||
262 IM
->Flag
[IM
->Start
] & (VERT_BIT_END
| VERT_BIT_END_VB
));
264 for (i
= IM
->Start
; i
<= IM
->Count
; i
+= IM
->PrimitiveLength
[i
])
265 if (IM
->Flag
[i
] & (VERT_BIT_END
| VERT_BIT_END_VB
)) {
266 IM
->PrimitiveLength
[IM
->CopyStart
] = i
- IM
->CopyStart
;
267 if (IM
->Flag
[i
] & VERT_BIT_END_VB
) {
268 IM
->Primitive
[IM
->CopyStart
] |= PRIM_LAST
;
269 IM
->LastPrimitive
= IM
->CopyStart
;
271 if (IM
->Flag
[i
] & VERT_BIT_END
) {
272 IM
->Primitive
[IM
->CopyStart
] |= PRIM_END
;
280 /* Undo any changes potentially made to the immediate in the range
281 * IM->Start..IM->Count above.
283 static void restore_compiled_primitives( GLcontext
*ctx
, struct immediate
*IM
)
285 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
286 IM
->Primitive
[IM
->Start
] = tnl
->DlistPrimitive
;
287 IM
->PrimitiveLength
[IM
->Start
] = tnl
->DlistPrimitiveLength
;
293 execute_compiled_cassette( GLcontext
*ctx
, void *data
)
295 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
296 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
297 struct immediate
*IM
= node
->IM
;
299 /* _mesa_debug("%s\n", __FUNCTION__); */
301 IM
->Start
= node
->Start
;
302 IM
->CopyStart
= node
->Start
;
303 IM
->Count
= node
->Count
;
304 IM
->BeginState
= node
->BeginState
;
305 IM
->SavedBeginState
= node
->SavedBeginState
;
306 IM
->OrFlag
= node
->OrFlag
;
307 IM
->TexSize
= node
->TexSize
;
308 IM
->AndFlag
= node
->AndFlag
;
309 IM
->LastData
= node
->LastData
;
310 IM
->LastPrimitive
= node
->LastPrimitive
;
311 IM
->LastMaterial
= node
->LastMaterial
;
312 IM
->MaterialOrMask
= node
->MaterialOrMask
;
313 IM
->MaterialAndMask
= node
->MaterialAndMask
;
315 if ((MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) &&
316 (MESA_VERBOSE
& VERBOSE_IMMEDIATE
))
317 _tnl_print_cassette( IM
);
319 if (MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) {
320 _mesa_debug(ctx
, "Run cassette %d, rows %d..%d, beginstate %x ",
321 IM
->id
, IM
->Start
, IM
->Count
, IM
->BeginState
);
322 _tnl_print_vert_flags("orflag", IM
->OrFlag
);
326 /* Need to respect 'HardBeginEnd' even if the commands are looped
327 * back to a driver tnl module.
329 if (IM
->SavedBeginState
) {
330 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
331 tnl
->ReplayHardBeginEnd
= 1;
332 if (!tnl
->ReplayHardBeginEnd
) {
333 /* This is a user error. Whatever operation (like glRectf)
334 * decomposed to this hard begin/end pair is now being run
335 * inside a begin/end object -- illegally. Reject it and
338 _mesa_error(ctx
, GL_INVALID_OPERATION
, "hard replay");
343 if (tnl
->LoopbackDListCassettes
) {
344 /* (tnl->IsolateMaterials && (IM->OrFlag & VERT_MATERIAL)) ) { */
345 fixup_compiled_primitives( ctx
, IM
);
346 loopback_compiled_cassette( ctx
, IM
);
347 restore_compiled_primitives( ctx
, IM
);
351 _mesa_update_state(ctx
);
353 if (tnl
->pipeline
.build_state_changes
)
354 _tnl_validate_pipeline( ctx
);
356 _tnl_fixup_compiled_cassette( ctx
, IM
);
357 fixup_compiled_primitives( ctx
, IM
);
359 if (IM
->Primitive
[IM
->LastPrimitive
] & PRIM_END
)
360 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
361 else if ((IM
->Primitive
[IM
->LastPrimitive
] & PRIM_BEGIN
) ||
362 (IM
->Primitive
[IM
->LastPrimitive
] & PRIM_MODE_MASK
) ==
363 PRIM_OUTSIDE_BEGIN_END
) {
364 ctx
->Driver
.CurrentExecPrimitive
=
365 IM
->Primitive
[IM
->LastPrimitive
] & PRIM_MODE_MASK
;
368 _tnl_get_exec_copy_verts( ctx
, IM
);
370 if (IM
->NormalLengthPtr
)
371 fixup_normal_lengths( IM
);
373 if (IM
->Count
== IM
->Start
)
374 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
, IM
->LastData
);
376 /* _tnl_print_cassette( IM ); */
377 _tnl_run_cassette( ctx
, IM
);
380 restore_compiled_primitives( ctx
, IM
);
383 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
384 tnl
->ReplayHardBeginEnd
= 0;
388 destroy_compiled_cassette( GLcontext
*ctx
, void *data
)
390 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
392 if ( --node
->IM
->ref_count
== 0 )
393 _tnl_free_immediate( ctx
, node
->IM
);
398 print_compiled_cassette( GLcontext
*ctx
, void *data
)
400 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
401 struct immediate
*IM
= node
->IM
;
403 _mesa_debug(ctx
, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
404 node
->IM
->id
, node
->Start
, node
->Count
);
406 IM
->Start
= node
->Start
;
407 IM
->CopyStart
= node
->Start
;
408 IM
->Count
= node
->Count
;
409 IM
->BeginState
= node
->BeginState
;
410 IM
->OrFlag
= node
->OrFlag
;
411 IM
->TexSize
= node
->TexSize
;
412 IM
->AndFlag
= node
->AndFlag
;
413 IM
->LastData
= node
->LastData
;
414 IM
->LastPrimitive
= node
->LastPrimitive
;
415 IM
->LastMaterial
= node
->LastMaterial
;
416 IM
->MaterialOrMask
= node
->MaterialOrMask
;
417 IM
->MaterialAndMask
= node
->MaterialAndMask
;
419 _tnl_print_cassette( node
->IM
);
423 _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
427 FLUSH_CURRENT(ctx
, 0);
431 /* Called at the tail of a CallList. Make current immediate aware of
432 * any new to-be-copied vertices.
435 _tnl_EndCallList( GLcontext
*ctx
)
437 GLuint beginstate
= 0;
439 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
440 beginstate
= VERT_BEGIN_0
|VERT_BEGIN_1
;
442 _tnl_reset_exec_input( ctx
, TNL_CURRENT_IM(ctx
)->Start
, beginstate
, 0 );
447 _tnl_EndList( GLcontext
*ctx
)
449 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
454 /* outside begin/end, even in COMPILE_AND_EXEC,
455 * so no vertices to copy, right?
457 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
459 /* If this one isn't free, get a clean one. (Otherwise we'll be
460 * using one that's already half full).
462 if (IM
->ref_count
!= 0)
463 IM
= _tnl_alloc_immediate( ctx
);
465 ASSERT(IM
->ref_count
== 0);
467 SET_IMMEDIATE( ctx
, IM
);
470 _tnl_reset_exec_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
475 _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
477 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
479 /* Use the installed immediate struct. No vertices in the current
480 * immediate, no copied vertices in the system.
482 ASSERT(TNL_CURRENT_IM(ctx
));
483 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== IMM_MAX_COPIED_VERTS
);
484 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== TNL_CURRENT_IM(ctx
)->Count
);
485 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
487 /* Set current Begin/End state to unknown:
489 IM
->BeginState
= VERT_BEGIN_0
;
490 ctx
->Driver
.CurrentSavePrimitive
= PRIM_UNKNOWN
;
495 _tnl_dlist_init( GLcontext
*ctx
)
497 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
499 tnl
->opcode_vertex_cassette
=
500 _mesa_alloc_opcode( ctx
,
501 sizeof(TNLvertexcassette
),
502 execute_compiled_cassette
,
503 destroy_compiled_cassette
,
504 print_compiled_cassette
);
508 static void emit_material( struct gl_material
*src
, GLuint bitmask
)
510 if (bitmask
& FRONT_EMISSION_BIT
)
511 glMaterialfv( GL_FRONT
, GL_EMISSION
, src
[0].Emission
);
513 if (bitmask
& BACK_EMISSION_BIT
)
514 glMaterialfv( GL_BACK
, GL_EMISSION
, src
[1].Emission
);
516 if (bitmask
& FRONT_AMBIENT_BIT
)
517 glMaterialfv( GL_FRONT
, GL_AMBIENT
, src
[0].Ambient
);
519 if (bitmask
& BACK_AMBIENT_BIT
)
520 glMaterialfv( GL_BACK
, GL_AMBIENT
, src
[1].Ambient
);
522 if (bitmask
& FRONT_DIFFUSE_BIT
)
523 glMaterialfv( GL_FRONT
, GL_DIFFUSE
, src
[0].Diffuse
);
525 if (bitmask
& BACK_DIFFUSE_BIT
)
526 glMaterialfv( GL_BACK
, GL_DIFFUSE
, src
[1].Diffuse
);
528 if (bitmask
& FRONT_SPECULAR_BIT
)
529 glMaterialfv( GL_FRONT
, GL_SPECULAR
, src
[0].Specular
);
531 if (bitmask
& BACK_SPECULAR_BIT
)
532 glMaterialfv( GL_BACK
, GL_SPECULAR
, src
[1].Specular
);
534 if (bitmask
& FRONT_SHININESS_BIT
)
535 glMaterialfv( GL_FRONT
, GL_SHININESS
, &src
[0].Shininess
);
537 if (bitmask
& BACK_SHININESS_BIT
)
538 glMaterialfv( GL_BACK
, GL_SHININESS
, &src
[1].Shininess
);
540 if (bitmask
& FRONT_INDEXES_BIT
) {
542 ind
[0] = src
[0].AmbientIndex
;
543 ind
[1] = src
[0].DiffuseIndex
;
544 ind
[2] = src
[0].SpecularIndex
;
545 glMaterialfv( GL_FRONT
, GL_COLOR_INDEXES
, ind
);
548 if (bitmask
& BACK_INDEXES_BIT
) {
550 ind
[0] = src
[1].AmbientIndex
;
551 ind
[1] = src
[1].DiffuseIndex
;
552 ind
[2] = src
[1].SpecularIndex
;
553 glMaterialfv( GL_BACK
, GL_COLOR_INDEXES
, ind
);
558 /* Low-performance helper function to allow driver-supplied tnl
559 * modules to process tnl display lists. This is primarily supplied
560 * to avoid fallbacks if CallList is invoked inside a Begin/End pair.
561 * For higher performance, drivers should fallback to tnl (if outside
562 * begin/end), or (for tnl hardware) implement their own display list
565 static void loopback_compiled_cassette( GLcontext
*ctx
, struct immediate
*IM
)
568 GLuint
*flags
= IM
->Flag
;
569 GLuint orflag
= IM
->OrFlag
;
571 void (GLAPIENTRY
*vertex
)( const GLfloat
* );
572 void (GLAPIENTRY
*texcoordfv
[MAX_TEXTURE_UNITS
])( GLenum
, const GLfloat
* );
574 GLuint p
, length
, prim
= 0;
576 if (orflag
& VERT_BITS_OBJ_234
)
577 vertex
= (void (GLAPIENTRY
*)(const GLfloat
*)) glVertex4fv
;
579 vertex
= (void (GLAPIENTRY
*)(const GLfloat
*)) glVertex3fv
;
581 if (orflag
& VERT_BITS_TEX_ANY
) {
582 for (j
= 0 ; j
< ctx
->Const
.MaxTextureUnits
; j
++) {
583 if (orflag
& VERT_BIT_TEX(j
)) {
585 if ((IM
->TexSize
& TEX_SIZE_4(j
)) == TEX_SIZE_4(j
))
586 texcoordfv
[j
] = glMultiTexCoord4fvARB
;
587 else if (IM
->TexSize
& TEX_SIZE_3(j
))
588 texcoordfv
[j
] = glMultiTexCoord3fvARB
;
590 texcoordfv
[j
] = glMultiTexCoord2fvARB
;
595 for (p
= IM
->Start
; !(prim
& PRIM_LAST
) ; p
+= length
)
597 prim
= IM
->Primitive
[p
];
598 length
= IM
->PrimitiveLength
[p
];
599 ASSERT(length
|| (prim
& PRIM_LAST
));
600 ASSERT((prim
& PRIM_MODE_MASK
) <= GL_POLYGON
+1);
602 if (prim
& PRIM_BEGIN
) {
603 glBegin(prim
& PRIM_MODE_MASK
);
606 for ( i
= p
; i
<= p
+length
; i
++) {
607 if (flags
[i
] & VERT_BITS_TEX_ANY
) {
609 for (k
= 0 ; k
< maxtex
; k
++) {
610 if (flags
[i
] & VERT_BIT_TEX(k
)) {
611 texcoordfv
[k
]( GL_TEXTURE0_ARB
+ k
,
612 IM
->Attrib
[VERT_ATTRIB_TEX0
+ k
][i
] );
617 if (flags
[i
] & VERT_BIT_NORMAL
)
618 glNormal3fv(IM
->Attrib
[VERT_ATTRIB_NORMAL
][i
]);
620 if (flags
[i
] & VERT_BIT_COLOR0
)
621 glColor4fv( IM
->Attrib
[VERT_ATTRIB_COLOR0
][i
] );
623 if (flags
[i
] & VERT_BIT_COLOR1
)
624 _glapi_Dispatch
->SecondaryColor3fvEXT( IM
->Attrib
[VERT_ATTRIB_COLOR1
][i
] );
626 if (flags
[i
] & VERT_BIT_FOG
)
627 _glapi_Dispatch
->FogCoordfEXT( IM
->Attrib
[VERT_ATTRIB_FOG
][i
][0] );
629 if (flags
[i
] & VERT_BIT_INDEX
)
630 glIndexi( IM
->Index
[i
] );
632 if (flags
[i
] & VERT_BIT_EDGEFLAG
)
633 glEdgeFlag( IM
->EdgeFlag
[i
] );
635 if (flags
[i
] & VERT_BIT_MATERIAL
)
636 emit_material( IM
->Material
[i
], IM
->MaterialMask
[i
] );
638 if (flags
[i
]&VERT_BITS_OBJ_234
)
639 vertex( IM
->Attrib
[VERT_ATTRIB_POS
][i
] );
640 else if (flags
[i
] & VERT_BIT_EVAL_C1
)
641 glEvalCoord1f( IM
->Attrib
[VERT_ATTRIB_POS
][i
][0] );
642 else if (flags
[i
] & VERT_BIT_EVAL_P1
)
643 glEvalPoint1( (GLint
) IM
->Attrib
[VERT_ATTRIB_POS
][i
][0] );
644 else if (flags
[i
] & VERT_BIT_EVAL_C2
)
645 glEvalCoord2f( IM
->Attrib
[VERT_ATTRIB_POS
][i
][0],
646 IM
->Attrib
[VERT_ATTRIB_POS
][i
][1] );
647 else if (flags
[i
] & VERT_BIT_EVAL_P2
)
648 glEvalPoint2( (GLint
) IM
->Attrib
[VERT_ATTRIB_POS
][i
][0],
649 (GLint
) IM
->Attrib
[VERT_ATTRIB_POS
][i
][1] );
652 if (prim
& PRIM_END
) {