123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799 |
- /******************************************************************************
- @File PVRTVertex.cpp
- @Title PVRTVertex
- @Version
- @Copyright Copyright (C) Imagination Technologies Limited.
- @Platform ANSI compatible
- @Description Utility functions which process vertices.
- ******************************************************************************/
- /****************************************************************************
- ** Includes
- ****************************************************************************/
- #include "PVRTGlobal.h"
- #include "PVRTContext.h"
- #include <stdlib.h>
- #include <string.h>
- #include "PVRTFixedPoint.h"
- #include "PVRTMatrix.h"
- #include "PVRTVertex.h"
- /****************************************************************************
- ** Defines
- ****************************************************************************/
- /****************************************************************************
- ** Macros
- ****************************************************************************/
- #define MAX_VERTEX_OUT (3*nVtxNum)
- /****************************************************************************
- ** Structures
- ****************************************************************************/
- /****************************************************************************
- ** Constants
- ****************************************************************************/
- /****************************************************************************
- ** Local function definitions
- ****************************************************************************/
- /*****************************************************************************
- ** Functions
- *****************************************************************************/
- /*!***************************************************************************
- @Function PVRTVertexRead
- @Output pV
- @Input pData
- @Input eType
- @Input nCnt
- @Description Read a vector
- *****************************************************************************/
- void PVRTVertexRead(
- PVRTVECTOR4f * const pV,
- const void * const pData,
- const EPVRTDataType eType,
- const int nCnt)
- {
- int i;
- float *pOut = (float*)pV;
- pV->x = 0;
- pV->y = 0;
- pV->z = 0;
- pV->w = 1;
- switch(eType)
- {
- default:
- _ASSERT(false);
- break;
- case EPODDataFloat:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = ((float*)pData)[i];
- break;
- case EPODDataFixed16_16:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = ((int*)pData)[i] * 1.0f / (float)(1 << 16);
- break;
- case EPODDataInt:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((int*)pData)[i];
- break;
- case EPODDataUnsignedInt:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((unsigned int*)pData)[i];
- break;
- case EPODDataByte:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((char*)pData)[i];
- break;
- case EPODDataByteNorm:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((char*)pData)[i] / (float)((1 << 7)-1);
- break;
- case EPODDataUnsignedByte:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((unsigned char*)pData)[i];
- break;
- case EPODDataUnsignedByteNorm:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((unsigned char*)pData)[i] / (float)((1 << 8)-1);
- break;
- case EPODDataShort:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((short*)pData)[i];
- break;
- case EPODDataShortNorm:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((short*)pData)[i] / (float)((1 << 15)-1);
- break;
- case EPODDataUnsignedShort:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((unsigned short*)pData)[i];
- break;
- case EPODDataUnsignedShortNorm:
- for(i = 0; i < nCnt; ++i)
- pOut[i] = (float)((unsigned short*)pData)[i] / (float)((1 << 16)-1);
- break;
- case EPODDataRGBA:
- {
- unsigned int dwVal = *(unsigned int*)pData;
- unsigned char v[4];
- v[0] = (unsigned char) (dwVal >> 24);
- v[1] = (unsigned char) (dwVal >> 16);
- v[2] = (unsigned char) (dwVal >> 8);
- v[3] = (unsigned char) (dwVal >> 0);
- for(i = 0; i < 4; ++i)
- pOut[i] = 1.0f / 255.0f * (float)v[i];
- }
- break;
- case EPODDataARGB:
- case EPODDataD3DCOLOR:
- {
- unsigned int dwVal = *(unsigned int*)pData;
- unsigned char v[4];
- v[0] = (unsigned char) (dwVal >> 16);
- v[1] = (unsigned char) (dwVal >> 8);
- v[2] = (unsigned char) (dwVal >> 0);
- v[3] = (unsigned char) (dwVal >> 24);
- for(i = 0; i < 4; ++i)
- pOut[i] = 1.0f / 255.0f * (float)v[i];
- }
- break;
- case EPODDataUBYTE4:
- {
- unsigned int dwVal = *(unsigned int*)pData;
- unsigned char v[4];
- v[0] = (unsigned char) (dwVal >> 0);
- v[1] = (unsigned char) (dwVal >> 8);
- v[2] = (unsigned char) (dwVal >> 16);
- v[3] = (unsigned char) (dwVal >> 24);
- for(i = 0; i < 4; ++i)
- pOut[i] = v[i];
- }
- break;
- case EPODDataDEC3N:
- {
- int dwVal = *(int*)pData;
- int v[4];
- v[0] = (dwVal << 22) >> 22;
- v[1] = (dwVal << 12) >> 22;
- v[2] = (dwVal << 2) >> 22;
- v[3] = 0;
- for(i = 0; i < 3; ++i)
- pOut[i] = (float)v[i] * (1.0f / 511.0f);
- }
- break;
- }
- }
- /*!***************************************************************************
- @Function PVRTVertexRead
- @Output pV
- @Input pData
- @Input eType
- @Description Read an int
- *****************************************************************************/
- void PVRTVertexRead(
- unsigned int * const pV,
- const void * const pData,
- const EPVRTDataType eType)
- {
- switch(eType)
- {
- default:
- _ASSERT(false);
- break;
- case EPODDataUnsignedShort:
- *pV = *(unsigned short*)pData;
- break;
- case EPODDataUnsignedInt:
- *pV = *(unsigned int*)pData;
- break;
- }
- }
- /*!***************************************************************************
- @Function PVRTVertexWrite
- @Output pOut
- @Input eType
- @Input nCnt
- @Input pV
- @Description Write a vector
- *****************************************************************************/
- void PVRTVertexWrite(
- void * const pOut,
- const EPVRTDataType eType,
- const int nCnt,
- const PVRTVECTOR4f * const pV)
- {
- int i;
- float *pData = (float*)pV;
- switch(eType)
- {
- default:
- _ASSERT(false);
- break;
- case EPODDataDEC3N:
- {
- int v[3];
- for(i = 0; i < nCnt; ++i)
- {
- v[i] = (int)(pData[i] * 511.0f);
- v[i] = PVRT_CLAMP(v[i], -511, 511);
- v[i] &= 0x000003ff;
- }
- for(; i < 3; ++i)
- {
- v[i] = 0;
- }
- *(unsigned int*)pOut = (v[0] << 0) | (v[1] << 10) | (v[2] << 20);
- }
- break;
- case EPODDataARGB:
- case EPODDataD3DCOLOR:
- {
- unsigned char v[4];
- for(i = 0; i < nCnt; ++i)
- v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f);
- for(; i < 4; ++i)
- v[i] = 0;
- *(unsigned int*)pOut = (v[3] << 24) | (v[0] << 16) | (v[1] << 8) | v[2];
- }
- break;
- case EPODDataRGBA:
- {
- unsigned char v[4];
- for(i = 0; i < nCnt; ++i)
- v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f);
- for(; i < 4; ++i)
- v[i] = 0;
- *(unsigned int*)pOut = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
- }
- break;
- case EPODDataUBYTE4:
- {
- unsigned char v[4];
- for(i = 0; i < nCnt; ++i)
- v[i] = (unsigned char)PVRT_CLAMP(pData[i], 0.0f, 255.0f);
- for(; i < 4; ++i)
- v[i] = 0;
- *(unsigned int*)pOut = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0];
- }
- break;
- case EPODDataFloat:
- for(i = 0; i < nCnt; ++i)
- ((float*)pOut)[i] = pData[i];
- break;
- case EPODDataFixed16_16:
- for(i = 0; i < nCnt; ++i)
- ((int*)pOut)[i] = (int)(pData[i] * (float)(1 << 16));
- break;
- case EPODDataInt:
- for(i = 0; i < nCnt; ++i)
- ((int*)pOut)[i] = (int)pData[i];
- break;
- case EPODDataUnsignedInt:
- for(i = 0; i < nCnt; ++i)
- ((unsigned int*)pOut)[i] = (unsigned int)pData[i];
- break;
- case EPODDataByte:
- for(i = 0; i < nCnt; ++i)
- ((char*)pOut)[i] = (char)pData[i];
- break;
- case EPODDataByteNorm:
- for(i = 0; i < nCnt; ++i)
- ((char*)pOut)[i] = (char)(pData[i] * (float)((1 << 7)-1));
- break;
- case EPODDataUnsignedByte:
- for(i = 0; i < nCnt; ++i)
- ((unsigned char*)pOut)[i] = (unsigned char)pData[i];
- break;
- case EPODDataUnsignedByteNorm:
- for(i = 0; i < nCnt; ++i)
- ((char*)pOut)[i] = (unsigned char)(pData[i] * (float)((1 << 8)-1));
- break;
- case EPODDataShort:
- for(i = 0; i < nCnt; ++i)
- ((short*)pOut)[i] = (short)pData[i];
- break;
- case EPODDataShortNorm:
- for(i = 0; i < nCnt; ++i)
- ((short*)pOut)[i] = (short)(pData[i] * (float)((1 << 15)-1));
- break;
- case EPODDataUnsignedShort:
- for(i = 0; i < nCnt; ++i)
- ((unsigned short*)pOut)[i] = (unsigned short)pData[i];
- break;
- case EPODDataUnsignedShortNorm:
- for(i = 0; i < nCnt; ++i)
- ((unsigned short*)pOut)[i] = (unsigned short)(pData[i] * (float)((1 << 16)-1));
- break;
- }
- }
- /*!***************************************************************************
- @Function PVRTVertexWrite
- @Output pOut
- @Input eType
- @Input V
- @Description Write an int
- *****************************************************************************/
- void PVRTVertexWrite(
- void * const pOut,
- const EPVRTDataType eType,
- const unsigned int V)
- {
- switch(eType)
- {
- default:
- _ASSERT(false);
- break;
- case EPODDataUnsignedShort:
- *(unsigned short*)pOut = (unsigned short) V;
- break;
- case EPODDataUnsignedInt:
- *(unsigned int*)pOut = V;
- break;
- }
- }
- /*!***************************************************************************
- @Function PVRTVertexTangentBitangent
- @Output pvTan
- @Output pvBin
- @Input pvNor
- @Input pfPosA
- @Input pfPosB
- @Input pfPosC
- @Input pfTexA
- @Input pfTexB
- @Input pfTexC
- @Description Calculates the tangent and bitangent vectors for
- vertex 'A' of the triangle defined by the 3 supplied
- 3D position coordinates (pfPosA) and 2D texture
- coordinates (pfTexA).
- *****************************************************************************/
- void 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)
- {
- PVRTVECTOR3f BaseVector1, BaseVector2, AlignedVector;
- if(PVRTMatrixVec3DotProductF(*pvNor, *pvNor) == 0)
- {
- pvTan->x = 0;
- pvTan->y = 0;
- pvTan->z = 0;
- pvBin->x = 0;
- pvBin->y = 0;
- pvBin->z = 0;
- return;
- }
- /* BaseVectors are A-B and A-C. */
- BaseVector1.x = pfPosB[0] - pfPosA[0];
- BaseVector1.y = pfPosB[1] - pfPosA[1];
- BaseVector1.z = pfPosB[2] - pfPosA[2];
- BaseVector2.x = pfPosC[0] - pfPosA[0];
- BaseVector2.y = pfPosC[1] - pfPosA[1];
- BaseVector2.z = pfPosC[2] - pfPosA[2];
- if (pfTexB[0]==pfTexA[0] && pfTexC[0]==pfTexA[0])
- {
- // Degenerate tri
- // _ASSERT(0);
- pvTan->x = 0;
- pvTan->y = 0;
- pvTan->z = 0;
- pvBin->x = 0;
- pvBin->y = 0;
- pvBin->z = 0;
- }
- else
- {
- /* Calc the vector that follows the V direction (it is not the tangent vector)*/
- if(pfTexB[0]==pfTexA[0]) {
- AlignedVector = BaseVector1;
- if((pfTexB[1] - pfTexA[1]) < 0) {
- AlignedVector.x = -AlignedVector.x;
- AlignedVector.y = -AlignedVector.y;
- AlignedVector.z = -AlignedVector.z;
- }
- } else if(pfTexC[0]==pfTexA[0]) {
- AlignedVector = BaseVector2;
- if((pfTexC[1] - pfTexA[1]) < 0) {
- AlignedVector.x = -AlignedVector.x;
- AlignedVector.y = -AlignedVector.y;
- AlignedVector.z = -AlignedVector.z;
- }
- } else {
- float fFac;
- fFac = -(pfTexB[0] - pfTexA[0]) / (pfTexC[0] - pfTexA[0]);
- /* This is the vector that follows the V direction (it is not the tangent vector)*/
- AlignedVector.x = BaseVector1.x + BaseVector2.x * fFac;
- AlignedVector.y = BaseVector1.y + BaseVector2.y * fFac;
- AlignedVector.z = BaseVector1.z + BaseVector2.z * fFac;
- if(((pfTexB[1] - pfTexA[1]) + (pfTexC[1] - pfTexA[1]) * fFac) < 0) {
- AlignedVector.x = -AlignedVector.x;
- AlignedVector.y = -AlignedVector.y;
- AlignedVector.z = -AlignedVector.z;
- }
- }
- PVRTMatrixVec3NormalizeF(AlignedVector, AlignedVector);
- /* The Tangent vector is perpendicular to the plane defined by vAlignedVector and the Normal. */
- PVRTMatrixVec3CrossProductF(*pvTan, *pvNor, AlignedVector);
- /* The Bitangent vector is the vector perpendicular to the Normal and Tangent (and
- that follows the vAlignedVector direction) */
- PVRTMatrixVec3CrossProductF(*pvBin, *pvTan, *pvNor);
- _ASSERT(PVRTMatrixVec3DotProductF(*pvBin, AlignedVector) > 0.0f);
- // Worry about wrapping; this is esentially a 2D cross product on texture coords
- if((pfTexC[0]-pfTexA[0])*(pfTexB[1]-pfTexA[1]) < (pfTexC[1]-pfTexA[1])*(pfTexB[0]-pfTexA[0])) {
- pvTan->x = -pvTan->x;
- pvTan->y = -pvTan->y;
- pvTan->z = -pvTan->z;
- }
- /* Normalize results */
- PVRTMatrixVec3NormalizeF(*pvTan, *pvTan);
- PVRTMatrixVec3NormalizeF(*pvBin, *pvBin);
- _ASSERT(PVRTMatrixVec3DotProductF(*pvNor, *pvNor) > 0.9f);
- _ASSERT(PVRTMatrixVec3DotProductF(*pvTan, *pvTan) > 0.9f);
- _ASSERT(PVRTMatrixVec3DotProductF(*pvBin, *pvBin) > 0.9f);
- }
- }
- /*!***************************************************************************
- @Function PVRTVertexGenerateTangentSpace
- @Output pnVtxNumOut Output vertex count
- @Output pVtxOut Output vertices (program must free() this)
- @Modified pui32Idx input AND output; index array for triangle list
- @Input nVtxNum Input vertex count
- @Input pVtx Input vertices
- @Input nStride Size of a vertex (in bytes)
- @Input nOffsetPos Offset in bytes to the vertex position
- @Input eTypePos Data type of the position
- @Input nOffsetNor Offset in bytes to the vertex normal
- @Input eTypeNor Data type of the normal
- @Input nOffsetTex Offset in bytes to the vertex texture coordinate to use
- @Input eTypeTex Data type of the texture coordinate
- @Input nOffsetTan Offset in bytes to the vertex tangent
- @Input eTypeTan Data type of the tangent
- @Input nOffsetBin Offset in bytes to the vertex bitangent
- @Input eTypeBin Data type of the bitangent
- @Input nTriNum Number of triangles
- @Input fSplitDifference Split a vertex if the DP3 of tangents/bitangents are below this (range -1..1)
- @Return PVR_FAIL if there was a problem.
- @Description Calculates the tangent space for all supplied vertices.
- Writes tangent and bitangent vectors to the output
- vertices, copies all other elements from input vertices.
- Will split vertices if necessary - i.e. if two triangles
- sharing a vertex want to assign it different
- tangent-space matrices. The decision whether to split
- uses fSplitDifference - of the DP3 of two desired
- tangents or two desired bitangents is higher than this,
- the vertex will be split.
- *****************************************************************************/
- EPVRTError 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)
- {
- const int cnMaxSharedVtx = 32;
- struct SVtxData
- {
- int n; // Number of items in following arrays, AKA number of tris using this vtx
- PVRTVECTOR3f pvTan[cnMaxSharedVtx]; // Tangent (one per triangle referencing this vtx)
- PVRTVECTOR3f pvBin[cnMaxSharedVtx]; // Bitangent (one per triangle referencing this vtx)
- int pnTri[cnMaxSharedVtx]; // Triangle index (one per triangle referencing this vtx)
- };
- SVtxData *psVtxData; // Array of desired tangent spaces per vertex
- SVtxData *psTSpass; // Array of *different* tangent spaces desired for current vertex
- unsigned int nTSpassLen;
- SVtxData *psVtx, *psCmp;
- unsigned int nVert, nCurr, i, j; // Loop counters
- unsigned int nIdx0, nIdx1, nIdx2;
- float pfPos0[4], pfPos1[4], pfPos2[4];
- float pfTex0[4], pfTex1[4], pfTex2[4];
- float pfNor0[4], pfNor1[4], pfNor2[4];
- unsigned int *pui32IdxNew; // New index array, this will be copied over the input array
- // Initialise the outputs
- *pnVtxNumOut = 0;
- *pVtxOut = (char*)malloc(MAX_VERTEX_OUT * nStride);
- if(!*pVtxOut)
- {
- return PVR_FAIL;
- }
- // Allocate some work space
- pui32IdxNew = (unsigned int*)malloc(nTriNum * 3 * sizeof(*pui32IdxNew));
- _ASSERT(pui32IdxNew);
- psVtxData = (SVtxData*)calloc(nVtxNum, sizeof(*psVtxData));
- _ASSERT(psVtxData);
- psTSpass = (SVtxData*)calloc(cnMaxSharedVtx, sizeof(*psTSpass));
- _ASSERT(psTSpass);
- if(!pui32IdxNew || !psVtxData || !psTSpass)
- {
- return PVR_FAIL;
- }
- for(nCurr = 0; nCurr < nTriNum; ++nCurr) {
- nIdx0 = pui32Idx[3*nCurr+0];
- nIdx1 = pui32Idx[3*nCurr+1];
- nIdx2 = pui32Idx[3*nCurr+2];
- _ASSERT(nIdx0 < nVtxNum);
- _ASSERT(nIdx1 < nVtxNum);
- _ASSERT(nIdx2 < nVtxNum);
- if(nIdx0 == nIdx1 || nIdx1 == nIdx2 || nIdx0 == nIdx2) {
- _RPT0(_CRT_WARN,"GenerateTangentSpace(): Degenerate triangle found.\n");
- return PVR_FAIL;
- }
- if(
- psVtxData[nIdx0].n >= cnMaxSharedVtx ||
- psVtxData[nIdx1].n >= cnMaxSharedVtx ||
- psVtxData[nIdx2].n >= cnMaxSharedVtx)
- {
- _RPT0(_CRT_WARN,"GenerateTangentSpace(): Too many tris sharing a vtx.\n");
- return PVR_FAIL;
- }
- PVRTVertexRead((PVRTVECTOR4f*) &pfPos0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetPos, eTypePos, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfPos1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetPos, eTypePos, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfPos2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetPos, eTypePos, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfNor0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetNor, eTypeNor, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfNor1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetNor, eTypeNor, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfNor2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetNor, eTypeNor, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfTex0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetTex, eTypeTex, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfTex1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetTex, eTypeTex, 3);
- PVRTVertexRead((PVRTVECTOR4f*) &pfTex2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetTex, eTypeTex, 3);
- PVRTVertexTangentBitangent(
- &psVtxData[nIdx0].pvTan[psVtxData[nIdx0].n],
- &psVtxData[nIdx0].pvBin[psVtxData[nIdx0].n],
- (PVRTVECTOR3f*) &pfNor0[0],
- pfPos0, pfPos1, pfPos2,
- pfTex0, pfTex1, pfTex2);
- PVRTVertexTangentBitangent(
- &psVtxData[nIdx1].pvTan[psVtxData[nIdx1].n],
- &psVtxData[nIdx1].pvBin[psVtxData[nIdx1].n],
- (PVRTVECTOR3f*) &pfNor1[0],
- pfPos1, pfPos2, pfPos0,
- pfTex1, pfTex2, pfTex0);
- PVRTVertexTangentBitangent(
- &psVtxData[nIdx2].pvTan[psVtxData[nIdx2].n],
- &psVtxData[nIdx2].pvBin[psVtxData[nIdx2].n],
- (PVRTVECTOR3f*) &pfNor2[0],
- pfPos2, pfPos0, pfPos1,
- pfTex2, pfTex0, pfTex1);
- psVtxData[nIdx0].pnTri[psVtxData[nIdx0].n] = nCurr;
- psVtxData[nIdx1].pnTri[psVtxData[nIdx1].n] = nCurr;
- psVtxData[nIdx2].pnTri[psVtxData[nIdx2].n] = nCurr;
- ++psVtxData[nIdx0].n;
- ++psVtxData[nIdx1].n;
- ++psVtxData[nIdx2].n;
- }
- // Now let's go through the vertices calculating avg tangent-spaces; create new vertices if necessary
- for(nVert = 0; nVert < nVtxNum; ++nVert) {
- psVtx = &psVtxData[nVert];
- // Start out with no output vertices required for this input vertex
- nTSpassLen = 0;
- // Run through each desired tangent space for this vertex
- for(nCurr = 0; nCurr < (unsigned int) psVtx->n; ++nCurr) {
- // Run through the possible vertices we can share with to see if we match
- for(i = 0; i < nTSpassLen; ++i) {
- psCmp = &psTSpass[i];
- // Check all the shared vertices which match
- for(j = 0; j < (unsigned int) psCmp->n; ++j) {
- if(PVRTMatrixVec3DotProductF(psVtx->pvTan[nCurr], psCmp->pvTan[j]) < fSplitDifference)
- break;
- if(PVRTMatrixVec3DotProductF(psVtx->pvBin[nCurr], psCmp->pvBin[j]) < fSplitDifference)
- break;
- }
- // Did all the existing vertices match?
- if(j == (unsigned int) psCmp->n) {
- // Yes, so add to list
- _ASSERT(psCmp->n < cnMaxSharedVtx);
- psCmp->pvTan[psCmp->n] = psVtx->pvTan[nCurr];
- psCmp->pvBin[psCmp->n] = psVtx->pvBin[nCurr];
- psCmp->pnTri[psCmp->n] = psVtx->pnTri[nCurr];
- ++psCmp->n;
- break;
- }
- }
- if(i == nTSpassLen) {
- // We never found another matching matrix, so let's add this as a different one
- _ASSERT(nTSpassLen < cnMaxSharedVtx);
- psTSpass[nTSpassLen].pvTan[0] = psVtx->pvTan[nCurr];
- psTSpass[nTSpassLen].pvBin[0] = psVtx->pvBin[nCurr];
- psTSpass[nTSpassLen].pnTri[0] = psVtx->pnTri[nCurr];
- psTSpass[nTSpassLen].n = 1;
- ++nTSpassLen;
- }
- }
- // OK, now we have 'nTSpassLen' different desired matrices, so we need to add that many to output
- _ASSERT(nTSpassLen >= 1);
- for(nCurr = 0; nCurr < nTSpassLen; ++nCurr) {
- psVtx = &psTSpass[nCurr];
- memset(&pfPos0, 0, sizeof(pfPos0));
- memset(&pfPos1, 0, sizeof(pfPos1));
- for(i = 0; i < (unsigned int) psVtx->n; ++i) {
- // Sum the tangent & bitangents, so we can average them
- pfPos0[0] += psVtx->pvTan[i].x;
- pfPos0[1] += psVtx->pvTan[i].y;
- pfPos0[2] += psVtx->pvTan[i].z;
- pfPos1[0] += psVtx->pvBin[i].x;
- pfPos1[1] += psVtx->pvBin[i].y;
- pfPos1[2] += psVtx->pvBin[i].z;
- // Update triangle indices to use this vtx
- if(pui32Idx[3 * psVtx->pnTri[i] + 0] == nVert) {
- pui32IdxNew[3 * psVtx->pnTri[i] + 0] = *pnVtxNumOut;
- } else if(pui32Idx[3 * psVtx->pnTri[i] + 1] == nVert) {
- pui32IdxNew[3 * psVtx->pnTri[i] + 1] = *pnVtxNumOut;
- } else if(pui32Idx[3 * psVtx->pnTri[i] + 2] == nVert) {
- pui32IdxNew[3 * psVtx->pnTri[i] + 2] = *pnVtxNumOut;
- } else {
- _ASSERT(0);
- }
- }
- PVRTMatrixVec3NormalizeF(*(PVRTVECTOR3f*) &pfPos0[0], *(PVRTVECTOR3f*) &pfPos0[0]);
- PVRTMatrixVec3NormalizeF(*(PVRTVECTOR3f*) &pfPos1[0], *(PVRTVECTOR3f*) &pfPos1[0]);
- if(*pnVtxNumOut >= MAX_VERTEX_OUT) {
- _RPT0(_CRT_WARN,"PVRTVertexGenerateTangentSpace() ran out of working space! (Too many split vertices)\n");
- return PVR_FAIL;
- }
- memcpy(&(*pVtxOut)[(*pnVtxNumOut) * nStride], &pVtx[nVert*nStride], nStride);
- PVRTVertexWrite((char*)&(*pVtxOut)[(*pnVtxNumOut) * nStride] + nOffsetTan, eTypeTan, 3, (PVRTVECTOR4f*) &pfPos0[0]);
- PVRTVertexWrite((char*)&(*pVtxOut)[(*pnVtxNumOut) * nStride] + nOffsetBin, eTypeBin, 3, (PVRTVECTOR4f*) &pfPos1[0]);
- ++*pnVtxNumOut;
- }
- }
- FREE(psTSpass);
- FREE(psVtxData);
- *pVtxOut = (char*)realloc(*pVtxOut, *pnVtxNumOut * nStride);
- _ASSERT(*pVtxOut);
- memcpy(pui32Idx, pui32IdxNew, nTriNum * 3 * sizeof(*pui32IdxNew));
- FREE(pui32IdxNew);
- _RPT3(_CRT_WARN, "GenerateTangentSpace(): %d tris, %d vtx in, %d vtx out\n", nTriNum, nVtxNum, *pnVtxNumOut);
- _ASSERT(*pnVtxNumOut >= nVtxNum);
- return PVR_SUCCESS;
- }
- /*****************************************************************************
- End of file (PVRTVertex.cpp)
- *****************************************************************************/
|