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 > PCX2SPRITE

#50525 - biubid_boy - Wed Aug 10, 2005 12:26 pm

I'm using Dovoto's PCX2SPRITE and a 256 colour .pcx file (8x32), but whenever I use it in my game, it comes up scrambled and weird coloured. My code is:

Code:
#include "gba.h"
#include "paddlersbg.h"
#include "ball.h"
#include "xxx.h"

void InitializeSprites(void);
void CopyOAM(void);
void MoveSprite(OAMEntry* sp, int x, int y);
void MoveBall(void);
void Movepaddleyellow(void);

OAMEntry sprites[128];

u16 xball = 30;
u16 yball = 50;
u16 xpaddleyellow = 10;
u16 ypaddleyellow = 10;

u8 ballDirection = 0;

u8 xMax = 148;
u8 yMax = 144;
u8 xMin = 8;
u8 yMin = 8;

int main() {

   u16 loop;

   SetMode(MODE_4 | BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D);

   for(loop = 0; loop < 256; loop++) {
   OBJ_PaletteMem[loop] = ballPalette[loop];
   }

   for (loop = 0; loop < 256; loop++) {
      BG_PaletteMem[loop]=paddlersbgPalette[loop];
   }

   for (loop = 0; loop < (120*160); loop++) {
      FrontBuffer[loop] = paddlersbgData[loop] ;
   }

   memcpy( (u16 *)0x06014000, &ballData, sizeof(ballData) );
   memcpy( (u16 *)0x06014100, &paddleyellowData, sizeof(paddleyellowData) );

   sprites[0].attribute0 = COLOR_256 | SQUARE | yball;
   sprites[0].attribute1 = SIZE_8 | xball;
   sprites[0].attribute2 = 512;

   sprites[1].attribute0 = COLOR_256 | TALL | ypaddleyellow;
   sprites[1].attribute1 = SIZE_32 | xpaddleyellow;
   sprites[1].attribute2 = 512 + 8;

   while(1)
   {
      MoveBall();
      Movepaddleyellow();
      MoveSprite(&sprites[0],xball,yball);
      MoveSprite(&sprites[1],xpaddleyellow,ypaddleyellow);
      WaitForVsync();
      CopyOAM();
   }

   return 0;

}

void InitializeSprites(void)
{
   u16 loop;
   for(loop = 0; loop < 128; loop++) {
      sprites[loop].attribute0 = 160;
      sprites[loop].attribute1 = 240;
   }
}

void CopyOAM(void)
{
   u16 loop;
   u16* temp;
   temp = (u16*)sprites;
   for(loop = 0; loop < 128*4; loop++)   {
      OAM_Mem[loop] = temp[loop];
   }
}

void MoveSprite(OAMEntry* sp, int x, int y)
{
   sp->attribute1 = sp->attribute1 & 0xFE00;
   sp->attribute1 = sp->attribute1 | x;

   sp->attribute0 = sp->attribute0 & 0xFF00;
   sp->attribute0 = sp->attribute0 | y;
}

void MoveBall(void) {
   if (ballDirection == 0 && xball < xMax && yball < yMax) {
      xball++;xball++;xball++;
      yball++;yball++;
   }
   if (ballDirection == 0 && (xball >= xMax || yball >= yMax )) {
      if (xball >= xMax) {
         ballDirection = 3;
      } else {
         ballDirection = 1;
      }
   }

   if (ballDirection == 1 && xball < xMax && yball > yMin) {
      xball++;xball++;xball++;
      yball--;yball--;
   }
   if (ballDirection == 1 && (xball >= xMax || yball <= yMin )) {
      if (xball >= xMax) {
         ballDirection = 2;
      } else {
         ballDirection = 0;
      }
   }

   if (ballDirection == 2 && xball > xMin && yball > yMin) {
      xball--;xball--;xball--;
      yball--;yball--;
   }
   if (ballDirection == 2 && (xball <= xMin || yball <= yMin )) {
      if (xball <= xMin) {
         ballDirection = 1;
      } else {
         ballDirection = 3;
      }
   }

   if (ballDirection == 3 && xball > xMin && yball < yMax) {
      xball--;xball--;xball--;
      yball++;yball++;
   }
   if (ballDirection == 3 && (xball <= xMin  || yball >= yMax)) {
      if (xball <= xMin) {
         ballDirection = 0;
      } else {
         ballDirection = 2;
      }
   }
}

void Movepaddleyellow(void)
{
   if(keyDown(KEY_DOWN) && ypaddleyellow < yMax - 24)
   {
       ypaddleyellow++;ypaddleyellow++;ypaddleyellow++;
   }
   if(keyDown(KEY_UP) && ypaddleyellow > yMin)
   {
       ypaddleyellow--;ypaddleyellow--;ypaddleyellow--;
   }
}


Anyone know why it keeps happening and how to fix it?

Thanks for any help,
Biubid_boy.

#50547 - Cearn - Wed Aug 10, 2005 5:47 pm

If graphics are scambled and/or garbled, it's often because a) the original bitmap wasn't in the bitdepth you thought it was, or b) the converter doesn't convert to the bitdepth you think it does. It could be that the pcx was 24bpp, and converter took it for 8bpp (which is technically true, as a 24bpp pcx uses 3 color planes), or maybe the converter defaults to 4bpp output. But it's difficult to say without seeing either the image or the exported data.

Another possibility is that the sprite attributes aren't set properly.
Quote:
Code:
   sprites[1].attribute0 = COLOR_256 | TALL | ypaddleyellow;
   sprites[1].attribute1 = SIZE_32 | xpaddleyellow;
   sprites[1].attribute2 = 512 + 8;

There are two types of tall 32 high sprites: 32x8 and 32x16. One of them uses the size parameter 0x8000 (SIZE_16), the other uses 0xC000 (SIZE_32). Guess which one belongs to 32x8.

Also, a few words of warning/recommendation for further programming:
  • Do NOT use bytes (s8/u8) or halfwords (s16/u16) for local variables unless you really, really have to. It does not save any memory, and actually reduces the speed of your algorithms. The GBA is a 32bit machine, so words (int/s32/u32) will work faster in pretty much every occasion (forum:5751).
  • Do NOT #include (graphics) data. That is, don't put data in header files, or include C files that have data in them. Compile the files with data separately and then link them, rather than include everything into main.c and compile that. This way, you'll avoid multiple definition errors, problems with having too much data in one C file, and cut down on compile time because you don't have to recompile the whole project with every little change (forum:2605, forum:2562, forum:3687).
  • Multiple ++ or -- statements should be using += or -=. "x++; x++" is both silly and horrible to look at; "x += 2" please.
  • Use the devkitARM toolchain rather than devkitadv, which hasn't been updated in ages. devkitARM is updated often, almost every other week it seems).
  • Be careful with memcpy() (forum:6461) and sizeof() (forum:6496).

I'll try to locate a few threads which deal with these problems, but I have to hurry right now. Feel free to search for these points yourself. A number of older tutorials have some horrible coding standards, which you could rather do without. One that don't have these kinds of problems are updated pern and *cough* my own, be sure to read those as well. Oh, and read the FAQ, if you haven't already.

ETA: linkies

#50647 - biubid_boy - Thu Aug 11, 2005 9:56 am

The sprite I am using is [Images not permitted - Click here to view it]
The result I get is [Images not permitted - Click here to view it].
Thanks for any help,
Biubid_boy.

#50649 - Cearn - Thu Aug 11, 2005 10:54 am

As I said earlier (well hinted at), for a 8x32 sprite you need SIZE_16, instead of SIZE_32.
The rest is a palette issue. I'm guessing it's because you use ballPalette for the object palette, and the palettes of the ball and paddle are different. There is one palette for all sprites, so your sprite graphics need to use the same palette. Or arrange the palettes in such a way that they can be put in the object palette without conflicting.

#50652 - biubid_boy - Thu Aug 11, 2005 11:43 am

Quote:
There is one palette for all sprites, so your sprite graphics need to use the same palette. Or arrange the palettes in such a way that they can be put in the object palette without conflicting.

How would i do that exactly?

#50669 - tepples - Thu Aug 11, 2005 4:44 pm

Cearn wrote:
There is one palette for all sprites, so your sprite graphics need to use the same palette. Or arrange the palettes in such a way that they can be put in the object palette without conflicting.

Specifically, use 4-bit tiles. This gives you 16 independent palettes each of 15 colors.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#50900 - biubid_boy - Sun Aug 14, 2005 11:52 am

Sorry, I can't seem to get it working. Could you tell me where I could find a tutorial for it. (I'm a newb).
Thanks for any help,
Biubid_boy.

#51991 - biubid_boy - Thu Aug 25, 2005 10:54 am

Anyone?

#51994 - Cearn - Thu Aug 25, 2005 11:12 am

Using the same palette for all graphics:
... just .... do it. Create a single bitmap with both the ball and paddles on it and convert the whole thing. Now there's one palette you can use for both sprites.

Using separate bitmaps with separate palettes:
Again, just do it. Let the ball bitmap use palette indices 0-15 (or 0-31 or whatever), let the paddle bitmap use palette entries 16-31. Convert both bitmaps. Copy the first 16 entries for the ball palette to OBJ-palette 0-15, copy entries 16-31 from the paddle palette to OBJ-palette 16-31.

#52287 - biubid_boy - Mon Aug 29, 2005 12:23 pm

I tried the first thing you said, and I got this .
Can you tell me how to fix it?
Thanks for any help,
Biubid_Boy.

#52296 - Cearn - Mon Aug 29, 2005 1:43 pm

When it comes to colors a screenshot is pretty much useless, the problem lies with the palette.

Bitmaps can be divided into true-color and palette images; in a palette image, the numbers in the pixels are not actual colors. The colors themselves are stored in a color look-up table (palette), and the pixel-values indicate which color should be displayed for that pixel. Then to change the colors, you change the palette, not the pixels.
On the GBA, you have two color tables: one for the backgrounds, one for the objects, each 256 entries long. When you export an image to 16 or 256 colors, the data of the xxxData array are not the actual colors, but just indices. There's usually a xxxPalette array for the actual colors. While a user may expect certain colors to go with a certain image, for paletted bitmap the colors and the pixeldata are completely separate. It's perfectly valid to use the palette of one bitmap as the color-table of another. The basic image is the same, just with different colors. And that's exactly the problem you're having here.
Quote:
Code:
   for(loop = 0; loop < 256; loop++) {
   OBJ_PaletteMem[loop] = ballPalette[loop];
   }

This loads the ball's colors, but if the palette of the paddle bitmap had different colors (and apparently it does), you'll get a paddle with ball colors. Because there's only a single palette for all objs, simply loading the paddle palette won't do you any good as in that case the ball would have use the paddle palette. To avoid this, you need to
a) Make sure the palettes of both bitmaps are the same, which is guaranteed if they're actually part of the same bitmap. Example.
b) If you must have multiple bitmaps and different palettes, make sure they never fight over the same palette indices. If both use, say, palette ranges 0-16 but expect different colors, you're screwed. Using different palette indices in making the bitmaps (or accounting for the difference in-game) would solve this ... as long as you also load only the part of the palettes that you need. And put them exactly where they are needed.
b ii) If you must have multiple bitmaps and different palettes, make sure they never fight over the same palette indices, part two. The color tables can also be interpreted as sixteen 16color palettes. For this, the data in VRAM should be 4 bits per pixel; this makes up the lower nybble of the palette index; the high nybble is taken from the top 4 bits of obj attribute 2. Load the 16 color palettes of different bitmaps into different sub-palettes, set attribute 2 and things should work.
Other methods exist too, of course.

Run demos from the various tutorial sites and check the various VBA viewers (especially palette and tile viewers) to understand what's going on. As for creating bitmaps, make sure you have a bitmap editor that lets you manipulate the palette directly. MS-Paint doesn't qualify for example.