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 > 16 color sprites

#6710 - hnager - Mon Jun 02, 2003 4:25 am

Hey all - I've been working at getting a 16 color sprite to simply display onscreen - I've had no problems with 256 color sprites, but decided to work with 16 colors because I have several variations of the sprites which could be handled with a palette swap.

So far my best result was a garbled square or red pixels - but at least it was properly positioned :)

That said - how does the process differ from 256 to 16 color sprite? Are there any examples floating around which anybody may point me toward?

#6713 - niltsair - Mon Jun 02, 2003 4:58 am

The difference is small.

Your sprite object must contains which palette to use.
Now, instead of writing 2 pixels at a time, you write 4. -> 3333 2222 1111 0000 Where 0,1,2,3 are the 3 pixel's colors.

#6737 - hnager - Mon Jun 02, 2003 1:48 pm

Well - here's what I have for main() - this works fine with a 256 color palette (minus the palette in attribute2 and COLOR_256 | SQUARE as opposed to 16), but with 16 all I get is a block of red(ish) pixels at 10,10 - which is defined below in SpriteInit().

If this all seems correct, maybe the error was in converting the pcx? thanks.


int main(){

SetMode(MODE_1 | OBJ_ENABLE | OBJ_MAP_1D);

Sprite blob;


//load the palette/sprite into memory
DMA_Copy(3,(void*)blobPalette,(void*)OBJPaletteMem,16,DMA_16NOW);
DMA_Copy(3,(void*)blobData,(void*)OAMData,384,DMA_16NOW);

InitializeSprites();

...etc


SpriteInit((Sprite_ptr)&blob,0,COLOR_16 | SQUARE,SIZE_16,10,10,0,0,0,0);

sprites[0].attribute2 = 0 | PALETTE(0);

while(1){

WaitForVsync(); //waits for the screen to stop drawing
CopyOAM(); //Copies sprite array into OAM.

}

return 0;
}

#6741 - niltsair - Mon Jun 02, 2003 2:27 pm

Did you re-exported your sprites tiles in 16colors?

Btw, you don't need your : WaitForVsync(); CopyOAM(); inside your while loop, just put it before.

#6742 - hnager - Mon Jun 02, 2003 2:30 pm

I did indeed - I used gfx2gba and then converted those to .cpp with b2x .

Does the rest of it look right?

Here's the palette and a snippet of the data:

const u16 blobData[] = {
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,

...

0x11,0xcf,0xcc,0xcc,0xfe,0xef,0xfa,0x11,
0x11,0xff,0xcc,0xee,0xff,0xcf,0xfa,0x11,
0x11,0xf1,0xef,0xfe,0xff,0xae,0x1d,0x11,
0x11,0xf1,0xff,0xff,0xff,0xdd,0x1f,0x11,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11
};

const u16 blobPalette[] = {
0x00,0x00,0x00,0x00,0x84,0x10,0x08,0x21,
0xff,0x7f,0x8e,0x08,0x46,0x00,0x6a,0x00,
0xbb,0x32,0x7f,0x5b,0x4c,0x7f,0xa6,0x6e,
0x26,0x76,0xc6,0x6d,0x44,0x5d,0x04,0x55
};

#6746 - niltsair - Mon Jun 02, 2003 2:44 pm

Mmm, your arrays are declared as const u16 (which is ok) but the content are 8bits value(which is not).

This value 0xCF will means 0x00CF in 16bits. You'll need to tell gfx2Gba to output 16bits value directly. Or alternatively, declare them as 8bits arrays (aligned on 16bits bondaries) and use them as 16bits arrays (by casting).

This is your problem, you only get the Red color part, with part of the Green :)

#6747 - hnager - Mon Jun 02, 2003 3:04 pm

good eye! I'll mess around will all those techniques...

Where would I do the casting for the array to u16? Using DMA_Copy I'm casting to void:

DMA_Copy(3,(void*)blobPalette,(void*)OBJPaletteMem,16,DMA_16NOW);

would this take care of it?

#6749 - niltsair - Mon Jun 02, 2003 3:22 pm

Yep. (void*) means a pointer, it doesn't care which kind. And when you do DMA_16NOW, it mean to use the data as 16bits chunk. Thus 2 values of 8bits are joined together, forming a 16bits.

You know, if the number of 16bits data to transfer is dividable by 2, then you can use DMA_32NOW instead, and have 1/2 the data to transfer. Like in your palette : DMA_Copy(3,(void*)blobPalette,(void*)OBJPaletteMem, 16/2 ,DMA_32NOW);

#6752 - hnager - Mon Jun 02, 2003 3:33 pm

Thanks - it sounds as if that should 'fix' my problem.

If I wanted to swap palettes for a sprite, would i just change this ont he fly?

sprites[0].attribute2 = 0 | PALETTE(0);

to on key press for example:

sprites[0].attribute2 = 0 | PALETTE(1);


?

#6754 - niltsair - Mon Jun 02, 2003 3:42 pm

exactly, and then recall the UpdateOAM() after a WaitVBlank()

#6755 - hnager - Mon Jun 02, 2003 3:49 pm

No need to clear the old palette out of there? if I wanted to do something like:

sprite[0].attribute2 = sprite[0].attribute2 | PALETTE(1) wouldn't I need to clear it our first? If so, how so ;)

#6756 - niltsair - Mon Jun 02, 2003 3:56 pm

No need to clear it out first.

By using palette 1, it means it's gonna use color 16-31. Palette 2 = color 32-47, etc...

So, you could either load all of your palettes in 1 shot(loading 256 colors) or just when you need it, loading the colors to their proper place.

#6801 - hnager - Mon Jun 02, 2003 11:42 pm

I've finally had time to try this out - I'm definately closer, but not totally there. Now I get the correct palette displayed (yay!) - but the sprite image is all garbled (looks striped horizontally - similar to problems I had in MODE 4 a while back).

To me it seems as if it's related to my sprite data and how I'm copying it in to OAM:

DMA_Copy(3,(void*)blobData,(void*)OAMData,128,DMA_16NOW);

this is the data - does it seem suspect? the sprite is 16x16:

u8 blobData [] = {
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
0x11,0x11,0x11,0x11,0x16,0x11,0x11,0x11,
0x11,0x51,0x55,0x11,0x16,0x51,0x55,0x11,
0x11,0x31,0x77,0x11,0x16,0x71,0x37,0x11,
0x11,0x51,0x77,0x11,0x16,0x71,0x57,0x11,
0x11,0x31,0x77,0x41,0x46,0x71,0x37,0x11,
0x11,0x51,0x75,0x47,0x46,0x77,0x55,0x11,
0x11,0x31,0x77,0x64,0x66,0x74,0x37,0x11,
0x11,0x51,0x47,0x66,0x22,0x46,0x57,0x11,
0x11,0x31,0x47,0x66,0x22,0x46,0x37,0x11,
0x11,0x51,0x47,0x64,0x66,0x44,0x57,0x11,
0x11,0x31,0x77,0x41,0x44,0x71,0x37,0x11,
0x11,0x51,0x77,0x11,0x11,0x71,0x57,0x11,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11
};

Any help is appreciated - Howard

#6803 - tepples - Tue Jun 03, 2003 1:00 am

hnager wrote:
this is the data - does it seem suspect? the sprite is 16x16

For a 16x16 sprite in 1D mapping mode, each separate 8x8 pixel piece of the cel must be stored in one piece, with the tiles following from left to right, top to bottom.

I assume you're trying to do this:
Code:
u8 blobData [] = {
 0x11,0x11,0x11,0x11,  0x11,0x11,0x11,0x11,
 0x11,0x11,0x11,0x11,  0x11,0x11,0x11,0x11,
 0x11,0x11,0x11,0x11,  0x16,0x11,0x11,0x11,
 0x11,0x51,0x55,0x11,  0x16,0x51,0x55,0x11,
 0x11,0x31,0x77,0x11,  0x16,0x71,0x37,0x11,
 0x11,0x51,0x77,0x11,  0x16,0x71,0x57,0x11,
 0x11,0x31,0x77,0x41,  0x46,0x71,0x37,0x11,
 0x11,0x51,0x75,0x47,  0x46,0x77,0x55,0x11,

 0x11,0x31,0x77,0x64,  0x66,0x74,0x37,0x11,
 0x11,0x51,0x47,0x66,  0x22,0x46,0x57,0x11,
 0x11,0x31,0x47,0x66,  0x22,0x46,0x37,0x11,
 0x11,0x51,0x47,0x64,  0x66,0x44,0x57,0x11,
 0x11,0x31,0x77,0x41,  0x44,0x71,0x37,0x11,
 0x11,0x51,0x77,0x11,  0x11,0x71,0x57,0x11,
 0x11,0x11,0x11,0x11,  0x11,0x11,0x11,0x11,
 0x11,0x11,0x11,0x11,  0x11,0x11,0x11,0x11
};


The GBA's actually looking for something like this:
Code:
u8 blobData [] = {
 0x11,0x11,0x11,0x11,  /* top left tile */
 0x11,0x11,0x11,0x11,
 0x11,0x11,0x11,0x11,
 0x11,0x51,0x55,0x11,
 0x11,0x31,0x77,0x11,
 0x11,0x51,0x77,0x11,
 0x11,0x31,0x77,0x41,
 0x11,0x51,0x75,0x47,
                0x11,0x11,0x11,0x11,  /* top right tile */
                0x11,0x11,0x11,0x11,
                0x16,0x11,0x11,0x11,
                0x16,0x51,0x55,0x11,
                0x16,0x71,0x37,0x11,
                0x16,0x71,0x57,0x11,
                0x46,0x71,0x37,0x11,
                0x46,0x77,0x55,0x11,

 0x11,0x31,0x77,0x64,  /* bottom left tile */
 0x11,0x51,0x47,0x66,
 0x11,0x31,0x47,0x66,
 0x11,0x51,0x47,0x64,
 0x11,0x31,0x77,0x41,
 0x11,0x51,0x77,0x11,
 0x11,0x11,0x11,0x11,
 0x11,0x11,0x11,0x11,
                0x66,0x74,0x37,0x11,  /* bottom right tile */
                0x22,0x46,0x57,0x11,
                0x22,0x46,0x37,0x11,
                0x66,0x44,0x57,0x11,
                0x44,0x71,0x37,0x11,
                0x11,0x71,0x57,0x11,
                0x11,0x11,0x11,0x11,
                0x11,0x11,0x11,0x11
};


In addition, you should usually make your tile data 'const' so that it'll go into ROM.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#6805 - hnager - Tue Jun 03, 2003 1:05 am

That did the trick! Which graphics converter do you suggest to output that? What I had was a result of a gfx2gba exporting a raw file and then running that through b2x...Thanks again!

#6809 - tepples - Tue Jun 03, 2003 1:49 am

Actually, I wrote my own graphics converter, which you can find in the TOD distribution. It's called 'bmp2bg', but don't be confused by the name; it can also output sprite cel data, provided that the bitmap is as wide as the sprite cels.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#6827 - Quirky - Tue Jun 03, 2003 7:45 am

hnager wrote:
That did the trick! Which graphics converter do you suggest to output that? What I had was a result of a gfx2gba exporting a raw file and then running that through b2x...Thanks again!


Don't run the output of gfx2gba through a raw->C converter. It's a needless step, wastes time as each C needs compiling and, as you have seen, is likely to introduce bugs. If you have large sprites or lots of them then this approach will drive you mad.

A better method is to use objcopy - it creates the "compiled" .o directly from the raw data without doing the parsing checks that gcc would have to do on a .c file. It also gives you symbols to be able to access that data (start, end, size). Just link that .o into your binary instead of the .o produced from the .c file and you're away.

#6840 - hnager - Tue Jun 03, 2003 11:58 am

Would this eliminate the problem I was having with how the 16 color sprite was being copied? Now that I have one, I have 15 more in an animation that needs to be copied in...The good news is that my quick test of two palettes worked which is great because I don't need to copy those 16 sprites in more than once.

I'll do some hunting around for objcopy - anybody have any good examples on hand?

#6845 - Quirky - Tue Jun 03, 2003 12:44 pm

objcopy is included in devkit advance. It lives in the /bin directory so you should be able to use it right away.

What I do is have a line in my makefile that objcopy's raw/map/pal files to .o files:

Code:

# create gcc object from map file
%.map.all.rodata.o: %.map
   @$(GCCARM)/objcopy -I binary -O elf32-little $< $@
      
# create gcc object from raw binary file
%.all.rodata.o: %.raw
   @$(GCCARM)/objcopy -I binary -O elf32-little $< $@

# create gcc object from palette file
%.pal.all.rodata.o: %.pal
   @$(GCCARM)/objcopy -I binary -O elf32-little $< $@


Then objcopy gives me a symbol in the .o that I can access from C like this:
Code:

extern unsigned char _binary_filename_ext_start[];


Where "unsigned char" could be replaced by 16 or 32 bit values or even structures, whatever is most suitable depending on the data type. That symbol name would be for a file called filename.ext that has been objcopied. More likely it would be a symbol something like _binary_master_pal_start for the default pallete name that gfx2gba spits out.

#6852 - hnager - Tue Jun 03, 2003 2:08 pm

Looks as if I'll have to step up my makefile skillz.

Currently I'm using the basic :

path=C:\GBA\bin
g++ -o main.elf main.cpp -lm
objcopy -O binary main.elf day3.bin

pause

I'll do my best to use objcopy with the raw files - but I may aswell ask: Anybody willing to give up a sample project using objcopy? I'm looking for a 16 color sprite example (best case) - but I'll take any sprite copied in with this method.