in shared/ext/mikktspace.cpp [1195:1362]
static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[],
const int iNrActiveGroups, const int piTriListIn[], const float fThresCos,
const SMikkTSpaceContext * pContext)
{
STSpace * pSubGroupTspace = NULL;
SSubGroup * pUniSubGroups = NULL;
int * pTmpMembers = NULL;
int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0;
for (g=0; g<iNrActiveGroups; g++)
if (iMaxNrFaces < pGroups[g].iNrFaces)
iMaxNrFaces = pGroups[g].iNrFaces;
if (iMaxNrFaces == 0) return TTRUE;
// make initial allocations
pSubGroupTspace = (STSpace *) malloc(sizeof(STSpace)*iMaxNrFaces);
pUniSubGroups = (SSubGroup *) malloc(sizeof(SSubGroup)*iMaxNrFaces);
pTmpMembers = (int *) malloc(sizeof(int)*iMaxNrFaces);
if (pSubGroupTspace==NULL || pUniSubGroups==NULL || pTmpMembers==NULL)
{
if (pSubGroupTspace!=NULL) free(pSubGroupTspace);
if (pUniSubGroups!=NULL) free(pUniSubGroups);
if (pTmpMembers!=NULL) free(pTmpMembers);
return TFALSE;
}
iUniqueTspaces = 0;
for (g=0; g<iNrActiveGroups; g++)
{
const SGroup * pGroup = &pGroups[g];
int iUniqueSubGroups = 0;
for (i=0; i<pGroup->iNrFaces; i++) // triangles
{
const int f = pGroup->pFaceIndices[i]; // triangle number
int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0;
SSubGroup tmp_group;
tbool bFound;
SVec3 n, vOs, vOt;
if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0;
else if (pTriInfos[f].AssignedGroup[1]==pGroup) index=1;
else if (pTriInfos[f].AssignedGroup[2]==pGroup) index=2;
assert(index>=0 && index<3);
_Analysis_assume_(index>=0 && index<3);
iVertIndex = piTriListIn[f*3+index];
assert(iVertIndex==pGroup->iVertexRepresentitive);
// is normalized already
n = GetNormal(pContext, iVertIndex);
// project
vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n));
vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n));
if ( VNotZero(vOs) ) vOs = Normalize(vOs);
if ( VNotZero(vOt) ) vOt = Normalize(vOt);
// original face number
iOF_1 = pTriInfos[f].iOrgFaceNumber;
iMembers = 0;
for (j=0; j<pGroup->iNrFaces; j++)
{
const int t = pGroup->pFaceIndices[j]; // triangle number
const int iOF_2 = pTriInfos[t].iOrgFaceNumber;
// project
SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n));
SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n));
if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2);
if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2);
{
const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE;
// make sure triangles which belong to the same quad are joined.
const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE;
const float fCosS = vdot(vOs,vOs2);
const float fCosT = vdot(vOt,vOt2);
assert(f!=t || bSameOrgFace); // sanity check
if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos))
pTmpMembers[iMembers++] = t;
}
}
// sort pTmpMembers
tmp_group.iNrFaces = iMembers;
tmp_group.pTriMembers = pTmpMembers;
if (iMembers>1)
{
unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
QuickSort(pTmpMembers, 0, iMembers-1, uSeed);
}
// look for an existing match
bFound = TFALSE;
l=0;
while (l<iUniqueSubGroups && !bFound)
{
bFound = CompareSubGroups(&tmp_group, &pUniSubGroups[l]);
if (!bFound) ++l;
}
// assign tangent space index
assert(bFound || l==iUniqueSubGroups);
//piTempTangIndices[f*3+index] = iUniqueTspaces+l;
// if no match was found we allocate a new subgroup
if (!bFound)
{
// insert new subgroup
int * pIndices = (int *) malloc(sizeof(int)*iMembers);
if (pIndices==NULL)
{
// clean up and return false
for (int s=0; s<iUniqueSubGroups; s++)
free(pUniSubGroups[s].pTriMembers);
free(pUniSubGroups);
free(pTmpMembers);
free(pSubGroupTspace);
return TFALSE;
}
pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers;
pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices;
memcpy(pIndices, tmp_group.pTriMembers, iMembers*sizeof(int));
pSubGroupTspace[iUniqueSubGroups] =
EvalTspace(tmp_group.pTriMembers, iMembers, piTriListIn, pTriInfos, pContext, pGroup->iVertexRepresentitive);
++iUniqueSubGroups;
}
// output tspace
{
const int iOffs = pTriInfos[f].iTSpacesOffs;
const int iVert = pTriInfos[f].vert_num[index];
STSpace * pTS_out = &psTspace[iOffs+iVert];
assert(pTS_out->iCounter<2);
assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering);
if (pTS_out->iCounter==1)
{
*pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]);
pTS_out->iCounter = 2; // update counter
pTS_out->bOrient = pGroup->bOrientPreservering;
}
else
{
assert(pTS_out->iCounter==0);
*pTS_out = pSubGroupTspace[l];
pTS_out->iCounter = 1; // update counter
pTS_out->bOrient = pGroup->bOrientPreservering;
}
}
}
// clean up and offset iUniqueTspaces
for (int s=0; s<iUniqueSubGroups; s++)
free(pUniSubGroups[s].pTriMembers);
iUniqueTspaces += iUniqueSubGroups;
}
// clean up
free(pUniSubGroups);
free(pTmpMembers);
free(pSubGroupTspace);
return TTRUE;
}