From aa833ba3ddef8bae50aa36dfbf051d5310e9531a Mon Sep 17 00:00:00 2001 From: grunt-lucas Date: Fri, 1 Sep 2023 17:36:44 -0700 Subject: [PATCH] Can now import compiled tiles.png --- src/compiler.cpp | 22 ++++++++++++++-------- src/driver.cpp | 22 +++++++++++----------- src/emitter.cpp | 9 +++++---- src/importer.cpp | 33 ++++++++++++++++++++++++++++++--- 4 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 3eb34993..7e23c65b 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -918,6 +918,12 @@ std::unique_ptr compile(PtContext &ctx, const DecompiledTileset internalerror_unknownCompilerMode("compiler::compile"); } + // Push back transparent tiles to pad out tileset to multiple of 16 + while (compiled->tiles.size() % 16 != 0) { + compiled->tiles.push_back(GBA_TILE_TRANSPARENT); + compiled->paletteIndexesOfTile.push_back(0); + } + return compiled; } } // namespace porytiles @@ -1716,7 +1722,7 @@ TEST_CASE("compile function should fill out primary CompiledTileset struct with auto compiledPrimary = porytiles::compile(ctx, decompiledPrimary); // Check that tiles are as expected - CHECK(compiledPrimary->tiles.size() == 5); + CHECK(compiledPrimary->tiles.size() == 16); REQUIRE(std::filesystem::exists("res/tests/simple_metatiles_3/primary/expected_tiles.png")); png::image expectedPng{"res/tests/simple_metatiles_3/primary/expected_tiles.png"}; for (std::size_t tileIndex = 0; tileIndex < compiledPrimary->tiles.size(); tileIndex++) { @@ -1729,7 +1735,7 @@ TEST_CASE("compile function should fill out primary CompiledTileset struct with } // Check that paletteIndexesOfTile are correct - CHECK(compiledPrimary->paletteIndexesOfTile.size() == 5); + CHECK(compiledPrimary->paletteIndexesOfTile.size() == 16); CHECK(compiledPrimary->paletteIndexesOfTile[0] == 0); CHECK(compiledPrimary->paletteIndexesOfTile[1] == 2); CHECK(compiledPrimary->paletteIndexesOfTile[2] == 1); @@ -1826,7 +1832,7 @@ TEST_CASE("compile function should fill out primary CompiledTileset struct with CHECK(compiledPrimary->colorIndexMap[porytiles::rgbaToBgr(porytiles::RGBA_WHITE)] == 4); // Check that tileIndexes is correct - CHECK(compiledPrimary->tileIndexes.size() == compiledPrimary->tiles.size()); + CHECK(compiledPrimary->tileIndexes.size() == 5); CHECK(compiledPrimary->tileIndexes[compiledPrimary->tiles[0]] == 0); CHECK(compiledPrimary->tileIndexes[compiledPrimary->tiles[1]] == 1); CHECK(compiledPrimary->tileIndexes[compiledPrimary->tiles[2]] == 2); @@ -1985,7 +1991,7 @@ TEST_CASE("compile function should fill out secondary CompiledTileset struct wit CHECK(compiledSecondary->colorIndexMap[porytiles::rgbaToBgr(porytiles::RGBA_GREY)] == 8); // Check that tileIndexes is correct - CHECK(compiledSecondary->tileIndexes.size() == compiledSecondary->tiles.size()); + CHECK(compiledSecondary->tileIndexes.size() == 6); CHECK(compiledSecondary->tileIndexes[compiledSecondary->tiles[0]] == 0); CHECK(compiledSecondary->tileIndexes[compiledSecondary->tiles[1]] == 1); CHECK(compiledSecondary->tileIndexes[compiledSecondary->tiles[2]] == 2); @@ -2052,7 +2058,7 @@ TEST_CASE("compile function should correctly compile primary set with animated t auto compiledPrimary = porytiles::compile(ctx, decompiledPrimary); - CHECK(compiledPrimary->tiles.size() == 10); + CHECK(compiledPrimary->tiles.size() == 16); REQUIRE(std::filesystem::exists("res/tests/anim_metatiles_1/primary/expected_tiles.png")); png::image expectedPng{"res/tests/anim_metatiles_1/primary/expected_tiles.png"}; @@ -2066,7 +2072,7 @@ TEST_CASE("compile function should correctly compile primary set with animated t } // Check that paletteIndexesOfTile is correct - CHECK(compiledPrimary->paletteIndexesOfTile.size() == 10); + CHECK(compiledPrimary->paletteIndexesOfTile.size() == 16); CHECK(compiledPrimary->paletteIndexesOfTile[0] == 0); CHECK(compiledPrimary->paletteIndexesOfTile[1] == 2); CHECK(compiledPrimary->paletteIndexesOfTile[2] == 2); @@ -2302,7 +2308,7 @@ TEST_CASE("compile function should correctly compile secondary set with animated auto compiledSecondary = porytiles::compile(ctx, decompiledSecondary); - CHECK(compiledSecondary->tiles.size() == 8); + CHECK(compiledSecondary->tiles.size() == 16); REQUIRE(std::filesystem::exists("res/tests/anim_metatiles_1/secondary/expected_tiles.png")); png::image expectedPng{"res/tests/anim_metatiles_1/secondary/expected_tiles.png"}; @@ -2316,7 +2322,7 @@ TEST_CASE("compile function should correctly compile secondary set with animated } // Check that paletteIndexesOfTile is correct - CHECK(compiledSecondary->paletteIndexesOfTile.size() == 8); + CHECK(compiledSecondary->paletteIndexesOfTile.size() == 16); CHECK(compiledSecondary->paletteIndexesOfTile[0] == 5); CHECK(compiledSecondary->paletteIndexesOfTile[1] == 5); CHECK(compiledSecondary->paletteIndexesOfTile[2] == 5); diff --git a/src/driver.cpp b/src/driver.cpp index 8894d200..9a27ae9e 100644 --- a/src/driver.cpp +++ b/src/driver.cpp @@ -45,7 +45,7 @@ static void driveTilesEmit(PtContext &ctx, const CompiledTileset &compiledTiles, // TODO : move this function's functionality into emitter const std::size_t imageWidth = porytiles::TILE_SIDE_LENGTH * porytiles::TILES_PNG_WIDTH_IN_TILES; const std::size_t imageHeight = - porytiles::TILE_SIDE_LENGTH * ((compiledTiles.tiles.size() / porytiles::TILES_PNG_WIDTH_IN_TILES) + 1); + porytiles::TILE_SIDE_LENGTH * ((compiledTiles.tiles.size() / porytiles::TILES_PNG_WIDTH_IN_TILES)); png::image tilesPng{static_cast(imageWidth), static_cast(imageHeight)}; emitTilesPng(ctx, tilesPng, compiledTiles); @@ -476,7 +476,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 primary set for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -583,7 +583,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 primary set actualHeightInTiles = actual_flower_white_00.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -599,7 +599,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 primary set actualHeightInTiles = actual_flower_white_01.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -615,7 +615,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 primary set actualHeightInTiles = actual_flower_white_02.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -630,7 +630,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 primary set actualHeightInTiles = actual_water_00.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -645,7 +645,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 primary set actualHeightInTiles = actual_water_01.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -690,7 +690,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 secondary s for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -794,7 +794,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 secondary s actualHeightInTiles = actual_flower_red_00.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -810,7 +810,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 secondary s actualHeightInTiles = actual_flower_red_01.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); @@ -826,7 +826,7 @@ TEST_CASE("drive should emit all expected files for anim_metatiles_2 secondary s actualHeightInTiles = actual_flower_red_02.get_height() / porytiles::TILE_SIDE_LENGTH; for (std::size_t tileIndex = 0; tileIndex < actualWidthInTiles * actualHeightInTiles; tileIndex++) { std::size_t tileRow = tileIndex / actualWidthInTiles; - std::size_t tileCol = tileIndex % actualHeightInTiles; + std::size_t tileCol = tileIndex % actualWidthInTiles; for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); diff --git a/src/emitter.cpp b/src/emitter.cpp index 3370374b..5d1a4098 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -104,13 +104,14 @@ void emitTilesPng(PtContext &ctx, png::image &out, const Compi std::size_t pixelCol = (tileCol * TILE_SIDE_LENGTH) + (pixelIndex % TILE_SIDE_LENGTH); if (tileIndex < tileset.tiles.size()) { const GBATile &tile = tileset.tiles.at(tileIndex); - png::byte paletteIndex = tileset.paletteIndexesOfTile.at(tileIndex); + png::byte paletteIndex = 0; png::byte indexInPalette = tile.getPixel(pixelIndex); switch (ctx.output.paletteMode) { case TilesOutputPalette::GREYSCALE: out[pixelRow][pixelCol] = indexInPalette; break; case TilesOutputPalette::TRUE_COLOR: + paletteIndex = tileset.paletteIndexesOfTile.at(tileIndex); out[pixelRow][pixelCol] = (paletteIndex << 4) | indexInPalette; break; default: @@ -118,8 +119,8 @@ void emitTilesPng(PtContext &ctx, png::image &out, const Compi } } else { - // Pad out transparent tiles at end of last tiles.png row - out[pixelRow][pixelCol] = 0; + internalerror(fmt::format("emitter::emitTilesPng tileIndex reached {} which is larger than size {}", tileIndex, + tileset.tiles.size())); } } } @@ -360,7 +361,7 @@ TEST_CASE("emitTilesPng should emit the expected tiles.png file") const size_t imageWidth = porytiles::TILE_SIDE_LENGTH * porytiles::TILES_PNG_WIDTH_IN_TILES; const size_t imageHeight = - porytiles::TILE_SIDE_LENGTH * ((compiledPrimary->tiles.size() / porytiles::TILES_PNG_WIDTH_IN_TILES) + 1); + porytiles::TILE_SIDE_LENGTH * ((compiledPrimary->tiles.size() / porytiles::TILES_PNG_WIDTH_IN_TILES)); png::image outPng{static_cast(imageWidth), static_cast(imageHeight)}; diff --git a/src/importer.cpp b/src/importer.cpp index f95b4891..ab63e9a3 100644 --- a/src/importer.cpp +++ b/src/importer.cpp @@ -16,6 +16,7 @@ #include #include "driver.h" +#include "emitter.h" #include "errors_warnings.h" #include "logger.h" #include "ptcontext.h" @@ -575,8 +576,30 @@ importAttributesFromCsv(PtContext &ctx, const std::unordered_map importMetatilesAndAttrs(PtContext &ctx, std::ifstream &metatilesBin, - std::ifstream &metatileAttributesBin) +static std::vector importCompiledTiles(PtContext &ctx, const png::image &tiles) +{ + std::vector gbaTiles{}; + + std::size_t widthInTiles = tiles.get_width() / porytiles::TILE_SIDE_LENGTH; + std::size_t heightInTiles = tiles.get_height() / porytiles::TILE_SIDE_LENGTH; + + for (std::size_t tileIndex = 0; tileIndex < widthInTiles * heightInTiles; tileIndex++) { + std::size_t tileRow = tileIndex / widthInTiles; + std::size_t tileCol = tileIndex % widthInTiles; + GBATile tile{}; + for (std::size_t pixelIndex = 0; pixelIndex < porytiles::TILE_NUM_PIX; pixelIndex++) { + std::size_t pixelRow = (tileRow * porytiles::TILE_SIDE_LENGTH) + (pixelIndex / porytiles::TILE_SIDE_LENGTH); + std::size_t pixelCol = (tileCol * porytiles::TILE_SIDE_LENGTH) + (pixelIndex % porytiles::TILE_SIDE_LENGTH); + tile.colorIndexes.at(pixelIndex) = tiles[pixelRow][pixelCol]; + } + gbaTiles.push_back(tile); + } + + return gbaTiles; +} + +static std::vector importCompiledMetatilesAndAttrs(PtContext &ctx, std::ifstream &metatilesBin, + std::ifstream &metatileAttributesBin) { std::vector assignments{}; @@ -670,7 +693,8 @@ CompiledTileset importCompiledTileset(PtContext &ctx, const std::filesystem::pat std::ifstream attributes{tilesetPath / "metatile_attributes.bin", std::ios::binary}; png::image tilesheetPng{tilesetPath / "tiles.png"}; - tileset.assignments = importMetatilesAndAttrs(ctx, metatiles, attributes); + tileset.tiles = importCompiledTiles(ctx, tilesheetPng); + tileset.assignments = importCompiledMetatilesAndAttrs(ctx, metatiles, attributes); return tileset; } @@ -1175,6 +1199,9 @@ TEST_CASE("importCompiledTileset should import a triple layer pokeemerald tilese porytiles::PtContext decompileCtx{}; porytiles::CompiledTileset importedTileset = porytiles::importCompiledTileset(decompileCtx, parentDir); + CHECK((compileCtx.compilerContext.resultTileset)->tiles.size() == importedTileset.tiles.size()); + CHECK((compileCtx.compilerContext.resultTileset)->tiles == importedTileset.tiles); + CHECK((compileCtx.compilerContext.resultTileset)->assignments.size() == importedTileset.assignments.size()); for (std::size_t assignmentIndex = 0; assignmentIndex < importedTileset.assignments.size(); assignmentIndex++) { const porytiles::Assignment &expectedAssignment =