In the normal draw events, GameMaker doesn't actually draw directly to the screen, but rather draws to a surface called the application surface.
This surface is basically a blank "canvas" that can be manipulated before being drawn to the screen when needed, and in most cases GameMaker handles this for you (although you can also manipulate it yourself in code for shaders, scaling and many other things - further details are given below).
Apart from the application surface, you can also create your own surfaces and use them to create stunning or subtle special effects in your game.
For example, you can use surfaces to "catch" instances, which can then be destroyed, and in this way you can create a decal effect where the sprite for the instance is displayed on the surface as if it still existed, permitting graphical effects like debris, blood, etc. without any real processing overhead.
Another thing you can do with surfaces is use them as textures to be manipulated, or to create sprites "on the fly", or to create complex overlays. In fact, the uses for surfaces are endless!
The basic use of a surface would be as follows:
surf = -1;
if (!surface_exists(surf))
{
surf = surface_create(960, 540);
}
surface_set_target(surf);
draw_clear_alpha(c_black, 0);
draw_sprite(spr_icon, 0, 48, 48);
surface_reset_target();
draw_surface(surf, 0, 0);
surface_free(surf);
Normal surfaces are quite easy to use, but there are a few basic rules to be followed when you use them:
NOTE This doesn't appear to happen with sprites or other visual assets (but actually does!) as they are also stored in regular memory (RAM) and when they are removed from texture memory (VRAM) they immediately get restored from regular memory when the game regains focus.
if (view_current == 0)
{
surface_set_target(surf);
with (obj_Effect)
{
var _vx = camera_get_view_x(view_camera[1]);
var _vy = camera_get_view_y(view_camera[1]);
draw_sprite(sprite_index, image_index, x - _vx, y - _vy);
}
surface_reset_target();
}
else
{
draw_surface(surf, 0, 0);
}
NOTE This is not true of the application surface, only user-created surfaces.
One thing to note is that should you require drawing the whole display to a surface (including tiles, backgrounds etc.) you can simply access the application surface itself (see below for further details) or you could assign a surface to a view port using the variable view_surface_id[0..7] as with this, all that is visible in that view port will be drawn to the corresponding surface.
The following functions exist to deal with surfaces (these functions are specific for creating and manipulating surfaces, but to actually draw them to the screen you should be using the specific draw functions that can be found below):
The following functions exist for drawing surfaces:
NOTE When working with surfaces there is the possibility that they can cease to exist at any time due to them being stored in texture memory. You should ALWAYS check that a surface exists using surface_exists before referencing them directly.
Finally, you have two functions for storing and retrieving surfaces in Buffers:
As mentioned above, GameMaker doesn't actually render most things to the screen directly, but instead it renders them to the application surface. This is essentially a surface - just like any that you can make yourself using the surface functions - and as such it can be manipulated, drawn to, sent to shaders, etc. Basically, anything that you would normally do with a surface you created can also be applied to the application surface.
NOTE The only thing you cannot do with the application surface is free it. It always exists, although the handle to access it may change.
When you run your game, this surface is created the first time that a draw event is called in each new room that you enter, which means that nothing is drawn until that point. However, you can still get the application surface position and resize it in the Create Event or any other event without getting any errors and the values used will be relevant to the surface when it is created. The actual sequence of events for the creation and drawing of the application surface is as follows:
The use of this surface means that you can easily create incredible transitions using shaders, or take the screen and wrap it around a 3D form, or simply scale a low-res game up to any resolution screen... The possibilities are endless!
To access this surface, you need to use the built-in global variable application_surface which is explained on the following page:
You also have a few functions that are designed only for use with the application surface: