From 6baa9a251c9276e02f3f5a64de8910b8a1143113 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sat, 30 Mar 2019 17:06:22 -0500 Subject: [PATCH] [nostalgia] Add new pack library to bundle project into OxFS --- src/nostalgia/tools/pack/CMakeLists.txt | 24 +++++ src/nostalgia/tools/pack/imgconv.cpp | 113 ++++++++++++++++++++++++ src/nostalgia/tools/pack/imgconv.hpp | 18 ++++ src/nostalgia/tools/pack/pack.cpp | 60 +++++++++++++ src/nostalgia/tools/pack/pack.hpp | 17 ++++ 5 files changed, 232 insertions(+) create mode 100644 src/nostalgia/tools/pack/CMakeLists.txt create mode 100644 src/nostalgia/tools/pack/imgconv.cpp create mode 100644 src/nostalgia/tools/pack/imgconv.hpp create mode 100644 src/nostalgia/tools/pack/pack.cpp create mode 100644 src/nostalgia/tools/pack/pack.hpp diff --git a/src/nostalgia/tools/pack/CMakeLists.txt b/src/nostalgia/tools/pack/CMakeLists.txt new file mode 100644 index 00000000..8f97f54e --- /dev/null +++ b/src/nostalgia/tools/pack/CMakeLists.txt @@ -0,0 +1,24 @@ + +add_library( + Pack SHARED + imgconv.cpp + pack.cpp +) + +target_link_libraries( + Pack + Qt5::Widgets + OxClArgs + OxFS + OxStd + OxMetalClaw + NostalgiaCommon + NostalgiaCore +) + +install( + TARGETS + Pack + LIBRARY DESTINATION + ${NOSTALGIA_DIST_LIB}/nostalgia +) diff --git a/src/nostalgia/tools/pack/imgconv.cpp b/src/nostalgia/tools/pack/imgconv.cpp new file mode 100644 index 00000000..c921cc01 --- /dev/null +++ b/src/nostalgia/tools/pack/imgconv.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2015 - 2019 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include + +#include "imgconv.hpp" + +namespace nostalgia { + +namespace { + +[[nodiscard]] uint16_t toGbaColor(QColor c) { + const auto r = static_cast(c.red()) >> 3; + const auto g = static_cast(c.green()) >> 3; + const auto b = static_cast(c.blue()) >> 3; + return (r << 10) | (g << 5) | (b << 0); +} + +[[nodiscard]] 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; +} + +} + +[[nodiscard]] static int countColors(const QImage &img, int argTiles) { + QMap colors; + // copy pixels as color ids + for (int x = 0; x < img.width(); x++) { + for (int y = 0; y < img.height(); y++) { + auto destI = pointToIdx(img.width(), x, y); + if (destI <= argTiles * 64) { + auto c = img.pixel(x, y); + // assign color a color id for the palette + if (!colors.contains(c)) { + colors[c] = true; + } + } + } + } + return colors.size(); +} + +ox::Error pngToGba(QString argInPath, int argTiles, int argBpp) { + ox::Error err = 0; + + QImage src(argInPath); + + if (argTiles == 0) { + argTiles = (src.width() * src.height()) / 64; + } + if (argBpp != 4 && argBpp != 8) { + argBpp = countColors(src, argTiles) > 16 ? 8 : 4; + } + + 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()); + 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); + } + return err; +} + +} diff --git a/src/nostalgia/tools/pack/imgconv.hpp b/src/nostalgia/tools/pack/imgconv.hpp new file mode 100644 index 00000000..1c966db8 --- /dev/null +++ b/src/nostalgia/tools/pack/imgconv.hpp @@ -0,0 +1,18 @@ +/* + * Copyright 2015 - 2018 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include + +namespace nostalgia { + +ox::Error pngToGba(QString argInPath, int argTiles, int argBpp = -1); + +} diff --git a/src/nostalgia/tools/pack/pack.cpp b/src/nostalgia/tools/pack/pack.cpp new file mode 100644 index 00000000..4ff50606 --- /dev/null +++ b/src/nostalgia/tools/pack/pack.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2015 - 2019 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include "imgconv.hpp" +#include "pack.hpp" + +namespace nostalgia { + +[[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 +ox::Error pathToInode(std::vector *buff) { + return OxError(0); +} + +// stub for now +ox::Error toMetalClaw(std::vector *buff) { + 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 inode) { + auto stat = src->stat(path.c_str()); + oxReturnError(stat.error); + if (stat.value.fileType == ox::FileType_Directory) { + const auto dir = path + name + '/'; + 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())); + // do transforms + if (endsWith(path, ".claw")) { + oxReturnError(pathToInode(&buff)); + oxReturnError(toMetalClaw(&buff)); + } else if (endsWith(path, ".png")) { + const auto fullPath = src->basePath() + path; + oxReturnError(pngToGba(fullPath.c_str(), 0, 0)); + } + // write file to dest + oxReturnError(dest->write(path.c_str(), buff.data(), buff.size())); + } + return OxError(0); + }); + return OxError(0); +} + +} diff --git a/src/nostalgia/tools/pack/pack.hpp b/src/nostalgia/tools/pack/pack.hpp new file mode 100644 index 00000000..dbad15af --- /dev/null +++ b/src/nostalgia/tools/pack/pack.hpp @@ -0,0 +1,17 @@ +/* + * Copyright 2015 - 2018 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +namespace nostalgia { + +ox::Error copy(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path = "/"); + +}