diff --git a/Editor/ContentBrowserWindow.cpp b/Editor/ContentBrowserWindow.cpp index 81e63f6b1..2c50ce81c 100644 --- a/Editor/ContentBrowserWindow.cpp +++ b/Editor/ContentBrowserWindow.cpp @@ -370,7 +370,6 @@ void ContentBrowserWindow::AddItem(const std::string& filename, const std::strin button.SetSize(siz); button.SetLocalizationEnabled(false); button.SetDescription(itemname); - button.SetTooltip(filename); button.OnClick([this, filename](wi::gui::EventArgs args) { wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { editor->Open(filename); @@ -380,9 +379,11 @@ void ContentBrowserWindow::AddItem(const std::string& filename, const std::strin button.font_description.params.h_align = wi::font::WIFALIGN_CENTER; button.font_description.params.v_align = wi::font::WIFALIGN_TOP; button.font.params.size = 42; + button.SetTooltip(filename + "\nSize: " + wi::helper::GetMemorySizeText(wi::helper::FileSize(filename))); if (ext.compare("WISCENE") == 0) { - wi::graphics::Texture archiveThumbnail = wi::Archive::PeekThumbnail(filename); + wi::Archive::Header archive_header; + wi::graphics::Texture archiveThumbnail = wi::Archive::PeekThumbnail(filename, &archive_header); if (archiveThumbnail.IsValid()) { for (int i = 0; i < arraysize(sprites); ++i) @@ -391,6 +392,7 @@ void ContentBrowserWindow::AddItem(const std::string& filename, const std::strin } button.SetText(""); } + button.SetTooltip(button.GetTooltip() + "\nVersion: " + std::to_string(archive_header.version) + (archive_header.properties.bits.compressed ? "\nCompressed : true" : "\nCompressed : false")); } else { diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index c1a6a7af2..1bdddc4bc 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -4771,8 +4771,11 @@ void EditorComponent::Save(const std::string& filename) scene.Serialize(archive); + archive.SetCompressionEnabled(generalWnd.saveCompressionCheckBox.GetCheck()); + if (dump_to_header) { + archive.SetCompressionEnabled(true); // embedded scene always saved as compressed archive archive.SaveHeaderFile(filename, wi::helper::RemoveExtension(wi::helper::GetFileNameFromPath(filename))); } } diff --git a/Editor/GeneralWindow.cpp b/Editor/GeneralWindow.cpp index 2f0c57c6b..9f025883a 100644 --- a/Editor/GeneralWindow.cpp +++ b/Editor/GeneralWindow.cpp @@ -218,6 +218,17 @@ void GeneralWindow::Create(EditorComponent* _editor) }); AddWidget(&saveModeComboBox); + saveCompressionCheckBox.Create("Save compressed: "); + saveCompressionCheckBox.SetTooltip("Set whether to enable compression when saving WISCENE files.\nNote that compressed WISCENE with embedded resources doesn't support texture streaming!"); + if (editor->main->config.GetSection("options").Has("save_compressed")) + { + saveCompressionCheckBox.SetCheck(editor->main->config.GetSection("options").GetBool("save_compressed")); + } + saveCompressionCheckBox.OnClick([&](wi::gui::EventArgs args) { + editor->main->config.GetSection("options").Set("save_compressed", args.bValue); + editor->main->config.Commit(); + }); + AddWidget(&saveCompressionCheckBox); transformToolOpacitySlider.Create(0, 1, 1, 100, "Transform Tool Opacity: "); transformToolOpacitySlider.SetTooltip("You can control the transparency of the object placement tool"); @@ -943,6 +954,8 @@ void GeneralWindow::ResizeLayout() y += saveModeComboBox.GetSize().y; y += padding; + add_right(saveCompressionCheckBox); + themeCombo.SetPos(XMFLOAT2(x_off, y)); themeCombo.SetSize(XMFLOAT2(width - x_off - themeCombo.GetScale().y - 1, themeCombo.GetScale().y)); y += themeCombo.GetSize().y; diff --git a/Editor/GeneralWindow.h b/Editor/GeneralWindow.h index 6370683af..25cf045c0 100644 --- a/Editor/GeneralWindow.h +++ b/Editor/GeneralWindow.h @@ -12,6 +12,7 @@ public: wi::gui::CheckBox otherinfoCheckBox; wi::gui::ComboBox themeCombo; wi::gui::ComboBox saveModeComboBox; + wi::gui::CheckBox saveCompressionCheckBox; wi::gui::ComboBox languageCombo; wi::gui::CheckBox physicsDebugCheckBox; diff --git a/WickedEngine/ArchiveVersionHistory.txt b/WickedEngine/ArchiveVersionHistory.txt index 1ca60b3c6..a6bf85b72 100644 --- a/WickedEngine/ArchiveVersionHistory.txt +++ b/WickedEngine/ArchiveVersionHistory.txt @@ -1,5 +1,6 @@ This file contains changelog of wi::Archive versions +92: added support for compressed archive 91: thumbnail image support for Archive 90: resource serialization resource name list and improvements 89: distortion particles must use the normal map slot from now on diff --git a/WickedEngine/CommonInclude.h b/WickedEngine/CommonInclude.h index dce4962f3..2b3d30905 100644 --- a/WickedEngine/CommonInclude.h +++ b/WickedEngine/CommonInclude.h @@ -300,10 +300,11 @@ constexpr bool has_flag(E lhs, E rhs) return (lhs & rhs) == rhs; } -constexpr auto* relative_path(const char* const path) +// Extract file name from a path at compile-time +constexpr const char* relative_path(const char* path) { - const auto* startPosition = path; - for (const auto* currentCharacter = path; *currentCharacter != '\0'; ++currentCharacter) + const char* startPosition = path; + for (const char* currentCharacter = path; *currentCharacter != '\0'; ++currentCharacter) { if (*currentCharacter == '\\' || *currentCharacter == '/') { @@ -319,4 +320,21 @@ constexpr auto* relative_path(const char* const path) return startPosition; } +// Extract function name from a string at compile-time +constexpr auto extract_function_name(const char* str) +{ + struct ReturnString + { + char chars[256] = {}; + constexpr operator const char* () const { return chars; } + constexpr const char* const c_str() const { return chars; } + } ret; + int i = 0; + for (const char* currentCharacter = str; *currentCharacter != '\0' && *currentCharacter != '(' && (i < sizeof(ret.chars) - 1); ++currentCharacter) + { + ret.chars[i++] = *currentCharacter; + } + return ret; +} + #endif //WICKEDENGINE_COMMONINCLUDE_H diff --git a/WickedEngine/offlineshadercompiler.cpp b/WickedEngine/offlineshadercompiler.cpp index ff25e13b0..b9985e5d6 100644 --- a/WickedEngine/offlineshadercompiler.cpp +++ b/WickedEngine/offlineshadercompiler.cpp @@ -626,7 +626,7 @@ int main(int argc, char* argv[]) auto& output = x.second; wi::vector compressed; - bool success = wi::helper::Compress(output.shaderdata, output.shadersize, compressed); + bool success = wi::helper::Compress(output.shaderdata, output.shadersize, compressed, 9); if (success) { total_raw += output.shadersize; total_compressed += compressed.size(); diff --git a/WickedEngine/wiArchive.cpp b/WickedEngine/wiArchive.cpp index 792dcf4d1..a5e6d4cc6 100644 --- a/WickedEngine/wiArchive.cpp +++ b/WickedEngine/wiArchive.cpp @@ -4,10 +4,18 @@ #include "Utility/stb_image.h" +// Archive memory layout: +// - Header (offset = 0, size = uint64_t * 2) +// - uint64_t version +// - uint64_t properties +// - Thumbnail data [optional] (offset = sizeof(Header), size = header.properties.bits.thumbnail_data_size) +// - JPEG compressed image if header.properties.bits.thumbnail_data_size > 0 +// - Data [optionally compressed] (offset = sizeof(Header) + header.properties.bits.thumbnail_data_size, size = remaining) + namespace wi { // this should always be only INCREMENTED and only if a new serialization is implemeted somewhere! - static constexpr uint64_t __archiveVersion = 91; + static constexpr uint64_t __archiveVersion = 92; // this is the version number of which below the archive is not compatible with the current version static constexpr uint64_t __archiveVersionBarrier = 22; @@ -48,7 +56,7 @@ namespace wi void Archive::CreateEmpty() { - version = __archiveVersion; + header.version = __archiveVersion; DATA.resize(128); // starting size data_ptr = DATA.data(); data_ptr_size = DATA.size(); @@ -62,36 +70,68 @@ namespace wi if (readMode) { - (*this) >> version; - if (version < __archiveVersionBarrier) + (*this) >> header.version; + if (header.version < __archiveVersionBarrier) { - wi::helper::messageBox("File is not supported!\nReason: The archive version (" + std::to_string(version) + ") is no longer supported! This is likely because trying to open a file that was created by a version of Wicked Engine that is too old.", "Error!"); + wi::helper::messageBox("File is not supported!\nReason: The archive version (" + std::to_string(header.version) + ") is no longer supported! This is likely because trying to open a file that was created by a version of Wicked Engine that is too old.", "Error!"); Close(); return; } - if (version > __archiveVersion) + if (header.version > __archiveVersion) { - wi::helper::messageBox("File is not supported!\nReason: The archive version (" + std::to_string(version) + ") is higher than the program's (" + std::to_string(__archiveVersion) + ")!\nThis is likely due to trying to open an Archive file that was not created by Wicked Engine.", "Error!"); + wi::helper::messageBox("File is not supported!\nReason: The archive version (" + std::to_string(header.version) + ") is higher than the program's (" + std::to_string(__archiveVersion) + ")!\nThis is likely due to trying to open an Archive file that was not created by Wicked Engine.", "Error!"); Close(); return; } - if (GetVersion() >= 91) + if (GetVersion() >= 92) { + (*this) >> header.properties.raw; + pos += header.properties.bits.thumbnail_data_size; + } + else if (GetVersion() >= 91) + { + size_t thumbnail_data_size = 0; (*this) >> thumbnail_data_size; - thumbnail_data_ptr = data_ptr + pos; pos += thumbnail_data_size; + header.properties.bits.thumbnail_data_size = thumbnail_data_size; + } + + if (header.properties.bits.compressed && !data_already_decompressed) + { + // Decompress data part if required and retarget data stream to uncompressed: + size_t data_offset = 0; + data_offset += sizeof(Header); + data_offset += header.properties.bits.thumbnail_data_size; + if (data_ptr_size > data_offset) + { + size_t data_size = data_ptr_size - data_offset; + wi::vector decompressed_part; + wi::helper::Decompress(data_ptr + data_offset, data_size, decompressed_part); + wi::vector final_data(data_offset + decompressed_part.size()); + size_t _offset = 0; + std::memcpy(final_data.data() + _offset, &header, sizeof(Header)); + _offset += sizeof(Header); + if (header.properties.bits.thumbnail_data_size > 0) + { + std::memcpy(final_data.data() + _offset, get_thumbnail_data(), header.properties.bits.thumbnail_data_size); + _offset += header.properties.bits.thumbnail_data_size; + } + std::memcpy(final_data.data() + _offset, decompressed_part.data(), decompressed_part.size()); + std::swap(DATA, final_data); // archive DATA is replaced by decompressed final_data + data_ptr = DATA.data(); + data_ptr_size = DATA.size(); + data_already_decompressed = true; // indicate that next call to SetReadModeAndResetPos() doesn't need to decompress data + } } } else { - (*this) << version; - (*this) << thumbnail_data_size; - const uint8_t* thumbnail_data_dst = data_ptr + pos; - for (size_t i = 0; i < thumbnail_data_size; ++i) + (*this) << header.version; + (*this) << header.properties.raw; + for (size_t i = 0; i < header.properties.bits.thumbnail_data_size; ++i) { - (*this) << thumbnail_data_ptr[i]; + (*this) << thumbnail_data_ptr_write[i]; } - thumbnail_data_ptr = thumbnail_data_dst; } } @@ -106,11 +146,23 @@ namespace wi bool Archive::SaveFile(const std::string& fileName) { + if (IsCompressionEnabled()) + { + wi::vector final_data; + WriteCompressedData(final_data); + return wi::helper::FileWrite(fileName, final_data.data(), final_data.size()); + } return wi::helper::FileWrite(fileName, data_ptr, pos); } bool Archive::SaveHeaderFile(const std::string& fileName, const std::string& dataName) { + if (IsCompressionEnabled()) + { + wi::vector final_data; + WriteCompressedData(final_data); + return wi::helper::Bin2H(final_data.data(), final_data.size(), fileName, dataName.c_str()); + } return wi::helper::Bin2H(data_ptr, pos, fileName, dataName.c_str()); } @@ -126,12 +178,12 @@ namespace wi wi::graphics::Texture Archive::CreateThumbnailTexture() const { - if (thumbnail_data_size == 0) + if (header.properties.bits.thumbnail_data_size == 0) return {}; int width = 0; int height = 0; int channels = 0; - uint8_t* rgba = stbi_load_from_memory(thumbnail_data_ptr, (int)thumbnail_data_size, &width, &height, &channels, 4); + uint8_t* rgba = stbi_load_from_memory(get_thumbnail_data(), (int)header.properties.bits.thumbnail_data_size, &width, &height, &channels, 4); if (rgba == nullptr) return {}; wi::graphics::Texture texture; @@ -144,18 +196,19 @@ namespace wi { wi::vector thumbnail_data; wi::helper::saveTextureToMemoryFile(texture, "JPG", thumbnail_data); - thumbnail_data_size = thumbnail_data.size(); - thumbnail_data_ptr = thumbnail_data.data(); + header.properties.bits.thumbnail_data_size = thumbnail_data.size(); + thumbnail_data_ptr_write = thumbnail_data.data(); SetReadModeAndResetPos(false); // start over in write mode with thumbnail image data + thumbnail_data_ptr_write = nullptr; } - wi::graphics::Texture Archive::PeekThumbnail(const std::string& filename) + wi::graphics::Texture Archive::PeekThumbnail(const std::string& filename, Header* out_header) { wi::vector filedata; - size_t required_size = sizeof(uint64_t) * 2; // version and thumbnail data size + size_t required_size = sizeof(Header); - wi::helper::FileRead(filename, filedata, required_size); // read only up to version and thumbnail data size + wi::helper::FileRead(filename, filedata, required_size); // read only the header if (filedata.empty()) return {}; @@ -163,9 +216,13 @@ namespace wi wi::Archive archive(filedata.data(), filedata.size()); if (archive.IsOpen()) { - if (archive.thumbnail_data_size == 0) + if (out_header != nullptr) + { + *out_header = archive.header; + } + if (archive.header.properties.bits.thumbnail_data_size == 0) return {}; - required_size += archive.thumbnail_data_size; + required_size += archive.header.properties.bits.thumbnail_data_size; } } @@ -177,4 +234,39 @@ namespace wi return archive.CreateThumbnailTexture(); } + void Archive::WriteData(wi::vector& dest) const + { + if (IsCompressionEnabled()) + { + WriteCompressedData(dest); + } + else + { + dest.resize(pos); + std::memcpy(dest.data(), data_ptr, pos); + } + } + + void Archive::WriteCompressedData(wi::vector& final_data) const + { + Header _header = header; + _header.properties.bits.compressed = 1; // force write compressed header + size_t data_offset = 0; + data_offset += sizeof(Header); + data_offset += _header.properties.bits.thumbnail_data_size; + size_t data_size = pos - data_offset; + wi::vector compressed_part; + wi::helper::Compress(data_ptr + data_offset, data_size, compressed_part, 9); + final_data.resize(data_offset + compressed_part.size()); + size_t _offset = 0; + std::memcpy(final_data.data() + _offset, &_header, sizeof(Header)); + _offset += sizeof(Header); + if (_header.properties.bits.thumbnail_data_size > 0) + { + std::memcpy(final_data.data() + _offset, get_thumbnail_data(), _header.properties.bits.thumbnail_data_size); + _offset += _header.properties.bits.thumbnail_data_size; + } + std::memcpy(final_data.data() + _offset, compressed_part.data(), compressed_part.size()); + } + } diff --git a/WickedEngine/wiArchive.h b/WickedEngine/wiArchive.h index 7858e8c45..2932b9066 100644 --- a/WickedEngine/wiArchive.h +++ b/WickedEngine/wiArchive.h @@ -15,19 +15,39 @@ namespace wi // The data flow is always FIFO (first in, first out) class Archive { + public: + struct Header + { + uint64_t version = 0; + union Properties + { + struct + { + uint64_t thumbnail_data_size : 32; + uint64_t compressed : 1; + uint64_t reserved : 31; + } bits; + uint64_t raw = 0; + } properties; + }; + static_assert(sizeof(Header) == sizeof(uint64_t) * 2); + private: - uint64_t version = 0; // the version number is used for maintaining backwards compatibility with earlier archive versions + Header header; bool readMode = false; // archive can be either read or write mode, but not both size_t pos = 0; // position of the next memory operation, relative to the data's beginning wi::vector DATA; // data suitable for read/write operations const uint8_t* data_ptr = nullptr; // this can either be a memory mapped pointer (read only), or the DATA's pointer size_t data_ptr_size = 0; + bool data_already_decompressed = false; std::string fileName; // save to this file on closing if not empty std::string directory; // the directory part from the fileName - size_t thumbnail_data_size = 0; - const uint8_t* thumbnail_data_ptr = nullptr; + const uint8_t* thumbnail_data_ptr_write = nullptr; // temp ptr to write archive data + constexpr const uint8_t* get_thumbnail_data() const { return data_ptr + sizeof(Header); } + + void WriteCompressedData(wi::vector& final_data) const; void CreateEmpty(); // creates new archive in write mode @@ -47,11 +67,11 @@ namespace wi Archive& operator=(const Archive&) = default; Archive& operator=(Archive&&) = default; - void WriteData(wi::vector& dest) const { dest.resize(pos); std::memcpy(dest.data(), data_ptr, pos); } + void WriteData(wi::vector& dest) const; const uint8_t* GetData() const { return data_ptr; } const size_t GetSize() const { return data_ptr_size; } size_t GetPos() const { return pos; } - constexpr uint64_t GetVersion() const { return version; } + constexpr uint64_t GetVersion() const { return header.version; } constexpr bool IsReadMode() const { return readMode; } // This can set the archive into either read or write mode, and it will reset it's position void SetReadModeAndResetPos(bool isReadMode); @@ -65,7 +85,7 @@ namespace wi // The archive data will be written starting from the beginning, to the current position bool SaveFile(const std::string& fileName); // Write the archive contents into a C++ header file - // dataName : it will be the name of the byte data array in the header, that can be memory mapped + // dataName : it will be the name of the byte data array in the header, that can be memory mapped as an Archive bool SaveHeaderFile(const std::string& fileName, const std::string& dataName); // If the archive was opened from a file, this will return the file's directory const std::string& GetSourceDirectory() const; @@ -73,6 +93,15 @@ namespace wi // The file's name will include the directory as well const std::string& GetSourceFileName() const; + // Set whether the archive should be compressed upon saving + // Note that in memory, the archive is uncompressed + // Note that compressed archive will not work with streaming! + constexpr void SetCompressionEnabled(bool value) { header.properties.bits.compressed = value; } + // Returns true if the archive data is originating from compressed data + // Note that even if the archive was opened from compressed data source, the archive is always uncompressed in memory + // Note that compressed archive will not work with streaming! + constexpr bool IsCompressionEnabled() const { return header.properties.bits.compressed; } + // If Archive contains thumbnail image data, then creates a Texture from it: wi::graphics::Texture CreateThumbnailTexture() const; @@ -80,7 +109,8 @@ namespace wi void SetThumbnailAndResetPos(const wi::graphics::Texture& texture); // Open just the tumbnail data from an archive, and return it as a Texture: - static wi::graphics::Texture PeekThumbnail(const std::string& filename); + // header: optional, can return header info if not null + static wi::graphics::Texture PeekThumbnail(const std::string& filename, Header* out_header = nullptr); // Appends the current archive write offset as uint64_t to the archive // Returns the previous write offset of the archive, which can be used by PatchUnknownJumpPosition() diff --git a/WickedEngine/wiAudio.cpp b/WickedEngine/wiAudio.cpp index 811d912bf..1332dd7de 100644 --- a/WickedEngine/wiAudio.cpp +++ b/WickedEngine/wiAudio.cpp @@ -31,9 +31,8 @@ static constexpr T AlignTo(T value, T alignment) #define fourccXWMA 'AMWX' #define fourccDPDS 'sdpd' -#define xaudio_assert(cond, fname) { wilog_assert(cond, "XAudio2 error: %s failed with %s (%s:%d)", fname, wi::helper::GetPlatformErrorString(hr), relative_path(__FILE__), __LINE__); } - -#define xaudio_check(call) [&]() { HRESULT hr = call; char buf[256]; xaudio_assert(SUCCEEDED(hr), wi::backlog::internal::extract_function_name(buf, #call)); return hr; }() +#define xaudio_assert(cond, fname) { wilog_assert(cond, "XAudio2 error: %s failed with %s (%s:%d)", fname, wi::helper::GetPlatformErrorString(hr).c_str(), relative_path(__FILE__), __LINE__); } +#define xaudio_check(call) [&]() { HRESULT hr = call; xaudio_assert(SUCCEEDED(hr), extract_function_name(#call).c_str()); return hr; }() namespace wi::audio { diff --git a/WickedEngine/wiBacklog.cpp b/WickedEngine/wiBacklog.cpp index 53b3ffbfb..ed3ecf240 100644 --- a/WickedEngine/wiBacklog.cpp +++ b/WickedEngine/wiBacklog.cpp @@ -23,16 +23,6 @@ using namespace std::chrono_literals; namespace wi::backlog { - namespace internal { - char* extract_function_name(char* dst, const char* src) - { - int i = 0; - while (src[i] != '(') i++; - memcpy(dst, src, i); - dst[i] = 0; - return dst; - } - } bool enabled = false; bool was_ever_enabled = enabled; struct LogEntry diff --git a/WickedEngine/wiBacklog.h b/WickedEngine/wiBacklog.h index 4f6111042..c5ce5501a 100644 --- a/WickedEngine/wiBacklog.h +++ b/WickedEngine/wiBacklog.h @@ -17,11 +17,6 @@ namespace wi::backlog { - namespace internal { - // Used by various *_check macros - char* extract_function_name(char* dst, const char* src); - } - // Do not modify the order, as this is exposed to LUA scripts as int! enum class LogLevel { diff --git a/WickedEngine/wiGraphicsDevice_DX12.h b/WickedEngine/wiGraphicsDevice_DX12.h index 787a3ee7b..c223593bd 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.h +++ b/WickedEngine/wiGraphicsDevice_DX12.h @@ -33,9 +33,8 @@ #include #include -#define dx12_assert(cond, fname) { wilog_assert(cond, "DX 12 error: %s failed with %s (%s:%d)", fname, wi::helper::GetPlatformErrorString(hr), relative_path(__FILE__), __LINE__); } - -#define dx12_check(call) [&]() { HRESULT hr = call; char buf[256]; dx12_assert(SUCCEEDED(hr), wi::backlog::internal::extract_function_name(buf, #call)); return hr; }() +#define dx12_assert(cond, fname) { wilog_assert(cond, "DX12 error: %s failed with %s (%s:%d)", fname, wi::helper::GetPlatformErrorString(hr).c_str(), relative_path(__FILE__), __LINE__); } +#define dx12_check(call) [&]() { HRESULT hr = call; dx12_assert(SUCCEEDED(hr), extract_function_name(#call).c_str()); return hr; }() namespace wi::graphics { diff --git a/WickedEngine/wiGraphicsDevice_Vulkan.cpp b/WickedEngine/wiGraphicsDevice_Vulkan.cpp index 4483340ba..db4deef9f 100644 --- a/WickedEngine/wiGraphicsDevice_Vulkan.cpp +++ b/WickedEngine/wiGraphicsDevice_Vulkan.cpp @@ -1576,8 +1576,6 @@ using namespace vulkan_internal; { this->device = device; - VkResult res; - // Create descriptor pool: VkDescriptorPoolSize poolSizes[10] = {}; uint32_t count = 0; @@ -3636,8 +3634,6 @@ using namespace vulkan_internal; swapchain->internal_state = internal_state; swapchain->desc = *desc; - VkResult res; - // Surface creation: if(internal_state->surface == VK_NULL_HANDLE) { @@ -6985,8 +6981,6 @@ using namespace vulkan_internal; CommandList GraphicsDevice_Vulkan::BeginCommandList(QUEUE_TYPE queue) { - VkResult res; - cmd_locker.lock(); uint32_t cmd_current = cmd_count++; if (cmd_current >= commandlists.size()) @@ -7108,8 +7102,6 @@ using namespace vulkan_internal; } void GraphicsDevice_Vulkan::SubmitCommandLists() { - VkResult res; - // Submit current frame: { uint32_t cmd_last = cmd_count; diff --git a/WickedEngine/wiGraphicsDevice_Vulkan.h b/WickedEngine/wiGraphicsDevice_Vulkan.h index 78784241a..5f51e8a98 100644 --- a/WickedEngine/wiGraphicsDevice_Vulkan.h +++ b/WickedEngine/wiGraphicsDevice_Vulkan.h @@ -29,11 +29,8 @@ #include #define vulkan_assert(cond, fname) { wilog_assert(cond, "Vulkan error: %s failed with %s (%s:%d)", fname, string_VkResult(res), relative_path(__FILE__), __LINE__); } - -#define vulkan_check_cond(cond, call) [&]() { VkResult res = call; char buf[256]; vulkan_assert(cond, wi::backlog::internal::extract_function_name(buf, #call)); return res; }() - +#define vulkan_check_cond(cond, call) [&]() { VkResult res = call; vulkan_assert(cond, extract_function_name(#call).c_str()); return res; }() #define vulkan_check(call) vulkan_check_cond(res == VK_SUCCESS, call) - #define vulkan_check_lenient(call) vulkan_check_cond(res >= VK_SUCCESS, call) namespace wi::graphics diff --git a/WickedEngine/wiHelper.cpp b/WickedEngine/wiHelper.cpp index 465f2d2de..e6b07ad38 100644 --- a/WickedEngine/wiHelper.cpp +++ b/WickedEngine/wiHelper.cpp @@ -1009,6 +1009,25 @@ namespace wi::helper std::filesystem::create_directories(ToNativeString(path)); } + size_t FileSize(const std::string& fileName) + { +#if defined(PLATFORM_LINUX) || defined(PLATFORM_PS5) + std::string filepath = fileName; + std::replace(filepath.begin(), filepath.end(), '\\', '/'); // Linux cannot handle backslash in file path, need to convert it to forward slash + std::ifstream file(filepath, std::ios::binary | std::ios::ate); +#else + std::ifstream file(ToNativeString(fileName), std::ios::binary | std::ios::ate); +#endif // PLATFORM_LINUX || PLATFORM_PS5 + + if (file.is_open()) + { + size_t dataSize = (size_t)file.tellg(); + file.close(); + return dataSize; + } + return 0; + } + template typename vector_interface> bool FileRead_Impl(const std::string& fileName, vector_interface>& data, size_t max_read, size_t offset) { diff --git a/WickedEngine/wiHelper.h b/WickedEngine/wiHelper.h index 65f1e2a27..f77c5cf87 100644 --- a/WickedEngine/wiHelper.h +++ b/WickedEngine/wiHelper.h @@ -88,6 +88,9 @@ namespace wi::helper void DirectoryCreate(const std::string& path); + // Returns the file size if the file exists, otherwise 0 + size_t FileSize(const std::string& fileName); + bool FileRead(const std::string& fileName, wi::vector& data, size_t max_read = ~0ull, size_t offset = 0); #if WI_VECTOR_TYPE diff --git a/WickedEngine/wiResourceManager.cpp b/WickedEngine/wiResourceManager.cpp index 488d363c1..b7f247de1 100644 --- a/WickedEngine/wiResourceManager.cpp +++ b/WickedEngine/wiResourceManager.cpp @@ -754,7 +754,7 @@ namespace wi } int mip_offset = 0; - if (has_flag(flags, Flags::STREAMING)) + if (has_flag(flags, Flags::STREAMING) && !has_flag(flags, Flags::FILE_ORIGIN_COMPRESSED_ARCHIVE)) { // Remember full mipcount for streaming: resource->streaming_texture.mip_count = desc.mip_levels; @@ -1634,7 +1634,7 @@ namespace wi archive.MapVector(resource.filedata, resource.filesize); size_t file_offset = archive.GetPos() - resource.filesize; - + resource.name = archive.GetSourceDirectory() + resource.name; if (Contains(resource.name)) @@ -1643,9 +1643,14 @@ namespace wi // "Loading" the resource can happen asynchronously to serialization of file data, to improve performance wi::jobsystem::Execute(ctx, [i, &temp_resources, &seri, &archive, file_offset](wi::jobsystem::JobArgs args) { auto& tmp_resource = temp_resources[i]; + Flags flags = Flags::IMPORT_DELAY; + if (archive.IsCompressionEnabled()) + { + flags |= Flags::FILE_ORIGIN_COMPRESSED_ARCHIVE; + } auto res = Load( tmp_resource.name, - Flags::IMPORT_DELAY, + flags, tmp_resource.filedata, tmp_resource.filesize, archive.GetSourceFileName(), @@ -1674,6 +1679,8 @@ namespace wi } else { + wi::unordered_map temp_compressed_archives; + // Count embedded resources: for (auto& name : resource_names) { @@ -1703,12 +1710,27 @@ namespace wi if (resource->filedata.empty()) { - wi::helper::FileRead( - resource->container_filename, - resource->filedata, - resource->container_filesize, - resource->container_fileoffset - ); + if (has_flag(resource->flags, Flags::FILE_ORIGIN_COMPRESSED_ARCHIVE)) + { + // Can not use the file directly, need to reopen and decompress archive again, then copy data from it: + if (temp_compressed_archives.count(resource->container_filename) == 0) + { + temp_compressed_archives[resource->container_filename] = wi::Archive(resource->container_filename); + } + const wi::Archive& ar = temp_compressed_archives[resource->container_filename]; + resource->filedata.resize(resource->container_filesize); + std::memcpy(resource->filedata.data(), ar.GetData() + resource->container_fileoffset, resource->container_filesize); + } + else + { + // Directly re-read the file part that is needed: + wi::helper::FileRead( + resource->container_filename, + resource->filedata, + resource->container_filesize, + resource->container_fileoffset + ); + } } archive << name; diff --git a/WickedEngine/wiResourceManager.h b/WickedEngine/wiResourceManager.h index 7566dc7f0..dc719e9b4 100644 --- a/WickedEngine/wiResourceManager.h +++ b/WickedEngine/wiResourceManager.h @@ -76,6 +76,7 @@ namespace wi IMPORT_BLOCK_COMPRESSED = 1 << 3, // image import will request block compression for uncompressed or transcodable formats IMPORT_DELAY = 1 << 4, // delay importing resource until later, for example when proper flags can be determined. STREAMING = 1 << 5, // use streaming if possible + FILE_ORIGIN_COMPRESSED_ARCHIVE = 1 << 6, // indicate that file source is compressed, cannot be directly read with offsets so it disables streaming }; // Load a resource diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 21f79d6d1..4fe666232 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 653; + const int revision = 654; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);