Skip to main content

Palix: tiles

A tilemap is rectangular grid of tiles, where each tile is a square made of pixels. The square is either 16 × 16 ("jumbo" tiles typically used for game levels) or 8 × 8 (typically used by fonts). The tile pictures come from a tileset, which is a collection of numbered tile images. For example, a video game forest might use a tile 7 for each bush, a tile 13 for a vertical segment of a dirt road, etc. As another example, the Hybrix text console is a tilemap where each tile is a text character (letter or number or punctuation mark or graphical glyph). In this case, the tileset represents a typeface font.

Note: The Hybrix framework defines two "tilemap" classes tilemap and io_tilemap. The tilemap class is used for designer art resources, whereas io_tilemap describes the hardware interface for rendering. The tile_layer class prepares io_tilemap using data from tilemap and tileset.

Screen dimensions

Here's a handy reference for measuring screen dimensions as tiles:

Screen sizeUnits
320 × 224pixels
40 × 28regular tiles (8 × 8)
20 × 14jumbo tiles (16 × 16)

Rendering

A tilemap is a two dimensional grid of cells, arranged in left-to-right rows, starting from the top row. The rows increase downwards like the Y axis, and columns increase rightwards like the X axis. Each cell contains a 16-bit pair called a tile code, whose binary bits encode three pieces of information for that cell:

Tile code bitsValuesEncoded field
0…90 – 1023tile index: indicates which tile to show from the tileset
10…140 – 31theme index: the color palette theme used in this cell
150 or 1matte coloring: if 1, then the io::matte_color is applied in this cell

If enabled, matte coloring causes the tile's transparent pixels to be painted using the globally specified io::matte_color. The HASCII {mat} mode makes use of this feature to add a solid background for text fonts. Matte coloring is guaranteed to eliminate all transparency; if io::matte_color specifies a transparent or invalid palette index, then the matte color will be black (system palette index #1).

The io_tilemap.x and io_tilemap.y fields position the entire tilemap on the screen. The coordinate origin is in the upper-left corner of the screen, with the Y axis pointing downwards and the X axis pointing to the right.

The tileset data is an array of up to 1,024 tile images. io::tileset_a_addresses defines the tileset for io::tileset_a and so forth.

Each array element of io::tileset_a_addresses stores the memory address of that tile's bitmap pixels, one byte per pixel, in left-to-right rows, starting from the top row. For regular 8 × 8 tiles, there will be 64 pixels. For "jumbo" 16 × 16 tiles, there will be 256 pixels. The first byte is the upper-left pixel of that tile.

Tilemap A always appears in front of Tilemap B, which always appears in front of Tilemap C. See display priority for sprite interaction with the tilemap.

Palix-sized tilemaps

The io_tilemap.col_count and io_tilemap.row_count locations must have one of these dimensions:

16, 32, 64, 128, or 256

If any other number is used, it is considered an error—Palix will not display that tilemap at all.

The Hybrix designer warns you if a tilemap's dimensions are not Palix-sized. Why allow non-Palix sizes at all? This can be useful for tilemaps that will not be rendered directly by io_tilemap. The idea is to configure io_tilemap with a separate tilemap buffer that is Palix-sized, and then the non-Palix tilemaps get copied into this buffer. For example, the framework's console sets up a kernel::console_grid buffer for font text. You could make a tilemap that is a dialog box with a non-Palix size, and then at runtime your program could copy it onto the screen. Another common example is an infinite scrolling plane (io_tilemap.edge_mode = 0), where the program generates the tiles interactively as they scroll onto the screen.

I/O definitions

class io_tilemap # size 16
# Screen coordinates of upper-left corner of tilemap
var x: pair, y: pair

# Possible values: 16, 32, 64, 128, 256
var col_count: pair, row_count: pair

# A pointer to a grid of tile codes arranged in left-to-right rows,
# starting from the top row. the array index is row*col_count+col.
# Each tile code is a 16-bit pair:
# bits 0..9 encode the tile index (0..1023) from the tileset
# bits 10..14 encode the theme index (0..31) into io::themes
# bit 15 if set, io::matte_color replaces any clear pixels in this tile
var tile_codes_address: int

# 0 = wrap: the map wraps around, repeating infinitely in every direction
# 1 = clip: cells outside the map bounds are transparent
var edge_mode: byte

# ------------------
# Tileset properties

# 0 = tiles are 8 x 8 pixels
# 1 = tiles are 16 x 16 pixels
var jumbo: byte

# Normally tileset_X_addresses entries point to contiguous tiles where:
# tile_pixel(x,y) = address + y*tile_width + x
# ...with tile_width being 8 for regular tiles or 16 for jumbo tiles.
# If tile_pitch is in the range 1..512, then this formula changes to:
# tile_pixel(x,y) = address + y*tile_pitch + x
# With tile_pitch>tile_width, the gaps enable a block of tilemap cells to
# be mapped to a contiguous linear frame buffer for advanced rasterizers.
var tile_pitch: pair # 0 = default behavior (use tile_width)
end class
module io
. . .
# Palix video system
var background_color: byte located at $d0_0300
var matte_color: byte located at $d0_0301
. . .
inset tilemap_a: io_tilemap located at $d0_0310 # ..$d0_031f
inset tilemap_b: io_tilemap located at $d0_0320 # ..$d0_032f
inset tilemap_c: io_tilemap located at $d0_0330 # ..$d0_033f
. . .
inset tileset_a_addresses: int[size 1024] located at $d0_1000 # ..$d0_1fff
inset tileset_b_addresses: int[size 1024] located at $d0_2000 # ..$d0_2fff
inset tileset_c_addresses: int[size 1024] located at $d0_3000 # ..$d0_3fff
end module