Fog coordinate stage which drivers may use to replace standard fogging
[mesa.git] / src / mesa / main / clip.c
1 /* $Id: clip.c,v 1.6 2000/02/25 03:55:39 keithw 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 #define CLIP_RGBA0 0x1
46 #define CLIP_RGBA1 0x2
47 #define CLIP_TEX0 0x4
48 #define CLIP_TEX1 0x8
49 #define CLIP_INDEX0 0x10
50 #define CLIP_INDEX1 0x20
51 #define CLIP_FOG_COORD 0x40
52
53
54 /* Linear interpolation between A and B: */
55 #define LINTERP( T, A, B ) ( (A) + (T) * ( (B) - (A) ) )
56
57
58
59 #define INTERP_SZ( t, vec, to, a, b, sz ) \
60 do { \
61 switch (sz) { \
62 case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \
63 case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \
64 case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \
65 case 1: vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \
66 } \
67 } while(0)
68
69
70 static clip_interp_func clip_interp_tab[0x80];
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 #define IND (CLIP_FOG_COORD)
117 #define NAME clip_FOG
118 #include "interp_tmp.h"
119
120 #define IND (CLIP_RGBA0|CLIP_FOG_COORD)
121 #define NAME clipRGBA0_FOG
122 #include "interp_tmp.h"
123
124 #define IND (CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD)
125 #define NAME clipRGBA0_RGBA1_FOG
126 #include "interp_tmp.h"
127
128 #define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_FOG_COORD)
129 #define NAME clipTEX0_RGBA0_FOG
130 #include "interp_tmp.h"
131
132 #define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD)
133 #define NAME clipTEX0_RGBA0_RGBA1_FOG
134 #include "interp_tmp.h"
135
136 #define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_FOG_COORD)
137 #define NAME clipTEX1_TEX0_RGBA0_FOG
138 #include "interp_tmp.h"
139
140 #define IND (CLIP_TEX0|CLIP_FOG_COORD)
141 #define NAME clipTEX0_FOG
142 #include "interp_tmp.h"
143
144 #define IND (CLIP_TEX1|CLIP_TEX0|CLIP_FOG_COORD)
145 #define NAME clipTEX1_TEX0_FOG
146 #include "interp_tmp.h"
147
148 #define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD)
149 #define NAME clipTEX1_TEX0_RGBA0_RGBA1_FOG
150 #include "interp_tmp.h"
151
152 #define IND (CLIP_INDEX0|CLIP_FOG_COORD)
153 #define NAME clipINDEX0_FOG
154 #include "interp_tmp.h"
155
156 #define IND (CLIP_INDEX0|CLIP_INDEX1|CLIP_FOG_COORD)
157 #define NAME clipINDEX0_INDEX1_FOG
158 #include "interp_tmp.h"
159
160
161
162
163 /**********************************************************************/
164 /* Get/Set User clip-planes. */
165 /**********************************************************************/
166
167
168
169 void
170 _mesa_ClipPlane( GLenum plane, const GLdouble *eq )
171 {
172 GET_CURRENT_CONTEXT(ctx);
173 GLint p;
174 GLfloat equation[4];
175
176 equation[0] = eq[0];
177 equation[1] = eq[1];
178 equation[2] = eq[2];
179 equation[3] = eq[3];
180
181 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClipPlane");
182
183 p = (GLint) plane - (GLint) GL_CLIP_PLANE0;
184 if (p<0 || p>=MAX_CLIP_PLANES) {
185 gl_error( ctx, GL_INVALID_ENUM, "glClipPlane" );
186 return;
187 }
188
189 /*
190 * The equation is transformed by the transpose of the inverse of the
191 * current modelview matrix and stored in the resulting eye coordinates.
192 *
193 * KW: Eqn is then transformed to the current clip space, where user
194 * clipping now takes place. The clip-space equations are recalculated
195 * whenever the projection matrix changes.
196 */
197 if (ctx->ModelView.flags & MAT_DIRTY_ALL_OVER) {
198 gl_matrix_analyze( &ctx->ModelView );
199 }
200 gl_transform_vector( ctx->Transform.EyeUserPlane[p], equation,
201 ctx->ModelView.inv );
202
203
204 if (ctx->Transform.ClipEnabled[p]) {
205 ctx->NewState |= NEW_USER_CLIP;
206
207 if (ctx->ProjectionMatrix.flags & MAT_DIRTY_ALL_OVER) {
208 gl_matrix_analyze( &ctx->ProjectionMatrix );
209 }
210 gl_transform_vector( ctx->Transform.ClipUserPlane[p],
211 ctx->Transform.EyeUserPlane[p],
212 ctx->ProjectionMatrix.inv );
213 }
214 }
215
216
217 void gl_update_userclip( GLcontext *ctx )
218 {
219 GLuint p;
220
221 for (p = 0 ; p < MAX_CLIP_PLANES ; p++) {
222 if (ctx->Transform.ClipEnabled[p]) {
223 gl_transform_vector( ctx->Transform.ClipUserPlane[p],
224 ctx->Transform.EyeUserPlane[p],
225 ctx->ProjectionMatrix.inv );
226 }
227 }
228 }
229
230 void
231 _mesa_GetClipPlane( GLenum plane, GLdouble *equation )
232 {
233 GET_CURRENT_CONTEXT(ctx);
234 GLint p;
235
236 ASSERT_OUTSIDE_BEGIN_END(ctx, "glGetClipPlane");
237
238
239 p = (GLint) (plane - GL_CLIP_PLANE0);
240 if (p<0 || p>=MAX_CLIP_PLANES) {
241 gl_error( ctx, GL_INVALID_ENUM, "glGetClipPlane" );
242 return;
243 }
244
245 equation[0] = (GLdouble) ctx->Transform.EyeUserPlane[p][0];
246 equation[1] = (GLdouble) ctx->Transform.EyeUserPlane[p][1];
247 equation[2] = (GLdouble) ctx->Transform.EyeUserPlane[p][2];
248 equation[3] = (GLdouble) ctx->Transform.EyeUserPlane[p][3];
249 }
250
251
252
253
254 /**********************************************************************/
255 /* View volume clipping. */
256 /**********************************************************************/
257
258
259 /*
260 * Clip a point against the view volume.
261 * Input: v - vertex-vector describing the point to clip
262 * Return: 0 = outside view volume
263 * 1 = inside view volume
264 */
265 GLuint gl_viewclip_point( const GLfloat v[] )
266 {
267 if ( v[0] > v[3] || v[0] < -v[3]
268 || v[1] > v[3] || v[1] < -v[3]
269 || v[2] > v[3] || v[2] < -v[3] ) {
270 return 0;
271 }
272 else {
273 return 1;
274 }
275 }
276
277 /*
278 * Clip a point against the user clipping planes.
279 * Input: v - vertex-vector describing the point to clip.
280 * Return: 0 = point was clipped
281 * 1 = point not clipped
282 */
283 GLuint gl_userclip_point( GLcontext* ctx, const GLfloat v[] )
284 {
285 GLuint p;
286
287 for (p=0;p<MAX_CLIP_PLANES;p++) {
288 if (ctx->Transform.ClipEnabled[p]) {
289 GLfloat dot = v[0] * ctx->Transform.ClipUserPlane[p][0]
290 + v[1] * ctx->Transform.ClipUserPlane[p][1]
291 + v[2] * ctx->Transform.ClipUserPlane[p][2]
292 + v[3] * ctx->Transform.ClipUserPlane[p][3];
293 if (dot < 0.0F) {
294 return 0;
295 }
296 }
297 }
298
299 return 1;
300 }
301
302
303
304
305 #if defined(__i386__)
306 #define NEGATIVE(x) ((*(int *)&x)<0)
307 #else
308 #define NEGATIVE(x) (x < 0)
309 #endif
310
311
312 static clip_poly_func gl_poly_clip_tab[2][5];
313 static clip_line_func gl_line_clip_tab[2][5];
314
315 #define W(i) coord[i][3]
316 #define Z(i) coord[i][2]
317 #define Y(i) coord[i][1]
318 #define X(i) coord[i][0]
319 #define SIZE 4
320 #define IND 0
321 #define TAG(x) x##_4
322 #include "clip_funcs.h"
323
324 #define W(i) 1.0
325 #define Z(i) coord[i][2]
326 #define Y(i) coord[i][1]
327 #define X(i) coord[i][0]
328 #define SIZE 3
329 #define IND 0
330 #define TAG(x) x##_3
331 #include "clip_funcs.h"
332
333 #define W(i) 1.0
334 #define Z(i) 0.0
335 #define Y(i) coord[i][1]
336 #define X(i) coord[i][0]
337 #define SIZE 2
338 #define IND 0
339 #define TAG(x) x##_2
340 #include "clip_funcs.h"
341
342 #define W(i) coord[i][3]
343 #define Z(i) coord[i][2]
344 #define Y(i) coord[i][1]
345 #define X(i) coord[i][0]
346 #define SIZE 4
347 #define IND CLIP_TAB_EDGEFLAG
348 #define TAG(x) x##_4_edgeflag
349 #include "clip_funcs.h"
350
351 #define W(i) 1.0
352 #define Z(i) coord[i][2]
353 #define Y(i) coord[i][1]
354 #define X(i) coord[i][0]
355 #define SIZE 3
356 #define IND CLIP_TAB_EDGEFLAG
357 #define TAG(x) x##_3_edgeflag
358 #include "clip_funcs.h"
359
360 #define W(i) 1.0
361 #define Z(i) 0.0
362 #define Y(i) coord[i][1]
363 #define X(i) coord[i][0]
364 #define SIZE 2
365 #define IND CLIP_TAB_EDGEFLAG
366 #define TAG(x) x##_2_edgeflag
367 #include "clip_funcs.h"
368
369
370
371
372 void gl_update_clipmask( GLcontext *ctx )
373 {
374 GLuint mask = 0;
375
376 if (ctx->Visual->RGBAflag)
377 {
378 if (ctx->Light.ShadeModel==GL_SMOOTH)
379 {
380 mask |= CLIP_RGBA0;
381
382 if (ctx->TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_SEPERATE_SPECULAR))
383 mask |= CLIP_RGBA1;
384 }
385
386 if (ctx->Texture.ReallyEnabled & 0xf0)
387 mask |= CLIP_TEX1|CLIP_TEX0;
388
389 if (ctx->Texture.ReallyEnabled & 0xf)
390 mask |= CLIP_TEX0;
391 }
392 else if (ctx->Light.ShadeModel==GL_SMOOTH)
393 {
394 mask |= CLIP_INDEX0;
395
396 if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE)
397 mask |= CLIP_INDEX1;
398 }
399
400 if (ctx->FogMode == FOG_FRAGMENT && (ctx->TriangleCaps & DD_CLIP_FOG_COORD))
401 mask |= CLIP_FOG_COORD;
402
403 ctx->ClipInterpFunc = clip_interp_tab[mask];
404 ctx->poly_clip_tab = gl_poly_clip_tab[0];
405 ctx->line_clip_tab = gl_line_clip_tab[0];
406
407 if (ctx->TriangleCaps & DD_TRI_UNFILLED) {
408 ctx->poly_clip_tab = gl_poly_clip_tab[1];
409 ctx->line_clip_tab = gl_line_clip_tab[0];
410 }
411 }
412
413
414 #define USER_CLIPTEST(NAME, SZ) \
415 static void NAME( struct vertex_buffer *VB ) \
416 { \
417 GLcontext *ctx = VB->ctx; \
418 GLubyte *clipMask = VB->ClipMask; \
419 GLubyte *userClipMask = VB->UserClipMask; \
420 GLuint start = VB->Start; \
421 GLuint count = VB->Count; \
422 GLuint p, i; \
423 GLubyte bit; \
424 \
425 \
426 for (bit = 1, p = 0; p < MAX_CLIP_PLANES ; p++, bit *=2) \
427 if (ctx->Transform.ClipEnabled[p]) { \
428 GLuint nr = 0; \
429 const GLfloat a = ctx->Transform.ClipUserPlane[p][0]; \
430 const GLfloat b = ctx->Transform.ClipUserPlane[p][1]; \
431 const GLfloat c = ctx->Transform.ClipUserPlane[p][2]; \
432 const GLfloat d = ctx->Transform.ClipUserPlane[p][3]; \
433 GLfloat *coord = VB->ClipPtr->start; \
434 GLuint stride = VB->ClipPtr->stride; \
435 \
436 for (i = start ; i < count ; i++, STRIDE_F(coord, stride)) { \
437 GLfloat dp = coord[0] * a + coord[1] * b; \
438 if (SZ > 2) dp += coord[2] * c; \
439 if (SZ > 3) dp += coord[3] * d; else dp += d; \
440 \
441 if (dp < 0) { \
442 clipMask[i] |= CLIP_USER_BIT; \
443 userClipMask[i] |= bit; \
444 nr++; \
445 } \
446 } \
447 \
448 if (nr > 0) { \
449 VB->ClipOrMask |= CLIP_USER_BIT; \
450 VB->CullMode |= CLIP_MASK_ACTIVE; \
451 if (nr == count - start) { \
452 VB->ClipAndMask |= CLIP_USER_BIT; \
453 VB->Culled = 1; \
454 return; \
455 } \
456 } \
457 } \
458 }
459
460
461 USER_CLIPTEST(userclip2, 2)
462 USER_CLIPTEST(userclip3, 3)
463 USER_CLIPTEST(userclip4, 4)
464
465 static void (*(usercliptab[5]))( struct vertex_buffer * ) = {
466 0,
467 0,
468 userclip2,
469 userclip3,
470 userclip4
471 };
472
473 void gl_user_cliptest( struct vertex_buffer *VB )
474 {
475 usercliptab[VB->ClipPtr->size]( VB );
476 }
477
478
479 void gl_init_clip(void)
480 {
481 init_clip_funcs_4();
482 init_clip_funcs_3();
483 init_clip_funcs_2();
484
485 init_clip_funcs_4_edgeflag();
486 init_clip_funcs_3_edgeflag();
487 init_clip_funcs_2_edgeflag();
488
489 clip_interp_tab[0] = clip_nil;
490 clip_interp_tab[CLIP_RGBA0] = clipRGBA0;
491 clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1] = clipRGBA0_RGBA1;
492 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0] = clipTEX0_RGBA0;
493 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] = clipTEX0_RGBA0_RGBA1;
494 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0] = clipTEX1_TEX0_RGBA0;
495 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] =
496 clipTEX1_TEX0_RGBA0_RGBA1;
497 clip_interp_tab[CLIP_TEX0] = clipTEX0;
498 clip_interp_tab[CLIP_TEX1|CLIP_TEX0] = clipTEX1_TEX0;
499 clip_interp_tab[CLIP_INDEX0] = clipINDEX0;
500 clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1] = clipINDEX0_INDEX1;
501
502 clip_interp_tab[CLIP_FOG_COORD] = clip_FOG;
503 clip_interp_tab[CLIP_RGBA0|CLIP_FOG_COORD] = clipRGBA0_FOG;
504 clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD] = clipRGBA0_RGBA1_FOG;
505 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_FOG_COORD] = clipTEX0_RGBA0_FOG;
506 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD] = clipTEX0_RGBA0_RGBA1_FOG;
507 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_FOG_COORD] = clipTEX1_TEX0_RGBA0_FOG;
508 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD] =
509 clipTEX1_TEX0_RGBA0_RGBA1_FOG;
510 clip_interp_tab[CLIP_TEX0|CLIP_FOG_COORD] = clipTEX0_FOG;
511 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_FOG_COORD] = clipTEX1_TEX0_FOG;
512 clip_interp_tab[CLIP_INDEX0|CLIP_FOG_COORD] = clipINDEX0_FOG;
513 clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1|CLIP_FOG_COORD] = clipINDEX0_INDEX1_FOG;
514 }
515