dimanche 28 septembre 2008

tiles and backgrounds

Manipulating tiles, their palettes and backgrounds asks for insight in the memory organization...

The knowledge is scattered, in simple examples, unfinished tutorials and tables. Here an effort to put it all together.

Our goal: getting a tiled background and a bitmap together, the bitmap serving as a frame around a game like chess, or minesweeper....without mixing up the memory by overlapping.

Most of the times the examples (see devkitPro) are clear while so simple. But combining some ideas immediately shows the complexity of the memory mappings the videorams and the BG registers.

The starting tile example is from Liranuna's blog: (lesson 3 and 4)


But we want to combine a bmp-background with the tiles, and we get into the trouble of mem overlapping, resulting in bad graphics.

Here a table and registers from:
http://www.dspassme.com/programmers_guide/tutorial/registers.html#bg0_cr

For the main screen:
Background Tile/Map Addresses
Care must be taken in choosing the map and graphic addresses as they overlap. (Indeed!)

Address Map Addresses Graphic Addresses
0x06000000 BG_MAP_RAM(0) BG_TILE_RAM(0)
0x06000800 BG_MAP_RAM(1)
0x06001000 BG_MAP_RAM(2)
0x06001800 BG_MAP_RAM(3)
0x06002000 BG_MAP_RAM(4)
0x06002800 BG_MAP_RAM(5)
0x06003000 BG_MAP_RAM(6)
0x06003800 BG_MAP_RAM(7)
0x06004000 BG_MAP_RAM(8) BG_TILE_RAM(1)
0x06004800 BG_MAP_RAM(9)
0x06005000 BG_MAP_RAM(10)
0x06005800 BG_MAP_RAM(11)
0x06006000 BG_MAP_RAM(12)
0x06006800 BG_MAP_RAM(13)
0x06007000 BG_MAP_RAM(14)
0x06007800 BG_MAP_RAM(15)
0x06008000 BG_MAP_RAM(16) BG_TILE_RAM(2)
0x06008800 BG_MAP_RAM(17)
0x06009000 BG_MAP_RAM(18)
0x06009800 BG_MAP_RAM(19)
0x0600A000 BG_MAP_RAM(20)
0x0600A800 BG_MAP_RAM(21)
0x0600B000 BG_MAP_RAM(22)
0x0600B800 BG_MAP_RAM(23)
0x0600C000 BG_MAP_RAM(24) BG_TILE_RAM(3)
0x0600C800 BG_MAP_RAM(25)
0x0600D000 BG_MAP_RAM(26)
0x0600D800 BG_MAP_RAM(27)
0x0600E000 BG_MAP_RAM(28)
0x0600E800 BG_MAP_RAM(29)
0x0600F000 BG_MAP_RAM(30)
0x0600F800 BG_MAP_RAM(31)

DISPLAY_CR (0x04000000)

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
31 BGExtPal29 28 27 26 25 24 23 22 21 20 FBBank ExtMode
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SprWinWin1Win0Obj BG3 BG2 BG1 BG0 BlnkScrU6 OAMHorzBlankObjMapMode 3D Mode

BG0_CR (0x04000008)

This 16 bit register controls the features related to background #0 on the main display. To activate this register, this background must be enabled in the DISPLAY_CR (0x04000000).

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Size Wrap Map Color Mosaic Tile Pri


So, in this example:
http://www.dspassme.com/programmers_guide/tutorial/using_tiles.html#tile02

for the main screen:
POWER_CR = POWER_ALL_2D;

vramSetBankA(VRAM_A_MAIN_BG);
DISPLAY_CR = MODE_0_2D | DISPLAY_BG0_ACTIVE;
BG0_CR = BG_256_COLOR | BG_TILE_BASE(0) | BG_MAP_BASE(20);

These last three lines form a chain, combining a memory location to the videoram
tile base on 0 and map base on (a safe???) 20.

In Liranuna's example, apparently the map is smaller and put in front:
BG0_CR = BG_32x32 | BG_COLOR_16 | BG_MAP_BASE(0) | BG_TILE_BASE(1);
the map first and the tiles behind it.

Then we have to copy the tiles and palettes
memcpy((void*)BG_TILE_RAM(1), arrowTile_bin, arrowTile_bin_size);
u16* bg0Map = (u16*)BG_TILE_RAM(0);//making a pointer to the map we can calculate where to put tiles.

Adding another background? A bitmap this time, two tile-bg's would be too much :-)
vramSetMainBanks(VRAM_A_MAIN_BG_0x06000000, VRAM_B_MAIN_BG_0x06020000);

and now
either this going for 0x06010000
BG3_CR = BG_BMP16_256x256 | BG_BMP_BASE(4) ; //this is 0x06010000
u16* backBuffer = (u16*)(0x06000000 + 256 * 256 * 1 );

or this aiming at 0x06020000
BG3_CR = BG_BMP16_256x256 | BG_BMP_BASE(8) ; //this is 0x06020000
u16* backBuffer = (u16*)(0x06000000 + 256 * 256 * 2 );

is possible....

BG3_XDX = 1 << bg3_xdy =" 0;" bg3_ydx =" 0;" bg3_ydy =" 1" bg3_cx =" 0;" bg3_cy =" 0;" class="mw-headline">Map Entries
from
http://dev-scene.com/NDS/Tutorials_Day_4
of course also this example is explaining the same procedure, only it gives the tiles as a matrix.
(The last entry of this excelent tutorial.....)

The complete main.c of lesson 3 of Liranuna, but with an extra background becomes:

// Including libnds’ set of defines
#include
// Include basic memory functions
#include

// Including our converted graphics
#include "arrowTile_bin.h"

// Macro to translate 2D coord into 1D map array
#define POS2IDX(x, y) (x + (y*32))

// Set of defines for tile flipping
#define TILE_FLIP_NONE (0 << reg_powercnt =" POWER_ALL_2D;" display_cr =" MODE_5_2D" bg0_cr =" BG_32x32" vram_a_cr =" VRAM_ENABLE" bg0map =" (u16*)BG_TILE_RAM(0);" bg0map =" (u16*)BG_MAP_BASE(0);" bg3_cr =" BG_BMP16_256x256" backbuffer =" (u16*)(0x06000000" bg3_cr =" BG_BMP16_256x256" backbuffer =" (u16*)(0x06000000" bg3_xdx =" 1" bg3_xdy =" 0;" bg3_ydx =" 0;" bg3_ydy =" 1" bg3_cx =" 0;" bg3_cy =" 0;" colormask =" 0x1F;" iy =" 0;" ix =" 0;" iy =" 186;" ix =" 0;" iy =" 0;" ix =" 240;" iy =" 0;" ix =" 0;">
which gives the tiles in a frame of red, located on another background layer

Liranuna gives a lesson 4 exemple with two backgrounds.
Very usefull.
I redesigned the frame exemple above with the arrows and a tiled image background.
Because the arrows are 16 colors and this tiled background 256 colors i had to shift
the colors of the tiled background, using gfx2gba, shifting 64 = 4 x 16 colors.
//gfx2gba -c256 -St.tls -t8 -St.tls -C64 -v0 -pback.pal -m back.bmp
then loading also shifted:
void *paletteBuffer = (void *)&BG_PALETTE[64] ;
(and dmaCopy(paletteData, paletteBuffer, paletteSize); of course)
This is how the palette looks, with four 16 color palettes and behind it the colors of the tiled background:

This is the 256 color map at 0x0610000, = BG_TILE_RAM(4), and map BG_MAP_RAM(1) =
0x06000800
arrows at: BG_TILE_BASE(3) = 0x0600C000 , tiles and BG_MAP_BASE(0), map (see table above )




These examples about background organization can be found here:

Above example,using the Liranuna's arrows and adding a red frame
Second example, 2 tiled background 16/256 color (arrows and image) example

If you wonder why Liranuna used a 16x8 arrow in his example, read the following blog!
PS, so this works for the main screen, but don't think that you can copy this frame right away to the sub screen. The subscreen mem is much smaller, as you can see further on, of course an image can be displayed, as can be text, even from your own 16x8 font, but the red frame poses more problems!

Main backgrounds: 0x06000000 - 0x06400000
Sub backgrounds: 0x06020000 - 0x06021000 which is much smaller

This is a useful link with all kinds of register definitions, and here you can see the differences between VRAM_A VRAM_C and for instance VRAM_B:

http://takuto.info/libnds/arm9/video_8h.html#3bce26742d17eb8c77cf7338089f3ccf7cb3c69e848e7b5f045e932ee1e41f94

So the frame drawing (in the example red) on a bitmap can be done on the MAIN in mode 5.
double tile - backgrounds can be done, both on MAIN and SUB, in mode 0

on the SUB drawing on a bitmap (the red frame example) does not seem to be possible, in mode 5?
Yes, this is possible, but you can only use one background (apparently)

This is the example:
simple script to see drawing on both screen in mode 5