Legacy GM Trying to create a surface under the application surface

Hey,

I'm new to surfaces and I'm trying to have a shader draw on a surface thats under the application surface so I can put objects in front of the shaderized object. (If you wonder, its the TrueWater2D from xygthop3 which I can't find in the marketplace anymore)

How can I achieve that? I ask it here because the shader uses scripts that are complicated for me right now. If you know an easier way, It might make everything easier for me :)
 

Simon Gust

Member
Code:
/// STEP EVENT
shader_set(my_shader);
surface_set_target(my_surface);

with (my_object)
{
    draw_self();
}

surface_reset_target();
shader_reset();
Now, the shader will only affect the drawings on that surface.

You need to make sure that you draw the surface first to the application surface before all other objects get their cut.
You could also disable the automatic drawing of the application surface and code it the way you want it.
Code:
/// CREATE EVENT
application_surface_draw_enable(false);
Code:
/// DRAW EVENT
draw_surface(my_surface, view_xview, view_yview);
draw_surface(application_surface, view_xview, view_yview);
 
Code:
/// STEP EVENT
shader_set(my_shader);
surface_set_target(my_surface);

with (my_object)
{
    draw_self();
}

surface_reset_target();
shader_reset();
Now, the shader will only affect the drawings on that surface.

You need to make sure that you draw the surface first to the application surface before all other objects get their cut.
You could also disable the automatic drawing of the application surface and code it the way you want it.
Code:
/// CREATE EVENT
application_surface_draw_enable(false);
Code:
/// DRAW EVENT
draw_surface(my_surface, view_xview, view_yview);
draw_surface(application_surface, view_xview, view_yview);
I can't really do it and don't know why.
I tried using the codes you typed but couldn't get the result I want, then I tried to do it on my own like this;

I have an object thats created after the shader object.

oShip1 Create Event
Code:
SurfShip = noone;
oShip1 Step Event
Code:
if !surface_exists(SurfShip)
 {
  SurfShip = surface_create(320,180); //320x180 is multiplied to make it 1920x1080
 }
oShip1 Draw Event
Code:
if ( surface_exists(SurfShip) )
 {
   surface_set_target(SurfShip);
   draw_self();
   surface_reset_target();
 }
  else
   {
     surface_set_target(SurfShip);
     draw_self();
     surface_reset_target();
   }
draw_surface(SurfShip,320,180);
oShip1 Game End Event
Code:
///Delete the surface if it exists

if (surface_exists(SurfShip))
 {
  surface_free(SurfShip);
 }
I can't see the ship object, does it get drawn under the application surface?
 

Simon Gust

Member
the surface get's drawn to the application surface.
It might be completely covered by all the other stuff that is drawn in your game. It depends on draw order.
Also what I forgot to tell you is to clear the surface before drawing stuff on it.
Code:
surface_set_target(SurfShip);
draw_clear_alpha(0, 0);
draw_self();
surface_reset_target();
Another thing to consider is my method where the code doesn't lie in the respective draw events of the ships you want to draw to the surface, but rather in another object.
Calling surface_set_target() costs some time, so you want to call it as little as possible. If you use a with statement, you only have to call it once per step.
 

Xor

@XorDev
There's a few things here you'll want to change. I wrote the code that I would use and commented explaining the changes (untested):
Code:
///Create Event
SurfShip = -1;//While not important, noone is for objects.
Code:
///Draw Event
if !surface_exists(SurfShip) //You can check it's existence in the draw event cut out an if.
{
   SurfShip = surface_create(320,180); //320x180 is multiplied to make it 1920x1080
}

// You were setting the surface whether or not it existed (no longer matters).
surface_set_target(SurfShip);
//Here's the main problem!
//You were drawing the sprite as though it was in the room, but in a surface it's different.
//Here I calculated the position relative to the view because the surface ignores the view.
//This should work for different view sizes and positions, but not rotation (it's harder).
var X,Y,Xscale,Yscale;
X = x-view_xview[0];
Y = y-view_yview[0];
Xscale = 320/view_wview[0];
Yscale = 180/view_hview[0];
draw_sprite_ext(sprite_index,image_index,X*Xscale,Y*Yscale,image_xscale*Xscale,image_yscale*Yscale,image_angle,image_blend,image_alpha);
surface_reset_target();
//Scale this as you need to fit the view.
draw_surface(SurfShip,320,180);
If you need view rotation, let me know and I'll give a corrected code, but for general use this should work fine.
-Xor
 
the surface get's drawn to the application surface.
It might be completely covered by all the other stuff that is drawn in your game. It depends on draw order.
Also what I forgot to tell you is to clear the surface before drawing stuff on it.
Code:
surface_set_target(SurfShip);
draw_clear_alpha(0, 0);
draw_self();
surface_reset_target();
Another thing to consider is my method where the code doesn't lie in the respective draw events of the ships you want to draw to the surface, but rather in another object.
Calling surface_set_target() costs some time, so you want to call it as little as possible. If you use a with statement, you only have to call it once per step.
I'll turn back to that part if we can't do it the way that Xor says, I just prefered it because he did the thing I was confused (scaling the view/surface or something like that)

There's a few things here you'll want to change. I wrote the code that I would use and commented explaining the changes (untested):
Code:
///Create Event
SurfShip = -1;//While not important, noone is for objects.
Code:
///Draw Event
if !surface_exists(SurfShip) //You can check it's existence in the draw event cut out an if.
{
   SurfShip = surface_create(320,180); //320x180 is multiplied to make it 1920x1080
}

// You were setting the surface whether or not it existed (no longer matters).
surface_set_target(SurfShip);
//Here's the main problem!
//You were drawing the sprite as though it was in the room, but in a surface it's different.
//Here I calculated the position relative to the view because the surface ignores the view.
//This should work for different view sizes and positions, but not rotation (it's harder).
var X,Y,Xscale,Yscale;
X = x-view_xview[0];
Y = y-view_yview[0];
Xscale = 320/view_wview[0];
Yscale = 180/view_hview[0];
draw_sprite_ext(sprite_index,image_index,X*Xscale,Y*Yscale,image_xscale*Xscale,image_yscale*Yscale,image_angle,image_blend,image_alpha);
surface_reset_target();
//Scale this as you need to fit the view.
draw_surface(SurfShip,320,180);
If you need view rotation, let me know and I'll give a corrected code, but for general use this should work fine.
-Xor
I tried the last codes you typed Xor but the ship didn't show up. But let me explain what I want to achieve.

Here, I just want to move this -and the other ships in game- to the red drawn place but I want it to be on top of that water object -which is using a water shader- and draw that ship's bottom part -green part- seperately and under the water, so it seems wavy. Even the bottom doesn't be able to seen, I just want to move ship a little bit away from the ground. Thats what I want to achieve, but the water shader overlaps it.
I can provide the shader extension, its removed from store.
upload_2018-9-1_4-57-51.png
 
Last edited:

Xor

@XorDev
Well you need to make sure that you're drawing the surface in the correct position. Your surface draw code should look like this:
Code:
draw_surface_stretched(SurfShip,view_xview[0],view_yview[0],view_wview[0],view_hview[0]);
Now to draw the reflections as you explained you should be able to use draw_sprite_part_ext instead of draw_sprite_ext. Just draw the top part of the sprite to the surface and you can draw the bottom part or the whole sprite under the shader. Let me know if this helps!
 
Well you need to make sure that you're drawing the surface in the correct position. Your surface draw code should look like this:
Code:
draw_surface_stretched(SurfShip,view_xview[0],view_yview[0],view_wview[0],view_hview[0]);
Now to draw the reflections as you explained you should be able to use draw_sprite_part_ext instead of draw_sprite_ext. Just draw the top part of the sprite to the surface and you can draw the bottom part or the whole sprite under the shader. Let me know if this helps!
I changed the object codes like this:
Create Event
Code:
y = 224;

SurfShip = -1;//While not important, noone is for objects.
Game End Event
Code:
///Delete the surface if it exists

if (surface_exists(SurfShip))
 {
  surface_free(SurfShip);
 }
Draw Event
Code:
if !surface_exists(SurfShip) //You can check it's existence in the draw event cut out an if.
{
   SurfShip = surface_create(320,180); //320x180 is multiplied to make it 1920x1080
}

// You were setting the surface whether or not it existed (no longer matters).
surface_set_target(SurfShip);
//Here's the main problem!
//You were drawing the sprite as though it was in the room, but in a surface it's different.
//Here I calculated the position relative to the view because the surface ignores the view.
//This should work for different view sizes and positions, but not rotation (it's harder).
var X,Y,Xscale,Yscale;
X = x-view_xview[0];
Y = y-view_yview[0];
Xscale = 320/view_wview[0];
Yscale = 180/view_hview[0];
draw_sprite_ext(self.sprite_index,0,X*Xscale,Y*Yscale,image_xscale*Xscale,image_yscale*Yscale,image_angle,image_blend,image_alpha);
surface_reset_target();
//Scale this as you need to fit the view.
draw_surface_stretched(SurfShip,view_xview[0],view_yview[0],view_wview[0],view_hview[0]);
and result is:
upload_2018-9-4_1-11-34.png
How do I draw the SurfShip above the application surface's GUI? and whats going on in this SS :D
 

Xor

@XorDev
I see! Delete the Draw Event code and put this in the Draw GUI Event:
Code:
if !surface_exists(SurfShip) //You can check it's existence in the draw event cut out an if.
{
   SurfShip = surface_create(320,180); //320x180 is multiplied to make it 1920x1080
}

// You were setting the surface whether or not it existed (no longer matters).
surface_set_target(SurfShip);
//Here's the main problem!
//You were drawing the sprite as though it was in the room, but in a surface it's different.
//Here I calculated the position relative to the view because the surface ignores the view.
//This should work for different view sizes and positions, but not rotation (it's harder).
var X,Y,Xscale,Yscale;
X = x-view_xview[0];
Y = y-view_yview[0];
Xscale = 320/view_wview[0];
Yscale = 180/view_hview[0];
draw_sprite_ext(self.sprite_index,0,X*Xscale,Y*Yscale,image_xscale*Xscale,image_yscale*Yscale,image_angle,image_blend,image_alpha);
surface_reset_target();
//Scale this as you need to fit the view.
draw_surface_stretched(SurfShip,0,0,view_wview[0],view_hview[0]);
So now it should be drawn after the application surface and with the ship on top.
 
Just a maybe very much unwelcome and unproductive thought: why drawing the bottom part at all? When looking at water from this angle you usually cant see whats beneath the surface because the reflection is to strong anyways.
 
I see! Delete the Draw Event code and put this in the Draw GUI Event:
Code:
if !surface_exists(SurfShip) //You can check it's existence in the draw event cut out an if.
{
   SurfShip = surface_create(320,180); //320x180 is multiplied to make it 1920x1080
}

// You were setting the surface whether or not it existed (no longer matters).
surface_set_target(SurfShip);
//Here's the main problem!
//You were drawing the sprite as though it was in the room, but in a surface it's different.
//Here I calculated the position relative to the view because the surface ignores the view.
//This should work for different view sizes and positions, but not rotation (it's harder).
var X,Y,Xscale,Yscale;
X = x-view_xview[0];
Y = y-view_yview[0];
Xscale = 320/view_wview[0];
Yscale = 180/view_hview[0];
draw_sprite_ext(self.sprite_index,0,X*Xscale,Y*Yscale,image_xscale*Xscale,image_yscale*Yscale,image_angle,image_blend,image_alpha);
surface_reset_target();
//Scale this as you need to fit the view.
draw_surface_stretched(SurfShip,0,0,view_wview[0],view_hview[0]);
So now it should be drawn after the application surface and with the ship on top.
Yes, its being drawn after! But why theres a streching like that??
Just a maybe very much unwelcome and unproductive thought: why drawing the bottom part at all? When looking at water from this angle you usually cant see whats beneath the surface because the reflection is to strong anyways.
Actually, the bottom part doesn't matter too much, but I'll probably use it. Instead, I needed the ship to seem a bit far away from the island, that was the thing I wasn't able to achieve :)
 

Xor

@XorDev
Yes, its being drawn after! But why theres a streching like that??
I'm not sure what you mean? Are you saying that it is no drawing when it wasn't before, but it is incorrectly stretched?
I made the assumption that the view port and view size were the same size. The more general code would be:
Code:
draw_surface_stretched(SurfShip,view_xport[0],view_yport[0],view_wport[0],view_hport[0]);
This will draw the surface with position and size as the view port so it should be properly mapped.
My apologies for all the code iterations! If this doesn't work please supply a screenshot so that I can see what the issues is.
 
I'm not sure what you mean? Are you saying that it is no drawing when it wasn't before, but it is incorrectly stretched?
I made the assumption that the view port and view size were the same size. The more general code would be:
Code:
draw_surface_stretched(SurfShip,view_xport[0],view_yport[0],view_wport[0],view_hport[0]);
This will draw the surface with position and size as the view port so it should be properly mapped.
My apologies for all the code iterations! If this doesn't work please supply a screenshot so that I can see what the issues is.
I've posted a screenshot above, look to the ship:
 

Xor

@XorDev
It doesn't look like the ship is drawing to the surface at all. Can I see your full Draw GUI code. You need to make sure the shader is applied first and then you draw the ship surface.
 
It doesn't look like the ship is drawing to the surface at all. Can I see your full Draw GUI code. You need to make sure the shader is applied first and then you draw the ship surface.
Draw GUI of oShip1 // Draw Event is empty with only a comment
Code:
if !surface_exists(SurfShip) //You can check it's existence in the draw event cut out an if.
{
   SurfShip = surface_create(320,180); //320x180 is multiplied to make it 1920x1080
}

// You were setting the surface whether or not it existed (no longer matters).
surface_set_target(SurfShip);
//Here's the main problem!
//You were drawing the sprite as though it was in the room, but in a surface it's different.
//Here I calculated the position relative to the view because the surface ignores the view.
//This should work for different view sizes and positions, but not rotation (it's harder).
var X,Y,Xscale,Yscale;
X = x-view_xview[0];
Y = y-view_yview[0];
Xscale = 320/view_wview[0];
Yscale = 180/view_hview[0];
draw_sprite_ext(self.sprite_index,0,X*Xscale,Y*Yscale,image_xscale*Xscale,image_yscale*Yscale,image_angle,image_blend,image_alpha);
surface_reset_target();
//Scale this as you need to fit the view.
draw_surface_stretched(SurfShip,0,0,view_wview[0],view_hview[0]);
Heres the shader's extension (I uploaded to my Drive to be able to share to you) if you want to check it
https://drive.google.com/open?id=1P_X8ZrhaeqqkUsox7JZiv0Qgy6llfSck
 
  • Like
Reactions: Xor

Xor

@XorDev
Sadly, I really can't help just off the info there. All I can assume is that the boat is being drawn before the water shader somehow and it should be drawn on top. If the water is drawn in the GUI event of some other object, then make sure that the boat depth is lower (like -1000) or that the code is put into the Draw GUI End Event.
 
Sadly, I really can't help just off the info there. All I can assume is that the boat is being drawn before the water shader somehow and it should be drawn on top. If the water is drawn in the GUI event of some other object, then make sure that the boat depth is lower (like -1000) or that the code is put into the Draw GUI End Event.
The shader is working with so many scripts but heres the Draw script of it:
Code:
///TrueWater_draw_water()
/*
USAGE:
  This script is intended to be called from the Post Draw or DrawGUI Event of obj_TrueWater_controller.
  No arguments required.
*/

TrueWater_surface_check();

draw_surface(application_surface,0,0);

shader_set(TrueWater_water);   
    shader_set_uniform_f(uni_camera_pos, camera_pos_x * aspect_ratio_x, camera_pos_y * aspect_ratio_y, var_resolution_x * aspect_ratio_x, var_resolution_y * aspect_ratio_y);
    texture_set_repeat_ext(samp_normal_map, true);
    texture_set_repeat_ext(samp_diffuse_tex, true);
   
//For each light object, create the shadows within its range
for (i=0; i<ds_grid_height(TrueWater_water_grid); i+=1)
  {
    var object = TrueWater_water_grid[# 0, i];
   
     if instance_exists(object)
     {
        //Get each objects variables from the grid
        var pos_x = (object.x - view_xview[TrueWater_room_view]) * aspect_ratio_x;
        var pos_y = (object.y - view_yview[TrueWater_room_view]) * aspect_ratio_y;       
        var spr_width = TrueWater_water_grid[# 1, i] * aspect_ratio_x;
        var spr_height = TrueWater_water_grid[# 2, i] * aspect_ratio_y;
        var xspeed = object._water_tick_x;
        var yspeed = object._water_tick_y;
        var spr_index = object.sprite_index;
        var img_index = object.image_index;
        var normalmap = object._water_normal;
        var normalmap_repeat = object._water_normal_repeat;
        var refraction_amount = object._water_refraction_amount;
        var perspective = object._water_perspective;
        var spr_coords = sprite_get_uvs(spr_index, img_index);
               
        //Set the correct textures for each object
        texture_set_stage(samp_diffuse_tex, sprite_get_texture(spr_index,img_index));
        texture_set_stage(samp_normal_map, sprite_get_texture(normalmap, -1));
        shader_set_uniform_f(uni_time, xspeed, yspeed);
        shader_set_uniform_f(uni_water_perspective, perspective);
       
        //Set the size, postion, speed and refraction for each object
        shader_set_uniform_f(uni_water_ypos, pos_y);
        shader_set_uniform_f(uni_texture_resolution, spr_width, spr_height);
        shader_set_uniform_f(uni_texture_position, pos_x, pos_y, refraction_amount, normalmap_repeat);
        shader_set_uniform_f(uni_sprite_coords, spr_coords[0], spr_coords[1], spr_coords[2], spr_coords[3]);
       
        draw_surface_part(application_surface, pos_x, pos_y, spr_width, spr_height, pos_x, pos_y);
      }
    }   
shader_reset();
It draws on application_surface, and SurfShip is above it, whats the problem :S
 
Top