GMS 2 Save surface with the "correct" alpha blending

CodeManu

Member
Hey all!

I've been trying to export an surface (via surface_save method) into a .png, but due to how alpha blending works on surfaces it gets tinted (towards black as I'm using draw_clear_alpha(c_black,0) to clear the surface).

I know this is the correct behaviour, and that It can be fixed by premultiplying alpha and using bm_one,bm_inv_src_alpha blendmode when drawing, but this doesn't apply to saving the surface as you can't apply the blendmode to the saved file.

Any clues on how to proceed?
 

CodeManu

Member
Bump and a bit more info about the issue:

This is how the image looks on aseprite with a 0.5 alpha, with the alpha being reduced on aseprite: https://i.imgur.com/GLCfPxh.png

This is how it looks with a 0.5 alpha, with the alpha being reduced on GMS and then saved with surface_save(): https://i.imgur.com/QETe8XK.png

The problem here is very simple, the image is getting merged with a black background with alpha 0, (rgba = 0,0,0,0) so it gets darker than it "should". As I say, this is working as intended, but not the result I'm looking for. You can fix this inside GMS by premultiplying alpha to rgb values of the image and then using blendmode_ext(bm_one,bm_inv_src_alpha) while creating the surface, and then using that same blendmode while drawing, but this last step can't be done while saving into a .png

So TL;DR, I'd like to have the first image I posted instead of the second one when exporting the surface.
 

Mike

nobody important
GMC Elder
In order to get the first version, you would need to disable blending as you write to the surface in the first place, otherwise it'll always be blended with whatever the background colour is.

Can you write to the surface without blending, then write to the alpha channel directly later, by locking off the colour channels and doing a filled rect over the whole image?

(kind of like this....)

clear surface
Disable blending
draw whatever
lock RGB channels
draw rect with alpha of 0.5
enable blending

save surface..... (or of course leave alpha as full, and just draw the surface alpha'd)
 
Last edited:

CodeManu

Member
Hi Mike, thanks for taking your time to answer!

That would certainly work if the image has only an overall alpha value of 0.5, but I'm afraid it wouldn't work if the image has different alpha at different points, for example, a gradient that goes from 1 to 0 alpha from left to right. I haven't tested it yet (it's late here, I'll do that tomorrow) so I might be wrong.
 

Mike

nobody important
GMC Elder
Or draw it in 2 parts.... draw the opaque bits first - without blending (or alphatest), then the variable alpha bits once you lock off the colour channels.
 

CodeManu

Member
I still didn't have time to test it, but giving it a second thought, wouldn' the alpha channel still be blended with the clear surface value? RGB channels would mantain the sprite values as they are not blended, but if the alpha is 0.5, and the surface clear alpha is 0, wouldn't it output a 0.25 final alpha value?

Also, this solution will work for a single sprite, but how would it be handled for multiple sprites with different alpha values? I suppose you could repeat that process and bounce surfaces for every image but It'd get expensive really fast.
 

CodeManu

Member
I've been doing some tests, and as I thought, it works perfectly for a single sprite, but sadly overlapping sprites with different alphas are not blended at all. Any chance for another idea?
 

josyanf1

Member
Or draw it in 2 parts.... draw the opaque bits first - without blending (or alphatest), then the variable alpha bits once you lock off the colour channels.
I've been doing some tests, and as I thought, it works perfectly for a single sprite, but sadly overlapping sprites with different alphas are not blended at all. Any chance for another idea?
Hi guys! The Mike's response also works for a single sprite. But like 'CodeManu', sprites with different alphas are not blended :(
 
Top