#14336 - Geoff - Mon Jan 05, 2004 5:37 pm
I started working through some GBA programming tutorials a few days ago and I'm having problems with displaying graphics. My sprites and background tile graphics appear all scrambled. The colours are correct, and the sizes are correct, but the bitmap data itself is all wrong.
The tutorials I'm working through involve using pcx2gba to convert pcx files to .h files. I bet most of you are familiar with this tool. Here is the code I use to copy the sprite Palette and Data arrays into memory:
source wrote: |
int main(void)
{
u16 i;
//Set mode 1 and enable sprites and 1d object mapping
SetMode(MODE_1 | OBJ_ENABLE | OBJ_MAP_1D);
//Retrieve the palette data from sprite.h
for(i=0; i<256; i++) {
OBJPaletteMem[i] = spritePalette[i];
}
//Put all 128 sprites offscreen
InitializeSprites();
//Sprite struct
Sprite guy;
guy.char_mem[0] = 0;
guy.cur_frame = 0;
guy.OAM_index = 0;
guy.rot_index = 0;
guy.x = guy.y = 0<<8;
guy.screen_x = guy.screen_y = 0;
guy.state = 0;
//Save these attributes in the OAMEntry array
sprites[0].attribute0 = COLOR_256|SQUARE|ROTATION_FLAG|guy.y;
sprites[0].attribute1 = SIZE_64|ROTDATA(0)|guy.x;
sprites[0].attribute2 = 0;
//Copy in the sprite's bitmap - 1D
for(i=0; i<(sprite_WIDTH*sprite_HEIGHT/2); i++) //16 bits at a time!
{
OAMData[i] = spriteData[i]; //data in sprite.h
}
//Main Game loop
while(1)
{
// -Other stuff here- not important - changing his position and stuff//
//Wait for vblank
WaitForVsync();
//Copy our sprites into OAM using DMA transfer
REG_DMA3SAD = (u32)sprites;
REG_DMA3DAD = (u32)OAM;
REG_DMA3CNT = (128 * 4)|DMA_16NOW;
}
}
|
I have omitted my background loading from this code because it would just get in the way. I load my background graphics in an almost identical manner. This stuff is based on the tutorial at the PERN Project FYI.
I hope someone can help.
#14337 - poslundc - Mon Jan 05, 2004 5:44 pm
Two things I notice at first glance:
1. You are using the sprites[] array as your shadow OAM, but you have only put values for the first entry of it. You need to populate the entire array to put the unused sprites offscreen.
2. You are using rotation sprites, but you have not filled out any of the rotation attributes. In order to display a rotation sprite without any scaling, rotation etc. applied to it, the sprite's pa and pd values must be (1 << 8) (or 0x100). I do not think a sprite with zero in all of those values will display at all.
Dan.
#14340 - Geoff - Mon Jan 05, 2004 6:00 pm
Quote: |
1. You are using the sprites[] array as your shadow OAM, but you have only put values for the first entry of it. You need to populate the entire array to put the unused sprites offscreen. |
Okay. Should I just make a dummy entry with default attributes then copy it into the entire array? Seems kind of strange.
#14342 - poslundc - Mon Jan 05, 2004 6:33 pm
I think that it's important that you understand what your main loop is doing. Every frame, during VBlank, you are instructing the DMA to copy an array of 1024 bytes into the GBA's object attribute memory (OAM). Why?
The best answer is because you want to be able to change the physical attributes of your sprites (coordinates on screen, rotation parameters, etc.) during the VDraw period, then quickly copy your changes to the GBA's actual OAM during VBlank (which is more-or-less the only time you have in which to do so).
This means that the array you are using as your source for this copy-every-single-frame is representative of all 128 of your sprites. So you'd better make sure that it has the correct data for all of them, no?
Dan.
#14344 - Paul Shirley - Mon Jan 05, 2004 6:41 pm
removed
Last edited by Paul Shirley on Sun Mar 28, 2004 9:25 pm; edited 1 time in total
#14346 - poslundc - Mon Jan 05, 2004 6:50 pm
Uh... I don't see how setting attribute 0 to the double-size flag kills a sprite.
Dan.
#14347 - CcSoccer881 - Mon Jan 05, 2004 6:51 pm
Neither do I o.O
_________________
www.rsstudios.net
#14351 - DekuTree64 - Mon Jan 05, 2004 7:11 pm
Setting SD without rot/scale does disable the sprite. It's sort of a hardware 'feature' because logically you would never need to set SD unless you're in rot/scale mode, so they could save one bit of OAM data by giving it 2 uses.
Also, I've heard Nintendo's docs say to do it that way too. Preferred over just moving it offscreen, because even if it's down past 160 where it won't interfere with the max sprite pixels/line limit, the hardware still has to draw it, which I assume would take just a tiny hint more battery power, so you may as well save it by using SD instead.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#14352 - DiscoStew - Mon Jan 05, 2004 7:13 pm
I believe I know why he's using the DOUBLE flag to supposably erase the sprite. Doesn't the SIZE_DOUBLE flag require that you also set the ROTATION_FLAG also, since the only use for doubling the area size of the sprite is for allow more area for scaling/rotating? I guess the GBA doesn't take kindly to this setting and doesn't display that particular sprite at all. Besides, if the sprite were to use roation/scaling, the DOUBLE_SIZE flag would not erase it
I would say instead to set only Attribute1 to 240, which makes it off-screen, without allowing it to interfere with anything else.
.
.
(EDIT)
Looks like you got to it before I did, DekuTree64. Your answer is very logical considering about the Y-Pos about it still redrawing. Looks like I learned another thing today. But what about setting it's X-Pos to offscreen? Would that help too? It kind of stinks that it would still draw it, even when it is off-screen, because they might as well have had a longer screen on the GBA than just 160 pixels.
_________________
DS - It's all about DiscoStew
#14356 - johnny_north - Mon Jan 05, 2004 7:47 pm
Check to make sure that pcx2gba outputs the data in the correct format. If it outputs data appropriate for the bitmap mode (i.e. it just strips up a whole 64x64 sprite as one long sequential array) the output will not be appropriate for a sprite and will look much like what you describe when loaded into sprite and bg tiles. Make sure that you are getting output that is "tiled" (ordered in 8x8 chunks).
#14402 - Geoff - Tue Jan 06, 2004 1:05 am
johnny_north wrote: |
Check to make sure that pcx2gba outputs the data in the correct format. If it outputs data appropriate for the bitmap mode (i.e. it just strips up a whole 64x64 sprite as one long sequential array) the output will not be appropriate for a sprite and will look much like what you describe when loaded into sprite and bg tiles. Make sure that you are getting output that is "tiled" (ordered in 8x8 chunks). |
The output is like what you have described - one long array. Is it necessary to get it ordered in 8x8 chunks? I was under the impression that 1D meant 1D, not a 1D array of 8x8 tiles.
Moving the other sprites offscreen is what I am currently doing. Sorry, I should have mentioned, InitializeSprites() does this. Thanks for the tip about size_double though.
#14403 - sajiimori - Tue Jan 06, 2004 1:16 am
Quote: |
I was under the impression that 1D meant 1D, not a 1D array of 8x8 tiles.
|
A 1D sprite character layout is still built out of 8x8 sprite characters. Check the pern tutorials.
#14405 - johnny_north - Tue Jan 06, 2004 1:28 am
I can recommend gfx2gba v0.13 by marcus. It has a wonderful set of features for optimzing palettes and tile sets and for setting default tile sizes.
#14438 - Geoff - Tue Jan 06, 2004 6:01 pm
I got sprites to work. Yeah.
But I have one more unrelated problem. I'm having trouble loading a 512x512 text background. I'm using background 0 in mode 1. I have a pointer 'bg0.mapData' to the screen base block. I have a 1 dimensional array of tile indices (unsigned chars) that I need to read into this pointer. Cast and copy works good with a rotatable background, but for a text background of this size things are different, I am told. This is what I have:
source wrote: |
u16* temp = (u16*)map1; //tile indices (map data) in the map1 array
u16 tile_x,tile_y;
for(tile_y=0; tile_y<64; tile_y++) {
for(tile_x=0; tile_x<64; tile_x++) {
if(tile_y < 32) {
if(tile_x < 32) {
bg0.mapData[tile_x + tile_y*32] = temp[tile_x + tile_y*64];
} else{
bg0.mapData[(tile_x-32) + tile_y*32 + 32*32] = temp[tile_x + tile_y*64];
}
} else{
if(tile_x < 32) {
bg0.mapData[tile_x + (tile_y-32)*32 + 2*32*32] = temp[tile_x + tile_y*64];
} else {
bg0.mapData[(tile_x-32) + (tile_y-32)*32 + 3*32*32] = temp[tile_x + tile_y*64];
}
}
}
}
|
Well, it's not working, so I was wondering if someone had some advice for loading 512x512 text backgrounds.
#14442 - johnny_north - Tue Jan 06, 2004 7:27 pm
Post more data on the nature of the problem by exploring the following:
Are you turning on the background you wish to display?
Run the binary in Visual Boy Advance. Go under tools and look at the map, tile and palette data. If you haven't loaded the palette for tiles you won't see jack. If you see ties and you map, your problem lies with your display code.
If you are trying to load the palette an tiles etc, but nothing is showing in VBA, you have a problem with your pointers or data types. Review them for correctness.
#14443 - yaustar - Tue Jan 06, 2004 7:30 pm
in text backgrounds, you to load it into memory 256x256 chunks at a time. Top left, top right, bottom left, bottom right.
[1][2]
[3][4]
_________________
[Blog] [Portfolio]
#14539 - Geoff - Thu Jan 08, 2004 4:02 am
My problem seems to be fixed.
What seemed to fix it was changing the map data array from an array of unsigned chars to an array of unsigned shorts. I overlooked the fact that text-background tiles are 16 bit, unlike rotatable-background tiles which are 8 bit. I got rid of the cast into the u16 'temp' buffer and just copied straight from the array into map data.
Yes!