diff options
Diffstat (limited to 'src/mesa/main/clip.c')
-rw-r--r-- | src/mesa/main/clip.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/mesa/main/clip.c b/src/mesa/main/clip.c new file mode 100644 index 00000000000..9feaf2472ea --- /dev/null +++ b/src/mesa/main/clip.c @@ -0,0 +1,460 @@ +/* $Id: clip.c,v 1.1 1999/08/19 00:55:41 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * + * Copyright (C) 1999 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + + + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <string.h> +#include <stdlib.h> +#include "clip.h" +#include "context.h" +#include "macros.h" +#include "matrix.h" +#include "mmath.h" +#include "types.h" +#include "vb.h" +#include "xform.h" +#ifdef XFree86Server +#include "GL/xf86glx.h" +#endif +#endif + + + + +/* Linear interpolation between A and B: */ +#define LINTERP( T, A, B ) ( (A) + (T) * ( (B) - (A) ) ) + + + +#define INTERP_SZ( t, vec, to, a, b, sz ) \ +do { \ + switch (sz) { \ + case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \ + case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \ + case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \ + case 1: vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \ + } \ +} while(0) + + + + +#define CLIP_RGBA0 0x1 +#define CLIP_RGBA1 0x2 +#define CLIP_TEX0 0x4 +#define CLIP_TEX1 0x8 +#define CLIP_INDEX0 0x10 +#define CLIP_INDEX1 0x20 +#define CLIP_EDGE 0x40 + +/* This is sparsely populated: */ +static clip_interp_func clip_interp_tab[0x80]; + +#define IND 0 +#define NAME clip_nil +#include "interp_tmp.h" + +#define IND (CLIP_RGBA0) +#define NAME clipRGBA0 +#include "interp_tmp.h" + +#define IND (CLIP_RGBA0|CLIP_RGBA1) +#define NAME clipRGBA0_RGBA1 +#include "interp_tmp.h" + +#define IND (CLIP_TEX0|CLIP_RGBA0) +#define NAME clipTEX0_RGBA0 +#include "interp_tmp.h" + +#define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1) +#define NAME clipTEX0_RGBA0_RGBA1 +#include "interp_tmp.h" + +#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0) +#define NAME clipTEX1_TEX0_RGBA0 +#include "interp_tmp.h" + +#define IND (CLIP_TEX0) +#define NAME clipTEX0 +#include "interp_tmp.h" + +#define IND (CLIP_TEX1|CLIP_TEX0) +#define NAME clipTEX1_TEX0 +#include "interp_tmp.h" + +#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1) +#define NAME clipTEX1_TEX0_RGBA0_RGBA1 +#include "interp_tmp.h" + +#define IND (CLIP_INDEX0) +#define NAME clipINDEX0 +#include "interp_tmp.h" + +#define IND (CLIP_INDEX0|CLIP_INDEX1) +#define NAME clipINDEX0_INDEX1 +#include "interp_tmp.h" + +#define IND (CLIP_RGBA0|CLIP_EDGE) +#define NAME clipRGBA0_EDGE +#include "interp_tmp.h" + +#define IND (CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE) +#define NAME clipRGBA0_RGBA1_EDGE +#include "interp_tmp.h" + +#define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE) +#define NAME clipTEX0_RGBA0_EDGE +#include "interp_tmp.h" + +#define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE) +#define NAME clipTEX0_RGBA0_RGBA1_EDGE +#include "interp_tmp.h" + +#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE) +#define NAME clipTEX1_TEX0_RGBA0_EDGE +#include "interp_tmp.h" + +#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE) +#define NAME clipTEX1_TEX0_RGBA0_RGBA1_EDGE +#include "interp_tmp.h" + +#define IND (CLIP_INDEX0|CLIP_EDGE) +#define NAME clipINDEX0_EDGE +#include "interp_tmp.h" + +#define IND (CLIP_INDEX0|CLIP_INDEX1|CLIP_EDGE) +#define NAME clipINDEX0_INDEX1_EDGE +#include "interp_tmp.h" + + + + +/**********************************************************************/ +/* Get/Set User clip-planes. */ +/**********************************************************************/ + + + +void gl_ClipPlane( GLcontext* ctx, GLenum plane, const GLfloat *equation ) +{ + GLint p; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClipPlane"); + + p = (GLint) plane - (GLint) GL_CLIP_PLANE0; + if (p<0 || p>=MAX_CLIP_PLANES) { + gl_error( ctx, GL_INVALID_ENUM, "glClipPlane" ); + return; + } + + /* + * The equation is transformed by the transpose of the inverse of the + * current modelview matrix and stored in the resulting eye coordinates. + * + * KW: Eqn is then transformed to the current clip space, where user + * clipping now takes place. The clip-space equations are recalculated + * whenever the projection matrix changes. + */ + if (ctx->ModelView.flags & MAT_DIRTY_ALL_OVER) { + gl_matrix_analyze( &ctx->ModelView ); + } + gl_transform_vector( ctx->Transform.EyeUserPlane[p], equation, + ctx->ModelView.inv ); + + + if (ctx->Transform.ClipEnabled[p]) { + ctx->NewState |= NEW_USER_CLIP; + + if (ctx->ProjectionMatrix.flags & MAT_DIRTY_ALL_OVER) { + gl_matrix_analyze( &ctx->ProjectionMatrix ); + } + gl_transform_vector( ctx->Transform.ClipUserPlane[p], + ctx->Transform.EyeUserPlane[p], + ctx->ProjectionMatrix.inv ); + } +} + + +void gl_update_userclip( GLcontext *ctx ) +{ + GLuint p; + + for (p = 0 ; p < MAX_CLIP_PLANES ; p++) { + if (ctx->Transform.ClipEnabled[p]) { + gl_transform_vector( ctx->Transform.ClipUserPlane[p], + ctx->Transform.EyeUserPlane[p], + ctx->ProjectionMatrix.inv ); + } + } +} + +void gl_GetClipPlane( GLcontext* ctx, GLenum plane, GLdouble *equation ) +{ + GLint p; + + ASSERT_OUTSIDE_BEGIN_END(ctx, "glGetClipPlane"); + + + p = (GLint) (plane - GL_CLIP_PLANE0); + if (p<0 || p>=MAX_CLIP_PLANES) { + gl_error( ctx, GL_INVALID_ENUM, "glGetClipPlane" ); + return; + } + + equation[0] = (GLdouble) ctx->Transform.EyeUserPlane[p][0]; + equation[1] = (GLdouble) ctx->Transform.EyeUserPlane[p][1]; + equation[2] = (GLdouble) ctx->Transform.EyeUserPlane[p][2]; + equation[3] = (GLdouble) ctx->Transform.EyeUserPlane[p][3]; +} + + + + +/**********************************************************************/ +/* View volume clipping. */ +/**********************************************************************/ + + +/* + * Clip a point against the view volume. + * Input: v - vertex-vector describing the point to clip + * Return: 0 = outside view volume + * 1 = inside view volume + */ +GLuint gl_viewclip_point( const GLfloat v[] ) +{ + if ( v[0] > v[3] || v[0] < -v[3] + || v[1] > v[3] || v[1] < -v[3] + || v[2] > v[3] || v[2] < -v[3] ) { + return 0; + } + else { + return 1; + } +} + +/* + * Clip a point against the user clipping planes. + * Input: v - vertex-vector describing the point to clip. + * Return: 0 = point was clipped + * 1 = point not clipped + */ +GLuint gl_userclip_point( GLcontext* ctx, const GLfloat v[] ) +{ + GLuint p; + + for (p=0;p<MAX_CLIP_PLANES;p++) { + if (ctx->Transform.ClipEnabled[p]) { + GLfloat dot = v[0] * ctx->Transform.ClipUserPlane[p][0] + + v[1] * ctx->Transform.ClipUserPlane[p][1] + + v[2] * ctx->Transform.ClipUserPlane[p][2] + + v[3] * ctx->Transform.ClipUserPlane[p][3]; + if (dot < 0.0F) { + return 0; + } + } + } + + return 1; +} + + + + +clip_poly_func gl_poly_clip_tab[5]; +clip_line_func gl_line_clip_tab[5]; + + +#if defined(__i386__) +#define NEGATIVE(x) ((*(int *)&x)<0) +#else +#define NEGATIVE(x) (x < 0) +#endif + +#define W(i) coord[i][3] +#define Z(i) coord[i][2] +#define Y(i) coord[i][1] +#define X(i) coord[i][0] +#define SIZE 4 +#define TAG(x) x##_4 +#include "clip_funcs.h" + + +#define W(i) 1.0 +#define Z(i) coord[i][2] +#define Y(i) coord[i][1] +#define X(i) coord[i][0] +#define SIZE 3 +#define TAG(x) x##_3 +#include "clip_funcs.h" + +#define W(i) 1.0 +#define Z(i) 0.0 +#define Y(i) coord[i][1] +#define X(i) coord[i][0] +#define SIZE 2 +#define TAG(x) x##_2 +#include "clip_funcs.h" + +#define USER_CLIPTEST(NAME, SZ) \ +static void NAME( struct vertex_buffer *VB ) \ +{ \ + GLcontext *ctx = VB->ctx; \ + GLubyte *clipMask = VB->ClipMask; \ + GLubyte *userClipMask = VB->UserClipMask; \ + GLuint start = VB->Start; \ + GLuint count = VB->Count; \ + GLuint p, i; \ + GLubyte bit; \ + \ + \ + for (bit = 1, p = 0; p < MAX_CLIP_PLANES ; p++, bit *=2) \ + if (ctx->Transform.ClipEnabled[p]) { \ + GLuint nr = 0; \ + const GLfloat a = ctx->Transform.ClipUserPlane[p][0]; \ + const GLfloat b = ctx->Transform.ClipUserPlane[p][1]; \ + const GLfloat c = ctx->Transform.ClipUserPlane[p][2]; \ + const GLfloat d = ctx->Transform.ClipUserPlane[p][3]; \ + GLfloat *coord = VB->ClipPtr->start; \ + GLuint stride = VB->ClipPtr->stride; \ + \ + for (i = start ; i < count ; i++, STRIDE_F(coord, stride)) { \ + GLfloat dp = coord[0] * a + coord[1] * b; \ + if (SZ > 2) dp += coord[2] * c; \ + if (SZ > 3) dp += coord[3] * d; else dp += d; \ + \ + if (dp < 0) { \ + clipMask[i] |= CLIP_USER_BIT; \ + userClipMask[i] |= bit; \ + nr++; \ + } \ + } \ + \ + if (nr > 0) { \ + VB->ClipOrMask |= CLIP_USER_BIT; \ + VB->CullMode |= CLIP_MASK_ACTIVE; \ + if (nr == count - start) { \ + VB->ClipAndMask |= CLIP_USER_BIT; \ + VB->Culled = 1; \ + return; \ + } \ + } \ + } \ +} + + +USER_CLIPTEST(userclip2, 2) +USER_CLIPTEST(userclip3, 3) +USER_CLIPTEST(userclip4, 4) + +static void (*(usercliptab[5]))( struct vertex_buffer * ) = { + 0, + 0, + userclip2, + userclip3, + userclip4 +}; + +void gl_user_cliptest( struct vertex_buffer *VB ) +{ + usercliptab[VB->ClipPtr->size]( VB ); +} + + + +static clip_interp_func get_interp_func( GLcontext *ctx ) +{ + GLuint mask = 0; + + if (ctx->Visual->RGBAflag) + { + if (ctx->Light.ShadeModel==GL_SMOOTH) + { + mask |= CLIP_RGBA0; + + if (ctx->TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_SEPERATE_SPECULAR)) + mask |= CLIP_RGBA1; + } + + if (ctx->Texture.ReallyEnabled & 0xf0) + mask |= CLIP_TEX1|CLIP_TEX0; + + if (ctx->Texture.ReallyEnabled & 0xf) + mask |= CLIP_TEX0; + } + else if (ctx->Light.ShadeModel==GL_SMOOTH) + { + mask |= CLIP_INDEX0; + + if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) + mask |= CLIP_INDEX1; + } + + + return clip_interp_tab[mask]; +} + + +void gl_update_clipmask( GLcontext *ctx ) +{ + ctx->ClipInterpFunc = get_interp_func( ctx ); +} + +void gl_init_clip(void) +{ + init_clip_funcs_4(); + init_clip_funcs_3(); + init_clip_funcs_2(); + + clip_interp_tab[0] = clip_nil; + clip_interp_tab[CLIP_RGBA0] = clipRGBA0; + clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1] = clipRGBA0_RGBA1; + clip_interp_tab[CLIP_TEX0|CLIP_RGBA0] = clipTEX0_RGBA0; + clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] = clipTEX0_RGBA0_RGBA1; + clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0] = clipTEX1_TEX0_RGBA0; + clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] = clipTEX1_TEX0_RGBA0_RGBA1; + + clip_interp_tab[CLIP_TEX0] = clipTEX0; + clip_interp_tab[CLIP_TEX1|CLIP_TEX0] = clipTEX1_TEX0; + + clip_interp_tab[CLIP_INDEX0] = clipINDEX0; + clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1] = clipINDEX0_INDEX1; + + clip_interp_tab[CLIP_RGBA0|CLIP_EDGE] = clipRGBA0_EDGE; + clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE] = clipRGBA0_RGBA1_EDGE; + clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE] = clipTEX0_RGBA0_EDGE; + clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE] = clipTEX0_RGBA0_RGBA1_EDGE; + clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE] = clipTEX1_TEX0_RGBA0_EDGE; + clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE] = clipTEX1_TEX0_RGBA0_RGBA1_EDGE; + clip_interp_tab[CLIP_INDEX0|CLIP_EDGE] = clipINDEX0_EDGE; + clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1|CLIP_EDGE] = clipINDEX0_INDEX1_EDGE; +} + |