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