/* * $Id$ * * $Date$ * $Revision$ * * (C) 1999 by Hyperion * All rights reserved * * This file is part of the MiniGL library project * See the file Licence.txt for more details * */ #include "displaylists.h" #include "selection.h" #include "smartlock.h" #include "sysinc.h" #include #include #include #include "hclip.h" extern void d_DrawPoints(struct GLcontext_t); extern void d_DrawLines(struct GLcontext_t); extern void d_DrawLineStrip(struct GLcontext_t); extern void d_DrawTriangles(struct GLcontext_t); extern void d_DrawTriangleFan(struct GLcontext_t); extern void d_DrawTriangleStrip(struct GLcontext_t); extern void d_DrawQuads(struct GLcontext_t); extern void d_DrawPolygon(struct GLcontext_t); extern void d_DrawFlatFan(struct GLcontext_t); extern void d_DrawQuadStrip(struct GLcontext_t); extern void fog_Set(GLcontext); extern float CLAMPF(float); extern GLboolean MGLEnsureVertexBufferSize(GLcontext, GLuint); extern void tex_EstablishEnvCombine(GLcontext); extern void light_UpdateColorMaterial(GLcontext); extern void light_UpdateColorMaterialVertex(GLcontext); extern void GLDrawElementsTriangles(GLcontext, GLsizei, GLenum, const GLvoid *); extern void v_GenTexCoords(GLcontext, int); extern void v_ToEye(GLcontext, int); extern void v_ToScreen(GLcontext, int); extern void m_CombineMatrices(GLcontext); GLfloat v_PolygonOffset(GLcontext context, int v1, int v2, int v3); extern void v_GenEyeCoords(GLcontext); extern void checkNeedEye(GLcontext context); #define min(x,y) (x) < (y) ? (x) : (y) #define max(x,y) (x) > (y) ? (x) : (y) static char rcsid[] UNUSED = "$Id$"; uint32 client_texture_state[] = { GLCS_TEXTURE0, GLCS_TEXTURE1, GLCS_TEXTURE2, GLCS_TEXTURE3 }; /* Table for interleaved array */ struct ILAInfo { GLboolean enable_color; GLboolean enable_normal; GLboolean enable_texture; GLuint vertex_size; GLuint vertex_offset; GLuint color_size; GLuint color_offset; GLuint texture_size; GLuint texture_offset; GLuint normal_offset; GLuint stride; GLenum color_format; }; struct ILAInfo ILATab[] = { /* color normal texture vert col tex n, s cf */ /* V2F */ {GL_FALSE, GL_FALSE, GL_FALSE, 2, 0, 0, 0, 0, 0, 0, 8, 0}, /* V3F */ {GL_FALSE, GL_FALSE, GL_FALSE, 3, 0, 0, 0, 0, 0, 0, 12, 0}, /* C4UB_V2F */ {GL_TRUE, GL_FALSE, GL_FALSE, 2, 4, 4, 0, 0, 0, 0, 12, GL_UNSIGNED_BYTE}, /* C4UB_V3F */ {GL_TRUE, GL_FALSE, GL_FALSE, 3, 4, 4, 0, 0, 0, 0, 16, GL_UNSIGNED_BYTE}, /* C3F_V3F */ {GL_TRUE, GL_FALSE, GL_FALSE, 3, 12, 3, 0, 0, 0, 0, 24, GL_FLOAT}, /* N3F_V3F */ {GL_FALSE, GL_TRUE, GL_FALSE, 3, 12, 0, 0, 0, 0, 0, 24, 0}, /* C4F_N3F_V3F */ {GL_TRUE, GL_TRUE, GL_FALSE, 3, 24, 4, 0, 0, 0, 16, 40, GL_FLOAT}, /* T2F_V3F */ {GL_FALSE, GL_FALSE, GL_TRUE, 3, 8, 0, 0, 2, 0, 0, 20, 0}, /* T4F_V4F */ {GL_FALSE, GL_FALSE, GL_TRUE, 4, 16, 0, 0, 4, 0, 0, 32, 0}, /* T2F_C4UB_V3F */ {GL_TRUE, GL_FALSE, GL_TRUE, 3, 12, 4, 8, 2, 0, 0, 24, GL_UNSIGNED_BYTE}, /* T2F_C3F_V3F */ {GL_TRUE, GL_FALSE, GL_TRUE, 3, 20, 3, 20, 2, 0, 0, 32, GL_FLOAT}, /* T2F_N3F_V3F */ {GL_FALSE, GL_TRUE, GL_TRUE, 3, 20, 0, 0, 2, 0, 8, 32, 0}, /* T2F_C4F_N3F_V3F */ {GL_TRUE, GL_TRUE, GL_TRUE, 3, 36, 4, 8, 2, 0, 24, 48, GL_FLOAT}, /* T4F_C4F_N3F_V4F */ {GL_TRUE, GL_TRUE, GL_TRUE, 4, 44, 4, 16, 4, 0, 32, 60, GL_FLOAT} }; /* These constants are used to build an index into an array of function pointers * that will be used to fetch certain combinations of size and amount of data. * So, a color fetch that would take 3 ubyte color component would be at index * FLAG_UBYTE|FLAG_3 */ #define FLAG_BYTE 0x00 #define FLAG_UBYTE 0x01 #define FLAG_SHORT 0x02 #define FLAG_USHORT 0x03 #define FLAG_INT 0x04 #define FLAG_UINT 0x05 #define FLAG_FLOAT 0x06 #define FLAG_DOUBLE 0x07 #define FLAG_1 0x10 #define FLAG_2 0x20 #define FLAG_3 0x30 #define FLAG_4 0x40 #define TABLE_SIZE 0x48 /* Arrays for color */ ArrayFetcherFn color_fetch[TABLE_SIZE]; ArrayFetcherIdxFn color_fetchIdx[TABLE_SIZE]; ArrayFetcherIdxFn color_fetchElement[TABLE_SIZE]; /* Color fetcher functions */ #define NAME(x) x##_byte #define TYPE GLbyte #define TYPEIDX FLAG_BYTE #define DIVIDE 255.0 #include "colorfetch.h" #define NAME(x) x##_ubyte #define TYPE GLubyte #define TYPEIDX FLAG_UBYTE #define DIVIDE 255.0 #include "colorfetch.h" #define NAME(x) x##_short #define TYPE GLshort #define TYPEIDX FLAG_SHORT #define DIVIDE 65535.0 #include "colorfetch.h" #define NAME(x) x##_ushort #define TYPE GLushort #define TYPEIDX FLAG_USHORT #define DIVIDE 65535.0 #include "colorfetch.h" #define NAME(x) x##_int #define TYPE GLint #define TYPEIDX FLAG_INT #define DIVIDE 4294967295.0 #include "colorfetch.h" #define NAME(x) x##_uint #define TYPE GLuint #define TYPEIDX FLAG_UINT #define DIVIDE 4294967295.0 #include "colorfetch.h" #define NAME(x) x##_float #define TYPE GLfloat #define TYPEIDX FLAG_FLOAT #include "colorfetch.h" #define NAME(x) x##_double #define TYPE GLdouble #define TYPEIDX FLAG_DOUBLE #include "colorfetch.h" void InitColorFetch(void) { IUtility->ClearMem(color_fetch, sizeof(color_fetch)); IUtility->ClearMem(color_fetchIdx, sizeof(color_fetchIdx)); IUtility->ClearMem(color_fetchElement, sizeof(color_fetchElement)); color_init_byte(); color_init_ubyte(); color_init_short(); color_init_ushort(); color_init_int(); color_init_uint(); color_init_float(); color_init_double(); } /* Arrays for texture coords */ ArrayFetcherFn texture_fetch[TABLE_SIZE]; ArrayFetcherIdxFn texture_fetchIdx[TABLE_SIZE]; ArrayFetcherIdxFn texture_fetchElement[TABLE_SIZE]; /* Texture fetcher functions */ #define NAME(x) x##_short #define TYPE GLshort #define TYPEIDX FLAG_SHORT #include "tcoordfetch.h" #define NAME(x) x##_int #define TYPE GLint #define TYPEIDX FLAG_INT #include "tcoordfetch.h" #define NAME(x) x##_float #define TYPE GLfloat #define TYPEIDX FLAG_FLOAT #include "tcoordfetch.h" #define NAME(x) x##_double #define TYPE GLdouble #define TYPEIDX FLAG_DOUBLE #include "tcoordfetch.h" void InitTextureFetch(void) { IUtility->ClearMem(texture_fetch, sizeof(texture_fetch)); IUtility->ClearMem(texture_fetchIdx, sizeof(texture_fetchIdx)); IUtility->ClearMem(texture_fetchElement, sizeof(texture_fetchElement)); texture_init_short(); texture_init_int(); texture_init_float(); texture_init_double(); } /* Arrays for vertex coords */ ArrayFetcherFn vertex_fetch[TABLE_SIZE]; ArrayFetcherIdxFn vertex_fetchIdx[TABLE_SIZE]; ArrayFetcherIdxFn vertex_fetchElement[TABLE_SIZE]; /* Vertex fetcher functions */ #define NAME(x) x##_short #define TYPE GLshort #define TYPEIDX FLAG_SHORT #include "vertexfetch.h" #define NAME(x) x##_int #define TYPE GLint #define TYPEIDX FLAG_INT #include "vertexfetch.h" #define NAME(x) x##_float #define TYPE GLfloat #define TYPEIDX FLAG_FLOAT #include "vertexfetch.h" #define NAME(x) x##_double #define TYPE GLdouble #define TYPEIDX FLAG_DOUBLE #include "vertexfetch.h" void InitVertexFetch(void) { IUtility->ClearMem(vertex_fetch, sizeof(vertex_fetch)); IUtility->ClearMem(vertex_fetchIdx, sizeof(vertex_fetchIdx)); IUtility->ClearMem(vertex_fetchElement, sizeof(vertex_fetchElement)); vertex_init_short(); vertex_init_int(); vertex_init_float(); vertex_init_double(); } /* Arrays for normal coords */ ArrayFetcherFn normal_fetch[TABLE_SIZE]; ArrayFetcherIdxFn normal_fetchIdx[TABLE_SIZE]; ArrayFetcherIdxFn normal_fetchElement[TABLE_SIZE]; /* normal fetcher functions */ #define NAME(x) x##_byte #define TYPE GLbyte #define TYPEIDX FLAG_BYTE #include "normalfetch.h" #define NAME(x) x##_short #define TYPE GLshort #define TYPEIDX FLAG_SHORT #include "normalfetch.h" #define NAME(x) x##_int #define TYPE GLint #define TYPEIDX FLAG_INT #include "normalfetch.h" #define NAME(x) x##_float #define TYPE GLfloat #define TYPEIDX FLAG_FLOAT #include "normalfetch.h" #define NAME(x) x##_double #define TYPE GLdouble #define TYPEIDX FLAG_DOUBLE #include "normalfetch.h" void InitNormalFetch(void) { IUtility->ClearMem(normal_fetch, sizeof(normal_fetch)); IUtility->ClearMem(normal_fetchIdx, sizeof(normal_fetchIdx)); IUtility->ClearMem(normal_fetchElement, sizeof(normal_fetchElement)); normal_init_byte(); normal_init_short(); normal_init_int(); normal_init_float(); normal_init_double(); } void InitVertexArray(void) { InitColorFetch(); InitTextureFetch(); InitNormalFetch(); InitVertexFetch(); } int sizeof_type(GLenum type) { switch (type) { case GL_BYTE: case GL_UNSIGNED_BYTE: return 1; case GL_SHORT: case GL_UNSIGNED_SHORT: return 2; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: return 4; case GL_DOUBLE: return 8; } return 0; } GLuint type_index(GLenum type) { switch (type) { case GL_BYTE: return FLAG_BYTE; case GL_UNSIGNED_BYTE: return FLAG_UBYTE; case GL_SHORT: return FLAG_SHORT; case GL_UNSIGNED_SHORT: return FLAG_USHORT; case GL_INT: return FLAG_INT; case GL_UNSIGNED_INT: return FLAG_UINT; case GL_FLOAT: return FLAG_FLOAT; case GL_DOUBLE: return FLAG_DOUBLE; } return 0; } GLuint size_index(GLint size) { switch (size) { case 1: return FLAG_1; case 2: return FLAG_2; case 3: return FLAG_3; case 4: return FLAG_4; } return 0; } void cgl_GLLockArrays(struct GLContextIFace *Self, GLint first, GLsizei count) { GLcontext context = GET_INSTANCE(Self); context->LockedArrays = context->vertex_array.ClientState; context->LockArraysFirst = first; context->LockArraysCount = count; /* Ensure the vertex buffer is large enough. If not, this function will re- * allocate it. If it can't do that, we can't use precompiled arrays... */ if (MGLEnsureVertexBufferSize(context, count-first)) { context->FrameCode ++; context->TexFrameCode ++; } else context->LockedArrays = 0; } void cgl_GLUnlockArrays(struct GLContextIFace *Self) { GLcontext context = GET_INSTANCE(Self); context->LockedArrays = 0; } void cgl_GLEnableClientState(struct GLContextIFace *Self, GLenum state) { GLcontext context = GET_INSTANCE(Self); switch (state) { case GL_TEXTURE_COORD_ARRAY: GLFlagError(context, context->vertex_array.ClientActiveTexture >= MAX_TEXTURE_UNITS, GL_INVALID_ENUM); context->vertex_array.ClientState |= client_texture_state[context->vertex_array.ClientActiveTexture]; break; case GL_COLOR_ARRAY: context->vertex_array.ClientState |= GLCS_COLOR; break; case GL_VERTEX_ARRAY: context->vertex_array.ClientState |= GLCS_VERTEX; break; case GL_NORMAL_ARRAY: context->vertex_array.ClientState |= GLCS_NORMAL; break; default: GLFlagError(context, 1, GL_INVALID_ENUM); break; } } void cgl_GLDisableClientState(struct GLContextIFace *Self, GLenum state) { GLcontext context = GET_INSTANCE(Self); switch (state) { case GL_TEXTURE_COORD_ARRAY: GLFlagError(context, context->vertex_array.ClientActiveTexture >= MAX_TEXTURE_UNITS, GL_INVALID_ENUM); context->vertex_array.ClientState &= ~client_texture_state[context->vertex_array.ClientActiveTexture]; break; case GL_COLOR_ARRAY: context->vertex_array.ClientState &= ~GLCS_COLOR; break; case GL_VERTEX_ARRAY: context->vertex_array.ClientState &= ~GLCS_VERTEX; break; case GL_NORMAL_ARRAY: context->vertex_array.ClientState &= ~GLCS_NORMAL; break; default: GLFlagError(context, 1, GL_INVALID_ENUM); break; } } void cgl_GLTexCoordPointer(struct GLContextIFace *Self, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { GLcontext context = GET_INSTANCE(Self); GLuint active = context->vertex_array.ClientActiveTexture; GLuint index = type_index(type) | size_index(size); GLFlagError(context, context->vertex_array.ClientActiveTexture >= MAX_TEXTURE_UNITS, GL_INVALID_ENUM); GLFlagError(context, size < 1 || size > 4, GL_INVALID_VALUE); GLFlagError(context, stride < 0, GL_INVALID_VALUE); context->TexFrameCode ++; if (stride == 0) stride = size*sizeof_type(type); context->vertex_array.TexCoordArray[active].size = size; context->vertex_array.TexCoordArray[active].type = type; context->vertex_array.TexCoordArray[active].stride = stride; context->vertex_array.TexCoordArray[active].pointer = (GLvoid *)pointer; context->vertex_array.TexCoordArray[active].fetch = texture_fetch[index]; context->vertex_array.TexCoordArray[active].fetchIdx = texture_fetchIdx[index]; context->vertex_array.TexCoordArray[active].fetchElement = texture_fetchElement[index]; GLFlagError(context, context->vertex_array.TexCoordArray[active].fetch == 0, GL_INVALID_ENUM); } void cgl_GLColorPointer(struct GLContextIFace *Self, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { GLcontext context = GET_INSTANCE(Self); GLuint index = type_index(type) | size_index(size); GLFlagError(context, size < 3 || size > 4, GL_INVALID_VALUE); GLFlagError(context, stride < 0, GL_INVALID_VALUE); context->FrameCode ++; if (stride == 0) stride = size*sizeof_type(type); context->vertex_array.ColorArray.size = size; context->vertex_array.ColorArray.type = type; context->vertex_array.ColorArray.stride = stride; context->vertex_array.ColorArray.pointer = (GLvoid *)pointer; context->vertex_array.ColorArray.fetch = color_fetch[index]; context->vertex_array.ColorArray.fetchIdx = color_fetchIdx[index]; context->vertex_array.ColorArray.fetchElement = color_fetchElement[index]; GLFlagError(context, context->vertex_array.ColorArray.fetch == 0, GL_INVALID_ENUM); } void cgl_GLVertexPointer(struct GLContextIFace *Self, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { GLcontext context = GET_INSTANCE(Self); GLuint index = type_index(type) | size_index(size); GLFlagError(context, size < 2 || size > 4, GL_INVALID_VALUE); GLFlagError(context, stride < 0, GL_INVALID_VALUE); context->FrameCode++; if (stride == 0) stride = size*sizeof_type(type); context->vertex_array.VertexArray.size = size; context->vertex_array.VertexArray.type = type; context->vertex_array.VertexArray.stride = stride; context->vertex_array.VertexArray.pointer = (GLvoid *)pointer; context->vertex_array.VertexArray.fetch = vertex_fetch[index]; context->vertex_array.VertexArray.fetchIdx = vertex_fetchIdx[index]; context->vertex_array.VertexArray.fetchElement = vertex_fetchElement[index]; GLFlagError(context, context->vertex_array.VertexArray.fetch == 0, GL_INVALID_ENUM); } void cgl_GLNormalPointer(struct GLContextIFace *Self, GLenum type, GLsizei stride, const GLvoid *pointer) { GLcontext context = GET_INSTANCE(Self); GLuint index = type_index(type); GLFlagError(context, stride < 0, GL_INVALID_VALUE); context->FrameCode ++; if (stride == 0) stride = 3*sizeof_type(type); context->vertex_array.NormalArray.size = 3; context->vertex_array.NormalArray.type = type; context->vertex_array.NormalArray.stride = stride; context->vertex_array.NormalArray.pointer = (GLvoid *)pointer; context->vertex_array.NormalArray.fetch = normal_fetch[index]; context->vertex_array.NormalArray.fetchIdx = normal_fetchIdx[index]; context->vertex_array.NormalArray.fetchElement = normal_fetchElement[index]; GLFlagError(context, context->vertex_array.NormalArray.fetch == 0, GL_INVALID_ENUM); } void cgl_GLInterleavedArrays(struct GLContextIFace *Self, GLenum format, GLsizei stride, const GLvoid *pointer) { GLcontext context = GET_INSTANCE(Self); GLint form = format - GL_V2F; GLubyte *base = (GLubyte *)pointer; GLFlagError(context, format < GL_V2F || form > GL_T4F_C4F_N3F_V4F, GL_INVALID_ENUM) GLFlagError(context, stride < 0, GL_INVALID_VALUE); context->FrameCode ++; context->vertex_array.ClientState = GLCS_VERTEX; if (stride == 0) stride = ILATab[form].stride; if (ILATab[form].enable_color) { context->vertex_array.ClientState |= GLCS_COLOR; Self->GLColorPointer(ILATab[form].color_size, ILATab[form].color_format, stride, base + ILATab[form].color_offset); } if (ILATab[form].enable_normal) { context->vertex_array.ClientState |= GLCS_NORMAL; Self->GLNormalPointer(GL_FLOAT, stride, base + ILATab[form].normal_offset); } if (ILATab[form].enable_texture) { context->TexFrameCode ++; context->vertex_array.ClientState |= GLCS_TEXTURE0; Self->GLTexCoordPointer(ILATab[form].texture_size, GL_FLOAT, stride, base + ILATab[form].texture_offset); } Self->GLVertexPointer(ILATab[form].vertex_size, GL_FLOAT, stride, base + ILATab[form].vertex_offset); } void cgl_GLClientActiveTexture(struct GLContextIFace *Self, GLenum texture) { GLcontext context = GET_INSTANCE(Self); texture -= GL_TEXTURE0; if (texture < MAX_TEXTURE_UNITS) context->vertex_array.ClientActiveTexture = texture; else GLFlagError(context, 1, GL_INVALID_ENUM); } static inline GLubyte *ArrayAddress(GLarray *array, int elem) { return (GLubyte *)array->pointer + array->stride * elem; } void cgl_GLArrayElement(struct GLContextIFace *Self, GLint i) { GLcontext context = GET_INSTANCE(Self); int t; if (context->vertex_array.ClientState & GLCS_COLOR && context->vertex_array.ColorArray.fetchElement) context->vertex_array.ColorArray.fetchElement(context, &context->vertex_array.ColorArray, i, 0); for (t = 0; t <= context->texture.MaxTextureUnit; t++) { if (context->vertex_array.ClientState & client_texture_state[t] && (context->enable.Texture2D[t] || context->enable.Texture1D[t]) && context->vertex_array.TexCoordArray[t].fetchElement) context->vertex_array.TexCoordArray[t].fetchElement(context, &context->vertex_array.TexCoordArray[t], i, t); } if (context->vertex_array.ClientState & GLCS_NORMAL && context->vertex_array.NormalArray.fetchElement) context->vertex_array.NormalArray.fetchElement(context, &context->vertex_array.NormalArray, i, 0); /* Note: This will also advance the vertex array pointer */ if (context->vertex_array.ClientState & GLCS_VERTEX && context->vertex_array.VertexArray.fetchElement) context->vertex_array.VertexArray.fetchElement(context, &context->vertex_array.VertexArray, i, 0); } static GLboolean ArrayBegin(GLcontext context, GLenum mode) { if (!context->LockedArrays) { context->FrameCode ++; context->TexFrameCode ++; } context->VertexBufferPointer = 0; tex_EstablishEnvCombine(context); checkNeedEye(context); if(context->renderMode == GL_RENDER) { switch((int)mode) { case GL_POINTS: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawPoints; break; case GL_LINES: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLines; break; case GL_LINE_STRIP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLineStrip; break; case GL_LINE_LOOP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLineStrip; break; case GL_TRIANGLES: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangles; break; case GL_TRIANGLE_STRIP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangleStrip; break; case GL_TRIANGLE_FAN: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangleFan; break; case GL_QUADS: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawQuads; break; case GL_QUAD_STRIP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawQuadStrip; break; case GL_POLYGON: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawPolygon; break; case MGL_FLATFAN: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawFlatFan; break; default: GLFlagError2(context, 1, GL_INVALID_OPERATION, GL_FALSE); } } else if(context->renderMode == GL_SELECT) { switch((int)mode) { case GL_POINTS: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawPoints; break; case GL_LINES: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawLines; break; case GL_LINE_STRIP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawLineStrip; break; case GL_LINE_LOOP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawLineStrip; break; case GL_TRIANGLES: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawTriangles; break; case GL_TRIANGLE_STRIP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawTriangleStrip; break; case GL_TRIANGLE_FAN: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawTriangleFan; break; case GL_QUADS: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawQuads; break; case GL_QUAD_STRIP: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawQuadStrip; break; case GL_POLYGON: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawPolygon; break; case MGL_FLATFAN: context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawFlatFan; break; default: GLFlagError2(context, 1, GL_INVALID_OPERATION, GL_FALSE); } } else { // GL_FEEDBACK mode not implemented yet GLFlagError2(context, 1, GL_INVALID_OPERATION, GL_FALSE); } return GL_TRUE; } void MaybeLock(GLcontext context) { tex_EstablishEnvCombine(context); if (context->FogDirty && context->enable.Fog) { fog_Set(context); context->FogDirty = GL_FALSE; } if (context->lighting.ShadeModel == GL_FLAT) { static W3D_Color color; color.r = CLAMPF(context->current.CurrentColor.r); color.g = CLAMPF(context->current.CurrentColor.g); color.b = CLAMPF(context->current.CurrentColor.b); color.a = CLAMPF(context->current.CurrentColor.a); IWarp3D->W3D_SetCurrentColor(context->w3dContext, &color); } #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("[glEnd] Error during W3D_LockHardware()\n"); return; // give up } IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS == IWarp3D->W3D_LockHardware(context->w3dContext)) { context->w3dLocked = GL_TRUE; IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); } else{ dprintf("[glEnd] Error during W3D_LockHardware()\n"); return; // give up } } else // Manual: Lock manually { IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); } #endif } void MaybeUnlock(GLcontext context) { if (context->LockMode == MGL_LOCK_SMART) { smartlock_endDraw(context->smartLock); } else if(context->LockMode == MGL_LOCK_AUTOMATIC){ IWarp3D->W3D_UnLockHardware(context->w3dContext); context->w3dLocked = GL_FALSE; } } static void ArrayEnd(GLcontext context) { context->fbDirty = GL_TRUE; if (context->FogDirty && context->enable.Fog) { fog_Set(context); context->FogDirty = GL_FALSE; } if (context->lighting.ShadeModel == GL_FLAT) { static W3D_Color color; color.r = CLAMPF(context->current.CurrentColor.r); color.g = CLAMPF(context->current.CurrentColor.g); color.b = CLAMPF(context->current.CurrentColor.b); color.a = CLAMPF(context->current.CurrentColor.a); IWarp3D->W3D_SetCurrentColor(context->w3dContext, &color); } // Check for blending inconsistancy // if (context->AlphaFellBack && (context->SrcAlpha == GL_ONE || context->DstAlpha == GL_ONE) // && context->Blend_State == GL_TRUE) // { // tex_ConvertTexture(context); // } if(context->renderMode == GL_RENDER) { #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART)// Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("[glEnd] Error during W3D_LockHardware()\n"); return; // give up } IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); context->CurrentDraw(context); // Draw! smartlock_endDraw(context->smartLock); } else if (context->LockMode == MGL_LOCK_AUTOMATIC) // Automatic: Lock per primitive { if (W3D_SUCCESS == IWarp3D->W3D_LockHardware(context->w3dContext)) { context->w3dLocked = GL_TRUE; IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); context->CurrentDraw(context); IWarp3D->W3D_UnLockHardware(context->w3dContext); context->w3dLocked = GL_FALSE; } else { dprintf("Error during LockHardware\n"); } } else // Manual: Lock manually { IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); context->CurrentDraw(context); } #else IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); context->CurrentDraw(context); #endif } else if(context->renderMode == GL_SELECT) { context->CurrentDraw(context); } else { // GL_FEEDBACK not implemented yet dprintf("%s: GL_FEEDBACK mode not implemented yet\n", __func__); } context->CurrentPrimitive = GL_BASE; } #define thisvertex context->VertexBuffer[context->VertexBufferPointer] void CurrentColorFetch(GLcontext context, struct GLarray_t *array, GLvoid *cur, GLuint unit) { thisvertex.r = context->current.CurrentColor.r; thisvertex.g = context->current.CurrentColor.g; thisvertex.b = context->current.CurrentColor.b; thisvertex.a = context->current.CurrentColor.a; #ifdef MGL_USE_LIGHTING if (context->enable.ColorMaterial) light_UpdateColorMaterialVertex(context); #endif } void CurrentNormalFetch(GLcontext context, struct GLarray_t *array, GLvoid *cur, GLuint unit) { thisvertex.Normal.x = context->current.CurrentNormal.x; thisvertex.Normal.y = context->current.CurrentNormal.y; thisvertex.Normal.z = context->current.CurrentNormal.z; } void CurrentTextureFetch(GLcontext context, struct GLarray_t *array, GLvoid *cur, GLuint i) { if (context->current.CurTexQValid[i] == GL_TRUE) { float oneoverq = 1.0 / context->current.CurTexQ[i]; thisvertex.uvw[i].u = context->current.CurTexS[i] * oneoverq; thisvertex.uvw[i].v = context->current.CurTexT[i] * oneoverq; thisvertex.uvw[i].w = context->current.CurTexQ[i]; thisvertex.rhw_valid[i] = GL_TRUE; } else { thisvertex.uvw[i].u = context->current.CurTexS[i]; thisvertex.uvw[i].v = context->current.CurTexT[i]; thisvertex.uvw[i].w = 1.0; thisvertex.rhw_valid[i] = GL_FALSE; } } #undef thisvertex void cgl_GLDrawArrays(struct GLContextIFace *Self, GLenum mode, GLint first, GLsizei count) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_DrawArrays(Self, mode, first, count); if(!dl_CompileAndExecuteMode(Self)){ return; } } BOOL splitLineLoop = FALSE; int i; int c; int full_packs; int part_verts; int pack_size = context->VertexBufferSize - 2; // So that there's always room for the residue from the previous pack MGLVertex t1, t2; int verts_to_copy = 0; int pass = 0; GLubyte *color = 0, *vertex = 0, *normal = 0, *texture[MAX_TEXTURE_UNITS] = {0, }; ArrayFetcherFn color_fetch = 0, vertex_fetch = 0, normal_fetch = 0, texture_fetch[MAX_TEXTURE_UNITS] = {0, }; GLFlagError(context, first < 0, GL_INVALID_VALUE); /* Some special handling for certain primitive types */ switch (mode) { case GL_TRIANGLES: pack_size = pack_size - (pack_size % 3); break; case GL_QUADS: pack_size = pack_size - (pack_size % 4); break; case GL_LINE_STRIP: case GL_TRIANGLE_FAN: case MGL_FLATFAN: verts_to_copy = 1; break; case GL_TRIANGLE_STRIP: case GL_QUAD_STRIP: verts_to_copy = 2; break; } full_packs = count / pack_size; part_verts = count % pack_size; if(mode == GL_LINE_LOOP && (full_packs > 1 || (full_packs == 1 && part_verts > 0))) { // The line loop will be broken up into segments. // Need to switch to line strips and manually loop back mode = GL_LINE_STRIP; splitLineLoop = TRUE; verts_to_copy = 1; } /* Setup the array and function pointers(if active) */ if (context->vertex_array.ClientState & GLCS_COLOR) { color_fetch = context->vertex_array.ColorArray.fetch; color = ArrayAddress(&context->vertex_array.ColorArray, first); GLFlagError(context, color_fetch == 0, GL_INVALID_ENUM); } else color_fetch = CurrentColorFetch; if (context->vertex_array.ClientState & GLCS_NORMAL) { normal_fetch = context->vertex_array.NormalArray.fetch; normal = ArrayAddress(&context->vertex_array.NormalArray, first); GLFlagError(context, normal_fetch == 0, GL_INVALID_ENUM); } else normal_fetch = CurrentNormalFetch; 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])) { texture_fetch[i] = context->vertex_array.TexCoordArray[i].fetch; texture[i] = ArrayAddress(&context->vertex_array.TexCoordArray[i], first); GLFlagError(context, texture_fetch[i] == 0, GL_INVALID_ENUM); } else texture_fetch[i] = CurrentTextureFetch; } if (context->vertex_array.ClientState & GLCS_VERTEX) { vertex_fetch = context->vertex_array.VertexArray.fetch; vertex = ArrayAddress(&context->vertex_array.VertexArray, first); } GLFlagError(context, vertex_fetch == 0, GL_INVALID_ENUM); /* Start drawing */ while (full_packs--) { if (GL_FALSE == ArrayBegin(context, mode)) return; /* On subsequent passes, strips and fans need "key" vertices copied */ if (pass != 0) { if (verts_to_copy == 1) { context->VertexBuffer[0] = t1; context->VertexBufferPointer = 1; } else if (verts_to_copy == 2) { context->VertexBuffer[0] = t1; context->VertexBuffer[1] = t2; context->VertexBufferPointer = 2; } } for (c = 0; c < pack_size; ++c) { color_fetch(context, &context->vertex_array.ColorArray, color, 0); color += context->vertex_array.ColorArray.stride; normal_fetch(context, &context->vertex_array.NormalArray, normal, 0); normal += context->vertex_array.NormalArray.stride; for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { texture_fetch[i](context, &context->vertex_array.TexCoordArray[i], texture[i], i); texture[i] += context->vertex_array.TexCoordArray[i].stride; } } vertex_fetch(context, &context->vertex_array.VertexArray, vertex, 0); vertex += context->vertex_array.VertexArray.stride; context->VertexBufferPointer ++; } pass++; if (verts_to_copy == 1) { if(mode == GL_LINE_STRIP) { t1 = context->VertexBuffer[context->VertexBufferPointer-1]; if(pass == 0 && splitLineLoop) { // storing the first vertex into t2 for the end t2 = context->VertexBuffer[0]; } } else { t1 = context->VertexBuffer[0]; } } else if (verts_to_copy == 2) { t1 = context->VertexBuffer[context->VertexBufferPointer-2]; t2 = context->VertexBuffer[context->VertexBufferPointer-1]; } if(splitLineLoop && full_packs == 1 && part_verts == 0) { // Close the loop context->VertexBuffer[context->VertexBufferPointer] = t2; context->VertexBufferPointer ++; } ArrayEnd(context); } /* Draw the rest which didn't fit the full packages */ if (part_verts) { if (GL_FALSE == ArrayBegin(context, mode)) return; if (pass != 0) { if (verts_to_copy == 1) { context->VertexBuffer[0] = t1; context->VertexBufferPointer = 1; } else if (verts_to_copy == 2) { context->VertexBuffer[0] = t1; context->VertexBuffer[1] = t2; context->VertexBufferPointer = 2; } } for (c = 0; c < part_verts; c++) { color_fetch(context, &context->vertex_array.ColorArray, color, 0); color += context->vertex_array.ColorArray.stride; normal_fetch(context, &context->vertex_array.NormalArray, normal, 0); normal += context->vertex_array.NormalArray.stride; for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { texture_fetch[i](context, &context->vertex_array.TexCoordArray[i], texture[i], i); texture[i] += context->vertex_array.TexCoordArray[i].stride; } } vertex_fetch(context, &context->vertex_array.VertexArray, vertex, 0); vertex += context->vertex_array.VertexArray.stride; context->VertexBufferPointer ++; } if(splitLineLoop) { // Close the loop context->VertexBuffer[context->VertexBufferPointer] = t2; context->VertexBufferPointer ++; } ArrayEnd(context); } } GLuint FetchElementByte(GLvoid **indices) { GLuint ret; GLubyte *index = (GLubyte *) *indices; ret = *index++; *indices = (GLvoid *)index; return ret; } GLuint FetchElementShort(GLvoid **indices) { GLuint ret; GLushort *index = (GLushort *) *indices; ret = *index++; *indices = (GLvoid *)index; return ret; } GLuint FetchElementInt(GLvoid **indices) { GLuint ret; GLuint *index = (GLuint *) *indices; ret = *index++; *indices = (GLvoid *)index; return ret; } void cgl_GLDrawRangeElements(struct GLContextIFace *Self, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid * indices) { Self->GLDrawElements(mode, count, type, indices); } void cgl_GLDrawElements(struct GLContextIFace *Self, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_DrawElements(Self, mode, count, type, indices); if(!dl_CompileAndExecuteMode(Self)){ return; } } BOOL splitLineLoop = FALSE; int i; int c; int full_packs; int part_verts; int pack_size = context->VertexBufferSize - 2; // So that there's always room for the residue from the previous pack MGLVertex t1, t2; int verts_to_copy = 0; int pass = 0; ArrayFetcherIdxFn color_fetch = 0, vertex_fetch = 0, normal_fetch = 0, texture_fetch[MAX_TEXTURE_UNITS] = {0, }; GLuint (*index_fetch)(GLvoid **indices); GLvoid *index_pointer = (GLvoid *)indices; #ifdef MGL_COMPILED_VERTEX_ARRAYS if (mode == GL_TRIANGLES && context->LockedArrays) { /* Try an optimized version */ GLDrawElementsTriangles(context, count, type, indices); return; } #endif /* Determine the index type */ switch (type) { case GL_UNSIGNED_BYTE: index_fetch = FetchElementByte; break; case GL_UNSIGNED_SHORT: index_fetch = FetchElementShort; break; case GL_UNSIGNED_INT: index_fetch = FetchElementInt; break; default: GLFlagError(context, 1, GL_INVALID_ENUM); } /* Some special handling for certain primitive types */ switch (mode) { case GL_TRIANGLES: pack_size = pack_size - (pack_size % 3); break; case GL_QUADS: pack_size = pack_size - (pack_size % 4); break; case GL_LINE_STRIP: case GL_TRIANGLE_FAN: case MGL_FLATFAN: verts_to_copy = 1; break; case GL_TRIANGLE_STRIP: case GL_QUAD_STRIP: verts_to_copy = 2; break; } full_packs = count / pack_size; part_verts = count % pack_size; if(mode == GL_LINE_LOOP && (full_packs > 1 || (full_packs == 1 && part_verts > 0))) { // The line loop will be broken up into segments. // Need to switch to line strips and manually loop back mode = GL_LINE_STRIP; splitLineLoop = TRUE; verts_to_copy = 1; } /* Setup the array and function pointers(if active) */ if (context->vertex_array.ClientState & GLCS_COLOR) { color_fetch = context->vertex_array.ColorArray.fetchIdx; GLFlagError(context, color_fetch == 0, GL_INVALID_ENUM); } else color_fetch = (ArrayFetcherIdxFn)CurrentColorFetch; if (context->vertex_array.ClientState & GLCS_NORMAL) { normal_fetch = context->vertex_array.NormalArray.fetchIdx; GLFlagError(context, normal_fetch == 0, GL_INVALID_ENUM); } else normal_fetch = (ArrayFetcherIdxFn)CurrentNormalFetch; 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])) { texture_fetch[i] = context->vertex_array.TexCoordArray[i].fetchIdx; GLFlagError(context, texture_fetch[i] == 0, GL_INVALID_ENUM); } else texture_fetch[i] = (ArrayFetcherIdxFn)CurrentTextureFetch; } if (context->vertex_array.ClientState & GLCS_VERTEX) { vertex_fetch = context->vertex_array.VertexArray.fetchIdx; } GLFlagError(context, vertex_fetch == 0, GL_INVALID_ENUM); /* Start drawing */ while (full_packs--) { if (GL_FALSE == ArrayBegin(context, mode)) return; /* On subsequent passes, strips and fans need "key" vertices copied */ if (pass != 0) { if (verts_to_copy == 1) { context->VertexBuffer[0] = t1; context->VertexBufferPointer = 1; } else if (verts_to_copy == 2) { context->VertexBuffer[0] = t1; context->VertexBuffer[1] = t2; context->VertexBufferPointer = 2; } } for (c = 0; c < pack_size; c++) { GLuint idx = index_fetch(&index_pointer); color_fetch(context, &context->vertex_array.ColorArray, idx, 0); normal_fetch(context, &context->vertex_array.NormalArray, idx, 0); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) texture_fetch[i](context, &context->vertex_array.TexCoordArray[i], idx, i); } vertex_fetch(context, &context->vertex_array.VertexArray, idx, 0); context->VertexBufferPointer ++; } ++pass; if (verts_to_copy == 1) { if(mode == GL_LINE_STRIP) { t1 = context->VertexBuffer[context->VertexBufferPointer-1]; if(pass == 0 && splitLineLoop) { // storing the first vertex into t2 for the end t2 = context->VertexBuffer[0]; } } else { t1 = context->VertexBuffer[0]; } } else if (verts_to_copy == 2) { t1 = context->VertexBuffer[context->VertexBufferPointer-2]; t2 = context->VertexBuffer[context->VertexBufferPointer-1]; } if(splitLineLoop && full_packs == 1 && part_verts == 0) { // Close the loop context->VertexBuffer[context->VertexBufferPointer] = t2; context->VertexBufferPointer ++; } ArrayEnd(context); } /* Draw the rest which didn't fit the full packages */ if (part_verts) { if (GL_FALSE == ArrayBegin(context, mode)) return; if (pass != 0) { if (verts_to_copy == 1) { context->VertexBuffer[0] = t1; context->VertexBufferPointer = 1; } else if (verts_to_copy == 2) { context->VertexBuffer[0] = t1; context->VertexBuffer[1] = t2; context->VertexBufferPointer = 2; } } for (c = 0; c < part_verts; ++c) { GLuint idx = index_fetch(&index_pointer); color_fetch(context, &context->vertex_array.ColorArray, idx, 0); normal_fetch(context, &context->vertex_array.NormalArray, idx, 0); for (i = 0; i <= context->texture.MaxTextureUnit; ++i) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) texture_fetch[i](context, &context->vertex_array.TexCoordArray[i], idx, i); } vertex_fetch(context, &context->vertex_array.VertexArray, idx, 0); context->VertexBufferPointer ++; } if(splitLineLoop) { // Close the loop context->VertexBuffer[context->VertexBufferPointer] = t2; context->VertexBufferPointer ++; } ArrayEnd(context); } } /* The following code is experimental and incomplete. It tries to implement * GL_compiled_vertex_arrays. Use with caution. */ #ifdef MGL_COMPILED_VERTEX_ARRAYS void v_MaybeTransform(GLcontext context, GLuint *or_codes, GLuint *and_codes) { int i, tmu; *or_codes = 0; *and_codes = 0xffffffff; if (context->NeedEye) v_GenEyeCoords(context); if (context->enable.TexGen == GL_TRUE) { for (i=0; iVertexBufferPointer; i++) v_GenTexCoords(context, i); } if (context->CombinedValid == GL_FALSE) m_CombineMatrices(context); for (tmu = 0; tmu <= context->texture.MaxTextureUnit; tmu++) { if (!(context->Texture[context->TextureNr[tmu]][tmu].flags & MGLMAT_IDENTITY)) { /* The current texture matrix is not an identity */ #define a(x) context->Texture[context->TextureNr[tmu]][tmu].v[OF_##x] float a11 = a(11); float a12 = a(12); float a14 = a(14); float a21 = a(21); float a22 = a(22); float a24 = a(24); #ifndef QUAKE3_HACK float a41 = a(41); float a42 = a(42); float a44 = a(44); #endif for (i = 0; i < context->VertexBufferPointer; i++) { MGLVertex *vx = &context->VertexBuffer[i]; if (vx->tex_frame_code != context->TexFrameCode) { float u = vx->uvw[tmu].u; float v = vx->uvw[tmu].v; float w __attribute__((unused)) = vx->uvw[tmu].w; #ifdef QUAKE3_HACK vx->uvw[tmu].u = a11*u + a12*v + a14; vx->uvw[tmu].v = a21*u + a22*v + a24; vx->rhw_valid[tmu] = GL_FALSE; vx->align[0] = 1; #else if (vx->rhw_valid == GL_FALSE) { vx->uvw[tmu].u = a11*u + a12*v + a14; vx->uvw[tmu].v = a21*u + a22*v + a24; vx->rhw_valid[tmu] = GL_FALSE; vx->align[0] = 1; } else { vx->uvw[tmu].u = a11*u + a12*v + a14*w; vx->uvw[tmu].v = a21*u + a22*v + a24*w; vx->uvw[tmu].w = a41*u + a42*v + a44*w; } #endif vx->tex_frame_code = context->TexFrameCode; } #undef a } } } if (context->WOne_Hint == GL_FALSE) { #define a(x) (context->CombinedMatrix.v[OF_##x]) float a11 = a(11); float a12 = a(12); float a13 = a(13); float a14 = a(14); float a21 = a(21); float a22 = a(22); float a23 = a(23); float a24 = a(24); float a31 = a(31); float a32 = a(32); float a33 = a(33); float a34 = a(34); float a41 = a(41); float a42 = a(42); float a43 = a(43); float a44 = a(44); int counter = context->VertexBufferPointer; MGLVertex *vf = context->VertexBuffer; for (i = 0; i < counter; i++) { MGLVertex *v = &vf[i]; if (v->frame_code != context->FrameCode) { float x = v->object.x; float y = v->object.y; float z = v->object.z; float w = v->object.w; v->clip.x = a11*x + a12*y + a13*z + a14*w; v->clip.y = a21*x + a22*y + a23*z + a24*w; v->clip.z = a31*x + a32*y + a33*z + a34*w; v->clip.w = a41*x + a42*y + a43*z + a44*w; hc_CodePoint(context, v); v->frame_code = context->FrameCode; v->align[0] = 2; } if (v->align[0]) v_ToScreen(context, i); *or_codes |= v->outcode; *and_codes &= v->outcode; } #undef a } else { #define a(x) (context->CombinedMatrix.v[OF_##x]) float a11 = a(11); float a12 = a(12); float a13 = a(13); float a14 = a(14); float a21 = a(21); float a22 = a(22); float a23 = a(23); float a24 = a(24); float a31 = a(31); float a32 = a(32); float a33 = a(33); float a34 = a(34); float a41 = a(41); float a42 = a(42); float a43 = a(43); float a44 = a(44); int counter = context->VertexBufferPointer; MGLVertex *vf = context->VertexBuffer; for (i=0; iframe_code != context->FrameCode) { float x = v->object.x; float y = v->object.y; float z = v->object.z; v->clip.x = a11*x + a12*y + a13*z + a14; v->clip.y = a21*x + a22*y + a23*z + a24; v->clip.z = a31*x + a32*y + a33*z + a34; v->clip.w = a41*x + a42*y + a43*z + a44; hc_CodePoint(context, v); v->frame_code = context->FrameCode; v->align[0] = 2; } if (v->align[0]) v_ToScreen(context, i); *or_codes |= v->outcode; *and_codes &= v->outcode; } #undef a } } #define NEED_SPECIAL_FILL (context->polygon.PolygonModeFront != GL_FILL \ || context->polygon.PolygonModeBack != GL_FILL) extern GLint v_GetPolyFillMode(GLcontext context, MGLPolygon *poly); extern void d_ClipAndDrawPolyWithFill(GLcontext context, MGLPolygon *poly, uint32 or_code, GLuint fillMode); void GLDrawElementsTriangles(GLcontext context, GLsizei count, GLenum type, const GLvoid *indices) { GLuint (*index_fetch)(GLvoid **indices); GLvoid *index_pointer = (GLvoid *)indices; uint32 w3dType; ArrayFetcherFn color_fetch = 0, vertex_fetch = 0, normal_fetch = 0, texture_fetch[MAX_TEXTURE_UNITS] = {0, }; GLubyte *color = 0, *vertex = 0, *normal = 0, *texture[MAX_TEXTURE_UNITS] = {0, }; GLuint drawBase; GLuint drawCount; GLuint indexScale; int i, tmu; GLuint and_code, or_code; GLbitfield clientState[10] = { GLCS_TEXTURE0, GLCS_TEXTURE1, GLCS_TEXTURE2, GLCS_TEXTURE3, 0,}; GLfloat offset; GLuint first = context->LockArraysFirst; context->fbDirty = GL_TRUE; /* Determine the index type */ switch (type) { case GL_UNSIGNED_BYTE: index_fetch = FetchElementByte; w3dType = W3D_INDEX_UBYTE; indexScale = 1; break; case GL_UNSIGNED_SHORT: index_fetch = FetchElementShort; w3dType = W3D_INDEX_UWORD; indexScale = 2; break; case GL_UNSIGNED_INT: index_fetch = FetchElementInt; w3dType = W3D_INDEX_ULONG; indexScale = 4; break; default: GLFlagError(context, 1, GL_INVALID_ENUM); } checkNeedEye(context); /* Setup the array and function pointers (if active) */ if (context->vertex_array.ClientState & GLCS_COLOR) { color_fetch = context->vertex_array.ColorArray.fetch; color = ArrayAddress(&context->vertex_array.ColorArray, first); GLFlagError(context, color_fetch == 0, GL_INVALID_ENUM); } else color_fetch = CurrentColorFetch; if (context->vertex_array.ClientState & GLCS_NORMAL) { normal_fetch = context->vertex_array.NormalArray.fetch; normal = ArrayAddress(&context->vertex_array.NormalArray, first); GLFlagError(context, normal_fetch == 0, GL_INVALID_ENUM); } else normal_fetch = CurrentNormalFetch; 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])) { texture_fetch[i] = context->vertex_array.TexCoordArray[i].fetch; texture[i] = ArrayAddress( &context->vertex_array.TexCoordArray[i], first); GLFlagError(context, texture_fetch[i] == 0, GL_INVALID_ENUM); } else texture_fetch[i] = CurrentTextureFetch; } if (context->vertex_array.ClientState & GLCS_VERTEX) { vertex_fetch = context->vertex_array.VertexArray.fetch; vertex = ArrayAddress(&context->vertex_array.VertexArray, first); } GLFlagError(context, vertex_fetch == 0, GL_INVALID_ENUM); and_code = 0xff; or_code = 0; /* First of all, fetch all vertices */ context->VertexBufferPointer = 0; for (i = 0; i < context->LockArraysCount; i++) { if (!(context->LockedArrays & GLCS_NORMAL) || context->VertexBuffer[i].frame_code != context->FrameCode) { normal_fetch(context, &context->vertex_array.NormalArray, normal, 0); } if (!(context->LockedArrays & GLCS_COLOR) || context->VertexBuffer[i].frame_code != context->FrameCode) { color_fetch(context, &context->vertex_array.ColorArray, color, 0); } for (tmu = 0; tmu <= context->texture.MaxTextureUnit; tmu++) { if (!context->enable.Texture2D[tmu] && !context->enable.Texture1D[tmu]) continue; if (!(context->LockedArrays & clientState[tmu]) || context->VertexBuffer[i].frame_code != context->FrameCode) { texture_fetch[tmu](context, &context->vertex_array.TexCoordArray[tmu], texture[tmu], tmu); } } if (!(context->LockedArrays & GLCS_VERTEX) || context->VertexBuffer[i].frame_code != context->FrameCode) { vertex_fetch(context, &context->vertex_array.VertexArray, vertex, 0); } color += context->vertex_array.ColorArray.stride; normal += context->vertex_array.NormalArray.stride; vertex += context->vertex_array.VertexArray.stride; for (tmu = 0; tmu <= context->texture.MaxTextureUnit; tmu++) { if (context->enable.Texture2D[tmu] || context->enable.Texture1D[tmu]) texture[tmu] += context->vertex_array.TexCoordArray[tmu].stride; } context->VertexBufferPointer ++; } /* Transform what we need */ v_MaybeTransform(context, &or_code, &and_code); /* If the and_codes are not 0, no triangle is on screen. Likewise, if the * or code is all 0, all triangles are completely on-screen */ #if 0 if (and_code) return; #endif if(context->renderMode != GL_RENDER) { if(context->renderMode == GL_SELECT) { // if we got to here, something was drawn s_GLDrawElementsTriangles(context, count, type, indices); } else { dprintf("%s: GL_FEEDBACK not implemented yet\n", __func__); } return; } #if 1 if (or_code == 0 && !context->enable.PolygonOffsetFill && !NEED_SPECIAL_FILL) { MaybeLock(context); if (context->enable.CullFace) IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_ENABLE); IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, w3dType, count, index_pointer); if (context->enable.CullFace) IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_DISABLE); MaybeUnlock(context); return; } #endif MaybeLock(context); /* If */ drawBase = 0; drawCount = 0; /* Go through the array and draw */ for (i = 0; i < count; i+=3) { void *idxbase = index_pointer; GLfloat z1 = 0.0, z2 = 0.0, z3 = 0.0; GLuint idx1 = index_fetch(&index_pointer) - first; GLuint idx2 = index_fetch(&index_pointer) - first; GLuint idx3 = index_fetch(&index_pointer) - first; or_code = context->VertexBuffer[idx1].outcode | context->VertexBuffer[idx2].outcode | context->VertexBuffer[idx3].outcode; and_code = context->VertexBuffer[idx1].outcode & context->VertexBuffer[idx2].outcode & context->VertexBuffer[idx3].outcode; if (and_code) continue; if ((hc_DecideFrontface(context, &(context->VertexBuffer[idx1]), &(context->VertexBuffer[idx2]), &(context->VertexBuffer[idx3]),or_code) == GL_FALSE)) { continue; } if (context->enable.PolygonOffsetFill) { offset = v_PolygonOffset(context, idx1, idx2, idx3); z1 = context->VertexBuffer[idx1].z; z2 = context->VertexBuffer[idx2].z; z3 = context->VertexBuffer[idx3].z; context->VertexBuffer[idx1].z = min (1.0, context->VertexBuffer[idx1].z + offset); context->VertexBuffer[idx2].z = min (1.0, context->VertexBuffer[idx2].z + offset); context->VertexBuffer[idx3].z = min (1.0, context->VertexBuffer[idx3].z + offset); } else offset = 0.0; if (or_code == 0 && !NEED_SPECIAL_FILL) { IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, w3dType, 3, idxbase); } else { static MGLPolygon poly; poly.numverts = 3; poly.verts[0] = idx1; poly.verts[1] = idx2; poly.verts[2] = idx3; poly.zoffset = offset; if (NEED_SPECIAL_FILL) { GLint fillMode = v_GetPolyFillMode(context, &poly); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode); } else hc_ClipAndDrawPoly(context, &poly, or_code, 0); } if (context->enable.PolygonOffsetFill) { context->VertexBuffer[idx1].z = z1; context->VertexBuffer[idx2].z = z2; context->VertexBuffer[idx3].z = z3; } } MaybeUnlock(context); } #endif void cgl_GLPushClientAttrib(struct GLContextIFace *Self, GLbitfield mask) { GLcontext context = GET_INSTANCE(Self); // ##### FIXME! ##### GLuint stackp = context->ClientAttribStackPointer; GLFlagError(context, context->ClientAttribStackPointer >= MGL_ATTRIB_STACK_SIZE, GL_STACK_OVERFLOW); context->ClientAttribStackPointer ++; context->ClientAttribStackBits[stackp] = mask; /* Push all required state. * Note: Enable bits are always pushed, but only those affected by mask * are actually restored on pop */ if (mask & GL_CLIENT_PIXEL_STORE_BIT) { context->pixel_store_stack[stackp] = context->pixel_store; } if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) { context->vertex_array_stack[stackp] = context->vertex_array; } } void cgl_GLPopClientAttrib(struct GLContextIFace *Self) { GLcontext context = GET_INSTANCE(Self); // ##### FIXME! ##### GLuint stackp; GLuint mask; GLFlagError(context, context->ClientAttribStackPointer == 0, GL_STACK_UNDERFLOW); stackp = --context->ClientAttribStackPointer; mask = context->ClientAttribStackBits[stackp]; if (mask & GL_CLIENT_PIXEL_STORE_BIT) { context->pixel_store = context->pixel_store_stack[stackp]; } if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) { context->vertex_array = context->vertex_array_stack[stackp]; } }