home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
mesa-1.2.8
/
src
/
clip.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-27
|
29KB
|
982 lines
/* $Id: clip.c,v 1.17 1996/05/13 14:20:34 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 1.2
* Copyright (C) 1995-1996 Brian Paul (brianp@ssec.wisc.edu)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Functions for clipping points, lines, and polygons against the view
* volume and user-defined clipping planes.
*/
/*
$Log: clip.c,v $
* Revision 1.17 1996/05/13 14:20:34 brianp
* removed trivial-inside clip test from gl_viewclip_polygon()
*
* Revision 1.16 1995/12/30 17:13:05 brianp
* interpolate texture R,Q components per Bill Triggs
*
* Revision 1.15 1995/12/20 15:25:31 brianp
* changed VB color indexes to GLuint
*
* Revision 1.14 1995/10/14 17:41:29 brianp
* made glClipPlane display list-able
*
* Revision 1.13 1995/09/15 18:54:09 brianp
* changed INSIDE, OUTSIDE macros to fix Oleg Krivosheev's clipping problems
*
* Revision 1.12 1995/07/28 21:32:12 brianp
* fixed aux data interpolation bug in gl_viewclip_line()
*
* Revision 1.11 1995/07/24 20:34:16 brianp
* replaced memset() with MEMSET() and memcpy() with MEMCPY()
*
* Revision 1.10 1995/07/14 16:11:26 brianp
* tests for divide by zero added to gl_userclip_line()
*
* Revision 1.9 1995/06/02 13:59:16 brianp
* changed MAX_VERTICES to VB_SIZE
*
* Revision 1.8 1995/05/22 21:02:41 brianp
* Release 1.2
*
* Revision 1.7 1995/05/12 19:24:13 brianp
* replaced CC.Mode!=0 with INSIDE_BEGIN_END
*
* Revision 1.6 1995/03/24 15:30:41 brianp
* introduced VB
*
* Revision 1.5 1995/03/09 21:41:03 brianp
* new ModelViewInv matrix logic
*
* Revision 1.4 1995/03/09 20:07:46 brianp
* changed order of arguments in gl_transform_vector
*
* Revision 1.3 1995/03/08 19:01:11 brianp
* removed extra #include "clip.h"
*
* Revision 1.2 1995/03/04 19:29:44 brianp
* 1.1 beta revision
*
* Revision 1.1 1995/02/24 14:18:09 brianp
* Initial revision
*
*/
#include <string.h>
#include "GL/gl.h"
#include "clip.h"
#include "context.h"
#include "list.h"
#include "macros.h"
#include "vb.h"
#include "xform.h"
/* Linear interpolation between A and B: */
#define LINTERP( T, A, B ) ( (A) + (T) * ( (B) - (A) ) )
#define EYE_SPACE 1
#define CLIP_SPACE 2
static GLuint Space;
/*
* This function is used to interpolate colors, indexes, and texture
* coordinates when clipping has to be done. In general, we compute
* aux[dst] = aux[in] + t * (aux[out] - aux[in])
* where aux is the quantity to be interpolated.
* Input: dst - index of array position to store interpolated value
* t - a value in [0,1]
* in - index of array position corresponding to 'inside' vertex
* out - index of array position corresponding to 'outside' vertex
*/
static void interpolate_aux( GLuint dst, GLfloat t, GLuint in, GLuint out )
{
if (CC.ClipMask & CLIP_FCOLOR_BIT) {
VB.Fcolor[dst][0] = LINTERP( t, VB.Fcolor[in][0], VB.Fcolor[out][0] );
VB.Fcolor[dst][1] = LINTERP( t, VB.Fcolor[in][1], VB.Fcolor[out][1] );
VB.Fcolor[dst][2] = LINTERP( t, VB.Fcolor[in][2], VB.Fcolor[out][2] );
VB.Fcolor[dst][3] = LINTERP( t, VB.Fcolor[in][3], VB.Fcolor[out][3] );
}
else if (CC.ClipMask & CLIP_FINDEX_BIT) {
VB.Findex[dst] = (GLuint) (GLint) LINTERP( t, (GLfloat) VB.Findex[in],
(GLfloat) VB.Findex[out] );
}
if (CC.ClipMask & CLIP_BCOLOR_BIT) {
VB.Bcolor[dst][0] = LINTERP( t, VB.Bcolor[in][0], VB.Bcolor[out][0] );
VB.Bcolor[dst][1] = LINTERP( t, VB.Bcolor[in][1], VB.Bcolor[out][1] );
VB.Bcolor[dst][2] = LINTERP( t, VB.Bcolor[in][2], VB.Bcolor[out][2] );
VB.Bcolor[dst][3] = LINTERP( t, VB.Bcolor[in][3], VB.Bcolor[out][3] );
}
else if (CC.ClipMask & CLIP_BINDEX_BIT) {
VB.Bindex[dst] = (GLuint) (GLint) LINTERP( t, (GLfloat) VB.Bindex[in],
(GLfloat) VB.Bindex[out] );
}
if (CC.ClipMask & CLIP_TEXTURE_BIT) {
/* TODO: is more sophisticated texture coord interpolation needed?? */
if (Space==CLIP_SPACE) {
/* also interpolate eye Z component */
VB.Eye[dst][2] = LINTERP( t, VB.Eye[in][2], VB.Eye[out][2] );
}
VB.TexCoord[dst][0] = LINTERP(t,VB.TexCoord[in][0],VB.TexCoord[out][0]);
VB.TexCoord[dst][1] = LINTERP(t,VB.TexCoord[in][1],VB.TexCoord[out][1]);
VB.TexCoord[dst][2] = LINTERP(t,VB.TexCoord[in][2],VB.TexCoord[out][2]);
VB.TexCoord[dst][3] = LINTERP(t,VB.TexCoord[in][3],VB.TexCoord[out][3]);
}
}
void gl_clipplane( GLenum plane, const float *equation )
{
GLint p;
p = (GLint) (plane - GL_CLIP_PLANE0);
if (p<0 || p>=MAX_CLIP_PLANES) {
gl_error( 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.
*/
if (!CC.ModelViewInvValid) {
gl_compute_modelview_inverse();
}
gl_transform_vector( CC.Transform.ClipEquation[p], equation,
CC.ModelViewInv );
}
void glClipPlane( GLenum plane, const GLdouble *equation )
{
GLfloat fequation[4];
fequation[0] = (GLfloat) equation[0];
fequation[1] = (GLfloat) equation[1];
fequation[2] = (GLfloat) equation[2];
fequation[3] = (GLfloat) equation[3];
if (CC.CompileFlag) {
gl_save_clipplane( plane, fequation );
}
if (CC.ExecuteFlag) {
gl_clipplane( plane, fequation );
}
}
void glGetClipPlane( GLenum plane, GLdouble *equation )
{
GLint p;
if (INSIDE_BEGIN_END) {
gl_error( GL_INVALID_OPERATION, "glGetClipPlane" );
return;
}
p = (GLint) (plane - GL_CLIP_PLANE0);
if (p<0 || p>=MAX_CLIP_PLANES) {
gl_error( GL_INVALID_ENUM, "glGetClipPlane" );
return;
}
equation[0] = (GLdouble) CC.Transform.ClipEquation[p][0];
equation[1] = (GLdouble) CC.Transform.ClipEquation[p][1];
equation[2] = (GLdouble) CC.Transform.ClipEquation[p][2];
equation[3] = (GLdouble) CC.Transform.ClipEquation[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 line segment against the view volume defined by -w<=x,y,z<=w.
* Input: i, j - indexes into VB.V* of endpoints of the line
* Return: 0 = line completely outside of view
* 1 = line is inside view.
*/
GLuint gl_viewclip_line( GLuint *i, GLuint *j )
{
GLfloat t, dx, dy, dz, dw;
register GLuint ii, jj;
Space = CLIP_SPACE;
ii = *i;
jj = *j;
/*
* We use 6 instances of this code to clip agains the 6 planes.
* For each plane, we define the OUTSIDE and COMPUTE_INTERSECTION
* macros apprpriately.
*/
#define GENERAL_CLIP \
if (OUTSIDE(ii)) { \
if (OUTSIDE(jj)) { \
/* both verts are outside ==> return 0 */ \
return 0; \
} \
else { \
/* ii is outside, jj is inside ==> clip */ \
/* new vertex put in position VB.Free */ \
COMPUTE_INTERSECTION( VB.Free, jj, ii ) \
if (CC.ClipMask) interpolate_aux( VB.Free, t, jj, ii ); \
ii = VB.Free; \
VB.Free++; \
if (VB.Free==VB_SIZE) VB.Free = 1; \
} \
} \
else { \
if (OUTSIDE(jj)) { \
/* ii is inside, jj is outside ==> clip */ \
/* new vertex put in position VB.Free */ \
COMPUTE_INTERSECTION( VB.Free, ii, jj ); \
if (CC.ClipMask) interpolate_aux( VB.Free, t, ii, jj ); \
jj = VB.Free; \
VB.Free++; \
if (VB.Free==VB_SIZE) VB.Free = 1; \
} \
/* else both verts are inside ==> do nothing */ \
}
#define X(I) VB.Clip[I][0]
#define Y(I) VB.Clip[I][1]
#define Z(I) VB.Clip[I][2]
#define W(I) VB.Clip[I][3]
/*
* Begin clipping
*/
/*** Clip against +X side ***/
#define OUTSIDE(K) (X(K) > W(K))
#define COMPUTE_INTERSECTION( new, in, out ) \
dx = X(out) - X(in); \
dw = W(out) - W(in); \
t = (X(in) - W(in)) / (dw-dx); \
X(new) = X(in) + t * dx; \
Y(new) = Y(in) + t * (Y(out) - Y(in)); \
Z(new) = Z(in) + t * (Z(out) - Z(in)); \
W(new) = W(in) + t * dw;
GENERAL_CLIP
#undef OUTSIDE
#undef COMPUTE_INTERSECTION
/*** Clip against -X side ***/
#define OUTSIDE(K) (X(K) < -W(K))
#define COMPUTE_INTERSECTION( new, in, out ) \
dx = X(out) - X(in); \
dw = W(out) - W(in); \
t = -(X(in) + W(in)) / (dw+dx); \
X(new) = X(in) + t * dx; \
Y(new) = Y(in) + t * (Y(out) - Y(in)); \
Z(new) = Z(in) + t * (Z(out) - Z(in)); \
W(new) = W(in) + t * dw;
GENERAL_CLIP
#undef OUTSIDE
#undef COMPUTE_INTERSECTION
/*** Clip against +Y side ***/
#define OUTSIDE(K) (Y(K) > W(K))
#define COMPUTE_INTERSECTION( new, in, out ) \
dy = Y(out) - Y(in); \
dw = W(out) - W(in); \
t = (Y(in) - W(in)) / (dw-dy); \
X(new) = X(in) + t * (X(out) - X(in)); \
Y(new) = Y(in) + t * dy; \
Z(new) = Z(in) + t * (Z(out) - Z(in)); \
W(new) = W(in) + t * dw;
GENERAL_CLIP
#undef OUTSIDE
#undef COMPUTE_INTERSECTION
/*** Clip against -Y side ***/
#define OUTSIDE(K) (Y(K) < -W(K))
#define COMPUTE_INTERSECTION( new, in, out ) \
dy = Y(out) - Y(in); \
dw = W(out) - W(in); \
t = -(Y(in) + W(in)) / (dw+dy); \
X(new) = X(in) + t * (X(out) - X(in)); \
Y(new) = Y(in) + t * dy; \
Z(new) = Z(in) + t * (Z(out) - Z(in)); \
W(new) = W(in) + t * dw;
GENERAL_CLIP
#undef OUTSIDE
#undef COMPUTE_INTERSECTION
/*** Clip against +Z side ***/
#define OUTSIDE(K) (Z(K) > W(K))
#define COMPUTE_INTERSECTION( new, in, out ) \
dz = Z(out) - Z(in); \
dw = W(out) - W(in); \
t = (Z(in) - W(in)) / (dw-dz); \
X(new) = X(in) + t * (X(out) - X(in)); \
Y(new) = Y(in) + t * (Y(out) - Y(in)); \
Z(new) = Z(in) + t * dz; \
W(new) = W(in) + t * dw;
GENERAL_CLIP
#undef OUTSIDE
#undef COMPUTE_INTERSECTION
/*** Clip against -Z side ***/
#define OUTSIDE(K) (Z(K) < -W(K))
#define COMPUTE_INTERSECTION( new, in, out ) \
dz = Z(out) - Z(in); \
dw = W(out) - W(in); \
t = -(Z(in) + W(in)) / (dw+dz); \
X(new) = X(in) + t * (X(out) - X(in)); \
Y(new) = Y(in) + t * (Y(out) - Y(in)); \
Z(new) = Z(in) + t * dz; \
W(new) = W(in) + t * dw;
GENERAL_CLIP
#undef OUTSIDE
#undef COMPUTE_INTERSECTION
#undef GENERAL_CLIP
*i = ii;
*j = jj;
return 1;
}
/*
* Clip a polygon against the view volume defined by -w<=x,y,z<=w.
* Input: n - number of vertices in input polygon.
* vlist - list of indexes into VB.V* of polygon to clip.
* Output: vlist - modified list of vertex indexes
* Return: number of vertices in resulting polygon
*/
GLuint gl_viewclip_polygon( GLuint n, GLuint vlist[] )
{
GLuint previ, prevj;
GLuint curri, currj;
GLuint vlist2[VB_MAX];
GLuint n2;
GLfloat dx, dy, dz, dw, t;
GLuint incount, i;
Space = CLIP_SPACE;
/*
* We use 6 instances of this code to implement clipping against the
* 6 sides of the view volume. Prior to each we define the macros:
* INLIST = array which lists input vertices
* OUTLIST = array which lists output vertices
* INCOUNT = variable which is the number of vertices in INLIST[]
* OUTCOUNT = variable which is the number of vertices in OUTLIST[]
* INSIDE(J) = test if vertex[J] is inside the view volume
* COMPUTE_INTERSECTION(inv,outv,newv) = compute intersection of line
* from inv[] to outv[] with the clipping plane and store
* the result in newv[]
*/
#define GENERAL_CLIP \
if (INCOUNT<3) return 0; \
previ = INCOUNT-1; /* let previous = last vertex */ \
prevj = INLIST[previ]; \
OUTCOUNT = 0; \
for (curri=0;curri<INCOUNT;curri++) { \
currj = INLIST[curri]; \
if (INSIDE(currj)) { \
if (INSIDE(prevj)) { \
/* both verts are inside ==> copy current to outlist */ \
OUTLIST[OUTCOUNT] = currj; \
OUTCOUNT++; \
} \
else { \
/* current is inside and previous is outside ==> clip */ \
COMPUTE_INTERSECTION( VB.Clip[currj], VB.Clip[prevj], \
VB.Clip[VB.Free] ) \
/* interpolate aux info using the value of t */ \
if (CC.ClipMask) interpolate_aux( VB.Free, t, currj, prevj ); \
VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj]; \
OUTLIST[OUTCOUNT] = VB.Free; \
VB.Free++; \
if (VB.Free==VB_SIZE) VB.Free = 1; \
OUTCOUNT++; \
/* Output current */ \
OUTLIST[OUTCOUNT] = currj; \
OUTCOUNT++; \
} \
} \
else { \
if (INSIDE(prevj)) { \
/* current is outside and previous is inside ==> clip */ \
COMPUTE_INTERSECTION( VB.Clip[prevj], VB.Clip[currj], \
VB.Clip[VB.Free] ) \
/* interpolate aux info using the value of t */ \
if (CC.ClipMask) interpolate_aux( VB.Free, t, prevj, currj ); \
VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj]; \
OUTLIST[OUTCOUNT] = VB.Free; \
VB.Free++; \
if (VB.Free==VB_SIZE) VB.Free = 1; \
OUTCOUNT++; \
} \
/* else both verts are outside ==> do nothing */ \
} \
/* let previous = current */ \
previ = curri; \
prevj = currj; \
}
/*
* Clip against +X
*/
#define INCOUNT n
#define OUTCOUNT n2
#define INLIST vlist
#define OUTLIST vlist2
#define INSIDE(J) ( VB.Clip[J][0] <= VB.Clip[J][3] )
#define COMPUTE_INTERSECTION( inv, outv, newv ) \
dx = outv[0] - inv[0]; \
dw = outv[3] - inv[3]; \
t = (inv[0]-inv[3]) / (dw-dx); \
newv[0] = inv[0] + t * dx; \
newv[1] = inv[1] + t * (outv[1]-inv[1]); \
newv[2] = inv[2] + t * (outv[2]-inv[2]); \
newv[3] = inv[3] + t * dw;
GENERAL_CLIP
#undef INCOUNT
#undef OUTCOUNT
#undef INLIST
#undef OUTLIST
#undef INSIDE
#undef COMPUTE_INTERSECTION
/*
* Clip against -X
*/
#define INCOUNT n2
#define OUTCOUNT n
#define INLIST vlist2
#define OUTLIST vlist
#define INSIDE(J) (VB.Clip[J][0] >= -VB.Clip[J][3])
#define COMPUTE_INTERSECTION( inv, outv, newv ) \
dx = outv[0]-inv[0]; \
dw = outv[3]-inv[3]; \
t = -(inv[0]+inv[3]) / (dw+dx); \
newv[0] = inv[0] + t * dx; \
newv[1] = inv[1] + t * (outv[1]-inv[1]); \
newv[2] = inv[2] + t * (outv[2]-inv[2]); \
newv[3] = inv[3] + t * dw;
GENERAL_CLIP
#undef INCOUNT
#undef OUTCOUNT
#undef INLIST
#undef OUTLIST
#undef INSIDE
#undef COMPUTE_INTERSECTION
/*
* Clip against +Y
*/
#define INCOUNT n
#define OUTCOUNT n2
#define INLIST vlist
#define OUTLIST vlist2
#define INSIDE(J) (VB.Clip[J][1] <= VB.Clip[J][3])
#define COMPUTE_INTERSECTION( inv, outv, newv ) \
dy = outv[1]-inv[1]; \
dw = outv[3]-inv[3]; \
t = (inv[1]-inv[3]) / (dw-dy); \
newv[0] = inv[0] + t * (outv[0]-inv[0]); \
newv[1] = inv[1] + t * dy; \
newv[2] = inv[2] + t * (outv[2]-inv[2]); \
newv[3] = inv[3] + t * dw;
GENERAL_CLIP
#undef INCOUNT
#undef OUTCOUNT
#undef INLIST
#undef OUTLIST
#undef INSIDE
#undef COMPUTE_INTERSECTION
/*
* Clip against -Y
*/
#define INCOUNT n2
#define OUTCOUNT n
#define INLIST vlist2
#define OUTLIST vlist
#define INSIDE(J) (VB.Clip[J][1] >= -VB.Clip[J][3])
#define COMPUTE_INTERSECTION( inv, outv, newv ) \
dy = outv[1]-inv[1]; \
dw = outv[3]-inv[3]; \
t = -(inv[1]+inv[3]) / (dw+dy); \
newv[0] = inv[0] + t * (outv[0]-inv[0]); \
newv[1] = inv[1] + t * dy; \
newv[2] = inv[2] + t * (outv[2]-inv[2]); \
newv[3] = inv[3] + t * dw;
GENERAL_CLIP
#undef INCOUNT
#undef OUTCOUNT
#undef INLIST
#undef OUTLIST
#undef INSIDE
#undef COMPUTE_INTERSECTION
/*
* Clip against +Z
*/
#define INCOUNT n
#define OUTCOUNT n2
#define INLIST vlist
#define OUTLIST vlist2
#define INSIDE(J) (VB.Clip[J][2] <= VB.Clip[J][3])
#define COMPUTE_INTERSECTION( inv, outv, newv ) \
dz = outv[2]-inv[2]; \
dw = outv[3]-inv[3]; \
t = (inv[2]-inv[3]) / (dw-dz); \
newv[0] = inv[0] + t * (outv[0]-inv[0]); \
newv[1] = inv[1] + t * (outv[1]-inv[1]); \
newv[2] = inv[2] + t * dz; \
newv[3] = inv[3] + t * dw;
GENERAL_CLIP
#undef INCOUNT
#undef OUTCOUNT
#undef INLIST
#undef OUTLIST
#undef INSIDE
#undef COMPUTE_INTERSECTION
/*
* Clip against -Z
*/
#define INCOUNT n2
#define OUTCOUNT n
#define INLIST vlist2
#define OUTLIST vlist
#define INSIDE(J) (VB.Clip[J][2] >= -VB.Clip[J][3])
#define COMPUTE_INTERSECTION( inv, outv, newv ) \
dz = outv[2]-inv[2]; \
dw = outv[3]-inv[3]; \
t = -(inv[2]+inv[3]) / (dw+dz); \
newv[0] = inv[0] + t * (outv[0]-inv[0]); \
newv[1] = inv[1] + t * (outv[1]-inv[1]); \
newv[2] = inv[2] + t * dz; \
newv[3] = inv[3] + t * dw;
GENERAL_CLIP
#undef INCOUNT
#undef INLIST
#undef OUTLIST
#undef INSIDE
#undef COMPUTE_INTERSECTION
/* 'OUTCOUNT' clipped vertices are now back in v[] */
return OUTCOUNT;
#undef GENERAL_CLIP
#undef OUTCOUNT
}
/**********************************************************************/
/* Clipping against user-defined clipping planes. */
/**********************************************************************/
/*
* If the dot product of the eye coordinates of a vertex with the
* stored plane equation components is positive or zero, the vertex
* is in with respect to that clipping plane, otherwise it is out.
*/
/*
* 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( const GLfloat v[] )
{
GLuint p;
for (p=0;p<MAX_CLIP_PLANES;p++) {
if (CC.Transform.ClipEnabled[p]) {
GLfloat dot = v[0] * CC.Transform.ClipEquation[p][0]
+ v[1] * CC.Transform.ClipEquation[p][1]
+ v[2] * CC.Transform.ClipEquation[p][2]
+ v[3] * CC.Transform.ClipEquation[p][3];
if (dot < 0.0F) {
return 0;
}
}
}
return 1;
}
#define MAGIC_NUMBER -0.8e-03F
/* Test if VB.Eye[J] is inside the clipping plane defined by A,B,C,D */
#define INSIDE( J, A, B, C, D ) \
( (VB.Eye[J][0] * A + VB.Eye[J][1] * B \
+ VB.Eye[J][2] * C + VB.Eye[J][3] * D) >= MAGIC_NUMBER )
/* Test if VB.Eye[J] is outside the clipping plane defined by A,B,C,D */
#define OUTSIDE( J, A, B, C, D ) \
( (VB.Eye[J][0] * A + VB.Eye[J][1] * B \
+ VB.Eye[J][2] * C + VB.Eye[J][3] * D) < MAGIC_NUMBER )
/*
* Clip a line against the user clipping planes.
* Input: i, j - indexes into VB.V*[] of endpoints
* Output: i, j - indexes into VB.V*[] of (possibly clipped) endpoints
* Return: 0 = line completely clipped
* 1 = line is visible
*/
GLuint gl_userclip_line( GLuint *i, GLuint *j )
{
GLuint p, ii, jj;
Space = EYE_SPACE;
ii = *i;
jj = *j;
for (p=0;p<MAX_CLIP_PLANES;p++) {
if (CC.Transform.ClipEnabled[p]) {
register GLfloat a, b, c, d;
a = CC.Transform.ClipEquation[p][0];
b = CC.Transform.ClipEquation[p][1];
c = CC.Transform.ClipEquation[p][2];
d = CC.Transform.ClipEquation[p][3];
if (OUTSIDE( ii, a,b,c,d )) {
if (OUTSIDE( jj, a,b,c,d )) {
/* ii and jj outside ==> quit */
return 0;
}
else {
/* ii is outside, jj is inside ==> clip */
GLfloat dx, dy, dz, dw, t, denom;
dx = VB.Eye[ii][0] - VB.Eye[jj][0];
dy = VB.Eye[ii][1] - VB.Eye[jj][1];
dz = VB.Eye[ii][2] - VB.Eye[jj][2];
dw = VB.Eye[ii][3] - VB.Eye[jj][3];
denom = dx*a + dy*b + dz*c + dw*d;
if (denom==0.0) {
t = 0.0;
}
else {
t = -(VB.Eye[jj][0]*a+VB.Eye[jj][1]*b
+VB.Eye[jj][2]*c+VB.Eye[jj][3]*d) / denom;
if (t>1.0F) t = 1.0F;
}
VB.Eye[VB.Free][0] = VB.Eye[jj][0] + t * dx;
VB.Eye[VB.Free][1] = VB.Eye[jj][1] + t * dy;
VB.Eye[VB.Free][2] = VB.Eye[jj][2] + t * dz;
VB.Eye[VB.Free][3] = VB.Eye[jj][3] + t * dw;
/* Interpolate colors, indexes, and/or texture coords */
if (CC.ClipMask) interpolate_aux( VB.Free, t, jj, ii );
ii = VB.Free;
VB.Free++;
if (VB.Free==VB_SIZE) VB.Free = 1;
}
}
else {
if (OUTSIDE( jj, a,b,c,d )) {
/* ii is inside, jj is outside ==> clip */
GLfloat dx, dy, dz, dw, t, denom;
dx = VB.Eye[jj][0] - VB.Eye[ii][0];
dy = VB.Eye[jj][1] - VB.Eye[ii][1];
dz = VB.Eye[jj][2] - VB.Eye[ii][2];
dw = VB.Eye[jj][3] - VB.Eye[ii][3];
denom = dx*a + dy*b + dz*c + dw*d;
if (denom==0.0) {
t = 0.0;
}
else {
t = -(VB.Eye[ii][0]*a+VB.Eye[ii][1]*b
+VB.Eye[ii][2]*c+VB.Eye[ii][3]*d) / denom;
if (t>1.0F) t = 1.0F;
}
VB.Eye[VB.Free][0] = VB.Eye[ii][0] + t * dx;
VB.Eye[VB.Free][1] = VB.Eye[ii][1] + t * dy;
VB.Eye[VB.Free][2] = VB.Eye[ii][2] + t * dz;
VB.Eye[VB.Free][3] = VB.Eye[ii][3] + t * dw;
/* Interpolate colors, indexes, and/or texture coords */
if (CC.ClipMask) interpolate_aux( VB.Free, t, ii, jj );
jj = VB.Free;
VB.Free++;
if (VB.Free==VB_SIZE) VB.Free = 1;
}
else {
/* ii and jj inside ==> do nothing */
}
}
}
}
*i = ii;
*j = jj;
return 1;
}
/*
* Clip a polygon against the user clipping planes defined in eye coordinates.
* Input: n - number of vertices.
* vlist - list of vertices in input polygon.
* Output: vlist - list of vertices in output polygon.
* Return: number of vertices after clipping.
*/
GLuint gl_userclip_polygon( GLuint n, GLuint vlist[] )
{
GLuint vlist2[VB_MAX];
GLuint *inlist, *outlist;
GLuint incount, outcount;
GLuint curri, currj;
GLuint previ, prevj;
GLuint p;
Space = EYE_SPACE;
/* initialize input vertex list */
incount = n;
inlist = vlist;
outlist = vlist2;
for (p=0;p<MAX_CLIP_PLANES;p++) {
if (CC.Transform.ClipEnabled[p]) {
register float a = CC.Transform.ClipEquation[p][0];
register float b = CC.Transform.ClipEquation[p][1];
register float c = CC.Transform.ClipEquation[p][2];
register float d = CC.Transform.ClipEquation[p][3];
if (incount<3) return 0;
/* initialize prev to be last in the input list */
previ = incount - 1;
prevj = inlist[previ];
outcount = 0;
for (curri=0;curri<incount;curri++) {
currj = inlist[curri];
if (INSIDE(currj, a,b,c,d)) {
if (INSIDE(prevj, a,b,c,d)) {
/* both verts are inside ==> copy current to outlist */
outlist[outcount++] = currj;
}
else {
/* current is inside and previous is outside ==> clip */
GLfloat dx, dy, dz, dw, t, denom;
/* compute t */
dx = VB.Eye[prevj][0] - VB.Eye[currj][0];
dy = VB.Eye[prevj][1] - VB.Eye[currj][1];
dz = VB.Eye[prevj][2] - VB.Eye[currj][2];
dw = VB.Eye[prevj][3] - VB.Eye[currj][3];
denom = dx*a + dy*b + dz*c + dw*d;
if (denom==0.0) {
t = 0.0;
}
else {
t = -(VB.Eye[currj][0]*a+VB.Eye[currj][1]*b
+VB.Eye[currj][2]*c+VB.Eye[currj][3]*d) / denom;
if (t>1.0F) {
/*printf("t1=%g\n", t);*/
t = 1.0F;
}
}
/* interpolate new vertex position */
VB.Eye[VB.Free][0] = VB.Eye[currj][0] + t*dx;
VB.Eye[VB.Free][1] = VB.Eye[currj][1] + t*dy;
VB.Eye[VB.Free][2] = VB.Eye[currj][2] + t*dz;
VB.Eye[VB.Free][3] = VB.Eye[currj][3] + t*dw;
/* interpolate color, index, and/or texture coord */
if (CC.ClipMask) interpolate_aux( VB.Free, t, currj, prevj);
VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];
/* output new vertex */
outlist[outcount++] = VB.Free;
VB.Free++;
if (VB.Free==VB_SIZE) VB.Free = 1;
/* output current vertex */
outlist[outcount++] = currj;
}
}
else {
if (INSIDE(prevj, a,b,c,d)) {
/* current is outside and previous is inside ==> clip */
GLfloat dx, dy, dz, dw, t, denom;
/* compute t */
dx = VB.Eye[currj][0]-VB.Eye[prevj][0];
dy = VB.Eye[currj][1]-VB.Eye[prevj][1];
dz = VB.Eye[currj][2]-VB.Eye[prevj][2];
dw = VB.Eye[currj][3]-VB.Eye[prevj][3];
denom = dx*a + dy*b + dz*c + dw*d;
if (denom==0.0) {
t = 0.0;
}
else {
t = -(VB.Eye[prevj][0]*a+VB.Eye[prevj][1]*b
+VB.Eye[prevj][2]*c+VB.Eye[prevj][3]*d) / denom;
if (t>1.0F) {
/*printf("t2=%g\n", t);*/
t = 1.0F;
}
}
/* interpolate new vertex position */
VB.Eye[VB.Free][0] = VB.Eye[prevj][0] + t*dx;
VB.Eye[VB.Free][1] = VB.Eye[prevj][1] + t*dy;
VB.Eye[VB.Free][2] = VB.Eye[prevj][2] + t*dz;
VB.Eye[VB.Free][3] = VB.Eye[prevj][3] + t*dw;
/* interpolate color, index, and/or texture coord */
if (CC.ClipMask) interpolate_aux( VB.Free, t, prevj, currj);
VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];
/* output new vertex */
outlist[outcount++] = VB.Free;
VB.Free++;
if (VB.Free==VB_SIZE) VB.Free = 1;
}
/* else both verts are outside ==> do nothing */
}
previ = curri;
prevj = currj;
} /* for i */
/* swap inv and outv pointers */
{
GLuint *tmp;
tmp = inlist;
inlist = outlist;
outlist = tmp;
incount = outcount;
}
} /* if */
} /* for p */
/* outlist points to the list of vertices resulting from the last */
/* clipping. If outlist == vlist2 then we have to copy the vertices */
/* back to vlist */
if (outlist!=vlist2) {
MEMCPY( vlist, vlist2, outcount * sizeof(GLuint) );
}
return outcount;
}