• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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