clip.c revision c893a015d8a50a38cd3f727d99835e7e7e2ccea9
1/* $Id: clip.c,v 1.11 2000/10/28 20:41:13 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 "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 )			\
61do {								\
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
71static 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
170void
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      ctx->NewState |= NEW_USER_CLIP;
207
208      if (ctx->ProjectionMatrix.flags & MAT_DIRTY_ALL_OVER) {
209	 gl_matrix_analyze( &ctx->ProjectionMatrix );
210      }
211      gl_transform_vector( ctx->Transform.ClipUserPlane[p],
212			   ctx->Transform.EyeUserPlane[p],
213			   ctx->ProjectionMatrix.inv );
214   }
215}
216
217
218void gl_update_userclip( GLcontext *ctx )
219{
220   GLuint p;
221
222   for (p = 0 ; p < MAX_CLIP_PLANES ; p++) {
223      if (ctx->Transform.ClipEnabled[p]) {
224	 gl_transform_vector( ctx->Transform.ClipUserPlane[p],
225			      ctx->Transform.EyeUserPlane[p],
226			      ctx->ProjectionMatrix.inv );
227      }
228   }
229}
230
231void
232_mesa_GetClipPlane( GLenum plane, GLdouble *equation )
233{
234   GET_CURRENT_CONTEXT(ctx);
235   GLint p;
236
237   ASSERT_OUTSIDE_BEGIN_END(ctx, "glGetClipPlane");
238
239
240   p = (GLint) (plane - GL_CLIP_PLANE0);
241   if (p<0 || p>=MAX_CLIP_PLANES) {
242      gl_error( ctx, GL_INVALID_ENUM, "glGetClipPlane" );
243      return;
244   }
245
246   equation[0] = (GLdouble) ctx->Transform.EyeUserPlane[p][0];
247   equation[1] = (GLdouble) ctx->Transform.EyeUserPlane[p][1];
248   equation[2] = (GLdouble) ctx->Transform.EyeUserPlane[p][2];
249   equation[3] = (GLdouble) ctx->Transform.EyeUserPlane[p][3];
250}
251
252
253
254
255/**********************************************************************/
256/*                         View volume clipping.                      */
257/**********************************************************************/
258
259
260/*
261 * Clip a point against the view volume.
262 * Input:  v - vertex-vector describing the point to clip
263 * Return:  0 = outside view volume
264 *          1 = inside view volume
265 */
266GLuint gl_viewclip_point( const GLfloat v[] )
267{
268   if (   v[0] > v[3] || v[0] < -v[3]
269       || v[1] > v[3] || v[1] < -v[3]
270       || v[2] > v[3] || v[2] < -v[3] ) {
271      return 0;
272   }
273   else {
274      return 1;
275   }
276}
277
278/*
279 * Clip a point against the user clipping planes.
280 * Input:  v - vertex-vector describing the point to clip.
281 * Return:  0 = point was clipped
282 *          1 = point not clipped
283 */
284GLuint gl_userclip_point( GLcontext* ctx, const GLfloat v[] )
285{
286   GLuint p;
287
288   for (p=0;p<MAX_CLIP_PLANES;p++) {
289      if (ctx->Transform.ClipEnabled[p]) {
290	 GLfloat dot = v[0] * ctx->Transform.ClipUserPlane[p][0]
291		     + v[1] * ctx->Transform.ClipUserPlane[p][1]
292		     + v[2] * ctx->Transform.ClipUserPlane[p][2]
293		     + v[3] * ctx->Transform.ClipUserPlane[p][3];
294         if (dot < 0.0F) {
295            return 0;
296         }
297      }
298   }
299
300   return 1;
301}
302
303
304
305
306#if 0
307#define NEGATIVE(x) ((*(int *)&x)<0)
308#define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
309#else
310#define NEGATIVE(x) (x < 0)
311#define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
312#endif
313
314
315static clip_poly_func gl_poly_clip_tab[2][5];
316static clip_line_func gl_line_clip_tab[2][5];
317
318#define W(i) coord[i][3]
319#define Z(i) coord[i][2]
320#define Y(i) coord[i][1]
321#define X(i) coord[i][0]
322#define SIZE 4
323#define IND 0
324#define TAG(x) x##_4
325#include "clip_funcs.h"
326
327#define W(i) 1.0
328#define Z(i) coord[i][2]
329#define Y(i) coord[i][1]
330#define X(i) coord[i][0]
331#define SIZE 3
332#define IND 0
333#define TAG(x) x##_3
334#include "clip_funcs.h"
335
336#define W(i) 1.0
337#define Z(i) 0.0
338#define Y(i) coord[i][1]
339#define X(i) coord[i][0]
340#define SIZE 2
341#define IND 0
342#define TAG(x) x##_2
343#include "clip_funcs.h"
344
345#define W(i) coord[i][3]
346#define Z(i) coord[i][2]
347#define Y(i) coord[i][1]
348#define X(i) coord[i][0]
349#define SIZE 4
350#define IND CLIP_TAB_EDGEFLAG
351#define TAG(x) x##_4_edgeflag
352#include "clip_funcs.h"
353
354#define W(i) 1.0
355#define Z(i) coord[i][2]
356#define Y(i) coord[i][1]
357#define X(i) coord[i][0]
358#define SIZE 3
359#define IND CLIP_TAB_EDGEFLAG
360#define TAG(x) x##_3_edgeflag
361#include "clip_funcs.h"
362
363#define W(i) 1.0
364#define Z(i) 0.0
365#define Y(i) coord[i][1]
366#define X(i) coord[i][0]
367#define SIZE 2
368#define IND CLIP_TAB_EDGEFLAG
369#define TAG(x) x##_2_edgeflag
370#include "clip_funcs.h"
371
372
373
374
375void gl_update_clipmask( GLcontext *ctx )
376{
377   GLuint mask = 0;
378
379   if (ctx->Visual.RGBAflag)
380   {
381      mask |= CLIP_RGBA0;
382
383      if (ctx->TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_SEPERATE_SPECULAR))
384         mask |= CLIP_RGBA1;
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->Fog.Enabled)
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)						\
415static 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
461USER_CLIPTEST(userclip2, 2)
462USER_CLIPTEST(userclip3, 3)
463USER_CLIPTEST(userclip4, 4)
464
465static void (*(usercliptab[5]))( struct vertex_buffer * ) = {
466   0,
467   0,
468   userclip2,
469   userclip3,
470   userclip4
471};
472
473void gl_user_cliptest( struct vertex_buffer *VB )
474{
475   usercliptab[VB->ClipPtr->size]( VB );
476}
477
478
479void 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
516