Make the transition to script-genereated GLX code easier.
[mesa.git] / src / glx / x11 / vertarr.c
1 /* $XFree86: xc/lib/GL/glx/vertarr.c,v 1.4 2001/03/25 05:32:00 tsi Exp $ */
2 /*
3 ** License Applicability. Except to the extent portions of this file are
4 ** made subject to an alternative license as permitted in the SGI Free
5 ** Software License B, Version 1.1 (the "License"), the contents of this
6 ** file are subject only to the provisions of the License. You may not use
7 ** this file except in compliance with the License. You may obtain a copy
8 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
9 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
10 **
11 ** http://oss.sgi.com/projects/FreeB
12 **
13 ** Note that, as provided in the License, the Software is distributed on an
14 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
15 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
16 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
17 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
18 **
19 ** Original Code. The Original Code is: OpenGL Sample Implementation,
20 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
21 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
22 ** Copyright in any portions created by third parties is as indicated
23 ** elsewhere herein. All Rights Reserved.
24 **
25 ** Additional Notice Provisions: The application programming interfaces
26 ** established by SGI in conjunction with the Original Code are The
27 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
28 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
29 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
30 ** Window System(R) (Version 1.3), released October 19, 1998. This software
31 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
32 ** published by SGI, but has not been independently verified as being
33 ** compliant with the OpenGL(R) version 1.2.1 Specification.
34 **
35 */
36
37 #include <assert.h>
38 #include "glxclient.h"
39 #include "packrender.h"
40 #include "indirect.h"
41 #include <string.h>
42 #include <limits.h> /* INT_MAX */
43
44 /* macros for setting function pointers */
45 #define __GL_VERTEX_FUNC(NAME, let) \
46 case GL_##NAME: \
47 if (size == 2) \
48 vertexPointer->proc = (void (*)(const void *))__indirect_glVertex2##let##v; \
49 else if (size == 3) \
50 vertexPointer->proc = (void (*)(const void *))__indirect_glVertex3##let##v; \
51 else if (size == 4) \
52 vertexPointer->proc = (void (*)(const void *))__indirect_glVertex4##let##v; \
53 break
54
55 #define __GL_NORMAL_FUNC(NAME, let) \
56 case GL_##NAME: \
57 normalPointer->proc = (void (*)(const void *))__indirect_glNormal3##let##v; \
58 break
59
60 #define __GL_COLOR_FUNC(NAME, let) \
61 case GL_##NAME: \
62 if (size == 3) \
63 colorPointer->proc = (void (*)(const void *))__indirect_glColor3##let##v; \
64 else if (size == 4)\
65 colorPointer->proc = (void (*)(const void *))__indirect_glColor4##let##v; \
66 break
67
68 #define __GL_SEC_COLOR_FUNC(NAME, let) \
69 case GL_##NAME: \
70 seccolorPointer->proc = (void (*)(const void *))__indirect_glSecondaryColor3##let##vEXT; \
71
72 #define __GL_FOG_FUNC(NAME, let) \
73 case GL_##NAME: \
74 fogPointer->proc = (void (*)(const void *))__indirect_glFogCoord##let##vEXT; \
75
76 #define __GL_INDEX_FUNC(NAME, let) \
77 case GL_##NAME: \
78 indexPointer->proc = (void (*)(const void *))__indirect_glIndex##let##v; \
79 break
80
81 #define __GL_TEXTURE_FUNC(NAME, let) \
82 case GL_##NAME: \
83 if (size == 1) { \
84 texCoordPointer->proc = (void (*)(const void *))__indirect_glTexCoord1##let##v; \
85 texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))__indirect_glMultiTexCoord1##let##vARB; \
86 } else if (size == 2) { \
87 texCoordPointer->proc = (void (*)(const void *))__indirect_glTexCoord2##let##v; \
88 texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))__indirect_glMultiTexCoord2##let##vARB; \
89 } else if (size == 3) { \
90 texCoordPointer->proc = (void (*)(const void *))__indirect_glTexCoord3##let##v; \
91 texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))__indirect_glMultiTexCoord2##let##vARB; \
92 } else if (size == 4) { \
93 texCoordPointer->proc = (void (*)(const void *))__indirect_glTexCoord4##let##v; \
94 texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))__indirect_glMultiTexCoord4##let##vARB; \
95 } break
96
97 /**
98 * Table of sizes, in bytes, of a GL types. All of the type enums are be in
99 * the range 0x1400 - 0x140F. That includes types added by extensions (i.e.,
100 * \c GL_HALF_FLOAT_NV). This elements of this table correspond to the
101 * type enums masked with 0x0f.
102 *
103 * \notes
104 * \c GL_HAVE_FLOAT_NV is not included. Neither are \c GL_2_BYTES,
105 * \c GL_3_BYTES, or \c GL_4_BYTES.
106 */
107 static const GLuint __glXTypeSize_table[16] = {
108 1, 1, 2, 2, 4, 4, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0
109 };
110
111 #define __glXTypeSize(e) ((((e) & ~0x0f) != 0x1400) \
112 ? 0 : __glXTypeSize_table[ (e) & 0x0f ])
113
114
115 /**
116 * Initialize vertex array state for a GLX context.
117 *
118 * \param gc GLX context whose vertex array state is to be initialized.
119 *
120 * \todo
121 * Someone is going to have to check the spec. This function takes greate
122 * care to initialize the \c size and \c type fields to "correct" values
123 * for each array. I'm not sure this is necessary. I think it should be
124 * acceptable to just \c memset the whole \c arrays and \c texCoord arrays
125 * to zero and be done with it. The spec may say something to the contrary,
126 * however.
127 */
128 void __glXInitVertexArrayState(__GLXcontext *gc)
129 {
130 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
131 __GLXvertArrayState *va = &state->vertArray;
132 GLint i;
133
134 va->enables = 0;
135 va->texture_enables = 0;
136
137 for ( i = 0 ; i < __GLX_MAX_ARRAYS ; i++ ) {
138 va->arrays[ i ].proc = NULL;
139 va->arrays[ i ].skip = 0;
140 va->arrays[ i ].ptr = 0;
141 va->arrays[ i ].size = 1;
142 va->arrays[ i ].type = GL_FLOAT;
143 va->arrays[ i ].stride = 0;
144 }
145
146 va->arrays[ edgeFlag_ARRAY ].type = GL_UNSIGNED_BYTE;;
147
148 va->arrays[ secondaryColor_ARRAY ].size = 3;
149 va->arrays[ color_ARRAY ].size = 4;
150 va->arrays[ normal_ARRAY ].size = 3;
151 va->arrays[ vertex_ARRAY ].size = 4;
152
153 for ( i = 0 ; i < __GLX_MAX_TEXTURE_UNITS ; i++ ) {
154 va->texCoord[ i ].proc = NULL;
155 va->texCoord[ i ].skip = 0;
156 va->texCoord[ i ].ptr = 0;
157 va->texCoord[ i ].size = 4;
158 va->texCoord[ i ].type = GL_FLOAT;
159 va->texCoord[ i ].stride = 0;
160 }
161
162 va->maxElementsVertices = INT_MAX;
163 va->maxElementsIndices = INT_MAX;
164 }
165
166 /*****************************************************************************/
167
168 void __indirect_glVertexPointer(GLint size, GLenum type, GLsizei stride,
169 const GLvoid *pointer)
170 {
171 __GLXcontext *gc = __glXGetCurrentContext();
172 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
173 __GLXvertexArrayPointerState *vertexPointer = &state->vertArray.arrays[ vertex_ARRAY ];
174
175 /* Check arguments */
176 if (size < 2 || size > 4 || stride < 0) {
177 __glXSetError(gc, GL_INVALID_VALUE);
178 return;
179 }
180
181 /* Choose appropriate api proc */
182 switch(type) {
183 __GL_VERTEX_FUNC(SHORT, s);
184 __GL_VERTEX_FUNC(INT, i);
185 __GL_VERTEX_FUNC(FLOAT, f);
186 __GL_VERTEX_FUNC(DOUBLE, d);
187 default:
188 __glXSetError(gc, GL_INVALID_ENUM);
189 return;
190 }
191
192 vertexPointer->size = size;
193 vertexPointer->type = type;
194 vertexPointer->stride = stride;
195 vertexPointer->ptr = pointer;
196
197 /* Set internal state */
198 if (stride == 0) {
199 vertexPointer->skip = __glXTypeSize(type) * size;
200 } else {
201 vertexPointer->skip = stride;
202 }
203 }
204
205 void __indirect_glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer)
206 {
207 __GLXcontext *gc = __glXGetCurrentContext();
208 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
209 __GLXvertexArrayPointerState *normalPointer = &state->vertArray.arrays[ normal_ARRAY ];
210
211 /* Check arguments */
212 if (stride < 0) {
213 __glXSetError(gc, GL_INVALID_VALUE);
214 return;
215 }
216
217 /* Choose appropriate api proc */
218 switch(type) {
219 __GL_NORMAL_FUNC(BYTE, b);
220 __GL_NORMAL_FUNC(SHORT, s);
221 __GL_NORMAL_FUNC(INT, i);
222 __GL_NORMAL_FUNC(FLOAT, f);
223 __GL_NORMAL_FUNC(DOUBLE, d);
224 default:
225 __glXSetError(gc, GL_INVALID_ENUM);
226 return;
227 }
228
229 normalPointer->type = type;
230 normalPointer->stride = stride;
231 normalPointer->ptr = pointer;
232
233 /* Set internal state */
234 if (stride == 0) {
235 normalPointer->skip = 3 * __glXTypeSize(type);
236 } else {
237 normalPointer->skip = stride;
238 }
239 }
240
241 void __indirect_glColorPointer(GLint size, GLenum type, GLsizei stride,
242 const GLvoid *pointer)
243 {
244 __GLXcontext *gc = __glXGetCurrentContext();
245 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
246 __GLXvertexArrayPointerState *colorPointer = &state->vertArray.arrays[ color_ARRAY ];
247
248 /* Check arguments */
249 if (stride < 0) {
250 __glXSetError(gc, GL_INVALID_VALUE);
251 return;
252 }
253
254 /* Choose appropriate api proc */
255 switch(type) {
256 __GL_COLOR_FUNC(BYTE, b);
257 __GL_COLOR_FUNC(UNSIGNED_BYTE, ub);
258 __GL_COLOR_FUNC(SHORT, s);
259 __GL_COLOR_FUNC(UNSIGNED_SHORT, us);
260 __GL_COLOR_FUNC(INT, i);
261 __GL_COLOR_FUNC(UNSIGNED_INT, ui);
262 __GL_COLOR_FUNC(FLOAT, f);
263 __GL_COLOR_FUNC(DOUBLE, d);
264 default:
265 __glXSetError(gc, GL_INVALID_ENUM);
266 return;
267 }
268
269 colorPointer->size = size;
270 colorPointer->type = type;
271 colorPointer->stride = stride;
272 colorPointer->ptr = pointer;
273
274 /* Set internal state */
275 if (stride == 0) {
276 colorPointer->skip = size * __glXTypeSize(type);
277 } else {
278 colorPointer->skip = stride;
279 }
280 }
281
282 void __indirect_glIndexPointer(GLenum type, GLsizei stride, const GLvoid *pointer)
283 {
284 __GLXcontext *gc = __glXGetCurrentContext();
285 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
286 __GLXvertexArrayPointerState *indexPointer = &state->vertArray.arrays[ index_ARRAY ];
287
288 /* Check arguments */
289 if (stride < 0) {
290 __glXSetError(gc, GL_INVALID_VALUE);
291 return;
292 }
293
294 /* Choose appropriate api proc */
295 switch(type) {
296 __GL_INDEX_FUNC(UNSIGNED_BYTE, ub);
297 __GL_INDEX_FUNC(SHORT, s);
298 __GL_INDEX_FUNC(INT, i);
299 __GL_INDEX_FUNC(FLOAT, f);
300 __GL_INDEX_FUNC(DOUBLE, d);
301 default:
302 __glXSetError(gc, GL_INVALID_ENUM);
303 return;
304 }
305
306 indexPointer->type = type;
307 indexPointer->stride = stride;
308 indexPointer->ptr = pointer;
309
310 /* Set internal state */
311 if (stride == 0) {
312 indexPointer->skip = __glXTypeSize(type);
313 } else {
314 indexPointer->skip = stride;
315 }
316 }
317
318 void __indirect_glTexCoordPointer(GLint size, GLenum type, GLsizei stride,
319 const GLvoid *pointer)
320 {
321 __GLXcontext *gc = __glXGetCurrentContext();
322 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
323 __GLXvertexArrayPointerState *texCoordPointer =
324 &state->vertArray.texCoord[state->vertArray.activeTexture];
325
326 /* Check arguments */
327 if (size < 1 || size > 4 || stride < 0) {
328 __glXSetError(gc, GL_INVALID_VALUE);
329 return;
330 }
331
332 /* Choose appropriate api proc */
333 switch(type) {
334 __GL_TEXTURE_FUNC(SHORT, s);
335 __GL_TEXTURE_FUNC(INT, i);
336 __GL_TEXTURE_FUNC(FLOAT, f);
337 __GL_TEXTURE_FUNC(DOUBLE, d);
338 default:
339 __glXSetError(gc, GL_INVALID_ENUM);
340 return;
341 }
342
343 texCoordPointer->size = size;
344 texCoordPointer->type = type;
345 texCoordPointer->stride = stride;
346 texCoordPointer->ptr = pointer;
347
348 /* Set internal state */
349 if (stride == 0) {
350 texCoordPointer->skip = __glXTypeSize(type) * size;
351 } else {
352 texCoordPointer->skip = stride;
353 }
354 }
355
356 void __indirect_glEdgeFlagPointer(GLsizei stride, const GLvoid *pointer)
357 {
358 __GLXcontext *gc = __glXGetCurrentContext();
359 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
360 __GLXvertexArrayPointerState *edgeFlagPointer = &state->vertArray.arrays[ edgeFlag_ARRAY ];
361
362 /* Check arguments */
363 if (stride < 0) {
364 __glXSetError(gc, GL_INVALID_VALUE);
365 return;
366 }
367
368 /* Choose appropriate api proc */
369 edgeFlagPointer->proc = (void (*)(const void *))__indirect_glEdgeFlagv;
370
371 edgeFlagPointer->stride = stride;
372 edgeFlagPointer->ptr = pointer;
373
374 /* Set internal state */
375 if (stride == 0) {
376 edgeFlagPointer->skip = sizeof(GLboolean);
377 } else {
378 edgeFlagPointer->skip = stride;
379 }
380
381 }
382
383 void __indirect_glSecondaryColorPointerEXT(GLint size, GLenum type, GLsizei stride,
384 const GLvoid * pointer )
385 {
386 __GLXcontext *gc = __glXGetCurrentContext();
387 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
388 __GLXvertexArrayPointerState *seccolorPointer = &state->vertArray.arrays[ secondaryColor_ARRAY ];
389
390 /* Check arguments */
391 if ( (stride < 0) || (size != 3) ) {
392 __glXSetError(gc, GL_INVALID_VALUE);
393 return;
394 }
395
396 /* Choose appropriate api proc */
397 switch(type) {
398 __GL_SEC_COLOR_FUNC(BYTE, b);
399 __GL_SEC_COLOR_FUNC(UNSIGNED_BYTE, ub);
400 __GL_SEC_COLOR_FUNC(SHORT, s);
401 __GL_SEC_COLOR_FUNC(UNSIGNED_SHORT, us);
402 __GL_SEC_COLOR_FUNC(INT, i);
403 __GL_SEC_COLOR_FUNC(UNSIGNED_INT, ui);
404 __GL_SEC_COLOR_FUNC(FLOAT, f);
405 __GL_SEC_COLOR_FUNC(DOUBLE, d);
406 default:
407 __glXSetError(gc, GL_INVALID_ENUM);
408 return;
409 }
410
411 seccolorPointer->size = size;
412 seccolorPointer->type = type;
413 seccolorPointer->stride = stride;
414 seccolorPointer->ptr = pointer;
415
416 /* Set internal state */
417 if (stride == 0) {
418 seccolorPointer->skip = size * __glXTypeSize(type);
419 } else {
420 seccolorPointer->skip = stride;
421 }
422 }
423
424 void __indirect_glFogCoordPointerEXT(GLenum type, GLsizei stride, const GLvoid * pointer)
425 {
426 __GLXcontext *gc = __glXGetCurrentContext();
427 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
428 __GLXvertexArrayPointerState *fogPointer = &state->vertArray.arrays[ fogCoord_ARRAY ];
429
430 /* Check arguments */
431 if (stride < 0) {
432 __glXSetError(gc, GL_INVALID_VALUE);
433 return;
434 }
435
436 /* Choose appropriate api proc */
437 switch(type) {
438 __GL_FOG_FUNC(FLOAT, f);
439 __GL_FOG_FUNC(DOUBLE, d);
440 default:
441 __glXSetError(gc, GL_INVALID_ENUM);
442 return;
443 }
444
445 fogPointer->size = 1;
446 fogPointer->type = type;
447 fogPointer->stride = stride;
448 fogPointer->ptr = pointer;
449
450 /* Set internal state */
451 if (stride == 0) {
452 fogPointer->skip = __glXTypeSize(type);
453 } else {
454 fogPointer->skip = stride;
455 }
456 }
457
458 void __indirect_glInterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
459 {
460 __GLXcontext *gc = __glXGetCurrentContext();
461 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
462 GLboolean tEnable = GL_FALSE, cEnable = GL_FALSE, nEnable = GL_FALSE;
463 GLenum tType = GL_FLOAT, nType = GL_FLOAT, vType = GL_FLOAT;
464 GLenum cType = GL_FALSE;
465 GLint tSize = 0, cSize = 0, nSize = 3, vSize;
466 int cOffset = 0, nOffset = 0, vOffset = 0;
467 GLint trueStride, size;
468
469 switch (format) {
470 case GL_V2F:
471 vSize = 2;
472 size = __glXTypeSize(vType) * vSize;
473 break;
474 case GL_V3F:
475 vSize = 3;
476 size = __glXTypeSize(vType) * vSize;
477 break;
478 case GL_C4UB_V2F:
479 cEnable = GL_TRUE;
480 cSize = 4;
481 cType = GL_UNSIGNED_BYTE;
482 vSize = 2;
483 vOffset = __glXTypeSize(cType) * cSize;
484 size = vOffset + __glXTypeSize(vType) * vSize;
485 break;
486 case GL_C4UB_V3F:
487 cEnable = GL_TRUE;
488 cSize = 4;
489 cType = GL_UNSIGNED_BYTE;
490 vSize = 3;
491 vOffset = __glXTypeSize(vType) * cSize;
492 size = vOffset + __glXTypeSize(vType) * vSize;
493 break;
494 case GL_C3F_V3F:
495 cEnable = GL_TRUE;
496 cSize = 3;
497 cType = GL_FLOAT;
498 vSize = 3;
499 vOffset = __glXTypeSize(cType) * cSize;
500 size = vOffset + __glXTypeSize(vType) * vSize;
501 break;
502 case GL_N3F_V3F:
503 nEnable = GL_TRUE;
504 vSize = 3;
505 vOffset = __glXTypeSize(nType) * nSize;
506 size = vOffset + __glXTypeSize(vType) * vSize;
507 break;
508 case GL_C4F_N3F_V3F:
509 cEnable = GL_TRUE;
510 cSize = 4;
511 cType = GL_FLOAT;
512 nEnable = GL_TRUE;
513 nOffset = __glXTypeSize(cType) * cSize;
514 vSize = 3;
515 vOffset = nOffset + __glXTypeSize(nType) * nSize;
516 size = vOffset + __glXTypeSize(vType) * vSize;
517 break;
518 case GL_T2F_V3F:
519 tEnable = GL_TRUE;
520 tSize = 2;
521 vSize = 3;
522 vOffset = __glXTypeSize(tType) * tSize;
523 size = vOffset + __glXTypeSize(vType) * vSize;
524 break;
525 case GL_T4F_V4F:
526 tEnable = GL_TRUE;
527 tSize = 4;
528 vSize = 4;
529 vOffset = __glXTypeSize(tType) * tSize;
530 size = vOffset + __glXTypeSize(vType) * vSize;
531 break;
532 case GL_T2F_C4UB_V3F:
533 tEnable = GL_TRUE;
534 tSize = 2;
535 cEnable = GL_TRUE;
536 cSize = 4;
537 cType = GL_UNSIGNED_BYTE;
538 cOffset = __glXTypeSize(tType) * tSize;
539 vSize = 3;
540 vOffset = cOffset + __glXTypeSize(cType) * cSize;
541 size = vOffset + __glXTypeSize(vType) * vSize;
542 break;
543 case GL_T2F_C3F_V3F:
544 tEnable = GL_TRUE;
545 tSize = 2;
546 cEnable = GL_TRUE;
547 cSize = 3;
548 cType = GL_FLOAT;
549 cOffset = __glXTypeSize(tType) * tSize;
550 vSize = 3;
551 vOffset = cOffset + __glXTypeSize(cType) * cSize;
552 size = vOffset + __glXTypeSize(vType) * vSize;
553 break;
554 case GL_T2F_N3F_V3F:
555 tEnable = GL_TRUE;
556 tSize = 2;
557 nEnable = GL_TRUE;
558 nOffset = __glXTypeSize(tType) * tSize;
559 vSize = 3;
560 vOffset = nOffset + __glXTypeSize(nType) * nSize;
561 size = vOffset + __glXTypeSize(vType) * vSize;
562 break;
563 case GL_T2F_C4F_N3F_V3F:
564 tEnable = GL_TRUE;
565 tSize = 2;
566 cEnable = GL_TRUE;
567 cSize = 4;
568 cType = GL_FLOAT;
569 cOffset = __glXTypeSize(tType) * tSize;
570 nEnable = GL_TRUE;
571 nOffset = cOffset + __glXTypeSize(cType) * cSize;
572 vSize = 3;
573 vOffset = nOffset + __glXTypeSize(nType) * nSize;
574 size = vOffset + __glXTypeSize(vType) * vSize;
575 break;
576 case GL_T4F_C4F_N3F_V4F:
577 tEnable = GL_TRUE;
578 tSize = 4;
579 cEnable = GL_TRUE;
580 cSize = 4;
581 cType = GL_FLOAT;
582 cOffset = __glXTypeSize(tType) * tSize;
583 nEnable = GL_TRUE;
584 nOffset = cOffset + __glXTypeSize(cType) * cSize;
585 vSize = 4;
586 vOffset = nOffset + __glXTypeSize(nType) * nSize;
587 size = vOffset + __glXTypeSize(vType) * vSize;
588 break;
589 default:
590 __glXSetError(gc, GL_INVALID_ENUM);
591 return;
592 }
593
594 trueStride = (stride == 0) ? size : stride;
595
596 state->vertArray.enables = 0;
597 state->vertArray.texture_enables = 0;
598 if (tEnable) {
599 __indirect_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
600 __indirect_glTexCoordPointer(tSize, tType, trueStride, (const char *)pointer);
601 }
602 if (cEnable) {
603 __indirect_glEnableClientState(GL_COLOR_ARRAY);
604 __indirect_glColorPointer(cSize, cType, trueStride, (const char *)pointer+cOffset);
605 }
606 if (nEnable) {
607 __indirect_glEnableClientState(GL_NORMAL_ARRAY);
608 __indirect_glNormalPointer(nType, trueStride, (const char *)pointer+nOffset);
609 }
610 __indirect_glEnableClientState(GL_VERTEX_ARRAY);
611 __indirect_glVertexPointer(vSize, vType, trueStride, (const char *)pointer+vOffset);
612 }
613
614 /*****************************************************************************/
615
616 void __indirect_glArrayElement(GLint i)
617 {
618 __GLXcontext *gc = __glXGetCurrentContext();
619 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
620 __GLXvertArrayState *va = &state->vertArray;
621 GLint j;
622
623
624 if (IS_TEXARRAY_ENABLED(state, 0)) {
625 (*va->texCoord[0].proc)(va->texCoord[0].ptr+i*va->texCoord[0].skip);
626 }
627
628 /* Multitexturing is handled specially because the protocol
629 * requires an extra parameter.
630 */
631 for (j=1; j<__GLX_MAX_TEXTURE_UNITS; ++j) {
632 if (IS_TEXARRAY_ENABLED(state, j)) {
633 (*va->texCoord[j].mtex_proc)(GL_TEXTURE0 + j, va->texCoord[j].ptr+i*va->texCoord[j].skip);
634 }
635 }
636
637 for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) {
638 if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) {
639 (*va->arrays[ j ].proc)(va->arrays[ j ].ptr+i*va->arrays[ j ].skip);
640 }
641 }
642 }
643
644
645 struct array_info {
646 __GLXdispatchDrawArraysComponentHeader ai;
647 GLsizei bytes;
648 const GLubyte *ptr;
649 GLsizei skip;
650 };
651
652
653 /**
654 * Initialize a \c array_info structure for each array that is enabled in
655 * \c state. Determine how many arrays are enabled, and store the result
656 * in \c num_arrays. Determine how big each vertex is, and store the result
657 * in \c total_vertex_size.
658 *
659 * \returns The size of the final request. This is the size, in bytes, of
660 * the DrawArrays header, the ARRAY_INFO structures, and all the vertex data.
661 * This value \b assumes a \c X_GLXRender command is used. The true size
662 * will be 4 bytes larger if a \c X_GLXRenderLarge command is used.
663 */
664 static GLuint
665 prep_arrays(const __GLXattribute * const state, struct array_info * arrays,
666 GLint count,
667 GLsizei *num_arrays, GLsizei *total_vertex_size)
668 {
669 GLsizei na = 0;
670 GLsizei vs = 0;
671
672 #define ASSIGN_ARRAY_INFO(state, enum_name, arr) \
673 do { \
674 arrays[ na ].ai.datatype = state->vertArray. arr .type ; \
675 arrays[ na ].ai.numVals = state->vertArray. arr .size ; \
676 arrays[ na ].ai.component = GL_ ## enum_name ## _ARRAY; \
677 \
678 arrays[ na ].bytes = state->vertArray. arr .size \
679 * __glXTypeSize( state->vertArray. arr .type ); \
680 arrays[ na ].ptr = state->vertArray. arr .ptr; \
681 arrays[ na ].skip = state->vertArray. arr .skip; \
682 \
683 vs += __GLX_PAD(arrays[ na ].bytes); \
684 na++; \
685 } while( 0 )
686
687 #define ADD_ARRAY_IF_ENABLED(state, enum_name, arr) \
688 do { if ( IS_ARRAY_ENABLED(state, arr) ) { \
689 ASSIGN_ARRAY_INFO(state, enum_name, arrays[ arr ## _ARRAY ] ); \
690 } } while( 0 )
691
692 ADD_ARRAY_IF_ENABLED(state, VERTEX, vertex);
693 ADD_ARRAY_IF_ENABLED(state, NORMAL, normal);
694 ADD_ARRAY_IF_ENABLED(state, COLOR, color);
695 ADD_ARRAY_IF_ENABLED(state, SECONDARY_COLOR, secondaryColor);
696 ADD_ARRAY_IF_ENABLED(state, FOG_COORD, fogCoord);
697 ADD_ARRAY_IF_ENABLED(state, EDGE_FLAG, edgeFlag);
698 ADD_ARRAY_IF_ENABLED(state, INDEX, index);
699
700 /* The standard DrawArrays protocol *only* supports a single array of
701 * texture coordinates.
702 */
703 if ( IS_TEXARRAY_ENABLED(state, 0) ) {
704 ASSIGN_ARRAY_INFO(state, TEXTURE_COORD, texCoord[0]);
705 }
706
707 *num_arrays = na;
708 *total_vertex_size = vs;
709
710 return __GLX_PAD((__GLX_COMPONENT_HDR_SIZE * na)
711 + (vs * count)
712 + __GLX_DRAWARRAYS_CMD_HDR_SIZE);
713 }
714
715
716 /**
717 * Emits the vertex data for the DrawArrays GLX protocol.
718 */
719 static GLsizei
720 emit_vertex(GLubyte * data, const struct array_info * arrays,
721 GLsizei num_arrays, GLint element, GLsizei offset)
722 {
723 GLint i;
724
725 for ( i = 0 ; i < num_arrays ; i++ ) {
726 (void) memcpy( data + offset,
727 arrays[i].ptr + (arrays[i].skip * element),
728 arrays[i].bytes );
729 offset += __GLX_PAD(arrays[i].bytes);
730 }
731
732 return offset;
733 }
734
735
736 static void
737 emit_header(GLubyte * pc, const struct array_info * arrays,
738 GLsizei num_arrays, GLsizei count, GLenum mode)
739 {
740 __GLXdispatchDrawArraysComponentHeader *arrayInfo;
741 GLsizei i;
742
743 __GLX_PUT_LONG(0, count);
744 __GLX_PUT_LONG(4, num_arrays);
745 __GLX_PUT_LONG(8, mode);
746
747 arrayInfo = (__GLXdispatchDrawArraysComponentHeader *)
748 (pc + __GLX_DRAWARRAYS_HDR_SIZE);
749
750
751 /* Write the ARRAY_INFO data.
752 */
753
754 for ( i = 0 ; i < num_arrays ; i++ ) {
755 arrayInfo[i] = arrays[i].ai;
756 }
757 }
758
759
760 /**
761 * Emit GLX DrawArrays protocol using a GLXRender packet.
762 */
763 static void
764 emit_Render_DrawArrays(__GLXcontext * gc, const struct array_info * arrays,
765 GLsizei first, GLsizei count, GLsizei num_arrays, GLenum mode,
766 GLsizei cmdlen, GLsizei total_vertex_size)
767 {
768 GLubyte * pc = gc->pc;
769 GLsizei offset;
770 GLsizei i;
771
772 __GLX_BEGIN_VARIABLE(X_GLrop_DrawArrays, cmdlen);
773 emit_header(pc + 4, arrays, num_arrays, count, mode);
774
775
776 /* Write the actual array data.
777 */
778
779 offset = __GLX_DRAWARRAYS_CMD_HDR_SIZE
780 + (num_arrays * __GLX_COMPONENT_HDR_SIZE);
781 for ( i = 0 ; i < count ; i++ ) {
782 offset = emit_vertex(pc, arrays, num_arrays, i + first, offset);
783 }
784
785 __GLX_END(cmdlen);
786 }
787
788
789 /**
790 * Emit GLX DrawArrays protocol using a GLXRenderLarge packet.
791 */
792 static void
793 emit_RenderLarge_DrawArrays(__GLXcontext * gc, const struct array_info * arrays,
794 GLsizei first, GLsizei count, GLsizei num_arrays, GLenum mode,
795 GLsizei cmdlen, GLsizei total_vertex_size)
796 {
797 GLubyte * pc = gc->pc;
798 GLsizei offset;
799 GLsizei i;
800 GLint maxSize;
801 GLint totalRequests;
802 GLint requestNumber;
803 GLsizei elements_per_request;
804
805
806 /* Calculate the maximum amount of data can be stuffed into a single
807 * packet. sz_xGLXRenderReq is added because bufSize is the maximum
808 * packet size minus sz_xGLXRenderReq.
809 *
810 * The important value here is elements_per_request. This is the number
811 * of complete array elements that will fit in a single buffer. There
812 * may be some wasted space at the end of the buffer, but splitting
813 * elements across buffer boundries would be painful.
814 */
815
816 maxSize = (gc->bufSize + sz_xGLXRenderReq) - sz_xGLXRenderLargeReq;
817
818 elements_per_request = maxSize / total_vertex_size;
819
820 totalRequests = ((count + (elements_per_request - 1))
821 / elements_per_request) + 1;
822
823
824 /* Fill in the header data and send it away.
825 */
826
827 __GLX_BEGIN_VARIABLE_LARGE(X_GLrop_DrawArrays, cmdlen+4);
828 emit_header(pc + 8, arrays, num_arrays, count, mode);
829
830 gc->pc = pc + (__GLX_DRAWARRAYS_CMD_HDR_SIZE + 4)
831 + (__GLX_COMPONENT_HDR_SIZE * num_arrays);
832 __glXSendLargeChunk(gc, 1, totalRequests, gc->buf, gc->pc - gc->buf);
833
834
835 /* Write the actual array data.
836 */
837 offset = 0;
838 requestNumber = 2;
839 for ( i = 0 ; i < count ; i++ ) {
840 if ( i == elements_per_request ) {
841 __glXSendLargeChunk(gc, requestNumber, totalRequests,
842 gc->buf, offset);
843 requestNumber++;
844 offset = 0;
845
846 count -= i;
847 first += i;
848 i = 0;
849 }
850
851 offset = emit_vertex(gc->buf, arrays, num_arrays, i + first, offset);
852 }
853
854 /* If the buffer isn't empty, emit the last, partial request.
855 */
856 if ( offset != 0 ) {
857 assert(requestNumber == totalRequests);
858 __glXSendLargeChunk(gc, requestNumber, totalRequests, gc->buf, offset);
859 }
860
861 gc->pc = gc->buf;
862 }
863
864
865 /**
866 * Emit DrawArrays protocol. This function acts as a switch betteen
867 * \c emit_Render_DrawArrays and \c emit_RenderLarge_DrawArrays depending
868 * on how much array data is to be sent.
869 */
870 static void
871 emit_DrawArraysEXT(const __GLXattribute * const state,
872 GLint first, GLsizei count, GLenum mode)
873 {
874 struct array_info arrays[32];
875 GLsizei num_arrays;
876 GLsizei total_vertex_size;
877 __GLXcontext *gc = __glXGetCurrentContext();
878 GLuint cmdlen;
879
880
881 /* Determine how big the final request will be. This depends on a number
882 * of factors. It depends on how many array elemets there are (which is
883 * the passed-in 'count'), how many arrays are enabled, how many elements
884 * are in each array entry, and what the types are for each array.
885 */
886
887 cmdlen = prep_arrays(state, arrays, count, & num_arrays,
888 & total_vertex_size);
889
890
891 /* If the data payload and the protocol header is too large for a Render
892 * command, use a RenderLarge command.
893 */
894 if (cmdlen > gc->maxSmallRenderCommandSize) {
895 emit_RenderLarge_DrawArrays(gc, arrays, first, count, num_arrays,
896 mode, cmdlen, total_vertex_size);
897 }
898 else {
899 emit_Render_DrawArrays(gc, arrays, first, count, num_arrays,
900 mode, cmdlen, total_vertex_size);
901 }
902 }
903
904
905 /**
906 * Emit a DrawArrays call using the old "protocol." This isn't really
907 * DrawArrays protocol at all. It just simulates DrawArrays by using
908 * immediate-mode vertex calls. Very, very slow for large arrays, but works
909 * with every GLX server.
910 */
911 static void
912 emit_DrawArrays_old(const __GLXattribute * const state,
913 GLint first, GLsizei count, GLenum mode)
914 {
915 const __GLXvertArrayState *va = &state->vertArray;
916 const GLubyte *vaPtr[__GLX_MAX_ARRAYS];
917 const GLubyte *tcaPtr[__GLX_MAX_TEXTURE_UNITS];
918 GLint i, j;
919
920 /*
921 ** Set up pointers for quick array traversal.
922 */
923
924 (void) memset( vaPtr, 0, sizeof(vaPtr) );
925 (void) memset( tcaPtr, 0, sizeof(tcaPtr) );
926
927 for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) {
928 if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) {
929 vaPtr[ j ] = va->arrays[ j ].ptr + first * va->arrays[ j ].skip;
930 }
931 }
932
933 for ( j = 0 ; j < __GLX_MAX_TEXTURE_UNITS ; j++ ) {
934 if (IS_TEXARRAY_ENABLED(state, j))
935 tcaPtr[ j ] = va->texCoord[ j ].ptr + first * va->texCoord[ j ].skip;
936 }
937
938 __indirect_glBegin(mode);
939 for (i = 0; i < count; i++) {
940 if (IS_TEXARRAY_ENABLED(state, 0)) {
941 (*va->texCoord[0].proc)(tcaPtr[0]);
942 tcaPtr[0] += va->texCoord[0].skip;
943 }
944
945 /* Multitexturing is handled specially because the protocol
946 * requires an extra parameter.
947 */
948 for (j=1; j<__GLX_MAX_TEXTURE_UNITS; ++j) {
949 if (IS_TEXARRAY_ENABLED(state, j)) {
950 (*va->texCoord[j].mtex_proc)(GL_TEXTURE0 + j, tcaPtr[j]);
951 tcaPtr[j] += va->texCoord[j].skip;
952 }
953 }
954
955 for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) {
956 if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) {
957 (*va->arrays[ j ].proc)(vaPtr[ j ]);
958 vaPtr[ j ] += va->arrays[ j ].skip;
959 }
960 }
961 }
962 __indirect_glEnd();
963 }
964
965
966 /**
967 * Validate that the \c mode and \c count parameters to \c glDrawArrays or
968 * \c glDrawElements are valid. If the arguments are not valid, then an
969 * error code is set in the GLX context.
970 *
971 * \returns \c GL_TRUE if the arguments are valide, \c GL_FALSE if they are
972 * not.
973 */
974 static GLboolean
975 glx_validate_array_args(__GLXcontext *gc, GLenum mode, GLsizei count)
976 {
977 switch(mode) {
978 case GL_POINTS:
979 case GL_LINE_STRIP:
980 case GL_LINE_LOOP:
981 case GL_LINES:
982 case GL_TRIANGLE_STRIP:
983 case GL_TRIANGLE_FAN:
984 case GL_TRIANGLES:
985 case GL_QUAD_STRIP:
986 case GL_QUADS:
987 case GL_POLYGON:
988 break;
989 default:
990 __glXSetError(gc, GL_INVALID_ENUM);
991 return GL_FALSE;
992 }
993
994 if (count < 0) {
995 __glXSetError(gc, GL_INVALID_VALUE);
996 return GL_FALSE;
997 }
998
999 return GL_TRUE;
1000 }
1001
1002
1003 void __indirect_glDrawArrays(GLenum mode, GLint first, GLsizei count)
1004 {
1005 __GLXcontext *gc = __glXGetCurrentContext();
1006 const __GLXattribute * state =
1007 (const __GLXattribute *)(gc->client_state_private);
1008
1009
1010 if ( ! glx_validate_array_args(gc, mode, count) ) {
1011 return;
1012 }
1013
1014 /* The "true" DrawArrays protocol does not support generic attributes,
1015 * multiple vertex arrays, or multiple texture coordinate arrays.
1016 */
1017 if ( state->NoDrawArraysProtocol
1018 || (state->vertArray.texture_enables > 1) ) {
1019 emit_DrawArrays_old(state, first, count, mode);
1020 }
1021 else {
1022 emit_DrawArraysEXT(state, first, count, mode);
1023 }
1024 }
1025
1026
1027 /**
1028 * \todo Modify this to use the "true" DrawArrays protocol if possible. This
1029 * would probably require refactoring out parts of \c emit_DrawArraysEXT into
1030 * more general functions that could be used in either place.
1031 */
1032 void __indirect_glDrawElements(GLenum mode, GLsizei count, GLenum type,
1033 const GLvoid *indices)
1034 {
1035 __GLXcontext *gc = __glXGetCurrentContext();
1036 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
1037 __GLXvertArrayState *va = &state->vertArray;
1038 const GLubyte *iPtr1 = NULL;
1039 const GLushort *iPtr2 = NULL;
1040 const GLuint *iPtr3 = NULL;
1041 GLint i, j, offset = 0;
1042
1043 if ( ! glx_validate_array_args(gc, mode, count) ) {
1044 return;
1045 }
1046
1047 switch (type) {
1048 case GL_UNSIGNED_BYTE:
1049 iPtr1 = (const GLubyte *)indices;
1050 break;
1051 case GL_UNSIGNED_SHORT:
1052 iPtr2 = (const GLushort *)indices;
1053 break;
1054 case GL_UNSIGNED_INT:
1055 iPtr3 = (const GLuint *)indices;
1056 break;
1057 default:
1058 __glXSetError(gc, GL_INVALID_ENUM);
1059 return;
1060 }
1061
1062 __indirect_glBegin(mode);
1063 for (i = 0; i < count; i++) {
1064 switch (type) {
1065 case GL_UNSIGNED_BYTE:
1066 offset = (GLint)(*iPtr1++);
1067 break;
1068 case GL_UNSIGNED_SHORT:
1069 offset = (GLint)(*iPtr2++);
1070 break;
1071 case GL_UNSIGNED_INT:
1072 offset = (GLint)(*iPtr3++);
1073 break;
1074 }
1075
1076 if (IS_TEXARRAY_ENABLED(state, 0)) {
1077 (*va->texCoord[0].proc)(va->texCoord[0].ptr+
1078 (offset*va->texCoord[0].skip));
1079 }
1080
1081 /* Multitexturing is handled specially because the protocol
1082 * requires an extra parameter.
1083 */
1084 for (j=1; j<__GLX_MAX_TEXTURE_UNITS; ++j) {
1085 if (IS_TEXARRAY_ENABLED(state, j)) {
1086 (*va->texCoord[j].mtex_proc)(GL_TEXTURE0 + j,
1087 va->texCoord[j].ptr+
1088 (offset*va->texCoord[j].skip));
1089 }
1090 }
1091
1092 for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) {
1093 if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) {
1094 (*va->arrays[ j ].proc)(va->arrays[ j ].ptr
1095 +(offset*va->arrays[ j ].skip));
1096 }
1097 }
1098 }
1099 __indirect_glEnd();
1100 }
1101
1102 void __indirect_glDrawRangeElements(GLenum mode, GLuint start, GLuint end,
1103 GLsizei count, GLenum type,
1104 const GLvoid *indices)
1105 {
1106 __GLXcontext *gc = __glXGetCurrentContext();
1107
1108 if (end < start) {
1109 __glXSetError(gc, GL_INVALID_VALUE);
1110 return;
1111 }
1112
1113 __indirect_glDrawElements(mode,count,type,indices);
1114 }
1115
1116 void __indirect_glMultiDrawArraysEXT(GLenum mode, GLint *first, GLsizei *count,
1117 GLsizei primcount)
1118 {
1119 GLsizei i;
1120
1121 for(i=0; i<primcount; i++) {
1122 if ( count[i] > 0 ) {
1123 __indirect_glDrawArrays( mode, first[i], count[i] );
1124 }
1125 }
1126 }
1127
1128 void __indirect_glMultiDrawElementsEXT(GLenum mode, const GLsizei *count,
1129 GLenum type, const GLvoid ** indices,
1130 GLsizei primcount)
1131 {
1132 GLsizei i;
1133
1134 for(i=0; i<primcount; i++) {
1135 if ( count[i] > 0 ) {
1136 __indirect_glDrawElements( mode, count[i], type, indices[i] );
1137 }
1138 }
1139 }
1140
1141 void __indirect_glClientActiveTextureARB(GLenum texture)
1142 {
1143 __GLXcontext *gc = __glXGetCurrentContext();
1144 __GLXattribute * state = (__GLXattribute *)(gc->client_state_private);
1145 GLint unit = (GLint) texture - GL_TEXTURE0;
1146
1147 if (unit < 0 || __GLX_MAX_TEXTURE_UNITS <= unit) {
1148 __glXSetError(gc, GL_INVALID_ENUM);
1149 return;
1150 }
1151 state->vertArray.activeTexture = unit;
1152 }