/* * $Id$ * * $Date: 2006-02-21 12:26:08 -0359 * $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 "smartlock.h" #include "sysinc.h" #include #include #include "hclip.h" #include #include "altivec_math.h" extern BOOL useVectorUnit; #ifdef DISABLE_TRANSFORMATION #warning "Compiling without transformation pipeline. Only flat geometry supported" #endif static char rcsid[] UNUSED = "$Id$"; #define DUMP_VERTEX(vert) #define DUMP_VERTEX2(vert) /* * If this macro returns TRUE, the polygon modes are not FILL for both front- * and backfacing polygons, and hence require special treatment. */ #define NEED_SPECIAL_FILL (context->polygon.PolygonModeFront != GL_FILL \ || context->polygon.PolygonModeBack != GL_FILL) GLboolean hc_GetFrontFacing(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *c, GLuint outcode); void d_DrawPoly(GLcontext context, MGLPolygon *poly); void dh_DrawPolyFF(GLcontext context, MGLPolygon *poly, DrawPolyFlags_t flags); void d_DrawPolyExt(GLcontext context, MGLPolygon *poly); void d_DrawPoints (GLcontext); void d_DrawLines (GLcontext); void d_DrawLineStrip (GLcontext); void d_DrawTriangles (GLcontext); void d_DrawTriangleFan (GLcontext); void d_DrawTriangleStrip (GLcontext); void d_DrawQuads (GLcontext); void d_DrawPolygon (GLcontext); void d_DrawFlatFan (GLcontext); void d_DrawQuadStrip (GLcontext); INLINE void v_ApplyMatrixElCheapo(GLcontext context, Matrix *pA, int vnum); INLINE GLvoid v_Transform(GLcontext context); INLINE void v_ToScreen(GLcontext context, int i); void m_CombineMatrices(GLcontext context); extern void m_BuildInverted(GLcontext context); extern void hc_ClipAndDrawLine(GLcontext context, MGLPolygon *poly, GLuint or_codes); extern void light_LightVertex(GLcontext context, GLuint vertex, GLfloat area); extern void hc_ClipLine(GLcontext context, MGLPolygon *poly, GLuint or_codes, uint32 *out1, uint32 *out2); extern void EstablishCullState(GLcontext context); #define min(x,y) (x) < (y) ? (x) : (y) #define max(x,y) (x) > (y) ? (x) : (y) //extern void hc_ClipLine(GLcontext context, MGLPolygon *poly, GLuint or_codes, // uint32 *out1, uint32 *out2); extern GLboolean hc_LineClip(GLcontext context, uint32 pts[2]); /* 3-component vector math */ #define VEC_NORM3(v) \ { \ GLdouble recM = fast_reciprocal_sqrt(v.x*v.x + v.y*v.y + v.z*v.z); \ v.x *= recM; \ v.y *= recM; \ v.z *= recM; \ } void SetFlatColor(GLcontext context, GLfloat r, GLfloat g, GLfloat b, GLfloat a) { W3D_Color col; col.r = r; col.g = g; col.b = b; col.a = a; IWarp3D->W3D_SetCurrentColor(context->w3dContext, &col); } INLINE GLint v_GetFillMode(GLcontext context, GLboolean isFrontFace) { if (isFrontFace) return context->polygon.PolygonModeFront; else return context->polygon.PolygonModeBack; } // doesn't work if the first three points are colinear GLint v_GetPolyFillMode(GLcontext context, MGLPolygon *poly) { if (poly->numverts < 3) return GL_FILL; GLboolean isFrontFace = hc_GetFrontFacing(context, &(context->VertexBuffer[poly->verts[0]]), &(context->VertexBuffer[poly->verts[1]]), &(context->VertexBuffer[poly->verts[2]]),0); return v_GetFillMode(context, isFrontFace); } INLINE GLboolean v_CheckTriArea(GLfloat threshold, W3D_Vertex *v1, W3D_Vertex *v2, W3D_Vertex *v3) { GLfloat x1 = v2->x - v1->x; GLfloat y1 = v2->y - v1->y; GLfloat x2 = v3->x - v1->x; GLfloat y2 = v3->y - v1->y; GLfloat area = -(y2*x1 - x2*y1); if (fast_fabs(area) > threshold) return GL_TRUE; else return GL_FALSE; } INLINE GLfloat v_GetTriArea(GLcontext context, int _v1, int _v2, int _v3) { #define v1 context->VertexBuffer[_v1] #define v2 context->VertexBuffer[_v2] #define v3 context->VertexBuffer[_v3] GLfloat x1 = v2.x - v1.x; GLfloat y1 = v2.y - v1.y; GLfloat x2 = v3.x - v1.x; GLfloat y2 = v3.y - v1.y; GLfloat area = y2*x1 - x2*y1; return -area; #undef v1 #undef v2 #undef v3 #undef v4 } INLINE GLboolean v_CheckQuadArea(GLfloat threshold, W3D_Vertex *v1, W3D_Vertex *v2, W3D_Vertex *v3, W3D_Vertex *v4) { GLfloat area = (v1->x*v2->y - v2->y*v1->x) - (v2->x*v3->y - v3->x*v2->y) - (v3->x*v4->y - v4->x*v3->y) - (v4->x*v1->y - v1->x*v4->y); if (fast_fabs(area) > threshold) return GL_TRUE; else return GL_FALSE; } INLINE GLfloat v_GetQuadArea(GLcontext context, int _v1, int _v2, int _v3, int _v4) { #define v1 context->VertexBuffer[_v1] #define v2 context->VertexBuffer[_v2] #define v3 context->VertexBuffer[_v3] #define v4 context->VertexBuffer[_v4] return (v1.x*v2.y - v2.y*v1.x) - (v2.x*v3.y - v3.x*v2.y) - (v3.x*v4.y - v4.x*v3.y) - (v4.x*v1.y - v1.x*v4.y); #undef v1 #undef v2 #undef v3 #undef v4 } inline GLfloat dh_AreaSign(GLcontext context, MGLPolygon *poly) { int i,j; GLfloat area=0.0; #define x(i) (context->VertexBuffer[poly->verts[i]].x) #define y(i) (context->VertexBuffer[poly->verts[i]].y) for (i=0; inumverts; i++) { j=(i+1)%(poly->numverts); area += (x(i)*y(j) - x(j)*y(i)); } #undef x #undef y // Since our Y coordinates are inverted (i.e. Y = 0 is the top not bottom) // we need to use the negative area here return -area; } void v_GenEyeCoords(GLcontext context) { int vertex; #define a(x) (CurrentMV->v[OF_##x]) #define b(x) (CurrentP->v[OF_##x]) #define eyex (context->VertexBuffer[vertex].eye.x) #define eyey (context->VertexBuffer[vertex].eye.y) #define eyez (context->VertexBuffer[vertex].eye.z) #define eyew (context->VertexBuffer[vertex].eye.w) #define verx (context->VertexBuffer[vertex].object.x) #define very (context->VertexBuffer[vertex].object.y) #define verz (context->VertexBuffer[vertex].object.z) #define verw (context->VertexBuffer[vertex].object.w) for (vertex = 0; vertex < context->VertexBufferPointer; vertex++) { eyex = a(11)*verx + a(12)*very + a(13)*verz + a(14)*verw; eyey = a(21)*verx + a(22)*very + a(23)*verz + a(24)*verw; eyez = a(31)*verx + a(32)*very + a(33)*verz + a(34)*verw; eyew = a(41)*verx + a(42)*very + a(43)*verz + a(44)*verw; if (eyew != 1.0) { float one_over_eyew = 1.0/eyew; eyex *= one_over_eyew; eyey *= one_over_eyew; eyez *= one_over_eyew; eyew = 1.0; } } #undef a #undef b #undef eyex #undef eyey #undef eyez #undef eyew #undef verx #undef very #undef verz #undef verw #define ver(c) (context->VertexBuffer[vertex].Normal.c) #define a(x) (context->InvRot[x]) #define nx (context->VertexBuffer[vertex].EyeNormal.x) #define ny (context->VertexBuffer[vertex].EyeNormal.y) #define nz (context->VertexBuffer[vertex].EyeNormal.z) if (context->NeedEyeNormal) { if (context->InvRotValid == GL_FALSE) m_BuildInverted(context); for (vertex = 0; vertex < context->VertexBufferPointer; vertex++) { // InvRot is row-major nx = ver(x)*a(0) + ver(y)*a(3) + ver(z)*a(6); ny = ver(x)*a(1) + ver(y)*a(4) + ver(z)*a(7); nz = ver(x)*a(2) + ver(y)*a(5) + ver(z)*a(8); if(context->Normalize){ VEC_NORM3(context->VertexBuffer[vertex].EyeNormal); } } } #undef ver #undef a #undef nx #undef ny #undef nz } /* ** This computationally intensive piece of code generates coordinates ** for the reflective image used in spherical environment mapping. ** This is a good place for optimizations. ** After generation, transforms into the clipping space... ** ** Note that this is after the book. It is probably a big time-eater. ** ** (Turned out not to be so time intensive after all...) */ void v_GenTexCoords(GLcontext context, int vertex) { float u[4]; float recUL; float nx,ny,nz; float nu; float rx = 0.0, ry = 0.0, rz = 0.0; float m = 0.0; float rw = 0.0; //surgeon int i; BOOL needR = FALSE; BOOL needM = FALSE; for (i = 0; i <= context->texture.MaxTextureUnit; i++) { /* If either (or both) gen's are enabled and either SPHERE_MAP ot * REFLECTION_MAP, compute r and mfirst */ if (context->enable.TexGenS[i]) { if (context->texture.TexGenS[i].needR) needR = TRUE; if (context->texture.TexGenS[i].needM) needM = TRUE; } if (context->enable.TexGenT[i]) { if (context->texture.TexGenT[i].needR) needR = TRUE; if (context->texture.TexGenT[i].needM) needM = TRUE; } } if (needR) { u[0] = context->VertexBuffer[vertex].eye.x; u[1] = context->VertexBuffer[vertex].eye.y; u[2] = context->VertexBuffer[vertex].eye.z; nx = context->VertexBuffer[vertex].EyeNormal.x; ny = context->VertexBuffer[vertex].EyeNormal.y; nz = context->VertexBuffer[vertex].EyeNormal.z; // nomalize unit vector float magSq = (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]); if (magSq == 0.f) return; recUL = (float)fast_reciprocal_sqrt(magSq); u[0] *= recUL; u[1] *= recUL; u[2] *= recUL; nu = nx*u[0] + ny*u[1]+nz*u[2]; nu *= 2.f; rx = u[0] - nx*nu; ry = u[1] - ny*nu; rz = u[2] - nz*nu; rw = rz+1.f; //surgeon } if (needM) m = 0.5f * (float)fast_reciprocal_sqrt((rx*rx + ry*ry + rw*rw)); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.TexGenS[i] == GL_TRUE) { switch (context->texture.TexGenS[i].mode) { case GL_SPHERE_MAP: context->VertexBuffer[vertex].uvw[i].u = rx * m + 0.5; break; case GL_REFLECTION_MAP: context->VertexBuffer[vertex].uvw[i].u = rx; break; case GL_OBJECT_LINEAR: context->VertexBuffer[vertex].uvw[i].u = context->VertexBuffer[vertex].object.x * context->texture.TexGenS[i].objectPlane[0] + context->VertexBuffer[vertex].object.y * context->texture.TexGenS[i].objectPlane[1] + context->VertexBuffer[vertex].object.z * context->texture.TexGenS[i].objectPlane[2] + context->VertexBuffer[vertex].object.w * context->texture.TexGenS[i].objectPlane[3]; break; case GL_EYE_LINEAR: context->VertexBuffer[vertex].uvw[i].u = context->VertexBuffer[vertex].object.x * context->texture.TexGenS[i].eyePlane[0] + context->VertexBuffer[vertex].object.y * context->texture.TexGenS[i].eyePlane[1] + context->VertexBuffer[vertex].object.z * context->texture.TexGenS[i].eyePlane[2] + context->VertexBuffer[vertex].object.w * context->texture.TexGenS[i].eyePlane[3]; break; case GL_NORMAL_MAP: context->VertexBuffer[vertex].uvw[i].u = context->VertexBuffer[vertex].EyeNormal.x; break; } } if (context->enable.TexGenT[i] == GL_TRUE) { switch (context->texture.TexGenT[i].mode) { case GL_SPHERE_MAP: context->VertexBuffer[vertex].uvw[i].v = ry * m + 0.5; break; case GL_REFLECTION_MAP: context->VertexBuffer[vertex].uvw[i].v = ry; break; case GL_OBJECT_LINEAR: context->VertexBuffer[vertex].uvw[i].v = context->VertexBuffer[vertex].object.x * context->texture.TexGenT[i].objectPlane[0] + context->VertexBuffer[vertex].object.y * context->texture.TexGenT[i].objectPlane[1] + context->VertexBuffer[vertex].object.z * context->texture.TexGenT[i].objectPlane[2] + context->VertexBuffer[vertex].object.w * context->texture.TexGenT[i].objectPlane[3]; break; case GL_EYE_LINEAR: context->VertexBuffer[vertex].uvw[i].v = context->VertexBuffer[vertex].object.x * context->texture.TexGenT[i].eyePlane[0] + context->VertexBuffer[vertex].object.y * context->texture.TexGenT[i].eyePlane[1] + context->VertexBuffer[vertex].object.z * context->texture.TexGenT[i].eyePlane[2] + context->VertexBuffer[vertex].object.w * context->texture.TexGenT[i].eyePlane[3]; break; case GL_NORMAL_MAP: context->VertexBuffer[vertex].uvw[i].v = context->VertexBuffer[vertex].EyeNormal.y; break; } } } } INLINE void v_Transform(GLcontext context) { int i, tmu; 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); float a41 = a(41); float a42 = a(42); float a44 = a(44); register MGLVertex *vx = &context->VertexBuffer[0]; float u, v, w; for (i = 0; i < context->VertexBufferPointer; i++) { u = vx->uvw[tmu].u; v = vx->uvw[tmu].v; w = vx->uvw[tmu].w; if (vx->rhw_valid == GL_FALSE) { vx->uvw[tmu].u = a11*u + a12*v + a14; vx->uvw[tmu].v = a21*u + a22*v + a24; } 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; } ++vx; } #undef a } } if (useVectorUnit) { v_TransformToClip(context); } else 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; float x, y, z, w; MGLVertex *vf = context->VertexBuffer; register MGLVertex *v = &vf[0]; for (i = 0; i < counter; i++) { x = v->object.x; y = v->object.y; z = v->object.z; 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; ++v; } #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; float x, y, z; MGLVertex *vf = context->VertexBuffer; register MGLVertex *v = &vf[0]; for (i=0; iobject.x; y = v->object.y; 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; ++v; x = v->object.x; y = v->object.y; 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; ++v; } if(i > counter) { // Have one more to go x = v->object.x; y = v->object.y; 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; } #undef a } } #define CLAMP(x,a,b) ( (x) < (a) ? (a) \ : (x) > (b) ? (b) \ : (x) ) #define ABS(x) ((x) < 0.0f ? -(x) : (x)) INLINE void v_ToScreen(GLcontext context, int i) { float w; int tmu; float fogDepth = 0.0f; float c = 0.0f; w = 1.0 / context->VertexBuffer[i].clip.w; context->VertexBuffer[i].x = context->ax + context->VertexBuffer[i].clip.x * w * context->sx; context->VertexBuffer[i].y = context->ay - context->VertexBuffer[i].clip.y * w * context->sy; context->VertexBuffer[i].z = context->az + context->VertexBuffer[i].clip.z * w * context->sz; if (context->enable.ZOffset == GL_TRUE) context->VertexBuffer[i].z += (W3D_Float)context->depth_buffer.ZOffset; /* Set texture w if it wasn't given in glTexCoord */ for (tmu = 0; tmu <= context->texture.MaxTextureUnit; tmu++) { if (context->VertexBuffer[i].rhw_valid[tmu] == GL_FALSE) context->VertexBuffer[i].uvw[tmu].w = w; } if (context->UseZFog == GL_FALSE) { if (context->fog.CurrentFogSource == GL_FRAGMENT_DEPTH) context->VertexBuffer[i].fogdepth = w; else context->VertexBuffer[i].fogdepth = 1/(context->VertexBuffer[i].bf * w * context->sz); } else { if (context->InvRotValid == GL_FALSE) m_BuildInverted(context); GLfloat depth = 0.0f; if (context->fog.CurrentFogSource == GL_FRAGMENT_DEPTH) { if (!context->NeedEye) { #define a(x) (CurrentMV->v[OF_##x]) #define verx (context->VertexBuffer[i].object.x) #define very (context->VertexBuffer[i].object.y) #define verz (context->VertexBuffer[i].object.z) #define verw (context->VertexBuffer[i].object.w) depth = a(31)*verx + a(32)*very + a(33)*verz + a(34)*verw; GLfloat eyew = a(41)*verx + a(42)*very + a(43)*verz + a(44)*verw; if (eyew != 1.0) depth /= eyew; #undef verx #undef very #undef verz #undef verw #undef a } else { depth = context->VertexBuffer[i].eye.z; } } else { dprintf("FOG_COORD not handled by %s yet\n", __func__); // handle FOG_COORD } // FIXME: Handle that via a lookup table or similar switch(context->fog.FogMode) { case GL_LINEAR: context->VertexBuffer[i].fogdepth = (context->fog.FogEnd - depth) / (context->fog.FogEnd - context->fog.FogStart); fogDepth = (context->fog.FogEnd - ABS(depth)) / (context->fog.FogEnd - context->fog.FogStart); break; case GL_EXP: c = context->fog.FogDensity * ABS(depth); fogDepth = exp(-c); break; case GL_EXP2: c = context->fog.FogDensity * ABS(depth); fogDepth = exp(-(c*c)); break; } context->VertexBuffer[i].fogdepth = CLAMP(fogDepth, 0.0f, 1.0f); } } #ifndef max #define max(x,y) (x) > (y) ? (x) : (y) #endif GLfloat v_PolygonOffset(GLcontext context, int v1, int v2, int v3) { #define vert(i) context->VertexBuffer[i] GLfloat dx1 = vert(v1).x - vert(v3).x; GLfloat dx2 = vert(v2).x - vert(v3).x; GLfloat dy1 = vert(v1).y - vert(v3).y; GLfloat dy2 = vert(v2).y - vert(v3).y; GLfloat dz1 = vert(v1).z - vert(v3).z; GLfloat dz2 = vert(v2).z - vert(v3).z; GLfloat iarea = 1.0 / (dx1*dy2 - dx2*dy1); GLfloat dxdz = iarea * (dy1*dz2 - dz1*dy2); GLfloat dydz = iarea * (dz1*dx2 - dx1*dz2); if (dxdz < 0) dxdz = -dxdz; if (dydz < 0) dydz = -dydz; return context->polygon.PolygonOffsetUnits*context->DepthBufferUnit + context->polygon.PolygonOffsetFactor * (max(dxdz, dydz)); } GLfloat v_PolygonOffsetArea(GLcontext context, int v1, int v2, int v3, GLfloat iarea) { #define vert(i) context->VertexBuffer[i] GLfloat dx1 = vert(v1).x - vert(v3).x; GLfloat dx2 = vert(v2).x - vert(v3).x; GLfloat dy1 = vert(v1).y - vert(v3).y; GLfloat dy2 = vert(v2).y - vert(v3).y; GLfloat dz1 = vert(v1).z - vert(v3).z; GLfloat dz2 = vert(v2).z - vert(v3).z; GLfloat dxdz = iarea * (dy1*dz2 - dz1*dy2); GLfloat dydz = iarea * (dz1*dx2 - dx1*dz2); if (dxdz < 0) dxdz = -dxdz; if (dydz < 0) dydz = -dydz; return context->polygon.PolygonOffsetUnits*context->DepthBufferUnit + context->polygon.PolygonOffsetFactor * (max(dxdz, dydz)); } void d_ClipAndDrawPolyPoint(GLcontext context, MGLPolygon *poly, uint32 or_code) { dprintf("called\n"); uint32 *idx = (uint32 *)context->IndexBuffer; uint32 num = 0; for (int i=0; inumverts; i++) { if (context->VertexBuffer[poly->verts[i]].outcode == 0) { *idx++ = poly->verts[i]; num++; v_ToScreen(context, poly->verts[i]); } } if (num != 0) // Anything left after clipping? { #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif // Draw indexed, some points are off IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_POINTS, W3D_INDEX_ULONG, num, context->IndexBuffer); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } } void d_ClipAndDrawPolyLine(GLcontext context, MGLPolygon *poly, uint32 or_code) { dprintf("called\n"); for (int i = 0; i< poly->numverts; i++) { v_ToScreen(context, poly->verts[i]); } int cur = 0; int prev = poly->numverts-1; int i = poly->numverts; #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. while (i) { #if 1 uint32 pts[2]; // Draw a line between prev and next pts[0] = poly->verts[prev]; pts[1] = poly->verts[cur]; if (hc_LineClip(context, pts)) { v_ToScreen(context, pts[0]); v_ToScreen(context, pts[1]); IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_LINES, W3D_INDEX_ULONG, 2, pts); } #else MGLPolygon p; GLuint or_code = context->VertexBuffer[poly->verts[prev]].outcode | context->VertexBuffer[poly->verts[cur]].outcode; p.numverts = 2; p.verts[0] = poly->verts[prev]; p.verts[1] = poly->verts[cur]; hc_ClipAndDrawLine(context, &p, or_code); #endif --i; prev = cur; cur++; context->VertexBufferPointer = vertexPointerTemp; } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void d_ClipAndDrawPoly(GLcontext context, MGLPolygon *poly, uint32 or_code, DrawPolyFlags_t flags) { #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif hc_ClipAndDrawPoly(context, poly, or_code, flags); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void d_ClipAndDrawPolyWithFill(GLcontext context, MGLPolygon *poly, uint32 or_code, GLuint fillMode, DrawPolyFlags_t flags) { dprintf("called\n"); switch(fillMode) { case GL_POINT: d_ClipAndDrawPolyPoint(context, poly, or_code); break; case GL_LINE: d_ClipAndDrawPolyLine(context, poly, or_code); break; case GL_FILL: d_ClipAndDrawPoly(context, poly, or_code, flags); break; } } void d_DrawPoints(GLcontext context) { int i; uint32 *idx = (uint32 *)context->IndexBuffer; uint32 num = 0; dprintf("called\n"); v_Transform(context); for (i=0; iVertexBufferPointer; i++) { /* First of all, code the point and see if it is inside */ hc_CodePoint(context, &(context->VertexBuffer[i])); if (context->VertexBuffer[i].outcode == 0) { /* Any point inside the clip volume is added to the index array */ *idx++ = i; num++; v_ToScreen(context, i); } } #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif if (num != 0) // Anything left after clipping? { if(context->lighting.ShadeModel == GL_FLAT) { /* temp enable gouroud to get so color is not ignore for points in GL_FLAT */ IWarp3D->W3D_SetState(context->w3dContext, W3D_GOURAUD, W3D_ENABLE); } if (num < context->VertexBufferPointer - 1) { // Draw indexed, some points are off IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_POINTS, W3D_INDEX_ULONG, num, context->IndexBuffer); } else { // Draw in one go, all of them are onscreen IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_POINTS, 0, num); } if(context->lighting.ShadeModel == GL_FLAT) { IWarp3D->W3D_SetState(context->w3dContext, W3D_GOURAUD, W3D_DISABLE); } } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void d_DrawLines(GLcontext context) { /* FIXME: Implement them in the driver, or do a replacement here */ int i; // W3D_Line lin; GLuint or_code, and_code; ULONG error; v_Transform(context); dprintf("called\n"); #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. GLuint array_size = 0; GLuint array_start = 0; for (i=0; iVertexBufferPointer; i+=2) { hc_CodePoint(context, &(context->VertexBuffer[i])); hc_CodePoint(context, &(context->VertexBuffer[i+1])); or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode; if (and_code) { if(array_size > 0 && (context->lighting.ShadeModel == GL_SMOOTH) ) { error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_LINES, array_start, array_size); array_size=0; } continue; } if (or_code == 0) { v_ToScreen(context, i); v_ToScreen(context, i+1); if (context->enable.Lighting) { light_LightVertex(context, i, 1); light_LightVertex(context, i+1, 1); } if(context->lighting.ShadeModel == GL_FLAT) { /* Flat mode do one by one */ #if 0 lin.v1.x = context->VertexBuffer[i+0].x; lin.v1.y = context->VertexBuffer[i+0].y; lin.v1.z = context->VertexBuffer[i+0].z; lin.v1.w = context->VertexBuffer[i+0].uvw[0].w; lin.v1.color.r = context->VertexBuffer[i+0].r; lin.v1.color.g = context->VertexBuffer[i+0].g; lin.v1.color.b = context->VertexBuffer[i+0].b; lin.v1.color.a = context->VertexBuffer[i+0].a; lin.v2.x = context->VertexBuffer[i+1].x; lin.v2.y = context->VertexBuffer[i+1].y; lin.v2.z = context->VertexBuffer[i+1].z; lin.v2.w = context->VertexBuffer[i+1].uvw[0].w; lin.v2.color.r = context->VertexBuffer[i+1].r; lin.v2.color.g = context->VertexBuffer[i+1].g; lin.v2.color.b = context->VertexBuffer[i+1].b; lin.v2.color.a = context->VertexBuffer[i+1].a; lin.tex = 0; //context->w3dTexBuffer[context->CurrentBinding]; lin.st_pattern = 0; lin.st_enable = 0; lin.st_factor = 1; lin.linewidth = context->LineWidth; error = IWarp3D->W3D_DrawLine(context->w3dContext, &lin); #else if(context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[i].r, context->VertexBuffer[i].g, context->VertexBuffer[i].b, context->VertexBuffer[i].a); } error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_LINES, i, 2); #endif } else { /* smooth mode so 'add' to array */ if(array_size == 0) array_start = i; array_size += 2; } } else { if(array_size > 0 && (context->lighting.ShadeModel == GL_SMOOTH)) { /* render any pending */ error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_LINES, array_start, array_size); array_size=0; } static MGLPolygon poly; poly.numverts = 2; poly.verts[0] = i; poly.verts[1] = i+1; hc_ClipAndDrawLine(context, &poly, or_code); context->VertexBufferPointer = vertexPointerTemp; } } if(array_size > 0 && (context->lighting.ShadeModel == GL_SMOOTH)) { /* render any pending */ error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_LINES, array_start, array_size); array_size=0; } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void dh_DrawLine(GLcontext context, MGLPolygon *poly) { /* FIXME: Implement in driver, or replace */ ULONG error; // static W3D_Line lin; dprintf("called\n"); v_ToScreen(context, poly->verts[0]); v_ToScreen(context, poly->verts[1]); if (context->enable.Lighting) { light_LightVertex(context, 0, 1); light_LightVertex(context, 1, 1); } #if 0 lin.v1.x = context->VertexBuffer[poly->verts[0]].x; lin.v1.y = context->VertexBuffer[poly->verts[0]].y; lin.v1.z = context->VertexBuffer[poly->verts[0]].z; lin.v1.w = context->VertexBuffer[poly->verts[0]].uvw[0].w; lin.v1.color.r = context->VertexBuffer[0].r; lin.v1.color.g = context->VertexBuffer[0].g; lin.v1.color.b = context->VertexBuffer[0].b; lin.v1.color.a = context->VertexBuffer[0].a; lin.v2.x = context->VertexBuffer[poly->verts[1]].x; lin.v2.y = context->VertexBuffer[poly->verts[1]].y; lin.v2.z = context->VertexBuffer[poly->verts[1]].z; lin.v2.w = context->VertexBuffer[poly->verts[1]].uvw[0].w; lin.v2.color.r = context->VertexBuffer[1].r; lin.v2.color.g = context->VertexBuffer[1].g; lin.v2.color.b = context->VertexBuffer[1].b; lin.v2.color.a = context->VertexBuffer[1].a; lin.tex = 0; lin.st_pattern = 0; lin.st_enable = 0; lin.st_factor = 1; lin.linewidth = context->LineWidth; error = IWarp3D->W3D_DrawLine(context->w3dContext, &lin); #else if(context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[poly->verts[0]].r, context->VertexBuffer[poly->verts[0]].g, context->VertexBuffer[poly->verts[0]].b, context->VertexBuffer[poly->verts[0]].a); } error = IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_LINES, W3D_INDEX_ULONG, 2, poly->verts); #endif } #define NEXT_IDX(a) (((a)+1)%context->VertexBufferPointer) #define PREV_IDX(a) ((a) == 0?context->VertexBufferPointer-1:(a)-1) #define IS_INSIDE(a) ((a) == 0) #define IS_OUTSIDE(a) ((a) != 0) #ifndef MAX #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #endif #ifndef MIN #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) #endif void d_DrawLineStrip(GLcontext context) { GLuint or_code, and_code; ULONG error; v_Transform(context); dprintf("called\n"); or_code = 0; and_code = 0; for (int i=0; iVertexBufferPointer; i++) { hc_CodePoint(context, &(context->VertexBuffer[i])); or_code |= context->VertexBuffer[i+0].outcode; and_code &= context->VertexBuffer[i+0].outcode; } if (and_code) return; if (or_code == 0) { // nice case - everything is on-screen uint32 prim = W3D_PRIMITIVE_LINESTRIP; if (context->CurrentPrimitive == GL_LINE_LOOP) prim = W3D_PRIMITIVE_LINELOOP; for (int i = 0; i < context->VertexBufferPointer; i++) v_ToScreen(context, i); #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif error = IWarp3D->W3D_DrawArray(context->w3dContext, prim, 0, context->VertexBufferPointer); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } else { /* * If there is at least one vertex outside the screen, we need to draw * the whole loop/strip as a series of line strips. We start at the * first vertex (or the last vertex if it is a loop) and move along * the lines of the strip, adding points to the index array as we * go. */ int count = 0; // Number of points in the current loop. int vtxcount = 1; // total number of vertices processed (always start with at least one processed) int currentIndex; int primSize = context->VertexBufferPointer; if (context->CurrentPrimitive == GL_LINE_LOOP) { currentIndex = primSize-1; vtxcount--; // Need to process one more vertex in order to close the loop } else { currentIndex = 0; } /* * If the starting point is on-screen, we output it prior to the * inner loop, because we will always add endpoints of the line. */ if (context->VertexBuffer[currentIndex].outcode == 0) { context->IndexBuffer[count] = currentIndex; v_ToScreen(context, currentIndex); count ++; } currentIndex = NEXT_IDX(currentIndex); #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. //while (currentIndex < primSize) for (; vtxcount < primSize; vtxcount++) { /* * The inner loop starts here * There are four cases we have to take care of * 1) we are outside and stay outside * 2) we are outside but pass into the inside * 3) we are inside and stay inside * 4) we are inside and pass into the outside * * if 1) do nothing * if 2) clip the line segment, adding the new point as the * start of a new loop * if 3) add the current point to the line loop * if 4) clip the line segment, the add new (clipped) point to the * output, then draw it. * * There is actually one more case which is borderline - the place * when we hit the end of the actual loop/strip. This is not * strictly part of the inner loop, and hence will be handled after * the end of the while loop if there is an incomplete strip * waiting. * * Note that the points we usually add are the endpoints of the * line segments. */ int thisOutcode = context->VertexBuffer[currentIndex].outcode; int prevOutcode = context->VertexBuffer[PREV_IDX(currentIndex)].outcode; // we don't handle case 1. There is nothing to do but increment // the counter if (IS_OUTSIDE(prevOutcode) && IS_INSIDE(thisOutcode)) { // case 2 uint32 pts[2]; pts[0] = currentIndex; pts[1] = PREV_IDX(currentIndex); // can ignore result - this is never rejected completely hc_LineClip(context, pts); uint32 out1 = pts[0]; uint32 out2 = pts[1]; count = 0; // start a new strip here // add the clipped point... if (out1 >= primSize) // out1 is new { context->IndexBuffer[count] = out1; context->VertexBufferPointer = MAX(context->VertexBufferPointer, out1+1); v_ToScreen(context, out1); } else { context->IndexBuffer[count] = out2; context->VertexBufferPointer = MAX(context->VertexBufferPointer, out2+1); v_ToScreen(context, out2); } count++; // ... and the endpoint context->IndexBuffer[count] = currentIndex; v_ToScreen(context, currentIndex); count++; } else if (IS_INSIDE(prevOutcode) && IS_INSIDE(thisOutcode)) { // case 3 context->IndexBuffer[count] = currentIndex; v_ToScreen(context, currentIndex); count++; } else if (IS_INSIDE(prevOutcode) && IS_OUTSIDE(thisOutcode)) { // case 4 uint32 pts[2]; pts[0] = currentIndex; pts[1] = PREV_IDX(currentIndex); // can ignore result - this is never rejected completely hc_LineClip(context, pts); uint32 out1 = pts[0]; uint32 out2 = pts[1]; // add the clipped point if (out1 >= primSize) // out1 is new { context->IndexBuffer[count] = out1; context->VertexBufferPointer = MAX(context->VertexBufferPointer, out1+1); v_ToScreen(context, out1); } else { context->IndexBuffer[count] = out2; context->VertexBufferPointer = MAX(context->VertexBufferPointer, out2+1); v_ToScreen(context, out2); } count++; // draw the strip IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_LINESTRIP, W3D_INDEX_ULONG, count, context->IndexBuffer); count = 0; context->VertexBufferPointer = vertexPointerTemp; } else { uint32 and_code = prevOutcode & thisOutcode; if (!and_code) { uint32 pts[2]; pts[0] = PREV_IDX(currentIndex); pts[1] = currentIndex; MGLPolygon line; int prev = PREV_IDX(currentIndex); line.verts[1] = MAX(currentIndex, prev); line.verts[0] = MIN(currentIndex, prev); line.numverts = 2; hc_ClipAndDrawLine(context, &line, thisOutcode | prevOutcode); context->VertexBufferPointer = vertexPointerTemp; } } currentIndex = NEXT_IDX(currentIndex); //if (currentIndex == primSize/*-1*/) break; } if (count) { IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_LINESTRIP, W3D_INDEX_ULONG, count, context->IndexBuffer); } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } } //surgeon: added fast path when primitive or_code equals 0 #define CLIP_EPS (1e-7) void d_DrawTriangleFan(GLcontext context) { int i; GLuint and_code, or_code, local_or, local_and; ULONG error; static W3D_Vertex **verts = NULL; static GLboolean visible[MGL_MAXVERTS]; // Should be enough...? static GLubyte complete[MGL_MAXVERTS]; // Ditto int triangle = 0; dprintf("called\n"); if (verts == NULL) { verts = (W3D_Vertex **)IExec->AllocVec(sizeof(W3D_Vertex *) * context->VertexBufferSize, MEMF_ANY); if (!verts) return; } if(context->enable.CullFace == GL_TRUE && context->polygon.CullFace == GL_FRONT_AND_BACK) return; v_Transform(context); and_code = 0xFF; or_code = 0; for (i=0; iVertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->clip.w; GLuint local_outcode = 0; if (w < CLIP_EPS ) local_outcode |= MGL_CLIP_NEGW; if (-w > v->clip.x) local_outcode |= MGL_CLIP_LEFT; else if (v->clip.x > w) local_outcode |= MGL_CLIP_RIGHT; if (-w > v->clip.y) local_outcode |= MGL_CLIP_BOTTOM; else if (v->clip.y > w) local_outcode |= MGL_CLIP_TOP; if (-w > v->clip.z) local_outcode |= MGL_CLIP_BACK; else if (v->clip.z > w) local_outcode |= MGL_CLIP_FRONT; v->outcode = local_outcode; and_code &= local_outcode; or_code |= local_outcode; } if (and_code) return; if (context->enable.Lighting) { GLfloat area = v_GetTriArea(context, 0, 1, 2); light_LightVertex(context, 0, area); light_LightVertex(context, 1, area); for (i = 2; i < context->VertexBufferPointer; i++) { area = v_GetTriArea(context, 0, i-1, i); light_LightVertex(context, i, area); } } if (context->enable.PolygonOffsetFill) { GLfloat offset = v_PolygonOffset(context, 0, 1, 2); context->VertexBuffer[0].z += offset; context->VertexBuffer[1].z += offset; context->VertexBuffer[2].z += offset; for (i = 2; i < context->VertexBufferPointer; i+= 2); { GLfloat offset = v_PolygonOffset(context, 0, i, i+1); context->VertexBuffer[i].z += offset; context->VertexBuffer[i+1].z += offset; } } if (or_code == 0 && !NEED_SPECIAL_FILL) //primitive completely visible { int i; #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif if (context->enable.CullFace) IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_ENABLE); for (i = 0; i < context->VertexBufferPointer; i++) v_ToScreen(context, i); IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, 0, context->VertexBufferPointer); if (context->enable.CullFace) IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_DISABLE); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif return; } if (!NEED_SPECIAL_FILL) { GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. /* ** Up to now everything is like a polygon. Unlike a polygon, however, ** triangle fans and strips may be concave, and each individual triangle ** might be backfacing. ** ** We calculate how many of the triangles are visible. */ for (i=1,triangle=0; iVertexBufferPointer - 1; i++, triangle++) { local_or = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if (local_and == 0) // if the local and code is zero, we're not { // completely off screen. visible[triangle] = hc_DecideFrontface(context, &(context->VertexBuffer[0]), &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1]), local_or); // if our local or codes are zero, we are completely // visible complete[triangle] = local_or; } else { visible[triangle] = GL_FALSE; } } /* ** Draw... ** There are three cases: ** ** 1) Triangle is partially visible ** 2) Triangle is fully visible ** 3) Triangle is invisible ** ** In case 1, we draw the triangle with clip_ClipAndDrawPoly. ** In case 2, we collect a triangle fan/strip of maximum length ** and draw that directly ** in case 3... WE IGNORE IT! HA! */ triangle = 0; i=1; #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif do { if (visible[triangle] == GL_FALSE) // case 3 { triangle ++; i ++; } else { if (complete[triangle]) // case 1 { static MGLPolygon poly; poly.numverts = 3; poly.verts[0] = 0; poly.verts[1] = i; poly.verts[2] = i + 1; // HERE hc_ClipAndDrawPoly(context, &poly, complete[triangle], 0); triangle++; i++; context->VertexBufferPointer = vertexPointerTemp; } else { // case 2 (the difficult part) int k = 3; context->IndexBuffer[0] = 0; context->IndexBuffer[1] = i; context->IndexBuffer[2] = i+1; v_ToScreen(context, 0); v_ToScreen(context, i); v_ToScreen(context, i+1); triangle ++; i ++; while (complete[triangle]==0 && visible[triangle] && iVertexBufferPointer - 1) { context->IndexBuffer[k] = i+1; v_ToScreen(context, i+1); i++; k++; triangle++; } error = IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_ULONG, k, context->IndexBuffer); } } } while (iVertexBufferPointer-1); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } else { #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. // Fill mode dictates we need to draw these singular for (i=1; iVertexBufferPointer - 1; i++) { MGLPolygon poly; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if (local_and) continue; poly.numverts = 3; poly.verts[0] = 0; poly.verts[1] = i; poly.verts[2] = i+1; local_or = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode; GLuint fillMode = v_GetPolyFillMode(context, &poly); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode, 0); context->VertexBufferPointer = vertexPointerTemp; } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } } ; //surgeon: added fast path when primitive or_code equals 0 void d_DrawTriangleStrip(GLcontext context) { int i; GLuint and_code, or_code, local_or, local_and; ULONG error; static W3D_Vertex **verts = NULL; static GLboolean visible[MGL_MAXVERTS]; // Should be enough...? static GLubyte complete[MGL_MAXVERTS]; // Ditto int triangle = 0; GLenum CurrentFrontFace = context->polygon.FrontFace; dprintf("called\n"); if(context->VertexBufferPointer < 3) { // nothing to draw return; } if (verts == NULL) { verts = (W3D_Vertex **)IExec->AllocVec(sizeof(W3D_Vertex *) * context->VertexBufferSize, MEMF_ANY); if (!verts) return; } if(context->enable.CullFace == GL_TRUE && context->polygon.CullFace == GL_FRONT_AND_BACK) return; v_Transform(context); for (i = 0; i < context->VertexBufferPointer; i++) v_ToScreen(context, i); and_code = 0xFF; or_code = 0; for (i=0; iVertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->clip.w; GLuint local_outcode = 0; if (w < CLIP_EPS ) { local_outcode |= MGL_CLIP_NEGW; } if (-w > v->clip.x) { local_outcode |= MGL_CLIP_LEFT; } else if (v->clip.x > w) { local_outcode |= MGL_CLIP_RIGHT; } if (-w > v->clip.y) { local_outcode |= MGL_CLIP_BOTTOM; } else if (v->clip.y > w) { local_outcode |= MGL_CLIP_TOP; } if (-w > v->clip.z) { local_outcode |= MGL_CLIP_BACK; } else if (v->clip.z > w) { local_outcode |= MGL_CLIP_FRONT; } v->outcode = local_outcode; and_code &= local_outcode; or_code |= local_outcode; } if (and_code) return; if (context->enable.Lighting) { GLfloat area = v_GetTriArea(context, 0, 1, 2); light_LightVertex(context, 0, area); light_LightVertex(context, 1, area); light_LightVertex(context, 2, area); GLfloat area2; for (i = 2; i < context->VertexBufferPointer - 1; i++) { area2 = area; area = v_GetTriArea(context, i-1, i+1, i); if(i % 2 == 0) { area = -area; } area = min(area, area2); light_LightVertex(context, i, area); } area = v_GetTriArea(context, i-2, i-1, i); if(i % 2 == 1) { area = -area; } light_LightVertex(context, i, area); } if (or_code == 0 && !NEED_SPECIAL_FILL && !(context->enable.PolygonOffsetFill)) //primitive completely visible { int i; if (context->enable.CullFace) IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_ENABLE); if (context->lighting.ShadeModel == GL_FLAT) { #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif // Fill mode dictates we need to draw these singular for (i=0; iVertexBufferPointer - 2; i++) { MGLPolygon poly; local_and = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (local_and) continue; poly.numverts = 3; poly.verts[0] = i+0; poly.verts[1] = i+1; poly.verts[2] = i+2; local_or = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; SetFlatColor(context, context->VertexBuffer[i+2].r, context->VertexBuffer[i+2].g, context->VertexBuffer[i+2].b, context->VertexBuffer[i+2].a); // Need to switch the cull state EstablishCullState(context); GLuint fillMode = v_GetPolyFillMode(context, &poly); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode, 0); if (context->polygon.FrontFace == GL_CCW) context->polygon.FrontFace = GL_CW; else context->polygon.FrontFace = GL_CCW; } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif context->polygon.FrontFace = CurrentFrontFace; // May need to restore to switch the cull state EstablishCullState(context); return; } else { #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, 0, context->VertexBufferPointer); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } if (context->enable.CullFace) IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_DISABLE); return; } if (!NEED_SPECIAL_FILL && context->lighting.ShadeModel != GL_FLAT && !(context->enable.PolygonOffsetFill)) { dprintf("special fill \n"); /* ** Up to now everything is like a polygon. Unlike a polygon, however, ** triangle fans and strips may be concave, and each individual triangle ** might be backfacing. ** ** We calculate how many of the triangles are visible. */ for (i=0,triangle=0; iVertexBufferPointer - 2; i++, triangle++) { local_or = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; local_and = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (local_and == 0) // if the local and code is zero, we're not { // completely off screen. visible[triangle] = hc_DecideFrontface(context, &(context->VertexBuffer[i+0]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2]), local_or); // if our local or codes are zero, we are completely // visible complete[triangle] = local_or; } else { visible[triangle] = GL_FALSE; } if (context->polygon.FrontFace == GL_CCW) context->polygon.FrontFace = GL_CW; else context->polygon.FrontFace = GL_CCW; } /* ** Draw... ** There are three cases: ** ** 1) Triangle is partially visible ** 2) Triangle is fully visible ** 3) Triangle is invisible ** ** In case 1, we draw the triangle with clip_ClipAndDrawPoly. ** In case 2, we collect a triangle fan/strip of maximum length ** and draw that directly ** in case 3... WE IGNORE IT! HA! */ triangle = 0; i=0; context->polygon.FrontFace = CurrentFrontFace; #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. do { if (visible[triangle] == GL_FALSE) // case 3 { triangle ++; i ++; } else { if (complete[triangle]) // case 1 { static MGLPolygon poly; poly.numverts = 3; poly.verts[0] = i + 0; poly.verts[1] = i + 1; poly.verts[2] = i + 2; // Need to switch the cull state EstablishCullState(context); hc_ClipAndDrawPoly(context, &poly, complete[triangle], 0); triangle++; i++; context->VertexBufferPointer = vertexPointerTemp; } else { // case 2 (the difficult part) int k = 3; int base = i; triangle ++; i ++; while (complete[triangle]==0 && visible[triangle] && iVertexBufferPointer - 2) { // v_ToScreen(context, i+2); i++; k++; triangle++; } // Need to switch the cull state EstablishCullState(context); error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, base, k); if(k % 2 == 0) { // Need to swap the front-face again to sync up with the current triangle in the strip if (context->polygon.FrontFace == GL_CCW) context->polygon.FrontFace = GL_CW; else context->polygon.FrontFace = GL_CCW; } } } if (context->polygon.FrontFace == GL_CCW) context->polygon.FrontFace = GL_CW; else context->polygon.FrontFace = GL_CCW; } while (iVertexBufferPointer - 2); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } else { #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. // Fill mode dictates we need to draw these singular for (i=0; iVertexBufferPointer - 2; i++) { MGLPolygon poly; local_and = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (local_and) continue; poly.numverts = 3; poly.verts[0] = i+0; poly.verts[1] = i+1; poly.verts[2] = i+2; local_or = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; // if (context->enable.PolygonOffsetFill) // { // GLfloat offset = v_PolygonOffset(context, i, i+1, i+2); // old_z0 = context->VertexBuffer[i].z; // old_z1 = context->VertexBuffer[i+1].z; // old_z2 = context->VertexBuffer[i+2].z; // // context->VertexBuffer[i].z += offset; // context->VertexBuffer[i+1].z += offset; // context->VertexBuffer[i+2].z += offset; // } if(context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[i].r, context->VertexBuffer[i].g, context->VertexBuffer[i].b, context->VertexBuffer[i].a); } // Need to switch the cull state EstablishCullState(context); GLuint fillMode = v_GetPolyFillMode(context, &poly); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode, HCDRAW_DO_POLYOFFSET); // if (context->enable.PolygonOffsetFill) // { // context->VertexBuffer[i].z = old_z0; // context->VertexBuffer[i+1].z = old_z1; // context->VertexBuffer[i+2].z = old_z2; // } if (context->polygon.FrontFace == GL_CCW) context->polygon.FrontFace = GL_CW; else context->polygon.FrontFace = GL_CCW; context->VertexBufferPointer = vertexPointerTemp; } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } context->polygon.FrontFace = CurrentFrontFace; // May need to restore to switch the cull state EstablishCullState(context); } void d_DrawQuadStrip(GLcontext context) { int i; GLuint or_code, and_code; ULONG error; GLfloat old_z1 = 0.0; GLfloat old_z2 = 0.0; dprintf("called\n"); if(context->VertexBufferPointer < 4) { // nothing to draw return; } v_Transform(context); #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. for (i=0; iVertexBufferPointer-3; i+=2) { hc_CodePoint(context, &(context->VertexBuffer[i])); hc_CodePoint(context, &(context->VertexBuffer[i+1])); hc_CodePoint(context, &(context->VertexBuffer[i+2])); hc_CodePoint(context, &(context->VertexBuffer[i+3])); or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode | context->VertexBuffer[i+3].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode & context->VertexBuffer[i+3].outcode; if (and_code){ continue; } if (hc_DecideFrontface(context, &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2]), or_code) == GL_FALSE && hc_DecideFrontface(context, &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+3]), &(context->VertexBuffer[i+2]), or_code) == GL_FALSE){ continue; } if (context->enable.PolygonOffsetFill) { GLfloat offset = v_PolygonOffset(context, i, i+1, i+2); old_z1 = context->VertexBuffer[i+2].z; old_z2 = context->VertexBuffer[i+3].z; context->VertexBuffer[i].z += offset; context->VertexBuffer[i+1].z += offset; context->VertexBuffer[i+2].z += offset; context->VertexBuffer[i+3].z += offset; } if (context->enable.Lighting) { /* Triangle area is enough for lighting */ GLfloat area = v_GetTriArea(context, i, i+1, i+2) + v_GetTriArea(context, i+1, i+3, i+2); //IExec->DebugPrintF("area = %f\n", area); light_LightVertex(context, i, area); light_LightVertex(context, i+1, area); light_LightVertex(context, i+2, area); light_LightVertex(context, i+3, area); } if (or_code == 0 && !NEED_SPECIAL_FILL) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); v_ToScreen(context, i+3); if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[i].r, context->VertexBuffer[i].g, context->VertexBuffer[i].b, context->VertexBuffer[i].a); } error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, i, 4); } else { static MGLPolygon poly; poly.numverts = 4; poly.verts[0] = i; poly.verts[1] = i+1; poly.verts[2] = i+3; poly.verts[3] = i+2; if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[i].r, context->VertexBuffer[i].g, context->VertexBuffer[i].b, context->VertexBuffer[i].a); } if (NEED_SPECIAL_FILL) { GLint fillMode = v_GetPolyFillMode(context, &poly); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode, 0); } else hc_ClipAndDrawPoly(context, &poly, or_code, 0); context->VertexBufferPointer = vertexPointerTemp; } if (context->enable.PolygonOffsetFill) { context->VertexBuffer[i+2].z = old_z1; context->VertexBuffer[i+3].z = old_z2; } } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void d_DrawQuads(GLcontext context) { int i; GLuint or_code, and_code; ULONG error; dprintf("Num quads: %u\n", context->VertexBufferPointer / 4); v_Transform(context); #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. for (i=0; iVertexBufferPointer; i+=4) { hc_CodePoint(context, &(context->VertexBuffer[i])); hc_CodePoint(context, &(context->VertexBuffer[i+1])); hc_CodePoint(context, &(context->VertexBuffer[i+2])); hc_CodePoint(context, &(context->VertexBuffer[i+3])); or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode | context->VertexBuffer[i+3].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode & context->VertexBuffer[i+3].outcode; if (and_code) continue; if (hc_DecideFrontface(context, &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2]),or_code) == GL_FALSE) continue; if (context->enable.PolygonOffsetFill) { GLfloat offset = v_PolygonOffset(context, i, i+1, i+2); context->VertexBuffer[i].z += offset; context->VertexBuffer[i+1].z += offset; context->VertexBuffer[i+2].z += offset; context->VertexBuffer[i+3].z += offset; } if (or_code == 0 && !NEED_SPECIAL_FILL) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); v_ToScreen(context, i+3); if (context->enable.Lighting) { GLfloat area = v_GetQuadArea(context, i, i+1, i+2, i+3); light_LightVertex(context, i, area); light_LightVertex(context, i+1, area); light_LightVertex(context, i+2, area); light_LightVertex(context, i+3, area); } if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[i].r, context->VertexBuffer[i].g, context->VertexBuffer[i].b, context->VertexBuffer[i].a); } error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, i, 4); } else { static MGLPolygon poly; poly.numverts = 4; poly.verts[0] = i; poly.verts[1] = i+1; poly.verts[2] = i+2; poly.verts[3] = i+3; if (NEED_SPECIAL_FILL) { GLint fillMode = v_GetPolyFillMode(context, &poly); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode, 0); } else { hc_ClipAndDrawPoly(context, &poly, or_code, 0); } context->VertexBufferPointer = vertexPointerTemp; } } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void d_DrawPolygon(GLcontext context) { int i; GLuint or_code, and_code; MGLPolygon poly; dprintf("called\n"); v_Transform(context); or_code = 0; and_code = 0xFF; for (i=0; iVertexBufferPointer; i++) { hc_CodePoint(context, &(context->VertexBuffer[i])); or_code |= context->VertexBuffer[i].outcode; and_code &= context->VertexBuffer[i].outcode; poly.verts[i] = i; } if (and_code) return; poly.numverts = context->VertexBufferPointer; if (context->enable.PolygonOffsetFill) { GLfloat area = dh_AreaSign(context, &poly); GLfloat offset = v_PolygonOffsetArea(context, 0, 1, 2, area); for (i=0; iVertexBufferPointer; i++) context->VertexBuffer[i].z += offset; } #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif if (or_code == 0 && !NEED_SPECIAL_FILL) { dh_DrawPolyFF(context, &poly, 0); } else { if (NEED_SPECIAL_FILL) { GLboolean isFrontFace; GLfloat area; for (i=0; iVertexBufferPointer; i++) { v_ToScreen(context, i); } area = dh_AreaSign(context, &poly); if (context->polygon.FrontFace == GL_CW) { area *= -1.f; } if (area >= context->MinTriArea) { isFrontFace = GL_TRUE; } else { isFrontFace = GL_FALSE; } if (context->enable.CullFace) { switch(context->polygon.CullFace) { case GL_FRONT_AND_BACK: goto UNLOCK; break; case GL_FRONT: if (isFrontFace) goto UNLOCK; break; case GL_BACK: if (!isFrontFace) goto UNLOCK; break; } } GLint fillMode = v_GetFillMode(context, isFrontFace); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode, 0); } else { hc_ClipAndDrawPolyFF(context, &poly, or_code, 0); } } UNLOCK: #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void d_DrawTriangles(GLcontext context) { int i; GLuint or_code, and_code; dprintf("called\n"); /* FIXME: Use an approach similar to strips/fans: Gather as many triangles as * possible (i.e. visible, non-clipped) and draw them in one go */ v_Transform(context); #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif GLuint vertexPointerTemp = context->VertexBufferPointer; // We'll need to reset this periodically so that the // extra vertices produced by clipping don't overflow // the buffer. for (i=0; iVertexBufferPointer; i+=3) { hc_CodePoint(context, &(context->VertexBuffer[i])); hc_CodePoint(context, &(context->VertexBuffer[i+1])); hc_CodePoint(context, &(context->VertexBuffer[i+2])); or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (and_code) continue; if (hc_DecideFrontface(context, &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2]),or_code) == GL_FALSE) continue; if (or_code == 0 && !NEED_SPECIAL_FILL) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); if (context->enable.Lighting) { GLfloat area = v_GetTriArea(context, i, i+1, i+2); light_LightVertex(context, i, area); light_LightVertex(context, i+1, area); light_LightVertex(context, i+2, area); } if (context->enable.PolygonOffsetFill) { GLfloat offset = v_PolygonOffset(context, i, i+1, i+2); context->VertexBuffer[i].z += offset; context->VertexBuffer[i+1].z += offset; context->VertexBuffer[i+2].z += offset; } if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[i].r, context->VertexBuffer[i].g, context->VertexBuffer[i].b, context->VertexBuffer[i].a); } IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, i, 3); } else { static MGLPolygon poly; poly.numverts = 3; poly.verts[0] = i; poly.verts[1] = i+1; poly.verts[2] = i+2; if (context->enable.Lighting) { GLfloat area = v_GetTriArea(context, i, i+1, i+2); light_LightVertex(context, i, area); light_LightVertex(context, i+1, area); light_LightVertex(context, i+2, area); } if (context->enable.PolygonOffsetFill) { GLfloat offset = v_PolygonOffset(context, i, i+1, i+2); context->VertexBuffer[i].z += offset; context->VertexBuffer[i+1].z += offset; context->VertexBuffer[i+2].z += offset; } if (NEED_SPECIAL_FILL) { GLint fillMode = v_GetPolyFillMode(context, &poly); d_ClipAndDrawPolyWithFill(context, &poly, or_code, fillMode, 0); } else { hc_ClipAndDrawPoly(context, &poly, or_code, 0); } context->VertexBufferPointer = vertexPointerTemp; } } #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } /* ** A FlatFan is a triangle fan that is specified in device corrdinates and ** is drawn regardless of current matrix or other */ void d_DrawFlatFan(GLcontext context) { dprintf("called\n"); ULONG error; int i; for (i=0; iVertexBufferPointer; i++) { context->VertexBuffer[i].x = (W3D_Float) context->VertexBuffer[i].object.x; context->VertexBuffer[i].y = (W3D_Float) context->VertexBuffer[i].object.y; context->VertexBuffer[i].z = (W3D_Double)context->VertexBuffer[i].object.z; context->VertexBuffer[i].uvw[context->texture.ActiveTexture].w = (W3D_Float) context->VertexBuffer[i].object.w; } #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode == MGL_LOCK_SMART) // Smart: Lock timer based { if (smartlock_beginDraw(context->smartLock) == GL_FALSE) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } } else if(context->LockMode == MGL_LOCK_AUTOMATIC) { if (W3D_SUCCESS != IWarp3D->W3D_LockHardware(context->w3dContext)) { dprintf("Error during W3D_LockHardware()\n"); return; // give up } else{ context->w3dLocked = GL_TRUE; } } #endif error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, 0, context->VertexBufferPointer); #ifdef AUTOMATIC_LOCKING_ENABLE 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; } #endif } void dh_DrawPoly(GLcontext context, MGLPolygon *poly, DrawPolyFlags_t flags) { dprintf("called\n"); int i; float area; for (i=0; inumverts; i++) v_ToScreen(context, poly->verts[i]); if (context->enable.CullFace == GL_TRUE) { area = dh_AreaSign(context, poly); switch(context->polygon.CullFace) { case GL_FRONT_AND_BACK: return; case GL_FRONT: area *= -1.f; break; case GL_BACK: default: ; } if (context->polygon.FrontFace == GL_CW) { if (-area < context->MinTriArea) return; // Either backfacing, or too small } else{ if (area < context->MinTriArea) return; // Either backfacing, or too small } } else { area = dh_AreaSign(context, poly); if (fast_fabs(area) < context->MinTriArea) return; } if (context->enable.Lighting) { for (i = 0; i < poly->numverts; i++) light_LightVertex(context, poly->verts[i], area); } if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[poly->verts[0]].r, context->VertexBuffer[poly->verts[0]].g, context->VertexBuffer[poly->verts[0]].b, context->VertexBuffer[poly->verts[0]].a); } if (context->enable.PolygonOffsetFill && (flags & HCDRAW_DO_POLYOFFSET)) { GLfloat offset = v_PolygonOffset(context, poly->verts[0], poly->verts[1], poly->verts[2]); for (i=0; inumverts; i++) { // Any better idea than that ? context->VertexBuffer[poly->verts[i]].z_back = context->VertexBuffer[poly->verts[i]].z; context->VertexBuffer[poly->verts[i]].z += offset; } } IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_ULONG, poly->numverts, poly->verts); if (context->enable.PolygonOffsetFill && (flags & HCDRAW_DO_POLYOFFSET)) { for (i=0; inumverts; i++) context->VertexBuffer[poly->verts[i]].z = context->VertexBuffer[poly->verts[i]].z_back; } } void dh_DrawPolyFF(GLcontext context, MGLPolygon *poly, DrawPolyFlags_t flags) { dprintf("called\n"); int i; GLfloat area = 0.0; GLfloat z[MGL_MAXVERTS]; for (i=0; inumverts; i++) v_ToScreen(context, poly->verts[i]); if (context->enable.Lighting) { area = dh_AreaSign(context, poly); for (i = 0; i < poly->numverts; i++) light_LightVertex(context, poly->verts[i], area); } if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[poly->verts[0]].r, context->VertexBuffer[poly->verts[0]].g, context->VertexBuffer[poly->verts[0]].b, context->VertexBuffer[poly->verts[0]].a); } if (context->enable.CullFace == GL_TRUE) { area = dh_AreaSign(context, poly); switch(context->polygon.CullFace) { case GL_FRONT_AND_BACK: return; case GL_FRONT: area *= -1.f; break; case GL_BACK: default: ; } if (context->polygon.FrontFace == GL_CW) { if (-area < context->MinTriArea) return; // Either backfacing, or too small } else{ if (area < context->MinTriArea) return; // Either backfacing, or too small } } else { area = dh_AreaSign(context, poly); if (fast_fabs(area) < context->MinTriArea) return; } if (context->enable.PolygonOffsetFill) { /* This is really bad! */ for (i=0; inumverts; i++) { z[i] = context->VertexBuffer[poly->verts[i]].z; context->VertexBuffer[poly->verts[i]].z = min (1.0, context->VertexBuffer[poly->verts[i]].z + poly->zoffset); } } IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_ULONG, poly->numverts, poly->verts); if (context->enable.PolygonOffsetFill && (flags & HCDRAW_DO_POLYOFFSET)) { for (i=0; inumverts; i++) { context->VertexBuffer[poly->verts[i]].z = z[i]; } } } void cgl_GLRectf(struct GLContextIFace *Self, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { dprintf("called\n"); if(dl_IsDLActive(Self)){ dl_save_Rectf(Self, x1, y1, x2, y2); if(!dl_CompileAndExecuteMode(Self)){ return; } } Self->GLBegin(GL_POLYGON); Self->GLVertex4f(x1, y1, 0.0, 1.0); Self->GLVertex4f(x2, y1, 0.0, 1.0); Self->GLVertex4f(x2, y2, 0.0, 1.0); Self->GLVertex4f(x1, y2, 0.0, 1.0); Self->GLEnd(); }