Sprite copied by surface interpolates differently than original?

J

JoshuaJSlone

Guest
I want to do some sprite combining by way of surfaces, and before I did anything complicated I wanted to try the test case of duplicating a sprite by way of surface. Create a surface exactly the size of the sprite, draw the sprite there, create a sprite from that surface, and then tell an existing object to start using the new sprite instead.

var surf;
surf = surface_create(64, 64);
surface_set_target(surf);
draw_clear_alpha(c_black, 1);
draw_sprite(spr_ship, 0, 32, 32);
spr_custom = sprite_create_from_surface(surf, 0, 0, 64, 64, true, false, 32, 32);
surface_reset_target();
surface_free(surf);

sprite_index=spr_custom;
If this was working exactly, I'd think the before and after should be a total match. However, they're not quite. Actually, I found that if I turn off "Interpolate colors between pixels" they are a perfect match, but with it on there are slight differences. Are there some sort of interpolation settings in sprites that aren't by default the same in a sprite created this way and one created from the GUI?



The differences are subtle, but I think more apparent in motion. The original sprite is on the left, while the copied sprite is on the right. The copied sprite seems to have thinner/darker gray lines compared to the original. The copied sprite also seems to have greater smoothing on the outside of the diagonal white lines seen at the corners of the object here.
 

obscene

Member
No matter how many posts about this I read I don't understand it, but somehow the blend mode is different for surfaces. If you want the same results you need to use draw_set_blend_mode_ext(bm_one, bm_inv_src_alpha) before drawing the surface to screen. ( I THINK )
 
if the surface edges don't line up with the image you drew onto it, there wont be hard edges on the outside. If the image on the left is a rotated sprite, the hard edges on the diagonals may be the edge of the sprite. There are no pixels to interpolate on the very edge.

I'm not sure why the lines seem thinner in the right image. It could be because the image on the right was interpolated one time more than the image on the left. once when the sprite was drawn to the surface, and once again when the image on the surface was drawn. I'm guessing the discrepency would become more apparent with greater scaling.
 
J

JoshuaJSlone

Guest
That may or may not be the problem. Using specifically the line you suggested didn't work for me, but since you've introduced me to blend modes I see the subtle problems people have with it and the many combinations possible with draw_set_blend_mode_ext and think maybe one of them will do something.

However, I never do draw the surface to screen exactly. The surface contents get copied back to sprite before being displayed on screen. I tried setting identical blend modes (the simple draw_set_blend_mode(bm_normal);) both for the regular screen/surface and the created surface, but I can still see a difference toggling between the original and copied sprite.

I've just tried using sprite_save on the copied sprite, and my confusion increases. Looking at it in an external image editor, it appears identical to the original image I loaded up. Same size, same shape, same colors. So I tried adding it in manually as another sprite so I could toggle between it and the other two states. Aaaand... it's not exactly like either. It has the thinner gray lines of the copied sprite, but the less smooth outer edges of the original.

I have to stop for the day, but I'll update if I figure anything else out.
 
J

JoshuaJSlone

Guest
if the surface edges don't line up with the image you drew onto it, there wont be hard edges on the outside. If the image on the left is a rotated sprite, the hard edges on the diagonals may be the edge of the sprite. There are no pixels to interpolate on the very edge.

I'm not sure why the lines seem thinner in the right image. It could be because the image on the right was interpolated one time more than the image on the left. once when the sprite was drawn to the surface, and once again when the image on the surface was drawn. I'm guessing the discrepency would become more apparent with greater scaling.
Didn't see this added reply until after I posted the above.

Here's the original image I fed into the program.


and here's the copied sprite saved.


It doesn't seem like being drawn to the surface affected anything visible, and in neither case are any of the non-transparent pixels actually on the edge of the sprite.
 
I don't know for sure, but I suspect game maker automatically removes transparent regions when building the texture page, in which case it is possible the edges of the first image might be against a hard primitive edge. You could test that by checking "used for 3d" for that spirte, and see if the hard edges go away.
 
J

JoshuaJSlone

Guest
That "used for 3D" thing did make a difference. Today I tried using sprite_duplicate and was confused how even duplicating a sprite that way there were differences as to how it handled edges--now I see that apparently the newly created duplicate sprite must have "used for 3D" on by default, because once I switch that on for the original resource it became indistinguishable from that duplicate.

I tried a slightly different route for getting a sprite from the surface. I figured, if there was some difference in sprite settings, then maybe adding it to the existing original sprite (or rather a duplicate since it won't let you add to the original) would take care of that, since they'd just be separate frames in the same sprite. However, doing things that way

sprite_add_from_surface(spr_custom, surf, 0, 0, 64, 64, true, false);

there is a visible flicker between the original and newly created frame. Even though again, exporting both frames to PNG form they appear identical. There is a difference in the export file sizes, though, 471 bytes for the original frame vs 579 for the one created by surface, so there must be something different about them causing that size difference, I just don't know how to tell what that is.

At this point my inability to create a perfect copy by way of surface is still bugging me, but it's preventing me from frying bigger fish for what is really a minor appearance difference that is probably most noticeable because I'm testing it on such a crude pseudo-vector image. I'll update if I do happen to figure out what the problem was, though.
 
did you try using the smooth option with sprite_create_from_surface?

nevermind, that doesn't do any good.

EDIT: I just tried to reproduce your problem on my computer. I definately see a difference along the edges of the images, but I don't see any difference in the internal parts of the images. Which makes me think something else is going on in your project that I don't know about. maybe a scaling problem?

left is original sprite, middle is surface that the sprite was coppied to, right is the new sprite.
all have been rotated by 230 degrees, and scaled 4x. Except for the edges of the first image, they are exactly the same.


The only way that I can think of to fix the hard edges in the first sprite, besides turning on (used for 3d), is to draw two pixels into the sprite using "1" opacity (the lowest value above zero), one in the upper left-hand corner, and one in the lower-right hand corner. And the purpose of that is to force game maker not to cut out the transparent area around your sprite. There should be an option in game maker to automatically add a pixel wide transparent border around your image when you don't want hard edges on your sprites.

Actually probably the more useful suggestion is this one. If you have GM:S pro, is set the texture group containing this sprite to not use cropping. This will stop the transparent regions around the edge from being removed (will waste space on the texture page though). But what you could do there is make sure the sprite is just large enough to fit the image plus a 1-pixel wide transparent border. Go to global game settings and click the texture groups tab.
 
Last edited:
Top