home *** CD-ROM | disk | FTP | other *** search
- /* $Id: clip_funcs.h,v 1.4 1999/09/30 11:18:21 keithw Exp $ */
-
- /*
- * Mesa 3-D graphics library
- * Version: 3.1
- *
- * Copyright (C) 1999 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
- /*
- * New (3.1) transformation code written by Keith Whitwell.
- */
-
- static GLuint TAG(userclip_line)( struct vertex_buffer *VB,
- GLuint *i, GLuint *j );
- static GLuint TAG(userclip_polygon)( struct vertex_buffer *VB,
- GLuint n, GLuint vlist[] );
-
-
-
- /* This now calls the user clip functions if required.
- */
- static GLuint TAG(viewclip_line)( struct vertex_buffer *VB,
- GLuint *i, GLuint *j,
- GLubyte mask )
- {
- GLfloat (*coord)[4] = VB->ClipPtr->data;
- GLfloat t, dx, dy, dz, dw, neww;
- GLuint ii = *i, jj = *j;
- GLuint vlist[2];
- GLuint n;
- clip_interp_func interp = VB->ctx->ClipInterpFunc;
- GLuint vb_free = VB->FirstFree;
-
- /*
- * We use 6 instances of this code to clip agains the 6 planes.
- * For each plane, we define the OUTSIDE and COMPUTE_INTERSECTION
- * macros apprpriately.
- */
- #define GENERAL_CLIP \
- if (mask & PLANE) { \
- GLuint flagI = INSIDE( ii ); \
- GLuint flagJ = INSIDE( jj ); \
- \
- if (!(flagI|flagJ)) \
- return 0; \
- \
- if (flagI ^ flagJ) { \
- COMPUTE_INTERSECTION( jj, ii, vb_free ); \
- interp( VB, vb_free, t, jj, ii); \
- \
- if (flagI) { \
- VB->ClipMask[jj] |= PLANE; \
- jj = vb_free; \
- } else { \
- VB->ClipMask[ii] |= PLANE; \
- ii = vb_free; \
- } \
- \
- VB->ClipMask[vb_free++] = 0; \
- } \
- }
-
- #include "general_clip.h"
-
- VB->Free = vb_free;
-
- if (mask & CLIP_USER_BIT) {
- if ( TAG(userclip_line)( VB, &ii, &jj ) == 0 )
- return 0;
- }
-
- vlist[0] = ii;
- vlist[1] = jj;
- n = 2;
-
- /* Should always be at least one new vertex.
- */
- {
- const GLfloat *m = VB->ctx->Viewport.WindowMap.m;
- GLfloat sx = m[MAT_SX];
- GLfloat tx = m[MAT_TX];
- GLfloat sy = m[MAT_SY];
- GLfloat ty = m[MAT_TY];
- GLfloat sz = m[MAT_SZ];
- GLfloat tz = m[MAT_TZ];
- GLuint i, j;
- GLfloat (*win)[4] = VB->Win.data;
- GLuint start = VB->FirstFree;
-
- for (i = 0; i < n; i++) {
- j = vlist[i];
- if (j >= start) {
- if (W(j) != 0.0F) {
- GLfloat wInv = 1.0F / W(j);
- win[j][0] = X(j) * wInv * sx + tx;
- win[j][1] = Y(j) * wInv * sy + ty;
- win[j][2] = Z(j) * wInv * sz + tz;
- win[j][3] = wInv;
- } else {
- win[j][0] = win[j][1] = win[j][2] = 0.0F;
- win[j][3] = 1.0F;
- }
- }
- }
- }
-
- if (VB->ctx->Driver.RasterSetup)
- VB->ctx->Driver.RasterSetup(VB, VB->FirstFree, VB->Free);
-
- *i = ii;
- *j = jj;
- return 1;
- }
-
- /* We now clip polygon triangles individually. This is necessary to
- * avoid artifacts dependent on where the boundary of the VB falls
- * within the polygon. As a result, there is an upper bound on the
- * number of vertices which may be created, and the test against VB_SIZE
- * is redundant.
- */
- static GLuint TAG(viewclip_polygon)( struct vertex_buffer *VB,
- GLuint n, GLuint vlist[],
- GLubyte mask )
- {
- GLfloat (*coord)[4] = VB->ClipPtr->data;
- GLuint vlist2[VB_SIZE-VB_MAX];
- GLuint *inlist = vlist, *outlist = vlist2;
- GLdouble dx, dy, dz, dw, t = 0, neww;
- GLuint i;
- GLuint vb_free = VB->FirstFree;
- clip_interp_func interp = VB->ctx->ClipInterpFunc;
-
- if (mask & CLIP_ALL_BITS) {
-
- #define GENERAL_CLIP \
- if (mask & PLANE) { \
- GLuint prevj = inlist[n-1]; \
- GLuint prevflag = INSIDE(prevj); \
- GLuint outcount = 0; \
- GLuint ef_state = 3; \
- GLuint i; \
- \
- \
- for (i = 0; i < n; i++) { \
- GLuint j = inlist[i]; \
- GLuint flag = INSIDE(j); \
- \
- if (flag ^ prevflag) { \
- if (flag) { \
- /* Coming back in \
- */ \
- COMPUTE_INTERSECTION( j, prevj, vb_free ); \
- interp( VB, vb_free, t, j, prevj ); \
- \
- if (IND&CLIP_TAB_EDGEFLAG) \
- VB->EdgeFlagPtr->data[vb_free] = \
- VB->EdgeFlagPtr->data[prevj] & ef_state; \
- \
- \
- } else { \
- /* Going out of bounds \
- */ \
- COMPUTE_INTERSECTION( prevj, j, vb_free ); \
- interp( VB, vb_free, t, prevj, j ); \
- \
- if (IND&CLIP_TAB_EDGEFLAG) \
- VB->EdgeFlagPtr->data[vb_free] = 1; \
- } \
- \
- outlist[outcount++] = vb_free; \
- VB->ClipMask[vb_free++] = 0; \
- } \
- \
- if (flag) { \
- outlist[outcount++] = j; \
- } else { \
- VB->ClipMask[j] |= (PLANE&CLIP_ALL_BITS); /* don't setup */ \
- } \
- prevj = j; \
- prevflag = flag; \
- ef_state = 1; \
- } \
- \
- if (outcount < 3) \
- return 0; \
- else { \
- GLuint *tmp = inlist; \
- inlist = outlist; \
- outlist = tmp; \
- n = outcount; \
- } \
- }
-
-
- #include "general_clip.h"
-
- if (inlist != vlist)
- for (i = 0 ; i < n ; i++)
- vlist[i] = inlist[i];
- }
-
- VB->Free = vb_free;
-
- /* Clip against user clipping planes in clip space.
- */
- if (mask & CLIP_USER_BIT) {
- n = TAG(userclip_polygon)( VB, n, vlist );
- if (n < 3) return 0;
- }
-
-
- {
- const GLfloat *m = VB->ctx->Viewport.WindowMap.m;
- GLfloat sx = m[MAT_SX];
- GLfloat tx = m[MAT_TX];
- GLfloat sy = m[MAT_SY];
- GLfloat ty = m[MAT_TY];
- GLfloat sz = m[MAT_SZ];
- GLfloat tz = m[MAT_TZ];
- GLuint i;
- GLfloat (*win)[4] = VB->Win.data;
- GLuint first = VB->FirstFree;
-
- for (i = 0; i < n; i++) {
- GLuint j = vlist[i];
- if (j >= first) {
- if (W(j) != 0.0F) {
- GLfloat wInv = 1.0F / W(j);
- win[j][0] = X(j) * wInv * sx + tx;
- win[j][1] = Y(j) * wInv * sy + ty;
- win[j][2] = Z(j) * wInv * sz + tz;
- win[j][3] = wInv;
- } else {
- win[j][0] = win[j][1] = win[j][2] = 0.0;
- win[j][3] = 1.0F;
- }
- }
- }
- }
-
- if (VB->ctx->Driver.RasterSetup)
- VB->ctx->Driver.RasterSetup(VB, VB->FirstFree, VB->Free);
-
- return n;
- }
-
-
- #define INSIDE( J ) !NEGATIVE(J)
- #define OUTSIDE( J ) NEGATIVE(J)
-
-
-
-
- static GLuint TAG(userclip_line)( struct vertex_buffer *VB,
- GLuint *i, GLuint *j )
- {
- GLcontext *ctx = VB->ctx;
- GLfloat (*coord)[4] = VB->ClipPtr->data;
- clip_interp_func interp = ctx->ClipInterpFunc;
- GLuint ii = *i;
- GLuint jj = *j;
- GLuint p;
- GLuint vb_free = VB->Free;
-
- for (p=0;p<MAX_CLIP_PLANES;p++) {
- if (ctx->Transform.ClipEnabled[p]) {
- GLfloat a = ctx->Transform.ClipUserPlane[p][0];
- GLfloat b = ctx->Transform.ClipUserPlane[p][1];
- GLfloat c = ctx->Transform.ClipUserPlane[p][2];
- GLfloat d = ctx->Transform.ClipUserPlane[p][3];
-
- GLfloat dpI = d*W(ii) + c*Z(ii) + b*Y(ii) + a*X(ii);
- GLfloat dpJ = d*W(jj) + c*Z(jj) + b*Y(jj) + a*X(jj);
-
- GLuint flagI = OUTSIDE( dpI );
- GLuint flagJ = OUTSIDE( dpJ );
-
- if (flagI & flagJ)
- return 0;
-
- if (flagI ^ flagJ) {
- GLfloat t = -dpI/(dpJ-dpI);
-
- INTERP_SZ( t, coord, vb_free, ii, jj, SIZE );
- interp( VB, vb_free, t, ii, jj );
-
- if (flagI) {
- VB->ClipMask[ii] |= CLIP_USER_BIT;
- ii = vb_free;
- } else {
- VB->ClipMask[jj] |= CLIP_USER_BIT;
- jj = vb_free;
- }
-
- VB->ClipMask[vb_free++] = 0;
- }
- }
- }
-
- VB->Free = vb_free;
- *i = ii;
- *j = jj;
- return 1;
- }
-
-
- static GLuint TAG(userclip_polygon)( struct vertex_buffer *VB,
- GLuint n, GLuint vlist[] )
- {
- GLcontext *ctx = VB->ctx;
- GLfloat (*coord)[4] = VB->ClipPtr->data;
- clip_interp_func interp = ctx->ClipInterpFunc;
- GLuint vlist2[VB_SIZE];
- GLuint *inlist = vlist, *outlist = vlist2;
- GLuint vb_free = VB->Free;
- GLuint p;
-
- for (p=0;p<MAX_CLIP_PLANES;p++) {
- if (ctx->Transform.ClipEnabled[p]) {
- register float a = ctx->Transform.ClipUserPlane[p][0];
- register float b = ctx->Transform.ClipUserPlane[p][1];
- register float c = ctx->Transform.ClipUserPlane[p][2];
- register float d = ctx->Transform.ClipUserPlane[p][3];
-
- /* initialize prev to be last in the input list */
- GLuint prevj = inlist[n - 1];
- GLfloat dpJ = d*W(prevj) + c*Z(prevj) + b*Y(prevj) + a*X(prevj);
- GLuint flagJ = INSIDE(dpJ);
- GLuint outcount = 0;
- GLuint curri;
-
- for (curri=0;curri<n;curri++) {
- GLuint currj = inlist[curri];
- GLfloat dpI = d*W(currj) + c*Z(currj) + b*Y(currj) + a*X(currj);
- GLuint flagI = INSIDE(dpI);
-
- if (flagI ^ flagJ) {
- GLfloat t;
- GLuint in;
- GLuint out;
-
- if (flagI) {
- out = prevj;
- in = currj;
- t = dpI/(dpI-dpJ);
-
- if (IND&CLIP_TAB_EDGEFLAG)
- VB->EdgeFlagPtr->data[vb_free] =
- VB->EdgeFlagPtr->data[prevj];
- } else {
- in = prevj;
- out = currj;
- t = dpJ/(dpJ-dpI);
-
- if (IND&CLIP_TAB_EDGEFLAG)
- VB->EdgeFlagPtr->data[vb_free] = 1;
- }
-
- INTERP_SZ( t, coord, vb_free, in, out, SIZE );
- interp( VB, vb_free, t, in, out);
- outlist[outcount++] = vb_free;
- VB->ClipMask[vb_free++] = 0;
- }
-
- if (flagI) {
- outlist[outcount++] = currj;
- } else {
- VB->ClipMask[currj] |= CLIP_USER_BIT;
- }
-
- prevj = currj;
- flagJ = flagI;
- dpJ = dpI;
- }
-
- if (outcount < 3)
- return 0;
- else {
- GLuint *tmp;
- tmp = inlist;
- inlist = outlist;
- outlist = tmp;
- n = outcount;
- }
-
- } /* if */
- } /* for p */
-
- if (inlist!=vlist) {
- GLuint i;
- for (i = 0 ; i < n ; i++)
- vlist[i] = inlist[i];
- }
-
- VB->Free = vb_free;
- return n;
- }
-
-
- static void TAG(init_clip_funcs)(void)
- {
- gl_poly_clip_tab[IND][SIZE] = TAG(viewclip_polygon);
- gl_line_clip_tab[IND][SIZE] = TAG(viewclip_line);
- }
-
- #undef W
- #undef Z
- #undef Y
- #undef X
- #undef SIZE
- #undef TAG
- #undef INSIDE
- #undef OUTSIDE
- #undef IND
-