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

Legacy GM Issue with Surface and Minimization

S

Sanctifier

Guest
Hi Everyone.

I have an issue with my surfaces when I minimize my game. When I restore it again, a copy of all my drawings and instances gets 'baked' onto the screen. This doesn't occur straight away, but when I draw something to the targeted surface. Also it seems to draw these objects at their last position before minimization.

Here's my code.

- Draw Event of obj_Surface_Controller
Code:
if (obj_Controller.endGame == true)
{
    surface_set_target(surf);
    draw_clear_alpha(0, 0);
    surface_reset_target();
}

//Draw surface
if (!surface_exists(surf))
{
    surf = surface_create(room_width, room_height);
}
//Create a new surface if DX destroys the old surface due to resizing
else
{
    draw_surface(surf, 0, 0);
}
And Here's an example of me drawing something to the surface.
- Draw Event of obj_Casings
Code:
draw_self();

if (moveSpd <= 0)
{
    if (instance_exists(obj_Surface_Controller))
    {
        surface_set_target(obj_Surface_Controller.surf);
        draw_sprite_ext(spr_Casings, image_index, x, y, image_xscale, image_yscale, image_angle, c_white, image_alpha);
        surface_reset_target();
    }
}

I'm struggling to find a solution, particularly since I don't know of any way to check for a minimized screen.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Okay, the issue probably is that when you minimise the window, the surface is being destroyed, but then when you maximise it, you are creating a new surface. This new surface probably uses the same memory allocation from the old surface and since you haven't cleared the surface then you get whatever was in that memory position drawn to the screen...

To explain a bit better... A surface is simply an allocated chunk of memory that is used for drawing. When you create a surface, all you are doing is reserving this piece of memory, and it may have previously contained information. If you do not clear the surface on creation, the information that was previously in the memory allocated to the surface will be shown as the contents of the surface. The solution, however, is really simple! Clear the surface on creation... like this:

Code:
if (!surface_exists(surf))
{
    surf = surface_create(room_width, room_height);
    surface_set_target(surf);
    draw_clear_alpha(0,0);
    surface_reset_target();
}
Hope that helps!
 

Simon Gust

Member
Must be an instance ordering issue.
I suggest putting the drawing part in the controller object.
Code:
if (obj_Controller.endGame == true)
{
    surface_set_target(surf);
    draw_clear_alpha(0, 0);
    surface_reset_target();
}

//Draw surface
if (!surface_exists(surf))
{
    surf = surface_create(room_width, room_height);  
    surface_set_target(surf);
    draw_clear_alpha(0, 0);
    with (obj_Casings)
    {
         if (movespd <= 0)
         {
             draw_sprite_ext(spr_Casings, image_index, x, y, image_xscale, image_yscale, image_angle, c_white, image_alpha);
         }
    }
    surface_reset_target();
}
//Create a new surface if DX destroys the old surface due to resizing
else
{
    draw_surface(surf, 0, 0);
}
and then in obj_Casings
Code:
if (moveSpd > 0)
{
    draw_self();
}
 
S

Sanctifier

Guest
Okay, the issue probably is that when you minimise the window, the surface is being destroyed, but then when you maximise it, you are creating a new surface. This new surface probably uses the same memory allocation from the old surface and since you haven't cleared the surface then you get whatever was in that memory position drawn to the screen...

To explain a bit better... A surface is simply an allocated chunk of memory that is used for drawing. When you create a surface, all you are doing is reserving this piece of memory, and it may have previously contained information. If you do not clear the surface on creation, the information that was previously in the memory allocated to the surface will be shown as the contents of the surface. The solution, however, is really simple! Clear the surface on creation... like this:

Code:
if (!surface_exists(surf))
{
    surf = surface_create(room_width, room_height);
    surface_set_target(surf);
    draw_clear_alpha(0,0);
    surface_reset_target();
}
Hope that helps!
The problem with that though is that I clear everything created with the surface, which means I lose all the blood effects and empty casings that were created
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
The problem with that though is that I clear everything created with the surface, which means I lose all the blood effects and empty casings that were created
Sadly, that's just the way surfaces work... You COULD save the surface every few steps and then check if it exists and if it doesn't check to see if there is a saved surface and load that instead of recreating it and clearing it only...
 
S

Sanctifier

Guest
Sadly, that's just the way surfaces work... You COULD save the surface every few steps and then check if it exists and if it doesn't check to see if there is a saved surface and load that instead of recreating it and clearing it only...
Could I do something like save it to a buffer perhaps?
 
S

Sanctifier

Guest
Yep! That should work.
So saving my surface to a buffer seemed to do the trick.

There's one problem though. It drops my real fps to about 70.

Here's the code that I have now.

Code:
//Draw surface
if (!surface_exists(surf))
{
    surf = surface_create(room_width, room_height);
    surface_set_target(surf);
   
    with (obj_Casings)
    {
        if (moveSpd <= 0)
        {
            draw_sprite_ext(spr_Casings, image_index, x, y, image_xscale, image_yscale, image_angle, c_white, image_alpha);
        }
    }

    draw_clear_alpha(0, 0);
    surface_reset_target();
}
//Create a new surface if DX destroys the old surface due to resizing
else
{
    buffer_get_surface(surfBuff, surf, 0, 0, 0);
    buffer_set_surface(surfBuff, surf, 0, 0, 0);
    draw_surface(surf, 0, 0);
}
In the create event of the surface controller I set it up like this.

Code:
surfBuff = buffer_create(960*960*4, buffer_fast, 1);
Is there a way to implement this that won't cause such a large drop in frame rates. I tried using true / false flags but that didn't seem to work.
 
S

Sanctifier

Guest
Does anyone have any pointers for saving a surface to a buffer for retrieval. The above code is the only way I could get this to half work, but it causes some surface elements to disappear rather than get drawn and it also causes a large frame rate drop.
 
L

Ludorverr

Guest
At the moment you're saving and loading the entire surface to the buffer every step. (buffer_get_surface/buffer_set_surface)
You could put it on a timer but that's still an expensive lagspike whenever the timer goes off, because the surface and buffer is so large. Buffers are faster at dealing with smaller amounts of information.

One idea, it's very complex though; is whenever you draw something to the surface - write that same information into the buffer (don't copy the whole surface to the buffer, just the part of the surface you're modifying, this should be faster). To keep your code clean call a script whenever you draw your blood effects and empty casings, so that you can perform both the draw and buffer write at the same time. As a result the buffer should mirror the appearance of your surface without needing to copy the entire thing.

Now when the surface is destroyed/recreated - load the entire buffer to the entire surface. A single lagspike is fine here, because what destroys surfaces is stuff like resizing the window or alt-tabbing, the player won't mind a single lag spike when they're doing that.

Maybe ask someone else for technical help, I'm sure this is possible but it's difficult.
 
Top