diff --git a/Frostbite2D/include/frostbite2D/2d/sprite.h b/Frostbite2D/include/frostbite2D/2d/sprite.h index 2640c89..dee3ade 100644 --- a/Frostbite2D/include/frostbite2D/2d/sprite.h +++ b/Frostbite2D/include/frostbite2D/2d/sprite.h @@ -15,7 +15,8 @@ public: virtual ~Sprite(); static Ptr createFromFile(const std::string& path); - static Ptr createFromMemory(uint8* data, int width, int height, int channels); + static Ptr createFromMemory(const uint8* data, int width, int height, int channels); + static Ptr createFromNpk(const std::string& imgPath, size_t frameIndex = 0); void Render() override; diff --git a/Frostbite2D/include/frostbite2D/graphics/texture.h b/Frostbite2D/include/frostbite2D/graphics/texture.h index 2effc02..8ee11e7 100644 --- a/Frostbite2D/include/frostbite2D/graphics/texture.h +++ b/Frostbite2D/include/frostbite2D/graphics/texture.h @@ -11,7 +11,7 @@ namespace frostbite2D { class Texture : public RefObject { public: static Ptr loadFromFile(const std::string& path); - static Ptr createFromMemory(uint8* data, int width, int height, int channels); + static Ptr createFromMemory(const uint8* data, int width, int height, int channels); static Ptr createEmpty(int width, int height); ~Texture(); diff --git a/Frostbite2D/include/frostbite2D/resource/npk_archive.h b/Frostbite2D/include/frostbite2D/resource/npk_archive.h new file mode 100644 index 0000000..6df7284 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/resource/npk_archive.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace frostbite2D { + +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: + NpkArchive() = default; + ~NpkArchive() = default; + + std::string normalizePath(const std::string& path) 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(BinaryReader& reader); + + static const uint8 NPK_KEY[256]; + + std::string imagePackDirectory_ = "ImagePacks2"; + bool initialized_ = false; + std::map imgIndex_; + std::map imageCache_; + std::list lruList_; + size_t maxCacheSize_ = 512 * 1024 * 1024; + size_t currentCacheSize_ = 0; + std::string defaultImgPath_; + size_t defaultImgFrame_ = 0; +}; + +} diff --git a/Frostbite2D/src/frostbite2D/2d/sprite.cpp b/Frostbite2D/src/frostbite2D/2d/sprite.cpp index 4ba90b9..da99782 100644 --- a/Frostbite2D/src/frostbite2D/2d/sprite.cpp +++ b/Frostbite2D/src/frostbite2D/2d/sprite.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ Ptr Sprite::createFromFile(const std::string &path) { return sprite; } -Ptr Sprite::createFromMemory(uint8* data, int width, int height, int channels) { +Ptr Sprite::createFromMemory(const uint8* data, int width, int height, int channels) { Ptr texture = Texture::createFromMemory(data, width, height, channels); if (!texture) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, @@ -176,5 +177,68 @@ Quad Sprite::createQuad() const { return quad; } +Ptr Sprite::createFromNpk(const std::string& imgPath, size_t frameIndex) { + NpkArchive& npk = NpkArchive::get(); + + auto imgOpt = npk.getImg(imgPath); + if (imgOpt) { + auto frameOpt = npk.getImageFrame(*imgOpt, frameIndex); + if (frameOpt && !frameOpt->data.empty()) { + const ImageFrame& frame = *frameOpt; + + std::vector convertedData(frame.data.size()); + for (size_t i = 0; i < frame.data.size(); i += 4) { + uint8 b = frame.data[i + 0]; + uint8 g = frame.data[i + 1]; + uint8 r = frame.data[i + 2]; + uint8 a = frame.data[i + 3]; + convertedData[i + 0] = r; + convertedData[i + 1] = g; + convertedData[i + 2] = b; + convertedData[i + 3] = a; + } + + return createFromMemory( + convertedData.data(), + frame.width, + frame.height, + 4 + ); + } + } + + const std::string& defaultPath = npk.getDefaultImgPath(); + if (!defaultPath.empty()) { + auto defaultImgOpt = npk.getImg(defaultPath); + if (defaultImgOpt) { + auto defaultFrameOpt = npk.getImageFrame(*defaultImgOpt, npk.getDefaultImgFrame()); + if (defaultFrameOpt && !defaultFrameOpt->data.empty()) { + const ImageFrame& frame = *defaultFrameOpt; + + std::vector convertedData(frame.data.size()); + for (size_t i = 0; i < frame.data.size(); i += 4) { + uint8 b = frame.data[i + 0]; + uint8 g = frame.data[i + 1]; + uint8 r = frame.data[i + 2]; + uint8 a = frame.data[i + 3]; + convertedData[i + 0] = r; + convertedData[i + 1] = g; + convertedData[i + 2] = b; + convertedData[i + 3] = a; + } + + return createFromMemory( + convertedData.data(), + frame.width, + frame.height, + 4 + ); + } + } + } + + return nullptr; +} + } diff --git a/Frostbite2D/src/frostbite2D/graphics/texture.cpp b/Frostbite2D/src/frostbite2D/graphics/texture.cpp index 64d7432..b219d53 100644 --- a/Frostbite2D/src/frostbite2D/graphics/texture.cpp +++ b/Frostbite2D/src/frostbite2D/graphics/texture.cpp @@ -88,7 +88,7 @@ Ptr Texture::loadFromFile(const std::string& path) { return texture; } -Ptr Texture::createFromMemory(uint8* data, int width, int height, int channels) { +Ptr Texture::createFromMemory(const uint8* data, int width, int height, int channels) { if (!data) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create texture from memory: null data"); return nullptr; diff --git a/Frostbite2D/src/frostbite2D/resource/asset.cpp b/Frostbite2D/src/frostbite2D/resource/asset.cpp index 59bf604..d6331ff 100644 --- a/Frostbite2D/src/frostbite2D/resource/asset.cpp +++ b/Frostbite2D/src/frostbite2D/resource/asset.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include namespace frostbite2D { @@ -268,10 +270,13 @@ std::vector Asset::listAll(const std::string &directoryPath, std::vector Asset::listFilesWithExtension(const std::string &directoryPath, - const std::string &extension, bool recursive) { + const std::string &extension, bool recursive) { std::vector files; fs::path fullPath = toPath(resolveFullPath(directoryPath)); - fs::path ext = toPath(extension); + + std::string extLower = extension; + std::transform(extLower.begin(), extLower.end(), extLower.begin(), + [](unsigned char c) { return std::tolower(c); }); std::error_code ec; if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { @@ -279,15 +284,22 @@ Asset::listFilesWithExtension(const std::string &directoryPath, } try { + auto checkExtension = [&](const fs::path& filePath) { + std::string fileExt = fromPath(filePath.extension()); + std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(), + [](unsigned char c) { return std::tolower(c); }); + return fileExt == extLower; + }; + if (recursive) { for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { - if (entry.is_regular_file() && entry.path().extension() == ext) { + if (entry.is_regular_file() && checkExtension(entry.path())) { files.push_back(fromPath(entry.path())); } } } else { for (const auto &entry : fs::directory_iterator(fullPath, ec)) { - if (entry.is_regular_file() && entry.path().extension() == ext) { + if (entry.is_regular_file() && checkExtension(entry.path())) { files.push_back(fromPath(entry.path())); } } diff --git a/Frostbite2D/src/frostbite2D/resource/npk_archive.cpp b/Frostbite2D/src/frostbite2D/resource/npk_archive.cpp new file mode 100644 index 0000000..6bef450 --- /dev/null +++ b/Frostbite2D/src/frostbite2D/resource/npk_archive.cpp @@ -0,0 +1,394 @@ +#include +#include +#include +#include + +namespace frostbite2D { + +const uint8 NpkArchive::NPK_KEY[256] = { + 112, 117, 99, 104, 105, 107, 111, 110, 64, 110, 101, 111, 112, 108, 101, 32, + 100, 117, 110, 103, 101, 111, 110, 32, 97, 110, 100, 32, 102, 105, 103, 104, + 116, 101, 114, 32, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, + 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, + 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, + 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, + 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, + 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, + 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, + 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, + 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 0 +}; + +NpkArchive& NpkArchive::get() { + static NpkArchive instance; + return instance; +} + +void NpkArchive::setImagePackDirectory(const std::string& dir) { + imagePackDirectory_ = dir; +} + +const std::string& NpkArchive::getImagePackDirectory() const { + return imagePackDirectory_; +} + +void NpkArchive::init() { + if (initialized_) { + close(); + } + + scanNpkFiles(); + initialized_ = true; +} + +void NpkArchive::close() { + imgIndex_.clear(); + imageCache_.clear(); + lruList_.clear(); + currentCacheSize_ = 0; + initialized_ = false; +} + +bool NpkArchive::isOpen() const { + return initialized_; +} + +std::string NpkArchive::normalizePath(const std::string& path) const { + std::string result = path; + std::transform(result.begin(), result.end(), result.begin(), + [](unsigned char c) { return std::tolower(c); }); + return result; +} + +void NpkArchive::scanNpkFiles() { + Asset& asset = Asset::get(); + std::string npkDir = asset.resolvePath(imagePackDirectory_); + if (!asset.isDirectory(npkDir)) { + SDL_Log("NPK directory not found: %s", npkDir.c_str()); + return; + } + + std::vector files = asset.listFilesWithExtension(npkDir, ".npk"); + SDL_Log("Scanning %d NPK files...", static_cast(files.size())); + for (const auto &file : files) { + parseNpkFile(file); + } +} + +bool NpkArchive::parseNpkFile(const std::string& npkPath) { + Asset& asset = Asset::get(); + BinaryReader reader(npkPath); + + if (!reader.isOpen()) { + SDL_Log("Failed to open NPK file: %s", npkPath.c_str()); + return false; + } + + std::string npkFileName = asset.getFileName(npkPath); + std::string header = reader.readNullTerminatedString(); + + if (header.find("NeoplePack_Bill") == std::string::npos) { + return false; + } + + int32 imageCount = reader.readInt32(); + + for (int32 i = 0; i < imageCount; ++i) { + int32 offset = reader.readInt32(); + int32 length = reader.readInt32(); + std::string imgPath = readNpkInfoString(reader); + + ImgRef img; + img.path = normalizePath(imgPath); + img.npkFile = npkFileName; + img.offset = static_cast(offset); + img.size = static_cast(length); + img.loaded = false; + + imgIndex_[img.path] = img; + } + + return true; +} + +bool NpkArchive::hasImg(const std::string& path) const { + return imgIndex_.find(normalizePath(path)) != imgIndex_.end(); +} + +std::optional NpkArchive::getImg(const std::string& path) { + auto it = imgIndex_.find(normalizePath(path)); + if (it == imgIndex_.end()) { + return std::nullopt; + } + return it->second; +} + +std::vector NpkArchive::listImgs() const { + std::vector result; + result.reserve(imgIndex_.size()); + for (const auto& pair : imgIndex_) { + result.push_back(pair.first); + } + return result; +} + +std::optional NpkArchive::getImageFrame(const ImgRef& img, size_t index) { + std::string imgPath = normalizePath(img.path); + + auto cacheIt = imageCache_.find(imgPath); + if (cacheIt == imageCache_.end()) { + auto it = imgIndex_.find(imgPath); + if (it == imgIndex_.end()) { + return std::nullopt; + } + + if (!loadImgData(it->second)) { + return std::nullopt; + } + cacheIt = imageCache_.find(imgPath); + if (cacheIt == imageCache_.end()) { + return std::nullopt; + } + } + + updateCacheUsage(imgPath); + + if (index >= cacheIt->second.frames.size()) { + return std::nullopt; + } + + return cacheIt->second.frames[index]; +} + +size_t NpkArchive::getFrameCount(const ImgRef& img) const { + std::string imgPath = normalizePath(img.path); + auto it = imgIndex_.find(imgPath); + if (it == imgIndex_.end()) { + return 0; + } + return it->second.frameCount; +} + +bool NpkArchive::loadImgData(ImgRef& img) { + Asset& asset = Asset::get(); + std::string npkPath = asset.combinePath(imagePackDirectory_, img.npkFile); + npkPath = asset.resolvePath(npkPath); + + BinaryReader reader(npkPath); + if (!reader.isOpen()) { + SDL_Log("Failed to open NPK for IMG: %s", npkPath.c_str()); + return false; + } + + reader.seek(img.offset); + std::string flag = reader.readNullTerminatedString(); + + if (flag.find("Neople Img File") == std::string::npos) { + return false; + } + + int64 tableLength = reader.readInt64(); + reader.readInt32(); + int32 indexCount = reader.readInt32(); + + img.frameCount = static_cast(indexCount); + + CachedImageData cachedData; + cachedData.frames.resize(indexCount); + + size_t dataStartPos = img.offset + static_cast(tableLength) + 32; + + for (int32 i = 0; i < indexCount; ++i) { + ImageFrame& frame = cachedData.frames[i]; + frame.type = reader.readInt32(); + + if (frame.type == 17) { + int32 refIndex = reader.readInt32(); + frame.compressionType = refIndex; + frame.width = cachedData.frames[refIndex].width; + frame.height = cachedData.frames[refIndex].height; + frame.xPos = cachedData.frames[refIndex].xPos; + frame.yPos = cachedData.frames[refIndex].yPos; + frame.frameXPos = cachedData.frames[refIndex].frameXPos; + frame.frameYPos = cachedData.frames[refIndex].frameYPos; + frame.offset = cachedData.frames[refIndex].offset; + frame.size = cachedData.frames[refIndex].size; + continue; + } + + frame.compressionType = reader.readInt32(); + frame.width = reader.readInt32(); + frame.height = reader.readInt32(); + int32 size = reader.readInt32(); + frame.xPos = reader.readInt32(); + frame.yPos = reader.readInt32(); + frame.frameXPos = reader.readInt32(); + frame.frameYPos = reader.readInt32(); + + frame.size = size; + if (i == 0) { + frame.offset = static_cast(dataStartPos); + } else { + frame.offset = cachedData.frames[i - 1].offset + cachedData.frames[i - 1].size; + } + } + + for (int32 i = 0; i < indexCount; ++i) { + ImageFrame& frame = cachedData.frames[i]; + + if (frame.type == 17) { + int32 refIndex = frame.compressionType; + frame.data = cachedData.frames[refIndex].data; + continue; + } + + reader.seek(frame.offset); + std::vector compressedData = reader.readBytes(static_cast(frame.size)); + + int32 deSize = frame.width * frame.height * 4; + std::vector decompressedData(deSize); + unsigned long realSize = static_cast(deSize); + + int uncompressResult = uncompress( + decompressedData.data(), + &realSize, + compressedData.data(), + static_cast(frame.size) + ); + + if (uncompressResult != Z_OK) { + SDL_Log("Failed to uncompress image data: %d", uncompressResult); + continue; + } + + if (frame.type != 16) { + int32 pngByteSize = deSize * 2; + frame.data.resize(pngByteSize); + + for (int32 e = 0; e < pngByteSize; e += 4) { + uint8 needData[2] = {0, 0}; + if ((e / 4) * 2 + 1 < static_cast(decompressedData.size())) { + needData[0] = decompressedData[(e / 4) * 2]; + needData[1] = decompressedData[(e / 4) * 2 + 1]; + } + parseColor(needData, frame.type, frame.data.data(), e); + } + } else { + frame.data = std::move(decompressedData); + } + + cachedData.memoryUsage += frame.data.size(); + } + + imageCache_[img.path] = std::move(cachedData); + currentCacheSize_ += imageCache_[img.path].memoryUsage; + lruList_.push_front(img.path); + + img.loaded = true; + imgIndex_[img.path] = img; + + return true; +} + +void NpkArchive::parseColor(const uint8* tab, int type, uint8* saveByte, int offset) { + uint8 a = 0, r = 0, g = 0, b = 0; + + switch (type) { + case 0x0e: + a = static_cast(tab[1] >> 7); + r = static_cast((tab[1] >> 2) & 0x1f); + g = static_cast((tab[0] >> 5) | ((tab[1] & 3) << 3)); + b = static_cast(tab[0] & 0x1f); + a = static_cast(a * 0xff); + r = static_cast((r << 3) | (r >> 2)); + g = static_cast((g << 3) | (g >> 2)); + b = static_cast((b << 3) | (b >> 2)); + break; + + case 0x0f: + a = static_cast(tab[1] & 0xf0); + r = static_cast((tab[1] & 0xf) << 4); + g = static_cast(tab[0] & 0xf0); + b = static_cast((tab[0] & 0xf) << 4); + break; + } + + saveByte[offset + 0] = b; + saveByte[offset + 1] = g; + saveByte[offset + 2] = r; + saveByte[offset + 3] = a; +} + +void NpkArchive::setCacheSize(size_t maxBytes) { + maxCacheSize_ = maxBytes; + evictCacheIfNeeded(0); +} + +void NpkArchive::clearCache() { + imageCache_.clear(); + lruList_.clear(); + currentCacheSize_ = 0; +} + +size_t NpkArchive::getCacheUsage() const { + return currentCacheSize_; +} + +void NpkArchive::evictCacheIfNeeded(size_t requiredSize) { + while (currentCacheSize_ + requiredSize > maxCacheSize_ && !lruList_.empty()) { + std::string oldest = lruList_.back(); + lruList_.pop_back(); + + auto it = imageCache_.find(oldest); + if (it != imageCache_.end()) { + currentCacheSize_ -= it->second.memoryUsage; + imageCache_.erase(it); + } + } +} + +void NpkArchive::updateCacheUsage(const std::string& imgPath) { + auto it = std::find(lruList_.begin(), lruList_.end(), imgPath); + if (it != lruList_.end()) { + lruList_.erase(it); + } + lruList_.push_front(imgPath); + + auto cacheIt = imageCache_.find(imgPath); + if (cacheIt != imageCache_.end()) { + cacheIt->second.lastUseTime = SDL_GetTicks(); + } +} + +std::string NpkArchive::readNpkInfoString(BinaryReader& reader) { + if (reader.eof()) { + return ""; + } + + std::vector encrypted = reader.readBytes(256); + if (encrypted.size() < 256) { + return ""; + } + + std::vector decrypted(256); + for (int i = 0; i < 256; ++i) { + decrypted[i] = static_cast(encrypted[i] ^ NPK_KEY[i]); + } + + return std::string(decrypted.data()); +} + +void NpkArchive::setDefaultImg(const std::string& imgPath, size_t frameIndex) { + defaultImgPath_ = normalizePath(imgPath); + defaultImgFrame_ = frameIndex; +} + +const std::string& NpkArchive::getDefaultImgPath() const { + return defaultImgPath_; +} + +size_t NpkArchive::getDefaultImgFrame() const { + return defaultImgFrame_; +} + +} diff --git a/Game/assets/ImagePacks2/!HUD_CW.NPK b/Game/assets/ImagePacks2/!HUD_CW.NPK new file mode 100644 index 0000000..b93b362 Binary files /dev/null and b/Game/assets/ImagePacks2/!HUD_CW.NPK differ diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 9e485bb..4a59ad3 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -14,8 +14,9 @@ #include #include -#include #include +#include +#include using namespace frostbite2D; @@ -42,59 +43,59 @@ int main(int argc, char **argv) { // 尝试加载精灵 auto sprite = Sprite::createFromFile("assets/player.png"); if (sprite) { - sprite->SetPosition(100, 100); + sprite->SetPosition(0, 0); menuScene->AddActor(sprite); SDL_Log("Sprite created and added to scene"); } else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from file!"); } - auto &archive = PvfArchive::get(); - if (archive.open("assets/Script.pvf")) { - archive.init(); - // 文件内容读取 - if (auto rawData = archive.getFileRawData("region/balmayer_north.rgn")) { - ScriptParser parser(*rawData, "script/example.bin"); - // // 方式1:迭代解析 - // while (!parser.isEnd()) { - // if (auto value = parser.next()) { - // switch (value->type) { - // case ScriptValueType::Integer: - // SDL_Log("Integer: %d", value->intValue); - // break; - // case ScriptValueType::Float: - // SDL_Log("Float: %f", value->floatValue); - // break; - // case ScriptValueType::String: - // SDL_Log("String: %s", value->stringValue.c_str()); - // break; - // default: - // break; - // } - // } - // } + // auto &archive = PvfArchive::get(); + // if (archive.open("assets/Script.pvf")) { + // archive.init(); + // // 文件内容读取 + // if (auto rawData = archive.getFileRawData("region/balmayer_north.rgn")) { + // ScriptParser parser(*rawData, "script/example.bin"); + // // // 方式1:迭代解析 + // // while (!parser.isEnd()) { + // // if (auto value = parser.next()) { + // // switch (value->type) { + // // case ScriptValueType::Integer: + // // SDL_Log("Integer: %d", value->intValue); + // // break; + // // case ScriptValueType::Float: + // // SDL_Log("Float: %f", value->floatValue); + // // break; + // // case ScriptValueType::String: + // // SDL_Log("String: %s", value->stringValue.c_str()); + // // break; + // // default: + // // break; + // // } + // // } + // // } - // // 方式2:批量解析 - // parser.reset(); - auto allValues = parser.parseAll(); - for (const auto &value : allValues) { - // 处理 value - switch (value.type) { - case ScriptValueType::Integer: - SDL_Log("Integer: %d", value.intValue); - break; - case ScriptValueType::Float: - SDL_Log("Float: %f", value.floatValue); - break; - case ScriptValueType::String: - SDL_Log("String: %s", value.stringValue.c_str()); - break; - default: - break; - } - } - } - } + // // // 方式2:批量解析 + // // parser.reset(); + // auto allValues = parser.parseAll(); + // for (const auto &value : allValues) { + // // 处理 value + // switch (value.type) { + // case ScriptValueType::Integer: + // SDL_Log("Integer: %d", value.intValue); + // break; + // case ScriptValueType::Float: + // SDL_Log("Float: %f", value.floatValue); + // break; + // case ScriptValueType::String: + // SDL_Log("String: %s", value.stringValue.c_str()); + // break; + // default: + // break; + // } + // } + // } + // } AudioSystem::get().init(); AudioSystem::get().setMasterVolume(1.0f); @@ -108,6 +109,19 @@ int main(int argc, char **argv) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background music!"); } + NpkArchive &npk = NpkArchive::get(); + npk.setImagePackDirectory("assets/ImagePacks2"); + npk.setDefaultImg("sprite/interface/base.img", 0); + npk.init(); + + auto sprite1 = Sprite::createFromNpk("sprite/newtitle/nangua.img", 0); + if (sprite1) { + sprite1->SetPosition(0, 0); + menuScene->AddActor(sprite1); + } else { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from NPK!"); + } + app.run(); app.shutdown(); diff --git a/platform/linux.lua b/platform/linux.lua index 9f79285..90cf367 100644 --- a/platform/linux.lua +++ b/platform/linux.lua @@ -3,6 +3,7 @@ add_requires("libsdl2", {configs = {shared = true,wayland = true}}) add_requires("libsdl2_image") add_requires("libsdl2_mixer") add_requires("glm") +add_requires("zlib") target("Frostbite2D") set_kind("binary") @@ -17,6 +18,7 @@ target("Frostbite2D") add_packages("libsdl2_image") add_packages("libsdl2_mixer") add_packages("glm") + add_packages("zlib") -- 复制着色器文件到输出目录 after_build(function (target) diff --git a/platform/mingw.lua b/platform/mingw.lua index b88e147..cf02dc2 100644 --- a/platform/mingw.lua +++ b/platform/mingw.lua @@ -5,6 +5,7 @@ add_requires("libsdl2", {configs = {shared = true}}) add_requires("libsdl2_image", {configs = {shared = true}}) add_requires("libsdl2_mixer", {configs = {shared = true}}) add_requires("glm") +add_requires("zlib") target("Frostbite2D") set_kind("binary") @@ -19,6 +20,7 @@ target("Frostbite2D") add_packages("libsdl2_image") add_packages("libsdl2_mixer") add_packages("glm") + add_packages("zlib") -- 复制 assets 目录到输出目录 after_build(function (target)