New 32x game in development!

Importante releases or news for the communauty

Moderator: KanedaFr

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Thu Feb 02, 2023 10:42 pm

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?

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: New 32x game in development!

Post by Chilly Willy » Thu Feb 02, 2023 11:28 pm

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.

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Fri Feb 03, 2023 5:22 am

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

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;
}
And below is the code i'm using to call my function afterwords. Perhaps i'm just in pointer hell and I'm needing a second pair of eyes lol? sprite_sheet is another unsigned short* with my sprite sheet bitmap data.

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);

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: New 32x game in development!

Post by Chilly Willy » Sat Feb 04, 2023 12:15 am

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

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;
    }
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.

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Sat Feb 04, 2023 12:58 am

Chilly Willy wrote:
Sat Feb 04, 2023 12:15 am
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

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;
    }
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.
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?:)

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;

Vic
Interested
Posts: 27
Joined: Wed Nov 03, 2021 6:01 pm

Re: New 32x game in development!

Post by Vic » Sat Feb 04, 2023 9:32 am

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.

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Sat Feb 04, 2023 4:40 pm

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?

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);
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 :(

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: New 32x game in development!

Post by Chilly Willy » Sun Feb 05, 2023 1:05 am

matthewnimmo wrote:
Sat Feb 04, 2023 12:58 am
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
Yes.
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));
You can malloc it, or just use an array.

u8 buffer[width * height];

Then dst = buffer;
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
Not the BMP itself, but the pixel data in the BMP. I believe that's right after the palette.
5). If i do allocate memory using malloc im guessing i need to call free(pointer); as soon as im done drawing correct?
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.
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;
You only have a few choices.... embedded in rom, a buffer in ram, or in the frame buffer itself offscreen.

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);
I'm assuming pal is the start of the palette in the BMP. The end will be pal + 256*4. Your crashes could be from anything from the wrong size in the malloc to the constant use of short pointers when your data is only byte size.

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Sun Feb 05, 2023 5:14 am

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.

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);
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.

Vic
Interested
Posts: 27
Joined: Wed Nov 03, 2021 6:01 pm

Re: New 32x game in development!

Post by Vic » Sun Feb 05, 2023 8:40 am

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!

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Sun Feb 05, 2023 1:43 pm

Vic wrote:
Sun Feb 05, 2023 8:40 am
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!
Wow! Thank you soooo much. Ill be pulling down the latest and integrating:)

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: New 32x game in development!

Post by Chilly Willy » Sun Feb 05, 2023 3:17 pm

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.

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Sun Feb 05, 2023 4:25 pm

Chilly Willy wrote:
Sun Feb 05, 2023 3:17 pm
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.
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 lol

Thank you both Chilly and Vic! Ill be integrating this sometime today/tonight and hopefully reporting good progress in my next post!

matthewnimmo
Very interested
Posts: 87
Joined: Thu Jan 07, 2021 8:04 pm

Re: New 32x game in development!

Post by matthewnimmo » Mon Feb 06, 2023 3:55 am

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.

Code: Select all

extern char pal[];
Below is where I'm pulling out just the bitmap information. If I just draw this entire sprite, it's flipped vertically.

Code: Select all

unsigned short* sprite_sheet = (unsigned short*)((int)pal + 0x431); //gets the bitmap data
Now, below is the code we've been playing with. I changed from malloc to an array as well.

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 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.
16.png
16.png (47.8 KiB) Viewed 67405 times
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.
17.png
17.png (45.14 KiB) Viewed 67405 times
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)
18.png
18.png (31.88 KiB) Viewed 67405 times

Vic
Interested
Posts: 27
Joined: Wed Nov 03, 2021 6:01 pm

Re: New 32x game in development!

Post by Vic » Mon Feb 06, 2023 8:05 am

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
		

Post Reply