1 /****************************************************************************** 2 3 @File PVRTModelPOD.cpp 4 5 @Title PVRTModelPOD 6 7 @Version 8 9 @Copyright Copyright (c) Imagination Technologies Limited. 10 11 @Platform ANSI compatible 12 13 @Description Code to load POD files - models exported from MAX. 14 15 ******************************************************************************/ 16 #include <math.h> 17 #include <stdlib.h> 18 #include <stdio.h> 19 #include <string.h> 20 21 #include "PVRTGlobal.h" 22 #if defined(BUILD_DX11) 23 #include "PVRTContext.h" 24 #endif 25 #include "PVRTFixedPoint.h" 26 #include "PVRTMatrix.h" 27 #include "PVRTQuaternion.h" 28 #include "PVRTVertex.h" 29 #include "PVRTBoneBatch.h" 30 #include "PVRTModelPOD.h" 31 #include "PVRTMisc.h" 32 #include "PVRTResourceFile.h" 33 #include "PVRTTrans.h" 34 35 /**************************************************************************** 36 ** Defines 37 ****************************************************************************/ 38 #define PVRTMODELPOD_TAG_MASK (0x80000000) 39 #define PVRTMODELPOD_TAG_START (0x00000000) 40 #define PVRTMODELPOD_TAG_END (0x80000000) 41 42 #define CFAH (1024) 43 44 /**************************************************************************** 45 ** Enumerations 46 ****************************************************************************/ 47 /*!**************************************************************************** 48 @Struct EPODFileName 49 @Brief Enum for the binary pod blocks 50 ******************************************************************************/ 51 enum EPODFileName 52 { 53 ePODFileVersion = 1000, 54 ePODFileScene, 55 ePODFileExpOpt, 56 ePODFileHistory, 57 ePODFileEndiannessMisMatch = -402456576, 58 59 ePODFileColourBackground = 2000, 60 ePODFileColourAmbient, 61 ePODFileNumCamera, 62 ePODFileNumLight, 63 ePODFileNumMesh, 64 ePODFileNumNode, 65 ePODFileNumMeshNode, 66 ePODFileNumTexture, 67 ePODFileNumMaterial, 68 ePODFileNumFrame, 69 ePODFileCamera, // Will come multiple times 70 ePODFileLight, // Will come multiple times 71 ePODFileMesh, // Will come multiple times 72 ePODFileNode, // Will come multiple times 73 ePODFileTexture, // Will come multiple times 74 ePODFileMaterial, // Will come multiple times 75 ePODFileFlags, 76 ePODFileFPS, 77 ePODFileUserData, 78 ePODFileUnits, 79 80 ePODFileMatName = 3000, 81 ePODFileMatIdxTexDiffuse, 82 ePODFileMatOpacity, 83 ePODFileMatAmbient, 84 ePODFileMatDiffuse, 85 ePODFileMatSpecular, 86 ePODFileMatShininess, 87 ePODFileMatEffectFile, 88 ePODFileMatEffectName, 89 ePODFileMatIdxTexAmbient, 90 ePODFileMatIdxTexSpecularColour, 91 ePODFileMatIdxTexSpecularLevel, 92 ePODFileMatIdxTexBump, 93 ePODFileMatIdxTexEmissive, 94 ePODFileMatIdxTexGlossiness, 95 ePODFileMatIdxTexOpacity, 96 ePODFileMatIdxTexReflection, 97 ePODFileMatIdxTexRefraction, 98 ePODFileMatBlendSrcRGB, 99 ePODFileMatBlendSrcA, 100 ePODFileMatBlendDstRGB, 101 ePODFileMatBlendDstA, 102 ePODFileMatBlendOpRGB, 103 ePODFileMatBlendOpA, 104 ePODFileMatBlendColour, 105 ePODFileMatBlendFactor, 106 ePODFileMatFlags, 107 ePODFileMatUserData, 108 109 ePODFileTexName = 4000, 110 111 ePODFileNodeIdx = 5000, 112 ePODFileNodeName, 113 ePODFileNodeIdxMat, 114 ePODFileNodeIdxParent, 115 ePODFileNodePos, 116 ePODFileNodeRot, 117 ePODFileNodeScale, 118 ePODFileNodeAnimPos, 119 ePODFileNodeAnimRot, 120 ePODFileNodeAnimScale, 121 ePODFileNodeMatrix, 122 ePODFileNodeAnimMatrix, 123 ePODFileNodeAnimFlags, 124 ePODFileNodeAnimPosIdx, 125 ePODFileNodeAnimRotIdx, 126 ePODFileNodeAnimScaleIdx, 127 ePODFileNodeAnimMatrixIdx, 128 ePODFileNodeUserData, 129 130 ePODFileMeshNumVtx = 6000, 131 ePODFileMeshNumFaces, 132 ePODFileMeshNumUVW, 133 ePODFileMeshFaces, 134 ePODFileMeshStripLength, 135 ePODFileMeshNumStrips, 136 ePODFileMeshVtx, 137 ePODFileMeshNor, 138 ePODFileMeshTan, 139 ePODFileMeshBin, 140 ePODFileMeshUVW, // Will come multiple times 141 ePODFileMeshVtxCol, 142 ePODFileMeshBoneIdx, 143 ePODFileMeshBoneWeight, 144 ePODFileMeshInterleaved, 145 ePODFileMeshBoneBatches, 146 ePODFileMeshBoneBatchBoneCnts, 147 ePODFileMeshBoneBatchOffsets, 148 ePODFileMeshBoneBatchBoneMax, 149 ePODFileMeshBoneBatchCnt, 150 ePODFileMeshUnpackMatrix, 151 152 ePODFileLightIdxTgt = 7000, 153 ePODFileLightColour, 154 ePODFileLightType, 155 ePODFileLightConstantAttenuation, 156 ePODFileLightLinearAttenuation, 157 ePODFileLightQuadraticAttenuation, 158 ePODFileLightFalloffAngle, 159 ePODFileLightFalloffExponent, 160 161 ePODFileCamIdxTgt = 8000, 162 ePODFileCamFOV, 163 ePODFileCamFar, 164 ePODFileCamNear, 165 ePODFileCamAnimFOV, 166 167 ePODFileDataType = 9000, 168 ePODFileN, 169 ePODFileStride, 170 ePODFileData 171 }; 172 173 /**************************************************************************** 174 ** Structures 175 ****************************************************************************/ 176 struct SPVRTPODImpl 177 { 178 VERTTYPE fFrame; /*!< Frame number */ 179 VERTTYPE fBlend; /*!< Frame blend (AKA fractional part of animation frame number) */ 180 int nFrame; /*!< Frame number (AKA integer part of animation frame number) */ 181 182 VERTTYPE *pfCache; /*!< Cache indicating the frames at which the matrix cache was filled */ 183 PVRTMATRIX *pWmCache; /*!< Cache of world matrices */ 184 PVRTMATRIX *pWmZeroCache; /*!< Pre-calculated frame 0 matrices */ 185 186 bool bFromMemory; /*!< Was the mesh data loaded from memory? */ 187 188 #ifdef _DEBUG 189 PVRTint64 nWmTotal, nWmCacheHit, nWmZeroCacheHit; 190 float fHitPerc, fHitPercZero; 191 #endif 192 }; 193 194 /**************************************************************************** 195 ** Local code: Memory allocation 196 ****************************************************************************/ 197 198 /*!*************************************************************************** 199 @Function SafeAlloc 200 @Input cnt 201 @Output ptr 202 @Return false if memory allocation failed 203 @Description Allocates a block of memory. 204 *****************************************************************************/ 205 template <typename T> 206 bool SafeAlloc(T* &ptr, size_t cnt) 207 { 208 _ASSERT(!ptr); 209 if(cnt) 210 { 211 ptr = (T*)calloc(cnt, sizeof(T)); 212 _ASSERT(ptr); 213 if(!ptr) 214 return false; 215 } 216 return true; 217 } 218 219 /*!*************************************************************************** 220 @Function SafeRealloc 221 @Modified ptr 222 @Input cnt 223 @Description Changes the size of a memory allocation. 224 *****************************************************************************/ 225 template <typename T> 226 void SafeRealloc(T* &ptr, size_t cnt) 227 { 228 ptr = (T*)realloc(ptr, cnt * sizeof(T)); 229 _ASSERT(ptr); 230 } 231 232 /**************************************************************************** 233 ** Class: CPODData 234 ****************************************************************************/ 235 /*!*************************************************************************** 236 @Function Reset 237 @Description Resets the POD Data to NULL 238 *****************************************************************************/ 239 void CPODData::Reset() 240 { 241 eType = EPODDataFloat; 242 n = 0; 243 nStride = 0; 244 FREE(pData); 245 } 246 247 // check32BitType and check16BitType are structs where only the specialisations have a standard declaration (complete type) 248 // if this struct is instantiated with a different type then the compiler will choke on it 249 // Place a line like: " check32BitType<channelType>(); " in a template function 250 // to ensure it won't be called using a type of the wrong size. 251 template<class T> struct check32BitType; 252 template<> struct check32BitType<unsigned int> {}; 253 template<> struct check32BitType<int> {}; 254 template<> struct check32BitType<float> {}; 255 template<class T> struct check16BitType; 256 template<> struct check16BitType<unsigned short> {}; 257 template<> struct check16BitType<short> {}; 258 259 /*!*************************************************************************** 260 Class: CSource 261 *****************************************************************************/ 262 class CSource 263 { 264 public: 265 /*!*************************************************************************** 266 @Function ~CSource 267 @Description Destructor 268 *****************************************************************************/ 269 virtual ~CSource() {}; 270 virtual bool Read(void* lpBuffer, const unsigned int dwNumberOfBytesToRead) = 0; 271 virtual bool Skip(const unsigned int nBytes) = 0; 272 273 template <typename T> 274 bool Read(T &n) 275 { 276 return Read(&n, sizeof(T)); 277 } 278 279 template <typename T> 280 bool Read32(T &n) 281 { 282 unsigned char ub[4]; 283 284 if(Read(&ub, 4)) 285 { 286 unsigned int *pn = (unsigned int*) &n; 287 *pn = (unsigned int) ((ub[3] << 24) | (ub[2] << 16) | (ub[1] << 8) | ub[0]); 288 return true; 289 } 290 291 return false; 292 } 293 294 template <typename T> 295 bool Read16(T &n) 296 { 297 unsigned char ub[2]; 298 299 if(Read(&ub, 2)) 300 { 301 unsigned short *pn = (unsigned short*) &n; 302 *pn = (unsigned short) ((ub[1] << 8) | ub[0]); 303 return true; 304 } 305 306 return false; 307 } 308 309 bool ReadMarker(unsigned int &nName, unsigned int &nLen); 310 311 template <typename T> 312 bool ReadAfterAlloc(T* &lpBuffer, const unsigned int dwNumberOfBytesToRead) 313 { 314 if(!SafeAlloc(lpBuffer, dwNumberOfBytesToRead)) 315 return false; 316 return Read(lpBuffer, dwNumberOfBytesToRead); 317 } 318 319 template <typename T> 320 bool ReadAfterAlloc32(T* &lpBuffer, const unsigned int dwNumberOfBytesToRead) 321 { 322 check32BitType<T>(); 323 if(!SafeAlloc(lpBuffer, dwNumberOfBytesToRead/4)) 324 return false; 325 return ReadArray32((unsigned int*) lpBuffer, dwNumberOfBytesToRead / 4); 326 } 327 328 template <typename T> 329 bool ReadArray32(T* pn, const unsigned int i32Size) 330 { 331 check32BitType<T>(); 332 bool bRet = true; 333 334 for(unsigned int i = 0; i < i32Size; ++i) 335 bRet &= Read32(pn[i]); 336 337 return bRet; 338 } 339 340 template <typename T> 341 bool ReadAfterAlloc16(T* &lpBuffer, const unsigned int dwNumberOfBytesToRead) 342 { 343 check16BitType<T>(); 344 if(!SafeAlloc(lpBuffer, dwNumberOfBytesToRead/2 )) 345 return false; 346 return ReadArray16((unsigned short*) lpBuffer, dwNumberOfBytesToRead / 2); 347 } 348 349 bool ReadArray16(unsigned short* pn, unsigned int i32Size) 350 { 351 bool bRet = true; 352 353 for(unsigned int i = 0; i < i32Size; ++i) 354 bRet &= Read16(pn[i]); 355 356 return bRet; 357 } 358 }; 359 360 bool CSource::ReadMarker(unsigned int &nName, unsigned int &nLen) 361 { 362 if(!Read32(nName)) 363 return false; 364 if(!Read32(nLen)) 365 return false; 366 return true; 367 } 368 369 /*!*************************************************************************** 370 Class: CSourceStream 371 *****************************************************************************/ 372 class CSourceStream : public CSource 373 { 374 protected: 375 CPVRTResourceFile* m_pFile; 376 size_t m_BytesReadCount; 377 378 public: 379 /*!*************************************************************************** 380 @Function CSourceStream 381 @Description Constructor 382 *****************************************************************************/ 383 CSourceStream() : m_pFile(0), m_BytesReadCount(0) {} 384 385 /*!*************************************************************************** 386 @Function ~CSourceStream 387 @Description Destructor 388 *****************************************************************************/ 389 virtual ~CSourceStream(); 390 391 bool Init(const char * const pszFileName); 392 bool Init(const char * const pData, const size_t i32Size); 393 394 virtual bool Read(void* lpBuffer, const unsigned int dwNumberOfBytesToRead); 395 virtual bool Skip(const unsigned int nBytes); 396 }; 397 398 /*!*************************************************************************** 399 @Function ~CSourceStream 400 @Description Destructor 401 *****************************************************************************/ 402 CSourceStream::~CSourceStream() 403 { 404 delete m_pFile; 405 } 406 407 /*!*************************************************************************** 408 @Function Init 409 @Input pszFileName Source file 410 @Description Initialises the source stream with a file at the specified 411 directory. 412 *****************************************************************************/ 413 bool CSourceStream::Init(const char * const pszFileName) 414 { 415 m_BytesReadCount = 0; 416 if (m_pFile) 417 { 418 delete m_pFile; 419 m_pFile = 0; 420 } 421 422 if(!pszFileName) 423 return false; 424 425 m_pFile = new CPVRTResourceFile(pszFileName); 426 if (!m_pFile->IsOpen()) 427 { 428 delete m_pFile; 429 m_pFile = 0; 430 return false; 431 } 432 return true; 433 } 434 435 /*!*************************************************************************** 436 @Function Init 437 @Input pData Address of the source data 438 @Input i32Size Size of the data (in bytes) 439 @Description Initialises the source stream with the data at the specified 440 directory. 441 *****************************************************************************/ 442 bool CSourceStream::Init(const char * pData, size_t i32Size) 443 { 444 m_BytesReadCount = 0; 445 if (m_pFile) delete m_pFile; 446 447 m_pFile = new CPVRTResourceFile(pData, i32Size); 448 if (!m_pFile->IsOpen()) 449 { 450 delete m_pFile; 451 m_pFile = 0; 452 return false; 453 } 454 return true; 455 } 456 457 /*!*************************************************************************** 458 @Function Read 459 @Modified lpBuffer Buffer to write the data into 460 @Input dwNumberOfBytesToRead Number of bytes to read 461 @Description Reads specified number of bytes from the source stream 462 into the output buffer. 463 *****************************************************************************/ 464 bool CSourceStream::Read(void* lpBuffer, const unsigned int dwNumberOfBytesToRead) 465 { 466 _ASSERT(lpBuffer); 467 _ASSERT(m_pFile); 468 469 if (m_BytesReadCount + dwNumberOfBytesToRead > m_pFile->Size()) return false; 470 471 memcpy(lpBuffer, &((char*) m_pFile->DataPtr())[m_BytesReadCount], dwNumberOfBytesToRead); 472 473 m_BytesReadCount += dwNumberOfBytesToRead; 474 return true; 475 } 476 477 /*!*************************************************************************** 478 @Function Skip 479 @Input nBytes The number of bytes to skip 480 @Description Skips the specified number of bytes of the source stream. 481 *****************************************************************************/ 482 bool CSourceStream::Skip(const unsigned int nBytes) 483 { 484 if (m_BytesReadCount + nBytes > m_pFile->Size()) return false; 485 m_BytesReadCount += nBytes; 486 return true; 487 } 488 489 #if defined(_WIN32) 490 /*!*************************************************************************** 491 Class: CSourceResource 492 *****************************************************************************/ 493 class CSourceResource : public CSource 494 { 495 protected: 496 const unsigned char *m_pData; 497 unsigned int m_nSize, m_nReadPos; 498 499 public: 500 bool Init(const TCHAR * const pszName); 501 virtual bool Read(void* lpBuffer, const unsigned int dwNumberOfBytesToRead); 502 virtual bool Skip(const unsigned int nBytes); 503 }; 504 505 /*!*************************************************************************** 506 @Function Init 507 @Input pszName The file extension of the resource file 508 @Description Initialises the source resource from the data at the 509 specified file extension. 510 *****************************************************************************/ 511 bool CSourceResource::Init(const TCHAR * const pszName) 512 { 513 HRSRC hR; 514 HGLOBAL hG; 515 516 // Find the resource 517 hR = FindResource(GetModuleHandle(NULL), pszName, RT_RCDATA); 518 if(!hR) 519 return false; 520 521 // How big is the resource? 522 m_nSize = SizeofResource(NULL, hR); 523 if(!m_nSize) 524 return false; 525 526 // Get a pointer to the resource data 527 hG = LoadResource(NULL, hR); 528 if(!hG) 529 return false; 530 531 m_pData = (unsigned char*)LockResource(hG); 532 if(!m_pData) 533 return false; 534 535 m_nReadPos = 0; 536 return true; 537 } 538 539 /*!*************************************************************************** 540 @Function Read 541 @Modified lpBuffer The buffer to write to 542 @Input dwNumberOfBytesToRead The number of bytes to read 543 @Description Reads data from the resource to the specified output buffer. 544 *****************************************************************************/ 545 bool CSourceResource::Read(void* lpBuffer, const unsigned int dwNumberOfBytesToRead) 546 { 547 if(m_nReadPos + dwNumberOfBytesToRead > m_nSize) 548 return false; 549 550 _ASSERT(lpBuffer); 551 memcpy(lpBuffer, &m_pData[m_nReadPos], dwNumberOfBytesToRead); 552 m_nReadPos += dwNumberOfBytesToRead; 553 return true; 554 } 555 556 bool CSourceResource::Skip(const unsigned int nBytes) 557 { 558 if(m_nReadPos + nBytes > m_nSize) 559 return false; 560 561 m_nReadPos += nBytes; 562 return true; 563 } 564 565 #endif /* _WIN32 */ 566 567 /**************************************************************************** 568 ** Local code: File writing 569 ****************************************************************************/ 570 571 /*!*************************************************************************** 572 @Function WriteFileSafe 573 @Input pFile 574 @Input lpBuffer 575 @Input nNumberOfBytesToWrite 576 @Return true if successful 577 @Description Writes data to a file, checking return codes. 578 *****************************************************************************/ 579 static bool WriteFileSafe(FILE *pFile, const void * const lpBuffer, const unsigned int nNumberOfBytesToWrite) 580 { 581 if(nNumberOfBytesToWrite) 582 { 583 size_t count = fwrite(lpBuffer, nNumberOfBytesToWrite, 1, pFile); 584 return count == 1; 585 } 586 return true; 587 } 588 589 static bool WriteFileSafe16(FILE *pFile, const unsigned short * const lpBuffer, const unsigned int nSize) 590 { 591 if(nSize) 592 { 593 unsigned char ub[2]; 594 bool bRet = true; 595 596 for(unsigned int i = 0; i < nSize; ++i) 597 { 598 ub[0] = (unsigned char) lpBuffer[i]; 599 ub[1] = lpBuffer[i] >> 8; 600 601 bRet &= (fwrite(ub, 2, 1, pFile) == 1); 602 } 603 604 return bRet; 605 } 606 return true; 607 } 608 609 static bool WriteFileSafe32(FILE *pFile, const unsigned int * const lpBuffer, const unsigned int nSize) 610 { 611 if(nSize) 612 { 613 unsigned char ub[4]; 614 bool bRet = true; 615 616 for(unsigned int i = 0; i < nSize; ++i) 617 { 618 ub[0] = (unsigned char) (lpBuffer[i]); 619 ub[1] = (unsigned char) (lpBuffer[i] >> 8); 620 ub[2] = (unsigned char) (lpBuffer[i] >> 16); 621 ub[3] = (unsigned char) (lpBuffer[i] >> 24); 622 623 bRet &= (fwrite(ub, 4, 1, pFile) == 1); 624 } 625 626 return bRet; 627 } 628 return true; 629 } 630 /*!*************************************************************************** 631 @Function WriteMarker 632 @Input pFile 633 @Input nName 634 @Input bEnd 635 @Input nLen 636 Return true if successful 637 @Description Write a marker to a POD file. If bEnd if false, it's a 638 beginning marker, otherwise it's an end marker. 639 *****************************************************************************/ 640 static bool WriteMarker( 641 FILE * const pFile, 642 const unsigned int nName, 643 const bool bEnd, 644 const unsigned int nLen = 0) 645 { 646 unsigned int nMarker; 647 bool bRet; 648 649 _ASSERT((nName & ~PVRTMODELPOD_TAG_MASK) == nName); 650 nMarker = nName | (bEnd ? PVRTMODELPOD_TAG_END : PVRTMODELPOD_TAG_START); 651 652 bRet = WriteFileSafe32(pFile, &nMarker, 1); 653 bRet &= WriteFileSafe32(pFile, &nLen, 1); 654 655 return bRet; 656 } 657 658 /*!*************************************************************************** 659 @Function WriteData 660 @Input pFile 661 @Input nName 662 @Input pData 663 @Input nLen 664 @Return true if successful 665 @Description Write nLen bytes of data from pData, bracketed by an nName 666 begin/end markers. 667 *****************************************************************************/ 668 static bool WriteData( 669 FILE * const pFile, 670 const unsigned int nName, 671 const void * const pData, 672 const unsigned int nLen) 673 { 674 if(pData) 675 { 676 _ASSERT(nLen); 677 if(!WriteMarker(pFile, nName, false, nLen)) return false; 678 if(!WriteFileSafe(pFile, pData, nLen)) return false; 679 if(!WriteMarker(pFile, nName, true)) return false; 680 } 681 return true; 682 } 683 684 /*!*************************************************************************** 685 @Function WriteData16 686 @Input pFile 687 @Input nName 688 @Input pData 689 @Input i32Size 690 @Return true if successful 691 @Description Write i32Size no. of unsigned shorts from pData, bracketed by 692 an nName begin/end markers. 693 *****************************************************************************/ 694 template <typename T> 695 static bool WriteData16( 696 FILE * const pFile, 697 const unsigned int nName, 698 const T * const pData, 699 int i32Size = 1) 700 { 701 if(pData) 702 { 703 if(!WriteMarker(pFile, nName, false, 2 * i32Size)) return false; 704 if(!WriteFileSafe16(pFile, (unsigned short*) pData, i32Size)) return false; 705 if(!WriteMarker(pFile, nName, true)) return false; 706 } 707 return true; 708 } 709 710 /*!*************************************************************************** 711 @Function WriteData32 712 @Input pFile 713 @Input nName 714 @Input pData 715 @Input i32Size 716 @Return true if successful 717 @Description Write i32Size no. of unsigned ints from pData, bracketed by 718 an nName begin/end markers. 719 *****************************************************************************/ 720 template <typename T> 721 static bool WriteData32( 722 FILE * const pFile, 723 const unsigned int nName, 724 const T * const pData, 725 int i32Size = 1) 726 { 727 if(pData) 728 { 729 if(!WriteMarker(pFile, nName, false, 4 * i32Size)) return false; 730 if(!WriteFileSafe32(pFile, (unsigned int*) pData, i32Size)) return false; 731 if(!WriteMarker(pFile, nName, true)) return false; 732 } 733 return true; 734 } 735 736 /*!*************************************************************************** 737 @Function WriteData 738 @Input pFile 739 @Input nName 740 @Input n 741 @Return true if successful 742 @Description Write the value n, bracketed by an nName begin/end markers. 743 *****************************************************************************/ 744 template <typename T> 745 static bool WriteData( 746 FILE * const pFile, 747 const unsigned int nName, 748 const T &n) 749 { 750 unsigned int nSize = sizeof(T); 751 752 bool bRet = WriteData(pFile, nName, (void*)&n, nSize); 753 754 return bRet; 755 } 756 757 /*!*************************************************************************** 758 @Function WriteCPODData 759 @Input pFile 760 @Input nName 761 @Input n 762 @Input nEntries 763 @Input bValidData 764 @Return true if successful 765 @Description Write the value n, bracketed by an nName begin/end markers. 766 *****************************************************************************/ 767 static bool WriteCPODData( 768 FILE * const pFile, 769 const unsigned int nName, 770 const CPODData &n, 771 const unsigned int nEntries, 772 const bool bValidData) 773 { 774 if(!WriteMarker(pFile, nName, false)) return false; 775 if(!WriteData32(pFile, ePODFileDataType, &n.eType)) return false; 776 if(!WriteData32(pFile, ePODFileN, &n.n)) return false; 777 if(!WriteData32(pFile, ePODFileStride, &n.nStride)) return false; 778 if(bValidData) 779 { 780 switch(PVRTModelPODDataTypeSize(n.eType)) 781 { 782 case 1: if(!WriteData(pFile, ePODFileData, n.pData, nEntries * n.nStride)) return false; break; 783 case 2: if(!WriteData16(pFile, ePODFileData, n.pData, nEntries * (n.nStride / 2))) return false; break; 784 case 4: if(!WriteData32(pFile, ePODFileData, n.pData, nEntries * (n.nStride / 4))) return false; break; 785 default: { _ASSERT(false); } 786 }; 787 } 788 else 789 { 790 unsigned int offset = (unsigned int) (size_t) n.pData; 791 if(!WriteData32(pFile, ePODFileData, &offset)) return false; 792 } 793 if(!WriteMarker(pFile, nName, true)) return false; 794 return true; 795 } 796 797 /*!*************************************************************************** 798 @Function WriteInterleaved 799 @Input pFile 800 @Input mesh 801 @Return true if successful 802 @Description Write out the interleaved data to file. 803 *****************************************************************************/ 804 static bool WriteInterleaved(FILE * const pFile, SPODMesh &mesh) 805 { 806 if(!mesh.pInterleaved) 807 return true; 808 809 unsigned int i; 810 unsigned int ui32CPODDataSize = 0; 811 CPODData **pCPODData = new CPODData*[7 + mesh.nNumUVW]; 812 813 if(mesh.sVertex.n) pCPODData[ui32CPODDataSize++] = &mesh.sVertex; 814 if(mesh.sNormals.n) pCPODData[ui32CPODDataSize++] = &mesh.sNormals; 815 if(mesh.sTangents.n) pCPODData[ui32CPODDataSize++] = &mesh.sTangents; 816 if(mesh.sBinormals.n) pCPODData[ui32CPODDataSize++] = &mesh.sBinormals; 817 if(mesh.sVtxColours.n) pCPODData[ui32CPODDataSize++] = &mesh.sVtxColours; 818 if(mesh.sBoneIdx.n) pCPODData[ui32CPODDataSize++] = &mesh.sBoneIdx; 819 if(mesh.sBoneWeight.n) pCPODData[ui32CPODDataSize++] = &mesh.sBoneWeight; 820 821 for(i = 0; i < mesh.nNumUVW; ++i) 822 if(mesh.psUVW[i].n) pCPODData[ui32CPODDataSize++] = &mesh.psUVW[i]; 823 824 // Bubble sort pCPODData based on the vertex element offsets 825 bool bSwap = true; 826 unsigned int ui32Size = ui32CPODDataSize; 827 828 while(bSwap) 829 { 830 bSwap = false; 831 832 for(i = 0; i < ui32Size - 1; ++i) 833 { 834 if(pCPODData[i]->pData > pCPODData[i + 1]->pData) 835 { 836 PVRTswap(pCPODData[i], pCPODData[i + 1]); 837 bSwap = true; 838 } 839 } 840 841 --ui32Size; 842 } 843 844 // Write out the data 845 if(!WriteMarker(pFile, ePODFileMeshInterleaved, false, mesh.nNumVertex * mesh.sVertex.nStride)) return false; 846 847 for(i = 0; i < mesh.nNumVertex; ++i) 848 { 849 unsigned char* pVtxStart = mesh.pInterleaved + (i * mesh.sVertex.nStride); 850 851 for(unsigned int j = 0; j < ui32CPODDataSize; ++j) 852 { 853 unsigned char* pData = pVtxStart + (size_t) pCPODData[j]->pData; 854 855 switch(PVRTModelPODDataTypeSize(pCPODData[j]->eType)) 856 { 857 case 1: if(!WriteFileSafe(pFile, pData, pCPODData[j]->n)) return false; break; 858 case 2: if(!WriteFileSafe16(pFile, (unsigned short*) pData, pCPODData[j]->n)) return false; break; 859 case 4: if(!WriteFileSafe32(pFile, (unsigned int*) pData, pCPODData[j]->n)) return false; break; 860 default: { _ASSERT(false); } 861 }; 862 863 // Write out the padding 864 size_t padding; 865 866 if(j != ui32CPODDataSize - 1) 867 padding = ((size_t)pCPODData[j + 1]->pData - (size_t)pCPODData[j]->pData) - PVRTModelPODDataStride(*pCPODData[j]); 868 else 869 padding = (pCPODData[j]->nStride - (size_t)pCPODData[j]->pData) - PVRTModelPODDataStride(*pCPODData[j]); 870 871 fwrite("\0\0\0\0", padding, 1, pFile); 872 } 873 } 874 875 if(!WriteMarker(pFile, ePODFileMeshInterleaved, true)) return false; 876 877 // Delete our CPOD data array 878 delete[] pCPODData; 879 880 return true; 881 } 882 883 /*!*************************************************************************** 884 @Function PVRTModelPODGetAnimArraySize 885 @Input pAnimDataIdx 886 @Input ui32Frames 887 @Input ui32Components 888 @Return Size of the animation array 889 @Description Calculates the size of an animation array 890 *****************************************************************************/ 891 PVRTuint32 PVRTModelPODGetAnimArraySize(PVRTuint32 *pAnimDataIdx, PVRTuint32 ui32Frames, PVRTuint32 ui32Components) 892 { 893 if(pAnimDataIdx) 894 { 895 // Find the largest index value 896 PVRTuint32 ui32Max = 0; 897 for(unsigned int i = 0; i < ui32Frames; ++i) 898 { 899 if(ui32Max < pAnimDataIdx[i]) 900 ui32Max = pAnimDataIdx[i]; 901 } 902 903 return ui32Max + ui32Components; 904 } 905 906 return ui32Frames * ui32Components; 907 } 908 909 /*!*************************************************************************** 910 @Function WritePOD 911 @Output The file referenced by pFile 912 @Input s The POD Scene to write 913 @Input pszExpOpt Exporter options 914 @Return true if successful 915 @Description Write a POD file 916 *****************************************************************************/ 917 static bool WritePOD( 918 FILE * const pFile, 919 const char * const pszExpOpt, 920 const char * const pszHistory, 921 const SPODScene &s) 922 { 923 unsigned int i, j; 924 925 // Save: file version 926 { 927 char *pszVersion = (char*)PVRTMODELPOD_VERSION; 928 929 if(!WriteData(pFile, ePODFileVersion, pszVersion, (unsigned int)strlen(pszVersion) + 1)) return false; 930 } 931 932 // Save: exporter options 933 if(pszExpOpt && *pszExpOpt) 934 { 935 if(!WriteData(pFile, ePODFileExpOpt, pszExpOpt, (unsigned int)strlen(pszExpOpt) + 1)) return false; 936 } 937 938 // Save: .pod file history 939 if(pszHistory && *pszHistory) 940 { 941 if(!WriteData(pFile, ePODFileHistory, pszHistory, (unsigned int)strlen(pszHistory) + 1)) return false; 942 } 943 944 // Save: scene descriptor 945 if(!WriteMarker(pFile, ePODFileScene, false)) return false; 946 947 { 948 if(!WriteData32(pFile, ePODFileUnits, &s.fUnits)) return false; 949 if(!WriteData32(pFile, ePODFileColourBackground, s.pfColourBackground, sizeof(s.pfColourBackground) / sizeof(*s.pfColourBackground))) return false; 950 if(!WriteData32(pFile, ePODFileColourAmbient, s.pfColourAmbient, sizeof(s.pfColourAmbient) / sizeof(*s.pfColourAmbient))) return false; 951 if(!WriteData32(pFile, ePODFileNumCamera, &s.nNumCamera)) return false; 952 if(!WriteData32(pFile, ePODFileNumLight, &s.nNumLight)) return false; 953 if(!WriteData32(pFile, ePODFileNumMesh, &s.nNumMesh)) return false; 954 if(!WriteData32(pFile, ePODFileNumNode, &s.nNumNode)) return false; 955 if(!WriteData32(pFile, ePODFileNumMeshNode, &s.nNumMeshNode)) return false; 956 if(!WriteData32(pFile, ePODFileNumTexture, &s.nNumTexture)) return false; 957 if(!WriteData32(pFile, ePODFileNumMaterial, &s.nNumMaterial)) return false; 958 if(!WriteData32(pFile, ePODFileNumFrame, &s.nNumFrame)) return false; 959 960 if(s.nNumFrame) 961 { 962 if(!WriteData32(pFile, ePODFileFPS, &s.nFPS)) return false; 963 } 964 965 if(!WriteData32(pFile, ePODFileFlags, &s.nFlags)) return false; 966 if(!WriteData(pFile, ePODFileUserData, s.pUserData, s.nUserDataSize)) return false; 967 968 // Save: cameras 969 for(i = 0; i < s.nNumCamera; ++i) 970 { 971 if(!WriteMarker(pFile, ePODFileCamera, false)) return false; 972 if(!WriteData32(pFile, ePODFileCamIdxTgt, &s.pCamera[i].nIdxTarget)) return false; 973 if(!WriteData32(pFile, ePODFileCamFOV, &s.pCamera[i].fFOV)) return false; 974 if(!WriteData32(pFile, ePODFileCamFar, &s.pCamera[i].fFar)) return false; 975 if(!WriteData32(pFile, ePODFileCamNear, &s.pCamera[i].fNear)) return false; 976 if(!WriteData32(pFile, ePODFileCamAnimFOV, s.pCamera[i].pfAnimFOV, s.nNumFrame)) return false; 977 if(!WriteMarker(pFile, ePODFileCamera, true)) return false; 978 } 979 // Save: lights 980 for(i = 0; i < s.nNumLight; ++i) 981 { 982 if(!WriteMarker(pFile, ePODFileLight, false)) return false; 983 if(!WriteData32(pFile, ePODFileLightIdxTgt, &s.pLight[i].nIdxTarget)) return false; 984 if(!WriteData32(pFile, ePODFileLightColour, s.pLight[i].pfColour, sizeof(s.pLight[i].pfColour) / sizeof(*s.pLight[i].pfColour))) return false; 985 if(!WriteData32(pFile, ePODFileLightType, &s.pLight[i].eType)) return false; 986 987 if(s.pLight[i].eType != ePODDirectional) 988 { 989 if(!WriteData32(pFile, ePODFileLightConstantAttenuation, &s.pLight[i].fConstantAttenuation)) return false; 990 if(!WriteData32(pFile, ePODFileLightLinearAttenuation, &s.pLight[i].fLinearAttenuation)) return false; 991 if(!WriteData32(pFile, ePODFileLightQuadraticAttenuation, &s.pLight[i].fQuadraticAttenuation)) return false; 992 } 993 994 if(s.pLight[i].eType == ePODSpot) 995 { 996 if(!WriteData32(pFile, ePODFileLightFalloffAngle, &s.pLight[i].fFalloffAngle)) return false; 997 if(!WriteData32(pFile, ePODFileLightFalloffExponent, &s.pLight[i].fFalloffExponent)) return false; 998 } 999 1000 if(!WriteMarker(pFile, ePODFileLight, true)) return false; 1001 } 1002 1003 // Save: materials 1004 for(i = 0; i < s.nNumMaterial; ++i) 1005 { 1006 if(!WriteMarker(pFile, ePODFileMaterial, false)) return false; 1007 1008 if(!WriteData32(pFile, ePODFileMatFlags, &s.pMaterial[i].nFlags)) return false; 1009 if(!WriteData(pFile, ePODFileMatName, s.pMaterial[i].pszName, (unsigned int)strlen(s.pMaterial[i].pszName)+1)) return false; 1010 if(!WriteData32(pFile, ePODFileMatIdxTexDiffuse, &s.pMaterial[i].nIdxTexDiffuse)) return false; 1011 if(!WriteData32(pFile, ePODFileMatIdxTexAmbient, &s.pMaterial[i].nIdxTexAmbient)) return false; 1012 if(!WriteData32(pFile, ePODFileMatIdxTexSpecularColour, &s.pMaterial[i].nIdxTexSpecularColour)) return false; 1013 if(!WriteData32(pFile, ePODFileMatIdxTexSpecularLevel, &s.pMaterial[i].nIdxTexSpecularLevel)) return false; 1014 if(!WriteData32(pFile, ePODFileMatIdxTexBump, &s.pMaterial[i].nIdxTexBump)) return false; 1015 if(!WriteData32(pFile, ePODFileMatIdxTexEmissive, &s.pMaterial[i].nIdxTexEmissive)) return false; 1016 if(!WriteData32(pFile, ePODFileMatIdxTexGlossiness, &s.pMaterial[i].nIdxTexGlossiness)) return false; 1017 if(!WriteData32(pFile, ePODFileMatIdxTexOpacity, &s.pMaterial[i].nIdxTexOpacity)) return false; 1018 if(!WriteData32(pFile, ePODFileMatIdxTexReflection, &s.pMaterial[i].nIdxTexReflection)) return false; 1019 if(!WriteData32(pFile, ePODFileMatIdxTexRefraction, &s.pMaterial[i].nIdxTexRefraction)) return false; 1020 if(!WriteData32(pFile, ePODFileMatOpacity, &s.pMaterial[i].fMatOpacity)) return false; 1021 if(!WriteData32(pFile, ePODFileMatAmbient, s.pMaterial[i].pfMatAmbient, sizeof(s.pMaterial[i].pfMatAmbient) / sizeof(*s.pMaterial[i].pfMatAmbient))) return false; 1022 if(!WriteData32(pFile, ePODFileMatDiffuse, s.pMaterial[i].pfMatDiffuse, sizeof(s.pMaterial[i].pfMatDiffuse) / sizeof(*s.pMaterial[i].pfMatDiffuse))) return false; 1023 if(!WriteData32(pFile, ePODFileMatSpecular, s.pMaterial[i].pfMatSpecular, sizeof(s.pMaterial[i].pfMatSpecular) / sizeof(*s.pMaterial[i].pfMatSpecular))) return false; 1024 if(!WriteData32(pFile, ePODFileMatShininess, &s.pMaterial[i].fMatShininess)) return false; 1025 if(!WriteData(pFile, ePODFileMatEffectFile, s.pMaterial[i].pszEffectFile, s.pMaterial[i].pszEffectFile ? ((unsigned int)strlen(s.pMaterial[i].pszEffectFile)+1) : 0)) return false; 1026 if(!WriteData(pFile, ePODFileMatEffectName, s.pMaterial[i].pszEffectName, s.pMaterial[i].pszEffectName ? ((unsigned int)strlen(s.pMaterial[i].pszEffectName)+1) : 0)) return false; 1027 if(!WriteData32(pFile, ePODFileMatBlendSrcRGB, &s.pMaterial[i].eBlendSrcRGB))return false; 1028 if(!WriteData32(pFile, ePODFileMatBlendSrcA, &s.pMaterial[i].eBlendSrcA)) return false; 1029 if(!WriteData32(pFile, ePODFileMatBlendDstRGB, &s.pMaterial[i].eBlendDstRGB))return false; 1030 if(!WriteData32(pFile, ePODFileMatBlendDstA, &s.pMaterial[i].eBlendDstA)) return false; 1031 if(!WriteData32(pFile, ePODFileMatBlendOpRGB, &s.pMaterial[i].eBlendOpRGB)) return false; 1032 if(!WriteData32(pFile, ePODFileMatBlendOpA, &s.pMaterial[i].eBlendOpA)) return false; 1033 if(!WriteData32(pFile, ePODFileMatBlendColour, s.pMaterial[i].pfBlendColour, sizeof(s.pMaterial[i].pfBlendColour) / sizeof(*s.pMaterial[i].pfBlendColour))) return false; 1034 if(!WriteData32(pFile, ePODFileMatBlendFactor, s.pMaterial[i].pfBlendFactor, sizeof(s.pMaterial[i].pfBlendFactor) / sizeof(*s.pMaterial[i].pfBlendFactor))) return false; 1035 if(!WriteData(pFile, ePODFileMatUserData, s.pMaterial[i].pUserData, s.pMaterial[i].nUserDataSize)) return false; 1036 1037 if(!WriteMarker(pFile, ePODFileMaterial, true)) return false; 1038 } 1039 1040 // Save: meshes 1041 for(i = 0; i < s.nNumMesh; ++i) 1042 { 1043 if(!WriteMarker(pFile, ePODFileMesh, false)) return false; 1044 1045 if(!WriteData32(pFile, ePODFileMeshNumVtx, &s.pMesh[i].nNumVertex)) return false; 1046 if(!WriteData32(pFile, ePODFileMeshNumFaces, &s.pMesh[i].nNumFaces)) return false; 1047 if(!WriteData32(pFile, ePODFileMeshNumUVW, &s.pMesh[i].nNumUVW)) return false; 1048 if(!WriteData32(pFile, ePODFileMeshStripLength, s.pMesh[i].pnStripLength, s.pMesh[i].nNumStrips)) return false; 1049 if(!WriteData32(pFile, ePODFileMeshNumStrips, &s.pMesh[i].nNumStrips)) return false; 1050 if(!WriteInterleaved(pFile, s.pMesh[i])) return false; 1051 if(!WriteData32(pFile, ePODFileMeshBoneBatchBoneMax,&s.pMesh[i].sBoneBatches.nBatchBoneMax)) return false; 1052 if(!WriteData32(pFile, ePODFileMeshBoneBatchCnt, &s.pMesh[i].sBoneBatches.nBatchCnt)) return false; 1053 if(!WriteData32(pFile, ePODFileMeshBoneBatches, s.pMesh[i].sBoneBatches.pnBatches, s.pMesh[i].sBoneBatches.nBatchBoneMax * s.pMesh[i].sBoneBatches.nBatchCnt)) return false; 1054 if(!WriteData32(pFile, ePODFileMeshBoneBatchBoneCnts, s.pMesh[i].sBoneBatches.pnBatchBoneCnt, s.pMesh[i].sBoneBatches.nBatchCnt)) return false; 1055 if(!WriteData32(pFile, ePODFileMeshBoneBatchOffsets, s.pMesh[i].sBoneBatches.pnBatchOffset,s.pMesh[i].sBoneBatches.nBatchCnt)) return false; 1056 if(!WriteData32(pFile, ePODFileMeshUnpackMatrix, s.pMesh[i].mUnpackMatrix.f, 16)) return false; 1057 1058 if(!WriteCPODData(pFile, ePODFileMeshFaces, s.pMesh[i].sFaces, PVRTModelPODCountIndices(s.pMesh[i]), true)) return false; 1059 if(!WriteCPODData(pFile, ePODFileMeshVtx, s.pMesh[i].sVertex, s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1060 if(!WriteCPODData(pFile, ePODFileMeshNor, s.pMesh[i].sNormals, s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1061 if(!WriteCPODData(pFile, ePODFileMeshTan, s.pMesh[i].sTangents, s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1062 if(!WriteCPODData(pFile, ePODFileMeshBin, s.pMesh[i].sBinormals, s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1063 1064 for(j = 0; j < s.pMesh[i].nNumUVW; ++j) 1065 if(!WriteCPODData(pFile, ePODFileMeshUVW, s.pMesh[i].psUVW[j], s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1066 1067 if(!WriteCPODData(pFile, ePODFileMeshVtxCol, s.pMesh[i].sVtxColours, s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1068 if(!WriteCPODData(pFile, ePODFileMeshBoneIdx, s.pMesh[i].sBoneIdx, s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1069 if(!WriteCPODData(pFile, ePODFileMeshBoneWeight, s.pMesh[i].sBoneWeight, s.pMesh[i].nNumVertex, s.pMesh[i].pInterleaved == 0)) return false; 1070 1071 if(!WriteMarker(pFile, ePODFileMesh, true)) return false; 1072 } 1073 1074 int iTransformationNo; 1075 // Save: node 1076 for(i = 0; i < s.nNumNode; ++i) 1077 { 1078 if(!WriteMarker(pFile, ePODFileNode, false)) return false; 1079 1080 { 1081 if(!WriteData32(pFile, ePODFileNodeIdx, &s.pNode[i].nIdx)) return false; 1082 if(!WriteData(pFile, ePODFileNodeName, s.pNode[i].pszName, (unsigned int)strlen(s.pNode[i].pszName)+1)) return false; 1083 if(!WriteData32(pFile, ePODFileNodeIdxMat, &s.pNode[i].nIdxMaterial)) return false; 1084 if(!WriteData32(pFile, ePODFileNodeIdxParent, &s.pNode[i].nIdxParent)) return false; 1085 if(!WriteData32(pFile, ePODFileNodeAnimFlags, &s.pNode[i].nAnimFlags)) return false; 1086 1087 if(s.pNode[i].pnAnimPositionIdx) 1088 { 1089 if(!WriteData32(pFile, ePODFileNodeAnimPosIdx, s.pNode[i].pnAnimPositionIdx, s.nNumFrame)) return false; 1090 } 1091 1092 iTransformationNo = s.pNode[i].nAnimFlags & ePODHasPositionAni ? PVRTModelPODGetAnimArraySize(s.pNode[i].pnAnimPositionIdx, s.nNumFrame, 3) : 3; 1093 if(!WriteData32(pFile, ePODFileNodeAnimPos, s.pNode[i].pfAnimPosition, iTransformationNo)) return false; 1094 1095 if(s.pNode[i].pnAnimRotationIdx) 1096 { 1097 if(!WriteData32(pFile, ePODFileNodeAnimRotIdx, s.pNode[i].pnAnimRotationIdx, s.nNumFrame)) return false; 1098 } 1099 1100 iTransformationNo = s.pNode[i].nAnimFlags & ePODHasRotationAni ? PVRTModelPODGetAnimArraySize(s.pNode[i].pnAnimRotationIdx, s.nNumFrame, 4) : 4; 1101 if(!WriteData32(pFile, ePODFileNodeAnimRot, s.pNode[i].pfAnimRotation, iTransformationNo)) return false; 1102 1103 if(s.pNode[i].pnAnimScaleIdx) 1104 { 1105 if(!WriteData32(pFile, ePODFileNodeAnimScaleIdx, s.pNode[i].pnAnimScaleIdx, s.nNumFrame)) return false; 1106 } 1107 1108 iTransformationNo = s.pNode[i].nAnimFlags & ePODHasScaleAni ? PVRTModelPODGetAnimArraySize(s.pNode[i].pnAnimScaleIdx, s.nNumFrame, 7) : 7; 1109 if(!WriteData32(pFile, ePODFileNodeAnimScale, s.pNode[i].pfAnimScale, iTransformationNo)) return false; 1110 1111 if(s.pNode[i].pnAnimMatrixIdx) 1112 { 1113 if(!WriteData32(pFile, ePODFileNodeAnimMatrixIdx, s.pNode[i].pnAnimMatrixIdx, s.nNumFrame)) return false; 1114 } 1115 1116 iTransformationNo = s.pNode[i].nAnimFlags & ePODHasMatrixAni ? PVRTModelPODGetAnimArraySize(s.pNode[i].pnAnimMatrixIdx, s.nNumFrame, 16) : 16; 1117 if(!WriteData32(pFile, ePODFileNodeAnimMatrix,s.pNode[i].pfAnimMatrix, iTransformationNo)) return false; 1118 1119 if(!WriteData(pFile, ePODFileNodeUserData, s.pNode[i].pUserData, s.pNode[i].nUserDataSize)) return false; 1120 } 1121 1122 if(!WriteMarker(pFile, ePODFileNode, true)) return false; 1123 } 1124 1125 // Save: texture 1126 for(i = 0; i < s.nNumTexture; ++i) 1127 { 1128 if(!WriteMarker(pFile, ePODFileTexture, false)) return false; 1129 if(!WriteData(pFile, ePODFileTexName, s.pTexture[i].pszName, (unsigned int)strlen(s.pTexture[i].pszName)+1)) return false; 1130 if(!WriteMarker(pFile, ePODFileTexture, true)) return false; 1131 } 1132 } 1133 if(!WriteMarker(pFile, ePODFileScene, true)) return false; 1134 1135 return true; 1136 } 1137 1138 /**************************************************************************** 1139 ** Local code: File reading 1140 ****************************************************************************/ 1141 /*!*************************************************************************** 1142 @Function ReadCPODData 1143 @Modified s The CPODData to read into 1144 @Input src CSource object to read data from. 1145 @Input nSpec 1146 @Input bValidData 1147 @Return true if successful 1148 @Description Read a CPODData block in from a pod file 1149 *****************************************************************************/ 1150 static bool ReadCPODData( 1151 CPODData &s, 1152 CSource &src, 1153 const unsigned int nSpec, 1154 const bool bValidData) 1155 { 1156 unsigned int nName, nLen, nBuff; 1157 1158 while(src.ReadMarker(nName, nLen)) 1159 { 1160 if(nName == (nSpec | PVRTMODELPOD_TAG_END)) 1161 return true; 1162 1163 switch(nName) 1164 { 1165 case ePODFileDataType: if(!src.Read32(s.eType)) return false; break; 1166 case ePODFileN: if(!src.Read32(s.n)) return false; break; 1167 case ePODFileStride: if(!src.Read32(s.nStride)) return false; break; 1168 case ePODFileData: 1169 if(bValidData) 1170 { 1171 switch(PVRTModelPODDataTypeSize(s.eType)) 1172 { 1173 case 1: if(!src.ReadAfterAlloc(s.pData, nLen)) return false; break; 1174 case 2: 1175 { // reading 16bit data but have 8bit pointer 1176 PVRTuint16 *p16Pointer=NULL; 1177 if(!src.ReadAfterAlloc16(p16Pointer, nLen)) return false; 1178 s.pData = (unsigned char*)p16Pointer; 1179 break; 1180 } 1181 case 4: 1182 { // reading 32bit data but have 8bit pointer 1183 PVRTuint32 *p32Pointer=NULL; 1184 if(!src.ReadAfterAlloc32(p32Pointer, nLen)) return false; 1185 s.pData = (unsigned char*)p32Pointer; 1186 break; 1187 } 1188 default: 1189 { _ASSERT(false);} 1190 } 1191 } 1192 else 1193 { 1194 if(src.Read32(nBuff)) 1195 { 1196 s.pData = (unsigned char*) (size_t) nBuff; 1197 } 1198 else 1199 { 1200 return false; 1201 } 1202 } 1203 break; 1204 1205 default: 1206 if(!src.Skip(nLen)) return false; 1207 } 1208 } 1209 return false; 1210 } 1211 1212 /*!*************************************************************************** 1213 @Function ReadCamera 1214 @Modified s The SPODCamera to read into 1215 @Input src CSource object to read data from. 1216 @Return true if successful 1217 @Description Read a camera block in from a pod file 1218 *****************************************************************************/ 1219 static bool ReadCamera( 1220 SPODCamera &s, 1221 CSource &src) 1222 { 1223 unsigned int nName, nLen; 1224 s.pfAnimFOV = 0; 1225 1226 while(src.ReadMarker(nName, nLen)) 1227 { 1228 switch(nName) 1229 { 1230 case ePODFileCamera | PVRTMODELPOD_TAG_END: return true; 1231 1232 case ePODFileCamIdxTgt: if(!src.Read32(s.nIdxTarget)) return false; break; 1233 case ePODFileCamFOV: if(!src.Read32(s.fFOV)) return false; break; 1234 case ePODFileCamFar: if(!src.Read32(s.fFar)) return false; break; 1235 case ePODFileCamNear: if(!src.Read32(s.fNear)) return false; break; 1236 case ePODFileCamAnimFOV: if(!src.ReadAfterAlloc32(s.pfAnimFOV, nLen)) return false; break; 1237 1238 default: 1239 if(!src.Skip(nLen)) return false; 1240 } 1241 } 1242 return false; 1243 } 1244 1245 /*!*************************************************************************** 1246 @Function ReadLight 1247 @Modified s The SPODLight to read into 1248 @Input src CSource object to read data from. 1249 @Return true if successful 1250 @Description Read a light block in from a pod file 1251 *****************************************************************************/ 1252 static bool ReadLight( 1253 SPODLight &s, 1254 CSource &src) 1255 { 1256 unsigned int nName, nLen; 1257 1258 while(src.ReadMarker(nName, nLen)) 1259 { 1260 switch(nName) 1261 { 1262 case ePODFileLight | PVRTMODELPOD_TAG_END: return true; 1263 1264 case ePODFileLightIdxTgt: if(!src.Read32(s.nIdxTarget)) return false; break; 1265 case ePODFileLightColour: if(!src.ReadArray32(s.pfColour, 3)) return false; break; 1266 case ePODFileLightType: if(!src.Read32(s.eType)) return false; break; 1267 case ePODFileLightConstantAttenuation: if(!src.Read32(s.fConstantAttenuation)) return false; break; 1268 case ePODFileLightLinearAttenuation: if(!src.Read32(s.fLinearAttenuation)) return false; break; 1269 case ePODFileLightQuadraticAttenuation: if(!src.Read32(s.fQuadraticAttenuation)) return false; break; 1270 case ePODFileLightFalloffAngle: if(!src.Read32(s.fFalloffAngle)) return false; break; 1271 case ePODFileLightFalloffExponent: if(!src.Read32(s.fFalloffExponent)) return false; break; 1272 default: 1273 if(!src.Skip(nLen)) return false; 1274 } 1275 } 1276 return false; 1277 } 1278 1279 /*!*************************************************************************** 1280 @Function ReadMaterial 1281 @Modified s The SPODMaterial to read into 1282 @Input src CSource object to read data from. 1283 @Return true if successful 1284 @Description Read a material block in from a pod file 1285 *****************************************************************************/ 1286 static bool ReadMaterial( 1287 SPODMaterial &s, 1288 CSource &src) 1289 { 1290 unsigned int nName, nLen; 1291 1292 // Set texture IDs to -1 1293 s.nIdxTexDiffuse = -1; 1294 s.nIdxTexAmbient = -1; 1295 s.nIdxTexSpecularColour = -1; 1296 s.nIdxTexSpecularLevel = -1; 1297 s.nIdxTexBump = -1; 1298 s.nIdxTexEmissive = -1; 1299 s.nIdxTexGlossiness = -1; 1300 s.nIdxTexOpacity = -1; 1301 s.nIdxTexReflection = -1; 1302 s.nIdxTexRefraction = -1; 1303 1304 // Set defaults for blend modes 1305 s.eBlendSrcRGB = s.eBlendSrcA = ePODBlendFunc_ONE; 1306 s.eBlendDstRGB = s.eBlendDstA = ePODBlendFunc_ZERO; 1307 s.eBlendOpRGB = s.eBlendOpA = ePODBlendOp_ADD; 1308 1309 memset(s.pfBlendColour, 0, sizeof(s.pfBlendColour)); 1310 memset(s.pfBlendFactor, 0, sizeof(s.pfBlendFactor)); 1311 1312 // Set default for material flags 1313 s.nFlags = 0; 1314 1315 // Set default for user data 1316 s.pUserData = 0; 1317 s.nUserDataSize = 0; 1318 1319 while(src.ReadMarker(nName, nLen)) 1320 { 1321 switch(nName) 1322 { 1323 case ePODFileMaterial | PVRTMODELPOD_TAG_END: return true; 1324 1325 case ePODFileMatFlags: if(!src.Read32(s.nFlags)) return false; break; 1326 case ePODFileMatName: if(!src.ReadAfterAlloc(s.pszName, nLen)) return false; break; 1327 case ePODFileMatIdxTexDiffuse: if(!src.Read32(s.nIdxTexDiffuse)) return false; break; 1328 case ePODFileMatIdxTexAmbient: if(!src.Read32(s.nIdxTexAmbient)) return false; break; 1329 case ePODFileMatIdxTexSpecularColour: if(!src.Read32(s.nIdxTexSpecularColour)) return false; break; 1330 case ePODFileMatIdxTexSpecularLevel: if(!src.Read32(s.nIdxTexSpecularLevel)) return false; break; 1331 case ePODFileMatIdxTexBump: if(!src.Read32(s.nIdxTexBump)) return false; break; 1332 case ePODFileMatIdxTexEmissive: if(!src.Read32(s.nIdxTexEmissive)) return false; break; 1333 case ePODFileMatIdxTexGlossiness: if(!src.Read32(s.nIdxTexGlossiness)) return false; break; 1334 case ePODFileMatIdxTexOpacity: if(!src.Read32(s.nIdxTexOpacity)) return false; break; 1335 case ePODFileMatIdxTexReflection: if(!src.Read32(s.nIdxTexReflection)) return false; break; 1336 case ePODFileMatIdxTexRefraction: if(!src.Read32(s.nIdxTexRefraction)) return false; break; 1337 case ePODFileMatOpacity: if(!src.Read32(s.fMatOpacity)) return false; break; 1338 case ePODFileMatAmbient: if(!src.ReadArray32(s.pfMatAmbient, sizeof(s.pfMatAmbient) / sizeof(*s.pfMatAmbient))) return false; break; 1339 case ePODFileMatDiffuse: if(!src.ReadArray32(s.pfMatDiffuse, sizeof(s.pfMatDiffuse) / sizeof(*s.pfMatDiffuse))) return false; break; 1340 case ePODFileMatSpecular: if(!src.ReadArray32(s.pfMatSpecular, sizeof(s.pfMatSpecular) / sizeof(*s.pfMatSpecular))) return false; break; 1341 case ePODFileMatShininess: if(!src.Read32(s.fMatShininess)) return false; break; 1342 case ePODFileMatEffectFile: if(!src.ReadAfterAlloc(s.pszEffectFile, nLen)) return false; break; 1343 case ePODFileMatEffectName: if(!src.ReadAfterAlloc(s.pszEffectName, nLen)) return false; break; 1344 case ePODFileMatBlendSrcRGB: if(!src.Read32(s.eBlendSrcRGB)) return false; break; 1345 case ePODFileMatBlendSrcA: if(!src.Read32(s.eBlendSrcA)) return false; break; 1346 case ePODFileMatBlendDstRGB: if(!src.Read32(s.eBlendDstRGB)) return false; break; 1347 case ePODFileMatBlendDstA: if(!src.Read32(s.eBlendDstA)) return false; break; 1348 case ePODFileMatBlendOpRGB: if(!src.Read32(s.eBlendOpRGB)) return false; break; 1349 case ePODFileMatBlendOpA: if(!src.Read32(s.eBlendOpA)) return false; break; 1350 case ePODFileMatBlendColour: if(!src.ReadArray32(s.pfBlendColour, sizeof(s.pfBlendColour) / sizeof(*s.pfBlendColour))) return false; break; 1351 case ePODFileMatBlendFactor: if(!src.ReadArray32(s.pfBlendFactor, sizeof(s.pfBlendFactor) / sizeof(*s.pfBlendFactor))) return false; break; 1352 1353 case ePODFileMatUserData: 1354 if(!src.ReadAfterAlloc(s.pUserData, nLen)) 1355 return false; 1356 else 1357 { 1358 s.nUserDataSize = nLen; 1359 break; 1360 } 1361 1362 default: 1363 if(!src.Skip(nLen)) return false; 1364 } 1365 } 1366 return false; 1367 } 1368 1369 /*!*************************************************************************** 1370 @Function PVRTFixInterleavedEndiannessUsingCPODData 1371 @Modified pInterleaved - The interleaved data 1372 @Input data - The CPODData. 1373 @Return ui32Size - Number of elements in pInterleaved 1374 @Description Called multiple times and goes through the interleaved data 1375 correcting the endianness. 1376 *****************************************************************************/ 1377 static void PVRTFixInterleavedEndiannessUsingCPODData(unsigned char* pInterleaved, CPODData &data, unsigned int ui32Size) 1378 { 1379 if(!data.n) 1380 return; 1381 1382 size_t ui32TypeSize = PVRTModelPODDataTypeSize(data.eType); 1383 1384 unsigned char ub[4]; 1385 unsigned char *pData = pInterleaved + (size_t) data.pData; 1386 1387 switch(ui32TypeSize) 1388 { 1389 case 1: return; 1390 case 2: 1391 { 1392 for(unsigned int i = 0; i < ui32Size; ++i) 1393 { 1394 for(unsigned int j = 0; j < data.n; ++j) 1395 { 1396 ub[0] = pData[ui32TypeSize * j + 0]; 1397 ub[1] = pData[ui32TypeSize * j + 1]; 1398 1399 ((unsigned short*) pData)[j] = (unsigned short) ((ub[1] << 8) | ub[0]); 1400 } 1401 1402 pData += data.nStride; 1403 } 1404 } 1405 break; 1406 case 4: 1407 { 1408 for(unsigned int i = 0; i < ui32Size; ++i) 1409 { 1410 for(unsigned int j = 0; j < data.n; ++j) 1411 { 1412 ub[0] = pData[ui32TypeSize * j + 0]; 1413 ub[1] = pData[ui32TypeSize * j + 1]; 1414 ub[2] = pData[ui32TypeSize * j + 2]; 1415 ub[3] = pData[ui32TypeSize * j + 3]; 1416 1417 ((unsigned int*) pData)[j] = (unsigned int) ((ub[3] << 24) | (ub[2] << 16) | (ub[1] << 8) | ub[0]); 1418 } 1419 1420 pData += data.nStride; 1421 } 1422 } 1423 break; 1424 default: { _ASSERT(false); } 1425 }; 1426 } 1427 1428 static void PVRTFixInterleavedEndianness(SPODMesh &s) 1429 { 1430 if(!s.pInterleaved || PVRTIsLittleEndian()) 1431 return; 1432 1433 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.sVertex, s.nNumVertex); 1434 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.sNormals, s.nNumVertex); 1435 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.sTangents, s.nNumVertex); 1436 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.sBinormals, s.nNumVertex); 1437 1438 for(unsigned int i = 0; i < s.nNumUVW; ++i) 1439 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.psUVW[i], s.nNumVertex); 1440 1441 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.sVtxColours, s.nNumVertex); 1442 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.sBoneIdx, s.nNumVertex); 1443 PVRTFixInterleavedEndiannessUsingCPODData(s.pInterleaved, s.sBoneWeight, s.nNumVertex); 1444 } 1445 1446 /*!*************************************************************************** 1447 @Function ReadMesh 1448 @Modified s The SPODMesh to read into 1449 @Input src CSource object to read data from. 1450 @Return true if successful 1451 @Description Read a mesh block in from a pod file 1452 *****************************************************************************/ 1453 static bool ReadMesh( 1454 SPODMesh &s, 1455 CSource &src) 1456 { 1457 unsigned int nName, nLen; 1458 unsigned int nUVWs=0; 1459 1460 PVRTMatrixIdentity(s.mUnpackMatrix); 1461 1462 while(src.ReadMarker(nName, nLen)) 1463 { 1464 switch(nName) 1465 { 1466 case ePODFileMesh | PVRTMODELPOD_TAG_END: 1467 if(nUVWs != s.nNumUVW) 1468 return false; 1469 PVRTFixInterleavedEndianness(s); 1470 return true; 1471 1472 case ePODFileMeshNumVtx: if(!src.Read32(s.nNumVertex)) return false; break; 1473 case ePODFileMeshNumFaces: if(!src.Read32(s.nNumFaces)) return false; break; 1474 case ePODFileMeshNumUVW: if(!src.Read32(s.nNumUVW)) return false; if(!SafeAlloc(s.psUVW, s.nNumUVW)) return false; break; 1475 case ePODFileMeshStripLength: if(!src.ReadAfterAlloc32(s.pnStripLength, nLen)) return false; break; 1476 case ePODFileMeshNumStrips: if(!src.Read32(s.nNumStrips)) return false; break; 1477 case ePODFileMeshInterleaved: if(!src.ReadAfterAlloc(s.pInterleaved, nLen)) return false; break; 1478 case ePODFileMeshBoneBatches: if(!src.ReadAfterAlloc32(s.sBoneBatches.pnBatches, nLen)) return false; break; 1479 case ePODFileMeshBoneBatchBoneCnts: if(!src.ReadAfterAlloc32(s.sBoneBatches.pnBatchBoneCnt, nLen)) return false; break; 1480 case ePODFileMeshBoneBatchOffsets: if(!src.ReadAfterAlloc32(s.sBoneBatches.pnBatchOffset, nLen)) return false; break; 1481 case ePODFileMeshBoneBatchBoneMax: if(!src.Read32(s.sBoneBatches.nBatchBoneMax)) return false; break; 1482 case ePODFileMeshBoneBatchCnt: if(!src.Read32(s.sBoneBatches.nBatchCnt)) return false; break; 1483 case ePODFileMeshUnpackMatrix: if(!src.ReadArray32(&s.mUnpackMatrix.f[0], 16)) return false; break; 1484 1485 case ePODFileMeshFaces: if(!ReadCPODData(s.sFaces, src, ePODFileMeshFaces, true)) return false; break; 1486 case ePODFileMeshVtx: if(!ReadCPODData(s.sVertex, src, ePODFileMeshVtx, s.pInterleaved == 0)) return false; break; 1487 case ePODFileMeshNor: if(!ReadCPODData(s.sNormals, src, ePODFileMeshNor, s.pInterleaved == 0)) return false; break; 1488 case ePODFileMeshTan: if(!ReadCPODData(s.sTangents, src, ePODFileMeshTan, s.pInterleaved == 0)) return false; break; 1489 case ePODFileMeshBin: if(!ReadCPODData(s.sBinormals, src, ePODFileMeshBin, s.pInterleaved == 0)) return false; break; 1490 case ePODFileMeshUVW: if(!ReadCPODData(s.psUVW[nUVWs++], src, ePODFileMeshUVW, s.pInterleaved == 0)) return false; break; 1491 case ePODFileMeshVtxCol: if(!ReadCPODData(s.sVtxColours, src, ePODFileMeshVtxCol, s.pInterleaved == 0)) return false; break; 1492 case ePODFileMeshBoneIdx: if(!ReadCPODData(s.sBoneIdx, src, ePODFileMeshBoneIdx, s.pInterleaved == 0)) return false; break; 1493 case ePODFileMeshBoneWeight: if(!ReadCPODData(s.sBoneWeight, src, ePODFileMeshBoneWeight, s.pInterleaved == 0)) return false; break; 1494 1495 default: 1496 if(!src.Skip(nLen)) return false; 1497 } 1498 } 1499 return false; 1500 } 1501 1502 /*!*************************************************************************** 1503 @Function ReadNode 1504 @Modified s The SPODNode to read into 1505 @Input src CSource object to read data from. 1506 @Return true if successful 1507 @Description Read a node block in from a pod file 1508 *****************************************************************************/ 1509 static bool ReadNode( 1510 SPODNode &s, 1511 CSource &src) 1512 { 1513 unsigned int nName, nLen; 1514 bool bOldNodeFormat = false; 1515 VERTTYPE fPos[3] = {0,0,0}; 1516 VERTTYPE fQuat[4] = {0,0,0,f2vt(1)}; 1517 VERTTYPE fScale[7] = {f2vt(1),f2vt(1),f2vt(1),0,0,0,0}; 1518 1519 // Set default for user data 1520 s.pUserData = 0; 1521 s.nUserDataSize = 0; 1522 1523 while(src.ReadMarker(nName, nLen)) 1524 { 1525 switch(nName) 1526 { 1527 case ePODFileNode | PVRTMODELPOD_TAG_END: 1528 if(bOldNodeFormat) 1529 { 1530 if(s.pfAnimPosition) 1531 s.nAnimFlags |= ePODHasPositionAni; 1532 else 1533 { 1534 s.pfAnimPosition = (VERTTYPE*) malloc(sizeof(fPos)); 1535 memcpy(s.pfAnimPosition, fPos, sizeof(fPos)); 1536 } 1537 1538 if(s.pfAnimRotation) 1539 s.nAnimFlags |= ePODHasRotationAni; 1540 else 1541 { 1542 s.pfAnimRotation = (VERTTYPE*) malloc(sizeof(fQuat)); 1543 memcpy(s.pfAnimRotation, fQuat, sizeof(fQuat)); 1544 } 1545 1546 if(s.pfAnimScale) 1547 s.nAnimFlags |= ePODHasScaleAni; 1548 else 1549 { 1550 s.pfAnimScale = (VERTTYPE*) malloc(sizeof(fScale)); 1551 memcpy(s.pfAnimScale, fScale, sizeof(fScale)); 1552 } 1553 } 1554 return true; 1555 1556 case ePODFileNodeIdx: if(!src.Read32(s.nIdx)) return false; break; 1557 case ePODFileNodeName: if(!src.ReadAfterAlloc(s.pszName, nLen)) return false; break; 1558 case ePODFileNodeIdxMat: if(!src.Read32(s.nIdxMaterial)) return false; break; 1559 case ePODFileNodeIdxParent: if(!src.Read32(s.nIdxParent)) return false; break; 1560 case ePODFileNodeAnimFlags:if(!src.Read32(s.nAnimFlags))return false; break; 1561 1562 case ePODFileNodeAnimPosIdx: if(!src.ReadAfterAlloc32(s.pnAnimPositionIdx, nLen)) return false; break; 1563 case ePODFileNodeAnimPos: if(!src.ReadAfterAlloc32(s.pfAnimPosition, nLen)) return false; break; 1564 1565 case ePODFileNodeAnimRotIdx: if(!src.ReadAfterAlloc32(s.pnAnimRotationIdx, nLen)) return false; break; 1566 case ePODFileNodeAnimRot: if(!src.ReadAfterAlloc32(s.pfAnimRotation, nLen)) return false; break; 1567 1568 case ePODFileNodeAnimScaleIdx: if(!src.ReadAfterAlloc32(s.pnAnimScaleIdx, nLen)) return false; break; 1569 case ePODFileNodeAnimScale: if(!src.ReadAfterAlloc32(s.pfAnimScale, nLen)) return false; break; 1570 1571 case ePODFileNodeAnimMatrixIdx: if(!src.ReadAfterAlloc32(s.pnAnimMatrixIdx, nLen)) return false; break; 1572 case ePODFileNodeAnimMatrix:if(!src.ReadAfterAlloc32(s.pfAnimMatrix, nLen)) return false; break; 1573 1574 case ePODFileNodeUserData: 1575 if(!src.ReadAfterAlloc(s.pUserData, nLen)) 1576 return false; 1577 else 1578 { 1579 s.nUserDataSize = nLen; 1580 break; 1581 } 1582 1583 // Parameters from the older pod format 1584 case ePODFileNodePos: if(!src.ReadArray32(&fPos[0], 3)) return false; bOldNodeFormat = true; break; 1585 case ePODFileNodeRot: if(!src.ReadArray32(&fQuat[0], 4)) return false; bOldNodeFormat = true; break; 1586 case ePODFileNodeScale: if(!src.ReadArray32(&fScale[0], 3)) return false; bOldNodeFormat = true; break; 1587 1588 default: 1589 if(!src.Skip(nLen)) return false; 1590 } 1591 } 1592 1593 return false; 1594 } 1595 1596 /*!*************************************************************************** 1597 @Function ReadTexture 1598 @Modified s The SPODTexture to read into 1599 @Input src CSource object to read data from. 1600 @Return true if successful 1601 @Description Read a texture block in from a pod file 1602 *****************************************************************************/ 1603 static bool ReadTexture( 1604 SPODTexture &s, 1605 CSource &src) 1606 { 1607 unsigned int nName, nLen; 1608 1609 while(src.ReadMarker(nName, nLen)) 1610 { 1611 switch(nName) 1612 { 1613 case ePODFileTexture | PVRTMODELPOD_TAG_END: return true; 1614 1615 case ePODFileTexName: if(!src.ReadAfterAlloc(s.pszName, nLen)) return false; break; 1616 1617 default: 1618 if(!src.Skip(nLen)) return false; 1619 } 1620 } 1621 return false; 1622 } 1623 1624 /*!*************************************************************************** 1625 @Function ReadScene 1626 @Modified s The SPODScene to read into 1627 @Input src CSource object to read data from. 1628 @Return true if successful 1629 @Description Read a scene block in from a pod file 1630 *****************************************************************************/ 1631 static bool ReadScene( 1632 SPODScene &s, 1633 CSource &src) 1634 { 1635 unsigned int nName, nLen; 1636 unsigned int nCameras=0, nLights=0, nMaterials=0, nMeshes=0, nTextures=0, nNodes=0; 1637 s.nFPS = 30; 1638 s.fUnits = 1.0f; 1639 1640 // Set default for user data 1641 s.pUserData = 0; 1642 s.nUserDataSize = 0; 1643 1644 while(src.ReadMarker(nName, nLen)) 1645 { 1646 switch(nName) 1647 { 1648 case ePODFileScene | PVRTMODELPOD_TAG_END: 1649 if(nCameras != s.nNumCamera) return false; 1650 if(nLights != s.nNumLight) return false; 1651 if(nMaterials != s.nNumMaterial) return false; 1652 if(nMeshes != s.nNumMesh) return false; 1653 if(nTextures != s.nNumTexture) return false; 1654 if(nNodes != s.nNumNode) return false; 1655 return true; 1656 1657 case ePODFileUnits: if(!src.Read32(s.fUnits)) return false; break; 1658 case ePODFileColourBackground: if(!src.ReadArray32(&s.pfColourBackground[0], sizeof(s.pfColourBackground) / sizeof(*s.pfColourBackground))) return false; break; 1659 case ePODFileColourAmbient: if(!src.ReadArray32(&s.pfColourAmbient[0], sizeof(s.pfColourAmbient) / sizeof(*s.pfColourAmbient))) return false; break; 1660 case ePODFileNumCamera: if(!src.Read32(s.nNumCamera)) return false; if(!SafeAlloc(s.pCamera, s.nNumCamera)) return false; break; 1661 case ePODFileNumLight: if(!src.Read32(s.nNumLight)) return false; if(!SafeAlloc(s.pLight, s.nNumLight)) return false; break; 1662 case ePODFileNumMesh: if(!src.Read32(s.nNumMesh)) return false; if(!SafeAlloc(s.pMesh, s.nNumMesh)) return false; break; 1663 case ePODFileNumNode: if(!src.Read32(s.nNumNode)) return false; if(!SafeAlloc(s.pNode, s.nNumNode)) return false; break; 1664 case ePODFileNumMeshNode: if(!src.Read32(s.nNumMeshNode)) return false; break; 1665 case ePODFileNumTexture: if(!src.Read32(s.nNumTexture)) return false; if(!SafeAlloc(s.pTexture, s.nNumTexture)) return false; break; 1666 case ePODFileNumMaterial: if(!src.Read32(s.nNumMaterial)) return false; if(!SafeAlloc(s.pMaterial, s.nNumMaterial)) return false; break; 1667 case ePODFileNumFrame: if(!src.Read32(s.nNumFrame)) return false; break; 1668 case ePODFileFPS: if(!src.Read32(s.nFPS)) return false; break; 1669 case ePODFileFlags: if(!src.Read32(s.nFlags)) return false; break; 1670 1671 case ePODFileCamera: if(!ReadCamera(s.pCamera[nCameras++], src)) return false; break; 1672 case ePODFileLight: if(!ReadLight(s.pLight[nLights++], src)) return false; break; 1673 case ePODFileMaterial: if(!ReadMaterial(s.pMaterial[nMaterials++], src)) return false; break; 1674 case ePODFileMesh: if(!ReadMesh(s.pMesh[nMeshes++], src)) return false; break; 1675 case ePODFileNode: if(!ReadNode(s.pNode[nNodes++], src)) return false; break; 1676 case ePODFileTexture: if(!ReadTexture(s.pTexture[nTextures++], src)) return false; break; 1677 1678 case ePODFileUserData: 1679 if(!src.ReadAfterAlloc(s.pUserData, nLen)) 1680 return false; 1681 else 1682 { 1683 s.nUserDataSize = nLen; 1684 break; 1685 } 1686 1687 default: 1688 if(!src.Skip(nLen)) return false; 1689 } 1690 } 1691 return false; 1692 } 1693 1694 /*!*************************************************************************** 1695 @Function Read 1696 @Output pS SPODScene data. May be NULL. 1697 @Input src CSource object to read data from. 1698 @Output pszExpOpt Export options. 1699 @Input count Data size. 1700 @Output pszHistory Export history. 1701 @Input historyCount History data size. 1702 @Description Loads the specified ".POD" file; returns the scene in 1703 pScene. This structure must later be destroyed with 1704 PVRTModelPODDestroy() to prevent memory leaks. 1705 ".POD" files are exported from 3D Studio MAX using a 1706 PowerVR plugin. pS may be NULL if only the export options 1707 are required. 1708 *****************************************************************************/ 1709 static bool Read( 1710 SPODScene * const pS, 1711 CSource &src, 1712 char * const pszExpOpt, 1713 const size_t count, 1714 char * const pszHistory, 1715 const size_t historyCount) 1716 { 1717 unsigned int nName, nLen; 1718 bool bVersionOK = false, bDone = false; 1719 bool bNeedOptions = pszExpOpt != 0; 1720 bool bNeedHistory = pszHistory != 0; 1721 bool bLoadingOptionsOrHistory = bNeedOptions || bNeedHistory; 1722 1723 while(src.ReadMarker(nName, nLen)) 1724 { 1725 switch(nName) 1726 { 1727 case ePODFileVersion: 1728 { 1729 char *pszVersion = NULL; 1730 if(nLen != strlen(PVRTMODELPOD_VERSION)+1) return false; 1731 if(!SafeAlloc(pszVersion, nLen)) return false; 1732 if(!src.Read(pszVersion, nLen)) return false; 1733 if(strcmp(pszVersion, PVRTMODELPOD_VERSION) != 0) return false; 1734 bVersionOK = true; 1735 FREE(pszVersion); 1736 } 1737 continue; 1738 1739 case ePODFileScene: 1740 if(pS) 1741 { 1742 if(!ReadScene(*pS, src)) 1743 return false; 1744 bDone = true; 1745 } 1746 continue; 1747 1748 case ePODFileExpOpt: 1749 if(bNeedOptions) 1750 { 1751 if(!src.Read(pszExpOpt, PVRT_MIN(nLen, (unsigned int) count))) 1752 return false; 1753 1754 bNeedOptions = false; 1755 1756 if(count < nLen) 1757 nLen -= (unsigned int) count ; // Adjust nLen as the read has moved our position 1758 else 1759 nLen = 0; 1760 } 1761 break; 1762 1763 case ePODFileHistory: 1764 if(bNeedHistory) 1765 { 1766 if(!src.Read(pszHistory, PVRT_MIN(nLen, (unsigned int) historyCount))) 1767 return false; 1768 1769 bNeedHistory = false; 1770 1771 if(count < nLen) 1772 nLen -= (unsigned int) historyCount; // Adjust nLen as the read has moved our position 1773 else 1774 nLen = 0; 1775 } 1776 break; 1777 1778 case ePODFileScene | PVRTMODELPOD_TAG_END: 1779 return bVersionOK == true && bDone == true; 1780 1781 case (unsigned int) ePODFileEndiannessMisMatch: 1782 PVRTErrorOutputDebug("Error: Endianness mismatch between the .pod file and the platform.\n"); 1783 return false; 1784 1785 } 1786 1787 if(bLoadingOptionsOrHistory && !bNeedOptions && !bNeedHistory) 1788 return true; // The options and/or history has been loaded 1789 1790 // Unhandled data, skip it 1791 if(!src.Skip(nLen)) 1792 return false; 1793 } 1794 1795 if(bLoadingOptionsOrHistory) 1796 return true; 1797 1798 if(!pS) 1799 return false; 1800 1801 /* 1802 Convert data to fixed or float point as this build desires 1803 */ 1804 #ifdef PVRT_FIXED_POINT_ENABLE 1805 if(!(pS->nFlags & PVRTMODELPODSF_FIXED)) 1806 { 1807 PVRTErrorOutputDebug("Error: The tools have been compiled with fixed point enabled but the POD file isn't in fixed point format.\n"); 1808 #else 1809 if(pS->nFlags & PVRTMODELPODSF_FIXED) 1810 { 1811 PVRTErrorOutputDebug("Error: The POD file is in fixed point format but the tools haven't been compiled with fixed point enabled.\n"); 1812 #endif 1813 return false; 1814 } 1815 1816 1817 return bVersionOK == true && bDone == true; 1818 } 1819 1820 /*!*************************************************************************** 1821 @Function ReadFromSourceStream 1822 @Output pS CPVRTModelPOD data. May not be NULL. 1823 @Input src CSource object to read data from. 1824 @Output pszExpOpt Export options. 1825 @Input count Data size. 1826 @Output pszHistory Export history. 1827 @Input historyCount History data size. 1828 @Description Loads the ".POD" data from the source stream; returns the scene 1829 in pS. 1830 *****************************************************************************/ 1831 static EPVRTError ReadFromSourceStream( 1832 CPVRTModelPOD * const pS, 1833 CSourceStream &src, 1834 char * const pszExpOpt, 1835 const size_t count, 1836 char * const pszHistory, 1837 const size_t historyCount) 1838 { 1839 memset(pS, 0, sizeof(*pS)); 1840 if(!Read(pszExpOpt || pszHistory ? NULL : pS, src, pszExpOpt, count, pszHistory, historyCount)) 1841 return PVR_FAIL; 1842 1843 if(pS->InitImpl() != PVR_SUCCESS) 1844 return PVR_FAIL; 1845 1846 return PVR_SUCCESS; 1847 } 1848 1849 /**************************************************************************** 1850 ** Class: CPVRTModelPOD 1851 ****************************************************************************/ 1852 1853 /*!*************************************************************************** 1854 @Function ReadFromFile 1855 @Input pszFileName Filename to load 1856 @Output pszExpOpt String in which to place exporter options 1857 @Input count Maximum number of characters to store. 1858 @Output pszHistory String in which to place the pod file history 1859 @Input historyCount Maximum number of characters to store. 1860 @Return PVR_SUCCESS if successful, PVR_FAIL if not 1861 @Description Loads the specified ".POD" file; returns the scene in 1862 pScene. This structure must later be destroyed with 1863 PVRTModelPODDestroy() to prevent memory leaks. 1864 ".POD" files are exported using the PVRGeoPOD exporters. 1865 If pszExpOpt is NULL, the scene is loaded; otherwise the 1866 scene is not loaded and pszExpOpt is filled in. The same 1867 is true for pszHistory. 1868 *****************************************************************************/ 1869 EPVRTError CPVRTModelPOD::ReadFromFile( 1870 const char * const pszFileName, 1871 char * const pszExpOpt, 1872 const size_t count, 1873 char * const pszHistory, 1874 const size_t historyCount) 1875 { 1876 CSourceStream src; 1877 1878 if(!src.Init(pszFileName)) 1879 return PVR_FAIL; 1880 1881 return ReadFromSourceStream(this, src, pszExpOpt, count, pszHistory, historyCount); 1882 } 1883 1884 /*!*************************************************************************** 1885 @Function ReadFromMemory 1886 @Input pData Data to load 1887 @Input i32Size Size of data 1888 @Output pszExpOpt String in which to place exporter options 1889 @Input count Maximum number of characters to store. 1890 @Output pszHistory String in which to place the pod file history 1891 @Input historyCount Maximum number of characters to store. 1892 @Return PVR_SUCCESS if successful, PVR_FAIL if not 1893 @Description Loads the supplied pod data. This data can be exported 1894 directly to a header using one of the pod exporters. 1895 If pszExpOpt is NULL, the scene is loaded; otherwise the 1896 scene is not loaded and pszExpOpt is filled in. The same 1897 is true for pszHistory. 1898 *****************************************************************************/ 1899 EPVRTError CPVRTModelPOD::ReadFromMemory( 1900 const char * pData, 1901 const size_t i32Size, 1902 char * const pszExpOpt, 1903 const size_t count, 1904 char * const pszHistory, 1905 const size_t historyCount) 1906 { 1907 CSourceStream src; 1908 1909 if(!src.Init(pData, i32Size)) 1910 return PVR_FAIL; 1911 1912 return ReadFromSourceStream(this, src, pszExpOpt, count, pszHistory, historyCount); 1913 } 1914 1915 /*!*************************************************************************** 1916 @Function ReadFromMemory 1917 @Input scene Scene data from the header file 1918 @Return PVR_SUCCESS if successful, PVR_FAIL if not 1919 @Description Sets the scene data from the supplied data structure. Use 1920 when loading from .H files. 1921 *****************************************************************************/ 1922 EPVRTError CPVRTModelPOD::ReadFromMemory( 1923 const SPODScene &scene) 1924 { 1925 Destroy(); 1926 1927 memset(this, 0, sizeof(*this)); 1928 1929 *(SPODScene*)this = scene; 1930 1931 if(InitImpl() != PVR_SUCCESS) 1932 return PVR_FAIL; 1933 1934 m_pImpl->bFromMemory = true; 1935 1936 return PVR_SUCCESS; 1937 } 1938 1939 /*!*************************************************************************** 1940 @Function CopyFromMemory 1941 @Input scene Scene data 1942 @Return PVR_SUCCESS if successful, PVR_FAIL if not 1943 @Description Sets the scene data from the supplied data structure. 1944 *****************************************************************************/ 1945 EPVRTError CPVRTModelPOD::CopyFromMemory(const SPODScene &scene) 1946 { 1947 Destroy(); 1948 1949 unsigned int i; 1950 1951 // SPODScene 1952 nNumFrame = scene.nNumFrame; 1953 nFPS = scene.nFPS; 1954 nFlags = scene.nFlags; 1955 fUnits = scene.fUnits; 1956 1957 for(i = 0; i < 3; ++i) 1958 { 1959 pfColourBackground[i] = scene.pfColourBackground[i]; 1960 pfColourAmbient[i] = scene.pfColourAmbient[i]; 1961 } 1962 1963 // Nodes 1964 if(scene.nNumNode && SafeAlloc(pNode, scene.nNumNode)) 1965 { 1966 nNumNode = scene.nNumNode; 1967 nNumMeshNode = scene.nNumMeshNode; 1968 1969 for(i = 0; i < nNumNode; ++i) 1970 PVRTModelPODCopyNode(scene.pNode[i], pNode[i], scene.nNumFrame); 1971 } 1972 1973 // Meshes 1974 if(scene.nNumMesh && SafeAlloc(pMesh, scene.nNumMesh)) 1975 { 1976 nNumMesh = scene.nNumMesh; 1977 1978 for(i = 0; i < nNumMesh; ++i) 1979 PVRTModelPODCopyMesh(scene.pMesh[i], pMesh[i]); 1980 } 1981 1982 // Cameras 1983 if(scene.nNumCamera && SafeAlloc(pCamera, scene.nNumCamera)) 1984 { 1985 nNumCamera = scene.nNumCamera; 1986 1987 for(i = 0; i < nNumCamera; ++i) 1988 PVRTModelPODCopyCamera(scene.pCamera[i], pCamera[i], scene.nNumFrame); 1989 } 1990 1991 // Lights 1992 if(scene.nNumLight && SafeAlloc(pLight, scene.nNumLight)) 1993 { 1994 nNumLight = scene.nNumLight; 1995 1996 for(i = 0; i < nNumLight; ++i) 1997 PVRTModelPODCopyLight(scene.pLight[i], pLight[i]); 1998 } 1999 2000 // Textures 2001 if(scene.nNumTexture && SafeAlloc(pTexture, scene.nNumTexture)) 2002 { 2003 nNumTexture = scene.nNumTexture; 2004 2005 for(i = 0; i < nNumTexture; ++i) 2006 PVRTModelPODCopyTexture(scene.pTexture[i], pTexture[i]); 2007 } 2008 2009 // Materials 2010 if(scene.nNumMaterial && SafeAlloc(pMaterial, scene.nNumMaterial)) 2011 { 2012 nNumMaterial = scene.nNumMaterial; 2013 2014 for(i = 0; i < nNumMaterial; ++i) 2015 PVRTModelPODCopyMaterial(scene.pMaterial[i], pMaterial[i]); 2016 } 2017 2018 if(scene.pUserData && SafeAlloc(pUserData, scene.nUserDataSize)) 2019 { 2020 memcpy(pUserData, scene.pUserData, nUserDataSize); 2021 nUserDataSize = scene.nUserDataSize; 2022 } 2023 2024 if(InitImpl() != PVR_SUCCESS) 2025 return PVR_FAIL; 2026 2027 return PVR_SUCCESS; 2028 } 2029 2030 #if defined(_WIN32) 2031 /*!*************************************************************************** 2032 @Function ReadFromResource 2033 @Input pszName Name of the resource to load from 2034 @Return PVR_SUCCESS if successful, PVR_FAIL if not 2035 @Description Loads the specified ".POD" file; returns the scene in 2036 pScene. This structure must later be destroyed with 2037 PVRTModelPODDestroy() to prevent memory leaks. 2038 ".POD" files are exported from 3D Studio MAX using a 2039 PowerVR plugin. 2040 *****************************************************************************/ 2041 EPVRTError CPVRTModelPOD::ReadFromResource( 2042 const TCHAR * const pszName) 2043 { 2044 CSourceResource src; 2045 2046 if(!src.Init(pszName)) 2047 return PVR_FAIL; 2048 2049 memset(this, 0, sizeof(*this)); 2050 if(!Read(this, src, NULL, 0, NULL, 0)) 2051 return PVR_FAIL; 2052 if(InitImpl() != PVR_SUCCESS) 2053 return PVR_FAIL; 2054 return PVR_SUCCESS; 2055 } 2056 #endif /* WIN32 */ 2057 2058 /*!*********************************************************************** 2059 @Function InitImpl 2060 @Description Used by the Read*() fns to initialise implementation 2061 details. Should also be called by applications which 2062 manually build data in the POD structures for rendering; 2063 in this case call it after the data has been created. 2064 Otherwise, do not call this function. 2065 *************************************************************************/ 2066 EPVRTError CPVRTModelPOD::InitImpl() 2067 { 2068 // Allocate space for implementation data 2069 delete m_pImpl; 2070 m_pImpl = new SPVRTPODImpl; 2071 if(!m_pImpl) 2072 return PVR_FAIL; 2073 2074 // Zero implementation data 2075 memset(m_pImpl, 0, sizeof(*m_pImpl)); 2076 2077 #ifdef _DEBUG 2078 m_pImpl->nWmTotal = 0; 2079 #endif 2080 2081 // Allocate world-matrix cache 2082 m_pImpl->pfCache = new VERTTYPE[nNumNode]; 2083 m_pImpl->pWmCache = new PVRTMATRIX[nNumNode]; 2084 m_pImpl->pWmZeroCache = new PVRTMATRIX[nNumNode]; 2085 FlushCache(); 2086 2087 return PVR_SUCCESS; 2088 } 2089 2090 /*!*********************************************************************** 2091 @Function DestroyImpl 2092 @Description Used to free memory allocated by the implementation. 2093 *************************************************************************/ 2094 void CPVRTModelPOD::DestroyImpl() 2095 { 2096 if(m_pImpl) 2097 { 2098 if(m_pImpl->pfCache) delete [] m_pImpl->pfCache; 2099 if(m_pImpl->pWmCache) delete [] m_pImpl->pWmCache; 2100 if(m_pImpl->pWmZeroCache) delete [] m_pImpl->pWmZeroCache; 2101 2102 delete m_pImpl; 2103 m_pImpl = 0; 2104 } 2105 } 2106 2107 /*!*********************************************************************** 2108 @Function FlushCache 2109 @Description Clears the matrix cache; use this if necessary when you 2110 edit the position or animation of a node. 2111 *************************************************************************/ 2112 void CPVRTModelPOD::FlushCache() 2113 { 2114 // Pre-calc frame zero matrices 2115 SetFrame(0); 2116 for(unsigned int i = 0; i < nNumNode; ++i) 2117 GetWorldMatrixNoCache(m_pImpl->pWmZeroCache[i], pNode[i]); 2118 2119 // Load cache with frame-zero data 2120 memcpy(m_pImpl->pWmCache, m_pImpl->pWmZeroCache, nNumNode * sizeof(*m_pImpl->pWmCache)); 2121 memset(m_pImpl->pfCache, 0, nNumNode * sizeof(*m_pImpl->pfCache)); 2122 } 2123 2124 /*!*********************************************************************** 2125 @Function IsLoaded 2126 @Description Boolean to check whether a POD file has been loaded. 2127 *************************************************************************/ 2128 bool CPVRTModelPOD::IsLoaded() 2129 { 2130 return (m_pImpl!=NULL); 2131 } 2132 2133 /*!*************************************************************************** 2134 @Function Constructor 2135 @Description Initializes the pointer to scene data to NULL 2136 *****************************************************************************/ 2137 CPVRTModelPOD::CPVRTModelPOD() : m_pImpl(NULL) 2138 {} 2139 2140 /*!*************************************************************************** 2141 @Function Destructor 2142 @Description Frees the memory allocated to store the scene in pScene. 2143 *****************************************************************************/ 2144 CPVRTModelPOD::~CPVRTModelPOD() 2145 { 2146 Destroy(); 2147 } 2148 2149 /*!*************************************************************************** 2150 @Function Destroy 2151 @Description Frees the memory allocated to store the scene in pScene. 2152 *****************************************************************************/ 2153 void CPVRTModelPOD::Destroy() 2154 { 2155 unsigned int i; 2156 2157 if(m_pImpl != NULL) 2158 { 2159 /* 2160 Only attempt to free this memory if it was actually allocated at 2161 run-time, as opposed to compiled into the app. 2162 */ 2163 if(!m_pImpl->bFromMemory) 2164 { 2165 2166 for(i = 0; i < nNumCamera; ++i) 2167 FREE(pCamera[i].pfAnimFOV); 2168 FREE(pCamera); 2169 2170 FREE(pLight); 2171 2172 for(i = 0; i < nNumMaterial; ++i) 2173 { 2174 FREE(pMaterial[i].pszName); 2175 FREE(pMaterial[i].pszEffectFile); 2176 FREE(pMaterial[i].pszEffectName); 2177 FREE(pMaterial[i].pUserData); 2178 } 2179 FREE(pMaterial); 2180 2181 for(i = 0; i < nNumMesh; ++i) { 2182 FREE(pMesh[i].sFaces.pData); 2183 FREE(pMesh[i].pnStripLength); 2184 if(pMesh[i].pInterleaved) 2185 { 2186 FREE(pMesh[i].pInterleaved); 2187 } 2188 else 2189 { 2190 FREE(pMesh[i].sVertex.pData); 2191 FREE(pMesh[i].sNormals.pData); 2192 FREE(pMesh[i].sTangents.pData); 2193 FREE(pMesh[i].sBinormals.pData); 2194 for(unsigned int j = 0; j < pMesh[i].nNumUVW; ++j) 2195 FREE(pMesh[i].psUVW[j].pData); 2196 FREE(pMesh[i].sVtxColours.pData); 2197 FREE(pMesh[i].sBoneIdx.pData); 2198 FREE(pMesh[i].sBoneWeight.pData); 2199 } 2200 FREE(pMesh[i].psUVW); 2201 pMesh[i].sBoneBatches.Release(); 2202 } 2203 FREE(pMesh); 2204 2205 for(i = 0; i < nNumNode; ++i) { 2206 FREE(pNode[i].pszName); 2207 FREE(pNode[i].pfAnimPosition); 2208 FREE(pNode[i].pnAnimPositionIdx); 2209 FREE(pNode[i].pfAnimRotation); 2210 FREE(pNode[i].pnAnimRotationIdx); 2211 FREE(pNode[i].pfAnimScale); 2212 FREE(pNode[i].pnAnimScaleIdx); 2213 FREE(pNode[i].pfAnimMatrix); 2214 FREE(pNode[i].pnAnimMatrixIdx); 2215 FREE(pNode[i].pUserData); 2216 pNode[i].nAnimFlags = 0; 2217 } 2218 2219 FREE(pNode); 2220 2221 for(i = 0; i < nNumTexture; ++i) 2222 FREE(pTexture[i].pszName); 2223 FREE(pTexture); 2224 2225 FREE(pUserData); 2226 } 2227 2228 // Free the working space used by the implementation 2229 DestroyImpl(); 2230 } 2231 2232 memset(this, 0, sizeof(*this)); 2233 } 2234 2235 /*!*************************************************************************** 2236 @Function SetFrame 2237 @Input fFrame Frame number 2238 @Description Set the animation frame for which subsequent Get*() calls 2239 should return data. 2240 *****************************************************************************/ 2241 void CPVRTModelPOD::SetFrame(const VERTTYPE fFrame) 2242 { 2243 if(nNumFrame) { 2244 /* 2245 Limit animation frames. 2246 2247 Example: If there are 100 frames of animation, the highest frame 2248 number allowed is 98, since that will blend between frames 98 and 2249 99. (99 being of course the 100th frame.) 2250 */ 2251 _ASSERT(fFrame <= f2vt((float)(nNumFrame-1))); 2252 m_pImpl->nFrame = (int)vt2f(fFrame); 2253 m_pImpl->fBlend = fFrame - f2vt(m_pImpl->nFrame); 2254 } 2255 else 2256 { 2257 m_pImpl->fBlend = 0; 2258 m_pImpl->nFrame = 0; 2259 } 2260 2261 m_pImpl->fFrame = fFrame; 2262 } 2263 2264 /*!*************************************************************************** 2265 @Function GetRotationMatrix 2266 @Output mOut Rotation matrix 2267 @Input node Node to get the rotation matrix from 2268 @Description Generates the world matrix for the given Mesh Instance; 2269 applies the parent's transform too. Uses animation data. 2270 *****************************************************************************/ 2271 void CPVRTModelPOD::GetRotationMatrix( 2272 PVRTMATRIX &mOut, 2273 const SPODNode &node) const 2274 { 2275 PVRTQUATERNION q; 2276 2277 if(node.pfAnimRotation) 2278 { 2279 if(node.nAnimFlags & ePODHasRotationAni) 2280 { 2281 if(node.pnAnimRotationIdx) 2282 { 2283 PVRTMatrixQuaternionSlerp( 2284 q, 2285 (PVRTQUATERNION&)node.pfAnimRotation[node.pnAnimRotationIdx[m_pImpl->nFrame]], 2286 (PVRTQUATERNION&)node.pfAnimRotation[node.pnAnimRotationIdx[m_pImpl->nFrame+1]], m_pImpl->fBlend); 2287 } 2288 else 2289 { 2290 PVRTMatrixQuaternionSlerp( 2291 q, 2292 (PVRTQUATERNION&)node.pfAnimRotation[4*m_pImpl->nFrame], 2293 (PVRTQUATERNION&)node.pfAnimRotation[4*(m_pImpl->nFrame+1)], m_pImpl->fBlend); 2294 } 2295 2296 PVRTMatrixRotationQuaternion(mOut, q); 2297 } 2298 else 2299 { 2300 PVRTMatrixRotationQuaternion(mOut, *(PVRTQUATERNION*)node.pfAnimRotation); 2301 } 2302 } 2303 else 2304 { 2305 PVRTMatrixIdentity(mOut); 2306 } 2307 } 2308 2309 /*!*************************************************************************** 2310 @Function GetRotationMatrix 2311 @Input node Node to get the rotation matrix from 2312 @Returns Rotation matrix 2313 @Description Generates the world matrix for the given Mesh Instance; 2314 applies the parent's transform too. Uses animation data. 2315 *****************************************************************************/ 2316 PVRTMat4 CPVRTModelPOD::GetRotationMatrix(const SPODNode &node) const 2317 { 2318 PVRTMat4 mOut; 2319 GetRotationMatrix(mOut,node); 2320 return mOut; 2321 } 2322 2323 /*!*************************************************************************** 2324 @Function GetScalingMatrix 2325 @Output mOut Scaling matrix 2326 @Input node Node to get the rotation matrix from 2327 @Description Generates the world matrix for the given Mesh Instance; 2328 applies the parent's transform too. Uses animation data. 2329 *****************************************************************************/ 2330 void CPVRTModelPOD::GetScalingMatrix( 2331 PVRTMATRIX &mOut, 2332 const SPODNode &node) const 2333 { 2334 PVRTVECTOR3 v; 2335 2336 if(node.pfAnimScale) 2337 { 2338 if(node.nAnimFlags & ePODHasScaleAni) 2339 { 2340 if(node.pnAnimScaleIdx) 2341 { 2342 PVRTMatrixVec3Lerp( 2343 v, 2344 (PVRTVECTOR3&)node.pfAnimScale[node.pnAnimScaleIdx[m_pImpl->nFrame+0]], 2345 (PVRTVECTOR3&)node.pfAnimScale[node.pnAnimScaleIdx[m_pImpl->nFrame+1]], m_pImpl->fBlend); 2346 } 2347 else 2348 { 2349 PVRTMatrixVec3Lerp( 2350 v, 2351 (PVRTVECTOR3&)node.pfAnimScale[7*(m_pImpl->nFrame+0)], 2352 (PVRTVECTOR3&)node.pfAnimScale[7*(m_pImpl->nFrame+1)], m_pImpl->fBlend); 2353 } 2354 2355 PVRTMatrixScaling(mOut, v.x, v.y, v.z); 2356 } 2357 else 2358 { 2359 PVRTMatrixScaling(mOut, node.pfAnimScale[0], node.pfAnimScale[1], node.pfAnimScale[2]); 2360 } 2361 } 2362 else 2363 { 2364 PVRTMatrixIdentity(mOut); 2365 } 2366 } 2367 2368 /*!*************************************************************************** 2369 @Function GetScalingMatrix 2370 @Input node Node to get the rotation matrix from 2371 @Returns Scaling matrix 2372 @Description Generates the world matrix for the given Mesh Instance; 2373 applies the parent's transform too. Uses animation data. 2374 *****************************************************************************/ 2375 PVRTMat4 CPVRTModelPOD::GetScalingMatrix(const SPODNode &node) const 2376 { 2377 PVRTMat4 mOut; 2378 GetScalingMatrix(mOut, node); 2379 return mOut; 2380 } 2381 2382 /*!*************************************************************************** 2383 @Function GetTranslation 2384 @Output V Translation vector 2385 @Input node Node to get the translation vector from 2386 @Description Generates the translation vector for the given Mesh 2387 Instance. Uses animation data. 2388 *****************************************************************************/ 2389 void CPVRTModelPOD::GetTranslation( 2390 PVRTVECTOR3 &V, 2391 const SPODNode &node) const 2392 { 2393 if(node.pfAnimPosition) 2394 { 2395 if(node.nAnimFlags & ePODHasPositionAni) 2396 { 2397 if(node.pnAnimPositionIdx) 2398 { 2399 PVRTMatrixVec3Lerp(V, 2400 (PVRTVECTOR3&)node.pfAnimPosition[node.pnAnimPositionIdx[m_pImpl->nFrame+0]], 2401 (PVRTVECTOR3&)node.pfAnimPosition[node.pnAnimPositionIdx[m_pImpl->nFrame+1]], m_pImpl->fBlend); 2402 } 2403 else 2404 { 2405 PVRTMatrixVec3Lerp(V, 2406 (PVRTVECTOR3&)node.pfAnimPosition[3 * (m_pImpl->nFrame+0)], 2407 (PVRTVECTOR3&)node.pfAnimPosition[3 * (m_pImpl->nFrame+1)], m_pImpl->fBlend); 2408 } 2409 } 2410 else 2411 { 2412 V = *(PVRTVECTOR3*) node.pfAnimPosition; 2413 } 2414 } 2415 else 2416 { 2417 _ASSERT(false); 2418 } 2419 } 2420 2421 /*!*************************************************************************** 2422 @Function GetTranslation 2423 @Input node Node to get the translation vector from 2424 @Returns Translation vector 2425 @Description Generates the translation vector for the given Mesh 2426 Instance. Uses animation data. 2427 *****************************************************************************/ 2428 PVRTVec3 CPVRTModelPOD::GetTranslation(const SPODNode &node) const 2429 { 2430 PVRTVec3 vOut; 2431 GetTranslation(vOut, node); 2432 return vOut; 2433 } 2434 2435 /*!*************************************************************************** 2436 @Function GetTranslationMatrix 2437 @Output mOut Translation matrix 2438 @Input node Node to get the translation matrix from 2439 @Description Generates the world matrix for the given Mesh Instance; 2440 applies the parent's transform too. Uses animation data. 2441 *****************************************************************************/ 2442 void CPVRTModelPOD::GetTranslationMatrix( 2443 PVRTMATRIX &mOut, 2444 const SPODNode &node) const 2445 { 2446 PVRTVECTOR3 v; 2447 2448 if(node.pfAnimPosition) 2449 { 2450 if(node.nAnimFlags & ePODHasPositionAni) 2451 { 2452 if(node.pnAnimPositionIdx) 2453 { 2454 PVRTMatrixVec3Lerp(v, 2455 (PVRTVECTOR3&)node.pfAnimPosition[node.pnAnimPositionIdx[m_pImpl->nFrame+0]], 2456 (PVRTVECTOR3&)node.pfAnimPosition[node.pnAnimPositionIdx[m_pImpl->nFrame+1]], m_pImpl->fBlend); 2457 } 2458 else 2459 { 2460 PVRTMatrixVec3Lerp(v, 2461 (PVRTVECTOR3&)node.pfAnimPosition[3*(m_pImpl->nFrame+0)], 2462 (PVRTVECTOR3&)node.pfAnimPosition[3*(m_pImpl->nFrame+1)], m_pImpl->fBlend); 2463 } 2464 2465 PVRTMatrixTranslation(mOut, v.x, v.y, v.z); 2466 } 2467 else 2468 { 2469 PVRTMatrixTranslation(mOut, node.pfAnimPosition[0], node.pfAnimPosition[1], node.pfAnimPosition[2]); 2470 } 2471 } 2472 else 2473 { 2474 PVRTMatrixIdentity(mOut); 2475 } 2476 } 2477 2478 /*!*************************************************************************** 2479 @Function GetTranslationMatrix 2480 @Input node Node to get the translation matrix from 2481 @Returns Translation matrix 2482 @Description Generates the world matrix for the given Mesh Instance; 2483 applies the parent's transform too. Uses animation data. 2484 *****************************************************************************/ 2485 PVRTMat4 CPVRTModelPOD::GetTranslationMatrix(const SPODNode &node) const 2486 { 2487 PVRTMat4 mOut; 2488 GetTranslationMatrix(mOut, node); 2489 return mOut; 2490 } 2491 2492 /*!*************************************************************************** 2493 @Function GetTransformationMatrix 2494 @Output mOut Transformation matrix 2495 @Input node Node to get the transformation matrix from 2496 @Description Generates the world matrix for the given Mesh Instance; 2497 applies the parent's transform too. Uses animation data. 2498 *****************************************************************************/ 2499 void CPVRTModelPOD::GetTransformationMatrix(PVRTMATRIX &mOut, const SPODNode &node) const 2500 { 2501 if(node.pfAnimMatrix) 2502 { 2503 if(node.nAnimFlags & ePODHasMatrixAni) 2504 { 2505 if(node.pnAnimMatrixIdx) 2506 mOut = *((PVRTMATRIX*) &node.pfAnimMatrix[node.pnAnimMatrixIdx[m_pImpl->nFrame]]); 2507 else 2508 mOut = *((PVRTMATRIX*) &node.pfAnimMatrix[16*m_pImpl->nFrame]); 2509 } 2510 else 2511 { 2512 mOut = *((PVRTMATRIX*) node.pfAnimMatrix); 2513 } 2514 } 2515 else 2516 { 2517 PVRTMatrixIdentity(mOut); 2518 } 2519 } 2520 /*!*************************************************************************** 2521 @Function GetWorldMatrixNoCache 2522 @Output mOut World matrix 2523 @Input node Node to get the world matrix from 2524 @Description Generates the world matrix for the given Mesh Instance; 2525 applies the parent's transform too. Uses animation data. 2526 *****************************************************************************/ 2527 void CPVRTModelPOD::GetWorldMatrixNoCache( 2528 PVRTMATRIX &mOut, 2529 const SPODNode &node) const 2530 { 2531 PVRTMATRIX mTmp; 2532 2533 if(node.pfAnimMatrix) // The transformations are stored as matrices 2534 GetTransformationMatrix(mOut, node); 2535 else 2536 { 2537 // Scale 2538 GetScalingMatrix(mOut, node); 2539 2540 // Rotation 2541 GetRotationMatrix(mTmp, node); 2542 PVRTMatrixMultiply(mOut, mOut, mTmp); 2543 2544 // Translation 2545 GetTranslationMatrix(mTmp, node); 2546 PVRTMatrixMultiply(mOut, mOut, mTmp); 2547 } 2548 2549 // Do we have to worry about a parent? 2550 if(node.nIdxParent < 0) 2551 return; 2552 2553 // Apply parent's transform too. 2554 GetWorldMatrixNoCache(mTmp, pNode[node.nIdxParent]); 2555 PVRTMatrixMultiply(mOut, mOut, mTmp); 2556 } 2557 2558 /*!*************************************************************************** 2559 @Function GetWorldMatrixNoCache 2560 @Input node Node to get the world matrix from 2561 @Returns World matrix 2562 @Description Generates the world matrix for the given Mesh Instance; 2563 applies the parent's transform too. Uses animation data. 2564 *****************************************************************************/ 2565 PVRTMat4 CPVRTModelPOD::GetWorldMatrixNoCache(const SPODNode& node) const 2566 { 2567 PVRTMat4 mWorld; 2568 GetWorldMatrixNoCache(mWorld,node); 2569 return mWorld; 2570 } 2571 2572 /*!*************************************************************************** 2573 @Function GetWorldMatrix 2574 @Output mOut World matrix 2575 @Input node Node to get the world matrix from 2576 @Description Generates the world matrix for the given Mesh Instance; 2577 applies the parent's transform too. Uses animation data. 2578 *****************************************************************************/ 2579 void CPVRTModelPOD::GetWorldMatrix( 2580 PVRTMATRIX &mOut, 2581 const SPODNode &node) const 2582 { 2583 unsigned int nIdx; 2584 2585 #ifdef _DEBUG 2586 ++m_pImpl->nWmTotal; 2587 m_pImpl->fHitPerc = (float)m_pImpl->nWmCacheHit / (float)m_pImpl->nWmTotal; 2588 m_pImpl->fHitPercZero = (float)m_pImpl->nWmZeroCacheHit / (float)m_pImpl->nWmTotal; 2589 #endif 2590 2591 // Calculate a node index 2592 nIdx = (unsigned int)(&node - pNode); 2593 2594 // There is a dedicated cache for frame 0 data 2595 if(m_pImpl->fFrame == 0) 2596 { 2597 mOut = m_pImpl->pWmZeroCache[nIdx]; 2598 #ifdef _DEBUG 2599 ++m_pImpl->nWmZeroCacheHit; 2600 #endif 2601 return; 2602 } 2603 2604 // Has this matrix been calculated & cached? 2605 if(m_pImpl->fFrame == m_pImpl->pfCache[nIdx]) 2606 { 2607 mOut = m_pImpl->pWmCache[nIdx]; 2608 #ifdef _DEBUG 2609 ++m_pImpl->nWmCacheHit; 2610 #endif 2611 return; 2612 } 2613 2614 GetWorldMatrixNoCache(mOut, node); 2615 2616 // Cache the matrix 2617 m_pImpl->pfCache[nIdx] = m_pImpl->fFrame; 2618 m_pImpl->pWmCache[nIdx] = mOut; 2619 } 2620 2621 /*!*************************************************************************** 2622 @Function GetWorldMatrix 2623 @Input node Node to get the world matrix from 2624 @Returns World matrix 2625 @Description Generates the world matrix for the given Mesh Instance; 2626 applies the parent's transform too. Uses animation data. 2627 *****************************************************************************/ 2628 PVRTMat4 CPVRTModelPOD::GetWorldMatrix(const SPODNode& node) const 2629 { 2630 PVRTMat4 mWorld; 2631 GetWorldMatrix(mWorld,node); 2632 return mWorld; 2633 } 2634 2635 /*!*************************************************************************** 2636 @Function GetBoneWorldMatrix 2637 @Output mOut Bone world matrix 2638 @Input NodeMesh Mesh to take the bone matrix from 2639 @Input NodeBone Bone to take the matrix from 2640 @Description Generates the world matrix for the given bone. 2641 *****************************************************************************/ 2642 void CPVRTModelPOD::GetBoneWorldMatrix( 2643 PVRTMATRIX &mOut, 2644 const SPODNode &NodeMesh, 2645 const SPODNode &NodeBone) 2646 { 2647 PVRTMATRIX mTmp; 2648 VERTTYPE fFrame; 2649 2650 fFrame = m_pImpl->fFrame; 2651 2652 SetFrame(0); 2653 2654 // Transform by object matrix 2655 GetWorldMatrix(mOut, NodeMesh); 2656 2657 // Back transform bone from frame 0 position 2658 GetWorldMatrix(mTmp, NodeBone); 2659 PVRTMatrixInverse(mTmp, mTmp); 2660 PVRTMatrixMultiply(mOut, mOut, mTmp); 2661 2662 // The bone origin should now be at the origin 2663 2664 SetFrame(fFrame); 2665 2666 // Transform bone into frame fFrame position 2667 GetWorldMatrix(mTmp, NodeBone); 2668 PVRTMatrixMultiply(mOut, mOut, mTmp); 2669 } 2670 2671 /*!*************************************************************************** 2672 @Function GetBoneWorldMatrix 2673 @Input NodeMesh Mesh to take the bone matrix from 2674 @Input NodeBone Bone to take the matrix from 2675 @Returns Bone world matrix 2676 @Description Generates the world matrix for the given bone. 2677 *****************************************************************************/ 2678 PVRTMat4 CPVRTModelPOD::GetBoneWorldMatrix( 2679 const SPODNode &NodeMesh, 2680 const SPODNode &NodeBone) 2681 { 2682 PVRTMat4 mOut; 2683 GetBoneWorldMatrix(mOut,NodeMesh,NodeBone); 2684 return mOut; 2685 } 2686 2687 /*!*************************************************************************** 2688 @Function GetCamera 2689 @Output vFrom Position of the camera 2690 @Output vTo Target of the camera 2691 @Output vUp Up direction of the camera 2692 @Input nIdx Camera number 2693 @Return Camera horizontal FOV 2694 @Description Calculate the From, To and Up vectors for the given 2695 camera. Uses animation data. 2696 Note that even if the camera has a target, *pvTo is not 2697 the position of that target. *pvTo is a position in the 2698 correct direction of the target, one unit away from the 2699 camera. 2700 *****************************************************************************/ 2701 VERTTYPE CPVRTModelPOD::GetCamera( 2702 PVRTVECTOR3 &vFrom, 2703 PVRTVECTOR3 &vTo, 2704 PVRTVECTOR3 &vUp, 2705 const unsigned int nIdx) const 2706 { 2707 PVRTMATRIX mTmp; 2708 VERTTYPE *pfData; 2709 SPODCamera *pCam; 2710 const SPODNode *pNd; 2711 2712 _ASSERT(nIdx < nNumCamera); 2713 2714 // Camera nodes are after the mesh and light nodes in the array 2715 pNd = &pNode[nNumMeshNode + nNumLight + nIdx]; 2716 2717 pCam = &pCamera[pNd->nIdx]; 2718 2719 GetWorldMatrix(mTmp, *pNd); 2720 2721 // View position is 0,0,0,1 transformed by world matrix 2722 vFrom.x = mTmp.f[12]; 2723 vFrom.y = mTmp.f[13]; 2724 vFrom.z = mTmp.f[14]; 2725 2726 // View direction is 0,-1,0,1 transformed by world matrix 2727 vTo.x = -mTmp.f[4] + mTmp.f[12]; 2728 vTo.y = -mTmp.f[5] + mTmp.f[13]; 2729 vTo.z = -mTmp.f[6] + mTmp.f[14]; 2730 2731 #if defined(BUILD_DX11) 2732 /* 2733 When you rotate the camera from "straight forward" to "straight down", in 2734 D3D the UP vector will be [0, 0, 1] 2735 */ 2736 vUp.x = mTmp.f[ 8]; 2737 vUp.y = mTmp.f[ 9]; 2738 vUp.z = mTmp.f[10]; 2739 #endif 2740 2741 #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3) 2742 /* 2743 When you rotate the camera from "straight forward" to "straight down", in 2744 OpenGL the UP vector will be [0, 0, -1] 2745 */ 2746 vUp.x = -mTmp.f[ 8]; 2747 vUp.y = -mTmp.f[ 9]; 2748 vUp.z = -mTmp.f[10]; 2749 #endif 2750 2751 /* 2752 Find & calculate FOV value 2753 */ 2754 if(pCam->pfAnimFOV) { 2755 pfData = &pCam->pfAnimFOV[m_pImpl->nFrame]; 2756 2757 return pfData[0] + m_pImpl->fBlend * (pfData[1] - pfData[0]); 2758 } else { 2759 return pCam->fFOV; 2760 } 2761 } 2762 2763 /*!*************************************************************************** 2764 @Function GetCameraPos 2765 @Output vFrom Position of the camera 2766 @Output vTo Target of the camera 2767 @Input nIdx Camera number 2768 @Return Camera horizontal FOV 2769 @Description Calculate the position of the camera and its target. Uses 2770 animation data. 2771 If the queried camera does not have a target, *pvTo is 2772 not changed. 2773 *****************************************************************************/ 2774 VERTTYPE CPVRTModelPOD::GetCameraPos( 2775 PVRTVECTOR3 &vFrom, 2776 PVRTVECTOR3 &vTo, 2777 const unsigned int nIdx) const 2778 { 2779 PVRTMATRIX mTmp; 2780 VERTTYPE *pfData; 2781 SPODCamera *pCam; 2782 const SPODNode *pNd; 2783 2784 _ASSERT(nIdx < nNumCamera); 2785 2786 // Camera nodes are after the mesh and light nodes in the array 2787 pNd = &pNode[nNumMeshNode + nNumLight + nIdx]; 2788 2789 // View position is 0,0,0,1 transformed by world matrix 2790 GetWorldMatrix(mTmp, *pNd); 2791 vFrom.x = mTmp.f[12]; 2792 vFrom.y = mTmp.f[13]; 2793 vFrom.z = mTmp.f[14]; 2794 2795 pCam = &pCamera[pNd->nIdx]; 2796 if(pCam->nIdxTarget >= 0) 2797 { 2798 // View position is 0,0,0,1 transformed by world matrix 2799 GetWorldMatrix(mTmp, pNode[pCam->nIdxTarget]); 2800 vTo.x = mTmp.f[12]; 2801 vTo.y = mTmp.f[13]; 2802 vTo.z = mTmp.f[14]; 2803 } 2804 2805 /* 2806 Find & calculate FOV value 2807 */ 2808 if(pCam->pfAnimFOV) { 2809 pfData = &pCam->pfAnimFOV[m_pImpl->nFrame]; 2810 2811 return pfData[0] + m_pImpl->fBlend * (pfData[1] - pfData[0]); 2812 } else { 2813 return pCam->fFOV; 2814 } 2815 } 2816 2817 /*!*************************************************************************** 2818 @Function GetLight 2819 @Output vPos Position of the light 2820 @Output vDir Direction of the light 2821 @Input nIdx Light number 2822 @Description Calculate the position and direction of the given Light. 2823 Uses animation data. 2824 *****************************************************************************/ 2825 void CPVRTModelPOD::GetLight( 2826 PVRTVECTOR3 &vPos, 2827 PVRTVECTOR3 &vDir, 2828 const unsigned int nIdx) const 2829 { 2830 PVRTMATRIX mTmp; 2831 const SPODNode *pNd; 2832 2833 _ASSERT(nIdx < nNumLight); 2834 2835 // Light nodes are after the mesh nodes in the array 2836 pNd = &pNode[nNumMeshNode + nIdx]; 2837 2838 GetWorldMatrix(mTmp, *pNd); 2839 2840 // View position is 0,0,0,1 transformed by world matrix 2841 vPos.x = mTmp.f[12]; 2842 vPos.y = mTmp.f[13]; 2843 vPos.z = mTmp.f[14]; 2844 2845 // View direction is 0,-1,0,0 transformed by world matrix 2846 vDir.x = -mTmp.f[4]; 2847 vDir.y = -mTmp.f[5]; 2848 vDir.z = -mTmp.f[6]; 2849 } 2850 2851 /*!*************************************************************************** 2852 @Function GetLightPositon 2853 @Input u32Idx Light number 2854 @Return PVRTVec4 position of light with w set correctly 2855 @Description Calculates the position of the given light. Uses animation data 2856 *****************************************************************************/ 2857 PVRTVec4 CPVRTModelPOD::GetLightPosition(const unsigned int u32Idx) const 2858 { // TODO: make this a real function instead of just wrapping GetLight() 2859 PVRTVec3 vPos, vDir; 2860 GetLight(vPos,vDir,u32Idx); 2861 2862 _ASSERT(u32Idx < nNumLight); 2863 _ASSERT(pLight[u32Idx].eType!=ePODDirectional); 2864 return PVRTVec4(vPos,1); 2865 } 2866 2867 /*!*************************************************************************** 2868 @Function GetLightDirection 2869 @Input u32Idx Light number 2870 @Return PVRTVec4 direction of light with w set correctly 2871 @Description Calculate the direction of the given Light. Uses animation data. 2872 *****************************************************************************/ 2873 PVRTVec4 CPVRTModelPOD::GetLightDirection(const unsigned int u32Idx) const 2874 { // TODO: make this a real function instead of just wrapping GetLight() 2875 PVRTVec3 vPos, vDir; 2876 GetLight(vPos,vDir,u32Idx); 2877 2878 _ASSERT(u32Idx < nNumLight); 2879 _ASSERT(pLight[u32Idx].eType!=ePODPoint); 2880 return PVRTVec4(vDir,0); 2881 } 2882 2883 /*!*************************************************************************** 2884 @Function CreateSkinIdxWeight 2885 @Output pIdx Four bytes containing matrix indices for vertex (0..255) (D3D: use UBYTE4) 2886 @Output pWeight Four bytes containing blend weights for vertex (0.0 .. 1.0) (D3D: use D3DCOLOR) 2887 @Input nVertexBones Number of bones this vertex uses 2888 @Input pnBoneIdx Pointer to 'nVertexBones' indices 2889 @Input pfBoneWeight Pointer to 'nVertexBones' blend weights 2890 @Description Creates the matrix indices and blend weights for a boned 2891 vertex. Call once per vertex of a boned mesh. 2892 *****************************************************************************/ 2893 EPVRTError CPVRTModelPOD::CreateSkinIdxWeight( 2894 char * const pIdx, // Four bytes containing matrix indices for vertex (0..255) (D3D: use UBYTE4) 2895 char * const pWeight, // Four bytes containing blend weights for vertex (0.0 .. 1.0) (D3D: use D3DCOLOR) 2896 const int nVertexBones, // Number of bones this vertex uses 2897 const int * const pnBoneIdx, // Pointer to 'nVertexBones' indices 2898 const VERTTYPE * const pfBoneWeight) // Pointer to 'nVertexBones' blend weights 2899 { 2900 int i, nSum; 2901 int nIdx[4]; 2902 int nWeight[4]; 2903 2904 for(i = 0; i < nVertexBones; ++i) 2905 { 2906 nIdx[i] = pnBoneIdx[i]; 2907 nWeight[i] = (int)vt2f((VERTTYPEMUL(f2vt(255.0f), pfBoneWeight[i]))); 2908 2909 if(nIdx[i] > 255) 2910 { 2911 PVRTErrorOutputDebug("Too many bones (highest index is 255).\n"); 2912 return PVR_FAIL; 2913 } 2914 2915 nWeight[i] = PVRT_MAX(nWeight[i], 0); 2916 nWeight[i] = PVRT_MIN(nWeight[i], 255); 2917 } 2918 2919 for(; i < 4; ++i) 2920 { 2921 nIdx[i] = 0; 2922 nWeight[i] = 0; 2923 } 2924 2925 if(nVertexBones) 2926 { 2927 // It's important the weights sum to 1 2928 nSum = 0; 2929 for(i = 0; i < 4; ++i) 2930 nSum += nWeight[i]; 2931 2932 if(!nSum) 2933 return PVR_FAIL; 2934 2935 _ASSERT(nSum <= 255); 2936 2937 i = 0; 2938 while(nSum < 255) 2939 { 2940 if(nWeight[i]) { 2941 ++nWeight[i]; 2942 ++nSum; 2943 } 2944 2945 if(++i > 3) 2946 i = 0; 2947 } 2948 2949 _ASSERT(nSum == 255); 2950 } 2951 2952 #if defined(BUILD_DX11) 2953 *(unsigned int*)pIdx = ((unsigned int)(((nIdx[3]&0xff)<<24)|((nIdx[2]&0xff)<<16)|((nIdx[1]&0xff)<<8)|(nIdx[0]&0xff))); // UBYTE4 is WZYX 2954 *(unsigned int*)pWeight = ((unsigned int)(((nWeight[3]&0xff)<<24)|((nWeight[0]&0xff)<<16)|((nWeight[1]&0xff)<<8)|(nWeight[2]&0xff))); // D3DCOLORs are WXYZ 2955 #endif 2956 2957 #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3) 2958 // Return indices and weights as bytes 2959 for(i = 0; i < 4; ++i) 2960 { 2961 pIdx[i] = (char) nIdx[i]; 2962 pWeight[i] = (char) nWeight[i]; 2963 } 2964 #endif 2965 2966 return PVR_SUCCESS; 2967 } 2968 2969 /*!*************************************************************************** 2970 @Function SavePOD 2971 @Input pszFilename Filename to save to 2972 @Input pszExpOpt A string containing the options used by the exporter 2973 @Description Save a binary POD file (.POD). 2974 *****************************************************************************/ 2975 EPVRTError CPVRTModelPOD::SavePOD(const char * const pszFilename, const char * const pszExpOpt, const char * const pszHistory) 2976 { 2977 FILE *pFile; 2978 bool bRet; 2979 2980 pFile = fopen(pszFilename, "wb+"); 2981 if(!pFile) 2982 return PVR_FAIL; 2983 2984 bRet = WritePOD(pFile, pszExpOpt, pszHistory, *this); 2985 2986 // Done 2987 fclose(pFile); 2988 return bRet ? PVR_SUCCESS : PVR_FAIL; 2989 } 2990 2991 2992 /*!*************************************************************************** 2993 @Function PVRTModelPODDataTypeSize 2994 @Input type Type to get the size of 2995 @Return Size of the data element 2996 @Description Returns the size of each data element. 2997 *****************************************************************************/ 2998 PVRTuint32 PVRTModelPODDataTypeSize(const EPVRTDataType type) 2999 { 3000 switch(type) 3001 { 3002 default: 3003 _ASSERT(false); 3004 return 0; 3005 case EPODDataFloat: 3006 return static_cast<PVRTuint32>(sizeof(float)); 3007 case EPODDataInt: 3008 case EPODDataUnsignedInt: 3009 return static_cast<PVRTuint32>(sizeof(int)); 3010 case EPODDataShort: 3011 case EPODDataShortNorm: 3012 case EPODDataUnsignedShort: 3013 case EPODDataUnsignedShortNorm: 3014 return static_cast<PVRTuint32>(sizeof(unsigned short)); 3015 case EPODDataRGBA: 3016 return static_cast<PVRTuint32>(sizeof(unsigned int)); 3017 case EPODDataABGR: 3018 return static_cast<PVRTuint32>(sizeof(unsigned int)); 3019 case EPODDataARGB: 3020 return static_cast<PVRTuint32>(sizeof(unsigned int)); 3021 case EPODDataD3DCOLOR: 3022 return static_cast<PVRTuint32>(sizeof(unsigned int)); 3023 case EPODDataUBYTE4: 3024 return static_cast<PVRTuint32>(sizeof(unsigned int)); 3025 case EPODDataDEC3N: 3026 return static_cast<PVRTuint32>(sizeof(unsigned int)); 3027 case EPODDataFixed16_16: 3028 return static_cast<PVRTuint32>(sizeof(unsigned int)); 3029 case EPODDataUnsignedByte: 3030 case EPODDataUnsignedByteNorm: 3031 case EPODDataByte: 3032 case EPODDataByteNorm: 3033 return static_cast<PVRTuint32>(sizeof(unsigned char)); 3034 } 3035 } 3036 3037 /*!*************************************************************************** 3038 @Function PVRTModelPODDataTypeComponentCount 3039 @Input type Type to get the number of components from 3040 @Return number of components in the data element 3041 @Description Returns the number of components in a data element. 3042 *****************************************************************************/ 3043 PVRTuint32 PVRTModelPODDataTypeComponentCount(const EPVRTDataType type) 3044 { 3045 switch(type) 3046 { 3047 default: 3048 _ASSERT(false); 3049 return 0; 3050 3051 case EPODDataFloat: 3052 case EPODDataInt: 3053 case EPODDataUnsignedInt: 3054 case EPODDataShort: 3055 case EPODDataShortNorm: 3056 case EPODDataUnsignedShort: 3057 case EPODDataUnsignedShortNorm: 3058 case EPODDataFixed16_16: 3059 case EPODDataByte: 3060 case EPODDataByteNorm: 3061 case EPODDataUnsignedByte: 3062 case EPODDataUnsignedByteNorm: 3063 return 1; 3064 3065 case EPODDataDEC3N: 3066 return 3; 3067 3068 case EPODDataRGBA: 3069 case EPODDataABGR: 3070 case EPODDataARGB: 3071 case EPODDataD3DCOLOR: 3072 case EPODDataUBYTE4: 3073 return 4; 3074 } 3075 } 3076 3077 /*!*************************************************************************** 3078 @Function PVRTModelPODDataStride 3079 @Input data Data elements 3080 @Return Size of the vector elements 3081 @Description Returns the size of the vector of data elements. 3082 *****************************************************************************/ 3083 PVRTuint32 PVRTModelPODDataStride(const CPODData &data) 3084 { 3085 return PVRTModelPODDataTypeSize(data.eType) * data.n; 3086 } 3087 3088 /*!*************************************************************************** 3089 @Function PVRTModelPODDataConvert 3090 @Modified data Data elements to convert 3091 @Input eNewType New type of elements 3092 @Input nCnt Number of elements 3093 @Description Convert the format of the array of vectors. 3094 *****************************************************************************/ 3095 void PVRTModelPODDataConvert(CPODData &data, const unsigned int nCnt, const EPVRTDataType eNewType) 3096 { 3097 PVRTVECTOR4f v; 3098 unsigned int i; 3099 CPODData old; 3100 3101 if(!data.pData || data.eType == eNewType) 3102 return; 3103 3104 old = data; 3105 3106 switch(eNewType) 3107 { 3108 case EPODDataFloat: 3109 case EPODDataInt: 3110 case EPODDataUnsignedInt: 3111 case EPODDataUnsignedShort: 3112 case EPODDataUnsignedShortNorm: 3113 case EPODDataFixed16_16: 3114 case EPODDataUnsignedByte: 3115 case EPODDataUnsignedByteNorm: 3116 case EPODDataShort: 3117 case EPODDataShortNorm: 3118 case EPODDataByte: 3119 case EPODDataByteNorm: 3120 data.n = (PVRTuint32) (old.n * PVRTModelPODDataTypeComponentCount(old.eType)); 3121 break; 3122 case EPODDataRGBA: 3123 case EPODDataABGR: 3124 case EPODDataARGB: 3125 case EPODDataD3DCOLOR: 3126 case EPODDataUBYTE4: 3127 case EPODDataDEC3N: 3128 data.n = 1; 3129 break; 3130 default: 3131 _ASSERT(false); // unrecognised type 3132 break; 3133 } 3134 3135 data.eType = eNewType; 3136 data.nStride = (unsigned int)PVRTModelPODDataStride(data); 3137 3138 // If the old & new strides are identical, we can convert it in place 3139 if(old.nStride != data.nStride) 3140 { 3141 data.pData = (unsigned char*)malloc(data.nStride * nCnt); 3142 } 3143 3144 for(i = 0; i < nCnt; ++i) 3145 { 3146 PVRTVertexRead(&v, old.pData + i * old.nStride, old.eType, old.n); 3147 PVRTVertexWrite(data.pData + i * data.nStride, eNewType, (int) (data.n * PVRTModelPODDataTypeComponentCount(data.eType)), &v); 3148 } 3149 3150 if(old.nStride != data.nStride) 3151 { 3152 FREE(old.pData); 3153 } 3154 } 3155 3156 /*!*************************************************************************** 3157 @Function PVRTModelPODScaleAndConvertVtxData 3158 @Modified mesh POD mesh to scale and convert the mesh data 3159 @Input eNewType The data type to scale and convert the vertex data to 3160 @Return PVR_SUCCESS on success and PVR_FAIL on failure. 3161 @Description Scales the vertex data to fit within the range of the requested 3162 data type and then converts the data to that type. This function 3163 isn't currently compiled in for fixed point builds of the tools. 3164 *****************************************************************************/ 3165 #if !defined(PVRT_FIXED_POINT_ENABLE) 3166 EPVRTError PVRTModelPODScaleAndConvertVtxData(SPODMesh &mesh, const EPVRTDataType eNewType) 3167 { 3168 // Initialise the matrix to identity 3169 PVRTMatrixIdentity(mesh.mUnpackMatrix); 3170 3171 // No vertices to process 3172 if(!mesh.nNumVertex) 3173 return PVR_SUCCESS; 3174 3175 // This function expects the data to be floats and not interleaved 3176 if(mesh.sVertex.eType != EPODDataFloat && mesh.pInterleaved != 0) 3177 return PVR_FAIL; 3178 3179 if(eNewType == EPODDataFloat) // Nothing to do 3180 return PVR_FAIL; 3181 3182 // A few variables 3183 float fLower = 0.0f, fUpper = 0.0f; 3184 PVRTBOUNDINGBOX BoundingBox; 3185 PVRTMATRIX mOffset, mScale; 3186 PVRTVECTOR4 v,o; 3187 3188 // Set the w component of o as it is needed for later 3189 o.w = 1.0f; 3190 3191 // Calc bounding box 3192 PVRTBoundingBoxComputeInterleaved(&BoundingBox, mesh.sVertex.pData, mesh.nNumVertex, 0, mesh.sVertex.nStride); 3193 3194 // Get new type data range that we wish to scale the data to 3195 3196 // Due to a hardware bug in early MBXs in some cases we clamp the data to the minimum possible value +1 3197 switch(eNewType) 3198 { 3199 case EPODDataInt: 3200 fUpper = 1 << 30; 3201 fLower = -fUpper; 3202 break; 3203 case EPODDataUnsignedInt: 3204 fUpper = 1 << 30; 3205 break; 3206 case EPODDataShort: 3207 case EPODDataFixed16_16: 3208 fUpper = 32767.0f; 3209 fLower = -fUpper; 3210 break; 3211 case EPODDataUnsignedShort: 3212 fUpper = 0x0ffff; 3213 break; 3214 case EPODDataRGBA: 3215 case EPODDataABGR: 3216 case EPODDataARGB: 3217 case EPODDataD3DCOLOR: 3218 fUpper = 1.0f; 3219 break; 3220 case EPODDataUBYTE4: 3221 case EPODDataUnsignedByte: 3222 fUpper = 0x0ff; 3223 break; 3224 case EPODDataShortNorm: 3225 case EPODDataUnsignedShortNorm: 3226 case EPODDataByteNorm: 3227 case EPODDataUnsignedByteNorm: 3228 fUpper = 1.0f; 3229 fLower = -fUpper; 3230 break; 3231 case EPODDataDEC3N: 3232 fUpper = 511.0f; 3233 fLower = -fUpper; 3234 break; 3235 case EPODDataByte: 3236 fUpper = 127.0f; 3237 fLower = -fUpper; 3238 break; 3239 default: 3240 _ASSERT(false); 3241 return PVR_FAIL; // Unsupported format specified 3242 } 3243 3244 PVRTVECTOR3f vScale, vOffset; 3245 3246 float fRange = fUpper - fLower; 3247 vScale.x = fRange / (BoundingBox.Point[7].x - BoundingBox.Point[0].x); 3248 vScale.y = fRange / (BoundingBox.Point[7].y - BoundingBox.Point[0].y); 3249 vScale.z = fRange / (BoundingBox.Point[7].z - BoundingBox.Point[0].z); 3250 3251 vOffset.x = -BoundingBox.Point[0].x; 3252 vOffset.y = -BoundingBox.Point[0].y; 3253 vOffset.z = -BoundingBox.Point[0].z; 3254 3255 PVRTMatrixTranslation(mOffset, -fLower, -fLower, -fLower); 3256 PVRTMatrixScaling(mScale, 1.0f / vScale.x, 1.0f / vScale.y, 1.0f / vScale.z); 3257 PVRTMatrixMultiply(mesh.mUnpackMatrix, mOffset, mScale); 3258 3259 PVRTMatrixTranslation(mOffset, -vOffset.x, -vOffset.y, -vOffset.z); 3260 PVRTMatrixMultiply(mesh.mUnpackMatrix, mesh.mUnpackMatrix, mOffset); 3261 3262 // Transform vertex data 3263 for(unsigned int i = 0; i < mesh.nNumVertex; ++i) 3264 { 3265 PVRTVertexRead(&v, mesh.sVertex.pData + i * mesh.sVertex.nStride, mesh.sVertex.eType, mesh.sVertex.n); 3266 3267 o.x = (v.x + vOffset.x) * vScale.x + fLower; 3268 o.y = (v.y + vOffset.y) * vScale.y + fLower; 3269 o.z = (v.z + vOffset.z) * vScale.z + fLower; 3270 3271 _ASSERT((o.x >= fLower && o.x <= fUpper) || fabs(1.0f - o.x / fLower) < 0.01f || fabs(1.0f - o.x / fUpper) < 0.01f); 3272 _ASSERT((o.y >= fLower && o.y <= fUpper) || fabs(1.0f - o.y / fLower) < 0.01f || fabs(1.0f - o.y / fUpper) < 0.01f); 3273 _ASSERT((o.z >= fLower && o.z <= fUpper) || fabs(1.0f - o.z / fLower) < 0.01f || fabs(1.0f - o.z / fUpper) < 0.01f); 3274 3275 #if defined(_DEBUG) 3276 PVRTVECTOR4 res; 3277 PVRTTransform(&res, &o, &mesh.mUnpackMatrix); 3278 3279 _ASSERT(fabs(res.x - v.x) <= 0.02); 3280 _ASSERT(fabs(res.y - v.y) <= 0.02); 3281 _ASSERT(fabs(res.z - v.z) <= 0.02); 3282 _ASSERT(fabs(res.w - 1.0) <= 0.02); 3283 #endif 3284 3285 PVRTVertexWrite(mesh.sVertex.pData + i * mesh.sVertex.nStride, mesh.sVertex.eType, (int) (mesh.sVertex.n * PVRTModelPODDataTypeComponentCount(mesh.sVertex.eType)), &o); 3286 } 3287 3288 // Convert the data to the chosen format 3289 PVRTModelPODDataConvert(mesh.sVertex, mesh.nNumVertex, eNewType); 3290 3291 return PVR_SUCCESS; 3292 } 3293 #endif 3294 /*!*************************************************************************** 3295 @Function PVRTModelPODDataShred 3296 @Modified data Data elements to modify 3297 @Input nCnt Number of elements 3298 @Input pChannels A list of the wanted channels, e.g. {'x', 'y', 0} 3299 @Description Reduce the number of dimensions in 'data' using the requested 3300 channel array. The array should have a maximum length of 4 3301 or be null terminated if less channels are wanted. It is also 3302 possible to negate an element, e.g. {'x','y', -'z'}. 3303 *****************************************************************************/ 3304 void PVRTModelPODDataShred(CPODData &data, const unsigned int nCnt, const int * pChannels) 3305 { 3306 CPODData old; 3307 PVRTVECTOR4f v,o; 3308 float * const pv = &v.x; 3309 float * const po = &o.x; 3310 unsigned int i, nCh; 3311 int i32Map[4]; 3312 bool bNegate[4]; 3313 3314 if(!data.pData || !pChannels) 3315 return; 3316 3317 old = data; 3318 3319 // Count the number of output channels while setting up cMap and bNegate 3320 for(data.n = 0; data.n < 4 && pChannels[data.n]; ++data.n) 3321 { 3322 i32Map[data.n] = abs(pChannels[data.n]) == 'w' ? 3 : abs(pChannels[data.n]) - 'x'; 3323 bNegate[data.n] = pChannels[data.n] < 0; 3324 } 3325 3326 if(data.n > old.n) 3327 data.n = old.n; 3328 3329 // Allocate output memory 3330 data.nStride = (unsigned int)PVRTModelPODDataStride(data); 3331 3332 if(data.nStride == 0) 3333 { 3334 FREE(data.pData); 3335 return; 3336 } 3337 3338 data.pData = (unsigned char*)malloc(data.nStride * nCnt); 3339 3340 for(i = 0; i < nCnt; ++i) 3341 { 3342 // Read the vector 3343 PVRTVertexRead(&v, old.pData + i * old.nStride, old.eType, old.n); 3344 3345 // Shred the vector 3346 for(nCh = 0; nCh < 4 && pChannels[nCh]; ++nCh) 3347 po[nCh] = bNegate[nCh] ? -pv[i32Map[nCh]] : pv[i32Map[nCh]]; 3348 3349 for(; nCh < 4; ++nCh) 3350 po[nCh] = 0; 3351 3352 // Write the vector 3353 PVRTVertexWrite((char*)data.pData + i * data.nStride, data.eType, (int) (data.n * PVRTModelPODDataTypeComponentCount(data.eType)), &o); 3354 } 3355 3356 FREE(old.pData); 3357 } 3358 3359 /*!*************************************************************************** 3360 @Function PVRTModelPODReorderFaces 3361 @Modified mesh The mesh to re-order the faces of 3362 @Input i32El1 The first index to be written out 3363 @Input i32El2 The second index to be written out 3364 @Input i32El3 The third index to be written out 3365 @Description Reorders the face indices of a mesh. 3366 *****************************************************************************/ 3367 void PVRTModelPODReorderFaces(SPODMesh &mesh, const int i32El1, const int i32El2, const int i32El3) 3368 { 3369 if(!mesh.sFaces.pData) 3370 return; 3371 3372 unsigned int ui32V[3]; 3373 3374 for(unsigned int i = 0; i < mesh.nNumFaces * 3; i += 3) 3375 { 3376 unsigned char *pData = mesh.sFaces.pData + i * mesh.sFaces.nStride; 3377 3378 // Read 3379 PVRTVertexRead(&ui32V[0], pData, mesh.sFaces.eType); 3380 PVRTVertexRead(&ui32V[1], pData + mesh.sFaces.nStride, mesh.sFaces.eType); 3381 PVRTVertexRead(&ui32V[2], pData + 2 * mesh.sFaces.nStride, mesh.sFaces.eType); 3382 3383 // Write in place the new order 3384 PVRTVertexWrite(pData, mesh.sFaces.eType, ui32V[i32El1]); 3385 PVRTVertexWrite(pData + mesh.sFaces.nStride, mesh.sFaces.eType, ui32V[i32El2]); 3386 PVRTVertexWrite(pData + 2 * mesh.sFaces.nStride, mesh.sFaces.eType, ui32V[i32El3]); 3387 } 3388 } 3389 3390 /*!*************************************************************************** 3391 @Function InterleaveArray 3392 @Modified pInterleaved 3393 @Modified data 3394 @Input nNumVertex 3395 @Input nStride 3396 @Input nPadding 3397 @Input nOffset 3398 @Description Interleaves the pod data 3399 *****************************************************************************/ 3400 static void InterleaveArray( 3401 char * const pInterleaved, 3402 CPODData &data, 3403 const PVRTuint32 nNumVertex, 3404 const PVRTuint32 nStride, 3405 const PVRTuint32 nPadding, 3406 PVRTuint32 &nOffset) 3407 { 3408 if(!data.nStride) 3409 return; 3410 3411 for(PVRTuint32 i = 0; i < nNumVertex; ++i) 3412 memcpy(pInterleaved + i * nStride + nOffset, (char*)data.pData + i * data.nStride, data.nStride); 3413 3414 FREE(data.pData); 3415 data.pData = (unsigned char*)nOffset; 3416 data.nStride = nStride; 3417 nOffset += PVRTModelPODDataStride(data) + nPadding; 3418 } 3419 3420 /*!*************************************************************************** 3421 @Function DeinterleaveArray 3422 @Input data 3423 @Input pInter 3424 @Input nNumVertex 3425 @Description DeInterleaves the pod data 3426 *****************************************************************************/ 3427 static void DeinterleaveArray( 3428 CPODData &data, 3429 const void * const pInter, 3430 const PVRTuint32 nNumVertex, 3431 const PVRTuint32 nAlignToNBytes) 3432 { 3433 const PVRTuint32 nSrcStride = data.nStride; 3434 const PVRTuint32 nDestStride= PVRTModelPODDataStride(data); 3435 const PVRTuint32 nAlignedStride = nDestStride + ((nAlignToNBytes - nDestStride % nAlignToNBytes) % nAlignToNBytes); 3436 const char *pSrc = (char*)pInter + (size_t)data.pData; 3437 3438 if(!nSrcStride) 3439 return; 3440 3441 data.pData = 0; 3442 SafeAlloc(data.pData, nAlignedStride * nNumVertex); 3443 data.nStride = nAlignedStride; 3444 3445 for(PVRTuint32 i = 0; i < nNumVertex; ++i) 3446 memcpy((char*)data.pData + i * nAlignedStride, pSrc + i * nSrcStride, nDestStride); 3447 } 3448 3449 /*!*************************************************************************** 3450 @Function PVRTModelPODToggleInterleaved 3451 @Modified mesh Mesh to modify 3452 @Input ui32AlignToNBytes Align the interleaved data to this no. of bytes. 3453 @Description Switches the supplied mesh to or from interleaved data format. 3454 *****************************************************************************/ 3455 void PVRTModelPODToggleInterleaved(SPODMesh &mesh, const PVRTuint32 ui32AlignToNBytes) 3456 { 3457 unsigned int i; 3458 3459 if(!mesh.nNumVertex) 3460 return; 3461 3462 if(mesh.pInterleaved) 3463 { 3464 /* 3465 De-interleave 3466 */ 3467 DeinterleaveArray(mesh.sVertex, mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3468 DeinterleaveArray(mesh.sNormals, mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3469 DeinterleaveArray(mesh.sTangents, mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3470 DeinterleaveArray(mesh.sBinormals, mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3471 3472 for(i = 0; i < mesh.nNumUVW; ++i) 3473 DeinterleaveArray(mesh.psUVW[i], mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3474 3475 DeinterleaveArray(mesh.sVtxColours, mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3476 DeinterleaveArray(mesh.sBoneIdx, mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3477 DeinterleaveArray(mesh.sBoneWeight, mesh.pInterleaved, mesh.nNumVertex, ui32AlignToNBytes); 3478 FREE(mesh.pInterleaved); 3479 } 3480 else 3481 { 3482 PVRTuint32 nStride, nOffset, nBytes; 3483 3484 #define NEEDED_PADDING(x) ((x && ui32AlignToNBytes) ? (ui32AlignToNBytes - x % ui32AlignToNBytes) % ui32AlignToNBytes : 0) 3485 3486 // Interleave 3487 3488 PVRTuint32 nVertexStride, nNormalStride, nTangentStride, nBinormalStride, nVtxColourStride, nBoneIdxStride, nBoneWeightStride; 3489 PVRTuint32 nUVWStride[8]; 3490 PVRTuint32 nVertexPadding, nNormalPadding, nTangentPadding, nBinormalPadding, nVtxColourPadding, nBoneIdxPadding, nBoneWeightPadding; 3491 PVRTuint32 nUVWPadding[8]; 3492 3493 _ASSERT(mesh.nNumUVW < 8); 3494 3495 nStride = nVertexStride = PVRTModelPODDataStride(mesh.sVertex); 3496 nStride += nVertexPadding = NEEDED_PADDING(nVertexStride); 3497 3498 nStride += nNormalStride = PVRTModelPODDataStride(mesh.sNormals); 3499 nStride += nNormalPadding = NEEDED_PADDING(nNormalStride); 3500 3501 nStride += nTangentStride = PVRTModelPODDataStride(mesh.sTangents); 3502 nStride += nTangentPadding = NEEDED_PADDING(nTangentStride); 3503 3504 nStride += nBinormalStride = PVRTModelPODDataStride(mesh.sBinormals); 3505 nStride += nBinormalPadding = NEEDED_PADDING(nBinormalStride); 3506 3507 for(i = 0; i < mesh.nNumUVW; ++i) 3508 { 3509 nStride += nUVWStride[i] = PVRTModelPODDataStride(mesh.psUVW[i]); 3510 nStride += nUVWPadding[i] = NEEDED_PADDING(nUVWStride[i]); 3511 } 3512 3513 nStride += nVtxColourStride = PVRTModelPODDataStride(mesh.sVtxColours); 3514 nStride += nVtxColourPadding = NEEDED_PADDING(nVtxColourStride); 3515 3516 nStride += nBoneIdxStride = PVRTModelPODDataStride(mesh.sBoneIdx); 3517 nStride += nBoneIdxPadding = NEEDED_PADDING(nBoneIdxStride); 3518 3519 nStride += nBoneWeightStride = PVRTModelPODDataStride(mesh.sBoneWeight); 3520 nStride += nBoneWeightPadding = NEEDED_PADDING(nBoneWeightStride); 3521 3522 #undef NEEDED_PADDING 3523 // Allocate interleaved array 3524 SafeAlloc(mesh.pInterleaved, mesh.nNumVertex * nStride); 3525 3526 // Interleave the data 3527 nOffset = 0; 3528 3529 for(nBytes = 4; nBytes > 0; nBytes >>= 1) 3530 { 3531 if(PVRTModelPODDataTypeSize(mesh.sVertex.eType) == nBytes) 3532 InterleaveArray((char*)mesh.pInterleaved, mesh.sVertex, mesh.nNumVertex, nStride, nVertexPadding, nOffset); 3533 3534 if(PVRTModelPODDataTypeSize(mesh.sNormals.eType) == nBytes) 3535 InterleaveArray((char*)mesh.pInterleaved, mesh.sNormals, mesh.nNumVertex, nStride, nNormalPadding, nOffset); 3536 3537 if(PVRTModelPODDataTypeSize(mesh.sTangents.eType) == nBytes) 3538 InterleaveArray((char*)mesh.pInterleaved, mesh.sTangents, mesh.nNumVertex, nStride, nTangentPadding, nOffset); 3539 3540 if(PVRTModelPODDataTypeSize(mesh.sBinormals.eType) == nBytes) 3541 InterleaveArray((char*)mesh.pInterleaved, mesh.sBinormals, mesh.nNumVertex, nStride, nBinormalPadding, nOffset); 3542 3543 if(PVRTModelPODDataTypeSize(mesh.sVtxColours.eType) == nBytes) 3544 InterleaveArray((char*)mesh.pInterleaved, mesh.sVtxColours, mesh.nNumVertex, nStride, nVtxColourPadding, nOffset); 3545 3546 for(i = 0; i < mesh.nNumUVW; ++i) 3547 { 3548 if(PVRTModelPODDataTypeSize(mesh.psUVW[i].eType) == nBytes) 3549 InterleaveArray((char*)mesh.pInterleaved, mesh.psUVW[i], mesh.nNumVertex, nStride, nUVWPadding[i], nOffset); 3550 } 3551 3552 if(PVRTModelPODDataTypeSize(mesh.sBoneIdx.eType) == nBytes) 3553 InterleaveArray((char*)mesh.pInterleaved, mesh.sBoneIdx, mesh.nNumVertex, nStride, nBoneIdxPadding, nOffset); 3554 3555 if(PVRTModelPODDataTypeSize(mesh.sBoneWeight.eType) == nBytes) 3556 InterleaveArray((char*)mesh.pInterleaved, mesh.sBoneWeight, mesh.nNumVertex, nStride, nBoneWeightPadding, nOffset); 3557 } 3558 } 3559 } 3560 3561 /*!*************************************************************************** 3562 @Function PVRTModelPODDeIndex 3563 @Modified mesh Mesh to modify 3564 @Description De-indexes the supplied mesh. The mesh must be 3565 Interleaved before calling this function. 3566 *****************************************************************************/ 3567 void PVRTModelPODDeIndex(SPODMesh &mesh) 3568 { 3569 unsigned char *pNew = 0; 3570 3571 if(!mesh.pInterleaved || !mesh.nNumVertex) 3572 return; 3573 3574 _ASSERT(mesh.nNumVertex && mesh.nNumFaces); 3575 3576 // Create a new vertex list 3577 mesh.nNumVertex = PVRTModelPODCountIndices(mesh); 3578 SafeAlloc(pNew, mesh.sVertex.nStride * mesh.nNumVertex); 3579 3580 // Deindex the vertices 3581 if(mesh.sFaces.eType == EPODDataUnsignedShort) 3582 { 3583 for(unsigned int i = 0; i < mesh.nNumVertex; ++i) 3584 memcpy(pNew + i * mesh.sVertex.nStride, (char*)mesh.pInterleaved + ((unsigned short*)mesh.sFaces.pData)[i] * mesh.sVertex.nStride, mesh.sVertex.nStride); 3585 } 3586 else 3587 { 3588 _ASSERT(mesh.sFaces.eType == EPODDataUnsignedInt); 3589 3590 for(unsigned int i = 0; i < mesh.nNumVertex; ++i) 3591 memcpy(pNew + i * mesh.sVertex.nStride, (char*)mesh.pInterleaved + ((unsigned int*)mesh.sFaces.pData)[i] * mesh.sVertex.nStride, mesh.sVertex.nStride); 3592 } 3593 3594 // Replace the old vertex list 3595 FREE(mesh.pInterleaved); 3596 mesh.pInterleaved = pNew; 3597 3598 // Get rid of the index list 3599 FREE(mesh.sFaces.pData); 3600 mesh.sFaces.n = 0; 3601 mesh.sFaces.nStride = 0; 3602 } 3603 3604 /*!*************************************************************************** 3605 @Function PVRTModelPODToggleStrips 3606 @Modified mesh Mesh to modify 3607 @Description Converts the supplied mesh to or from strips. 3608 *****************************************************************************/ 3609 void PVRTModelPODToggleStrips(SPODMesh &mesh) 3610 { 3611 CPODData old; 3612 size_t nIdxSize, nTriStride; 3613 3614 if(!mesh.nNumFaces) 3615 return; 3616 3617 _ASSERT(mesh.sFaces.n == 1); 3618 nIdxSize = PVRTModelPODDataTypeSize(mesh.sFaces.eType); 3619 nTriStride = PVRTModelPODDataStride(mesh.sFaces) * 3; 3620 3621 old = mesh.sFaces; 3622 mesh.sFaces.pData = 0; 3623 SafeAlloc(mesh.sFaces.pData, nTriStride * mesh.nNumFaces); 3624 3625 if(mesh.nNumStrips) 3626 { 3627 unsigned int nListIdxCnt, nStripIdxCnt; 3628 3629 // Convert to list 3630 nListIdxCnt = 0; 3631 nStripIdxCnt = 0; 3632 3633 for(unsigned int i = 0; i < mesh.nNumStrips; ++i) 3634 { 3635 for(unsigned int j = 0; j < mesh.pnStripLength[i]; ++j) 3636 { 3637 if(j) 3638 { 3639 _ASSERT(j == 1); // Because this will surely break with any other number 3640 3641 memcpy( 3642 (char*)mesh.sFaces.pData + nIdxSize * nListIdxCnt, 3643 (char*)old.pData + nIdxSize * (nStripIdxCnt - 1), 3644 nIdxSize); 3645 nListIdxCnt += 1; 3646 3647 memcpy( 3648 (char*)mesh.sFaces.pData + nIdxSize * nListIdxCnt, 3649 (char*)old.pData + nIdxSize * (nStripIdxCnt - 2), 3650 nIdxSize); 3651 nListIdxCnt += 1; 3652 3653 memcpy( 3654 (char*)mesh.sFaces.pData + nIdxSize * nListIdxCnt, 3655 (char*)old.pData + nIdxSize * nStripIdxCnt, 3656 nIdxSize); 3657 nListIdxCnt += 1; 3658 3659 nStripIdxCnt += 1; 3660 } 3661 else 3662 { 3663 memcpy( 3664 (char*)mesh.sFaces.pData + nIdxSize * nListIdxCnt, 3665 (char*)old.pData + nIdxSize * nStripIdxCnt, 3666 nTriStride); 3667 3668 nStripIdxCnt += 3; 3669 nListIdxCnt += 3; 3670 } 3671 } 3672 } 3673 3674 _ASSERT(nListIdxCnt == mesh.nNumFaces*3); 3675 FREE(mesh.pnStripLength); 3676 mesh.nNumStrips = 0; 3677 } 3678 else 3679 { 3680 int nIdxCnt; 3681 int nBatchCnt; 3682 unsigned int n0, n1, n2; 3683 unsigned int p0, p1, p2, nFaces; 3684 unsigned char* pFaces; 3685 3686 // Convert to strips 3687 mesh.pnStripLength = (unsigned int*)calloc(mesh.nNumFaces, sizeof(*mesh.pnStripLength)); 3688 mesh.nNumStrips = 0; 3689 nIdxCnt = 0; 3690 nBatchCnt = mesh.sBoneBatches.nBatchCnt ? mesh.sBoneBatches.nBatchCnt : 1; 3691 3692 for(int h = 0; h < nBatchCnt; ++h) 3693 { 3694 n0 = 0; 3695 n1 = 0; 3696 n2 = 0; 3697 3698 if(!mesh.sBoneBatches.nBatchCnt) 3699 { 3700 nFaces = mesh.nNumFaces; 3701 pFaces = old.pData; 3702 } 3703 else 3704 { 3705 if(h + 1 < mesh.sBoneBatches.nBatchCnt) 3706 nFaces = mesh.sBoneBatches.pnBatchOffset[h+1] - mesh.sBoneBatches.pnBatchOffset[h]; 3707 else 3708 nFaces = mesh.nNumFaces - mesh.sBoneBatches.pnBatchOffset[h]; 3709 3710 pFaces = &old.pData[3 * mesh.sBoneBatches.pnBatchOffset[h] * old.nStride]; 3711 } 3712 3713 for(unsigned int i = 0; i < nFaces; ++i) 3714 { 3715 p0 = n0; 3716 p1 = n1; 3717 p2 = n2; 3718 3719 PVRTVertexRead(&n0, (char*)pFaces + (3 * i + 0) * old.nStride, old.eType); 3720 PVRTVertexRead(&n1, (char*)pFaces + (3 * i + 1) * old.nStride, old.eType); 3721 PVRTVertexRead(&n2, (char*)pFaces + (3 * i + 2) * old.nStride, old.eType); 3722 3723 if(mesh.pnStripLength[mesh.nNumStrips]) 3724 { 3725 if(mesh.pnStripLength[mesh.nNumStrips] & 0x01) 3726 { 3727 if(p1 == n1 && p2 == n0) 3728 { 3729 PVRTVertexWrite((char*)mesh.sFaces.pData + nIdxCnt * mesh.sFaces.nStride, mesh.sFaces.eType, n2); 3730 ++nIdxCnt; 3731 mesh.pnStripLength[mesh.nNumStrips] += 1; 3732 continue; 3733 } 3734 } 3735 else 3736 { 3737 if(p2 == n1 && p0 == n0) 3738 { 3739 PVRTVertexWrite((char*)mesh.sFaces.pData + nIdxCnt * mesh.sFaces.nStride, mesh.sFaces.eType, n2); 3740 ++nIdxCnt; 3741 mesh.pnStripLength[mesh.nNumStrips] += 1; 3742 continue; 3743 } 3744 } 3745 3746 ++mesh.nNumStrips; 3747 } 3748 3749 // Start of strip, copy entire triangle 3750 PVRTVertexWrite((char*)mesh.sFaces.pData + nIdxCnt * mesh.sFaces.nStride, mesh.sFaces.eType, n0); 3751 ++nIdxCnt; 3752 PVRTVertexWrite((char*)mesh.sFaces.pData + nIdxCnt * mesh.sFaces.nStride, mesh.sFaces.eType, n1); 3753 ++nIdxCnt; 3754 PVRTVertexWrite((char*)mesh.sFaces.pData + nIdxCnt * mesh.sFaces.nStride, mesh.sFaces.eType, n2); 3755 ++nIdxCnt; 3756 3757 mesh.pnStripLength[mesh.nNumStrips] += 1; 3758 } 3759 } 3760 3761 if(mesh.pnStripLength[mesh.nNumStrips]) 3762 ++mesh.nNumStrips; 3763 3764 SafeRealloc(mesh.sFaces.pData, nIdxCnt * nIdxSize); 3765 mesh.pnStripLength = (unsigned int*)realloc(mesh.pnStripLength, sizeof(*mesh.pnStripLength) * mesh.nNumStrips); 3766 } 3767 3768 FREE(old.pData); 3769 } 3770 3771 /*!*************************************************************************** 3772 @Function PVRTModelPODCountIndices 3773 @Input mesh Mesh 3774 @Return Number of indices used by mesh 3775 @Description Counts the number of indices of a mesh 3776 *****************************************************************************/ 3777 unsigned int PVRTModelPODCountIndices(const SPODMesh &mesh) 3778 { 3779 return mesh.nNumStrips ? mesh.nNumFaces + (mesh.nNumStrips * 2) : mesh.nNumFaces * 3; 3780 } 3781 3782 /*!*************************************************************************** 3783 @Function PVRTModelPODCopyCPODData 3784 @Input in 3785 @Output out 3786 @Input ui32No 3787 @Input bInterleaved 3788 @Description Used to copy a CPODData of a mesh 3789 *****************************************************************************/ 3790 void PVRTModelPODCopyCPODData(const CPODData &in, CPODData &out, unsigned int ui32No, bool bInterleaved) 3791 { 3792 FREE(out.pData); 3793 3794 out.eType = in.eType; 3795 out.n = in.n; 3796 out.nStride = in.nStride; 3797 3798 if(bInterleaved) 3799 { 3800 out.pData = in.pData; 3801 } 3802 else if(in.pData) 3803 { 3804 size_t ui32Size = PVRTModelPODDataStride(out) * ui32No; 3805 3806 if(SafeAlloc(out.pData, ui32Size)) 3807 memcpy(out.pData, in.pData, ui32Size); 3808 } 3809 } 3810 3811 /*!*************************************************************************** 3812 @Function PVRTModelPODCopyNode 3813 @Input in 3814 @Output out 3815 @Input nNumFrames 3816 @Description Used to copy a pod node 3817 *****************************************************************************/ 3818 void PVRTModelPODCopyNode(const SPODNode &in, SPODNode &out, int nNumFrames) 3819 { 3820 out.nIdx = in.nIdx; 3821 out.nIdxMaterial = in.nIdxMaterial; 3822 out.nIdxParent = in.nIdxParent; 3823 out.nAnimFlags = in.nAnimFlags; 3824 out.pUserData = 0; 3825 out.nUserDataSize = 0; 3826 3827 if(in.pszName && SafeAlloc(out.pszName, strlen(in.pszName) + 1)) 3828 memcpy(out.pszName, in.pszName, strlen(in.pszName) + 1); 3829 3830 int i32Size; 3831 3832 // Position 3833 i32Size = in.nAnimFlags & ePODHasPositionAni ? PVRTModelPODGetAnimArraySize(in.pnAnimPositionIdx, nNumFrames, 3) : 3; 3834 3835 if(in.pnAnimPositionIdx && SafeAlloc(out.pnAnimPositionIdx, nNumFrames)) 3836 memcpy(out.pnAnimPositionIdx, in.pnAnimPositionIdx, sizeof(*out.pnAnimPositionIdx) * nNumFrames); 3837 3838 if(in.pfAnimPosition && SafeAlloc(out.pfAnimPosition, i32Size)) 3839 memcpy(out.pfAnimPosition, in.pfAnimPosition, sizeof(*out.pfAnimPosition) * i32Size); 3840 3841 // Rotation 3842 i32Size = in.nAnimFlags & ePODHasRotationAni ? PVRTModelPODGetAnimArraySize(in.pnAnimRotationIdx, nNumFrames, 4) : 4; 3843 3844 if(in.pnAnimRotationIdx && SafeAlloc(out.pnAnimRotationIdx, nNumFrames)) 3845 memcpy(out.pnAnimRotationIdx, in.pnAnimRotationIdx, sizeof(*out.pnAnimRotationIdx) * nNumFrames); 3846 3847 if(in.pfAnimRotation && SafeAlloc(out.pfAnimRotation, i32Size)) 3848 memcpy(out.pfAnimRotation, in.pfAnimRotation, sizeof(*out.pfAnimRotation) * i32Size); 3849 3850 // Scale 3851 i32Size = in.nAnimFlags & ePODHasScaleAni ? PVRTModelPODGetAnimArraySize(in.pnAnimScaleIdx, nNumFrames, 7) : 7; 3852 3853 if(in.pnAnimScaleIdx && SafeAlloc(out.pnAnimScaleIdx, nNumFrames)) 3854 memcpy(out.pnAnimScaleIdx, in.pnAnimScaleIdx, sizeof(*out.pnAnimScaleIdx) * nNumFrames); 3855 3856 if(in.pfAnimScale && SafeAlloc(out.pfAnimScale, i32Size)) 3857 memcpy(out.pfAnimScale, in.pfAnimScale, sizeof(*out.pfAnimScale) * i32Size); 3858 3859 // Matrix 3860 i32Size = in.nAnimFlags & ePODHasMatrixAni ? PVRTModelPODGetAnimArraySize(in.pnAnimMatrixIdx, nNumFrames, 16) : 16; 3861 3862 if(in.pnAnimMatrixIdx && SafeAlloc(out.pnAnimMatrixIdx, nNumFrames)) 3863 memcpy(out.pnAnimMatrixIdx, in.pnAnimMatrixIdx, sizeof(*out.pnAnimMatrixIdx) * nNumFrames); 3864 3865 if(in.pfAnimMatrix && SafeAlloc(out.pfAnimMatrix, i32Size)) 3866 memcpy(out.pfAnimMatrix, in.pfAnimMatrix, sizeof(*out.pfAnimMatrix) * i32Size); 3867 3868 if(in.pUserData && SafeAlloc(out.pUserData, in.nUserDataSize)) 3869 { 3870 memcpy(out.pUserData, in.pUserData, in.nUserDataSize); 3871 out.nUserDataSize = in.nUserDataSize; 3872 } 3873 } 3874 3875 /*!*************************************************************************** 3876 @Function PVRTModelPODCopyMesh 3877 @Input in 3878 @Output out 3879 @Description Used to copy a pod mesh 3880 *****************************************************************************/ 3881 void PVRTModelPODCopyMesh(const SPODMesh &in, SPODMesh &out) 3882 { 3883 unsigned int i; 3884 bool bInterleaved = in.pInterleaved != 0; 3885 out.nNumVertex = in.nNumVertex; 3886 out.nNumFaces = in.nNumFaces; 3887 3888 // Face data 3889 PVRTModelPODCopyCPODData(in.sFaces , out.sFaces , out.nNumFaces * 3, false); 3890 3891 // Vertex data 3892 PVRTModelPODCopyCPODData(in.sVertex , out.sVertex , out.nNumVertex, bInterleaved); 3893 PVRTModelPODCopyCPODData(in.sNormals , out.sNormals , out.nNumVertex, bInterleaved); 3894 PVRTModelPODCopyCPODData(in.sTangents , out.sTangents , out.nNumVertex, bInterleaved); 3895 PVRTModelPODCopyCPODData(in.sBinormals , out.sBinormals , out.nNumVertex, bInterleaved); 3896 PVRTModelPODCopyCPODData(in.sVtxColours, out.sVtxColours, out.nNumVertex, bInterleaved); 3897 PVRTModelPODCopyCPODData(in.sBoneIdx , out.sBoneIdx , out.nNumVertex, bInterleaved); 3898 PVRTModelPODCopyCPODData(in.sBoneWeight, out.sBoneWeight, out.nNumVertex, bInterleaved); 3899 3900 if(in.nNumUVW && SafeAlloc(out.psUVW, in.nNumUVW)) 3901 { 3902 out.nNumUVW = in.nNumUVW; 3903 3904 for(i = 0; i < out.nNumUVW; ++i) 3905 { 3906 PVRTModelPODCopyCPODData(in.psUVW[i], out.psUVW[i], out.nNumVertex, bInterleaved); 3907 } 3908 } 3909 3910 // Allocate and copy interleaved array 3911 if(bInterleaved && SafeAlloc(out.pInterleaved, out.nNumVertex * in.sVertex.nStride)) 3912 memcpy(out.pInterleaved, in.pInterleaved, out.nNumVertex * in.sVertex.nStride); 3913 3914 if(in.pnStripLength && SafeAlloc(out.pnStripLength, out.nNumFaces)) 3915 { 3916 memcpy(out.pnStripLength, in.pnStripLength, sizeof(*out.pnStripLength) * out.nNumFaces); 3917 out.nNumStrips = in.nNumStrips; 3918 } 3919 3920 if(in.sBoneBatches.nBatchCnt) 3921 { 3922 out.sBoneBatches.Release(); 3923 3924 out.sBoneBatches.nBatchBoneMax = in.sBoneBatches.nBatchBoneMax; 3925 out.sBoneBatches.nBatchCnt = in.sBoneBatches.nBatchCnt; 3926 3927 if(in.sBoneBatches.pnBatches) 3928 { 3929 out.sBoneBatches.pnBatches = (int*) malloc(out.sBoneBatches.nBatchCnt * out.sBoneBatches.nBatchBoneMax * sizeof(*out.sBoneBatches.pnBatches)); 3930 3931 if(out.sBoneBatches.pnBatches) 3932 memcpy(out.sBoneBatches.pnBatches, in.sBoneBatches.pnBatches, out.sBoneBatches.nBatchCnt * out.sBoneBatches.nBatchBoneMax * sizeof(*out.sBoneBatches.pnBatches)); 3933 } 3934 3935 if(in.sBoneBatches.pnBatchBoneCnt) 3936 { 3937 out.sBoneBatches.pnBatchBoneCnt = (int*) malloc(out.sBoneBatches.nBatchCnt * sizeof(*out.sBoneBatches.pnBatchBoneCnt)); 3938 3939 if(out.sBoneBatches.pnBatchBoneCnt) 3940 memcpy(out.sBoneBatches.pnBatchBoneCnt, in.sBoneBatches.pnBatchBoneCnt, out.sBoneBatches.nBatchCnt * sizeof(*out.sBoneBatches.pnBatchBoneCnt)); 3941 } 3942 3943 if(in.sBoneBatches.pnBatchOffset) 3944 { 3945 out.sBoneBatches.pnBatchOffset = (int*) malloc(out.sBoneBatches.nBatchCnt * sizeof(out.sBoneBatches.pnBatchOffset)); 3946 3947 if(out.sBoneBatches.pnBatchOffset) 3948 memcpy(out.sBoneBatches.pnBatchOffset, in.sBoneBatches.pnBatchOffset, out.sBoneBatches.nBatchCnt * sizeof(*out.sBoneBatches.pnBatchOffset)); 3949 } 3950 } 3951 3952 memcpy(out.mUnpackMatrix.f, in.mUnpackMatrix.f, sizeof(in.mUnpackMatrix.f[0]) * 16); 3953 3954 out.ePrimitiveType = in.ePrimitiveType; 3955 } 3956 3957 /*!*************************************************************************** 3958 @Function PVRTModelPODCopyTexture 3959 @Input in 3960 @Output out 3961 @Description Used to copy a pod texture 3962 *****************************************************************************/ 3963 void PVRTModelPODCopyTexture(const SPODTexture &in, SPODTexture &out) 3964 { 3965 if(in.pszName && SafeAlloc(out.pszName, strlen(in.pszName) + 1)) 3966 memcpy(out.pszName, in.pszName, strlen(in.pszName) + 1); 3967 } 3968 3969 /*!*************************************************************************** 3970 @Function PVRTModelPODCopyMaterial 3971 @Input in 3972 @Output out 3973 @Description Used to copy a pod material 3974 *****************************************************************************/ 3975 void PVRTModelPODCopyMaterial(const SPODMaterial &in, SPODMaterial &out) 3976 { 3977 memcpy(&out, &in, sizeof(SPODMaterial)); 3978 3979 out.pszName = 0; 3980 out.pszEffectFile = 0; 3981 out.pszEffectName = 0; 3982 out.pUserData = 0; 3983 out.nUserDataSize = 0; 3984 3985 if(in.pszName && SafeAlloc(out.pszName, strlen(in.pszName) + 1)) 3986 memcpy(out.pszName, in.pszName, strlen(in.pszName) + 1); 3987 3988 if(in.pszEffectFile && SafeAlloc(out.pszEffectFile, strlen(in.pszEffectFile) + 1)) 3989 memcpy(out.pszEffectFile, in.pszEffectFile, strlen(in.pszEffectFile) + 1); 3990 3991 if(in.pszEffectName && SafeAlloc(out.pszEffectName, strlen(in.pszEffectName) + 1)) 3992 memcpy(out.pszEffectName, in.pszEffectName, strlen(in.pszEffectName) + 1); 3993 3994 if(in.pUserData && SafeAlloc(out.pUserData, in.nUserDataSize)) 3995 { 3996 memcpy(out.pUserData, in.pUserData, in.nUserDataSize); 3997 out.nUserDataSize = in.nUserDataSize; 3998 } 3999 } 4000 4001 /*!*************************************************************************** 4002 @Function PVRTModelPODCopyCamera 4003 @Input in 4004 @Output out 4005 @Input nNumFrames The number of animation frames 4006 @Description Used to copy a pod camera 4007 *****************************************************************************/ 4008 void PVRTModelPODCopyCamera(const SPODCamera &in, SPODCamera &out, int nNumFrames) 4009 { 4010 memcpy(&out, &in, sizeof(SPODCamera)); 4011 4012 out.pfAnimFOV = 0; 4013 4014 if(in.pfAnimFOV && SafeAlloc(out.pfAnimFOV, nNumFrames)) 4015 memcpy(out.pfAnimFOV, in.pfAnimFOV, sizeof(*out.pfAnimFOV) * nNumFrames); 4016 } 4017 4018 /*!*************************************************************************** 4019 @Function PVRTModelPODCopyLight 4020 @Input in 4021 @Output out 4022 @Description Used to copy a pod light 4023 *****************************************************************************/ 4024 void PVRTModelPODCopyLight(const SPODLight &in, SPODLight &out) 4025 { 4026 memcpy(&out, &in, sizeof(SPODLight)); 4027 } 4028 4029 /*!*************************************************************************** 4030 @Function TransformCPODData 4031 @Input in 4032 @Output out 4033 @Input idx Value to transform 4034 @Input pPalette Palette of matrices to transform with 4035 @Input pBoneIdx Array of indices into pPalette 4036 @Input pBoneWeight Array of weights to weight the influence of the matrices of pPalette with 4037 @Input i32BoneCnt Size of pBoneIdx and pBoneWeight 4038 @Description Used to transform a particular value in a CPODData 4039 *****************************************************************************/ 4040 inline void TransformCPODData(CPODData &in, CPODData &out, int idx, PVRTMATRIX *pPalette, float *pBoneIdx, float *pBoneW, int i32BoneCnt, bool bNormalise) 4041 { 4042 PVRTVECTOR4f fResult, fOrig, fTmp; 4043 4044 if(in.n) 4045 { 4046 4047 PVRTVertexRead(&fOrig, in.pData + (idx * in.nStride), in.eType, in.n); 4048 4049 memset(&fResult.x, 0, sizeof(fResult)); 4050 4051 if(i32BoneCnt) 4052 { 4053 for(int i = 0; i < i32BoneCnt; ++i) 4054 { 4055 int i32BoneIdx = (int) pBoneIdx[i]; 4056 fTmp.x = vt2f(pPalette[i32BoneIdx].f[0]) * fOrig.x + vt2f(pPalette[i32BoneIdx].f[4]) * fOrig.y + vt2f(pPalette[i32BoneIdx].f[8]) * fOrig.z + vt2f(pPalette[i32BoneIdx].f[12]) * fOrig.w; 4057 fTmp.y = vt2f(pPalette[i32BoneIdx].f[1]) * fOrig.x + vt2f(pPalette[i32BoneIdx].f[5]) * fOrig.y + vt2f(pPalette[i32BoneIdx].f[9]) * fOrig.z + vt2f(pPalette[i32BoneIdx].f[13]) * fOrig.w; 4058 fTmp.z = vt2f(pPalette[i32BoneIdx].f[2]) * fOrig.x + vt2f(pPalette[i32BoneIdx].f[6]) * fOrig.y + vt2f(pPalette[i32BoneIdx].f[10])* fOrig.z + vt2f(pPalette[i32BoneIdx].f[14]) * fOrig.w; 4059 fTmp.w = vt2f(pPalette[i32BoneIdx].f[3]) * fOrig.x + vt2f(pPalette[i32BoneIdx].f[7]) * fOrig.y + vt2f(pPalette[i32BoneIdx].f[11])* fOrig.z + vt2f(pPalette[i32BoneIdx].f[15]) * fOrig.w; 4060 4061 fResult.x += fTmp.x * pBoneW[i]; 4062 fResult.y += fTmp.y * pBoneW[i]; 4063 fResult.z += fTmp.z * pBoneW[i]; 4064 fResult.w += fTmp.w * pBoneW[i]; 4065 } 4066 } 4067 else 4068 { 4069 fResult.x = vt2f(pPalette[0].f[0]) * fOrig.x + vt2f(pPalette[0].f[4]) * fOrig.y + vt2f(pPalette[0].f[8]) * fOrig.z + vt2f(pPalette[0].f[12]) * fOrig.w; 4070 fResult.y = vt2f(pPalette[0].f[1]) * fOrig.x + vt2f(pPalette[0].f[5]) * fOrig.y + vt2f(pPalette[0].f[9]) * fOrig.z + vt2f(pPalette[0].f[13]) * fOrig.w; 4071 fResult.z = vt2f(pPalette[0].f[2]) * fOrig.x + vt2f(pPalette[0].f[6]) * fOrig.y + vt2f(pPalette[0].f[10])* fOrig.z + vt2f(pPalette[0].f[14]) * fOrig.w; 4072 fResult.w = vt2f(pPalette[0].f[3]) * fOrig.x + vt2f(pPalette[0].f[7]) * fOrig.y + vt2f(pPalette[0].f[11])* fOrig.z + vt2f(pPalette[0].f[15]) * fOrig.w; 4073 } 4074 4075 if(bNormalise) 4076 { 4077 double temp = (double)(fResult.x * fResult.x + fResult.y * fResult.y + fResult.z * fResult.z); 4078 temp = 1.0 / sqrt(temp); 4079 float f = (float)temp; 4080 4081 fResult.x = fResult.x * f; 4082 fResult.y = fResult.y * f; 4083 fResult.z = fResult.z * f; 4084 } 4085 4086 PVRTVertexWrite(out.pData + (idx * out.nStride), out.eType, in.n, &fResult); 4087 } 4088 } 4089 /*!*************************************************************************** 4090 @Function PVRTModelPODFlattenToWorldSpace 4091 @Input in - Source scene. All meshes must not be interleaved. 4092 @Output out 4093 @Description Used to flatten a pod scene to world space. All animation 4094 and skinning information will be removed. The returned 4095 position, normal, binormals and tangent data if present 4096 will be returned as floats regardless of the input data 4097 type. 4098 *****************************************************************************/ 4099 EPVRTError PVRTModelPODFlattenToWorldSpace(CPVRTModelPOD &in, CPVRTModelPOD &out) 4100 { 4101 unsigned int i, j, k, l; 4102 PVRTMATRIX mWorld; 4103 4104 // Destroy the out pod scene to make sure it is clean 4105 out.Destroy(); 4106 4107 // Init mesh and node arrays 4108 SafeAlloc(out.pNode, in.nNumNode); 4109 SafeAlloc(out.pMesh, in.nNumMeshNode); 4110 4111 out.nNumNode = in.nNumNode; 4112 out.nNumMesh = out.nNumMeshNode = in.nNumMeshNode; 4113 4114 // Init scene values 4115 out.nNumFrame = 0; 4116 out.nFlags = in.nFlags; 4117 out.fUnits = in.fUnits; 4118 4119 for(i = 0; i < 3; ++i) 4120 { 4121 out.pfColourBackground[i] = in.pfColourBackground[i]; 4122 out.pfColourAmbient[i] = in.pfColourAmbient[i]; 4123 } 4124 4125 // flatten meshes to world space 4126 for(i = 0; i < in.nNumMeshNode; ++i) 4127 { 4128 4129 4130 SPODNode& inNode = in.pNode[i]; 4131 SPODNode& outNode = out.pNode[i]; 4132 4133 // Get the meshes 4134 SPODMesh& inMesh = in.pMesh[inNode.nIdx]; 4135 SPODMesh& outMesh = out.pMesh[i]; 4136 4137 if(inMesh.pInterleaved != 0) // This function requires all the meshes to be de-interleaved 4138 { 4139 _ASSERT(inMesh.pInterleaved == 0); 4140 out.Destroy(); // Destroy the out pod scene 4141 return PVR_FAIL; 4142 } 4143 4144 // Copy the node 4145 PVRTModelPODCopyNode(inNode, outNode, in.nNumFrame); 4146 4147 // Strip out animation and parenting 4148 outNode.nIdxParent = -1; 4149 4150 outNode.nAnimFlags = 0; 4151 FREE(outNode.pfAnimMatrix); 4152 FREE(outNode.pfAnimPosition); 4153 FREE(outNode.pfAnimRotation); 4154 FREE(outNode.pfAnimScale); 4155 4156 // Update the mesh ID. The rest of the IDs should remain correct 4157 outNode.nIdx = i; 4158 4159 // Copy the mesh 4160 PVRTModelPODCopyMesh(inMesh, outMesh); 4161 4162 // Strip out skinning information as that is no longer needed 4163 outMesh.sBoneBatches.Release(); 4164 outMesh.sBoneIdx.Reset(); 4165 outMesh.sBoneWeight.Reset(); 4166 4167 // Set the data type to float and resize the arrays as this function outputs transformed data as float only 4168 if(inMesh.sVertex.n) 4169 { 4170 outMesh.sVertex.eType = EPODDataFloat; 4171 outMesh.sVertex.pData = (unsigned char*) realloc(outMesh.sVertex.pData, PVRTModelPODDataStride(outMesh.sVertex) * inMesh.nNumVertex); 4172 } 4173 4174 if(inMesh.sNormals.n) 4175 { 4176 outMesh.sNormals.eType = EPODDataFloat; 4177 outMesh.sNormals.pData = (unsigned char*) realloc(outMesh.sNormals.pData, PVRTModelPODDataStride(outMesh.sNormals) * inMesh.nNumVertex); 4178 } 4179 4180 if(inMesh.sTangents.n) 4181 { 4182 outMesh.sTangents.eType = EPODDataFloat; 4183 outMesh.sTangents.pData = (unsigned char*) realloc(outMesh.sTangents.pData, PVRTModelPODDataStride(outMesh.sTangents) * inMesh.nNumVertex); 4184 } 4185 4186 if(inMesh.sBinormals.n) 4187 { 4188 outMesh.sBinormals.eType = EPODDataFloat; 4189 outMesh.sBinormals.pData = (unsigned char*) realloc(outMesh.sBinormals.pData, PVRTModelPODDataStride(outMesh.sBinormals) * inMesh.nNumVertex); 4190 } 4191 4192 if(inMesh.sBoneBatches.nBatchCnt) 4193 { 4194 unsigned int ui32BatchPaletteSize = 0; 4195 PVRTMATRIX *pPalette = 0; 4196 PVRTMATRIX *pPaletteInvTrans = 0; 4197 unsigned int ui32Offset = 0, ui32Strip = 0; 4198 bool *pbTransformed = 0; 4199 4200 SafeAlloc(pPalette, inMesh.sBoneBatches.nBatchBoneMax); 4201 SafeAlloc(pPaletteInvTrans, inMesh.sBoneBatches.nBatchBoneMax); 4202 SafeAlloc(pbTransformed, inMesh.nNumVertex); 4203 4204 for(j = 0; j < (unsigned int) inMesh.sBoneBatches.nBatchCnt; ++j) 4205 { 4206 ui32BatchPaletteSize = (unsigned int) inMesh.sBoneBatches.pnBatchBoneCnt[j]; 4207 4208 for(k = 0; k < ui32BatchPaletteSize; ++k) 4209 { 4210 // Get the Node of the bone 4211 int i32NodeID = inMesh.sBoneBatches.pnBatches[j * inMesh.sBoneBatches.nBatchBoneMax + k]; 4212 4213 // Get the World transformation matrix for this bone 4214 in.GetBoneWorldMatrix(pPalette[k], inNode, in.pNode[i32NodeID]); 4215 4216 // Get the inverse transpose of the 3x3 4217 if(inMesh.sNormals.n || inMesh.sTangents.n || inMesh.sBinormals.n) 4218 { 4219 pPaletteInvTrans[k] = pPalette[k]; 4220 pPaletteInvTrans[k].f[3] = pPaletteInvTrans[k].f[7] = pPaletteInvTrans[k].f[11] = 0; 4221 pPaletteInvTrans[k].f[12] = pPaletteInvTrans[k].f[13] = pPaletteInvTrans[k].f[14] = 0; 4222 PVRTMatrixInverse(pPaletteInvTrans[k], pPaletteInvTrans[k]); 4223 PVRTMatrixTranspose(pPaletteInvTrans[k], pPaletteInvTrans[k]); 4224 } 4225 } 4226 // Calculate the number of triangles in the current batch 4227 unsigned int ui32Tris; 4228 4229 if(j + 1 < (unsigned int) inMesh.sBoneBatches.nBatchCnt) 4230 ui32Tris = inMesh.sBoneBatches.pnBatchOffset[j + 1] - inMesh.sBoneBatches.pnBatchOffset[j]; 4231 else 4232 ui32Tris = inMesh.nNumFaces - inMesh.sBoneBatches.pnBatchOffset[j]; 4233 4234 unsigned int idx; 4235 float fBoneIdx[4], fBoneWeights[4]; 4236 4237 if(inMesh.nNumStrips == 0) 4238 { 4239 ui32Offset = 3 * inMesh.sBoneBatches.pnBatchOffset[j]; 4240 4241 for(l = ui32Offset; l < ui32Offset + (ui32Tris * 3); ++l) 4242 { 4243 if(inMesh.sFaces.pData) // Indexed Triangle Lists 4244 PVRTVertexRead(&idx, inMesh.sFaces.pData + (l * inMesh.sFaces.nStride), inMesh.sFaces.eType); 4245 else // Indexed Triangle Lists 4246 idx = l; 4247 4248 if(!pbTransformed[idx]) 4249 { 4250 PVRTVertexRead((PVRTVECTOR4f*) &fBoneIdx[0], inMesh.sBoneIdx.pData + (idx * inMesh.sBoneIdx.nStride), inMesh.sBoneIdx.eType, inMesh.sBoneIdx.n); 4251 PVRTVertexRead((PVRTVECTOR4f*) &fBoneWeights[0], inMesh.sBoneWeight.pData + (idx * inMesh.sBoneWeight.nStride), inMesh.sBoneWeight.eType, inMesh.sBoneWeight.n); 4252 4253 TransformCPODData(inMesh.sVertex, outMesh.sVertex, idx, pPalette, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, false); 4254 TransformCPODData(inMesh.sNormals, outMesh.sNormals, idx, pPaletteInvTrans, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, true); 4255 TransformCPODData(inMesh.sTangents, outMesh.sTangents, idx, pPaletteInvTrans, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, true); 4256 TransformCPODData(inMesh.sBinormals, outMesh.sBinormals, idx, pPaletteInvTrans, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, true); 4257 pbTransformed[idx] = true; 4258 } 4259 } 4260 } 4261 else 4262 { 4263 unsigned int ui32TrisDrawn = 0; 4264 4265 while(ui32TrisDrawn < ui32Tris) 4266 { 4267 for(l = ui32Offset; l < ui32Offset + (inMesh.pnStripLength[ui32Strip]+2); ++l) 4268 { 4269 if(inMesh.sFaces.pData) // Indexed Triangle Strips 4270 PVRTVertexRead(&idx, inMesh.sFaces.pData + (l * inMesh.sFaces.nStride), inMesh.sFaces.eType); 4271 else // Triangle Strips 4272 idx = l; 4273 4274 if(!pbTransformed[idx]) 4275 { 4276 PVRTVertexRead((PVRTVECTOR4f*) &fBoneIdx[0], inMesh.sBoneIdx.pData + (idx * inMesh.sBoneIdx.nStride), inMesh.sBoneIdx.eType, inMesh.sBoneIdx.n); 4277 PVRTVertexRead((PVRTVECTOR4f*) &fBoneWeights[0], inMesh.sBoneWeight.pData + (idx * inMesh.sBoneWeight.nStride), inMesh.sBoneWeight.eType, inMesh.sBoneWeight.n); 4278 4279 TransformCPODData(inMesh.sVertex, outMesh.sVertex, idx, pPalette, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, false); 4280 TransformCPODData(inMesh.sNormals, outMesh.sNormals, idx, pPaletteInvTrans, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, true); 4281 TransformCPODData(inMesh.sTangents, outMesh.sTangents, idx, pPaletteInvTrans, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, true); 4282 TransformCPODData(inMesh.sBinormals, outMesh.sBinormals, idx, pPaletteInvTrans, &fBoneIdx[0], &fBoneWeights[0], inMesh.sBoneIdx.n, true); 4283 pbTransformed[idx] = true; 4284 } 4285 } 4286 4287 ui32Offset += inMesh.pnStripLength[ui32Strip] + 2; 4288 ui32TrisDrawn += inMesh.pnStripLength[ui32Strip]; 4289 4290 ++ui32Strip; 4291 } 4292 } 4293 } 4294 4295 FREE(pPalette); 4296 FREE(pPaletteInvTrans); 4297 FREE(pbTransformed); 4298 } 4299 else 4300 { 4301 // Get transformation matrix 4302 in.GetWorldMatrix(mWorld, inNode); 4303 PVRTMATRIX mWorldInvTrans; 4304 4305 // Get the inverse transpose of the 3x3 4306 if(inMesh.sNormals.n || inMesh.sTangents.n || inMesh.sBinormals.n) 4307 { 4308 mWorldInvTrans = mWorld; 4309 mWorldInvTrans.f[3] = mWorldInvTrans.f[7] = mWorldInvTrans.f[11] = 0; 4310 mWorldInvTrans.f[12] = mWorldInvTrans.f[13] = mWorldInvTrans.f[14] = 0; 4311 PVRTMatrixInverse(mWorldInvTrans, mWorldInvTrans); 4312 PVRTMatrixTranspose(mWorldInvTrans, mWorldInvTrans); 4313 } 4314 4315 // Transform the vertices 4316 for(j = 0; j < inMesh.nNumVertex; ++j) 4317 { 4318 TransformCPODData(inMesh.sVertex, outMesh.sVertex, j, &mWorld, 0, 0, 0, false); 4319 TransformCPODData(inMesh.sNormals, outMesh.sNormals, j, &mWorldInvTrans, 0, 0, 0, true); 4320 TransformCPODData(inMesh.sTangents, outMesh.sTangents, j, &mWorldInvTrans, 0, 0, 0, true); 4321 TransformCPODData(inMesh.sBinormals, outMesh.sBinormals, j, &mWorldInvTrans, 0, 0, 0, true); 4322 } 4323 } 4324 } 4325 4326 // Copy the rest of the nodes 4327 for(i = in.nNumMeshNode; i < in.nNumNode; ++i) 4328 { 4329 PVRTModelPODCopyNode(in.pNode[i], out.pNode[i], in.nNumFrame); 4330 4331 // Strip out animation and parenting 4332 out.pNode[i].nIdxParent = -1; 4333 4334 out.pNode[i].nAnimFlags = 0; 4335 FREE(out.pNode[i].pfAnimMatrix); 4336 FREE(out.pNode[i].pnAnimMatrixIdx); 4337 4338 FREE(out.pNode[i].pfAnimPosition); 4339 FREE(out.pNode[i].pnAnimPositionIdx); 4340 4341 FREE(out.pNode[i].pfAnimRotation); 4342 FREE(out.pNode[i].pnAnimRotationIdx); 4343 4344 FREE(out.pNode[i].pfAnimScale); 4345 FREE(out.pNode[i].pnAnimScaleIdx); 4346 4347 // Get world transformation matrix.... 4348 in.GetWorldMatrix(mWorld, in.pNode[i]); 4349 4350 // ...set the out node transformation matrix 4351 if(SafeAlloc(out.pNode[i].pfAnimMatrix, 16)) 4352 memcpy(out.pNode[i].pfAnimMatrix, mWorld.f, sizeof(PVRTMATRIX)); 4353 } 4354 4355 // Copy camera, lights 4356 if(in.nNumCamera && SafeAlloc(out.pCamera, in.nNumCamera)) 4357 { 4358 out.nNumCamera = in.nNumCamera; 4359 4360 for(i = 0; i < in.nNumCamera; ++i) 4361 PVRTModelPODCopyCamera(in.pCamera[i], out.pCamera[i], in.nNumFrame); 4362 } 4363 4364 if(in.nNumLight && SafeAlloc(out.pLight, in.nNumLight)) 4365 { 4366 out.nNumLight = in.nNumLight; 4367 4368 for(i = 0; i < out.nNumLight; ++i) 4369 PVRTModelPODCopyLight(in.pLight[i], out.pLight[i]); 4370 } 4371 4372 // Copy textures 4373 if(in.nNumTexture && SafeAlloc(out.pTexture, in.nNumTexture)) 4374 { 4375 out.nNumTexture = in.nNumTexture; 4376 4377 for(i = 0; i < out.nNumTexture; ++i) 4378 PVRTModelPODCopyTexture(in.pTexture[i], out.pTexture[i]); 4379 } 4380 4381 // Copy materials 4382 if(in.nNumMaterial && SafeAlloc(out.pMaterial, in.nNumMaterial)) 4383 { 4384 out.nNumMaterial = in.nNumMaterial; 4385 4386 for(i = 0; i < in.nNumMaterial; ++i) 4387 PVRTModelPODCopyMaterial(in.pMaterial[i], out.pMaterial[i]); 4388 } 4389 4390 out.InitImpl(); 4391 4392 return PVR_SUCCESS; 4393 } 4394 4395 static bool MergeTexture(const CPVRTModelPOD &src, CPVRTModelPOD &dst, const int &srcTexID, int &dstTexID) 4396 { 4397 if(srcTexID != -1 && srcTexID < (int) src.nNumTexture) 4398 { 4399 if(dstTexID == -1) 4400 { 4401 // Resize our texture array to add our texture 4402 dst.pTexture = (SPODTexture*) realloc(dst.pTexture, (dst.nNumTexture + 1) * sizeof(SPODTexture)); 4403 4404 if(!dst.pTexture) 4405 return false; 4406 4407 dstTexID = dst.nNumTexture; 4408 ++dst.nNumTexture; 4409 4410 dst.pTexture[dstTexID].pszName = (char*) malloc(strlen(src.pTexture[srcTexID].pszName) + 1); 4411 strcpy(dst.pTexture[dstTexID].pszName, src.pTexture[srcTexID].pszName); 4412 return true; 4413 } 4414 4415 // See if our texture names match 4416 if(strcmp(src.pTexture[srcTexID].pszName, dst.pTexture[dstTexID].pszName) == 0) 4417 return true; // Nothing to do 4418 4419 // See if our texture filenames match 4420 char * srcName = src.pTexture[srcTexID].pszName; 4421 char * dstName = dst.pTexture[dstTexID].pszName; 4422 bool bFoundPossibleEndOfFilename = false; 4423 bool bStrMatch = true, bFilenameMatch = true; 4424 4425 while(*srcName != '\0' && *dstName != '\0') 4426 { 4427 if(*srcName != *dstName) 4428 { 4429 if(!bFoundPossibleEndOfFilename) 4430 return true; // They don't match 4431 4432 bStrMatch = false; 4433 } 4434 4435 if(*srcName == '.') 4436 { 4437 if(!bStrMatch) 4438 return true; // They don't match 4439 4440 bFoundPossibleEndOfFilename = true; 4441 bFilenameMatch = bStrMatch; 4442 } 4443 4444 ++srcName; 4445 ++dstName; 4446 } 4447 4448 if(bFilenameMatch) 4449 { 4450 // Our filenames match but our extensions don't so merge our textures 4451 FREE(dst.pTexture[dstTexID].pszName); 4452 dst.pTexture[dstTexID].pszName = (char*) malloc(strlen(src.pTexture[srcTexID].pszName) + 1); 4453 strcpy(dst.pTexture[dstTexID].pszName, src.pTexture[srcTexID].pszName); 4454 return true; 4455 } 4456 4457 // Our texture names aren't the same so don't try and merge 4458 } 4459 4460 return true; 4461 } 4462 4463 /*!*************************************************************************** 4464 @Function PVRTModelPODMergeMaterials 4465 @Input src - Source scene 4466 @Output dst - Destination scene 4467 @Description This function takes two scenes and merges the textures, 4468 PFX effects and blending parameters from the src materials 4469 into the dst materials if they have the same material name. 4470 *****************************************************************************/ 4471 EPVRTError PVRTModelPODMergeMaterials(const CPVRTModelPOD &src, CPVRTModelPOD &dst) 4472 { 4473 if(!src.nNumMaterial || !dst.nNumMaterial) 4474 return PVR_SUCCESS; 4475 4476 bool *bMatched = (bool*) calloc(dst.nNumMaterial, sizeof(bool)); 4477 4478 if(!bMatched) 4479 return PVR_FAIL; 4480 4481 for(unsigned int i = 0; i < src.nNumMaterial; ++i) 4482 { 4483 const SPODMaterial &srcMaterial = src.pMaterial[i]; 4484 4485 // Match our current material with one in the dst 4486 for(unsigned int j = 0; j < dst.nNumMaterial; ++j) 4487 { 4488 if(bMatched[j]) 4489 continue; // We have already matched this material with another 4490 4491 SPODMaterial &dstMaterial = dst.pMaterial[j]; 4492 4493 // We've found a material with the same name 4494 if(strcmp(srcMaterial.pszName, dstMaterial.pszName) == 0) 4495 { 4496 bMatched[j] = true; 4497 4498 // Merge the textures 4499 if(!MergeTexture(src, dst, srcMaterial.nIdxTexDiffuse, dstMaterial.nIdxTexDiffuse)) 4500 { 4501 FREE(bMatched); 4502 return PVR_FAIL; 4503 } 4504 4505 if(!MergeTexture(src, dst, srcMaterial.nIdxTexAmbient, dstMaterial.nIdxTexAmbient)) 4506 { 4507 FREE(bMatched); 4508 return PVR_FAIL; 4509 } 4510 4511 if(!MergeTexture(src, dst, srcMaterial.nIdxTexSpecularColour, dstMaterial.nIdxTexSpecularColour)) 4512 { 4513 FREE(bMatched); 4514 return PVR_FAIL; 4515 } 4516 4517 if(!MergeTexture(src, dst, srcMaterial.nIdxTexSpecularLevel, dstMaterial.nIdxTexSpecularLevel)) 4518 { 4519 FREE(bMatched); 4520 return PVR_FAIL; 4521 } 4522 4523 if(!MergeTexture(src, dst, srcMaterial.nIdxTexBump, dstMaterial.nIdxTexBump)) 4524 { 4525 FREE(bMatched); 4526 return PVR_FAIL; 4527 } 4528 4529 if(!MergeTexture(src, dst, srcMaterial.nIdxTexEmissive, dstMaterial.nIdxTexEmissive)) 4530 { 4531 FREE(bMatched); 4532 return PVR_FAIL; 4533 } 4534 4535 if(!MergeTexture(src, dst, srcMaterial.nIdxTexGlossiness, dstMaterial.nIdxTexGlossiness)) 4536 { 4537 FREE(bMatched); 4538 return PVR_FAIL; 4539 } 4540 4541 if(!MergeTexture(src, dst, srcMaterial.nIdxTexOpacity, dstMaterial.nIdxTexOpacity)) 4542 { 4543 FREE(bMatched); 4544 return PVR_FAIL; 4545 } 4546 4547 if(!MergeTexture(src, dst, srcMaterial.nIdxTexReflection, dstMaterial.nIdxTexReflection)) 4548 { 4549 FREE(bMatched); 4550 return PVR_FAIL; 4551 } 4552 4553 if(!MergeTexture(src, dst, srcMaterial.nIdxTexRefraction, dstMaterial.nIdxTexRefraction)) 4554 { 4555 FREE(bMatched); 4556 return PVR_FAIL; 4557 } 4558 4559 dstMaterial.eBlendSrcRGB = srcMaterial.eBlendSrcRGB; 4560 dstMaterial.eBlendSrcA = srcMaterial.eBlendSrcA; 4561 dstMaterial.eBlendDstRGB = srcMaterial.eBlendDstRGB; 4562 dstMaterial.eBlendDstA = srcMaterial.eBlendDstA; 4563 dstMaterial.eBlendOpRGB = srcMaterial.eBlendOpRGB; 4564 dstMaterial.eBlendOpA = srcMaterial.eBlendOpA; 4565 memcpy(dstMaterial.pfBlendColour, srcMaterial.pfBlendColour, 4 * sizeof(VERTTYPE)); 4566 memcpy(dstMaterial.pfBlendFactor, srcMaterial.pfBlendFactor, 4 * sizeof(VERTTYPE)); 4567 dstMaterial.nFlags = srcMaterial.nFlags; 4568 4569 // Merge effect names 4570 if(srcMaterial.pszEffectFile) 4571 { 4572 FREE(dstMaterial.pszEffectFile); 4573 dstMaterial.pszEffectFile = (char*) malloc(strlen(srcMaterial.pszEffectFile) + 1); 4574 strcpy(dstMaterial.pszEffectFile, srcMaterial.pszEffectFile); 4575 } 4576 4577 if(srcMaterial.pszEffectName) 4578 { 4579 FREE(dstMaterial.pszEffectName); 4580 dstMaterial.pszEffectName = (char*) malloc(strlen(srcMaterial.pszEffectName) + 1); 4581 strcpy(dstMaterial.pszEffectName, srcMaterial.pszEffectName); 4582 } 4583 4584 break; 4585 } 4586 } 4587 } 4588 4589 FREE(bMatched); 4590 return PVR_SUCCESS; 4591 } 4592 4593 /***************************************************************************** 4594 End of file (PVRTModelPOD.cpp) 4595 *****************************************************************************/ 4596 4597