diff options
Diffstat (limited to 'src/glx/x11/vertarr.c')
-rw-r--r-- | src/glx/x11/vertarr.c | 1152 |
1 files changed, 1152 insertions, 0 deletions
diff --git a/src/glx/x11/vertarr.c b/src/glx/x11/vertarr.c new file mode 100644 index 00000000000..3f8cfcfde3a --- /dev/null +++ b/src/glx/x11/vertarr.c @@ -0,0 +1,1152 @@ +/* $XFree86: xc/lib/GL/glx/vertarr.c,v 1.4 2001/03/25 05:32:00 tsi Exp $ */ +/* +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: The application programming interfaces +** established by SGI in conjunction with the Original Code are The +** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released +** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version +** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X +** Window System(R) (Version 1.3), released October 19, 1998. This software +** was created using the OpenGL(R) version 1.2.1 Sample Implementation +** published by SGI, but has not been independently verified as being +** compliant with the OpenGL(R) version 1.2.1 Specification. +** +*/ + +#define NEED_GL_FUNCS_WRAPPED +#include <assert.h> +#include "glxclient.h" +#include "packrender.h" +#include <string.h> +#include <limits.h> /* INT_MAX */ + +/* macros for setting function pointers */ +#define __GL_VERTEX_FUNC(NAME, let) \ + case GL_##NAME: \ + if (size == 2) \ + vertexPointer->proc = (void (*)(const void *))glVertex2##let##v; \ + else if (size == 3) \ + vertexPointer->proc = (void (*)(const void *))glVertex3##let##v; \ + else if (size == 4) \ + vertexPointer->proc = (void (*)(const void *))glVertex4##let##v; \ + break + +#define __GL_NORMAL_FUNC(NAME, let) \ + case GL_##NAME: \ + normalPointer->proc = (void (*)(const void *))glNormal3##let##v; \ + break + +#define __GL_COLOR_FUNC(NAME, let) \ + case GL_##NAME: \ + if (size == 3) \ + colorPointer->proc = (void (*)(const void *))glColor3##let##v; \ + else if (size == 4)\ + colorPointer->proc = (void (*)(const void *))glColor4##let##v; \ + break + +#define __GL_SEC_COLOR_FUNC(NAME, let) \ + case GL_##NAME: \ + seccolorPointer->proc = (void (*)(const void *))glSecondaryColor3##let##v; \ + +#define __GL_FOG_FUNC(NAME, let) \ + case GL_##NAME: \ + fogPointer->proc = (void (*)(const void *))glFogCoord##let##v; \ + +#define __GL_INDEX_FUNC(NAME, let) \ + case GL_##NAME: \ + indexPointer->proc = (void (*)(const void *))glIndex##let##v; \ + break + +#define __GL_TEXTURE_FUNC(NAME, let) \ + case GL_##NAME: \ + if (size == 1) { \ + texCoordPointer->proc = (void (*)(const void *))glTexCoord1##let##v; \ + texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))glMultiTexCoord1##let##vARB; \ + } else if (size == 2) { \ + texCoordPointer->proc = (void (*)(const void *))glTexCoord2##let##v; \ + texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))glMultiTexCoord2##let##vARB; \ + } else if (size == 3) { \ + texCoordPointer->proc = (void (*)(const void *))glTexCoord3##let##v; \ + texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))glMultiTexCoord2##let##vARB; \ + } else if (size == 4) { \ + texCoordPointer->proc = (void (*)(const void *))glTexCoord4##let##v; \ + texCoordPointer->mtex_proc = (void (*)(GLenum, const void *))glMultiTexCoord4##let##vARB; \ + } break + +/** + * Table of sizes, in bytes, of a GL types. All of the type enums are be in + * the range 0x1400 - 0x140F. That includes types added by extensions (i.e., + * \c GL_HALF_FLOAT_NV). This elements of this table correspond to the + * type enums masked with 0x0f. + * + * \notes + * \c GL_HAVE_FLOAT_NV is not included. Neither are \c GL_2_BYTES, + * \c GL_3_BYTES, or \c GL_4_BYTES. + */ +static const GLuint __glXTypeSize_table[16] = { + 1, 1, 2, 2, 4, 4, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0 +}; + +#define __glXTypeSize(e) ((((e) & ~0x0f) != 0x1400) \ + ? 0 : __glXTypeSize_table[ (e) & 0x0f ]) + + +/** + * Initialize vertex array state for a GLX context. + * + * \param gc GLX context whose vertex array state is to be initialized. + * + * \todo + * Someone is going to have to check the spec. This function takes greate + * care to initialize the \c size and \c type fields to "correct" values + * for each array. I'm not sure this is necessary. I think it should be + * acceptable to just \c memset the whole \c arrays and \c texCoord arrays + * to zero and be done with it. The spec may say something to the contrary, + * however. + */ +void __glXInitVertexArrayState(__GLXcontext *gc) +{ + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertArrayState *va = &state->vertArray; + GLint i; + + va->enables = 0; + va->texture_enables = 0; + + for ( i = 0 ; i < __GLX_MAX_ARRAYS ; i++ ) { + va->arrays[ i ].proc = NULL; + va->arrays[ i ].skip = 0; + va->arrays[ i ].ptr = 0; + va->arrays[ i ].size = 1; + va->arrays[ i ].type = GL_FLOAT; + va->arrays[ i ].stride = 0; + } + + va->arrays[ edgeFlag_ARRAY ].type = GL_UNSIGNED_BYTE;; + + va->arrays[ secondaryColor_ARRAY ].size = 3; + va->arrays[ color_ARRAY ].size = 4; + va->arrays[ normal_ARRAY ].size = 3; + va->arrays[ vertex_ARRAY ].size = 4; + + for ( i = 0 ; i < __GLX_MAX_TEXTURE_UNITS ; i++ ) { + va->texCoord[ i ].proc = NULL; + va->texCoord[ i ].skip = 0; + va->texCoord[ i ].ptr = 0; + va->texCoord[ i ].size = 4; + va->texCoord[ i ].type = GL_FLOAT; + va->texCoord[ i ].stride = 0; + } + + va->maxElementsVertices = INT_MAX; + va->maxElementsIndices = INT_MAX; +} + +/*****************************************************************************/ + +void glVertexPointer(GLint size, GLenum type, GLsizei stride, + const GLvoid *pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *vertexPointer = &state->vertArray.arrays[ vertex_ARRAY ]; + + /* Check arguments */ + if (size < 2 || size > 4 || stride < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + switch(type) { + __GL_VERTEX_FUNC(SHORT, s); + __GL_VERTEX_FUNC(INT, i); + __GL_VERTEX_FUNC(FLOAT, f); + __GL_VERTEX_FUNC(DOUBLE, d); + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + vertexPointer->size = size; + vertexPointer->type = type; + vertexPointer->stride = stride; + vertexPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + vertexPointer->skip = __glXTypeSize(type) * size; + } else { + vertexPointer->skip = stride; + } +} + +void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *normalPointer = &state->vertArray.arrays[ normal_ARRAY ]; + + /* Check arguments */ + if (stride < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + switch(type) { + __GL_NORMAL_FUNC(BYTE, b); + __GL_NORMAL_FUNC(SHORT, s); + __GL_NORMAL_FUNC(INT, i); + __GL_NORMAL_FUNC(FLOAT, f); + __GL_NORMAL_FUNC(DOUBLE, d); + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + normalPointer->type = type; + normalPointer->stride = stride; + normalPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + normalPointer->skip = 3 * __glXTypeSize(type); + } else { + normalPointer->skip = stride; + } +} + +void glColorPointer(GLint size, GLenum type, GLsizei stride, + const GLvoid *pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *colorPointer = &state->vertArray.arrays[ color_ARRAY ]; + + /* Check arguments */ + if (stride < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + switch(type) { + __GL_COLOR_FUNC(BYTE, b); + __GL_COLOR_FUNC(UNSIGNED_BYTE, ub); + __GL_COLOR_FUNC(SHORT, s); + __GL_COLOR_FUNC(UNSIGNED_SHORT, us); + __GL_COLOR_FUNC(INT, i); + __GL_COLOR_FUNC(UNSIGNED_INT, ui); + __GL_COLOR_FUNC(FLOAT, f); + __GL_COLOR_FUNC(DOUBLE, d); + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + colorPointer->size = size; + colorPointer->type = type; + colorPointer->stride = stride; + colorPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + colorPointer->skip = size * __glXTypeSize(type); + } else { + colorPointer->skip = stride; + } +} + +void glIndexPointer(GLenum type, GLsizei stride, const GLvoid *pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *indexPointer = &state->vertArray.arrays[ index_ARRAY ]; + + /* Check arguments */ + if (stride < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + switch(type) { + __GL_INDEX_FUNC(UNSIGNED_BYTE, ub); + __GL_INDEX_FUNC(SHORT, s); + __GL_INDEX_FUNC(INT, i); + __GL_INDEX_FUNC(FLOAT, f); + __GL_INDEX_FUNC(DOUBLE, d); + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + indexPointer->type = type; + indexPointer->stride = stride; + indexPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + indexPointer->skip = __glXTypeSize(type); + } else { + indexPointer->skip = stride; + } +} + +void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, + const GLvoid *pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *texCoordPointer = + &state->vertArray.texCoord[state->vertArray.activeTexture]; + + /* Check arguments */ + if (size < 1 || size > 4 || stride < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + switch(type) { + __GL_TEXTURE_FUNC(SHORT, s); + __GL_TEXTURE_FUNC(INT, i); + __GL_TEXTURE_FUNC(FLOAT, f); + __GL_TEXTURE_FUNC(DOUBLE, d); + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + texCoordPointer->size = size; + texCoordPointer->type = type; + texCoordPointer->stride = stride; + texCoordPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + texCoordPointer->skip = __glXTypeSize(type) * size; + } else { + texCoordPointer->skip = stride; + } +} + +void glEdgeFlagPointer(GLsizei stride, const GLvoid *pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *edgeFlagPointer = &state->vertArray.arrays[ edgeFlag_ARRAY ]; + + /* Check arguments */ + if (stride < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + edgeFlagPointer->proc = (void (*)(const void *))glEdgeFlagv; + + edgeFlagPointer->stride = stride; + edgeFlagPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + edgeFlagPointer->skip = sizeof(GLboolean); + } else { + edgeFlagPointer->skip = stride; + } + +} + +void glSecondaryColorPointer(GLint size, GLenum type, GLsizei stride, + const GLvoid * pointer ) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *seccolorPointer = &state->vertArray.arrays[ secondaryColor_ARRAY ]; + + /* Check arguments */ + if ( (stride < 0) || (size != 3) ) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + switch(type) { + __GL_SEC_COLOR_FUNC(BYTE, b); + __GL_SEC_COLOR_FUNC(UNSIGNED_BYTE, ub); + __GL_SEC_COLOR_FUNC(SHORT, s); + __GL_SEC_COLOR_FUNC(UNSIGNED_SHORT, us); + __GL_SEC_COLOR_FUNC(INT, i); + __GL_SEC_COLOR_FUNC(UNSIGNED_INT, ui); + __GL_SEC_COLOR_FUNC(FLOAT, f); + __GL_SEC_COLOR_FUNC(DOUBLE, d); + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + seccolorPointer->size = size; + seccolorPointer->type = type; + seccolorPointer->stride = stride; + seccolorPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + seccolorPointer->skip = size * __glXTypeSize(type); + } else { + seccolorPointer->skip = stride; + } +} + +void glFogCoordPointer(GLenum type, GLsizei stride, const GLvoid * pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertexArrayPointerState *fogPointer = &state->vertArray.arrays[ fogCoord_ARRAY ]; + + /* Check arguments */ + if (stride < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + /* Choose appropriate api proc */ + switch(type) { + __GL_FOG_FUNC(FLOAT, f); + __GL_FOG_FUNC(DOUBLE, d); + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + fogPointer->size = 1; + fogPointer->type = type; + fogPointer->stride = stride; + fogPointer->ptr = pointer; + + /* Set internal state */ + if (stride == 0) { + fogPointer->skip = __glXTypeSize(type); + } else { + fogPointer->skip = stride; + } +} + +void glInterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + GLboolean tEnable = GL_FALSE, cEnable = GL_FALSE, nEnable = GL_FALSE; + GLenum tType = GL_FLOAT, nType = GL_FLOAT, vType = GL_FLOAT; + GLenum cType = GL_FALSE; + GLint tSize = 0, cSize = 0, nSize = 3, vSize; + int cOffset = 0, nOffset = 0, vOffset = 0; + GLint trueStride, size; + + switch (format) { + case GL_V2F: + vSize = 2; + size = __glXTypeSize(vType) * vSize; + break; + case GL_V3F: + vSize = 3; + size = __glXTypeSize(vType) * vSize; + break; + case GL_C4UB_V2F: + cEnable = GL_TRUE; + cSize = 4; + cType = GL_UNSIGNED_BYTE; + vSize = 2; + vOffset = __glXTypeSize(cType) * cSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_C4UB_V3F: + cEnable = GL_TRUE; + cSize = 4; + cType = GL_UNSIGNED_BYTE; + vSize = 3; + vOffset = __glXTypeSize(vType) * cSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_C3F_V3F: + cEnable = GL_TRUE; + cSize = 3; + cType = GL_FLOAT; + vSize = 3; + vOffset = __glXTypeSize(cType) * cSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_N3F_V3F: + nEnable = GL_TRUE; + vSize = 3; + vOffset = __glXTypeSize(nType) * nSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_C4F_N3F_V3F: + cEnable = GL_TRUE; + cSize = 4; + cType = GL_FLOAT; + nEnable = GL_TRUE; + nOffset = __glXTypeSize(cType) * cSize; + vSize = 3; + vOffset = nOffset + __glXTypeSize(nType) * nSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_T2F_V3F: + tEnable = GL_TRUE; + tSize = 2; + vSize = 3; + vOffset = __glXTypeSize(tType) * tSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_T4F_V4F: + tEnable = GL_TRUE; + tSize = 4; + vSize = 4; + vOffset = __glXTypeSize(tType) * tSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_T2F_C4UB_V3F: + tEnable = GL_TRUE; + tSize = 2; + cEnable = GL_TRUE; + cSize = 4; + cType = GL_UNSIGNED_BYTE; + cOffset = __glXTypeSize(tType) * tSize; + vSize = 3; + vOffset = cOffset + __glXTypeSize(cType) * cSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_T2F_C3F_V3F: + tEnable = GL_TRUE; + tSize = 2; + cEnable = GL_TRUE; + cSize = 3; + cType = GL_FLOAT; + cOffset = __glXTypeSize(tType) * tSize; + vSize = 3; + vOffset = cOffset + __glXTypeSize(cType) * cSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_T2F_N3F_V3F: + tEnable = GL_TRUE; + tSize = 2; + nEnable = GL_TRUE; + nOffset = __glXTypeSize(tType) * tSize; + vSize = 3; + vOffset = nOffset + __glXTypeSize(nType) * nSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_T2F_C4F_N3F_V3F: + tEnable = GL_TRUE; + tSize = 2; + cEnable = GL_TRUE; + cSize = 4; + cType = GL_FLOAT; + cOffset = __glXTypeSize(tType) * tSize; + nEnable = GL_TRUE; + nOffset = cOffset + __glXTypeSize(cType) * cSize; + vSize = 3; + vOffset = nOffset + __glXTypeSize(nType) * nSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + case GL_T4F_C4F_N3F_V4F: + tEnable = GL_TRUE; + tSize = 4; + cEnable = GL_TRUE; + cSize = 4; + cType = GL_FLOAT; + cOffset = __glXTypeSize(tType) * tSize; + nEnable = GL_TRUE; + nOffset = cOffset + __glXTypeSize(cType) * cSize; + vSize = 4; + vOffset = nOffset + __glXTypeSize(nType) * nSize; + size = vOffset + __glXTypeSize(vType) * vSize; + break; + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + trueStride = (stride == 0) ? size : stride; + + state->vertArray.enables = 0; + state->vertArray.texture_enables = 0; + if (tEnable) { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(tSize, tType, trueStride, (const char *)pointer); + } + if (cEnable) { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(cSize, cType, trueStride, (const char *)pointer+cOffset); + } + if (nEnable) { + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(nType, trueStride, (const char *)pointer+nOffset); + } + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(vSize, vType, trueStride, (const char *)pointer+vOffset); +} + +/*****************************************************************************/ + +void glArrayElement(GLint i) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertArrayState *va = &state->vertArray; + GLint j; + + + if (IS_TEXARRAY_ENABLED(state, 0)) { + (*va->texCoord[0].proc)(va->texCoord[0].ptr+i*va->texCoord[0].skip); + } + + /* Multitexturing is handled specially because the protocol + * requires an extra parameter. + */ + for (j=1; j<__GLX_MAX_TEXTURE_UNITS; ++j) { + if (IS_TEXARRAY_ENABLED(state, j)) { + (*va->texCoord[j].mtex_proc)(GL_TEXTURE0 + j, va->texCoord[j].ptr+i*va->texCoord[j].skip); + } + } + + for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) { + if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) { + (*va->arrays[ j ].proc)(va->arrays[ j ].ptr+i*va->arrays[ j ].skip); + } + } +} + + +struct array_info { + __GLXdispatchDrawArraysComponentHeader ai; + GLsizei bytes; + const GLubyte *ptr; + GLsizei skip; +}; + + +/** + * Initialize a \c array_info structure for each array that is enabled in + * \c state. Determine how many arrays are enabled, and store the result + * in \c num_arrays. Determine how big each vertex is, and store the result + * in \c total_vertex_size. + * + * \returns The size of the final request. This is the size, in bytes, of + * the DrawArrays header, the ARRAY_INFO structures, and all the vertex data. + * This value \b assumes a \c X_GLXRender command is used. The true size + * will be 4 bytes larger if a \c X_GLXRenderLarge command is used. + */ +static GLuint +prep_arrays(const __GLXattribute * const state, struct array_info * arrays, + GLint count, + GLsizei *num_arrays, GLsizei *total_vertex_size) +{ + GLsizei na = 0; + GLsizei vs = 0; + +#define ASSIGN_ARRAY_INFO(state, enum_name, arr) \ + do { \ + arrays[ na ].ai.datatype = state->vertArray. arr .type ; \ + arrays[ na ].ai.numVals = state->vertArray. arr .size ; \ + arrays[ na ].ai.component = GL_ ## enum_name ## _ARRAY; \ +\ + arrays[ na ].bytes = state->vertArray. arr .size \ + * __glXTypeSize( state->vertArray. arr .type ); \ + arrays[ na ].ptr = state->vertArray. arr .ptr; \ + arrays[ na ].skip = state->vertArray. arr .skip; \ +\ + vs += __GLX_PAD(arrays[ na ].bytes); \ + na++; \ + } while( 0 ) + +#define ADD_ARRAY_IF_ENABLED(state, enum_name, arr) \ + do { if ( IS_ARRAY_ENABLED(state, arr) ) { \ + ASSIGN_ARRAY_INFO(state, enum_name, arrays[ arr ## _ARRAY ] ); \ + } } while( 0 ) + + ADD_ARRAY_IF_ENABLED(state, VERTEX, vertex); + ADD_ARRAY_IF_ENABLED(state, NORMAL, normal); + ADD_ARRAY_IF_ENABLED(state, COLOR, color); + ADD_ARRAY_IF_ENABLED(state, SECONDARY_COLOR, secondaryColor); + ADD_ARRAY_IF_ENABLED(state, FOG_COORD, fogCoord); + ADD_ARRAY_IF_ENABLED(state, EDGE_FLAG, edgeFlag); + ADD_ARRAY_IF_ENABLED(state, INDEX, index); + + /* The standard DrawArrays protocol *only* supports a single array of + * texture coordinates. + */ + if ( IS_TEXARRAY_ENABLED(state, 0) ) { + ASSIGN_ARRAY_INFO(state, TEXTURE_COORD, texCoord[0]); + } + + *num_arrays = na; + *total_vertex_size = vs; + + return __GLX_PAD((__GLX_COMPONENT_HDR_SIZE * na) + + (vs * count) + + __GLX_DRAWARRAYS_CMD_HDR_SIZE); +} + + +/** + * Emits the vertex data for the DrawArrays GLX protocol. + */ +static GLsizei +emit_vertex(GLubyte * data, const struct array_info * arrays, + GLsizei num_arrays, GLint element, GLsizei offset) +{ + GLint i; + + for ( i = 0 ; i < num_arrays ; i++ ) { + (void) memcpy( data + offset, + arrays[i].ptr + (arrays[i].skip * element), + arrays[i].bytes ); + offset += __GLX_PAD(arrays[i].bytes); + } + + return offset; +} + + +static void +emit_header(GLubyte * pc, const struct array_info * arrays, + GLsizei num_arrays, GLsizei count, GLenum mode) +{ + __GLXdispatchDrawArraysComponentHeader *arrayInfo; + GLsizei i; + + __GLX_PUT_LONG(0, count); + __GLX_PUT_LONG(4, num_arrays); + __GLX_PUT_LONG(8, mode); + + arrayInfo = (__GLXdispatchDrawArraysComponentHeader *) + (pc + __GLX_DRAWARRAYS_HDR_SIZE); + + + /* Write the ARRAY_INFO data. + */ + + for ( i = 0 ; i < num_arrays ; i++ ) { + arrayInfo[i] = arrays[i].ai; + } +} + + +/** + * Emit GLX DrawArrays protocol using a GLXRender packet. + */ +static void +emit_Render_DrawArrays(__GLXcontext * gc, const struct array_info * arrays, + GLsizei first, GLsizei count, GLsizei num_arrays, GLenum mode, + GLsizei cmdlen, GLsizei total_vertex_size) +{ + GLubyte * pc = gc->pc; + GLsizei offset; + GLsizei i; + + __GLX_BEGIN_VARIABLE(X_GLrop_DrawArrays, cmdlen); + emit_header(pc + 4, arrays, num_arrays, count, mode); + + + /* Write the actual array data. + */ + + offset = __GLX_DRAWARRAYS_CMD_HDR_SIZE + + (num_arrays * __GLX_COMPONENT_HDR_SIZE); + for ( i = 0 ; i < count ; i++ ) { + offset = emit_vertex(pc, arrays, num_arrays, i + first, offset); + } + + __GLX_END(cmdlen); +} + + +/** + * Emit GLX DrawArrays protocol using a GLXRenderLarge packet. + */ +static void +emit_RenderLarge_DrawArrays(__GLXcontext * gc, const struct array_info * arrays, + GLsizei first, GLsizei count, GLsizei num_arrays, GLenum mode, + GLsizei cmdlen, GLsizei total_vertex_size) +{ + GLubyte * pc = gc->pc; + GLsizei offset; + GLsizei i; + GLint maxSize; + GLint totalRequests; + GLint requestNumber; + GLsizei elements_per_request; + + + /* Calculate the maximum amount of data can be stuffed into a single + * packet. sz_xGLXRenderReq is added because bufSize is the maximum + * packet size minus sz_xGLXRenderReq. + * + * The important value here is elements_per_request. This is the number + * of complete array elements that will fit in a single buffer. There + * may be some wasted space at the end of the buffer, but splitting + * elements across buffer boundries would be painful. + */ + + maxSize = (gc->bufSize + sz_xGLXRenderReq) - sz_xGLXRenderLargeReq; + + elements_per_request = maxSize / total_vertex_size; + + totalRequests = ((count + (elements_per_request - 1)) + / elements_per_request) + 1; + + + /* Fill in the header data and send it away. + */ + + __GLX_BEGIN_VARIABLE_LARGE(X_GLrop_DrawArrays, cmdlen+4); + emit_header(pc + 8, arrays, num_arrays, count, mode); + + gc->pc = pc + (__GLX_DRAWARRAYS_CMD_HDR_SIZE + 4) + + (__GLX_COMPONENT_HDR_SIZE * num_arrays); + __glXSendLargeChunk(gc, 1, totalRequests, gc->buf, gc->pc - gc->buf); + + + /* Write the actual array data. + */ + offset = 0; + requestNumber = 2; + for ( i = 0 ; i < count ; i++ ) { + if ( i == elements_per_request ) { + __glXSendLargeChunk(gc, requestNumber, totalRequests, + gc->buf, offset); + requestNumber++; + offset = 0; + + count -= i; + first += i; + i = 0; + } + + offset = emit_vertex(gc->buf, arrays, num_arrays, i + first, offset); + } + + /* If the buffer isn't empty, emit the last, partial request. + */ + if ( offset != 0 ) { + assert(requestNumber == totalRequests); + __glXSendLargeChunk(gc, requestNumber, totalRequests, gc->buf, offset); + } + + gc->pc = gc->buf; +} + + +/** + * Emit DrawArrays protocol. This function acts as a switch betteen + * \c emit_Render_DrawArrays and \c emit_RenderLarge_DrawArrays depending + * on how much array data is to be sent. + */ +static void +emit_DrawArraysEXT(const __GLXattribute * const state, + GLint first, GLsizei count, GLenum mode) +{ + struct array_info arrays[32]; + GLsizei num_arrays; + GLsizei total_vertex_size; + __GLXcontext *gc = __glXGetCurrentContext(); + GLuint cmdlen; + + + /* Determine how big the final request will be. This depends on a number + * of factors. It depends on how many array elemets there are (which is + * the passed-in 'count'), how many arrays are enabled, how many elements + * are in each array entry, and what the types are for each array. + */ + + cmdlen = prep_arrays(state, arrays, count, & num_arrays, + & total_vertex_size); + + + /* If the data payload and the protocol header is too large for a Render + * command, use a RenderLarge command. + */ + if (cmdlen > gc->maxSmallRenderCommandSize) { + emit_RenderLarge_DrawArrays(gc, arrays, first, count, num_arrays, + mode, cmdlen, total_vertex_size); + } + else { + emit_Render_DrawArrays(gc, arrays, first, count, num_arrays, + mode, cmdlen, total_vertex_size); + } +} + + +/** + * Emit a DrawArrays call using the old "protocol." This isn't really + * DrawArrays protocol at all. It just simulates DrawArrays by using + * immediate-mode vertex calls. Very, very slow for large arrays, but works + * with every GLX server. + */ +static void +emit_DrawArrays_old(const __GLXattribute * const state, + GLint first, GLsizei count, GLenum mode) +{ + const __GLXvertArrayState *va = &state->vertArray; + const GLubyte *vaPtr[__GLX_MAX_ARRAYS]; + const GLubyte *tcaPtr[__GLX_MAX_TEXTURE_UNITS]; + GLint i, j; + + /* + ** Set up pointers for quick array traversal. + */ + + (void) memset( vaPtr, 0, sizeof(vaPtr) ); + (void) memset( tcaPtr, 0, sizeof(tcaPtr) ); + + for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) { + if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) { + vaPtr[ j ] = va->arrays[ j ].ptr + first * va->arrays[ j ].skip; + } + } + + for ( j = 0 ; j < __GLX_MAX_TEXTURE_UNITS ; j++ ) { + if (IS_TEXARRAY_ENABLED(state, j)) + tcaPtr[ j ] = va->texCoord[ j ].ptr + first * va->texCoord[ j ].skip; + } + + glBegin(mode); + for (i = 0; i < count; i++) { + if (IS_TEXARRAY_ENABLED(state, 0)) { + (*va->texCoord[0].proc)(tcaPtr[0]); + tcaPtr[0] += va->texCoord[0].skip; + } + + /* Multitexturing is handled specially because the protocol + * requires an extra parameter. + */ + for (j=1; j<__GLX_MAX_TEXTURE_UNITS; ++j) { + if (IS_TEXARRAY_ENABLED(state, j)) { + (*va->texCoord[j].mtex_proc)(GL_TEXTURE0 + j, tcaPtr[j]); + tcaPtr[j] += va->texCoord[j].skip; + } + } + + for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) { + if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) { + (*va->arrays[ j ].proc)(vaPtr[ j ]); + vaPtr[ j ] += va->arrays[ j ].skip; + } + } + } + glEnd(); +} + + +/** + * Validate that the \c mode and \c count parameters to \c glDrawArrays or + * \c glDrawElements are valid. If the arguments are not valid, then an + * error code is set in the GLX context. + * + * \returns \c GL_TRUE if the arguments are valide, \c GL_FALSE if they are + * not. + */ +static GLboolean +glx_validate_array_args(__GLXcontext *gc, GLenum mode, GLsizei count) +{ + switch(mode) { + case GL_POINTS: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + case GL_LINES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: + case GL_QUAD_STRIP: + case GL_QUADS: + case GL_POLYGON: + break; + default: + __glXSetError(gc, GL_INVALID_ENUM); + return GL_FALSE; + } + + if (count < 0) { + __glXSetError(gc, GL_INVALID_VALUE); + return GL_FALSE; + } + + return GL_TRUE; +} + + +void glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + const __GLXattribute * state = + (const __GLXattribute *)(gc->client_state_private); + + + if ( ! glx_validate_array_args(gc, mode, count) ) { + return; + } + + /* The "true" DrawArrays protocol does not support generic attributes, + * multiple vertex arrays, or multiple texture coordinate arrays. + */ + if ( state->NoDrawArraysProtocol + || (state->vertArray.texture_enables > 1) ) { + emit_DrawArrays_old(state, first, count, mode); + } + else { + emit_DrawArraysEXT(state, first, count, mode); + } +} + + +/** + * \todo Modify this to use the "true" DrawArrays protocol if possible. This + * would probably require refactoring out parts of \c emit_DrawArraysEXT into + * more general functions that could be used in either place. + */ +void glDrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + __GLXvertArrayState *va = &state->vertArray; + const GLubyte *iPtr1 = NULL; + const GLushort *iPtr2 = NULL; + const GLuint *iPtr3 = NULL; + GLint i, j, offset = 0; + + if ( ! glx_validate_array_args(gc, mode, count) ) { + return; + } + + switch (type) { + case GL_UNSIGNED_BYTE: + iPtr1 = (const GLubyte *)indices; + break; + case GL_UNSIGNED_SHORT: + iPtr2 = (const GLushort *)indices; + break; + case GL_UNSIGNED_INT: + iPtr3 = (const GLuint *)indices; + break; + default: + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + + glBegin(mode); + for (i = 0; i < count; i++) { + switch (type) { + case GL_UNSIGNED_BYTE: + offset = (GLint)(*iPtr1++); + break; + case GL_UNSIGNED_SHORT: + offset = (GLint)(*iPtr2++); + break; + case GL_UNSIGNED_INT: + offset = (GLint)(*iPtr3++); + break; + } + + if (IS_TEXARRAY_ENABLED(state, 0)) { + (*va->texCoord[0].proc)(va->texCoord[0].ptr+ + (offset*va->texCoord[0].skip)); + } + + /* Multitexturing is handled specially because the protocol + * requires an extra parameter. + */ + for (j=1; j<__GLX_MAX_TEXTURE_UNITS; ++j) { + if (IS_TEXARRAY_ENABLED(state, j)) { + (*va->texCoord[j].mtex_proc)(GL_TEXTURE0 + j, + va->texCoord[j].ptr+ + (offset*va->texCoord[j].skip)); + } + } + + for ( j = 0 ; j < __GLX_MAX_ARRAYS ; j++ ) { + if (IS_ARRAY_ENABLED_BY_INDEX(state, j)) { + (*va->arrays[ j ].proc)(va->arrays[ j ].ptr + +(offset*va->arrays[ j ].skip)); + } + } + } + glEnd(); +} + +void glDrawRangeElements(GLenum mode, GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid *indices) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + + if (end < start) { + __glXSetError(gc, GL_INVALID_VALUE); + return; + } + + glDrawElements(mode,count,type,indices); +} + +void glMultiDrawArrays(GLenum mode, GLint *first, GLsizei *count, + GLsizei primcount) +{ + GLsizei i; + + for(i=0; i<primcount; i++) { + if ( count[i] > 0 ) { + glDrawArrays( mode, first[i], count[i] ); + } + } +} + +void glMultiDrawElements(GLenum mode, const GLsizei *count, + GLenum type, const GLvoid ** indices, + GLsizei primcount) +{ + GLsizei i; + + for(i=0; i<primcount; i++) { + if ( count[i] > 0 ) { + glDrawElements( mode, count[i], type, indices[i] ); + } + } +} + +void glClientActiveTextureARB(GLenum texture) +{ + __GLXcontext *gc = __glXGetCurrentContext(); + __GLXattribute * state = (__GLXattribute *)(gc->client_state_private); + GLint unit = (GLint) texture - GL_TEXTURE0; + + if (unit < 0 || __GLX_MAX_TEXTURE_UNITS <= unit) { + __glXSetError(gc, GL_INVALID_ENUM); + return; + } + state->vertArray.activeTexture = unit; +} |