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>
SafeAlloc(T * & ptr,size_t cnt)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>
SafeRealloc(T * & ptr,size_t cnt)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 *****************************************************************************/
Reset()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 *****************************************************************************/
~CSource()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>
Read(T & n)274 bool Read(T &n)
275 {
276 return Read(&n, sizeof(T));
277 }
278
279 template <typename T>
Read32(T & n)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>
Read16(T & n)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>
ReadAfterAlloc(T * & lpBuffer,const unsigned int dwNumberOfBytesToRead)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>
ReadAfterAlloc32(T * & lpBuffer,const unsigned int dwNumberOfBytesToRead)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>
ReadArray32(T * pn,const unsigned int i32Size)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>
ReadAfterAlloc16(T * & lpBuffer,const unsigned int dwNumberOfBytesToRead)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
ReadArray16(unsigned short * pn,unsigned int i32Size)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
ReadMarker(unsigned int & nName,unsigned int & nLen)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 *****************************************************************************/
CSourceStream()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 *****************************************************************************/
~CSourceStream()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 *****************************************************************************/
Init(const char * const pszFileName)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 *****************************************************************************/
Init(const char * pData,size_t i32Size)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 *****************************************************************************/
Read(void * lpBuffer,const unsigned int dwNumberOfBytesToRead)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 *****************************************************************************/
Skip(const unsigned int nBytes)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 *****************************************************************************/
Init(const TCHAR * const pszName)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 *****************************************************************************/
Read(void * lpBuffer,const unsigned int dwNumberOfBytesToRead)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
Skip(const unsigned int nBytes)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 *****************************************************************************/
WriteFileSafe(FILE * pFile,const void * const lpBuffer,const unsigned int nNumberOfBytesToWrite)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
WriteFileSafe16(FILE * pFile,const unsigned short * const lpBuffer,const unsigned int nSize)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
WriteFileSafe32(FILE * pFile,const unsigned int * const lpBuffer,const unsigned int nSize)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 *****************************************************************************/
WriteMarker(FILE * const pFile,const unsigned int nName,const bool bEnd,const unsigned int nLen=0)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 *****************************************************************************/
WriteData(FILE * const pFile,const unsigned int nName,const void * const pData,const unsigned int nLen)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>
WriteData16(FILE * const pFile,const unsigned int nName,const T * const pData,int i32Size=1)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>
WriteData32(FILE * const pFile,const unsigned int nName,const T * const pData,int i32Size=1)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>
WriteData(FILE * const pFile,const unsigned int nName,const T & n)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 *****************************************************************************/
WriteCPODData(FILE * const pFile,const unsigned int nName,const CPODData & n,const unsigned int nEntries,const bool bValidData)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 *****************************************************************************/
WriteInterleaved(FILE * const pFile,SPODMesh & mesh)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 *****************************************************************************/
PVRTModelPODGetAnimArraySize(PVRTuint32 * pAnimDataIdx,PVRTuint32 ui32Frames,PVRTuint32 ui32Components)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 *****************************************************************************/
WritePOD(FILE * const pFile,const char * const pszExpOpt,const char * const pszHistory,const SPODScene & s)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 *****************************************************************************/
ReadCPODData(CPODData & s,CSource & src,const unsigned int nSpec,const bool bValidData)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 *****************************************************************************/
ReadCamera(SPODCamera & s,CSource & src)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 *****************************************************************************/
ReadLight(SPODLight & s,CSource & src)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 *****************************************************************************/
ReadMaterial(SPODMaterial & s,CSource & src)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 *****************************************************************************/
PVRTFixInterleavedEndiannessUsingCPODData(unsigned char * pInterleaved,CPODData & data,unsigned int ui32Size)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
PVRTFixInterleavedEndianness(SPODMesh & s)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 *****************************************************************************/
ReadMesh(SPODMesh & s,CSource & src)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 *****************************************************************************/
ReadNode(SPODNode & s,CSource & src)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 *****************************************************************************/
ReadTexture(SPODTexture & s,CSource & src)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 *****************************************************************************/
ReadScene(SPODScene & s,CSource & src)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 *****************************************************************************/
Read(SPODScene * const pS,CSource & src,char * const pszExpOpt,const size_t count,char * const pszHistory,const size_t historyCount)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