#2253 - loopy - Fri Jan 31, 2003 8:35 pm
There's something I'm missing and I'm not sure what it is:
I wrote a dynamic sprite allocator which loads character data into a free slot automatically. For this I'm using an array of 1024 bytes to indicate whether or not a certain 8x8 block is free.
Everything seems to work fine, except that when I want to set the character name of sprite attribute 2 (in order for the sprite to point to the right character data) I have to multiply the index I used in my byte array by 2, regardless of whether I'm using 256 or 16 color sprites.
Does anyone know why this is? Maybe it just works under the simple test conditions I'm using now. Time will tell. I hate "magic code" that works without understanding.
I'm programming in C.
#2254 - Splam - Fri Jan 31, 2003 8:53 pm
No idea without seeing the code, the only thing I can think is you've messed up somewhere in your allocation code and aren't taking into account the actual SIZE difference with 16 and 256 colour ie you're ALWAYS putting 16 colour ones on even boundaries even though you could put them on odd too if there was a gap for them (no 256 colour one in the previous even slot). I know you mentioned "regardless of whether I'm using 256 or 16 color sprites" so you obviously know the difference with how they work but it seems to be the only thing you could be doing wrong.
#2255 - loopy - Fri Jan 31, 2003 9:31 pm
Ok, here's all of (I think) the relevant code. It's cut and pasted from several files so bear with me:
Code: |
u8 spriteAllocMap[1024];
u16 LoadSprite(u16 colors, const u16 *spriteData, u8 sizeX, u8 sizeY)
{
u16 index, loop, spriteIndex;
u8 slotFound, tiles;
if (colors == 16) tiles = (sizeX * sizeY) / 128;
else tiles = (sizeX * sizeY) / 64;
// search for a free spot in the sprite allocation map
index = 0;
slotFound = 0;
while (slotFound == 0)
{
slotFound = 1;
if (spriteAllocMap[index] != SPRALLOC_UNUSED)
{
index++; // this slot is used, keep moving
slotFound = 0;
}
else // the slot was free; lets see if there's enough space for the sprite
{
for (loop = 1; loop < tiles; loop++)
{
if (spriteAllocMap[index + loop] != SPRALLOC_UNUSED)
{
if (slotFound != 0) index += tiles;
slotFound = 0;
}
}
}
}
// we found a spot for our sprite, so let's allocate it
spriteAllocMap[index] = SPRALLOC_USED;
for (loop = 1; loop < tiles; loop++)
{
spriteAllocMap[index + loop] = SPRALLOC_CONTINUE;
}
spriteIndex = index << 1;
index *= 32; // each character is 32 bytes
// load images into character memory
if (colors == 16)
for(loop = 0; loop < (sizeX * sizeY >> 2); loop++) { OAMdata[index++] = spriteData[loop]; }
else
for(loop = 0; loop < (sizeX * sizeY >> 1); loop++) { OAMdata[index++] = spriteData[loop]; }
return spriteIndex;
}
void LoadSamusSprites()
{
LoadSpritePalette(palSamus, 0, 16);
p1 = LoadSprite(16, sprSamusFaceFwd, 16, 32);
p2 = LoadSprite(256, sprSamusFaceFwd2, 16, 32);
p3 = LoadSprite(16, sprSamusRunTop1, 16, 16);
SetSpriteAttribute(0, 0, SPR_COLOR_256 | SPR_TALL | 20);
SetSpriteAttribute(0, 1, SPR_SIZE_32 | 20);
SetSpriteAttribute(0, 2, p2 | SPR_PRIORITY(3));
}
|
One thing I think it's missing that you mentioned is that this will try loading 256 color sprites on odd boundaries if it can - I'll can fix that later.
Anyway, LoadSprite() is supposed to put a sprite into a free memory slot and return the character name which, if I understand correctly, SHOULD be the same as the index into spriteAllocMap[] which I've created.
I test out the function in LoadSamusSprites(), the last line of which contains a reference to p2, a previously allocated sprite. This code works for p1, p2, and p3.
The point of confusion is in LoadSprite() where I have to say "spriteIndex = index << 1;" which is effectively multiplying by 2 in order to return a result compatible with sprite attribute 2 shown above.
There are a bunch of functions and things not defined here but I'm sure you get the gist of it. Maybe this is all just confusing - my coding isnt' so great.
#2265 - loopy - Fri Jan 31, 2003 10:54 pm
Well, you're right - I'm always putting my 16 color ones on an even boundary according to VisualBoy Advance's tile viewer. Now I just need to figure out why and how.
#2266 - Herg - Fri Jan 31, 2003 10:57 pm
It's the end of a long day, and my brain hasn't cooled off yet, but shouldn't a 256 8x8 tile be 64 bytes?
#2270 - Splam - Fri Jan 31, 2003 11:20 pm
Just a quick thought that if you're using 1d mapping I don't think there is any restriction to the positioning of 256 colour sprites, you can put them at odd numbers if you want, it's only 2d mapping where this isn't allowed.
I'll have a look through that code you posted as soon as I've finished some I'm writing else I'll just confuse myself with loads of different code to look at ;)
#2271 - Splam - Fri Jan 31, 2003 11:26 pm
Herg wrote: |
It's the end of a long day, and my brain hasn't cooled off yet, but shouldn't a 256 8x8 tile be 64 bytes? |
Yes..
Hmm just noticed that the original tiles calculation can go wrong. If you enter with an 8x8 16colour sprite then /128 you end up with 0 but the sprite size (data) is 32 bytes. I can see what you're trying to do but it will fail on small sprite allocations.
#2275 - loopy - Sat Feb 01, 2003 12:01 am
Ok, I totally reworked the code. I changed quite a bit and now it all works fine. For the curious, the new code is below. One thing I was missing was that the OAMdata pointer is a 16-bit pointer where I was doing a lot of math on bytes. Fixed it.
Thanks for everyone's help - I just needed to talk myself through it I guess. And Splam, I will test out loading on an odd boundary. I redid that part before you posted again.
Code: |
u16 LoadSprite(u16 colors, const u16 *spriteData, u8 sizeX, u8 sizeY)
{
u16 index, loop, spriteIndex;
u8 slotFound, tiles, step;
// how many characters does the sprite consume?
// 256-color sprites consume 2 tiles per 8 x 8 block.
// "step" is used to crawl through the array at a different resolution
// (256-color sprites can only be allocated on an even boundary)
if (colors == 16)
{
tiles = (sizeX * sizeY) / 64;
step = 1;
}
else
{
tiles = (sizeX * sizeY) / 32;
step = 2;
}
// search for a free spot in the sprite allocation map
index = 0;
slotFound = 0;
while (slotFound == 0)
{
slotFound = 1;
if (spriteAllocMap[index] != SPRALLOC_UNUSED)
{
index += step; // this slot is used, keep moving
slotFound = 0;
}
else // the slot was free; lets see if there's enough space for the sprite
{
for (loop = 1; loop < tiles; loop++)
{
if (spriteAllocMap[index + loop] != SPRALLOC_UNUSED)
{
if (slotFound != 0) index += tiles;
slotFound = 0;
}
}
}
}
// we found a spot for our sprite, so let's allocate it
spriteAllocMap[index] = SPRALLOC_USED;
for (loop = 1; loop < tiles; loop++)
{
spriteAllocMap[index + loop] = SPRALLOC_CONTINUE;
}
spriteIndex = index;
index *= 16;
// load images into character memory
for(loop = 0; loop < tiles * 16; loop++) { OAMdata[index++] = spriteData[loop]; }
return spriteIndex;
}
|
#2276 - loopy - Sat Feb 01, 2003 12:03 am
Oh, BTW Splam, size is in pixels. Forgot to mention that important bit.
Also, I just confirmed that yes, 256 color sprites don't need to be on even boundaries when in 1D mode. Again, thanks for the support, you guys! Just being able to write my problem out helped.
#2279 - Splam - Sat Feb 01, 2003 12:15 am
Yup, I sussed the x and y were pixel sizes but they way you had it b4 would've been 16 colour 8x8=64 then /128 ouch ;) Code as it is now should be fine with that too though.