3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Keith Whitwell <keith@tungstengraphics.com>
30 #define CLIP_DOTPROD(K, A, B, C, D) X(K)*A + Y(K)*B + Z(K)*C + W(K)*D
32 #define POLY_CLIP( PLANE, A, B, C, D ) \
35 GLuint idxPrev = inlist[0]; \
36 GLfloat dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \
37 GLuint outcount = 0; \
40 inlist[n] = inlist[0]; /* prevent rotation of vertices */ \
41 for (i = 1; i <= n; i++) { \
42 GLuint idx = inlist[i]; \
43 GLfloat dp = CLIP_DOTPROD(idx, A, B, C, D ); \
45 clipmask[idxPrev] |= PLANE; \
46 if (!IS_NEGATIVE(dpPrev)) { \
47 outlist[outcount++] = idxPrev; \
48 clipmask[idxPrev] &= ~PLANE; \
51 if (DIFFERENT_SIGNS(dp, dpPrev)) { \
52 GLuint newvert = VB->LastClipped++; \
53 VB->ClipMask[newvert] = 0; \
54 outlist[outcount++] = newvert; \
55 if (IS_NEGATIVE(dp)) { \
56 /* Going out of bounds. Avoid division by zero as we \
57 * know dp != dpPrev from DIFFERENT_SIGNS, above. \
59 GLfloat t = dp / (dp - dpPrev); \
60 INTERP_4F( t, coord[newvert], coord[idx], coord[idxPrev]); \
61 interp( ctx, t, newvert, idx, idxPrev, GL_TRUE ); \
65 GLfloat t = dpPrev / (dpPrev - dp); \
66 INTERP_4F( t, coord[newvert], coord[idxPrev], coord[idx]); \
67 interp( ctx, t, newvert, idxPrev, idx, GL_FALSE ); \
79 GLuint *tmp = inlist; \
88 #define LINE_CLIP(PLANE, A, B, C, D ) \
91 GLfloat dpI = CLIP_DOTPROD( ii, A, B, C, D ); \
92 GLfloat dpJ = CLIP_DOTPROD( jj, A, B, C, D ); \
94 if (DIFFERENT_SIGNS(dpI, dpJ)) { \
95 GLuint newvert = VB->LastClipped++; \
96 VB->ClipMask[newvert] = 0; \
97 if (IS_NEGATIVE(dpJ)) { \
98 GLfloat t = dpI / (dpI - dpJ); \
99 VB->ClipMask[jj] |= PLANE; \
100 INTERP_4F( t, coord[newvert], coord[ii], coord[jj] ); \
101 interp( ctx, t, newvert, ii, jj, GL_FALSE ); \
104 GLfloat t = dpJ / (dpJ - dpI); \
105 VB->ClipMask[ii] |= PLANE; \
106 INTERP_4F( t, coord[newvert], coord[jj], coord[ii] ); \
107 interp( ctx, t, newvert, jj, ii, GL_FALSE ); \
111 else if (IS_NEGATIVE(dpI)) \
118 /* Clip a line against the viewport and user clip planes.
121 TAG(clip_line
)( GLcontext
*ctx
, GLuint i
, GLuint j
, GLubyte mask
)
123 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
124 struct vertex_buffer
*VB
= &tnl
->vb
;
125 tnl_interp_func interp
= tnl
->Driver
.Render
.Interp
;
126 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
127 GLuint ii
= i
, jj
= j
, p
;
129 VB
->LastClipped
= VB
->Count
;
132 LINE_CLIP( CLIP_RIGHT_BIT
, -1, 0, 0, 1 );
133 LINE_CLIP( CLIP_LEFT_BIT
, 1, 0, 0, 1 );
134 LINE_CLIP( CLIP_TOP_BIT
, 0, -1, 0, 1 );
135 LINE_CLIP( CLIP_BOTTOM_BIT
, 0, 1, 0, 1 );
136 LINE_CLIP( CLIP_FAR_BIT
, 0, 0, -1, 1 );
137 LINE_CLIP( CLIP_NEAR_BIT
, 0, 0, 1, 1 );
140 if (mask
& CLIP_USER_BIT
) {
141 for (p
=0;p
<MAX_CLIP_PLANES
;p
++) {
142 if (ctx
->Transform
.ClipPlanesEnabled
& (1 << p
)) {
143 const GLfloat a
= ctx
->Transform
._ClipUserPlane
[p
][0];
144 const GLfloat b
= ctx
->Transform
._ClipUserPlane
[p
][1];
145 const GLfloat c
= ctx
->Transform
._ClipUserPlane
[p
][2];
146 const GLfloat d
= ctx
->Transform
._ClipUserPlane
[p
][3];
147 LINE_CLIP( CLIP_USER_BIT
, a
, b
, c
, d
);
152 if ((ctx
->_TriangleCaps
& DD_FLATSHADE
) && j
!= jj
)
153 tnl
->Driver
.Render
.CopyPV( ctx
, jj
, j
);
155 tnl
->Driver
.Render
.ClippedLine( ctx
, ii
, jj
);
159 /* Clip a triangle against the viewport and user clip planes.
162 TAG(clip_tri
)( GLcontext
*ctx
, GLuint v0
, GLuint v1
, GLuint v2
, GLubyte mask
)
164 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
165 struct vertex_buffer
*VB
= &tnl
->vb
;
166 tnl_interp_func interp
= tnl
->Driver
.Render
.Interp
;
167 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
169 GLuint vlist
[2][MAX_CLIPPED_VERTICES
];
170 GLuint
*inlist
= vlist
[0], *outlist
= vlist
[1];
172 GLubyte
*clipmask
= VB
->ClipMask
;
175 ASSIGN_3V(inlist
, v2
, v0
, v1
); /* pv rotated to slot zero */
177 VB
->LastClipped
= VB
->Count
;
180 POLY_CLIP( CLIP_RIGHT_BIT
, -1, 0, 0, 1 );
181 POLY_CLIP( CLIP_LEFT_BIT
, 1, 0, 0, 1 );
182 POLY_CLIP( CLIP_TOP_BIT
, 0, -1, 0, 1 );
183 POLY_CLIP( CLIP_BOTTOM_BIT
, 0, 1, 0, 1 );
184 POLY_CLIP( CLIP_FAR_BIT
, 0, 0, -1, 1 );
185 POLY_CLIP( CLIP_NEAR_BIT
, 0, 0, 1, 1 );
188 if (mask
& CLIP_USER_BIT
) {
189 for (p
=0;p
<MAX_CLIP_PLANES
;p
++) {
190 if (ctx
->Transform
.ClipPlanesEnabled
& (1 << p
)) {
191 const GLfloat a
= ctx
->Transform
._ClipUserPlane
[p
][0];
192 const GLfloat b
= ctx
->Transform
._ClipUserPlane
[p
][1];
193 const GLfloat c
= ctx
->Transform
._ClipUserPlane
[p
][2];
194 const GLfloat d
= ctx
->Transform
._ClipUserPlane
[p
][3];
195 POLY_CLIP( CLIP_USER_BIT
, a
, b
, c
, d
);
200 if (ctx
->_TriangleCaps
& DD_FLATSHADE
) {
201 if (pv
!= inlist
[0]) {
202 ASSERT( inlist
[0] >= VB
->Count
);
203 tnl
->Driver
.Render
.CopyPV( ctx
, inlist
[0], pv
);
207 tnl
->Driver
.Render
.ClippedPolygon( ctx
, inlist
, n
);
211 /* Clip a quad against the viewport and user clip planes.
214 TAG(clip_quad
)( GLcontext
*ctx
, GLuint v0
, GLuint v1
, GLuint v2
, GLuint v3
,
217 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
218 struct vertex_buffer
*VB
= &tnl
->vb
;
219 tnl_interp_func interp
= tnl
->Driver
.Render
.Interp
;
220 GLfloat (*coord
)[4] = VB
->ClipPtr
->data
;
222 GLuint vlist
[2][MAX_CLIPPED_VERTICES
];
223 GLuint
*inlist
= vlist
[0], *outlist
= vlist
[1];
225 GLubyte
*clipmask
= VB
->ClipMask
;
228 ASSIGN_4V(inlist
, v3
, v0
, v1
, v2
); /* pv rotated to slot zero */
230 VB
->LastClipped
= VB
->Count
;
233 POLY_CLIP( CLIP_RIGHT_BIT
, -1, 0, 0, 1 );
234 POLY_CLIP( CLIP_LEFT_BIT
, 1, 0, 0, 1 );
235 POLY_CLIP( CLIP_TOP_BIT
, 0, -1, 0, 1 );
236 POLY_CLIP( CLIP_BOTTOM_BIT
, 0, 1, 0, 1 );
237 POLY_CLIP( CLIP_FAR_BIT
, 0, 0, -1, 1 );
238 POLY_CLIP( CLIP_NEAR_BIT
, 0, 0, 1, 1 );
241 if (mask
& CLIP_USER_BIT
) {
242 for (p
=0;p
<MAX_CLIP_PLANES
;p
++) {
243 if (ctx
->Transform
.ClipPlanesEnabled
& (1 << p
)) {
244 const GLfloat a
= ctx
->Transform
._ClipUserPlane
[p
][0];
245 const GLfloat b
= ctx
->Transform
._ClipUserPlane
[p
][1];
246 const GLfloat c
= ctx
->Transform
._ClipUserPlane
[p
][2];
247 const GLfloat d
= ctx
->Transform
._ClipUserPlane
[p
][3];
248 POLY_CLIP( CLIP_USER_BIT
, a
, b
, c
, d
);
253 if (ctx
->_TriangleCaps
& DD_FLATSHADE
) {
254 if (pv
!= inlist
[0]) {
255 ASSERT( inlist
[0] >= VB
->Count
);
256 tnl
->Driver
.Render
.CopyPV( ctx
, inlist
[0], pv
);
260 tnl
->Driver
.Render
.ClippedPolygon( ctx
, inlist
, n
);