• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker [SOLVED] gpu_set_blendmode(bm_subtract) doesn't work

A

ajan-ko

Guest
So, basically I'm trying to create a glow effect, but it just doesn't work.
Here's my code.
Code:
if active {
    color_fog=c_black;
    draw_set_alpha(0.5);
    
   //set the target
    surface_set_target(fog);
    draw_set_color(color_fog);
  
    //draw the fog
    draw_rectangle(0,0,camera_get_view_width(view_camera[0]),camera_get_view_height(view_camera[0]),0);
  
    //draw the light source;
    if instance_exists(obj_char)
    with obj_char {
        //substract the black rectagle
        gpu_set_blendmode(bm_subtract);
        light_size=120
        draw_ellipse_color(x-light_size-camera_get_view_x(view_camera[0]),y-light_size-camera_get_view_y(view_camera[0]),x+light_size-camera_get_view_x(view_camera[0]),y+light_size-camera_get_view_y(view_camera[0]),c_white,c_black,0);
        gpu_set_blendmode(bm_normal);
    }
  
    //draw the surface to origin
    if surface_exists(fog){
        draw_surface(fog,camera_get_view_x(view_camera[0]),camera_get_view_y(view_camera[0]));
    }
    draw_set_alpha(1);
    surface_reset_target();
}
By the way, I put that code to draw GUI. Here's the result
 
Last edited:
A

ajan-ko

Guest
How 'bout moving that

surface_reset_target();

before the
//draw the surface to origin
?
Nope, doesn't work.
The draw_surface doesn't stack with surface_set_target, so you only draw the surface to the application surface in GM2.

Wait, let me try this code on GM1. If it's working in GM1 then GM2 has problem with surface.

EDIT, yep, I found the substract doesn't worked at all...
Plus for some reason the draw_set_alpha() and surface_set_target() WILL NOT AFFECT draw_surface.

Here's my code working in GM1
Code:
    var color_fog=c_black;
    draw_set_alpha(1);
  
   //set the target
    surface_set_target(fog);
    draw_set_color(color_fog);
 
    //draw the fog
    draw_rectangle(0,0,view_wview[0],view_hview[0],0);
 
    //draw the light source;
    if instance_exists(obj_char)
    with obj_char {
        //substract the black rectagle
        draw_set_blend_mode(bm_subtract);
        var light_size=120
        draw_ellipse_color(x-light_size-view_xview[0],y-light_size-view_yview[0],x+light_size-view_xview[0],y+light_size-view_yview[0],c_white,c_black,0);
        draw_set_blend_mode(bm_normal);
    }
    draw_set_alpha(0.5);
    surface_reset_target();
    //draw the surface to origin
    if surface_exists(fog){
        //GUI should be 0 0 
        draw_surface(fog,0,0);
    }
Next I will try to put in on draw event and see how it goes.
 
Last edited:

vdweller

Member
Nope, doesn't work.
The draw_surface doesn't stack with surface_set_target, so you only draw the surface to the application surface in GM2.

Wait, let me try this code on GM1. If it's working in GM1 then GM2 has problem with surface.
Wut.

I copied your code to a new project in GMS2 to verify my claim. It worked with the change I proposed. Maybe there's something I'm missing here.

draw_surface draws to whatever surface has been set and not exclusively the app surface.
 

vdweller

Member
Nope, doesn't work.
The draw_surface doesn't stack with surface_set_target, so you only draw the surface to the application surface in GM2.

Wait, let me try this code on GM1. If it's working in GM1 then GM2 has problem with surface.

EDIT, yep, I found the substract doesn't worked at all...
Plus for some reason the draw_set_alpha() and surface_set_target() WILL NOT AFFECT draw_surface.

Here's my code working in GM1
Code:
    var color_fog=c_black;
    draw_set_alpha(1);
 
   //set the target
    surface_set_target(fog);
    draw_set_color(color_fog);
 
    //draw the fog
    draw_rectangle(0,0,view_wview[0],view_hview[0],0);
 
    //draw the light source;
    if instance_exists(obj_char)
    with obj_char {
        //substract the black rectagle
        draw_set_blend_mode(bm_subtract);
        var light_size=120
        draw_ellipse_color(x-light_size-view_xview[0],y-light_size-view_yview[0],x+light_size-view_xview[0],y+light_size-view_yview[0],c_white,c_black,0);
        draw_set_blend_mode(bm_normal);
    }
    draw_set_alpha(0.5);
    surface_reset_target();
    //draw the surface to origin
    if surface_exists(fog){
        draw_surface(fog,view_xview[0],view_yview[0]);
    }
Next I will try to put in on draw event and see how it goes.
Your code working in Gm1 has surface_reset_target() before draw_surface(fog,view_xview[0],view_yview[0]), like it should. Not the case in your GMS2 example.

EDIT: Unless you meant that it works in GMS1 but not in GMS2, but then it worked in my GMS2 project...
 
Last edited:
A

ajan-ko

Guest
Your code working in Gm1 has surface_reset_target() before draw_surface(fog,view_xview[0],view_yview[0]), like it should. Not the case in your GMS2 example.
I tried the code in GMS2, after I edit the code, and still not working.

Here's my current code.
Code:
if active {
    color_fog=c_black;
    draw_set_alpha(0.5);
    surface_set_target(fog);
    draw_set_color(color_fog);
 
    //draw the fog
    draw_rectangle(0,0,camera_get_view_width(view_camera[0]),camera_get_view_height(view_camera[0]),0);
 
    //draw the light source;
    gpu_set_blendmode(bm_subtract);
    if instance_exists(obj_char)
    with obj_char {
        //substract the black rectagle
        light_size=120
        draw_ellipse_color(x-light_size-camera_get_view_x(view_camera[0]),y-light_size-camera_get_view_y(view_camera[0]),x+light_size-camera_get_view_x(view_camera[0]),y+light_size-camera_get_view_y(view_camera[0]),c_white,c_black,0);
    }
    gpu_set_blendmode(bm_normal);
    //draw the surface to origin
 
    surface_reset_target();
    if surface_exists(fog){
        draw_surface(fog,0,0);
    }
    draw_set_alpha(1);
}
At this point, probably there's another code I miss. I should try to create new project in GMS2 and see is this code works or not...

If this doesn't work, probably because of the version? What version you use? Mine was
IDE 2.2.0.343
Runtime 2.2.0.258
 
Last edited:

vdweller

Member


Dunno bro. Your current code works for me in GMS2.

1) Have you checked if the active var is glitched?
2) Have you checked a sprite-based approach instead of drawing primitives? I'm asking in case some graphics cards don't play well with these things, although I don't believe that's the case.
3) You can always use surface_save to debug such problems. Save the fog surface as a png and it will show precisely what you've done to it, no matter the surface target or how it's drawn.
4) Add a draw_clear_alpha after setting the fog surface as the target and see if it works.
 
Last edited:
A

ajan-ko

Guest
2) Have you checked a sprite-based approach instead of drawing primitives? I'm asking in case some graphics cards don't play well with these things, although I don't believe that's the case.
Wait, what? What is this mean?
 

vdweller

Member
Wait, what? What is this mean?
Instead of drawing a black rectangle, draw a scaled 1x1 black pixel sprite and intead of drawing an ellipse, draw a, for example, 512x512 circle sprite (it can have a smooth/blurry edge so the effect will also look much, much better). However I think it's highly unlikely that using primitives is the source of your problem so make sure you try the other options first!
 
A

ajan-ko

Guest
FOUND IT..
You cannot put the surface_create on obj_create
Instead what you do is create the surface each time the draw_gui loop and free them each second.
 
A

ajan-ko

Guest
Instead of drawing a black rectangle, draw a scaled 1x1 black pixel sprite and intead of drawing an ellipse, draw a, for example, 512x512 circle sprite (it can have a smooth/blurry edge so the effect will also look much, much better). However I think it's highly unlikely that using primitives is the source of your problem so make sure you try the other options first!
Thanks, man. I appreciate the help.
 

vdweller

Member
FOUND IT..
You cannot put the surface_create on obj_create
Instead what you do is create the surface each time the draw_gui loop and free them each second.
In my project, using your code, I created the surface in the Create event and there were no problems. In all my projects I do this, to be honest.

Creating and freeing a surface each step can be resource-consuming, maybe not such a big problem for modern machines but still it is really unnecessary. I still think the real problem is elsewhere.
 
A

ajan-ko

Guest
In my project, using your code, I created the surface in the Create event and there were no problems. In all my projects I do this, to be honest.

Creating and freeing a surface each step can be resource-consuming, maybe not such a big problem for modern machines but still it is really unnecessary. I still think the real problem is elsewhere.
Hmm... yeah, but the problem is I tried from clean project and it still doesn't work.
Maybe it's from the
surface_create() function.

Mine was like this:
Code:
fog=surface_create(camera_get_view_width(view_camera[0]),camera_get_view_height(view_camera[0]));
 

vdweller

Member
Do you have a failsafe to recreate the surface if it gets lost, ie from a full screen switch? Try adding this code in the draw event before anything else:

if (!surface_exists(fog)) then {
fog=surface_create(camera_get_view_width(view_camera[0]),camera_get_view_height(view_camera[0]));
}

Maybe this is what your problem is about. Fog surface gets created in the create event, gets a value eg 0.

Then it gets lost, value 0 refers to something else, problems occur. Although GM usually throws an error when a surface doesn't exist any more.

EDIT: Obviously, you should also create the surface in the Create event first!
 
A

ajan-ko

Guest
Do you have a failsafe to recreate the surface if it gets lost, ie from a full screen switch? Try adding this code in the draw event before anything else:

if (!surface_exists(fog)) then {
fog=surface_create(camera_get_view_width(view_camera[0]),camera_get_view_height(view_camera[0]));
}

Maybe this is what your problem is about. Fog surface gets created in the create event, gets a value eg 0.

Then it gets lost, value 0 refers to something else, problems occur. Although GM usually throws an error when a surface doesn't exist any more.

EDIT: Obviously, you should also create the surface in the Create event first!
FOUND IT, windows_set_size will affect the surface for some reason.
So yeah, the failsave is working. probably like you said, the surface doesn't exist, but there's no error message.
 

vdweller

Member
FOUND IT, windows_set_size will affect the surface for some reason.
So yeah, the failsave is working. probably like you said, the surface doesn't exist, but there's no error message.
I have just confirmed that this is indeed your problem.
By adding

if (!surface_exists(fog)) then {
fog=surface_create(camera_get_view_width(view_camera[0]),camera_get_view_height(view_camera[0]));
}

In the beginning of your draw event, it is fixed.

Do this for all your surfaces, always! Before you draw a surface, check if it exists, if it doesn't, create it again! There is no problem if you create a surface anywhere in your code, including the Create event!
 
Top