gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Semi-beginner in need of help. DEVKITPRO/TONC

#177974 - CountSymphonic - Sat Jun 22, 2013 5:40 am

Hey all, first I must say that it's nice to join everyone here in this exciting area of programming. It is my hope that this be the start of something wonderful not only for myself, but for the entire scene.

Ahh, pipe dreams. Anyways I'm somewhat of a semi-beginner, meaning that I've been getting into programming off and on for about 10 years... however I never got real deep into it. That said, here's what I'm familiar with as far as C is concerned, mind you, I don't necessarily mean that I've mastered the concepts, more that I UNDERSTAND them; Branches, Loops, Pointers, Functions, Variables, Libs and Includes (let's just say I know the basic of the basics with these), setting up IDE.

I've been able to put together a basic hello world, a calculator, and a very simple text based game in C, for the command line interface. Nothing fancy, or complex for that matter. I was going to learn Allegro, but I really want to skip that and go straight to the juice... GBA programming. I want desperately to use GBA programming, making a Zelda clone to facilitate learning C and GBA programming simultaneously. Obviously this will make things a bit more complicated, but this is how I wish to proceed.

That said. I'm so freaking confused and lost right now. There seems to be no real documentation on DEVKITARM/LIBGBA. So learning how to use it, well that's my roadblock. Also there's TONC, which is rich with explanations and whatnot, however, can I use the TONC library without using functions from DevKitArm/libgba? Can I use TONC's features alone to create a full fledged Zelda clone?

I've got everything set up, I've compiled hello worlds for the GBA, they work great. I just need to figure out how to proceed further. I would use source code examples to help me learn but I'm having a lot of trouble finding what I need. I've been looking around for info googling for the past couple of weeks!

Thanks in "advance"... heh.

#177975 - DekuTree64 - Sat Jun 22, 2013 5:51 pm

Hello and welcome :)
I kind of vanished from the programming scene a few years back, but have been getting back into it this past month, working on a GBA game somewhere between FF1 and FF4 style.

If you can get a hello world program to compile and run, you're already done with the hard part. I think libgba has auto-generated documentation via Doxygen, but it's easy enough to make your own Gba.h as well. Here's mine (I use the linkscript and crt0 from devkitpro, but that's it): http://deku.rydia.net/temp/Gba.h
Feel free to use it, if you like it better than libgba's split up headers. The actual info in it is pretty much all from GBATEK anyway (which is the go-to reference for how the GBA hardware works).

I'm not that familiar with TONC, but regardless of whether you actually use its libraries, the tutorials should be good for learning the general way things go... copy some data to a particular memory area, set some register values, stuff shows up on the screen.

As for the game, probably the most difficult part of a Zelda clone will be creating the maps. But it can be done without a fancy map editor, especially if you have simple tilesets like Zelda 1. Sometimes I even "draw" maps in code :) For example, a single-screen map using 16x16 pixel tiles like Zelda uses could be done like this
Code:

const u8 testmap[15*10] = {
 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
};

Where tile 0 in your tileset image is blank and unused, tile 1 is a "top left" wall corner tile, 2 is "top" wall, 9 is "bottom right" corner, and 5 is walkable floor.

GBA screen resolution is 240x160 pixels, so divide by 16 (tile size) and that's 15 tiles wide, 10 tiles tall (hence the map dimensions). However, GBA only supports 8x8 tiles... so in order to do 16x16 tiles, you have to build them out of four 8x8 tiles. So that map can't be copied to VRAM straight away. You have to use a separate table generated from your tileset image to translate each map tile index into 4 different GBA tile indices... it's a little tricky at first, but harder to explain than to understand.

For your very first learning, just work in 8x8 tiles directly. But once you understand the hardware better and want to get to the actual game making, learn how to do the 16x16 tile thing.

Good luck and have fun! Not many active GBA devs these days, it seems, but rest assured there are still people out there with a soft spot for it :)
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#177976 - CountSymphonic - Mon Jun 24, 2013 5:00 am

Wow thanks for the reply. It's nice to know the GBA scene still lives! I'll definitely have a look at the header. But yes, I've managed to get things compiled and running.

For me, making the maps seems to be fairly easy. I was already using 16x16, because it just allows more detail. I've already started creating my own tileset in that format (16x16), and played with GBAMAPPY for creating the maps, kudos to you for being able to do it in code. Now, making the maps for me is easy, I'm thinking implementing them will be the tricky part, but hopefully not too hard as your explanation will definitely be instrumental in getting this to work on the GBA, so thank you very much for your generous advice.

I've really been stuck for two weeks figuring out how to work with all of the GBA programming. I understand what you're saying about GBATEK. I have a copy of it, is that basically what I need to learn and understand how to code for the GBA in C? I've pretty much just been looking at a ton of source examples, and whenever there was something I didn't understand, it was off to the C books for a good study... since I'm still a bit blah with C anyways.

Final Fantasy was always a huge inspiration for me, that's awesome that you're doing something of that caliber.

But basically about getting the 16x16 thing down. Can I make a function that tells the GBA to handle 8x8 tiles as 16x16 tiles? In laymen's words anyways, obviously the function would require more code, using the method you indicated and surely there's more ways to do it. The way my custom tileset is arranged, the tiles are already set up as 16x16. Either way, I understand what you're saying. I'm just thinking I'll have to make a function that handles the tiles as 16x16.

BTW, I took a look at your demos. Very, very impressive work. Inspiring even, alot of it brought me back to the Golden Sun days... :)

#177977 - DekuTree64 - Mon Jun 24, 2013 7:25 pm

CountSymphonic wrote:
I've really been stuck for two weeks figuring out how to work with all of the GBA programming. I understand what you're saying about GBATEK. I have a copy of it, is that basically what I need to learn and understand how to code for the GBA in C?

GBATEK has all the info you need about the GBA hardware, but it's definitely not a tutorial, and would be hard to piece together how it all works from that. And it has nothing to do with C.

The TONC tutorials will give you a much better guide to how tile VRAM, screen VRAM, palette RAM, and BG control registers all work together, and do demonstrate it in C.

Quote:
But basically about getting the 16x16 thing down. Can I make a function that tells the GBA to handle 8x8 tiles as 16x16 tiles?

That's the idea. The only real tricky bit has to do with tile ordering, i.e. this: (image scaled up 4x so the grid lines and numbers are more readable and don't cover everything so much... fat lines mark 16x16 tile borders, thin lines mark 8x8 tile borders)
[Images not permitted - Click here to view it]
If you break up the image into 8x8 tiles, then your first 16x16 tile is made up of tiles 0, 1, 6, and 7... which is a pain to work with. Much easier if it's 0, 1, 2, 3, and second 16x16 tile is made up of 8x8 tiles 4, 5, 6 and 7. Here's one way to make that happen... arrange your tiles all into a vertical strip 16 pixels wide:
[Images not permitted - Click here to view it]
Which is still kind of a pain to do. I reorder the wide image tiles in my BMP to GBA-friendly format converter, but the strip style is probably less confusing.

Come to think of it, do you have a BMP to GBA-friendly format converter? If not, you (and anyone else) are welcome to use mine: http://deku.rydia.net/program/bmpconv.zip
Don't judge the code too harshly... I wrote that around 10 years ago and haven't changed it much since, aside from adding the 16x16 tile mode a couple weeks ago :P
It takes an 8-bit .bmp file and spits out 3 files, which you need to get into your GBA ROM any way you can... I use Tepples' GBFS. The .gfx file contains the actual tile pixel data (just copy it to VRAM directly), .pal file can be copied to palette RAM directly, and the .map file contains screen map data, in the format described here

Also as mentioned on that page, hardware BG screen maps are always 32x32 tiles. Screen data is very much the same concept as the map in your map editor. Each 16-bit value of the screen data contains a tile number to display there, as well as flags for horizontal/vertical flipping, and a palette index if using 4 bits per pixel tile data (I almost always use 4-bit myself)

So, the .map file is in the correct format to copy to VRAM directly, except it will only line up correctly if the original .bmp was 256 pixels (32 tiles) wide like hardware BG maps. Otherwise you have to copy it row by row:
Code:
for (y = 0; y < srcHeight; y++)
    for(x = 0; x < srcWidth; x++)
        bgScreenVRAM[x + y*32] = srcMapFile[x + y*srcWidth];

Where srcWidth is the width of the .bmp, in 8x8 tiles.

But since you'll be using a 16 pixel wide image, and it's just a tileset which is referenced by map editor data, then your copy to screen will actually look more like this:
Code:
    // This assumes game maps are always 15 tiles wide, 10 tiles tall (i.e. the size of the screen)
for(y = 0; y < 10; y++)
{
    for(x = 0; x < 15; x++)
    {
        int tileIndex = gameMap[x + y*15];
        bgScreenVRAM[(x*2 + 0) + (y*2 + 0)*32] = srcMapFile[tileIndex*4 + 0];
        bgScreenVRAM[(x*2 + 1) + (y*2 + 0)*32] = srcMapFile[tileIndex*4 + 1];
        bgScreenVRAM[(x*2 + 0) + (y*2 + 1)*32] = srcMapFile[tileIndex*4 + 2];
        bgScreenVRAM[(x*2 + 1) + (y*2 + 1)*32] = srcMapFile[tileIndex*4 + 3];
    }
}


Quote:
BTW, I took a look at your demos. Very, very impressive work. Inspiring even, alot of it brought me back to the Golden Sun days... :)

Thanks :) You know, Golden Sun brings me back to the Lufia 2 days... I love the puzzle solving in both of those games. I think I'll add some of that to mine, since I prefer visible enemies instead of random battles, and dungeons are pretty much just boring maze navigation if you're not being punished for every step you take.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#177978 - CountSymphonic - Tue Jun 25, 2013 10:20 am

I thought I read somewhere for GBA, that you could use arrays for the graphics in two ways. One in a linear fashion and the other in a 2d fashion... might I take advantage of the linear fashion when arranging my tiles for 16x16? If they are all numbered in a straight 1,2,3 fashion and arranged properly before hand?

Either way, your insight will definitely prove to be an invaluable reference, my next test rom will have to be practicing loading up tiles, as I've been messing with text and colors for my first test, and it's starting to get old haha. I suppose that after a while testing out all these different features with the GBA that it will all come together eventually. Thanks again for sharing your wisdom, you've obviously put much effort and dedication into learning this stuff. So next up on the agenda is loading tiles. They say it's best to practice with the bitmap modes because they're "easier" but I feel like skipping straight to the tile modes, shame on me. After that, it's time for practicing with button input, vsync, and animations! One step at a time.

On a side note, I think we share something very interesting in common. It's nice to know that I'm not the only music composer that is also into programming and making RPG's. It's because of music and the interesting distraction it gives that I'm not very sharp with programming, I spent years on music after all! I have this sneaking suspicion that it was the music in the many great RPG's and the RPG's themselves that also might've inspired you to want to get into music and programming also, that's how it was for me anyways.

Quote:
Thanks :) You know, Golden Sun brings me back to the Lufia 2 days... I love the puzzle solving in both of those games. I think I'll add some of that to mine, since I prefer visible enemies instead of random battles, and dungeons are pretty much just boring maze navigation if you're not being punished for every step you take.


FFVII is a wonderful example of this issue that you present, which FFVII is one of my all time favorites from childhood. I find it more difficult nowadays to play through that game because of the repetitive nature, while games like Zelda still feel fresh. Don't get me wrong though. I still appreciate the nature of turn based RPG's, especially the music ;)

What are you currently using for your music production software? Still sticking with MIDI's and .sf2's?

I thought I might've had a converter bmp to gba, stuffed in my hard drive somewhere, but honestly, I prefer to have more options so I can choose something that might be more suitable for my needs. But by all means, I won't be the one to judge anyone's code. Mine's going to be looking a lot worse for a while anyways.

#177979 - Dwedit - Tue Jun 25, 2013 4:07 pm

Here's the short description of how to make games for console systems:

Background
- Render a screen of a complete background to start.
- Incrementally replace rows/columns of tiles as the camera moves. Watch games like Golden Sun in the map viewer and you can see it do this.
- Replace tiles that are visible on the screen if you have map tiles changing.

Game Objects
- Have a list of all the objects to handle, be able to add, remove, and replace items in the list. Probably a fixed size array, but you don't necessarily have to use that.
- Call a handler for every object, the handler calls all the code that the object needs to do. This is where almost all the code goes.
- Create new objects as the camera moves and objects become closer to the screen.
- Remove objects that are too far from the screen.

Animation frames
- A "frame" of a sprite will become one or more physical sprites for the hardware's sprite table (OAM).
- Sprite flipping, etc... Either store them separately, or generate them from unflipped versions.
- Code will convert the object table into sprites for the OAM.

Sprite animations
- You can separate the animation sequences from the game logic, so the game logic won't need to pick the exact animation frames all the time.
- Call a handler for every object
- Game logic selects which animation to play, and the animation code will select exactly which frame of animation to display, simple lists of sequential frames may be good enough.
- Loop animations, trigger events after an animation has finished playing, etc...
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#177980 - DekuTree64 - Tue Jun 25, 2013 6:59 pm

CountSymphonic wrote:
I thought I read somewhere for GBA, that you could use arrays for the graphics in two ways. One in a linear fashion and the other in a 2d fashion... might I take advantage of the linear fashion when arranging my tiles for 16x16? If they are all numbered in a straight 1,2,3 fashion and arranged properly before hand?

BG tiles are always mapped linearly. The 2D mapping mode is only for sprites, and despite my attempts, I've never come up with a scenario that gives it any advantage whatsoever over 1D mapping. If you can think of one, let me know :lol:
Bottom line: don't bother learning the 2D mapping mode.

Quote:
I have this sneaking suspicion that it was the music in the many great RPG's and the RPG's themselves that also might've inspired you to want to get into music and programming also, that's how it was for me anyways.

Close :) I've been playing music longer than I've been playing video games (and drawing longer than that). But the music in RPGs is a big part of the enjoyment of playing and inspiration to learn programming. I'm a particularly big fan of Yasunori Mitsuda (Chrono Trigger and Xenogears). Programmer/musicians aren't as rare as you might think. In fact, they seem to be somewhat related skills... whereas programming and artwork seem to be somewhat opposing.
You should say hey to another friend of mine from this forum, who loves FF7 and music, and is getting to be a great 3D modeller as well: http://forum.gbadev.org/profile.php?mode=viewprofile&u=9623

Quote:
What are you currently using for your music production software? Still sticking with MIDI's and .sf2's?

For this game, ModPlug tracker, 4 channel .mod format, using chiptune style instruments. Fun for the classic vibe, plus I already had a player written for it from my tutorial series :P Although I did write a new mixer because the tutorial one is terribly slow: http://deku.rydia.net/temp/SoundMix.s http://deku.rydia.net/temp/Sound.h Perhaps sometime I'll write another tutorial chapter explaining all the tricks used in it.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#177981 - CountSymphonic - Wed Jun 26, 2013 2:20 am

Quote:
Background
- Render a screen of a complete background to start.
- Incrementally replace rows/columns of tiles as the camera moves. Watch games like Golden Sun in the map viewer and you can see it do this.
- Replace tiles that are visible on the screen if you have map tiles changing.


If I understand what you're saying... wouldn't a comparable example of this be something similar used in alot of 3D games today? For example, Wind Waker, a very sandbox style game. Very close up islands would be full blown 3D models, but as you got further away from the island it was more like a 2D plane, or perhaps a simpler model with less vertices and simpler textures, sort of a way to optimize things and keep the framerate up. Is this sort of what you're trying to explain? Loading and clearing tiles as you need/don't need them, depending on how close they are to the viewport?

Quote:
Game Objects
- Have a list of all the objects to handle, be able to add, remove, and replace items in the list. Probably a fixed size array, but you don't necessarily have to use that.
- Call a handler for every object, the handler calls all the code that the object needs to do. This is where almost all the code goes.
- Create new objects as the camera moves and objects become closer to the screen.
- Remove objects that are too far from the screen.

Animation frames
- A "frame" of a sprite will become one or more physical sprites for the hardware's sprite table (OAM).
- Sprite flipping, etc... Either store them separately, or generate them from unflipped versions.
- Code will convert the object table into sprites for the OAM.


Understood. Thank you, for your insight!




Quote:
BG tiles are always mapped linearly. The 2D mapping mode is only for sprites, and despite my attempts, I've never come up with a scenario that gives it any advantage whatsoever over 1D mapping. If you can think of one, let me know :lol:
Bottom line: don't bother learning the 2D mapping mode.


I see what you're saying. So with BG's being mapped linearly, does this mean that each 8x8 tile is in sequential order 1,2,3,4,5...? If not, how does it work?

Quote:
Close :) I've been playing music longer than I've been playing video games (and drawing longer than that). But the music in RPGs is a big part of the enjoyment of playing and inspiration to learn programming. I'm a particularly big fan of Yasunori Mitsuda (Chrono Trigger and Xenogears). Programmer/musicians aren't as rare as you might think. In fact, they seem to be somewhat related skills... whereas programming and artwork seem to be somewhat opposing.
You should say hey to another friend of mine from this forum, who loves FF7 and music, and is getting to be a great 3D modeller as well: http://forum.gbadev.org/profile.php?mode=viewprofile&u=9623


Interesting point you bring up. Music composition for me... does have a very abstracted way of being done. Song layers. Motifs, the patterns... sorta like functions that can be reused and varied. Interesting parallel.

Quote:
For this game, ModPlug tracker, 4 channel .mod format, using chiptune style instruments. Fun for the classic vibe, plus I already had a player written for it from my tutorial series :P Although I did write a new mixer because the tutorial one is terribly slow: http://deku.rydia.net/temp/SoundMix.s http://deku.rydia.net/temp/Sound.h Perhaps sometime I'll write another tutorial chapter explaining all the tricks used in it.


Cool I'll have to look into all that. For chiptunes, I would use LSDJ for Gameboy... which is useless for composing for homebrew games at this point... :( I also use Sunvox, which is an excellent modular tracker! If you have an Android phone/tablet or iOS device, it's great for NES/GB/GBA and POSSIBLY Sega Genesis style music. But it can only output to .wav and it's own proprietary format so it's useless for homebrew, but could be used to a great extent for PC based games.

You guys are awesome. Thanks for the help thus far. Besides that, we should definitely keep in touch. I feel right at home here :)

#177982 - Dwedit - Wed Jun 26, 2013 3:25 am

CountSymphonic wrote:

If I understand what you're saying... wouldn't a comparable example of this be something similar used in alot of 3D games today? For example, Wind Waker, a very sandbox style game. Very close up islands would be full blown 3D models, but as you got further away from the island it was more like a 2D plane, or perhaps a simpler model with less vertices and simpler textures, sort of a way to optimize things and keep the framerate up. Is this sort of what you're trying to explain? Loading and clearing tiles as you need/don't need them, depending on how close they are to the viewport?


The trick of using low-detail polygon models is a nice trick to save resources, but I'm not taking about this at all.
I'm saying it's literally impossible to scroll the screen without overwriting a newly exposed column or row of tiles on the VRAM map. The hardware's tilemap is 32x32 8x8 tiles (256x256 pixels), and your screen is 240x160 pixels. Scrolling works by wrapping, so when you go off the right edge of the tilemap, it's drawing tiles from the left edge. So if you scroll horizontally at all, you will need to send new columns as they appear on the screen.
So your camera is at X=0. You've filled the map with 30 columns of 8x8 tiles. You move one pixel to the right. You need a new column of tiles to appear on the map. Then you can move the camera to X position 8 and still not need any new tiles on the screen. But when you move the camera to X position 9, then you need a new column of tiles on the map.
Same idea when moving the camera to the left, and moving the camera vertically, you send new rows of tiles as they are exposed on the screen.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#177983 - CountSymphonic - Wed Jun 26, 2013 8:00 am

Dwedit wrote:
CountSymphonic wrote:

If I understand what you're saying... wouldn't a comparable example of this be something similar used in alot of 3D games today? For example, Wind Waker, a very sandbox style game. Very close up islands would be full blown 3D models, but as you got further away from the island it was more like a 2D plane, or perhaps a simpler model with less vertices and simpler textures, sort of a way to optimize things and keep the framerate up. Is this sort of what you're trying to explain? Loading and clearing tiles as you need/don't need them, depending on how close they are to the viewport?


The trick of using low-detail polygon models is a nice trick to save resources, but I'm not taking about this at all.
I'm saying it's literally impossible to scroll the screen without overwriting a newly exposed column or row of tiles on the VRAM map. The hardware's tilemap is 32x32 8x8 tiles (256x256 pixels), and your screen is 240x160 pixels. Scrolling works by wrapping, so when you go off the right edge of the tilemap, it's drawing tiles from the left edge. So if you scroll horizontally at all, you will need to send new columns as they appear on the screen.
So your camera is at X=0. You've filled the map with 30 columns of 8x8 tiles. You move one pixel to the right. You need a new column of tiles to appear on the map. Then you can move the camera to X position 8 and still not need any new tiles on the screen. But when you move the camera to X position 9, then you need a new column of tiles on the map.
Same idea when moving the camera to the left, and moving the camera vertically, you send new rows of tiles as they are exposed on the screen.



I misunderstood you. What you're saying is that if I were to load a small tilemap without updating the new tiles near the edge of the screen and if I were to move, I would end up seeing the tilemap repeat itself. I noticed this while toying around with one of the Tonc demos. Imust say, that this is something that I probably would've stumbled on trying to figure out on my own. This should make loading and handling 16x16 tiles more interesting heh heh.


Thanks for the correction. It's easy to misinterpret the intended meaning in spoken language.

#177984 - Dwedit - Thu Jun 27, 2013 2:14 am

But you can also dynamically load graphics for tiles that will appear on the screen. It's just a little tricky to do that.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#177985 - CountSymphonic - Thu Jun 27, 2013 9:20 am

Dwedit wrote:
But you can also dynamically load graphics for tiles that will appear on the screen. It's just a little tricky to do that.


Is it tricky because of memory constraints? Mem speed?

#177986 - sverx - Thu Jun 27, 2013 11:20 am

Dwedit wrote:
But you can also dynamically load graphics for tiles that will appear on the screen. It's just a little tricky to do that.


I'm curious about that. If you've got more than 1024 possible different tiles for a single background, how would you link the video ram dynamically allocated tile index with the tile map index you've got in rom and that you probably made with grit or similar?
(I still never tried any approach, I'm just very curious... :D )
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary

#177987 - Dwedit - Thu Jun 27, 2013 3:11 pm

Surprisingly enough, on the GBA, VRAM is the second fastest kind of memory. It's much faster than the 256k of EWRAM, or reading ROM out of the cartridge slot. When you copy graphics from ROM to VRAM, reading the ROM is the slow part, writing to VRAM is the fast part. It's like the exact opposite of a PC. I've even executed code from inside of VRAM when I ran out of IWRAM, and it runs faster than code stored in EWRAM or ROM.

The reason it's tricky to dynamically load tiles is that you're no longer using simple tile indexes into VRAM. There are two main ways to do it:

#1) Use a common tileset and a swappable tileset, then when certain areas get exposed on the screen, swap the tileset out. Don't put areas using two different swappable tilesets next to each other, pad them apart with a screen that only uses the common tileset.

#2) Use a cache system for background tiles.
You will need to use a lookup table which maps virtual tile numbers to physical tile numbers in VRAM. If the tile is not found, add a tile to VRAM, and make note of it in the map.
You also keep track of reference counts of tiles, so you know whether a tile is actually in use or not.
When you add a new tile to VRAM, you look through the map, and find a tile which is no longer used. FIFO is a good way to do this. When you remove a tile, change its entry in the lookup table to indicate that it no longer exists.
Data structures used:
* Lookup converting virtual tiles to physical tiles (either a flat array, hash table, search tree, sorted list, etc)
* Array mapping physical tiles to the virtual tile it corresponds to
* Reference counts for physical tiles
* Cursor for replacing tiles, this corresponds to a physical tile index
Algorithm:
Replacing a tile on the map with a new virtual tile:
Decrease reference count of the old physical tile.
Lookup contains the new virtual tile?
If so, use the known physical tile
Otherwise, replace an old tile with a new virtual tile
Increase reference count of the new physical tile

Replacing a tile:
Is physical tile at the cursor not in use (reference count is zero)?
If so:
* remove old virtual tile from the lookup table
* load graphics for the new virtual tile
* set new virtual tile for physical->virtual array
* set new physical tile for virtual->physical lookup table
If tile is in use:
* move to the next tile and try again, this means wrapping to 0 when you reach the max tile number
If every single tile has a reference count > 0
* oh noes! Abort so you don't crash.

To avoid a full cache, you can also replace tiles with a dummy tile when they scroll off the screen so the reference count decreases.

I think the cache system is overkill, but it should allow you to use any number of tiles you can possibly think of.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#177988 - sverx - Fri Jun 28, 2013 11:00 am

Wonderful explanation! Thanks! :)
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary

#177989 - CountSymphonic - Sat Jun 29, 2013 9:31 am

Wow. This is an impressive library of information, you guys sure do know what you're doing and you know what? You're taking all the fun out me learning how to do it myself! Haha.

This thread will definitely be of good reference when I get around to putting together a tiling engine/demo. I can't wait to get started.

I managed to get in contact with the author of TONC. He seems like a pretty cool guy. It's a shame that he put together TONC when the NDS pretty much took over, which don't get me wrong... the NDS is amazing and all, but I'm a sucker for older hardware. I'd almost rather be putting together regular Gameboy homebrew if there was more reliable information out for it.

#177990 - gauauu - Mon Jul 01, 2013 2:55 pm

Yeah, Cearn is a great guy. Super helpful, nice, and really knowledgeable. Tonc's been the best way to learn GBA programming since...oh, whenever he made it. 2004 or whatever it was.

#178039 - sverx - Tue Aug 13, 2013 2:22 pm

Dwedit wrote:
[...]
Use a cache system for background tiles.
You will need to use a lookup table which maps virtual tile numbers to physical tile numbers in VRAM. If the tile is not found, add a tile to VRAM, and make note of it in the map.
You also keep track of reference counts of tiles, so you know whether a tile is actually in use or not.
When you add a new tile to VRAM, you look through the map, and find a tile which is no longer used. FIFO is a good way to do this. When you remove a tile, change its entry in the lookup table to indicate that it no longer exists.
Data structures used:
* Lookup converting virtual tiles to physical tiles (either a flat array, hash table, search tree, sorted list, etc)
* Array mapping physical tiles to the virtual tile it corresponds to
* Reference counts for physical tiles
* Cursor for replacing tiles, this corresponds to a physical tile index
Algorithm:
Replacing a tile on the map with a new virtual tile:
Decrease reference count of the old physical tile.
Lookup contains the new virtual tile?
If so, use the known physical tile
Otherwise, replace an old tile with a new virtual tile
Increase reference count of the new physical tile

Replacing a tile:
Is physical tile at the cursor not in use (reference count is zero)?
If so:
* remove old virtual tile from the lookup table
* load graphics for the new virtual tile
* set new virtual tile for physical->virtual array
* set new physical tile for virtual->physical lookup table
If tile is in use:
* move to the next tile and try again, this means wrapping to 0 when you reach the max tile number
If every single tile has a reference count > 0
* oh noes! Abort so you don't crash.

To avoid a full cache, you can also replace tiles with a dummy tile when they scroll off the screen so the reference count decreases.

I think the cache system is overkill, but it should allow you to use any number of tiles you can possibly think of.


I'm testing a simplified version of this. It works this way: we don't have to count the occurrences of the same tile... assume they're all different (they never repeat). This way you 'reserve' 31x21 tiles in VRAM and you just load the full 'row' (or 'column') that enters the screen, onto the tiles that are left by the row (or column) that goes off-screen.

Of course in the worst case (when we have both horizontal and vertical movement) we'll load 52 tiles, but that's true for your cache system too...

So far it seems it's working good enough. It could theoretically handle a background of any size, having up to 65536 tiles, using only one 32x32 VRAM map and 651 (31x21) tiles space (in VRAM too). This means I would probably be able to have up to 3 (!!!) backgrounds made this way at the very same moment... which is surely enough for me :)
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary

#178054 - sverx - Tue Aug 20, 2013 4:53 pm

... and here's a little demo of it.
The image is "Pixeltown: a massive (2835x900) pixel art beach city scene" (as described here, bottom of page) created by stridenoble and used with his kind permission.
(I converted it to a 16 color image and then passed to GRIT which converted it to a 39269 different tiles & a 355x113 flat map). I'm using a single 32x32 16 color-tiles background, with 651 (31x21) tiles allocated.
Scroll using D-pad (and when you finally get bored, I suggest to download the original image ;) )
_________________
libXM7|NDS programming tutorial (Italiano)|Waimanu DS / GBA|A DS Homebrewer's Diary