diff options
Diffstat (limited to 'src/mesa/tnl/t_vb_cliptmp.h')
-rw-r--r-- | src/mesa/tnl/t_vb_cliptmp.h | 558 |
1 files changed, 161 insertions, 397 deletions
diff --git a/src/mesa/tnl/t_vb_cliptmp.h b/src/mesa/tnl/t_vb_cliptmp.h index 1aeb014e159..5957f4960cc 100644 --- a/src/mesa/tnl/t_vb_cliptmp.h +++ b/src/mesa/tnl/t_vb_cliptmp.h @@ -1,4 +1,4 @@ -/* $Id: t_vb_cliptmp.h,v 1.4 2000/12/28 22:11:05 keithw Exp $ */ +/* $Id: t_vb_cliptmp.h,v 1.5 2001/01/05 02:26:49 keithw Exp $ */ /* * Mesa 3-D graphics library @@ -28,340 +28,45 @@ */ -#define INSIDE( J ) !NEGATIVE(J) -#define OUTSIDE( J ) NEGATIVE(J) +#define CLIP_DOTPROD(K, A, B, C, D) X(K)*A + Y(K)*B + Z(K)*C + W(K)*D - - - -static GLuint TAG(userclip_line)( GLcontext *ctx, - GLuint *i, GLuint *j, - interp_func interp ) -{ - struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; - GLfloat (*coord)[4] = VB->ClipPtr->data; - GLuint ii = *i; - GLuint jj = *j; - GLuint p; - - 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) { - if (flagJ) { - GLfloat t = dpI / (dpI - dpJ); - VB->ClipMask[jj] |= CLIP_USER_BIT; - jj = interp( ctx, t, ii, jj, GL_FALSE ); - VB->ClipMask[jj] = 0; - } else { - GLfloat t = dpJ / (dpJ - dpI); - VB->ClipMask[ii] |= CLIP_USER_BIT; - ii = interp( ctx, t, jj, ii, GL_FALSE ); - VB->ClipMask[ii] = 0; - } - } - else if (flagI) - return 0; - } - } - - *i = ii; - *j = jj; - return 1; -} - - -static GLuint TAG(userclip_polygon)( GLcontext *ctx, - GLuint n, - GLuint vlist[], - interp_func interp ) -{ - struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; - GLfloat (*coord)[4] = VB->ClipPtr->data; - GLuint vlist2[MAX_CLIPPED_VERTICES]; - GLuint *inlist = vlist, *outlist = vlist2; - GLubyte *clipmask = VB->ClipMask; - GLuint p; - -#define CLIP_DOTPROD(xx) d*W(xx) + c*Z(xx) + b*Y(xx) + a*X(xx) - - /* Can be speeded up to if vertex_stage actually saves the - * UserClipMask, and if it is used in this loop (after computing a - * UserClipOrMask). - */ - 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 idxPrev = inlist[n-1]; - GLfloat dpPrev = CLIP_DOTPROD(idxPrev); - GLuint outcount = 0; - GLuint i; - - for (i = 0 ; i < n ; i++) { - GLuint idx = inlist[i]; - GLfloat dp = CLIP_DOTPROD(idx); - - if (!NEGATIVE(dpPrev)) { - outlist[outcount++] = idxPrev; - clipmask[idxPrev] &= ~CLIP_USER_BIT; - } else { - clipmask[idxPrev] |= CLIP_USER_BIT; - } - - - if (DIFFERENT_SIGNS(dp, dpPrev)) { - GLuint newvert; - if (NEGATIVE(dp)) { - /* Going out of bounds. Avoid division by zero as we - * know dp != dpPrev from DIFFERENT_SIGNS, above. - */ - GLfloat t = dp / (dp - dpPrev); - newvert = interp( ctx, t, idx, idxPrev, GL_TRUE ); - } else { - /* Coming back in. - */ - GLfloat t = dpPrev / (dpPrev - dp); - newvert = interp( ctx, t, idxPrev, idx, GL_FALSE ); - } - clipmask[newvert] = 0; - outlist[outcount++] = newvert; - } - - idxPrev = idx; - dpPrev = dp; - } - - if (outcount < 3) - return 0; - - { - 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]; - } - - return n; -} - - -/* This now calls the user clip functions if required. - */ -static void TAG(viewclip_line)( GLcontext *ctx, - GLuint i, GLuint j, - GLubyte mask ) -{ - struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; - interp_func interp = (interp_func) VB->interpfunc; - GLfloat (*coord)[4] = VB->ClipPtr->data; - GLuint ii = i, jj = j; - GLuint vlist[2]; - GLuint n; - - VB->LastClipped = VB->FirstClipped; - -/* - * We use 6 instances of this code to clip against the 6 planes. - */ -#define GENERAL_CLIP \ - if (mask & PLANE) { \ - GLfloat dpI = CLIP_DOTPROD( ii ); \ - GLfloat dpJ = CLIP_DOTPROD( jj ); \ - \ - if (DIFFERENT_SIGNS(dpI, dpJ)) { \ - if (NEGATIVE(dpJ)) { \ - GLfloat t = dpI / (dpI - dpJ); \ - VB->ClipMask[jj] |= PLANE; \ - jj = interp( ctx, t, ii, jj, GL_FALSE ); \ - VB->ClipMask[jj] = 0; \ - } else { \ - GLfloat t = dpJ / (dpJ - dpI); \ - VB->ClipMask[ii] |= PLANE; \ - ii = interp( ctx, t, jj, ii, GL_FALSE ); \ - VB->ClipMask[ii] = 0; \ - } \ - } \ - else if (NEGATIVE(dpI)) \ - return; \ - } - -#undef CLIP_DOTPROD -#define PLANE CLIP_RIGHT_BIT -#define CLIP_DOTPROD(K) (- X(K) + W(K)) - - GENERAL_CLIP - -#undef CLIP_DOTPROD -#undef PLANE -#define PLANE CLIP_LEFT_BIT -#define CLIP_DOTPROD(K) (X(K) + W(K)) - - GENERAL_CLIP - -#undef CLIP_DOTPROD -#undef PLANE -#define PLANE CLIP_TOP_BIT -#define CLIP_DOTPROD(K) (- Y(K) + W(K)) - - GENERAL_CLIP - -#undef CLIP_DOTPROD -#undef PLANE -#define PLANE CLIP_BOTTOM_BIT -#define CLIP_DOTPROD(K) (Y(K) + W(K)) - - GENERAL_CLIP - -#undef CLIP_DOTPROD -#undef PLANE -#define PLANE CLIP_FAR_BIT -#define CLIP_DOTPROD(K) (- Z(K) + W(K)) - - if (SIZE >= 3) { - GENERAL_CLIP - } - -#undef CLIP_DOTPROD -#undef PLANE -#define PLANE CLIP_NEAR_BIT -#define CLIP_DOTPROD(K) (Z(K) + W(K)) - - if (SIZE >=3 ) { - GENERAL_CLIP - } - -#undef CLIP_DOTPROD -#undef PLANE -#undef GENERAL_CLIP - - - if (mask & CLIP_USER_BIT) { - if ( TAG(userclip_line)( ctx, &ii, &jj, interp ) == 0 ) - return; - } - - vlist[0] = ii; - vlist[1] = jj; - n = 2; - - /* If necessary, project new vertices. - */ - { - GLuint i, j; - GLfloat (*proj)[4] = VB->ProjectedClipPtr->data; - GLuint start = VB->FirstClipped; - - for (i = 0; i < n; i++) { - j = vlist[i]; - if (j >= start) { - if (SIZE == 4 && W(j) != 0.0F) { - GLfloat wInv = 1.0F / W(j); - proj[j][0] = X(j) * wInv; - proj[j][1] = Y(j) * wInv; - proj[j][2] = Z(j) * wInv; - proj[j][3] = wInv; - } else { - proj[j][0] = X(j); - proj[j][1] = Y(j); - proj[j][2] = Z(j); - proj[j][3] = W(j); - } - } - } - } - - if (ctx->Driver.BuildProjectedVertices) - ctx->Driver.BuildProjectedVertices(ctx, - VB->FirstClipped, - VB->LastClipped, - ~0); - - - /* Render the new line. - */ - ctx->Driver.LineFunc( ctx, ii, jj, j ); -} - -/* 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 void TAG(viewclip_polygon)( GLcontext *ctx, - GLuint n, GLuint vlist[], GLuint pv, - GLubyte mask ) -{ - struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; - interp_func interp = (interp_func) VB->interpfunc; - GLfloat (*coord)[4] = VB->ClipPtr->data; - GLuint vlist2[MAX_CLIPPED_VERTICES]; - GLuint *inlist = vlist, *outlist = vlist2; - GLuint i; - GLubyte *clipmask = VB->ClipMask; - - VB->LastClipped = VB->FirstClipped; - - if (mask & CLIP_ALL_BITS) { - -#define GENERAL_CLIP \ +#define POLY_CLIP( PLANE, A, B, C, D ) \ +do { \ if (mask & PLANE) { \ - GLuint idxPrev = inlist[n-1]; \ - GLfloat dpPrev = CLIP_DOTPROD(idxPrev); \ + GLuint idxPrev = inlist[0]; \ + GLfloat dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \ GLuint outcount = 0; \ GLuint i; \ - \ - mask &= ~PLANE; \ - \ - for (i = 0; i < n; i++) { \ + \ + inlist[n] = inlist[0]; /* prevent rotation of vertices */ \ + for (i = 1; i <= n; i++) { \ GLuint idx = inlist[i]; \ - GLfloat dp = CLIP_DOTPROD(idx); \ + GLfloat dp = CLIP_DOTPROD(idx, A, B, C, D ); \ \ + clipmask[idxPrev] |= PLANE; \ if (!NEGATIVE(dpPrev)) { \ outlist[outcount++] = idxPrev; \ clipmask[idxPrev] &= ~PLANE; \ } \ \ if (DIFFERENT_SIGNS(dp, dpPrev)) { \ - GLuint newvert; \ + GLuint newvert = VB->LastClipped++; \ + VB->ClipMask[newvert] = 0; \ + outlist[outcount++] = newvert; \ if (NEGATIVE(dp)) { \ /* Going out of bounds. Avoid division by zero as we \ * know dp != dpPrev from DIFFERENT_SIGNS, above. \ */ \ GLfloat t = dp / (dp - dpPrev); \ - newvert = interp( ctx, t, idx, idxPrev, GL_TRUE ); \ - } else { \ + LINTERP_SZ( t, coord, newvert, idx, idxPrev, SIZE ); \ + interp( ctx, t, newvert, idx, idxPrev, GL_TRUE ); \ + } else { \ /* Coming back in. \ */ \ GLfloat t = dpPrev / (dpPrev - dp); \ - newvert = interp( ctx, t, idxPrev, idx, GL_FALSE ); \ + LINTERP_SZ( t, coord, newvert, idxPrev, idx, SIZE ); \ + interp( ctx, t, newvert, idxPrev, idx, GL_FALSE ); \ } \ - clipmask[newvert] = mask; \ - outlist[outcount++] = newvert; \ } \ \ idxPrev = idx; \ @@ -377,125 +82,184 @@ static void TAG(viewclip_polygon)( GLcontext *ctx, outlist = tmp; \ n = outcount; \ } \ - } - - -#define PLANE CLIP_RIGHT_BIT -#define CLIP_DOTPROD(K) (- X(K) + W(K)) - - GENERAL_CLIP - -#undef CLIP_DOTPROD -#undef PLANE - - -#define PLANE CLIP_LEFT_BIT -#define CLIP_DOTPROD(K) (X(K) + W(K)) - - GENERAL_CLIP + } \ +} while (0) + + +#define LINE_CLIP(PLANE, A, B, C, D ) \ +do { \ + if (mask & PLANE) { \ + GLfloat dpI = CLIP_DOTPROD( ii, A, B, C, D ); \ + GLfloat dpJ = CLIP_DOTPROD( jj, A, B, C, D ); \ + \ + if (DIFFERENT_SIGNS(dpI, dpJ)) { \ + GLuint newvert = VB->LastClipped++; \ + VB->ClipMask[newvert] = 0; \ + if (NEGATIVE(dpJ)) { \ + GLfloat t = dpI / (dpI - dpJ); \ + VB->ClipMask[jj] |= PLANE; \ + LINTERP_SZ( t, coord, newvert, ii, jj, SIZE ); \ + interp( ctx, t, newvert, ii, jj, GL_FALSE ); \ + jj = newvert; \ + } else { \ + GLfloat t = dpJ / (dpJ - dpI); \ + VB->ClipMask[ii] |= PLANE; \ + LINTERP_SZ( t, coord, newvert, jj, ii, SIZE ); \ + interp( ctx, t, newvert, jj, ii, GL_FALSE ); \ + ii = newvert; \ + } \ + } \ + else if (NEGATIVE(dpI)) \ + return; \ + } \ +} while (0) + + +/* Project if necessary. + */ +static void TAG(build_proj_verts)( GLcontext *ctx ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLfloat (*coord)[4] = VB->ClipPtr->data; + GLfloat (*proj)[4] = VB->ProjectedClipPtr->data; + GLuint last = VB->LastClipped; + GLuint i; -#undef CLIP_DOTPROD -#undef PLANE + for (i = VB->FirstClipped; i < last; i++) { + if (VB->ClipMask[i] == 0) { + if (SIZE == 4 && W(i) != 0.0F) { + GLfloat wInv = 1.0F / W(i); + proj[i][0] = X(i) * wInv; + proj[i][1] = Y(i) * wInv; + proj[i][2] = Z(i) * wInv; + proj[i][3] = wInv; + } else { + proj[i][0] = X(i); + proj[i][1] = Y(i); + proj[i][2] = Z(i); + proj[i][3] = W(i); + } + } + } -#define PLANE CLIP_TOP_BIT -#define CLIP_DOTPROD(K) (- Y(K) + W(K)) + ctx->Driver.BuildProjectedVertices(ctx, + VB->FirstClipped, + VB->LastClipped, + ~0); +} - GENERAL_CLIP +/* Clip a line against the viewport and user clip planes. + */ +static void TAG(clip_line)( GLcontext *ctx, + GLuint i, GLuint j, + GLubyte mask ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + interp_func interp = (interp_func) VB->interpfunc; + GLfloat (*coord)[4] = VB->ClipPtr->data; + GLuint ii = i, jj = j, p; -#undef CLIP_DOTPROD -#undef PLANE + VB->LastClipped = VB->FirstClipped; -#define PLANE CLIP_BOTTOM_BIT -#define CLIP_DOTPROD(K) (Y(K) + W(K)) + if (mask & 0x3f) { + LINE_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); + LINE_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); + LINE_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); + LINE_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 ); + LINE_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 ); + LINE_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 ); + } - GENERAL_CLIP + if (mask & CLIP_USER_BIT) { + 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]; + LINE_CLIP( CLIP_USER_BIT, a, b, c, d ); + } + } + } -#undef CLIP_DOTPROD -#undef PLANE + TAG(build_proj_verts)( ctx ); -#define PLANE CLIP_FAR_BIT -#define CLIP_DOTPROD(K) (- Z(K) + W(K)) + if ((ctx->_TriangleCaps & DD_FLATSHADE) && j != jj) + VB->copypvfunc( ctx, jj, j ); - if (SIZE >= 3) { - GENERAL_CLIP - } + /* Render the new line. + */ + ctx->Driver.LineFunc( ctx, ii, jj ); -#undef CLIP_DOTPROD -#undef PLANE +} -#define PLANE CLIP_NEAR_BIT -#define CLIP_DOTPROD(K) (Z(K) + W(K)) - if (SIZE >=3 ) { - GENERAL_CLIP - } +/* Clip a triangle or quad against the viewport and user clip planes. + */ +static void TAG(clip_polygon)( GLcontext *ctx, + GLuint n, GLuint vlist[], + GLubyte mask ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + interp_func interp = (interp_func) VB->interpfunc; + GLfloat (*coord)[4] = VB->ClipPtr->data; + GLuint pv = vlist[0]; + GLuint vlist2[MAX_CLIPPED_VERTICES]; + GLuint *inlist = vlist, *outlist = vlist2; + GLuint p; + GLubyte *clipmask = VB->ClipMask; -#undef CLIP_DOTPROD -#undef PLANE -#undef GENERAL_CLIP + VB->LastClipped = VB->FirstClipped; - if (inlist != vlist) - for (i = 0 ; i < n ; i++) - vlist[i] = inlist[i]; + if (mask & 0x3f) { + POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); + POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); + POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); + POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 ); + POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 ); + POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 ); } - /* Clip against user clipping planes in clip space. - */ if (mask & CLIP_USER_BIT) { - n = TAG(userclip_polygon)( ctx, n, vlist, interp ); - if (n < 3) return; + 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]; + POLY_CLIP( CLIP_USER_BIT, a, b, c, d ); + } + } } - /* Project if necessary. - */ - { - GLuint i; - GLfloat (*proj)[4] = VB->ProjectedClipPtr->data; - GLuint first = VB->FirstClipped; - - for (i = 0; i < n; i++) { - GLuint j = vlist[i]; - if (j >= first) { - if (SIZE == 4 && W(j) != 0.0F) { - GLfloat wInv = 1.0F / W(j); - proj[j][0] = X(j) * wInv; - proj[j][1] = Y(j) * wInv; - proj[j][2] = Z(j) * wInv; - proj[j][3] = wInv; - } else { - proj[j][0] = X(j); - proj[j][1] = Y(j); - proj[j][2] = Z(j); - proj[j][3] = W(j); - } - } + if (ctx->_TriangleCaps & DD_FLATSHADE) { + if (pv != inlist[0]) { + ASSERT( inlist[0] >= VB->FirstClipped ); + VB->copypvfunc( ctx, inlist[0], pv ); } } - if (ctx->Driver.BuildProjectedVertices) - ctx->Driver.BuildProjectedVertices(ctx, - VB->FirstClipped, - VB->LastClipped, - ~0); + TAG(build_proj_verts)( ctx ); /* Render the new vertices as an unclipped polygon. - * Argh - need to pass in pv... */ { GLuint *tmp = VB->Elts; - VB->Elts = vlist; - render_poly_pv_raw_elts( ctx, 0, n, PRIM_BEGIN|PRIM_END, pv ); + VB->Elts = inlist; + ctx->Driver.RenderTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END ); VB->Elts = tmp; } } + + #undef W #undef Z #undef Y #undef X #undef SIZE #undef TAG -#undef INSIDE -#undef OUTSIDE +#undef POLY_CLIP +#undef LINE_CLIP |