Creating texture atlas with the rover-design pattern

Texture management becomes important with increasing the number of textures. An intuitive approach of using different OpenGL texture objects for each game texture presents the major bottleneck with rapid texture switching. That's because every time you change active texture unit, the graphic card needs to change its internal state. This problem can be eliminated using fewer larger textures that contain smaller images. This can be compared to a texture atlas where images are placed next to each other. These images can be accessed using different texture coordinates for every image.

Texture atlas can use evenly-spaced images with the same size or use some placement algorithm to place images of unequal sizes efficiently.

The first method was used in older games and is often used in games in which the images have the same size. Such texture atlas is often pregenerated to save the game loading time. Every time the game needs to use a different set of images, a new texture atlas is loaded into memory. The disadvantage is that these texture atlases may contain the same images from other atlases and you can't add a new image to them. These texture atlases are often called tiles.

The second method uses dynamic generated texture atlases. These are generated on-the-fly and each new image takes a specific place. Image placement can be controlled by a certain algorithm, which can make the placement more compact so that the space is used more efficiently. One of the algorithms is called the rover design pattern. This algorithm can be found, for example, in games from the id software company.

Getting ready

The texture atlas technique uses storing smaller images into one big texture. The basic prerequisite is at least one free texture that can be used as storage. This texture should at least be as big as the largest image you'll be using. In a memory-constrained environment, you can do proportional resizing of the image so that it fits into the texture atlas. LuaSDL offers this kind of function called SDL.GFX_zoomSurface and it's specified using the following function definition:

local surface = SDL.GFX_ZoomSurface(surface, scale_x, scale_y, smooth)

This function will accept the source surface object in the first argument. Scale values present scaling factors and the last argument is a numeric flag value to enable antialiasing for zooming. The next sample code will scale the image down to half of its original size with smoothing enabled:

local scale_x = 0.5
local scale_y = 0.5
local dst_surface = SDL.GFX_ZoomSurface(src_surface, scale_x, scale_y, 1)

The total size of the atlas texture can be set dynamically to achieve a certain level of texture detail. This is commonly found in modern games where you have an option in the settings to set the texture quality.

How to do it…

This example of texture atlas algorithm will use a texture atlas with the size of 512 x 512 pixels. You can use it every time you need to place a new image into the texture atlas. It will return coordinates in the texture atlas for the specified size of the image. If there is not enough space for the image, it will return false:

local atlas = {
  width = 512,
  height = 512,
  fill = {},
  full = false,
}

local function allocBlock(width, height)
  local allocated = atlas.fill
  local i,j,best1,best2,x,y = 0,0,atlas.height,0,0,0
  for i=0, atlas.width-width do
    best2 = 0
    for k=0,width-1 do
      local column = allocated[i+k]
      j = k
      if not column then
        column = 0
        allocated[i+k] = column
      end
      if (column >= best1) then
        break
      end
      if (column > best2) then
        best2 = column
      end
    end
    if j == width-1 then
      -- valid area
      x = i
      y, best1 = best2, best2
    end
  end
  if (best1 + height) > atlas.height then
    return false
  end
  for i=0, width-1 do
    allocated[x+i] = best1 + height
  end
  return x,y
end

How it works…

The texture atlas function uses the atlas table to store the information about free space in the texture atlas. Free space lookup works just like the famous Tetris game with the board flipped upside-down. This algorithm works in two nested loops. The first one (the outer loop) tries to place the block of specified size from the left side to the right side. The second one (the inner loop) checks whether there are any obstacles in the current block placement. If there aren't any, the placement is regarded as valid and the function returns this position.

Note that the order of placement is important in this case. Smaller objects should be placed first, although there might be better methods with additional heuristics.

The texture atlas can look like the following figure:

How it works…
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.104.95