/* * $Id: displaylist.c 200 2007-11-03 11:53:08Z hderuiter $ * * $Date: 2007-11-03 12:26:08 $ * $Revision: 000 $ * * (C) 2007 by Hans de Ruiter * All rights reserved * * This file is part of the MiniGL library project * See the file Licence.txt for more details * */ #include "displaylists.h" #include "displaylists_structs.h" #include #include #include #include #include #include "util.h" #include "mgl_profileitems.h" extern GLuint eval_GetMapK1(GLenum target); extern GLuint eval_GetMapK2(GLenum target); extern uint32 client_texture_state[]; // ----- PRIVATE FUNCTION PROTOTYPES ----- /** Initialises a list (the list will have a single NULL operation). * * @param list the list to initialize * * @return BOOL set to TRUE if successful */ BOOL dl_InitList(DisplayList *list); /** Allocates a new operation and links it in to the list. * * @param prevOp pointer to the previous operation in the list, or NULL if this is the start of a new list * @param extraBytes the number of extra bytes required for the operation's data. This memory will be allocated * and automatically be pointed to by the data field * * @return DLOperation* pointer to the new operation, or NULL if failed (i.e., out of memory) */ DLOperation* dl_NewOperation(DLOperation *prevOp, GLuint extraBytes); /** Frees an operation. */ void dl_FreeOperation(DLOperation *op); /** Clears a display list. */ void dl_ClearList(DisplayList *list); // Returns the buffer size required to store the image data in bytes. GLuint dl_imageSize(GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type); // Copies image data from an image into a packed buffer. This will follow the OpenGL's unpack settings void dl_copyImage( struct GLContextIFace *Self, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *srcImage, void *destImage ); // Call these macros before and after packed image uploading #define BEGIN_IMAGEUPLOAD \ GLint unpackAlignment, unpackRowLength, skipPixels, skipRows; \ Self->GLGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackAlignment); \ Self->GLGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackRowLength); \ Self->GLGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skipPixels); \ Self->GLGetIntegerv(GL_UNPACK_SKIP_ROWS, &skipRows); \ \ Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, 1); \ Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, 0); \ Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); \ Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, 0); #define END_IMAGEUPLOAD \ Self->GLPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment); \ Self->GLPixelStorei(GL_UNPACK_ROW_LENGTH, unpackRowLength); \ Self->GLPixelStorei(GL_UNPACK_SKIP_PIXELS, skipPixels); \ Self->GLPixelStorei(GL_UNPACK_SKIP_ROWS, skipRows); /** Returns the number of elements in the vertex array needed to perform a DrawElements() operation with the given indices. * This assumes that all elements up to the highest addressed element are going to be used (i.e., no compression in order * to get rid of non-used elements). * * @param count the number of indices in the indices array * @param type the type of the indices * @param indices pointer to the indices array itself * * @return GLsizei the number of elements that the vertex array must contain */ GLsizei dl_getVertexArrayCountFromIndices(GLsizei count, GLint type, const void *indices); /** Returns the size in bytes that the vertex arrays would take up if the arrays were packed, for the current client state. * * @param context pointer to the context containing the arrays * @param count the number of elements in the array * * @return int the size of the vertex array in bytes */ int dl_getVertexArraySize(GLcontext context, GLsizei count); /** Copies the vertex array data into the given buffer. This buffer should be the size returned by dl_getVertexArraySize() * * @param context pointer to the context whose vertex array data will be copied * @param vertexArray pointer to the target vertex array * @param vertexArrayBuffer pointer to the buffer where the packed vertex data will be stored * @param first the first element in the vertex array to copy * @param count the number of elements in the vertex array to copy */ void dl_copyVertexArray(GLcontext context, struct GLvertex_array_state *vertexArray, GLvoid *vertexArrayBuffer, GLint first, GLsizei count); // ----- PUBLIC FUNCTIONS ----- void cgl_GLCallList(struct GLContextIFace *Self, GLuint list) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(CallList(Self, list)); PROFILE_ENTRY(FID_CGL_GL_CALL_LIST); if (list == 0) { context->DisplayListNestingLevel = 0; return; } DisplayList *dList = &(context->DisplayListArray[list - 1]); for (DLOperation *currOp = dList->firstOp; currOp; currOp = currOp->nextOp) { currOp->opFunc(Self, currOp); } PROFILE_EXIT(FID_CGL_GL_CALL_LIST); } #define BIG_ENDIAN void cgl_GLCallLists(struct GLContextIFace *Self, GLsizei n, GLenum type, const GLvoid *lists) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(CallLists(Self, n, type, lists)); PROFILE_ENTRY(FID_CGL_GL_CALL_LISTS) if (!lists) { context->CurrentError = GL_INVALID_VALUE; return; } #ifdef BIG_ENDIAN if ((type == GL_2_BYTES) && ((uint32)lists & 1UL)==0) { type = GL_UNSIGNED_SHORT; } else if ((type == GL_4_BYTES) && ((uint32)lists & 3UL)==0) { type = GL_UNSIGNED_INT; } #endif switch (type) { case GL_BYTE: { const GLbyte *listArray = lists; for (int i = 0; i < n; i++) { cgl_GLCallList(Self, listArray[i] + context->DisplayListBaseOffset); } break; } case GL_UNSIGNED_BYTE: { const GLubyte *listArray = lists; for (int i = 0; i < n; i++) { cgl_GLCallList(Self, listArray[i] + context->DisplayListBaseOffset); } break; } case GL_SHORT: { const GLshort *listArray = lists; for (int i = 0; i < n; i++) { cgl_GLCallList(Self, listArray[i] + context->DisplayListBaseOffset); } break; } case GL_UNSIGNED_SHORT: { const GLushort *listArray = lists; for (int i = 0; i < n; i++) { cgl_GLCallList(Self, listArray[i] + context->DisplayListBaseOffset); } break; } case GL_INT: { const GLint *listArray = lists; for (int i = 0; i < n; i++) { cgl_GLCallList(Self, listArray[i] + context->DisplayListBaseOffset); } break; } case GL_UNSIGNED_INT: { const GLuint *listArray = lists; for (int i = 0; i < n; i++) { cgl_GLCallList(Self, listArray[i] + context->DisplayListBaseOffset); } break; } case GL_FLOAT: { const GLfloat *listArray = lists; for (int i = 0; i < n; i++) { cgl_GLCallList(Self, listArray[i] + context->DisplayListBaseOffset); } break; } case GL_2_BYTES: { const GLubyte *listArray = lists; for (int i = 0; i < n; i++) { GLuint val = ( ((uint32)listArray[i<<1] << 8) | listArray[(i<<1) + 1] ) + context->DisplayListBaseOffset; cgl_GLCallList(Self, val); } break; } case GL_3_BYTES: { const GLubyte *listArray = lists; for (int i = 0; i < n; i++) { GLuint val = ( ((uint32)listArray[3*i] << 16) | ((uint32)listArray[3*i + 1] << 8) | listArray[3*i + 2] ) + context->DisplayListBaseOffset; cgl_GLCallList(Self, val); } break; } case GL_4_BYTES: { const GLubyte *listArray = lists; for (int i = 0; i < n; i++) { GLuint val = ( ((uint32)listArray[i<<2] << 24) + ((uint32)listArray[(i<<2) + 1] <<16) + ((uint32)listArray[(i<<2) + 2] <<8) + listArray[(i<<2) + 3] ) + context->DisplayListBaseOffset; cgl_GLCallList(Self, val); } break; } default: context->CurrentError = GL_INVALID_ENUM; break; } PROFILE_EXIT(FID_CGL_GL_CALL_LISTS); } void cgl_GLDeleteLists(struct GLContextIFace *Self, GLuint list, GLsizei range) { GLcontext context = GET_INSTANCE(Self); if (range < 0) { context->CurrentError = GL_INVALID_VALUE; } if (list - 1 + range > context->DisplayListArraySize) { range = context->DisplayListArraySize - (list - 1); } int i; for (i = list - 1; i < range + list - 1; i++) { dl_ClearList(&(context->DisplayListArray[i])); context->DisplayListArray[i].firstOp = NULL; } } void cgl_GLEndList(struct GLContextIFace *Self) { GLcontext context = GET_INSTANCE(Self); // Make sure that we're not between glBegin()/glEnd() calls if (context->CurrentPrimitive != GL_BASE) { context->CurrentError = GL_INVALID_OPERATION; return; } if (context->DisplayListCompileError) { context->CurrentError = context->DisplayListCompileError; return; } #ifdef MGL_DISPLAYLIST_COMPILEW3DARRAYS // Compile list into W3DVertexArray objects // ##### FIXME! ##### #endif GLuint listIdx = context->TargetDisplayListIdx; if (context->TargetDisplayListStart != context->DisplayListArray[listIdx].firstOp) { // need to delete the old list dl_ClearList(&(context->DisplayListArray[listIdx])); } context->DisplayListArray[listIdx].firstOp = context->TargetDisplayListStart; context->TargetDisplayListStart = NULL; context->TargetDisplayListEnd = NULL; // Delete the dummy op at the start of the list if ( context->DisplayListArray[listIdx].firstOp && !context->DisplayListArray[listIdx].firstOp->opFunc ) { DLOperation *actualFirstOp = context->DisplayListArray[listIdx].firstOp->nextOp; dl_FreeOperation(context->DisplayListArray[listIdx].firstOp); context->DisplayListArray[listIdx].firstOp = actualFirstOp; } } GLuint cgl_GLGenLists(struct GLContextIFace *Self, GLsizei range) { GLcontext context = GET_INSTANCE(Self); if (range < 0) { context->CurrentError = GL_INVALID_VALUE; } if (range == 0) { return 0; } // Make sure that we're not between glBegin()/glEnd() calls if (context->CurrentPrimitive != GL_BASE) { context->CurrentError = GL_INVALID_OPERATION; return 0; } // Find a free spot in the display-list array and allocate the new lists int i, j; BOOL foundGap = FALSE; for (i = 0; i < context->DisplayListArraySize - range; i++) { if (context->DisplayListArray[i].firstOp == NULL) { foundGap = TRUE; // note, we're testing this assertion for (j = i; j < i + range; j++) { if (context->DisplayListArray[i].firstOp) { foundGap = GL_FALSE; break; } } if (foundGap) { for (j = i; j < i + range; j++) { if (dl_InitList(&(context->DisplayListArray[j])) == FALSE) { return 0; } } return i + 1; } else{ i += j; } } } return 0; } GLboolean cgl_GLIsList(struct GLContextIFace *Self, GLuint list) { GLcontext context = GET_INSTANCE(Self); // Make sure that we're not between glBegin()/glEnd() calls if (context->CurrentPrimitive != GL_BASE) { context->CurrentError = GL_INVALID_OPERATION; return GL_FALSE; } if (list > 0 && list <= context->DisplayListArraySize) { if (context->DisplayListArray[list - 1].firstOp) { return GL_TRUE; } } return GL_FALSE; } void cgl_GLListBase(struct GLContextIFace *Self, GLuint base) { GLcontext context = GET_INSTANCE(Self); // Make sure that we're not between glBegin()/glEnd() calls if (context->CurrentPrimitive != GL_BASE) { context->CurrentError = GL_INVALID_OPERATION; return; } context->DisplayListBaseOffset = base; } void cgl_GLNewList(struct GLContextIFace *Self, GLuint list, GLenum mode) { GLcontext context = GET_INSTANCE(Self); if (list == 0 || list >= context->DisplayListArraySize) { context->CurrentError = GL_INVALID_VALUE; return; } if (mode != GL_COMPILE && mode != GL_COMPILE_AND_EXECUTE) { context->CurrentError = GL_INVALID_ENUM; return; } // Make sure that we're not between glBegin()/glEnd() calls if (context->CurrentPrimitive != GL_BASE) { context->CurrentError = GL_INVALID_OPERATION; return; } // Some naughty OpenGL apps don't call glGenLists() and hard-code list numbers. // We'll generate new lists on the fly in this case if (context->DisplayListArray[list-1].firstOp == NULL) { if (dl_InitList(&(context->DisplayListArray[list-1])) == FALSE) { // OpenGL apps shouldn't be doing this anyway context->CurrentError = GL_INVALID_VALUE; return; } } if (context->DisplayListArray[list-1].firstOp->opFunc == NULL) { context->TargetDisplayListStart = context->DisplayListArray[list-1].firstOp; } else { // Have to construct a new list without destroying the old one context->TargetDisplayListStart = dl_NewOperation(NULL, 0); if (!context->TargetDisplayListStart) { context->CurrentError = GL_OUT_OF_MEMORY; return; } context->TargetDisplayListStart->opFunc = NULL; } context->TargetDisplayListEnd = context->TargetDisplayListStart; context->TargetDisplayListIdx = list - 1; context->DisplayListCompileMode = mode; context->DisplayListCompileError = 0; } // ----- PRIVATE FUNCTIONS ----- BOOL dl_InitList(DisplayList *list) { if ( list->firstOp != NULL) { return FALSE; } list->firstOp = dl_NewOperation(NULL, 0); if (!list->firstOp) { return FALSE; } list->firstOp->opFunc = NULL; return TRUE; } DLOperation* dl_NewOperation(DLOperation *prevOp, GLuint extraBytes) { DLOperation *newOp = (DLOperation*)AllocVecInternal(sizeof(DLOperation) + extraBytes, 0); if (newOp) { newOp->opFunc = NULL; newOp->nextOp = NULL; if (extraBytes) { newOp->opData.data = (void*)(newOp + 1); } } if (prevOp) { prevOp->nextOp = newOp; } return newOp; } void dl_FreeOperation(DLOperation *op) { FreeVecInternal(op); } void dl_ClearList(DisplayList *list) { if (!list) { return; } DLOperation *currOp = list->firstOp; while (currOp) { DLOperation *nextOp = currOp->nextOp; dl_FreeOperation(currOp); currOp = nextOp; } list->firstOp = NULL; } GLuint dl_imageSize(GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type) { GLuint elementSize, typeSize; switch(format) { case GL_COLOR_INDEX: case GL_RED: case GL_GREEN: case GL_BLUE: case GL_ALPHA: case GL_LUMINANCE: elementSize = 1; break; case GL_RGB: case GL_BGR: elementSize = 3; break; case GL_RGBA: case GL_BGRA: elementSize = 4; break; case GL_LUMINANCE_ALPHA: elementSize = 2; default: return 0; } switch(type) { case GL_BITMAP: return (width + 7) / 8 * height; break; case GL_UNSIGNED_BYTE: case GL_BYTE: case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: typeSize = sizeof(GLbyte); break; case GL_UNSIGNED_SHORT: case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: case GL_SHORT: typeSize = sizeof(GLshort); break; case GL_UNSIGNED_INT: case GL_INT: case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: case GL_UNSIGNED_INT_10_10_10_2: // case GL_UNSIGNED_INT_2_10_10_10_RE: typeSize = sizeof(GLint); break; case GL_FLOAT: typeSize = sizeof(GLfloat); break; default: return 0; } return width * height * elementSize * typeSize; } void dl_copyImage( struct GLContextIFace *Self, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *srcImage, void *destImage) { #ifdef MGL_PROFILING GLcontext context = GET_INSTANCE(Self); #endif PROFILE_ENTRY(FID_DL_COPY_IMAGE); GLint unpackRowLength, skipPixels, skipRows; Self->GLGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackRowLength); Self->GLGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skipPixels); Self->GLGetIntegerv(GL_UNPACK_SKIP_ROWS, &skipRows); GLuint elementSize, typeSize; switch(format) { case GL_COLOR_INDEX: case GL_RED: case GL_GREEN: case GL_BLUE: case GL_ALPHA: case GL_LUMINANCE: elementSize = 1; break; case GL_RGB: case GL_BGR: elementSize = 3; break; case GL_RGBA: case GL_BGRA: elementSize = 4; break; case GL_LUMINANCE_ALPHA: elementSize = 2; // ??? default: return; } switch (type) { case GL_BITMAP: // This special case is dealt with below break; case GL_UNSIGNED_BYTE: case GL_BYTE: case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: typeSize = sizeof(GLbyte); break; case GL_UNSIGNED_SHORT: case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: case GL_SHORT: typeSize = sizeof(GLshort); break; case GL_UNSIGNED_INT: case GL_INT: case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: case GL_UNSIGNED_INT_10_10_10_2: //case GL_UNSIGNED_INT_2_10_10_10_RE: typeSize = sizeof(GLint); break; case GL_FLOAT: typeSize = sizeof(GLfloat); break; default: return; } GLuint bytesPerRow, rowOffset; if (type == GL_BITMAP) { bytesPerRow = (width + 7) / 8; rowOffset = (skipPixels + 7) / 8; // ##### FIXME! ##### maybe the pixels need to be shifted? } else { GLuint bytesPerPixel = elementSize *typeSize; bytesPerRow = width * bytesPerPixel; rowOffset = skipPixels * bytesPerPixel; } GLubyte *destPixel = (GLubyte*) destImage; GLubyte *srcRowStart = (GLubyte*) srcImage + skipRows * bytesPerRow + rowOffset; for (GLsizei y = 0; y < height; y++) { for (GLsizei x = 0; x < bytesPerRow; x++) { *destPixel = srcRowStart[x]; destPixel++; } srcRowStart += bytesPerRow; } PROFILE_EXIT(FID_DL_COPY_IMAGE); } #ifndef max #define max(a, b) (((a) > (b)) ? (a) : (b)) #endif GLsizei dl_getVertexArrayCountFromIndices(GLsizei count, GLint type, const void *indices) { GLsizei vertexArrayCount = 0; switch(type) { case GL_UNSIGNED_BYTE: { GLubyte *srcIndices = (GLubyte*) indices; for (GLsizei i = 0; i < count; i++) { vertexArrayCount = max(vertexArrayCount, srcIndices[i]); } break; } case GL_UNSIGNED_SHORT: { GLushort *srcIndices = (GLushort*) indices; for (GLsizei i = 0; i < count; i++) { vertexArrayCount = max(vertexArrayCount, srcIndices[i]); } break; } case GL_UNSIGNED_INT: { GLuint *srcIndices = (GLuint*) indices; for (GLsizei i = 0; i < count; i++) { vertexArrayCount = max(vertexArrayCount, srcIndices[i]); } break; } default: return 0; } return vertexArrayCount + 1; // indices start at 0 not 1 } int typeSize(GLenum type) { switch (type) { case GL_BYTE: return sizeof(GLbyte); case GL_UNSIGNED_BYTE: return sizeof(GLubyte); case GL_SHORT: return sizeof(GLshort); case GL_UNSIGNED_SHORT: return sizeof(GLushort); case GL_INT: return sizeof(GLint); case GL_UNSIGNED_INT: return sizeof(GLuint); case GL_FLOAT: return sizeof(GLdouble); case GL_DOUBLE: return sizeof(GLdouble); default: return 0; } } int dl_getVertexArraySize(GLcontext context, GLsizei count) { int i; int vertexArrayElementSize = 0; // Calculate how much space is needed for a single row in the array if (context->vertex_array.ClientState & GLCS_COLOR) { int elementSize = typeSize(context->vertex_array.ColorArray.type) * context->vertex_array.ColorArray.size; if (elementSize == 0) { return 0; } vertexArrayElementSize += elementSize; } if (context->vertex_array.ClientState & GLCS_NORMAL) { int elementSize = typeSize(context->vertex_array.NormalArray.type) * context->vertex_array.NormalArray.size; if (elementSize == 0) { return 0; } vertexArrayElementSize += elementSize; } for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->vertex_array.ClientState & client_texture_state[i] && (context->enable.Texture2D[i] || context->enable.Texture1D[i])) { int elementSize = typeSize(context->vertex_array.TexCoordArray[i].type) * context->vertex_array.TexCoordArray[i].size; if (elementSize == 0) { return 0; } vertexArrayElementSize += elementSize; } } if (context->vertex_array.ClientState & GLCS_VERTEX) { int elementSize = typeSize(context->vertex_array.VertexArray.type) * context->vertex_array.VertexArray.size; if (elementSize == 0) { return 0; } vertexArrayElementSize += elementSize; } return vertexArrayElementSize * count; } void dl_copyVertexArray(GLcontext context, struct GLvertex_array_state *vertexArray, GLvoid *vertexArrayBuffer, GLint first, GLsizei count) { PROFILE_ENTRY(FID_DL_COPY_VERTEX_ARRAY); int i, j; // Copy basic vertex state data *vertexArray = context->vertex_array; // Calculate the storage requirements and set up the copy operation int vertexArrayElementSize = 0; int colourElementSize, texCoordElementSize[MAX_TEXTURE_UNITS], normalElementSize, vertexElementSize; GLsizei colourStride, texCoordStride[MAX_TEXTURE_UNITS], normalStride, vertexStride; GLubyte *colourElementPtr, *texCoordElementPtr[MAX_TEXTURE_UNITS], *normalElementPtr, *vertexElementPtr; if (context->vertex_array.ClientState & GLCS_COLOR) { colourElementSize = typeSize(context->vertex_array.ColorArray.type) * context->vertex_array.ColorArray.size; if (colourElementSize != 0) { vertexArrayElementSize += colourElementSize; colourStride = context->vertex_array.ColorArray.stride; colourElementPtr = (GLubyte*)context->vertex_array.ColorArray.pointer + colourStride * first; } else { colourStride = 0; // to suppress a compiler warning colourElementPtr = NULL; } } else { colourElementSize = 0; // to suppress a compiler warning colourStride = 0; // to suppress a compiler warning colourElementPtr = NULL; } if (context->vertex_array.ClientState & GLCS_NORMAL) { normalElementSize = typeSize(context->vertex_array.NormalArray.type) * context->vertex_array.NormalArray.size; if (normalElementSize != 0) { vertexArrayElementSize += normalElementSize; normalStride = context->vertex_array.NormalArray.stride; normalElementPtr = (GLubyte*)context->vertex_array.NormalArray.pointer + normalStride * first; } else { normalStride = 0; // to suppress a compiler warning normalElementPtr = NULL; } } else { normalElementSize = 0; // to suppress a compiler warning normalStride = 0; // to suppress a compiler warning normalElementPtr = NULL; } for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if ( context->vertex_array.ClientState & client_texture_state[i] && (context->enable.Texture2D[i] || context->enable.Texture1D[i]) ) { texCoordElementSize[i] = typeSize(context->vertex_array.TexCoordArray[i].type) * context->vertex_array.TexCoordArray[i].size; if (texCoordElementSize[i] != 0) { vertexArrayElementSize += texCoordElementSize[i]; texCoordStride[i] = context->vertex_array.TexCoordArray[i].stride; texCoordElementPtr[i] = (GLubyte*)context->vertex_array.TexCoordArray[i].pointer + texCoordStride[i] * first; } else { texCoordStride[i] = 0; // to suppress a compiler warning texCoordElementPtr[i] = NULL; } } else { texCoordElementSize[i] = 0; // to suppress a compiler warning texCoordStride[i] = 0; // to suppress a compiler warning texCoordElementPtr[i] = NULL; } } if (context->vertex_array.ClientState & GLCS_VERTEX) { vertexElementSize = typeSize(context->vertex_array.VertexArray.type) * context->vertex_array.VertexArray.size; if (vertexElementSize != 0) { vertexArrayElementSize += vertexElementSize; vertexStride = context->vertex_array.VertexArray.stride; vertexElementPtr = (GLubyte*)context->vertex_array.VertexArray.pointer + vertexStride * first; } else { vertexStride = 0; // to suppress a compiler warning vertexElementPtr = NULL; } } else { vertexElementSize = 0; // to suppress a compiler warning vertexStride = 0; // to suppress a compiler warning vertexElementPtr = NULL; } // Now copy the vertex data GLubyte *outArrayLinePtr = vertexArrayBuffer; for (i = 0; i < count; ++i) { GLubyte *currOutPtr = outArrayLinePtr; if (colourElementPtr) { memcpy(currOutPtr, colourElementPtr, colourElementSize); currOutPtr += colourElementSize; colourElementPtr += colourStride; } for (j = 0; j <= context->texture.MaxTextureUnit; j++) { if (texCoordElementPtr[j]) { memcpy(currOutPtr, texCoordElementPtr[j], texCoordElementSize[j]); currOutPtr += texCoordElementSize[j]; texCoordElementPtr[j] += texCoordStride[j]; } } if (normalElementPtr) { memcpy(currOutPtr, normalElementPtr, normalElementSize); currOutPtr += normalElementSize; normalElementPtr += normalStride; } if (vertexElementPtr) { memcpy(currOutPtr, vertexElementPtr, vertexElementSize); currOutPtr += vertexElementSize; vertexElementPtr += vertexStride; } outArrayLinePtr += vertexArrayElementSize; } // Update the vertex data pointers and stride GLubyte *dataPtr = vertexArrayBuffer; if (colourElementPtr) { vertexArray->ColorArray.pointer = (void*)dataPtr; vertexArray->ColorArray.stride = vertexArrayElementSize; dataPtr += colourElementSize; } for (j = 0; j <= context->texture.MaxTextureUnit; j++) { if (texCoordElementPtr[j]) { vertexArray->TexCoordArray[j].pointer = (void*)dataPtr; vertexArray->TexCoordArray[j].stride = vertexArrayElementSize; dataPtr += texCoordElementSize[j]; } } if (normalElementPtr) { vertexArray->NormalArray.pointer = (void*)dataPtr; vertexArray->NormalArray.stride = vertexArrayElementSize; dataPtr += normalElementSize; } if (vertexElementPtr) { vertexArray->VertexArray.pointer = (void*)dataPtr; vertexArray->VertexArray.stride = vertexArrayElementSize; dataPtr += vertexElementSize; } PROFILE_EXIT(FID_DL_COPY_VERTEX_ARRAY); }