/* * $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 "util.h" 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) { #ifdef MGL_TABOR return (a>0.0f) ? ((a<1.0f) ? a : 1.0f) : 0.0f; #else 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; #endif } void cgl_GLBegin(struct GLContextIFace *Self, GLenum mode) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(Begin(Self, mode)) 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); DL_CHECK(Color4f(Self, red, green, blue, alpha)) 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); DL_CHECK(Vertex4f(Self, x, y, z, w)) // 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: THIS_VERTEX.object.x = x; THIS_VERTEX.object.y = y; THIS_VERTEX.object.z = z; THIS_VERTEX.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) { THIS_VERTEX.uvw[i].u = context->current.CurTexS[i] / context->current.CurTexQ[i]; THIS_VERTEX.uvw[i].v = context->current.CurTexT[i] / context->current.CurTexQ[i]; THIS_VERTEX.uvw[i].w = context->current.CurTexQ[i]; THIS_VERTEX.rhw_valid[i] = GL_TRUE; } else { THIS_VERTEX.uvw[i].u = context->current.CurTexS[i]; THIS_VERTEX.uvw[i].v = context->current.CurTexT[i]; THIS_VERTEX.uvw[i].w = 1.0; THIS_VERTEX.rhw_valid[i] = GL_FALSE; } } } } THIS_VERTEX.r = context->current.CurrentColor.r; THIS_VERTEX.g = context->current.CurrentColor.g; THIS_VERTEX.b = context->current.CurrentColor.b; THIS_VERTEX.a = context->current.CurrentColor.a; THIS_VERTEX.Normal.x = context->current.CurrentNormal.x; THIS_VERTEX.Normal.y = context->current.CurrentNormal.y; THIS_VERTEX.Normal.z = context->current.CurrentNormal.z; THIS_VERTEX.outcode = 0; THIS_VERTEX.inview = GL_FALSE; if (context->fog.CurrentFogSource == GL_FOG_COORD) { THIS_VERTEX.bf = context->current.CurrentFogDepth; } else { THIS_VERTEX.bf = z; } context->VertexBufferPointer ++; } void cgl_GLNormal3f(struct GLContextIFace *Self, GLfloat x, GLfloat y, GLfloat z) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(Normal3f(Self, x, y, z)) 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); DL_CHECK(TexCoord2f(Self, s, t)) 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); DL_CHECK(TexCoord4f(Self, s, t, r, q)) 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); DL_CHECK(MultiTexCoord2f(Self, stage, s, t)) 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); DL_CHECK(MultiTexCoord4f(Self, stage, s, t, r, q)) 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); DL_CHECK(DepthRange(Self, n, f)) 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); DL_CHECK(Viewport(Self, x, y, w, h)) 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); DL_CHECK(End(Self)) 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 ); if ((uint32)context->CurrentDraw > 4096UL) { context->CurrentDraw(context); } else { dprintf("WTF? context->CurrentDraw = %p\n", context->CurrentDraw); } 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; } void cgl_GLNormal3fv(struct GLContextIFace *Self, const GLfloat *xyz) { cgl_GLNormal3f(Self,xyz[0],xyz[1],xyz[2]); } void cgl_GLVertex4fv(struct GLContextIFace *Self, const GLfloat *xyzw) { cgl_GLVertex4f(Self,xyzw[0],xyzw[1],xyzw[2],xyzw[3]); } void cgl_GLVertex3fv(struct GLContextIFace *Self, const GLfloat *xyz) { cgl_GLVertex4f(Self,xyz[0],xyz[1],xyz[2],1.0f); }