#pragma once #include "shared.hpp" #include "vector.hpp" #include "read_helpers.hpp" namespace ace { namespace p3d { class _compressed_base { protected: int _mikero_lzo1x_decompress_safe(const uint8_t*, uint8_t*, uint32_t); int _decompress_safe(std::istream &, uint32_t); #if _MSC_VER == 1800 std::shared_ptr<uint8_t[]> _data; #else std::unique_ptr<uint8_t[]> _data; #endif }; template<typename T> class compressed_base : public _compressed_base { public: compressed_base() : fill(false), size(0), flag(0) {} T & operator[] (const int index) { return data[index]; } uint32_t size; bool fill; std::vector<T> data; bool flag; }; template<typename T> class compressed : public compressed_base<T> { public: compressed() { } compressed(std::istream &stream_, bool compressed_ = false, bool fill_ = false, uint32_t version = 68) { stream_.read((char *)&this->size, sizeof(uint32_t)); // if(version <) if(fill_) READ_BOOL(this->fill); assert(this->size < 4095 * 10); if (this->size > 0) { if (this->fill) { T val; stream_.read((char *)&val, sizeof(T)); for (int x = 0; x < this->size; x++) { this->data.push_back(val); } } else { if (version >= 64 && compressed_) { READ_BOOL(this->flag); } if ( (this->size * sizeof(T) >= 1024 && compressed_ && version < 64) || (this->flag && compressed_)) { int32_t result = this->_decompress_safe(stream_, this->size * sizeof(T)); assert(result > 0); T * ptr = (T *)(this->_data.get()); this->data.assign(ptr, ptr + this->size ); } else { for (int x = 0; x < this->size; x++) { T val; stream_.read((char *)&val, sizeof(T)); this->data.push_back(val); } } } } } }; template<> class compressed<vector3<float>> : public compressed_base<vector3<float>>{ public: compressed() {} compressed(std::istream &stream_, bool compressed_ = false, bool fill_ = false, bool xyzCompressed = false, uint32_t version = 68) { stream_.read((char *)&size, sizeof(uint32_t)); if(fill_) READ_BOOL(fill); if (fill) { ace::vector3<float> val(stream_); for (int x = 0; x < size; x++) { data.push_back(val); } } else { if (version >= 64) { READ_BOOL(flag); } if ((size * sizeof(float)*3 >= 1024 && compressed_ && version < 64) || (flag && compressed_)) { if (xyzCompressed) { int32_t result = _decompress_safe(stream_, size * sizeof(float)); uint32_t * ptr = (uint32_t *)(_data.get()); for (int x = 0; x < size; x++) { uint32_t value = ptr[x]; data.push_back(decode_xyz(value)); } } else { int32_t result = _decompress_safe(stream_, size * sizeof(float) * 3); float * ptr = (float *)(_data.get()); for (int x = 0; x < size*3; x+=3) { data.push_back(ace::vector3<float>(ptr+x)); } } } else { for (int x = 0; x < size; x++) { data.push_back(ace::vector3<float>(stream_)); } } } } ace::vector3<float> decode_xyz(uint32_t CompressedXYZ) { double scaleFactor = -1.0 / 511; int x = CompressedXYZ & 0x3FF; int y = (CompressedXYZ >> 10) & 0x3FF; int z = (CompressedXYZ >> 20) & 0x3FF; if (x > 511) x -= 1024; if (y > 511) y -= 1024; if (z > 511) z -= 1024; return ace::vector3<float>(x * scaleFactor, y * scaleFactor, z * scaleFactor); } }; template<> class compressed<pair<float>> : public compressed_base<pair<float>>{ public: compressed() {} compressed(std::istream &stream_, bool compressed_ = false, bool fill_ = false, uint32_t version = 68) { stream_.read((char *)&size, sizeof(uint32_t)); if (fill_) READ_BOOL(fill); if (fill) { ace::pair<float> val(stream_); for (int x = 0; x < size; x++) { data.push_back(val); } } else { if (version >= 64) { READ_BOOL(flag); } if ((size * sizeof(float)*2 >= 1024 && compressed_ && version < 64) || (flag && compressed_)) { int32_t result = _decompress_safe(stream_, size * sizeof(float) * 2); float * ptr = (float *)(_data.get()); for (int x = 0; x < size * 2; x += 2) { data.push_back(ace::pair<float>(ptr + x)); } } else { for (int x = 0; x < size; x++) { data.push_back(ace::pair<float>(stream_)); } } } } }; } }