1f220fa62Smrg/* 2f220fa62Smrg** License Applicability. Except to the extent portions of this file are 3f220fa62Smrg** made subject to an alternative license as permitted in the SGI Free 4f220fa62Smrg** Software License B, Version 1.1 (the "License"), the contents of this 5f220fa62Smrg** file are subject only to the provisions of the License. You may not use 6f220fa62Smrg** this file except in compliance with the License. You may obtain a copy 7f220fa62Smrg** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 8f220fa62Smrg** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: 9f220fa62Smrg** 10f220fa62Smrg** http://oss.sgi.com/projects/FreeB 11f220fa62Smrg** 12f220fa62Smrg** Note that, as provided in the License, the Software is distributed on an 13f220fa62Smrg** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS 14f220fa62Smrg** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND 15f220fa62Smrg** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A 16f220fa62Smrg** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. 17f220fa62Smrg** 18f220fa62Smrg** Original Code. The Original Code is: OpenGL Sample Implementation, 19f220fa62Smrg** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, 20f220fa62Smrg** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. 21f220fa62Smrg** Copyright in any portions created by third parties is as indicated 22f220fa62Smrg** elsewhere herein. All Rights Reserved. 23f220fa62Smrg** 24f220fa62Smrg** Additional Notice Provisions: The application programming interfaces 25f220fa62Smrg** established by SGI in conjunction with the Original Code are The 26f220fa62Smrg** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released 27f220fa62Smrg** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version 28f220fa62Smrg** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X 29f220fa62Smrg** Window System(R) (Version 1.3), released October 19, 1998. This software 30f220fa62Smrg** was created using the OpenGL(R) version 1.2.1 Sample Implementation 31f220fa62Smrg** published by SGI, but has not been independently verified as being 32f220fa62Smrg** compliant with the OpenGL(R) version 1.2.1 Specification. 33f220fa62Smrg*/ 34f220fa62Smrg 35f220fa62Smrg/* 36f220fa62Smrg * patch.c++ 37f220fa62Smrg * 38f220fa62Smrg */ 39f220fa62Smrg 40f220fa62Smrg#include <stdio.h> 41f220fa62Smrg#include "glimports.h" 42f220fa62Smrg#include "mystdio.h" 43f220fa62Smrg#include "myassert.h" 44f220fa62Smrg#include "mymath.h" 45f220fa62Smrg#include "mystring.h" 46f220fa62Smrg#include "patch.h" 47f220fa62Smrg#include "mapdesc.h" 48f220fa62Smrg#include "quilt.h" 49f220fa62Smrg#include "nurbsconsts.h" 50f220fa62Smrg#include "simplemath.h" //for glu_abs function in ::singleStep(); 51f220fa62Smrg 52f220fa62Smrg 53f220fa62Smrg/*-------------------------------------------------------------------------- 54f220fa62Smrg * Patch - copy patch from quilt and transform control points 55f220fa62Smrg *-------------------------------------------------------------------------- 56f220fa62Smrg */ 57f220fa62Smrg 58f220fa62SmrgPatch::Patch( Quilt_ptr geo, REAL *pta, REAL *ptb, Patch *n ) 59f220fa62Smrg{ 60f220fa62Smrg/* pspec[i].range is uninit here */ 61f220fa62Smrg mapdesc = geo->mapdesc; 62f220fa62Smrg cullval = mapdesc->isCulling() ? CULL_ACCEPT : CULL_TRIVIAL_ACCEPT; 63f220fa62Smrg notInBbox = mapdesc->isBboxSubdividing() ? 1 : 0; 64f220fa62Smrg needsSampling = mapdesc->isRangeSampling() ? 1 : 0; 65f220fa62Smrg pspec[0].order = geo->qspec[0].order; 66f220fa62Smrg pspec[1].order = geo->qspec[1].order; 67f220fa62Smrg pspec[0].stride = pspec[1].order * MAXCOORDS; 68f220fa62Smrg pspec[1].stride = MAXCOORDS; 69f220fa62Smrg 70f220fa62Smrg /* transform control points to sampling and culling spaces */ 71f220fa62Smrg REAL *ps = geo->cpts; 72f220fa62Smrg geo->select( pta, ptb ); 73f220fa62Smrg ps += geo->qspec[0].offset; 74f220fa62Smrg ps += geo->qspec[1].offset; 75f220fa62Smrg ps += geo->qspec[0].index * geo->qspec[0].order * geo->qspec[0].stride; 76f220fa62Smrg ps += geo->qspec[1].index * geo->qspec[1].order * geo->qspec[1].stride; 77f220fa62Smrg 78f220fa62Smrg if( needsSampling ) { 79f220fa62Smrg mapdesc->xformSampling( ps, geo->qspec[0].order, geo->qspec[0].stride, 80f220fa62Smrg geo->qspec[1].order, geo->qspec[1].stride, 81f220fa62Smrg spts, pspec[0].stride, pspec[1].stride ); 82f220fa62Smrg } 83f220fa62Smrg 84f220fa62Smrg if( cullval == CULL_ACCEPT ) { 85f220fa62Smrg mapdesc->xformCulling( ps, geo->qspec[0].order, geo->qspec[0].stride, 86f220fa62Smrg geo->qspec[1].order, geo->qspec[1].stride, 87f220fa62Smrg cpts, pspec[0].stride, pspec[1].stride ); 88f220fa62Smrg } 89f220fa62Smrg 90f220fa62Smrg if( notInBbox ) { 91f220fa62Smrg mapdesc->xformBounding( ps, geo->qspec[0].order, geo->qspec[0].stride, 92f220fa62Smrg geo->qspec[1].order, geo->qspec[1].stride, 93f220fa62Smrg bpts, pspec[0].stride, pspec[1].stride ); 94f220fa62Smrg } 95f220fa62Smrg 96f220fa62Smrg /* set scale range */ 97f220fa62Smrg pspec[0].range[0] = geo->qspec[0].breakpoints[geo->qspec[0].index]; 98f220fa62Smrg pspec[0].range[1] = geo->qspec[0].breakpoints[geo->qspec[0].index+1]; 99f220fa62Smrg pspec[0].range[2] = pspec[0].range[1] - pspec[0].range[0]; 100f220fa62Smrg 101f220fa62Smrg pspec[1].range[0] = geo->qspec[1].breakpoints[geo->qspec[1].index]; 102f220fa62Smrg pspec[1].range[1] = geo->qspec[1].breakpoints[geo->qspec[1].index+1]; 103f220fa62Smrg pspec[1].range[2] = pspec[1].range[1] - pspec[1].range[0]; 104f220fa62Smrg 105f220fa62Smrg // may need to subdivide to match range of sub-patch 106f220fa62Smrg if( pspec[0].range[0] != pta[0] ) { 107f220fa62Smrg assert( pspec[0].range[0] < pta[0] ); 108f220fa62Smrg Patch lower( *this, 0, pta[0], 0 ); 109f220fa62Smrg *this = lower; 110f220fa62Smrg } 111f220fa62Smrg 112f220fa62Smrg if( pspec[0].range[1] != ptb[0] ) { 113f220fa62Smrg assert( pspec[0].range[1] > ptb[0] ); 114f220fa62Smrg Patch upper( *this, 0, ptb[0], 0 ); 115f220fa62Smrg } 116f220fa62Smrg 117f220fa62Smrg if( pspec[1].range[0] != pta[1] ) { 118f220fa62Smrg assert( pspec[1].range[0] < pta[1] ); 119f220fa62Smrg Patch lower( *this, 1, pta[1], 0 ); 120f220fa62Smrg *this = lower; 121f220fa62Smrg } 122f220fa62Smrg 123f220fa62Smrg if( pspec[1].range[1] != ptb[1] ) { 124f220fa62Smrg assert( pspec[1].range[1] > ptb[1] ); 125f220fa62Smrg Patch upper( *this, 1, ptb[1], 0 ); 126f220fa62Smrg } 127f220fa62Smrg checkBboxConstraint(); 128f220fa62Smrg next = n; 129f220fa62Smrg} 130f220fa62Smrg 131f220fa62Smrg/*-------------------------------------------------------------------------- 132f220fa62Smrg * Patch - subdivide a patch along an isoparametric line 133f220fa62Smrg *-------------------------------------------------------------------------- 134f220fa62Smrg */ 135f220fa62Smrg 136f220fa62SmrgPatch::Patch( Patch& upper, int param, REAL value, Patch *n ) 137f220fa62Smrg{ 138f220fa62Smrg Patch& lower = *this; 139f220fa62Smrg 140f220fa62Smrg lower.cullval = upper.cullval; 141f220fa62Smrg lower.mapdesc = upper.mapdesc; 142f220fa62Smrg lower.notInBbox = upper.notInBbox; 143f220fa62Smrg lower.needsSampling = upper.needsSampling; 144f220fa62Smrg lower.pspec[0].order = upper.pspec[0].order; 145f220fa62Smrg lower.pspec[1].order = upper.pspec[1].order; 146f220fa62Smrg lower.pspec[0].stride = upper.pspec[0].stride; 147f220fa62Smrg lower.pspec[1].stride = upper.pspec[1].stride; 148f220fa62Smrg lower.next = n; 149f220fa62Smrg 150f220fa62Smrg /* reset scale range */ 151f220fa62Smrg switch( param ) { 152f220fa62Smrg case 0: { 153f220fa62Smrg REAL d = (value-upper.pspec[0].range[0]) / upper.pspec[0].range[2]; 154f220fa62Smrg if( needsSampling ) 155f220fa62Smrg mapdesc->subdivide( upper.spts, lower.spts, d, pspec[1].order, 156f220fa62Smrg pspec[1].stride, pspec[0].order, pspec[0].stride ); 157f220fa62Smrg 158f220fa62Smrg if( cullval == CULL_ACCEPT ) 159f220fa62Smrg mapdesc->subdivide( upper.cpts, lower.cpts, d, pspec[1].order, 160f220fa62Smrg pspec[1].stride, pspec[0].order, pspec[0].stride ); 161f220fa62Smrg 162f220fa62Smrg if( notInBbox ) 163f220fa62Smrg mapdesc->subdivide( upper.bpts, lower.bpts, d, pspec[1].order, 164f220fa62Smrg pspec[1].stride, pspec[0].order, pspec[0].stride ); 165f220fa62Smrg 166f220fa62Smrg lower.pspec[0].range[0] = upper.pspec[0].range[0]; 167f220fa62Smrg lower.pspec[0].range[1] = value; 168f220fa62Smrg lower.pspec[0].range[2] = value - upper.pspec[0].range[0]; 169f220fa62Smrg upper.pspec[0].range[0] = value; 170f220fa62Smrg upper.pspec[0].range[2] = upper.pspec[0].range[1] - value; 171f220fa62Smrg 172f220fa62Smrg lower.pspec[1].range[0] = upper.pspec[1].range[0]; 173f220fa62Smrg lower.pspec[1].range[1] = upper.pspec[1].range[1]; 174f220fa62Smrg lower.pspec[1].range[2] = upper.pspec[1].range[2]; 175f220fa62Smrg break; 176f220fa62Smrg } 177f220fa62Smrg case 1: { 178f220fa62Smrg REAL d = (value-upper.pspec[1].range[0]) / upper.pspec[1].range[2]; 179f220fa62Smrg if( needsSampling ) 180f220fa62Smrg mapdesc->subdivide( upper.spts, lower.spts, d, pspec[0].order, 181f220fa62Smrg pspec[0].stride, pspec[1].order, pspec[1].stride ); 182f220fa62Smrg if( cullval == CULL_ACCEPT ) 183f220fa62Smrg mapdesc->subdivide( upper.cpts, lower.cpts, d, pspec[0].order, 184f220fa62Smrg pspec[0].stride, pspec[1].order, pspec[1].stride ); 185f220fa62Smrg if( notInBbox ) 186f220fa62Smrg mapdesc->subdivide( upper.bpts, lower.bpts, d, pspec[0].order, 187f220fa62Smrg pspec[0].stride, pspec[1].order, pspec[1].stride ); 188f220fa62Smrg lower.pspec[0].range[0] = upper.pspec[0].range[0]; 189f220fa62Smrg lower.pspec[0].range[1] = upper.pspec[0].range[1]; 190f220fa62Smrg lower.pspec[0].range[2] = upper.pspec[0].range[2]; 191f220fa62Smrg 192f220fa62Smrg lower.pspec[1].range[0] = upper.pspec[1].range[0]; 193f220fa62Smrg lower.pspec[1].range[1] = value; 194f220fa62Smrg lower.pspec[1].range[2] = value - upper.pspec[1].range[0]; 195f220fa62Smrg upper.pspec[1].range[0] = value; 196f220fa62Smrg upper.pspec[1].range[2] = upper.pspec[1].range[1] - value; 197f220fa62Smrg break; 198f220fa62Smrg } 199f220fa62Smrg } 200f220fa62Smrg 201f220fa62Smrg // inherit bounding box 202f220fa62Smrg if( mapdesc->isBboxSubdividing() && ! notInBbox ) 203f220fa62Smrg memcpy( lower.bb, upper.bb, sizeof( bb ) ); 204f220fa62Smrg 205f220fa62Smrg lower.checkBboxConstraint(); 206f220fa62Smrg upper.checkBboxConstraint(); 207f220fa62Smrg} 208f220fa62Smrg 209f220fa62Smrg/*-------------------------------------------------------------------------- 210f220fa62Smrg * clamp - clamp the sampling rate to a given maximum 211f220fa62Smrg *-------------------------------------------------------------------------- 212f220fa62Smrg */ 213f220fa62Smrg 214f220fa62Smrgvoid 215f220fa62SmrgPatch::clamp( void ) 216f220fa62Smrg{ 217f220fa62Smrg if( mapdesc->clampfactor != N_NOCLAMPING ) { 218f220fa62Smrg pspec[0].clamp( mapdesc->clampfactor ); 219f220fa62Smrg pspec[1].clamp( mapdesc->clampfactor ); 220f220fa62Smrg } 221f220fa62Smrg} 222f220fa62Smrg 223f220fa62Smrgvoid 224f220fa62SmrgPatchspec::clamp( REAL clampfactor ) 225f220fa62Smrg{ 226f220fa62Smrg if( sidestep[0] < minstepsize ) 227f220fa62Smrg sidestep[0] = clampfactor * minstepsize; 228f220fa62Smrg if( sidestep[1] < minstepsize ) 229f220fa62Smrg sidestep[1] = clampfactor * minstepsize; 230f220fa62Smrg if( stepsize < minstepsize ) 231f220fa62Smrg stepsize = clampfactor * minstepsize; 232f220fa62Smrg} 233f220fa62Smrg 234f220fa62Smrgvoid 235f220fa62SmrgPatch::checkBboxConstraint( void ) 236f220fa62Smrg{ 237f220fa62Smrg if( notInBbox && 238f220fa62Smrg mapdesc->bboxTooBig( bpts, pspec[0].stride, pspec[1].stride, 239f220fa62Smrg pspec[0].order, pspec[1].order, bb ) != 1 ) { 240f220fa62Smrg notInBbox = 0; 241f220fa62Smrg } 242f220fa62Smrg} 243f220fa62Smrg 244f220fa62Smrgvoid 245f220fa62SmrgPatch::bbox( void ) 246f220fa62Smrg{ 247f220fa62Smrg if( mapdesc->isBboxSubdividing() ) 248f220fa62Smrg mapdesc->surfbbox( bb ); 249f220fa62Smrg} 250f220fa62Smrg 251f220fa62Smrg/*-------------------------------------------------------------------------- 252f220fa62Smrg * getstepsize - compute the sampling density across the patch 253f220fa62Smrg * and determine if patch needs to be subdivided 254f220fa62Smrg *-------------------------------------------------------------------------- 255f220fa62Smrg */ 256f220fa62Smrg 257f220fa62Smrgvoid 258f220fa62SmrgPatch::getstepsize( void ) 259f220fa62Smrg{ 260f220fa62Smrg pspec[0].minstepsize = pspec[1].minstepsize = 0; 261f220fa62Smrg pspec[0].needsSubdivision = pspec[1].needsSubdivision = 0; 262f220fa62Smrg 263f220fa62Smrg if( mapdesc->isConstantSampling() ) { 264f220fa62Smrg // fixed number of samples per patch in each direction 265f220fa62Smrg // maxsrate is number of s samples per patch 266f220fa62Smrg // maxtrate is number of t samples per patch 267f220fa62Smrg pspec[0].getstepsize( mapdesc->maxsrate ); 268f220fa62Smrg pspec[1].getstepsize( mapdesc->maxtrate ); 269f220fa62Smrg 270f220fa62Smrg } else if( mapdesc->isDomainSampling() ) { 271f220fa62Smrg // maxsrate is number of s samples per unit s length of domain 272f220fa62Smrg // maxtrate is number of t samples per unit t length of domain 273f220fa62Smrg pspec[0].getstepsize( mapdesc->maxsrate * pspec[0].range[2] ); 274f220fa62Smrg pspec[1].getstepsize( mapdesc->maxtrate * pspec[1].range[2] ); 275f220fa62Smrg 276f220fa62Smrg } else if( ! needsSampling ) { 277f220fa62Smrg pspec[0].singleStep(); 278f220fa62Smrg pspec[1].singleStep(); 279f220fa62Smrg } else { 280f220fa62Smrg // upper bound on path length between sample points 281f220fa62Smrg REAL tmp[MAXORDER][MAXORDER][MAXCOORDS]; 282f220fa62Smrg const int trstride = sizeof(tmp[0]) / sizeof(REAL); 283f220fa62Smrg const int tcstride = sizeof(tmp[0][0]) / sizeof(REAL); 284f220fa62Smrg 285f220fa62Smrg assert( pspec[0].order <= MAXORDER ); 286f220fa62Smrg 287f220fa62Smrg /* points have been transformed, therefore they are homogeneous */ 288f220fa62Smrg 289f220fa62Smrg int val = mapdesc->project( spts, pspec[0].stride, pspec[1].stride, 290f220fa62Smrg &tmp[0][0][0], trstride, tcstride, 291f220fa62Smrg pspec[0].order, pspec[1].order ); 292f220fa62Smrg if( val == 0 ) { 293f220fa62Smrg // control points cross infinity, therefore partials are undefined 294f220fa62Smrg pspec[0].getstepsize( mapdesc->maxsrate ); 295f220fa62Smrg pspec[1].getstepsize( mapdesc->maxtrate ); 296f220fa62Smrg } else { 297f220fa62Smrg REAL t1 = mapdesc->getProperty( N_PIXEL_TOLERANCE ); 298f220fa62Smrg// REAL t2 = mapdesc->getProperty( N_ERROR_TOLERANCE ); 299f220fa62Smrg pspec[0].minstepsize = ( mapdesc->maxsrate > 0.0 ) ? 300f220fa62Smrg (pspec[0].range[2] / mapdesc->maxsrate) : 0.0; 301f220fa62Smrg pspec[1].minstepsize = ( mapdesc->maxtrate > 0.0 ) ? 302f220fa62Smrg (pspec[1].range[2] / mapdesc->maxtrate) : 0.0; 303f220fa62Smrg if( mapdesc->isParametricDistanceSampling() || 304f220fa62Smrg mapdesc->isObjectSpaceParaSampling() ) { 305f220fa62Smrg 306f220fa62Smrg REAL t2; 307f220fa62Smrg t2 = mapdesc->getProperty( N_ERROR_TOLERANCE ); 308f220fa62Smrg 309f220fa62Smrg // t2 is upper bound on the distance between surface and tessellant 310f220fa62Smrg REAL ssv[2], ttv[2]; 311f220fa62Smrg REAL ss = mapdesc->calcPartialVelocity( ssv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 2, 0, pspec[0].range[2], pspec[1].range[2], 0 ); 312f220fa62Smrg REAL st = mapdesc->calcPartialVelocity( 0, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 1, 1, pspec[0].range[2], pspec[1].range[2], -1 ); 313f220fa62Smrg REAL tt = mapdesc->calcPartialVelocity( ttv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 0, 2, pspec[0].range[2], pspec[1].range[2], 1 ); 314f220fa62Smrg //make sure that ss st and tt are nonnegative: 315f220fa62Smrg if(ss <0) ss = -ss; 316f220fa62Smrg if(st <0) st = -st; 317f220fa62Smrg if(tt <0) tt = -tt; 318f220fa62Smrg 319f220fa62Smrg if( ss != 0.0 && tt != 0.0 ) { 320f220fa62Smrg /* printf( "ssv[0] %g ssv[1] %g ttv[0] %g ttv[1] %g\n", 321f220fa62Smrg ssv[0], ssv[1], ttv[0], ttv[1] ); */ 322f220fa62Smrg REAL ttq = sqrtf( (float) ss ); 323f220fa62Smrg REAL ssq = sqrtf( (float) tt ); 324f220fa62Smrg REAL ds = sqrtf( 4 * t2 * ttq / ( ss * ttq + st * ssq ) ); 325f220fa62Smrg REAL dt = sqrtf( 4 * t2 * ssq / ( tt * ssq + st * ttq ) ); 326f220fa62Smrg pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2]; 327f220fa62Smrg REAL scutoff = 2.0 * t2 / ( pspec[0].range[2] * pspec[0].range[2]); 328f220fa62Smrg pspec[0].sidestep[0] = (ssv[0] > scutoff) ? sqrtf( 2.0 * t2 / ssv[0] ) : pspec[0].range[2]; 329f220fa62Smrg pspec[0].sidestep[1] = (ssv[1] > scutoff) ? sqrtf( 2.0 * t2 / ssv[1] ) : pspec[0].range[2]; 330f220fa62Smrg 331f220fa62Smrg pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2]; 332f220fa62Smrg REAL tcutoff = 2.0 * t2 / ( pspec[1].range[2] * pspec[1].range[2]); 333f220fa62Smrg pspec[1].sidestep[0] = (ttv[0] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[0] ) : pspec[1].range[2]; 334f220fa62Smrg pspec[1].sidestep[1] = (ttv[1] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[1] ) : pspec[1].range[2]; 335f220fa62Smrg } else if( ss != 0.0 ) { 336f220fa62Smrg REAL x = pspec[1].range[2] * st; 337f220fa62Smrg REAL ds = ( sqrtf( x * x + 8.0 * t2 * ss ) - x ) / ss; 338f220fa62Smrg pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2]; 339f220fa62Smrg REAL scutoff = 2.0 * t2 / ( pspec[0].range[2] * pspec[0].range[2]); 340f220fa62Smrg pspec[0].sidestep[0] = (ssv[0] > scutoff) ? sqrtf( 2.0 * t2 / ssv[0] ) : pspec[0].range[2]; 341f220fa62Smrg pspec[0].sidestep[1] = (ssv[1] > scutoff) ? sqrtf( 2.0 * t2 / ssv[1] ) : pspec[0].range[2]; 342f220fa62Smrg pspec[1].singleStep(); 343f220fa62Smrg } else if( tt != 0.0 ) { 344f220fa62Smrg REAL x = pspec[0].range[2] * st; 345f220fa62Smrg REAL dt = ( sqrtf( x * x + 8.0 * t2 * tt ) - x ) / tt; 346f220fa62Smrg pspec[0].singleStep(); 347f220fa62Smrg REAL tcutoff = 2.0 * t2 / ( pspec[1].range[2] * pspec[1].range[2]); 348f220fa62Smrg pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2]; 349f220fa62Smrg pspec[1].sidestep[0] = (ttv[0] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[0] ) : pspec[1].range[2]; 350f220fa62Smrg pspec[1].sidestep[1] = (ttv[1] > tcutoff) ? sqrtf( 2.0 * t2 / ttv[1] ) : pspec[1].range[2]; 351f220fa62Smrg } else { 352f220fa62Smrg if( 4.0 * t2 > st * pspec[0].range[2] * pspec[1].range[2] ) { 353f220fa62Smrg pspec[0].singleStep(); 354f220fa62Smrg pspec[1].singleStep(); 355f220fa62Smrg } else { 356f220fa62Smrg REAL area = 4.0 * t2 / st; 357f220fa62Smrg REAL ds = sqrtf( area * pspec[0].range[2] / pspec[1].range[2] ); 358f220fa62Smrg REAL dt = sqrtf( area * pspec[1].range[2] / pspec[0].range[2] ); 359f220fa62Smrg pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2]; 360f220fa62Smrg pspec[0].sidestep[0] = pspec[0].range[2]; 361f220fa62Smrg pspec[0].sidestep[1] = pspec[0].range[2]; 362f220fa62Smrg 363f220fa62Smrg pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2]; 364f220fa62Smrg pspec[1].sidestep[0] = pspec[1].range[2]; 365f220fa62Smrg pspec[1].sidestep[1] = pspec[1].range[2]; 366f220fa62Smrg } 367f220fa62Smrg } 368f220fa62Smrg } else if( mapdesc->isPathLengthSampling() || 369f220fa62Smrg mapdesc->isObjectSpacePathSampling()) { 370f220fa62Smrg // t1 is upper bound on path length 371f220fa62Smrg REAL msv[2], mtv[2]; 372f220fa62Smrg REAL ms = mapdesc->calcPartialVelocity( msv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 1, 0, pspec[0].range[2], pspec[1].range[2], 0 ); 373f220fa62Smrg REAL mt = mapdesc->calcPartialVelocity( mtv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 0, 1, pspec[0].range[2], pspec[1].range[2], 1 ); 374f220fa62Smrg REAL side_scale = 1.0; 375f220fa62Smrg 376f220fa62Smrg if( ms != 0.0 ) { 377f220fa62Smrg if( mt != 0.0 ) { 378f220fa62Smrg/* REAL d = t1 / ( ms * ms + mt * mt );*/ 379f220fa62Smrg/* REAL ds = mt * d;*/ 380f220fa62Smrg REAL ds = t1 / (2.0*ms); 381f220fa62Smrg/* REAL dt = ms * d;*/ 382f220fa62Smrg REAL dt = t1 / (2.0*mt); 383f220fa62Smrg pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2]; 384f220fa62Smrg pspec[0].sidestep[0] = ( msv[0] * pspec[0].range[2] > t1 ) ? (side_scale* t1 / msv[0]) : pspec[0].range[2]; 385f220fa62Smrg pspec[0].sidestep[1] = ( msv[1] * pspec[0].range[2] > t1 ) ? (side_scale* t1 / msv[1]) : pspec[0].range[2]; 386f220fa62Smrg 387f220fa62Smrg pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2]; 388f220fa62Smrg pspec[1].sidestep[0] = ( mtv[0] * pspec[1].range[2] > t1 ) ? (side_scale*t1 / mtv[0]) : pspec[1].range[2]; 389f220fa62Smrg pspec[1].sidestep[1] = ( mtv[1] * pspec[1].range[2] > t1 ) ? (side_scale*t1 / mtv[1]) : pspec[1].range[2]; 390f220fa62Smrg } else { 391f220fa62Smrg pspec[0].stepsize = ( t1 < ms * pspec[0].range[2] ) ? (t1 / ms) : pspec[0].range[2]; 392f220fa62Smrg pspec[0].sidestep[0] = ( msv[0] * pspec[0].range[2] > t1 ) ? (t1 / msv[0]) : pspec[0].range[2]; 393f220fa62Smrg pspec[0].sidestep[1] = ( msv[1] * pspec[0].range[2] > t1 ) ? (t1 / msv[1]) : pspec[0].range[2]; 394f220fa62Smrg 395f220fa62Smrg pspec[1].singleStep(); 396f220fa62Smrg } 397f220fa62Smrg } else { 398f220fa62Smrg if( mt != 0.0 ) { 399f220fa62Smrg pspec[0].singleStep(); 400f220fa62Smrg 401f220fa62Smrg pspec[1].stepsize = ( t1 < mt * pspec[1].range[2] ) ? (t1 / mt) : pspec[1].range[2]; 402f220fa62Smrg pspec[1].sidestep[0] = ( mtv[0] * pspec[1].range[2] > t1 ) ? (t1 / mtv[0]) : pspec[1].range[2]; 403f220fa62Smrg pspec[1].sidestep[1] = ( mtv[1] * pspec[1].range[2] > t1 ) ? (t1 / mtv[1]) : pspec[1].range[2]; 404f220fa62Smrg } else { 405f220fa62Smrg pspec[0].singleStep(); 406f220fa62Smrg pspec[1].singleStep(); 407f220fa62Smrg } 408f220fa62Smrg } 409f220fa62Smrg } else if( mapdesc->isSurfaceAreaSampling() ) { 410f220fa62Smrg // t is the square root of area 411f220fa62Smrg/* 412f220fa62Smrg REAL msv[2], mtv[2]; 413f220fa62Smrg REAL ms = mapdesc->calcPartialVelocity( msv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 1, 0, pspec[0].range[2], pspec[1].range[2], 0 ); 414f220fa62Smrg REAL mt = mapdesc->calcPartialVelocity( mtv, &tmp[0][0][0], trstride, tcstride, pspec[0].order, pspec[1].order, 0, 1, pspec[0].range[2], pspec[1].range[2], 1 ); 415f220fa62Smrg if( ms != 0.0 && mt != 0.0 ) { 416f220fa62Smrg REAL d = 1.0 / (ms * mt); 417f220fa62Smrg t *= M_SQRT2; 418f220fa62Smrg REAL ds = t * sqrtf( d * pspec[0].range[2] / pspec[1].range[2] ); 419f220fa62Smrg REAL dt = t * sqrtf( d * pspec[1].range[2] / pspec[0].range[2] ); 420f220fa62Smrg pspec[0].stepsize = ( ds < pspec[0].range[2] ) ? ds : pspec[0].range[2]; 421f220fa62Smrg pspec[0].sidestep[0] = ( msv[0] * pspec[0].range[2] > t ) ? (t / msv[0]) : pspec[0].range[2]; 422f220fa62Smrg pspec[0].sidestep[1] = ( msv[1] * pspec[0].range[2] > t ) ? (t / msv[1]) : pspec[0].range[2]; 423f220fa62Smrg 424f220fa62Smrg pspec[1].stepsize = ( dt < pspec[1].range[2] ) ? dt : pspec[1].range[2]; 425f220fa62Smrg pspec[1].sidestep[0] = ( mtv[0] * pspec[1].range[2] > t ) ? (t / mtv[0]) : pspec[1].range[2]; 426f220fa62Smrg pspec[1].sidestep[1] = ( mtv[1] * pspec[1].range[2] > t ) ? (t / mtv[1]) : pspec[1].range[2]; 427f220fa62Smrg } else { 428f220fa62Smrg pspec[0].singleStep(); 429f220fa62Smrg pspec[1].singleStep(); 430f220fa62Smrg } 431f220fa62Smrg*/ 432f220fa62Smrg } else { 433f220fa62Smrg pspec[0].singleStep(); 434f220fa62Smrg pspec[1].singleStep(); 435f220fa62Smrg } 436f220fa62Smrg } 437f220fa62Smrg } 438f220fa62Smrg 439f220fa62Smrg#ifdef DEBUG 440f220fa62Smrg _glu_dprintf( "sidesteps %g %g %g %g, stepsize %g %g\n", 441f220fa62Smrg pspec[0].sidestep[0], pspec[0].sidestep[1], 442f220fa62Smrg pspec[1].sidestep[0], pspec[1].sidestep[1], 443f220fa62Smrg pspec[0].stepsize, pspec[1].stepsize ); 444f220fa62Smrg#endif 445f220fa62Smrg 446f220fa62Smrg if( mapdesc->minsavings != N_NOSAVINGSSUBDIVISION ) { 447f220fa62Smrg REAL savings = 1./(pspec[0].stepsize * pspec[1].stepsize) ; 448f220fa62Smrg savings-= (2./( pspec[0].sidestep[0] + pspec[0].sidestep[1] )) * 449f220fa62Smrg (2./( pspec[1].sidestep[0] + pspec[1].sidestep[1] )); 450f220fa62Smrg 451f220fa62Smrg savings *= pspec[0].range[2] * pspec[1].range[2]; 452f220fa62Smrg if( savings > mapdesc->minsavings ) { 453f220fa62Smrg pspec[0].needsSubdivision = pspec[1].needsSubdivision = 1; 454f220fa62Smrg } 455f220fa62Smrg } 456f220fa62Smrg 457f220fa62Smrg if( pspec[0].stepsize < pspec[0].minstepsize ) pspec[0].needsSubdivision = 1; 458f220fa62Smrg if( pspec[1].stepsize < pspec[1].minstepsize ) pspec[1].needsSubdivision = 1; 459f220fa62Smrg needsSampling = (needsSampling ? needsSamplingSubdivision() : 0); 460f220fa62Smrg} 461f220fa62Smrg 462f220fa62Smrgvoid 463f220fa62SmrgPatchspec::singleStep() 464f220fa62Smrg{ 465f220fa62Smrg stepsize = sidestep[0] = sidestep[1] = glu_abs(range[2]); 466f220fa62Smrg} 467f220fa62Smrg 468f220fa62Smrgvoid 469f220fa62SmrgPatchspec::getstepsize( REAL max ) // max is number of samples for entire patch 470f220fa62Smrg{ 471f220fa62Smrg stepsize = ( max >= 1.0 ) ? range[2] / max : range[2]; 472f220fa62Smrg if (stepsize < 0.0) { 473f220fa62Smrg stepsize = -stepsize; 474f220fa62Smrg } 475f220fa62Smrg sidestep[0] = sidestep[1] = minstepsize = stepsize; 476f220fa62Smrg} 477f220fa62Smrg 478f220fa62Smrgint 479f220fa62SmrgPatch::needsSamplingSubdivision( void ) 480f220fa62Smrg{ 481f220fa62Smrg return (pspec[0].needsSubdivision || pspec[1].needsSubdivision) ? 1 : 0; 482f220fa62Smrg} 483f220fa62Smrg 484f220fa62Smrgint 485f220fa62SmrgPatch::needsNonSamplingSubdivision( void ) 486f220fa62Smrg{ 487f220fa62Smrg return notInBbox; 488f220fa62Smrg} 489f220fa62Smrg 490f220fa62Smrgint 491f220fa62SmrgPatch::needsSubdivision( int param ) 492f220fa62Smrg{ 493f220fa62Smrg return pspec[param].needsSubdivision; 494f220fa62Smrg} 495f220fa62Smrg 496f220fa62Smrgint 497f220fa62SmrgPatch::cullCheck( void ) 498f220fa62Smrg{ 499f220fa62Smrg if( cullval == CULL_ACCEPT ) 500f220fa62Smrg cullval = mapdesc->cullCheck( cpts, pspec[0].order, pspec[0].stride, 501f220fa62Smrg pspec[1].order, pspec[1].stride ); 502f220fa62Smrg return cullval; 503f220fa62Smrg} 504f220fa62Smrg 505