OSDN Git Service

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