1 /****************************************************************************** 2 3 @File PVRTVertex.cpp 4 5 @Title PVRTVertex 6 7 @Version 8 9 @Copyright Copyright (c) Imagination Technologies Limited. 10 11 @Platform ANSI compatible 12 13 @Description Utility functions which process vertices. 14 15 ******************************************************************************/ 16 17 /**************************************************************************** 18 ** Includes 19 ****************************************************************************/ 20 #include "PVRTGlobal.h" 21 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "PVRTFixedPoint.h" 26 #include "PVRTMatrix.h" 27 #include "PVRTVertex.h" 28 29 /**************************************************************************** 30 ** Defines 31 ****************************************************************************/ 32 33 /**************************************************************************** 34 ** Macros 35 ****************************************************************************/ 36 #define MAX_VERTEX_OUT (3*nVtxNum) 37 38 /**************************************************************************** 39 ** Structures 40 ****************************************************************************/ 41 42 /**************************************************************************** 43 ** Constants 44 ****************************************************************************/ 45 46 /**************************************************************************** 47 ** Local function definitions 48 ****************************************************************************/ 49 50 /***************************************************************************** 51 ** Functions 52 *****************************************************************************/ 53 54 /*!*************************************************************************** 55 @Function PVRTVertexRead 56 @Output pV 57 @Input pData 58 @Input eType 59 @Input nCnt 60 @Description Read a vector 61 *****************************************************************************/ 62 void PVRTVertexRead( 63 PVRTVECTOR4f * const pV, 64 const void * const pData, 65 const EPVRTDataType eType, 66 const int nCnt) 67 { 68 int i; 69 float *pOut = (float*)pV; 70 71 pV->x = 0; 72 pV->y = 0; 73 pV->z = 0; 74 pV->w = 1; 75 76 switch(eType) 77 { 78 default: 79 _ASSERT(false); 80 break; 81 82 case EPODDataFloat: 83 for(i = 0; i < nCnt; ++i) 84 pOut[i] = ((float*)pData)[i]; 85 break; 86 87 case EPODDataFixed16_16: 88 for(i = 0; i < nCnt; ++i) 89 pOut[i] = ((int*)pData)[i] * 1.0f / (float)(1 << 16); 90 break; 91 92 case EPODDataInt: 93 for(i = 0; i < nCnt; ++i) 94 pOut[i] = (float)((int*)pData)[i]; 95 break; 96 97 case EPODDataUnsignedInt: 98 for(i = 0; i < nCnt; ++i) 99 pOut[i] = (float)((unsigned int*)pData)[i]; 100 break; 101 102 case EPODDataByte: 103 for(i = 0; i < nCnt; ++i) 104 pOut[i] = (float)((char*)pData)[i]; 105 break; 106 107 case EPODDataByteNorm: 108 for(i = 0; i < nCnt; ++i) 109 pOut[i] = (float)((char*)pData)[i] / (float)((1 << 7)-1); 110 break; 111 112 case EPODDataUnsignedByte: 113 for(i = 0; i < nCnt; ++i) 114 pOut[i] = (float)((unsigned char*)pData)[i]; 115 break; 116 117 case EPODDataUnsignedByteNorm: 118 for(i = 0; i < nCnt; ++i) 119 pOut[i] = (float)((unsigned char*)pData)[i] / (float)((1 << 8)-1); 120 break; 121 122 case EPODDataShort: 123 for(i = 0; i < nCnt; ++i) 124 pOut[i] = (float)((short*)pData)[i]; 125 break; 126 127 case EPODDataShortNorm: 128 for(i = 0; i < nCnt; ++i) 129 pOut[i] = (float)((short*)pData)[i] / (float)((1 << 15)-1); 130 break; 131 132 case EPODDataUnsignedShort: 133 for(i = 0; i < nCnt; ++i) 134 pOut[i] = (float)((unsigned short*)pData)[i]; 135 break; 136 137 case EPODDataUnsignedShortNorm: 138 for(i = 0; i < nCnt; ++i) 139 pOut[i] = (float)((unsigned short*)pData)[i] / (float)((1 << 16)-1); 140 break; 141 142 case EPODDataRGBA: 143 { 144 unsigned int dwVal = *(unsigned int*)pData; 145 unsigned char v[4]; 146 147 v[0] = (unsigned char) (dwVal >> 24); 148 v[1] = (unsigned char) (dwVal >> 16); 149 v[2] = (unsigned char) (dwVal >> 8); 150 v[3] = (unsigned char) (dwVal >> 0); 151 152 for(i = 0; i < 4; ++i) 153 pOut[i] = 1.0f / 255.0f * (float)v[i]; 154 } 155 break; 156 157 case EPODDataABGR: 158 { 159 unsigned int dwVal = *(unsigned int*)pData; 160 unsigned char v[4]; 161 162 v[0] = (unsigned char) (dwVal >> 0); 163 v[1] = (unsigned char) (dwVal >> 8); 164 v[2] = (unsigned char) (dwVal >> 16); 165 v[3] = (unsigned char) (dwVal >> 24); 166 167 for(i = 0; i < 4; ++i) 168 pOut[i] = 1.0f / 255.0f * (float)v[i]; 169 } 170 break; 171 172 case EPODDataARGB: 173 case EPODDataD3DCOLOR: 174 { 175 unsigned int dwVal = *(unsigned int*)pData; 176 unsigned char v[4]; 177 178 v[0] = (unsigned char) (dwVal >> 16); 179 v[1] = (unsigned char) (dwVal >> 8); 180 v[2] = (unsigned char) (dwVal >> 0); 181 v[3] = (unsigned char) (dwVal >> 24); 182 183 for(i = 0; i < 4; ++i) 184 pOut[i] = 1.0f / 255.0f * (float)v[i]; 185 } 186 break; 187 188 case EPODDataUBYTE4: 189 { 190 unsigned int dwVal = *(unsigned int*)pData; 191 unsigned char v[4]; 192 193 v[0] = (unsigned char) (dwVal >> 0); 194 v[1] = (unsigned char) (dwVal >> 8); 195 v[2] = (unsigned char) (dwVal >> 16); 196 v[3] = (unsigned char) (dwVal >> 24); 197 198 for(i = 0; i < 4; ++i) 199 pOut[i] = v[i]; 200 } 201 break; 202 203 case EPODDataDEC3N: 204 { 205 int dwVal = *(int*)pData; 206 int v[4]; 207 208 v[0] = (dwVal << 22) >> 22; 209 v[1] = (dwVal << 12) >> 22; 210 v[2] = (dwVal << 2) >> 22; 211 v[3] = 0; 212 213 for(i = 0; i < 3; ++i) 214 pOut[i] = (float)v[i] * (1.0f / 511.0f); 215 } 216 break; 217 } 218 } 219 220 /*!*************************************************************************** 221 @Function PVRTVertexRead 222 @Output pV 223 @Input pData 224 @Input eType 225 @Description Read an int 226 *****************************************************************************/ 227 void PVRTVertexRead( 228 unsigned int * const pV, 229 const void * const pData, 230 const EPVRTDataType eType) 231 { 232 switch(eType) 233 { 234 default: 235 _ASSERT(false); 236 break; 237 238 case EPODDataUnsignedShort: 239 *pV = *(unsigned short*)pData; 240 break; 241 242 case EPODDataUnsignedInt: 243 *pV = *(unsigned int*)pData; 244 break; 245 } 246 } 247 248 /*!*************************************************************************** 249 @Function PVRTVertexWrite 250 @Output pOut 251 @Input eType 252 @Input nCnt 253 @Input pV 254 @Description Write a vector 255 *****************************************************************************/ 256 void PVRTVertexWrite( 257 void * const pOut, 258 const EPVRTDataType eType, 259 const int nCnt, 260 const PVRTVECTOR4f * const pV) 261 { 262 int i; 263 float *pData = (float*)pV; 264 265 switch(eType) 266 { 267 default: 268 _ASSERT(false); 269 break; 270 271 case EPODDataDEC3N: 272 { 273 int v[3]; 274 275 for(i = 0; i < nCnt; ++i) 276 { 277 v[i] = (int)(pData[i] * 511.0f); 278 v[i] = PVRT_CLAMP(v[i], -511, 511); 279 v[i] &= 0x000003ff; 280 } 281 282 for(; i < 3; ++i) 283 { 284 v[i] = 0; 285 } 286 287 *(unsigned int*)pOut = (v[0] << 0) | (v[1] << 10) | (v[2] << 20); 288 } 289 break; 290 291 case EPODDataARGB: 292 case EPODDataD3DCOLOR: 293 { 294 unsigned char v[4]; 295 296 for(i = 0; i < nCnt; ++i) 297 v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f); 298 299 for(; i < 4; ++i) 300 v[i] = 0; 301 302 *(unsigned int*)pOut = (v[3] << 24) | (v[0] << 16) | (v[1] << 8) | v[2]; 303 } 304 break; 305 306 case EPODDataRGBA: 307 { 308 unsigned char v[4]; 309 310 for(i = 0; i < nCnt; ++i) 311 v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f); 312 313 for(; i < 4; ++i) 314 v[i] = 0; 315 316 *(unsigned int*)pOut = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3]; 317 } 318 break; 319 320 case EPODDataABGR: 321 { 322 unsigned char v[4]; 323 324 for(i = 0; i < nCnt; ++i) 325 v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f); 326 327 for(; i < 4; ++i) 328 v[i] = 0; 329 330 *(unsigned int*)pOut = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0]; 331 } 332 break; 333 334 case EPODDataUBYTE4: 335 { 336 unsigned char v[4]; 337 338 for(i = 0; i < nCnt; ++i) 339 v[i] = (unsigned char)PVRT_CLAMP(pData[i], 0.0f, 255.0f); 340 341 for(; i < 4; ++i) 342 v[i] = 0; 343 344 *(unsigned int*)pOut = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0]; 345 } 346 break; 347 348 case EPODDataFloat: 349 for(i = 0; i < nCnt; ++i) 350 ((float*)pOut)[i] = pData[i]; 351 break; 352 353 case EPODDataFixed16_16: 354 for(i = 0; i < nCnt; ++i) 355 ((int*)pOut)[i] = (int)(pData[i] * (float)(1 << 16)); 356 break; 357 358 case EPODDataInt: 359 for(i = 0; i < nCnt; ++i) 360 ((int*)pOut)[i] = (int)pData[i]; 361 break; 362 363 case EPODDataUnsignedInt: 364 for(i = 0; i < nCnt; ++i) 365 ((unsigned int*)pOut)[i] = (unsigned int)pData[i]; 366 break; 367 368 case EPODDataByte: 369 for(i = 0; i < nCnt; ++i) 370 ((char*)pOut)[i] = (char)pData[i]; 371 break; 372 373 case EPODDataByteNorm: 374 for(i = 0; i < nCnt; ++i) 375 ((char*)pOut)[i] = (char)(pData[i] * (float)((1 << 7)-1)); 376 break; 377 378 case EPODDataUnsignedByte: 379 for(i = 0; i < nCnt; ++i) 380 ((unsigned char*)pOut)[i] = (unsigned char)pData[i]; 381 break; 382 383 case EPODDataUnsignedByteNorm: 384 for(i = 0; i < nCnt; ++i) 385 ((char*)pOut)[i] = (unsigned char)(pData[i] * (float)((1 << 8)-1)); 386 break; 387 388 case EPODDataShort: 389 for(i = 0; i < nCnt; ++i) 390 ((short*)pOut)[i] = (short)pData[i]; 391 break; 392 393 case EPODDataShortNorm: 394 for(i = 0; i < nCnt; ++i) 395 ((short*)pOut)[i] = (short)(pData[i] * (float)((1 << 15)-1)); 396 break; 397 398 case EPODDataUnsignedShort: 399 for(i = 0; i < nCnt; ++i) 400 ((unsigned short*)pOut)[i] = (unsigned short)pData[i]; 401 break; 402 403 case EPODDataUnsignedShortNorm: 404 for(i = 0; i < nCnt; ++i) 405 ((unsigned short*)pOut)[i] = (unsigned short)(pData[i] * (float)((1 << 16)-1)); 406 break; 407 } 408 } 409 410 /*!*************************************************************************** 411 @Function PVRTVertexWrite 412 @Output pOut 413 @Input eType 414 @Input V 415 @Description Write an int 416 *****************************************************************************/ 417 void PVRTVertexWrite( 418 void * const pOut, 419 const EPVRTDataType eType, 420 const unsigned int V) 421 { 422 switch(eType) 423 { 424 default: 425 _ASSERT(false); 426 break; 427 428 case EPODDataUnsignedShort: 429 *(unsigned short*)pOut = (unsigned short) V; 430 break; 431 432 case EPODDataUnsignedInt: 433 *(unsigned int*)pOut = V; 434 break; 435 } 436 } 437 438 /*!*************************************************************************** 439 @Function PVRTVertexTangentBitangent 440 @Output pvTan 441 @Output pvBin 442 @Input pvNor 443 @Input pfPosA 444 @Input pfPosB 445 @Input pfPosC 446 @Input pfTexA 447 @Input pfTexB 448 @Input pfTexC 449 @Description Calculates the tangent and bitangent vectors for 450 vertex 'A' of the triangle defined by the 3 supplied 451 3D position coordinates (pfPosA) and 2D texture 452 coordinates (pfTexA). 453 *****************************************************************************/ 454 void PVRTVertexTangentBitangent( 455 PVRTVECTOR3f * const pvTan, 456 PVRTVECTOR3f * const pvBin, 457 const PVRTVECTOR3f * const pvNor, 458 const float * const pfPosA, 459 const float * const pfPosB, 460 const float * const pfPosC, 461 const float * const pfTexA, 462 const float * const pfTexB, 463 const float * const pfTexC) 464 { 465 PVRTVECTOR3f BaseVector1, BaseVector2, AlignedVector; 466 467 if(PVRTMatrixVec3DotProductF(*pvNor, *pvNor) == 0) 468 { 469 pvTan->x = 0; 470 pvTan->y = 0; 471 pvTan->z = 0; 472 pvBin->x = 0; 473 pvBin->y = 0; 474 pvBin->z = 0; 475 return; 476 } 477 478 /* BaseVectors are A-B and A-C. */ 479 BaseVector1.x = pfPosB[0] - pfPosA[0]; 480 BaseVector1.y = pfPosB[1] - pfPosA[1]; 481 BaseVector1.z = pfPosB[2] - pfPosA[2]; 482 483 BaseVector2.x = pfPosC[0] - pfPosA[0]; 484 BaseVector2.y = pfPosC[1] - pfPosA[1]; 485 BaseVector2.z = pfPosC[2] - pfPosA[2]; 486 487 if (pfTexB[0]==pfTexA[0] && pfTexC[0]==pfTexA[0]) 488 { 489 // Degenerate tri 490 // _ASSERT(0); 491 pvTan->x = 0; 492 pvTan->y = 0; 493 pvTan->z = 0; 494 pvBin->x = 0; 495 pvBin->y = 0; 496 pvBin->z = 0; 497 } 498 else 499 { 500 /* Calc the vector that follows the V direction (it is not the tangent vector)*/ 501 if(pfTexB[0]==pfTexA[0]) { 502 AlignedVector = BaseVector1; 503 if((pfTexB[1] - pfTexA[1]) < 0) { 504 AlignedVector.x = -AlignedVector.x; 505 AlignedVector.y = -AlignedVector.y; 506 AlignedVector.z = -AlignedVector.z; 507 } 508 } else if(pfTexC[0]==pfTexA[0]) { 509 AlignedVector = BaseVector2; 510 if((pfTexC[1] - pfTexA[1]) < 0) { 511 AlignedVector.x = -AlignedVector.x; 512 AlignedVector.y = -AlignedVector.y; 513 AlignedVector.z = -AlignedVector.z; 514 } 515 } else { 516 float fFac; 517 518 fFac = -(pfTexB[0] - pfTexA[0]) / (pfTexC[0] - pfTexA[0]); 519 520 /* This is the vector that follows the V direction (it is not the tangent vector)*/ 521 AlignedVector.x = BaseVector1.x + BaseVector2.x * fFac; 522 AlignedVector.y = BaseVector1.y + BaseVector2.y * fFac; 523 AlignedVector.z = BaseVector1.z + BaseVector2.z * fFac; 524 525 if(((pfTexB[1] - pfTexA[1]) + (pfTexC[1] - pfTexA[1]) * fFac) < 0) { 526 AlignedVector.x = -AlignedVector.x; 527 AlignedVector.y = -AlignedVector.y; 528 AlignedVector.z = -AlignedVector.z; 529 } 530 } 531 532 PVRTMatrixVec3NormalizeF(AlignedVector, AlignedVector); 533 534 /* The Tangent vector is perpendicular to the plane defined by vAlignedVector and the Normal. */ 535 PVRTMatrixVec3CrossProductF(*pvTan, *pvNor, AlignedVector); 536 537 /* The Bitangent vector is the vector perpendicular to the Normal and Tangent (and 538 that follows the vAlignedVector direction) */ 539 PVRTMatrixVec3CrossProductF(*pvBin, *pvTan, *pvNor); 540 541 _ASSERT(PVRTMatrixVec3DotProductF(*pvBin, AlignedVector) > 0.0f); 542 543 // Worry about wrapping; this is esentially a 2D cross product on texture coords 544 if((pfTexC[0]-pfTexA[0])*(pfTexB[1]-pfTexA[1]) < (pfTexC[1]-pfTexA[1])*(pfTexB[0]-pfTexA[0])) { 545 pvTan->x = -pvTan->x; 546 pvTan->y = -pvTan->y; 547 pvTan->z = -pvTan->z; 548 } 549 550 /* Normalize results */ 551 PVRTMatrixVec3NormalizeF(*pvTan, *pvTan); 552 PVRTMatrixVec3NormalizeF(*pvBin, *pvBin); 553 554 _ASSERT(PVRTMatrixVec3DotProductF(*pvNor, *pvNor) > 0.9f); 555 _ASSERT(PVRTMatrixVec3DotProductF(*pvTan, *pvTan) > 0.9f); 556 _ASSERT(PVRTMatrixVec3DotProductF(*pvBin, *pvBin) > 0.9f); 557 } 558 } 559 560 /*!*************************************************************************** 561 @Function PVRTVertexGenerateTangentSpace 562 @Output pnVtxNumOut Output vertex count 563 @Output pVtxOut Output vertices (program must free() this) 564 @Modified pui32Idx input AND output; index array for triangle list 565 @Input nVtxNum Input vertex count 566 @Input pVtx Input vertices 567 @Input nStride Size of a vertex (in bytes) 568 @Input nOffsetPos Offset in bytes to the vertex position 569 @Input eTypePos Data type of the position 570 @Input nOffsetNor Offset in bytes to the vertex normal 571 @Input eTypeNor Data type of the normal 572 @Input nOffsetTex Offset in bytes to the vertex texture coordinate to use 573 @Input eTypeTex Data type of the texture coordinate 574 @Input nOffsetTan Offset in bytes to the vertex tangent 575 @Input eTypeTan Data type of the tangent 576 @Input nOffsetBin Offset in bytes to the vertex bitangent 577 @Input eTypeBin Data type of the bitangent 578 @Input nTriNum Number of triangles 579 @Input fSplitDifference Split a vertex if the DP3 of tangents/bitangents are below this (range -1..1) 580 @Return PVR_FAIL if there was a problem. 581 @Description Calculates the tangent space for all supplied vertices. 582 Writes tangent and bitangent vectors to the output 583 vertices, copies all other elements from input vertices. 584 Will split vertices if necessary - i.e. if two triangles 585 sharing a vertex want to assign it different 586 tangent-space matrices. The decision whether to split 587 uses fSplitDifference - of the DP3 of two desired 588 tangents or two desired bitangents is higher than this, 589 the vertex will be split. 590 *****************************************************************************/ 591 EPVRTError PVRTVertexGenerateTangentSpace( 592 unsigned int * const pnVtxNumOut, 593 char ** const pVtxOut, 594 unsigned int * const pui32Idx, 595 const unsigned int nVtxNum, 596 const char * const pVtx, 597 const unsigned int nStride, 598 const unsigned int nOffsetPos, 599 EPVRTDataType eTypePos, 600 const unsigned int nOffsetNor, 601 EPVRTDataType eTypeNor, 602 const unsigned int nOffsetTex, 603 EPVRTDataType eTypeTex, 604 const unsigned int nOffsetTan, 605 EPVRTDataType eTypeTan, 606 const unsigned int nOffsetBin, 607 EPVRTDataType eTypeBin, 608 const unsigned int nTriNum, 609 const float fSplitDifference) 610 { 611 const int cnMaxSharedVtx = 32; 612 struct SVtxData 613 { 614 int n; // Number of items in following arrays, AKA number of tris using this vtx 615 PVRTVECTOR3f pvTan[cnMaxSharedVtx]; // Tangent (one per triangle referencing this vtx) 616 PVRTVECTOR3f pvBin[cnMaxSharedVtx]; // Bitangent (one per triangle referencing this vtx) 617 int pnTri[cnMaxSharedVtx]; // Triangle index (one per triangle referencing this vtx) 618 }; 619 SVtxData *psVtxData; // Array of desired tangent spaces per vertex 620 SVtxData *psTSpass; // Array of *different* tangent spaces desired for current vertex 621 unsigned int nTSpassLen; 622 SVtxData *psVtx, *psCmp; 623 unsigned int nVert, nCurr, i, j; // Loop counters 624 unsigned int nIdx0, nIdx1, nIdx2; 625 float pfPos0[4], pfPos1[4], pfPos2[4]; 626 float pfTex0[4], pfTex1[4], pfTex2[4]; 627 float pfNor0[4], pfNor1[4], pfNor2[4]; 628 unsigned int *pui32IdxNew; // New index array, this will be copied over the input array 629 630 // Initialise the outputs 631 *pnVtxNumOut = 0; 632 *pVtxOut = (char*)malloc(MAX_VERTEX_OUT * nStride); 633 if(!*pVtxOut) 634 { 635 return PVR_FAIL; 636 } 637 638 // Allocate some work space 639 pui32IdxNew = (unsigned int*)calloc(nTriNum * 3, sizeof(*pui32IdxNew)); 640 _ASSERT(pui32IdxNew); 641 psVtxData = (SVtxData*)calloc(nVtxNum, sizeof(*psVtxData)); 642 _ASSERT(psVtxData); 643 psTSpass = (SVtxData*)calloc(cnMaxSharedVtx, sizeof(*psTSpass)); 644 _ASSERT(psTSpass); 645 if(!pui32IdxNew || !psVtxData || !psTSpass) 646 { 647 free(pui32IdxNew); 648 free(psVtxData); 649 free(psTSpass); 650 return PVR_FAIL; 651 } 652 653 for(nCurr = 0; nCurr < nTriNum; ++nCurr) { 654 nIdx0 = pui32Idx[3*nCurr+0]; 655 nIdx1 = pui32Idx[3*nCurr+1]; 656 nIdx2 = pui32Idx[3*nCurr+2]; 657 658 _ASSERT(nIdx0 < nVtxNum); 659 _ASSERT(nIdx1 < nVtxNum); 660 _ASSERT(nIdx2 < nVtxNum); 661 662 if(nIdx0 == nIdx1 || nIdx1 == nIdx2 || nIdx0 == nIdx2) { 663 _RPT0(_CRT_WARN,"GenerateTangentSpace(): Degenerate triangle found.\n"); 664 return PVR_FAIL; 665 } 666 667 if( 668 psVtxData[nIdx0].n >= cnMaxSharedVtx || 669 psVtxData[nIdx1].n >= cnMaxSharedVtx || 670 psVtxData[nIdx2].n >= cnMaxSharedVtx) 671 { 672 _RPT0(_CRT_WARN,"GenerateTangentSpace(): Too many tris sharing a vtx.\n"); 673 return PVR_FAIL; 674 } 675 676 PVRTVertexRead((PVRTVECTOR4f*) &pfPos0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetPos, eTypePos, 3); 677 PVRTVertexRead((PVRTVECTOR4f*) &pfPos1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetPos, eTypePos, 3); 678 PVRTVertexRead((PVRTVECTOR4f*) &pfPos2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetPos, eTypePos, 3); 679 680 PVRTVertexRead((PVRTVECTOR4f*) &pfNor0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetNor, eTypeNor, 3); 681 PVRTVertexRead((PVRTVECTOR4f*) &pfNor1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetNor, eTypeNor, 3); 682 PVRTVertexRead((PVRTVECTOR4f*) &pfNor2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetNor, eTypeNor, 3); 683 684 PVRTVertexRead((PVRTVECTOR4f*) &pfTex0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetTex, eTypeTex, 3); 685 PVRTVertexRead((PVRTVECTOR4f*) &pfTex1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetTex, eTypeTex, 3); 686 PVRTVertexRead((PVRTVECTOR4f*) &pfTex2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetTex, eTypeTex, 3); 687 688 PVRTVertexTangentBitangent( 689 &psVtxData[nIdx0].pvTan[psVtxData[nIdx0].n], 690 &psVtxData[nIdx0].pvBin[psVtxData[nIdx0].n], 691 (PVRTVECTOR3f*) &pfNor0[0], 692 pfPos0, pfPos1, pfPos2, 693 pfTex0, pfTex1, pfTex2); 694 695 PVRTVertexTangentBitangent( 696 &psVtxData[nIdx1].pvTan[psVtxData[nIdx1].n], 697 &psVtxData[nIdx1].pvBin[psVtxData[nIdx1].n], 698 (PVRTVECTOR3f*) &pfNor1[0], 699 pfPos1, pfPos2, pfPos0, 700 pfTex1, pfTex2, pfTex0); 701 702 PVRTVertexTangentBitangent( 703 &psVtxData[nIdx2].pvTan[psVtxData[nIdx2].n], 704 &psVtxData[nIdx2].pvBin[psVtxData[nIdx2].n], 705 (PVRTVECTOR3f*) &pfNor2[0], 706 pfPos2, pfPos0, pfPos1, 707 pfTex2, pfTex0, pfTex1); 708 709 psVtxData[nIdx0].pnTri[psVtxData[nIdx0].n] = nCurr; 710 psVtxData[nIdx1].pnTri[psVtxData[nIdx1].n] = nCurr; 711 psVtxData[nIdx2].pnTri[psVtxData[nIdx2].n] = nCurr; 712 713 ++psVtxData[nIdx0].n; 714 ++psVtxData[nIdx1].n; 715 ++psVtxData[nIdx2].n; 716 } 717 718 // Now let's go through the vertices calculating avg tangent-spaces; create new vertices if necessary 719 for(nVert = 0; nVert < nVtxNum; ++nVert) { 720 psVtx = &psVtxData[nVert]; 721 722 // Start out with no output vertices required for this input vertex 723 nTSpassLen = 0; 724 725 // Run through each desired tangent space for this vertex 726 for(nCurr = 0; nCurr < (unsigned int) psVtx->n; ++nCurr) { 727 // Run through the possible vertices we can share with to see if we match 728 for(i = 0; i < nTSpassLen; ++i) { 729 psCmp = &psTSpass[i]; 730 731 // Check all the shared vertices which match 732 for(j = 0; j < (unsigned int) psCmp->n; ++j) { 733 if(PVRTMatrixVec3DotProductF(psVtx->pvTan[nCurr], psCmp->pvTan[j]) < fSplitDifference) 734 break; 735 if(PVRTMatrixVec3DotProductF(psVtx->pvBin[nCurr], psCmp->pvBin[j]) < fSplitDifference) 736 break; 737 } 738 739 // Did all the existing vertices match? 740 if(j == (unsigned int) psCmp->n) { 741 // Yes, so add to list 742 _ASSERT(psCmp->n < cnMaxSharedVtx); 743 psCmp->pvTan[psCmp->n] = psVtx->pvTan[nCurr]; 744 psCmp->pvBin[psCmp->n] = psVtx->pvBin[nCurr]; 745 psCmp->pnTri[psCmp->n] = psVtx->pnTri[nCurr]; 746 ++psCmp->n; 747 break; 748 } 749 } 750 751 if(i == nTSpassLen) { 752 // We never found another matching matrix, so let's add this as a different one 753 _ASSERT(nTSpassLen < cnMaxSharedVtx); 754 psTSpass[nTSpassLen].pvTan[0] = psVtx->pvTan[nCurr]; 755 psTSpass[nTSpassLen].pvBin[0] = psVtx->pvBin[nCurr]; 756 psTSpass[nTSpassLen].pnTri[0] = psVtx->pnTri[nCurr]; 757 psTSpass[nTSpassLen].n = 1; 758 ++nTSpassLen; 759 } 760 } 761 762 // OK, now we have 'nTSpassLen' different desired matrices, so we need to add that many to output 763 _ASSERT(nTSpassLen >= 1); 764 for(nCurr = 0; nCurr < nTSpassLen; ++nCurr) { 765 psVtx = &psTSpass[nCurr]; 766 767 memset(&pfPos0, 0, sizeof(pfPos0)); 768 memset(&pfPos1, 0, sizeof(pfPos1)); 769 770 for(i = 0; i < (unsigned int) psVtx->n; ++i) { 771 // Sum the tangent & bitangents, so we can average them 772 pfPos0[0] += psVtx->pvTan[i].x; 773 pfPos0[1] += psVtx->pvTan[i].y; 774 pfPos0[2] += psVtx->pvTan[i].z; 775 776 pfPos1[0] += psVtx->pvBin[i].x; 777 pfPos1[1] += psVtx->pvBin[i].y; 778 pfPos1[2] += psVtx->pvBin[i].z; 779 780 // Update triangle indices to use this vtx 781 if(pui32Idx[3 * psVtx->pnTri[i] + 0] == nVert) { 782 pui32IdxNew[3 * psVtx->pnTri[i] + 0] = *pnVtxNumOut; 783 784 } else if(pui32Idx[3 * psVtx->pnTri[i] + 1] == nVert) { 785 pui32IdxNew[3 * psVtx->pnTri[i] + 1] = *pnVtxNumOut; 786 787 } else if(pui32Idx[3 * psVtx->pnTri[i] + 2] == nVert) { 788 pui32IdxNew[3 * psVtx->pnTri[i] + 2] = *pnVtxNumOut; 789 790 } else { 791 _ASSERT(0); 792 } 793 } 794 795 PVRTMatrixVec3NormalizeF(*(PVRTVECTOR3f*) &pfPos0[0], *(PVRTVECTOR3f*) &pfPos0[0]); 796 PVRTMatrixVec3NormalizeF(*(PVRTVECTOR3f*) &pfPos1[0], *(PVRTVECTOR3f*) &pfPos1[0]); 797 798 if(*pnVtxNumOut >= MAX_VERTEX_OUT) { 799 _RPT0(_CRT_WARN,"PVRTVertexGenerateTangentSpace() ran out of working space! (Too many split vertices)\n"); 800 return PVR_FAIL; 801 } 802 803 memcpy(&(*pVtxOut)[(*pnVtxNumOut) * nStride], &pVtx[nVert*nStride], nStride); 804 PVRTVertexWrite((char*)&(*pVtxOut)[(*pnVtxNumOut) * nStride] + nOffsetTan, eTypeTan, 3, (PVRTVECTOR4f*) &pfPos0[0]); 805 PVRTVertexWrite((char*)&(*pVtxOut)[(*pnVtxNumOut) * nStride] + nOffsetBin, eTypeBin, 3, (PVRTVECTOR4f*) &pfPos1[0]); 806 807 ++*pnVtxNumOut; 808 } 809 } 810 811 FREE(psTSpass); 812 FREE(psVtxData); 813 814 *pVtxOut = (char*)realloc(*pVtxOut, *pnVtxNumOut * nStride); 815 _ASSERT(*pVtxOut); 816 817 memcpy(pui32Idx, pui32IdxNew, nTriNum * 3 * sizeof(*pui32IdxNew)); 818 FREE(pui32IdxNew); 819 820 _RPT3(_CRT_WARN, "GenerateTangentSpace(): %d tris, %d vtx in, %d vtx out\n", nTriNum, nVtxNum, *pnVtxNumOut); 821 _ASSERT(*pnVtxNumOut >= nVtxNum); 822 823 return PVR_SUCCESS; 824 } 825 826 /***************************************************************************** 827 End of file (PVRTVertex.cpp) 828 *****************************************************************************/ 829 830