1 /* $Id: t_vb_cliptmp.h,v 1.3 2000/12/27 21:49:40 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
);
138 GLfloat t
= dpPrev
/ (dpPrev
- dp
);
139 newvert
= interp( ctx
, t
, idxPrev
, idx
, GL_FALSE
);
141 clipmask
[newvert
] = 0;
142 outlist
[outcount
++] = newvert
;
164 for (i
= 0 ; i
< n
; i
++)
165 vlist
[i
] = inlist
[i
];
172 /* This now calls the user clip functions if required.
174 static void TAG(viewclip_line
)( GLcontext
*ctx
,
178 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
179 interp_func interp
= (interp_func
) VB
->interpfunc
;
180 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
181 GLuint ii
= i
, jj
= j
;
185 VB
->LastClipped
= VB
->FirstClipped
;
188 * We use 6 instances of this code to clip against the 6 planes.
190 #define GENERAL_CLIP \
191 if (mask & PLANE) { \
192 GLfloat dpI = CLIP_DOTPROD( ii ); \
193 GLfloat dpJ = CLIP_DOTPROD( jj ); \
195 if (DIFFERENT_SIGNS(dpI, dpJ)) { \
196 if (NEGATIVE(dpJ)) { \
197 GLfloat t = dpI / (dpI - dpJ); \
198 VB->ClipMask[jj] |= PLANE; \
199 jj = interp( ctx, t, ii, jj, GL_FALSE ); \
200 VB->ClipMask[jj] = 0; \
202 GLfloat t = dpJ / (dpJ - dpI); \
203 VB->ClipMask[ii] |= PLANE; \
204 ii = interp( ctx, t, jj, ii, GL_FALSE ); \
205 VB->ClipMask[ii] = 0; \
208 else if (NEGATIVE(dpI)) \
213 #define PLANE CLIP_RIGHT_BIT
214 #define CLIP_DOTPROD(K) (- X(K) + W(K))
220 #define PLANE CLIP_LEFT_BIT
221 #define CLIP_DOTPROD(K) (X(K) + W(K))
227 #define PLANE CLIP_TOP_BIT
228 #define CLIP_DOTPROD(K) (- Y(K) + W(K))
234 #define PLANE CLIP_BOTTOM_BIT
235 #define CLIP_DOTPROD(K) (Y(K) + W(K))
241 #define PLANE CLIP_FAR_BIT
242 #define CLIP_DOTPROD(K) (- Z(K) + W(K))
250 #define PLANE CLIP_NEAR_BIT
251 #define CLIP_DOTPROD(K) (Z(K) + W(K))
262 if (mask
& CLIP_USER_BIT
) {
263 if ( TAG(userclip_line
)( ctx
, &ii
, &jj
, interp
) == 0 )
271 /* If necessary, project new vertices.
275 GLfloat (*proj
)[4] = VB
->ProjectedClipPtr
->data
;
276 GLuint start
= VB
->FirstClipped
;
278 for (i
= 0; i
< n
; i
++) {
281 if (SIZE
== 4 && W(j
) != 0.0F
) {
282 GLfloat wInv
= 1.0F
/ W(j
);
283 proj
[j
][0] = X(j
) * wInv
;
284 proj
[j
][1] = Y(j
) * wInv
;
285 proj
[j
][2] = Z(j
) * wInv
;
297 if (ctx
->Driver
.BuildProjectedVertices
)
298 ctx
->Driver
.BuildProjectedVertices(ctx
,
304 /* Render the new line.
306 ctx
->Driver
.LineFunc( ctx
, ii
, jj
, j
);
309 /* We now clip polygon triangles individually. This is necessary to
310 * avoid artifacts dependent on where the boundary of the VB falls
311 * within the polygon. As a result, there is an upper bound on the
312 * number of vertices which may be created, and the test against VB_SIZE
315 static void TAG(viewclip_polygon
)( GLcontext
*ctx
,
316 GLuint n
, GLuint vlist
[], GLuint pv
,
319 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
320 interp_func interp
= (interp_func
) VB
->interpfunc
;
321 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
322 GLuint vlist2
[MAX_CLIPPED_VERTICES
];
323 GLuint
*inlist
= vlist
, *outlist
= vlist2
;
325 GLubyte
*clipmask
= VB
->ClipMask
;
327 VB
->LastClipped
= VB
->FirstClipped
;
329 if (mask
& CLIP_ALL_BITS
) {
331 #define GENERAL_CLIP \
332 if (mask & PLANE) { \
333 GLuint idxPrev = inlist[n-1]; \
334 GLfloat dpPrev = CLIP_DOTPROD(idxPrev); \
335 GLuint outcount = 0; \
340 for (i = 0; i < n; i++) { \
341 GLuint idx = inlist[i]; \
342 GLfloat dp = CLIP_DOTPROD(idx); \
344 if (!NEGATIVE(dpPrev)) { \
345 outlist[outcount++] = idxPrev; \
346 clipmask[idxPrev] &= ~PLANE; \
349 if (DIFFERENT_SIGNS(dp, dpPrev)) { \
351 if (NEGATIVE(dp)) { \
352 /* Going out of bounds. Avoid division by zero as we \
353 * know dp != dpPrev from DIFFERENT_SIGNS, above. \
355 GLfloat t = dp / (dp - dpPrev); \
356 newvert = interp( ctx, t, idx, idxPrev, GL_TRUE ); \
360 GLfloat t = dpPrev / (dpPrev - dp); \
361 newvert = interp( ctx, t, idxPrev, idx, GL_FALSE ); \
363 clipmask[newvert] = mask; \
364 outlist[outcount++] = newvert; \
375 GLuint *tmp = inlist; \
383 #define PLANE CLIP_RIGHT_BIT
384 #define CLIP_DOTPROD(K) (- X(K) + W(K))
392 #define PLANE CLIP_LEFT_BIT
393 #define CLIP_DOTPROD(K) (X(K) + W(K))
400 #define PLANE CLIP_TOP_BIT
401 #define CLIP_DOTPROD(K) (- Y(K) + W(K))
408 #define PLANE CLIP_BOTTOM_BIT
409 #define CLIP_DOTPROD(K) (Y(K) + W(K))
416 #define PLANE CLIP_FAR_BIT
417 #define CLIP_DOTPROD(K) (- Z(K) + W(K))
426 #define PLANE CLIP_NEAR_BIT
427 #define CLIP_DOTPROD(K) (Z(K) + W(K))
438 for (i
= 0 ; i
< n
; i
++)
439 vlist
[i
] = inlist
[i
];
442 /* Clip against user clipping planes in clip space.
444 if (mask
& CLIP_USER_BIT
) {
445 n
= TAG(userclip_polygon
)( ctx
, n
, vlist
, interp
);
449 /* Project if necessary.
453 GLfloat (*proj
)[4] = VB
->ProjectedClipPtr
->data
;
454 GLuint first
= VB
->FirstClipped
;
456 for (i
= 0; i
< n
; i
++) {
459 if (SIZE
== 4 && W(j
) != 0.0F
) {
460 GLfloat wInv
= 1.0F
/ W(j
);
461 proj
[j
][0] = X(j
) * wInv
;
462 proj
[j
][1] = Y(j
) * wInv
;
463 proj
[j
][2] = Z(j
) * wInv
;
475 if (ctx
->Driver
.BuildProjectedVertices
)
476 ctx
->Driver
.BuildProjectedVertices(ctx
,
481 /* Render the new vertices as an unclipped polygon.
482 * Argh - need to pass in pv...
485 GLuint
*tmp
= VB
->Elts
;
487 render_poly_pv_raw_elts( ctx
, 0, n
, PRIM_BEGIN
|PRIM_END
, pv
);