diff --git a/src/nostalgia/tools/CMakeLists.txt b/src/nostalgia/tools/CMakeLists.txt index 8dc63218..f2f9758b 100644 --- a/src/nostalgia/tools/CMakeLists.txt +++ b/src/nostalgia/tools/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries( OxMetalClaw NostalgiaCommon NostalgiaCore + NostalgiaPack ) install( diff --git a/src/nostalgia/tools/pack.cpp b/src/nostalgia/tools/pack.cpp index 7d3e76a8..1ad5f4e5 100644 --- a/src/nostalgia/tools/pack.cpp +++ b/src/nostalgia/tools/pack.cpp @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include #include #include @@ -14,155 +15,42 @@ #include #include #include +#include + +#include "pack/pack.hpp" using namespace std; using namespace ox; using namespace nostalgia::core; using namespace nostalgia::common; -uint8_t *loadFileBuff(QString path, ::size_t *sizeOut = nullptr) { +ox::ValErr> loadFileBuff(QString path, ::size_t *sizeOut = nullptr) { auto file = fopen(path.toUtf8(), "rb"); if (file) { fseek(file, 0, SEEK_END); const auto size = ftell(file); rewind(file); - auto buff = new uint8_t[size]; - auto itemsRead = fread(buff, size, 1, file); + std::vector buff(size); + auto itemsRead = fread(buff.data(), buff.size(), 1, file); fclose(file); if (sizeOut) { *sizeOut = itemsRead ? size : 0; } return buff; } else { - return nullptr; + return {{}, OxError(1)}; } } -uint16_t toGbaColor(QColor c) { - auto r = static_cast(c.red()) >> 3; - auto g = static_cast(c.green()) >> 3; - auto b = static_cast(c.blue()) >> 3; - return (r << 10) | (g << 5) | (b << 0); -} - -int pointToIdx(int w, int x, int y) { - const auto colLength = 64; - const auto rowLength = (w / 8) * colLength; - const auto colStart = colLength * (x / 8); - const auto rowStart = rowLength * (y / 8); - const auto colOffset = x % 8; - const auto rowOffset = (y % 8) * 8; - return colStart + colOffset + rowStart + rowOffset; -} - int run(ClArgs args) { - Error err = 0; - int argInode = args.getInt("inode"); - QString argInPath = args.getString("img").c_str(); - QString argFsPath = args.getString("fs").c_str(); - auto argCompact = args.getBool("c"); - auto argTiles = args.getInt("tiles"); - auto argBpp = args.getInt("bpp"); - - QImage src(argInPath); - - if (!src.isNull()) { - if (argTiles == 0) { - argTiles = (src.width() * src.height()) / 64; - } - if (argBpp != 4 && argBpp != 8) { - argBpp = 8; - } - - QMap colors; - const auto imgDataBuffSize = sizeof(GbaImageData) + 1 + argTiles * 64; - QVector imgDataBuff(imgDataBuffSize); - memset(imgDataBuff.data(), 0, imgDataBuffSize); - auto id = reinterpret_cast(imgDataBuff.data()); - id->header.bpp = argBpp; - id->header.tileCount = argTiles; - int colorId = 0; - - // copy pixels as color ids - for (int x = 0; x < src.width(); x++) { - for (int y = 0; y < src.height(); y++) { - auto destI = pointToIdx(src.width(), x, y); - if (destI <= argTiles * 64) { - auto c = src.pixel(x, y); - // assign color a color id for the palette - if (!colors.contains(c)) { - colors[c] = colorId; - colorId++; - } - // set pixel color - if (argBpp == 4) { - if (destI % 2) { // is odd number pixel - id->tiles[destI / 2] |= colors[c] << 4; - } else { - id->tiles[destI / 2] |= colors[c]; - } - } else { - id->tiles[destI] = colors[c]; - } - } - } - } - - // store colors in palette with the corresponding color id - for (auto key : colors.keys()) { - auto colorId = colors[key]; - id->pal[colorId] = toGbaColor(key); - } - - - size_t fsBuffSize; - auto fsBuff = loadFileBuff(argFsPath, &fsBuffSize); - if (fsBuff && !err) { - auto fs = FileSystem32(FileStore32(fsBuff, fsBuffSize)); - - if (fs.valid()) { - const auto sizeNeeded = fs.size() + fs.spaceNeeded(imgDataBuffSize); - if (sizeNeeded > fsBuffSize) { - auto newBuff = new uint8_t[sizeNeeded]; - memcpy(newBuff, fsBuff, fsBuffSize); - delete[] fsBuff; - fsBuff = newBuff; - fsBuffSize = sizeNeeded; - } - fsBuff = fs.buff(); // update fsBuff pointer in case there is a new buff - err |= fs.write(argInode, imgDataBuff.data(), imgDataBuffSize); - - if (!err) { - if (argCompact) { - FileStore32(fsBuff, fsBuffSize).compact(); - } - - auto fsFile = fopen(argFsPath.toUtf8(), "wb"); - if (fsFile) { - err = fwrite(fsBuff, fs.size(), 1, fsFile) != 1; - err |= fclose(fsFile); - if (err) { - cerr << "Could not write to file system file.\n"; - } - } else { - err = 2; - } - } else { - err = 3; - } - } else { - err = 4; - } - } - - if (fsBuff) { - delete[] fsBuff; - } - } else { - err = 5; - } - - return err; + QString argSrc = args.getString("src").c_str(); + QString argDst = args.getString("dst").c_str(); + std::array buff; + ox::FileSystem32::format(buff.data(), buff.size()); + ox::PassThroughFS src(argSrc.toUtf8()); + ox::FileSystem32 dst(ox::FileStore32(buff.data(), buff.size())); + oxReturnError(nostalgia::pack(&src, &dst)); + return 0; } int main(int argc, const char **args) { diff --git a/src/nostalgia/tools/pack/CMakeLists.txt b/src/nostalgia/tools/pack/CMakeLists.txt index 8f97f54e..05071c06 100644 --- a/src/nostalgia/tools/pack/CMakeLists.txt +++ b/src/nostalgia/tools/pack/CMakeLists.txt @@ -1,12 +1,12 @@ add_library( - Pack SHARED + NostalgiaPack SHARED imgconv.cpp pack.cpp ) target_link_libraries( - Pack + NostalgiaPack Qt5::Widgets OxClArgs OxFS @@ -18,7 +18,7 @@ target_link_libraries( install( TARGETS - Pack + NostalgiaPack LIBRARY DESTINATION ${NOSTALGIA_DIST_LIB}/nostalgia ) diff --git a/src/nostalgia/tools/pack/imgconv.cpp b/src/nostalgia/tools/pack/imgconv.cpp index c921cc01..01e61856 100644 --- a/src/nostalgia/tools/pack/imgconv.cpp +++ b/src/nostalgia/tools/pack/imgconv.cpp @@ -56,11 +56,13 @@ namespace { return colors.size(); } -ox::Error pngToGba(QString argInPath, int argTiles, int argBpp) { - ox::Error err = 0; - +[[nodiscard]] std::vector pngToGba(QString argInPath, int argTiles, int argBpp) { QImage src(argInPath); + if (src.isNull()) { + return {}; + } + if (argTiles == 0) { argTiles = (src.width() * src.height()) / 64; } @@ -70,9 +72,8 @@ ox::Error pngToGba(QString argInPath, int argTiles, int argBpp) { QMap colors; const auto imgDataBuffSize = sizeof(core::GbaImageData) + 1 + argTiles * 64; - auto imgDataBuff = std::make_unique(imgDataBuffSize); - memset(imgDataBuff.get(), 0, imgDataBuffSize); - auto id = reinterpret_cast(imgDataBuff.get()); + std::vector imgDataBuff(imgDataBuffSize); + auto id = new (imgDataBuff.data()) core::GbaImageData; id->header.bpp = argBpp; id->header.tileCount = argTiles; int colorId = 0; @@ -82,7 +83,7 @@ ox::Error pngToGba(QString argInPath, int argTiles, int argBpp) { for (int y = 0; y < src.height(); y++) { auto destI = pointToIdx(src.width(), x, y); if (destI <= argTiles * 64) { - auto c = src.pixel(x, y); + const auto c = src.pixel(x, y); // assign color a color id for the palette if (!colors.contains(c)) { colors[c] = colorId; @@ -107,7 +108,8 @@ ox::Error pngToGba(QString argInPath, int argTiles, int argBpp) { auto colorId = colors[key]; id->pal[colorId] = toGbaColor(key); } - return err; + + return imgDataBuff; } } diff --git a/src/nostalgia/tools/pack/imgconv.hpp b/src/nostalgia/tools/pack/imgconv.hpp index 1c966db8..16af96aa 100644 --- a/src/nostalgia/tools/pack/imgconv.hpp +++ b/src/nostalgia/tools/pack/imgconv.hpp @@ -13,6 +13,6 @@ namespace nostalgia { -ox::Error pngToGba(QString argInPath, int argTiles, int argBpp = -1); +[[nodiscard]] std::vector pngToGba(QString argInPath, int argTiles, int argBpp = -1); } diff --git a/src/nostalgia/tools/pack/pack.cpp b/src/nostalgia/tools/pack/pack.cpp index a582fb75..9cce07c4 100644 --- a/src/nostalgia/tools/pack/pack.cpp +++ b/src/nostalgia/tools/pack/pack.cpp @@ -14,11 +14,18 @@ namespace nostalgia { +namespace { + [[nodiscard]] static constexpr bool endsWith(std::string_view str, std::string_view ending) { return str.size() >= ending.size() && str.substr(str.size() - ending.size()) == ending; } -// stub for now +/** + * Convert path references to inodes to save space + * @param buff buffer holding file + * @return error + * stub for now + */ ox::Error pathToInode(std::vector*) { return OxError(0); } @@ -28,6 +35,34 @@ ox::Error toMetalClaw(std::vector*) { return OxError(0); } +// claw file transformations are broken out because path to inode +// transformations need to be done after the copy to the new FS is complete +ox::Error transformClaw(ox::FileSystem32 *dest, std::string path) { + // copy + dest->ls(path.c_str(), [dest, path](const char *name, ox::InodeId_t) { + auto stat = dest->stat(path.c_str()); + oxReturnError(stat.error); + if (stat.value.fileType == ox::FileType_Directory) { + const auto dir = path + name + '/'; + oxReturnError(transformClaw(dest, dir)); + } else { + // do transforms + if (endsWith(path, ".claw")) { + // load file + std::vector buff(stat.value.size); + oxReturnError(dest->read(path.c_str(), buff.data(), buff.size())); + // do transformations + oxReturnError(pathToInode(&buff)); + oxReturnError(toMetalClaw(&buff)); + // write file to dest + oxReturnError(dest->write(path.c_str(), buff.data(), buff.size())); + } + } + return OxError(0); + }); + return OxError(0); +} + ox::Error copy(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path) { // copy src->ls(path.c_str(), [src, dest, path](const char *name, ox::InodeId_t) { @@ -38,16 +73,19 @@ ox::Error copy(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path) oxReturnError(dest->mkdir(dir.c_str())); oxReturnError(copy(src, dest, dir)); } else { - std::vector buff(stat.value.size); - // load file - oxReturnError(src->read(path.c_str(), buff.data(), buff.size())); + std::vector buff; // do transforms - if (endsWith(path, ".claw")) { - oxReturnError(pathToInode(&buff)); - oxReturnError(toMetalClaw(&buff)); - } else if (endsWith(path, ".png")) { + if (endsWith(path, ".png")) { + // load file from full path and transform const auto fullPath = src->basePath() + path; - oxReturnError(pngToGba(fullPath.c_str(), 0, 0)); + buff = pngToGba(fullPath.c_str(), 0, 0); + if (!buff.size()) { + return OxError(1); + } + } else { + // load file + buff.resize(stat.value.size); + oxReturnError(src->read(path.c_str(), buff.data(), buff.size())); } // write file to dest oxReturnError(dest->write(path.c_str(), buff.data(), buff.size())); @@ -58,3 +96,11 @@ ox::Error copy(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path) } } + +ox::Error pack(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path) { + oxReturnError(copy(src, dest, path)); + oxReturnError(transformClaw(dest, path)); + return OxError(0); +} + +} diff --git a/src/nostalgia/tools/pack/pack.hpp b/src/nostalgia/tools/pack/pack.hpp index dbad15af..b82c2c91 100644 --- a/src/nostalgia/tools/pack/pack.hpp +++ b/src/nostalgia/tools/pack/pack.hpp @@ -12,6 +12,6 @@ namespace nostalgia { -ox::Error copy(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path = "/"); +ox::Error pack(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path = "/"); }