1 /* $Id: t_vb_cliptmp.h,v 1.2 2000/12/27 19:57:37 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Keith Whitwell <keithw@valinux.com>
31 #define INSIDE( J ) !NEGATIVE(J)
32 #define OUTSIDE( J ) NEGATIVE(J)
37 static GLuint
TAG(userclip_line
)( GLcontext
*ctx
,
41 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
42 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
47 for (p
=0;p
<MAX_CLIP_PLANES
;p
++) {
48 if (ctx
->Transform
.ClipEnabled
[p
]) {
49 GLfloat a
= ctx
->Transform
._ClipUserPlane
[p
][0];
50 GLfloat b
= ctx
->Transform
._ClipUserPlane
[p
][1];
51 GLfloat c
= ctx
->Transform
._ClipUserPlane
[p
][2];
52 GLfloat d
= ctx
->Transform
._ClipUserPlane
[p
][3];
54 GLfloat dpI
= d
*W(ii
) + c
*Z(ii
) + b
*Y(ii
) + a
*X(ii
);
55 GLfloat dpJ
= d
*W(jj
) + c
*Z(jj
) + b
*Y(jj
) + a
*X(jj
);
57 GLuint flagI
= OUTSIDE( dpI
);
58 GLuint flagJ
= OUTSIDE( dpJ
);
62 GLfloat t
= dpI
/ (dpI
- dpJ
);
63 VB
->ClipMask
[jj
] |= CLIP_USER_BIT
;
64 jj
= interp( ctx
, t
, ii
, jj
, GL_FALSE
);
67 GLfloat t
= dpJ
/ (dpJ
- dpI
);
68 VB
->ClipMask
[ii
] |= CLIP_USER_BIT
;
69 ii
= interp( ctx
, t
, jj
, ii
, GL_FALSE
);
84 static GLuint
TAG(userclip_polygon
)( GLcontext
*ctx
,
89 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
90 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
91 GLuint vlist2
[MAX_CLIPPED_VERTICES
];
92 GLuint
*inlist
= vlist
, *outlist
= vlist2
;
93 GLubyte
*clipmask
= VB
->ClipMask
;
96 #define CLIP_DOTPROD(xx) d*W(xx) + c*Z(xx) + b*Y(xx) + a*X(xx)
98 /* Can be speeded up to if vertex_stage actually saves the
99 * UserClipMask, and if it is used in this loop (after computing a
102 for (p
=0;p
<MAX_CLIP_PLANES
;p
++) {
103 if (ctx
->Transform
.ClipEnabled
[p
]) {
104 register float a
= ctx
->Transform
._ClipUserPlane
[p
][0];
105 register float b
= ctx
->Transform
._ClipUserPlane
[p
][1];
106 register float c
= ctx
->Transform
._ClipUserPlane
[p
][2];
107 register float d
= ctx
->Transform
._ClipUserPlane
[p
][3];
109 /* initialize prev to be last in the input list */
110 GLuint idxPrev
= inlist
[n
-1];
111 GLfloat dpPrev
= CLIP_DOTPROD(idxPrev
);
115 for (i
= 0 ; i
< n
; i
++) {
116 GLuint idx
= inlist
[i
];
117 GLfloat dp
= CLIP_DOTPROD(idx
);
119 if (!NEGATIVE(dpPrev
)) {
120 outlist
[outcount
++] = idxPrev
;
121 clipmask
[idxPrev
] &= ~CLIP_USER_BIT
;
123 clipmask
[idxPrev
] |= CLIP_USER_BIT
;
127 if (DIFFERENT_SIGNS(dp
, dpPrev
)) {
130 /* Going out of bounds. Avoid division by zero as we
131 * know dp != dpPrev from DIFFERENT_SIGNS, above.
133 GLfloat t
= dp
/ (dp
- dpPrev
);
134 newvert
= interp( ctx
, t
, idx
, idxPrev
, GL_TRUE
);
135 /* fprintf(stderr,"Goint out: in: %d/%d out: %d/%d new: %d/%d\n", */
136 /* idxPrev, VB->EdgeFlagPtr->data[idxPrev], */
137 /* idx, VB->EdgeFlagPtr->data[idx], */
138 /* newvert, VB->EdgeFlagPtr->data[newvert]); */
142 GLfloat t
= dpPrev
/ (dpPrev
- dp
);
143 newvert
= interp( ctx
, t
, idxPrev
, idx
, GL_FALSE
);
144 /* fprintf(stderr,"coming in: in: %d/%d out: %d/%d new: %d/%d\n", */
145 /* idx, VB->EdgeFlagPtr->data[idx], */
146 /* idxPrev, VB->EdgeFlagPtr->data[idxPrev], */
147 /* newvert, VB->EdgeFlagPtr->data[newvert]); */
149 clipmask
[newvert
] = 0;
150 outlist
[outcount
++] = newvert
;
172 for (i
= 0 ; i
< n
; i
++)
173 vlist
[i
] = inlist
[i
];
176 /* fprintf(stderr, "%s: finally:\n", __FUNCTION__); */
177 /* for (i = 0 ; i < n ; i++) */
178 /* fprintf(stderr, "%d: %d\n", vlist[i], VB->EdgeFlagPtr->data[vlist[i]]); */
184 /* This now calls the user clip functions if required.
186 static void TAG(viewclip_line
)( GLcontext
*ctx
,
190 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
191 interp_func interp
= (interp_func
) VB
->interpfunc
;
192 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
193 GLuint ii
= i
, jj
= j
;
197 VB
->LastClipped
= VB
->FirstClipped
;
200 * We use 6 instances of this code to clip against the 6 planes.
202 #define GENERAL_CLIP \
203 if (mask & PLANE) { \
204 GLfloat dpI = CLIP_DOTPROD( ii ); \
205 GLfloat dpJ = CLIP_DOTPROD( jj ); \
207 if (DIFFERENT_SIGNS(dpI, dpJ)) { \
208 if (NEGATIVE(dpJ)) { \
209 GLfloat t = dpI / (dpI - dpJ); \
210 VB->ClipMask[jj] |= PLANE; \
211 jj = interp( ctx, t, ii, jj, GL_FALSE ); \
212 VB->ClipMask[jj] = 0; \
214 GLfloat t = dpJ / (dpJ - dpI); \
215 VB->ClipMask[ii] |= PLANE; \
216 ii = interp( ctx, t, jj, ii, GL_FALSE ); \
217 VB->ClipMask[ii] = 0; \
220 else if (NEGATIVE(dpI)) \
225 #define PLANE CLIP_RIGHT_BIT
226 #define CLIP_DOTPROD(K) (- X(K) + W(K))
232 #define PLANE CLIP_LEFT_BIT
233 #define CLIP_DOTPROD(K) (X(K) + W(K))
239 #define PLANE CLIP_TOP_BIT
240 #define CLIP_DOTPROD(K) (- Y(K) + W(K))
246 #define PLANE CLIP_BOTTOM_BIT
247 #define CLIP_DOTPROD(K) (Y(K) + W(K))
253 #define PLANE CLIP_FAR_BIT
254 #define CLIP_DOTPROD(K) (- Z(K) + W(K))
262 #define PLANE CLIP_NEAR_BIT
263 #define CLIP_DOTPROD(K) (Z(K) + W(K))
274 if (mask
& CLIP_USER_BIT
) {
275 if ( TAG(userclip_line
)( ctx
, &ii
, &jj
, interp
) == 0 )
283 /* If necessary, project new vertices.
287 GLfloat (*proj
)[4] = VB
->ProjectedClipPtr
->data
;
288 GLuint start
= VB
->FirstClipped
;
290 for (i
= 0; i
< n
; i
++) {
293 if (SIZE
== 4 && W(j
) != 0.0F
) {
294 GLfloat wInv
= 1.0F
/ W(j
);
295 proj
[j
][0] = X(j
) * wInv
;
296 proj
[j
][1] = Y(j
) * wInv
;
297 proj
[j
][2] = Z(j
) * wInv
;
309 if (ctx
->Driver
.BuildProjectedVertices
)
310 ctx
->Driver
.BuildProjectedVertices(ctx
,
316 /* Render the new line.
318 ctx
->Driver
.LineFunc( ctx
, ii
, jj
, j
);
321 /* We now clip polygon triangles individually. This is necessary to
322 * avoid artifacts dependent on where the boundary of the VB falls
323 * within the polygon. As a result, there is an upper bound on the
324 * number of vertices which may be created, and the test against VB_SIZE
327 static void TAG(viewclip_polygon
)( GLcontext
*ctx
,
328 GLuint n
, GLuint vlist
[], GLuint pv
,
331 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
332 interp_func interp
= (interp_func
) VB
->interpfunc
;
333 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
334 GLuint vlist2
[MAX_CLIPPED_VERTICES
];
335 GLuint
*inlist
= vlist
, *outlist
= vlist2
;
337 GLubyte
*clipmask
= VB
->ClipMask
;
339 VB
->LastClipped
= VB
->FirstClipped
;
341 if (mask
& CLIP_ALL_BITS
) {
343 #define GENERAL_CLIP \
344 if (mask & PLANE) { \
345 GLuint idxPrev = inlist[n-1]; \
346 GLfloat dpPrev = CLIP_DOTPROD(idxPrev); \
347 GLuint outcount = 0; \
352 for (i = 0; i < n; i++) { \
353 GLuint idx = inlist[i]; \
354 GLfloat dp = CLIP_DOTPROD(idx); \
356 if (!NEGATIVE(dpPrev)) { \
357 outlist[outcount++] = idxPrev; \
358 clipmask[idxPrev] &= ~PLANE; \
361 if (DIFFERENT_SIGNS(dp, dpPrev)) { \
363 if (NEGATIVE(dp)) { \
364 /* Going out of bounds. Avoid division by zero as we \
365 * know dp != dpPrev from DIFFERENT_SIGNS, above. \
367 GLfloat t = dp / (dp - dpPrev); \
368 newvert = interp( ctx, t, idx, idxPrev, GL_TRUE ); \
372 GLfloat t = dpPrev / (dpPrev - dp); \
373 newvert = interp( ctx, t, idxPrev, idx, GL_FALSE ); \
375 clipmask[newvert] = mask; \
376 outlist[outcount++] = newvert; \
387 GLuint *tmp = inlist; \
395 #define PLANE CLIP_RIGHT_BIT
396 #define CLIP_DOTPROD(K) (- X(K) + W(K))
404 #define PLANE CLIP_LEFT_BIT
405 #define CLIP_DOTPROD(K) (X(K) + W(K))
412 #define PLANE CLIP_TOP_BIT
413 #define CLIP_DOTPROD(K) (- Y(K) + W(K))
420 #define PLANE CLIP_BOTTOM_BIT
421 #define CLIP_DOTPROD(K) (Y(K) + W(K))
428 #define PLANE CLIP_FAR_BIT
429 #define CLIP_DOTPROD(K) (- Z(K) + W(K))
438 #define PLANE CLIP_NEAR_BIT
439 #define CLIP_DOTPROD(K) (Z(K) + W(K))
450 for (i
= 0 ; i
< n
; i
++)
451 vlist
[i
] = inlist
[i
];
454 /* Clip against user clipping planes in clip space.
456 if (mask
& CLIP_USER_BIT
) {
457 n
= TAG(userclip_polygon
)( ctx
, n
, vlist
, interp
);
461 /* Project if necessary.
465 GLfloat (*proj
)[4] = VB
->ProjectedClipPtr
->data
;
466 GLuint first
= VB
->FirstClipped
;
468 for (i
= 0; i
< n
; i
++) {
471 if (SIZE
== 4 && W(j
) != 0.0F
) {
472 GLfloat wInv
= 1.0F
/ W(j
);
473 proj
[j
][0] = X(j
) * wInv
;
474 proj
[j
][1] = Y(j
) * wInv
;
475 proj
[j
][2] = Z(j
) * wInv
;
487 if (ctx
->Driver
.BuildProjectedVertices
)
488 ctx
->Driver
.BuildProjectedVertices(ctx
,
493 /* Render the new vertices as an unclipped polygon.
494 * Argh - need to pass in pv...
497 GLuint
*tmp
= VB
->Elts
;
499 render_poly_pv_raw_elts( ctx
, 0, n
, PRIM_BEGIN
|PRIM_END
, pv
);