#include "Abstract.hpp" #include #include #include #include #include #include namespace LV { CompressedVoxels compressVoxels_byte(const std::vector& voxels) { std::u8string compressed; std::vector defines; DefVoxelId maxValue = 0; defines.reserve(voxels.size()); compressed.push_back(1); assert(voxels.size() <= 65535); for(const VoxelCube& cube : voxels) { defines.push_back(cube.VoxelId); if(cube.VoxelId > maxValue) maxValue = cube.VoxelId; } { std::sort(defines.begin(), defines.end()); auto last = std::unique(defines.begin(), defines.end()); defines.erase(last, defines.end()); defines.shrink_to_fit(); } // Количество байт на идентификатор в сыром виде uint8_t bytes_raw = std::ceil(std::log2(maxValue)/8); assert(bytes_raw >= 1 && bytes_raw <= 3); // Количество байт без таблицы индексов size_t size_in_raw = (bytes_raw+6)*voxels.size(); // Количество байт на индекс uint8_t bytes_per_define = std::ceil(std::log2(defines.size())/8); assert(bytes_per_define == 1 || bytes_per_define == 2); // Количество байт после таблицы индексов size_t size_after_indices = (bytes_per_define+6)*voxels.size(); // Размер таблицы индексов size_t indeces_size = 2+bytes_raw*defines.size(); if(indeces_size+size_after_indices < size_in_raw) { // Выгодней писать с таблицей индексов // Индексы, размер идентификатора ключа к таблице, размер значения таблицы compressed.push_back(1 | (bytes_per_define << 1) | (bytes_raw << 2)); compressed.push_back(defines.size() & 0xff); compressed.push_back((defines.size() >> 8) & 0xff); // Таблица for(DefVoxelId id : defines) { compressed.push_back(id & 0xff); if(bytes_raw > 1) compressed.push_back((id >> 8) & 0xff); if(bytes_raw > 2) compressed.push_back((id >> 16) & 0xff); } compressed.push_back(voxels.size() & 0xff); compressed.push_back((voxels.size() >> 8) & 0xff); for(const VoxelCube& cube : voxels) { size_t index = std::binary_search(defines.begin(), defines.end(), cube.VoxelId); compressed.push_back(index & 0xff); if(bytes_per_define > 1) compressed.push_back((index >> 8) & 0xff); compressed.push_back(cube.Meta); compressed.push_back(cube.Pos.x); compressed.push_back(cube.Pos.y); compressed.push_back(cube.Pos.z); compressed.push_back(cube.Size.x); compressed.push_back(cube.Size.y); compressed.push_back(cube.Size.z); } } else { compressed.push_back(0 | (0 << 1) | (bytes_raw << 2)); compressed.push_back(voxels.size() & 0xff); compressed.push_back((voxels.size() >> 8) & 0xff); for(const VoxelCube& cube : voxels) { compressed.push_back(cube.VoxelId & 0xff); if(bytes_raw > 1) compressed.push_back((cube.VoxelId >> 8) & 0xff); if(bytes_raw > 2) compressed.push_back((cube.VoxelId >> 16) & 0xff); compressed.push_back(cube.Meta); compressed.push_back(cube.Pos.x); compressed.push_back(cube.Pos.y); compressed.push_back(cube.Pos.z); compressed.push_back(cube.Size.x); compressed.push_back(cube.Size.y); compressed.push_back(cube.Size.z); } } return {compressLinear(compressed), defines}; } CompressedVoxels compressVoxels_bit(const std::vector& voxels) { std::vector profile; std::vector one_byte[7]; DefVoxelId maxValueProfile = 0; DefVoxelId maxValues[7] = {0}; profile.reserve(voxels.size()); for(int iter = 0; iter < 7; iter++) one_byte[iter].reserve(voxels.size()); assert(voxels.size() <= 65535); for(const VoxelCube& cube : voxels) { profile.push_back(cube.VoxelId); one_byte[0].push_back(cube.Meta); one_byte[1].push_back(cube.Pos.x); one_byte[2].push_back(cube.Pos.y); one_byte[3].push_back(cube.Pos.z); one_byte[4].push_back(cube.Size.x); one_byte[5].push_back(cube.Size.y); one_byte[6].push_back(cube.Size.z); if(cube.VoxelId > maxValueProfile) maxValueProfile = cube.VoxelId; if(cube.Meta > maxValues[0]) maxValues[0] = cube.Meta; if(cube.Pos.x > maxValues[1]) maxValues[1] = cube.Pos.x; if(cube.Pos.y > maxValues[2]) maxValues[2] = cube.Pos.y; if(cube.Pos.z > maxValues[3]) maxValues[3] = cube.Pos.z; if(cube.Size.x > maxValues[4]) maxValues[4] = cube.Size.x; if(cube.Size.y > maxValues[5]) maxValues[5] = cube.Size.y; if(cube.Size.z > maxValues[6]) maxValues[6] = cube.Size.z; } { std::sort(profile.begin(), profile.end()); auto last = std::unique(profile.begin(), profile.end()); profile.erase(last, profile.end()); profile.shrink_to_fit(); } for (int iter = 0; iter < 7; iter++) { std::sort(one_byte[iter].begin(), one_byte[iter].end()); auto last = std::unique(one_byte[iter].begin(), one_byte[iter].end()); one_byte[iter].erase(last, one_byte[iter].end()); } // Количество бит на идентификатор в сыром виде size_t bits_raw_profile = std::ceil(std::log2(maxValueProfile)); assert(bits_raw_profile >= 1 && bits_raw_profile <= 24); size_t bits_index_profile = std::ceil(std::log2(profile.size())); bool indices_profile = 16+bits_raw_profile*profile.size()+bits_index_profile*voxels.size() < bits_raw_profile*voxels.size(); size_t bits_raw[7]; size_t bits_index[7]; bool indices[7]; for(int iter = 0; iter < 7; iter++) { bits_raw[iter] = std::ceil(std::log2(maxValues[iter])); assert(bits_raw[iter] >= 1 && bits_raw[iter] <= 8); bits_index[iter] = std::ceil(std::log2(one_byte[iter].size())); } std::vector buff; buff.push_back(indices_profile); for(int iter = 0; iter < 7; iter++) buff.push_back(indices[iter]); auto write = [&](size_t value, int count) { for(int iter = 0; iter < count; iter++) buff.push_back((value >> iter) & 0x1); }; write(0, 8); // Таблицы if(indices_profile) { write(profile.size(), 16); write(bits_raw_profile, 5); write(bits_index_profile, 4); for(DefNodeId id : profile) write(id, bits_raw_profile); } else { write(bits_raw_profile, 5); } for(int iter = 0; iter < 7; iter++) { if(indices[iter]) { write(one_byte[iter].size(), 16); write(bits_raw[iter], 3); write(bits_index[iter], 3); for(uint8_t id : one_byte[iter]) write(id, bits_raw[iter]); } else { write(bits_raw[iter], 3); } } // Данные write(voxels.size(), 16); for(const VoxelCube& cube : voxels) { if(indices_profile) write(std::binary_search(profile.begin(), profile.end(), cube.VoxelId), bits_index_profile); else write(cube.VoxelId, bits_raw_profile); for(int iter = 0; iter < 7; iter++) { uint8_t val; if(iter == 0) val = cube.Meta; else if(iter == 1) val = cube.Pos.x; else if(iter == 2) val = cube.Pos.y; else if(iter == 3) val = cube.Pos.z; else if(iter == 4) val = cube.Size.x; else if(iter == 5) val = cube.Size.y; else if(iter == 6) val = cube.Size.z; if(indices[iter]) write(std::binary_search(one_byte[iter].begin(), one_byte[iter].end(), val), bits_index[iter]); else write(val, bits_raw[iter]); } } std::u8string compressed((buff.size()+7)/8, '\0'); for(int begin = 0, end = compressed.size()*8-buff.size(); begin < end; begin++) compressed.push_back(0); for(size_t iter = 0; iter < buff.size(); iter++) compressed[iter / 8] |= (buff[iter] << (iter % 8)); return {compressLinear(compressed), profile}; } CompressedVoxels compressVoxels(const std::vector& voxels, bool fast) { if(fast) return compressVoxels_byte(voxels); else return compressVoxels_bit(voxels); } std::vector unCompressVoxels_byte(const std::u8string& compressed) { size_t pos = 1; auto read = [&]() -> size_t { assert(pos < compressed.size()); return compressed[pos++]; }; uint8_t cmd = read(); if(cmd & 0x1) { // Таблица uint8_t bytes_per_define = (cmd >> 1) & 0x1; uint8_t bytes_raw = (cmd >> 2) & 0x3; std::vector defines; defines.resize(read() | (read() << 8)); for(size_t iter = 0; iter < defines.size(); iter++) { DefVoxelId id = read(); if(bytes_raw > 1) id |= read() << 8; if(bytes_raw > 2) id |= read() << 16; } std::vector voxels; voxels.resize(read() | (read() << 8)); for(size_t iter = 0; iter < voxels.size(); iter++) { size_t index = read(); if(bytes_per_define > 1) index |= read() << 8; VoxelCube &cube = voxels[iter]; assert(index < defines.size()); cube.VoxelId = defines[index]; cube.Meta = read(); cube.Pos.x = read(); cube.Pos.y = read(); cube.Pos.z = read(); cube.Size.x = read(); cube.Size.y = read(); cube.Size.z = read(); } return voxels; } else { uint8_t bytes_raw = (cmd >> 2) & 0x3; std::vector voxels; voxels.resize(read() | (read() << 8)); for(size_t iter = 0; iter < voxels.size(); iter++) { VoxelCube &cube = voxels[iter]; cube.VoxelId = read(); if(bytes_raw > 1) cube.VoxelId |= read() << 8; if(bytes_raw > 2) cube.VoxelId |= read() << 16; cube.Meta = read(); cube.Pos.x = read(); cube.Pos.y = read(); cube.Pos.z = read(); cube.Size.x = read(); cube.Size.y = read(); cube.Size.z = read(); } return voxels; } } std::vector unCompressVoxels_bit(const std::u8string& compressed) { size_t pos = 1; auto read = [&](int bits) -> size_t { size_t out = 0; for(int iter = 0; iter < bits; iter++, pos++) { assert(pos < compressed.size()*8); out |= (compressed[pos / 8] >> (pos % 8)) << iter; } return out; }; bool indices_profile = read(1); bool indices[7]; for(int iter = 0; iter < 7; iter++) indices[iter] = read(1); std::vector profile; std::vector one_byte[7]; uint8_t bits_raw_profile; uint8_t bits_index_profile; size_t bits_raw[7]; size_t bits_index[7]; // Таблицы if(indices_profile) { profile.resize(read(16)); bits_raw_profile = read(5); bits_index_profile = read(4); for(size_t iter = 0; iter < profile.size(); iter++) profile[iter] = read(bits_raw_profile); } else { bits_raw_profile = read(5); } for(int iter = 0; iter < 7; iter++) { if(indices[iter]) { one_byte[iter].resize(read(16)); bits_raw[iter] = read(3); bits_index[iter] = read(3); for(size_t iter2 = 0; iter2 < one_byte[iter].size(); iter2++) one_byte[iter][iter2] = read(bits_raw[iter]); } else { bits_raw[iter] = read(3); } } // Данные std::vector voxels; voxels.resize(read(16)); for(size_t iter = 0; iter < voxels.size(); iter++) { VoxelCube &cube = voxels[iter]; if(indices_profile) cube.VoxelId = profile[read(bits_index_profile)]; else cube.VoxelId = read(bits_raw_profile); for(int iter = 0; iter < 7; iter++) { uint8_t val; if(indices[iter]) val = one_byte[iter][read(bits_index[iter])]; else val = read(bits_raw[iter]); if(iter == 0) cube.Meta = val; else if(iter == 1) cube.Pos.x = val; else if(iter == 2) cube.Pos.y = val; else if(iter == 3) cube.Pos.z = val; else if(iter == 4) cube.Size.x = val; else if(iter == 5) cube.Size.y = val; else if(iter == 6) cube.Size.z = val; } } return voxels; } std::vector unCompressVoxels(const std::u8string& compressed) { const std::u8string& next = unCompressLinear(compressed); if(next.front()) return unCompressVoxels_byte(next); else return unCompressVoxels_bit(next); } CompressedNodes compressNodes_byte(const Node* nodes) { std::u8string compressed; std::vector profiles; profiles.reserve(16*16*16); compressed.push_back(1); DefNodeId maxValueProfile = 0; for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; profiles.push_back(node.NodeId); if(node.NodeId > maxValueProfile) maxValueProfile = node.NodeId; } { std::sort(profiles.begin(), profiles.end()); auto last = std::unique(profiles.begin(), profiles.end()); profiles.erase(last, profiles.end()); profiles.shrink_to_fit(); } // Количество байт на идентификатор в сыром виде uint8_t bytes_raw_profile = std::ceil(std::log2(maxValueProfile+1)/8); assert(bytes_raw_profile >= 0 && bytes_raw_profile <= 3); // Количество байт на индекс uint8_t bytes_indices_profile = std::ceil(std::log2(profiles.size())/8); assert(bytes_indices_profile >= 0 && bytes_indices_profile <= 2); bool indices_profile = 3+bytes_raw_profile*profiles.size()+bytes_indices_profile*16*16*16 < bytes_raw_profile*16*16*16; compressed.push_back(indices_profile | (bytes_raw_profile << 1) | (bytes_indices_profile << 3)); if(indices_profile) { // Таблица compressed.push_back(profiles.size() & 0xff); compressed.push_back((profiles.size() >> 8) & 0xff); compressed.push_back((profiles.size() >> 16) & 0xff); for(DefNodeId id : profiles) { if(bytes_raw_profile > 0) compressed.push_back(id & 0xff); if(bytes_raw_profile > 1) compressed.push_back((id >> 8) & 0xff); if(bytes_raw_profile > 2) compressed.push_back((id >> 16) & 0xff); } // Данные for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; size_t index = std::binary_search(profiles.begin(), profiles.end(), node.NodeId); compressed.push_back(index & 0xff); if(bytes_indices_profile > 1) compressed.push_back((index >> 8) & 0xff); compressed.push_back(node.Meta); } } else { for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; if(bytes_raw_profile > 0) compressed.push_back(node.NodeId & 0xff); if(bytes_raw_profile > 1) compressed.push_back((node.NodeId >> 8) & 0xff); if(bytes_raw_profile > 2) compressed.push_back((node.NodeId >> 8) & 0xff); compressed.push_back(node.Meta); } } profiles.shrink_to_fit(); return {compressLinear(compressed), profiles}; } CompressedNodes compressNodes_bit(const Node* nodes) { std::u8string compressed; std::vector profiles; std::vector meta; profiles.reserve(16*16*16); meta.reserve(16*16*16); compressed.push_back(1); DefNodeId maxValueProfile = 0, maxValueMeta = 0; for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; profiles.push_back(node.NodeId); meta.push_back(node.Meta); if(node.NodeId > maxValueProfile) maxValueProfile = node.NodeId; if(node.Meta > maxValueMeta) maxValueMeta = node.Meta; } { std::sort(profiles.begin(), profiles.end()); auto last = std::unique(profiles.begin(), profiles.end()); profiles.erase(last, profiles.end()); profiles.shrink_to_fit(); } { std::sort(meta.begin(), meta.end()); auto last = std::unique(meta.begin(), meta.end()); meta.erase(last, meta.end()); meta.shrink_to_fit(); } // Количество бит на идентификатор в сыром виде uint8_t bits_raw_profile = std::ceil(std::log2(maxValueProfile+1)); assert(bits_raw_profile >= 1 && bits_raw_profile <= 24); // Количество бит на индекс uint8_t bits_indices_profile = std::ceil(std::log2(profiles.size())); assert(bits_indices_profile >= 1 && bits_indices_profile <= 16); bool indices_profile = 3*8+bits_raw_profile*profiles.size()+bits_indices_profile*16*16*16 < bits_raw_profile*16*16*16; std::vector buff; auto write = [&](size_t value, int count) { for(int iter = 0; iter < count; iter++) buff.push_back((value >> iter) & 0x1); }; write(indices_profile, 1); write(bits_raw_profile, 5); write(bits_indices_profile, 4); // Количество бит на идентификатор в сыром виде uint8_t bits_raw_meta = std::ceil(std::log2(maxValueMeta+1)); assert(bits_raw_meta >= 1 && bits_raw_meta <= 8); // Количество бит на индекс uint8_t bits_indices_meta = std::ceil(std::log2(meta.size())); assert(bits_indices_meta >= 1 && bits_indices_meta <= 8); bool indices_meta = 3*8+bits_raw_meta*profiles.size()+bits_indices_meta*16*16*16 < bits_raw_meta*16*16*16; write(indices_meta, 1); write(bits_raw_meta, 3); write(bits_indices_meta, 3); // Таблицы if(indices_profile) { write(profiles.size(), 12); for(DefNodeId id : profiles) { write(id, bits_raw_profile); } } if(indices_meta) { write(meta.size(), 8); for(DefNodeId id : meta) { write(id, bits_raw_meta); } } // Данные for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; if(indices_profile) { size_t index = std::binary_search(profiles.begin(), profiles.end(), node.NodeId); write(index, bits_indices_profile); } else { write(node.NodeId, bits_raw_profile); } if(indices_meta) { size_t index = std::binary_search(meta.begin(), meta.end(), node.Meta); write(index, bits_indices_meta); } else { write(node.Meta, bits_raw_meta); } } return {compressLinear(compressed), profiles}; } CompressedNodes compressNodes(const Node* nodes, bool fast) { std::u8string data(16*16*16*sizeof(Node), '\0'); const char8_t *ptr = (const char8_t*) nodes; std::copy(ptr, ptr+16*16*16*4, data.data()); std::vector node(16*16*16); for(int iter = 0; iter < 16*16*16; iter++) { node[iter] = nodes[iter].NodeId; } { std::sort(node.begin(), node.end()); auto last = std::unique(node.begin(), node.end()); node.erase(last, node.end()); node.shrink_to_fit(); } return {compressLinear(data), std::move(node)}; // if(fast) // return compressNodes_byte(nodes); // else // return compressNodes_bit(nodes); } void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) { size_t pos = 1; auto read = [&]() -> size_t { assert(pos < compressed.size()); return compressed[pos++]; }; uint8_t value = read(); uint8_t bytes_raw_profile = (value >> 1) & 0x3; uint8_t bytes_indices_profile = (value >> 3) & 0x3; bool indices_profile = value & 0x1; if(indices_profile) { std::vector profiles; profiles.resize(read() | (read() << 8) | (read() << 16)); for(size_t iter = 0; iter < profiles.size(); iter++) { DefNodeId id = 0; if(bytes_raw_profile > 0) id = read(); if(bytes_raw_profile > 1) id |= read() << 8; if(bytes_raw_profile > 2) id |= read() << 16; } for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; DefNodeId index = read(); if(bytes_indices_profile > 1) index |= read() << 8; node.NodeId = profiles[index]; node.Meta = read(); } } else { for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; node.NodeId = 0; if(bytes_raw_profile > 0) node.NodeId = read(); if(bytes_raw_profile > 1) node.NodeId |= read() << 8; if(bytes_raw_profile > 2) node.NodeId |= read() << 16; node.Meta = read(); } } } void unCompressNodes_bit(const std::u8string& compressed, Node* ptr) { size_t pos = 1; auto read = [&](int bits) -> size_t { size_t out = 0; for(int iter = 0; iter < bits; iter++, pos++) { assert(pos < compressed.size()*8); out |= (compressed[pos / 8] >> (pos % 8)) << iter; } return out; }; std::vector meta; bool indices_profile = read(1); uint8_t bits_raw_profile = read(5); uint8_t bits_indices_profile = read(4); bool indices_meta = read(1); uint8_t bits_raw_meta = read(3); uint8_t bits_indices_meta = read(3); std::vector profiles; // Таблицы if(indices_profile) { profiles.resize(read(12)); for(size_t iter = 0; iter < profiles.size(); iter++) { profiles[iter] = read(bits_raw_profile); } } if(indices_meta) { meta.resize(read(8)); for(size_t iter = 0; iter < meta.size(); iter++) { meta[iter] = read(bits_raw_meta); } } // Данные for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; if(indices_profile) { node.NodeId = profiles[read(bits_indices_profile)]; } else { node.NodeId = read(bits_raw_profile); } if(indices_meta) { node.Meta = meta[read(bits_indices_meta)]; } else { node.Meta = read(bits_raw_meta); } } } void unCompressNodes(const std::u8string& compressed, Node* ptr) { const std::u8string& next = unCompressLinear(compressed); const Node *lPtr = (const Node*) next.data(); std::copy(lPtr, lPtr+16*16*16, ptr); // if(next.front()) // return unCompressNodes_byte(next, ptr); // else // return unCompressNodes_bit(next, ptr); } std::u8string compressLinear(const std::u8string& data) { std::stringstream in; in.write((const char*) data.data(), data.size()); boost::iostreams::filtering_streambuf out; out.push(boost::iostreams::zlib_compressor()); out.push(in); std::stringstream compressed; boost::iostreams::copy(out, compressed); std::string outString = compressed.str(); return *(std::u8string*) &outString; } std::u8string unCompressLinear(const std::u8string& data) { std::stringstream in; in.write((const char*) data.data(), data.size()); boost::iostreams::filtering_streambuf out; out.push(boost::iostreams::zlib_decompressor()); out.push(in); std::stringstream compressed; boost::iostreams::copy(out, compressed); std::string outString = compressed.str(); return *(std::u8string*) &outString; } }