1 /* NAME: 2 E3GeometryNURBPatch.c 3 4 DESCRIPTION: 5 Implementation of Quesa NURB Patch geometry class. 6 7 COPYRIGHT: 8 Copyright (c) 1999-2005, Quesa Developers. All rights reserved. 9 10 For the current release of Quesa, please see: 11 12 <http://www.quesa.org/> 13 14 Redistribution and use in source and binary forms, with or without 15 modification, are permitted provided that the following conditions 16 are met: 17 18 o Redistributions of source code must retain the above copyright 19 notice, this list of conditions and the following disclaimer. 20 21 o Redistributions in binary form must reproduce the above 22 copyright notice, this list of conditions and the following 23 disclaimer in the documentation and/or other materials provided 24 with the distribution. 25 26 o Neither the name of Quesa nor the names of its contributors 27 may be used to endorse or promote products derived from this 28 software without specific prior written permission. 29 30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 36 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 37 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 38 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 39 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 40 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 ___________________________________________________________________________ 42 */ 43 //============================================================================= 44 // Include files 45 //----------------------------------------------------------------------------- 46 #include "E3Prefix.h" 47 #include "E3View.h" 48 #include "E3Geometry.h" 49 #include "E3GeometryTriMesh.h" 50 #include "E3GeometryNURBPatch.h" 51 52 53 54 55 56 //============================================================================= 57 // Internal constants 58 //----------------------------------------------------------------------------- 59 #define kFiniteSubdivision 32 60 61 62 63 64 65 //============================================================================= 66 // Internal types 67 //----------------------------------------------------------------------------- 68 69 class E3NURBPatch : public E3Geometry // This is a leaf class so no other classes use this, 70 // so it can be here in the .c file rather than in 71 // the .h file, hence all the fields can be public 72 // as nobody should be including this file 73 { 74 Q3_CLASS_ENUMS ( kQ3GeometryTypeNURBPatch, E3NURBPatch, E3Geometry ) 75 public : 76 77 TQ3NURBPatchData instanceData ; 78 79 } ; 80 81 82 83 //============================================================================= 84 // Internal functions 85 //----------------------------------------------------------------------------- 86 // e3geom_patch_copydata : Copy TQ3NURBPatchData from one to another. 87 //----------------------------------------------------------------------------- 88 // Note : If isDuplicate is true, we duplicate shared objects rather than 89 // obtaining new references to them. 90 //----------------------------------------------------------------------------- 91 static TQ3Status 92 e3geom_patch_copydata(const TQ3NURBPatchData *src, TQ3NURBPatchData *dst, TQ3Boolean isDuplicate) 93 { 94 TQ3Status qd3dStatus = kQ3Success; 95 TQ3Uns32 theSize, i, j, numKnots; 96 97 // copy uOrders, vOrder, numColumns, numRows, numTrimLoops 98 dst->uOrder = src->uOrder; 99 dst->vOrder = src->vOrder; 100 dst->numColumns = src->numColumns; 101 dst->numRows = src->numRows; 102 dst->numTrimLoops = src->numTrimLoops; 103 104 // copy controlPoints, uKnots, vKnots 105 theSize = sizeof(TQ3RationalPoint4D) * src->numColumns * src->numRows; 106 dst->controlPoints = (TQ3RationalPoint4D *) Q3Memory_Allocate( theSize ); 107 Q3Memory_Copy( src->controlPoints, dst->controlPoints, theSize ); 108 109 theSize = sizeof(float) * (src->uOrder+src->numColumns); 110 dst->uKnots = (float *) Q3Memory_Allocate( theSize ); 111 Q3Memory_Copy( src->uKnots, dst->uKnots, theSize ); 112 113 theSize = sizeof(float) * (src->vOrder+src->numRows); 114 dst->vKnots = (float *) Q3Memory_Allocate( theSize ); 115 Q3Memory_Copy( src->vKnots, dst->vKnots, theSize ); 116 117 // Copy all trim loops. 118 // This is complicated because we have several layers of nested arrays. 119 dst->numTrimLoops = src->numTrimLoops; 120 if (src->numTrimLoops) 121 { 122 // Copy TrimLoops, basic data. 123 theSize = sizeof(TQ3NURBPatchTrimLoopData) * src->numTrimLoops; 124 dst->trimLoops = (TQ3NURBPatchTrimLoopData *) Q3Memory_Allocate( theSize ); 125 Q3Memory_Copy( src->trimLoops, dst->trimLoops, theSize ); 126 127 // Now iterate over trim loop curves, copy them. 128 for (i=0; i < src->numTrimLoops; i++) { 129 130 // For a particular trimLoop i, copy its array of curve data. 131 theSize = sizeof(TQ3NURBPatchTrimCurveData) * src->trimLoops[i].numTrimCurves; 132 if (theSize) { 133 dst->trimLoops[i].trimCurves = (TQ3NURBPatchTrimCurveData *) Q3Memory_Allocate( theSize ); 134 Q3Memory_Copy( src->trimLoops[i].trimCurves, dst->trimLoops[i].trimCurves, theSize ); 135 136 // Now, for a particular curve, copy its control points and knots. 137 for (j=0; j < src->trimLoops[i].numTrimCurves; j++) { 138 theSize = sizeof(TQ3RationalPoint3D) * src->trimLoops[i].trimCurves[j].numPoints; 139 if (theSize) { 140 dst->trimLoops[i].trimCurves[j].controlPoints = (TQ3RationalPoint3D *) Q3Memory_Allocate(theSize); 141 Q3Memory_Copy( src->trimLoops[i].trimCurves[j].controlPoints, 142 dst->trimLoops[i].trimCurves[j].controlPoints, 143 theSize ); 144 } 145 numKnots = src->trimLoops[i].trimCurves[j].numPoints 146 + src->trimLoops[i].trimCurves[j].order; 147 theSize = sizeof(float) * numKnots; 148 if (theSize) { 149 dst->trimLoops[i].trimCurves[j].knots = (float *) Q3Memory_Allocate(theSize); 150 Q3Memory_Copy( src->trimLoops[i].trimCurves[j].knots, 151 dst->trimLoops[i].trimCurves[j].knots, 152 theSize ); 153 } 154 } 155 } 156 } 157 } else dst->trimLoops = NULL; 158 159 160 // copy or shared-replace the attributes 161 if (isDuplicate) 162 { 163 if (src->patchAttributeSet != NULL) 164 { 165 dst->patchAttributeSet = Q3Object_Duplicate(src->patchAttributeSet); 166 if (dst->patchAttributeSet == NULL) qd3dStatus = kQ3Failure; 167 } else dst->patchAttributeSet = NULL; 168 169 } 170 else { 171 E3Shared_Replace(&dst->patchAttributeSet, src->patchAttributeSet); 172 } 173 174 return qd3dStatus; 175 } 176 177 178 179 180 181 //============================================================================= 182 // e3geom_patch_disposedata : Dispose of a TQ3NURBPatch's data. 183 //----------------------------------------------------------------------------- 184 static void 185 e3geom_patch_disposedata(TQ3NURBPatchData *theNURBPatch) 186 { 187 TQ3Uns32 i, j; 188 189 Q3Memory_Free( &theNURBPatch->controlPoints ); 190 Q3Memory_Free( &theNURBPatch->uKnots ); 191 Q3Memory_Free( &theNURBPatch->vKnots ); 192 Q3Object_CleanDispose(&theNURBPatch->patchAttributeSet ); 193 194 for (i=0; i < theNURBPatch->numTrimLoops; i++) { 195 for (j=0; j < theNURBPatch->trimLoops[i].numTrimCurves; j++) { 196 Q3Memory_Free( &theNURBPatch->trimLoops[i].trimCurves[j].controlPoints ); 197 Q3Memory_Free( &theNURBPatch->trimLoops[i].trimCurves[j].knots ); 198 } 199 Q3Memory_Free( &theNURBPatch->trimLoops[i].trimCurves ); 200 } 201 Q3Memory_Free( &theNURBPatch->trimLoops ); 202 } 203 204 205 206 207 208 //============================================================================= 209 // e3geom_nurbpatch_new : NURBPatch new method. 210 //----------------------------------------------------------------------------- 211 static TQ3Status 212 e3geom_nurbpatch_new(TQ3Object theObject, void *privateData, const void *paramData) 213 { TQ3NURBPatchData *instanceData = (TQ3NURBPatchData *) privateData; 214 const TQ3NURBPatchData *nurbpatchData = (const TQ3NURBPatchData *) paramData; 215 TQ3Status qd3dStatus; 216 #pragma unused(theObject) 217 218 219 // Initialise our instance data 220 qd3dStatus = e3geom_patch_copydata(nurbpatchData, instanceData, kQ3False); 221 222 return(qd3dStatus); 223 } 224 225 226 227 228 229 //============================================================================= 230 // e3geom_nurbpatch_delete : NURBPatch delete method. 231 //----------------------------------------------------------------------------- 232 static void 233 e3geom_nurbpatch_delete(TQ3Object theObject, void *privateData) 234 { TQ3NURBPatchData *instanceData = (TQ3NURBPatchData *) privateData; 235 #pragma unused(theObject) 236 237 238 // Dispose of our instance data 239 e3geom_patch_disposedata(instanceData); 240 } 241 242 243 244 245 246 //============================================================================= 247 // e3geom_nurbpatch_duplicate : NURBPatch duplicate method. 248 //----------------------------------------------------------------------------- 249 static TQ3Status 250 e3geom_nurbpatch_duplicate(TQ3Object fromObject, const void *fromPrivateData, 251 TQ3Object toObject, void *toPrivateData) 252 { const TQ3NURBPatchData *fromInstanceData = (const TQ3NURBPatchData *) fromPrivateData; 253 TQ3NURBPatchData *toInstanceData = (TQ3NURBPatchData *) toPrivateData; 254 TQ3Status qd3dStatus; 255 #pragma unused(fromObject) 256 #pragma unused(toObject) 257 258 259 260 // Validate our parameters 261 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(fromObject), kQ3Failure); 262 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(fromPrivateData), kQ3Failure); 263 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(toObject), kQ3Failure); 264 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(toPrivateData), kQ3Failure); 265 266 267 268 // Initialise the instance data of the new object 269 qd3dStatus = e3geom_patch_copydata( fromInstanceData, toInstanceData, kQ3True ); 270 271 272 273 // Handle failure 274 if (qd3dStatus != kQ3Success) 275 e3geom_patch_disposedata(toInstanceData); 276 277 return(qd3dStatus); 278 } 279 280 281 282 283 284 //============================================================================= 285 // e3geom_nurbpatch_evaluate_basis : Evaluate the basis. 286 //----------------------------------------------------------------------------- 287 // Note : This is the recursive definition, as in the Schneider article. 288 // fracR = 1 - fracL. That's why non-recursive versions are so 289 // fast, they take one-minus over and over again. 290 //----------------------------------------------------------------------------- 291 static float 292 e3geom_nurbpatch_evaluate_basis( float u, TQ3Uns32 i, TQ3Uns32 k, float *knots ) 293 { float bottomL, bottomR, fracL, fracR, theResult; 294 295 296 if ( k == 1 ) { 297 if ( u >= knots[i] && u <= knots[i+1] ) 298 theResult = 1.0f ; 299 else 300 theResult = 0.0f ; 301 } 302 303 else { 304 bottomL = ( knots[i+k-1] - knots[i] ) ; 305 fracL = 306 ( bottomL <= kQ3RealZero ) ? 0.0f : // floating point inaccuracies 307 ( u - knots[i] ) / bottomL ; 308 bottomR = ( knots[i+k] - knots[i+1] ) ; 309 fracR = 310 ( bottomR <= kQ3RealZero ) ? 0.0f : // fp inaccuracies 311 ( knots[i+k] - u ) / bottomR ; 312 313 // stops recursing if we already know the result will be 0 314 if ( fracL > kQ3RealZero ) // fp inaccuracies 315 fracL *= e3geom_nurbpatch_evaluate_basis(u,i,k-1,knots) ; 316 else fracL = 0.0f ; 317 318 if ( fracR > kQ3RealZero ) // fp inaccuracies 319 fracR *= e3geom_nurbpatch_evaluate_basis(u,i+1,k-1,knots) ; 320 else fracR = 0.0f ; 321 322 theResult = fracL + fracR ; 323 } 324 325 return theResult; 326 } 327 328 329 330 331 332 //============================================================================= 333 // e3geom_nurbpatch_evaluate_basis_deriv : Evaluate the basis derivative. 334 //----------------------------------------------------------------------------- 335 // Note : Also lifted from the B,B,&B book. 336 //----------------------------------------------------------------------------- 337 static float 338 e3geom_nurbpatch_evaluate_basis_deriv( float u, TQ3Uns32 i, TQ3Uns32 k, float *knots ) 339 { 340 341 //float theResult ; 342 float bottomL, bottomR, fracL, fracR ; 343 344 bottomL = ( knots[i+k-1] - knots[i] ) ; 345 fracL = 346 ( bottomL <= kQ3RealZero ) ? 0.0f : // floating point inaccuracies 347 1.0f / bottomL ; 348 bottomR = ( knots[i+k] - knots[i+1] ) ; 349 fracR = 350 ( bottomR <= kQ3RealZero ) ? 0.0f : // fp inaccuracies 351 1.0f / bottomR ; 352 353 // stops recursing if we already know the result will be 0 354 if ( fracL > kQ3RealZero ) // fp inaccuracies 355 fracL *= e3geom_nurbpatch_evaluate_basis(u,i,k-1,knots) ; 356 else fracL = 0.0f ; 357 358 if ( fracR > kQ3RealZero ) // fp inaccuracies 359 fracR *= e3geom_nurbpatch_evaluate_basis(u,i+1,k-1,knots) ; 360 else fracR = 0.0f ; 361 362 return (k-1)*(fracL - fracR) ; 363 } 364 365 366 367 368 369 //============================================================================= 370 // e3geom_nurbpatch_evaluate_uv : Evaluate the NURB patch data, computing 371 // the normal. 372 //----------------------------------------------------------------------------- 373 // Note : Returns the coordinates into outPoint and the normal into 374 // outNormal. 375 //----------------------------------------------------------------------------- 376 static void 377 e3geom_nurbpatch_evaluate_uv( float u, float v, const TQ3NURBPatchData * patchData, TQ3Vector3D * outNormal, TQ3Point3D * outPoint, 378 float* uBasisValues, float* vBasisValues, float* uBasisDerivValues, float* vBasisDerivValues ) 379 { 380 381 TQ3Uns32 iU, jV ; 382 float xTop, yTop, zTop, xTopDu, yTopDu, zTopDu, xTopDv, yTopDv, zTopDv ; 383 float OneOverBottom, bottom, bottom_squared, bottomDu, bottomDv ; 384 TQ3Vector3D dU, dV ; 385 386 // Let's... 387 xTop = yTop = zTop = bottom = xTopDu = xTopDv = yTopDu = yTopDv = zTopDu = zTopDv = bottomDu = bottomDv = 0.0f ; 388 // Go 389 for ( iU = 0; iU < patchData->numColumns; iU++ ) { 390 uBasisValues[iU] = e3geom_nurbpatch_evaluate_basis( u, iU, patchData->uOrder, patchData->uKnots) ; 391 uBasisDerivValues[iU] = e3geom_nurbpatch_evaluate_basis_deriv( u, iU, patchData->uOrder, patchData->uKnots) ; 392 } 393 394 // Again 395 for ( jV = 0; jV < patchData->numRows; jV++ ) { 396 vBasisValues[jV] = e3geom_nurbpatch_evaluate_basis( v, jV, patchData->vOrder, patchData->vKnots) ; 397 vBasisDerivValues[jV] = e3geom_nurbpatch_evaluate_basis_deriv( v, jV, patchData->vOrder, patchData->vKnots) ; 398 } 399 400 // Now some summation rotation recreation, like p. 46-47 in Bartels, Beatty, & Barsky 401 for ( jV = 0; jV < patchData->numRows; jV++ ) { 402 for ( iU = 0; iU < patchData->numColumns; iU++ ) { 403 // First the point 404 xTop += patchData->controlPoints[patchData->numColumns*jV + iU].x * uBasisValues[iU] * vBasisValues[jV] ; 405 yTop += patchData->controlPoints[patchData->numColumns*jV + iU].y * uBasisValues[iU] * vBasisValues[jV] ; 406 zTop += patchData->controlPoints[patchData->numColumns*jV + iU].z * uBasisValues[iU] * vBasisValues[jV] ; 407 bottom += patchData->controlPoints[patchData->numColumns*jV + iU].w * uBasisValues[iU] * vBasisValues[jV] ; 408 /* Now let's take care of the derivatives */ 409 /* 410 * To do the derivative, we must use the chain rule: 411 * ((low * Dhigh) - (high * Dlow)) / low^2. 412 * 413 * So for this upcoming loop, we are building the Du of the individual Top's and the bottom, as well as the Dv of the Top's 414 * and bottom. 415 * Then later I will put it together with that chain rule to get my answer. 416 */ 417 // So first Du 418 xTopDu += patchData->controlPoints[patchData->numColumns*jV + iU].x * uBasisDerivValues[iU] * vBasisValues[jV] ; 419 yTopDu += patchData->controlPoints[patchData->numColumns*jV + iU].y * uBasisDerivValues[iU] * vBasisValues[jV] ; 420 zTopDu += patchData->controlPoints[patchData->numColumns*jV + iU].z * uBasisDerivValues[iU] * vBasisValues[jV] ; 421 bottomDu += patchData->controlPoints[patchData->numColumns*jV + iU].w * uBasisDerivValues[iU] * vBasisValues[jV] ; 422 // And next Dv 423 xTopDv += patchData->controlPoints[patchData->numColumns*jV + iU].x * uBasisValues[iU] * vBasisDerivValues[jV] ; 424 yTopDv += patchData->controlPoints[patchData->numColumns*jV + iU].y * uBasisValues[iU] * vBasisDerivValues[jV] ; 425 zTopDv += patchData->controlPoints[patchData->numColumns*jV + iU].z * uBasisValues[iU] * vBasisDerivValues[jV] ; 426 bottomDv += patchData->controlPoints[patchData->numColumns*jV + iU].w * uBasisValues[iU] * vBasisDerivValues[jV] ; 427 } } 428 429 430 // Calculate bottom squared 431 Q3_ASSERT(bottom != 0.0f); 432 bottom_squared = bottom * bottom ; 433 434 435 // The point 436 OneOverBottom = 1.0f / bottom ; 437 outPoint->x = xTop * OneOverBottom ; 438 outPoint->y = yTop * OneOverBottom ; 439 outPoint->z = zTop * OneOverBottom ; 440 441 /* The Du vector */ 442 // low^2 = bottom^2 443 OneOverBottom = 1.0f / bottom_squared ; 444 // ((low * Dhigh) - (high * Dlow)) / bottom^2 445 dU.x = ((bottom * xTopDu) - (xTop * bottomDu))*OneOverBottom ; 446 dU.y = ((bottom * yTopDu) - (yTop * bottomDu))*OneOverBottom ; 447 dU.z = ((bottom * zTopDu) - (zTop * bottomDu))*OneOverBottom ; 448 449 /* The Dv vector */ 450 // low^2 = bottom^2 451 // OneOverBottom = same as above 452 // ((low * Dhigh) - (high * Dlow)) / bottom^2 453 dV.x = ((bottom * xTopDv) - (xTop * bottomDv))*OneOverBottom ; 454 dV.y = ((bottom * yTopDv) - (yTop * bottomDv))*OneOverBottom ; 455 dV.z = ((bottom * zTopDv) - (zTop * bottomDv))*OneOverBottom ; 456 457 Q3Vector3D_Cross(&dU, &dV, outNormal); 458 459 // Normalize the normal vector 460 if (Q3FastVector3D_LengthSquared(outNormal) < kQ3RealZero) 461 { 462 outNormal->x = 1.0f; // arbitrary unit vector 463 outNormal->y = 0.0f; 464 outNormal->z = 0.0f; 465 } 466 else 467 { 468 Q3FastVector3D_Normalize( outNormal, outNormal ); 469 } 470 } 471 472 473 474 475 476 //============================================================================= 477 // e3geom_nurbpatch_evaluate_uv_no_deriv : Evaluate the NURB patch data 478 // without computing the normal. 479 //----------------------------------------------------------------------------- 480 // Note : Returns the coordinates into outPoint 481 //----------------------------------------------------------------------------- 482 static void 483 e3geom_nurbpatch_evaluate_uv_no_deriv( float u, float v, const TQ3NURBPatchData * patchData, TQ3Point3D * outPoint, 484 float* uBasisValues, float* vBasisValues ) 485 { 486 487 TQ3Uns32 iU, jV ; 488 float xTop, yTop, zTop ; 489 float OneOverBottom, bottom ; 490 491 // Let's... 492 xTop = yTop = zTop = bottom = 0.0f ; 493 // Go 494 for ( iU = 0; iU < patchData->numColumns; iU++ ) { 495 uBasisValues[iU] = e3geom_nurbpatch_evaluate_basis( u, iU, patchData->uOrder, patchData->uKnots) ; 496 } 497 498 // Again 499 for ( jV = 0; jV < patchData->numRows; jV++ ) { 500 vBasisValues[jV] = e3geom_nurbpatch_evaluate_basis( v, jV, patchData->vOrder, patchData->vKnots) ; 501 } 502 503 // Now some summation rotation recreation, like p. 46-47 in Bartels, Beatty, & Barsky 504 for ( jV = 0; jV < patchData->numRows; jV++ ) { 505 for ( iU = 0; iU < patchData->numColumns; iU++ ) { 506 // First the point 507 xTop += patchData->controlPoints[patchData->numColumns*jV + iU].x * uBasisValues[iU] * vBasisValues[jV] ; 508 yTop += patchData->controlPoints[patchData->numColumns*jV + iU].y * uBasisValues[iU] * vBasisValues[jV] ; 509 zTop += patchData->controlPoints[patchData->numColumns*jV + iU].z * uBasisValues[iU] * vBasisValues[jV] ; 510 bottom += patchData->controlPoints[patchData->numColumns*jV + iU].w * uBasisValues[iU] * vBasisValues[jV] ; 511 } } 512 513 514 // The point 515 OneOverBottom = 1.0f / bottom ; 516 outPoint->x = xTop * OneOverBottom ; 517 outPoint->y = yTop * OneOverBottom ; 518 outPoint->z = zTop * OneOverBottom ; 519 } 520 521 522 523 524 525 //============================================================================= 526 // e3geom_nurbpatch_interesting_knots : Find the interesting knots. 527 //----------------------------------------------------------------------------- 528 // Note : Interesting == non-repetitive. 529 //----------------------------------------------------------------------------- 530 static TQ3Uns32 531 e3geom_nurbpatch_interesting_knots( float * inKnots, TQ3Uns32 numPoints, TQ3Uns32 order, float * interestingK ) 532 { 533 TQ3Uns32 count, n ; 534 interestingK[0] = inKnots[order - 1] ; 535 536 count = 1 ; 537 for( n = order ; n <= numPoints ; n++ ) { 538 539 // if current knot differs from the previous, add this knot 540 if( inKnots[n] != inKnots[n-1] ) { 541 interestingK[ count ] = inKnots[n] ; 542 count++ ; 543 } 544 545 } // ~for( n in knot vector ) 546 547 #if Q3_DEBUG 548 Q3_ASSERT( count <= numPoints - order + 2 ) ; 549 #endif 550 return (TQ3Uns32) count ; 551 } 552 553 554 555 556 557 //============================================================================= 558 // e3geom_nurbpatch_recursive_quad_world_subdivide : Recursively subdivide 559 // a patch into 4 560 // parametrically square 561 // sections. 562 //----------------------------------------------------------------------------- 563 // Note : Returns the maximum depth of recursion. 564 //----------------------------------------------------------------------------- 565 static TQ3Uns32 566 e3geom_nurbpatch_recursive_quad_world_subdivide( TQ3Uns32 depth, float subdiv, float fu, float lu, float fv, float lv, 567 const TQ3Point3D* Pfufv, const TQ3Point3D* Plufv, const TQ3Point3D* Pfulv, const TQ3Point3D* Plulv, 568 const TQ3NURBPatchData *geomData, const TQ3Matrix4x4* localToWorld, 569 float* uBasisValues, float* vBasisValues ) 570 { 571 float hu, hv ; 572 TQ3Point3D Phufv, Pfuhv, Phuhv, Pluhv, Phulv ; 573 574 TQ3Uns32 recurseDepth, maxRecurseDepth ; 575 576 depth++ ; 577 maxRecurseDepth = 0 ; 578 579 #define a Q3Point3D_DistanceSquared( Pfufv, Plufv ) 580 #define b Q3Point3D_DistanceSquared( Plufv, Plulv ) 581 #define c Q3Point3D_DistanceSquared( Pfulv, Plulv ) 582 #define d Q3Point3D_DistanceSquared( Pfufv, Pfulv ) 583 584 if( a > subdiv || b > subdiv || c > subdiv || d > subdiv ) { 585 586 hu = (fu + lu)*0.5f ; 587 hv = (fv + lv)*0.5f ; 588 589 e3geom_nurbpatch_evaluate_uv_no_deriv( hu, 590 fv, 591 geomData, 592 &Phufv, 593 uBasisValues, vBasisValues ); 594 Q3Point3D_Transform( &Phufv, localToWorld, &Phufv ) ; 595 596 e3geom_nurbpatch_evaluate_uv_no_deriv( fu, 597 hv, 598 geomData, 599 &Pfuhv, 600 uBasisValues, vBasisValues ); 601 Q3Point3D_Transform( &Pfuhv, localToWorld, &Pfuhv ) ; 602 603 e3geom_nurbpatch_evaluate_uv_no_deriv( hu, 604 hv, 605 geomData, 606 &Phuhv, 607 uBasisValues, vBasisValues ); 608 Q3Point3D_Transform( &Phuhv, localToWorld, &Phuhv ) ; 609 610 e3geom_nurbpatch_evaluate_uv_no_deriv( lu, 611 hv, 612 geomData, 613 &Pluhv, 614 uBasisValues, vBasisValues ); 615 Q3Point3D_Transform( &Pluhv, localToWorld, &Pluhv ) ; 616 617 e3geom_nurbpatch_evaluate_uv_no_deriv( hu, 618 lv, 619 geomData, 620 &Phulv, 621 uBasisValues, vBasisValues ); 622 Q3Point3D_Transform( &Phulv, localToWorld, &Phulv ) ; 623 624 // Top-left square 625 recurseDepth = e3geom_nurbpatch_recursive_quad_world_subdivide( depth, 626 subdiv, fu, hu, fv, hv, 627 Pfufv, &Phufv, &Pfuhv, &Phuhv, 628 geomData, localToWorld, 629 uBasisValues, vBasisValues ) ; 630 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 631 632 // Top-right square 633 recurseDepth = e3geom_nurbpatch_recursive_quad_world_subdivide( depth, 634 subdiv, hu, lu, fv, hv, 635 &Phufv, Plufv, &Phuhv, &Pluhv, 636 geomData, localToWorld, 637 uBasisValues, vBasisValues ) ; 638 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 639 640 // Bottom-left square 641 recurseDepth = e3geom_nurbpatch_recursive_quad_world_subdivide( depth, 642 subdiv, fu, hu, hv, lv, 643 &Pfuhv, &Phuhv, Pfulv, &Phulv, 644 geomData, localToWorld, 645 uBasisValues, vBasisValues ) ; 646 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 647 648 // Bottom-right square 649 recurseDepth = e3geom_nurbpatch_recursive_quad_world_subdivide( depth, 650 subdiv, hu, lu, hv, lv, 651 &Phuhv, &Pluhv, &Phulv, Plulv, 652 geomData, localToWorld, 653 uBasisValues, vBasisValues ) ; 654 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 655 } 656 657 depth = depth > maxRecurseDepth ? depth : maxRecurseDepth ; 658 659 return depth ; 660 661 #undef a 662 #undef b 663 #undef c 664 #undef d 665 } 666 667 668 669 670 671 //============================================================================= 672 // e3geom_nurbpatch_recursive_quad_screen_subdivide : Recursively subdivide 673 // a patch into 4 674 // parametrically square 675 // sections. 676 //----------------------------------------------------------------------------- 677 // Note : If *points == NULL, an error has occurred (memory). 678 //----------------------------------------------------------------------------- 679 static TQ3Uns32 680 e3geom_nurbpatch_recursive_quad_screen_subdivide( TQ3Uns32 depth, float subdiv, float fu, float lu, float fv, float lv, 681 const TQ3Point2D* Pfufv2, const TQ3Point2D* Plufv2, const TQ3Point2D* Pfulv2, const TQ3Point2D* Plulv2, 682 const TQ3NURBPatchData *geomData, const TQ3Matrix4x4* localToWindow, 683 float* uBasisValues, float* vBasisValues ) 684 { 685 float hu, hv ; 686 TQ3Point3D Phufv, Pfuhv, Phuhv, Pluhv, Phulv, transformPoint ; 687 TQ3Point2D Phufv2, Pfuhv2, Phuhv2, Pluhv2, Phulv2 ; 688 689 TQ3Uns32 recurseDepth, maxRecurseDepth ; 690 691 depth++ ; 692 maxRecurseDepth = 0 ; 693 694 #define a Q3Point2D_DistanceSquared( Pfufv2, Plufv2 ) 695 #define b Q3Point2D_DistanceSquared( Plufv2, Plulv2 ) 696 #define c Q3Point2D_DistanceSquared( Pfulv2, Plulv2 ) 697 #define d Q3Point2D_DistanceSquared( Pfufv2, Pfulv2 ) 698 699 if( a > subdiv || b > subdiv || c > subdiv || d > subdiv ) { 700 701 hu = (fu + lu)*0.5f ; 702 hv = (fv + lv)*0.5f ; 703 704 e3geom_nurbpatch_evaluate_uv_no_deriv( hu, 705 fv, 706 geomData, 707 &Phufv, 708 uBasisValues, vBasisValues ); 709 Q3Point3D_Transform( &Phufv, localToWindow, &transformPoint ) ; 710 Phufv2.x = transformPoint.x ; 711 Phufv2.y = transformPoint.y ; 712 713 e3geom_nurbpatch_evaluate_uv_no_deriv( fu, 714 hv, 715 geomData, 716 &Pfuhv, 717 uBasisValues, vBasisValues ); 718 Q3Point3D_Transform( &Pfuhv, localToWindow, &transformPoint ) ; 719 Pfuhv2.x = transformPoint.x ; 720 Pfuhv2.y = transformPoint.y ; 721 722 e3geom_nurbpatch_evaluate_uv_no_deriv( hu, 723 hv, 724 geomData, 725 &Phuhv, 726 uBasisValues, vBasisValues ); 727 Q3Point3D_Transform( &Phuhv, localToWindow, &transformPoint ) ; 728 Phuhv2.x = transformPoint.x ; 729 Phuhv2.y = transformPoint.y ; 730 731 e3geom_nurbpatch_evaluate_uv_no_deriv( lu, 732 hv, 733 geomData, 734 &Pluhv, 735 uBasisValues, vBasisValues ); 736 Q3Point3D_Transform( &Pluhv, localToWindow, &transformPoint ) ; 737 Pluhv2.x = transformPoint.x ; 738 Pluhv2.y = transformPoint.y ; 739 740 e3geom_nurbpatch_evaluate_uv_no_deriv( hu, 741 lv, 742 geomData, 743 &Phulv, 744 uBasisValues, vBasisValues ); 745 Q3Point3D_Transform( &Phulv, localToWindow, &transformPoint ) ; 746 Phulv2.x = transformPoint.x ; 747 Phulv2.y = transformPoint.y ; 748 749 // Top-left square 750 recurseDepth = e3geom_nurbpatch_recursive_quad_screen_subdivide( depth, 751 subdiv, fu, hu, fv, hv, 752 Pfufv2, &Phufv2, &Pfuhv2, &Phuhv2, 753 geomData, localToWindow, 754 uBasisValues, vBasisValues ) ; 755 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 756 757 // Top-right square 758 recurseDepth = e3geom_nurbpatch_recursive_quad_screen_subdivide( depth, 759 subdiv, hu, lu, fv, hv, 760 &Phufv2, Plufv2, &Phuhv2, &Pluhv2, 761 geomData, localToWindow, 762 uBasisValues, vBasisValues ) ; 763 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 764 765 // Bottom-left square 766 recurseDepth = e3geom_nurbpatch_recursive_quad_screen_subdivide( depth, 767 subdiv, fu, hu, hv, lv, 768 &Pfuhv2, &Phuhv2, Pfulv2, &Phulv2, 769 geomData, localToWindow, 770 uBasisValues, vBasisValues ) ; 771 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 772 773 // Bottom-right square 774 recurseDepth = e3geom_nurbpatch_recursive_quad_screen_subdivide( depth, 775 subdiv, hu, lu, hv, lv, 776 &Phuhv2, &Pluhv2, &Phulv2, Plulv2, 777 geomData, localToWindow, 778 uBasisValues, vBasisValues ) ; 779 maxRecurseDepth = maxRecurseDepth > recurseDepth ? maxRecurseDepth : recurseDepth ; 780 } 781 782 depth = depth > maxRecurseDepth ? depth : maxRecurseDepth ; 783 784 return depth ; 785 786 #undef a 787 #undef b 788 #undef c 789 #undef d 790 } 791 792 793 794 795 796 //============================================================================= 797 // e3geom_nurbcurve_worldscreen_subdiv : Subdivide the given NURB curve 798 // into triangles whose edges have 799 // at most the given world or 800 // screen-space length. Vertices are 801 // guaranteed at knots. 802 //----------------------------------------------------------------------------- 803 // Note : Calls through to e3geom_nurbcurve_constant_subdiv. 804 // If the points array is non-NULL on return, be sure to free it 805 // with Q3Memory_Free(). If it is NULL, then an error has occurred. 806 //----------------------------------------------------------------------------- 807 // I need the function declaration for constant subdivision since I call through to it 808 static void 809 e3geom_nurbpatch_constant_subdiv( TQ3Point3D** thePoints, TQ3Uns32* numPoints, 810 TQ3Param2D** theUVs, TQ3Vector3D** theNormals, 811 TQ3TriMeshTriangleData** theTriangles, TQ3Uns32* numTriangles, 812 float subdivU, float subdivV, 813 const TQ3NURBPatchData *geomData, 814 float* uBasisValues, float* vBasisValues, float* uBasisDerivValues, float* vBasisDerivValues ) ; 815 816 static void 817 e3geom_nurbpatch_worldscreen_subdiv( TQ3Point3D** thePoints, TQ3Uns32* numPoints, 818 TQ3Param2D** theUVs, TQ3Vector3D** theNormals, 819 TQ3TriMeshTriangleData** theTriangles, TQ3Uns32* numTriangles, 820 float subdiv, 821 const TQ3NURBPatchData *geomData, TQ3ViewObject theView, TQ3Boolean isScreenSpaceSubdivision, 822 float* uBasisValues, float* vBasisValues, float* uBasisDerivValues, float* vBasisDerivValues ) 823 { float *interestingU, *interestingV ; 824 TQ3Uns32 nu, nv, 825 maxdepth, somedepth, 826 numIntU, numIntV ; 827 TQ3Point3D u0v0, u1v0, u0v1, u1v1 ; 828 TQ3Point2D u0v02, u1v02, u0v12, u1v12 ; 829 // To cache the local -> world and local -> screen matrices 830 TQ3Matrix4x4 localToWorld, worldToFrustum, frustumToWindow, localToWindow ; 831 832 #if Q3_DEBUG 833 Q3_ASSERT( thePoints != NULL && numPoints != NULL && theUVs != NULL && theNormals != NULL 834 && theTriangles != NULL && numTriangles != NULL ) ; 835 #endif 836 837 // For the error handler 838 interestingU = interestingV = NULL ; 839 840 // First some sanity checking on subdivisionData 841 subdiv = E3Num_Max(subdiv, 0.001f) ; 842 843 // Find the interesting knots (ie skip the repeated knots) 844 interestingU = (float *) Q3Memory_Allocate((geomData->numColumns - geomData->uOrder + 2) * sizeof(float)); 845 if (interestingU == NULL) { 846 goto nurbpatch_world_subdiv_error_handler ; 847 } 848 numIntU = e3geom_nurbpatch_interesting_knots( geomData->uKnots, geomData->numColumns, geomData->uOrder, interestingU ); 849 850 interestingV = (float *) Q3Memory_Allocate((geomData->numRows - geomData->vOrder + 2) * sizeof(float)); 851 if (interestingV == NULL) { 852 goto nurbpatch_world_subdiv_error_handler ; 853 } 854 numIntV = e3geom_nurbpatch_interesting_knots( geomData->vKnots, geomData->numRows, geomData->vOrder, interestingV ); 855 856 // we need the localToWorld matrix for both world and screen subdivisions 857 Q3View_GetLocalToWorldMatrixState(theView, &localToWorld); 858 // if we are doing a screen subdivision, 859 // truncate subdiv into an integer and cache the worldToWindow matrix 860 if( isScreenSpaceSubdivision ) { 861 // truncate subdiv 862 subdiv = (float) floor( subdiv ) ; 863 // cache the localToWindow matrix for theView 864 Q3View_GetWorldToFrustumMatrixState(theView, &worldToFrustum); 865 Q3View_GetFrustumToWindowMatrixState(theView, &frustumToWindow); 866 867 Q3Matrix4x4_Multiply(&localToWorld, &worldToFrustum, &localToWindow); 868 Q3Matrix4x4_Multiply(&localToWindow, &frustumToWindow, &localToWindow); 869 } 870 871 872 // square subdiv now to save a whole lot of sqrt's later (in the distance comparison) 873 subdiv *= subdiv ; 874 875 maxdepth = 0 ; 876 877 // Iterate over every 'square' of the grid resulting from (u-knots) x (v-knots) 878 for( nv = 0 ; nv < numIntV -1 ; nv++ ) { 879 for( nu = 0 ; nu < numIntU -1 ; nu++ ) { 880 881 e3geom_nurbpatch_evaluate_uv_no_deriv( interestingU[ nu ], 882 interestingV[ nv ], 883 geomData, 884 &u0v0, 885 uBasisValues, vBasisValues ); 886 e3geom_nurbpatch_evaluate_uv_no_deriv( interestingU[ nu +1 ], 887 interestingV[ nv ], 888 geomData, 889 &u1v0, 890 uBasisValues, vBasisValues ); 891 e3geom_nurbpatch_evaluate_uv_no_deriv( interestingU[ nu ], 892 interestingV[ nv +1 ], 893 geomData, 894 &u0v1, 895 uBasisValues, vBasisValues ); 896 e3geom_nurbpatch_evaluate_uv_no_deriv( interestingU[ nu +1 ], 897 interestingV[ nv +1 ], 898 geomData, 899 &u1v1, 900 uBasisValues, vBasisValues ); 901 902 if( kQ3False == isScreenSpaceSubdivision ) { 903 Q3Point3D_Transform(&u0v0, &localToWorld, &u0v0) ; 904 Q3Point3D_Transform(&u1v0, &localToWorld, &u1v0) ; 905 Q3Point3D_Transform(&u0v1, &localToWorld, &u0v1) ; 906 Q3Point3D_Transform(&u1v1, &localToWorld, &u1v1) ; 907 somedepth = e3geom_nurbpatch_recursive_quad_world_subdivide( 0, subdiv, 908 interestingU[ nu ], interestingU[ nu +1 ], 909 interestingV[ nv ], interestingV[ nv +1 ], 910 &u0v0, &u1v0, &u0v1, &u1v1, 911 geomData, &localToWorld, 912 uBasisValues, vBasisValues ) ; 913 } else { 914 Q3Point3D_Transform(&u0v0, &localToWorld, &u0v0) ; 915 u0v02.x = u0v0.x ; 916 u0v02.y = u0v0.y ; 917 Q3Point3D_Transform(&u1v0, &localToWorld, &u1v0) ; 918 u1v02.x = u1v0.x ; 919 u1v02.y = u1v0.y ; 920 Q3Point3D_Transform(&u0v1, &localToWorld, &u0v1) ; 921 u0v12.x = u0v1.x ; 922 u0v12.y = u0v1.y ; 923 Q3Point3D_Transform(&u1v1, &localToWorld, &u1v1) ; 924 u1v12.x = u1v1.x ; 925 u1v12.y = u1v1.y ; 926 somedepth = e3geom_nurbpatch_recursive_quad_screen_subdivide( 0, subdiv, 927 interestingU[ nu ], interestingU[ nu +1 ], 928 interestingV[ nv ], interestingV[ nv +1 ], 929 &u0v02, &u1v02, &u0v12, &u1v12, 930 geomData, &localToWindow, 931 uBasisValues, vBasisValues ) ; 932 } 933 934 maxdepth = maxdepth > somedepth ? maxdepth : somedepth ; 935 936 } // ~for( nu ) 937 } // ~for( nv ) 938 Q3Memory_Free( &interestingU ) ; 939 Q3Memory_Free( &interestingV ) ; 940 941 subdiv = (float)pow( 2.0, (int)maxdepth -1 ) ; 942 943 944 // I am not sure what causes subdiv to become infinite or what the value should really be, 945 // but I am sure that we do not want infinity here. 946 if (!isfinite( subdiv )) 947 subdiv = kFiniteSubdivision; 948 949 950 e3geom_nurbpatch_constant_subdiv( thePoints, numPoints, theUVs, theNormals, 951 theTriangles, numTriangles, 952 subdiv, subdiv, 953 geomData, 954 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ) ; 955 956 return ; 957 958 nurbpatch_world_subdiv_error_handler: 959 Q3Memory_Free( &interestingU ) ; 960 Q3Memory_Free( &interestingV ) ; 961 962 *thePoints = NULL ; 963 return ; 964 } 965 966 967 968 969 970 //============================================================================= 971 // e3geom_nurbpatch_constant_subdiv : Subdivide the given NURB curve into 972 // the some number of segments. 973 //----------------------------------------------------------------------------- 974 // Note : If the points array is non-NULL on return, be sure to free it 975 // with Q3Memory_Free(). If it is NULL, then an error has occured. 976 //----------------------------------------------------------------------------- 977 static void 978 e3geom_nurbpatch_constant_subdiv( TQ3Point3D** thePoints, TQ3Uns32* numPoints, 979 TQ3Param2D** theUVs, TQ3Vector3D** theNormals, 980 TQ3TriMeshTriangleData** theTriangles, TQ3Uns32* numTriangles, 981 float subdivU, float subdivV, 982 const TQ3NURBPatchData *geomData, 983 float* uBasisValues, float* vBasisValues, float* uBasisDerivValues, float* vBasisDerivValues ) 984 { float incrementU, incrementV, curIncrU, curIncrV, curU, curV ; 985 float *interestingU, *interestingV; 986 TQ3Uns32 curKnotU, curKnotV, u, v, ptInd, trInd, 987 numIntU, numIntV, numrows, numcolumns, numpts, numtris ; 988 989 #if Q3_DEBUG 990 Q3_ASSERT( thePoints != NULL && numPoints != NULL && theUVs != NULL && theNormals != NULL 991 && theTriangles != NULL && numTriangles != NULL ) ; 992 #endif 993 994 // First some sanity checking on subdivisionData 995 subdivU = (float) ((TQ3Uns32) E3Num_Clamp(subdivU, 1.0f, 256.0f)); 996 subdivV = (float) ((TQ3Uns32) E3Num_Clamp(subdivV, 1.0f, 256.0f)); 997 998 // Find the interesting knots (ie skip the repeated knots) 999 interestingU = (float *) Q3Memory_Allocate((geomData->numColumns - geomData->uOrder + 2) * sizeof(float)); 1000 if (interestingU == NULL) { 1001 *thePoints = NULL ; 1002 return ; 1003 } 1004 numIntU = e3geom_nurbpatch_interesting_knots( geomData->uKnots, geomData->numColumns, geomData->uOrder, interestingU ); 1005 numcolumns = (numIntU-1)*((TQ3Uns32)subdivU) + 1; 1006 1007 interestingV = (float *) Q3Memory_Allocate((geomData->numRows - geomData->vOrder + 2) * sizeof(float)); 1008 if (interestingV == NULL) { 1009 Q3Memory_Free( &interestingU ) ; 1010 1011 *thePoints = NULL ; 1012 return ; 1013 } 1014 numIntV = e3geom_nurbpatch_interesting_knots( geomData->vKnots, geomData->numRows, geomData->vOrder, interestingV ); 1015 numrows = (numIntV-1)*((TQ3Uns32)subdivV) + 1; 1016 1017 // Number of points, number of triangles 1018 numpts = numrows * numcolumns; 1019 numtris = (numrows - 1)*(numcolumns - 1)*2; 1020 1021 // Allocate some memory for the TriMesh 1022 *thePoints = (TQ3Point3D *) Q3Memory_Allocate(numpts * sizeof(TQ3Point3D)); 1023 *theNormals = (TQ3Vector3D *) Q3Memory_Allocate(numpts * sizeof(TQ3Vector3D)); 1024 *theUVs = (TQ3Param2D *) Q3Memory_Allocate(numpts * sizeof(TQ3Param2D)); 1025 *theTriangles = (TQ3TriMeshTriangleData *) Q3Memory_Allocate(numtris * sizeof(TQ3TriMeshTriangleData)); 1026 1027 if (*thePoints == NULL || *theNormals == NULL || *theUVs == NULL || *theTriangles == NULL) { 1028 Q3Memory_Free( &interestingU ) ; 1029 Q3Memory_Free( &interestingV ) ; 1030 1031 *thePoints = NULL ; 1032 return ; 1033 } 1034 // Outer V loop 1035 for (curKnotV = 0; curKnotV < numIntV - 1; curKnotV++ ) { 1036 incrementV = (interestingV[curKnotV+1] - interestingV[curKnotV]) / subdivV; 1037 1038 for (curIncrV = 0.0f; curIncrV < subdivV; curIncrV+=1.0f ) { 1039 curV = interestingV[curKnotV] + curIncrV*incrementV; 1040 1041 // Inner U loop 1042 for (curKnotU = 0; curKnotU < numIntU - 1; curKnotU++ ) { 1043 incrementU = (interestingU[curKnotU+1] - interestingU[curKnotU]) / subdivU; 1044 1045 for (curIncrU = 0.0f; curIncrU < subdivU; curIncrU+=1.0f ) { 1046 curU = interestingU[curKnotU] + curIncrU*incrementU; 1047 1048 ptInd = ( curKnotV*(TQ3Uns32)subdivV+(TQ3Uns32)curIncrV )*numcolumns + 1049 curKnotU*(TQ3Uns32)subdivU+(TQ3Uns32)curIncrU ; 1050 // Let's try this for our uv's 1051 (*theUVs)[ptInd].u = curU ; 1052 (*theUVs)[ptInd].v = curV ; 1053 1054 e3geom_nurbpatch_evaluate_uv( 1055 curU, 1056 curV, 1057 geomData, 1058 &(*theNormals)[ptInd], 1059 &(*thePoints)[ptInd], 1060 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ); 1061 } 1062 } 1063 // Cap evaluation for u 1064 ptInd = ( curKnotV*(TQ3Uns32)subdivV+(TQ3Uns32)curIncrV )*numcolumns + 1065 numcolumns - 1; 1066 // Let's try this for our uv's 1067 (*theUVs)[ptInd].u = interestingU[numIntU - 1] ; 1068 (*theUVs)[ptInd].v = curV ; 1069 e3geom_nurbpatch_evaluate_uv( 1070 interestingU[numIntU - 1], 1071 curV, 1072 geomData, 1073 &(*theNormals)[ptInd], 1074 &(*thePoints)[ptInd], 1075 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ); 1076 1077 } 1078 } 1079 // Final evaluation loop (on the v-cap) 1080 for (curKnotU = 0; curKnotU < numIntU - 1; curKnotU++ ) { 1081 incrementU = (interestingU[curKnotU+1] - interestingU[curKnotU]) / subdivU; 1082 1083 for (curIncrU = 0.0f; curIncrU < subdivU; curIncrU+=1.0f ) { 1084 curU = interestingU[curKnotU] + curIncrU*incrementU; 1085 1086 ptInd = (numrows - 1)*numcolumns + 1087 curKnotU*(TQ3Uns32)subdivU+(TQ3Uns32)curIncrU ; 1088 // Let's try this for our uv's 1089 (*theUVs)[ptInd].u = curU ; 1090 (*theUVs)[ptInd].v = interestingV[numIntV - 1] ; 1091 1092 e3geom_nurbpatch_evaluate_uv( 1093 curU, 1094 interestingV[numIntV - 1], 1095 geomData, 1096 &(*theNormals)[ptInd], 1097 &(*thePoints)[ptInd], 1098 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ); 1099 } 1100 } 1101 // The grande finale cap evaluation 1102 ptInd = numpts - 1; 1103 // Let's try this for our uv's 1104 (*theUVs)[ptInd].u = interestingU[numIntU - 1] ; 1105 (*theUVs)[ptInd].v = interestingV[numIntV - 1] ; 1106 1107 e3geom_nurbpatch_evaluate_uv( 1108 interestingU[numIntU - 1], 1109 interestingV[numIntV - 1], 1110 geomData, 1111 &(*theNormals)[ptInd], 1112 &(*thePoints)[numpts - 1], 1113 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ); 1114 1115 // Make triangles from the points 1116 for ( v = 0; v < numrows - 1; v++ ) 1117 for ( u = 0; u < (numcolumns - 1)*2; u+=2 ) { 1118 // The first triangle 1119 trInd = v*(numcolumns-1)*2 + u; 1120 ptInd = v*numcolumns + u/2; 1121 (*theTriangles)[trInd].pointIndices[0] = ptInd; 1122 ptInd = v*numcolumns + u/2 +1; 1123 (*theTriangles)[trInd].pointIndices[1] = ptInd; 1124 ptInd = (v+1)*numcolumns + u/2; 1125 (*theTriangles)[trInd].pointIndices[2] = ptInd; 1126 // The second triangle 1127 trInd = v*(numcolumns-1)*2 + u+1; 1128 ptInd = v*numcolumns + u/2 +1; 1129 (*theTriangles)[trInd].pointIndices[0] = ptInd; 1130 ptInd = (v+1)*numcolumns + u/2 +1; 1131 (*theTriangles)[trInd].pointIndices[1] = ptInd; 1132 ptInd = (v+1)*numcolumns + u/2; 1133 (*theTriangles)[trInd].pointIndices[2] = ptInd; 1134 } 1135 1136 // Uncomment this and get a big flat square approximating the surface. 1137 // Not very interesting if what is supposed to work does ;) 1138 // (*theTriangles)[0].pointIndices[0] = 0; 1139 // (*theTriangles)[0].pointIndices[1] = numpts-1;//numcolumns - 1; 1140 // (*theTriangles)[0].pointIndices[2] = (numrows-1)*(numcolumns); 1141 // (*theTriangles)[1].pointIndices[0] = numrows - 1; 1142 // (*theTriangles)[1].pointIndices[1] = numpts - 1; 1143 // (*theTriangles)[1].pointIndices[2] = (numrows-1)*(numcolumns); 1144 1145 *numPoints = numpts ; 1146 *numTriangles = numtris ; 1147 } 1148 1149 1150 1151 1152 1153 //============================================================================= 1154 // e3geom_nurbpatch_cache_new : NURBPatch cache new method. 1155 //----------------------------------------------------------------------------- 1156 static TQ3Object 1157 e3geom_nurbpatch_cache_new(TQ3ViewObject theView, TQ3GeometryObject theGeom, const TQ3NURBPatchData *geomData) 1158 { TQ3TriMeshData triMeshData; 1159 TQ3GeometryObject theTriMesh; 1160 TQ3GroupObject theGroup; 1161 TQ3Point3D *points; 1162 TQ3Vector3D *normals; 1163 TQ3Param2D *uvs; 1164 TQ3TriMeshTriangleData *triangles; 1165 TQ3SubdivisionStyleData subdivisionData; 1166 TQ3TriMeshAttributeData vertexAttributes[2]; 1167 float subdivU = 10.0f, subdivV = 10.0f; 1168 TQ3Uns32 numpoints, numtriangles; 1169 float *uBasisValues, *vBasisValues, *uBasisDerivValues, *vBasisDerivValues ; 1170 1171 theGroup = NULL; 1172 points = NULL ; 1173 normals = NULL ; 1174 uvs = NULL ; 1175 triangles = NULL ; 1176 uBasisValues = vBasisValues = uBasisDerivValues = vBasisDerivValues = NULL ; 1177 1178 // Set NULL initially so that return value is NULL if we goto the error label 1179 Q3Memory_Clear(&triMeshData, sizeof(triMeshData)); 1180 theTriMesh = NULL; 1181 1182 uBasisValues = (float*) Q3Memory_Allocate( geomData->numColumns * sizeof(float) ) ; 1183 if( uBasisValues == NULL ) 1184 goto surface_cache_new_error_cleanup ; 1185 vBasisValues = (float*) Q3Memory_Allocate( geomData->numRows * sizeof(float) ) ; 1186 if( vBasisValues == NULL ) 1187 goto surface_cache_new_error_cleanup ; 1188 1189 uBasisDerivValues = (float*) Q3Memory_Allocate( geomData->numColumns * sizeof(float) ) ; 1190 if( uBasisDerivValues == NULL ) 1191 goto surface_cache_new_error_cleanup ; 1192 vBasisDerivValues = (float*) Q3Memory_Allocate( geomData->numRows * sizeof(float) ) ; 1193 if( vBasisDerivValues == NULL ) 1194 goto surface_cache_new_error_cleanup ; 1195 1196 // Get the subdivision style, figure out how to tessellate. 1197 if (Q3View_GetSubdivisionStyleState( theView, &subdivisionData ) == kQ3Success) { 1198 subdivU = subdivisionData.c1; 1199 subdivV = subdivisionData.c2; 1200 1201 switch (subdivisionData.method) { 1202 case kQ3SubdivisionMethodScreenSpace: 1203 e3geom_nurbpatch_worldscreen_subdiv( &points, &numpoints, &uvs, &normals, 1204 &triangles, &numtriangles, 1205 subdivU, 1206 geomData, theView, kQ3True, 1207 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ) ; 1208 1209 if( points == NULL ) 1210 goto surface_cache_new_error_cleanup ; 1211 1212 break; 1213 1214 case kQ3SubdivisionMethodWorldSpace: 1215 e3geom_nurbpatch_worldscreen_subdiv( &points, &numpoints, &uvs, &normals, 1216 &triangles, &numtriangles, 1217 subdivU, 1218 geomData, theView, kQ3False, 1219 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ) ; 1220 1221 if( points == NULL ) 1222 goto surface_cache_new_error_cleanup ; 1223 1224 break; 1225 1226 case kQ3SubdivisionMethodConstant: 1227 e3geom_nurbpatch_constant_subdiv( &points, &numpoints, &uvs, &normals, 1228 &triangles, &numtriangles, 1229 subdivU, subdivV, 1230 geomData, 1231 uBasisValues, vBasisValues, uBasisDerivValues, vBasisDerivValues ) ; 1232 1233 if( points == NULL ) 1234 goto surface_cache_new_error_cleanup ; 1235 1236 break; 1237 1238 case kQ3SubdivisionMethodSize32: 1239 default: 1240 Q3_ASSERT(!"Unknown subdivision method"); 1241 break; 1242 } 1243 } 1244 1245 1246 1247 // set up the attributes 1248 E3AttributeSet_Combine(geomData->patchAttributeSet, NULL, &triMeshData.triMeshAttributeSet); 1249 1250 1251 1252 // set up remaining trimesh data 1253 vertexAttributes[0].attributeType = kQ3AttributeTypeNormal; 1254 vertexAttributes[0].data = normals; 1255 vertexAttributes[0].attributeUseArray = NULL; 1256 1257 vertexAttributes[1].attributeType = kQ3AttributeTypeSurfaceUV; 1258 vertexAttributes[1].data = uvs; 1259 vertexAttributes[1].attributeUseArray = NULL; 1260 1261 triMeshData.numPoints = numpoints; 1262 triMeshData.points = points; 1263 triMeshData.numTriangles = numtriangles; 1264 triMeshData.triangles = triangles; 1265 triMeshData.numTriangleAttributeTypes = 0; 1266 triMeshData.triangleAttributeTypes = NULL; 1267 triMeshData.numEdges = 0; 1268 triMeshData.edges = NULL; 1269 triMeshData.numEdgeAttributeTypes = 0; 1270 triMeshData.edgeAttributeTypes = NULL; 1271 triMeshData.numVertexAttributeTypes = 2; 1272 triMeshData.vertexAttributeTypes = vertexAttributes; 1273 1274 Q3BoundingBox_SetFromPoints3D(&triMeshData.bBox, 1275 triMeshData.points, 1276 numpoints, 1277 sizeof(TQ3Point3D)); 1278 1279 1280 1281 // finally, create the TriMesh 1282 theTriMesh = Q3TriMesh_New(&triMeshData); 1283 theGroup = E3TriMesh_BuildOrientationGroup(theTriMesh, kQ3OrientationStyleCounterClockwise); 1284 1285 1286 1287 // Clean up 1288 surface_cache_new_error_cleanup: 1289 1290 Q3Object_CleanDispose(&triMeshData.triMeshAttributeSet); 1291 Q3Memory_Free(&points); 1292 Q3Memory_Free(&normals); 1293 Q3Memory_Free(&uvs); 1294 Q3Memory_Free(&triangles); 1295 1296 Q3Memory_Free(&uBasisValues); 1297 Q3Memory_Free(&vBasisValues); 1298 Q3Memory_Free(&uBasisDerivValues); 1299 Q3Memory_Free(&vBasisDerivValues); 1300 1301 return(theGroup); 1302 } 1303 1304 1305 1306 1307 1308 //============================================================================= 1309 // e3geom_nurbpatch_bounds : NURBPatch bounds method. 1310 //----------------------------------------------------------------------------- 1311 // Note : Untested. A more efficient algorithm would only pass 'suspect' 1312 // control points that have a chance of being used. But this might 1313 // just mean stepping on some boundingbox function toes and make 1314 // things slower. 1315 //----------------------------------------------------------------------------- 1316 static TQ3Status 1317 e3geom_nurbpatch_bounds(TQ3ViewObject theView, TQ3ObjectType objectType, TQ3Object theObject, const void *objectData) 1318 { const TQ3NURBPatchData *instanceData = (const TQ3NURBPatchData *) objectData; 1319 #pragma unused(objectType) 1320 #pragma unused(theObject) 1321 1322 1323 1324 // Update the bounds 1325 E3View_UpdateBounds(theView, instanceData->numRows * instanceData->numColumns, sizeof(TQ3RationalPoint4D), (TQ3Point3D *)instanceData->controlPoints); 1326 1327 return(kQ3Success); 1328 } 1329 1330 1331 1332 1333 1334 //============================================================================= 1335 // e3geom_nurbpatch_get_attribute : NURBPatch get attribute set pointer. 1336 //----------------------------------------------------------------------------- 1337 static TQ3AttributeSet * 1338 e3geom_nurbpatch_get_attribute ( E3NURBPatch* nurbPatch ) 1339 { 1340 // Return the address of the geometry attribute set 1341 return & nurbPatch->instanceData.patchAttributeSet ; 1342 } 1343 1344 1345 1346 1347 1348 //============================================================================= 1349 // e3geom_nurbpatch_metahandler : NURBPatch metahandler. 1350 //----------------------------------------------------------------------------- 1351 static TQ3XFunctionPointer 1352 e3geom_nurbpatch_metahandler(TQ3XMethodType methodType) 1353 { TQ3XFunctionPointer theMethod = NULL; 1354 1355 1356 1357 // Return our methods 1358 switch (methodType) { 1359 case kQ3XMethodTypeObjectNew: 1360 theMethod = (TQ3XFunctionPointer) e3geom_nurbpatch_new; 1361 break; 1362 1363 case kQ3XMethodTypeObjectDelete: 1364 theMethod = (TQ3XFunctionPointer) e3geom_nurbpatch_delete; 1365 break; 1366 1367 case kQ3XMethodTypeObjectDuplicate: 1368 theMethod = (TQ3XFunctionPointer) e3geom_nurbpatch_duplicate; 1369 break; 1370 1371 case kQ3XMethodTypeGeomCacheNew: 1372 theMethod = (TQ3XFunctionPointer) e3geom_nurbpatch_cache_new; 1373 break; 1374 1375 case kQ3XMethodTypeObjectSubmitBounds: 1376 theMethod = (TQ3XFunctionPointer) e3geom_nurbpatch_bounds; 1377 break; 1378 1379 case kQ3XMethodTypeGeomGetAttribute: 1380 theMethod = (TQ3XFunctionPointer) e3geom_nurbpatch_get_attribute; 1381 break; 1382 1383 case kQ3XMethodTypeGeomUsesSubdivision: 1384 theMethod = (TQ3XFunctionPointer) kQ3True; 1385 break; 1386 } 1387 1388 return(theMethod); 1389 } 1390 1391 1392 1393 1394 1395 //============================================================================= 1396 // Public functions 1397 //----------------------------------------------------------------------------- 1398 // E3GeometryNURBPatch_RegisterClass : Register the class. 1399 //----------------------------------------------------------------------------- 1400 #pragma mark - 1401 TQ3Status 1402 E3GeometryNURBPatch_RegisterClass(void) 1403 { 1404 // Register the class 1405 return Q3_REGISTER_CLASS ( kQ3ClassNameGeometryNURBPatch, 1406 e3geom_nurbpatch_metahandler, 1407 E3NURBPatch ) ; 1408 } 1409 1410 1411 1412 1413 1414 //============================================================================= 1415 // E3GeometryNURBPatch_UnregisterClass : Unregister the class. 1416 //----------------------------------------------------------------------------- 1417 TQ3Status 1418 E3GeometryNURBPatch_UnregisterClass(void) 1419 { TQ3Status qd3dStatus; 1420 1421 1422 1423 // Unregister the class 1424 qd3dStatus = E3ClassTree::UnregisterClass(kQ3GeometryTypeNURBPatch, kQ3True); 1425 1426 return(qd3dStatus); 1427 } 1428 1429 1430 1431 1432 1433 //============================================================================= 1434 // E3NURBPatch_New : Create a NURB patch object. 1435 //----------------------------------------------------------------------------- 1436 #pragma mark - 1437 TQ3GeometryObject 1438 E3NURBPatch_New(const TQ3NURBPatchData *nurbPatchData) 1439 { TQ3Object theObject; 1440 1441 1442 1443 // Create the object 1444 theObject = E3ClassTree::CreateInstance ( kQ3GeometryTypeNURBPatch, kQ3False, nurbPatchData); 1445 return(theObject); 1446 } 1447 1448 1449 1450 1451 1452 //============================================================================= 1453 // E3NURBPatch_Submit : Submit a NURB patch. 1454 //----------------------------------------------------------------------------- 1455 TQ3Status 1456 E3NURBPatch_Submit(const TQ3NURBPatchData *nurbPatchData, TQ3ViewObject theView) 1457 { TQ3Status qd3dStatus; 1458 1459 1460 1461 // Submit the geometry 1462 qd3dStatus = E3View_SubmitImmediate(theView, kQ3GeometryTypeNURBPatch, nurbPatchData); 1463 return(qd3dStatus); 1464 } 1465 1466 1467 1468 1469 1470 //============================================================================= 1471 // E3NURBPatch_SetData : Set a NURBPatch's internal data from public data. 1472 //----------------------------------------------------------------------------- 1473 // Note : Quite untested. 1474 //----------------------------------------------------------------------------- 1475 TQ3Status 1476 E3NURBPatch_SetData(TQ3GeometryObject theNurbPatch, const TQ3NURBPatchData *nurbPatchData) 1477 { 1478 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1479 1480 // first, free the old data 1481 e3geom_patch_disposedata ( & nurbPatch->instanceData ) ; 1482 1483 // then copy in the new data 1484 TQ3Status qd3dStatus = e3geom_patch_copydata ( nurbPatchData, & nurbPatch->instanceData, kQ3False ) ; 1485 Q3Shared_Edited ( nurbPatch ) ; 1486 1487 return qd3dStatus ; 1488 } 1489 1490 1491 1492 1493 1494 //============================================================================= 1495 // E3NURBPatch_GetData : Get a NURBPatch's data. 1496 //----------------------------------------------------------------------------- 1497 // Note : Quite untested. 1498 //----------------------------------------------------------------------------- 1499 TQ3Status 1500 E3NURBPatch_GetData(TQ3GeometryObject theNurbPatch, TQ3NURBPatchData *nurbPatchData) 1501 { 1502 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1503 1504 // Copy the data out of the NURBPatch 1505 nurbPatchData->patchAttributeSet = NULL; 1506 1507 return e3geom_patch_copydata ( & nurbPatch->instanceData, nurbPatchData, kQ3False ) ; 1508 } 1509 1510 1511 1512 1513 1514 //============================================================================= 1515 // E3NURBPatch_EmptyData : Dispose of a NURBPatch's data. 1516 //----------------------------------------------------------------------------- 1517 // Note : Quite untested. 1518 //----------------------------------------------------------------------------- 1519 TQ3Status 1520 E3NURBPatch_EmptyData(TQ3NURBPatchData *nurbPatchData) 1521 { 1522 1523 // Dispose of the data 1524 e3geom_patch_disposedata(nurbPatchData); 1525 1526 return(kQ3Success); 1527 } 1528 1529 1530 1531 1532 1533 //============================================================================= 1534 // E3NURBPatch_SetControlPoint : Set a NURB patch control point. 1535 //----------------------------------------------------------------------------- 1536 // Note : Untested. 1537 //----------------------------------------------------------------------------- 1538 TQ3Status 1539 E3NURBPatch_SetControlPoint(TQ3GeometryObject theNurbPatch, TQ3Uns32 rowIndex, TQ3Uns32 columnIndex, const TQ3RationalPoint4D *point4D) 1540 { 1541 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1542 1543 // Copy the point from point4D to controlPoints 1544 Q3Memory_Copy ( point4D, & nurbPatch->instanceData.controlPoints [ nurbPatch->instanceData.numColumns * rowIndex + columnIndex ], sizeof(TQ3RationalPoint4D) ) ; 1545 1546 Q3Shared_Edited ( nurbPatch ) ; 1547 1548 return kQ3Success ; 1549 } 1550 1551 1552 1553 1554 1555 //============================================================================= 1556 // E3NURBPatch_GetControlPoint : Get a NURB patch control point. 1557 //----------------------------------------------------------------------------- 1558 // Note : Untested. 1559 //----------------------------------------------------------------------------- 1560 TQ3Status 1561 E3NURBPatch_GetControlPoint(TQ3GeometryObject theNurbPatch, TQ3Uns32 rowIndex, TQ3Uns32 columnIndex, TQ3RationalPoint4D *point4D) 1562 { 1563 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1564 1565 // Copy the point from controlPoints to point4D 1566 Q3Memory_Copy ( & nurbPatch->instanceData.controlPoints [ nurbPatch->instanceData.numColumns * rowIndex + columnIndex ], point4D, sizeof(TQ3RationalPoint4D) ) ; 1567 1568 return kQ3Success ; 1569 } 1570 1571 1572 1573 1574 1575 //============================================================================= 1576 // E3NURBPatch_SetUKnot : Set a NURB patch knot on the U axis. 1577 //----------------------------------------------------------------------------- 1578 // Note : Untested. 1579 //----------------------------------------------------------------------------- 1580 TQ3Status 1581 E3NURBPatch_SetUKnot(TQ3GeometryObject theNurbPatch, TQ3Uns32 knotIndex, float knotValue) 1582 { 1583 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1584 1585 // Copy the knot from knotValue to uKnots 1586 Q3Memory_Copy ( &knotValue, & nurbPatch->instanceData.uKnots [ knotIndex ], sizeof(float) ) ; 1587 1588 Q3Shared_Edited ( nurbPatch ) ; 1589 1590 return kQ3Success ; 1591 } 1592 1593 1594 1595 1596 1597 //============================================================================= 1598 // E3NURBPatch_SetVKnot : Set a NURB patch knot on the V axis. 1599 //----------------------------------------------------------------------------- 1600 // Note : Untested. 1601 //----------------------------------------------------------------------------- 1602 TQ3Status 1603 E3NURBPatch_SetVKnot(TQ3GeometryObject theNurbPatch, TQ3Uns32 knotIndex, float knotValue) 1604 { 1605 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1606 1607 // Copy the knot from knotValue to vKnots 1608 Q3Memory_Copy ( &knotValue, & nurbPatch->instanceData.vKnots [ knotIndex ], sizeof(float) ) ; 1609 1610 Q3Shared_Edited ( nurbPatch ) ; 1611 1612 return kQ3Success ; 1613 } 1614 1615 1616 1617 1618 1619 //============================================================================= 1620 // E3NURBPatch_GetUKnot : Get a NURB patch knot on the U axis. 1621 //----------------------------------------------------------------------------- 1622 // Note : Untested. 1623 //----------------------------------------------------------------------------- 1624 TQ3Status 1625 E3NURBPatch_GetUKnot(TQ3GeometryObject theNurbPatch, TQ3Uns32 knotIndex, float *knotValue) 1626 { 1627 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1628 1629 // Copy the knot from uKnots to knotValue 1630 Q3Memory_Copy ( & nurbPatch->instanceData.uKnots [ knotIndex ], knotValue, sizeof(float) ) ; 1631 1632 return kQ3Success ; 1633 } 1634 1635 1636 1637 1638 1639 //============================================================================= 1640 // E3NURBPatch_GetVKnot : Get a NURB patch knot on the V axis. 1641 //----------------------------------------------------------------------------- 1642 // Note : Untested. 1643 //----------------------------------------------------------------------------- 1644 TQ3Status 1645 E3NURBPatch_GetVKnot(TQ3GeometryObject theNurbPatch, TQ3Uns32 knotIndex, float *knotValue) 1646 { 1647 E3NURBPatch* nurbPatch = (E3NURBPatch*) theNurbPatch ; 1648 1649 // Copy the knot from uKnots to knotValue 1650 Q3Memory_Copy ( & nurbPatch->instanceData.vKnots [ knotIndex ], knotValue, sizeof(float) ) ; 1651 1652 return kQ3Success ; 1653 } 1654 1655 1656 1657 1658 1659 1660 1661