minor clean-ups, comments, etc
[mesa.git] / src / mesa / tnl / t_imm_dlist.c
1 /* $Id: t_imm_dlist.c,v 1.47 2003/03/28 01:39:05 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 5.1
6 *
7 * Copyright (C) 1999-2003 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 <keith@tungstengraphics.com>
28 */
29
30
31 #include "glheader.h"
32 #include "context.h"
33 #include "dlist.h"
34 #include "debug.h"
35 #include "macros.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
70 build_normal_lengths( struct immediate *IM )
71 {
72 GLuint i;
73 GLfloat len;
74 GLfloat (*data)[4] = IM->Attrib[VERT_ATTRIB_NORMAL] + IM->Start;
75 GLfloat *dest = IM->NormalLengthPtr;
76 GLuint *flags = IM->Flag + IM->Start;
77 GLuint count = IM->Count - IM->Start;
78
79 if (!dest) {
80 dest = IM->NormalLengthPtr = (GLfloat *) ALIGN_MALLOC( IMM_SIZE*sizeof(GLfloat), 32 );
81 if (!dest) return;
82 }
83 dest += IM->Start;
84
85 len = (GLfloat) LEN_3FV( data[0] );
86 if (len > 0.0F) len = 1.0F / len;
87
88 for (i = 0 ; i < count ; ) {
89 dest[i] = len;
90 if (flags[++i] & VERT_BIT_NORMAL) {
91 len = (GLfloat) LEN_3FV( data[i] );
92 if (len > 0.0F) len = 1.0F / len;
93 }
94 }
95 }
96
97
98 static void
99 fixup_normal_lengths( struct immediate *IM )
100 {
101 GLuint i;
102 GLfloat len = 1.0F; /* just to silence warnings */
103 GLfloat (*data)[4] = IM->Attrib[VERT_ATTRIB_NORMAL];
104 GLfloat *dest = IM->NormalLengthPtr;
105 GLuint *flags = IM->Flag;
106
107 for (i = IM->CopyStart ; i <= IM->Start ; i++) {
108 len = (GLfloat) LEN_3FV( data[i] );
109 if (len > 0.0F) len = 1.0F / len;
110 dest[i] = len;
111 }
112
113 if (i < IM->Count) {
114 while (!(flags[i] & (VERT_BIT_NORMAL|VERT_BIT_END_VB))) {
115 dest[i] = len;
116 i++;
117 }
118 }
119 }
120
121
122
123 /* Insert the active immediate struct onto the display list currently
124 * being built.
125 */
126 void
127 _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
128 {
129 struct immediate *im = TNL_CURRENT_IM(ctx);
130 TNLcontext *tnl = TNL_CONTEXT(ctx);
131 TNLvertexcassette *node;
132 GLuint new_beginstate;
133
134 if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST)
135 _mesa_debug(ctx, "_tnl_compiled_cassette IM: %d\n", IM->id);
136
137 if (IM->FlushElt) {
138 ASSERT (IM->FlushElt == FLUSH_ELT_LAZY);
139 _tnl_translate_array_elts( ctx, IM, IM->Start, IM->Count );
140 }
141
142 _tnl_compute_orflag( IM, IM->Start );
143
144 /* Need to clear this flag, or fixup gets confused. (The
145 * array-elements have been translated away by now, so it's ok to
146 * remove it.)
147 */
148 IM->OrFlag &= ~VERT_BIT_ELT;
149 IM->AndFlag &= ~VERT_BIT_ELT;
150
151 _tnl_fixup_input( ctx, IM );
152
153 /* Allocate space for this structure in the display list currently
154 * being compiled.
155 */
156 node = (TNLvertexcassette *)
157 _mesa_alloc_instruction(ctx,
158 tnl->opcode_vertex_cassette,
159 sizeof(TNLvertexcassette));
160 if (!node)
161 return;
162
163 node->IM = im; im->ref_count++;
164 node->Start = im->Start;
165 node->Count = im->Count;
166 node->BeginState = im->BeginState;
167 node->SavedBeginState = im->SavedBeginState;
168 node->OrFlag = im->OrFlag;
169 node->TexSize = im->TexSize;
170 node->AndFlag = im->AndFlag;
171 node->LastData = im->LastData;
172 node->LastPrimitive = im->LastPrimitive;
173 node->LastMaterial = im->LastMaterial;
174 node->MaterialOrMask = im->MaterialOrMask;
175 node->MaterialAndMask = im->MaterialAndMask;
176
177 if (tnl->CalcDListNormalLengths) {
178 build_normal_lengths( im );
179 }
180
181 if (ctx->ExecuteFlag) {
182 execute_compiled_cassette( ctx, (void *)node );
183 }
184
185 /* Discard any errors raised in the last cassette.
186 */
187 new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
188
189 /* Decide whether this immediate struct is full, or can be used for
190 * the next batch of vertices as well.
191 */
192 if (im->Count > IMM_MAXDATA - 16) {
193 /* Call it full...
194 */
195 struct immediate *new_im = _tnl_alloc_immediate(ctx);
196 new_im->ref_count++;
197 im->ref_count--; /* remove CURRENT_IM reference */
198 ASSERT(im->ref_count > 0); /* it is compiled into a display list */
199 SET_IMMEDIATE( ctx, new_im );
200 _tnl_reset_compile_input( ctx, IMM_MAX_COPIED_VERTS,
201 new_beginstate, node->SavedBeginState );
202 } else {
203 /* Still some room in the current immediate.
204 */
205 _tnl_reset_compile_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
206 new_beginstate, node->SavedBeginState);
207 }
208 }
209
210
211 static void
212 fixup_compiled_primitives( GLcontext *ctx, struct immediate *IM )
213 {
214 TNLcontext *tnl = TNL_CONTEXT(ctx);
215
216 /* Can potentially overwrite primitive details - need to save the
217 * first slot:
218 */
219 tnl->DlistPrimitive = IM->Primitive[IM->Start];
220 tnl->DlistPrimitiveLength = IM->PrimitiveLength[IM->Start];
221 tnl->DlistLastPrimitive = IM->LastPrimitive;
222
223 /* The first primitive may be different from what was recorded in
224 * the immediate struct. Consider an immediate that starts with a
225 * glBegin, compiled in a display list, which is called from within
226 * an existing Begin/End object.
227 */
228 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
229 GLuint i;
230
231 if (IM->BeginState & VERT_ERROR_1)
232 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
233
234 for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
235 if (IM->Flag[i] & (VERT_BIT_BEGIN|VERT_BIT_END_VB))
236 break;
237
238 /* Would like to just ignore vertices upto this point. Can't
239 * set copystart because it might skip materials?
240 */
241 ASSERT(IM->Start == IM->CopyStart);
242 if (i > IM->CopyStart || !(IM->Flag[IM->Start] & VERT_BIT_BEGIN)) {
243 IM->Primitive[IM->CopyStart] = GL_POLYGON+1;
244 IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
245 if (IM->Flag[i] & VERT_BIT_END_VB) {
246 IM->Primitive[IM->CopyStart] |= PRIM_LAST;
247 IM->LastPrimitive = IM->CopyStart;
248 }
249 }
250 }
251 else {
252 GLuint i;
253
254 if (IM->BeginState & VERT_ERROR_0)
255 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
256
257 if (IM->CopyStart == IM->Start &&
258 IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB))
259 {
260 /* nothing */
261 }
262 else
263 {
264 IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
265 if (tnl->ExecParity)
266 IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
267
268 /* one of these should be true, else we'll be in an infinite loop
269 */
270 ASSERT(IM->PrimitiveLength[IM->Start] > 0 ||
271 IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB));
272
273 for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i]) {
274 if (IM->Flag[i] & (VERT_BIT_END | VERT_BIT_END_VB)) {
275 IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
276 if (IM->Flag[i] & VERT_BIT_END_VB) {
277 IM->Primitive[IM->CopyStart] |= PRIM_LAST;
278 IM->LastPrimitive = IM->CopyStart;
279 }
280 if (IM->Flag[i] & VERT_BIT_END) {
281 IM->Primitive[IM->CopyStart] |= PRIM_END;
282 }
283 break;
284 }
285 }
286 }
287 }
288 }
289
290
291 /* Undo any changes potentially made to the immediate in the range
292 * IM->Start..IM->Count above.
293 */
294 static void
295 restore_compiled_primitives( GLcontext *ctx, struct immediate *IM )
296 {
297 TNLcontext *tnl = TNL_CONTEXT(ctx);
298 IM->Primitive[IM->Start] = tnl->DlistPrimitive;
299 IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength;
300 }
301
302
303 static void
304 execute_compiled_cassette( GLcontext *ctx, void *data )
305 {
306 TNLcontext *tnl = TNL_CONTEXT(ctx);
307 TNLvertexcassette *node = (TNLvertexcassette *)data;
308 struct immediate *IM = node->IM;
309
310 /* _mesa_debug("%s\n", __FUNCTION__); */
311
312 IM->Start = node->Start;
313 IM->CopyStart = node->Start;
314 IM->Count = node->Count;
315 IM->BeginState = node->BeginState;
316 IM->SavedBeginState = node->SavedBeginState;
317 IM->OrFlag = node->OrFlag;
318 IM->TexSize = node->TexSize;
319 IM->AndFlag = node->AndFlag;
320 IM->LastData = node->LastData;
321 IM->LastPrimitive = node->LastPrimitive;
322 IM->LastMaterial = node->LastMaterial;
323 IM->MaterialOrMask = node->MaterialOrMask;
324 IM->MaterialAndMask = node->MaterialAndMask;
325
326 if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
327 (MESA_VERBOSE & VERBOSE_IMMEDIATE))
328 _tnl_print_cassette( IM );
329
330 if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
331 _mesa_debug(ctx, "Run cassette %d, rows %d..%d, beginstate %x ",
332 IM->id, IM->Start, IM->Count, IM->BeginState);
333 _tnl_print_vert_flags("orflag", IM->OrFlag);
334 }
335
336
337 /* Need to respect 'HardBeginEnd' even if the commands are looped
338 * back to a driver tnl module.
339 */
340 if (IM->SavedBeginState) {
341 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
342 tnl->ReplayHardBeginEnd = 1;
343 if (!tnl->ReplayHardBeginEnd) {
344 /* This is a user error. Whatever operation (like glRectf)
345 * decomposed to this hard begin/end pair is now being run
346 * inside a begin/end object -- illegally. Reject it and
347 * raise an error.
348 */
349 _mesa_error(ctx, GL_INVALID_OPERATION, "hard replay");
350 return;
351 }
352 }
353
354 if (tnl->LoopbackDListCassettes) {
355 /* (tnl->IsolateMaterials && (IM->OrFlag & VERT_MATERIAL)) ) { */
356 fixup_compiled_primitives( ctx, IM );
357 loopback_compiled_cassette( ctx, IM );
358 restore_compiled_primitives( ctx, IM );
359 }
360 else {
361 if (ctx->NewState)
362 _mesa_update_state(ctx);
363
364 if (tnl->pipeline.build_state_changes)
365 _tnl_validate_pipeline( ctx );
366
367 _tnl_fixup_compiled_cassette( ctx, IM );
368 fixup_compiled_primitives( ctx, IM );
369
370 if (IM->Primitive[IM->LastPrimitive] & PRIM_END)
371 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
372 else if ((IM->Primitive[IM->LastPrimitive] & PRIM_BEGIN) ||
373 (IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK) ==
374 PRIM_OUTSIDE_BEGIN_END) {
375 ctx->Driver.CurrentExecPrimitive =
376 IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK;
377 }
378
379 _tnl_get_exec_copy_verts( ctx, IM );
380
381 if (IM->NormalLengthPtr)
382 fixup_normal_lengths( IM );
383
384 if (IM->Count == IM->Start)
385 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
386 else {
387 /* _tnl_print_cassette( IM ); */
388 _tnl_run_cassette( ctx, IM );
389 }
390
391 restore_compiled_primitives( ctx, IM );
392 }
393
394 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
395 tnl->ReplayHardBeginEnd = 0;
396 }
397
398
399 static void
400 destroy_compiled_cassette( GLcontext *ctx, void *data )
401 {
402 TNLvertexcassette *node = (TNLvertexcassette *)data;
403
404 if ( --node->IM->ref_count == 0 )
405 _tnl_free_immediate( ctx, node->IM );
406 }
407
408
409 static void
410 print_compiled_cassette( GLcontext *ctx, void *data )
411 {
412 TNLvertexcassette *node = (TNLvertexcassette *)data;
413 struct immediate *IM = node->IM;
414
415 _mesa_debug(ctx, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
416 node->IM->id, node->Start, node->Count);
417
418 IM->Start = node->Start;
419 IM->CopyStart = node->Start;
420 IM->Count = node->Count;
421 IM->BeginState = node->BeginState;
422 IM->OrFlag = node->OrFlag;
423 IM->TexSize = node->TexSize;
424 IM->AndFlag = node->AndFlag;
425 IM->LastData = node->LastData;
426 IM->LastPrimitive = node->LastPrimitive;
427 IM->LastMaterial = node->LastMaterial;
428 IM->MaterialOrMask = node->MaterialOrMask;
429 IM->MaterialAndMask = node->MaterialAndMask;
430
431 _tnl_print_cassette( node->IM );
432 }
433
434
435 void
436 _tnl_BeginCallList( GLcontext *ctx, GLuint list )
437 {
438 (void) ctx;
439 (void) list;
440 FLUSH_CURRENT(ctx, 0);
441 }
442
443
444 /* Called at the tail of a CallList. Make current immediate aware of
445 * any new to-be-copied vertices.
446 */
447 void
448 _tnl_EndCallList( GLcontext *ctx )
449 {
450 GLuint beginstate = 0;
451
452 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
453 beginstate = VERT_BEGIN_0|VERT_BEGIN_1;
454
455 _tnl_reset_exec_input( ctx, TNL_CURRENT_IM(ctx)->Start, beginstate, 0 );
456 }
457
458
459 void
460 _tnl_EndList( GLcontext *ctx )
461 {
462 struct immediate *IM = TNL_CURRENT_IM(ctx);
463
464 ctx->swtnl_im = 0;
465 IM->ref_count--;
466
467 /* outside begin/end, even in COMPILE_AND_EXEC,
468 * so no vertices to copy, right?
469 */
470 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
471
472 /* If this one isn't free, get a clean one. (Otherwise we'll be
473 * using one that's already half full).
474 */
475 if (IM->ref_count != 0)
476 IM = _tnl_alloc_immediate( ctx );
477
478 ASSERT(IM->ref_count == 0);
479
480 SET_IMMEDIATE( ctx, IM );
481 IM->ref_count++;
482
483 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
484 }
485
486
487 void
488 _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
489 {
490 struct immediate *IM = TNL_CURRENT_IM(ctx);
491
492 /* Use the installed immediate struct. No vertices in the current
493 * immediate, no copied vertices in the system.
494 */
495 ASSERT(TNL_CURRENT_IM(ctx));
496 ASSERT(TNL_CURRENT_IM(ctx)->Start == IMM_MAX_COPIED_VERTS);
497 ASSERT(TNL_CURRENT_IM(ctx)->Start == TNL_CURRENT_IM(ctx)->Count);
498 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
499
500 /* Set current Begin/End state to unknown:
501 */
502 IM->BeginState = VERT_BEGIN_0;
503 ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
504 }
505
506
507 void
508 _tnl_dlist_init( GLcontext *ctx )
509 {
510 TNLcontext *tnl = TNL_CONTEXT(ctx);
511
512 tnl->opcode_vertex_cassette =
513 _mesa_alloc_opcode( ctx,
514 sizeof(TNLvertexcassette),
515 execute_compiled_cassette,
516 destroy_compiled_cassette,
517 print_compiled_cassette );
518 }
519
520
521 /**
522 * Call glMaterialfv for the attributes specified by bitmask, using the
523 * material colors in src.
524 */
525 static void
526 emit_material( const struct gl_material *src, GLuint bitmask )
527 {
528 if (bitmask & FRONT_EMISSION_BIT)
529 glMaterialfv( GL_FRONT, GL_EMISSION, src[0].Emission );
530
531 if (bitmask & BACK_EMISSION_BIT)
532 glMaterialfv( GL_BACK, GL_EMISSION, src[1].Emission );
533
534 if (bitmask & FRONT_AMBIENT_BIT)
535 glMaterialfv( GL_FRONT, GL_AMBIENT, src[0].Ambient );
536
537 if (bitmask & BACK_AMBIENT_BIT)
538 glMaterialfv( GL_BACK, GL_AMBIENT, src[1].Ambient );
539
540 if (bitmask & FRONT_DIFFUSE_BIT)
541 glMaterialfv( GL_FRONT, GL_DIFFUSE, src[0].Diffuse );
542
543 if (bitmask & BACK_DIFFUSE_BIT)
544 glMaterialfv( GL_BACK, GL_DIFFUSE, src[1].Diffuse );
545
546 if (bitmask & FRONT_SPECULAR_BIT)
547 glMaterialfv( GL_FRONT, GL_SPECULAR, src[0].Specular );
548
549 if (bitmask & BACK_SPECULAR_BIT)
550 glMaterialfv( GL_BACK, GL_SPECULAR, src[1].Specular );
551
552 if (bitmask & FRONT_SHININESS_BIT)
553 glMaterialfv( GL_FRONT, GL_SHININESS, &src[0].Shininess );
554
555 if (bitmask & BACK_SHININESS_BIT)
556 glMaterialfv( GL_BACK, GL_SHININESS, &src[1].Shininess );
557
558 if (bitmask & FRONT_INDEXES_BIT) {
559 GLfloat ind[3];
560 ind[0] = src[0].AmbientIndex;
561 ind[1] = src[0].DiffuseIndex;
562 ind[2] = src[0].SpecularIndex;
563 glMaterialfv( GL_FRONT, GL_COLOR_INDEXES, ind );
564 }
565
566 if (bitmask & BACK_INDEXES_BIT) {
567 GLfloat ind[3];
568 ind[0] = src[1].AmbientIndex;
569 ind[1] = src[1].DiffuseIndex;
570 ind[2] = src[1].SpecularIndex;
571 glMaterialfv( GL_BACK, GL_COLOR_INDEXES, ind );
572 }
573 }
574
575
576 /* Low-performance helper function to allow driver-supplied tnl
577 * modules to process tnl display lists. This is primarily supplied
578 * to avoid fallbacks if CallList is invoked inside a Begin/End pair.
579 * For higher performance, drivers should fallback to tnl (if outside
580 * begin/end), or (for tnl hardware) implement their own display list
581 * mechanism.
582 */
583 static void
584 loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM )
585 {
586 const GLuint *flags = IM->Flag;
587 const GLuint orflag = IM->OrFlag;
588 void (GLAPIENTRY *vertex)( const GLfloat * );
589 void (GLAPIENTRY *texcoordfv[MAX_TEXTURE_COORD_UNITS])( GLenum, const GLfloat * );
590 GLuint i, j, p, length, prim = 0, maxtex = 0;
591
592 if (orflag & VERT_BITS_OBJ_234)
593 vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex4fv;
594 else
595 vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex3fv;
596
597 if (orflag & VERT_BITS_TEX_ANY) {
598 for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) {
599 if (orflag & VERT_BIT_TEX(j)) {
600 maxtex = j+1;
601 if ((IM->TexSize & TEX_SIZE_4(j)) == TEX_SIZE_4(j))
602 texcoordfv[j] = glMultiTexCoord4fvARB;
603 else if (IM->TexSize & TEX_SIZE_3(j))
604 texcoordfv[j] = glMultiTexCoord3fvARB;
605 else
606 texcoordfv[j] = glMultiTexCoord2fvARB;
607 }
608 }
609 }
610
611 for (p = IM->Start ; !(prim & PRIM_LAST) ; p += length)
612 {
613 prim = IM->Primitive[p];
614 length= IM->PrimitiveLength[p];
615 ASSERT(length || (prim & PRIM_LAST));
616 ASSERT((prim & PRIM_MODE_MASK) <= GL_POLYGON+1);
617
618 if (prim & PRIM_BEGIN) {
619 glBegin(prim & PRIM_MODE_MASK);
620 }
621
622 for ( i = p ; i <= p+length ; i++) {
623 if (flags[i] & VERT_BITS_TEX_ANY) {
624 GLuint k;
625 for (k = 0 ; k < maxtex ; k++) {
626 if (flags[i] & VERT_BIT_TEX(k)) {
627 texcoordfv[k]( GL_TEXTURE0_ARB + k,
628 IM->Attrib[VERT_ATTRIB_TEX0 + k][i] );
629 }
630 }
631 }
632
633 if (flags[i] & VERT_BIT_NORMAL)
634 glNormal3fv(IM->Attrib[VERT_ATTRIB_NORMAL][i]);
635
636 if (flags[i] & VERT_BIT_COLOR0)
637 glColor4fv( IM->Attrib[VERT_ATTRIB_COLOR0][i] );
638
639 if (flags[i] & VERT_BIT_COLOR1)
640 _glapi_Dispatch->SecondaryColor3fvEXT( IM->Attrib[VERT_ATTRIB_COLOR1][i] );
641
642 if (flags[i] & VERT_BIT_FOG)
643 _glapi_Dispatch->FogCoordfEXT( IM->Attrib[VERT_ATTRIB_FOG][i][0] );
644
645 if (flags[i] & VERT_BIT_INDEX)
646 glIndexi( IM->Index[i] );
647
648 if (flags[i] & VERT_BIT_EDGEFLAG)
649 glEdgeFlag( IM->EdgeFlag[i] );
650
651 if (flags[i] & VERT_BIT_MATERIAL)
652 emit_material( IM->Material[i], IM->MaterialMask[i] );
653
654 if (flags[i]&VERT_BITS_OBJ_234)
655 vertex( IM->Attrib[VERT_ATTRIB_POS][i] );
656 else if (flags[i] & VERT_BIT_EVAL_C1)
657 glEvalCoord1f( IM->Attrib[VERT_ATTRIB_POS][i][0] );
658 else if (flags[i] & VERT_BIT_EVAL_P1)
659 glEvalPoint1( (GLint) IM->Attrib[VERT_ATTRIB_POS][i][0] );
660 else if (flags[i] & VERT_BIT_EVAL_C2)
661 glEvalCoord2f( IM->Attrib[VERT_ATTRIB_POS][i][0],
662 IM->Attrib[VERT_ATTRIB_POS][i][1] );
663 else if (flags[i] & VERT_BIT_EVAL_P2)
664 glEvalPoint2( (GLint) IM->Attrib[VERT_ATTRIB_POS][i][0],
665 (GLint) IM->Attrib[VERT_ATTRIB_POS][i][1] );
666 }
667
668 if (prim & PRIM_END) {
669 glEnd();
670 }
671 }
672 }