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