New 32x game in development!
Moderator: KanedaFr
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
Re: New 32x game in development!
Hey Chilly, another question i have for you around sprites. specifically, animated sprites. So, i know that I can manually create my animations by have a single .bmp for every frame of that sprite i want to be animated. For example, let's say i have a hero sprite that has 4 positions in his animation for an idle animation. I can have 4 individual smaller .bmp files loaded up and then just draw the appropriate .bmp after a few tics to produce an animation effect.
My question is.... is that the right approach? Or should i have something (write something) that loads an entire .bmp file (let's say the hero's animation sprite sheet) and only loads up section of that .bmp file between tics to produce the animation?
Or does it really matter (either one larger .bmp file or a bunch of smaller ones with some custom code to write)
Thoughts?
My question is.... is that the right approach? Or should i have something (write something) that loads an entire .bmp file (let's say the hero's animation sprite sheet) and only loads up section of that .bmp file between tics to produce the animation?
Or does it really matter (either one larger .bmp file or a bunch of smaller ones with some custom code to write)
Thoughts?
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
Re: New 32x game in development!
You can find many of the 32X docs here:
https://segaretro.org/32X_official_documentation
You can find the hardware and software manuals for the SH2 in a number of places, but I have an arc of the two at mediafire:
https://www.mediafire.com/file/sjkp1vuk ... ls.7z/file
As to whether something is the "right approach" - that would depend on the program and the programmer. Everyone has their own way of doing things, and my way might not make as much sense to you as another way. It's one reason I tend rely of demos for console programming rather than simply telling people "this is how you do it". I'm always on the look out for open source projects. I like looking at many different approaches to problems as something might not have occurred to me but is clearly better. How I do something today may not be how I did it 10 years ago, and may not be how I do it 10 years from now.
That said, my first thought would be one sprite sheet per object, with animations being a rows, and different states (like rotations) being columns. Then just use an offset into the BMP to draw the current state and animation frame. The state would select the Y coord, and the animation frame count the X coord.
https://segaretro.org/32X_official_documentation
You can find the hardware and software manuals for the SH2 in a number of places, but I have an arc of the two at mediafire:
https://www.mediafire.com/file/sjkp1vuk ... ls.7z/file
As to whether something is the "right approach" - that would depend on the program and the programmer. Everyone has their own way of doing things, and my way might not make as much sense to you as another way. It's one reason I tend rely of demos for console programming rather than simply telling people "this is how you do it". I'm always on the look out for open source projects. I like looking at many different approaches to problems as something might not have occurred to me but is clearly better. How I do something today may not be how I did it 10 years ago, and may not be how I do it 10 years from now.
That said, my first thought would be one sprite sheet per object, with animations being a rows, and different states (like rotations) being columns. Then just use an offset into the BMP to draw the current state and animation frame. The state would select the Y coord, and the animation frame count the X coord.
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
Re: New 32x game in development!
Thanks Chilly for the info! So, i'm losing my mind here. Below I have written a routine that get's the sprite frame that I need (i've confirmed this within a simple draw sprite routine). but, when I try to turn it into a function and pass the return values to my original draw routine ...all hell breaks loose and doesn't look right. I'm thinking im missing something here? also, if i'm doing this way harder than it needs to be, just let me know, you won't hurt my feelings lol.Chilly Willy wrote: ↑Thu Feb 02, 2023 11:28 pm...
That said, my first thought would be one sprite sheet per object, with animations being a rows, and different states (like rotations) being columns. Then just use an offset into the BMP to draw the current state and animation frame. The state would select the Y coord, and the animation frame count the X coord.
The parameters section below i still need to move up as parameters; but for testing purposes I kept them were they are for now. My Draw Sprite routine requires an unsigned short* for the sprite data
Code: Select all
unsigned short* GetSpriteFrameFromSheet(u32* spriteBuffer, u16 spriteSheetWidth, u16 spriteSheetHeight)
{
// src sprite pointer
u32* src = spriteBuffer;
const u16 qwidth = spriteSheetWidth / 4;
const int dstStep = 80 - qwidth;
u16 row = spriteSheetHeight;
vu32* dst = &spriteBuffer[1];
//parameters
int spriteHeight = 32;
int spriteWidth = 32;
int spriteRowLocation = 1;
int spriteColLocation = 2;
//temp places holders such as current row and column
int currentRow = 0;
int currentCol = 0;
int widthCounter = 0;
//get the size of the spritesheet
int size = (qwidth * row);
while (size--)
{
//let's get to the right row
if (currentRow < (spriteRowLocation * spriteHeight))
{
//then we need to skip until at the rowPosition we want
*src++;
//*dst++;
widthCounter++;
if (widthCounter == qwidth)
{
currentRow++;
widthCounter = 0;
}
//continue looping
continue;
}
//Let's get to the right column now
if (currentCol != spriteColLocation)
{
//Then we need to skip until at the colPosition we want
*src++;
//*dst++;
widthCounter++;
if (widthCounter == (spriteColLocation * spriteWidth) / 4)
{
currentCol = spriteColLocation;
}
//continue looping
continue;
}
//safe to increment widthcounter
widthCounter++;
//if we get inside here, then we have written the sprite data to the buffer and need to skip the rest of the row
if (widthCounter >= ((spriteColLocation * spriteWidth) + spriteWidth) / 4)
{
//We have written the width of the sprite. we then skip until the end of the width
*src++;
//*dst++;
if (widthCounter == qwidth) //end of current row
{
widthCounter = 0;
currentRow++;
if (currentCol > 0) currentCol = 0; // back to start
}
//if we have hit the last row we need to write out...break loop?
if (currentRow > (spriteRowLocation * spriteHeight) + spriteHeight)
break;
//continue looping
continue;
}
//no more conditions, free to write to buffer
*dst++ = *src++;
}
return &dst;
}
Code: Select all
unsigned short* tempShip = &GetSpriteFrameFromSheet(sprite_sheet, 320, 202);
draw_sprite(npc_sprite_currentX_position-currentMapX_position, 200-currentMapY_position, 32, 32, tempShip, DRAWSPR_PRECISE, 1);
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
Re: New 32x game in development!
Unless you're caching the sprite in ram somewhere, you probably want to draw directly from the sprite sheet. Assuming the sheet is packed at the dimensions of the sprite, the source would be the sheet + state * sprH * shtW + frame * sprW, and the stride would be shtW - sprW. Just do a normal block draw to the cache location, or the screen if drawing straight from the sheet. Something like
Of course, if the sprite sheet is the pixel array of a BMP, you'd need to reflect that it's upside down and do the y part upside down. If you're drawing to the screen instead of a cache buffer, you'd add the screen stride to dst right after adding the sheet stride to src. But that's pretty much the simple way of handling the sprite sheet.
Code: Select all
u8 *src, *dst;
int x, y;
src = sheet + state * sprH * shtW + frame * sprW;
dst = buffer;
for (y = 0; y < sprH; y++)
{
for (x = 0; x < sprW; x++)
*dst++ = *src++;
src += shtW - sprW;
}
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
Re: New 32x game in development!
Im going to play with this some tonight and tomorrow Chilly. I guess im slightly lost on a few spots if you don’t mind helping a little further?:)Chilly Willy wrote: ↑Sat Feb 04, 2023 12:15 amUnless you're caching the sprite in ram somewhere, you probably want to draw directly from the sprite sheet. Assuming the sheet is packed at the dimensions of the sprite, the source would be the sheet + state * sprH * shtW + frame * sprW, and the stride would be shtW - sprW. Just do a normal block draw to the cache location, or the screen if drawing straight from the sheet. Something likeOf course, if the sprite sheet is the pixel array of a BMP, you'd need to reflect that it's upside down and do the y part upside down. If you're drawing to the screen instead of a cache buffer, you'd add the screen stride to dst right after adding the sheet stride to src. But that's pretty much the simple way of handling the sprite sheet.Code: Select all
u8 *src, *dst; int x, y; src = sheet + state * sprH * shtW + frame * sprW; dst = buffer; for (y = 0; y < sprH; y++) { for (x = 0; x < sprW; x++) *dst++ = *src++; src += shtW - sprW; }
1). State- earlier you mentioned this being the Y coordinate. So lets say i have a 4 x 4 sprite sheet. That would be 16 different sprites. My State would say “which row do i want 0-3” and Frame would say “which column 0-3”. Correct?
2). Frame - same as above
3). Would my buffer for dst be a memory allocation if im not directly drawing it at this point? Im using Vic’s sprite draw function so i was just planning on pass his function this cropped sprite from the sprite sheet as he is looking for uint8_t* to that data. Would my memory allocation look like this? dst = (u8*)malloc((crop_x * crop_width + crop_y * crop_height) * sizeof(u8));
4). Src being the sheet. Are you meaning just passing my images.s reference to the spritesheet.bmp via .incbin? So would be like below:
Extern u8* spritesheet;
…
Src = spritesheet
5). If i do allocate memory using malloc im guessing i need to call free(pointer); as soon as im done drawing correct?
6). Related to 3 & 5 is there a better place to store dst while i pass it to Vic’s drawing routine? For example: dst = &MARS_OVERWRITE_IMG;
Re: New 32x game in development!
As of now, the drawing routines in yatssd do not support arbitary stride/pitch for sprites. The stride would need to be passed as a new field in drawsprcmd_t and the routines in draw_inc.h would have to take it into account.
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
Re: New 32x game in development!
Also, I've put together I believe what Chilly recommended and still not working unfortunately (maybe because of Vic's post stating that stride isn't implemented in his draw routine?)
Any thoughts?
Also, it runs for about a few seconds and freezes up. Seems like my malloc isn't getting free'd up even though i thought i was freeing it up after the draw?
All of this is a maybe in vain though if Vic's routine doesn't support stride for sprites (maybe I'm wrong with my understanding isn't the stride just to advance the src pointer to finish off the row since we drew that row's worth of pixel data?).
Worst case scenario, I can just punt the football here and just have a single .bmp for each frame of a sprite animation. So in my spritesheet of 4x4 I would have 16 different .bmp files to work with and load them up accordingly.
As for implemetning stride in Vic's routines ... theres a lot of them and I'm not skilled enough to do that yet
Any thoughts?
Code: Select all
int crop_x, crop_y, crop_width, crop_height;
crop_height = 32;
crop_width = 32;
crop_y = 4;
crop_x = 4;
int src_width = 320;
sprite_sheet = (unsigned short*)((int)pal + 0x431) + crop_y * crop_height * src_width + crop_x * crop_width;
unsigned short* output = (unsigned short *)malloc((crop_x * crop_width + crop_y * crop_height) * sizeof(unsigned short));
//short* output = &MARS_SDRAM;
for (int yy = 0; yy < crop_height; yy++)
{
for (int xx = 0; xx < crop_width; xx++)
{
*output++ = *sprite_sheet++;
}
sprite_sheet += src_width - crop_height;
}
draw_sprite(npc_sprite_currentX_position-currentMapX_position, npc_sprite_currentY_position-currentMapY_position, 32, 32, output, DRAWSPR_PRECISE, 1); //test
free(output);
All of this is a maybe in vain though if Vic's routine doesn't support stride for sprites (maybe I'm wrong with my understanding isn't the stride just to advance the src pointer to finish off the row since we drew that row's worth of pixel data?).
Worst case scenario, I can just punt the football here and just have a single .bmp for each frame of a sprite animation. So in my spritesheet of 4x4 I would have 16 different .bmp files to work with and load them up accordingly.
As for implemetning stride in Vic's routines ... theres a lot of them and I'm not skilled enough to do that yet
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
Re: New 32x game in development!
Yes.matthewnimmo wrote: ↑Sat Feb 04, 2023 12:58 am1). State- earlier you mentioned this being the Y coordinate. So lets say i have a 4 x 4 sprite sheet. That would be 16 different sprites. My State would say “which row do i want 0-3” and Frame would say “which column 0-3”. Correct?
2). Frame - same as above
You can malloc it, or just use an array.3). Would my buffer for dst be a memory allocation if im not directly drawing it at this point? Im using Vic’s sprite draw function so i was just planning on pass his function this cropped sprite from the sprite sheet as he is looking for uint8_t* to that data. Would my memory allocation look like this? dst = (u8*)malloc((crop_x * crop_width + crop_y * crop_height) * sizeof(u8));
u8 buffer[width * height];
Then dst = buffer;
Not the BMP itself, but the pixel data in the BMP. I believe that's right after the palette.4). Src being the sheet. Are you meaning just passing my images.s reference to the spritesheet.bmp via .incbin? So would be like below:
Extern u8* spritesheet;
…
Src = spritesheet
Yes. Remember to be careful as you don't really have a lot of ram to play with. Look at the cache code in d32xr to get an idea of how Vic handles cached graphics in ram.5). If i do allocate memory using malloc im guessing i need to call free(pointer); as soon as im done drawing correct?
You only have a few choices.... embedded in rom, a buffer in ram, or in the frame buffer itself offscreen.6). Related to 3 & 5 is there a better place to store dst while i pass it to Vic’s drawing routine? For example: dst = &MARS_OVERWRITE_IMG;
Some edits...
Code: Select all
int crop_x, crop_y, crop_width, crop_height;
crop_height = 32;
crop_width = 32;
crop_y = 4;
crop_x = 4;
int src_width = 320;
sprite_sheet = (unsigned char*)((int)pal + 1024 + crop_y * crop_height * src_width + crop_x * crop_width);
unsigned char *output = (unsigned char *)malloc(crop_width * crop_height);
for (int yy = 0; yy < crop_height; yy++)
{
for (int xx = 0; xx < crop_width; xx++)
{
*output++ = *sprite_sheet++;
}
sprite_sheet += src_width - crop_width;
}
draw_sprite(npc_sprite_currentX_position-currentMapX_position, npc_sprite_currentY_position-currentMapY_position, 32, 32, output, DRAWSPR_PRECISE, 1); //test
free(output);
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
Re: New 32x game in development!
As always thank you Chilly! And Vic (if you're watching this thread still...been bugging him through discord ). So I believe the shorts and the malloc size being wrong was causing my freezes....that no longer happens, so that's great! I've implemented the changes but unfortunately i'm still getting a pixelated blob square instead of a ship sprite flying in all its glory
Below is the code that is running now. The pal from earlier was actually the spritesheet.bmp file that I originally was just taking the pal from ... i was lazy and just copied that (so it should have just been the bitmap data not the palette). I went ahead and corrected that below to just the sprite_sheet info so that it's less confusing.
Also after chatting with Vic, i've been trying to extend his draw sprite functionality to include stride. I think I had cornered the change within his FUNC functions, but still working out those details there. He mentioned changing ts += hsw; to something like ts += stride >> DUINT_RSH
But even after those changes, something still isn't right. I'm sure i'm just messing it up Thanks again! Anymore pointers are always greatly appreciated.
Below is the code that is running now. The pal from earlier was actually the spritesheet.bmp file that I originally was just taking the pal from ... i was lazy and just copied that (so it should have just been the bitmap data not the palette). I went ahead and corrected that below to just the sprite_sheet info so that it's less confusing.
Code: Select all
int crop_x, crop_y, crop_width, crop_height;
crop_height = 32;
crop_width = 32;
crop_y = 4;
crop_x = 4;
int src_width = 320;
unsigned char *src = (unsigned char*)(sprite_sheet + crop_y * crop_height * src_width + crop_x * crop_width);
unsigned char *output = (unsigned char *)malloc(crop_width + crop_height);
for (int yy = 0; yy < crop_height; yy++)
{
for (int xx = 0; xx < crop_width; xx++)
{
*output++ = *src++;
}
src += src_width - crop_width;
}
draw_sprite(npc_sprite_currentX_position-currentMapX_position, npc_sprite_currentY_position-currentMapY_position, 32, 32, output, DRAWSPR_PRECISE, 1); //test
free(output);
But even after those changes, something still isn't right. I'm sure i'm just messing it up Thanks again! Anymore pointers are always greatly appreciated.
Re: New 32x game in development!
I've added support for custom stride to my sprite drawing routines. Check out the new function prototypes in draw.h, usage example - in main.c. Cheers!
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
Re: New 32x game in development!
Make sure your artwork is properly aligned. From the code, it's 320 x whatever, and uses a 32x32 cell. If your objects are 32x32, but not in a 32x32 cell of the picture, you're going to have a problem.
Also,
malloc(crop_width + crop_height);
that + should be a *. Not sure if that was you or me, but it's a problem as you're not allocating enough space.
Also,
malloc(crop_width + crop_height);
that + should be a *. Not sure if that was you or me, but it's a problem as you're not allocating enough space.
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
Re: New 32x game in development!
Oh good call on the +. Yes the sprite sheet is some test 320x202 and the speites are not fully aligned but that should be easy to fix via aseprite. So im expecting some of my sprites to be a little off. Im hoping that these changes will at least give me mis aligned sprites instead of a bunch of random pixels lolChilly Willy wrote: ↑Sun Feb 05, 2023 3:17 pmMake sure your artwork is properly aligned. From the code, it's 320 x whatever, and uses a 32x32 cell. If your objects are 32x32, but not in a 32x32 cell of the picture, you're going to have a problem.
Also,
malloc(crop_width + crop_height);
that + should be a *. Not sure if that was you or me, but it's a problem as you're not allocating enough space.
Thank you both Chilly and Vic! Ill be integrating this sometime today/tonight and hopefully reporting good progress in my next post!
-
- Very interested
- Posts: 87
- Joined: Thu Jan 07, 2021 8:04 pm
Re: New 32x game in development!
hmm, ok. So I believe I have the latest Yatssd integrated with the stride implementation; but still not getting my sprites to show up. Instead, still pixelated blobs. So, I'm going through a few more steps here to see what you guys think. Perhaps i'm missing something else here.
Here is the line of code that brings in the sprite sheet .bmp file. This file was originally just used as the palette for all my sprites, but since it's the spritesheet i'm using it for this test.
Below is where I'm pulling out just the bitmap information. If I just draw this entire sprite, it's flipped vertically.
Now, below is the code we've been playing with. I changed from malloc to an array as well.
Now below are some screen shots on what is going on. Ignore the background colors as I know they are off and that's ok, I haven't updated the palette with the new tilemap that i created. You can see the sprites on the screen with the on in the center that is scaling that are all based upon Vic's example of drawing sprites. These sprites are just from a single .bmp and not from the sprite sheet. The square pixelated blob is the one sprite that i'm attempting to drawing from the sprite sheet routine from above.
Now below is what things look like when i draw that same sprite that should be clipped at the edge of the screen (I think something is still not quite right with the clipping with stride introduced). The sprite was suppose to be on the left side of the screen and clipped; but it starts stretching and begins showing up on the right side of the screen.
I really appreciate both your guys' help Chilly and Vic. GREATLY appreciate you vic going in and adding the stride functionality, so please don't read anything from this but appreciation and gratitude Any thoughts? I'm going to keep playing around some more tonight just in case i'm missing something.
Oh! And Vic. Below is a screen shot of the sprites being drawn (none sprite sheet) with the draw mode of DRAWSPR_OVERWRITE | DRAWSPR_PRECISE | DRAWSPR_VFLIP (Or DRAWSPR_HFLIP). You'll see these fine little verticle lines that appear when scrolling horizontally (not vertically though)
Here is the line of code that brings in the sprite sheet .bmp file. This file was originally just used as the palette for all my sprites, but since it's the spritesheet i'm using it for this test.
Code: Select all
extern char pal[];
Code: Select all
unsigned short* sprite_sheet = (unsigned short*)((int)pal + 0x431); //gets the bitmap data
Code: Select all
int crop_x, crop_y, crop_width, crop_height;
crop_height = 32;
crop_width = 32;
crop_y = 4;
crop_x = 4;
int src_width = 320;
unsigned char *src = (unsigned char*)(sprite_sheet + crop_y * crop_height * src_width + crop_x * crop_width);
uint8_t buffer[crop_width * crop_height];
unsigned char* output = buffer;
for (int yy = 0; yy < crop_height; yy++)
{
for (int xx = 0; xx < crop_width; xx++)
{
*output++ = *src++;
}
src += src_width - crop_width;
}
draw_sprite(npc_sprite_currentX_position-currentMapX_position, npc_sprite_currentY_position-currentMapY_position, 32, 32,src_width - crop_width, output, DRAWSPR_OVERWRITE | DRAWSPR_PRECISE); //test
Now below is what things look like when i draw that same sprite that should be clipped at the edge of the screen (I think something is still not quite right with the clipping with stride introduced). The sprite was suppose to be on the left side of the screen and clipped; but it starts stretching and begins showing up on the right side of the screen.
I really appreciate both your guys' help Chilly and Vic. GREATLY appreciate you vic going in and adding the stride functionality, so please don't read anything from this but appreciation and gratitude Any thoughts? I'm going to keep playing around some more tonight just in case i'm missing something.
Oh! And Vic. Below is a screen shot of the sprites being drawn (none sprite sheet) with the draw mode of DRAWSPR_OVERWRITE | DRAWSPR_PRECISE | DRAWSPR_VFLIP (Or DRAWSPR_HFLIP). You'll see these fine little verticle lines that appear when scrolling horizontally (not vertically though)
Re: New 32x game in development!
Change your drawing code to the following:
Code: Select all
int crop_x, crop_y, crop_width, crop_height;
crop_height = 32;
crop_width = 32;
crop_y = 4;
crop_x = 4;
int src_width = 320;
unsigned char *src = (unsigned char*)(sprite_sheet + crop_y * src_width + crop_x);
draw_sprite(npc_sprite_currentX_position-currentMapX_position, npc_sprite_currentY_position-currentMapY_position, crop_width-crop_x, crop_height-crop_y, src_width, src, DRAWSPR_OVERWRITE | DRAWSPR_PRECISE); //test