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