/* * $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" #include "util.h" #include "mgl_profileitems.h" void cgl_GLVertex4f(struct GLContextIFace *Self, GLfloat x, GLfloat y, GLfloat z, GLfloat w); 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); //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) { return isFrontFace ? context->polygon.PolygonModeFront : 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); return fast_fabs(area) > threshold ? GL_TRUE : 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); return fast_fabs(area) > threshold ? GL_TRUE : 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) { PROFILE_ENTRY(FID_V_GEN_TEX_COORDS) 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 (context->enable.TexGenQ[i]) { if (context->texture.TexGenQ[i].needR) { needR = TRUE; } if (context->texture.TexGenQ[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; } } if (context->enable.TexGenQ[i] == GL_TRUE) { switch (context->texture.TexGenQ[i].mode) { case GL_OBJECT_LINEAR: context->VertexBuffer[vertex].uvw[i].w = context->VertexBuffer[vertex].object.x * context->texture.TexGenQ[i].objectPlane[0] + context->VertexBuffer[vertex].object.y * context->texture.TexGenQ[i].objectPlane[1] + context->VertexBuffer[vertex].object.z * context->texture.TexGenQ[i].objectPlane[2] + context->VertexBuffer[vertex].object.w * context->texture.TexGenQ[i].objectPlane[3]; break; case GL_EYE_LINEAR: context->VertexBuffer[vertex].uvw[i].w = context->VertexBuffer[vertex].object.x * context->texture.TexGenQ[i].eyePlane[0] + context->VertexBuffer[vertex].object.y * context->texture.TexGenQ[i].eyePlane[1] + context->VertexBuffer[vertex].object.z * context->texture.TexGenQ[i].eyePlane[2] + context->VertexBuffer[vertex].object.w * context->texture.TexGenQ[i].eyePlane[3]; break; } /* FIXME */ //context->VertexBuffer[vertex].uvw[i].u /= context->VertexBuffer[vertex].uvw[i].w; //context->VertexBuffer[vertex].uvw[i].v /= context->VertexBuffer[vertex].uvw[i].w; float oneoverq = 1.0 / context->VertexBuffer[vertex].uvw[i].w; context->VertexBuffer[vertex].uvw[i].u *= oneoverq; context->VertexBuffer[vertex].uvw[i].v *= oneoverq; context->VertexBuffer[vertex].rhw_valid[i] = GL_TRUE; } } PROFILE_EXIT(FID_V_GEN_TEX_COORDS) } INLINE void v_Transform(GLcontext context) { int i, tmu; PROFILE_ENTRY(FID_V_TRANSFORM) 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 } } #ifdef MGL_USE_ALTIVEC if (useVectorUnit) { v_TransformToClip(context); } else #endif 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 } PROFILE_EXIT(FID_V_TRANSFORM) } #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) { PROFILE_ENTRY(FID_V_TO_SCREEN) 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 { // GL_FOG_COORD depth = context->VertexBuffer[i].bf; } // FIXME: Handle that via a lookup table or similar switch (context->fog.FogMode) { case GL_LINEAR: fogDepth = (context->fog.FogEnd - fast_fabs(depth)) / (context->fog.FogEnd - context->fog.FogStart); break; case GL_EXP: c = context->fog.FogDensity * fast_fabs(depth); fogDepth = exp(-c); break; case GL_EXP2: c = context->fog.FogDensity * fast_fabs(depth); fogDepth = exp(-(c*c)); break; } context->VertexBuffer[i].fogdepth = CLAMP(fogDepth, 0.0f, 1.0f); } PROFILE_EXIT(FID_V_TO_SCREEN) } 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) { PROFILE_ENTRY(FID_D_CLIP_AND_DRAW_POLY_POINT) 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]); } } // Anything left after clipping? if (num != 0) { ENTER_LOCK // Draw indexed, some points are off IWarp3D->W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_POINTS, W3D_INDEX_ULONG, num, context->IndexBuffer ); EXIT_LOCK } PROFILE_EXIT(FID_D_CLIP_AND_DRAW_POLY_POINT) } void d_ClipAndDrawPolyLine(GLcontext context, MGLPolygon *poly, uint32 or_code) { PROFILE_ENTRY(FID_D_CLIP_AND_DRAW_POLY_LINE) 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; ENTER_LOCK 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; } EXIT_LOCK PROFILE_EXIT(FID_D_CLIP_AND_DRAW_POLY_LINE) } void d_ClipAndDrawPoly(GLcontext context, MGLPolygon *poly, uint32 or_code, DrawPolyFlags_t flags) { PROFILE_ENTRY(FID_D_CLIP_AND_DRAW_POLY) ENTER_LOCK hc_ClipAndDrawPoly(context, poly, or_code, flags); EXIT_LOCK PROFILE_EXIT(FID_D_CLIP_AND_DRAW_POLY) } void d_ClipAndDrawPolyWithFill( GLcontext context, MGLPolygon *poly, uint32 or_code, GLuint fillMode, DrawPolyFlags_t flags) { 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) { PROFILE_ENTRY(FID_D_DRAW_POINTS) int i; uint32 *idx = (uint32 *)context->IndexBuffer; uint32 num = 0; 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); } } // Anything left after clipping? if (num != 0) { ENTER_LOCK 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); } EXIT_LOCK } PROFILE_EXIT(FID_D_DRAW_POINTS) } void d_DrawLines(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_LINES) /* FIXME: Implement them in the driver, or do a replacement here */ int i; // W3D_Line lin; GLuint or_code, and_code; v_Transform(context); ENTER_LOCK 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])); and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode; if (and_code) { if (array_size > 0 && (context->lighting.ShadeModel == GL_SMOOTH) ) { IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_LINES, array_start, array_size ); array_size=0; } continue; } or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode; 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; IWarp3D->W3D_DrawLine(context->w3dContext, &lin); #else //if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor( context, context->VertexBuffer[i+1].r, context->VertexBuffer[i+1].g, context->VertexBuffer[i+1].b, context->VertexBuffer[i+1].a ); //} 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 */ IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_LINES, array_start, array_size ); array_size=0; } 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 */ IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_LINES, array_start, array_size ); array_size=0; } EXIT_LOCK PROFILE_EXIT(FID_D_DRAW_LINES) } void dh_DrawLine(GLcontext context, MGLPolygon *poly) { /* FIXME: Implement in driver, or replace */ 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; IWarp3D->W3D_DrawLine(context->w3dContext, &lin); #else if (context->lighting.ShadeModel == GL_FLAT) { SetFlatColor(context, context->VertexBuffer[poly->verts[1]].r, context->VertexBuffer[poly->verts[1]].g, context->VertexBuffer[poly->verts[1]].b, context->VertexBuffer[poly->verts[1]].a ); } 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) void d_DrawLineStrip(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_LINE_STRIP) GLuint or_code, and_code; v_Transform(context); 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) { PROFILE_EXIT(FID_D_DRAW_LINE_STRIP) 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); } ENTER_LOCK IWarp3D->W3D_DrawArray( context->w3dContext, prim, 0, context->VertexBufferPointer ); EXIT_LOCK } 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); ENTER_LOCK 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) { 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 ); } EXIT_LOCK } PROFILE_EXIT(FID_D_DRAW_LINE_STRIP) } //surgeon: added fast path when primitive or_code equals 0 #define CLIP_EPS (1e-7) void d_DrawTriangleFan(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_TRIANGLE_FAN) int i; GLuint and_code, or_code, local_or, local_and; GLboolean * visible = context->ts_Visible; GLubyte * complete = context->ts_Complete; int triangle = 0; // dprintf("REVIEW ME\n"); if ( context->VertexBufferPointer < 3 || ( context->enable.CullFace == GL_TRUE && context->polygon.CullFace == GL_FRONT_AND_BACK ) ) { PROFILE_EXIT(FID_D_DRAW_TRIANGLE_FAN) 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) { PROFILE_EXIT(FID_D_DRAW_TRIANGLE_FAN) 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; ENTER_LOCK 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); } EXIT_LOCK PROFILE_EXIT(FID_D_DRAW_TRIANGLE_FAN) 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_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if (local_and == 0) { local_or = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode; // 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; ENTER_LOCK do { if (visible[triangle] == GL_FALSE) { // case 3 triangle++; i++; } else { if (complete[triangle]) { // case 1 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], HCDRAW_FLATSHADE_LASTVTX); 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++; } IWarp3D->W3D_DrawElements( context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_ULONG, k, context->IndexBuffer ); } } } while (iVertexBufferPointer-1); EXIT_LOCK } else { ENTER_LOCK 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, HCDRAW_FLATSHADE_LASTVTX); context->VertexBufferPointer = vertexPointerTemp; } EXIT_LOCK } PROFILE_EXIT(FID_D_DRAW_TRIANGLE_FAN) } ; //surgeon: added fast path when primitive or_code equals 0 void d_DrawTriangleStrip(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_TRIANGLE_STRIP) int i; GLuint and_code, or_code, local_or, local_and; GLboolean * visible = context->ts_Visible; GLubyte * complete = context->ts_Complete; int triangle = 0; GLenum CurrentFrontFace = context->polygon.FrontFace; //dprintf("REVIEW ME\n"); if (context->VertexBufferPointer < 3) { // nothing to draw PROFILE_EXIT(FID_D_DRAW_TRIANGLE_STRIP) return; } if ( context->enable.CullFace == GL_TRUE && context->polygon.CullFace == GL_FRONT_AND_BACK ) { PROFILE_EXIT(FID_D_DRAW_TRIANGLE_STRIP) 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) { PROFILE_EXIT(FID_D_DRAW_TRIANGLE_STRIP) 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 & 1) == 0) { area = -area; } area = MIN(area, area2); light_LightVertex(context, i, area); } area = v_GetTriArea(context, i-2, i-1, i); if (i & 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) { ENTER_LOCK // 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; if(i & 1) { // Swapped vertices so front-facing triangles in the strip are still front-facing poly.verts[0] = i+0; poly.verts[1] = i+1; } else { 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, HCDRAW_FLATSHADE_LASTVTX); } EXIT_LOCK context->polygon.FrontFace = CurrentFrontFace; // May need to restore to switch the cull state EstablishCullState(context); if (context->enable.CullFace) { IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_DISABLE); } PROFILE_EXIT(FID_D_DRAW_TRIANGLE_STRIP) return; } else { ENTER_LOCK IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_TRISTRIP, 0, context->VertexBufferPointer ); EXIT_LOCK } if (context->enable.CullFace) { IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_DISABLE); } PROFILE_EXIT(FID_D_DRAW_TRIANGLE_STRIP) return; } if (!NEED_SPECIAL_FILL && context->lighting.ShadeModel != GL_FLAT && !(context->enable.PolygonOffsetFill)) { /* ** 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_and = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (local_and == 0) { local_or = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; // 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; } SWAP_FRONT_FACE } /* ** 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; ENTER_LOCK 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 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], HCDRAW_FLATSHADE_LASTVTX); 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); IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_TRISTRIP, base, k ); if (!(k & 1)) { // Need to swap the front-face again to sync up with the current triangle in the strip SWAP_FRONT_FACE } } } SWAP_FRONT_FACE } while (iVertexBufferPointer - 2); EXIT_LOCK } else { ENTER_LOCK 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+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, 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; // } SWAP_FRONT_FACE context->VertexBufferPointer = vertexPointerTemp; } EXIT_LOCK } context->polygon.FrontFace = CurrentFrontFace; // May need to restore to switch the cull state EstablishCullState(context); PROFILE_EXIT(FID_D_DRAW_TRIANGLE_STRIP) } void d_DrawQuadStrip(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_QUAD_STRIP) int i; GLuint or_code, and_code; GLfloat old_z1 = 0.0; GLfloat old_z2 = 0.0; if (context->VertexBufferPointer < 4) { // nothing to draw PROFILE_EXIT(FID_D_DRAW_QUAD_STRIP) return; } v_Transform(context); ENTER_LOCK 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])); 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; } or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode | context->VertexBuffer[i+3].outcode; 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+3].r, context->VertexBuffer[i+3].g, context->VertexBuffer[i+3].b, context->VertexBuffer[i+3].a ); } IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_TRISTRIP, i, 4 ); } else { 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, HCDRAW_FLATSHADE_LASTVTX); } else { hc_ClipAndDrawPoly(context, &poly, or_code, HCDRAW_FLATSHADE_LASTVTX); } context->VertexBufferPointer = vertexPointerTemp; } if (context->enable.PolygonOffsetFill) { context->VertexBuffer[i+2].z = old_z1; context->VertexBuffer[i+3].z = old_z2; } } PROFILE_EXIT(FID_D_DRAW_QUAD_STRIP) EXIT_LOCK } void d_DrawQuads(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_QUADS) int i; GLuint or_code, and_code; v_Transform(context); ENTER_LOCK 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])); 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; } or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode | context->VertexBuffer[i+3].outcode; 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]), &(context->VertexBuffer[i+2]), &(context->VertexBuffer[i+3]), 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+3].r, context->VertexBuffer[i+3].g, context->VertexBuffer[i+3].b, context->VertexBuffer[i+3].a ); } IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_TRIFAN, i, 4 ); } else { 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, HCDRAW_FLATSHADE_LASTVTX); } else { hc_ClipAndDrawPoly(context, &poly, or_code, HCDRAW_FLATSHADE_LASTVTX); } context->VertexBufferPointer = vertexPointerTemp; } } EXIT_LOCK PROFILE_EXIT(FID_D_DRAW_QUADS) } void d_DrawPolygon(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_POLYGON) int i; GLuint or_code, and_code; //MGLPolygon poly; MGLPolygon *poly = context->LargePolygon; 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) { PROFILE_EXIT(FID_D_DRAW_POLYGON) 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; } } ENTER_LOCK 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, HCDRAW_FLATSHADE_LASTVTX); } else { hc_ClipAndDrawPolyFF(context, poly, or_code, 0); } } UNLOCK: EXIT_LOCK PROFILE_EXIT(FID_D_DRAW_POLYGON) } void d_DrawTriangles(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_TRIANGLES) int i; GLuint or_code, and_code; /* 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); ENTER_LOCK 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])); and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (and_code) { continue; } or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; 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+2].r, context->VertexBuffer[i+2].g, context->VertexBuffer[i+2].b, context->VertexBuffer[i+2].a ); } IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, i, 3); } else { 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, HCDRAW_FLATSHADE_LASTVTX); } else { hc_ClipAndDrawPoly(context, &poly, or_code, HCDRAW_FLATSHADE_LASTVTX); } context->VertexBufferPointer = vertexPointerTemp; } } EXIT_LOCK PROFILE_EXIT(FID_D_DRAW_TRIANGLES) } /* ** A FlatFan is a triangle fan that is specified in device coordinates and ** is drawn regardless of current matrix or other */ void d_DrawFlatFan(GLcontext context) { PROFILE_ENTRY(FID_D_DRAW_FLAT_FAN) int i; // KC: Try having a fan of less than two vertices... if (context->VertexBufferPointer > 2) { 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; } ENTER_LOCK IWarp3D->W3D_DrawArray( context->w3dContext, W3D_PRIMITIVE_TRIFAN, 0, context->VertexBufferPointer ); EXIT_LOCK } PROFILE_EXIT(FID_D_DRAW_FLAT_FAN) } void dh_DrawPoly(GLcontext context, MGLPolygon *poly, DrawPolyFlags_t flags) { 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) { if((flags & HCDRAW_FLATSHADE_LASTVTX) != 0) { GLsizei colorIdx = poly->numverts - 1; SetFlatColor( context, context->VertexBuffer[poly->verts[colorIdx]].r, context->VertexBuffer[poly->verts[colorIdx]].g, context->VertexBuffer[poly->verts[colorIdx]].b, context->VertexBuffer[poly->verts[colorIdx]].a ); } else { 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) { 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) { if((flags & HCDRAW_FLATSHADE_LASTVTX) != 0) { GLsizei colorIdx = poly->numverts - 1; SetFlatColor( context, context->VertexBuffer[poly->verts[colorIdx]].r, context->VertexBuffer[poly->verts[colorIdx]].g, context->VertexBuffer[poly->verts[colorIdx]].b, context->VertexBuffer[poly->verts[colorIdx]].a ); } else { 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) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(Rectf(Self, x1, y1, x2, y2)); Self->GLBegin(GL_POLYGON); cgl_GLVertex4f(Self,x1, y1, 0.0, 1.0); cgl_GLVertex4f(Self,x2, y1, 0.0, 1.0); cgl_GLVertex4f(Self,x2, y2, 0.0, 1.0); cgl_GLVertex4f(Self,x1, y2, 0.0, 1.0); Self->GLEnd(); }