// simplify shit below #define index(v,n) (uint32_t(v.x)+uint32_t(v.y)*n+uint32_t(v.z)*n*n) // derived from 2d bayer, the recursive construction // 0: 1->2, 1: 2->4, 2: 4->8 std::vector< uint32_t > values = { 0 }; for ( int i = 0; i < 3; i++ ) { // the size is x8 each step const size_t prevSize = values.size(); std::vector< uint32_t > newValues; newValues.resize( prevSize * 8 ); // source edge size is 2^i, 1, 2, 4 for the three iterations const int64_t edgeSizePrev = intPow( 2, i ); const int64_t edgeSizeNext = intPow( 2, i + 1 ); // the cantidate pattern const ivec3 iPattern [] = { ivec3( 0, 0, 1 ), ivec3( 1, 1, 0 ), ivec3( 0, 1, 1 ), ivec3( 1, 0, 0 ), ivec3( 0, 1, 0 ), ivec3( 1, 0, 1 ), ivec3( 0, 0, 0 ), ivec3( 1, 1, 1 ), }; // for each value in the current set of offsets in iPattern for ( int x = 0; x < edgeSizePrev; x++ ) for ( int y = 0; y < edgeSizePrev; y++ ) for ( int z = 0; z < edgeSizePrev; z++ ) { ivec3 basePt = ivec3( x, y, z ); uint32_t v = values[ index( basePt, edgeSizePrev ) ]; for ( int i = 0; i < 8; i++ ) { ivec3 pt = basePt + iPattern[ i ] * int( edgeSizePrev ); newValues[ index( pt, edgeSizeNext ) ] = v * 8 + i; } } // prep for next iteration values.clear(); values = newValues; } // iterate through all of them, and get the result as ivec3s in the list of offsets aquariaConfig.offsets.resize( 8 * 8 * 8 ); for ( int x = 0; x < 8; x++ ) for ( int y = 0; y < 8; y++ ) for ( int z = 0; z < 8; z++ ) { ivec3 loc = ivec3( x, y, z ); uint32_t idx = index( loc, 8 ); aquariaConfig.offsets[ values[ idx ] ] = loc; }