clip.c revision fe5d67d95f3a5fc84c5421d409a6464642aaf2cb
1/* $Id: clip.c,v 1.10 2000/10/27 16:44:40 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 )			\
60do {								\
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
70static 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
169void
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
217void 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
230void
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 */
265GLuint 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 */
283GLuint 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 0
306#define NEGATIVE(x) ((*(int *)&x)<0)
307#define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
308#else
309#define NEGATIVE(x) (x < 0)
310#define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
311#endif
312
313
314static clip_poly_func gl_poly_clip_tab[2][5];
315static clip_line_func gl_line_clip_tab[2][5];
316
317#define W(i) coord[i][3]
318#define Z(i) coord[i][2]
319#define Y(i) coord[i][1]
320#define X(i) coord[i][0]
321#define SIZE 4
322#define IND 0
323#define TAG(x) x##_4
324#include "clip_funcs.h"
325
326#define W(i) 1.0
327#define Z(i) coord[i][2]
328#define Y(i) coord[i][1]
329#define X(i) coord[i][0]
330#define SIZE 3
331#define IND 0
332#define TAG(x) x##_3
333#include "clip_funcs.h"
334
335#define W(i) 1.0
336#define Z(i) 0.0
337#define Y(i) coord[i][1]
338#define X(i) coord[i][0]
339#define SIZE 2
340#define IND 0
341#define TAG(x) x##_2
342#include "clip_funcs.h"
343
344#define W(i) coord[i][3]
345#define Z(i) coord[i][2]
346#define Y(i) coord[i][1]
347#define X(i) coord[i][0]
348#define SIZE 4
349#define IND CLIP_TAB_EDGEFLAG
350#define TAG(x) x##_4_edgeflag
351#include "clip_funcs.h"
352
353#define W(i) 1.0
354#define Z(i) coord[i][2]
355#define Y(i) coord[i][1]
356#define X(i) coord[i][0]
357#define SIZE 3
358#define IND CLIP_TAB_EDGEFLAG
359#define TAG(x) x##_3_edgeflag
360#include "clip_funcs.h"
361
362#define W(i) 1.0
363#define Z(i) 0.0
364#define Y(i) coord[i][1]
365#define X(i) coord[i][0]
366#define SIZE 2
367#define IND CLIP_TAB_EDGEFLAG
368#define TAG(x) x##_2_edgeflag
369#include "clip_funcs.h"
370
371
372
373
374void gl_update_clipmask( GLcontext *ctx )
375{
376   GLuint mask = 0;
377
378   if (ctx->Visual.RGBAflag)
379   {
380      mask |= CLIP_RGBA0;
381
382      if (ctx->TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_SEPERATE_SPECULAR))
383         mask |= CLIP_RGBA1;
384
385      if (ctx->Texture.ReallyEnabled & 0xf0)
386	 mask |= CLIP_TEX1|CLIP_TEX0;
387
388      if (ctx->Texture.ReallyEnabled & 0xf)
389	 mask |= CLIP_TEX0;
390   }
391   else if (ctx->Light.ShadeModel==GL_SMOOTH)
392   {
393      mask |= CLIP_INDEX0;
394
395      if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE)
396	 mask |= CLIP_INDEX1;
397   }
398
399   if (ctx->Fog.Enabled)
400      mask |= CLIP_FOG_COORD;
401
402   ctx->ClipInterpFunc = clip_interp_tab[mask];
403   ctx->poly_clip_tab = gl_poly_clip_tab[0];
404   ctx->line_clip_tab = gl_line_clip_tab[0];
405
406   if (ctx->TriangleCaps & DD_TRI_UNFILLED) {
407      ctx->poly_clip_tab = gl_poly_clip_tab[1];
408      ctx->line_clip_tab = gl_line_clip_tab[0];
409   }
410}
411
412
413#define USER_CLIPTEST(NAME, SZ)						\
414static void NAME( struct vertex_buffer *VB )				\
415{									\
416   GLcontext *ctx = VB->ctx;						\
417   GLubyte *clipMask = VB->ClipMask;					\
418   GLubyte *userClipMask = VB->UserClipMask;				\
419   GLuint start = VB->Start;						\
420   GLuint count = VB->Count;						\
421   GLuint p, i;								\
422   GLubyte bit;								\
423									\
424									\
425   for (bit = 1, p = 0; p < MAX_CLIP_PLANES ; p++, bit *=2)		\
426      if (ctx->Transform.ClipEnabled[p]) {				\
427	 GLuint nr = 0;							\
428	 const GLfloat a = ctx->Transform.ClipUserPlane[p][0];		\
429	 const GLfloat b = ctx->Transform.ClipUserPlane[p][1];		\
430	 const GLfloat c = ctx->Transform.ClipUserPlane[p][2];		\
431	 const GLfloat d = ctx->Transform.ClipUserPlane[p][3];		\
432         GLfloat *coord = VB->ClipPtr->start;				\
433         GLuint stride = VB->ClipPtr->stride;				\
434									\
435	 for (i = start ; i < count ; i++, STRIDE_F(coord, stride)) {	\
436	    GLfloat dp = coord[0] * a + coord[1] * b;			\
437	    if (SZ > 2) dp += coord[2] * c;				\
438	    if (SZ > 3) dp += coord[3] * d; else dp += d;		\
439									\
440	    if (dp < 0) {						\
441	       clipMask[i] |= CLIP_USER_BIT;				\
442	       userClipMask[i] |= bit;					\
443	       nr++;							\
444	    }								\
445	 }								\
446									\
447	 if (nr > 0) {							\
448	    VB->ClipOrMask |= CLIP_USER_BIT;				\
449	    VB->CullMode |= CLIP_MASK_ACTIVE;				\
450	    if (nr == count - start) {					\
451	       VB->ClipAndMask |= CLIP_USER_BIT;			\
452	       VB->Culled = 1;						\
453	       return;							\
454	    }								\
455	 }								\
456      }									\
457}
458
459
460USER_CLIPTEST(userclip2, 2)
461USER_CLIPTEST(userclip3, 3)
462USER_CLIPTEST(userclip4, 4)
463
464static void (*(usercliptab[5]))( struct vertex_buffer * ) = {
465   0,
466   0,
467   userclip2,
468   userclip3,
469   userclip4
470};
471
472void gl_user_cliptest( struct vertex_buffer *VB )
473{
474   usercliptab[VB->ClipPtr->size]( VB );
475}
476
477
478void gl_init_clip(void)
479{
480   init_clip_funcs_4();
481   init_clip_funcs_3();
482   init_clip_funcs_2();
483
484   init_clip_funcs_4_edgeflag();
485   init_clip_funcs_3_edgeflag();
486   init_clip_funcs_2_edgeflag();
487
488   clip_interp_tab[0] = clip_nil;
489   clip_interp_tab[CLIP_RGBA0] = clipRGBA0;
490   clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1] = clipRGBA0_RGBA1;
491   clip_interp_tab[CLIP_TEX0|CLIP_RGBA0] = clipTEX0_RGBA0;
492   clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] = clipTEX0_RGBA0_RGBA1;
493   clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0] = clipTEX1_TEX0_RGBA0;
494   clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] =
495      clipTEX1_TEX0_RGBA0_RGBA1;
496   clip_interp_tab[CLIP_TEX0] = clipTEX0;
497   clip_interp_tab[CLIP_TEX1|CLIP_TEX0] = clipTEX1_TEX0;
498   clip_interp_tab[CLIP_INDEX0] = clipINDEX0;
499   clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1] = clipINDEX0_INDEX1;
500
501   clip_interp_tab[CLIP_FOG_COORD] = clip_FOG;
502   clip_interp_tab[CLIP_RGBA0|CLIP_FOG_COORD] = clipRGBA0_FOG;
503   clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD] = clipRGBA0_RGBA1_FOG;
504   clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_FOG_COORD] = clipTEX0_RGBA0_FOG;
505   clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD] = clipTEX0_RGBA0_RGBA1_FOG;
506   clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_FOG_COORD] = clipTEX1_TEX0_RGBA0_FOG;
507   clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_FOG_COORD] =
508      clipTEX1_TEX0_RGBA0_RGBA1_FOG;
509   clip_interp_tab[CLIP_TEX0|CLIP_FOG_COORD] = clipTEX0_FOG;
510   clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_FOG_COORD] = clipTEX1_TEX0_FOG;
511   clip_interp_tab[CLIP_INDEX0|CLIP_FOG_COORD] = clipINDEX0_FOG;
512   clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1|CLIP_FOG_COORD] = clipINDEX0_INDEX1_FOG;
513}
514
515