/************************************************************************** * * * Copyright (C) 1992, Silicon Graphics, Inc. * * * * These coded instructions, statements, and computer programs contain * * unpublished proprietary information of Silicon Graphics, Inc., and * * are protected by Federal copyright law. They may not be disclosed * * to third parties or copied or duplicated in any form, in whole or * * in part, without the prior written consent of Silicon Graphics, Inc. * * * **************************************************************************/ /* * mapdesc.c++ - $Revision: 1.2 $ * Derrick Burns - 1991 */ #include "glimport.h" #include "mystdio.h" #include "myassert.h" #include "mystring.h" #include "mymath.h" #include "backend.h" #include "nurbscon.h" #include "mapdesc.h" Mapdesc::Mapdesc( long _type, int _israt, int _ncoords, Backend& b ) : backend( b ) { type = _type; isrational = _israt; ncoords = _ncoords; hcoords = _ncoords + (_israt ? 0 : 1 ); inhcoords = _ncoords - (_israt ? 1 : 0 ); mask = ((1<<(inhcoords*2))-1); next = 0; assert( hcoords <= MAXCOORDS ); assert( inhcoords >= 1 ); pixel_tolerance = 1.0; error_tolerance = 1.0; bbox_subdividing = N_NOBBOXSUBDIVISION; culling_method = N_NOCULLING; sampling_method = N_NOSAMPLING; clampfactor = N_NOCLAMPING; minsavings = N_NOSAVINGSSUBDIVISION; s_steps = 0.0; t_steps = 0.0; maxrate = ( s_steps < 0.0 ) ? 0.0 : s_steps; maxsrate = ( s_steps < 0.0 ) ? 0.0 : s_steps; maxtrate = ( t_steps < 0.0 ) ? 0.0 : t_steps; identify( bmat ); identify( cmat ); identify( smat ); for( int i = 0; i != inhcoords; i++ ) bboxsize[i] = 1.0; } void Mapdesc::setBboxsize( INREAL *mat ) { for( int i = 0; i != inhcoords; i++ ) bboxsize[i] = (REAL) mat[i]; } void Mapdesc::identify( REAL dest[MAXCOORDS][MAXCOORDS] ) { memset( dest, 0, sizeof( dest ) ); for( int i=0; i != hcoords; i++ ) dest[i][i] = 1.0; } void Mapdesc::surfbbox( REAL bb[2][MAXCOORDS] ) { backend.surfbbox( type, bb[0], bb[1] ); } void Mapdesc::copy( REAL dest[MAXCOORDS][MAXCOORDS], long n, INREAL *src, long rstride, long cstride ) { assert( n >= 0 ); for( int i=0; i != n; i++ ) for( int j=0; j != n; j++ ) dest[i][j] = src[i*rstride + j*cstride]; } /*-------------------------------------------------------------------------- * copyPt - copy a homogeneous point *-------------------------------------------------------------------------- */ void Mapdesc::copyPt( REAL *d, REAL *s ) { assert( hcoords > 0 ); switch( hcoords ) { case 4: d[3] = s[3]; d[2] = s[2]; d[1] = s[1]; d[0] = s[0]; break; case 3: d[2] = s[2]; d[1] = s[1]; d[0] = s[0]; break; case 2: d[1] = s[1]; d[0] = s[0]; break; case 1: d[0] = s[0]; break; case 5: d[4] = s[4]; d[3] = s[3]; d[2] = s[2]; d[1] = s[1]; d[0] = s[0]; break; default: memcpy( d, s, hcoords * sizeof( REAL ) ); break; } } /*-------------------------------------------------------------------------- * sumPt - compute affine combination of two homogeneous points *-------------------------------------------------------------------------- */ void Mapdesc::sumPt( REAL *dst, REAL *src1, REAL *src2, register REAL alpha, register REAL beta ) { assert( hcoords > 0 ); switch( hcoords ) { case 4: dst[3] = src1[3] * alpha + src2[3] * beta; dst[2] = src1[2] * alpha + src2[2] * beta; dst[1] = src1[1] * alpha + src2[1] * beta; dst[0] = src1[0] * alpha + src2[0] * beta; break; case 3: dst[2] = src1[2] * alpha + src2[2] * beta; dst[1] = src1[1] * alpha + src2[1] * beta; dst[0] = src1[0] * alpha + src2[0] * beta; break; case 2: dst[1] = src1[1] * alpha + src2[1] * beta; dst[0] = src1[0] * alpha + src2[0] * beta; break; case 1: dst[0] = src1[0] * alpha + src2[0] * beta; break; case 5: dst[4] = src1[4] * alpha + src2[4] * beta; dst[3] = src1[3] * alpha + src2[3] * beta; dst[2] = src1[2] * alpha + src2[2] * beta; dst[1] = src1[1] * alpha + src2[1] * beta; dst[0] = src1[0] * alpha + src2[0] * beta; break; default: { for( int i = 0; i != hcoords; i++ ) dst[i] = src1[i] * alpha + src2[i] * beta; } break; } } /*-------------------------------------------------------------------------- * clipbits - compute bit-vector indicating point/window position * of a (transformed) homogeneous point *-------------------------------------------------------------------------- */ unsigned int Mapdesc::clipbits( REAL *p ) { assert( inhcoords >= 0 ); assert( inhcoords <= 3 ); register int nc = inhcoords; register REAL pw = p[nc]; register REAL nw = -pw; register unsigned int bits = 0; if( pw == 0.0 ) return mask; if( pw > 0.0 ) { switch( nc ) { case 3: if( p[2] <= pw ) bits |= (1<<5); if( p[2] >= nw ) bits |= (1<<4); if( p[1] <= pw ) bits |= (1<<3); if( p[1] >= nw ) bits |= (1<<2); if( p[0] <= pw ) bits |= (1<<1); if( p[0] >= nw ) bits |= (1<<0); return bits; case 2: if( p[1] <= pw ) bits |= (1<<3); if( p[1] >= nw ) bits |= (1<<2); if( p[0] <= pw ) bits |= (1<<1); if( p[0] >= nw ) bits |= (1<<0); return bits; case 1: if( p[0] <= pw ) bits |= (1<<1); if( p[0] >= nw ) bits |= (1<<0); return bits; default: { int bit = 1; for( int i=0; i= nw ) bits |= bit; bit <<= 1; if( p[i] <= pw ) bits |= bit; bit <<= 1; } #ifdef NT return 0; #else abort(); #endif break; } } } else { switch( nc ) { case 3: if( p[2] <= nw ) bits |= (1<<5); if( p[2] >= pw ) bits |= (1<<4); if( p[1] <= nw ) bits |= (1<<3); if( p[1] >= pw ) bits |= (1<<2); if( p[0] <= nw ) bits |= (1<<1); if( p[0] >= pw ) bits |= (1<<0); return bits; case 2: if( p[1] <= nw ) bits |= (1<<3); if( p[1] >= pw ) bits |= (1<<2); if( p[0] <= nw ) bits |= (1<<1); if( p[0] >= pw ) bits |= (1<<0); return bits; case 1: if( p[0] <= nw ) bits |= (1<<1); if( p[0] >= pw ) bits |= (1<<0); return bits; default: { int bit = 1; for( int i=0; i= pw ) bits |= bit; bit <<= 1; if( p[i] <= nw ) bits |= bit; bit <<= 1; } #ifdef NT return 0; #else abort(); #endif break; } } } return bits; } /*-------------------------------------------------------------------------- * xformRational - transform a homogeneous point *-------------------------------------------------------------------------- */ void Mapdesc::xformRational( Maxmatrix mat, REAL *d, REAL *s ) { assert( hcoords >= 0 ); if( hcoords == 3 ) { REAL x = s[0]; REAL y = s[1]; REAL z = s[2]; d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0]; d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1]; d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2]; } else if( hcoords == 4 ) { REAL x = s[0]; REAL y = s[1]; REAL z = s[2]; REAL w = s[3]; d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0]+w*mat[3][0]; d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1]+w*mat[3][1]; d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2]+w*mat[3][2]; d[3] = x*mat[0][3]+y*mat[1][3]+z*mat[2][3]+w*mat[3][3]; } else { for( int i=0; i != hcoords; i++ ) { d[i] = 0; for( int j = 0; j != hcoords; j++ ) d[i] += s[j] * mat[j][i]; } } } /*-------------------------------------------------------------------------- * xformNonrational - transform a inhomogeneous point to a homogeneous point *-------------------------------------------------------------------------- */ void Mapdesc::xformNonrational( Maxmatrix mat, REAL *d, REAL *s ) { if( inhcoords == 2 ) { REAL x = s[0]; REAL y = s[1]; d[0] = x*mat[0][0]+y*mat[1][0]+mat[2][0]; d[1] = x*mat[0][1]+y*mat[1][1]+mat[2][1]; d[2] = x*mat[0][2]+y*mat[1][2]+mat[2][2]; } else if( inhcoords == 3 ) { REAL x = s[0]; REAL y = s[1]; REAL z = s[2]; d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0]+mat[3][0]; d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1]+mat[3][1]; d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2]+mat[3][2]; d[3] = x*mat[0][3]+y*mat[1][3]+z*mat[2][3]+mat[3][3]; } else { assert( inhcoords >= 0 ); for( int i=0; i != hcoords; i++ ) { d[i] = mat[inhcoords][i]; for( int j = 0; j < inhcoords; j++ ) d[i] += s[j] * mat[j][i]; } } } /*-------------------------------------------------------------------------- * xformAndCullCheck - transform a set of points that may be EITHER * homogeneous or inhomogeneous depending on the map description and * check if they are either completely inside, completely outside, * or intersecting the viewing frustrum. *-------------------------------------------------------------------------- */ int Mapdesc::xformAndCullCheck( REAL *pts, int uorder, int ustride, int vorder, int vstride ) { assert( uorder > 0 ); assert( vorder > 0 ); unsigned int inbits = mask; unsigned int outbits = 0; REAL *p = pts; for( REAL *pend = p + uorder * ustride; p != pend; p += ustride ) { REAL *q = p; for( REAL *qend = q + vorder * vstride; q != qend; q += vstride ) { REAL cpts[MAXCOORDS]; xformCulling( cpts, q ); unsigned int bits = clipbits( cpts ); outbits |= bits; inbits &= bits; if( ( outbits == mask ) && ( inbits != mask ) ) return CULL_ACCEPT; } } if( outbits != mask ) { return CULL_TRIVIAL_REJECT; } else if( inbits == mask ) { return CULL_TRIVIAL_ACCEPT; } else { return CULL_ACCEPT; } } /*-------------------------------------------------------------------------- * cullCheck - check if a set of homogeneous transformed points are * either completely inside, completely outside, * or intersecting the viewing frustrum. *-------------------------------------------------------------------------- */ int Mapdesc::cullCheck( REAL *pts, int uorder, int ustride, int vorder, int vstride ) { unsigned int inbits = mask; unsigned int outbits = 0; REAL *p = pts; for( REAL *pend = p + uorder * ustride; p != pend; p += ustride ) { REAL *q = p; for( REAL *qend = q + vorder * vstride; q != qend; q += vstride ) { unsigned int bits = clipbits( q ); outbits |= bits; inbits &= bits; if( ( outbits == mask ) && ( inbits != mask ) ) return CULL_ACCEPT; } } if( outbits != mask ) { return CULL_TRIVIAL_REJECT; } else if( inbits == mask ) { return CULL_TRIVIAL_ACCEPT; } else { return CULL_ACCEPT; } } /*-------------------------------------------------------------------------- * cullCheck - check if a set of homogeneous transformed points are * either completely inside, completely outside, * or intersecting the viewing frustrum. *-------------------------------------------------------------------------- */ int Mapdesc::cullCheck( REAL *pts, int order, int stride ) { unsigned int inbits = mask; unsigned int outbits = 0; REAL *p = pts; for( REAL *pend = p + order * stride; p != pend; p += stride ) { unsigned int bits = clipbits( p ); outbits |= bits; inbits &= bits; if( ( outbits == mask ) && ( inbits != mask ) ) return CULL_ACCEPT; } if( outbits != mask ) { return CULL_TRIVIAL_REJECT; } else if( inbits == mask ) { return CULL_TRIVIAL_ACCEPT; } else { return CULL_ACCEPT; } } /*-------------------------------------------------------------------------- * xformSampling - transform a set of points that may be EITHER * homogeneous or inhomogeneous depending on the map description * into sampling space *-------------------------------------------------------------------------- */ void Mapdesc::xformSampling( REAL *pts, int order, int stride, REAL *sp, int outstride ) { xformMat( smat, pts, order, stride, sp, outstride ); } void Mapdesc::xformBounding( REAL *pts, int order, int stride, REAL *sp, int outstride ) { xformMat( bmat, pts, order, stride, sp, outstride ); } /*-------------------------------------------------------------------------- * xformCulling - transform a set of points that may be EITHER * homogeneous or inhomogeneous depending on the map description * into culling space *-------------------------------------------------------------------------- */ void Mapdesc::xformCulling( REAL *pts, int order, int stride, REAL *cp, int outstride ) { xformMat( cmat, pts, order, stride, cp, outstride ); } /*-------------------------------------------------------------------------- * xformCulling - transform a set of points that may be EITHER * homogeneous or inhomogeneous depending on the map description * into culling space *-------------------------------------------------------------------------- */ void Mapdesc::xformCulling( REAL *pts, int uorder, int ustride, int vorder, int vstride, REAL *cp, int outustride, int outvstride ) { xformMat( cmat, pts, uorder, ustride, vorder, vstride, cp, outustride, outvstride ); } /*-------------------------------------------------------------------------- * xformSampling - transform a set of points that may be EITHER * homogeneous or inhomogeneous depending on the map description * into sampling space *-------------------------------------------------------------------------- */ void Mapdesc::xformSampling( REAL *pts, int uorder, int ustride, int vorder, int vstride, REAL *sp, int outustride, int outvstride ) { xformMat( smat, pts, uorder, ustride, vorder, vstride, sp, outustride, outvstride ); } void Mapdesc::xformBounding( REAL *pts, int uorder, int ustride, int vorder, int vstride, REAL *sp, int outustride, int outvstride ) { xformMat( bmat, pts, uorder, ustride, vorder, vstride, sp, outustride, outvstride ); } void Mapdesc::xformMat( Maxmatrix mat, REAL * pts, int order, int stride, REAL * cp, int outstride ) { if( isrational ) { REAL *pend = pts + order * stride; for( REAL *p = pts ; p != pend; p += stride ) { xformRational( mat, cp, p ); cp += outstride; } } else { REAL *pend = pts + order * stride; for( REAL *p = pts ; p != pend; p += stride ) { xformNonrational( mat, cp, p ); cp += outstride; } } } void Mapdesc::xformMat( Maxmatrix mat, REAL *pts, int uorder, int ustride, int vorder, int vstride, REAL *cp, int outustride, int outvstride ) { if( isrational ) { REAL *pend = pts + uorder * ustride; for( REAL *p = pts ; p != pend; p += ustride ) { REAL *cpts2 = cp; REAL *qend = p + vorder * vstride; for( REAL *q = p; q != qend; q += vstride ) { xformRational( mat, cpts2, q ); cpts2 += outvstride; } cp += outustride; } } else { REAL *pend = pts + uorder * ustride; for( REAL *p = pts ; p != pend; p += ustride ) { REAL *cpts2 = cp; REAL *qend = p + vorder * vstride; for( REAL *q = p; q != qend; q += vstride ) { xformNonrational( mat, cpts2, q ); cpts2 += outvstride; } cp += outustride; } } } /*-------------------------------------------------------------------------- * subdivide - subdivide a curve along an isoparametric line *-------------------------------------------------------------------------- */ void Mapdesc::subdivide( REAL *src, REAL *dst, REAL v, int stride, int order ) { REAL mv = 1.0 - v; for( REAL *send=src+stride*order; src!=send; send-=stride, dst+=stride ) { copyPt( dst, src ); REAL *qpnt = src + stride; for( REAL *qp=src; qpnt!=send; qp=qpnt, qpnt+=stride ) sumPt( qp, qp, qpnt, mv, v ); } } /*-------------------------------------------------------------------------- * subdivide - subdivide a patch along an isoparametric line *-------------------------------------------------------------------------- */ void Mapdesc::subdivide( REAL *src, REAL *dst, REAL v, int so, int ss, int to, int ts ) { REAL mv = 1.0 - v; for( REAL *slast = src+ss*so; src != slast; src += ss, dst += ss ) { REAL *sp = src; REAL *dp = dst; for( REAL *send = src+ts*to; sp != send; send -= ts, dp += ts ) { copyPt( dp, sp ); REAL *qp = sp; for( REAL *qpnt = sp+ts; qpnt != send; qp = qpnt, qpnt += ts ) sumPt( qp, qp, qpnt, mv, v ); } } } #define sign(x) ((x > 0) ? 1 : ((x < 0.0) ? -1 : 0)) /*-------------------------------------------------------------------------- * project - project a set of homogeneous coordinates into inhomogeneous ones *-------------------------------------------------------------------------- */ int Mapdesc::project( REAL *src, int rstride, int cstride, REAL *dest, int trstride, int tcstride, int nrows, int ncols ) { int s = sign( src[inhcoords] ); REAL *rlast = src + nrows * rstride; REAL *trptr = dest; for( REAL *rptr=src; rptr != rlast; rptr+=rstride, trptr+=trstride ) { REAL *clast = rptr + ncols * cstride; REAL *tcptr = trptr; for( REAL *cptr = rptr; cptr != clast; cptr+=cstride, tcptr+=tcstride ) { REAL *coordlast = cptr + inhcoords; if( sign( *coordlast ) != s ) return 0; REAL *tcoord = tcptr; for( REAL *coord = cptr; coord != coordlast; coord++, tcoord++ ) { *tcoord = *coord / *coordlast; } } } return 1; } /*-------------------------------------------------------------------------- * project - project a set of homogeneous coordinates into inhomogeneous ones *-------------------------------------------------------------------------- */ int Mapdesc::project( REAL *src, int stride, REAL *dest, int tstride, int ncols ) { int s = sign( src[inhcoords] ); REAL *clast = src + ncols * stride; for( REAL *cptr = src, *tcptr = dest; cptr != clast; cptr+=stride, tcptr+=tstride ) { REAL *coordlast = cptr + inhcoords; if( sign( *coordlast ) != s ) return 0; for( REAL *coord = cptr, *tcoord = tcptr; coord != coordlast; coord++, tcoord++ ) *tcoord = *coord / *coordlast; } return 1; } int Mapdesc::bboxTooBig( REAL *p, int rstride, int cstride, int nrows, int ncols, REAL bb[2][MAXCOORDS] ) { REAL bbpts[MAXORDER][MAXORDER][MAXCOORDS]; const int trstride = sizeof(bbpts[0]) / sizeof(REAL); const int tcstride = sizeof(bbpts[0][0]) / sizeof(REAL); // points have been transformed, therefore they are homogeneous // project points int val = project( p, rstride, cstride, &bbpts[0][0][0], trstride, tcstride, nrows, ncols ); if( val == 0 ) return -1; // compute bounding box bbox( bb, &bbpts[0][0][0], trstride, tcstride, nrows, ncols ); // find out if bounding box can't fit in unit cube if( bbox_subdividing == N_BBOXROUND ) { for( int k=0; k != inhcoords; k++ ) if( ceilf(bb[1][k]) - floorf(bb[0][k]) > bboxsize[k] ) return 1; } else { for( int k=0; k != inhcoords; k++ ) if( bb[1][k] - bb[0][k] > bboxsize[k] ) return 1; } return 0; } void Mapdesc::bbox( REAL bb[2][MAXCOORDS], REAL *p, int rstride, int cstride, int nrows, int ncols ) { for( int k=0; k != inhcoords; k++ ) bb[0][k] = bb[1][k] = p[k]; for( int i=0; i != nrows; i++ ) for( int j=0; j != ncols; j++ ) for( k=0; k != inhcoords; k++ ) { REAL x = p[i*rstride + j*cstride + k]; if( x < bb[0][k] ) bb[0][k] = x; else if( x > bb[1][k] ) bb[1][k] = x; } } /*-------------------------------------------------------------------------- * calcVelocityRational - calculate upper bound on first partial derivative * of a homogeneous set of points and bounds on each row of points. *-------------------------------------------------------------------------- */ REAL Mapdesc::calcVelocityRational( REAL *p, int stride, int ncols ) { REAL tmp[MAXORDER][MAXCOORDS]; assert( ncols <= MAXORDER ); const int tstride = sizeof(tmp[0]) / sizeof(REAL); if( project( p, stride, &tmp[0][0], tstride, ncols ) ) { return calcPartialVelocity( &tmp[0][0], tstride, ncols, 1, 1.0 ); } else { /* XXX */ return calcPartialVelocity( &tmp[0][0], tstride, ncols, 1, 1.0 ); } } /*-------------------------------------------------------------------------- * calcVelocityNonrational - calculate upper bound on first partial * derivative of a inhomogeneous set of points. *-------------------------------------------------------------------------- */ REAL Mapdesc::calcVelocityNonrational( REAL *pts, int stride, int ncols ) { return calcPartialVelocity( pts, stride, ncols, 1, 1.0 ); } int Mapdesc::isProperty( long property ) { switch ( property ) { case N_PIXEL_TOLERANCE: case N_ERROR_TOLERANCE: case N_CULLING: case N_BBOX_SUBDIVIDING: case N_S_STEPS: case N_T_STEPS: case N_SAMPLINGMETHOD: case N_CLAMPFACTOR: case N_MINSAVINGS: return 1; default: return 0; } } REAL Mapdesc::getProperty( long property ) { switch ( property ) { case N_PIXEL_TOLERANCE: return pixel_tolerance; case N_ERROR_TOLERANCE: return error_tolerance; case N_CULLING: return culling_method; case N_BBOX_SUBDIVIDING: return bbox_subdividing; case N_S_STEPS: return s_steps; case N_T_STEPS: return t_steps; case N_SAMPLINGMETHOD: return sampling_method; case N_CLAMPFACTOR: return clampfactor; case N_MINSAVINGS: return minsavings; default: #ifdef NT return( (REAL) 0.0 ); #else abort(); return -1; //not necessary, needed to shut up compiler #endif } } void Mapdesc::setProperty( long property, REAL value ) { switch ( property ) { case N_PIXEL_TOLERANCE: pixel_tolerance = value; break; case N_ERROR_TOLERANCE: error_tolerance = value; break; case N_CULLING: culling_method = value; break; case N_BBOX_SUBDIVIDING: if( value <= 0.0 ) value = N_NOBBOXSUBDIVISION; bbox_subdividing = value; break; case N_S_STEPS: if( value < 0.0 ) value = 0.0; s_steps = value; maxrate = ( value < 0.0 ) ? 0.0 : value; maxsrate = ( value < 0.0 ) ? 0.0 : value; break; case N_T_STEPS: if( value < 0.0 ) value = 0.0; t_steps = value; maxtrate = ( value < 0.0 ) ? 0.0 : value; break; case N_SAMPLINGMETHOD: sampling_method = value; break; case N_CLAMPFACTOR: if( value <= 0.0 ) value = N_NOCLAMPING; clampfactor = value; break; case N_MINSAVINGS: if( value <= 0.0 ) value = N_NOSAVINGSSUBDIVISION; minsavings = value; break; default: #ifndef NT abort(); #endif break; } }