tbool genTangSpace()

in shared/ext/mikktspace.cpp [229:423]


tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold)
{
	// count nr_triangles
	int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL;
	STriInfo * pTriInfos = NULL;
	SGroup * pGroups = NULL;
	STSpace * psTspace = NULL;
	int iNrTrianglesIn = 0, f=0, t=0, i=0;
	int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0;
	int iNrActiveGroups = 0, index = 0;
	const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext);
	tbool bRes = TFALSE;
	const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f);

	// verify all call-backs have been set
	if ( pContext->m_pInterface->m_getNumFaces==NULL ||
		pContext->m_pInterface->m_getNumVerticesOfFace==NULL ||
		pContext->m_pInterface->m_getPosition==NULL ||
		pContext->m_pInterface->m_getNormal==NULL ||
		pContext->m_pInterface->m_getTexCoord==NULL )
		return TFALSE;

	// count triangles on supported faces
	for (f=0; f<iNrFaces; f++)
	{
		const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
		if (verts==3) ++iNrTrianglesIn;
		else if (verts==4) iNrTrianglesIn += 2;
	}
	if (iNrTrianglesIn<=0) return TFALSE;

	// allocate memory for an index list
	piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn);
	pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn);
	if (piTriListIn==NULL || pTriInfos==NULL)
	{
		if (piTriListIn!=NULL) free(piTriListIn);
		if (pTriInfos!=NULL) free(pTriInfos);
		return TFALSE;
	}

	// make an initial triangle --> face index list
	iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);

	// make a welded index list of identical positions and attributes (pos, norm, texc)
	//printf("gen welded index list begin\n");
	GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn);
	//printf("gen welded index list end\n");

	// Mark all degenerate triangles
	iTotTris = iNrTrianglesIn;
	iDegenTriangles = 0;
	for (t=0; t<iTotTris; t++)
	{
		const int i0 = piTriListIn[t*3+0];
		const int i1 = piTriListIn[t*3+1];
		const int i2 = piTriListIn[t*3+2];
		const SVec3 p0 = GetPosition(pContext, i0);
		const SVec3 p1 = GetPosition(pContext, i1);
		const SVec3 p2 = GetPosition(pContext, i2);
		if (veq(p0,p1) || veq(p0,p2) || veq(p1,p2))	// degenerate
		{
			pTriInfos[t].iFlag |= MARK_DEGENERATE;
			++iDegenTriangles;
		}
	}
	iNrTrianglesIn = iTotTris - iDegenTriangles;

	// mark all triangle pairs that belong to a quad with only one
	// good triangle. These need special treatment in DegenEpilogue().
	// Additionally, move all good triangles to the start of
	// pTriInfos[] and piTriListIn[] without changing order and
	// put the degenerate triangles last.
	DegenPrologue(pTriInfos, piTriListIn, iNrTrianglesIn, iTotTris);

	
	// evaluate triangle level attributes and neighbor list
	//printf("gen neighbors list begin\n");
	InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);
	//printf("gen neighbors list end\n");

	
	// based on the 4 rules, identify groups based on connectivity
	iNrMaxGroups = iNrTrianglesIn*3;
	pGroups = (SGroup *) malloc(sizeof(SGroup)*iNrMaxGroups);
	piGroupTrianglesBuffer = (int *) malloc(sizeof(int)*iNrTrianglesIn*3);
	if (pGroups==NULL || piGroupTrianglesBuffer==NULL)
	{
		if (pGroups!=NULL) free(pGroups);
		if (piGroupTrianglesBuffer!=NULL) free(piGroupTrianglesBuffer);
		free(piTriListIn);
		free(pTriInfos);
		return TFALSE;
	}
	//printf("gen 4rule groups begin\n");
	iNrActiveGroups =
		Build4RuleGroups(pTriInfos, pGroups, piGroupTrianglesBuffer, piTriListIn, iNrTrianglesIn);
	//printf("gen 4rule groups end\n");

	//

	psTspace = (STSpace *) malloc(sizeof(STSpace)*iNrTSPaces);
	if (psTspace==NULL)
	{
		free(piTriListIn);
		free(pTriInfos);
		free(pGroups);
		free(piGroupTrianglesBuffer);
		return TFALSE;
	}
	memset(psTspace, 0, sizeof(STSpace)*iNrTSPaces);
	for (t=0; t<iNrTSPaces; t++)
	{
#pragma prefast(push)
#pragma prefast(disable: 6386) // PREfast is confused about the writeable size
		psTspace[t].vOs.x=1.0f; psTspace[t].vOs.y=0.0f; psTspace[t].vOs.z=0.0f; psTspace[t].fMagS = 1.0f;
		psTspace[t].vOt.x=0.0f; psTspace[t].vOt.y=1.0f; psTspace[t].vOt.z=0.0f; psTspace[t].fMagT = 1.0f;
#pragma prefast(pop)
	}

	// make tspaces, each group is split up into subgroups if necessary
	// based on fAngularThreshold. Finally a tangent space is made for
	// every resulting subgroup
	//printf("gen tspaces begin\n");
	bRes = GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriListIn, fThresCos, pContext);
	//printf("gen tspaces end\n");
	
	// clean up
	free(pGroups);
	free(piGroupTrianglesBuffer);

	if (!bRes)	// if an allocation in GenerateTSpaces() failed
	{
		// clean up and return false
		free(pTriInfos); free(piTriListIn); free(psTspace);
		return TFALSE;
	}


	// degenerate quads with one good triangle will be fixed by copying a space from
	// the good triangle to the coinciding vertex.
	// all other degenerate triangles will just copy a space from any good triangle
	// with the same welded index in piTriListIn[].
	DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris);

	free(pTriInfos); free(piTriListIn);

	index = 0;
	for (f=0; f<iNrFaces; f++)
	{
		const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
		if (verts!=3 && verts!=4) continue;
		

		// I've decided to let degenerate triangles and group-with-anythings
		// vary between left/right hand coordinate systems at the vertices.
		// All healthy triangles on the other hand are built to always be either or.

		/*// force the coordinate system orientation to be uniform for every face.
		// (this is already the case for good triangles but not for
		// degenerate ones and those with bGroupWithAnything==true)
		bool bOrient = psTspace[index].bOrient;
		if (psTspace[index].iCounter == 0)	// tspace was not derived from a group
		{
			// look for a space created in GenerateTSpaces() by iCounter>0
			bool bNotFound = true;
			int i=1;
			while (i<verts && bNotFound)
			{
				if (psTspace[index+i].iCounter > 0) bNotFound=false;
				else ++i;
			}
			if (!bNotFound) bOrient = psTspace[index+i].bOrient;
		}*/

		// set data
		for (i=0; i<verts; i++)
		{
			const STSpace * pTSpace = &psTspace[index];
			float tang[] = {pTSpace->vOs.x, pTSpace->vOs.y, pTSpace->vOs.z};
			float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z};
			if (pContext->m_pInterface->m_setTSpace!=NULL)
				pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i);
			if (pContext->m_pInterface->m_setTSpaceBasic!=NULL)
				pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i);

			++index;
		}
	}

	free(psTspace);

	
	return TTRUE;
}