# How to deal with arbitrarily large images in 2D games?

Question

When you have a 2D game that uses really large images (larger than your hardware can support), what do you do? Maybe there's some interesting solution to this problem that never occured to me before.

I'm basically working on a sort of graphic adventure game maker. My target audience are people with little to no game development (and programming) experience. If you were working with such an application, wouldn't you prefer for it to handle the problem internally rather than telling you to "go split your images"?

Context

It's well known that graphic cards impose a set of restrictions on the size of the textures they can use. For instance, when working with XNA you're restricted to a maximum texture size of 2048 or 4096 pixels depending on which profile you choose.

Usually this doesn't pose much a problem in 2D games because most of them have levels that can be constructed from smaller individual pieces (e.g. tiles or transformed sprites).

But think about a few classic point'n'click graphic adventure games (e.g. Monkey Island). Rooms in graphic adventure games are usually designed as a whole, with little or no repeatable sections, just like a painter working on a landscape. Or perhaps a game like Final Fantasy 7 which uses large pre-rendered backgrounds.

Some of these rooms can get pretty large, frequently spanning three or more screens of width. Now if we consider these backgrounds in the context of a modern high definition game, they will easily exceed the maximum supported texture size.

Now, the obvious solution to this is to split the background into smaller sections that fit within the requirements and draw them side by side. But should you (or your artist) have to be the one splitting all of your textures?

If you're working with a high level API, shouldn't it perhaps be prepared to deal with this situation and do the splitting and assembling of the textures internally (either as a pre-process such as XNA's Content Pipeline or at runtime)?

Edit

Here's what I was thinking, from a XNA implementation point of view.

My 2D engine only requires a very small subset of Texture2D's functionality. I can actually reduce it down to this interface:

public interface ITexture
{
int Height { get; }
int Width { get; }
void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color  color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}


The only external method I use that relies on Texture2D is SpriteBatch.Draw() so I could create a bridge between them by adding an extension method:

    public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
{
texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
}


This would allow me to use an ITexture interchangibly whenever I used a Texture2D before.

Then I could create two different implementations of ITexture e.g. RegularTexture and LargeTexture, where RegularTexture would simply wrap a regular Texture2D.

On the other hand, LargeTexture would keep a List of Texture2D's each corresponding to one of the splitted pieces of the full image. The most important part is that calling Draw() on the LargeTexture should be able to apply all the transformations and draw all the pieces as if they were just one contiguous image.

Finally, to make the entire process transparent, I'd create an unified texture loader class that would act as a Factory Method. It would take the path of the texture as a parameter and return a ITexture which would be either a RegularTexture or a LargeTexture depending on the image size exceeding the limit or not. But the user didn't need to know which one it was.

A bit overkill or does it sound okay?

• Well if you want to go with the splitting the image, extend the Content Pipeline to do that programmatically. Not all functionality exists to cover every single scenario and at some point you're going to have to extend it yourself. Personally splitting sounds like the simplest solution, as you can then handle images sort of like tile maps, which there are numerous resources on. – DMan Dec 10 '11 at 0:16
• Doing it on the on the content pipeline is the most sensible approach. But in my case I needed to load my images at runtime and I've already managed to come up with a runtime solution (which is why I asked this question yesterday). But the real beauty comes from taking this "tile map" and making it behave like a normal texture. I.e. you can still pass it to spritebatch to draw, and you can still specify position, rotation, scale, src/dest rectangles, etc. I'm about halfway there by now :) – David Gouveia Dec 10 '11 at 0:26
• But truth be told, I'm already at a point where I wonder if all that is really worth it or if I should simply show a warning to the user telling him that the maximum supported image size is 2048x2048 and be done with it. – David Gouveia Dec 10 '11 at 0:29
• It's really up to you about the design. If you finish the project and you can't scroll between rooms it will be better then not finished editor that allows you to scroll large textures :D – Aleks Dec 10 '11 at 1:20
• Hiding it in the API sounds like a nice way to make game authors' lives easier. I'd probably implement it in the Polygon (sprite) and Texture classes, and not special-case the smaller images, but rather just make them a tile that is 1x1. So the texture class is a texture group describing all the tiles & how many rows/columns. The Polygon class then looks at this info to split itself up and draw each tile with the appropriate texture. That way, it is the same class. Bonus points if your sprite class only draws visible tiles, and texture groups don't load textures until needed. – uliwitness Dec 7 '14 at 23:13

I think you are on the right track. You have to split the images to smaller pieces. Since you making a game maker you can't use the XNA's Content pipeline. Unless your maker is more like an Engine that will still require the developers to use Visual Studio. So you need to build your own routines that will do the splitting. You should even consider streaming the pieces a bit before that become visizble so that you still don't put limit of how much video memory the players should have.

There are some tricks you can do specifically for adventure games. I imagine like all classic adventure games you will have few layers of these textures so that ... your character can walk behind the tree or the building...

If you want these layers to have paralaxing effect then when you splitting your tiles just skip all the translucent once. Here you need to think of the size of the tiles. Smaller tiles will add managing overhead and draw calls, but will be less data where larger tiles will be more GPU friendly but will have a lot of translucency.

If you don't have paralaxing effect then instead of covering the whole scene with 2-4 giant images that have 32bits depth you can create just one 32 bits depth. And you can have a stenciling or depth layer that will be only 8 bits per pixel.

I know this sound like hard to manage assets by non game developers but it actually doesn't have to be. For example if you have a street with 3 trees and the player goes behind 2 of them and in front of the third tree and the rest of the background... Just make the scene layout the way you want in your editor and then in a build step from your game maker you can bake these giant images (well small tiles of a big image).

About how the classic games were doing it. I'm not sure they probably did simmilar tricks but you have to remember that at the time the screen were 320x240 the games were with 16 colors which when using palattelized textures allows you to encode 2 pixels in single byte. But this is not how the current architectures work so :D

Good Luck

• Thanks, A lot of very interesting ideas here! I've actually seen the stencil layer technique used before in Adventure Game Studio. As for my application I'm doing things a bit differently. Rooms don't necessarily have one background image. Instead there's a palette of images that the user imported, and a background/foreground layer. The user is free to drag and drop pieces into the room to create it. So if he wanted he could compose it out of smaller pieces too without having to non-interactive create game objects. There's no parallax though, since there are only those two layers. – David Gouveia Dec 10 '11 at 0:52
• And I've looked at the data files for Monkey Island Special Edition (the HQ remake). Every background is split into exactly 1024x1024 pieces (even if a large part of the image is left unused). Anyway, check my edit for what in mind in order to make the entire process transparent. – David Gouveia Dec 10 '11 at 0:55
• I would probably pick something more reasonable like 256x256. This way I won't waste resources and if later decide to implement streaming it will be loading more reasonable chunks. Maybe I didn't explain it well enough but I suggested that you could bake all these small static game objects into large texture. What you will save is, in case you have a large background texture, all the pixels covered by the static objects on top. – Aleks Dec 10 '11 at 1:15
• I see, so merge all of the static objects into the background, then split and create a texture atlas. I could also bake everything else into texture atlas following that train of thought. That's a nice idea too. But I'll leave it for later, because right now I don't have any "build" step, i.e. both the editor and the game client run on top of the same engine and the same data format. – David Gouveia Dec 10 '11 at 1:22
• I like the stencil approach but if I'm making adventure game editor I probably wouldn't use it... Maybe because if I'm building such tool I'll intended for game developers. Well it has it's pros and cons. For example you can use another image on which the bits can define triggers per pixel or if you have some water animated you can easily stencil it out. Note: One strange unrelated suggestion look into UML State/Activity diagrams for your scripting. – Aleks Dec 10 '11 at 1:28

Cut them up so they're no longer arbitrarily large, like you say. There is no magic. Those old 2D games either did that or they were rendered in software, in which case there were no hardware restrictions beyond RAM size. Of note is that many of those 2D games really didn't have huge backgrounds, they just scrolled slowly so they felt huge.

What you're looking to do in your graphic adventure game maker is pre-process those big images during some kind of "build" or "integrate" step before the game is packaged up to run.

If you want to use an existing API and library instead of writing your own I'd suggest that you convert those big images to tiles during that "build" and use a 2D tile engine, of which there are many.

If you want to use 3D techniques of your own you may still want to split into tiles and use a well known and well designed 2D API to write your own 3D library for that, in this way you're guaranteed to at least be starting with a good API design and less design required on your part.

• Doing it at build time would be ideal... But my editor also uses XNA for rendering, it's not just the engine. That means that once the user imports the image and drags it into a room, XNA should already be able to render it. So my big dillema is whether to do the splitting in memory when loading the content, or on disk when importing the content. Also, physically splitting the image into multiple files would mean that I would need a way to store these differently, whereas doing it in memory at runtime wouldn't require any change to the game's data files. – David Gouveia Dec 10 '11 at 1:03

If you're familiar with how a quadtree looks in visual practice, I have used a method that cuts detailed large images into smaller images relatively similar to what a proof/visualization of a quadtree looks like. However mine were made that way to cut up areas specifically that could be encoded or compressed differently based on the color. You could use this method and do what I described, as it is also useful.

At run time cutting them would require more memory temporarily and cause load times to be slowed down. I would say though it depends on whether you care more about physical storage or the load time of a users game made with your editor.

Load/Run Time: The way that I would go about the loading is just cutting it up into proportionally sized pieces. Account for one pixel on the right most piece if it's odd number of pixels though, no one likes their images being cut, especially inexperienced users who might just not know that it's not entirely up to them. Make them half the width OR half the height (or 3rds, 4ths whatever) the reason not into squares or 4 sections (2 rows 2 columns) is because it would make tiling memory smaller since you wouldn't be worrying about both x and y at the same time (and depending on how many images are that large, it could be pretty important)

Before Hand/Automatically: In this case I like the idea of giving the user the choice of storing it in one image or storing it as separate pieces (one image should be default). Storing the image as a .gif would work great. The image would be in one file, and rather than each frame being an animation it would be more like a compressed archive of all the same image (which is essentially what a .gif is anyway). It would allow for ease of physical file transportation, ease of loading:

1. It's a single file
2. All of the files would have almost identical formatting
3. You could easily choose when AND if to cut it up into individual textures
4. It may be easier to access the individual images if they're already in a single loaded .gif since it wouldn't require as much of a mess of image files in memory

Oh and if you use the .gif method, you should change the file extension to something else (.gif -> .kittens) for the sake of less confusion when your .gif animates like it's a broken file. (don't worry about legality of that, .gif is an open format)

• Hello and thank you for your comment! Sorry if I misunderstood but isn't what you wrote primarily concerned with compression and storage? In this case all I'm really worrying about is the user of my application being able to import any image, and the engine (in XNA) being capable of loading and displaying any image at runtime. I've managed to solve it simply by using GDI to read different sections of the image into separate XNA Textures, and wrapping them within a class that behaves just like a regular texture (i.e. supports drawing and transformations as a whole). – David Gouveia Dec 10 '11 at 3:12
• But out of curiosity, could you elaborate some more on what criteria you used to select which area of the image went into each section? – David Gouveia Dec 10 '11 at 3:13
• Some of it may be over your head if you're less experienced with image handling. But essentially, I was describing cutting up the image into segments. And yes the .gif point was describing both storage and loading, but it's meant as a method for you to cut up the image, and then store it on the computer how it is. If you save it as a gif I was saying that you can cut it into the individual images, and then save it as an animated gif, with each cut of the image being saved as separate animation frames. It works well and I even added other features it might help with. – Joshua Hedges Dec 10 '11 at 3:31
• The quadtree system as I described is entirely stated as a reference, as it's where I got an idea from. Although instead of crowding a possibly usable question for readers who may have similar issues, we should use private messaging if you would like to know more. – Joshua Hedges Dec 10 '11 at 3:32
• Roger, I got the part about using GIF frames as an archive of sorts. But I'm also wondering, isn't GIF an indexed format with limited color palette? Can I just store entire 32bpp RGBA images in each frame? And I imagine the process of loading it ending up even more complicated, as XNA supports nothing of this. – David Gouveia Dec 10 '11 at 3:43

This is going to sound obvious, but, why not just split your room into smaller pieces? Pick an arbitrary size that won't bump heads against any graphics cards (like 1024x1024, or maybe larger) and just break your rooms into multiple pieces.

I know that this avoids the problem, and honestly, this is a very interesting problem to solve. Anyway, this is kind of a trivial solution, which may work some of the time for you.

• I think I might have mentioned the reason somewhere in this thread, but since I'm not sure I'll repeat. Basically because it's not a game but rather a game maker for the general public (think something on the same scope as RPG maker), so instead of forcing the texture size limitation when the users are importing their own assets, it might be nice to handle the splitting and stitching automatically behind the scenes without ever bothering them with the technical details of texture size limitations. – David Gouveia Apr 19 '12 at 3:52
• Okay, that makes sense. Sorry, I guess I missed that. – ashes999 Apr 19 '12 at 10:17