justgook / webgl-playground / Playground.Extra

Shapes

tile : Basics.Float -> Basics.Float -> String -> Basics.Int -> Playground.Shape

Show tile from a tileset.

All tiles are fixed size and placed into a grid, where the first tile has a 0 index increasing left to right and top to bottom.

Example: having a 3x3 tileset with each tile of 16x24 pixels

| 0 1 2 |
| 3 4 5 |
| 6 7 8 |

this draws the first tile of the second row

tile 16 24 "sprites.png" 3

sprite : String -> { xmin : Basics.Float, xmax : Basics.Float, ymin : Basics.Float, ymax : Basics.Float } -> Playground.Shape

Show sprite from a sprite sheet.

Sprites can be placed anywhere in the sprite sheet and each can have different sizes.

Example: this draws a sprite of 16x24 pixels taking it from a sprite sheet, starting at position 16,0 up to including pixels at 31,23

sprite "sprites.png" { xmin = 16, xmax = 31, ymin = 0, ymax = 23 }

Batch renders

tilemap : Basics.Float -> Basics.Float -> String -> String -> Playground.Shape

Show tilemap from a tileset and a corresponding lookup table stored as a texture.

For example, this lookup table is used to draw a T-shaped platform:

| 2 2 2 |
| 0 1 0 |
| 0 1 0 |

which in turn uses this 3x3 tileset with each tile 16x24px.

| 1 2 3 |
| 4 5 6 |
| 7 8 9 |

Finally, the function is used as follows:

tilemap 16 24 "sprites.png" "lookuptable.png"

Note: tileset indexing starts from 1 when used in lookup table, since 0 is used to communicate "no tile here".

Why

For tiny maps tile function is enough. However, when the game map grows in size performance issues creep in. The underlying issue is that for each tile the WebGL rendering engine uses what is called an Entity. WebGL can handle a few thousands of such entities thus having a map with 100x100 tiles means to draw 10.000 entities for each frame - that’s way too much for WebGL.

How it works

To avoid performance issues the idea is to draw a single WebGL Entity for each tilemap call by pushing the composition of the map down the rendering pipeline.

To do that we need to pass to playground both the tileset and a 2D array of tile indices. The latter will be used to look-up the correct tile.

You can visualize the lookup table like those mini-maps you see on video games HUD. Each lookup table pixel represents a tile in the final tilemap, while the color value of that pixel is an index telling which tile to pick from the tileset.

All tiles are fixed size and placed into a grid, with indices increasing left to right and top to bottom. Notice that a fully black but transparent pixel (0x00000000) means "no tile here" and nothing is rendered. Hence, unlike tile function, this makes the lookup table indices to start from 1.

More details about this rendering technique can be found in Brandon Jones’ blog.