123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- /******************************************************************************
- @File PVRTBoneBatch.cpp
- @Title PVRTBoneBatch
- @Version
- @Copyright Copyright (C) Imagination Technologies Limited.
- @Platform ANSI compatible
- @Description Utility functions which process vertices.
- ******************************************************************************/
- /****************************************************************************
- ** Includes
- ****************************************************************************/
- #include "PVRTGlobal.h"
- #include "PVRTContext.h"
- #include <vector>
- #include <list>
- #include "PVRTMatrix.h"
- #include "PVRTVertex.h"
- #include "PVRTBoneBatch.h"
- /****************************************************************************
- ** Defines
- ****************************************************************************/
- /****************************************************************************
- ** Macros
- ****************************************************************************/
- /****************************************************************************
- ** Structures
- ****************************************************************************/
- /*!***************************************************************************
- @Class CBatch
- @Brief Class to contain and manage batch information.
- *****************************************************************************/
- class CBatch
- {
- protected:
- int m_nCapacity, // Maximum size of the batch
- m_nCnt, // Number of elements currently contained in the batch
- *m_pnPalette; // Array of palette indices
- public:
- /*!***************************************************************************
- @Function CBatch
- @Description The default constructor
- *****************************************************************************/
- CBatch()
- {
- m_pnPalette = NULL;
- }
- /*!***************************************************************************
- @Function CBatch
- @Input src CBatch to copy
- @Description Copy constructor
- *****************************************************************************/
- CBatch(const CBatch &src)
- {
- m_pnPalette = NULL;
- SetSize(src.m_nCapacity);
- *this = src;
- }
-
- /*!***************************************************************************
- @Function ~CBatch
- @Description Destructor
- *****************************************************************************/
- ~CBatch()
- {
- FREE(m_pnPalette);
- }
-
- /*!***************************************************************************
- @Function operator=
- @Description Operator overload for the '=' operand
- *****************************************************************************/
- void operator= (const CBatch &src)
- {
- _ASSERT(m_nCapacity == src.m_nCapacity);
- m_nCnt = src.m_nCnt;
- memcpy(m_pnPalette, src.m_pnPalette, m_nCnt * sizeof(*m_pnPalette));
- }
-
- /*!***************************************************************************
- @Function SetSize
- @Input nSize The new size of the batch
- @Description Delete all current information and resizes the batch
- to the value that has been passed in.
- *****************************************************************************/
- void SetSize(const int nSize)
- {
- FREE(m_pnPalette);
- m_nCapacity = nSize;
- m_nCnt = 0;
- m_pnPalette = (int*)malloc(m_nCapacity * sizeof(*m_pnPalette));
- }
-
- /*!***************************************************************************
- @Function Clear
- @Description Resets the count
- *****************************************************************************/
- void Clear()
- {
- m_nCnt = 0;
- }
- /*!***************************************************************************
- @Function Clear
- @Input n The index of the new item
- Return bool Returns true if the item already exists or has been added.
- @Description Adds a new item to the batch, providing it has not already
- been added to the batch and the count doesn't exceed the
- maximum number of bones the batch can hold.
- *****************************************************************************/
- bool Add(const int n)
- {
- int i;
- if(n < 0)
- return false;
- // If we already have this item, do nothing
- for(i = 0; i < m_nCnt; ++i)
- {
- if(m_pnPalette[i] == n)
- return true;
- }
- // Add the new item
- if(m_nCnt < m_nCapacity)
- {
- m_pnPalette[m_nCnt] = n;
- ++m_nCnt;
- return true;
- }
- else
- {
- return false;
- }
- }
- /*!***************************************************************************
- @Function Merge
- @Input src The batch to merge with
- @Description Merges the input batch with the current batch.
- *****************************************************************************/
- void Merge(const CBatch &src)
- {
- int i;
- for(i = 0; i < src.m_nCnt; ++i)
- Add(src.m_pnPalette[i]);
- }
- /*!***************************************************************************
- @Function TestMerge
- @Input src The batch to merge with
- @Return int The number of items that are not already
- present in the batch. -1 if the merge will
- exceed the capacity of the batch
- @Description Tests how many of the items of the input batch are not
- already contained in the batch. This returns the number of
- items that would need to be added, or -1 if the number
- of additional items would exceed the capacity of the batch.
- *****************************************************************************/
- int TestMerge(const CBatch &src)
- {
- int i, nCnt;
- nCnt = 0;
- for(i = 0; i < src.m_nCnt; ++i)
- if(!Contains(src.m_pnPalette[i]))
- ++nCnt;
- return m_nCnt+nCnt > m_nCapacity ? -1 : nCnt;
- }
- /*!***************************************************************************
- @Function Contains
- @Input src The batch to compare
- @Return bool Returns true if the batch and the input batch
- have at least one item in common
- @Description Returns true if the batch's have at least one item in common
- *****************************************************************************/
- bool Contains(const CBatch &batch) const
- {
- int i;
- for(i = 0; i < batch.m_nCnt; ++i)
- if(!Contains(batch.m_pnPalette[i]))
- return false;
- return true;
- }
-
- /*!***************************************************************************
- @Function Contains
- @Input n The index of the new item
- @Return bool Returns true if the batch contains the item
- @Description Returns true if the batch contains the item.
- *****************************************************************************/
- bool Contains(const int n) const
- {
- int i;
- for(i = 0; i < m_nCnt; ++i)
- if(m_pnPalette[i] == n)
- return true;
- return false;
- }
-
- /*!***************************************************************************
- @Function Write
- @Output pn The array of items to overwrite
- @Output pnCnt The number of items in the array
- @Description Writes the array of items and the number of items to the output
- parameters.
- *****************************************************************************/
- void Write(
- int * const pn,
- int * const pnCnt) const
- {
- memcpy(pn, m_pnPalette, m_nCnt * sizeof(*pn));
- *pnCnt = m_nCnt;
- }
- /*!***************************************************************************
- @Function GetVertexBoneIndices
- @Modified pfI Returned index
- @Input pfW Weight?
- @Input n Length of index array
- @Description For each element of the input array, the index value is compared
- with the palette's index value. If the values are equal, the
- value of the current input array element is replaced with the
- palette index, otherwise the value is set to zero.
- *****************************************************************************/
- void GetVertexBoneIndices(
- float * const pfI,
- const float * const pfW,
- const int n)
- {
- int i, j;
- for(i = 0; i < n; ++i)
- {
- if(pfW[i] != 0)
- {
- for(j = 0; j < m_nCnt; ++j)
- {
- if(pfI[i] != m_pnPalette[j])
- continue;
- pfI[i] = (float)j;
- break;
- }
- // This batch *must* contain this vertex
- _ASSERT(j != m_nCnt);
- }
- else
- {
- pfI[i] = 0;
- }
- }
- }
- };
- /*!***************************************************************************
- @Class CGrowableArray
- @Brief Class that provides an array structure that can change its size dynamically.
- *****************************************************************************/
- class CGrowableArray
- {
- protected:
- char *m_p;
- int m_nSize;
- int m_nCnt;
- public:
- /*!***************************************************************************
- @Function CGrowableArray
- @Input nSize The size of the data (in bytes) that the array will contain
- @Description Initialises the size of the data the array will contain to the
- value that has been passed in and initialises the remaining
- data members with default values.
- *****************************************************************************/
- CGrowableArray(const int nSize)
- {
- m_p = NULL;
- m_nSize = nSize;
- m_nCnt = 0;
- }
-
- /*!***************************************************************************
- @Function ~CGrowableArray
- @Description The destructor
- *****************************************************************************/
- ~CGrowableArray()
- {
- FREE(m_p);
- }
-
- /*!***************************************************************************
- @Function Append
- @Input pData The data to append
- @Input nCnt The amount of data elements to append
- @Description Resizes the array and appends the new data that has been passed in.
- *****************************************************************************/
- void Append(const void * const pData, const int nCnt)
- {
- m_p = (char*)realloc(m_p, (m_nCnt + nCnt) * m_nSize);
- _ASSERT(m_p);
- memcpy(&m_p[m_nCnt * m_nSize], pData, nCnt * m_nSize);
- m_nCnt += nCnt;
- }
- /*!***************************************************************************
- @Function last
- @Return char* The last element of the array
- @Description Returns a pointer to the last element of the array.
- *****************************************************************************/
- char *last()
- {
- return at(m_nCnt-1);
- }
- /*!***************************************************************************
- @Function at
- @Input nIdx The index of the requested element
- @Return char* The element at the specified index of the array
- @Description Returns a pointer to the data at the specified index of the array.
- *****************************************************************************/
- char *at(const int nIdx)
- {
- return &m_p[nIdx * m_nSize];
- }
- /*!***************************************************************************
- @Function size
- @Return int The number of elements contained in the array
- @Description Returns the number of elements contained in the array.
- *****************************************************************************/
- int size() const
- {
- return m_nCnt;
- }
- /*!***************************************************************************
- @Function Surrender
- @Output pData The pointer to surrender the data to
- @Description Assigns the memory address of the data to the pointer that has
- been passed in. Sets the class's number of elements and
- data pointer back to their default values.
- *****************************************************************************/
- int Surrender(
- char ** const pData)
- {
- int nCnt;
- *pData = m_p;
- nCnt = m_nCnt;
- m_p = NULL;
- m_nCnt = 0;
- return nCnt;
- }
- };
- /****************************************************************************
- ** Constants
- ****************************************************************************/
- /****************************************************************************
- ** Local function definitions
- ****************************************************************************/
- static bool FillBatch(
- CBatch &batch,
- const unsigned int * const pui32Idx, // input AND output; index array for triangle list
- const char * const pVtx, // Input vertices
- const int nStride, // Size of a vertex (in bytes)
- const int nOffsetWeight, // Offset in bytes to the vertex bone-weights
- EPVRTDataType eTypeWeight, // Data type of the vertex bone-weights
- const int nOffsetIdx, // Offset in bytes to the vertex bone-indices
- EPVRTDataType eTypeIdx, // Data type of the vertex bone-indices
- const int nVertexBones); // Number of bones affecting each vertex
- static bool BonesMatch(
- const float * const pfIdx0,
- const float * const pfIdx1);
- /*****************************************************************************
- ** Functions
- *****************************************************************************/
- /*!***************************************************************************
- @Function Create
- @Output pnVtxNumOut vertex count
- @Output pVtxOut Output vertices (program must free() this)
- @Modified pui32Idx index array for triangle list
- @Input nVtxNum vertex count
- @Input pVtx vertices
- @Input nStride Size of a vertex (in bytes)
- @Input nOffsetWeight Offset in bytes to the vertex bone-weights
- @Input eTypeWeight Data type of the vertex bone-weights
- @Input nOffsetIdx Offset in bytes to the vertex bone-indices
- @Input eTypeIdx Data type of the vertex bone-indices
- @Input nTriNum Number of triangles
- @Input nBatchBoneMax Number of bones a batch can reference
- @Input nVertexBones Number of bones affecting each vertex
- @Returns PVR_SUCCESS if successful
- @Description Fills the bone batch structure
- *****************************************************************************/
- EPVRTError CPVRTBoneBatches::Create(
- int * const pnVtxNumOut,
- char ** const pVtxOut,
- unsigned int * const pui32Idx,
- const int nVtxNum,
- const char * const pVtx,
- const int nStride,
- const int nOffsetWeight,
- const EPVRTDataType eTypeWeight,
- const int nOffsetIdx,
- const EPVRTDataType eTypeIdx,
- const int nTriNum,
- const int nBatchBoneMax,
- const int nVertexBones)
- {
- int i, j, k, nTriCnt;
- CBatch batch;
- std::list<CBatch> lBatch;
- std::list<CBatch>::iterator iBatch, iBatch2;
- CBatch **ppBatch;
- unsigned int *pui32IdxNew;
- const char *pV, *pV2;
- PVRTVECTOR4 vWeight, vIdx;
- PVRTVECTOR4 vWeight2, vIdx2;
- std::vector<int> *pvDup;
- CGrowableArray *pVtxBuf;
- unsigned int ui32SrcIdx;
- memset(this, 0, sizeof(*this));
- if(nVertexBones <= 0 || nVertexBones > 4)
- {
- _RPT0(_CRT_WARN, "CPVRTBoneBatching() will only handle 1..4 bones per vertex.\n");
- return PVR_FAIL;
- }
- memset(&vWeight, 0, sizeof(vWeight));
- memset(&vWeight2, 0, sizeof(vWeight2));
- memset(&vIdx, 0, sizeof(vIdx));
- memset(&vIdx2, 0, sizeof(vIdx2));
- batch.SetSize(nBatchBoneMax);
- // Allocate some working space
- ppBatch = (CBatch**)malloc(nTriNum * sizeof(*ppBatch));
- pui32IdxNew = (unsigned int*)malloc(nTriNum * 3 * sizeof(*pui32IdxNew));
- pvDup = new std::vector<int>[nVtxNum];
- pVtxBuf = new CGrowableArray(nStride);
- // Check what batches are necessary
- for(i = 0; i < nTriNum; ++i)
- {
- // Build the batch
- if(!FillBatch(batch, &pui32Idx[i * 3], pVtx, nStride, nOffsetWeight, eTypeWeight, nOffsetIdx, eTypeIdx, nVertexBones))
- return PVR_FAIL;
- // Update the batch list
- for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
- {
- // Do nothing if an existing batch is a superset of this new batch
- if(iBatch->Contains(batch))
- {
- break;
- }
- // If this new batch is a superset of an existing batch, replace the old with the new
- if(batch.Contains(*iBatch))
- {
- *iBatch = batch;
- break;
- }
- }
- // If no suitable batch exists, create a new one
- if(iBatch == lBatch.end())
- {
- lBatch.push_back(batch);
- }
- }
- // Group batches into fewer batches. This simple greedy algorithm could be improved.
- int nCurrent, nShortest;
- std::list<CBatch>::iterator iShortest;
- for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
- {
- for(;;)
- {
- nShortest = nBatchBoneMax;
- iBatch2 = iBatch;
- ++iBatch2;
- for(; iBatch2 != lBatch.end(); ++iBatch2)
- {
- nCurrent = iBatch->TestMerge(*iBatch2);
- if(nCurrent >= 0 && nCurrent < nShortest)
- {
- nShortest = nCurrent;
- iShortest = iBatch2;
- }
- }
- if(nShortest < nBatchBoneMax)
- {
- iBatch->Merge(*iShortest);
- lBatch.erase(iShortest);
- }
- else
- {
- break;
- }
- }
- }
- // Place each triangle in a batch.
- for(i = 0; i < nTriNum; ++i)
- {
- if(!FillBatch(batch, &pui32Idx[i * 3], pVtx, nStride, nOffsetWeight, eTypeWeight, nOffsetIdx, eTypeIdx, nVertexBones))
- return PVR_FAIL;
- for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
- {
- if(iBatch->Contains(batch))
- {
- ppBatch[i] = &*iBatch;
- break;
- }
- }
- _ASSERT(iBatch != lBatch.end());
- }
- // Now that we know how many batches there are, we can allocate the output arrays
- CPVRTBoneBatches::nBatchBoneMax = nBatchBoneMax;
- pnBatches = new int[lBatch.size() * nBatchBoneMax];
- pnBatchBoneCnt = new int[lBatch.size()];
- pnBatchOffset = new int[lBatch.size()];
- memset(pnBatches, 0, lBatch.size() * nBatchBoneMax * sizeof(int));
- memset(pnBatchBoneCnt, 0, lBatch.size() * sizeof(int));
- memset(pnBatchOffset, 0, lBatch.size() * sizeof(int));
- // Create the new triangle index list, the new vertex list, and the batch information.
- nTriCnt = 0;
- nBatchCnt = 0;
- for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
- {
- // Write pnBatches, pnBatchBoneCnt and pnBatchOffset for this batch.
- iBatch->Write(&pnBatches[nBatchCnt * nBatchBoneMax], &pnBatchBoneCnt[nBatchCnt]);
- pnBatchOffset[nBatchCnt] = nTriCnt;
- ++nBatchCnt;
- // Copy any triangle indices for this batch
- for(i = 0; i < nTriNum; ++i)
- {
- if(ppBatch[i] != &*iBatch)
- continue;
- for(j = 0; j < 3; ++j)
- {
- ui32SrcIdx = pui32Idx[3 * i + j];
- // Get desired bone indices for this vertex/tri
- pV = &pVtx[ui32SrcIdx * nStride];
- PVRTVertexRead(&vWeight, &pV[nOffsetWeight], eTypeWeight, nVertexBones);
- PVRTVertexRead(&vIdx, &pV[nOffsetIdx], eTypeIdx, nVertexBones);
- iBatch->GetVertexBoneIndices(&vIdx.x, &vWeight.x, nVertexBones);
- _ASSERT(vIdx.x == 0 || vIdx.x != vIdx.y);
- // Check the list of copies of this vertex for one with suitable bone indices
- for(k = 0; k < (int)pvDup[ui32SrcIdx].size(); ++k)
- {
- pV2 = pVtxBuf->at(pvDup[ui32SrcIdx][k]);
- PVRTVertexRead(&vWeight2, &pV2[nOffsetWeight], eTypeWeight, nVertexBones);
- PVRTVertexRead(&vIdx2, &pV2[nOffsetIdx], eTypeIdx, nVertexBones);
- if(BonesMatch(&vIdx2.x, &vIdx.x))
- {
- pui32IdxNew[3 * nTriCnt + j] = pvDup[ui32SrcIdx][k];
- break;
- }
- }
- if(k != (int)pvDup[ui32SrcIdx].size())
- continue;
- // Did not find a suitable duplicate of the vertex, so create one
- pVtxBuf->Append(pV, 1);
- pvDup[ui32SrcIdx].push_back(pVtxBuf->size() - 1);
- PVRTVertexWrite(&pVtxBuf->last()[nOffsetIdx], eTypeIdx, nVertexBones, &vIdx);
- pui32IdxNew[3 * nTriCnt + j] = pVtxBuf->size() - 1;
- }
- ++nTriCnt;
- }
- }
- _ASSERTE(nTriCnt == nTriNum);
- _ASSERTE(nBatchCnt == (int)lBatch.size());
- // Copy indices to output
- memcpy(pui32Idx, pui32IdxNew, nTriNum * 3 * sizeof(*pui32IdxNew));
- // Move vertices to output
- *pnVtxNumOut = pVtxBuf->Surrender(pVtxOut);
- // Free working memory
- delete [] pvDup;
- delete pVtxBuf;
- FREE(ppBatch);
- FREE(pui32IdxNew);
- return PVR_SUCCESS;
- }
- /****************************************************************************
- ** Local functions
- ****************************************************************************/
- /*!***********************************************************************
- @Function FillBatch
- @Modified batch The batch to fill
- @Input pui32Idx Input index array for triangle list
- @Input pVtx Input vertices
- @Input nStride Size of a vertex (in bytes)
- @Input nOffsetWeight Offset in bytes to the vertex bone-weights
- @Input eTypeWeight Data type of the vertex bone-weights
- @Input nOffsetIdx Offset in bytes to the vertex bone-indices
- @Input eTypeIdx Data type of the vertex bone-indices
- @Input nVertexBones Number of bones affecting each vertex
- @Returns True if successful
- @Description Creates a bone batch from a triangle.
- *************************************************************************/
- static bool FillBatch(
- CBatch &batch,
- const unsigned int * const pui32Idx,
- const char * const pVtx,
- const int nStride,
- const int nOffsetWeight,
- EPVRTDataType eTypeWeight,
- const int nOffsetIdx,
- EPVRTDataType eTypeIdx,
- const int nVertexBones)
- {
- PVRTVECTOR4 vWeight, vIdx;
- const char *pV;
- int i;
- bool bOk;
- bOk = true;
- batch.Clear();
- for(i = 0; i < 3; ++i)
- {
- pV = &pVtx[pui32Idx[i] * nStride];
- memset(&vWeight, 0, sizeof(vWeight));
- PVRTVertexRead(&vWeight, &pV[nOffsetWeight], eTypeWeight, nVertexBones);
- PVRTVertexRead(&vIdx, &pV[nOffsetIdx], eTypeIdx, nVertexBones);
- if(nVertexBones >= 1 && vWeight.x != 0) bOk &= batch.Add((int)vIdx.x);
- if(nVertexBones >= 2 && vWeight.y != 0) bOk &= batch.Add((int)vIdx.y);
- if(nVertexBones >= 3 && vWeight.z != 0) bOk &= batch.Add((int)vIdx.z);
- if(nVertexBones >= 4 && vWeight.w != 0) bOk &= batch.Add((int)vIdx.w);
- }
- return bOk;
- }
- /*!***********************************************************************
- @Function BonesMatch
- @Input pfIdx0 A float 4 array
- @Input pfIdx1 A float 4 array
- @Returns True if the two float4 arraus are identical
- @Description Checks if the two float4 arrays are identical.
- *************************************************************************/
- static bool BonesMatch(
- const float * const pfIdx0,
- const float * const pfIdx1)
- {
- int i;
- for(i = 0; i < 4; ++i)
- {
- if(pfIdx0[i] != pfIdx1[i])
- return false;
- }
- return true;
- }
- /*****************************************************************************
- End of file (PVRTBoneBatch.cpp)
- *****************************************************************************/
|