{"id":20851195,"url":"https://github.com/elementbound/gms-layer-core","last_synced_at":"2026-03-19T17:49:45.691Z","repository":{"id":71330458,"uuid":"69769109","full_name":"elementbound/gms-layer-core","owner":"elementbound","description":"Fancy-ish demo and RAM usage experiment in GMS 1.4","archived":false,"fork":false,"pushed_at":"2016-12-10T13:54:17.000Z","size":12173,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-07T03:51:20.703Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Game Maker Language","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elementbound.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-01T23:24:57.000Z","updated_at":"2025-10-03T10:12:42.000Z","dependencies_parsed_at":"2023-03-13T20:20:28.474Z","dependency_job_id":null,"html_url":"https://github.com/elementbound/gms-layer-core","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/elementbound/gms-layer-core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elementbound%2Fgms-layer-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elementbound%2Fgms-layer-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elementbound%2Fgms-layer-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elementbound%2Fgms-layer-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elementbound","download_url":"https://codeload.github.com/elementbound/gms-layer-core/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elementbound%2Fgms-layer-core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29539974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T08:11:05.436Z","status":"ssl_error","status_checked_at":"2026-02-17T08:09:38.860Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T03:12:47.186Z","updated_at":"2026-02-17T10:03:55.545Z","avatar_url":"https://github.com/elementbound.png","language":"Game Maker Language","readme":"# layer-core\n\n![Final product](https://raw.githubusercontent.com/elementbound/gms-layer-core/master/dev/final.png)\n\nThis sample is one part fancy 3D content, one part trying to cut back on memory usage.\n\nMy current project, at this moment, consumes around 1 GB of RAM while running. Most of this comes from textures.\nI load my textures from external files and simply store them as backgrounds, which takes a huge amount of memory.\nTo combat this, I have decided to have two types of textures:\n  * _Permanent textures_: This is what my current project uses. Load image into background, be happy with that, devour all the RAMs.\n  * _Volatile textures_: These textures are stored in surfaces, which reside (mostly?)* on the GPU.\n    The drawback is that they can just vanish at any time. To combat this, volatile textures are always checked, and if they are\n    lost, they resort to a default texture, and get reloaded some time later. Reloading textures is spread out over multiple steps,\n    so the game doesn't just lock up for several seconds.\n\nI also hope that the thing looks nice :P\n\n## Stats ##\n\n  * With volatile textures: 108 MB\n  * With permanent textures: 153 MB\n\nSince I happen to not use too many textures ( although I cranked up the resolution a bit, just in case ), the difference is not\nearth-shattering.\n\nAfter adding 21 MBs of 2k PNG files and running it again:\n  * With volatile textures: 350 MB\n  * With permanent textures: 520 MB\n\n## Settings ##\n\nThe demo starts off in full-screen, in desktop resolution by default. You can change this behaviour by changing rSize's Creation\nCode. Most of it is self-explanatory. There are two modes of anti-aliasing. You can set aa_mode to _'msaa'_, which is the default\nmethod supported by GMS. The other method, _'brute'_ is a quick hack, because _'msaa'_ doesn't smooth the edges inside the core.\nIf you use _'brute'_, it's not really worth it to set _aa_ above 2.\n\n## Code ##\n\nSome things worth checking out are:\n\n### Shaders ###\n\nWith the lava shader, I didn't want to run into the usual problem of properly unwrapping spheres. I decided to generate my\nmeshes, so I didn't have to bother with mesh loaders ( that'll happen in another tutorial/samle :P ). So I just went with\na regular UV sphere, which is known to distort on the poles, unless you use some special method of unwrapping.\n\nMy solution here was triplanar mapping. [This](https://gamedevelopment.tutsplus.com/articles/use-tri-planar-texture-mapping-for-better-terrain--gamedev-13821)\narticle explains it pretty well.\n\n ---\n\nThe shaders also often use ramps, which is also a nice little trick worth knowing.\n\n ---\n\nWith the pillars sticking out from the core, the process is a bit more complex. To see the original concept, you can look\nat dev/concept.blend's M.Earth material. It's composed of a gradient over the whole cylinder, and a messy grass part on\nboth ends.\n\nFor the grass part, I also sample a pre-baked noise texture, and compare it to a threshold. This value is calculated based\non the cylinder's UVs. We can use the fact that the V coordinate goes from zero to one, spanning the mesh's whole height.\nSo, if the grass is high enough, it's visible, otherwise it isn't. With the same method, we also apply a gradient to the\ngrass part.\n\nThe best way to understand this is to either look at the .blend file, or to look at the pixel shader code.\n\nSince I don't use any kind of lighting in this demo, that also has to be faked somehow. In Blender, I use approximate\nindirect lights. But looking at it, it's easy to notice that it's mostly random-brightness gradients on the sides of\nthe cylinder. That's easily done through a texture. The sides texture contains 32 gradients with various intensity,\nand the cylinder's UV's are transformed in the vertex shader to only cover six random gradients ( next to each other ).\n\nThis mostly works, the only exception is when two cylinders with very different brightnesses overlap.\n\nLastly, we need to give the cylinders the feeling that they are over a molten core, so we add a weak ambient lighting.\n\n### Assets ###\n\nThe sample uses a very basic asset manager. The concept is to have a central object managing all the resources, with\na dedicated map to each resource type. These can be later used to access each resource by name. If you'd like to get\nmore fancy, you could write get/set/exists/load scripts for each resource type. This would allow for a 'default'\nresource to be returned when the selected one doesn't exist. This can't easily be done with the raw map accesses\nI do in this sample.\n\n ---\n\nAnother aspect of the asset management is loading. You could delegate this functionality to a different object, and\nyou could also separate the loading code to different objects/scripts, but in our case, the assets are simple enough\nto just have everything in the _assets_ object.\n\nSo, we have a queue for resources to be loaded. Each resource is queued as a (type, name, data...) triplet. Note that\nthe data part can have multiple values.\n\nFor example, the only data a texture needs is the file name:\n\u003e ('texture', 'earth-ramp', 'textures/earth-gradient.png')\n\nHowever, if we want to generate a mesh, we also need to know how detailed it should be:\n\u003e ('mesh/gen', 'cylinder', meshgen_cylinder, 6)\n\nThe loader dequeues a single task in each step to execute. This way we can have very simple ( and non-animated! )\nprogress bars. You could also easily extend this loader to support async tasks ( like load an image from a URL and\nnot block while we wait for the image ). Just make each task an object, that lives until the task is complete\n( and preferably does not ruin the framerate too much ).\n\n### Meshes ###\n\nSee _mesh_data_. We could easily go with just storing vertex buffers in the _assets_ object's mesh pool, but that's\na bit limited. Storing some form of additional mesh data ( even if it's just a vertex count ) gives many more\npossibilities. To stay with our example, we could easily output the amount of submitted vertices, or the number\nof rendered faces just by simply keeping an accumulator variable.\n\nThis also lets us easily manipulate meshes - transform them, remove faces, bend them, or even spawn a particle at\neach vertex for some fun effects. This also increases memory usage, so the mesh data lists could be just cleared\nafter the mesh is built ( aka. its vertex buffer is generated from the lists containing vertex data ).\n\n ---\n\nSince a single mesh could be rendered multiple times at different places, we also have a _mesh_object_ object.\nThese point to a _mesh_data_ instance to use, and have their own transform.\n\nThe more interesting part about this object is that it also handles shader data. Now I'm not saying that this\nis generally a nice design, since in more complex renderers and scenes, the same mesh instance could be rendered\nmultiple times per frame, with different shaders, parameters and goals.\n\nHowever, in our case, each mesh instance is rendered only once, with only one shader, per frame. So it made sense\nto store the shader settings in the instance itself, too. This allows for a very handy and convenient way\nto specify shader settings. Combine this with the ease of querying resources, and you get something like this:\n\n```\n// From scene object, Alarm 0 event:\nwith(instance_create(0,0, mesh_object)) {\n    data = assets.meshes[?\"cylinder\"];\n    texture = assets.textures[?\"earth-ramp\"];\n\n    // [...]\n\n    shader = shd_earth;\n\n    samplers[?\"u_Sides\"] = assets.textures[?\"sides\"];\n    samplers[?\"u_Noise\"] = assets.textures[?\"grass-noise\"];\n    samplers[?\"u_GrassRamp\"] = assets.textures[?\"grass-ramp\"];\n\n    uniforms[?\"u_GrassStart\"] = random_range(0.925, 0.975);\n    uniforms[?\"u_SideIntensity\"] = random_range(0.75, 1);\n    uniforms[?\"u_Ambient\"] = array(0.95/4, 0.325/4, 0.0/4, 0.0);\n    uniforms[?\"u_TextureMatrix\"] = matrix_build(irandom(32)/32,0,0, 0,0,0, 6/32,1,1);\n\n    // [...]\n}\n```\n\nYou can update these values at any time, so animating shader parameters is pretty easy as well.\n\n### Utility scripts ###\n\nSee _concat_. This script takes an arbitrary amount of arguments, concatenates them as strings\nand returns the result. Handy for most kind of string assembly. Until we have a 16 argument\nlimit, keep an eye on that.\n\n_rtdbg_ stands for real-time debug. Whether this makes sense or not ( it blocks the whole game ),\nI'll let you be the judge of that. Argument-wise it is the same as _concat_, except it displays\nthe result in a message box.\n\n__All scripts in the project are public domain. This includes everything in the scripts directory.__\nFor the rest of the project, see [LICENSE](LICENSE). \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felementbound%2Fgms-layer-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felementbound%2Fgms-layer-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felementbound%2Fgms-layer-core/lists"}