• 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!

SOLVED Having trouble with application_surface_draw_enable

Nox2004

Member
So my game has an object that sets application_surface_draw_enable to false and then apply some effects (shaders and stuff) to the application surface, drawing it to the screen in the post draw event:
GML:
gpu_set_blendenable(false);

draw_surface_ext(surf,
window_get_width()/2 - (app_width*scale)/2,
window_get_height()/2 - (app_height*scale)/2,
scale,
scale,
0,
c_white,
1.0);

gpu_set_blendenable(true);
The problem is, I have another object that uses bm_subtract blendmode to draw a lightning surface, and when I put both objects in the same room I just get a black screen. At first I though this was happening because blendenable was set to false, but even when I put gpu_set_blendenable(true) directly before the lightning object draw code, I still get this problem.

After experimenting a little I realized the problem is caused by the application_surface_draw_enable function, since when I set it to true, the game just works normally (but if I do it, I cant draw the screen visual effects I mentioned before), can anyone help me with this?

The oLightning object draw code:
GML:
gpu_set_blendenable(true)

gpu_set_blendmode(bm_subtract);
draw_surface(global.lightning_surf,0,0); //right now this surface is a gray rectangle
gpu_set_blendmode(bm_normal);
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Could it be that you don't want to use the blendenable function? That is for ALPHA blending and not for blendmodes... What happens if you comment out all instances of that function? Also, WHERE are you drawing the app surface? Keep in mind, that trying to draw it during the Draw Begin, Draw, or Draw End steps won't work as it's still the render target by the engine. When disabling drawing of the app surface, you can really only draw it yourself in the GUI events or the Post Draw event...
 

Nox2004

Member
Could it be that you don't want to use the blendenable function? That is for ALPHA blending and not for blendmodes... What happens if you comment out all instances of that function?
Thank you for your help. I tried out commenting all the blendenable functions, still getting the black screen :( (BTW, I discovered it's not exactly a black screen, but the lightning surface being drawn as black, even though it's a fully gray surface)
Also, WHERE are you drawing the app surface?
I'm drawing the application surface in the Post Draw event
 
Last edited:

Nocturne

Friendly Tyrant
Forum Staff
Admin
I think you need to post a bit more code to explain what you're doing then... and make sure to flag what event and object each thing is happening in. Also, have yo tried running the game in debug mode, then pausing and checking the textures in the debugger to see what is actually being drawn to each of the surfaces (including the app surface)? This could give you a clue as to what the issue is...
 

Nox2004

Member
I think you need to post a bit more code to explain what you're doing then... and make sure to flag what event and object each thing is happening in.
Ok ok. I have an object called oDrawApplicationSurface, in the create event I disabled application surface draw, declared a timer and a list of visual effects.

oDrawApplicationSurface create event:
GML:
application_surface_draw_enable(false);

timer = 0;

enum Effects {
    Noise,
    ScanLines,
    GrayScale
}

visual_effects = ds_list_create();

visual_effects[| Effects.Noise] = {
    effect_enabled : false,
    sprite : sWhiteNoise,
    subimage : 0,
    image_spd : 2, //changes subimage every X frames
    strength : 0   //0 - normal  1 - onlynoise
};

visual_effects[| Effects.ScanLines] = {
    effect_enabled : false,
    lines_size : 0,
    strength : 0
};

visual_effects[| Effects.GrayScale] = {
    effect_enabled : false,
    shader : shGrayScale,
    uniform_strength : shader_get_uniform(shGrayScale, "strength"),
    strength : 0 //0 - normal  1 - grey scale
};

then at the post draw event I apply the effects to a local surface looping trough that ds list, and at the end I draw this locally stored surface directly to the window as my application surface and free it.

oDrawApplicationSurface Post Draw event:
GML:
var app_width = surface_get_width(application_surface);
var app_height = surface_get_height(application_surface);
surf = surface_create(app_width,app_height);

surface_copy(surf,0,0,application_surface);

for (var i = 0; i < ds_list_size(visual_effects); i++)
{
    var effect = visual_effects[| i];
    if (effect.effect_enabled == false) continue;
  
    switch (i)
    {
        case Effects.Noise:
        {
            surface_set_target(surf);
          
            //sprite animation
            effect.subimage = timer / effect.image_spd;
            var image_n = sprite_get_number(effect.sprite);
          
            effect.subimage = effect.subimage - floor(effect.subimage/image_n) * image_n;
          
            //draw sprite to "application surface" (surf)
            draw_sprite_stretched_ext(effect.sprite,
            effect.subimage,
            0,
            0,
            surface_get_width(surf),
            surface_get_height(surf),
            c_white,
            effect.strength)
          
            surface_reset_target();
        }
        break;
        case Effects.ScanLines:
        {
            surface_set_target(surf);
          
            for (var j = 0; j <= app_height/effect.lines_size; j++)
            {
                var _c = c_ltgray;              //lite gray if odd
                if (j % 2 == 0) _c = c_dkgray;  //dark gray if even
              
                var y1 = j*effect.lines_size;
                var y2 = y1 + effect.lines_size;
              
                draw_set_color(_c);
                draw_set_alpha(effect.strength);
              
                draw_rectangle(0,y1,app_width,y2,false);
              
                draw_set_color(c_white);
                draw_set_alpha(1.0);
            }
          
            surface_reset_target();
        }
        case Effects.GrayScale:
        {
            var copy_surf = surface_create(app_width,app_height);
            surface_copy(copy_surf,0,0,surf);
          
            surface_set_target(surf);
          
            shader_set(effect.shader);
            shader_set_uniform_f(effect.uniform_strength,effect.strength);
          
            draw_surface(copy_surf,0,0);
          
            shader_reset();
          
            surface_reset_target();
          
            surface_free(copy_surf);
        }
        break;
    }
}


var app_scale = app_width / app_height;                       // 16:9
var window_scale = window_get_width() / window_get_height();  // window scale

var scale;
if (window_scale >= app_scale) //if window is larger than app
{
    scale = window_get_height() / app_height
}
else                           //if window is taller than app
{
    scale = window_get_width() / app_width
}

gpu_set_blendenable(false); //disables blending to draw the application surface

draw_surface_ext(surf,
window_get_width()/2 - (app_width*scale)/2,
window_get_height()/2 - (app_height*scale)/2,
scale,
scale,
0,
c_white,
1.0);

gpu_set_blendenable(true);

surface_free(surf);

the object works as just intended when on the room. Like at this image:
1635192343414.png

The other object is called oLightning, it creates a global surface and fills it with the gray color at the start of each step.

oLightning Create Event:
GML:
global.lightning_surf = surface_create(room_width,room_height);

darkness_level = 0.5; //1 - total dark    0 - no darkness

oLightning Begin Step Event:
GML:
if (!surface_exists(global.lightning_surf))
{
    global.lightning_surf = surface_create(room_width,room_height);
}

surface_set_target(global.lightning_surf);

draw_clear_alpha(make_color_rgb(darkness_level*255,darkness_level*255,darkness_level*255),1);

surface_reset_target();

and at the draw event it draws this surface at bm_subtract blendmode

oLightning Draw Event:
GML:
gpu_set_blendmode(bm_subtract);
draw_surface(global.lightning_surf,0,0);
gpu_set_blendmode(bm_normal);

as you can see in the image, if I set application surface draw to true in the oDrawApplicationSurface Create Event, the oLightning event will also work just fine:
1635193270403.png
1635193197154.png

But whenever I set the draw application surface enable, the global.lightning_surf surface will be drawn as entirely black, i am guessing the problem here is related to the subtract blendmode, but I really dont know how to solve it

Also, have yo tried running the game in debug mode, then pausing and checking the textures in the debugger to see what is actually being drawn to each of the surfaces (including the app surface)?
Tried it right now, the gpu settings look normal to me (not sure though, since I'm not really experienced with all the gpu stuff haha), the lightning surface is also alright (gray as it was meant to be), but it seems like it is not being drawed to the room, since the application surface is this 1635195189408.png

EDIT: discovered something interesting using the debugger, until the lightning surface being drawn the app surface looks normal (would put a print here, but I reached the file limit), but right after the line draw_surface_ext(global.lightning_surf,0,0,1,1,0,c_white,1); it becomes an empty 160x90 canvas (maybe for some reason the alpha is also being subtracted from the destination when the lightning surf is drawn?)
 

Attachments

Last edited:

Nox2004

Member
šŸ˜€ SOLVED IT

apparently the application_surface_draw_enable function changes a lot the way gamemaker works with surfaces and blending, so bm_subtract blendmode ends up also subtracting the alpha from the destination color or something like this, I used gpu_set_colourwriteenable to disable alpha writing when drawing the light surface.

GML:
gpu_set_colourwriteenable(true, true, true, false);
gpu_set_blendmode(bm_subtract);
draw_surface(global.lightning_surf,0,0);
gpu_set_blendmode(bm_normal);
gpu_set_colourwriteenable(true, true, true, true);

Here is an image of both working fine together:

1635243848441.png

Also would like to thanks a lot nocturne for the help, if it wasn't for your idea on using the debugger surfaces window I would never have figured this out :D
 
Top