GameMaker When I change the window size, I see "surface isn't found" error, or surface resets

I'm working on a drawing program.
If I create a surface in create event then I get an error about "surface not found" when I resize the window. If I create the surface in draw event, when I resize the window the surface is automatically aligned to that size and I am not getting an error, but the paintings on the surface disappear. that is, surface is resetting.

If I create the surface in Create Event :

If I create the surface in Draw Event :

This is what I want; If I resize the window, surface will not reset and I will not get an error about "surface not found". Is there a way I can do that ?
Thanks :) ♥
 

CloseRange

Member
Firstly don't create the surface in the draw event, this will cause a memory leak.
Try this:
Code:
if(surface_exists(surface_id))
      /// draw surface
else show_debug_message("no surface");
that should clear up the error but depending on how bad the error was you might not see anything if you don't see anything we need to see the code.
Where do you delete the surface?
 
@CloseRange
Thank you so much for your reply and your time :) ♥
I don't delete the surface.
All code about the surface :
obj_surface Create Event:
Code:
global.surface01 = -1;
obj_surface Step Event (allows me to draw on this surface)
Code:
if global.tool == "brush"
{
    if mouse_enter() && mouse_check_button(mb_left)
    {
        surface_set_target(global.surface01);
        draw_set_colour(global.brushcolor);
        draw_line_width(mx, my, mxp, myp, global.brushsize);
        draw_circle(mx,my,global.brushsize/2,false);
        draw_circle(mxp,myp,global.brushsize/2,false);
        surface_reset_target();
        drawing_brush = 1;
    }
    if !mouse_enter()
    {
        drawing_brush = 0;
    }
}
obj_surface Draw Event :
Code:
if !surface_exists(global.surface01)
    global.surface01 = surface_create(real(global.canvas_w), real(global.canvas_h));
 
draw_surface(global.surface01, x - c01_w/2, y - c01_h/2);
This is the all code about the surface. If I resize the window , surface is resetting.
 

CloseRange

Member
Did a quick search (I'm not an expert on surfaces) and just checked the docs
and it says this:
First, you should realise that surfaces (except the application surface) are "volatile". This means that if the device or window loses focus or is minimised (good examples are when a screensaver comes up in Windows, or on an Android device when the app loses focus due to a call) then the surface may be destroyed. This is because it is stored in the texture memory and may be overwritten when the target platform needs that memory for something else which means that you should always have some type of fail-safe code in place, usually with the surface_exists function.
This seems a bit silly but kind of understandable. You're best bet might just be to just stick with using the application surface.
 
Or save the surface to a buffer and use that buffer instead of the surface, which is kinda what they mean by: which means that you should always have some type of fail-safe code in place.
 
@CloseRange and @RefresherTowel Thank you so much for your replies and your times. :) ♥
• I can't use application surface. Because I need a canvas size. And I want program supports saving transparent images. I'm not sure, but maybe I can do this by using surface_save or sprite_create_from_surface or sprite_add_from_surface.

Buffers. This seems pretty logical. But I'm not a professional at GML. I'm not sure how I can do that. Maybe I can do it as a result of research and long trials. I'll try it. But it's much better if there's an easier way. :D

And actually I have an idea in my mind but it creates a huge performance problem. before the window size is changed, I can get the image of the surface using sprite_create_from_surface or sprite_add_from_surface. And after resetting the surface, I can draw this sprite into the surface. However, I don't think this is logical in terms of performance.

I'm going to deal with buffers for now. But if I can't, I don't have an idea other than my unreasonable idea. :D

Thanks so much again for your replies and times : ) ♥
 
If you have many surfaces, or a very large one, I would only copy them to a buffer after a change is made to a surface, because copying them to a buffer is rather slow. Just something to keep in mind.
 
Thank you so much for reply :) ♥
I tried this but I think I did it wrong :D
Create Event:
Code:
global.canvas01_buffer = buffer_create(4096,buffer_grow,4);
global.canvas01_ss = -1;
alarm[0] = 300;
Alarm 0 Event:
Code:
buffer_delete(global.canvas01_buffer);

var c1_w = real(global.canvas_w);
var c1_h = real(global.canvas_h);
global.canvas01_ss = sprite_create_from_surface(global.surface01,0,0,c1_w,c1_h,false,false,c1_w/2,c1_h/2);

if !buffer_exists(global.canvas01_buffer)
    global.canvas01_buffer = buffer_create(4096,buffer_grow,4);
    
if buffer_exists(global.canvas01_buffer)
{
    buffer_seek(global.canvas01_buffer, buffer_seek_start, 1);
    buffer_write(global.canvas01_buffer,buffer_u64, global.canvas01_ss);
}

alarm[0] = 300;
Draw Event:
Code:
if !surface_exists(global.surface01)
{
    global.surface01 = surface_create(real(global.canvas_w), real(global.canvas_h));
    surface_set_target(global.surface01);
    if buffer_exists(global.canvas01_buffer)
        draw_sprite(buffer_read(global.canvas01_buffer, buffer_u64),0,x,y);

    surface_reset_target();
}
    
draw_surface(global.surface01, x - c01_w/2, y - c01_h/2);
This didn't give the result I wanted. It drew the first sprite from the first texture page. ? :D
I tried the same system without using buffer. I tried to draw the image I stored in the variable directly. But it didn't draw anything. So this didn't work either.
I don't know what I should do. :/
 
the game speed is 300 per secs.
and I think we can't check if window is resizing. I searched this on the internet, but I couldn't find a function or extension. so I thought I should get the image on the surface every second. :D If the window is resized, the surface will disappear and the code in Draw Event will run. So the image stored in buffer will be redrawn on the surface. But it didn't work :D
 
In any case, this is the code to create a buffer with a surface:
Code:
width = 100;
height = 100;
surf = -1;
buff = buffer_create((width*height)*4,buffer_grow,1); // Create the buffer with (w*h)*colour_channels (4 includes alpha)
var temp_surf = surface_create(width,height); // Create a temp surface that we will delete after
surface_set_target(temp_surf); // Set the draw target
draw_sprite(sprite0,0,sprite_get_xoffset(sprite0),sprite_get_yoffset(sprite0)); // The sprite_get_offsets are only if the sprite is center aligned, otherwise just 0, 0
surface_reset_target();
buffer_get_surface(buff,temp_surf,buffer_surface_copy,0,0); // Copy the data from the surface to the buffer
surface_free(temp_surf);
If you want to update the buffer (so have it draw something new) you just need this bit:
Code:
var temp_surf = surface_create(width,height); // Create a temp surface that we will delete after
surface_set_target(temp_surf); // Set the draw target
draw_sprite(sprite0,0,sprite_get_xoffset(sprite0),sprite_get_yoffset(sprite0)); // The sprite_get_offsets are only if the sprite is center aligned, otherwise just 0, 0
surface_reset_target();
buffer_get_surface(buff,temp_surf,buffer_surface_copy,0,0); // Copy the data from the surface to the buffer
surface_free(temp_surf); // Free up our temp surface
And to draw it, it is this code:
Code:
if (!surface_exists(surf)) {
   surf = surface_create(width,height); // If surf isn't a surface, make it one
   buffer_set_surface(buff,surf,0,0,0); // Copy the data from the buffer to the surface
}
draw_surface(surf,0,0); // Draw the surface at 0, 0 in the room.
 
It worked !!! Really endless thank you. Even (∞ * ♥)^∞ thanks !! : ) ♥
I don't know if there's anything I can really do, but I owe you. : )
It didn't work when I used code that you wrote as it was. I don't know, maybe I made a mistake. But I made a few changes and it was exactly what I wanted. I couldn't have done it without you. : ) ♥

That's exactly what I do :
Create Event :
Code:
global.surface01 = -1;
global.surface01_buffer = buffer_create((width*height)*4,buffer_grow,1);
temp_surface = surface_create(width,height);

buffer_get_surface(global.surface01_buffer,temp_surface,buffer_surface_copy,0,0);
Step Event :
Code:
if !surface_exists(temp_surface)
{
    temp_surface = surface_create(width,height);
    buffer_set_surface(global.surface01_buffer, temp_surface, 0, 0, 0);
}
surface_set_target(temp_surface);

//Draw codes

surface_reset_target();
buffer_get_surface(global.surface01_buffer,temp_surface,buffer_surface_copy,0,0);
Draw Event :
Code:
if !surface_exists(global.surface01)
{
    global.surface01 = surface_create(width, height);
}
buffer_set_surface(global.surface01_buffer,global.surface01,0,0,0);
draw_surface(global.surface01, x - width/2, y - height/2);
Endless thanks again : ) ♥
 
Top