• 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!
  • Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Question - Code Question. External assets and drawing layers to surfaces.

T

Tankwars

Guest
I'm still learning the ropes of GMS:2, so I apologise if these questions sound a little stupid. :oops:

First question, is it possible to draw specific layers of any type to a surface? Reason i'm asking is because I want to try to add multiple shader effects to some layers, but not others. In GMS:1, I had to draw sprites to one surface to apply an effect, then feed that surface into a new surface to apply another effect, before finally drawing the last surface in the chain. I know that in GMS:1, you could only have one shader set at a specific time, and it seems to work the same way in GMS:2. I am aware of the layer_shader() function, but you can only have one active for each layer it seems. Combining two shader effects into one wouldn't really help, because sometimes you need a bit more flexibility over how an effect behaves.

Second question, will there be any further functionality for external asset management? I've read from others in the past that loading external sprites puts them on their own texture page. Wasn't that something to be avoided because of the numerous texture swaps? Will we get functions to add external sprites, and put them in a specific texture group/page? I think it would be pretty sweet to have this because you could unload art assets you don't need from memory, but you when you do need them, they could go in a shared texture group/page of your choosing to reduce texture swaps. I believe it also helps with exe file size? I could be wrong.

Feedback appreciated. :cool:
 
Last edited by a moderator:
T

Tankwars

Guest
Just clarifying what i'm talking about here.

Draw layers to surfaces:
------------------------------------------------------------------
The sort of functionality I'm looking for is:
Code:
surface_set_target(surf);

draw_layer(layer_id, x, y, xscale, yscale, width, height, angle, colour, alpha);

surface_reset_target();
Perhaps it could be split into other functions such as:
draw_layer_ext()
draw_layer_stretched()
draw_layer_general()
draw_layer_part()
draw_layer_part_ext()

maybe it could be type specific?
draw_layer_tiles_ext
draw_layer_sprites_ext
etc...

should also be possible to do something like this as well if things are set up correctly (also usable when setting surfaces to views):
Code:
if (view_current == 0)
{
   //draw tile layers
   draw_layer(parameters);
   draw_layer_ext(parameters);
   draw_layer_stretched(parameters);
   draw_layer_part(parameters);
}

if (view_current == 1)
{
   //draw instance layers
   draw_layer(parameters)
   draw_layer_ext(parameters);
}
------------------------------------------------------------------

External art asset management:
-------------------------------------------------------------------
There was another thread about this, I can't find it though. It was going on about functions to add more control over adding external art assets at runtime.

Right now, there is:
sprite_add(fname, subimages, removeback, smooth, xorig, yorig)

Would be nice if there was also:
sprite_add_ext(fname, subimages, removeback, smooth, xorig, yorig, texturegroupid)
variablename = texture_group_create(); (possibly?)

Obviously, there would need to be ways of freeing things like dynamically created texture groups from memory, removing added sprites (that works with the proposed functions) and support for adding tiles. Hopefully this is a little more clear :)
-----------------------------------------------------------------
 

mMcFab

Member
I'm still learning the ropes of GMS:2, so I apologise if these questions sound a little stupid. :oops:

First question, is it possible to draw specific layers of any type to a surface? Reason i'm asking is because I want to try to add multiple shader effects to some layers, but not others. In GMS:1, I had to draw sprites to one surface to apply an effect, then feed that surface into a new surface to apply another effect, before finally drawing the last surface in the chain. I know that in GMS:1, you could only have one shader set at a specific time, and it seems to work the same way in GMS:2. I am aware of the layer_shader() function, but you can only have one active for each layer it seems. Combining two shader effects into one wouldn't really help, because sometimes you need a bit more flexibility over how an effect behaves.

Second question, will there be any further functionality for external asset management? I've read from others in the past that loading external sprites puts them on their own texture page. Wasn't that something to be avoided because of the numerous texture swaps? Will we get functions to add external sprites, and put them in a specific texture group/page? I think it would be pretty sweet to have this because you could unload art assets you don't need from memory, but you when you do need them, they could go in a shared texture group/page of your choosing to reduce texture swaps. I believe it also helps with exe file size? I could be wrong.

Feedback appreciated. :cool:
I can maybe help with the draw_layer stuff in the meantime:

Not sure if we'll get specific layer drawing functions, but you can draw layers to a surface using layer scripts.
You need a script that contains surface_set_target() and use "layer_script_begin" to set it, and a script that resets the surface target that is set to the layer with "layer_script_end".
I've tested this, and the surface needs to be the room size or whatever your maximum bounds are - the layer is drawn based on world position, not view position, so draw the surface at [0,0] to appear as normal. You can change this behaviour with matrix transforms however.
In the meantime, to apply other transforms you'd use matrices and use shaders for color/alpha blending. Again, set these in the scripts and use "layer_shader" etc.

As for drawing layers to specific views, I think you may be able to do that with camera scripts - use "camera_set_begin_script" and test for the view (still using view_current), then use "layer_set_visible" as necessary

I know I've not been super in-depth - and I haven't really tested the camera thing, but this is how I think I'd go about some of this stuff (unless draw_layer functions were added ;)).
 
T

Tankwars

Guest
Just tested some of the ideas you suggested. Setting the surface target inside the layer scripts seems to work. However, the problem here is that it isn't view based, so it won't move around when the view position/size changes. I haven't really got any experience with the matrix functions, so I don't know how to use them unfortunately. :/

The view testing inside the camera scripts and toggling layer visibility didn't seem to work, I'm guessing the 'visible' setting when true takes place on the next game step. It is so close, there's gotta be a way of setting specific layers to surfaces, while also being view based.

I may quickly test the camera script method again tomorrow (or today technically xD) just in case I did something wrong. Right now, I need sleep. :cool:
 

mMcFab

Member
Just tested some of the ideas you suggested. Setting the surface target inside the layer scripts seems to work. However, the problem here is that it isn't view based, so it won't move around when the view position/size changes. I haven't really got any experience with the matrix functions, so I don't know how to use them unfortunately. :/

The view testing inside the camera scripts and toggling layer visibility didn't seem to work, I'm guessing the 'visible' setting when true takes place on the next game step. It is so close, there's gotta be a way of setting specific layers to surfaces, while also being view based.

I may quickly test the camera script method again tomorrow (or today technically xD) just in case I did something wrong. Right now, I need sleep. :cool:
I wasn't certain the camera script would work, but it's a bummer that it doesn't. I suppose the workaround would be to draw all layers to view-specific surfaces and draw them per view, but that's a big load of stuff just to show or hide layers depending on the view.

It's probably worth you looking at the matrix functions at some point, they are rather simple yet powerful and don't actually require any real understanding of matrices (unless you get to multiplying them or work in 3D, then you need to know them a little better).
Here's a little test script that does render to a surface that is the size of the viewport and draws the layer based on view position - just to give you an idea on what you could do:
This is probably really buggy, but it was just for a quick test. When rendering back into the same view I got a little bit of jitter when the view was moving. You don't get the jitter when rendering to the GUI (and probably not when rendering to another surface).
Code:
var vp_w = view_get_wport(view_current);
var vp_h = view_get_hport(view_current);

if(!surface_exists(global.laySurf))
{
    global.laySurf = surface_create(vp_w, vp_h);
}

surface_set_target(global.laySurf);

var viewCam = view_camera[view_current]

//Build and translate the "view"
var viewBoundMatrix = matrix_build_identity();
viewBoundMatrix[12] = -camera_get_view_x(viewCam);
viewBoundMatrix[13] = -camera_get_view_y(viewCam);
//show_debug_message(viewBoundMatrix[12]);


viewBoundMatrix = matrix_multiply(viewBoundMatrix,
                                matrix_build(0,//We've already translated the view, so these parameters don't matter
                                  0,
                                  0,//z depth not relevant here
                                  0,//x rotation does not apply here
                                  0,//y rotation does not apply here
                                  0,//camera_get_view_angle(viewCam),//The view angle matters more when drawing to gui - a little glitchy as I haven't fully tested it
                                  vp_w / camera_get_view_width(viewCam),
                                  vp_h / camera_get_view_height(viewCam),
                                  1 //z-scale should probably stay at 1 here
                                      ));


matrix_set(matrix_world, viewBoundMatrix);
You also need to reset the world matrix post layer draw (or post camera) with "matrix_set(matrix_world, matrix_build_identity())".
It's probably not worth resizing to the view bounds in the room since you'd just end up with more pixels than you're actually ouputting. Of course, this varies depending on what you intend to achieve.
Then you can either draw it at the view position or in the GUI. To make sure it scales correctly to the view you'd probably need to use "draw_surface_stretched"

Funny though, I just mentioned only needing to know matrices a little better in order to understand stuff like matrix_multiply, and then I go and use it! Don't worry too much on it - in this case I'm just translating the layer before scaling it down so it stays consistent with normal rendering. The only thing that might need a little more work here is view angle.
 
T

Tankwars

Guest
@MaddeMichael

Just played around with the code you posted. Looks like I've managed to get two layers on onto their own surface, while also being view based! Both are instance layers right now, though i'm assuming it will work the same way for other layer types. Both view surfaces are drawn to another surface named 'PrimarySurface' (the application surface is disabled), which is what gets drawn to the screen right now.

Still got to do more testing though, various things have to work, such as:
1) Dynamic view zooming, hopefully I can rescale the matrix views inside the layer scripts when the player wants to zoom in/out with... let's say, the mouse wheel.
2) Drawing multiple layers onto the same view surface.
3) Multiple graphical effects on separate layers through shaders, which I think can be done through surface chains now that I can get the surface texture that the layers are assigned to. Post-processing effects essentially.
4) Compatibility with changing the resolution of the surfaces, so things will scale correctly on for example: 1600x900, 1920x1080, 2880x1620, 4K, things like that. So the game will display correctly on different monitors. I've got this half working, but still need to do more tests and make it work for windowed mode as well.

There's probably other things on the to-do list that I can't quite remember right now. ;)

You mentioned that '0,//camera_get_view_angle(viewCam)' in matrix_build() is a little glitchy. What does it do exactly?

EDIT: also, would matrix views perform well on larger rooms like 10000x10000 in size, but while having a view size of 1920x1080 or similar?

Anyway, you've been a HUGE help with this. I'll keep you updated with how things go. Thanks! :)
 
Last edited by a moderator:

mMcFab

Member
@MaddeMichael

Just played around with the code you posted. Looks like I've managed to get two layers on onto their own surface, while also being view based! Both are instance layers right now, though i'm assuming it will work the same way for other layer types. Both view surfaces are drawn to another surface named 'PrimarySurface' (the application surface is disabled), which is what gets drawn to the screen right now.

Still got to do more testing though, various things have to work, such as:
1) Dynamic view zooming, hopefully I can rescale the matrix views inside the layer scripts when the player wants to zoom in/out with... let's say, the mouse wheel.
2) Drawing multiple layers onto the same view surface.
3) Multiple graphical effects on separate layers through shaders, which I think can be done through surface chains now that I can get the surface texture that the layers are assigned to. Post-processing effects essentially.
4) Compatibility with changing the resolution of the surfaces, so things will scale correctly on for example: 1600x900, 1920x1080, 2880x1620, 4K, things like that. So the game will display correctly on different monitors. I've got this half working, but still need to do more tests and make it work for windowed mode as well.

There's probably other things on the to-do list that I can't quite remember right now. ;)

You mentioned that '0,//camera_get_view_angle(viewCam)' in matrix_build() is a little glitchy. What does it do exactly?

EDIT: also, would matrix views perform well on larger rooms like 10000x10000 in size, but while having a view size of 1920x1080 or similar?

Anyway, you've been a HUGE help with this. I'll keep you updated with how things go. Thanks! :)
Glad I'm helping!
The code should work on other layer types - the type I focused more on when testing was tile layers, and they worked fine.
View zooming worked in a little test - I actually tested the code with my camera tutorial demo and the zooming worked (This uses the mouse wheel too!). Although I should have passed the base/starting view size instead of the viewport size for scaling. Hm.

The camera angle thing I mentioned being glitchy - technically, I don't think there were any glitches, it was more down to "I haven't tested it in properly in all cases so it might break sometimes" - it should work okay though as it seemed to on the GUI drawing test. As for what it does, it just includes the view angle into the transform. There's a possibility I just need to tweak when this transform applies (perhaps before scale, I'm not sure yet - I don't use view angle very often).

As for performance on matrix views in large rooms - they should work fine with little to no performance hits - the math is always the same regardless of room/view size. Room size should have no impact since this example uses the actual output port. The only minor hit will be with actually drawing larger surfaces, which is standard anyway (drawing a HD image will always take longer than drawing a 640x480 image, for example). To make it a little faster, you could probably calculate this transform matrix in a camera begin script and then pass use it in the layer scripts (then the matrix is calculated once per view, instead of once per layer per view)
 
T

Tankwars

Guest
Ok, time for a little update. :cool:

1) Tested some basic dynamic zooming, works like a charm.
2) Drawing multiple layers on one surface worked in a test.
3) --- I will get to this in just one moment....
4) I don't see why this wouldn't be possible. If no. 1 is possible, then this should be as well. Haven't gotten around to properly testing this yet, because of no. 3.

Ok, about number 3:

There seems to be an issue with the blending shader I'm using on the Primary Surface. It is not behaving as expected. Funny thing is, it works completely fine in GMS1. I have found where the problem starts in the code, but it doesn't make sense to me why it isn't working, I suspect it's a bug, but I don't know. I will be opening a new thread about this at some point though, since it is a little bit off topic for this thread.
 
Top