Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
56 pj 1
/* $Id: t_imm_dlist.c,v 1.1 2003-02-28 11:48:06 pj 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 <keith@tungstengraphics.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
}