From: Brian Paul Date: Sun, 8 Feb 2004 02:03:41 +0000 (+0000) Subject: Updated to handle generic vertex attributes accessed vi glArrayElement(). X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0aa8a1062a06616fad18a1901afb5fa67fdcf82a;p=mesa.git Updated to handle generic vertex attributes accessed vi glArrayElement(). In fact, handle all conventional vertex attributes in terms of generic attributes (execept for edge flags and color indexes). --- diff --git a/src/mesa/main/api_arrayelt.c b/src/mesa/main/api_arrayelt.c index 93ba0b7bc35..3c2d43005a4 100644 --- a/src/mesa/main/api_arrayelt.c +++ b/src/mesa/main/api_arrayelt.c @@ -1,8 +1,8 @@ /* * Mesa 3-D graphics library - * Version: 5.1 + * Version: 6.1 * - * Copyright (C) 1999-2003 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,118 +34,35 @@ #include "macros.h" #include "mtypes.h" - -typedef void (GLAPIENTRY *texarray_func)( GLenum, const void * ); - -typedef struct { - GLint unit; - struct gl_client_array *array; - texarray_func func; -} AEtexarray; - typedef void (GLAPIENTRY *array_func)( const void * ); typedef struct { - struct gl_client_array *array; + const struct gl_client_array *array; array_func func; } AEarray; +typedef void (GLAPIENTRY *attrib_func)( GLuint indx, const void *data, GLboolean normalized, GLuint size ); + typedef struct { - AEtexarray texarrays[MAX_TEXTURE_COORD_UNITS + 1]; - AEarray arrays[32]; + const struct gl_client_array *array; + attrib_func func; + GLuint index; +} AEattrib; + +typedef struct { + AEarray arrays[3]; /* color index, edge flag, null terminator */ + AEattrib attribs[VERT_ATTRIB_MAX + 1]; GLuint NewState; } AEcontext; #define AE_CONTEXT(ctx) ((AEcontext *)(ctx)->aelt_context) -#define TYPE_IDX(t) ((t) & 0xf) - -static void (GLAPIENTRY *colorfuncs[2][8])( const void * ) = { - { (array_func)glColor3bv, - (array_func)glColor3ubv, - (array_func)glColor3sv, - (array_func)glColor3usv, - (array_func)glColor3iv, - (array_func)glColor3uiv, - (array_func)glColor3fv, - (array_func)glColor3dv }, - - { (array_func)glColor4bv, - (array_func)glColor4ubv, - (array_func)glColor4sv, - (array_func)glColor4usv, - (array_func)glColor4iv, - (array_func)glColor4uiv, - (array_func)glColor4fv, - (array_func)glColor4dv } -}; -static void (GLAPIENTRY *vertexfuncs[3][8])( const void * ) = { - { 0, - 0, - (array_func)glVertex2sv, - 0, - (array_func)glVertex2iv, - 0, - (array_func)glVertex2fv, - (array_func)glVertex2dv }, - - { 0, - 0, - (array_func)glVertex3sv, - 0, - (array_func)glVertex3iv, - 0, - (array_func)glVertex3fv, - (array_func)glVertex3dv }, - - { 0, - 0, - (array_func)glVertex4sv, - 0, - (array_func)glVertex4iv, - 0, - (array_func)glVertex4fv, - (array_func)glVertex4dv } -}; - - -static void (GLAPIENTRY *multitexfuncs[4][8])( GLenum, const void * ) = { - { 0, - 0, - (texarray_func)glMultiTexCoord1svARB, - 0, - (texarray_func)glMultiTexCoord1ivARB, - 0, - (texarray_func)glMultiTexCoord1fvARB, - (texarray_func)glMultiTexCoord1dvARB }, - - { 0, - 0, - (texarray_func)glMultiTexCoord2svARB, - 0, - (texarray_func)glMultiTexCoord2ivARB, - 0, - (texarray_func)glMultiTexCoord2fvARB, - (texarray_func)glMultiTexCoord2dvARB }, - - { 0, - 0, - (texarray_func)glMultiTexCoord3svARB, - 0, - (texarray_func)glMultiTexCoord3ivARB, - 0, - (texarray_func)glMultiTexCoord3fvARB, - (texarray_func)glMultiTexCoord3dvARB }, - - { 0, - 0, - (texarray_func)glMultiTexCoord4svARB, - 0, - (texarray_func)glMultiTexCoord4ivARB, - 0, - (texarray_func)glMultiTexCoord4fvARB, - (texarray_func)glMultiTexCoord4dvARB } -}; +/* + * Convert GL_BYTE, GL_UNSIGNED_BYTE, .. GL_DOUBLE into an integer + * in the range [0, 7]. Luckily these type tokens are sequentially + * numbered in gl.h + */ +#define TYPE_IDX(t) ((t) & 0xf) static void (GLAPIENTRY *indexfuncs[8])( const void * ) = { 0, @@ -159,93 +76,316 @@ static void (GLAPIENTRY *indexfuncs[8])( const void * ) = { }; -static void (GLAPIENTRY *normalfuncs[8])( const void * ) = { - (array_func)glNormal3bv, - 0, - (array_func)glNormal3sv, - 0, - (array_func)glNormal3iv, - 0, - (array_func)glNormal3fv, - (array_func)glNormal3dv, -}; - - -/* Wrapper functions in case glSecondaryColor*EXT doesn't exist */ -static void SecondaryColor3bvEXT(const GLbyte *c) -{ - _glapi_Dispatch->SecondaryColor3bvEXT(c); -} +/**********************************************************************/ -static void SecondaryColor3ubvEXT(const GLubyte *c) +/* 1, 2, 3 or 4 GL_BYTE attribute */ +static void VertexAttribbv(GLuint index, const GLbyte *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->SecondaryColor3ubvEXT(c); + switch (size) { + case 1: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, BYTE_TO_FLOAT(v[0]), + 0, 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], 0, 0, 1); + return; + case 2: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, BYTE_TO_FLOAT(v[0]), + BYTE_TO_FLOAT(v[1]), 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], 0, 1); + return; + case 3: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, BYTE_TO_FLOAT(v[0]), + BYTE_TO_FLOAT(v[1]), + BYTE_TO_FLOAT(v[2]), 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], 1); + return; + case 4: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, BYTE_TO_FLOAT(v[0]), + BYTE_TO_FLOAT(v[1]), + BYTE_TO_FLOAT(v[2]), + BYTE_TO_FLOAT(v[3])); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], v[3]); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribbv"); + } } -static void SecondaryColor3svEXT(const GLshort *c) +/* 1, 2, 3 or 4 GL_UNSIGNED_BYTE attribute */ +static void VertexAttribubv(GLuint index, const GLubyte *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->SecondaryColor3svEXT(c); + switch (size) { + case 1: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UBYTE_TO_FLOAT(v[0]), + 0, 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], 0, 0, 1); + return; + case 2: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UBYTE_TO_FLOAT(v[0]), + UBYTE_TO_FLOAT(v[1]), 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], 0, 1); + return; + case 3: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UBYTE_TO_FLOAT(v[0]), + UBYTE_TO_FLOAT(v[1]), + UBYTE_TO_FLOAT(v[2]), 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], 1); + return; + case 4: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UBYTE_TO_FLOAT(v[0]), + UBYTE_TO_FLOAT(v[1]), + UBYTE_TO_FLOAT(v[2]), + UBYTE_TO_FLOAT(v[3])); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], v[3]); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribubv"); + } } -static void SecondaryColor3usvEXT(const GLushort *c) +/* 1, 2, 3 or 4 GL_SHORT attribute */ +static void VertexAttribsv(GLuint index, const GLshort *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->SecondaryColor3usvEXT(c); + switch (size) { + case 1: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, SHORT_TO_FLOAT(v[0]), + 0, 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], 0, 0, 1); + return; + case 2: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, SHORT_TO_FLOAT(v[0]), + SHORT_TO_FLOAT(v[1]), 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], 0, 1); + return; + case 3: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, SHORT_TO_FLOAT(v[0]), + SHORT_TO_FLOAT(v[1]), + SHORT_TO_FLOAT(v[2]), 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], 1); + return; + case 4: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, SHORT_TO_FLOAT(v[0]), + SHORT_TO_FLOAT(v[1]), + SHORT_TO_FLOAT(v[2]), + SHORT_TO_FLOAT(v[3])); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], v[3]); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribsv"); + } } -static void SecondaryColor3ivEXT(const GLint *c) -{ - _glapi_Dispatch->SecondaryColor3ivEXT(c); -} -static void SecondaryColor3uivEXT(const GLuint *c) +/* 1, 2, 3 or 4 GL_UNSIGNED_SHORT attribute */ +static void VertexAttribusv(GLuint index, const GLushort *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->SecondaryColor3uivEXT(c); + switch (size) { + case 1: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, USHORT_TO_FLOAT(v[0]), + 0, 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], 0, 0, 1); + return; + case 2: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, USHORT_TO_FLOAT(v[0]), + USHORT_TO_FLOAT(v[1]), 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], 0, 1); + return; + case 3: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, USHORT_TO_FLOAT(v[0]), + USHORT_TO_FLOAT(v[1]), + USHORT_TO_FLOAT(v[2]), 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], 1); + return; + case 4: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, USHORT_TO_FLOAT(v[0]), + USHORT_TO_FLOAT(v[1]), + USHORT_TO_FLOAT(v[2]), + USHORT_TO_FLOAT(v[3])); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], v[3]); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribusv"); + } } -static void SecondaryColor3fvEXT(const GLfloat *c) +/* 1, 2, 3 or 4 GL_INT attribute */ +static void VertexAttribiv(GLuint index, const GLint *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->SecondaryColor3fvEXT(c); + switch (size) { + case 1: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, INT_TO_FLOAT(v[0]), + 0, 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], 0, 0, 1); + return; + case 2: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, INT_TO_FLOAT(v[0]), + INT_TO_FLOAT(v[1]), 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], 0, 1); + return; + case 3: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, INT_TO_FLOAT(v[0]), + INT_TO_FLOAT(v[1]), + INT_TO_FLOAT(v[2]), 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], 1); + return; + case 4: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, INT_TO_FLOAT(v[0]), + INT_TO_FLOAT(v[1]), + INT_TO_FLOAT(v[2]), + INT_TO_FLOAT(v[3])); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], v[3]); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribiv"); + } } -static void SecondaryColor3dvEXT(const GLdouble *c) +/* 1, 2, 3 or 4 GL_UNSIGNED_INT attribute */ +static void VertexAttribuiv(GLuint index, const GLuint *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->SecondaryColor3dvEXT(c); + switch (size) { + case 1: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UINT_TO_FLOAT(v[0]), + 0, 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], 0, 0, 1); + return; + case 2: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UINT_TO_FLOAT(v[0]), + UINT_TO_FLOAT(v[1]), 0, 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], 0, 1); + return; + case 3: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UINT_TO_FLOAT(v[0]), + UINT_TO_FLOAT(v[1]), + UINT_TO_FLOAT(v[2]), 1); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], 1); + return; + case 4: + if (normalized) + _glapi_Dispatch->VertexAttrib4fNV(index, UINT_TO_FLOAT(v[0]), + UINT_TO_FLOAT(v[1]), + UINT_TO_FLOAT(v[2]), + UINT_TO_FLOAT(v[3])); + else + _glapi_Dispatch->VertexAttrib4fNV(index, v[0], v[1], v[2], v[3]); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribuiv"); + } } -static void (GLAPIENTRY *secondarycolorfuncs[8])( const void * ) = { - (array_func) SecondaryColor3bvEXT, - (array_func) SecondaryColor3ubvEXT, - (array_func) SecondaryColor3svEXT, - (array_func) SecondaryColor3usvEXT, - (array_func) SecondaryColor3ivEXT, - (array_func) SecondaryColor3uivEXT, - (array_func) SecondaryColor3fvEXT, - (array_func) SecondaryColor3dvEXT, -}; - - -/* Again, wrapper functions in case glSecondaryColor*EXT doesn't exist */ -static void FogCoordfvEXT(const GLfloat *f) +/* 1, 2, 3 or 4 GL_FLOAT attribute */ +static void VertexAttribfv(GLuint index, const GLfloat *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->FogCoordfvEXT(f); + (void) normalized; + switch (size) { + case 1: + _glapi_Dispatch->VertexAttrib1fvNV(index, v); + return; + case 2: + _glapi_Dispatch->VertexAttrib2fvNV(index, v); + return; + case 3: + _glapi_Dispatch->VertexAttrib3fvNV(index, v); + return; + case 4: + _glapi_Dispatch->VertexAttrib4fvNV(index, v); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribfv"); + } } -static void FogCoorddvEXT(const GLdouble *f) +/* 1, 2, 3 or 4 GL_DOUBLE attribute */ +static void VertexAttribdv(GLuint index, const GLdouble *v, + GLboolean normalized, GLuint size) { - _glapi_Dispatch->FogCoorddvEXT(f); + (void) normalized; + switch (size) { + case 1: + _glapi_Dispatch->VertexAttrib1dvNV(index, v); + return; + case 2: + _glapi_Dispatch->VertexAttrib2dvNV(index, v); + return; + case 3: + _glapi_Dispatch->VertexAttrib3dvNV(index, v); + return; + case 4: + _glapi_Dispatch->VertexAttrib4dvNV(index, v); + return; + default: + _mesa_problem(NULL, "Bad size in VertexAttribdv"); + } } -static void (GLAPIENTRY *fogcoordfuncs[8])( const void * ) = { - 0, - 0, - 0, - 0, - 0, - 0, - (array_func) FogCoordfvEXT, - (array_func) FogCoorddvEXT +/* + * Array [size][type] of VertexAttrib functions + */ +static void (GLAPIENTRY *attribfuncs[8])( GLuint, const void *, GLboolean, GLuint ) = { + (attrib_func) VertexAttribbv, + (attrib_func) VertexAttribubv, + (attrib_func) VertexAttribsv, + (attrib_func) VertexAttribusv, + (attrib_func) VertexAttribiv, + (attrib_func) VertexAttribuiv, + (attrib_func) VertexAttribfv, + (attrib_func) VertexAttribdv }; +/**********************************************************************/ GLboolean _ae_create_context( GLcontext *ctx ) @@ -271,68 +411,88 @@ void _ae_destroy_context( GLcontext *ctx ) } +/* + * Return pointer to the conventional vertex array which corresponds + * to the given vertex attribute index. + */ +static struct gl_client_array * +conventional_array(GLcontext *ctx, GLuint index) +{ + ASSERT(index < VERT_ATTRIB_MAX); + switch (index) { + case VERT_ATTRIB_POS: + return &ctx->Array.Vertex; + case VERT_ATTRIB_NORMAL: + return &ctx->Array.Normal; + case VERT_ATTRIB_COLOR0: + return &ctx->Array.Color; + case VERT_ATTRIB_COLOR1: + return &ctx->Array.SecondaryColor; + case VERT_ATTRIB_FOG: + return &ctx->Array.FogCoord; + case VERT_ATTRIB_TEX0: + case VERT_ATTRIB_TEX1: + case VERT_ATTRIB_TEX2: + case VERT_ATTRIB_TEX3: + case VERT_ATTRIB_TEX4: + case VERT_ATTRIB_TEX5: + case VERT_ATTRIB_TEX6: + case VERT_ATTRIB_TEX7: + return &ctx->Array.TexCoord[index - VERT_ATTRIB_TEX0]; + default: + return NULL; + } +} + + +/** + * Make a list of functions to call per glArrayElement call which will + * access the vertex array data. + * Most vertex attributes are handled via glVertexAttrib4fvNV. + */ static void _ae_update_state( GLcontext *ctx ) { AEcontext *actx = AE_CONTEXT(ctx); - AEtexarray *ta = actx->texarrays; AEarray *aa = actx->arrays; + AEattrib *at = actx->attribs; GLuint i; - for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) - if (ctx->Array.TexCoord[i].Enabled) { - ta->unit = i; - ta->array = &ctx->Array.TexCoord[i]; - ta->func = multitexfuncs[ta->array->Size-1][TYPE_IDX(ta->array->Type)]; - ta++; - } - - ta->func = 0; - - if (ctx->Array.Color.Enabled) { - aa->array = &ctx->Array.Color; - aa->func = colorfuncs[aa->array->Size-3][TYPE_IDX(aa->array->Type)]; - aa++; - } - - if (ctx->Array.Normal.Enabled) { - aa->array = &ctx->Array.Normal; - aa->func = normalfuncs[TYPE_IDX(aa->array->Type)]; - aa++; - } - + /* yuck, no generic array to correspond to color index or edge flag */ if (ctx->Array.Index.Enabled) { aa->array = &ctx->Array.Index; aa->func = indexfuncs[TYPE_IDX(aa->array->Type)]; aa++; } - if (ctx->Array.EdgeFlag.Enabled) { aa->array = &ctx->Array.EdgeFlag; - aa->func = (array_func)glEdgeFlagv; - aa++; - } - - if (ctx->Array.FogCoord.Enabled) { - aa->array = &ctx->Array.FogCoord; - aa->func = fogcoordfuncs[TYPE_IDX(aa->array->Type)]; - aa++; - } - - if (ctx->Array.SecondaryColor.Enabled) { - aa->array = &ctx->Array.SecondaryColor; - aa->func = secondarycolorfuncs[TYPE_IDX(aa->array->Type)]; + aa->func = (array_func) glEdgeFlagv; aa++; } + aa->func = NULL; /* terminate the list */ + + /* all other arrays handled here */ + for (i = 0; i < VERT_ATTRIB_MAX; i++) { + /* Note: we count down to zero so glVertex (attrib 0) is last!!! */ + const GLuint index = VERT_ATTRIB_MAX - i - 1; + struct gl_client_array *array = conventional_array(ctx, index); + + /* check for overriding generic vertex attribute */ + if (ctx->VertexProgram.Enabled + && ctx->Array.VertexAttrib[index].Enabled) { + array = &ctx->Array.VertexAttrib[index]; + } - /* Must be last - */ - if (ctx->Array.Vertex.Enabled) { - aa->array = &ctx->Array.Vertex; - aa->func = vertexfuncs[aa->array->Size-2][TYPE_IDX(aa->array->Type)]; - aa++; + /* if array's enabled, add it to the list */ + if (array && array->Enabled) { + at->array = array; + at->func = attribfuncs[TYPE_IDX(array->Type)]; + at->index = index; + at++; + } } + ASSERT(at - actx->attribs <= VERT_ATTRIB_MAX); + at->func = NULL; /* terminate the list */ - aa->func = 0; actx->NewState = 0; } @@ -340,27 +500,27 @@ static void _ae_update_state( GLcontext *ctx ) void GLAPIENTRY _ae_loopback_array_elt( GLint elt ) { GET_CURRENT_CONTEXT(ctx); - AEcontext *actx = AE_CONTEXT(ctx); - AEtexarray *ta; - AEarray *aa; + const AEcontext *actx = AE_CONTEXT(ctx); + const AEarray *aa; + const AEattrib *at; if (actx->NewState) _ae_update_state( ctx ); - for (ta = actx->texarrays ; ta->func ; ta++) { - GLubyte *src = ta->array->BufferObj->Data - + (GLuint) ta->array->Ptr - + elt * ta->array->StrideB; - ta->func( ta->unit + GL_TEXTURE0_ARB, src); + /* color index and edge flags */ + for (aa = actx->arrays; aa->func ; aa++) { + const GLubyte *src = aa->array->BufferObj->Data + + (GLuint) aa->array->Ptr + + elt * aa->array->StrideB; + aa->func( src ); } - /* Must be last - */ - for (aa = actx->arrays ; aa->func ; aa++) { - GLubyte *src = aa->array->BufferObj->Data - + (GLuint) aa->array->Ptr - + elt * aa->array->StrideB; - aa->func( src ); + /* all other attributes */ + for (at = actx->attribs; at->func; at++) { + const GLubyte *src = at->array->BufferObj->Data + + (GLuint) at->array->Ptr + + elt * at->array->StrideB; + at->func( at->index, src, at->array->Normalized, at->array->Size ); } }