first big check-in of new Mesa 3.3 code
[mesa.git] / src / mesa / main / clip.c
1 /* $Id: clip.c,v 1.5 1999/11/11 01:22:25 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.3
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
27
28 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include "glheader.h"
32 #include "clip.h"
33 #include "context.h"
34 #include "macros.h"
35 #include "matrix.h"
36 #include "mmath.h"
37 #include "types.h"
38 #include "vb.h"
39 #include "xform.h"
40 #endif
41
42
43
44
45 /* Linear interpolation between A and B: */
46 #define LINTERP( T, A, B ) ( (A) + (T) * ( (B) - (A) ) )
47
48
49
50 #define INTERP_SZ( t, vec, to, a, b, sz ) \
51 do { \
52 switch (sz) { \
53 case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \
54 case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \
55 case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \
56 case 1: vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \
57 } \
58 } while(0)
59
60
61
62
63 #define CLIP_RGBA0 0x1
64 #define CLIP_RGBA1 0x2
65 #define CLIP_TEX0 0x4
66 #define CLIP_TEX1 0x8
67 #define CLIP_INDEX0 0x10
68 #define CLIP_INDEX1 0x20
69
70 static clip_interp_func clip_interp_tab[0x40];
71
72 #define IND 0
73 #define NAME clip_nil
74 #include "interp_tmp.h"
75
76 #define IND (CLIP_RGBA0)
77 #define NAME clipRGBA0
78 #include "interp_tmp.h"
79
80 #define IND (CLIP_RGBA0|CLIP_RGBA1)
81 #define NAME clipRGBA0_RGBA1
82 #include "interp_tmp.h"
83
84 #define IND (CLIP_TEX0|CLIP_RGBA0)
85 #define NAME clipTEX0_RGBA0
86 #include "interp_tmp.h"
87
88 #define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1)
89 #define NAME clipTEX0_RGBA0_RGBA1
90 #include "interp_tmp.h"
91
92 #define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0)
93 #define NAME clipTEX1_TEX0_RGBA0
94 #include "interp_tmp.h"
95
96 #define IND (CLIP_TEX0)
97 #define NAME clipTEX0
98 #include "interp_tmp.h"
99
100 #define IND (CLIP_TEX1|CLIP_TEX0)
101 #define NAME clipTEX1_TEX0
102 #include "interp_tmp.h"
103
104 #define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1)
105 #define NAME clipTEX1_TEX0_RGBA0_RGBA1
106 #include "interp_tmp.h"
107
108 #define IND (CLIP_INDEX0)
109 #define NAME clipINDEX0
110 #include "interp_tmp.h"
111
112 #define IND (CLIP_INDEX0|CLIP_INDEX1)
113 #define NAME clipINDEX0_INDEX1
114 #include "interp_tmp.h"
115
116
117
118
119 /**********************************************************************/
120 /* Get/Set User clip-planes. */
121 /**********************************************************************/
122
123
124
125 void
126 _mesa_ClipPlane( GLenum plane, const GLdouble *eq )
127 {
128 GET_CURRENT_CONTEXT(ctx);
129 GLint p;
130 GLfloat equation[4];
131
132 equation[0] = eq[0];
133 equation[1] = eq[1];
134 equation[2] = eq[2];
135 equation[3] = eq[3];
136
137 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClipPlane");
138
139 p = (GLint) plane - (GLint) GL_CLIP_PLANE0;
140 if (p<0 || p>=MAX_CLIP_PLANES) {
141 gl_error( ctx, GL_INVALID_ENUM, "glClipPlane" );
142 return;
143 }
144
145 /*
146 * The equation is transformed by the transpose of the inverse of the
147 * current modelview matrix and stored in the resulting eye coordinates.
148 *
149 * KW: Eqn is then transformed to the current clip space, where user
150 * clipping now takes place. The clip-space equations are recalculated
151 * whenever the projection matrix changes.
152 */
153 if (ctx->ModelView.flags & MAT_DIRTY_ALL_OVER) {
154 gl_matrix_analyze( &ctx->ModelView );
155 }
156 gl_transform_vector( ctx->Transform.EyeUserPlane[p], equation,
157 ctx->ModelView.inv );
158
159
160 if (ctx->Transform.ClipEnabled[p]) {
161 ctx->NewState |= NEW_USER_CLIP;
162
163 if (ctx->ProjectionMatrix.flags & MAT_DIRTY_ALL_OVER) {
164 gl_matrix_analyze( &ctx->ProjectionMatrix );
165 }
166 gl_transform_vector( ctx->Transform.ClipUserPlane[p],
167 ctx->Transform.EyeUserPlane[p],
168 ctx->ProjectionMatrix.inv );
169 }
170 }
171
172
173 void gl_update_userclip( GLcontext *ctx )
174 {
175 GLuint p;
176
177 for (p = 0 ; p < MAX_CLIP_PLANES ; p++) {
178 if (ctx->Transform.ClipEnabled[p]) {
179 gl_transform_vector( ctx->Transform.ClipUserPlane[p],
180 ctx->Transform.EyeUserPlane[p],
181 ctx->ProjectionMatrix.inv );
182 }
183 }
184 }
185
186 void
187 _mesa_GetClipPlane( GLenum plane, GLdouble *equation )
188 {
189 GET_CURRENT_CONTEXT(ctx);
190 GLint p;
191
192 ASSERT_OUTSIDE_BEGIN_END(ctx, "glGetClipPlane");
193
194
195 p = (GLint) (plane - GL_CLIP_PLANE0);
196 if (p<0 || p>=MAX_CLIP_PLANES) {
197 gl_error( ctx, GL_INVALID_ENUM, "glGetClipPlane" );
198 return;
199 }
200
201 equation[0] = (GLdouble) ctx->Transform.EyeUserPlane[p][0];
202 equation[1] = (GLdouble) ctx->Transform.EyeUserPlane[p][1];
203 equation[2] = (GLdouble) ctx->Transform.EyeUserPlane[p][2];
204 equation[3] = (GLdouble) ctx->Transform.EyeUserPlane[p][3];
205 }
206
207
208
209
210 /**********************************************************************/
211 /* View volume clipping. */
212 /**********************************************************************/
213
214
215 /*
216 * Clip a point against the view volume.
217 * Input: v - vertex-vector describing the point to clip
218 * Return: 0 = outside view volume
219 * 1 = inside view volume
220 */
221 GLuint gl_viewclip_point( const GLfloat v[] )
222 {
223 if ( v[0] > v[3] || v[0] < -v[3]
224 || v[1] > v[3] || v[1] < -v[3]
225 || v[2] > v[3] || v[2] < -v[3] ) {
226 return 0;
227 }
228 else {
229 return 1;
230 }
231 }
232
233 /*
234 * Clip a point against the user clipping planes.
235 * Input: v - vertex-vector describing the point to clip.
236 * Return: 0 = point was clipped
237 * 1 = point not clipped
238 */
239 GLuint gl_userclip_point( GLcontext* ctx, const GLfloat v[] )
240 {
241 GLuint p;
242
243 for (p=0;p<MAX_CLIP_PLANES;p++) {
244 if (ctx->Transform.ClipEnabled[p]) {
245 GLfloat dot = v[0] * ctx->Transform.ClipUserPlane[p][0]
246 + v[1] * ctx->Transform.ClipUserPlane[p][1]
247 + v[2] * ctx->Transform.ClipUserPlane[p][2]
248 + v[3] * ctx->Transform.ClipUserPlane[p][3];
249 if (dot < 0.0F) {
250 return 0;
251 }
252 }
253 }
254
255 return 1;
256 }
257
258
259
260
261 #if defined(__i386__)
262 #define NEGATIVE(x) ((*(int *)&x)<0)
263 #else
264 #define NEGATIVE(x) (x < 0)
265 #endif
266
267
268 static clip_poly_func gl_poly_clip_tab[2][5];
269 static clip_line_func gl_line_clip_tab[2][5];
270
271 #define W(i) coord[i][3]
272 #define Z(i) coord[i][2]
273 #define Y(i) coord[i][1]
274 #define X(i) coord[i][0]
275 #define SIZE 4
276 #define IND 0
277 #define TAG(x) x##_4
278 #include "clip_funcs.h"
279
280 #define W(i) 1.0
281 #define Z(i) coord[i][2]
282 #define Y(i) coord[i][1]
283 #define X(i) coord[i][0]
284 #define SIZE 3
285 #define IND 0
286 #define TAG(x) x##_3
287 #include "clip_funcs.h"
288
289 #define W(i) 1.0
290 #define Z(i) 0.0
291 #define Y(i) coord[i][1]
292 #define X(i) coord[i][0]
293 #define SIZE 2
294 #define IND 0
295 #define TAG(x) x##_2
296 #include "clip_funcs.h"
297
298 #define W(i) coord[i][3]
299 #define Z(i) coord[i][2]
300 #define Y(i) coord[i][1]
301 #define X(i) coord[i][0]
302 #define SIZE 4
303 #define IND CLIP_TAB_EDGEFLAG
304 #define TAG(x) x##_4_edgeflag
305 #include "clip_funcs.h"
306
307 #define W(i) 1.0
308 #define Z(i) coord[i][2]
309 #define Y(i) coord[i][1]
310 #define X(i) coord[i][0]
311 #define SIZE 3
312 #define IND CLIP_TAB_EDGEFLAG
313 #define TAG(x) x##_3_edgeflag
314 #include "clip_funcs.h"
315
316 #define W(i) 1.0
317 #define Z(i) 0.0
318 #define Y(i) coord[i][1]
319 #define X(i) coord[i][0]
320 #define SIZE 2
321 #define IND CLIP_TAB_EDGEFLAG
322 #define TAG(x) x##_2_edgeflag
323 #include "clip_funcs.h"
324
325
326
327
328 void gl_update_clipmask( GLcontext *ctx )
329 {
330 GLuint mask = 0;
331
332 if (ctx->Visual->RGBAflag)
333 {
334 if (ctx->Light.ShadeModel==GL_SMOOTH)
335 {
336 mask |= CLIP_RGBA0;
337
338 if (ctx->TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_SEPERATE_SPECULAR))
339 mask |= CLIP_RGBA1;
340 }
341
342 if (ctx->Texture.ReallyEnabled & 0xf0)
343 mask |= CLIP_TEX1|CLIP_TEX0;
344
345 if (ctx->Texture.ReallyEnabled & 0xf)
346 mask |= CLIP_TEX0;
347 }
348 else if (ctx->Light.ShadeModel==GL_SMOOTH)
349 {
350 mask |= CLIP_INDEX0;
351
352 if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE)
353 mask |= CLIP_INDEX1;
354 }
355
356
357 ctx->ClipInterpFunc = clip_interp_tab[mask];
358 ctx->poly_clip_tab = gl_poly_clip_tab[0];
359 ctx->line_clip_tab = gl_line_clip_tab[0];
360
361 if (ctx->TriangleCaps & DD_TRI_UNFILLED) {
362 ctx->poly_clip_tab = gl_poly_clip_tab[1];
363 ctx->line_clip_tab = gl_line_clip_tab[0];
364 }
365 }
366
367
368 #define USER_CLIPTEST(NAME, SZ) \
369 static void NAME( struct vertex_buffer *VB ) \
370 { \
371 GLcontext *ctx = VB->ctx; \
372 GLubyte *clipMask = VB->ClipMask; \
373 GLubyte *userClipMask = VB->UserClipMask; \
374 GLuint start = VB->Start; \
375 GLuint count = VB->Count; \
376 GLuint p, i; \
377 GLubyte bit; \
378 \
379 \
380 for (bit = 1, p = 0; p < MAX_CLIP_PLANES ; p++, bit *=2) \
381 if (ctx->Transform.ClipEnabled[p]) { \
382 GLuint nr = 0; \
383 const GLfloat a = ctx->Transform.ClipUserPlane[p][0]; \
384 const GLfloat b = ctx->Transform.ClipUserPlane[p][1]; \
385 const GLfloat c = ctx->Transform.ClipUserPlane[p][2]; \
386 const GLfloat d = ctx->Transform.ClipUserPlane[p][3]; \
387 GLfloat *coord = VB->ClipPtr->start; \
388 GLuint stride = VB->ClipPtr->stride; \
389 \
390 for (i = start ; i < count ; i++, STRIDE_F(coord, stride)) { \
391 GLfloat dp = coord[0] * a + coord[1] * b; \
392 if (SZ > 2) dp += coord[2] * c; \
393 if (SZ > 3) dp += coord[3] * d; else dp += d; \
394 \
395 if (dp < 0) { \
396 clipMask[i] |= CLIP_USER_BIT; \
397 userClipMask[i] |= bit; \
398 nr++; \
399 } \
400 } \
401 \
402 if (nr > 0) { \
403 VB->ClipOrMask |= CLIP_USER_BIT; \
404 VB->CullMode |= CLIP_MASK_ACTIVE; \
405 if (nr == count - start) { \
406 VB->ClipAndMask |= CLIP_USER_BIT; \
407 VB->Culled = 1; \
408 return; \
409 } \
410 } \
411 } \
412 }
413
414
415 USER_CLIPTEST(userclip2, 2)
416 USER_CLIPTEST(userclip3, 3)
417 USER_CLIPTEST(userclip4, 4)
418
419 static void (*(usercliptab[5]))( struct vertex_buffer * ) = {
420 0,
421 0,
422 userclip2,
423 userclip3,
424 userclip4
425 };
426
427 void gl_user_cliptest( struct vertex_buffer *VB )
428 {
429 usercliptab[VB->ClipPtr->size]( VB );
430 }
431
432
433 void gl_init_clip(void)
434 {
435 init_clip_funcs_4();
436 init_clip_funcs_3();
437 init_clip_funcs_2();
438
439 init_clip_funcs_4_edgeflag();
440 init_clip_funcs_3_edgeflag();
441 init_clip_funcs_2_edgeflag();
442
443 clip_interp_tab[0] = clip_nil;
444 clip_interp_tab[CLIP_RGBA0] = clipRGBA0;
445 clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1] = clipRGBA0_RGBA1;
446 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0] = clipTEX0_RGBA0;
447 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] = clipTEX0_RGBA0_RGBA1;
448 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0] = clipTEX1_TEX0_RGBA0;
449 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] =
450 clipTEX1_TEX0_RGBA0_RGBA1;
451
452 clip_interp_tab[CLIP_TEX0] = clipTEX0;
453 clip_interp_tab[CLIP_TEX1|CLIP_TEX0] = clipTEX1_TEX0;
454
455 clip_interp_tab[CLIP_INDEX0] = clipINDEX0;
456 clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1] = clipINDEX0_INDEX1;
457 }
458