surface_save(application_surface) alpha blending problem...

FoxyOfJungle

Kazan Games
Hi!

#1 - I have this code in the Step Event of an object:

GML:
if keyboard_check_pressed(vk_space) {
    surface_save(application_surface, "ImageFile.png");
}

#2 - Result:



As you can see, there is a color difference in anything with transparency (like the shadow of the player) between the saved image and the game's application_surface.
This is normal? Why does it happen? How do I make this not happen? Is it a bug and should I report it?

Notes: I didn't disable the application_surface and I'm not drawing manually, it's all default, I'm just saving the application_surface.


Saved surface:




I did a test and this also occurs the same problem:
GML:
_surf = surface_create(surface_get_width(application_surface), surface_get_height(application_surface));
surface_copy(_surf, 0, 0, application_surface);
surface_save(_surf, "10.png");
 
Last edited:

basementApe

Member
I've had similar problems drawing sprites with alpha to surfaces before. What worked for me was setting gpu_set_colorwriteenable(true, true, true, false) right before drawing the sprite and then setting it back to gpu_set_colorwriteenable(true, true, true, true) after the drawing finished.
 

FoxyOfJungle

Kazan Games
I've had similar problems drawing sprites with alpha to surfaces before. What worked for me was setting gpu_set_colorwriteenable(true, true, true, false) right before drawing the sprite and then setting it back to gpu_set_colorwriteenable(true, true, true, true) after the drawing finished.
Yes, I already tested that and it doesn't work, unfortunately:

GML:
_surf = surface_create(surface_get_width(application_surface), surface_get_height(application_surface));

surface_set_target(_surf);
draw_clear_alpha(c_black, 0);
surface_reset_target();

gpu_set_colorwriteenable(true, true, true, false);
surface_copy(_surf, 0, 0, application_surface);
gpu_set_colorwriteenable(true, true, true, true);

surface_save(_surf, "10.png");
The saved surface turns all transparent. And I really need to copy the surface, so there's no way to use this function in this case.

Already tried:
  • Put gpu_set_colorwriteenable(true, true, true, false); on the Draw Begin and gpu_set_colorwriteenable(true, true, true, true); on Draw End.
  • Create a surface, define the target, clear the black alpha, disable the alpha write, draw the application_surface and re-enable everything again, reset the target and save the surface after 1 step.
  • Save the surface inside the Draw GUI event.

Thanks.
 
Last edited:

FoxyOfJungle

Kazan Games
I submitted a bug report:
Ticket number: 187540

Hello!

Well, it doesn't matter what I do, but the application_surface is always saved with a different color than it actually is. This happens if there are transparent sprites in it, such as the player's shadow and others. The pixels where there was transparency, get a darker color in the saved or copied surface.

I used surface_copy() and surface_save() and it's like the opacity is doubled, getting a darker color when saved.
This problem is bad because I'm making a transition system, and whenever I copy the application_surface, this issue is very visible on the screen.

I showed the problem reproduction here:
I also sent a simple project.

I've tested it on Windows and HTML5, but I think it should affect all platforms.

Thanks for listening. Have a nice day!
 

FoxyOfJungle

Kazan Games
Okay, I partially solved this issue myself by writing this shader and replace the surface_copy() to a custom one:

GML:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 _color = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord);
    _color.a = 1.0;
    gl_FragColor = _color;
}
Any pixel with opacity less than 1, it sets the pixel opacity to 1.

 
Last edited:

Liquid

Member
hi, im searching a solution for a similar problem - thats how i came to your thread.....

it happens regularly that my program has to copy a sprite to a surface,
and after some little changes it will be changed back to a new sprite, the old sprite is deleted.

my problem : The transparency is eaten up over time. every time i do sprite2surface2sprite very few of the alpha is cut off and finally only alpha255 xor alpha0 is remaining.

i tried alot with different blendmodes,
and used
gpu_set_alphatestenable(true)
gpu_set_alphatestref(0)

as a test i even tried to save the alpha of a sprite as png:
gpu_set_colorwriteenable(false,false,false,true);
write sprite to a surface, saving the surface as png
but even there the alpha is NOT the original!

very frustrating.
i want to keep original alpha but i cannot edit sprits without sending them to a surface and there the alpha is changed somehow.
 

Liquid

Member
...gpu_set_blendenable(false)...
THANKS !

finally it is working! (i still dont know how to save alpha without loss - but i can live with that for now)

Funny thing :
When doing my sprite2surface2sprite GM2 is still changing the alpha BUT only once. After one call i can call it multiple times and it will stay the same.
I assume its cause of the different internal Format surfaces use. Actually loading a sprite ingame and saving it without touching it in any changing way will cause a change too.

But im happy its filnally working ;)

GML:
gpu_set_blendenable(false)

var _w = sprite_get_width(_spr)
var _h = sprite_get_height(_spr)

var _surf = surface_create(_w,_h)
surface_set_target(_surf);
draw_clear_alpha(c_black, 0); // i guess this line is not needed with blendenable turned off
draw_sprite(_spr,0,0,0)  
surface_reset_target();
sprite_delete(_spr)

_spr = sprite_create_from_surface(_surf,0,0,_w,_h,false,false,0,0)

surface_free(_surf)

gpu_set_blendenable(true)
 
Top