• 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 How to use Texture Pages?

TheBroman90

Member
I'm working on an isometric game which means that I need a lot of sprites for all directions.


In my current test the character walks in 8 directions with 8 frames per animation.
So 64 sprites for just a walk animation.

To reduce the amount of texture swaps I guess I need to organize my texture pages. But I have never done that before.
I know that I should put menu sprites on one page for example, but how do I best organize my character sprites? :)
 

Simon Gust

Member
Since it's this type of game, it probably wont have different levels. Thinking about it, it's probably going to be bad no matter how you do it because of 2.5D and how much that's going to have you swap a texture due to depth ordering. The best solution would be to just have a gigantic texture page size 8192x8192 or something. Having the menu on a seperate one is fine though.
You could also build your own pages and use vertex buffers but that won't be easy.
 

TheBroman90

Member
So because of my depth ordering I shouldn't bother with texture pages. Is there something else I can do to improve performance with a lot of sprites,
or is there no point in doing isometric games at all?
 

Simon Gust

Member
So because of my depth ordering I shouldn't bother with texture pages. Is there something else I can do to improve performance with a lot of sprites,
or is there no point in doing isometric games at all?
2.5D is very hard, harder than 3D just because of depth ordering.
A tip I have is drawing sprites only if they are in view.
 

JackTurbo

Member
What resolution are your sprites going to be?
Whats your target platform?

How are you handling depth sorting?

Are you using GMS1 or GMS2?
 

TheBroman90

Member
I'm only going to draw characters inside the view.
An isometric tile is 96x48. The character canvas is 96x96 before I trim it in Game Maker to save space.
It's a Windows game.
For depth I'm using depth = -(x + y);
I'm using GMS1.
 
Z

zendraw

Guest
so, it swaps only for things that are displayed, so you dont have to manually not draw out of the view, another thing, the amount of swaps it will do is (different depths in view)*(texture groups used) it doesnt use a texture group that is not required. so if you are displayngtiles at 10 depths + 10 enemies at 10 more depths thats 20 depths, if your enemies and tiles are on 3 pages thats 20x3 swaps. im not sure if this is correct, but from my experience this is how it goes. and the logic to doing isometric is use a dynamic depth only on things that actually need it. for instance you dont need to set a different depth to things that are aways beneath the char, like the ground, you need to set depth only on things that the character can go behind.
 

JackTurbo

Member
In that case I think you'll be fine.

Let look at it this way. If you go with a 2048px square texture pages, which is pretty conservative for PC.
2048/96 = 21
21*21 = 441

So you can fit 441 96px square frames per texture page.

I really dont think this will be a problem.
 

TheBroman90

Member
Thanks, guys! So I guess there won't be a problem. But I can optimize it a bit by putting all my ground images on one texture page.
 

JackTurbo

Member
Yeah, another simple way is if you have any sprites that you will always draw on top of everything (like text), then group them and draw them in draw end event.
 
Z

zendraw

Guest
does draw end event work like draw gui in sense that it draws things on top of everything?
 

DukeSoft

Member
You should try to group drawing as much as possible. I usually disable visibility on all of my objects, and then draw them in batches grouped by the texture page. For example, I have 1 group for walls / ground - in a controller you'd do:
Code:
with (obj_floor) {
    draw_self(); //or event_perform(ev_draw);
}
with (obj_wall) {
    draw_self(); //or event_perform(ev_draw);
}
Then for particles;
Code:
draw_set_blend_mode(bm_add);
with (obj_explosion) {
    draw_self(); //or event_perform(ev_draw);
}
with (obj_fire) {
    draw_self(); //or event_perform(ev_draw);
}
draw_set_blend_mode(bm_normal);
^^ Also grouping sprites that have a special blend mode (because changing the blend mode also resets the drawing batch).

This method can have enormous results (especially if e.g. walls and particles have the same depth) and will save a LOT of draw batch breaking and texture swaps.

EDIT: @blacklemon
No, it just happens after the draw event *for that depth*.

So;

PRE DRAW FOR ALL DEPTHS
Depth 1:
pre-draw
Depth 2:
pre-draw

DRAW FOR ALL DEPTHS
Depth 1:
draw
Depth 2:
draw

POST DRAW FOR ALL DEPTHS
Depth 1:
post-draw
Depth 2:
post-draw

PRE-GUI DRAW FOR ALL DEPTHS
Depth 1:
pre-draw-gui
Depth 2:
pre-draw-gui

DRAW-GUI FOR ALL DEPTHS
Depth 1:
draw-gui
Depth 2:
draw-gui

POST-GUI DRAW FOR ALL DEPTHS
Depth 1:
post-draw-gui
Depth 2:
post-draw-gui

This also happens because the GUI is drawn on a different surface (the gui surface) than the regular draw events (application_surface)
 

DukeSoft

Member
Tiles are good too. Maybe just try to enable the debug overlay and see what changes will bring down your texture page swaps / vertex batches. And still, if all your units / buildings / whatnot are on the same texture page - there is no need to worry. Its all on 1 page so you'll be golden :)

Please do note that some computers can not handle 8192x8192 textures - some can't even handle 4096x4096 - so increasing the texture page size isn't always the best solution.
 
Z

zendraw

Guest
btw, aside from the depth problem with the with (), it is optimal only when drawing things that are atleast 70% of the time on the screen. so popup texts shuld just have theyr own event.

Edit: i think the page size matters only for mobile devices, not that much for PC`s, dont know about laptops. my pc is atleast 10y old with no hardware upgrades and has no problem with 8k pages.
 
You can cut out some of the animations if you flip the sprites horizontally. So instead of 8 animations for each direction, you could use 5. This would work best if the design is symmetrical like the image in the first post.
 

JackTurbo

Member
does draw end event work like draw gui in sense that it draws things on top of everything?
Sort of, but sort of not as well. It depends on what you mean.


My understanding of it is as follows (if I've got anything wrong here, please let me know):
  • What ever is drawn last will be drawn on top of everything else. What ever is drawn first is at the bottom.
  • Depth dictates the draw order of instances.
  • All draw_begin events run first. Then all draw events run. Finally all draw_end events run.
  • Within each event depth dictates the order that instances do their drawing.
  • All gui_draw events run after all regular draw events.
So if you have a bunch of sprites that need to be on top (like text) but need to be positioned in the game space (so cant be gui_draw event) then using the draw_end event will do this. But it also means that because all draw_end events happen after all the regular draw events have finished that these benefit from being all on the same texture page.
 
Z

zendraw

Guest
makes sense, but will have to test it out. altho u can still use the gui draw for drawing things with x/y coords. x-view_xview, y-view_yview.
 
Z

zendraw

Guest
id suggest go with 4k, bare in mind game maker wont create a page bigger then it needs to be, atleast when i take a look at the texture pages they aways at minimum possible size. so if you have a singe 198x198 image in 1 texture page, the page will be 256x256. it wont be 4k. what you set i assume is maximum page size.
 

CMAllen

Member
Sprites that always go 'behind' or 'in front' of everything else should go on one texture page. This would be tiles for the ground or elements for your UI, possibly some unsorted visual effects. Sprites that are used for objects that need to be drawn in variable orders are the ones you need to watch out for. This means anything that can overlap something else (or not, or be overlapped by something else). Walls, trees, enemies, projectiles and skill effects, etc.

I would also point out (being that this is where I'm going with my current project), that you're going to come to loathe build times. Change anything about a texture page, and GM will have to re-sort all the sprite assets on it. Right now, one of my texture pages takes about 20m to rebuild (customizable player sprite, with probably in the area of 10k sub-images to sort), and if I were to include enemies or allies on that page, it would have to be rebuilt any time I added new allies or enemies to my game. Use the project cleaner tool, and all pages have to be rebuilt. I mention this, because the more sprite assets you have crammed onto a given texture page, the longer it takes GM to sort and build it. And the larger a given texture page is to accommodate more sprites, the longer you're going to spend watching that build timer. Food for thought.

I do wish there were some options or controls for how aggressively GM's texture packing system tries to optimize space use. Maybe I don't care about how well optimized it is as much as I care about how quickly it's built (at least not until I'm ready to finalize production).
 

kupo15

Member
You should try to group drawing as much as possible. I usually disable visibility on all of my objects, and then draw them in batches grouped by the texture page. For example, I have 1 group for walls / ground - in a controller you'd do:

This also happens because the GUI is drawn on a different surface (the gui surface) than the regular draw events (application_surface)
That's pretty clever. I'll have to keep that in mind. Also even though I use the GUI draw I guess its really for convenience now that I think about it. You could easily create a gui draw yourself and stick it on the app surface and save a drawing layer for optimization. But I digress...just a thought that came to me :p

Sprites that always go 'behind' or 'in front' of everything else should go on one texture page. This would be tiles for the ground or elements for your UI, possibly some unsorted visual effects. Sprites that are used for objects that need to be drawn in variable orders are the ones you need to watch out for. This means anything that can overlap something else (or not, or be overlapped by something else). Walls, trees, enemies, projectiles and skill effects, etc.

I would also point out (being that this is where I'm going with my current project), that you're going to come to loathe build times. Change anything about a texture page, and GM will have to re-sort all the sprite assets on it. Right now, one of my texture pages takes about 20m to rebuild (customizable player sprite, with probably in the area of 10k sub-images to sort), and if I were to include enemies or allies on that page, it would have to be rebuilt any time I added new allies or enemies to my game. Use the project cleaner tool, and all pages have to be rebuilt. I mention this, because the more sprite assets you have crammed onto a given texture page, the longer it takes GM to sort and build it. And the larger a given texture page is to accommodate more sprites, the longer you're going to spend watching that build timer. Food for thought.

I do wish there were some options or controls for how aggressively GM's texture packing system tries to optimize space use. Maybe I don't care about how well optimized it is as much as I care about how quickly it's built (at least not until I'm ready to finalize production).
This is another reason why texture groups are good because it reduces recompile times a ton when you make a simple change
 

CMAllen

Member
This is another reason why texture groups are good because it reduces recompile times a ton when you make a simple change
It can, yes. But if you try to cram everything into a single texture group/page, you'll get better performance (assuming the target platform can handle a texture page that size), but ANY change to your sprite resources (even a no-change where you just happen to look at a given sprite asset's properties) will require a complete rebuild of that page and all the sub-images that go on it. As I said, I've got one page dedicated to my player sprite (because it has so many pieces) and that page alone takes ~20m for GMS to rebuild. A game using a single 8k texture page will be a nightmare for compile times until you finalize all your sprite resources.
 

kupo15

Member
It can, yes. But if you try to cram everything into a single texture group/page, you'll get better performance (assuming the target platform can handle a texture page that size), but ANY change to your sprite resources (even a no-change where you just happen to look at a given sprite asset's properties) will require a complete rebuild of that page and all the sub-images that go on it. As I said, I've got one page dedicated to my player sprite (because it has so many pieces) and that page alone takes ~20m for GMS to rebuild. A game using a single 8k texture page will be a nightmare for compile times until you finalize all your sprite resources.
Yes and no with your performance point. Firstly, how does your single player sprites take 20mins to recompile? How massively big are your sprites and how many of them do you have to require that much time? (unless a ton of small sprites takes longer time to pack) And you said it only takes up one texture page? (not group) How big are your tex pages?

Edit just saw your post. With that many subimages I think you would be better off splitting your player group into several texture groups. You wouldn't lose any performance benefit doing this and your recompiles will be faster also

But if you try to cram everything into a single texture group/page you'll get better performance (assuming the target platform can handle a texture page that size)
texture group and texture page are not interchangable. You can have a single texture group but it spans multiple pages depending on how many assets are packed in there and the size of the pages. Secondly the performance benefit you are implying only really takes effect if your entire game can fit on a single texture page. If anything, the less tex groups you have the more memory optimization you get and less performance benefit (unless they all fit on one then you get both) On the other end the more texture groups you have, if you do it smartly you get better performance and less memory optimization.

If you cram everything in one tgroup and it doesn't all fit on one tex page then all your assets are going to be strewn across a bunch of pages and you will have to have swaps anyway. Furthermore since they aren't manually organized you could have more swaps than it would take if you split everything up into multiple tgroups depending on how you draw your game and how the sprites are split among the pages.
 

CMAllen

Member
It would definitely have a performance impact, because the total composition is drawn iteratively (the base, clothing articles, customizable pieces, etc). All on different pages, they'd require multiple texture page swaps to draw that one object. GMS2 handles page swaps better than 1.4, but there's still a performance impact associated with every page swap. Since they all fit on a single page, the only swap is when the first draw call for the player starts. No further page swaps until the player object is finished drawing.

In the end, it's all about finding the right mix of organization and condensation -- keeping things in associated groups, but on as few texture pages as you can manage.
 

kupo15

Member
It would definitely have a performance impact, because the total composition is drawn iteratively (the base, clothing articles, customizable pieces, etc). All on different pages, they'd require multiple texture page swaps to draw that one object. GMS2 handles page swaps better than 1.4, but there's still a performance impact associated with every page swap. Since they all fit on a single page, the only swap is when the first draw call for the player starts. No further page swaps until the player object is finished drawing.

In the end, it's all about finding the right mix of organization and condensation -- keeping things in associated groups, but on as few texture pages as you can manage.
Ah ok in that case yeah you are right. I thought you had standalone sprites in which case you could only pull one subimage per frame so multiple texture groups wouldn't make a difference there. So you are able to fit all your player sprite parts on a single tex page? How big are your sprites and how big are your tex pages? I find it hard to believe that you can fit 10k sprites on a single tex page
 

CMAllen

Member
Ah ok in that case yeah you are right. I thought you had standalone sprites in which case you could only pull one subimage per frame so multiple texture groups wouldn't make a difference there. So you are able to fit all your player sprite parts on a single tex page? How big are your sprites and how big are your tex pages? I find it hard to believe that you can fit 10k sprites on a single tex page
The largest is the base sprite, which is 32x64 at most. The rest range from 32x32 to 8x8. But there 5-8 sub-images per sprite, 8 sprites per direction, and multiple different animation sets. So they're not particularly large. But to be honest, I haven't done a page preview (that takes as long as building all of the texture pages), so I can't actually confirm they fit on a single page, but I've set it to 4096x texture page size.
 

kupo15

Member
The largest is the base sprite, which is 32x64 at most. The rest range from 32x32 to 8x8. But there 5-8 sub-images per sprite, 8 sprites per direction, and multiple different animation sets. So they're not particularly large. But to be honest, I haven't done a page preview (that takes as long as building all of the texture pages), so I can't actually confirm they fit on a single page, but I've set it to 4096x texture page size.
There is no way all of your player sprites fit on a single 4096x tex page. It doesn't take 20mins to compile and load a single 4096x page and your number of around 10k player sprites confirm it also. You're player sprites definitely are created on many 4096x pages even though they are all in the same texture group.

Given this fact my original suggestion still stands that if you were to split your player texture group into several groups "tex_player0, tex_player1 etc" you would not be seeing a performance decrease and will be getting faster recompile times. How do I know this? Its because you have no idea what parts of your character are on which texture page. Because they are all grouped in the same tex group GM takes all the sprites and packs them the best it can splitting it up if it has to.

Consider this:
Not knowing fully your game, if you have a base body, clothes, accessory, and a hat, all 4 sprites could be on 4 texture pages with your current grouping in which case you will have 4 tex swaps. However, if you break your player tex page up into many smaller groups that you know will all fit on a single tex page then you can save the swaps. For example:

tex_player0 contains 10 complete player costumes and that's all you assign to it
tex_player1 contains the next 10 complete player costumes and that's it

Now when you go to draw your player you know a complete costume is all found on one texture page no matter what and you will save your swaps. Now you are manually grouping your current mass grouping of sprites into organized tex pages and you will have the same number of tex pages (not that the number of tex pages really matters on its own)

However! If you allow your player to mix and match to create an infinite number of unique costumes then there is no way you will be able draw your character with one swap. Reason being is because the costume the user decides to create is random and the parts could be on 4 different pages. You have no control over what the user will pick to be able to organize your tpages effectively for swaps. At that point just create multiple groups to break things up to make your recompile times much shorter


Also, I don't think you have any reason to be using 4096x tex pages. 2048x is perfectly fine for the size of your sprites. Especially if you aren't able to optimize for swaps the smaller tex pages will be quicker to swap in and out because they are smaller
 
Last edited:

The-any-Key

Member
To optimize, make sure you remove all tiles outside of the view, they also lag.
Note: Even if you have one million tiles outside view. GM wont try to draw them, GM only draw the tiles inside the view. This is a built-in function. Just try to keep all the tiles in the same texture page.
 

YanBG

Member
You can test it in a new example project, i have 3 tiles(they are in a separate background each). Depending on the size of the world(i'm trying to work with one room only) and the changes of the tiles you have to do(hide layers etc), it will be way faster to loop through ~900 tiles(size of the view matters too) at any given time than 14k(that's even only a small 128x128 world grid). The difference here might seem small(from 400 to 300 fps) but i've seen sometimes to drop below 200, if it's not about the drawing i assume GM does some math on the tiles:
 
Top