Ookay, as the thing is quite easy to make in basic form, I wrote the code to do the reordering+unwelding.
Have fun:
void* Flattenize(int NumVerts,const void* VertsData,int VtxSize,
int NumTris,int* inoutTriVtxIndices,const void* TrisData,int TriSize,
int &outNumVerts,int &outVtxSize // write-only, updated on success
){
struct FVTX{
const char* var_data;
const char* flat_data;
};
if(NumVerts<=0 || NumTris<=0)return null;
FVTX* verts = new FVTX[NumTris>NumVerts ? NumTris*3 : NumVerts*3]; // worst-case size, including precaution if some verts are not being used originally
int FNumNewVerts = NumVerts;
const char* inVertsData2 = (const char*)VertsData; // utility pointering
const char* inTrisData2 = (const char*)TrisData; // utility
int i;
for(i=0;i<NumVerts;i++){
verts[i].var_data = &inVertsData2[i*VtxSize];
verts[i].flat_data=null;
}
int* pVtxIndex = inoutTriVtxIndices; // to allow easy change to per-primitive-numVerts
for(i=0;i<NumTris;i++){
int FirstOpenSlot = -1;
int* pTriVtxIndex = pVtxIndex; pVtxIndex+=3;
const char* triFlatData = &inTrisData2[i*TriSize];
for(int j=0;j<3;j++){
if(verts[pTriVtxIndex[j]].flat_data!=null)continue;
FirstOpenSlot=j;
break;
}
if(FirstOpenSlot==-1){ // uhoh, unweld first vertex
int oldIdx = pTriVtxIndex[0];
int newIdx = FNumNewVerts++;
pTriVtxIndex[0] = newIdx;
verts[newIdx].var_data = verts[oldIdx].var_data;
verts[newIdx].flat_data = triFlatData;
}else{
//-----[ note: there is a possibly easy optimization: ]----------[
// instead of blindly picking the first vertex, smartly pick
// the most suitable one. The most suitable one is the one
// that is used in the least number of triangles.
// Thus, have the FVTX struct keep track of how many times
// it has been used.
//---------------------------------------------------------------/
while(FirstOpenSlot--){ // rotate indices
int fstidx = pTriVtxIndex[0];
pTriVtxIndex[0] = pTriVtxIndex[1];
pTriVtxIndex[1] = pTriVtxIndex[2];
pTriVtxIndex[2] = fstidx;
}
verts[pTriVtxIndex[0]].flat_data = triFlatData;
}
}
//--------[ now compose result verts array ]------------------[
int NewVtxSize = VtxSize + TriSize;
char* pResult = new char[FNumNewVerts*NewVtxSize];
memset(pResult,0,FNumNewVerts*NewVtxSize);
char* edi=pResult;
for(i=0;i<FNumNewVerts;i++){
memcpy(edi,verts[i].var_data,VtxSize); edi+= VtxSize;
if(verts[i].flat_data){
memcpy(edi,verts[i].flat_data,TriSize);
}else{
memset(edi,0,TriSize);
}
edi+= TriSize;
}
delete[] verts;
outNumVerts = FNumNewVerts;
outVtxSize = NewVtxSize;
//------------------------------------------------------------/
return pResult;
}
Now, your test-case:
// ************************* TESTING AREA. WEAR HELMETS ***************************************
struct VVV1{
int test1;
float pos[3];
float norm[3];
float data1[7];
};
struct TTT1{
int test2;
float clr[3];
};
VVV1 origVerts[4];
TTT1 origTris[4];
int origIndices[4*3] = {
0, 1, 3,
1, 2, 3,
2, 0, 3, // ****** I had to reorder this to match your problem-scenario
0, 2, 1
};
struct RES_VTX{ // resulting vertex
VVV1 v; // varying data
TTT1 t; // flat triangle data
};
void DO_FLATTENIZE(){ // main() for test
int resultNumVerts,resultVtxSize;
for(int i=0;i<4;i++){
origVerts[i].test1 = i + 100;
origTris[i].test2 = i + 10000;
}
RES_VTX* data1 = (RES_VTX*)Flattenize(4,origVerts,sizeof(VVV1),4,origIndices,origTris,sizeof(TTT1),resultNumVerts,resultVtxSize);
print(resultNumVerts);
print(resultVtxSize);
for(int i=0;i<resultNumVerts;i++){
trace("vtx[%d]= %d , %d",i,data1[i].v.test1,data1[i].t.test2);
}
for(int i=0;i<4;i++){
trace(" tri %d: %d, %d, %d",i,origIndices[i*3+0],origIndices[i*3+1],origIndices[i*3+2]);
}
}
And the debugging output for it:
resultNumVerts = 5
resultVtxSize = 72
vtx[0]= 100 , 10000
vtx[1]= 101 , 10001
vtx[2]= 102 , 10002
vtx[3]= 103 , 0 ***** NOTICE
vtx[4]= 100 , 10003
tri 0: 0, 1, 3
tri 1: 1, 2, 3
tri 2: 2, 0, 3
tri 3: 4, 2, 1