#include <cstdio>
template<typename R, typename T>
R* generate_uv_ids( T* index_buffer, int index_count, int vertex_count = 0 );
int i_buf[] = {0,1,2,2,1,3,2,1,4,4,3,5}; //test index buffer
const int i_count = sizeof(i_buf) / sizeof(i_buf[0]);
int main() {
int* vids = generate_uv_ids<int>( i_buf, i_count );
printf("generated mapping: ");
for( int i = 0; i < i_count; i+=3 )
printf("(%d %d %d) ", vids[ i_buf[i] ], vids[ i_buf[i+1] ], vids[ i_buf[i+2] ] );
delete[] vids;
return 0;
}
template<typename R, typename T>
R* generate_uv_ids( T* index_buffer, int index_count, int vertex_count ) {
//check preconditions
if( ! index_buffer ) return nullptr;
if( ! index_count ) return nullptr;
if( ! vertex_count ) {
for( int i = 0; i < index_count; i++ )
vertex_count = vertex_count < index_buffer[i] ? index_buffer[i] : vertex_count;
++vertex_count;
}
#define mask(a,b,c) ((a) << 4) | ((b) << 2) | (c)
typedef unsigned char byte;
//a helper data structure for generating proper uv ids
struct mask_to_values {
byte mask;
byte value[3];
};
mask_to_values mv[] = {
{ mask(3,3,3), {0,1,2} },
{ mask(3,3,0), {1,2,0} },
{ mask(3,3,1), {0,2,1} },
{ mask(3,3,2), {0,1,2} },
{ mask(3,0,3), {1,0,2} },
{ mask(3,0,1), {2,0,1} },
{ mask(3,0,2), {1,0,2} },
{ mask(3,1,3), {0,1,2} },
{ mask(3,1,0), {2,1,0} },
{ mask(3,1,2), {0,1,2} },
{ mask(3,2,3), {0,2,1} },
{ mask(3,2,0), {1,2,0} },
{ mask(3,2,1), {0,2,1} },
{ mask(0,3,3), {0,1,2} },
{ mask(0,3,1), {0,2,1} },
{ mask(0,3,2), {0,1,2} },
{ mask(0,1,3), {0,1,2} },
{ mask(0,1,2), {3,3,3} },
{ mask(0,2,3), {0,2,1} },
{ mask(0,2,1), {3,3,3} },
{ mask(1,3,3), {1,2,0} },
{ mask(1,3,0), {1,2,0} },
{ mask(1,3,2), {1,0,2} },
{ mask(1,0,3), {1,0,2} },
{ mask(1,0,2), {3,3,3} },
{ mask(1,2,3), {1,2,0} },
{ mask(1,2,0), {3,3,3} },
{ mask(2,3,3), {2,1,0} },
{ mask(2,3,0), {2,1,0} },
{ mask(2,3,1), {2,0,1} },
{ mask(2,0,3), {2,0,1} },
{ mask(2,0,1), {3,3,3} },
{ mask(2,1,3), {2,1,0} },
{ mask(2,1,0), {3,3,3} },
};
//get the memory for the resulting vid buffer, delete with delete[]
R* vids = new R[ vertex_count ];
//init it with 3 (3 means vacant)
for( int i = 0; i < vertex_count; i++ ) vids[ i ] = 3;
int bad_tri = 0; //number of tris for which no good 0,1,2 mapping exists
//loop through the index buffer
for( int idx = 0; idx < index_count; idx+=3 ) {
byte m = mask( vids[ index_buffer[idx+0] ],
vids[ index_buffer[idx+1] ],
vids[ index_buffer[idx+2] ] ); //helper mask for searching in mv array
//loop through the mv array and find the mapping
int i = 0; const int mv_size = sizeof(mv)/sizeof(mv[0]);
for(; i < mv_size; i++ ) {
if( m == mv[i].mask ) {
printf("mapping (%d %d %d) -> (%d %d %d)\n",
vids[ index_buffer[idx+0] ], vids[ index_buffer[idx+1] ], vids[ index_buffer[idx+2] ],
mv[i].value[0], mv[i].value[1], mv[i].value[2]);
if( 3 == mv[i].value[0] ) break; //proper vids are already in place, early out
//assign
vids[index_buffer[idx+0]] = mv[i].value[0];
vids[index_buffer[idx+1]] = mv[i].value[1];
vids[index_buffer[idx+2]] = mv[i].value[2];
break;
}
}
if( i == mv_size) { //no mask was found, means we've got a tri with no proper mapping
bad_tri++; //print it to get the number of tris with wrong vertex ids, no or partial AA on them
printf("mapping (%d %d %d) -> no mapping\n",
vids[ index_buffer[idx+0] ], vids[ index_buffer[idx+1] ], vids[ index_buffer[idx+2] ] );
}
}
//clean up any remaining 3s
for( int i = 0; i < vertex_count; i++ ) vids[i] = vids[i] == 3 ? 0 : vids[i];
return vids;
}
I2luY2x1ZGUgPGNzdGRpbz4KCnRlbXBsYXRlPHR5cGVuYW1lIFIsIHR5cGVuYW1lIFQ+ClIqIGdlbmVyYXRlX3V2X2lkcyggVCogaW5kZXhfYnVmZmVyLCBpbnQgaW5kZXhfY291bnQsIGludCB2ZXJ0ZXhfY291bnQgPSAwICk7CgppbnQgaV9idWZbXSA9IHswLDEsMiwyLDEsMywyLDEsNCw0LDMsNX07IC8vdGVzdCBpbmRleCBidWZmZXIKY29uc3QgaW50IGlfY291bnQgPSBzaXplb2YoaV9idWYpIC8gc2l6ZW9mKGlfYnVmWzBdKTsKCmludCBtYWluKCkgewoJaW50KiB2aWRzID0gZ2VuZXJhdGVfdXZfaWRzPGludD4oIGlfYnVmLCBpX2NvdW50ICk7CglwcmludGYoImdlbmVyYXRlZCBtYXBwaW5nOiAiKTsKICAJZm9yKCBpbnQgaSA9IDA7IGkgPCBpX2NvdW50OyBpKz0zICkgCiAgCQlwcmludGYoIiglZCAlZCAlZCkgIiwgdmlkc1sgaV9idWZbaV0gXSwgdmlkc1sgaV9idWZbaSsxXSBdLCB2aWRzWyBpX2J1ZltpKzJdIF0gKTsKICAJZGVsZXRlW10gdmlkczsKCXJldHVybiAwOwp9CgoKdGVtcGxhdGU8dHlwZW5hbWUgUiwgdHlwZW5hbWUgVD4KUiogZ2VuZXJhdGVfdXZfaWRzKCBUKiBpbmRleF9idWZmZXIsIGludCBpbmRleF9jb3VudCwgaW50IHZlcnRleF9jb3VudCApIHsKCiAgLy9jaGVjayBwcmVjb25kaXRpb25zCiAgaWYoICEgaW5kZXhfYnVmZmVyICkgcmV0dXJuIG51bGxwdHI7CiAgaWYoICEgaW5kZXhfY291bnQgKSByZXR1cm4gbnVsbHB0cjsKICBpZiggISB2ZXJ0ZXhfY291bnQgKSB7CiAgICBmb3IoIGludCBpID0gMDsgaSA8IGluZGV4X2NvdW50OyBpKysgKSAKICAgICAgICB2ZXJ0ZXhfY291bnQgPSB2ZXJ0ZXhfY291bnQgPCBpbmRleF9idWZmZXJbaV0gPyBpbmRleF9idWZmZXJbaV0gOiB2ZXJ0ZXhfY291bnQ7CiAgICArK3ZlcnRleF9jb3VudDsKICB9CgogICNkZWZpbmUgbWFzayhhLGIsYykgKChhKSA8PCA0KSB8ICgoYikgPDwgMikgfCAoYykKICB0eXBlZGVmIHVuc2lnbmVkIGNoYXIgYnl0ZTsKCiAgLy9hIGhlbHBlciBkYXRhIHN0cnVjdHVyZSBmb3IgZ2VuZXJhdGluZyBwcm9wZXIgdXYgaWRzCiAgc3RydWN0IG1hc2tfdG9fdmFsdWVzIHsKICAgIGJ5dGUgbWFzazsKICAgIGJ5dGUgdmFsdWVbM107CiAgfTsKCiAgbWFza190b192YWx1ZXMgbXZbXSA9IHsKCiAgICB7IG1hc2soMywzLDMpLCB7MCwxLDJ9IH0sCiAgICB7IG1hc2soMywzLDApLCB7MSwyLDB9IH0sCiAgICB7IG1hc2soMywzLDEpLCB7MCwyLDF9IH0sCiAgICB7IG1hc2soMywzLDIpLCB7MCwxLDJ9IH0sCgogICAgeyBtYXNrKDMsMCwzKSwgezEsMCwyfSB9LAogICAgeyBtYXNrKDMsMCwxKSwgezIsMCwxfSB9LAogICAgeyBtYXNrKDMsMCwyKSwgezEsMCwyfSB9LAoKICAgIHsgbWFzaygzLDEsMyksIHswLDEsMn0gfSwKICAgIHsgbWFzaygzLDEsMCksIHsyLDEsMH0gfSwKICAgIHsgbWFzaygzLDEsMiksIHswLDEsMn0gfSwKCiAgICB7IG1hc2soMywyLDMpLCB7MCwyLDF9IH0sCiAgICB7IG1hc2soMywyLDApLCB7MSwyLDB9IH0sCiAgICB7IG1hc2soMywyLDEpLCB7MCwyLDF9IH0sCgogICAgeyBtYXNrKDAsMywzKSwgezAsMSwyfSB9LAogICAgeyBtYXNrKDAsMywxKSwgezAsMiwxfSB9LAogICAgeyBtYXNrKDAsMywyKSwgezAsMSwyfSB9LAogICAgeyBtYXNrKDAsMSwzKSwgezAsMSwyfSB9LAogICAgeyBtYXNrKDAsMSwyKSwgezMsMywzfSB9LAogICAgeyBtYXNrKDAsMiwzKSwgezAsMiwxfSB9LAogICAgeyBtYXNrKDAsMiwxKSwgezMsMywzfSB9LAoKICAgIHsgbWFzaygxLDMsMyksIHsxLDIsMH0gfSwKICAgIHsgbWFzaygxLDMsMCksIHsxLDIsMH0gfSwKICAgIHsgbWFzaygxLDMsMiksIHsxLDAsMn0gfSwKICAgIHsgbWFzaygxLDAsMyksIHsxLDAsMn0gfSwKICAgIHsgbWFzaygxLDAsMiksIHszLDMsM30gfSwKICAgIHsgbWFzaygxLDIsMyksIHsxLDIsMH0gfSwKICAgIHsgbWFzaygxLDIsMCksIHszLDMsM30gfSwKCiAgICB7IG1hc2soMiwzLDMpLCB7MiwxLDB9IH0sCiAgICB7IG1hc2soMiwzLDApLCB7MiwxLDB9IH0sCiAgICB7IG1hc2soMiwzLDEpLCB7MiwwLDF9IH0sCiAgICB7IG1hc2soMiwwLDMpLCB7MiwwLDF9IH0sCiAgICB7IG1hc2soMiwwLDEpLCB7MywzLDN9IH0sCiAgICB7IG1hc2soMiwxLDMpLCB7MiwxLDB9IH0sCiAgICB7IG1hc2soMiwxLDApLCB7MywzLDN9IH0sCgogIH07CgogIC8vZ2V0IHRoZSBtZW1vcnkgZm9yIHRoZSByZXN1bHRpbmcgdmlkIGJ1ZmZlciwgZGVsZXRlIHdpdGggZGVsZXRlW10KICBSKiB2aWRzID0gbmV3IFJbIHZlcnRleF9jb3VudCBdOwoKICAvL2luaXQgaXQgd2l0aCAzICgzIG1lYW5zIHZhY2FudCkKICBmb3IoIGludCBpID0gMDsgaSA8IHZlcnRleF9jb3VudDsgaSsrICkgdmlkc1sgaSBdID0gMzsKCiAgaW50IGJhZF90cmkgPSAwOyAvL251bWJlciBvZiB0cmlzIGZvciB3aGljaCBubyBnb29kIDAsMSwyIG1hcHBpbmcgZXhpc3RzCgogIC8vbG9vcCB0aHJvdWdoIHRoZSBpbmRleCBidWZmZXIKICBmb3IoIGludCBpZHggPSAwOyBpZHggPCBpbmRleF9jb3VudDsgaWR4Kz0zICkgewoKICAgIGJ5dGUgbSA9IG1hc2soIHZpZHNbIGluZGV4X2J1ZmZlcltpZHgrMF0gXSwgCiAgICAgICAgICAgICAgICAgICB2aWRzWyBpbmRleF9idWZmZXJbaWR4KzFdIF0sIAogICAgICAgICAgICAgICAgICAgdmlkc1sgaW5kZXhfYnVmZmVyW2lkeCsyXSBdICk7IC8vaGVscGVyIG1hc2sgZm9yIHNlYXJjaGluZyBpbiBtdiBhcnJheQoKICAgIC8vbG9vcCB0aHJvdWdoIHRoZSBtdiBhcnJheSBhbmQgZmluZCB0aGUgbWFwcGluZwogICAgaW50IGkgPSAwOyBjb25zdCBpbnQgbXZfc2l6ZSA9IHNpemVvZihtdikvc2l6ZW9mKG12WzBdKTsKICAgIGZvcig7IGkgPCBtdl9zaXplOyBpKysgKSB7CgogICAgICAgIGlmKCBtID09IG12W2ldLm1hc2sgKSB7CiAgICAgICAgCXByaW50ZigibWFwcGluZyAoJWQgJWQgJWQpIC0+ICglZCAlZCAlZClcbiIsCiAgICAgICAgCQl2aWRzWyBpbmRleF9idWZmZXJbaWR4KzBdIF0sIHZpZHNbIGluZGV4X2J1ZmZlcltpZHgrMV0gXSwgdmlkc1sgaW5kZXhfYnVmZmVyW2lkeCsyXSBdLAogICAgICAgIAkJbXZbaV0udmFsdWVbMF0sIG12W2ldLnZhbHVlWzFdLCBtdltpXS52YWx1ZVsyXSk7CiAgICAgICAgICAgIGlmKCAzID09IG12W2ldLnZhbHVlWzBdICkgYnJlYWs7IC8vcHJvcGVyIHZpZHMgYXJlIGFscmVhZHkgaW4gcGxhY2UsIGVhcmx5IG91dAogICAgICAgICAgICAvL2Fzc2lnbgogICAgICAgICAgICB2aWRzW2luZGV4X2J1ZmZlcltpZHgrMF1dID0gbXZbaV0udmFsdWVbMF07CiAgICAgICAgICAgIHZpZHNbaW5kZXhfYnVmZmVyW2lkeCsxXV0gPSBtdltpXS52YWx1ZVsxXTsKICAgICAgICAgICAgdmlkc1tpbmRleF9idWZmZXJbaWR4KzJdXSA9IG12W2ldLnZhbHVlWzJdOwogICAgICAgICAgICBicmVhazsKICAgICAgICB9IAogICAgfQoKICAgIGlmKCBpID09IG12X3NpemUpIHsgLy9ubyBtYXNrIHdhcyBmb3VuZCwgbWVhbnMgd2UndmUgZ290IGEgdHJpIHdpdGggbm8gcHJvcGVyIG1hcHBpbmcKICAgICAgYmFkX3RyaSsrOyAvL3ByaW50IGl0IHRvIGdldCB0aGUgbnVtYmVyIG9mIHRyaXMgd2l0aCB3cm9uZyB2ZXJ0ZXggaWRzLCBubyBvciBwYXJ0aWFsIEFBIG9uIHRoZW0KCSAgcHJpbnRmKCJtYXBwaW5nICglZCAlZCAlZCkgLT4gbm8gbWFwcGluZ1xuIiwKICAgICAgIHZpZHNbIGluZGV4X2J1ZmZlcltpZHgrMF0gXSwgdmlkc1sgaW5kZXhfYnVmZmVyW2lkeCsxXSBdLCB2aWRzWyBpbmRleF9idWZmZXJbaWR4KzJdIF0gKTsKICAgIH0KCiAgfQogIAogIC8vY2xlYW4gdXAgYW55IHJlbWFpbmluZyAzcwogIGZvciggaW50IGkgPSAwOyBpIDwgdmVydGV4X2NvdW50OyBpKysgKSB2aWRzW2ldID0gdmlkc1tpXSA9PSAzID8gMCA6IHZpZHNbaV07CgogIHJldHVybiB2aWRzOwp9Cg==