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