This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Tool for generating sprite definitions

Tool for generating sprite definitions
by on (#76421)
I have been thinking about making a tool to convert images to NES (meta)sprite definitions. Input is two files, the image file and a palette file. Output is the metasprite layout (tile, colorset and relative coordinates for each hardware sprite) and the corresponding CHR tiles. Palette file is needed to properly handle "layered" sprites (i.e. sprites on top of others to get more colors).

Generating optimal sprite definitions is not a trivial problem for layered sprites when many colorsets share the same colors. For example, if we have a sprite with size 16x8 which contains a horizontally centered 8x8 square, it wouldn't make sense to generate two h/w sprites out of it. I have yet to come up with a good algorithm for this.

As an example, the palette file could be something like this (4 colorsets, 3 colors each):
Image

And the image to be converted something like this:
Image

I was wondering if anybody has done a tool like this before?

by on (#76425)
I thought about making something like this, but I gave up when I started thinking about all the complications, like the one you mentioned about layering.

One thing I didn't see in your post was the reference for the relative coordinates... Some people like the sprite coordinates to be relative to the top left corner of the meta-sprite (so that all coordinates are positive, but then you can't vary the sprite size), others want the reference point to be at the center of the sprite, and so on. Personally, I use a horizontally centered point at the bottom of the sprites, since that is the primary point for surface collisions. You'd need a way to specify that in the images.

Another thing to consider is how to encode the coordinates. After some tweaking to my meta-sprite rendering routine, I was able to make it much faster if I didn't use 2's complement for the coordinates. Instead I have 0 = -128, 128 = 0 and 255 = 127. But I guess that will depend on the routine you use for rendering the definitions, which you will probably supply with the tool, so no worries.

by on (#76428)
tokumaru wrote:
One thing I didn't see in your post was the reference for the relative coordinates... Some people like the sprite coordinates to be relative to the top left corner of the meta-sprite (so that all coordinates are positive, but then you can't vary the sprite size), others want the reference point to be at the center of the sprite, and so on. Personally, I use a horizontally centered point at the bottom of the sprites, since that is the primary point for surface collisions. You'd need a way to specify that in the images.

Yeah that is true and I gave it some thought. I initially thought about having the reference point be at upper left and the user would have to manually specify the "hotspot" (and possibly some other points, if needed) in animation editor (or whatever) but now that you mentioned it it definitely would be more user friendly to be able to define it in the image itself... I just have no idea how it could be done in an artist friendly way, short of reading a layered image format.

EDIT: There's actually an option in Photoshop to export all layers to individual files -- this could be useful.

What do you mean about not being able to vary the sprite size with origo at (0, 0)?

Quote:
Another thing to consider is how to encode the coordinates. After some tweaking to my meta-sprite rendering routine, I was able to make it much faster if I didn't use 2's complement for the coordinates. Instead I have 0 = -128, 128 = 0 and 255 = 127. But I guess that will depend on the routine you use for rendering the definitions, which you will probably supply with the tool, so no worries.

Yeah, that's only a matter of how the definitions are exported, and if I release the tool I'll probably make it configurable. But thanks for the tip. :)

by on (#76430)
About the priority problem, my engine toggles between mazing the sprites "fowrard" and "backwards" every frame, so that it does sprite cycling.

So if any sprite overlap in a single metasprite, it will look flickery, so I never do that intentionally.
(the reason I do it this way is so that priority between different metasprites is preserved)

About the signed/unsigned thing I think it's not a big issue. Just support coordinates from -128 to +127 for both axises. This will work with people dealing with unsigned coordinates too, they will just have to be very careful not to put any unsigned value in.

by on (#76442)
thefox wrote:
I just have no idea how it could be done in an artist friendly way, short of reading a layered image format.

I just thought of another way that's pretty hackish, but if the hotspot is the only extra information you want to put in the image you could probably use the palette file for this. At the end of the palette file, you could specify a key color that will be used to specify the hotspot, and after that the actual color the pixel is supposed to have (that way you can first detect the hotspot and then restore the pixel). The key color should only be used in one pixel of the image. If that information is not provided, you could just default to using the top left corner.

Quote:
What do you mean about not being able to vary the sprite size with origo at (0, 0)?

Say your character is 16x32 pixels large, but he has an ability that causes his neck to stretch and his height goes up to 48 pixels. If you were to use the top left corner as a reference, because of the stretched neck frames you'd have to treat all frames as 16x48, even though in most of the frames there's nothing up there (I know that no tiles or sprites will be wasted, but it's still weird). What I mean is that you can't easily resize your character to the left or up if the relative coordinates are always positive, so you have to think ahead and decide on the reference point that will work for the largest animation frame of each character before generating all the definitions, because changing that later will be annoying.

Bregalad wrote:
About the priority problem, my engine toggles between mazing the sprites "fowrard" and "backwards" every frame, so that it does sprite cycling.

Yeah, in order to use layering you have to use a sprite cycling method that supports it. The fact that the tool supports layering doesn't mean you have to use it though, so it's not a problem. Just don't draw layered sprites.

Quote:
About the signed/unsigned thing I think it's not a big issue. Just support coordinates from -128 to +127 for both axises.

I didn't say it was a problem, just that working with negative coordinates was slower (because of flipping and detecting whether sprites go off screen), and that my solution was to "tweak" the meaning of the relative coordinates so that only positive values would be used, but still allowing sprites to be placed at the left and above the reference point. Because of this, it would be nice if the tool allowed some custom function to be applied to the coordinates instead of spitting straight 2's complement. In my case, just adding 128 to them would do it.

by on (#76465)
tokumaru wrote:
thefox wrote:
I just have no idea how it could be done in an artist friendly way, short of reading a layered image format.

I just thought of another way that's pretty hackish, but if the hotspot is the only extra information you want to put in the image you could probably use the palette file for this.

You're right! I guess it could be in the image file as well, like in the rightmost pixel column or something. I initially thought it would better to have the palette file shared between different images, but now that I think of it that's actually bad, because if the palette image is changed the colors in every single sprite image would need to be changed as well. So the palette should act as more of an reference where the colors go rather than representing the final palette assignment.

Also if this is the case I guess it might make sense to include the palette in the image file itself... Decisions, decisions, decisions.

Quote:
What I mean is that you can't easily resize your character to the left or up if the relative coordinates are always positive

Oh yeah I understand what you meant now.

by on (#76750)
I couldn't figure out a good deterministic algorithm for generating the definitions, so I made a genetic algorithm instead. To my own surprise it works quite well! However at the moment it's pretty slow, it usually takes couple of minutes for it to figure out the perfect solution (as in minimum number of sprites) for about 32x32 sprite with two layers. I'll have to tweak the GA parameters a little bit and see if I can make it faster that way, and if not, try to work on the code itself (there's definitely room for improvement).

EDIT: I had forgotten the frame limiter ON... it was only using about ~10% of CPU. Luckily I optimized it before noticing that, so now it's quite fast. Definitely fast enough for my use. Cool.