clip.c revision afb833d4e89c312460a4ab9ed6a7a8ca4ebbfe1c
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 )			\
58do {								\
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: */
79static 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
166void 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
206void 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
219void 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 */
252GLuint 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 */
270GLuint 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
292clip_poly_func gl_poly_clip_tab[5];
293clip_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)						\
328static 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
374USER_CLIPTEST(userclip2, 2)
375USER_CLIPTEST(userclip3, 3)
376USER_CLIPTEST(userclip4, 4)
377
378static void (*(usercliptab[5]))( struct vertex_buffer * ) = {
379   0,
380   0,
381   userclip2,
382   userclip3,
383   userclip4
384};
385
386void gl_user_cliptest( struct vertex_buffer *VB )
387{
388   usercliptab[VB->ClipPtr->size]( VB );
389}
390
391
392
393static 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
426void gl_update_clipmask( GLcontext *ctx )
427{
428   ctx->ClipInterpFunc = get_interp_func( ctx );
429}
430
431void 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
461