blob: 88f327a16f0807489a0c9cb59e5a44228abe41ba [file] [log] [blame]
/*
Copyright (c) 2011-2013 NVIDIA Corporation
Copyright (c) 2011-2012 Cass Everitt
Copyright (c) 2012 Scott Nations
Copyright (c) 2012 Mathias Schott
Copyright (c) 2012 Nigel Stewart
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Regal Vertex Array Object implementation
Cass Everitt
*/
#ifndef __REGAL_VAO_H__
#define __REGAL_VAO_H__
#include "RegalUtil.h"
REGAL_GLOBAL_BEGIN
#include <string>
#include "RegalEmu.h"
#include "RegalContext.h"
#include "RegalContextInfo.h"
#include "RegalSharedMap.h"
REGAL_GLOBAL_END
REGAL_NAMESPACE_BEGIN
#define REGAL_VAO_NUM_ARRAYS 16
namespace Emu
{
struct Vao
{
struct Array
{
Array()
: enabled( GL_FALSE )
, buffer( 0 )
, size( 4 )
, type( GL_FLOAT )
, normalized( GL_FALSE )
, integer( GL_FALSE )
, stride( 0 )
, pointer( NULL )
{}
GLboolean enabled;
GLuint buffer;
GLint size;
GLenum type;
GLboolean normalized;
GLboolean integer;
GLsizei stride;
const GLvoid *pointer;
};
struct Object
{
Object() : vertexBuffer( 0 ), indexBuffer( 0 ) {}
GLuint vertexBuffer;
GLuint indexBuffer;
Array a[ REGAL_VAO_NUM_ARRAYS ];
};
shared_map<GLuint, Object> objects;
GLenum clientActiveTexture;
GLuint current;
GLuint enables;
Object *currObject;
GLuint coreVao;
GLuint maxName;
// to alias vertex arrays to generic attribs
GLuint ffAttrMap[ REGAL_VAO_NUM_ARRAYS ];
GLuint ffAttrInvMap[ REGAL_VAO_NUM_ARRAYS ];
GLuint ffAttrTexBegin;
GLuint ffAttrTexEnd;
GLuint ffAttrNumTex;
GLuint maxVertexAttribs;
void Init( RegalContext &ctx )
{
maxName = 0;
clientActiveTexture = GL_TEXTURE0;
maxVertexAttribs = ctx.info->maxVertexAttribs;
RegalAssert( maxVertexAttribs <= REGAL_VAO_NUM_ARRAYS );
RegalContext *sharingWith = ctx.groupInitializedContext();
if (sharingWith)
objects = sharingWith->vao->objects;
// we have RFF2A maps for sets of 8 and 16 attributes. if
// REGAL_VAO_NUM_ARRAYS > 16 a new map needs to be added
RegalAssert( REGAL_VAO_NUM_ARRAYS <= 16 );
if ( maxVertexAttribs >= 16 )
{
RegalAssert( REGAL_VAO_NUM_ARRAYS == 16);
//RegalOutput( "Setting up for %d Vertex Attribs\n", maxVertexAttribs );
for( int i = 0; i < 16; i++ )
{
ffAttrMap[i] = RFF2AMap16[i];
ffAttrInvMap[i] = RFF2AInvMap16[i];
}
ffAttrTexBegin = RFF2ATexBegin16;
ffAttrTexEnd = RFF2ATexEnd16;
}
else
{
RegalAssert( maxVertexAttribs >= 8 );
//RegalOutput( "Setting up for 8 Vertex Attribs" );
for( int i = 0; i < 8; i++ )
{
ffAttrMap[i] = RFF2AMap8[i];
ffAttrInvMap[i] = RFF2AInvMap8[i];
}
for( int i = 8; i < REGAL_VAO_NUM_ARRAYS; i++ )
{
ffAttrMap[i] = GLuint(-1);
ffAttrInvMap[i] = GLuint(-1);
}
ffAttrTexBegin = RFF2ATexBegin8;
ffAttrTexEnd = RFF2ATexEnd8;
}
ffAttrNumTex = ffAttrTexEnd - ffAttrTexBegin;
if( ctx.info->core )
{
maxName = 1;
ctx.dispatcher.driver.glGenVertexArrays( 1, & coreVao );
RegalAssert( coreVao != 0 );
ctx.dispatcher.driver.glBindVertexArray( coreVao );
}
else
coreVao = 0;
current = 9999999; // this is only to force the bind...
currObject = NULL;
BindVertexArray( &ctx, 0 );
}
void Cleanup( RegalContext &ctx )
{
UNUSED_PARAMETER(ctx);
}
void ShadowBufferBinding( GLenum target, GLuint bufferBinding )
{
RegalAssert( currObject != NULL );
if( target == GL_ARRAY_BUFFER )
{
currObject->vertexBuffer = bufferBinding;
}
else if( target == GL_ELEMENT_ARRAY_BUFFER )
{
currObject->indexBuffer = bufferBinding;
}
}
void BindVertexArray( RegalContext *ctx, GLuint name )
{
if( name == current )
{
return;
}
current = name;
Object &vao = objects[current]; // force VAO construction
currObject = & vao;
if( maxName < current )
{
maxName = current;
}
DispatchTable &tbl = ctx->dispatcher.emulation;
tbl.glBindBuffer( GL_ARRAY_BUFFER, vao.vertexBuffer );
tbl.glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vao.indexBuffer );
GLuint lastBuffer = vao.vertexBuffer;
for( GLuint i = 0; i < maxVertexAttribs; i++ )
{
Array &a = vao.a[ i ];
if( a.buffer != lastBuffer )
{
//GLint e = tbl.glGetError();
tbl.glBindBuffer( GL_ARRAY_BUFFER, a.buffer );
//e = tbl.glGetError();
//RegalOutput( "Binding ARRAY_BUFFER %d - %d\n", a.buffer, e );
lastBuffer = a.buffer;
}
EnableDisableVertexAttribArray( ctx, a.enabled, i );
if( a.pointer || a.buffer )
{
tbl.glVertexAttribPointer( i, a.size, a.type, a.normalized, a.stride, a.pointer );
}
}
if( lastBuffer != vao.vertexBuffer )
{
tbl.glBindBuffer( GL_ARRAY_BUFFER, vao.vertexBuffer );
}
}
void GenVertexArrays( GLsizei n, GLuint *arrays )
{
if( maxName < 0x80000000 ) // fast gen for sequential allocation
{
for( GLsizei i = 0; i < n; i++ )
{
arrays[ i ] = ++maxName;
objects[ maxName ]; // gen allocates
}
}
else // otherwise plod through
{
GLsizei i = 0;
GLuint name = 1;
while( i < n )
{
if( objects.count( name ) == 0 )
{
arrays[ i++ ] = name;
objects[ name ]; // gen allocates
}
name++;
}
}
}
void DeleteVertexArrays( GLsizei n, const GLuint *arrays )
{
for( GLsizei i = 0; i < n; i++ )
{
GLuint name = arrays[ i ];
if( name != coreVao && objects.count( name ) > 0 )
{
objects.erase( name );
}
}
}
GLboolean IsVertexArray( GLuint name )
{
return objects.count( name ) > 0 ? GL_TRUE : GL_FALSE;
}
void EnableDisableVertexAttribArray( RegalContext *ctx, GLboolean enable, GLuint index )
{
RegalAssert( index < maxVertexAttribs );
DispatchTable &tbl = ctx->dispatcher.emulation;
Array &a = objects[current].a[index];
a.enabled = enable;
if( a.enabled == GL_TRUE )
{
tbl.glEnableVertexAttribArray( index );
enables |= 1 << index;
}
else
{
tbl.glDisableVertexAttribArray( index );
enables &= ~( 1 << index );
}
}
void EnableVertexAttribArray( RegalContext *ctx, GLuint index )
{
EnableDisableVertexAttribArray( ctx, GL_TRUE, index );
}
void DisableVertexAttribArray( RegalContext *ctx, GLuint index )
{
EnableDisableVertexAttribArray( ctx, GL_FALSE, index );
}
void AttribPointer( RegalContext *ctx, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer )
{
// do nothing for these various error conditions
if ( ctx->depthBeginEnd )
return;
if (index >= maxVertexAttribs)
return;
switch (size)
{
case 1:
case 2:
case 3:
case 4:
break;
case GL_BGRA:
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
break;
default:
return;
}
break;
default:
return;
}
switch (type)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_INT:
case GL_UNSIGNED_INT:
case GL_HALF_FLOAT:
case GL_FLOAT:
case GL_DOUBLE:
break;
case GL_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
if (size != 4 && size != GL_BGRA)
return;
break;
default:
RegalAssert( "Unknown <type> in for attrib." );
return;
}
if (size == GL_BGRA && normalized == GL_FALSE)
{
return;
}
if (stride < 0)
{
return;
}
//<> if ( ( currentClientState.vertexArrayState.vertexArrayObject != 0 ) &&
//<> ( currentClientState.vertexArrayState.vertexBuffer == 0 ) &&
//<> ( pointer != NULL ) ) {
//<> return;
//<> }
if( index == GLuint(~0) )
{
return;
}
if( index >= maxVertexAttribs )
{
return;
}
RegalAssert( index < maxVertexAttribs );
RegalAssert( currObject != NULL );
Array &a = objects[current].a[index];
a.buffer = currObject->vertexBuffer;
a.size = size;
a.type = type;
a.normalized = normalized;
a.stride = stride;
a.pointer = pointer;
RegalAssert( a.buffer == 0 || GLuint64( a.pointer ) < ( 1 << 22 ) );
ctx->dispatcher.emulation.glVertexAttribPointer( index, size, type, normalized, stride, pointer );
}
void Validate( RegalContext *ctx )
{
UNUSED_PARAMETER(ctx);
RegalAssert( currObject != NULL );
for( GLuint i = 0; i < maxVertexAttribs; i++ )
{
#if !REGAL_NO_ASSERT
const Array &a = currObject->a[ i ];
RegalAssert( !( a.enabled && a.buffer == 0 && GLuint64( a.pointer ) < 1024 ) );
#endif
}
}
template <typename T> void GetAttrib( GLint index, GLenum pname, T *params )
{
Array &a = objects[current].a[index];
switch( pname )
{
case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
*params = static_cast<T>(a.enabled);
break;
case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
*params = static_cast<T>(a.buffer);
break;
case GL_VERTEX_ATTRIB_ARRAY_SIZE:
//if( index == 3 ) RegalOutput( "Returning %d for index 3 from VAO GetAttrib for SIZE\n", a.size );
*params = static_cast<T>(a.size);
break;
case GL_VERTEX_ATTRIB_ARRAY_TYPE:
*params = static_cast<T>(a.type);
break;
case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
*params = static_cast<T>(a.normalized);
break;
case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
*params = static_cast<T>(a.stride);
break;
case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
*params = static_cast<T>(0);
default:
break;
}
}
template <typename T> void GetAttrib( GLint index, GLenum pname, T **params )
{
Array &a = objects[current].a[index];
switch( pname )
{
case GL_VERTEX_ATTRIB_ARRAY_POINTER:
*params = const_cast<T *>(a.pointer);
break;
default:
break;
}
}
template <typename T> bool Get( GLenum pname, T *params )
{
switch (pname)
{
case GL_VERTEX_ARRAY_BINDING:
*params = static_cast<T>( current );
break;
case GL_ARRAY_BUFFER_BINDING:
*params = static_cast<T>(currObject->vertexBuffer);
break;
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
*params = static_cast<T>(currObject->indexBuffer);
break;
default:
return false;
}
return true;
}
bool GetVertexAttribPointerv( GLuint index, GLenum pname, GLvoid **pointer)
{
if ( pname != GL_VERTEX_ATTRIB_ARRAY_POINTER )
return false;
Array &a = objects[current].a[index];
switch( pname )
{
case GL_VERTEX_ATTRIB_ARRAY_POINTER:
*pointer = const_cast<GLvoid *>(a.pointer);
break;
default:
return false;
}
return true;
}
GLuint ClientStateToAttribIndex( GLenum array )
{
switch ( array )
{
case GL_VERTEX_ARRAY:
return ffAttrMap[ RFF2A_Vertex ];
case GL_NORMAL_ARRAY:
return ffAttrMap[ RFF2A_Normal ];
case GL_COLOR_ARRAY:
return ffAttrMap[ RFF2A_Color ];
case GL_SECONDARY_COLOR_ARRAY:
return ffAttrMap[ RFF2A_SecondaryColor ];
case GL_FOG_COORD_ARRAY:
return ffAttrMap[ RFF2A_FogCoord ];
case GL_TEXTURE_COORD_ARRAY:
{
GLuint index = clientActiveTexture - GL_TEXTURE0;
RegalAssert(index < REGAL_VAO_NUM_ARRAYS);
if ( index < ffAttrNumTex )
return ffAttrTexBegin + index;
}
break;
default:
break;
}
return GLuint(~0);
}
void ShadowVertexArrayPointer( RegalContext *ctx, GLenum array, GLint size,
GLenum type, GLsizei stride, const GLvoid *pointer)
{
//<> if ( ( currentClientState.vertexArrayState.vertexArrayObject != 0 ) &&
//<> ( currentClientState.vertexArrayState.vertexBuffer == 0 ) &&
//<> ( pointer != NULL ) ) {
//<> return;
//<> }
GLuint index = ClientStateToAttribIndex( array );
AttribPointer( ctx, index, size, type, GL_TRUE, stride, pointer );
}
void ColorPointer(RegalContext *ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
if ( ctx->depthBeginEnd )
return;
switch (size)
{
case 3:
case 4:
break;
default:
return;
}
switch (type)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
case GL_DOUBLE:
break;
default:
return;
}
if (stride < 0)
return;
ShadowVertexArrayPointer(ctx, GL_COLOR_ARRAY, size, type, stride, pointer);
}
void SecondaryColorPointer(RegalContext *ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
if ( ctx->depthBeginEnd )
return;
if (size != 3)
return;
switch (type)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
case GL_DOUBLE:
break;
default:
return;
}
if (stride < 0)
return;
ShadowVertexArrayPointer(ctx, GL_SECONDARY_COLOR_ARRAY, size, type, stride, pointer);
}
void TexCoordPointer(RegalContext *ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
if ( ctx->depthBeginEnd )
return;
switch (size)
{
case 1:
case 2:
case 3:
case 4:
break;
default:
return;
}
switch (type)
{
case GL_SHORT:
case GL_INT:
case GL_FLOAT:
case GL_DOUBLE:
break;
default:
return;
}
if (stride < 0)
return;
ShadowVertexArrayPointer(ctx, GL_TEXTURE_COORD_ARRAY, size, type, stride, pointer);
}
void VertexPointer(RegalContext *ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
if ( ctx->depthBeginEnd )
return;
switch (size)
{
case 2:
case 3:
case 4:
break;
default:
return;
}
switch (type)
{
case GL_SHORT:
case GL_INT:
case GL_FLOAT:
case GL_DOUBLE:
break;
default:
return;
}
if (stride < 0)
return;
ShadowVertexArrayPointer(ctx, GL_VERTEX_ARRAY, size, type, stride, pointer);
}
void NormalPointer(RegalContext *ctx, GLenum type, GLsizei stride, const GLvoid *pointer)
{
if ( ctx->depthBeginEnd )
return;
switch (type)
{
case GL_BYTE:
case GL_SHORT:
case GL_INT:
case GL_FLOAT:
case GL_DOUBLE:
break;
default:
return;
}
if (stride < 0)
return;
ShadowVertexArrayPointer(ctx, GL_NORMAL_ARRAY, 0, type, stride, pointer);
}
void FogCoordPointer(RegalContext *ctx, GLenum type, GLsizei stride, const GLvoid *pointer)
{
if ( ctx->depthBeginEnd )
return;
switch (type)
{
case GL_FLOAT:
case GL_DOUBLE:
break;
default:
return;
}
if (stride < 0)
return;
ShadowVertexArrayPointer(ctx, GL_FOG_COORD_ARRAY, 0, type, stride, pointer);
}
void ClientActiveTexture( RegalContext *ctx, GLenum _texture)
{
UNUSED_PARAMETER(ctx);
if ( ctx->depthBeginEnd )
return;
GLint index = _texture - GL_TEXTURE0;
if (index >= 0 && index < REGAL_VAO_NUM_ARRAYS)
clientActiveTexture = _texture;
}
void ShadowEnableDisableClientState( RegalContext *ctx, GLenum array, GLboolean enable )
{
GLuint index = ClientStateToAttribIndex( array );
EnableDisableVertexAttribArray( ctx, enable, index );
}
void EnableClientState( RegalContext *ctx, GLenum array )
{
if ( ctx->depthBeginEnd )
return;
ShadowEnableDisableClientState( ctx, array, GL_TRUE );
}
void DisableClientState( RegalContext *ctx, GLenum array )
{
if ( ctx->depthBeginEnd )
return;
ShadowEnableDisableClientState( ctx, array, GL_FALSE );
}
void InterleavedArrays( RegalContext *ctx, GLenum format,
GLsizei stride, const GLvoid *pointer)
{
if ( ctx->depthBeginEnd )
return;
//<> how can stride be invalid?
//<> if ( stride is invalid )
//<> return;
switch ( format )
{
case GL_V2F:
case GL_V3F:
case GL_C4UB_V2F:
case GL_C4UB_V3F:
case GL_C3F_V3F:
case GL_N3F_V3F:
case GL_C4F_N3F_V3F:
case GL_T2F_V3F:
case GL_T4F_V4F:
case GL_T2F_C4UB_V3F:
case GL_T2F_C3F_V3F:
case GL_T2F_N3F_V3F:
case GL_T2F_C4F_N3F_V3F:
case GL_T4F_C4F_N3F_V4F:
break;
default:
RegalAssert( !"unhandled format value" );
return;
}
GLsizei f = sizeof(GL_FLOAT);
GLsizei c = 4 * sizeof(GL_UNSIGNED_BYTE);
//<> need to round up c to the nearest multiple of f
GLsizei pc = 0;
GLsizei pn = 0;
GLsizei pv = 0;
GLsizei s = 0;
switch ( format )
{
case GL_V2F:
pc = 0;
pn = 0;
pv = 0;
s = 2 * f;
break;
case GL_V3F:
pc = 0;
pn = 0;
pv = 0;
s = 3 * f;
break;
case GL_C4UB_V2F:
pc = 0;
pn = 0;
pv = c + 0;
s = c + 2 * f;
break;
case GL_C4UB_V3F:
pc = 0;
pn = 0;
pv = c + 0;
s = c + 3 * f;
break;
case GL_C3F_V3F:
pc = 0;
pn = 0;
pv = 3 * f;
s = 6 * f;
break;
case GL_N3F_V3F:
pc = 0;
pn = 0;
pv = 3 * f;
s = 6 * f;
break;
case GL_C4F_N3F_V3F:
pc = 0;
pn = 4 * f;
pv = 7 * f;
s = 10;
break;
case GL_T2F_V3F:
pc = 0;
pn = 0;
pv = 2 * f;
s = 5 * f;
break;
case GL_T4F_V4F:
pc = 0;
pn = 0;
pv = 4 * f;
s = 8 * f;
break;
case GL_T2F_C4UB_V3F:
pc = 2 * f;
pn = 0;
pv = c + 2 * f;
s = c + 5 * f;
break;
case GL_T2F_C3F_V3F:
pc = 2 * f;
pn = 0;
pv = 5 * f;
s = 8 * f;
break;
case GL_T2F_N3F_V3F:
pc = 0;
pn = 2 * f;
pv = 5 * f;
s = 8 * f;
break;
case GL_T2F_C4F_N3F_V3F:
pc = 2 * f;
pn = 6 * f;
pv = 9 * f;
s = 12 * f;
break;
case GL_T4F_C4F_N3F_V4F:
pc = 4 * f;
pn = 8 * f;
pv = 11 * f;
s = 15 * f;
break;
default:
RegalAssert( !"unhandled format value" );
break;
}
GLubyte *pointerc = static_cast<GLubyte *>( const_cast<GLvoid *>(pointer) ) + pc;
GLubyte *pointern = static_cast<GLubyte *>( const_cast<GLvoid *>(pointer) ) + pn;
GLubyte *pointerv = static_cast<GLubyte *>( const_cast<GLvoid *>(pointer) ) + pv;
if ( stride == 0 )
{
stride = s;
}
//<> ShadowEnableDisableClientState( ctx, GL_EDGE_FLAG_ARRAY, GL_FALSE );
//<> ShadowEnableDisableClientState( ctx, GL_INDEX_ARRAY, GL_FALSE );
ShadowEnableDisableClientState( ctx, GL_SECONDARY_COLOR_ARRAY, GL_FALSE );
ShadowEnableDisableClientState( ctx, GL_FOG_COORD_ARRAY, GL_FALSE );
GLint size = 0;
GLenum type = GL_FLOAT;
switch ( format )
{
case GL_T2F_V3F:
case GL_T4F_V4F:
case GL_T2F_C4UB_V3F:
case GL_T2F_C3F_V3F:
case GL_T2F_N3F_V3F:
case GL_T2F_C4F_N3F_V3F:
case GL_T4F_C4F_N3F_V4F:
size = ((format == GL_T4F_V4F) || (format == GL_T4F_C4F_N3F_V4F)) ? 4 : 2;
ShadowEnableDisableClientState( ctx, GL_TEXTURE_COORD_ARRAY, GL_TRUE );
TexCoordPointer(ctx, size, GL_FLOAT, stride, pointer);
break;
default:
ShadowEnableDisableClientState( ctx, GL_TEXTURE_COORD_ARRAY, GL_FALSE );
break;
}
switch ( format )
{
case GL_C4UB_V2F:
case GL_C4UB_V3F:
case GL_C3F_V3F:
case GL_C4F_N3F_V3F:
case GL_T2F_C4UB_V3F:
case GL_T2F_C3F_V3F:
case GL_T2F_C4F_N3F_V3F:
case GL_T4F_C4F_N3F_V4F:
size = ((format == GL_C3F_V3F) || (format == GL_T2F_C3F_V3F)) ? 3 : 4;
ShadowEnableDisableClientState( ctx, GL_COLOR_ARRAY, GL_TRUE );
ColorPointer(ctx, size, type, stride, pointerc);
break;
default:
ShadowEnableDisableClientState( ctx, GL_COLOR_ARRAY, GL_FALSE );
break;
}
switch ( format )
{
case GL_N3F_V3F:
case GL_C4F_N3F_V3F:
case GL_T2F_N3F_V3F:
case GL_T2F_C4F_N3F_V3F:
case GL_T4F_C4F_N3F_V4F:
ShadowEnableDisableClientState( ctx, GL_NORMAL_ARRAY, GL_TRUE );
NormalPointer(ctx, GL_FLOAT, stride, pointern);
break;
default:
ShadowEnableDisableClientState( ctx, GL_NORMAL_ARRAY, GL_FALSE );
break;
}
switch ( format )
{
case GL_V2F:
case GL_C4UB_V2F:
size = 2;
break;
case GL_V3F:
case GL_C4UB_V3F:
case GL_C3F_V3F:
case GL_N3F_V3F:
case GL_C4F_N3F_V3F:
case GL_T2F_V3F:
case GL_T2F_C4UB_V3F:
case GL_T2F_C3F_V3F:
case GL_T2F_N3F_V3F:
case GL_T2F_C4F_N3F_V3F:
size = 3;
break;
case GL_T4F_V4F:
case GL_T4F_C4F_N3F_V4F:
size = 4;
break;
default:
RegalAssert( !"unhandled format value" );
break;
}
ShadowEnableDisableClientState( ctx, GL_VERTEX_ARRAY, GL_TRUE );
VertexPointer(ctx, size, GL_FLOAT, stride, pointerv);
}
};
}
REGAL_NAMESPACE_END
#endif // ! __REGAL_VAO_H__