/* * $Id$ * * $Date$ * $Revision$ * * (C) 1999 by Hyperion * All rights reserved * * This file is part of the MiniGL library project * See the file Licence.txt for more details * */ #include "displaylists.h" #include "sysinc.h" #include #include "hclip.h" #include "util.h" static char rcsid[] UNUSED = "$Id$"; void m_BuildInvertedFull(GLcontext context); void v_ToEyeVertex(GLcontext context, MGLVertex *v); #define LERP(t,a,b) \ ({ float aa = a; float bb = b; (aa) + (float)t * ( (bb) - (aa) ); }) #define CLIP_EPS (1e-7) void hc_CodePoint(GLcontext context, MGLVertex *v) { float w = v->clip.w; GLuint outcode = 0; if (v->clip.w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->clip.x) { outcode |= MGL_CLIP_LEFT; } else if (v->clip.x > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->clip.y) { outcode |= MGL_CLIP_BOTTOM; } else if (v->clip.y > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->clip.z) { outcode |= MGL_CLIP_BACK; } else if (v->clip.z > w) { outcode |= MGL_CLIP_FRONT; } if (context->transform.MaxClipPlane != -1) { int i; for (i = 0; i <= context->transform.MaxClipPlane; i++) { if (context->enable.ClipPlane[i]) { GLfloat d = context->transform.UserClipPlane[i].eqn[0] * v->eye.x + context->transform.UserClipPlane[i].eqn[1] * v->eye.y + context->transform.UserClipPlane[i].eqn[2] * v->eye.z + context->transform.UserClipPlane[i].eqn[3] * v->eye.w; v->dist[i] = d; if (d < 0.0) { outcode |= context->transform.UserClipPlane[i].outcode; } // IExec->DebugPrintF("d = %f, eye = <%f, %f, %f, %f> eqn = <%f,%f,%f,%f>\n", // d, v->eye.x, v->eye.y, v->eye.z, v->eye.w, // context->transform.UserClipPlane[i].eqn[0], // context->transform.UserClipPlane[i].eqn[1], // context->transform.UserClipPlane[i].eqn[2], // context->transform.UserClipPlane[i].eqn[3]); // IExec->DebugPrintF("obj = <%f, %f, %f, %f>\n", // v->object.x, v->object.y, v->object.z, v->object.w); // IExec->DebugPrintF("%6.2f %6.2f %6.2f %6.2f\n%6.2f %6.2f %6.2f %6.2f\n%6.2f %6.2f %6.2f %6.2f\n%6.2f %6.2f %6.2f %6.2f\n", // CurrentMV->v[OF_11], CurrentMV->v[OF_12], CurrentMV->v[OF_13], CurrentMV->v[OF_14], // CurrentMV->v[OF_21], CurrentMV->v[OF_22], CurrentMV->v[OF_23], CurrentMV->v[OF_24], // CurrentMV->v[OF_31], CurrentMV->v[OF_32], CurrentMV->v[OF_33], CurrentMV->v[OF_34], // CurrentMV->v[OF_41], CurrentMV->v[OF_42], CurrentMV->v[OF_43], CurrentMV->v[OF_44]); } } } v->outcode = outcode; } #define _x1 (a->clip.x) #define _y1 (a->clip.y) #define _z1 (a->clip.z) #define _w1 (a->clip.w) #define _x2 (b->clip.x) #define _y2 (b->clip.y) #define _z2 (b->clip.z) #define _w2 (b->clip.w) static void hc_ClipPlane(GLcontext context, GLint plane, MGLVertex *a, MGLVertex *b, MGLVertex *r) { float t = 0.0; int i; if ((a->dist[plane] - b->dist[plane]) != 0.0) { t = a->dist[plane] / (a->dist[plane] - b->dist[plane]); } r->clip.x = LERP(t,a->clip.x, b->clip.x); r->clip.y = LERP(t,a->clip.y, b->clip.y); r->clip.z = LERP(t,a->clip.z, b->clip.z); r->clip.w = LERP(t,a->clip.w, b->clip.w); r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = LERP(t, a->uvw[i].w, b->uvw[i].w); } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = LERP(t, a->eye.w, b->eye.w); if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } static void hc_ClipWZero(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *r) { int i = 0; float w1 = _w1, w2 = _w2; float t = (CLIP_EPS-w1)/(w2-w1); r->clip.x = LERP(t,a->clip.x, b->clip.x); r->clip.y = LERP(t,a->clip.y, b->clip.y); r->clip.z = LERP(t,a->clip.z, b->clip.z); r->clip.w = CLIP_EPS; r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = CLIP_EPS; } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = 1.0; if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } static void hc_ClipTop(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *r) { int i = 0; float w1 = _w1, y1 = _y1, w2 = _w2, y2 = _y2; float t = (w1-y1)/((w1-y1)-(w2-y2)); r->clip.x = LERP(t,a->clip.x, b->clip.x); r->clip.z = LERP(t,a->clip.z, b->clip.z); r->clip.w = LERP(t,a->clip.w, b->clip.w); r->clip.y = r->clip.w; r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = LERP(t, a->uvw[i].w, b->uvw[i].w); } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = 1.0; if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } static void hc_ClipBottom(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *r) { int i = 0; float w1 = _w1, y1 = _y1, w2 = _w2, y2 = _y2; float t = (w1+y1)/((w1+y1)-(w2+y2)); r->clip.x = LERP(t,a->clip.x, b->clip.x); r->clip.z = LERP(t,a->clip.z, b->clip.z); r->clip.w = LERP(t,a->clip.w, b->clip.w); r->clip.y = -r->clip.w; r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = LERP(t, a->uvw[i].w, b->uvw[i].w); } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = 1.0; if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } static void hc_ClipLeft(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *r) { int i = 0; float w1=_w1, x1=_x1, w2=_w2, x2=_x2; float t = (w1+x1)/((w1+x1)-(w2+x2)); r->clip.y = LERP(t,a->clip.y, b->clip.y); r->clip.z = LERP(t,a->clip.z, b->clip.z); r->clip.w = LERP(t,a->clip.w, b->clip.w); r->clip.x = -r->clip.w; r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = LERP(t, a->uvw[i].w, b->uvw[i].w); } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = 1.0; if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } static void hc_ClipRight(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *r) { int i = 0; float w1=_w1, x1=_x1, w2=_w2, x2=_x2; float t = (w1-x1)/((w1-x1)-(w2-x2)); r->clip.y = LERP(t,a->clip.y, b->clip.y); r->clip.z = LERP(t,a->clip.z, b->clip.z); r->clip.w = LERP(t,a->clip.w, b->clip.w); r->clip.x = r->clip.w; r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = LERP(t, a->uvw[i].w, b->uvw[i].w); } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = 1.0; if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } static void hc_ClipFront(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *r) { int i = 0; float w1=_w1, z1=_z1, w2=_w2, z2=_z2; float t = (w1-z1)/((w1-z1)-(w2-z2)); r->clip.x = LERP(t,a->clip.x, b->clip.x); r->clip.y = LERP(t,a->clip.y, b->clip.y); r->clip.w = LERP(t,a->clip.w, b->clip.w); r->clip.z = r->clip.w; r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = LERP(t, a->uvw[i].w, b->uvw[i].w); } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = 1.0; if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } static void hc_ClipBack(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *r) { int i = 0; float w1=_w1,z1=_z1,w2=_w2,z2=_z2; float t = (w1+z1)/((w1+z1)-(w2+z2)); r->clip.x = LERP(t,a->clip.x, b->clip.x); r->clip.y = LERP(t,a->clip.y, b->clip.y); r->clip.w = LERP(t,a->clip.w, b->clip.w); r->clip.z = -r->clip.w; r->a = LERP(t,a->a, b->a); r->r = LERP(t,a->r, b->r); r->g = LERP(t,a->g, b->g); r->b = LERP(t,a->b, b->b); for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->enable.Texture2D[i] || context->enable.Texture1D[i]) { r->uvw[i].u = LERP(t,a->uvw[i].u, b->uvw[i].u); r->uvw[i].v = LERP(t,a->uvw[i].v, b->uvw[i].v); if (a->uvw[i].w == 1.0 && b->uvw[i].w == 1.0) { r->uvw[i].w = 1.0; } else { r->uvw[i].w = LERP(t, a->uvw[i].w, b->uvw[i].w); } r->rhw_valid[i] = a->rhw_valid[i]; } } if (context->NeedEye) { r->eye.x = LERP(t, a->eye.x, b->eye.x); r->eye.y = LERP(t, a->eye.y, b->eye.y); r->eye.z = LERP(t, a->eye.z, b->eye.z); r->eye.w = 1.0; if (context->NeedEyeNormal) { r->EyeNormal = a->EyeNormal; // FIXME: incorrect } } hc_CodePoint(context, r); } #undef x1 #undef y1 #undef z1 #undef w1 #undef x2 #undef y2 #undef z2 #undef w2 GLboolean hc_GetFrontFacing(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *c, GLuint outcode) { GLboolean front; float a1,a2,b1,b2,r; float aw,bw,cw; aw = 1.0 / a->clip.w; bw = 1.0 / b->clip.w; cw = 1.0 / c->clip.w; #define EPSILON 1e-5 a1 = a->clip.x*aw - b->clip.x*bw; a2 = a->clip.y*aw - b->clip.y*bw; b1 = c->clip.x*cw - b->clip.x*bw; b2 = c->clip.y*cw - b->clip.y*bw; r = a1*b2-a2*b1; if (fast_fabs(a1) < EPSILON && fast_fabs(a2) < EPSILON) { return GL_TRUE; } if (fast_fabs(b1) < EPSILON && fast_fabs(b2) < EPSILON) { return GL_TRUE; } if ((r < 0.0 && context->polygon.FrontFace == GL_CCW) || (r > 0.0 && context->polygon.FrontFace == GL_CW) ) { front = GL_TRUE; } else { front = GL_FALSE; } return front; } GLboolean hc_DecideFrontface(GLcontext context, MGLVertex *a, MGLVertex *b, MGLVertex *c, GLuint outcode) { GLboolean front; float a1,a2,b1,b2,r; float aw,bw,cw; if (context->enable.CullFace == GL_FALSE) { return GL_TRUE; } if (context->polygon.CullFace == GL_FRONT_AND_BACK) { return GL_FALSE; } /* ** The following line returns GL_TRUE if one or more of the vertices lie beyond the ** camera plane. This is of course a wrong assumption, but those will be culled at ** the clipping stage after the negative W coordinates have been removed. */ if (outcode&MGL_CLIP_NEGW) { return GL_TRUE; } aw = 1.0 / a->clip.w; bw = 1.0 / b->clip.w; cw = 1.0 / c->clip.w; #define EPSILON 1e-5 a1 = a->clip.x*aw - b->clip.x*bw; a2 = a->clip.y*aw - b->clip.y*bw; b1 = c->clip.x*cw - b->clip.x*bw; b2 = c->clip.y*cw - b->clip.y*bw; r = a1*b2-a2*b1; if (fast_fabs(a1) < EPSILON && fast_fabs(a2) < EPSILON) { return GL_TRUE; } if (fast_fabs(b1) < EPSILON && fast_fabs(b2) < EPSILON) { return GL_TRUE; } if ((r < 0.0 && context->polygon.FrontFace == GL_CCW) || (r > 0.0 && context->polygon.FrontFace == GL_CW) ) { front = GL_TRUE; } else { front = GL_FALSE; } if (context->polygon.CullFace == GL_BACK) { return front; } else { return !front; } } void EstablishCullState(GLcontext context) { /* See if it's enabled at all */ if (context->enable.CullFace == GL_FALSE) { /* No */ return; } else { switch (context->polygon.CullFace) { case GL_FRONT_AND_BACK: /* Same as off */ return; case GL_FRONT: /* Same as Warp3D */ if (context->polygon.FrontFace == GL_CCW) { IWarp3D->W3D_SetFrontFace(context->w3dContext, W3D_CW); } else { IWarp3D->W3D_SetFrontFace(context->w3dContext, W3D_CCW); } break; case GL_BACK: /* Opposite of Warp3D */ if (context->polygon.FrontFace == GL_CW) { IWarp3D->W3D_SetFrontFace(context->w3dContext, W3D_CW); } else { IWarp3D->W3D_SetFrontFace(context->w3dContext, W3D_CCW); } break; } } } void cgl_GLFrontFace(struct GLContextIFace *Self, GLenum mode) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(FrontFace(Self, mode)) if (mode == GL_CW || mode == GL_CCW) { context->polygon.FrontFace = mode; EstablishCullState(context); } else { GLFlagError(context, 1, GL_INVALID_ENUM); } } void cgl_GLCullFace(struct GLContextIFace *Self, GLenum mode) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(CullFace(Self, mode)) if (mode == GL_FRONT || mode == GL_FRONT_AND_BACK || mode == GL_BACK) { context->polygon.CullFace = mode; EstablishCullState(context); } else { GLFlagError(context, 1, GL_INVALID_ENUM); } } /* ** Complicated clipping macro stuff. */ #define VERTP(i) &(context->VertexBuffer[a->verts[i]]) #define VERT(i) context->VertexBuffer[a->verts[i]] #define POLYSWAP \ if (b->numverts == 0) return GL_FALSE; \ temp=a; a=b; b=temp; \ #define POLYSWAP_DBG \ if (b->numverts == 0) {IExec->DebugPrintF("nothing left\n"); return;} \ temp=a; a=b; b=temp; \ #define USERPLANES (MGL_CLIP_USER0|MGL_CLIP_USER1|MGL_CLIP_USER2|MGL_CLIP_USER3|MGL_CLIP_USER4|MGL_CLIP_USER5|MGL_CLIP_USER6|MGL_CLIP_USER7) #define DOCLIP(edge, routine) \ if (or_codes & edge) \ { \ b->numverts = 0; \ prev = 0; \ for (i=1; inumverts; i++) \ { \ /* Case 1 and 4*/ \ if (!(VERT(prev).outcode & edge)) \ { \ b->verts[b->numverts] = a->verts[prev]; \ b->numverts++; \ } \ /* Case 3 and 4 */ \ if ((VERT(prev).outcode ^ VERT(i).outcode) & edge) \ { \ hc_##routine (context, VERTP(prev), VERTP(i), \ &(context->VertexBuffer[free])); \ b->verts[b->numverts]=free++; \ b->numverts++; \ } \ prev = i; \ } \ /* Case 1 and 4*/ \ if (!(VERT(prev).outcode & edge)) \ { \ b->verts[b->numverts] = a->verts[prev]; \ b->numverts++; \ } \ /* Case 3 and 4 */ \ if ((VERT(prev).outcode ^ VERT(0).outcode) & edge) \ { \ hc_##routine (context, VERTP(prev), VERTP(0), \ &(context->VertexBuffer[free])); \ b->verts[b->numverts]=free++; \ b->numverts++; \ } \ POLYSWAP \ } #define DOCLIP_USER(edge, plane) \ if (or_codes & edge) \ { \ b->numverts = 0; \ prev = a->numverts-1; \ for (i=0; inumverts; i++) \ { \ /* Case 1 and 4*/ \ if (!(VERT(prev).outcode & edge)) \ { \ b->verts[b->numverts] = a->verts[prev]; \ b->numverts++; \ } \ /* Case 3 and 4 */ \ if ((VERT(prev).outcode ^ VERT(i).outcode) & edge) \ { \ hc_ClipPlane(context, plane, VERTP(prev), VERTP(i), \ &(context->VertexBuffer[free])); \ b->verts[b->numverts]=free++; \ b->numverts++; \ } \ prev = i; \ } \ POLYSWAP \ } extern void dh_DrawPoly(GLcontext context, MGLPolygon *poly, DrawPolyFlags_t flags); extern void dh_DrawPolyFF(GLcontext context, MGLPolygon *poly, DrawPolyFlags_t flags); inline GLboolean hc_ClipPoly(GLcontext context, MGLPolygon *poly, GLuint or_codes, MGLPolygon **output, MGLPolygon *tempPoly) { /* ** Sutherland-Hodgeman clipping algorithm (almost) ** ** This clipping algorithm sucessively clips against each of the six ** clipping planes (and, if enabled, user clipping planes). ** Vertices are copied from a to b and swapped at the end. ** Output occurs within the clipping region: ** ** ** | clip plane ** | ** a-------i-------b ** | | | ** | | | ** | | | ** d-------j-------c ** | ** | ** ** In the above figure, the algorithm first consideres edge d-a. Since it ** does not cross the clipping plane, it outputs d and proceeds to edge ** a-b. Since it crosses, it outputs a, calculates intersection i and outputs it. ** No output occurs while b-c is considered, since it lies outside the frustum ** and does not cross it. Finally, edge c-d yields output j. ** ** The result is d-a-i-j ** ** Classification of edges are divided into four cases: ** Case 1: Edge is completely inside -> two vertices (current and prev) ** Case 2: Edge is completely outside -> no output ** Case 3: Edge enters the frustum -> one output (current) ** Case 4: Edge leaves frustum -> two outputs (current and clipped) ** ** At any stage, if the output polygon has zero vertices, return immediately. */ MGLPolygon *a, *b, *temp; int i,j; int prev; int free = context->VertexBufferPointer; GLboolean flag; GLuint original_or_codes = or_codes; a = poly; b=tempPoly; DOCLIP(MGL_CLIP_NEGW, ClipWZero); for (j=0;jnumverts; j++) { or_codes |= context->VertexBuffer[a->verts[j]].outcode; } if (context->transform.MaxClipPlane != -1) { for (j = 0; j <= context->transform.MaxClipPlane; j++) { if (context->enable.ClipPlane[j]) { DOCLIP_USER(context->transform.UserClipPlane[j].outcode, j); } } } DOCLIP(MGL_CLIP_LEFT, ClipLeft) DOCLIP(MGL_CLIP_RIGHT, ClipRight) DOCLIP(MGL_CLIP_FRONT, ClipFront) DOCLIP(MGL_CLIP_BACK, ClipBack) DOCLIP(MGL_CLIP_TOP, ClipTop) DOCLIP(MGL_CLIP_BOTTOM, ClipBottom) if ((original_or_codes & MGL_CLIP_NEGW) && a->numverts>2) { flag = hc_DecideFrontface( context, &(context->VertexBuffer[a->verts[0]]), &(context->VertexBuffer[a->verts[1]]), &(context->VertexBuffer[a->verts[2]]), 0 ); if (flag == GL_FALSE) { return GL_FALSE; } } // If we get here, there are vertices left... a->zoffset = poly->zoffset; *output = a; return GL_TRUE; } void hc_ClipAndDrawPoly(GLcontext context, MGLPolygon *poly, GLuint or_codes, DrawPolyFlags_t flags) { MGLPolygon *outputPoly, *temp = context->LargePolygonOut; if (hc_ClipPoly(context, poly, or_codes, &outputPoly, temp) == GL_TRUE) { if (context->lighting.ShadeModel == GL_FLAT) { // Need to pull the flat colour from the original polygon MGLVertex *inVtx, *outVtx; if((flags & HCDRAW_FLATSHADE_LASTVTX) != 0) { inVtx = &(context->VertexBuffer[poly->verts[poly->numverts - 1]]); outVtx = &(context->VertexBuffer[outputPoly->verts[outputPoly->numverts - 1]]); } else { inVtx = &(context->VertexBuffer[poly->verts[0]]); outVtx = &(context->VertexBuffer[outputPoly->verts[0]]); } outVtx->r = inVtx->r; outVtx->g = inVtx->g; outVtx->b = inVtx->b; outVtx->a = inVtx->a; } dh_DrawPoly(context, outputPoly, flags); } } inline GLboolean hc_ClipPolyFF(GLcontext context, MGLPolygon *poly, GLuint or_codes, MGLPolygon **output, MGLPolygon *tempPoly) { MGLPolygon *a, *b, *temp; int i,j; int prev; int free = context->VertexBufferPointer; a = poly; b=tempPoly; DOCLIP(MGL_CLIP_NEGW, ClipWZero); for (j=0;jnumverts; j++) { or_codes |= context->VertexBuffer[a->verts[j]].outcode; } if (context->transform.MaxClipPlane != -1) { for (j = 0; j <= context->transform.MaxClipPlane; j++) { if (context->enable.ClipPlane[j]) { DOCLIP_USER(context->transform.UserClipPlane[j].outcode, j); } } } DOCLIP(MGL_CLIP_LEFT, ClipLeft) DOCLIP(MGL_CLIP_RIGHT, ClipRight) DOCLIP(MGL_CLIP_FRONT, ClipFront) DOCLIP(MGL_CLIP_BACK, ClipBack) DOCLIP(MGL_CLIP_TOP, ClipTop) DOCLIP(MGL_CLIP_BOTTOM, ClipBottom) // If we get here, there are vertices left... *output = a; return GL_TRUE; } void hc_ClipAndDrawPolyFF(GLcontext context, MGLPolygon *poly, GLuint or_codes, DrawPolyFlags_t flags) { MGLPolygon *outputPoly, *temp = context->LargePolygonOut; if (hc_ClipPolyFF(context, poly, or_codes, &outputPoly, temp) == GL_TRUE) { dh_DrawPolyFF(context, outputPoly, flags); } } #define LINE_CLIP(point, point2, plane, func) \ if (point->outcode & plane) \ { \ hc_##func(context, point, point2, r); \ point = r; \ } #define LINE_CLIP_USER(point, point2, plane, planeNr) \ if (point->outcode & plane) \ { \ hc_ClipPlane(context, planeNr, point, point2, r); \ point = r; \ } extern void dh_DrawLine(GLcontext context, MGLPolygon *poly); GLboolean hc_LineClip(GLcontext context, uint32 *pts) { MGLVertex *p1 = &context->VertexBuffer[pts[0]]; MGLVertex *p2 = &context->VertexBuffer[pts[1]]; uint32 free = context->VertexBufferPointer; int j; if (p1->outcode & p2->outcode) { // Trivial reject return GL_FALSE; } if ((p1->outcode | p2->outcode) == 0) { // Trivial accept return GL_TRUE; } if (p1->outcode) { // Point 1 is out of the frustum, clip to inside pts[0] = free; free++; MGLVertex *r = &context->VertexBuffer[pts[0]]; LINE_CLIP(p1, p2, MGL_CLIP_NEGW, ClipWZero) if (context->transform.MaxClipPlane != -1) { for (j = 0; j <= context->transform.MaxClipPlane; j++) { if (context->enable.ClipPlane[j]) { LINE_CLIP_USER(p1, p2, context->transform.UserClipPlane[j].outcode, j); } } } LINE_CLIP(p1, p2, MGL_CLIP_LEFT, ClipLeft) LINE_CLIP(p1, p2, MGL_CLIP_RIGHT, ClipRight) LINE_CLIP(p1, p2, MGL_CLIP_FRONT, ClipFront) LINE_CLIP(p1, p2, MGL_CLIP_BACK, ClipBack) LINE_CLIP(p1, p2, MGL_CLIP_TOP, ClipTop) LINE_CLIP(p1, p2, MGL_CLIP_BOTTOM, ClipBottom) } if (p2->outcode) { // point 2 is out of the furstum pts[1] = free; MGLVertex *r = &context->VertexBuffer[pts[1]]; LINE_CLIP(p2, p1, MGL_CLIP_NEGW, ClipWZero) if (context->transform.MaxClipPlane != -1) { for (j = 0; j <= context->transform.MaxClipPlane; j++) { if (context->enable.ClipPlane[j]) { LINE_CLIP_USER(p2, p1, context->transform.UserClipPlane[j].outcode, j); } } } LINE_CLIP(p2, p1, MGL_CLIP_LEFT, ClipLeft) LINE_CLIP(p2, p1, MGL_CLIP_RIGHT, ClipRight) LINE_CLIP(p2, p1, MGL_CLIP_FRONT, ClipFront) LINE_CLIP(p2, p1, MGL_CLIP_BACK, ClipBack) LINE_CLIP(p2, p1, MGL_CLIP_TOP, ClipTop) LINE_CLIP(p2, p1, MGL_CLIP_BOTTOM, ClipBottom) } return GL_TRUE; } // TODO: This was retrofitted to fit the old API, it would be better to // get this done right to get right of the queer conversion stuff. void hc_ClipAndDrawLine(GLcontext context, MGLPolygon *poly, GLuint or_codes) { MGLPolygon p; uint32 pts[2]; if (poly->numverts != 2) { return; // Huh? } pts[0] = poly->verts[0]; pts[1] = poly->verts[1]; if (GL_FALSE == hc_LineClip(context, pts)) { return; // rejected } p.numverts = 2; p.verts[0] = pts[0]; p.verts[1] = pts[1]; dh_DrawLine(context,&p); } void cgl_GLClipPlane(struct GLContextIFace *Self, GLenum plane, const GLdouble *eqn) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(ClipPlane(Self, plane, eqn)) GLFlagError(context, plane < GL_CLIP_PLANE0, GL_INVALID_ENUM); plane-= GL_CLIP_PLANE0; GLFlagError(context, plane >= MGL_MAX_CLIPPLANES, GL_INVALID_ENUM); if (context->InverseModelViewValid != GL_TRUE) { m_BuildInvertedFull(context); } #define a(x) (context->InverseModelView.v[OF_##x]) context->transform.UserClipPlane[plane].eqn[0] = a(11)*eqn[0] + a(21)*eqn[1] + a(31)*eqn[2] + a(41)*eqn[3]; context->transform.UserClipPlane[plane].eqn[1] = a(12)*eqn[0] + a(22)*eqn[1] + a(32)*eqn[2] + a(42)*eqn[3]; context->transform.UserClipPlane[plane].eqn[2] = a(13)*eqn[0] + a(23)*eqn[1] + a(33)*eqn[2] + a(43)*eqn[3]; context->transform.UserClipPlane[plane].eqn[3] = a(14)*eqn[0] + a(24)*eqn[1] + a(34)*eqn[2] + a(44)*eqn[3]; // IExec->DebugPrintF("GL_CLIP_PLANE%d: <%f, %f, %f, %f>\n", (planeNum), // (float)context->transform.UserClipPlane[planeNum].eqn[0], // (float)context->transform.UserClipPlane[planeNum].eqn[1], // (float)context->transform.UserClipPlane[planeNum].eqn[2], // (float)context->transform.UserClipPlane[planeNum].eqn[3]); #undef a } void cgl_GLGetClipPlane(struct GLContextIFace *Self, GLenum plane, GLdouble *eqn) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, plane < GL_CLIP_PLANE0, GL_INVALID_ENUM); plane-=GL_CLIP_PLANE0; GLFlagError(context, plane >= MGL_MAX_CLIPPLANES, GL_INVALID_ENUM); eqn[0] = context->transform.UserClipPlane[plane].eqn[0]; eqn[1] = context->transform.UserClipPlane[plane].eqn[1]; eqn[2] = context->transform.UserClipPlane[plane].eqn[2]; eqn[3] = context->transform.UserClipPlane[plane].eqn[3]; }