Header file clean-up:
[mesa.git] / src / mesa / tnl / t_imm_dlist.c
1 /* $Id: t_imm_dlist.c,v 1.43 2002/10/24 23:57:25 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
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.
25 *
26 * Authors:
27 * Keith Whitwell <keithw@valinux.com>
28 */
29
30
31 #include "glheader.h"
32 #include "context.h"
33 #include "dlist.h"
34 #include "debug.h"
35 #include "mmath.h"
36 #include "imports.h"
37 #include "state.h"
38
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"
48
49 typedef struct {
50 struct immediate *IM;
51 GLuint Start;
52 GLuint Count;
53 GLuint BeginState;
54 GLuint SavedBeginState;
55 GLuint OrFlag;
56 GLuint AndFlag;
57 GLuint TexSize;
58 GLuint LastData;
59 GLuint LastPrimitive;
60 GLuint LastMaterial;
61 GLuint MaterialOrMask;
62 GLuint MaterialAndMask;
63 } TNLvertexcassette;
64
65 static void execute_compiled_cassette( GLcontext *ctx, void *data );
66 static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM );
67
68
69 static void build_normal_lengths( struct immediate *IM )
70 {
71 GLuint i;
72 GLfloat len;
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;
77
78 if (!dest) {
79 dest = IM->NormalLengthPtr = (GLfloat *) ALIGN_MALLOC( IMM_SIZE*sizeof(GLfloat), 32 );
80 if (!dest) return;
81 }
82 dest += IM->Start;
83
84 len = (GLfloat) LEN_3FV( data[0] );
85 if (len > 0.0F) len = 1.0F / len;
86
87 for (i = 0 ; i < count ; ) {
88 dest[i] = len;
89 if (flags[++i] & VERT_BIT_NORMAL) {
90 len = (GLfloat) LEN_3FV( data[i] );
91 if (len > 0.0F) len = 1.0F / len;
92 }
93 }
94 }
95
96 static void fixup_normal_lengths( struct immediate *IM )
97 {
98 GLuint i;
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;
103
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;
107 dest[i] = len;
108 }
109
110 if (i < IM->Count) {
111 while (!(flags[i] & (VERT_BIT_NORMAL|VERT_BIT_END_VB))) {
112 dest[i] = len;
113 i++;
114 }
115 }
116 }
117
118
119
120 /* Insert the active immediate struct onto the display list currently
121 * being built.
122 */
123 void
124 _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
125 {
126 struct immediate *im = TNL_CURRENT_IM(ctx);
127 TNLcontext *tnl = TNL_CONTEXT(ctx);
128 TNLvertexcassette *node;
129 GLuint new_beginstate;
130
131 if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST)
132 _mesa_debug(ctx, "_tnl_compiled_cassette IM: %d\n", IM->id);
133
134 if (IM->FlushElt) {
135 ASSERT (IM->FlushElt == FLUSH_ELT_LAZY);
136 _tnl_translate_array_elts( ctx, IM, IM->Start, IM->Count );
137 }
138
139 _tnl_compute_orflag( IM, IM->Start );
140
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
143 * remove it.)
144 */
145 IM->OrFlag &= ~VERT_BIT_ELT;
146 IM->AndFlag &= ~VERT_BIT_ELT;
147
148 _tnl_fixup_input( ctx, IM );
149
150 node = (TNLvertexcassette *)
151 _mesa_alloc_instruction(ctx,
152 tnl->opcode_vertex_cassette,
153 sizeof(TNLvertexcassette));
154 if (!node)
155 return;
156
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;
170
171 if (tnl->CalcDListNormalLengths) {
172 build_normal_lengths( im );
173 }
174
175 if (ctx->ExecuteFlag) {
176 execute_compiled_cassette( ctx, (void *)node );
177 }
178
179 /* Discard any errors raised in the last cassette.
180 */
181 new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
182
183 /* Decide whether this immediate struct is full, or can be used for
184 * the next batch of vertices as well.
185 */
186 if (im->Count > IMM_MAXDATA - 16) {
187 /* Call it full...
188 */
189 struct immediate *new_im = _tnl_alloc_immediate(ctx);
190 new_im->ref_count++;
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 );
196 } else {
197 /* Still some room in the current immediate.
198 */
199 _tnl_reset_compile_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
200 new_beginstate, node->SavedBeginState);
201 }
202 }
203
204
205 static void fixup_compiled_primitives( GLcontext *ctx, struct immediate *IM )
206 {
207 TNLcontext *tnl = TNL_CONTEXT(ctx);
208
209 /* Can potentially overwrite primitive details - need to save the
210 * first slot:
211 */
212 tnl->DlistPrimitive = IM->Primitive[IM->Start];
213 tnl->DlistPrimitiveLength = IM->PrimitiveLength[IM->Start];
214 tnl->DlistLastPrimitive = IM->LastPrimitive;
215
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.
220 */
221 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
222 GLuint i;
223
224 if (IM->BeginState & VERT_ERROR_1)
225 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
226
227 for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
228 if (IM->Flag[i] & (VERT_BIT_BEGIN|VERT_BIT_END_VB))
229 break;
230
231 /* Would like to just ignore vertices upto this point. Can't
232 * set copystart because it might skip materials?
233 */
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;
241 }
242 }
243 } else {
244 GLuint i;
245
246 if (IM->BeginState & VERT_ERROR_0)
247 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
248
249 if (IM->CopyStart == IM->Start &&
250 IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB))
251 {
252 }
253 else
254 {
255 IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
256 if (tnl->ExecParity)
257 IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
258
259 /* one of these should be true, else we'll be in an infinite loop
260 */
261 ASSERT(IM->PrimitiveLength[IM->Start] > 0 ||
262 IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB));
263
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;
270 }
271 if (IM->Flag[i] & VERT_BIT_END) {
272 IM->Primitive[IM->CopyStart] |= PRIM_END;
273 }
274 break;
275 }
276 }
277 }
278 }
279
280 /* Undo any changes potentially made to the immediate in the range
281 * IM->Start..IM->Count above.
282 */
283 static void restore_compiled_primitives( GLcontext *ctx, struct immediate *IM )
284 {
285 TNLcontext *tnl = TNL_CONTEXT(ctx);
286 IM->Primitive[IM->Start] = tnl->DlistPrimitive;
287 IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength;
288 }
289
290
291
292 static void
293 execute_compiled_cassette( GLcontext *ctx, void *data )
294 {
295 TNLcontext *tnl = TNL_CONTEXT(ctx);
296 TNLvertexcassette *node = (TNLvertexcassette *)data;
297 struct immediate *IM = node->IM;
298
299 /* _mesa_debug("%s\n", __FUNCTION__); */
300
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;
314
315 if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
316 (MESA_VERBOSE & VERBOSE_IMMEDIATE))
317 _tnl_print_cassette( IM );
318
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);
323 }
324
325
326 /* Need to respect 'HardBeginEnd' even if the commands are looped
327 * back to a driver tnl module.
328 */
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
336 * raise an error.
337 */
338 _mesa_error(ctx, GL_INVALID_OPERATION, "hard replay");
339 return;
340 }
341 }
342
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 );
348 }
349 else {
350 if (ctx->NewState)
351 _mesa_update_state(ctx);
352
353 if (tnl->pipeline.build_state_changes)
354 _tnl_validate_pipeline( ctx );
355
356 _tnl_fixup_compiled_cassette( ctx, IM );
357 fixup_compiled_primitives( ctx, IM );
358
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;
366 }
367
368 _tnl_get_exec_copy_verts( ctx, IM );
369
370 if (IM->NormalLengthPtr)
371 fixup_normal_lengths( IM );
372
373 if (IM->Count == IM->Start)
374 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
375 else {
376 /* _tnl_print_cassette( IM ); */
377 _tnl_run_cassette( ctx, IM );
378 }
379
380 restore_compiled_primitives( ctx, IM );
381 }
382
383 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
384 tnl->ReplayHardBeginEnd = 0;
385 }
386
387 static void
388 destroy_compiled_cassette( GLcontext *ctx, void *data )
389 {
390 TNLvertexcassette *node = (TNLvertexcassette *)data;
391
392 if ( --node->IM->ref_count == 0 )
393 _tnl_free_immediate( ctx, node->IM );
394 }
395
396
397 static void
398 print_compiled_cassette( GLcontext *ctx, void *data )
399 {
400 TNLvertexcassette *node = (TNLvertexcassette *)data;
401 struct immediate *IM = node->IM;
402
403 _mesa_debug(ctx, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
404 node->IM->id, node->Start, node->Count);
405
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;
418
419 _tnl_print_cassette( node->IM );
420 }
421
422 void
423 _tnl_BeginCallList( GLcontext *ctx, GLuint list )
424 {
425 (void) ctx;
426 (void) list;
427 FLUSH_CURRENT(ctx, 0);
428 }
429
430
431 /* Called at the tail of a CallList. Make current immediate aware of
432 * any new to-be-copied vertices.
433 */
434 void
435 _tnl_EndCallList( GLcontext *ctx )
436 {
437 GLuint beginstate = 0;
438
439 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
440 beginstate = VERT_BEGIN_0|VERT_BEGIN_1;
441
442 _tnl_reset_exec_input( ctx, TNL_CURRENT_IM(ctx)->Start, beginstate, 0 );
443 }
444
445
446 void
447 _tnl_EndList( GLcontext *ctx )
448 {
449 struct immediate *IM = TNL_CURRENT_IM(ctx);
450
451 ctx->swtnl_im = 0;
452 IM->ref_count--;
453
454 /* outside begin/end, even in COMPILE_AND_EXEC,
455 * so no vertices to copy, right?
456 */
457 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
458
459 /* If this one isn't free, get a clean one. (Otherwise we'll be
460 * using one that's already half full).
461 */
462 if (IM->ref_count != 0)
463 IM = _tnl_alloc_immediate( ctx );
464
465 ASSERT(IM->ref_count == 0);
466
467 SET_IMMEDIATE( ctx, IM );
468 IM->ref_count++;
469
470 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
471 }
472
473
474 void
475 _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
476 {
477 struct immediate *IM = TNL_CURRENT_IM(ctx);
478
479 /* Use the installed immediate struct. No vertices in the current
480 * immediate, no copied vertices in the system.
481 */
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);
486
487 /* Set current Begin/End state to unknown:
488 */
489 IM->BeginState = VERT_BEGIN_0;
490 ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
491 }
492
493
494 void
495 _tnl_dlist_init( GLcontext *ctx )
496 {
497 TNLcontext *tnl = TNL_CONTEXT(ctx);
498
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 );
505 }
506
507
508 static void emit_material( struct gl_material *src, GLuint bitmask )
509 {
510 if (bitmask & FRONT_EMISSION_BIT)
511 glMaterialfv( GL_FRONT, GL_EMISSION, src[0].Emission );
512
513 if (bitmask & BACK_EMISSION_BIT)
514 glMaterialfv( GL_BACK, GL_EMISSION, src[1].Emission );
515
516 if (bitmask & FRONT_AMBIENT_BIT)
517 glMaterialfv( GL_FRONT, GL_AMBIENT, src[0].Ambient );
518
519 if (bitmask & BACK_AMBIENT_BIT)
520 glMaterialfv( GL_BACK, GL_AMBIENT, src[1].Ambient );
521
522 if (bitmask & FRONT_DIFFUSE_BIT)
523 glMaterialfv( GL_FRONT, GL_DIFFUSE, src[0].Diffuse );
524
525 if (bitmask & BACK_DIFFUSE_BIT)
526 glMaterialfv( GL_BACK, GL_DIFFUSE, src[1].Diffuse );
527
528 if (bitmask & FRONT_SPECULAR_BIT)
529 glMaterialfv( GL_FRONT, GL_SPECULAR, src[0].Specular );
530
531 if (bitmask & BACK_SPECULAR_BIT)
532 glMaterialfv( GL_BACK, GL_SPECULAR, src[1].Specular );
533
534 if (bitmask & FRONT_SHININESS_BIT)
535 glMaterialfv( GL_FRONT, GL_SHININESS, &src[0].Shininess );
536
537 if (bitmask & BACK_SHININESS_BIT)
538 glMaterialfv( GL_BACK, GL_SHININESS, &src[1].Shininess );
539
540 if (bitmask & FRONT_INDEXES_BIT) {
541 GLfloat ind[3];
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 );
546 }
547
548 if (bitmask & BACK_INDEXES_BIT) {
549 GLfloat ind[3];
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 );
554 }
555 }
556
557
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
563 * mechanism.
564 */
565 static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM )
566 {
567 GLuint i;
568 GLuint *flags = IM->Flag;
569 GLuint orflag = IM->OrFlag;
570 GLuint j;
571 void (GLAPIENTRY *vertex)( const GLfloat * );
572 void (GLAPIENTRY *texcoordfv[MAX_TEXTURE_UNITS])( GLenum, const GLfloat * );
573 GLuint maxtex = 0;
574 GLuint p, length, prim = 0;
575
576 if (orflag & VERT_BITS_OBJ_234)
577 vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex4fv;
578 else
579 vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex3fv;
580
581 if (orflag & VERT_BITS_TEX_ANY) {
582 for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) {
583 if (orflag & VERT_BIT_TEX(j)) {
584 maxtex = j+1;
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;
589 else
590 texcoordfv[j] = glMultiTexCoord2fvARB;
591 }
592 }
593 }
594
595 for (p = IM->Start ; !(prim & PRIM_LAST) ; p += length)
596 {
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);
601
602 if (prim & PRIM_BEGIN) {
603 glBegin(prim & PRIM_MODE_MASK);
604 }
605
606 for ( i = p ; i <= p+length ; i++) {
607 if (flags[i] & VERT_BITS_TEX_ANY) {
608 GLuint k;
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] );
613 }
614 }
615 }
616
617 if (flags[i] & VERT_BIT_NORMAL)
618 glNormal3fv(IM->Attrib[VERT_ATTRIB_NORMAL][i]);
619
620 if (flags[i] & VERT_BIT_COLOR0)
621 glColor4fv( IM->Attrib[VERT_ATTRIB_COLOR0][i] );
622
623 if (flags[i] & VERT_BIT_COLOR1)
624 _glapi_Dispatch->SecondaryColor3fvEXT( IM->Attrib[VERT_ATTRIB_COLOR1][i] );
625
626 if (flags[i] & VERT_BIT_FOG)
627 _glapi_Dispatch->FogCoordfEXT( IM->Attrib[VERT_ATTRIB_FOG][i][0] );
628
629 if (flags[i] & VERT_BIT_INDEX)
630 glIndexi( IM->Index[i] );
631
632 if (flags[i] & VERT_BIT_EDGEFLAG)
633 glEdgeFlag( IM->EdgeFlag[i] );
634
635 if (flags[i] & VERT_BIT_MATERIAL)
636 emit_material( IM->Material[i], IM->MaterialMask[i] );
637
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] );
650 }
651
652 if (prim & PRIM_END) {
653 glEnd();
654 }
655 }
656 }