Use correct PV when clipping.
[mesa.git] / src / mesa / tnl / t_vb_cliptmp.h
1 /* $Id: t_vb_cliptmp.h,v 1.12 2001/05/09 12:25:40 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
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.
25 *
26 * Authors:
27 * Keith Whitwell <keithw@valinux.com>
28 */
29
30
31 #define CLIP_DOTPROD(K, A, B, C, D) X(K)*A + Y(K)*B + Z(K)*C + W(K)*D
32
33 #define POLY_CLIP( PLANE, A, B, C, D ) \
34 do { \
35 if (mask & PLANE) { \
36 GLuint idxPrev = inlist[0]; \
37 GLfloat dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \
38 GLuint outcount = 0; \
39 GLuint i; \
40 \
41 inlist[n] = inlist[0]; /* prevent rotation of vertices */ \
42 for (i = 1; i <= n; i++) { \
43 GLuint idx = inlist[i]; \
44 GLfloat dp = CLIP_DOTPROD(idx, A, B, C, D ); \
45 \
46 clipmask[idxPrev] |= PLANE; \
47 if (!NEGATIVE(dpPrev)) { \
48 outlist[outcount++] = idxPrev; \
49 clipmask[idxPrev] &= ~PLANE; \
50 } \
51 \
52 if (DIFFERENT_SIGNS(dp, dpPrev)) { \
53 GLuint newvert = VB->LastClipped++; \
54 VB->ClipMask[newvert] = 0; \
55 outlist[outcount++] = newvert; \
56 if (NEGATIVE(dp)) { \
57 /* Going out of bounds. Avoid division by zero as we \
58 * know dp != dpPrev from DIFFERENT_SIGNS, above. \
59 */ \
60 GLfloat t = dp / (dp - dpPrev); \
61 INTERP_4F( t, coord[newvert], coord[idx], coord[idxPrev]); \
62 interp( ctx, t, newvert, idx, idxPrev, GL_TRUE ); \
63 } else { \
64 /* Coming back in. \
65 */ \
66 GLfloat t = dpPrev / (dpPrev - dp); \
67 INTERP_4F( t, coord[newvert], coord[idxPrev], coord[idx]); \
68 interp( ctx, t, newvert, idxPrev, idx, GL_FALSE ); \
69 } \
70 } \
71 \
72 idxPrev = idx; \
73 dpPrev = dp; \
74 } \
75 \
76 if (outcount < 3) \
77 return; \
78 \
79 { \
80 GLuint *tmp = inlist; \
81 inlist = outlist; \
82 outlist = tmp; \
83 n = outcount; \
84 } \
85 } \
86 } while (0)
87
88
89 #define LINE_CLIP(PLANE, A, B, C, D ) \
90 do { \
91 if (mask & PLANE) { \
92 GLfloat dpI = CLIP_DOTPROD( ii, A, B, C, D ); \
93 GLfloat dpJ = CLIP_DOTPROD( jj, A, B, C, D ); \
94 \
95 if (DIFFERENT_SIGNS(dpI, dpJ)) { \
96 GLuint newvert = VB->LastClipped++; \
97 VB->ClipMask[newvert] = 0; \
98 if (NEGATIVE(dpJ)) { \
99 GLfloat t = dpI / (dpI - dpJ); \
100 VB->ClipMask[jj] |= PLANE; \
101 INTERP_4F( t, coord[newvert], coord[ii], coord[jj] ); \
102 interp( ctx, t, newvert, ii, jj, GL_FALSE ); \
103 jj = newvert; \
104 } else { \
105 GLfloat t = dpJ / (dpJ - dpI); \
106 VB->ClipMask[ii] |= PLANE; \
107 INTERP_4F( t, coord[newvert], coord[jj], coord[ii] ); \
108 interp( ctx, t, newvert, jj, ii, GL_FALSE ); \
109 ii = newvert; \
110 } \
111 } \
112 else if (NEGATIVE(dpI)) \
113 return; \
114 } \
115 } while (0)
116
117
118
119 /* Clip a line against the viewport and user clip planes.
120 */
121 static __inline void TAG(clip_line)( GLcontext *ctx,
122 GLuint i, GLuint j,
123 GLubyte mask )
124 {
125 TNLcontext *tnl = TNL_CONTEXT(ctx);
126 struct vertex_buffer *VB = &tnl->vb;
127 interp_func interp = tnl->Driver.RenderInterp;
128 GLfloat (*coord)[4] = VB->ClipPtr->data;
129 GLuint ii = i, jj = j, p;
130
131 VB->LastClipped = VB->FirstClipped;
132
133 if (mask & 0x3f) {
134 LINE_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
135 LINE_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
136 LINE_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
137 LINE_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
138 LINE_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
139 LINE_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
140 }
141
142 if (mask & CLIP_USER_BIT) {
143 for (p=0;p<MAX_CLIP_PLANES;p++) {
144 if (ctx->Transform.ClipEnabled[p]) {
145 GLfloat a = ctx->Transform._ClipUserPlane[p][0];
146 GLfloat b = ctx->Transform._ClipUserPlane[p][1];
147 GLfloat c = ctx->Transform._ClipUserPlane[p][2];
148 GLfloat d = ctx->Transform._ClipUserPlane[p][3];
149 LINE_CLIP( CLIP_USER_BIT, a, b, c, d );
150 }
151 }
152 }
153
154 if ((ctx->_TriangleCaps & DD_FLATSHADE) && j != jj)
155 tnl->Driver.RenderCopyPV( ctx, jj, j );
156
157 tnl->Driver.RenderClippedLine( ctx, ii, jj );
158 }
159
160
161 /* Clip a triangle against the viewport and user clip planes.
162 */
163 static __inline void TAG(clip_tri)( GLcontext *ctx,
164 GLuint v0, GLuint v1, GLuint v2,
165 GLubyte mask )
166 {
167 TNLcontext *tnl = TNL_CONTEXT(ctx);
168 struct vertex_buffer *VB = &tnl->vb;
169 interp_func interp = tnl->Driver.RenderInterp;
170 GLfloat (*coord)[4] = VB->ClipPtr->data;
171 GLuint pv = v2;
172 GLuint vlist[2][MAX_CLIPPED_VERTICES];
173 GLuint *inlist = vlist[0], *outlist = vlist[1];
174 GLuint p;
175 GLubyte *clipmask = VB->ClipMask;
176 GLuint n = 3;
177
178 ASSIGN_3V(inlist, v2, v0, v1 ); /* pv rotated to slot zero */
179
180 VB->LastClipped = VB->FirstClipped;
181
182 if (mask & 0x3f) {
183 POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
184 POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
185 POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
186 POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
187 POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
188 POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
189 }
190
191 if (mask & CLIP_USER_BIT) {
192 for (p=0;p<MAX_CLIP_PLANES;p++) {
193 if (ctx->Transform.ClipEnabled[p]) {
194 GLfloat a = ctx->Transform._ClipUserPlane[p][0];
195 GLfloat b = ctx->Transform._ClipUserPlane[p][1];
196 GLfloat c = ctx->Transform._ClipUserPlane[p][2];
197 GLfloat d = ctx->Transform._ClipUserPlane[p][3];
198 POLY_CLIP( CLIP_USER_BIT, a, b, c, d );
199 }
200 }
201 }
202
203 if (ctx->_TriangleCaps & DD_FLATSHADE) {
204 if (pv != inlist[0]) {
205 ASSERT( inlist[0] >= VB->FirstClipped );
206 tnl->Driver.RenderCopyPV( ctx, inlist[0], pv );
207 }
208 }
209
210 tnl->Driver.RenderClippedPolygon( ctx, inlist, n );
211 }
212
213
214 /* Clip a quad against the viewport and user clip planes.
215 */
216 static __inline void TAG(clip_quad)( GLcontext *ctx,
217 GLuint v0, GLuint v1, GLuint v2, GLuint v3,
218 GLubyte mask )
219 {
220 TNLcontext *tnl = TNL_CONTEXT(ctx);
221 struct vertex_buffer *VB = &tnl->vb;
222 interp_func interp = tnl->Driver.RenderInterp;
223 GLfloat (*coord)[4] = VB->ClipPtr->data;
224 GLuint pv = v3;
225 GLuint vlist[2][MAX_CLIPPED_VERTICES];
226 GLuint *inlist = vlist[0], *outlist = vlist[1];
227 GLuint p;
228 GLubyte *clipmask = VB->ClipMask;
229 GLuint n = 4;
230
231 ASSIGN_4V(inlist, v3, v0, v1, v2 ); /* pv rotated to slot zero */
232
233 VB->LastClipped = VB->FirstClipped;
234
235 if (mask & 0x3f) {
236 POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
237 POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
238 POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
239 POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
240 POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
241 POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
242 }
243
244 if (mask & CLIP_USER_BIT) {
245 for (p=0;p<MAX_CLIP_PLANES;p++) {
246 if (ctx->Transform.ClipEnabled[p]) {
247 GLfloat a = ctx->Transform._ClipUserPlane[p][0];
248 GLfloat b = ctx->Transform._ClipUserPlane[p][1];
249 GLfloat c = ctx->Transform._ClipUserPlane[p][2];
250 GLfloat d = ctx->Transform._ClipUserPlane[p][3];
251 POLY_CLIP( CLIP_USER_BIT, a, b, c, d );
252 }
253 }
254 }
255
256 if (ctx->_TriangleCaps & DD_FLATSHADE) {
257 if (pv != inlist[0]) {
258 ASSERT( inlist[0] >= VB->FirstClipped );
259 tnl->Driver.RenderCopyPV( ctx, inlist[0], pv );
260 }
261 }
262
263 tnl->Driver.RenderClippedPolygon( ctx, inlist, n );
264 }
265
266 #undef W
267 #undef Z
268 #undef Y
269 #undef X
270 #undef SIZE
271 #undef TAG
272 #undef POLY_CLIP
273 #undef LINE_CLIP