varray.c revision 5857e988be9317810cf713478195b4ed849eea4a
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5.1
4 *
5 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include "glheader.h"
27#include "imports.h"
28#include "bufferobj.h"
29#include "context.h"
30#include "enable.h"
31#include "enums.h"
32#include "mtypes.h"
33#include "varray.h"
34#include "arrayobj.h"
35#include "glapi/dispatch.h"
36
37
38/**
39 * Update the fields of a vertex array object.
40 * We need to do a few special things for arrays that live in
41 * vertex buffer objects.
42 *
43 * \param array  the array to update
44 * \param dirtyBit  which bit to set in ctx->Array.NewState for this array
45 * \param elementSize  size of each array element, in bytes
46 * \param size  components per element (1, 2, 3 or 4)
47 * \param type  datatype of each component (GL_FLOAT, GL_INT, etc)
48 * \param stride  stride between elements, in elements
49 * \param normalized  are integer types converted to floats in [-1, 1]?
50 * \param ptr  the address (or offset inside VBO) of the array data
51 */
52static void
53update_array(GLcontext *ctx, struct gl_client_array *array,
54             GLbitfield dirtyBit, GLsizei elementSize,
55             GLint size, GLenum type,
56             GLsizei stride, GLboolean normalized, const GLvoid *ptr)
57{
58   array->Size = size;
59   array->Type = type;
60   array->Stride = stride;
61   array->StrideB = stride ? stride : elementSize;
62   array->Normalized = normalized;
63   array->Ptr = (const GLubyte *) ptr;
64#if FEATURE_ARB_vertex_buffer_object
65   array->BufferObj->RefCount--;
66   if (array->BufferObj->RefCount <= 0) {
67      ASSERT(array->BufferObj->Name);
68      _mesa_remove_buffer_object( ctx, array->BufferObj );
69      (*ctx->Driver.DeleteBuffer)( ctx, array->BufferObj );
70   }
71   array->BufferObj = ctx->Array.ArrayBufferObj;
72   array->BufferObj->RefCount++;
73   /* Compute the index of the last array element that's inside the buffer.
74    * Later in glDrawArrays we'll check if start + count > _MaxElement to
75    * be sure we won't go out of bounds.
76    */
77   if (ctx->Array.ArrayBufferObj->Name)
78      array->_MaxElement = ((GLsizeiptrARB) ctx->Array.ArrayBufferObj->Size
79                            - (GLsizeiptrARB) array->Ptr + array->StrideB
80                            - elementSize) / array->StrideB;
81   else
82#endif
83      array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
84
85   ctx->NewState |= _NEW_ARRAY;
86   ctx->Array.NewState |= dirtyBit;
87}
88
89
90void GLAPIENTRY
91_mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
92{
93   GLsizei elementSize;
94   GET_CURRENT_CONTEXT(ctx);
95   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
96
97   if (size < 2 || size > 4) {
98      _mesa_error( ctx, GL_INVALID_VALUE, "glVertexPointer(size)" );
99      return;
100   }
101   if (stride < 0) {
102      _mesa_error( ctx, GL_INVALID_VALUE, "glVertexPointer(stride)" );
103      return;
104   }
105
106   if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
107      _mesa_debug(ctx, "glVertexPointer( sz %d type %s stride %d )\n", size,
108                  _mesa_lookup_enum_by_nr( type ), stride);
109
110   /* always need to check that <type> is legal */
111   switch (type) {
112      case GL_SHORT:
113         elementSize = size * sizeof(GLshort);
114         break;
115      case GL_INT:
116         elementSize = size * sizeof(GLint);
117         break;
118      case GL_FLOAT:
119         elementSize = size * sizeof(GLfloat);
120         break;
121      case GL_DOUBLE:
122         elementSize = size * sizeof(GLdouble);
123         break;
124      default:
125         _mesa_error( ctx, GL_INVALID_ENUM, "glVertexPointer(type)" );
126         return;
127   }
128
129   update_array(ctx, &ctx->Array.ArrayObj->Vertex, _NEW_ARRAY_VERTEX,
130                elementSize, size, type, stride, GL_FALSE, ptr);
131
132   if (ctx->Driver.VertexPointer)
133      ctx->Driver.VertexPointer( ctx, size, type, stride, ptr );
134}
135
136
137void GLAPIENTRY
138_mesa_NormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr )
139{
140   GLsizei elementSize;
141   GET_CURRENT_CONTEXT(ctx);
142   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
143
144   if (stride < 0) {
145      _mesa_error( ctx, GL_INVALID_VALUE, "glNormalPointer(stride)" );
146      return;
147   }
148
149   if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
150      _mesa_debug(ctx, "glNormalPointer( type %s stride %d )\n",
151                  _mesa_lookup_enum_by_nr( type ), stride);
152
153   switch (type) {
154      case GL_BYTE:
155         elementSize = 3 * sizeof(GLbyte);
156         break;
157      case GL_SHORT:
158         elementSize = 3 * sizeof(GLshort);
159         break;
160      case GL_INT:
161         elementSize = 3 * sizeof(GLint);
162         break;
163      case GL_FLOAT:
164         elementSize = 3 * sizeof(GLfloat);
165         break;
166      case GL_DOUBLE:
167         elementSize = 3 * sizeof(GLdouble);
168         break;
169      default:
170         _mesa_error( ctx, GL_INVALID_ENUM, "glNormalPointer(type)" );
171         return;
172   }
173
174   update_array(ctx, &ctx->Array.ArrayObj->Normal, _NEW_ARRAY_NORMAL,
175                elementSize, 3, type, stride, GL_TRUE, ptr);
176
177   if (ctx->Driver.NormalPointer)
178      ctx->Driver.NormalPointer( ctx, type, stride, ptr );
179}
180
181
182void GLAPIENTRY
183_mesa_ColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
184{
185   GLsizei elementSize;
186   GET_CURRENT_CONTEXT(ctx);
187   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
188
189   if (size < 3 || size > 4) {
190      _mesa_error( ctx, GL_INVALID_VALUE, "glColorPointer(size)" );
191      return;
192   }
193   if (stride < 0) {
194      _mesa_error( ctx, GL_INVALID_VALUE, "glColorPointer(stride)" );
195      return;
196   }
197
198   if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
199      _mesa_debug(ctx, "glColorPointer( sz %d type %s stride %d )\n", size,
200                  _mesa_lookup_enum_by_nr( type ), stride);
201
202   switch (type) {
203      case GL_BYTE:
204         elementSize = size * sizeof(GLbyte);
205         break;
206      case GL_UNSIGNED_BYTE:
207         elementSize = size * sizeof(GLubyte);
208         break;
209      case GL_SHORT:
210         elementSize = size * sizeof(GLshort);
211         break;
212      case GL_UNSIGNED_SHORT:
213         elementSize = size * sizeof(GLushort);
214         break;
215      case GL_INT:
216         elementSize = size * sizeof(GLint);
217         break;
218      case GL_UNSIGNED_INT:
219         elementSize = size * sizeof(GLuint);
220         break;
221      case GL_FLOAT:
222         elementSize = size * sizeof(GLfloat);
223         break;
224      case GL_DOUBLE:
225         elementSize = size * sizeof(GLdouble);
226         break;
227      default:
228         _mesa_error( ctx, GL_INVALID_ENUM, "glColorPointer(type)" );
229         return;
230   }
231
232   update_array(ctx, &ctx->Array.ArrayObj->Color, _NEW_ARRAY_COLOR0,
233                elementSize, size, type, stride, GL_TRUE, ptr);
234
235   if (ctx->Driver.ColorPointer)
236      ctx->Driver.ColorPointer( ctx, size, type, stride, ptr );
237}
238
239
240void GLAPIENTRY
241_mesa_FogCoordPointerEXT(GLenum type, GLsizei stride, const GLvoid *ptr)
242{
243   GLint elementSize;
244   GET_CURRENT_CONTEXT(ctx);
245   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
246
247   if (stride < 0) {
248      _mesa_error( ctx, GL_INVALID_VALUE, "glFogCoordPointer(stride)" );
249      return;
250   }
251
252   switch (type) {
253      case GL_FLOAT:
254         elementSize = sizeof(GLfloat);
255         break;
256      case GL_DOUBLE:
257         elementSize = sizeof(GLdouble);
258         break;
259      default:
260         _mesa_error( ctx, GL_INVALID_ENUM, "glFogCoordPointer(type)" );
261         return;
262   }
263
264   update_array(ctx, &ctx->Array.ArrayObj->FogCoord, _NEW_ARRAY_FOGCOORD,
265                elementSize, 1, type, stride, GL_FALSE, ptr);
266
267   if (ctx->Driver.FogCoordPointer)
268      ctx->Driver.FogCoordPointer( ctx, type, stride, ptr );
269}
270
271
272void GLAPIENTRY
273_mesa_IndexPointer(GLenum type, GLsizei stride, const GLvoid *ptr)
274{
275   GLsizei elementSize;
276   GET_CURRENT_CONTEXT(ctx);
277   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
278
279   if (stride < 0) {
280      _mesa_error( ctx, GL_INVALID_VALUE, "glIndexPointer(stride)" );
281      return;
282   }
283
284   switch (type) {
285      case GL_UNSIGNED_BYTE:
286         elementSize = sizeof(GLubyte);
287         break;
288      case GL_SHORT:
289         elementSize = sizeof(GLshort);
290         break;
291      case GL_INT:
292         elementSize = sizeof(GLint);
293         break;
294      case GL_FLOAT:
295         elementSize = sizeof(GLfloat);
296         break;
297      case GL_DOUBLE:
298         elementSize = sizeof(GLdouble);
299         break;
300      default:
301         _mesa_error( ctx, GL_INVALID_ENUM, "glIndexPointer(type)" );
302         return;
303   }
304
305   update_array(ctx, &ctx->Array.ArrayObj->Index, _NEW_ARRAY_INDEX,
306                elementSize, 1, type, stride, GL_FALSE, ptr);
307
308   if (ctx->Driver.IndexPointer)
309      ctx->Driver.IndexPointer( ctx, type, stride, ptr );
310}
311
312
313void GLAPIENTRY
314_mesa_SecondaryColorPointerEXT(GLint size, GLenum type,
315			       GLsizei stride, const GLvoid *ptr)
316{
317   GLsizei elementSize;
318   GET_CURRENT_CONTEXT(ctx);
319   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
320
321   if (size != 3 && size != 4) {
322      _mesa_error( ctx, GL_INVALID_VALUE, "glSecondaryColorPointer(size)" );
323      return;
324   }
325   if (stride < 0) {
326      _mesa_error( ctx, GL_INVALID_VALUE, "glSecondaryColorPointer(stride)" );
327      return;
328   }
329
330   if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
331      _mesa_debug(ctx, "glSecondaryColorPointer( sz %d type %s stride %d )\n",
332                  size, _mesa_lookup_enum_by_nr( type ), stride);
333
334   switch (type) {
335      case GL_BYTE:
336         elementSize = size * sizeof(GLbyte);
337         break;
338      case GL_UNSIGNED_BYTE:
339         elementSize = size * sizeof(GLubyte);
340         break;
341      case GL_SHORT:
342         elementSize = size * sizeof(GLshort);
343         break;
344      case GL_UNSIGNED_SHORT:
345         elementSize = size * sizeof(GLushort);
346         break;
347      case GL_INT:
348         elementSize = size * sizeof(GLint);
349         break;
350      case GL_UNSIGNED_INT:
351         elementSize = size * sizeof(GLuint);
352         break;
353      case GL_FLOAT:
354         elementSize = size * sizeof(GLfloat);
355         break;
356      case GL_DOUBLE:
357         elementSize = size * sizeof(GLdouble);
358         break;
359      default:
360         _mesa_error( ctx, GL_INVALID_ENUM, "glSecondaryColorPointer(type)" );
361         return;
362   }
363
364   update_array(ctx, &ctx->Array.ArrayObj->SecondaryColor, _NEW_ARRAY_COLOR1,
365                elementSize, size, type, stride, GL_TRUE, ptr);
366
367   if (ctx->Driver.SecondaryColorPointer)
368      ctx->Driver.SecondaryColorPointer( ctx, size, type, stride, ptr );
369}
370
371
372void GLAPIENTRY
373_mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride,
374                      const GLvoid *ptr)
375{
376   GLint elementSize;
377   GET_CURRENT_CONTEXT(ctx);
378   const GLuint unit = ctx->Array.ActiveTexture;
379   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
380
381   if (size < 1 || size > 4) {
382      _mesa_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(size)" );
383      return;
384   }
385   if (stride < 0) {
386      _mesa_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(stride)" );
387      return;
388   }
389
390   if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
391      _mesa_debug(ctx, "glTexCoordPointer(unit %u sz %d type %s stride %d)\n",
392                  unit, size, _mesa_lookup_enum_by_nr( type ), stride);
393
394   /* always need to check that <type> is legal */
395   switch (type) {
396      case GL_SHORT:
397         elementSize = size * sizeof(GLshort);
398         break;
399      case GL_INT:
400         elementSize = size * sizeof(GLint);
401         break;
402      case GL_FLOAT:
403         elementSize = size * sizeof(GLfloat);
404         break;
405      case GL_DOUBLE:
406         elementSize = size * sizeof(GLdouble);
407         break;
408      default:
409         _mesa_error( ctx, GL_INVALID_ENUM, "glTexCoordPointer(type)" );
410         return;
411   }
412
413   update_array(ctx, &ctx->Array.ArrayObj->TexCoord[unit],
414                _NEW_ARRAY_TEXCOORD(unit),
415                elementSize, size, type, stride, GL_FALSE, ptr);
416
417   if (ctx->Driver.TexCoordPointer)
418      ctx->Driver.TexCoordPointer( ctx, size, type, stride, ptr );
419}
420
421
422void GLAPIENTRY
423_mesa_EdgeFlagPointer(GLsizei stride, const GLvoid *ptr)
424{
425   GET_CURRENT_CONTEXT(ctx);
426   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
427
428   if (stride < 0) {
429      _mesa_error( ctx, GL_INVALID_VALUE, "glEdgeFlagPointer(stride)" );
430      return;
431   }
432
433   update_array(ctx, &ctx->Array.ArrayObj->EdgeFlag, _NEW_ARRAY_EDGEFLAG,
434                sizeof(GLboolean), 1, GL_UNSIGNED_BYTE, stride, GL_FALSE, ptr);
435
436   if (ctx->Driver.EdgeFlagPointer)
437      ctx->Driver.EdgeFlagPointer( ctx, stride, ptr );
438}
439
440
441#if FEATURE_NV_vertex_program
442void GLAPIENTRY
443_mesa_VertexAttribPointerNV(GLuint index, GLint size, GLenum type,
444                            GLsizei stride, const GLvoid *ptr)
445{
446   const GLboolean normalized = GL_FALSE;
447   GLsizei elementSize;
448   GET_CURRENT_CONTEXT(ctx);
449   ASSERT_OUTSIDE_BEGIN_END(ctx);
450
451   if (index >= MAX_VERTEX_PROGRAM_ATTRIBS) {
452      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(index)");
453      return;
454   }
455
456   if (size < 1 || size > 4) {
457      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(size)");
458      return;
459   }
460
461   if (stride < 0) {
462      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(stride)");
463      return;
464   }
465
466   if (type == GL_UNSIGNED_BYTE && size != 4) {
467      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(size!=4)");
468      return;
469   }
470
471   /* check for valid 'type' and compute StrideB right away */
472   switch (type) {
473      case GL_UNSIGNED_BYTE:
474         elementSize = size * sizeof(GLubyte);
475         break;
476      case GL_SHORT:
477         elementSize = size * sizeof(GLshort);
478         break;
479      case GL_FLOAT:
480         elementSize = size * sizeof(GLfloat);
481         break;
482      case GL_DOUBLE:
483         elementSize = size * sizeof(GLdouble);
484         break;
485      default:
486         _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttribPointerNV(type)" );
487         return;
488   }
489
490   update_array(ctx, &ctx->Array.ArrayObj->VertexAttrib[index],
491                _NEW_ARRAY_ATTRIB(index),
492                elementSize, size, type, stride, normalized, ptr);
493
494   if (ctx->Driver.VertexAttribPointer)
495      ctx->Driver.VertexAttribPointer( ctx, index, size, type, stride, ptr );
496}
497#endif
498
499
500#if FEATURE_ARB_vertex_program
501void GLAPIENTRY
502_mesa_VertexAttribPointerARB(GLuint index, GLint size, GLenum type,
503                             GLboolean normalized,
504                             GLsizei stride, const GLvoid *ptr)
505{
506   GLsizei elementSize;
507   GET_CURRENT_CONTEXT(ctx);
508   ASSERT_OUTSIDE_BEGIN_END(ctx);
509
510   if (index >= ctx->Const.VertexProgram.MaxAttribs) {
511      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(index)");
512      return;
513   }
514
515   if (size < 1 || size > 4) {
516      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(size)");
517      return;
518   }
519
520   if (stride < 0) {
521      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(stride)");
522      return;
523   }
524
525   if (type == GL_UNSIGNED_BYTE && size != 4) {
526      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(size!=4)");
527      return;
528   }
529
530   /* check for valid 'type' and compute StrideB right away */
531   /* NOTE: more types are supported here than in the NV extension */
532   switch (type) {
533      case GL_BYTE:
534         elementSize = size * sizeof(GLbyte);
535         break;
536      case GL_UNSIGNED_BYTE:
537         elementSize = size * sizeof(GLubyte);
538         break;
539      case GL_SHORT:
540         elementSize = size * sizeof(GLshort);
541         break;
542      case GL_UNSIGNED_SHORT:
543         elementSize = size * sizeof(GLushort);
544         break;
545      case GL_INT:
546         elementSize = size * sizeof(GLint);
547         break;
548      case GL_UNSIGNED_INT:
549         elementSize = size * sizeof(GLuint);
550         break;
551      case GL_FLOAT:
552         elementSize = size * sizeof(GLfloat);
553         break;
554      case GL_DOUBLE:
555         elementSize = size * sizeof(GLdouble);
556         break;
557      default:
558         _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttribPointerARB(type)" );
559         return;
560   }
561
562   update_array(ctx, &ctx->Array.ArrayObj->VertexAttrib[index],
563                _NEW_ARRAY_ATTRIB(index),
564                elementSize, size, type, stride, normalized, ptr);
565
566   if (ctx->Driver.VertexAttribPointer)
567      ctx->Driver.VertexAttribPointer(ctx, index, size, type, stride, ptr);
568}
569#endif
570
571
572void GLAPIENTRY
573_mesa_VertexPointerEXT(GLint size, GLenum type, GLsizei stride,
574                       GLsizei count, const GLvoid *ptr)
575{
576   (void) count;
577   _mesa_VertexPointer(size, type, stride, ptr);
578}
579
580
581void GLAPIENTRY
582_mesa_NormalPointerEXT(GLenum type, GLsizei stride, GLsizei count,
583                       const GLvoid *ptr)
584{
585   (void) count;
586   _mesa_NormalPointer(type, stride, ptr);
587}
588
589
590void GLAPIENTRY
591_mesa_ColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count,
592                      const GLvoid *ptr)
593{
594   (void) count;
595   _mesa_ColorPointer(size, type, stride, ptr);
596}
597
598
599void GLAPIENTRY
600_mesa_IndexPointerEXT(GLenum type, GLsizei stride, GLsizei count,
601                      const GLvoid *ptr)
602{
603   (void) count;
604   _mesa_IndexPointer(type, stride, ptr);
605}
606
607
608void GLAPIENTRY
609_mesa_TexCoordPointerEXT(GLint size, GLenum type, GLsizei stride,
610                         GLsizei count, const GLvoid *ptr)
611{
612   (void) count;
613   _mesa_TexCoordPointer(size, type, stride, ptr);
614}
615
616
617void GLAPIENTRY
618_mesa_EdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *ptr)
619{
620   (void) count;
621   _mesa_EdgeFlagPointer(stride, ptr);
622}
623
624
625void GLAPIENTRY
626_mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
627{
628   GET_CURRENT_CONTEXT(ctx);
629   GLboolean tflag, cflag, nflag;  /* enable/disable flags */
630   GLint tcomps, ccomps, vcomps;   /* components per texcoord, color, vertex */
631   GLenum ctype = 0;               /* color type */
632   GLint coffset = 0, noffset = 0, voffset;/* color, normal, vertex offsets */
633   const GLint toffset = 0;        /* always zero */
634   GLint defstride;                /* default stride */
635   GLint c, f;
636
637   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
638
639   f = sizeof(GLfloat);
640   c = f * ((4 * sizeof(GLubyte) + (f - 1)) / f);
641
642   if (stride < 0) {
643      _mesa_error( ctx, GL_INVALID_VALUE, "glInterleavedArrays(stride)" );
644      return;
645   }
646
647   switch (format) {
648      case GL_V2F:
649         tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_FALSE;
650         tcomps = 0;  ccomps = 0;  vcomps = 2;
651         voffset = 0;
652         defstride = 2*f;
653         break;
654      case GL_V3F:
655         tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_FALSE;
656         tcomps = 0;  ccomps = 0;  vcomps = 3;
657         voffset = 0;
658         defstride = 3*f;
659         break;
660      case GL_C4UB_V2F:
661         tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
662         tcomps = 0;  ccomps = 4;  vcomps = 2;
663         ctype = GL_UNSIGNED_BYTE;
664         coffset = 0;
665         voffset = c;
666         defstride = c + 2*f;
667         break;
668      case GL_C4UB_V3F:
669         tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
670         tcomps = 0;  ccomps = 4;  vcomps = 3;
671         ctype = GL_UNSIGNED_BYTE;
672         coffset = 0;
673         voffset = c;
674         defstride = c + 3*f;
675         break;
676      case GL_C3F_V3F:
677         tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
678         tcomps = 0;  ccomps = 3;  vcomps = 3;
679         ctype = GL_FLOAT;
680         coffset = 0;
681         voffset = 3*f;
682         defstride = 6*f;
683         break;
684      case GL_N3F_V3F:
685         tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_TRUE;
686         tcomps = 0;  ccomps = 0;  vcomps = 3;
687         noffset = 0;
688         voffset = 3*f;
689         defstride = 6*f;
690         break;
691      case GL_C4F_N3F_V3F:
692         tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_TRUE;
693         tcomps = 0;  ccomps = 4;  vcomps = 3;
694         ctype = GL_FLOAT;
695         coffset = 0;
696         noffset = 4*f;
697         voffset = 7*f;
698         defstride = 10*f;
699         break;
700      case GL_T2F_V3F:
701         tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_FALSE;
702         tcomps = 2;  ccomps = 0;  vcomps = 3;
703         voffset = 2*f;
704         defstride = 5*f;
705         break;
706      case GL_T4F_V4F:
707         tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_FALSE;
708         tcomps = 4;  ccomps = 0;  vcomps = 4;
709         voffset = 4*f;
710         defstride = 8*f;
711         break;
712      case GL_T2F_C4UB_V3F:
713         tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_FALSE;
714         tcomps = 2;  ccomps = 4;  vcomps = 3;
715         ctype = GL_UNSIGNED_BYTE;
716         coffset = 2*f;
717         voffset = c+2*f;
718         defstride = c+5*f;
719         break;
720      case GL_T2F_C3F_V3F:
721         tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_FALSE;
722         tcomps = 2;  ccomps = 3;  vcomps = 3;
723         ctype = GL_FLOAT;
724         coffset = 2*f;
725         voffset = 5*f;
726         defstride = 8*f;
727         break;
728      case GL_T2F_N3F_V3F:
729         tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_TRUE;
730         tcomps = 2;  ccomps = 0;  vcomps = 3;
731         noffset = 2*f;
732         voffset = 5*f;
733         defstride = 8*f;
734         break;
735      case GL_T2F_C4F_N3F_V3F:
736         tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_TRUE;
737         tcomps = 2;  ccomps = 4;  vcomps = 3;
738         ctype = GL_FLOAT;
739         coffset = 2*f;
740         noffset = 6*f;
741         voffset = 9*f;
742         defstride = 12*f;
743         break;
744      case GL_T4F_C4F_N3F_V4F:
745         tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_TRUE;
746         tcomps = 4;  ccomps = 4;  vcomps = 4;
747         ctype = GL_FLOAT;
748         coffset = 4*f;
749         noffset = 8*f;
750         voffset = 11*f;
751         defstride = 15*f;
752         break;
753      default:
754         _mesa_error( ctx, GL_INVALID_ENUM, "glInterleavedArrays(format)" );
755         return;
756   }
757
758   if (stride==0) {
759      stride = defstride;
760   }
761
762   _mesa_DisableClientState( GL_EDGE_FLAG_ARRAY );
763   _mesa_DisableClientState( GL_INDEX_ARRAY );
764   /* XXX also disable secondary color and generic arrays? */
765
766   /* Texcoords */
767   if (tflag) {
768      _mesa_EnableClientState( GL_TEXTURE_COORD_ARRAY );
769      _mesa_TexCoordPointer( tcomps, GL_FLOAT, stride,
770                             (GLubyte *) pointer + toffset );
771   }
772   else {
773      _mesa_DisableClientState( GL_TEXTURE_COORD_ARRAY );
774   }
775
776   /* Color */
777   if (cflag) {
778      _mesa_EnableClientState( GL_COLOR_ARRAY );
779      _mesa_ColorPointer( ccomps, ctype, stride,
780			  (GLubyte *) pointer + coffset );
781   }
782   else {
783      _mesa_DisableClientState( GL_COLOR_ARRAY );
784   }
785
786
787   /* Normals */
788   if (nflag) {
789      _mesa_EnableClientState( GL_NORMAL_ARRAY );
790      _mesa_NormalPointer( GL_FLOAT, stride, (GLubyte *) pointer + noffset );
791   }
792   else {
793      _mesa_DisableClientState( GL_NORMAL_ARRAY );
794   }
795
796   /* Vertices */
797   _mesa_EnableClientState( GL_VERTEX_ARRAY );
798   _mesa_VertexPointer( vcomps, GL_FLOAT, stride,
799			(GLubyte *) pointer + voffset );
800}
801
802
803void GLAPIENTRY
804_mesa_LockArraysEXT(GLint first, GLsizei count)
805{
806   GET_CURRENT_CONTEXT(ctx);
807   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
808
809   if (MESA_VERBOSE & VERBOSE_API)
810      _mesa_debug(ctx, "glLockArrays %d %d\n", first, count);
811
812   if (first < 0) {
813      _mesa_error( ctx, GL_INVALID_VALUE, "glLockArraysEXT(first)" );
814      return;
815   }
816   if (count <= 0) {
817      _mesa_error( ctx, GL_INVALID_VALUE, "glLockArraysEXT(count)" );
818      return;
819   }
820   if (ctx->Array.LockCount != 0) {
821      _mesa_error( ctx, GL_INVALID_OPERATION, "glLockArraysEXT(reentry)" );
822      return;
823   }
824
825   ctx->Array.LockFirst = first;
826   ctx->Array.LockCount = count;
827
828   ctx->NewState |= _NEW_ARRAY;
829   ctx->Array.NewState |= _NEW_ARRAY_ALL;
830
831   if (ctx->Driver.LockArraysEXT)
832      ctx->Driver.LockArraysEXT( ctx, first, count );
833}
834
835
836void GLAPIENTRY
837_mesa_UnlockArraysEXT( void )
838{
839   GET_CURRENT_CONTEXT(ctx);
840   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
841
842   if (MESA_VERBOSE & VERBOSE_API)
843      _mesa_debug(ctx, "glUnlockArrays\n");
844
845   if (ctx->Array.LockCount == 0) {
846      _mesa_error( ctx, GL_INVALID_OPERATION, "glUnlockArraysEXT(reexit)" );
847      return;
848   }
849
850   ctx->Array.LockFirst = 0;
851   ctx->Array.LockCount = 0;
852   ctx->NewState |= _NEW_ARRAY;
853   ctx->Array.NewState |= _NEW_ARRAY_ALL;
854
855   if (ctx->Driver.UnlockArraysEXT)
856      ctx->Driver.UnlockArraysEXT( ctx );
857}
858
859
860/* GL_EXT_multi_draw_arrays */
861/* Somebody forgot to spec the first and count parameters as const! <sigh> */
862void GLAPIENTRY
863_mesa_MultiDrawArraysEXT( GLenum mode, GLint *first,
864                          GLsizei *count, GLsizei primcount )
865{
866   GET_CURRENT_CONTEXT(ctx);
867   GLint i;
868
869   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
870
871   for (i = 0; i < primcount; i++) {
872      if (count[i] > 0) {
873         CALL_DrawArrays(ctx->Exec, (mode, first[i], count[i]));
874      }
875   }
876}
877
878
879/* GL_EXT_multi_draw_arrays */
880void GLAPIENTRY
881_mesa_MultiDrawElementsEXT( GLenum mode, const GLsizei *count, GLenum type,
882                            const GLvoid **indices, GLsizei primcount )
883{
884   GET_CURRENT_CONTEXT(ctx);
885   GLint i;
886
887   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
888
889   for (i = 0; i < primcount; i++) {
890      if (count[i] > 0) {
891         CALL_DrawElements(ctx->Exec, (mode, count[i], type, indices[i]));
892      }
893   }
894}
895
896
897/* GL_IBM_multimode_draw_arrays */
898void GLAPIENTRY
899_mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
900			      const GLsizei * count,
901			      GLsizei primcount, GLint modestride )
902{
903   GET_CURRENT_CONTEXT(ctx);
904   GLint i;
905
906   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
907
908   for ( i = 0 ; i < primcount ; i++ ) {
909      if ( count[i] > 0 ) {
910         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
911	 CALL_DrawArrays(ctx->Exec, ( m, first[i], count[i] ));
912      }
913   }
914}
915
916
917/* GL_IBM_multimode_draw_arrays */
918void GLAPIENTRY
919_mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
920				GLenum type, const GLvoid * const * indices,
921				GLsizei primcount, GLint modestride )
922{
923   GET_CURRENT_CONTEXT(ctx);
924   GLint i;
925
926   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
927
928   /* XXX not sure about ARB_vertex_buffer_object handling here */
929
930   for ( i = 0 ; i < primcount ; i++ ) {
931      if ( count[i] > 0 ) {
932         GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
933	 CALL_DrawElements(ctx->Exec, ( m, count[i], type, indices[i] ));
934      }
935   }
936}
937
938
939/**
940 * Initialize vertex array state for given context.
941 */
942void
943_mesa_init_varray(GLcontext *ctx)
944{
945   ctx->Array.DefaultArrayObj = _mesa_new_array_object(ctx, 0);
946   ctx->Array.ArrayObj = ctx->Array.DefaultArrayObj;
947
948   ctx->Array.ActiveTexture = 0;   /* GL_ARB_multitexture */
949}
950