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