Porytiles
Loading...
Searching...
No Matches
porytiles::TilesPngWorkspace Class Reference

A workspace for managing canonical IndexPixel tiles destined for tiles.png output. More...

#include <tiles_png_workspace.hpp>

Public Member Functions

 TilesPngWorkspace (std::size_t capacity)
 Constructs a TilesPngWorkspace with a specified capacity, initializing all slots with transparent tiles.
 
 TilesPngWorkspace (const Image< IndexPixel > &img, std::size_t capacity)
 Constructs a TilesPngWorkspace from an existing IndexPixel image and capacity.
 
std::size_t insert_tile (const CanonicalPixelTile< IndexPixel > &tile)
 Attempts to insert a non-transparent tile into the workspace at the current cursor position.
 
std::optional< std::size_t > first_occurrence_of (const CanonicalPixelTile< IndexPixel > &tile) const
 Finds the first occurrence index of a given canonical tile in the workspace.
 
std::optional< std::size_t > first_occurrence_of_by_color (const CanonicalPixelTile< IndexPixel > &tile, const Palette< Rgba32, pal::max_size > &palette) const
 Finds the first occurrence of a tile using color-equivalence comparison.
 
CanonicalPixelTile< IndexPixeltile_at (std::size_t index) const
 Retrieves the canonical tile at the specified index in the workspace.
 
Image< IndexPixelexport_image (ExportFlipMode flip_mode=ExportFlipMode::canonical, ExportTrimMode trim_mode=ExportTrimMode::trim_trailing_transparent) const
 Exports the workspace tiles to an Image<IndexPixel> in tiles.png format.
 
Image< IndexPixelexport_secondary_image (std::size_t primary_tile_count, ExportFlipMode flip_mode=ExportFlipMode::canonical, ExportTrimMode trim_mode=ExportTrimMode::trim_trailing_transparent) const
 Exports only the secondary portion of the workspace (tiles from primary_tile_count onward).
 
bool at_capacity () const
 Checks if the workspace has reached capacity and can no longer accept new tile insertions.
 
void reserve_anim_slots (std::size_t anim_tile_count, std::size_t start_offset=1)
 Reserves contiguous slots for animation keyframe tiles starting at start_offset.
 
void place_anim_tile (std::size_t reserved_index, const CanonicalPixelTile< IndexPixel > &tile)
 Places an animation keyframe tile at a specific reserved index.
 
std::size_t anim_start_offset () const
 Returns the starting absolute index for animation tiles.
 
std::size_t anim_end_offset () const
 Returns the ending absolute index for animation tiles (exclusive).
 
bool has_anim_slots () const
 Returns whether animation slots have been reserved.
 
std::optional< std::size_t > find_contiguous_transparent_slots (std::size_t count) const
 Finds the first contiguous run of transparent tiles that can accommodate the requested count.
 
std::optional< std::size_t > find_existing_contiguous_tiles_by_color (const std::vector< CanonicalPixelTile< IndexPixel > > &tiles, const std::vector< const Palette< Rgba32, pal::max_size > * > &palettes) const
 Checks if a sequence of tiles already exists contiguously using color-equivalence comparison.
 
void place_tiles_at (std::size_t start_index, const std::vector< CanonicalPixelTile< IndexPixel > > &tiles)
 Places tiles at specific positions for patch mode animation placement.
 
std::size_t capacity () const
 Returns the maximum number of tiles this workspace can hold.
 

Static Public Member Functions

static TilesPngWorkspace for_secondary (const Image< IndexPixel > &primary_tiles_png, std::size_t primary_tile_count, std::size_t total_capacity)
 Creates a workspace pre-loaded with primary tiles for secondary tileset compilation.
 
static TilesPngWorkspace for_standalone_secondary (std::size_t primary_tile_count, std::size_t total_capacity)
 Creates a workspace for standalone secondary compilation with no paired primary.
 

Detailed Description

A workspace for managing canonical IndexPixel tiles destined for tiles.png output.

TilesPngWorkspace provides a fixed-capacity container for PixelTiles that will be written to the tiles.png output file in the PorymapTilesetComponent of a Tileset. The workspace manages tile deduplication, transparent tile slots, and efficient insertion through cursor-based tracking.

Storage Model: The workspace uses a pre-allocated vector where all slots are initialized with transparent tiles. Non-transparent tiles are inserted by replacing transparent tiles at the cursor position. The cursor always points to the next available transparent slot, skipping over already-inserted non-transparent tiles.

Canonical Forms: Only non-transparent tiles are tracked in the canonical forms map for deduplication purposes. This map stores the canonical (lexicographically minimal) representation of each unique tile and all indices where that tile appears in the workspace.

Definition at line 90 of file tiles_png_workspace.hpp.

Constructor & Destructor Documentation

◆ TilesPngWorkspace() [1/2]

porytiles::TilesPngWorkspace::TilesPngWorkspace ( std::size_t  capacity)
explicit

Constructs a TilesPngWorkspace with a specified capacity, initializing all slots with transparent tiles.

Creates a workspace that can hold up to capacity tiles. All tile slots are pre-initialized with transparent tiles (tiles where every pixel is IndexPixel(0)). The cursor is initialized to position 1, as position 0 is reserved for the mandatory transparent tile per GBA tileset requirements.

After construction:

  • tiles_ vector contains capacity transparent tiles
  • cursor_ points to index 1 (first available slot after the reserved tile 0)
  • canonical_forms_ map is empty (transparent tiles are not tracked)
  • The workspace is ready to accept non-transparent tile insertions
Parameters
capacityThe maximum number of tiles this workspace can hold

Definition at line 149 of file tiles_png_workspace.cpp.

◆ TilesPngWorkspace() [2/2]

porytiles::TilesPngWorkspace::TilesPngWorkspace ( const Image< IndexPixel > &  img,
std::size_t  capacity 
)
explicit

Constructs a TilesPngWorkspace from an existing IndexPixel image and capacity.

Extracts 8×8 pixel tiles from the input image in row-major order and populates the workspace. The image dimensions must be multiples of 8 (the tile dimension). If the image contains more tiles than the specified capacity, the constructor panics.

Extraction Process:

  1. Validates image dimensions are multiples of 8
  2. Calculates the number of tiles in the image (width/8 × height/8)
  3. Verifies the tile count does not exceed capacity
  4. Extracts each 8×8 tile region from the image in row-major order
  5. Creates a CanonicalPixelTile for each extracted tile
  6. Adds non-transparent tiles to the canonical_forms_ map for deduplication
  7. Pads the tiles_ vector to capacity with transparent tiles
  8. Sets the cursor to the first transparent tile after tile 0

Non-transparent tile tracking: Only tiles that contain at least one non-zero IndexPixel are added to canonical_forms_. This enables efficient deduplication via first_occurrence_of() lookups.

Cursor initialization: After loading the image, the cursor is positioned at the first transparent tile index greater than 0. If all tiles from the image are non-transparent, the cursor points to the first padding tile.

Precondition
Image dimensions must be multiples of 8
Image may not contain more tiles than the specified capacity
Parameters
imgThe IndexPixel image to extract tiles from; dimensions must be multiples of 8
capacityThe maximum number of tiles this workspace can hold

Definition at line 159 of file tiles_png_workspace.cpp.

Member Function Documentation

◆ anim_end_offset()

std::size_t porytiles::TilesPngWorkspace::anim_end_offset ( ) const
inline

Returns the ending absolute index for animation tiles (exclusive).

Returns the index just past the last reserved animation slot. If no animation slots were reserved, returns 1 (same as animation_start_offset()). Regular tile insertion begins at this index.

Returns
The first index after the animation region

Definition at line 410 of file tiles_png_workspace.hpp.

◆ anim_start_offset()

std::size_t porytiles::TilesPngWorkspace::anim_start_offset ( ) const
inline

Returns the starting absolute index for animation tiles.

For primary tilesets, animation tiles start at index 1 (after the transparent tile 0). For secondary tilesets, animation tiles start at num_tiles_in_primary + 1 (after the secondary transparent tile). The value is set by reserve_anim_slots() and defaults to 1.

Returns
The animation start index

Definition at line 396 of file tiles_png_workspace.hpp.

◆ at_capacity()

bool porytiles::TilesPngWorkspace::at_capacity ( ) const

Checks if the workspace has reached capacity and can no longer accept new tile insertions.

Returns true when the cursor has reached or exceeded the capacity, indicating that all available transparent tile slots have been filled with non-transparent tiles. At this point, insert_tile() will panic for any further insertion attempts.

Note: This method returns true even if there are still transparent tiles in the workspace behind the cursor position, as the cursor always advances forward and never backtracks. However, this state shouldn't be reachable under normal operation conditions.

Returns
true if cursor == capacity, false otherwise

Definition at line 413 of file tiles_png_workspace.cpp.

◆ capacity()

std::size_t porytiles::TilesPngWorkspace::capacity ( ) const
inline

Returns the maximum number of tiles this workspace can hold.

Returns the capacity value specified during construction. This is the fixed size of the tiles_ vector and represents the maximum number of tiles (both transparent and non-transparent) that can be stored.

Returns
The workspace capacity

Definition at line 487 of file tiles_png_workspace.hpp.

◆ export_image()

Image< IndexPixel > porytiles::TilesPngWorkspace::export_image ( ExportFlipMode  flip_mode = ExportFlipMode::canonical,
ExportTrimMode  trim_mode = ExportTrimMode::trim_trailing_transparent 
) const

Exports the workspace tiles to an Image<IndexPixel> in tiles.png format.

Creates an Image<IndexPixel> representation of tiles in the workspace, arranged in row-major order with 16 tiles per row (128 pixels wide). This method provides flexible control over both flip transformation application and trailing transparent tile trimming via enum parameters.

Image Layout:

  • Width: Always 128 pixels (16 tiles × 8 pixels per tile)
  • Height: Calculated based on the trim_mode parameter
  • Tile arrangement: Row-major order, matching the extraction order from the constructor

Flip Mode:

  • ExportFlipMode::canonical: Exports tiles in their canonical (lexicographically minimal) form as stored, without applying flip transformations. Appropriate for fresh compilations.
  • ExportFlipMode::original: Applies h_flip/v_flip transformations to restore original pixel arrangements, enabling round-trip preservation useful in patch builds.

Trim Mode:

Parameters
flip_modeControls whether tiles are exported in canonical or original (flipped) form
trim_modeControls whether trailing transparent tiles are included or trimmed
Returns
An Image<IndexPixel> containing workspace tiles in the specified format (tiles.png format)

Definition at line 392 of file tiles_png_workspace.cpp.

◆ export_secondary_image()

Image< IndexPixel > porytiles::TilesPngWorkspace::export_secondary_image ( std::size_t  primary_tile_count,
ExportFlipMode  flip_mode = ExportFlipMode::canonical,
ExportTrimMode  trim_mode = ExportTrimMode::trim_trailing_transparent 
) const

Exports only the secondary portion of the workspace (tiles from primary_tile_count onward).

Creates an Image<IndexPixel> containing only the secondary tiles. The tile at position primary_tile_count becomes the first tile (row 0, col 0) in the output image.

When trimming, if all secondary tiles are transparent, the output will contain at least the secondary transparent tile at position primary_tile_count.

Parameters
primary_tile_countThe number of primary tiles to skip (e.g. 512)
flip_modeControls whether tiles are exported in canonical or original (flipped) form
trim_modeControls whether trailing transparent tiles are included or trimmed
Returns
An Image<IndexPixel> containing only the secondary tiles in tiles.png format

Definition at line 401 of file tiles_png_workspace.cpp.

◆ find_contiguous_transparent_slots()

std::optional< std::size_t > porytiles::TilesPngWorkspace::find_contiguous_transparent_slots ( std::size_t  count) const

Finds the first contiguous run of transparent tiles that can accommodate the requested count.

Scans the workspace starting from index 1 (skipping reserved tile 0) to find a contiguous sequence of transparent tiles with length >= count. This is useful in patch mode to find free space for animation keyframes when they don't already exist in the workspace.

Parameters
countThe number of contiguous transparent slots needed
Returns
The starting index of the first suitable run, or std::nullopt if no run found

Definition at line 480 of file tiles_png_workspace.cpp.

◆ find_existing_contiguous_tiles_by_color()

std::optional< std::size_t > porytiles::TilesPngWorkspace::find_existing_contiguous_tiles_by_color ( const std::vector< CanonicalPixelTile< IndexPixel > > &  tiles,
const std::vector< const Palette< Rgba32, pal::max_size > * > &  palettes 
) const

Checks if a sequence of tiles already exists contiguously using color-equivalence comparison.

Uses color-equivalence comparison to find contiguous tile sequences. This handles the case where palettes contain duplicate colors at different indices. Two pixels are considered equivalent if they reference the same color value in the palette, even if their indices differ.

This is necessary for patch/locked builds where vanilla workspace tiles may use a different palette index than the one computed by index_tile_from_color_tile() (which always picks the first matching index). For example, if palette slot 7 and slot 14 both contain the same color, vanilla tiles might use slot 14 while our computed tiles use slot 7 - they should still be considered matching.

Note: This method performs a linear scan of the workspace (O(capacity × tiles × 64)). This is acceptable because animation sequences are typically small and workspace capacity is bounded.

Parameters
tilesThe sequence of canonical tiles to search for
palettesParallel vector of palette pointers corresponding to each tile (for color lookup)
Precondition
tiles.size() == palettes.size()
Returns
The starting index if found contiguously, or std::nullopt if not found

Definition at line 512 of file tiles_png_workspace.cpp.

◆ first_occurrence_of()

std::optional< std::size_t > porytiles::TilesPngWorkspace::first_occurrence_of ( const CanonicalPixelTile< IndexPixel > &  tile) const

Finds the first occurrence index of a given canonical tile in the workspace.

Searches the canonical_forms_ map for the given tile and returns the index of its first occurrence in the workspace. This method only finds non-transparent tiles that have been explicitly inserted or loaded from an image during construction.

Deduplication Use Case: This method is used to check if a tile already exists in the workspace before inserting it. If the tile is found, the caller can reuse the existing tile's index rather than inserting a duplicate.

Transparent Tiles: Transparent tiles are never tracked in canonical_forms_, so this method will always return std::nullopt for any transparent tile, even though the workspace may contain many transparent tiles. Since tile 0 is guaranteed to be transparent, callers who need to index into a transparent tile can always just use tile 0 instead of searching for one.

Parameters
tileThe canonical pixel tile to search for
Returns
The index of the tile's first occurrence if found, std::nullopt otherwise

Definition at line 353 of file tiles_png_workspace.cpp.

◆ first_occurrence_of_by_color()

std::optional< std::size_t > porytiles::TilesPngWorkspace::first_occurrence_of_by_color ( const CanonicalPixelTile< IndexPixel > &  tile,
const Palette< Rgba32, pal::max_size > &  palette 
) const

Finds the first occurrence of a tile using color-equivalence comparison.

Similar to first_occurrence_of(), but uses color-equivalence comparison instead of exact index matching. This handles the case where palettes contain duplicate colors at different indices. Two pixels are considered equivalent if they reference the same color value in the palette, even if their indices differ.

This is necessary for patch/locked builds where vanilla workspace tiles may use a different palette index than the one computed by index_tile_from_color_tile() (which always picks the first matching index). For example, if palette slot 7 and slot 14 both contain the same color, vanilla tiles might use slot 14 while our computed tiles use slot 7 - they should still be considered matching.

Note: This method performs a linear scan of the workspace (O(capacity × 64)) instead of the O(1) map lookup used by first_occurrence_of(). This is acceptable because workspace capacity is bounded and this method is only used in patch/locked modes.

Parameters
tileThe canonical pixel tile to search for
paletteThe palette to use for color lookup
Returns
The index of the tile's first occurrence if found, std::nullopt otherwise

Definition at line 363 of file tiles_png_workspace.cpp.

◆ for_secondary()

TilesPngWorkspace porytiles::TilesPngWorkspace::for_secondary ( const Image< IndexPixel > &  primary_tiles_png,
std::size_t  primary_tile_count,
std::size_t  total_capacity 
)
static

Creates a workspace pre-loaded with primary tiles for secondary tileset compilation.

Constructs a workspace with total_capacity tiles. Positions 0 through primary_tile_count - 1 are populated from primary_tiles_png. Position primary_tile_count is reserved as a transparent tile per vanilla secondary tileset convention. The cursor is set to primary_tile_count + 1, ready for secondary tile insertion.

Primary tiles are registered in the canonical forms map for deduplication, so secondary tiles that match an existing primary tile will reuse its global index rather than inserting a duplicate.

Parameters
primary_tiles_pngThe compiled primary tileset's tiles.png image
primary_tile_countThe number of tile slots reserved for primary tiles (e.g. 512)
total_capacityThe total tile capacity for primary + secondary (e.g. 1024)
Precondition
primary_tiles_png dimensions must be multiples of 8
primary_tile_count must be less than total_capacity
Returns
A workspace with primary tiles pre-loaded and cursor positioned for secondary insertion

Definition at line 228 of file tiles_png_workspace.cpp.

◆ for_standalone_secondary()

TilesPngWorkspace porytiles::TilesPngWorkspace::for_standalone_secondary ( std::size_t  primary_tile_count,
std::size_t  total_capacity 
)
static

Creates a workspace for standalone secondary compilation with no paired primary.

Creates a workspace with total_capacity tiles, all transparent. Positions 0 through primary_tile_count are reserved (transparent placeholders for primary tile slots). Position primary_tile_count is the secondary transparent tile (vanilla convention). The cursor is set to primary_tile_count + 1, ready for secondary tile insertion. No tiles are registered in canonical_forms_ since there are no primary tiles to deduplicate against.

Parameters
primary_tile_countNumber of primary tile slots to reserve.
total_capacityTotal workspace capacity (primary + secondary).
Precondition
primary_tile_count must be less than total_capacity.
Returns
A workspace with transparent primary region and cursor positioned for secondary insertion.

Definition at line 304 of file tiles_png_workspace.cpp.

◆ has_anim_slots()

bool porytiles::TilesPngWorkspace::has_anim_slots ( ) const
inline

Returns whether animation slots have been reserved.

Returns
True if reserve_animation_slots() has been called with a non-zero count

Definition at line 420 of file tiles_png_workspace.hpp.

◆ insert_tile()

std::size_t porytiles::TilesPngWorkspace::insert_tile ( const CanonicalPixelTile< IndexPixel > &  tile)

Attempts to insert a non-transparent tile into the workspace at the current cursor position.

Inserts the given canonical tile at the cursor position, replacing the transparent tile that was there. After insertion, the cursor is advanced to the next available transparent tile slot. The inserted tile is added to the canonical_forms_ map for deduplication support. The function then returns the index of the inserted tile.

Insertion Criteria:

  • Panics if the workspace is at capacity (cursor >= capacity)
  • Returns 0 if the tile is transparent (index 0 is standard location for transparent tile)
  • Returns index if the tile was successfully inserted

Post-insertion State:

  • The tile replaces the transparent tile at the cursor position
  • The tile's canonical form is added to canonical_forms_ with its index
  • The cursor advances to the next transparent tile (or reaches capacity)
  • Fast-forward: The cursor skips over any non-transparent tiles to find the next available slot

Cursor Fast-Forward: After inserting a tile, the cursor is incremented and then fast-forwarded through any non-transparent tiles until it finds the next transparent slot or reaches capacity. This ensures O(1) insertion for the next insert_tile call in the common case.

Parameters
tileThe canonical pixel tile to insert; must be non-transparent for successful insertion
Precondition
Workspace cursor is less than capacity, i.e., there is room in the workspace for new tiles
Returns
The index of the inserted tile

Definition at line 327 of file tiles_png_workspace.cpp.

◆ place_anim_tile()

void porytiles::TilesPngWorkspace::place_anim_tile ( std::size_t  reserved_index,
const CanonicalPixelTile< IndexPixel > &  tile 
)

Places an animation keyframe tile at a specific reserved index.

Places a tile in the reserved animation region. The index is an offset within the reserved region, NOT an absolute index. For example, if animation_tile_count tiles were reserved:

  • place_animation_tile(0, tile) places at absolute index 1
  • place_animation_tile(1, tile) places at absolute index 2
  • etc.
Parameters
reserved_indexThe index within the reserved animation region (0-based)
tileThe tile to place at the specified position
Precondition
reserve_animation_slots() must have been called first
reserved_index must be less than the reserved count

Definition at line 449 of file tiles_png_workspace.cpp.

◆ place_tiles_at()

void porytiles::TilesPngWorkspace::place_tiles_at ( std::size_t  start_index,
const std::vector< CanonicalPixelTile< IndexPixel > > &  tiles 
)

Places tiles at specific positions for patch mode animation placement.

Places the provided tiles starting at the specified index. All target positions must be transparent (the method panics if any position is non-transparent). After placement, the canonical_forms_ map is updated and the cursor is advanced past any newly-filled positions.

Parameters
start_indexThe starting index where tiles should be placed
tilesThe tiles to place at consecutive positions starting from start_index
Precondition
All target positions must be transparent
start_index + tiles.size() must not exceed capacity

Definition at line 557 of file tiles_png_workspace.cpp.

◆ reserve_anim_slots()

void porytiles::TilesPngWorkspace::reserve_anim_slots ( std::size_t  anim_tile_count,
std::size_t  start_offset = 1 
)

Reserves contiguous slots for animation keyframe tiles starting at start_offset.

Animation tiles are placed in a contiguous block to ensure stable offsets that can be referenced by the generated animation C code. This method reserves a contiguous block of slots for animation tiles and moves the cursor past the reserved region.

For primary tilesets, start_offset is 1 (after the transparent tile 0). For secondary tilesets, start_offset is num_tiles_in_primary + 1 (after the secondary transparent tile at num_tiles_in_primary).

After calling this method:

  • Indices start_offset through start_offset + anim_tile_count - 1 (inclusive) are reserved
  • The cursor is positioned at start_offset + anim_tile_count (first slot after reserved region)
  • Regular tile insertions via insert_tile() will not overwrite the reserved region
Parameters
anim_tile_countTotal number of tiles to reserve for animation keyframes
start_offsetThe starting index for the animation region (default: 1 for primary tilesets)
Precondition
Cursor must be at start_offset (no regular tiles inserted past that point)
start_offset + anim_tile_count must be less than capacity

Definition at line 418 of file tiles_png_workspace.cpp.

◆ tile_at()

CanonicalPixelTile< IndexPixel > porytiles::TilesPngWorkspace::tile_at ( std::size_t  index) const

Retrieves the canonical tile at the specified index in the workspace.

Returns a copy of the CanonicalPixelTile at the given index. The index must be within the bounds of the tiles_ vector (0 to capacity - 1). This method provides read-only access to any tile in the workspace, including transparent tiles and non-transparent tiles.

Bounds Checking: If the index is out of bounds, the method panics with an error message indicating the invalid index and the workspace size.

Parameters
indexThe zero-based index of the tile to retrieve; must be < capacity
Precondition
index must be less than tiles_.size()
Returns
A copy of the CanonicalPixelTile at the specified index

Definition at line 384 of file tiles_png_workspace.cpp.


The documentation for this class was generated from the following files: