Example #1
0
/*!***********************************************************************
 @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;
}
Example #2
0
/****************************************************************************
* Function Name	: FillBatch
* Inputs		:
* Returns		:
* Description	: Creates a bone batch from a triangle.
****************************************************************************/
static bool FillBatch(
	CBatch					&batch,
	const unsigned short	* const pwIdx,	// input 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
{
	PVRTVECTOR4	vWeight, vIdx;
	const char	*pV;
	int			i;
	bool		bOk;

	bOk = true;
	batch.Clear();
	for(i = 0; i < 3; ++i)
	{
		pV = &pVtx[pwIdx[i] * nStride];

		memset(&vWeight, 0, sizeof(vWeight));
		PVRTDataTypeRead(&vWeight, &pV[nOffsetWeight], eTypeWeight, nVertexBones);
		PVRTDataTypeRead(&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;
}
Example #3
0
/*!***************************************************************************
 @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))
		{
			free(pui32IdxNew);
			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))
		{
			free(pui32IdxNew);
			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		= (int*) calloc(lBatch.size() * nBatchBoneMax, sizeof(*pnBatches));
	pnBatchBoneCnt	= (int*) calloc(lBatch.size(), sizeof(*pnBatchBoneCnt));
	pnBatchOffset	= (int*) calloc(lBatch.size(), sizeof(*pnBatchOffset));

	// 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;
}