fix sproingies bug
[mesa.git] / src / mesa / tnl / t_vb_cliptmp.h
1 /* $Id: t_vb_cliptmp.h,v 1.3 2000/12/27 21:49:40 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999 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 * Author:
27 * Keith Whitwell <keithw@valinux.com>
28 */
29
30
31 #define INSIDE( J ) !NEGATIVE(J)
32 #define OUTSIDE( J ) NEGATIVE(J)
33
34
35
36
37 static GLuint TAG(userclip_line)( GLcontext *ctx,
38 GLuint *i, GLuint *j,
39 interp_func interp )
40 {
41 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
42 GLfloat (*coord)[4] = VB->ClipPtr->data;
43 GLuint ii = *i;
44 GLuint jj = *j;
45 GLuint p;
46
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];
53
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);
56
57 GLuint flagI = OUTSIDE( dpI );
58 GLuint flagJ = OUTSIDE( dpJ );
59
60 if (flagI ^ flagJ) {
61 if (flagJ) {
62 GLfloat t = dpI / (dpI - dpJ);
63 VB->ClipMask[jj] |= CLIP_USER_BIT;
64 jj = interp( ctx, t, ii, jj, GL_FALSE );
65 VB->ClipMask[jj] = 0;
66 } else {
67 GLfloat t = dpJ / (dpJ - dpI);
68 VB->ClipMask[ii] |= CLIP_USER_BIT;
69 ii = interp( ctx, t, jj, ii, GL_FALSE );
70 VB->ClipMask[ii] = 0;
71 }
72 }
73 else if (flagI)
74 return 0;
75 }
76 }
77
78 *i = ii;
79 *j = jj;
80 return 1;
81 }
82
83
84 static GLuint TAG(userclip_polygon)( GLcontext *ctx,
85 GLuint n,
86 GLuint vlist[],
87 interp_func interp )
88 {
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;
94 GLuint p;
95
96 #define CLIP_DOTPROD(xx) d*W(xx) + c*Z(xx) + b*Y(xx) + a*X(xx)
97
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
100 * UserClipOrMask).
101 */
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];
108
109 /* initialize prev to be last in the input list */
110 GLuint idxPrev = inlist[n-1];
111 GLfloat dpPrev = CLIP_DOTPROD(idxPrev);
112 GLuint outcount = 0;
113 GLuint i;
114
115 for (i = 0 ; i < n ; i++) {
116 GLuint idx = inlist[i];
117 GLfloat dp = CLIP_DOTPROD(idx);
118
119 if (!NEGATIVE(dpPrev)) {
120 outlist[outcount++] = idxPrev;
121 clipmask[idxPrev] &= ~CLIP_USER_BIT;
122 } else {
123 clipmask[idxPrev] |= CLIP_USER_BIT;
124 }
125
126
127 if (DIFFERENT_SIGNS(dp, dpPrev)) {
128 GLuint newvert;
129 if (NEGATIVE(dp)) {
130 /* Going out of bounds. Avoid division by zero as we
131 * know dp != dpPrev from DIFFERENT_SIGNS, above.
132 */
133 GLfloat t = dp / (dp - dpPrev);
134 newvert = interp( ctx, t, idx, idxPrev, GL_TRUE );
135 } else {
136 /* Coming back in.
137 */
138 GLfloat t = dpPrev / (dpPrev - dp);
139 newvert = interp( ctx, t, idxPrev, idx, GL_FALSE );
140 }
141 clipmask[newvert] = 0;
142 outlist[outcount++] = newvert;
143 }
144
145 idxPrev = idx;
146 dpPrev = dp;
147 }
148
149 if (outcount < 3)
150 return 0;
151
152 {
153 GLuint *tmp;
154 tmp = inlist;
155 inlist = outlist;
156 outlist = tmp;
157 n = outcount;
158 }
159 } /* if */
160 } /* for p */
161
162 if (inlist!=vlist) {
163 GLuint i;
164 for (i = 0 ; i < n ; i++)
165 vlist[i] = inlist[i];
166 }
167
168 return n;
169 }
170
171
172 /* This now calls the user clip functions if required.
173 */
174 static void TAG(viewclip_line)( GLcontext *ctx,
175 GLuint i, GLuint j,
176 GLubyte mask )
177 {
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;
182 GLuint vlist[2];
183 GLuint n;
184
185 VB->LastClipped = VB->FirstClipped;
186
187 /*
188 * We use 6 instances of this code to clip against the 6 planes.
189 */
190 #define GENERAL_CLIP \
191 if (mask & PLANE) { \
192 GLfloat dpI = CLIP_DOTPROD( ii ); \
193 GLfloat dpJ = CLIP_DOTPROD( jj ); \
194 \
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; \
201 } else { \
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; \
206 } \
207 } \
208 else if (NEGATIVE(dpI)) \
209 return; \
210 }
211
212 #undef CLIP_DOTPROD
213 #define PLANE CLIP_RIGHT_BIT
214 #define CLIP_DOTPROD(K) (- X(K) + W(K))
215
216 GENERAL_CLIP
217
218 #undef CLIP_DOTPROD
219 #undef PLANE
220 #define PLANE CLIP_LEFT_BIT
221 #define CLIP_DOTPROD(K) (X(K) + W(K))
222
223 GENERAL_CLIP
224
225 #undef CLIP_DOTPROD
226 #undef PLANE
227 #define PLANE CLIP_TOP_BIT
228 #define CLIP_DOTPROD(K) (- Y(K) + W(K))
229
230 GENERAL_CLIP
231
232 #undef CLIP_DOTPROD
233 #undef PLANE
234 #define PLANE CLIP_BOTTOM_BIT
235 #define CLIP_DOTPROD(K) (Y(K) + W(K))
236
237 GENERAL_CLIP
238
239 #undef CLIP_DOTPROD
240 #undef PLANE
241 #define PLANE CLIP_FAR_BIT
242 #define CLIP_DOTPROD(K) (- Z(K) + W(K))
243
244 if (SIZE >= 3) {
245 GENERAL_CLIP
246 }
247
248 #undef CLIP_DOTPROD
249 #undef PLANE
250 #define PLANE CLIP_NEAR_BIT
251 #define CLIP_DOTPROD(K) (Z(K) + W(K))
252
253 if (SIZE >=3 ) {
254 GENERAL_CLIP
255 }
256
257 #undef CLIP_DOTPROD
258 #undef PLANE
259 #undef GENERAL_CLIP
260
261
262 if (mask & CLIP_USER_BIT) {
263 if ( TAG(userclip_line)( ctx, &ii, &jj, interp ) == 0 )
264 return;
265 }
266
267 vlist[0] = ii;
268 vlist[1] = jj;
269 n = 2;
270
271 /* If necessary, project new vertices.
272 */
273 {
274 GLuint i, j;
275 GLfloat (*proj)[4] = VB->ProjectedClipPtr->data;
276 GLuint start = VB->FirstClipped;
277
278 for (i = 0; i < n; i++) {
279 j = vlist[i];
280 if (j >= start) {
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;
286 proj[j][3] = wInv;
287 } else {
288 proj[j][0] = X(j);
289 proj[j][1] = Y(j);
290 proj[j][2] = Z(j);
291 proj[j][3] = W(j);
292 }
293 }
294 }
295 }
296
297 if (ctx->Driver.BuildProjectedVertices)
298 ctx->Driver.BuildProjectedVertices(ctx,
299 VB->FirstClipped,
300 VB->LastClipped,
301 ~0);
302
303
304 /* Render the new line.
305 */
306 ctx->Driver.LineFunc( ctx, ii, jj, j );
307 }
308
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
313 * is redundant.
314 */
315 static void TAG(viewclip_polygon)( GLcontext *ctx,
316 GLuint n, GLuint vlist[], GLuint pv,
317 GLubyte mask )
318 {
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;
324 GLuint i;
325 GLubyte *clipmask = VB->ClipMask;
326
327 VB->LastClipped = VB->FirstClipped;
328
329 if (mask & CLIP_ALL_BITS) {
330
331 #define GENERAL_CLIP \
332 if (mask & PLANE) { \
333 GLuint idxPrev = inlist[n-1]; \
334 GLfloat dpPrev = CLIP_DOTPROD(idxPrev); \
335 GLuint outcount = 0; \
336 GLuint i; \
337 \
338 mask &= ~PLANE; \
339 \
340 for (i = 0; i < n; i++) { \
341 GLuint idx = inlist[i]; \
342 GLfloat dp = CLIP_DOTPROD(idx); \
343 \
344 if (!NEGATIVE(dpPrev)) { \
345 outlist[outcount++] = idxPrev; \
346 clipmask[idxPrev] &= ~PLANE; \
347 } \
348 \
349 if (DIFFERENT_SIGNS(dp, dpPrev)) { \
350 GLuint newvert; \
351 if (NEGATIVE(dp)) { \
352 /* Going out of bounds. Avoid division by zero as we \
353 * know dp != dpPrev from DIFFERENT_SIGNS, above. \
354 */ \
355 GLfloat t = dp / (dp - dpPrev); \
356 newvert = interp( ctx, t, idx, idxPrev, GL_TRUE ); \
357 } else { \
358 /* Coming back in. \
359 */ \
360 GLfloat t = dpPrev / (dpPrev - dp); \
361 newvert = interp( ctx, t, idxPrev, idx, GL_FALSE ); \
362 } \
363 clipmask[newvert] = mask; \
364 outlist[outcount++] = newvert; \
365 } \
366 \
367 idxPrev = idx; \
368 dpPrev = dp; \
369 } \
370 \
371 if (outcount < 3) \
372 return; \
373 \
374 { \
375 GLuint *tmp = inlist; \
376 inlist = outlist; \
377 outlist = tmp; \
378 n = outcount; \
379 } \
380 }
381
382
383 #define PLANE CLIP_RIGHT_BIT
384 #define CLIP_DOTPROD(K) (- X(K) + W(K))
385
386 GENERAL_CLIP
387
388 #undef CLIP_DOTPROD
389 #undef PLANE
390
391
392 #define PLANE CLIP_LEFT_BIT
393 #define CLIP_DOTPROD(K) (X(K) + W(K))
394
395 GENERAL_CLIP
396
397 #undef CLIP_DOTPROD
398 #undef PLANE
399
400 #define PLANE CLIP_TOP_BIT
401 #define CLIP_DOTPROD(K) (- Y(K) + W(K))
402
403 GENERAL_CLIP
404
405 #undef CLIP_DOTPROD
406 #undef PLANE
407
408 #define PLANE CLIP_BOTTOM_BIT
409 #define CLIP_DOTPROD(K) (Y(K) + W(K))
410
411 GENERAL_CLIP
412
413 #undef CLIP_DOTPROD
414 #undef PLANE
415
416 #define PLANE CLIP_FAR_BIT
417 #define CLIP_DOTPROD(K) (- Z(K) + W(K))
418
419 if (SIZE >= 3) {
420 GENERAL_CLIP
421 }
422
423 #undef CLIP_DOTPROD
424 #undef PLANE
425
426 #define PLANE CLIP_NEAR_BIT
427 #define CLIP_DOTPROD(K) (Z(K) + W(K))
428
429 if (SIZE >=3 ) {
430 GENERAL_CLIP
431 }
432
433 #undef CLIP_DOTPROD
434 #undef PLANE
435 #undef GENERAL_CLIP
436
437 if (inlist != vlist)
438 for (i = 0 ; i < n ; i++)
439 vlist[i] = inlist[i];
440 }
441
442 /* Clip against user clipping planes in clip space.
443 */
444 if (mask & CLIP_USER_BIT) {
445 n = TAG(userclip_polygon)( ctx, n, vlist, interp );
446 if (n < 3) return;
447 }
448
449 /* Project if necessary.
450 */
451 {
452 GLuint i;
453 GLfloat (*proj)[4] = VB->ProjectedClipPtr->data;
454 GLuint first = VB->FirstClipped;
455
456 for (i = 0; i < n; i++) {
457 GLuint j = vlist[i];
458 if (j >= first) {
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;
464 proj[j][3] = wInv;
465 } else {
466 proj[j][0] = X(j);
467 proj[j][1] = Y(j);
468 proj[j][2] = Z(j);
469 proj[j][3] = W(j);
470 }
471 }
472 }
473 }
474
475 if (ctx->Driver.BuildProjectedVertices)
476 ctx->Driver.BuildProjectedVertices(ctx,
477 VB->FirstClipped,
478 VB->LastClipped,
479 ~0);
480
481 /* Render the new vertices as an unclipped polygon.
482 * Argh - need to pass in pv...
483 */
484 {
485 GLuint *tmp = VB->Elts;
486 VB->Elts = vlist;
487 render_poly_pv_raw_elts( ctx, 0, n, PRIM_BEGIN|PRIM_END, pv );
488 VB->Elts = tmp;
489 }
490 }
491
492
493
494 #undef W
495 #undef Z
496 #undef Y
497 #undef X
498 #undef SIZE
499 #undef TAG
500 #undef INSIDE
501 #undef OUTSIDE