/******************************Module*Header*******************************\ * Module Name: array.c * * OpenGL client side vertex array functions. * * Created: 1-30-1996 * Author: Hock San Lee [hockl] * * Copyright (c) 1996 Microsoft Corporation \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include "os.h" #include "glsbcltu.h" #include "glclt.h" #include "compsize.h" #include "glsize.h" #include "context.h" #include "global.h" #include "lcfuncs.h" void FASTCALL VA_ArrayElementB(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_V2F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_C3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_N3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_C3F_N3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_C4F_N3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_T2F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_T2F_C3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_T2F_N3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_T2F_C3F_N3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElement_T2F_C4F_N3F_V3F_B(__GLcontext *gc, GLint firstVertex, GLint nVertices); void FASTCALL VA_ArrayElementBI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_V2F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_C3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_N3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_C3F_N3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_C4F_N3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_T2F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_T2F_C3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_T2F_N3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_T2F_C3F_N3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement_T2F_C4F_N3F_V3F_BI(__GLcontext *gc, GLint nVertices, VAMAP* indices); void FASTCALL VA_ArrayElement(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_V2F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_C3F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_N3F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_C3F_N3F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_C4F_N3F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_T2F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_T2F_C3F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_T2F_N3F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_T2F_C3F_N3F_V3F(__GLcontext *gc, GLint i); void FASTCALL VA_ArrayElement_T2F_C4F_N3F_V3F(__GLcontext *gc, GLint i); #define VAMASK_FORMAT_C3F \ (VAMASK_COLOR_ENABLE_MASK | VAMASK_COLOR_SIZE_3 | VAMASK_COLOR_TYPE_FLOAT) #define VAMASK_FORMAT_C4F \ (VAMASK_COLOR_ENABLE_MASK | VAMASK_COLOR_SIZE_4 | VAMASK_COLOR_TYPE_FLOAT) #define VAMASK_FORMAT_C4UB \ (VAMASK_COLOR_ENABLE_MASK | VAMASK_COLOR_SIZE_4 | VAMASK_COLOR_TYPE_UBYTE) #define VAMASK_FORMAT_N3F \ (VAMASK_NORMAL_ENABLE_MASK | VAMASK_NORMAL_TYPE_FLOAT) #define VAMASK_FORMAT_T2F \ (VAMASK_TEXCOORD_ENABLE_MASK | VAMASK_TEXCOORD_SIZE_2 | VAMASK_TEXCOORD_TYPE_FLOAT) #define VAMASK_FORMAT_T4F \ (VAMASK_TEXCOORD_ENABLE_MASK | VAMASK_TEXCOORD_SIZE_4 | VAMASK_TEXCOORD_TYPE_FLOAT) #define VAMASK_FORMAT_V2F \ (VAMASK_VERTEX_ENABLE_MASK | VAMASK_VERTEX_SIZE_2 | VAMASK_VERTEX_TYPE_FLOAT) #define VAMASK_FORMAT_V3F \ (VAMASK_VERTEX_ENABLE_MASK | VAMASK_VERTEX_SIZE_3 | VAMASK_VERTEX_TYPE_FLOAT) #define VAMASK_FORMAT_V4F \ (VAMASK_VERTEX_ENABLE_MASK | VAMASK_VERTEX_SIZE_4 | VAMASK_VERTEX_TYPE_FLOAT) #define VAMASK_FORMAT_C3F_V3F \ (VAMASK_FORMAT_C3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_N3F_V3F \ (VAMASK_FORMAT_N3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_C3F_N3F_V3F \ (VAMASK_FORMAT_C3F | VAMASK_FORMAT_N3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_C4F_N3F_V3F \ (VAMASK_FORMAT_C4F | VAMASK_FORMAT_N3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_T2F_V3F \ (VAMASK_FORMAT_T2F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_T2F_C3F_V3F \ (VAMASK_FORMAT_T2F | VAMASK_FORMAT_C3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_T2F_N3F_V3F \ (VAMASK_FORMAT_T2F | VAMASK_FORMAT_N3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_T2F_C3F_N3F_V3F \ (VAMASK_FORMAT_T2F | VAMASK_FORMAT_C3F | VAMASK_FORMAT_N3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_T2F_C4F_N3F_V3F \ (VAMASK_FORMAT_T2F | VAMASK_FORMAT_C4F | VAMASK_FORMAT_N3F | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_C4UB_V2F \ (VAMASK_FORMAT_C4UB | VAMASK_FORMAT_V2F) #define VAMASK_FORMAT_C4UB_V3F \ (VAMASK_FORMAT_C4UB | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_T4F_V4F \ (VAMASK_FORMAT_T4F | VAMASK_FORMAT_V4F) #define VAMASK_FORMAT_T2F_C4UB_V3F \ (VAMASK_FORMAT_T2F | VAMASK_FORMAT_C4UB | VAMASK_FORMAT_V3F) #define VAMASK_FORMAT_T4F_C4F_N3F_V4F \ (VAMASK_FORMAT_T4F | VAMASK_FORMAT_C4F | VAMASK_FORMAT_N3F | VAMASK_FORMAT_V4F) // TYPE_ASSERT GLint __glTypeSize[] = { sizeof(GLbyte), // GL_BYTE sizeof(GLubyte), // GL_UNSIGNED_BYTE sizeof(GLshort), // GL_SHORT sizeof(GLushort), // GL_UNSIGNED_SHORT sizeof(GLint), // GL_INT sizeof(GLuint), // GL_UNSIGNED_INT sizeof(GLfloat), // GL_FLOAT 2, // GL_2_BYTES 3, // GL_3_BYTES 4, // GL_4_BYTES sizeof(GLdouble) // GL_DOUBLE }; // ARRAY_TYPE_ASSERT GLuint vaEnable[] = { VAMASK_VERTEX_ENABLE_MASK, // GL_VERTEX_ARRAY VAMASK_NORMAL_ENABLE_MASK, // GL_NORMAL_ARRAY VAMASK_COLOR_ENABLE_MASK, // GL_COLOR_ARRAY VAMASK_INDEX_ENABLE_MASK, // GL_INDEX_ARRAY VAMASK_TEXCOORD_ENABLE_MASK, // GL_TEXTURE_COORD_ARRAY VAMASK_EDGEFLAG_ENABLE_MASK // GL_EDGE_FLAG_ARRAY }; PFNGLVECTOR afnTexCoord[] = { (PFNGLVECTOR)glcltTexCoord1sv, (PFNGLVECTOR)glcltTexCoord1iv, (PFNGLVECTOR)glcltTexCoord1fv, (PFNGLVECTOR)glcltTexCoord1dv, (PFNGLVECTOR)glcltTexCoord2sv, (PFNGLVECTOR)glcltTexCoord2iv, (PFNGLVECTOR)glcltTexCoord2fv, (PFNGLVECTOR)glcltTexCoord2dv, (PFNGLVECTOR)glcltTexCoord3sv, (PFNGLVECTOR)glcltTexCoord3iv, (PFNGLVECTOR)glcltTexCoord3fv, (PFNGLVECTOR)glcltTexCoord3dv, (PFNGLVECTOR)glcltTexCoord4sv, (PFNGLVECTOR)glcltTexCoord4iv, (PFNGLVECTOR)glcltTexCoord4fv, (PFNGLVECTOR)glcltTexCoord4dv, }; PFNGLVECTOR afnTexCoordCompile[] = { (PFNGLVECTOR)__gllc_TexCoord1sv, (PFNGLVECTOR)__gllc_TexCoord1iv, (PFNGLVECTOR)__gllc_TexCoord1fv, (PFNGLVECTOR)__gllc_TexCoord1dv, (PFNGLVECTOR)__gllc_TexCoord2sv, (PFNGLVECTOR)__gllc_TexCoord2iv, (PFNGLVECTOR)__gllc_TexCoord2fv, (PFNGLVECTOR)__gllc_TexCoord2dv, (PFNGLVECTOR)__gllc_TexCoord3sv, (PFNGLVECTOR)__gllc_TexCoord3iv, (PFNGLVECTOR)__gllc_TexCoord3fv, (PFNGLVECTOR)__gllc_TexCoord3dv, (PFNGLVECTOR)__gllc_TexCoord4sv, (PFNGLVECTOR)__gllc_TexCoord4iv, (PFNGLVECTOR)__gllc_TexCoord4fv, (PFNGLVECTOR)__gllc_TexCoord4dv, }; PFNGLVECTOR afnColor_InRGBA[] = { (PFNGLVECTOR)glcltColor3bv_InRGBA, (PFNGLVECTOR)glcltColor3ubv_InRGBA, (PFNGLVECTOR)glcltColor3sv_InRGBA, (PFNGLVECTOR)glcltColor3usv_InRGBA, (PFNGLVECTOR)glcltColor3iv_InRGBA, (PFNGLVECTOR)glcltColor3uiv_InRGBA, (PFNGLVECTOR)glcltColor3fv_InRGBA, (PFNGLVECTOR)glcltColor3dv_InRGBA, (PFNGLVECTOR)glcltColor4bv_InRGBA, (PFNGLVECTOR)glcltColor4ubv_InRGBA, (PFNGLVECTOR)glcltColor4sv_InRGBA, (PFNGLVECTOR)glcltColor4usv_InRGBA, (PFNGLVECTOR)glcltColor4iv_InRGBA, (PFNGLVECTOR)glcltColor4uiv_InRGBA, (PFNGLVECTOR)glcltColor4fv_InRGBA, (PFNGLVECTOR)glcltColor4dv_InRGBA, }; PFNGLVECTOR afnColor_InCI[] = { (PFNGLVECTOR)glcltColor3bv_InCI, (PFNGLVECTOR)glcltColor3ubv_InCI, (PFNGLVECTOR)glcltColor3sv_InCI, (PFNGLVECTOR)glcltColor3usv_InCI, (PFNGLVECTOR)glcltColor3iv_InCI, (PFNGLVECTOR)glcltColor3uiv_InCI, (PFNGLVECTOR)glcltColor3fv_InCI, (PFNGLVECTOR)glcltColor3dv_InCI, (PFNGLVECTOR)glcltColor4bv_InCI, (PFNGLVECTOR)glcltColor4ubv_InCI, (PFNGLVECTOR)glcltColor4sv_InCI, (PFNGLVECTOR)glcltColor4usv_InCI, (PFNGLVECTOR)glcltColor4iv_InCI, (PFNGLVECTOR)glcltColor4uiv_InCI, (PFNGLVECTOR)glcltColor4fv_InCI, (PFNGLVECTOR)glcltColor4dv_InCI, }; PFNGLVECTOR afnColorCompile[] = { (PFNGLVECTOR)__gllc_Color3bv, (PFNGLVECTOR)__gllc_Color3ubv, (PFNGLVECTOR)__gllc_Color3sv, (PFNGLVECTOR)__gllc_Color3usv, (PFNGLVECTOR)__gllc_Color3iv, (PFNGLVECTOR)__gllc_Color3uiv, (PFNGLVECTOR)__gllc_Color3fv, (PFNGLVECTOR)__gllc_Color3dv, (PFNGLVECTOR)__gllc_Color4bv, (PFNGLVECTOR)__gllc_Color4ubv, (PFNGLVECTOR)__gllc_Color4sv, (PFNGLVECTOR)__gllc_Color4usv, (PFNGLVECTOR)__gllc_Color4iv, (PFNGLVECTOR)__gllc_Color4uiv, (PFNGLVECTOR)__gllc_Color4fv, (PFNGLVECTOR)__gllc_Color4dv, }; PFNGLVECTOR afnIndex_InRGBA[] = { (PFNGLVECTOR)glcltIndexubv_InRGBA, (PFNGLVECTOR)glcltIndexsv_InRGBA, (PFNGLVECTOR)glcltIndexiv_InRGBA, (PFNGLVECTOR)glcltIndexfv_InRGBA, (PFNGLVECTOR)glcltIndexdv_InRGBA, }; PFNGLVECTOR afnIndex_InCI[] = { (PFNGLVECTOR)glcltIndexubv_InCI, (PFNGLVECTOR)glcltIndexsv_InCI, (PFNGLVECTOR)glcltIndexiv_InCI, (PFNGLVECTOR)glcltIndexfv_InCI, (PFNGLVECTOR)glcltIndexdv_InCI, }; PFNGLVECTOR afnIndexCompile[] = { (PFNGLVECTOR)__gllc_Indexubv, (PFNGLVECTOR)__gllc_Indexsv, (PFNGLVECTOR)__gllc_Indexiv, (PFNGLVECTOR)__gllc_Indexfv, (PFNGLVECTOR)__gllc_Indexdv, }; PFNGLVECTOR afnNormal[] = { (PFNGLVECTOR)glcltNormal3bv, (PFNGLVECTOR)glcltNormal3sv, (PFNGLVECTOR)glcltNormal3iv, (PFNGLVECTOR)glcltNormal3fv, (PFNGLVECTOR)glcltNormal3dv, }; PFNGLVECTOR afnNormalCompile[] = { (PFNGLVECTOR)__gllc_Normal3bv, (PFNGLVECTOR)__gllc_Normal3sv, (PFNGLVECTOR)__gllc_Normal3iv, (PFNGLVECTOR)__gllc_Normal3fv, (PFNGLVECTOR)__gllc_Normal3dv, }; PFNGLVECTOR afnVertex[] = { (PFNGLVECTOR)glcltVertex2sv, (PFNGLVECTOR)glcltVertex2iv, (PFNGLVECTOR)glcltVertex2fv, (PFNGLVECTOR)glcltVertex2dv, (PFNGLVECTOR)glcltVertex3sv, (PFNGLVECTOR)glcltVertex3iv, (PFNGLVECTOR)glcltVertex3fv, (PFNGLVECTOR)glcltVertex3dv, (PFNGLVECTOR)glcltVertex4sv, (PFNGLVECTOR)glcltVertex4iv, (PFNGLVECTOR)glcltVertex4fv, (PFNGLVECTOR)glcltVertex4dv, }; PFNGLVECTOR afnVertexCompile[] = { (PFNGLVECTOR)__gllc_Vertex2sv, (PFNGLVECTOR)__gllc_Vertex2iv, (PFNGLVECTOR)__gllc_Vertex2fv, (PFNGLVECTOR)__gllc_Vertex2dv, (PFNGLVECTOR)__gllc_Vertex3sv, (PFNGLVECTOR)__gllc_Vertex3iv, (PFNGLVECTOR)__gllc_Vertex3fv, (PFNGLVECTOR)__gllc_Vertex3dv, (PFNGLVECTOR)__gllc_Vertex4sv, (PFNGLVECTOR)__gllc_Vertex4iv, (PFNGLVECTOR)__gllc_Vertex4fv, (PFNGLVECTOR)__gllc_Vertex4dv, }; void FASTCALL __glInitVertexArray(__GLcontext *gc) { // Initial vertex array state. static __GLvertexArray defaultVertexArrayState = { __GL_VERTEX_ARRAY_DIRTY, // flags VAMASK_TEXCOORD_SIZE_4 | // mask VAMASK_TEXCOORD_TYPE_FLOAT | VAMASK_INDEX_TYPE_FLOAT | VAMASK_COLOR_SIZE_4 | VAMASK_COLOR_TYPE_FLOAT | VAMASK_NORMAL_TYPE_FLOAT | VAMASK_VERTEX_SIZE_4 | VAMASK_VERTEX_TYPE_FLOAT, VA_ArrayElement, // pfnArrayElement VA_ArrayElementB, // pfnArrayElementBatch VA_ArrayElementBI, // pfnArrayElementBatchIndirect { // edgeFlag sizeof(GLboolean), // ibytes 0, // stride NULL, // pointer glcltEdgeFlagv, // pfn __gllc_EdgeFlagv, // pfnCompile }, { // texcoord 4, // size GL_FLOAT, // type 4 * sizeof(GLfloat), // ibytes 0, // stride NULL, // pointer NULL, // pfn NULL, // pfnCompile }, { // index GL_FLOAT, // type sizeof(GLfloat), // ibytes 0, // stride NULL, // pointer NULL, // pfn NULL, // pfnCompile }, { // color 4, // size GL_FLOAT, // type 4 * sizeof(GLfloat), // ibytes 0, // stride NULL, // pointer NULL, // pfn NULL, // pfnCompile }, { // normal GL_FLOAT, // type 3 * sizeof(GLfloat), // ibytes 0, // stride NULL, // pointer NULL, // pfn NULL, // pfnCompile }, { // vertex 4, // size GL_FLOAT, // type 4 * sizeof(GLfloat), // ibytes 0, // stride NULL, // pointer NULL, // pfn NULL, // pfnCompile }, }; gc->vertexArray = defaultVertexArrayState; } void APIENTRY glcltEdgeFlagPointer (GLsizei stride, const GLvoid *pointer) { __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } if (stride < 0) { GLSETERROR(GL_INVALID_VALUE); return; } if (stride) gc->vertexArray.edgeFlag.ibytes = stride; else gc->vertexArray.edgeFlag.ibytes = sizeof(GLboolean); gc->vertexArray.edgeFlag.stride = stride; gc->vertexArray.edgeFlag.pointer = pointer; } void APIENTRY glcltTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { GLuint vaMask; __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } switch (type) { case GL_SHORT: vaMask = VAMASK_TEXCOORD_TYPE_SHORT; break; case GL_INT: vaMask = VAMASK_TEXCOORD_TYPE_INT; break; case GL_FLOAT: vaMask = VAMASK_TEXCOORD_TYPE_FLOAT; break; case GL_DOUBLE: vaMask = VAMASK_TEXCOORD_TYPE_DOUBLE; break; default: GLSETERROR(GL_INVALID_ENUM); return; } switch (size) { case 1: vaMask |= VAMASK_TEXCOORD_SIZE_1; break; case 2: vaMask |= VAMASK_TEXCOORD_SIZE_2; break; case 3: vaMask |= VAMASK_TEXCOORD_SIZE_3; break; case 4: vaMask |= VAMASK_TEXCOORD_SIZE_4; break; default: GLSETERROR(GL_INVALID_VALUE); return; } if (stride < 0) { GLSETERROR(GL_INVALID_VALUE); return; } if (stride) gc->vertexArray.texCoord.ibytes = stride; else gc->vertexArray.texCoord.ibytes = size * __GLTYPESIZE(type); gc->vertexArray.texCoord.size = size; gc->vertexArray.texCoord.type = type; gc->vertexArray.texCoord.stride = stride; gc->vertexArray.texCoord.pointer = pointer; if ((gc->vertexArray.mask & VAMASK_TEXCOORD_TYPE_SIZE_MASK) != vaMask) { gc->vertexArray.mask &= ~VAMASK_TEXCOORD_TYPE_SIZE_MASK; gc->vertexArray.mask |= vaMask; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } } void APIENTRY glcltColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { GLuint vaMask; __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } switch (type) { case GL_BYTE: vaMask = VAMASK_COLOR_TYPE_BYTE; break; case GL_UNSIGNED_BYTE: vaMask = VAMASK_COLOR_TYPE_UBYTE; break; case GL_SHORT: vaMask = VAMASK_COLOR_TYPE_SHORT; break; case GL_UNSIGNED_SHORT: vaMask = VAMASK_COLOR_TYPE_USHORT; break; case GL_INT: vaMask = VAMASK_COLOR_TYPE_INT; break; case GL_UNSIGNED_INT: vaMask = VAMASK_COLOR_TYPE_UINT; break; case GL_FLOAT: vaMask = VAMASK_COLOR_TYPE_FLOAT; break; case GL_DOUBLE: vaMask = VAMASK_COLOR_TYPE_DOUBLE; break; default: GLSETERROR(GL_INVALID_ENUM); return; } switch (size) { case 3: vaMask |= VAMASK_COLOR_SIZE_3; break; case 4: vaMask |= VAMASK_COLOR_SIZE_4; break; default: GLSETERROR(GL_INVALID_VALUE); return; } if (stride < 0) { GLSETERROR(GL_INVALID_VALUE); return; } if (stride) gc->vertexArray.color.ibytes = stride; else gc->vertexArray.color.ibytes = size * __GLTYPESIZE(type); gc->vertexArray.color.size = size; gc->vertexArray.color.type = type; gc->vertexArray.color.stride = stride; gc->vertexArray.color.pointer = pointer; if ((gc->vertexArray.mask & VAMASK_COLOR_TYPE_SIZE_MASK) != vaMask) { gc->vertexArray.mask &= ~VAMASK_COLOR_TYPE_SIZE_MASK; gc->vertexArray.mask |= vaMask; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } } void APIENTRY glcltIndexPointer (GLenum type, GLsizei stride, const GLvoid *pointer) { GLuint vaMask; __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } switch (type) { case GL_UNSIGNED_BYTE: vaMask = VAMASK_INDEX_TYPE_UBYTE; break; case GL_SHORT: vaMask = VAMASK_INDEX_TYPE_SHORT; break; case GL_INT: vaMask = VAMASK_INDEX_TYPE_INT; break; case GL_FLOAT: vaMask = VAMASK_INDEX_TYPE_FLOAT; break; case GL_DOUBLE: vaMask = VAMASK_INDEX_TYPE_DOUBLE; break; default: GLSETERROR(GL_INVALID_ENUM); return; } if (stride < 0) { GLSETERROR(GL_INVALID_VALUE); return; } if (stride) gc->vertexArray.index.ibytes = stride; else gc->vertexArray.index.ibytes = __GLTYPESIZE(type); gc->vertexArray.index.type = type; gc->vertexArray.index.stride = stride; gc->vertexArray.index.pointer = pointer; // update index function pointer! if ((gc->vertexArray.mask & VAMASK_INDEX_TYPE_SIZE_MASK) != vaMask) { gc->vertexArray.mask &= ~VAMASK_INDEX_TYPE_SIZE_MASK; gc->vertexArray.mask |= vaMask; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } } void APIENTRY glcltNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer) { GLuint vaMask; __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } switch (type) { case GL_BYTE: vaMask = VAMASK_NORMAL_TYPE_BYTE; break; case GL_SHORT: vaMask = VAMASK_NORMAL_TYPE_SHORT; break; case GL_INT: vaMask = VAMASK_NORMAL_TYPE_INT; break; case GL_FLOAT: vaMask = VAMASK_NORMAL_TYPE_FLOAT; break; case GL_DOUBLE: vaMask = VAMASK_NORMAL_TYPE_DOUBLE; break; default: GLSETERROR(GL_INVALID_ENUM); return; } if (stride < 0) { GLSETERROR(GL_INVALID_VALUE); return; } if (stride) gc->vertexArray.normal.ibytes = stride; else gc->vertexArray.normal.ibytes = 3 * __GLTYPESIZE(type); gc->vertexArray.normal.type = type; gc->vertexArray.normal.stride = stride; gc->vertexArray.normal.pointer = pointer; if ((gc->vertexArray.mask & VAMASK_NORMAL_TYPE_SIZE_MASK) != vaMask) { gc->vertexArray.mask &= ~VAMASK_NORMAL_TYPE_SIZE_MASK; gc->vertexArray.mask |= vaMask; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } } void APIENTRY glcltVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { GLuint vaMask; __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } switch (type) { case GL_SHORT: vaMask = VAMASK_VERTEX_TYPE_SHORT; break; case GL_INT: vaMask = VAMASK_VERTEX_TYPE_INT; break; case GL_FLOAT: vaMask = VAMASK_VERTEX_TYPE_FLOAT; break; case GL_DOUBLE: vaMask = VAMASK_VERTEX_TYPE_DOUBLE; break; default: GLSETERROR(GL_INVALID_ENUM); return; } switch (size) { case 2: vaMask |= VAMASK_VERTEX_SIZE_2; break; case 3: vaMask |= VAMASK_VERTEX_SIZE_3; break; case 4: vaMask |= VAMASK_VERTEX_SIZE_4; break; default: GLSETERROR(GL_INVALID_VALUE); return; } if (stride < 0) { GLSETERROR(GL_INVALID_VALUE); return; } if (stride) gc->vertexArray.vertex.ibytes = stride; else gc->vertexArray.vertex.ibytes = size * __GLTYPESIZE(type); gc->vertexArray.vertex.size = size; gc->vertexArray.vertex.type = type; gc->vertexArray.vertex.stride = stride; gc->vertexArray.vertex.pointer = pointer; if ((gc->vertexArray.mask & VAMASK_VERTEX_TYPE_SIZE_MASK) != vaMask) { gc->vertexArray.mask &= ~VAMASK_VERTEX_TYPE_SIZE_MASK; gc->vertexArray.mask |= vaMask; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } } void APIENTRY glcltEnableClientState (GLenum cap) { __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } // ARRAY_TYPE_ASSERT if (RANGE(cap,GL_VERTEX_ARRAY,GL_EDGE_FLAG_ARRAY)) { if (!(gc->vertexArray.mask & vaEnable[cap - GL_VERTEX_ARRAY])) { gc->vertexArray.mask |= vaEnable[cap - GL_VERTEX_ARRAY]; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } } } void APIENTRY glcltDisableClientState (GLenum cap) { __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } // ARRAY_TYPE_ASSERT if (RANGE(cap,GL_VERTEX_ARRAY,GL_EDGE_FLAG_ARRAY)) { if (gc->vertexArray.mask & vaEnable[cap - GL_VERTEX_ARRAY]) { gc->vertexArray.mask &= ~vaEnable[cap - GL_VERTEX_ARRAY]; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } } } void APIENTRY glcltGetPointerv (GLenum pname, GLvoid* *params) { __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } switch (pname) { case GL_VERTEX_ARRAY_POINTER: *params = (GLvoid *) gc->vertexArray.vertex.pointer; break; case GL_NORMAL_ARRAY_POINTER: *params = (GLvoid *) gc->vertexArray.normal.pointer; break; case GL_COLOR_ARRAY_POINTER: *params = (GLvoid *) gc->vertexArray.color.pointer; break; case GL_INDEX_ARRAY_POINTER: *params = (GLvoid *) gc->vertexArray.index.pointer; break; case GL_TEXTURE_COORD_ARRAY_POINTER: *params = (GLvoid *) gc->vertexArray.texCoord.pointer; break; case GL_EDGE_FLAG_ARRAY_POINTER: *params = (GLvoid *) gc->vertexArray.edgeFlag.pointer; break; case GL_SELECTION_BUFFER_POINTER: // The client pointer is maintained current at all times. *params = (GLvoid *) gc->select.resultBase; break; case GL_FEEDBACK_BUFFER_POINTER: // The client pointer is maintained current at all times. *params = (GLvoid *) gc->feedback.resultBase; break; default: GLSETERROR(GL_INVALID_ENUM); break; } } // We have special cases for the following formats. They also match the // special cases in display list. // // V2F // V3F // C3F_V3F // N3F_V3F // C3F_N3F_V3F (non 1.1 format) // C4F_N3F_V3F // T2F_V3F // T2F_C3F_V3F // T2F_N3F_V3F // T2F_C3F_N3F_V3F (non 1.1 format) // T2F_C4F_N3F_V3F // // There are no special cases for the following 1.1 formats: // // C4UB_V2F // C4UB_V3F // T4F_V4F // T2F_C4UB_V3F // T4F_C4F_N3F_V4F void FASTCALL VA_ValidateArrayPointers(__GLcontext *gc) { GLuint vaMask; GLuint formatMask; PFNVAELEMENT fp; PFNVAELEMENTBATCH fpB; PFNVAELEMENTBATCHINDIRECT fpBI; fp = VA_ArrayElement; fpB = VA_ArrayElementB; fpBI = VA_ArrayElementBI; vaMask = gc->vertexArray.mask; // The fast routines are for RGBA mode only. Edge flag and index array // pointers are disabled in these routines. Vertex array pointer is enabled. if (!gc->modes.colorIndexMode && !(vaMask & (VAMASK_EDGEFLAG_ENABLE_MASK | VAMASK_INDEX_ENABLE_MASK)) && (vaMask & VAMASK_VERTEX_ENABLE_MASK)) { formatMask = VAMASK_VERTEX_TYPE_SIZE_MASK | VAMASK_VERTEX_ENABLE_MASK; if (vaMask & VAMASK_TEXCOORD_ENABLE_MASK) formatMask |= VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_TEXCOORD_ENABLE_MASK; if (vaMask & VAMASK_COLOR_ENABLE_MASK) formatMask |= VAMASK_COLOR_TYPE_SIZE_MASK | VAMASK_COLOR_ENABLE_MASK; if (vaMask & VAMASK_NORMAL_ENABLE_MASK) formatMask |= VAMASK_NORMAL_TYPE_SIZE_MASK | VAMASK_NORMAL_ENABLE_MASK; switch (vaMask & formatMask) { case VAMASK_FORMAT_V2F: fp = VA_ArrayElement_V2F; fpB = VA_ArrayElement_V2F_B; fpBI = VA_ArrayElement_V2F_BI; break; case VAMASK_FORMAT_V3F: fp = VA_ArrayElement_V3F; fpB = VA_ArrayElement_V3F_B; fpBI = VA_ArrayElement_V3F_BI; break; case VAMASK_FORMAT_C3F_V3F: fp = VA_ArrayElement_C3F_V3F; fpB = VA_ArrayElement_C3F_V3F_B; fpBI = VA_ArrayElement_C3F_V3F_BI; break; case VAMASK_FORMAT_N3F_V3F: fp = VA_ArrayElement_N3F_V3F; fpB = VA_ArrayElement_N3F_V3F_B; fpBI = VA_ArrayElement_N3F_V3F_BI; break; case VAMASK_FORMAT_C3F_N3F_V3F: fp = VA_ArrayElement_C3F_N3F_V3F; fpB = VA_ArrayElement_C3F_N3F_V3F_B; fpBI = VA_ArrayElement_C3F_N3F_V3F_BI; break; case VAMASK_FORMAT_C4F_N3F_V3F: fp = VA_ArrayElement_C4F_N3F_V3F; fpB = VA_ArrayElement_C4F_N3F_V3F_B; fpBI = VA_ArrayElement_C4F_N3F_V3F_BI; break; case VAMASK_FORMAT_T2F_V3F: fp = VA_ArrayElement_T2F_V3F; fpB = VA_ArrayElement_T2F_V3F_B; fpBI = VA_ArrayElement_T2F_V3F_BI; break; case VAMASK_FORMAT_T2F_C3F_V3F: fp = VA_ArrayElement_T2F_C3F_V3F; fpB = VA_ArrayElement_T2F_C3F_V3F_B; fpBI = VA_ArrayElement_T2F_C3F_V3F_BI; break; case VAMASK_FORMAT_T2F_N3F_V3F: fp = VA_ArrayElement_T2F_N3F_V3F; fpB = VA_ArrayElement_T2F_N3F_V3F_B; fpBI = VA_ArrayElement_T2F_N3F_V3F_BI; break; case VAMASK_FORMAT_T2F_C3F_N3F_V3F: fp = VA_ArrayElement_T2F_C3F_N3F_V3F; fpB = VA_ArrayElement_T2F_C3F_N3F_V3F_B; fpBI = VA_ArrayElement_T2F_C3F_N3F_V3F_BI; break; case VAMASK_FORMAT_T2F_C4F_N3F_V3F: fp = VA_ArrayElement_T2F_C4F_N3F_V3F; fpB = VA_ArrayElement_T2F_C4F_N3F_V3F_B; fpBI = VA_ArrayElement_T2F_C4F_N3F_V3F_BI; break; } } // The default function pointers are used outside Begin. ASSERTOPENGL(gc->vertexArray.edgeFlag.pfn == (PFNGLVECTOR) glcltEdgeFlagv && gc->vertexArray.edgeFlag.pfnCompile == (PFNGLVECTOR) __gllc_EdgeFlagv, "edgeFlag.pfn and edgeFlag.pfnCompile not initialized\n"); gc->vertexArray.texCoord.pfn = afnTexCoord[(vaMask & VAMASK_TEXCOORD_TYPE_SIZE_MASK) >> VAMASK_TEXCOORD_TYPE_SHIFT]; gc->vertexArray.texCoord.pfnCompile = afnTexCoordCompile[(vaMask & VAMASK_TEXCOORD_TYPE_SIZE_MASK) >> VAMASK_TEXCOORD_TYPE_SHIFT]; if (gc->modes.colorIndexMode) { gc->vertexArray.color.pfn = afnColor_InCI[(vaMask & VAMASK_COLOR_TYPE_SIZE_MASK) >> VAMASK_COLOR_TYPE_SHIFT]; gc->vertexArray.index.pfn = afnIndex_InCI[(vaMask & VAMASK_INDEX_TYPE_SIZE_MASK) >> VAMASK_INDEX_TYPE_SHIFT]; } else { gc->vertexArray.color.pfn = afnColor_InRGBA[(vaMask & VAMASK_COLOR_TYPE_SIZE_MASK) >> VAMASK_COLOR_TYPE_SHIFT]; gc->vertexArray.index.pfn = afnIndex_InRGBA[(vaMask & VAMASK_INDEX_TYPE_SIZE_MASK) >> VAMASK_INDEX_TYPE_SHIFT]; } gc->vertexArray.color.pfnCompile = afnColorCompile[(vaMask & VAMASK_COLOR_TYPE_SIZE_MASK) >> VAMASK_COLOR_TYPE_SHIFT]; gc->vertexArray.index.pfnCompile = afnIndexCompile[(vaMask & VAMASK_INDEX_TYPE_SIZE_MASK) >> VAMASK_INDEX_TYPE_SHIFT]; gc->vertexArray.normal.pfn = afnNormal[(vaMask & VAMASK_NORMAL_TYPE_SIZE_MASK) >> VAMASK_NORMAL_TYPE_SHIFT]; gc->vertexArray.normal.pfnCompile = afnNormalCompile[(vaMask & VAMASK_NORMAL_TYPE_SIZE_MASK) >> VAMASK_NORMAL_TYPE_SHIFT]; gc->vertexArray.vertex.pfn = afnVertex[(vaMask & VAMASK_VERTEX_TYPE_SIZE_MASK) >> VAMASK_VERTEX_TYPE_SHIFT]; gc->vertexArray.vertex.pfnCompile = afnVertexCompile[(vaMask & VAMASK_VERTEX_TYPE_SIZE_MASK) >> VAMASK_VERTEX_TYPE_SHIFT]; gc->vertexArray.pfnArrayElement = fp; gc->vertexArray.pfnArrayElementBatch = fpB; gc->vertexArray.pfnArrayElementBatchIndirect = fpBI; gc->vertexArray.flags &= ~__GL_VERTEX_ARRAY_DIRTY; } void APIENTRY glcltArrayElement (GLint i) { __GL_SETUP(); if (gc->vertexArray.flags & __GL_VERTEX_ARRAY_DIRTY) VA_ValidateArrayPointers(gc); // The fast routines are called in Begin only. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) (*gc->vertexArray.pfnArrayElement)(gc, i); else VA_ArrayElement(gc, i); } // Define fast VA_ArrayElement functions. #define __VA_ARRAY_ELEMENT_V2F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_V2F #define __VA_ARRAY_ELEMENT_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_V3F #define __VA_ARRAY_ELEMENT_C3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_C3F_V3F #define __VA_ARRAY_ELEMENT_N3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_N3F_V3F #define __VA_ARRAY_ELEMENT_C3F_N3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_C3F_N3F_V3F #define __VA_ARRAY_ELEMENT_C4F_N3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_C4F_N3F_V3F #define __VA_ARRAY_ELEMENT_T2F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_T2F_V3F #define __VA_ARRAY_ELEMENT_T2F_C3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_T2F_C3F_V3F #define __VA_ARRAY_ELEMENT_T2F_N3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_T2F_N3F_V3F #define __VA_ARRAY_ELEMENT_T2F_C3F_N3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_T2F_C3F_N3F_V3F #define __VA_ARRAY_ELEMENT_T2F_C4F_N3F_V3F 1 #include "array.h" #undef __VA_ARRAY_ELEMENT_T2F_C4F_N3F_V3F #define CALLARRAYPOINTER(ap, i) \ ((*(ap).pfn)((ap).pointer + (i) * (ap).ibytes)) #define CALLARRAYPOINTERS \ if (vaMask & VAMASK_EDGEFLAG_ENABLE_MASK) \ CALLARRAYPOINTER(gc->vertexArray.edgeFlag, i); \ if (vaMask & VAMASK_TEXCOORD_ENABLE_MASK) \ CALLARRAYPOINTER(gc->vertexArray.texCoord, i); \ if (vaMask & VAMASK_COLOR_ENABLE_MASK) \ CALLARRAYPOINTER(gc->vertexArray.color, i); \ if (vaMask & VAMASK_INDEX_ENABLE_MASK) \ CALLARRAYPOINTER(gc->vertexArray.index, i); \ if (vaMask & VAMASK_NORMAL_ENABLE_MASK) \ CALLARRAYPOINTER(gc->vertexArray.normal, i); \ if (vaMask & VAMASK_VERTEX_ENABLE_MASK) \ CALLARRAYPOINTER(gc->vertexArray.vertex, i); void FASTCALL VA_ArrayElementB(__GLcontext *gc, GLint firstVertex, GLint nVertices) { GLint k, i; GLuint vaMask = gc->vertexArray.mask; for (k=0; k < nVertices; k++) { i = k+firstVertex; CALLARRAYPOINTERS; } } void FASTCALL VA_ArrayElementBI(__GLcontext *gc, GLint nVertices, VAMAP* indices) { GLint k, i; GLuint vaMask = gc->vertexArray.mask; for (k=0; k < nVertices; k++) { i = indices[k].iIn; CALLARRAYPOINTERS; } } void FASTCALL VA_ArrayElement(__GLcontext *gc, GLint i) { GLuint vaMask = gc->vertexArray.mask; CALLARRAYPOINTERS; } void APIENTRY glcltDrawArrays (GLenum mode, GLint first, GLsizei count) { int i; POLYARRAY *pa; PFNVAELEMENTBATCH pfn; __GL_SETUP(); pa = gc->paTeb; // Not allowed in begin/end. if (pa->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } if ((GLuint) mode > GL_POLYGON) { GLSETERROR(GL_INVALID_ENUM); return; } if (count < 0) { GLSETERROR(GL_INVALID_VALUE); return; } else if (!count) return; // Find array element function to use. if (gc->vertexArray.flags & __GL_VERTEX_ARRAY_DIRTY) VA_ValidateArrayPointers(gc); pfn = gc->vertexArray.pfnArrayElementBatch; // Check polyarray buffer size before calling Begin. // We will minimize breaking poly data records into batches where possible. // The number 8 is loosely chosen to allow for the poly array entry // and the flush limit. At worst, it causes an unnecessary attention! if (count <= (GLsizei) gc->vertex.pdBufSize - 8 && count >= (GLsizei) (pa->pdBufferMax - pa->pdBufferNext + 1 - 8)) glsbAttention(); // Draw the array elements. glcltBegin(mode); pa->flags |= POLYARRAY_SAME_POLYDATA_TYPE; (*pfn)(gc, first, count); glcltEnd(); } // Do not modify these constants. The code will likely break if they are // changed. #define VA_HASH_SIZE 256 #define VA_HASH(indexIn) ((GLubyte) indexIn) // If the size of the mapping array is greater than 256, we need to change // datatype and code below. #if (VA_DRAWELEM_MAP_SIZE > 256) #error "VA_DRAWELEM_MAP_SIZE is too large" #endif /******************************Public*Routine******************************\ * ReduceDrawElements * * Takes a set of DrawElements indices and reduces it into small chunks * of unique vertex indices * * History: * Sat Mar 02 14:25:26 1996 -by- Hock San Lee [hockl] * Wrote original version embedded in DrawElements * Sat Mar 02 14:25:26 1996 -by- Drew Bliss [drewb] * Split into function shared between immediate and dlist * \**************************************************************************/ void FASTCALL ReduceDrawElements(__GLcontext *gc, GLenum mode, GLsizei count, GLenum type, const GLvoid *pIn, pfnReducedElementsHandler pfnHandler) { GLushort _aHash[VA_HASH_SIZE + 2]; GLushort *pHash; VAMAP aMap[VA_DRAWELEM_MAP_SIZE]; GLushort iMap, iMapNext; GLushort iOutNext; GLubyte aOut[VA_DRAWELEM_INDEX_SIZE]; GLsizei iPartialIndices; GLsizei iCount, nLeft; GLuint iIn; // We will now sort the input index array using a hash table. The output // index array will be zero based. For example, if the input array is // [103, 101, 0, 2, 105, 103, 2, 4], the output index will be // [0, 1, 2, 3, 4, 0, 3, 5]. This allows us to store // vertices in a consecutive order. // Dword aligned hash array. pHash = (GLushort *) (((UINT_PTR) _aHash + 3) & ~3); // Initialize input index array pointer. iCount = 0; iPartialIndices = 0; DrawElements_NextBatch: // Reset output index array for this batch. // Initialize identity mapping for the first reserved vertex entries. // New vertices are accumulated after them. for (iOutNext = 0; iOutNext < (GLushort) iPartialIndices; iOutNext++) aOut[iOutNext] = (GLubyte) iOutNext; // Reset index mapping array that maps the In array to Out array. // The index map corresponds to the vertices in the vertex buffer. // Skip the reserved indices that are used for connectivity between // partial primitives. iMapNext = iOutNext; // Reset hash array to no mapping (-1). RtlFillMemoryUlong((PVOID) pHash, (ULONG) VA_HASH_SIZE * sizeof(*pHash), (ULONG) -1); // There are 3 possibilities in the following loop: // // 1. All input indices have been processed. The primitive is complete! // 2. The index map overflows. We have accumulated 256 vertices for a partial // primitive. // 3. The output index array overflows. We have exceeded our estimated size // of the output index array for a partial primitive. for ( ; iCount < count; iCount++) { // Get next input index. if (type == GL_UNSIGNED_BYTE) iIn = (GLuint) ((GLubyte *) pIn)[iCount]; else if (type == GL_UNSIGNED_SHORT) iIn = (GLuint) ((GLushort *) pIn)[iCount]; else iIn = (GLuint) ((GLuint *) pIn)[iCount]; #if DRAWELEM_DEBUG DbgPrint("iCount %d ", iCount); DbgPrint("iIn %d ", iIn); DbgPrint("iMapNext %d iOutNext %d", (GLuint) iMapNext, (GLuint) iOutNext); #endif // Look up previously mapped index if one exists. iMap = pHash[VA_HASH(iIn)]; while (iMap != (GLushort) -1 && aMap[iMap].iIn != iIn) iMap = aMap[iMap].next; #if DRAWELEM_DEBUG DbgPrint("iMapFound %d\n", (GLuint) iMap); #endif // If aMap or aOut overflows, flush the partial primitive. if (iOutNext >= VA_DRAWELEM_INDEX_SIZE || (iMap == (GLushort) -1 && iMapNext >= VA_DRAWELEM_MAP_SIZE)) { #if DRAWELEM_DEBUG DbgPrint("Flush iMapNext %d iOutNext %d\n", (GLuint) iMapNext, (GLuint) iOutNext); #endif // We have accumulated enough vertices for a partial primitive. We now // need to figure out the exact number of vertices to flush and redo // the leftover vertices in the next partial primitive. #if DBG if (iOutNext >= VA_DRAWELEM_INDEX_SIZE) DbgPrint("DrawElements: aOut buffer overflows\n"); #endif // Find the flush vertex of this partial primitive. nLeft = 0; switch (mode) { case GL_LINE_STRIP: case GL_TRIANGLE_FAN: break; case GL_POINTS: case GL_LINE_LOOP: case GL_POLYGON: ASSERTOPENGL(FALSE, "unexpected primitive type\n"); break; case GL_LINES: case GL_TRIANGLE_STRIP: case GL_QUAD_STRIP: // number of vertices must be a multiple of 2 if (iOutNext % 2) nLeft++; break; case GL_TRIANGLES: // number of vertices must be a multiple of 3 switch (iOutNext % 3) { case 2: nLeft++; // fall through case 1: nLeft++; } break; case GL_QUADS: // number of vertices must be a multiple of 4 switch (iOutNext % 4) { case 3: nLeft++; // fall through case 2: nLeft++; // fall through case 1: nLeft++; } break; } // Add the leftover vertices back to the input array and redo them // in the next partial primitive. iCount -= nLeft; iOutNext -= (GLushort) nLeft; // When passing on our data, skip any vertices // that were reserved from a previous partial primitive (*pfnHandler)(gc, mode, iMapNext-iPartialIndices, 0, aMap+iPartialIndices, iOutNext, aOut, GL_TRUE); iPartialIndices = nReservedIndicesPartialBegin[mode]; // Continue to process remaining vertices. goto DrawElements_NextBatch; } // If no previously mapped index is found, add the new vertex. if (iMap == (GLushort) -1) { ASSERTOPENGL(iMapNext < VA_DRAWELEM_MAP_SIZE, "index map overflows!\n"); #if DRAWELEM_DEBUG DbgPrint(" Add iIn %d iMap %d iHash %d\n", iIn, (GLuint) iMapNext, (GLuint) VA_HASH(iIn)); #endif iMap = iMapNext++; aMap[iMap].iIn = iIn; aMap[iMap].next = pHash[VA_HASH(iIn)]; pHash[VA_HASH(iIn)] = iMap; } // Add the mapped index to output index array. ASSERTOPENGL(iMap < VA_DRAWELEM_MAP_SIZE, "bad mapped index\n"); ASSERTOPENGL(iOutNext < VA_DRAWELEM_INDEX_SIZE, "aOut array overflows!\n"); #if DRAWELEM_DEBUG DbgPrint(" Add iOutNext %d iMap %d\n", (GLuint) iOutNext, (GLuint) iMap); #endif aOut[iOutNext++] = (GLubyte) iMap; } // We have processed all input vertices. // Pass on any remaining data (*pfnHandler)(gc, mode, iMapNext-iPartialIndices, 0, aMap+iPartialIndices, iOutNext, aOut, GL_FALSE); } void FASTCALL glcltReducedElementsHandler(__GLcontext *gc, GLenum mode, GLsizei iVertexCount, GLsizei iVertexBase, VAMAP *pvmVertices, GLsizei iElementCount, GLubyte *pbElements, GLboolean fPartial) { POLYARRAY *pa = gc->paTeb; PFNVAELEMENT pfn; GLsizei i; // Set up the vertex data pfn = gc->vertexArray.pfnArrayElement; if (pvmVertices != NULL) { PFNVAELEMENTBATCHINDIRECT pfn = gc->vertexArray.pfnArrayElementBatchIndirect; (*pfn)(gc, iVertexCount, pvmVertices); } else { // Access consecutive block of vertices, starting at iVertexBase PFNVAELEMENTBATCH pfn = gc->vertexArray.pfnArrayElementBatch; (*pfn)(gc, iVertexBase, iVertexCount); } // Copy the index array to the end of the polyarray primitive. pa->nIndices = (GLuint) iElementCount; // skip terminator vertex pa->aIndices = (GLubyte *) (pa->pdNextVertex + 1); ASSERTOPENGL(pa->aIndices + pa->nIndices <= (GLubyte *) (pa->pdBufferMax+1), "Vertex buffer overflows!\n"); memcpy(pa->aIndices, pbElements, pa->nIndices * sizeof(GLubyte)); if (fPartial) { // Flush the partial primitive. VA_DrawElementsFlushPartialPrimitive(pa, mode); } else { VA_DrawElementsEnd(pa); } } // This handles primitive modes that DrawElements or DrawRangeElements don't. void FASTCALL VA_DrawElementsHandleOtherPrimTypes( __GLcontext *gc, GLenum mode, GLsizei count, GLenum type, GLvoid *pIn ) { GLsizei iCount; PFNVAELEMENT pfn; POLYARRAY *pa; GLuint iIn; pa = gc->paTeb; pfn = gc->vertexArray.pfnArrayElement; glcltBegin(mode); pa->flags |= POLYARRAY_SAME_POLYDATA_TYPE; for (iCount = 0; iCount < count; iCount++) { // Get next input index. if (type == GL_UNSIGNED_BYTE) iIn = (GLuint) ((GLubyte *) pIn)[iCount]; else if (type == GL_UNSIGNED_SHORT) iIn = (GLuint) ((GLushort *) pIn)[iCount]; else iIn = (GLuint) ((GLuint *) pIn)[iCount]; (*pfn)(gc, iIn); } glcltEnd(); } void APIENTRY glcltDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *pIn) { POLYARRAY *pa; GLuint iIn; GLsizei iCount; __GL_SETUP(); pa = gc->paTeb; #define DRAWELEM_DEBUG 0 #if DRAWELEM_DEBUG { DbgPrint("mode %d, count %d, type %d\n", mode, count, type); DbgPrint("pIn: "); for (iCount = 0; iCount < count; iCount++) { if (type == GL_UNSIGNED_BYTE) iIn = (GLuint) ((GLubyte *) pIn)[iCount]; else if (type == GL_UNSIGNED_SHORT) iIn = (GLuint) ((GLushort *) pIn)[iCount]; else iIn = (GLuint) ((GLuint *) pIn)[iCount]; DbgPrint("%d ", iIn); } DbgPrint("\n"); } #endif // If we are already in the begin/end bracket, return an error. if (pa->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } if ((GLuint) mode > GL_POLYGON) { GLSETERROR(GL_INVALID_ENUM); return; } if (count < 0) { GLSETERROR(GL_INVALID_VALUE); return; } else if (!count) return; switch (type) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_SHORT: case GL_UNSIGNED_INT: break; default: GLSETERROR(GL_INVALID_ENUM); return; } // Find array element function to use. if (gc->vertexArray.flags & __GL_VERTEX_ARRAY_DIRTY) VA_ValidateArrayPointers(gc); // Send Points, Line Loop, and Polygon to Begin/End call. Points and Polygon // don't benefit from optimization in this function. Further, Polygon and // Line Loop are too tricky to deal with in this function. if (mode == GL_POINTS || mode == GL_LINE_LOOP || mode == GL_POLYGON) { VA_DrawElementsHandleOtherPrimTypes( gc, mode, count, type, (GLvoid *) pIn ); return; } // Begin primitive. VA_DrawElementsBegin(pa, mode, count); // The primitive will be ended on the last batch of // elements ReduceDrawElements(gc, mode, count, type, pIn, glcltReducedElementsHandler); } void RebaseIndices( GLvoid *pIn, GLubyte *aOut, GLsizei count, GLuint start, GLenum type ) { if (type == GL_UNSIGNED_BYTE) { while( count-- ) *aOut++ = (GLubyte) ( ((GLuint) *( ((GLubyte *) pIn) ++ )) - start); } else if (type == GL_UNSIGNED_SHORT) { while( count-- ) *aOut++ = (GLubyte) ( ((GLuint) *( ((GLushort *) pIn) ++ )) - start); } else { while( count-- ) *aOut++ = (GLubyte) ( ((GLuint) *( ((GLuint *) pIn) ++ )) - start); } } void APIENTRY glcltDrawRangeElementsWIN(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *pIn) { POLYARRAY *pa; GLuint iVertexCount; GLubyte aOut[VA_DRAWELEM_INDEX_SIZE]; __GL_SETUP(); pa = gc->paTeb; // If we are already in the begin/end bracket, return an error. if (pa->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } if ((GLuint) mode > GL_POLYGON) { GLSETERROR(GL_INVALID_ENUM); return; } iVertexCount = end-start+1; if( (count < 0) || (end < start) ) { GLSETERROR(GL_INVALID_VALUE); return; } else if (!count) { return; } switch (type) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_SHORT: case GL_UNSIGNED_INT: break; default: GLSETERROR(GL_INVALID_ENUM); return; } if (gc->vertexArray.flags & __GL_VERTEX_ARRAY_DIRTY) VA_ValidateArrayPointers(gc); // Send Points, Line Loop, and Polygon to Begin/End call. Points and Polygon // don't benefit from optimization in this function. Further, Polygon and // Line Loop are too tricky to deal with in this function. if (mode == GL_POINTS || mode == GL_LINE_LOOP || mode == GL_POLYGON) { VA_DrawElementsHandleOtherPrimTypes( gc, mode, count, type, (GLvoid *) pIn ); return; } // Begin primitive. VA_DrawElementsBegin(pa, mode, count); if ( (count > VA_DRAWRANGEELEM_MAX_INDICES) || (iVertexCount > VA_DRAWRANGEELEM_MAX_VERTICES) ) { // The primitive is too large to be processed directly so // we have to reduce it. The primitive will be ended on the // last batch of elements. ReduceDrawElements(gc, mode, count, type, pIn, glcltReducedElementsHandler); } else { // Need to rebase (0-base) the indices and convert them to ubyte for // the reduced element handler. RebaseIndices( (GLvoid *) pIn, aOut, count, start, type ); // Finish primitive glcltReducedElementsHandler(gc, mode, iVertexCount, start, // iVertexBase NULL, count, aOut, GL_FALSE); } } // Interleaved array AND mask. // INTERLEAVED_FORMAT_ASSERT GLuint iaAndMask[14] = { // GL_V2F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_COLOR_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_COLOR_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_C4UB_V2F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_C4UB_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_C3F_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_N3F_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_COLOR_TYPE_SIZE_MASK, // GL_C4F_N3F_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_TEXCOORD_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK, // GL_T2F_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_COLOR_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_T4F_V4F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_COLOR_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_T2F_C4UB_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_T2F_C3F_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_NORMAL_TYPE_SIZE_MASK, // GL_T2F_N3F_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK | VAMASK_COLOR_TYPE_SIZE_MASK, // GL_T2F_C4F_N3F_V3F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK, // GL_T4F_C4F_N3F_V4F VAMASK_EDGEFLAG_TYPE_SIZE_MASK | VAMASK_INDEX_TYPE_SIZE_MASK, }; // Interleaved array OR mask. // INTERLEAVED_FORMAT_ASSERT GLuint iaOrMask[14] = { VAMASK_FORMAT_V2F, // GL_V2F VAMASK_FORMAT_V3F, // GL_V3F VAMASK_FORMAT_C4UB_V2F, // GL_C4UB_V2F VAMASK_FORMAT_C4UB_V3F, // GL_C4UB_V3F VAMASK_FORMAT_C3F_V3F, // GL_C3F_V3F VAMASK_FORMAT_N3F_V3F, // GL_N3F_V3F VAMASK_FORMAT_C4F_N3F_V3F, // GL_C4F_N3F_V3F VAMASK_FORMAT_T2F_V3F, // GL_T2F_V3F VAMASK_FORMAT_T4F_V4F, // GL_T4F_V4F VAMASK_FORMAT_T2F_C4UB_V3F, // GL_T2F_C4UB_V3F VAMASK_FORMAT_T2F_C3F_V3F, // GL_T2F_C3F_V3F VAMASK_FORMAT_T2F_N3F_V3F, // GL_T2F_N3F_V3F VAMASK_FORMAT_T2F_C4F_N3F_V3F, // GL_T2F_C4F_N3F_V3F VAMASK_FORMAT_T4F_C4F_N3F_V4F, // GL_T4F_C4F_N3F_V4F }; // Interleaved array default strides. GLuint iaStride[14] = { 2 * sizeof(GLfloat), // GL_V2F 3 * sizeof(GLfloat), // GL_V3F 2 * sizeof(GLfloat) + 4 * sizeof(GLubyte), // GL_C4UB_V2F 3 * sizeof(GLfloat) + 4 * sizeof(GLubyte), // GL_C4UB_V3F 6 * sizeof(GLfloat), // GL_C3F_V3F 6 * sizeof(GLfloat), // GL_N3F_V3F 10 * sizeof(GLfloat), // GL_C4F_N3F_V3F 5 * sizeof(GLfloat), // GL_T2F_V3F 8 * sizeof(GLfloat), // GL_T4F_V4F 5 * sizeof(GLfloat) + 4 * sizeof(GLubyte), // GL_T2F_C4UB_V3F 8 * sizeof(GLfloat), // GL_T2F_C3F_V3F 8 * sizeof(GLfloat), // GL_T2F_N3F_V3F 12 * sizeof(GLfloat), // GL_T2F_C4F_N3F_V3F 15 * sizeof(GLfloat), // GL_T4F_C4F_N3F_V4F }; void APIENTRY glcltInterleavedArrays (GLenum format, GLsizei stride, const GLvoid *pointer) { GLuint iFormat, iStride; GLuint vaMask; const GLbyte *pb = pointer; __GL_SETUP(); // Not allowed in begin/end. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); return; } // INTERLEAVED_FORMAT_ASSERT iFormat = (GLuint) (format - GL_V2F); if (iFormat > GL_T4F_C4F_N3F_V4F) { GLSETERROR(GL_INVALID_ENUM); return; } if (stride < 0) { GLSETERROR(GL_INVALID_VALUE); return; } if (stride) iStride = stride; else iStride = iaStride[iFormat]; // Compute new mask. // If we are disabling an array, don't modify its type and size field! vaMask = gc->vertexArray.mask; vaMask &= iaAndMask[iFormat]; vaMask |= iaOrMask[iFormat]; if (gc->vertexArray.mask != vaMask) { gc->vertexArray.mask = vaMask; gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY; } if (vaMask & VAMASK_TEXCOORD_ENABLE_MASK) { gc->vertexArray.texCoord.type = GL_FLOAT; gc->vertexArray.texCoord.stride = iStride; gc->vertexArray.texCoord.ibytes = iStride; gc->vertexArray.texCoord.pointer = pb; if ((vaMask & VAMASK_TEXCOORD_TYPE_SIZE_MASK) == (VAMASK_TEXCOORD_SIZE_4 | VAMASK_TEXCOORD_TYPE_FLOAT)) { gc->vertexArray.texCoord.size = 4; pb += 4 * sizeof(GLfloat); } else { ASSERTOPENGL((vaMask & VAMASK_TEXCOORD_TYPE_SIZE_MASK) == (VAMASK_TEXCOORD_SIZE_2 | VAMASK_TEXCOORD_TYPE_FLOAT), "unhandled texcoord format\n"); gc->vertexArray.texCoord.size = 2; pb += 2 * sizeof(GLfloat); } } if (vaMask & VAMASK_COLOR_ENABLE_MASK) { gc->vertexArray.color.stride = iStride; gc->vertexArray.color.ibytes = iStride; gc->vertexArray.color.pointer = pb; switch (vaMask & VAMASK_COLOR_TYPE_SIZE_MASK) { case VAMASK_COLOR_TYPE_UBYTE | VAMASK_COLOR_SIZE_4: gc->vertexArray.color.type = GL_UNSIGNED_BYTE; gc->vertexArray.color.size = 4; pb += 4 * sizeof(GLubyte); break; case VAMASK_COLOR_TYPE_FLOAT | VAMASK_COLOR_SIZE_3: gc->vertexArray.color.type = GL_FLOAT; gc->vertexArray.color.size = 3; pb += 3 * sizeof(GLfloat); break; case VAMASK_COLOR_TYPE_FLOAT | VAMASK_COLOR_SIZE_4: gc->vertexArray.color.type = GL_FLOAT; gc->vertexArray.color.size = 4; pb += 4 * sizeof(GLfloat); break; default: ASSERTOPENGL(FALSE, "unhandled color format\n"); break; } } if (vaMask & VAMASK_NORMAL_ENABLE_MASK) { gc->vertexArray.normal.type = GL_FLOAT; gc->vertexArray.normal.stride = iStride; gc->vertexArray.normal.ibytes = iStride; gc->vertexArray.normal.pointer = pb; pb += 3 * sizeof(GLfloat); } gc->vertexArray.vertex.type = GL_FLOAT; gc->vertexArray.vertex.stride = iStride; gc->vertexArray.vertex.ibytes = iStride; gc->vertexArray.vertex.pointer = pb; switch (vaMask & VAMASK_VERTEX_TYPE_SIZE_MASK) { case VAMASK_VERTEX_TYPE_FLOAT | VAMASK_VERTEX_SIZE_4: gc->vertexArray.vertex.size = 4; break; case VAMASK_VERTEX_TYPE_FLOAT | VAMASK_VERTEX_SIZE_3: gc->vertexArray.vertex.size = 3; break; case VAMASK_VERTEX_TYPE_FLOAT | VAMASK_VERTEX_SIZE_2: gc->vertexArray.vertex.size = 2; break; default: ASSERTOPENGL(FALSE, "unhandled vertex format\n"); break; } }