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