OSDN Git Service

Merge branch 'mesa_7_6_branch'
[android-x86/external-mesa.git] / src / mesa / tnl / t_vb_cliptmp.h
1 /*
2  * Mesa 3-D graphics library
3  * Version:  6.5.2
4  *
5  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Keith Whitwell <keith@tungstengraphics.com>
26  */
27
28
29 #define CLIP_DOTPROD(K, A, B, C, D) X(K)*A + Y(K)*B + Z(K)*C + W(K)*D
30
31 #define POLY_CLIP( PLANE_BIT, A, B, C, D )                              \
32 do {                                                                    \
33    if (mask & PLANE_BIT) {                                              \
34       GLuint idxPrev = inlist[0];                                       \
35       GLfloat dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D );              \
36       GLuint outcount = 0;                                              \
37       GLuint i;                                                         \
38                                                                         \
39       inlist[n] = inlist[0]; /* prevent rotation of vertices */         \
40       for (i = 1; i <= n; i++) {                                        \
41          GLuint idx = inlist[i];                                        \
42          GLfloat dp = CLIP_DOTPROD(idx, A, B, C, D );                   \
43                                                                         \
44          if (!IS_NEGATIVE(dpPrev)) {                                    \
45             outlist[outcount++] = idxPrev;                              \
46          }                                                              \
47                                                                         \
48          if (DIFFERENT_SIGNS(dp, dpPrev)) {                             \
49             if (IS_NEGATIVE(dp)) {                                      \
50                /* Going out of bounds.  Avoid division by zero as we    \
51                 * know dp != dpPrev from DIFFERENT_SIGNS, above.        \
52                 */                                                      \
53                GLfloat t = dp / (dp - dpPrev);                          \
54                INTERP_4F( t, coord[newvert], coord[idx], coord[idxPrev]); \
55                interp( ctx, t, newvert, idx, idxPrev, GL_TRUE );        \
56             } else {                                                    \
57                /* Coming back in.                                       \
58                 */                                                      \
59                GLfloat t = dpPrev / (dpPrev - dp);                      \
60                INTERP_4F( t, coord[newvert], coord[idxPrev], coord[idx]); \
61                interp( ctx, t, newvert, idxPrev, idx, GL_FALSE );       \
62             }                                                           \
63             outlist[outcount++] = newvert++;                            \
64          }                                                              \
65                                                                         \
66          idxPrev = idx;                                                 \
67          dpPrev = dp;                                                   \
68       }                                                                 \
69                                                                         \
70       if (outcount < 3)                                                 \
71          return;                                                        \
72                                                                         \
73       {                                                                 \
74          GLuint *tmp = inlist;                                          \
75          inlist = outlist;                                              \
76          outlist = tmp;                                                 \
77          n = outcount;                                                  \
78       }                                                                 \
79    }                                                                    \
80 } while (0)
81
82
83 #define POLY_USERCLIP(PLANE)                                            \
84 do {                                                                    \
85    if (mask & CLIP_USER_BIT) {                                          \
86       GLuint idxPrev = inlist[0];                                       \
87       GLfloat dpPrev = VB->ClipDistancePtr[PLANE][idxPrev];             \
88       GLuint outcount = 0;                                              \
89       GLuint i;                                                         \
90                                                                         \
91       inlist[n] = inlist[0]; /* prevent rotation of vertices */         \
92       for (i = 1; i <= n; i++) {                                        \
93          GLuint idx = inlist[i];                                        \
94          GLfloat dp = VB->ClipDistancePtr[PLANE][idx];                  \
95                                                                         \
96          if (!IS_NEGATIVE(dpPrev)) {                                    \
97             outlist[outcount++] = idxPrev;                              \
98          }                                                              \
99                                                                         \
100          if (DIFFERENT_SIGNS(dp, dpPrev)) {                             \
101             if (IS_NEGATIVE(dp)) {                                      \
102                /* Going out of bounds.  Avoid division by zero as we    \
103                 * know dp != dpPrev from DIFFERENT_SIGNS, above.        \
104                 */                                                      \
105                GLfloat t = dp / (dp - dpPrev);                          \
106                INTERP_4F( t, coord[newvert], coord[idx], coord[idxPrev]); \
107                interp( ctx, t, newvert, idx, idxPrev, GL_TRUE );        \
108             } else {                                                    \
109                /* Coming back in.                                       \
110                 */                                                      \
111                GLfloat t = dpPrev / (dpPrev - dp);                      \
112                INTERP_4F( t, coord[newvert], coord[idxPrev], coord[idx]); \
113                interp( ctx, t, newvert, idxPrev, idx, GL_FALSE );       \
114             }                                                           \
115             outlist[outcount++] = newvert++;                            \
116          }                                                              \
117                                                                         \
118          idxPrev = idx;                                                 \
119          dpPrev = dp;                                                   \
120       }                                                                 \
121                                                                         \
122       if (outcount < 3)                                                 \
123          return;                                                        \
124                                                                         \
125       {                                                                 \
126          GLuint *tmp = inlist;                                          \
127          inlist = outlist;                                              \
128          outlist = tmp;                                                 \
129          n = outcount;                                                  \
130       }                                                                 \
131    }                                                                    \
132 } while (0)
133
134
135 #define LINE_CLIP(PLANE_BIT, A, B, C, D )                               \
136 do {                                                                    \
137    if (mask & PLANE_BIT) {                                              \
138       const GLfloat dp0 = CLIP_DOTPROD( v0, A, B, C, D );               \
139       const GLfloat dp1 = CLIP_DOTPROD( v1, A, B, C, D );               \
140       const GLboolean neg_dp0 = IS_NEGATIVE(dp0);                       \
141       const GLboolean neg_dp1 = IS_NEGATIVE(dp1);                       \
142                                                                         \
143       /* For regular clipping, we know from the clipmask that one       \
144        * (or both) of these must be negative (otherwise we wouldn't     \
145        * be here).                                                      \
146        * For userclip, there is only a single bit for all active        \
147        * planes, so we can end up here when there is nothing to do,     \
148        * hence the second IS_NEGATIVE() test:                           \
149        */                                                               \
150       if (neg_dp0 && neg_dp1)                                           \
151          return; /* both vertices outside clip plane: discard */        \
152                                                                         \
153       if (neg_dp1) {                                                    \
154          GLfloat t = dp1 / (dp1 - dp0);                                 \
155          if (t > t1) t1 = t;                                            \
156       } else if (neg_dp0) {                                             \
157          GLfloat t = dp0 / (dp0 - dp1);                                 \
158          if (t > t0) t0 = t;                                            \
159       }                                                                 \
160       if (t0 + t1 >= 1.0)                                               \
161          return; /* discard */                                          \
162    }                                                                    \
163 } while (0)
164
165
166 #define LINE_USERCLIP(PLANE)                                            \
167 do {                                                                    \
168    if (mask & CLIP_USER_BIT) {                                          \
169       const GLfloat dp0 = VB->ClipDistancePtr[PLANE][v0];               \
170       const GLfloat dp1 = VB->ClipDistancePtr[PLANE][v1];               \
171       const GLboolean neg_dp0 = IS_NEGATIVE(dp0);                       \
172       const GLboolean neg_dp1 = IS_NEGATIVE(dp1);                       \
173                                                                         \
174       /* For regular clipping, we know from the clipmask that one       \
175        * (or both) of these must be negative (otherwise we wouldn't     \
176        * be here).                                                      \
177        * For userclip, there is only a single bit for all active        \
178        * planes, so we can end up here when there is nothing to do,     \
179        * hence the second IS_NEGATIVE() test:                           \
180        */                                                               \
181       if (neg_dp0 && neg_dp1)                                           \
182          return; /* both vertices outside clip plane: discard */        \
183                                                                         \
184       if (neg_dp1) {                                                    \
185          GLfloat t = dp1 / (dp1 - dp0);                                 \
186          if (t > t1) t1 = t;                                            \
187       } else if (neg_dp0) {                                             \
188          GLfloat t = dp0 / (dp0 - dp1);                                 \
189          if (t > t0) t0 = t;                                            \
190       }                                                                 \
191       if (t0 + t1 >= 1.0)                                               \
192          return; /* discard */                                          \
193    }                                                                    \
194 } while (0)
195
196
197
198 /* Clip a line against the viewport and user clip planes.
199  */
200 static INLINE void
201 TAG(clip_line)( GLcontext *ctx, GLuint v0, GLuint v1, GLubyte mask )
202 {
203    TNLcontext *tnl = TNL_CONTEXT(ctx);
204    struct vertex_buffer *VB = &tnl->vb;
205    tnl_interp_func interp = tnl->Driver.Render.Interp;
206    GLfloat (*coord)[4] = VB->ClipPtr->data;
207    GLuint newvert = VB->Count;
208    GLfloat t0 = 0;
209    GLfloat t1 = 0;
210    GLuint p;
211    const GLuint v0_orig = v0;
212
213    if (mask & CLIP_FRUSTUM_BITS) {
214       LINE_CLIP( CLIP_RIGHT_BIT,  -1,  0,  0, 1 );
215       LINE_CLIP( CLIP_LEFT_BIT,    1,  0,  0, 1 );
216       LINE_CLIP( CLIP_TOP_BIT,     0, -1,  0, 1 );
217       LINE_CLIP( CLIP_BOTTOM_BIT,  0,  1,  0, 1 );
218       LINE_CLIP( CLIP_FAR_BIT,     0,  0, -1, 1 );
219       LINE_CLIP( CLIP_NEAR_BIT,    0,  0,  1, 1 );
220    }
221
222    if (mask & CLIP_USER_BIT) {
223       for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
224          if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
225             LINE_USERCLIP(p);
226          }
227       }
228    }
229
230    if (VB->ClipMask[v0]) {
231       INTERP_4F( t0, coord[newvert], coord[v0], coord[v1] );
232       interp( ctx, t0, newvert, v0, v1, GL_FALSE );
233       v0 = newvert;
234       newvert++;
235    }
236    else {
237       ASSERT(t0 == 0.0);
238    }
239
240    /* Note: we need to use vertex v0_orig when computing the new
241     * interpolated/clipped vertex position, not the current v0 which
242     * may have got set when we clipped the other end of the line!
243     */
244    if (VB->ClipMask[v1]) {
245       INTERP_4F( t1, coord[newvert], coord[v1], coord[v0_orig] );
246       interp( ctx, t1, newvert, v1, v0_orig, GL_FALSE );
247
248       if (ctx->Light.ShadeModel == GL_FLAT)
249          tnl->Driver.Render.CopyPV( ctx, newvert, v1 );
250
251       v1 = newvert;
252
253       newvert++;
254    }
255    else {
256       ASSERT(t1 == 0.0);
257    }
258
259    tnl->Driver.Render.ClippedLine( ctx, v0, v1 );
260 }
261
262
263 /* Clip a triangle against the viewport and user clip planes.
264  */
265 static INLINE void
266 TAG(clip_tri)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLubyte mask )
267 {
268    TNLcontext *tnl = TNL_CONTEXT(ctx);
269    struct vertex_buffer *VB = &tnl->vb;
270    tnl_interp_func interp = tnl->Driver.Render.Interp;
271    GLuint newvert = VB->Count;
272    GLfloat (*coord)[4] = VB->ClipPtr->data;
273    GLuint pv = v2;
274    GLuint vlist[2][MAX_CLIPPED_VERTICES];
275    GLuint *inlist = vlist[0], *outlist = vlist[1];
276    GLuint p;
277    GLuint n = 3;
278
279    ASSIGN_3V(inlist, v2, v0, v1 ); /* pv rotated to slot zero */
280
281    if (0) {
282       /* print pre-clip vertex coords */
283       GLuint i, j;
284       _mesa_printf("pre clip:\n");
285       for (i = 0; i < n; i++) {
286          j = inlist[i];
287          _mesa_printf("  %u: %u: %f, %f, %f, %f\n",
288                       i, j,
289                       coord[j][0], coord[j][1], coord[j][2], coord[j][3]);
290          assert(!IS_INF_OR_NAN(coord[j][0]));
291          assert(!IS_INF_OR_NAN(coord[j][1]));
292          assert(!IS_INF_OR_NAN(coord[j][2]));
293          assert(!IS_INF_OR_NAN(coord[j][3]));
294       }
295    }
296
297
298    if (mask & CLIP_FRUSTUM_BITS) {
299       POLY_CLIP( CLIP_RIGHT_BIT,  -1,  0,  0, 1 );
300       POLY_CLIP( CLIP_LEFT_BIT,    1,  0,  0, 1 );
301       POLY_CLIP( CLIP_TOP_BIT,     0, -1,  0, 1 );
302       POLY_CLIP( CLIP_BOTTOM_BIT,  0,  1,  0, 1 );
303       POLY_CLIP( CLIP_FAR_BIT,     0,  0, -1, 1 );
304       POLY_CLIP( CLIP_NEAR_BIT,    0,  0,  1, 1 );
305    }
306
307    if (mask & CLIP_USER_BIT) {
308       for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
309          if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
310             POLY_USERCLIP(p);
311          }
312       }
313    }
314
315    if (ctx->Light.ShadeModel == GL_FLAT) {
316       if (pv != inlist[0]) {
317          ASSERT( inlist[0] >= VB->Count );
318          tnl->Driver.Render.CopyPV( ctx, inlist[0], pv );
319       }
320    }
321
322    if (0) {
323       /* print post-clip vertex coords */
324       GLuint i, j;
325       _mesa_printf("post clip:\n");
326       for (i = 0; i < n; i++) {
327          j = inlist[i];
328          _mesa_printf("  %u: %u: %f, %f, %f, %f\n",
329                       i, j,
330                       coord[j][0], coord[j][1], coord[j][2], coord[j][3]);
331       }
332    }
333
334    tnl->Driver.Render.ClippedPolygon( ctx, inlist, n );
335 }
336
337
338 /* Clip a quad against the viewport and user clip planes.
339  */
340 static INLINE void
341 TAG(clip_quad)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint v3,
342                 GLubyte mask )
343 {
344    TNLcontext *tnl = TNL_CONTEXT(ctx);
345    struct vertex_buffer *VB = &tnl->vb;
346    tnl_interp_func interp = tnl->Driver.Render.Interp;
347    GLuint newvert = VB->Count;
348    GLfloat (*coord)[4] = VB->ClipPtr->data;
349    GLuint pv = v3;
350    GLuint vlist[2][MAX_CLIPPED_VERTICES];
351    GLuint *inlist = vlist[0], *outlist = vlist[1];
352    GLuint p;
353    GLuint n = 4;
354
355    ASSIGN_4V(inlist, v3, v0, v1, v2 ); /* pv rotated to slot zero */
356
357    if (mask & CLIP_FRUSTUM_BITS) {
358       POLY_CLIP( CLIP_RIGHT_BIT,  -1,  0,  0, 1 );
359       POLY_CLIP( CLIP_LEFT_BIT,    1,  0,  0, 1 );
360       POLY_CLIP( CLIP_TOP_BIT,     0, -1,  0, 1 );
361       POLY_CLIP( CLIP_BOTTOM_BIT,  0,  1,  0, 1 );
362       POLY_CLIP( CLIP_FAR_BIT,     0,  0, -1, 1 );
363       POLY_CLIP( CLIP_NEAR_BIT,    0,  0,  1, 1 );
364    }
365
366    if (mask & CLIP_USER_BIT) {
367       for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
368          if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
369             POLY_USERCLIP(p);
370          }
371       }
372    }
373
374    if (ctx->Light.ShadeModel == GL_FLAT) {
375       if (pv != inlist[0]) {
376          ASSERT( inlist[0] >= VB->Count );
377          tnl->Driver.Render.CopyPV( ctx, inlist[0], pv );
378       }
379    }
380
381    tnl->Driver.Render.ClippedPolygon( ctx, inlist, n );
382 }
383
384 #undef W
385 #undef Z
386 #undef Y
387 #undef X
388 #undef SIZE
389 #undef TAG
390 #undef POLY_CLIP
391 #undef POLY_USERCLIP
392 #undef LINE_CLIP
393 #undef LINE_USERCLIP