Chapter 06. Background layers

Table of Contents

Background layers

Background layers are one of the two main graphics entities in tilengine, the other are sprites. Background layers are a two dimensional arrangement of tiles, called tilemap, where each tile is a small square bitmap extracted from a bigger palette of tiles, called tileset, plus some flags that modify its appearance. Background layers can have transparent areas, where the underlying layer(s) or background color is seen.

Layers are referenced by an index, starting at 0 for the topmost, increasing up to number of layers minus 1 for the bottom-most.

Basic setup

In order to get displayed, a layer needs to have attached three items: a tilemap, a tileset and a palette. Usually a tilemap has an internal reference to its associated tileset, and a tileset has a palette embedded, we only have to explicitly set the tilemap and the other items are loaded automatically. This is accomplished with the TLN_SetLayer function.

We have to load the tilemap first with TLN_LoadTilemap (read more about tilemaps. Then we call TLN_SetLayer to attach it to the layer, passing the index layer, an optional tileset, and the tilemap to attach:

TLN_Tilemap tilemap = TLN_LoadTilemap ("ruff_n_tumble.tmx");
TLN_SetupLayer (0, NULL, tilemap);

Layer with tilemap loaded:

Layer with tilemap loaded

We can just pass a NULL to use the internal tileset referenced by the tilemap. But we can explicitly load and attach a tileset too with TLN_LoadTileset :

TLN_Tilemap tilemap = TLN_LoadTilemap ("ruff_n_tumble.tmx");
TLN_Tileset tileset = TLN_LoadTileset ("ruff_n_tumble.tsx");
TLN_SetupLayer (0, tileset, tilemap);

Scrolling

Scrolling is the common term for moving the display area inside a bigger map. By default, when a layer is setup for the first time, its located at position 0,0 inside the tilemap. But it can be relocated with TLN_SetLayerPosition . For example, to locate the layer 0 at position 120,16 (120 pixels to the right, 16 pixels down):

Layer moved to 120,16:

Layer moved to 120,16

Smooth scroll

Smooth scrolling consists in moving continuously a few pixels each time. This sample scrolls layer 0 to the right:

int x = 0;
{
x += 1;
}
Smooth scroll

Parallax scroll

Parallax scrolling consists in scrolling at least two or more layers, where the background layer represents objects that are far away and move slowly, whereas the foreground layer has the objects that are nearer to to player and move faster.

int x = 0;
{
TLN_SetLayerPosition (0, x,0); /* move foreground layer two pixels per frame */
TLN_SetLayerPosition (1, x/2,0); /* move background layer one pixel per frame */
x += 2;
}

Setting the palette

By default, any layer uses the palette that came with the attached tileset, but it can be changed and use any other palette with TLN_SetLayerPalette. We can explicitly load a palette with TLN_LoadPalette :

TLN_Palette palette = TLN_LoadPalette ("palette.act");
TLN_SetLayerPalette (0, palette);

Alternative palette:

Alternative palette

Blending

Blending is supported in layers, with different modes and effects. To get extended information about the modes and their effects, please refer to Chapter 09 - Blending.

To enable blending, call TLN_SetLayerBlendMode passing the layer index and the blending mode. For example, to set 50%/50% blending in layer 0:

TLN_SetLayerBlendMode (0, BLEND_MIX, 0);

The last parameter, factor, is kept for compatibility but isn't used.

To disable blending, call the same function with blending mode set to BLEND_NONE :

Clipping

Each layer can be assigned a clipping rectangle: a region that delimits where drawing occurs inside the window, leaving outside pixels untouched as if the layer were disabled. By default the clipping rectangle is disabled and the layer covers the entire window.

To enable the clipping rectangle, call TLN_SetLayerClip passing the index of the layer, and four numbers telling the x,y of the top-left corner, and the x,y of the bottom-right corner. For example, to set clipping in layer 0 from 32,20 to 360,240:

TLN_SetLayerClip (0, 32,20, 360,240);

Clipping rectangle 32,20 - 360,240:

Clipping rectangle

To disable the clipping rectangle, call TLN_DisableLayerClip passing the layer index to disable:

Column offset

This feature allows displacing each column of tiles in screen space by a given amount of pixels. This can be used to fake vertical parallaxing, or to do moderate tilting and deformation of terrain.

To setup the effect, it needs an array of integers as large as the number of columns that fit in one screen plus 2. For example, if you've setup a 400x240 framebuffer and are using 8x8 tiles, the number of positions is 400/8 + 2 = 52. Then call TLN_SetLayerColumnOffset passing the layer index and a pointer to the array of integers:

const int hres = 400;
const int tile = 8;
const int size = hres/tile + 2;
int offsets[size] = {0};
/* ... */

Now the layer 0 column offset is linked to the offsets array. Setting any value(s) inside the array and drawing a frame has immediate visible effects, there's no need to call the function each time. For example, to create a slightly sloped terrain:

int c;
for (c=0; c<size; c++)
offsets[c] = c;

Column offset: each column is displaced 1 pixel incrementally:

Column offset

To disable the effect, just call the function with a NULL pointer instead of a valid array:

Scaling

Scaling is the first of the three transformation modes supported by layers, in addition to affine transform and pixel mapping. Only one mode can be active at a given moment.

Layers can be drawn upscaled or downscaled with an arbitrary factor. The scaling starts in screen space at the top-left corner, so the scrolling position isn't affected by scaling. To enable scaling, call TLN_SetLayerScaling passing the layer index and two floating point values with the horizontal and vertical factor, respectively. Values greater than 1.0 upscale, and smaller than 1.0 downscale. For example to set an horizontal downscaling of 0.5 and vertical upscaling of 1.5 for layer 0:

TLN_SetLayerScaling (0, 0.5f, 1.5f);

Layer scaling x0.5 horizontal, x1.5 vertical:

Column offset

Affine trasform

Affine transform is the second of the three transformation modes supported by layers, in addition to scaling and pixel mapping. Only one mode can be active at a given moment.

Affine transform allows to rotate, translate and scale any layer (much like SNES Mode 7 works). To enable this transformation, call TLN_SetLayerTransform passing the layer index, rotation angle in degrees, two floating point values with the center of rotation in screen space, and two floating point values with horizontal and vertical scaling. For example, to enable affine transform on layer 0, 30 degrees rotation around the center of the screen, and 1.5 upscaling in both axis:

TLN_SetLayerTransform (0, 30.0f, 240.0f,160.0f, 1.5f,1.5f);

30ยบ degree rotation around 240,160 (screen center), x1.5 upscaling:

Affine transform

TIP: affine transform is an intensive operation. If you just want to implement scaling but not rotation, use TLN_SetLayerScaling instead because it's much more lightweight.

Per-pixel mapping

Per-pixel mapping is the last of the three transformation modes supported by layers, in addition to scaling and affine transform. Only one mode can be active at a given moment.

Per-pixel mapping is a similar operation to column offset, but applied to every screen pixel instead of just every column.

To setup the effect, it needs an array of TLN_PixelMap items with as positions as pixels in the framebuffer. For example, for a 480x320 setup, int needs to have 480x320 = 153,600 items. Each item contains a pair of integer values with the coordinates of that pixel relative to the to left corner of the screen at 0,0. Call TLN_SetLayerPixelMapping passing the layer index and a pointer to the array of TLN_PixelMap items:

const int hres = 480;
const int vres = 320;
const int num_pixels = hres * vres;
TLN_PixelMap pixel_map[num_pixels];
/* ... */
TLN_SetLayerPixelMapping (0, pixel_map);

Pixel mapping applying some trigonometric displacements to the TLN_PixelMap array

Affine transform

Setting the pixel mapping table

Let's we want that pixel at 320,240 takes its value from pixel located at 200,100. First we have to calculate which pixel to modify inside the TLN_PixelMap array. The formula is:

index = y * width + x

Then we set dx and dy with the coordinates of the desired source pixel:

int x = 320; /* pixel we want to remap */
int y = 240;
int index = y * width + x;
/* ... */
pixel_map[index].dx = 200;
pixel_map[index].dy = 100;

Disabling transformations

To disable any of the three previous transformation modes and return the layer to standard mode, call the TLN_ResetLayerMode passing the layer index:

Mosaic effect

The mosaic effect pixelates the layer, making some pixels bigger and skipping others so the relative image size keeps constant. It's similar to the mosaic effect in SNES, but more flexible. Different horizontal and vertical pixel values are possible -not just square pixels-, and any size can be set, not just powers of 2. To enable the effect, call TLN_SetLayerMosaic passing the layer index, the horizontal pixel size, and the vertical pixel size. For example to set mosaic on layer 0 with 8 pixel horizontal factor and 6 pixel vertical factor:

Mosaic effect with 8 horizontal and 6 vertical pixel size factor:

Affine transform

To disable the mosaic effect, just call TLN_DisableLayerMosaic passing the layer index:

Getting layer data

Sometimes it's useful to get info about the layer: width and height in pixels -which depends on its tileset and tilemap, its palette, and detailed data about a specific tile:

A basic feature in any game with backgrounds and sprites is the interaction with the background. Tilengine provides the TLN_TileInfo structure and the function TLN_GetLayerTile to query a tile in map coordinates. TLN_TileInfo returns the row and col of the tile inside of the tilemap, the pixel offset inside the tile (distance from the top-left corner of the tile to the requested pixel), the tile index, its type (type of terrain, etc) and color index. Let's say we want to know about tile located at map coordinates 1800,300:

TLN_TileInfo tile_info; /* declare struct to hold data */
TLN_GetLayerTile (0, 1800,300, &tile_info); /* get layer 0 tile at 1800,300 */

Disabling

To disable a layer so it is not rendered, just call TLN_DisableLayer passing the layer index: