xref: /reactos/dll/opengl/mesa/varray.c (revision 7eead935)
1 /* $Id: varray.c,v 1.17 1998/02/03 01:40:45 brianp Exp $ */
2 
3 /*
4  * Mesa 3-D graphics library
5  * Version:  2.4
6  * Copyright (C) 1995-1997  Brian Paul
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 
24 /*
25  * $Log: varray.c,v $
26  * Revision 1.17  1998/02/03 01:40:45  brianp
27  * fixed a few expressions for Amiga compilation (Sam Jordan)
28  *
29  * Revision 1.16  1997/08/14 01:15:47  brianp
30  * gl_ArrayElement()'s assignment of current normal was wrong
31  *
32  * Revision 1.15  1997/07/24 01:25:54  brianp
33  * changed precompiled header symbol from PCH to PC_HEADER
34  *
35  * Revision 1.14  1997/06/20 02:50:19  brianp
36  * replaced Current.IntColor with Current.ByteColor
37  *
38  * Revision 1.13  1997/05/28 03:26:49  brianp
39  * added precompiled header (PCH) support
40  *
41  * Revision 1.12  1997/05/24 12:07:43  brianp
42  * colors weren't being used in gl_ArrayElement()
43  *
44  * Revision 1.11  1997/04/20 20:29:11  brianp
45  * replaced abort() with gl_problem()
46  *
47  * Revision 1.10  1997/04/02 03:12:31  brianp
48  * misc changes for new vertex buffer organization
49  *
50  * Revision 1.9  1997/01/30 21:05:03  brianp
51  * moved gl_GetPointerv() to get.c
52  *
53  * Revision 1.8  1996/12/18 20:00:57  brianp
54  * gl_set_material() now takes a bitmask instead of face and pname
55  *
56  * Revision 1.7  1996/12/07 10:21:28  brianp
57  * call gl_set_material() instead of gl_Materialfv()
58  *
59  * Revision 1.6  1996/11/09 03:12:34  brianp
60  * now call gl_render_vb() after gl_transform_vb_part2() call
61  *
62  * Revision 1.5  1996/10/08 00:05:06  brianp
63  * added some missing stuff to gl_ArrayElement()
64  *
65  * Revision 1.4  1996/10/04 02:37:06  brianp
66  * gl_ArrayElement() wasn't always initializing vertex Z and W values
67  *
68  * Revision 1.3  1996/10/03 00:47:56  brianp
69  * added #include <stdlib.h> for abort()
70  *
71  * Revision 1.2  1996/09/27 01:33:07  brianp
72  * added missing default cases to switches
73  *
74  * Revision 1.1  1996/09/13 01:38:16  brianp
75  * Initial revision
76  *
77  */
78 
79 
80 
81 /*
82  * NOTE:  At this time, only three vertex array configurations are optimized:
83  *  1.  glVertex3fv(), zero stride
84  *  2.  glNormal3fv() with glVertex3fv(), zero stride
85  *  3.  glNormal3fv() with glVertex4fv(), zero stride
86  *
87  * More optimized array configurations can be added.
88  */
89 
90 
91 #ifdef PC_HEADER
92 #include "all.h"
93 #else
94 #include <stdlib.h>
95 #include <string.h>
96 #include "context.h"
97 #include "enable.h"
98 #include "dlist.h"
99 #include "light.h"
100 #include "macros.h"
101 #include "types.h"
102 #include "varray.h"
103 #include "vb.h"
104 #include "vbfill.h"
105 #include "vbrender.h"
106 #include "vbxform.h"
107 #include "xform.h"
108 #endif
109 
110 
111 void gl_VertexPointer( GLcontext *ctx,
112                        GLint size, GLenum type, GLsizei stride,
113                        const GLvoid *ptr )
114 {
115    if (size<2 || size>4) {
116       gl_error( ctx, GL_INVALID_VALUE, "glVertexPointer(size)" );
117       return;
118    }
119    if (stride<0) {
120       gl_error( ctx, GL_INVALID_VALUE, "glVertexPointer(stride)" );
121       return;
122    }
123    switch (type) {
124       case GL_SHORT:
125          ctx->Array.VertexStrideB = stride ? stride : size*sizeof(GLshort);
126          break;
127       case GL_INT:
128          ctx->Array.VertexStrideB = stride ? stride : size*sizeof(GLint);
129          break;
130       case GL_FLOAT:
131          ctx->Array.VertexStrideB = stride ? stride : size*sizeof(GLfloat);
132          break;
133       case GL_DOUBLE:
134          ctx->Array.VertexStrideB = stride ? stride : size*sizeof(GLdouble);
135          break;
136       default:
137          gl_error( ctx, GL_INVALID_ENUM, "glVertexPointer(type)" );
138          return;
139    }
140    ctx->Array.VertexSize = size;
141    ctx->Array.VertexType = type;
142    ctx->Array.VertexStride = stride;
143    ctx->Array.VertexPtr = (void *) ptr;
144 }
145 
146 
147 
148 
149 void gl_NormalPointer( GLcontext *ctx,
150                        GLenum type, GLsizei stride, const GLvoid *ptr )
151 {
152    if (stride<0) {
153       gl_error( ctx, GL_INVALID_VALUE, "glNormalPointer(stride)" );
154       return;
155    }
156    switch (type) {
157       case GL_BYTE:
158          ctx->Array.NormalStrideB = stride ? stride : 3*sizeof(GLbyte);
159          break;
160       case GL_SHORT:
161          ctx->Array.NormalStrideB = stride ? stride : 3*sizeof(GLshort);
162          break;
163       case GL_INT:
164          ctx->Array.NormalStrideB = stride ? stride : 3*sizeof(GLint);
165          break;
166       case GL_FLOAT:
167          ctx->Array.NormalStrideB = stride ? stride : 3*sizeof(GLfloat);
168          break;
169       case GL_DOUBLE:
170          ctx->Array.NormalStrideB = stride ? stride : 3*sizeof(GLdouble);
171          break;
172       default:
173          gl_error( ctx, GL_INVALID_ENUM, "glNormalPointer(type)" );
174          return;
175    }
176    ctx->Array.NormalType = type;
177    ctx->Array.NormalStride = stride;
178    ctx->Array.NormalPtr = (void *) ptr;
179 }
180 
181 
182 
183 void gl_ColorPointer( GLcontext *ctx,
184                       GLint size, GLenum type, GLsizei stride,
185                       const GLvoid *ptr )
186 {
187    if (size<3 || size>4) {
188       gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(size)" );
189       return;
190    }
191    if (stride<0) {
192       gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(stride)" );
193       return;
194    }
195    switch (type) {
196       case GL_BYTE:
197          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLbyte);
198          break;
199       case GL_UNSIGNED_BYTE:
200          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLubyte);
201          break;
202       case GL_SHORT:
203          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLshort);
204          break;
205       case GL_UNSIGNED_SHORT:
206          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLushort);
207          break;
208       case GL_INT:
209          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLint);
210          break;
211       case GL_UNSIGNED_INT:
212          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLuint);
213          break;
214       case GL_FLOAT:
215          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLfloat);
216          break;
217       case GL_DOUBLE:
218          ctx->Array.ColorStrideB = stride ? stride : size*sizeof(GLdouble);
219          break;
220       default:
221          gl_error( ctx, GL_INVALID_ENUM, "glColorPointer(type)" );
222          return;
223    }
224    ctx->Array.ColorSize = size;
225    ctx->Array.ColorType = type;
226    ctx->Array.ColorStride = stride;
227    ctx->Array.ColorPtr = (void *) ptr;
228 }
229 
230 
231 
232 void gl_IndexPointer( GLcontext *ctx,
233                       GLenum type, GLsizei stride, const GLvoid *ptr )
234 {
235    if (stride<0) {
236       gl_error( ctx, GL_INVALID_VALUE, "glIndexPointer(stride)" );
237       return;
238    }
239    switch (type) {
240       case GL_SHORT:
241          ctx->Array.IndexStrideB = stride ? stride : sizeof(GLbyte);
242          break;
243       case GL_INT:
244          ctx->Array.IndexStrideB = stride ? stride : sizeof(GLint);
245          break;
246       case GL_FLOAT:
247          ctx->Array.IndexStrideB = stride ? stride : sizeof(GLfloat);
248          break;
249       case GL_DOUBLE:
250          ctx->Array.IndexStrideB = stride ? stride : sizeof(GLdouble);
251          break;
252       default:
253          gl_error( ctx, GL_INVALID_ENUM, "glIndexPointer(type)" );
254          return;
255    }
256    ctx->Array.IndexType = type;
257    ctx->Array.IndexStride = stride;
258    ctx->Array.IndexPtr = (void *) ptr;
259 }
260 
261 
262 
263 void gl_TexCoordPointer( GLcontext *ctx,
264                          GLint size, GLenum type, GLsizei stride,
265                          const GLvoid *ptr )
266 {
267    if (size<1 || size>4) {
268       gl_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(size)" );
269       return;
270    }
271    switch (type) {
272       case GL_SHORT:
273          ctx->Array.TexCoordStrideB = stride ? stride : size*sizeof(GLshort);
274          break;
275       case GL_INT:
276          ctx->Array.TexCoordStrideB = stride ? stride : size*sizeof(GLint);
277          break;
278       case GL_FLOAT:
279          ctx->Array.TexCoordStrideB = stride ? stride : size*sizeof(GLfloat);
280          break;
281       case GL_DOUBLE:
282          ctx->Array.TexCoordStrideB = stride ? stride : size*sizeof(GLdouble);
283          break;
284       default:
285          gl_error( ctx, GL_INVALID_ENUM, "glTexCoordPointer(type)" );
286          return;
287    }
288    if (stride<0) {
289       gl_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(stride)" );
290       return;
291    }
292    ctx->Array.TexCoordSize = size;
293    ctx->Array.TexCoordType = type;
294    ctx->Array.TexCoordStride = stride;
295    ctx->Array.TexCoordPtr = (void *) ptr;
296 }
297 
298 
299 
300 void gl_EdgeFlagPointer( GLcontext *ctx,
301                          GLsizei stride, const GLboolean *ptr )
302 {
303    if (stride<0) {
304       gl_error( ctx, GL_INVALID_VALUE, "glEdgeFlagPointer(stride)" );
305       return;
306    }
307    ctx->Array.EdgeFlagStride = stride;
308    ctx->Array.EdgeFlagStrideB = stride ? stride : sizeof(GLboolean);
309    ctx->Array.EdgeFlagPtr = (GLboolean *) ptr;
310 }
311 
312 
313 
314 /*
315  * Execute
316  */
317 void gl_ArrayElement( GLcontext *ctx, GLint i )
318 {
319    struct vertex_buffer *VB = ctx->VB;
320    GLint count = VB->Count;
321 
322    /* copy vertex data into the Vertex Buffer */
323 
324    if (ctx->Array.NormalEnabled) {
325       GLbyte *p = (GLbyte*) ctx->Array.NormalPtr
326                   + i * ctx->Array.NormalStrideB;
327       switch (ctx->Array.NormalType) {
328          case GL_BYTE:
329             VB->Normal[count][0] = BYTE_TO_FLOAT( p[0] );
330             VB->Normal[count][1] = BYTE_TO_FLOAT( p[1] );
331             VB->Normal[count][2] = BYTE_TO_FLOAT( p[2] );
332             break;
333          case GL_SHORT:
334             VB->Normal[count][0] = SHORT_TO_FLOAT( ((GLshort*)p)[0] );
335             VB->Normal[count][1] = SHORT_TO_FLOAT( ((GLshort*)p)[1] );
336             VB->Normal[count][2] = SHORT_TO_FLOAT( ((GLshort*)p)[2] );
337             break;
338          case GL_INT:
339             VB->Normal[count][0] = INT_TO_FLOAT( ((GLint*)p)[0] );
340             VB->Normal[count][1] = INT_TO_FLOAT( ((GLint*)p)[1] );
341             VB->Normal[count][2] = INT_TO_FLOAT( ((GLint*)p)[2] );
342             break;
343          case GL_FLOAT:
344             VB->Normal[count][0] = ((GLfloat*)p)[0];
345             VB->Normal[count][1] = ((GLfloat*)p)[1];
346             VB->Normal[count][2] = ((GLfloat*)p)[2];
347             break;
348          case GL_DOUBLE:
349             VB->Normal[count][0] = ((GLdouble*)p)[0];
350             VB->Normal[count][1] = ((GLdouble*)p)[1];
351             VB->Normal[count][2] = ((GLdouble*)p)[2];
352             break;
353          default:
354             gl_problem(ctx, "Bad normal type in gl_ArrayElement");
355             return;
356       }
357       VB->MonoNormal = GL_FALSE;
358    }
359    else {
360       VB->Normal[count][0] = ctx->Current.Normal[0];
361       VB->Normal[count][1] = ctx->Current.Normal[1];
362       VB->Normal[count][2] = ctx->Current.Normal[2];
363    }
364 
365    /* TODO: directly set VB->Fcolor instead of calling a glColor command */
366    if (ctx->Array.ColorEnabled) {
367       GLbyte *p = (GLbyte*) ctx->Array.ColorPtr + i * ctx->Array.ColorStrideB;
368       switch (ctx->Array.ColorType) {
369          case GL_BYTE:
370             switch (ctx->Array.ColorSize) {
371                case 4:   glColor4bv( (GLbyte*) p );   break;
372                case 3:   glColor3bv( (GLbyte*) p );   break;
373             }
374             break;
375          case GL_UNSIGNED_BYTE:
376             switch (ctx->Array.ColorSize) {
377                case 3:   glColor3ubv( (GLubyte*) p );   break;
378                case 4:   glColor4ubv( (GLubyte*) p );   break;
379             }
380             break;
381          case GL_SHORT:
382             switch (ctx->Array.ColorSize) {
383                case 3:   glColor3sv( (GLshort*) p );   break;
384                case 4:   glColor4sv( (GLshort*) p );   break;
385             }
386             break;
387          case GL_UNSIGNED_SHORT:
388             switch (ctx->Array.ColorSize) {
389                case 3:   glColor3usv( (GLushort*) p );   break;
390                case 4:   glColor4usv( (GLushort*) p );   break;
391             }
392             break;
393          case GL_INT:
394             switch (ctx->Array.ColorSize) {
395                case 3:   glColor3iv( (GLint*) p );   break;
396                case 4:   glColor4iv( (GLint*) p );   break;
397             }
398             break;
399          case GL_UNSIGNED_INT:
400             switch (ctx->Array.ColorSize) {
401                case 3:   glColor3uiv( (GLuint*) p );   break;
402                case 4:   glColor4uiv( (GLuint*) p );   break;
403             }
404             break;
405          case GL_FLOAT:
406             switch (ctx->Array.ColorSize) {
407                case 3:   glColor3fv( (GLfloat*) p );   break;
408                case 4:   glColor4fv( (GLfloat*) p );   break;
409             }
410             break;
411          case GL_DOUBLE:
412             switch (ctx->Array.ColorSize) {
413                case 3:   glColor3dv( (GLdouble*) p );   break;
414                case 4:   glColor4dv( (GLdouble*) p );   break;
415             }
416             break;
417          default:
418             gl_problem(ctx, "Bad color type in gl_ArrayElement");
419             return;
420       }
421       ctx->VB->MonoColor = GL_FALSE;
422    }
423 
424    /* current color has been updated. store in vertex buffer now */
425    {
426       COPY_4UBV( VB->Fcolor[count], ctx->Current.ByteColor );
427       if (ctx->Light.ColorMaterialEnabled) {
428          GLfloat color[4];
429          color[0] = ctx->Current.ByteColor[0] * ctx->Visual->InvRedScale;
430          color[1] = ctx->Current.ByteColor[1] * ctx->Visual->InvGreenScale;
431          color[2] = ctx->Current.ByteColor[2] * ctx->Visual->InvBlueScale;
432          color[3] = ctx->Current.ByteColor[3] * ctx->Visual->InvAlphaScale;
433          gl_set_material( ctx, ctx->Light.ColorMaterialBitmask, color );
434       }
435    }
436 
437    if (ctx->Array.IndexEnabled) {
438       GLbyte *p = (GLbyte*) ctx->Array.IndexPtr + i * ctx->Array.IndexStrideB;
439       switch (ctx->Array.IndexType) {
440          case GL_SHORT:
441             VB->Findex[count] = (GLuint) (*((GLshort*) p));
442             break;
443          case GL_INT:
444             VB->Findex[count] = (GLuint) (*((GLint*) p));
445             break;
446          case GL_FLOAT:
447             VB->Findex[count] = (GLuint) (*((GLfloat*) p));
448             break;
449          case GL_DOUBLE:
450             VB->Findex[count] = (GLuint) (*((GLdouble*) p));
451             break;
452          default:
453             gl_problem(ctx, "Bad index type in gl_ArrayElement");
454             return;
455       }
456       ctx->VB->MonoColor = GL_FALSE;
457    }
458    else {
459       VB->Findex[count] = ctx->Current.Index;
460    }
461 
462    if (ctx->Array.TexCoordEnabled) {
463       GLbyte *p = (GLbyte*) ctx->Array.TexCoordPtr
464                   + i * ctx->Array.TexCoordStrideB;
465       VB->TexCoord[count][1] = 0.0F;
466       VB->TexCoord[count][2] = 0.0F;
467       VB->TexCoord[count][3] = 1.0F;
468       switch (ctx->Array.TexCoordType) {
469          case GL_SHORT:
470             switch (ctx->Array.TexCoordSize) {
471                /* FALL THROUGH! */
472                case 4:   VB->TexCoord[count][3] = ((GLshort*) p)[3];
473                case 3:   VB->TexCoord[count][2] = ((GLshort*) p)[2];
474                case 2:   VB->TexCoord[count][1] = ((GLshort*) p)[1];
475                case 1:   VB->TexCoord[count][0] = ((GLshort*) p)[0];
476             }
477             break;
478          case GL_INT:
479             switch (ctx->Array.TexCoordSize) {
480                /* FALL THROUGH! */
481                case 4:   VB->TexCoord[count][3] = ((GLint*) p)[3];
482                case 3:   VB->TexCoord[count][2] = ((GLint*) p)[2];
483                case 2:   VB->TexCoord[count][1] = ((GLint*) p)[1];
484                case 1:   VB->TexCoord[count][0] = ((GLint*) p)[0];
485             }
486             break;
487          case GL_FLOAT:
488             switch (ctx->Array.TexCoordSize) {
489                /* FALL THROUGH! */
490                case 4:   VB->TexCoord[count][3] = ((GLfloat*) p)[3];
491                case 3:   VB->TexCoord[count][2] = ((GLfloat*) p)[2];
492                case 2:   VB->TexCoord[count][1] = ((GLfloat*) p)[1];
493                case 1:   VB->TexCoord[count][0] = ((GLfloat*) p)[0];
494             }
495             break;
496          case GL_DOUBLE:
497             switch (ctx->Array.TexCoordSize) {
498                /* FALL THROUGH! */
499                case 4:   VB->TexCoord[count][3] = ((GLdouble*) p)[3];
500                case 3:   VB->TexCoord[count][2] = ((GLdouble*) p)[2];
501                case 2:   VB->TexCoord[count][1] = ((GLdouble*) p)[1];
502                case 1:   VB->TexCoord[count][0] = ((GLdouble*) p)[0];
503             }
504             break;
505          default:
506             gl_problem(ctx, "Bad texcoord type in gl_ArrayElement");
507             return;
508       }
509    }
510    else {
511       COPY_4V( VB->TexCoord[count], ctx->Current.TexCoord );
512    }
513 
514    if (ctx->Array.EdgeFlagEnabled) {
515       GLbyte *b = (GLbyte*) ctx->Array.EdgeFlagPtr
516                   + i * ctx->Array.EdgeFlagStrideB;
517       VB->Edgeflag[count] = *((GLboolean*) b);
518    }
519    else {
520       VB->Edgeflag[count] = ctx->Current.EdgeFlag;
521    }
522 
523    if (ctx->Array.VertexEnabled) {
524       GLbyte *b = (GLbyte*) ctx->Array.VertexPtr
525                   + i * ctx->Array.VertexStrideB;
526       VB->Obj[count][2] = 0.0F;
527       VB->Obj[count][3] = 1.0F;
528       switch (ctx->Array.VertexType) {
529          case GL_SHORT:
530             switch (ctx->Array.VertexSize) {
531                /* FALL THROUGH */
532                case 4:   VB->Obj[count][3] = ((GLshort*) b)[3];
533                case 3:   VB->Obj[count][2] = ((GLshort*) b)[2];
534                case 2:   VB->Obj[count][1] = ((GLshort*) b)[1];
535                          VB->Obj[count][0] = ((GLshort*) b)[0];
536             }
537             break;
538          case GL_INT:
539             switch (ctx->Array.VertexSize) {
540                /* FALL THROUGH */
541                case 4:   VB->Obj[count][3] = ((GLint*) b)[3];
542                case 3:   VB->Obj[count][2] = ((GLint*) b)[2];
543                case 2:   VB->Obj[count][1] = ((GLint*) b)[1];
544                          VB->Obj[count][0] = ((GLint*) b)[0];
545             }
546             break;
547          case GL_FLOAT:
548             switch (ctx->Array.VertexSize) {
549                /* FALL THROUGH */
550                case 4:   VB->Obj[count][3] = ((GLfloat*) b)[3];
551                case 3:   VB->Obj[count][2] = ((GLfloat*) b)[2];
552                case 2:   VB->Obj[count][1] = ((GLfloat*) b)[1];
553                          VB->Obj[count][0] = ((GLfloat*) b)[0];
554             }
555             break;
556          case GL_DOUBLE:
557             switch (ctx->Array.VertexSize) {
558                /* FALL THROUGH */
559                case 4:   VB->Obj[count][3] = ((GLdouble*) b)[3];
560                case 3:   VB->Obj[count][2] = ((GLdouble*) b)[2];
561                case 2:   VB->Obj[count][1] = ((GLdouble*) b)[1];
562                          VB->Obj[count][0] = ((GLdouble*) b)[0];
563             }
564             break;
565          default:
566             gl_problem(ctx, "Bad vertex type in gl_ArrayElement");
567             return;
568       }
569 
570       /* Only store vertex if Vertex array pointer is enabled */
571       count++;
572       VB->Count = count;
573       if (count==VB_MAX) {
574          gl_transform_vb_part1( ctx, GL_FALSE );
575       }
576 
577    }
578    else {
579       /* vertex array pointer not enabled: no vertex to process */
580    }
581 }
582 
583 
584 
585 
586 /*
587  * Save into display list
588  * Use external API entry points since speed isn't too important here
589  * and makes the code simpler.  Also, if GL_COMPILE_AND_EXECUTE then
590  * execute will happen too.
591  */
592 void gl_save_ArrayElement( GLcontext *ctx, GLint i )
593 {
594    if (ctx->Array.NormalEnabled) {
595       GLbyte *p = (GLbyte*) ctx->Array.NormalPtr
596                   + i * ctx->Array.NormalStrideB;
597       switch (ctx->Array.NormalType) {
598          case GL_BYTE:
599             glNormal3bv( (GLbyte*) p );
600             break;
601          case GL_SHORT:
602             glNormal3sv( (GLshort*) p );
603             break;
604          case GL_INT:
605             glNormal3iv( (GLint*) p );
606             break;
607          case GL_FLOAT:
608             glNormal3fv( (GLfloat*) p );
609             break;
610          case GL_DOUBLE:
611             glNormal3dv( (GLdouble*) p );
612             break;
613          default:
614             gl_problem(ctx, "Bad normal type in gl_save_ArrayElement");
615             return;
616       }
617    }
618 
619    if (ctx->Array.ColorEnabled) {
620       GLbyte *p = (GLbyte*) ctx->Array.ColorPtr + i * ctx->Array.ColorStrideB;
621       switch (ctx->Array.ColorType) {
622          case GL_BYTE:
623             switch (ctx->Array.ColorSize) {
624                case 3:   glColor3bv( (GLbyte*) p );   break;
625                case 4:   glColor4bv( (GLbyte*) p );   break;
626             }
627             break;
628          case GL_UNSIGNED_BYTE:
629             switch (ctx->Array.ColorSize) {
630                case 3:   glColor3ubv( (GLubyte*) p );   break;
631                case 4:   glColor4ubv( (GLubyte*) p );   break;
632             }
633             break;
634          case GL_SHORT:
635             switch (ctx->Array.ColorSize) {
636                case 3:   glColor3sv( (GLshort*) p );   break;
637                case 4:   glColor4sv( (GLshort*) p );   break;
638             }
639             break;
640          case GL_UNSIGNED_SHORT:
641             switch (ctx->Array.ColorSize) {
642                case 3:   glColor3usv( (GLushort*) p );   break;
643                case 4:   glColor4usv( (GLushort*) p );   break;
644             }
645             break;
646          case GL_INT:
647             switch (ctx->Array.ColorSize) {
648                case 3:   glColor3iv( (GLint*) p );   break;
649                case 4:   glColor4iv( (GLint*) p );   break;
650             }
651             break;
652          case GL_UNSIGNED_INT:
653             switch (ctx->Array.ColorSize) {
654                case 3:   glColor3uiv( (GLuint*) p );   break;
655                case 4:   glColor4uiv( (GLuint*) p );   break;
656             }
657             break;
658          case GL_FLOAT:
659             switch (ctx->Array.ColorSize) {
660                case 3:   glColor3fv( (GLfloat*) p );   break;
661                case 4:   glColor4fv( (GLfloat*) p );   break;
662             }
663             break;
664          case GL_DOUBLE:
665             switch (ctx->Array.ColorSize) {
666                case 3:   glColor3dv( (GLdouble*) p );   break;
667                case 4:   glColor4dv( (GLdouble*) p );   break;
668             }
669             break;
670          default:
671             gl_problem(ctx, "Bad color type in gl_save_ArrayElement");
672             return;
673       }
674    }
675 
676    if (ctx->Array.IndexEnabled) {
677       GLbyte *p = (GLbyte*) ctx->Array.IndexPtr + i * ctx->Array.IndexStrideB;
678       switch (ctx->Array.IndexType) {
679          case GL_SHORT:
680             glIndexsv( (GLshort*) p );
681             break;
682          case GL_INT:
683             glIndexiv( (GLint*) p );
684             break;
685          case GL_FLOAT:
686             glIndexfv( (GLfloat*) p );
687             break;
688          case GL_DOUBLE:
689             glIndexdv( (GLdouble*) p );
690             break;
691          default:
692             gl_problem(ctx, "Bad index type in gl_save_ArrayElement");
693             return;
694       }
695    }
696 
697    if (ctx->Array.TexCoordEnabled) {
698       GLbyte *p = (GLbyte*) ctx->Array.TexCoordPtr
699                   + i * ctx->Array.TexCoordStrideB;
700       switch (ctx->Array.TexCoordType) {
701          case GL_SHORT:
702             switch (ctx->Array.TexCoordSize) {
703                case 1:   glTexCoord1sv( (GLshort*) p );   break;
704                case 2:   glTexCoord2sv( (GLshort*) p );   break;
705                case 3:   glTexCoord3sv( (GLshort*) p );   break;
706                case 4:   glTexCoord4sv( (GLshort*) p );   break;
707             }
708             break;
709          case GL_INT:
710             switch (ctx->Array.TexCoordSize) {
711                case 1:   glTexCoord1iv( (GLint*) p );   break;
712                case 2:   glTexCoord2iv( (GLint*) p );   break;
713                case 3:   glTexCoord3iv( (GLint*) p );   break;
714                case 4:   glTexCoord4iv( (GLint*) p );   break;
715             }
716             break;
717          case GL_FLOAT:
718             switch (ctx->Array.TexCoordSize) {
719                case 1:   glTexCoord1fv( (GLfloat*) p );   break;
720                case 2:   glTexCoord2fv( (GLfloat*) p );   break;
721                case 3:   glTexCoord3fv( (GLfloat*) p );   break;
722                case 4:   glTexCoord4fv( (GLfloat*) p );   break;
723             }
724             break;
725          case GL_DOUBLE:
726             switch (ctx->Array.TexCoordSize) {
727                case 1:   glTexCoord1dv( (GLdouble*) p );   break;
728                case 2:   glTexCoord2dv( (GLdouble*) p );   break;
729                case 3:   glTexCoord3dv( (GLdouble*) p );   break;
730                case 4:   glTexCoord4dv( (GLdouble*) p );   break;
731             }
732             break;
733          default:
734             gl_problem(ctx, "Bad texcoord type in gl_save_ArrayElement");
735             return;
736       }
737    }
738 
739    if (ctx->Array.EdgeFlagEnabled) {
740       GLbyte *b = (GLbyte*) ctx->Array.EdgeFlagPtr + i * ctx->Array.EdgeFlagStrideB;
741       glEdgeFlagv( (GLboolean*) b );
742    }
743 
744    if (ctx->Array.VertexEnabled) {
745       GLbyte *b = (GLbyte*) ctx->Array.VertexPtr
746                   + i * ctx->Array.VertexStrideB;
747       switch (ctx->Array.VertexType) {
748          case GL_SHORT:
749             switch (ctx->Array.VertexSize) {
750                case 2:   glVertex2sv( (GLshort*) b );   break;
751                case 3:   glVertex3sv( (GLshort*) b );   break;
752                case 4:   glVertex4sv( (GLshort*) b );   break;
753             }
754             break;
755          case GL_INT:
756             switch (ctx->Array.VertexSize) {
757                case 2:   glVertex2iv( (GLint*) b );   break;
758                case 3:   glVertex3iv( (GLint*) b );   break;
759                case 4:   glVertex4iv( (GLint*) b );   break;
760             }
761             break;
762          case GL_FLOAT:
763             switch (ctx->Array.VertexSize) {
764                case 2:   glVertex2fv( (GLfloat*) b );   break;
765                case 3:   glVertex3fv( (GLfloat*) b );   break;
766                case 4:   glVertex4fv( (GLfloat*) b );   break;
767             }
768             break;
769          case GL_DOUBLE:
770             switch (ctx->Array.VertexSize) {
771                case 2:   glVertex2dv( (GLdouble*) b );   break;
772                case 3:   glVertex3dv( (GLdouble*) b );   break;
773                case 4:   glVertex4dv( (GLdouble*) b );   break;
774             }
775             break;
776          default:
777             gl_problem(ctx, "Bad vertex type in gl_save_ArrayElement");
778             return;
779       }
780    }
781 }
782 
783 
784 
785 /*
786  * Execute
787  */
788 void gl_DrawArrays( GLcontext *ctx,
789                     GLenum mode, GLint first, GLsizei count )
790 {
791    struct vertex_buffer* VB = ctx->VB;
792 
793    GLint i;
794    GLboolean need_edges;
795 
796    if (INSIDE_BEGIN_END(ctx)) {
797       gl_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
798       return;
799    }
800    if (count<0) {
801       gl_error( ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
802       return;
803    }
804 
805    if (ctx->Primitive==GL_TRIANGLES || ctx->Primitive==GL_QUADS
806        || ctx->Primitive==GL_POLYGON) {
807       need_edges = GL_TRUE;
808    }
809    else {
810       need_edges = GL_FALSE;
811    }
812 
813    if (!ctx->Light.Enabled
814        && !ctx->Texture.Enabled
815        && ctx->Array.VertexEnabled && ctx->Array.VertexType==GL_FLOAT
816        && ctx->Array.VertexStride==0 && ctx->Array.VertexSize==3
817        && !ctx->Array.NormalEnabled
818        && !ctx->Array.ColorEnabled
819        && !ctx->Array.IndexEnabled
820        && !ctx->Array.TexCoordEnabled
821        && !ctx->Array.EdgeFlagEnabled) {
822       /*
823        * SPECIAL CASE:  glVertex3fv() with no lighting
824        */
825       GLfloat (*vptr)[3];
826       GLint remaining;
827 
828       gl_Begin( ctx, mode );
829 
830       remaining = count;
831       vptr = (GLfloat (*)[3]) ctx->Array.VertexPtr;
832       vptr += 3 * first;
833       while (remaining>0) {
834          GLint vbspace, n;
835 
836          vbspace = VB_MAX - VB->Start;
837          n = MIN2( vbspace, remaining );
838 
839          gl_xform_points_3fv( n, VB->Eye+VB->Start, ctx->ModelViewMatrix, vptr );
840 
841          /* assign vertex colors */
842          {
843             GLint i, start = VB->Start;
844             for (i=0;i<n;i++) {
845                COPY_4UBV( VB->Fcolor[start+i], ctx->Current.ByteColor );
846             }
847          }
848 
849          /* assign polygon edgeflags */
850          if (need_edges) {
851             GLint i;
852             for (i=0;i<n;i++) {
853                VB->Edgeflag[VB->Start+i] = ctx->Current.EdgeFlag;
854             }
855          }
856 
857          remaining -= n;
858 
859          VB->MonoNormal = GL_FALSE;
860          VB->Count = VB->Start + n;
861          gl_transform_vb_part2( ctx, remaining==0 ? GL_TRUE : GL_FALSE );
862 
863          vptr += n;
864       }
865 
866       gl_End( ctx );
867    }
868    else if (!ctx->CompileFlag
869        && ctx->Light.Enabled
870        && !ctx->Texture.Enabled
871        && ctx->Array.VertexEnabled && ctx->Array.VertexType==GL_FLOAT
872        && ctx->Array.VertexStride==0 && ctx->Array.VertexSize==4
873        && ctx->Array.NormalEnabled && ctx->Array.NormalType==GL_FLOAT
874        && ctx->Array.NormalStride==0
875        && !ctx->Array.ColorEnabled
876        && !ctx->Array.IndexEnabled
877        && !ctx->Array.TexCoordEnabled
878        && !ctx->Array.EdgeFlagEnabled) {
879       /*
880        * SPECIAL CASE:  glNormal3fv();  glVertex4fv();  with lighting
881        */
882       GLfloat (*vptr)[4], (*nptr)[3];
883       GLint remaining;
884 
885       gl_Begin( ctx, mode );
886 
887       remaining = count;
888       vptr = (GLfloat (*)[4]) ctx->Array.VertexPtr;
889       vptr += 4 * first;
890       nptr = (GLfloat (*)[3]) ctx->Array.NormalPtr;
891       nptr += 3 * first;
892       while (remaining>0) {
893          GLint vbspace, n;
894 
895          vbspace = VB_MAX - VB->Start;
896          n = MIN2( vbspace, remaining );
897 
898          gl_xform_points_4fv( n, VB->Eye+VB->Start, ctx->ModelViewMatrix, vptr );
899          gl_xform_normals_3fv( n, VB->Normal+VB->Start, ctx->ModelViewInv, nptr,
900                                ctx->Transform.Normalize );
901 
902          /* assign polygon edgeflags */
903          if (need_edges) {
904             GLint i;
905             for (i=0;i<n;i++) {
906                VB->Edgeflag[VB->Start+i] = ctx->Current.EdgeFlag;
907             }
908          }
909 
910          remaining -= n;
911 
912          VB->MonoNormal = GL_FALSE;
913          VB->Count = VB->Start + n;
914          gl_transform_vb_part2( ctx, remaining==0 ? GL_TRUE : GL_FALSE );
915 
916          vptr += n;
917          nptr += n;
918       }
919 
920       gl_End( ctx );
921    }
922    else if (!ctx->CompileFlag
923        && ctx->Light.Enabled
924        && !ctx->Texture.Enabled
925        && ctx->Array.VertexEnabled && ctx->Array.VertexType==GL_FLOAT
926        && ctx->Array.VertexStride==0 && ctx->Array.VertexSize==3
927        && ctx->Array.NormalEnabled && ctx->Array.NormalType==GL_FLOAT
928        && ctx->Array.NormalStride==0
929        && !ctx->Array.ColorEnabled
930        && !ctx->Array.IndexEnabled
931        && !ctx->Array.TexCoordEnabled
932        && !ctx->Array.EdgeFlagEnabled) {
933       /*
934        * SPECIAL CASE:  glNormal3fv();  glVertex3fv();  with lighting
935        */
936       GLfloat (*vptr)[3], (*nptr)[3];
937       GLint remaining;
938 
939       gl_Begin( ctx, mode );
940 
941       remaining = count;
942       vptr = (GLfloat (*)[3]) ctx->Array.VertexPtr;
943       vptr += 3 * first;
944       nptr = (GLfloat (*)[3]) ctx->Array.NormalPtr;
945       nptr += 3 * first;
946       while (remaining>0) {
947          GLint vbspace, n;
948 
949          vbspace = VB_MAX - VB->Start;
950          n = MIN2( vbspace, remaining );
951 
952          gl_xform_points_3fv( n, VB->Eye+VB->Start, ctx->ModelViewMatrix, vptr );
953          gl_xform_normals_3fv( n, VB->Normal+VB->Start, ctx->ModelViewInv, nptr,
954                                ctx->Transform.Normalize );
955 
956          /* assign polygon edgeflags */
957          if (need_edges) {
958             GLint i;
959             for (i=0;i<n;i++) {
960                VB->Edgeflag[VB->Start+i] = ctx->Current.EdgeFlag;
961             }
962          }
963 
964          remaining -= n;
965 
966          VB->MonoNormal = GL_FALSE;
967          VB->Count = VB->Start + n;
968          gl_transform_vb_part2( ctx, remaining==0 ? GL_TRUE : GL_FALSE );
969 
970          vptr += n;
971          nptr += n;
972       }
973 
974       gl_End( ctx );
975    }
976    else {
977       /*
978        * GENERAL CASE:
979        */
980       gl_Begin( ctx, mode );
981       for (i=0;i<count;i++) {
982          gl_ArrayElement( ctx, first+i );
983       }
984       gl_End( ctx );
985    }
986 }
987 
988 
989 
990 /*
991  * Save into a display list
992  */
993 void gl_save_DrawArrays( GLcontext *ctx,
994                          GLenum mode, GLint first, GLsizei count )
995 {
996    GLint i;
997 
998    if (INSIDE_BEGIN_END(ctx)) {
999       gl_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
1000       return;
1001    }
1002    if (count<0) {
1003       gl_error( ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
1004       return;
1005    }
1006    switch (mode) {
1007       case GL_POINTS:
1008       case GL_LINES:
1009       case GL_LINE_STRIP:
1010       case GL_LINE_LOOP:
1011       case GL_TRIANGLES:
1012       case GL_TRIANGLE_STRIP:
1013       case GL_TRIANGLE_FAN:
1014       case GL_QUADS:
1015       case GL_QUAD_STRIP:
1016       case GL_POLYGON:
1017          /* OK */
1018          break;
1019       default:
1020          gl_error( ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
1021          return;
1022    }
1023 
1024 
1025    /* Note: this will do compile AND execute if needed */
1026    gl_save_Begin( ctx, mode );
1027    for (i=0;i<count;i++) {
1028       gl_save_ArrayElement( ctx, first+i );
1029    }
1030    gl_save_End( ctx );
1031 }
1032 
1033 
1034 
1035 
1036 /*
1037  * Execute only
1038  */
1039 void gl_DrawElements( GLcontext *ctx,
1040                       GLenum mode, GLsizei count,
1041                       GLenum type, const GLvoid *indices )
1042 {
1043 
1044    if (INSIDE_BEGIN_END(ctx)) {
1045       gl_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
1046       return;
1047    }
1048    if (count<0) {
1049       gl_error( ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
1050       return;
1051    }
1052    switch (mode) {
1053       case GL_POINTS:
1054       case GL_LINES:
1055       case GL_LINE_STRIP:
1056       case GL_LINE_LOOP:
1057       case GL_TRIANGLES:
1058       case GL_TRIANGLE_STRIP:
1059       case GL_TRIANGLE_FAN:
1060       case GL_QUADS:
1061       case GL_QUAD_STRIP:
1062       case GL_POLYGON:
1063          /* OK */
1064          break;
1065       default:
1066          gl_error( ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
1067          return;
1068    }
1069    switch (type) {
1070       case GL_UNSIGNED_BYTE:
1071          {
1072             GLubyte *ub_indices = (GLubyte *) indices;
1073             GLint i;
1074             gl_Begin( ctx, mode );
1075             for (i=0;i<count;i++) {
1076                gl_ArrayElement( ctx, (GLint) ub_indices[i] );
1077             }
1078             gl_End( ctx );
1079          }
1080          break;
1081       case GL_UNSIGNED_SHORT:
1082          {
1083             GLushort *us_indices = (GLushort *) indices;
1084             GLint i;
1085             gl_Begin( ctx, mode );
1086             for (i=0;i<count;i++) {
1087                gl_ArrayElement( ctx, (GLint) us_indices[i] );
1088             }
1089             gl_End( ctx );
1090          }
1091          break;
1092       case GL_UNSIGNED_INT:
1093          {
1094             GLuint *ui_indices = (GLuint *) indices;
1095             GLint i;
1096             gl_Begin( ctx, mode );
1097             for (i=0;i<count;i++) {
1098                gl_ArrayElement( ctx, (GLint) ui_indices[i] );
1099             }
1100             gl_End( ctx );
1101          }
1102          break;
1103       default:
1104          gl_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
1105          return;
1106    }
1107 }
1108 
1109 
1110 
1111 
1112 /*
1113  * Save (and perhaps execute)
1114  */
1115 void gl_save_DrawElements( GLcontext *ctx,
1116                            GLenum mode, GLsizei count,
1117                            GLenum type, const GLvoid *indices )
1118 {
1119    switch (type) {
1120       case GL_UNSIGNED_BYTE:
1121          {
1122             GLubyte *ub_indices = (GLubyte *) indices;
1123             GLint i;
1124             gl_save_Begin( ctx, mode );
1125             for (i=0;i<count;i++) {
1126                gl_save_ArrayElement( ctx, (GLint) ub_indices[i] );
1127             }
1128             gl_save_End( ctx );
1129          }
1130          break;
1131       case GL_UNSIGNED_SHORT:
1132          {
1133             GLushort *us_indices = (GLushort *) indices;
1134             GLint i;
1135             gl_save_Begin( ctx, mode );
1136             for (i=0;i<count;i++) {
1137                gl_save_ArrayElement( ctx, (GLint) us_indices[i] );
1138             }
1139             gl_save_End( ctx );
1140          }
1141          break;
1142       case GL_UNSIGNED_INT:
1143          {
1144             GLuint *ui_indices = (GLuint *) indices;
1145             GLint i;
1146             gl_save_Begin( ctx, mode );
1147             for (i=0;i<count;i++) {
1148                gl_save_ArrayElement( ctx, (GLint) ui_indices[i] );
1149             }
1150             gl_save_End( ctx );
1151          }
1152          break;
1153       default:
1154          gl_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
1155          return;
1156    }
1157 }
1158 
1159 
1160 
1161 
1162 void gl_InterleavedArrays( GLcontext *ctx,
1163                            GLenum format, GLsizei stride,
1164                            const GLvoid *pointer )
1165 {
1166    GLboolean tflag, cflag, nflag;  /* enable/disable flags */
1167    GLint tcomps, ccomps, vcomps;   /* components per texcoord, color, vertex */
1168    GLenum ctype;                   /* color type */
1169    GLint coffset, noffset, voffset;/* color, normal, vertex offsets */
1170    GLint defstride;                /* default stride */
1171    GLint c, f;
1172 
1173    f = sizeof(GLfloat);
1174    c = f * ((4*sizeof(GLubyte) + (f-1)) / f);
1175 
1176    if (stride<0) {
1177       gl_error( ctx, GL_INVALID_VALUE, "glInterleavedArrays(stride)" );
1178       return;
1179    }
1180 
1181    switch (format) {
1182       case GL_V2F:
1183          tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_FALSE;
1184          tcomps = 0;  ccomps = 0;  vcomps = 2;
1185          voffset = 0;
1186          defstride = 2*f;
1187          break;
1188       case GL_V3F:
1189          tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_FALSE;
1190          tcomps = 0;  ccomps = 0;  vcomps = 3;
1191          voffset = 0;
1192          defstride = 3*f;
1193          break;
1194       case GL_C4UB_V2F:
1195          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
1196          tcomps = 0;  ccomps = 4;  vcomps = 2;
1197          ctype = GL_UNSIGNED_BYTE;
1198          coffset = 0;
1199          voffset = c;
1200          defstride = c + 2*f;
1201          break;
1202       case GL_C4UB_V3F:
1203          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
1204          tcomps = 0;  ccomps = 4;  vcomps = 3;
1205          ctype = GL_UNSIGNED_BYTE;
1206          coffset = 0;
1207          voffset = c;
1208          defstride = c + 3*f;
1209          break;
1210       case GL_C3F_V3F:
1211          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
1212          tcomps = 0;  ccomps = 3;  vcomps = 3;
1213          ctype = GL_FLOAT;
1214          coffset = 0;
1215          voffset = 3*f;
1216          defstride = 6*f;
1217          break;
1218       case GL_N3F_V3F:
1219          tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_TRUE;
1220          tcomps = 0;  ccomps = 0;  vcomps = 3;
1221          noffset = 0;
1222          voffset = 3*f;
1223          defstride = 6*f;
1224          break;
1225       case GL_C4F_N3F_V3F:
1226          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_TRUE;
1227          tcomps = 0;  ccomps = 4;  vcomps = 3;
1228          ctype = GL_FLOAT;
1229          coffset = 0;
1230          noffset = 4*f;
1231          voffset = 7*f;
1232          defstride = 10*f;
1233          break;
1234       case GL_T2F_V3F:
1235          tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_FALSE;
1236          tcomps = 2;  ccomps = 0;  vcomps = 3;
1237          voffset = 2*f;
1238          defstride = 5*f;
1239          break;
1240       case GL_T4F_V4F:
1241          tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_FALSE;
1242          tcomps = 4;  ccomps = 0;  vcomps = 4;
1243          voffset = 4*f;
1244          defstride = 8*f;
1245          break;
1246       case GL_T2F_C4UB_V3F:
1247          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_FALSE;
1248          tcomps = 2;  ccomps = 4;  vcomps = 3;
1249          ctype = GL_UNSIGNED_BYTE;
1250          coffset = 2*f;
1251          voffset = c+2*f;
1252          defstride = c+5*f;
1253          break;
1254       case GL_T2F_C3F_V3F:
1255          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_FALSE;
1256          tcomps = 2;  ccomps = 3;  vcomps = 3;
1257          ctype = GL_FLOAT;
1258          coffset = 2*f;
1259          voffset = 5*f;
1260          defstride = 8*f;
1261          break;
1262       case GL_T2F_N3F_V3F:
1263          tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_TRUE;
1264          tcomps = 2;  ccomps = 0;  vcomps = 3;
1265          noffset = 2*f;
1266          voffset = 5*f;
1267          defstride = 8*f;
1268          break;
1269       case GL_T2F_C4F_N3F_V3F:
1270          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_TRUE;
1271          tcomps = 2;  ccomps = 4;  vcomps = 3;
1272          ctype = GL_FLOAT;
1273          coffset = 2*f;
1274          noffset = 6*f;
1275          voffset = 9*f;
1276          defstride = 12*f;
1277          break;
1278       case GL_T4F_C4F_N3F_V4F:
1279          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_TRUE;
1280          tcomps = 4;  ccomps = 4;  vcomps = 4;
1281          ctype = GL_FLOAT;
1282          coffset = 4*f;
1283          noffset = 8*f;
1284          voffset = 11*f;
1285          defstride = 15*f;
1286          break;
1287       default:
1288          gl_error( ctx, GL_INVALID_ENUM, "glInterleavedArrays(format)" );
1289          return;
1290    }
1291 
1292    if (stride==0) {
1293       stride = defstride;
1294    }
1295 
1296    gl_DisableClientState( ctx, GL_EDGE_FLAG_ARRAY );
1297    gl_DisableClientState( ctx, GL_INDEX_ARRAY );
1298 
1299    if (tflag) {
1300       gl_EnableClientState( ctx, GL_TEXTURE_COORD_ARRAY );
1301       gl_TexCoordPointer( ctx, tcomps, GL_FLOAT, stride, pointer );
1302    }
1303    else {
1304       gl_DisableClientState( ctx, GL_TEXTURE_COORD_ARRAY );
1305    }
1306 
1307    if (cflag) {
1308       gl_EnableClientState( ctx, GL_COLOR_ARRAY );
1309       gl_ColorPointer( ctx, ccomps, ctype, stride,
1310                        (GLubyte*) pointer + coffset );
1311    }
1312    else {
1313       gl_DisableClientState( ctx, GL_COLOR_ARRAY );
1314    }
1315 
1316    if (nflag) {
1317       gl_EnableClientState( ctx, GL_NORMAL_ARRAY );
1318       gl_NormalPointer( ctx, GL_FLOAT, stride,
1319                         (GLubyte*) pointer + noffset );
1320    }
1321    else {
1322       gl_DisableClientState( ctx, GL_NORMAL_ARRAY );
1323    }
1324 
1325    gl_EnableClientState( ctx, GL_VERTEX_ARRAY );
1326    gl_VertexPointer( ctx, vcomps, GL_FLOAT, stride,
1327                      (GLubyte *) pointer + voffset );
1328 }
1329 
1330 
1331 
1332 void gl_save_InterleavedArrays( GLcontext *ctx,
1333                                 GLenum format, GLsizei stride,
1334                                 const GLvoid *pointer )
1335 {
1336    /* Just execute since client-side state changes aren't put in
1337     * display lists.
1338     */
1339    gl_InterleavedArrays( ctx, format, stride, pointer );
1340 }
1341 
1342