/* * $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 static char rcsid[] UNUSED = "$Id$"; 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 int buf_GetBufferHeight(GLcontext, GLbuffer *); //extern void tex_ConvertTexture (GLcontext); extern void fog_Set (GLcontext); extern void light_UpdateColorMaterial(GLcontext); extern GLboolean MGLEnsureVertexBufferSize(GLcontext context, GLuint size); void cgl_GLEnd(struct GLContextIFace *Self); float CLAMPF(float a) { float res; __asm volatile( "fsel %0,%2,%2,%1" : "=f" (res): "f" (0.0f), "f" (a)); __asm volatile( "fsub %0,%1,%2" : "=f" (a): "f" (res), "f" (1.0f)); __asm volatile( "fsel %0,%1,%2,%3" : "=f" (res): "f" (a),"f" (1.0f),"f" (res)); return res; } void cgl_GLBegin(struct GLContextIFace *Self, GLenum mode) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_Begin(Self, mode); if(!dl_CompileAndExecuteMode(Self)){ return; } } extern void tex_EstablishEnvCombine(GLcontext context); extern void checkNeedEye(GLcontext context); // GLFlagError(context, context->CurrentPrimitive != GL_BASE, GL_INVALID_OPERATION); context->VertexBufferPointer = 0; context->FrameCode ++; context->TexFrameCode ++; tex_EstablishEnvCombine(context); checkNeedEye(context); if(context->renderMode == GL_RENDER) { switch((int)mode) { case GL_POINTS: //LOG(1, glBegin, "GL_POINTS"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawPoints; break; case GL_LINES: //LOG(1, glBegin, "GL_LINES"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLines; break; case GL_LINE_STRIP: //LOG(1, glBegin, "GL_LINE_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLineStrip; break; case GL_LINE_LOOP: //LOG(1, glBegin, "GL_LINE_LOOP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLineStrip; break; case GL_TRIANGLES: //LOG(1, glBegin, "GL_TRIANLES"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangles; break; case GL_TRIANGLE_STRIP: //LOG(1, glBegin, "GL_TRIANGLE_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangleStrip; break; case GL_TRIANGLE_FAN: //LOG(1, glBegin, "GL_TRIANGLE_FAN"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangleFan; break; case GL_QUADS: //LOG(1, glBegin, "GL_QUADS"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawQuads; break; case GL_QUAD_STRIP: //LOG(1, glBegin, "GL_QUAD_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawQuadStrip; break; case GL_POLYGON: //LOG(1, glBegin, "GL_POLYGON"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawPolygon; break; case MGL_FLATFAN: //LOG(1, glBegin, "MGL_FLATFAN"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawFlatFan; break; default: //LOG(1, glBegin, "Error GL_INVALID_OPERATION"); GLFlagError (context, 1, GL_INVALID_OPERATION); break; } } else if(context->renderMode == GL_SELECT) { switch((int)mode) { case GL_POINTS: //LOG(1, glBegin, "GL_POINTS"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawPoints; break; case GL_LINES: //LOG(1, glBegin, "GL_LINES"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawLines; break; case GL_LINE_STRIP: //LOG(1, glBegin, "GL_LINE_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawLineStrip; break; case GL_LINE_LOOP: //LOG(1, glBegin, "GL_LINE_LOOP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawLineStrip; break; case GL_TRIANGLES: //LOG(1, glBegin, "GL_TRIANLES"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawTriangles; break; case GL_TRIANGLE_STRIP: //LOG(1, glBegin, "GL_TRIANGLE_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawTriangleStrip; break; case GL_TRIANGLE_FAN: //LOG(1, glBegin, "GL_TRIANGLE_FAN"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawTriangleFan; break; case GL_QUADS: //LOG(1, glBegin, "GL_QUADS"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawQuads; break; case GL_QUAD_STRIP: //LOG(1, glBegin, "GL_QUAD_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawQuadStrip; break; case GL_POLYGON: //LOG(1, glBegin, "GL_POLYGON"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawPolygon; break; case MGL_FLATFAN: //LOG(1, glBegin, "MGL_FLATFAN"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)s_DrawFlatFan; break; default: //LOG(1, glBegin, "Error GL_INVALID_OPERATION"); GLFlagError (context, 1, GL_INVALID_OPERATION); break; } } else { // GL_FEEDBACK mode not implemented yet GLFlagError (context, 1, GL_INVALID_OPERATION); } } void cgl_GLColor4f(struct GLContextIFace *Self, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { GLcontext context = GET_INSTANCE(Self); dprintf("called\n"); if(dl_IsDLActive(Self)){ dl_save_Color4f(Self, red, green, blue, alpha); if(!dl_CompileAndExecuteMode(Self)){ return; } } context->current.CurrentColor.r = CLAMPF(red); context->current.CurrentColor.g = CLAMPF(green); context->current.CurrentColor.b = CLAMPF(blue); context->current.CurrentColor.a = CLAMPF(alpha); dprintf("color: (%f, %f, %f, %f)\n", context->current.CurrentColor.r, context->current.CurrentColor.g, context->current.CurrentColor.b, context->current.CurrentColor.a); #ifdef MGL_USE_LIGHTING if (context->enable.ColorMaterial) light_UpdateColorMaterial(context); #endif // context->FrameCode ++; } #define VBUFF_SIZEINCR (1000 + (context->UseVertexResidue ? 1 : 0)) // Increase the buffer size by this // amount each time that it's necessary #define VBUFF_OVERFLOW 4 // Space reserved for additional vertices that are generated during clipping void cgl_GLVertex4f(struct GLContextIFace *Self, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_Vertex4f(Self, x, y, z, w); if(!dl_CompileAndExecuteMode(Self)){ return; } } // Check if there is enough space for the vertex (GL_Polygon is a special case) if(( context->CurrentPrimitive == GL_POLYGON && context->VertexBufferPointer >= context->VertexBufferSize / 2) || context->VertexBufferPointer >= context->VertexBufferSize - VBUFF_OVERFLOW) { GLenum primitiveType = context->CurrentPrimitive; GLuint residuePointer = 0, residueSize = 0; // We are about to overflow the buffer, either flush the buffer or extend it switch(primitiveType) { case GL_POINTS: // just flush cgl_GLEnd(Self); cgl_GLBegin(Self, primitiveType); goto CONTINUE_ADDVERTEX; break; case GL_LINES: residueSize = context->VertexBufferPointer % 2; residuePointer = context->VertexBufferPointer - residueSize; context->VertexBufferPointer = residuePointer; break; case GL_LINE_STRIP: residueSize = 1; residuePointer = context->VertexBufferPointer - 1; break; case GL_LINE_LOOP: { // Need to switch to rendering as a line strip to flush the buffer primitiveType = GL_LINE_STRIP; context->CurrentPrimitive = GL_LINE_STRIP; context->CurrentDraw = (DrawFn)s_DrawLineStrip; // Save the first vertex separately as it needs to be added at the end in // order to close the loop if(context->UseVertexResidue == GL_FALSE) { // Render the current line strip before we enable the residue cgl_GLEnd(Self); cgl_GLBegin(Self, primitiveType); context->VertexResidue = context->VertexBuffer[0]; context->UseVertexResidue = GL_TRUE; // Adjust the vertex buffer size so that there's always room context->VertexBufferSize--; } else { // Render the current line strip without the vertex residue context->UseVertexResidue = GL_FALSE; cgl_GLEnd(Self); cgl_GLBegin(Self, primitiveType); context->UseVertexResidue = GL_TRUE; } // Copy the last vertex too, in order to continue the loop residuePointer = context->VertexBufferPointer - 1; context->VertexBuffer[0] = context->VertexBuffer[residuePointer]; context->VertexBufferPointer = 1; goto CONTINUE_ADDVERTEX; } case GL_TRIANGLES: residueSize = context->VertexBufferPointer % 3; residuePointer = context->VertexBufferPointer - residueSize; context->VertexBufferPointer = residuePointer; break; case GL_TRIANGLE_STRIP: { // Try to enlarge the buffer first GLuint vertexBufferPointerTemp = context->VertexBufferPointer; if(MGLEnsureVertexBufferSize(context, context->VertexBufferSize + VBUFF_SIZEINCR)) { context->VertexBufferPointer = vertexBufferPointerTemp; goto CONTINUE_ADDVERTEX; } // Just copy the last two residueSize = 1; residuePointer = context->VertexBufferPointer - 1; break; } case GL_TRIANGLE_FAN: case MGL_FLATFAN: // A special case. We need to preserve the first and last vertices in order to // continue the fan residuePointer = context->VertexBufferPointer - 1; cgl_GLEnd(Self); cgl_GLBegin(Self, primitiveType); context->VertexBuffer[1] = context->VertexBuffer[residuePointer]; context->VertexBufferPointer = 2; goto CONTINUE_ADDVERTEX; break; case GL_QUADS: residueSize = context->VertexBufferPointer % 4; residuePointer = context->VertexBufferPointer - residueSize; context->VertexBufferPointer = residuePointer; break; case GL_QUAD_STRIP: { // Try to enlarge the buffer first GLuint vertexBufferPointerTemp = context->VertexBufferPointer; if(MGLEnsureVertexBufferSize(context, context->VertexBufferSize + VBUFF_SIZEINCR)) { context->VertexBufferPointer = vertexBufferPointerTemp; goto CONTINUE_ADDVERTEX; } // Just copy the last to vertices residueSize = 2 + context->VertexBufferPointer % 2; residuePointer = context->VertexBufferPointer - residueSize; context->VertexBufferPointer = residuePointer + 2; break; } case GL_POLYGON: { // Try to enlarge the buffer first GLuint vertexBufferPointerTemp = context->VertexBufferPointer; if(MGLEnsureVertexBufferSize(context, context->VertexBufferSize + VBUFF_SIZEINCR)) { context->VertexBufferPointer = vertexBufferPointerTemp; goto CONTINUE_ADDVERTEX; } // Special case, we need to preserve the first and last vertices in order to // continue the polygon residuePointer = context->VertexBufferPointer - 1; cgl_GLEnd(Self); cgl_GLBegin(Self, primitiveType); context->VertexBuffer[1] = context->VertexBuffer[residuePointer]; context->VertexBufferPointer = 2; goto CONTINUE_ADDVERTEX; break; } } // Flush the current buffer minus the residue cgl_GLEnd(Self); cgl_GLBegin(Self, primitiveType); // Copy the remaining vertices (the residue) to the start of the buffer memcpy(context->VertexBuffer, context->VertexBuffer + residuePointer, residueSize * sizeof(MGLVertex)); context->VertexBufferPointer += residueSize; } CONTINUE_ADDVERTEX: #define thisvertex context->VertexBuffer[context->VertexBufferPointer] thisvertex.object.x = x; thisvertex.object.y = y; thisvertex.object.z = z; thisvertex.object.w = w; int i; /* ** Current texture coordinates are s/t resp. This means ** that texture wrap occurs at 0 and 1, not at 0 and width/height. */ if (context->texture.MaxTextureUnit > -1) { for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] == GL_TRUE || context->enable.Texture1D[i] == GL_TRUE) { if (context->current.CurTexQValid[i] == GL_TRUE) { thisvertex.uvw[i].u = context->current.CurTexS[i] / context->current.CurTexQ[i]; thisvertex.uvw[i].v = context->current.CurTexT[i] / context->current.CurTexQ[i]; 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; } } } } thisvertex.r = context->current.CurrentColor.r; thisvertex.g = context->current.CurrentColor.g; thisvertex.b = context->current.CurrentColor.b; thisvertex.a = context->current.CurrentColor.a; thisvertex.Normal.x = context->current.CurrentNormal.x; thisvertex.Normal.y = context->current.CurrentNormal.y; thisvertex.Normal.z = context->current.CurrentNormal.z; thisvertex.outcode = 0; thisvertex.inview = GL_FALSE; if (context->fog.CurrentFogSource == GL_FOG_COORD) thisvertex.bf = context->current.CurrentFogDepth; else thisvertex.bf = z; context->VertexBufferPointer ++; #undef thisvertex } void cgl_GLNormal3f(struct GLContextIFace *Self, GLfloat x, GLfloat y, GLfloat z) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_Normal3f(Self, x, y, z); if(!dl_CompileAndExecuteMode(Self)){ return; } } context->current.CurrentNormal.x = x; context->current.CurrentNormal.y = y; context->current.CurrentNormal.z = z; // context->FrameCode ++; } void cgl_GLTexCoord2f(struct GLContextIFace *Self, GLfloat s, GLfloat t) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_TexCoord2f(Self, s, t); if(!dl_CompileAndExecuteMode(Self)){ return; } } context->current.CurTexS[context->texture.ActiveTexture] = s; context->current.CurTexT[context->texture.ActiveTexture] = t; context->current.CurTexQ[context->texture.ActiveTexture] = 1.0; context->current.CurTexQValid[context->texture.ActiveTexture] = GL_FALSE; // context->TexFrameCode ++; } void cgl_GLTexCoord4f(struct GLContextIFace *Self, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_TexCoord4f(Self, s, t, r, q); if(!dl_CompileAndExecuteMode(Self)){ return; } } context->current.CurTexS[context->texture.ActiveTexture] = s; context->current.CurTexT[context->texture.ActiveTexture] = t; context->current.CurTexQ[context->texture.ActiveTexture] = q; context->current.CurTexQValid[context->texture.ActiveTexture] = GL_TRUE; // context->TexFrameCode ++; } void cgl_GLMultiTexCoord2f(struct GLContextIFace *Self, GLenum stage, GLfloat s, GLfloat t) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_MultiTexCoord2f(Self, stage, s, t); if(!dl_CompileAndExecuteMode(Self)){ return; } } stage -= GL_TEXTURE0; if (stage < context->NumTextureUnits) { context->current.CurTexS[stage] = s; context->current.CurTexT[stage] = t; context->current.CurTexQ[stage] = 1.0; context->current.CurTexQValid[stage] = GL_FALSE; // context->TexFrameCode ++; } } void cgl_GLMultiTexCoord4f(struct GLContextIFace *Self, GLenum stage, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_MultiTexCoord4f(Self, stage, s, t, r, q); if(!dl_CompileAndExecuteMode(Self)){ return; } } stage -= GL_TEXTURE0; if (stage < context->NumTextureUnits) { context->current.CurTexS[stage] = s; context->current.CurTexT[stage] = t; context->current.CurTexQ[stage] = q; context->current.CurTexQValid[stage] = GL_TRUE; // context->TexFrameCode ++; } } void cgl_GLDepthRange(struct GLContextIFace *Self, GLclampd n, GLclampd f) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_DepthRange(Self, n, f); if(!dl_CompileAndExecuteMode(Self)){ return; } } context->viewport.near = n; context->viewport.far = f; context->sz = (f-n)*0.5; context->az = (n+f)*0.5; } void cgl_GLViewport(struct GLContextIFace *Self, GLint x, GLint y, GLsizei w, GLsizei h) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_Viewport(Self, x, y, w, h); if(!dl_CompileAndExecuteMode(Self)){ return; } } context->viewport.x = x; context->viewport.y = y; context->viewport.w = w; context->viewport.h = h; context->ax = (double)x + (double)w*0.5; context->ay = (double)(buf_GetBufferHeight(context, context->drawBuffer) - y) - (h * 0.5); context->sx = (double)w * 0.5; context->sy = (double)h * 0.5; } void cgl_GLEnd(struct GLContextIFace *Self) { GLcontext context = GET_INSTANCE(Self); if(dl_IsDLActive(Self)){ dl_save_End(Self); if(!dl_CompileAndExecuteMode(Self)){ return; } } if(context->UseVertexResidue) { // Restore the true vertex buffer size (it was decremented when the residue was set) context->VertexBufferSize++; // Try to enlarge the buffer if necessary to fit the residue in if(context->VertexBufferPointer >= context->VertexBufferSize) { // Just ignore the residue. This should never happen anyway as we've adjusted the // vertex buffer size to compensate for the extra vertex dprintf("INTERNAL ERROR: No room in the vertex buffer to add GL_LINE_LOOP's " "residual vertex. This should not happen.\n"); } else { context->VertexBuffer[context->VertexBufferPointer] = context->VertexResidue; context->VertexBufferPointer++; } context->UseVertexResidue = GL_FALSE; } 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); } IWarp3D->W3D_InterleavedArray(context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED); context->CurrentDraw(context); context->CurrentPrimitive = GL_BASE; #ifdef MGL_USE_LIGHTING /* This is useful to get the color material back after evaulator use */ if (context->enable.ColorMaterial) light_UpdateColorMaterial(context); #endif context->fbDirty = GL_TRUE; }