Files
gbdk-2020/gbdk-support/png2asset/maps.cpp
Toxa b3a785bf0b png2asset: fix tile palette extraction and comparison (#862)
* improve png2asset tile palette handling
* revert to detecting palette by the corner pixel of the tile
* detect palette by maximum on the tile
* return zero tile result correctly
* remove the last (?) usage of the corner pixel peeking, use tile.pal instead
2026-02-21 13:54:01 -08:00

161 lines
6.6 KiB
C++

#include <vector>
#include <string>
#include <algorithm>
#include <cstring>
#include <set>
#include <stdio.h>
#include <fstream>
#include <cstdint>
#include "lodepng.h"
#include "mttile.h"
#include "export.h"
#include "cmp_int_color.h"
#include "tiles.h"
using namespace std;
#include "png2asset.h"
#include "image_utils.h"
#include "map_attributes.h"
#include "process_arguments.h"
void ExtractTileset(PNG2AssetData* assetData, vector< Tile > & tileset, bool keep_duplicate_tiles) {
// Placeholder vars needed for function call, they get discarded
size_t idx;
unsigned char props;
for(int y = 0; y < (int)assetData->image.h; y += assetData->image.tile_h)
{
for(int x = 0; x < (int)assetData->image.w; x += assetData->image.tile_w)
{
// Get a tile from the image
Tile tile(assetData->image.tile_w * assetData->image.tile_h);
assetData->image.ExtractTile(x, y, tile, assetData->args->sprite_mode, assetData->args->export_as_map, assetData->args->use_map_attributes);
if (keep_duplicate_tiles)
tileset.push_back(tile);
else {
if (!FindTile(tile, idx, props, tileset, assetData))
tileset.push_back(tile);
}
}
}
}
static void checkWarnMapTileLimits(PNG2AssetData* assetData) {
unsigned int maxUsedTileCount = (assetData->tiles.size() + assetData->args->tile_origin);
unsigned int maxTilesWarnLimit = 256; // 256 is default for GB, NES
// GB + Map Attributes implies GBC which has a secondary tile bank
if (((assetData->args->pack_mode == Tile::GB) && assetData->args->use_map_attributes) ||
(assetData->args->pack_mode == Tile::SMS)) {
maxTilesWarnLimit = 512;
}
if (maxUsedTileCount > maxTilesWarnLimit) {
printf("Warning: Tile count (%d) + tile origin (%d) = %d exceeds limit %d\n",
(unsigned int)assetData->tiles.size(), (unsigned int)assetData->args->tile_origin,
maxUsedTileCount, maxTilesWarnLimit);
}
// If using GBC, notify user about extra requirements to use > 256 tiles
if ((maxUsedTileCount > 256) && ((assetData->args->pack_mode == Tile::GB) && assetData->args->use_map_attributes)) {
printf("Warning: On GBC more then 256 tiles may require use of alternate tile bank. Tile count (%d) + tile origin (%d) = %d\n",
(unsigned int)assetData->tiles.size(), (unsigned int)assetData->args->tile_origin, maxUsedTileCount);
}
}
void GetMap(PNG2AssetData* assetData)
{
for(int y = 0; y < (int)assetData->image.h; y += assetData->image.tile_h)
{
for(int x = 0; x < (int)assetData->image.w; x += assetData->image.tile_w)
{
// Get a tile from the image
Tile tile(assetData->image.tile_w * assetData->image.tile_h);
assetData->image.ExtractTile(x, y, tile, assetData->args->sprite_mode, assetData->args->export_as_map, assetData->args->use_map_attributes);
size_t idx;
unsigned char props;
// If there is an entity tileset then always check that for a matching tile first
if (assetData->args->has_entity_tileset && FindTile(tile, idx, props, assetData->entity_tiles, assetData)) {
// Entity tilesets index counts from 255 down instead of 0 up,
// so invert the tile ID on the 8 bit boundary
idx = (256 - assetData->entity_tiles.size()) + idx;
props = assetData->args->props_default;
}
// When both -keep_duplicate_tiles and source tilesets are used then
// keep_duplicate_tiles should only apply to source tilesets, not the main image.
// (Since keeping duplicate tiles from the main image would
// cause the identical tiles in a source tileset to be ignored)
else if ((assetData->args->keep_duplicate_tiles) && (assetData->args->has_source_tilesets == false)) {
// Save tile pattern data, don't try to deduplicate it
assetData->tiles.push_back(tile);
idx = assetData->tiles.size() - 1;
props = assetData->args->props_default;
}
else {
// Otherwise if the tile pattern has not been encountered before then save it
if (!FindTile(tile, idx, props, assetData->tiles, assetData))
{
if (assetData->args->has_source_tilesets) {
printf("found a tile not in the source tileset at %d,%d\n", x, y);
assetData->args->includeTileData = true;
}
assetData->tiles.push_back(tile);
idx = assetData->tiles.size() - 1;
props = assetData->args->props_default;
}
}
// Creating map tile id and attributes entries is only when processing the the main image.
assetData->map.push_back((unsigned char)idx + assetData->args->tile_origin);
if(assetData->args->use_map_attributes)
{
unsigned char pal_idx = tile.pal;
if(assetData->args->pack_mode == Tile::SGB)
{
props = props << 1; //Mirror flags in SGB are on bit 7
props |= (pal_idx + 4) << 2; //Pals are in bits 2,3,4 and need to go from 4 to 7
assetData->map.push_back(props); //Also they are stored within the map tiles
}
else if(assetData->args->pack_mode == Tile::SMS)
{
props = (props >> 4) | ((pal_idx & 1) << 3);
if(idx > 255)
props |= 1;
if (assetData->args->use_structs) {
// put the attribute data in a separate array as with GBC
// for: -use_map_attributes + -use_structs[aka zgb] + SMS/GG
assetData->map_attributes.push_back(props);
} else {
assetData->map.push_back(props);
}
}
else
{
props |= pal_idx;
// If GBC and more than 256 tiles then add in tile bank num
if ((idx > 255) && (assetData->args->pack_mode == Tile::GB))
props |= CGB_BKGF_BANK1;
assetData->map_attributes.push_back(props);
}
}
}
}
checkWarnMapTileLimits(assetData);
HandleMapAttributes(assetData);
}