#pragma once #include #include #include #include #include #include #include #include #include namespace frostbite2D { class BinaryFileStreamReader; struct ImageFrame { int32 type = 0; int32 compressionType = 0; int32 width = 0; int32 height = 0; int32 xPos = 0; int32 yPos = 0; int32 frameXPos = 0; int32 frameYPos = 0; uint32 offset = 0; int32 size = 0; std::vector data; }; struct ImgRef { std::string path; std::string npkFile; size_t frameCount = 0; uint32 offset = 0; uint32 size = 0; bool loaded = false; }; struct CachedImageData { std::vector frames; uint64 lastUseTime = 0; size_t memoryUsage = 0; }; class NpkArchive { public: static NpkArchive& get(); NpkArchive(const NpkArchive&) = delete; NpkArchive& operator=(const NpkArchive&) = delete; NpkArchive(NpkArchive&&) = delete; NpkArchive& operator=(NpkArchive&&) = delete; void setImagePackDirectory(const std::string& dir); const std::string& getImagePackDirectory() const; void init(); void close(); bool isOpen() const; bool hasImg(const std::string& path) const; std::optional getImg(const std::string& path); std::vector listImgs() const; std::optional getImageFrame(const ImgRef& img, size_t index); size_t getFrameCount(const ImgRef& img) const; void setCacheSize(size_t maxBytes); void clearCache(); size_t getCacheUsage() const; void setDefaultImg(const std::string& imgPath, size_t frameIndex = 0); const std::string& getDefaultImgPath() const; size_t getDefaultImgFrame() const; private: enum class IndexCacheValidationMode : uint32 { TrustCache = 1, StrictSourceState = 2 }; struct SourceFileState { std::string fileName; uint64 size = 0; int64 writeTime = 0; bool operator==(const SourceFileState& other) const { return fileName == other.fileName && size == other.size && writeTime == other.writeTime; } }; NpkArchive() = default; ~NpkArchive() = default; std::string normalizePath(const std::string& path) const; std::string getCacheFilePath() const; IndexCacheValidationMode getIndexCacheValidationMode() const; std::vector collectSourceFileStates() const; bool loadIndexCache(const std::vector& sourceFiles); bool saveIndexCache(const std::vector& sourceFiles) const; void scanNpkFiles(); bool parseNpkFile(const std::string& npkPath); bool loadImgData(ImgRef& img); void parseColor(const uint8* tab, int type, uint8* saveByte, int offset); void evictCacheIfNeeded(size_t requiredSize); void updateCacheUsage(const std::string& imgPath); std::string readNpkInfoString(BinaryFileStreamReader& reader); static const uint8 NPK_KEY[256]; std::string imagePackDirectory_ = "ImagePacks2"; bool initialized_ = false; std::unordered_map imgIndex_; std::unordered_map imageCache_; std::list lruList_; std::unordered_map::iterator> lruLookup_; size_t maxCacheSize_ = 512 * 1024 * 1024; size_t currentCacheSize_ = 0; std::string defaultImgPath_; size_t defaultImgFrame_ = 0; bool verboseFallbackLog_ = #ifndef NDEBUG true; #else false; #endif }; }