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.

Coding > sprites in bitmap graphic modes (i.e. mode 3)

#133598 - cuse - Sat Jul 07, 2007 11:22 am

Hi!

I know this is a FAQ and I read the various hints that I can only use the upper 512 sprite tiles, but I still couldn't get sprites appear in a bitmap graphic mode. Here is my test code:

Code:
#include"../../HeaderFiles/gba.h"
#include"../../HeaderFiles/graphics.h"
#include"../../HeaderFiles/dma.h"
#include"../../HeaderFiles/interrupt.h"
#include"../../HeaderFiles/screenmode.h"
#include"../../HeaderFiles/sprite.h"

// just an arbitrary 16 color palette for sprites
const unsigned short characters_Palette[16] = {
0x0000, 0x7bde, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};

// this bitmap for our sprite reflects the digit 7
const unsigned char digit7_Bitmap[32] = {
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xff, 0xff, 0x1f, 0x11, 0xff, 0xff, 0x11, 0xf1,
0xff, 0x1f, 0x11, 0xff, 0xff, 0x1f, 0xf1, 0xff, 0xff, 0x1f, 0xf1, 0xff, 0xff, 0x1f, 0xf1, 0xff
};

#define DIGIT_SIZE 8 // height and width of sprites
#define DIGIT_SPRITE_SIZE     (DIGIT_SIZE*DIGIT_SIZE)   // size of sprites (in pixels)
#define DIGIT_SPRITE_SIZE_BY2   (DIGIT_SPRITE_SIZE/2)   // size of sprite bitmaps (in data-words, for copying of the data)
#define DIGIT_SPRITE_DISTANCE   (DIGIT_SPRITE_SIZE/32)   // size of sprite bitmaps (in 32byte blocks, for calculating the character index)

// some test sprite object
OAMEntry fooSprite;

inline void gba_cpy16(u16* target, u16* source, u16 count) {
    DMA3Copy(source,target, count, DMA_16NOW);
}

void copy_sprite_bitmaps_to_oamdata() {
    // the GBA supports up to 1024 sprite bitmaps (tiles) in text graphic modes,
    // and up to 512 (the upper 512 ones) in bitmap graphic modes, in this test
    // we simply apply to all 1024 sprite bitmap slots the same bitmap
    int i;
    for (i = 0; i < 1024; i++)
        gba_cpy16( OAMData + i * DIGIT_SPRITE_SIZE_BY2, (u16*) digit7_Bitmap, DIGIT_SPRITE_SIZE_BY2);
}

// load the pallete for our sprites
inline void copy_sprite_palette() {
    gba_cpy16((u16*)OBJPaletteMem, (u16*)characters_Palette, 16);
}

void interrupt_handler() {
    // disable interrupts
    REG_IME = 0;

    // retrieve the interrupt type that occured
    register u16 interrupts = REG_IE & REG_IF;

    // VBlank interrupt (60 times per second)
    if (interrupts & INT_VBLANK) {
        // the GBA supports 128 sprite objects, we simply apply to all 128
        // sprite objects the same data
        int i;
        for (i = 0; i < 128; ++i)
            gba_cpy16((u16*)&OAMMem[i*2], (u16*)&fooSprite, sizeof(OAMEntry)/2);
    }

    // mask out all interrupts we dealed with
    REG_IF |= REG_IF;
    // re-enable interrupts
    REG_IME = 1;
}

void setup_interrupts() {
    // our interrupt handler function
    REG_INTERUPT = (u32)interrupt_handler;
    // generate a VBlank interrupt on each redraw of the screen
    REG_DISPSTAT |= DISP_INT_VBLANK;
    // enable VBlank interrupt
    REG_IE |= INT_VBLANK;
    // enable the interrupt controller
    REG_IME = 1;
}

int main(void) {
    // set graphic mode
    //SetMode(MODE_0 | OBJ_ENABLE | OBJ_MAP_1D); // this graphic mode would work with sprites yes, but ...
    SetMode(MODE_3 | OBJ_ENABLE | OBJ_MAP_1D); // ... why the heck doesn't this app work with this graphic mode???

    // load the sprite bitmap and sprite palette to the respective GBA address
    copy_sprite_bitmaps_to_oamdata();
    copy_sprite_palette();

    // now we setup some demo sprite object ...

    // set sprite position
    const int x = 50;
    const int y = 20;
    fooSprite.attribute0 = SQUARE | COLOR_16 | y;
    fooSprite.attribute1 = SIZE_8 | x;
    // set sprite bitmap (a.k.a. "tile")
    const int bitmap = 512; // in bitmap graphic modes 512 is the first tile index we can allegedly use
    fooSprite.attribute2 &= 0xf000;
    fooSprite.attribute2 |= (bitmap * DIGIT_SPRITE_DISTANCE);
    // set sprite color palette
    const int palette = 0;
    fooSprite.attribute2 &= 0x0fff;
    fooSprite.attribute2 |= PALETTE(palette);

    // enable VBlank interrup, as we have to update the sprites object data
    // for each graphic frame
    setup_interrupts();

    // endless loop
    while(1);

    return 0;
}


The code above works fine for text modes, but not for bitmap graphic modes.

What am I doing wrong? Any hints?

#133603 - Cearn - Sat Jul 07, 2007 12:43 pm

cuse wrote:
Hi!

I know this is a FAQ and I read the various hints that I can only use the upper 512 sprite tiles, but I still couldn't get sprites appear in a bitmap graphic mode. Here is my test code:

Code:
 
#define DIGIT_SIZE 8 // height and width of sprites
#define DIGIT_SPRITE_SIZE     (DIGIT_SIZE*DIGIT_SIZE)   // size of sprites (in pixels)
#define DIGIT_SPRITE_SIZE_BY2   (DIGIT_SPRITE_SIZE/2)   // size of sprite bitmaps (in data-words, for copying of the data)
#define DIGIT_SPRITE_DISTANCE   (DIGIT_SPRITE_SIZE/32)   // size of sprite bitmaps (in 32byte blocks, for calculating the character index)

    <snip>

    // set sprite bitmap (a.k.a. "tile")
    const int bitmap = 512; // in bitmap graphic modes 512 is the first tile index we can allegedly use
    fooSprite.attribute2 &= 0xf000;
    fooSprite.attribute2 |= (bitmap * DIGIT_SPRITE_DISTANCE);

DIGIT_SPRITE_SIZE is the size in pixels, but not in bytes because tile-indexing for objects works in 4-bit (i.e., half-byte) mode. DIGIT_SPRITE_DISTANCE should be 1, not 2. (bitmap * DIGIT_SPRITE_DISTANCE) equals 512*2 = 1024, which will be interpreted as tile-index 0, which doesn't exist in the bitmap modes. DIGIT_SPRITE_SIZE_BY2 is too large for the same reason.

#133927 - cuse - Mon Jul 09, 2007 9:23 pm

Yep, that was it! Thanks a lot Cearn!