Asset - Scripts Fast Lights 2

Buff

Member

An efficient surface based 2d lighting and shadow system packed with features and optimizations, now for GMS2.​

Marketplace link.
Download the example project.
Download the Caster Creator executable.
Download the Caster Creator project.

I am happy to announce an upgrade to the popular Fast Lights, surface base lighting engine, now for GameMaker Studio 2.


Fast Lights is a highly optimized set of scripts that perform the drawing of 2d lights and polygonal shadows for games built with GMS.

This is a major upgrade to Fast Lights 1 and is not backwards compatible, though upgrading should not be difficult.
This update covers the following improvements:
  • Lights, casters, and the overall system are no longer tied to instance variables and globals.​
  • Support for multiple lighting systems in the same room, each with independent lights and casters.​
  • Lightmap masks which allow for lit areas that are shapes other than rectangles.​
  • New Caster Creator program for making point lists to use in a shadow caster.​
  • Overall improved code quality.​
The example project* should explain how to use the scripts, which are well documented. There are also some other goodies in the project including a simple platformer with a character controller and state based animation manager. Feel free to use any of this code.

The Caster Creator** is available in both a Windows executable and source. Feel free to use the source code or remix the project to your liking.

If you have any questions please check the original Fast Lights forum thread, many questions have been asked and answered there, otherwise ask your question on this thread and I will try to answer it when I can.

Fast Lights 2 is completely free to use, even for commercial projects, no credit required.
If you make something cool with Fast Lights, I'd love to see it, post it here!



*The example project contains free assets from https://www.gameart2d.com/freebies.html
**Caster Creator uses the incredible editable textbox from https://www.stuffbydavid.com/
 
Awesome work, thanks for taking the time to put this together and make it available for free to the community, very cool. I've added to my account and I'll give it a try here soon.

One quick question, and this is an issue I've had with just about all dynamic lighting systems like this, but with your system here is it possible to have pixelated shadow edges? It seems all these systems generate either sharp/hard edges or soft/smooth edges, but I need pixelated edges. My project's resolution is 480x270 and so I'd like to maintain the pixel effect to match the graphics.

My current solution, which is possibly the only solution, is to render my dynamic shadows to a surface at a smaller resolution and then rescale it to match the game. This works, however it creates a different issue. When doing that I inadvertently lose sub pixels which causes some jaggedness when I move the surface to follow the player. So my solution to that was to stop moving the shadow surface and just make it the entire room size and only draw the portion visible in the view. This works but it's not nearly as efficient as having a much smaller surface that I move around, especially in bigger rooms.

Hopefully that makes sense. I'd really love to find a system that can handle this in a better way, but I just don't know if it's possible.
 

Buff

Member
Awesome work, thanks for taking the time to put this together and make it available for free to the community, very cool. I've added to my account and I'll give it a try here soon.

One quick question, and this is an issue I've had with just about all dynamic lighting systems like this, but with your system here is it possible to have pixelated shadow edges? It seems all these systems generate either sharp/hard edges or soft/smooth edges, but I need pixelated edges. My project's resolution is 480x270 and so I'd like to maintain the pixel effect to match the graphics.

My current solution, which is possibly the only solution, is to render my dynamic shadows to a surface at a smaller resolution and then rescale it to match the game. This works, however it creates a different issue. When doing that I inadvertently lose sub pixels which causes some jaggedness when I move the surface to follow the player. So my solution to that was to stop moving the shadow surface and just make it the entire room size and only draw the portion visible in the view. This works but it's not nearly as efficient as having a much smaller surface that I move around, especially in bigger rooms.

Hopefully that makes sense. I'd really love to find a system that can handle this in a better way, but I just don't know if it's possible.
Hey rob,

You have the right idea. Fast Lights uses the same technique to save memory, you can change the quality parameter in light_init to create a smaller light map that gets scaled up. Fast Lights also supports only drawing a light map the size of the view, if you choose.

Try changing the quality parameter in light_init in the create event of ControlPlatformer in the example project to 0.1 or 0.05 for an extreme effect and you'll get something like this.
GML:
global.system = light_init(width, height, 1024, color, 0.05, -1, noone);
1588302702148.png
 

Snewpy

Member
Awesome work! Although, I see a problem with the masking feature, as changing the view size to something lower than 1024 x 768 causes issues.

New view size
Runner_2020_05_31_21_54_45_371.png
Original view size
Runner_2020_05_31_21_43_33_835.png
 

Buff

Member
Awesome work! Although, I see a problem with the masking feature, as changing the view size to something lower than 1024 x 768 causes issues.

New view size
View attachment 31689
Original view size
View attachment 31691
There's actually no mask on that area, the first house is just a square lighting surface, which does not require a mask.
Is changing the view size the only thing you did? I cannot reproduce the issue. Also can you describe the issue further? It looks like the light is ignoring some of the blocks.
 

Snewpy

Member
There's actually no mask on that area, the first house is just a square lighting surface, which does not require a mask.
Is changing the view size the only thing you did? I cannot reproduce the issue. Also can you describe the issue further? It looks like the light is ignoring some of the blocks.
I probably should've explained it more indepth, but basically the masking surface seems to move whenever the camera moves. I tested this on a new project file with the only difference being the view change, and the same issue occured but with the 2nd house. For the screenshots above, I added an object that covers the whole area with the lighting surface with a mask covering the first house, hence why the light is also ignoring some of the blocks, which is actually the effect I'm looking for. I can send you the project file from the screenshots if that helps.
 
Last edited:

O.Stogden

Member
Does this do something funky like delete all data structures somewhere in the code?

I added it to my game, which ran Fast Lights 1, but now it's in, I get an error about data structures not existing whenever I create a light and try to modify it using light_set_color or light_set_alpha for example.

Doing a quick show_debug_message after the light is created, shows that the ds_list for that light is populated with the correct info, but I'm guessing that ds_list gets deleted the step after, and the code to modify the light then crashes the game due to it not existing anymore.

I removed the code to draw the lighting, but doing a quick debug check, all the ds_lists in my game get deleted when it starts trying to handle lighting. I'm not sure if one of the "for" loops in light_draw might be destroying ds_lists that aren't associated with lighting.
 

Buff

Member
I probably should've explained it more indepth, but basically the masking surface seems to move whenever the camera moves. I tested this on a new project file with the only difference being the view change, and the same issue occured but with the 2nd house. For the screenshots above, I added an object that covers the whole area with the lighting surface with a mask covering the first house, hence why the light is also ignoring some of the blocks, which is actually the effect I'm looking for. I can send you the project file from the screenshots if that helps.
Ok, I did a little debugging and found a bug where the mask is drawn in the wrong location if the view size does not match the application_surface size. I was able to fix this by drawing the application_surface with the view size on line 295 in light_draw:

GML:
draw_surface_stretched(application_surface, (camera_get_view_x(view_camera[view_current]) - x_pos) * quality, (camera_get_view_y(view_camera[view_current]) - y_pos) * quality, camera_get_view_width(view_camera[view_current]) * quality, camera_get_view_height(view_camera[view_current]) * quality);
I have updated the package and the example project with this fix.
 

Buff

Member
Does this do something funky like delete all data structures somewhere in the code?

I added it to my game, which ran Fast Lights 1, but now it's in, I get an error about data structures not existing whenever I create a light and try to modify it using light_set_color or light_set_alpha for example.

Doing a quick show_debug_message after the light is created, shows that the ds_list for that light is populated with the correct info, but I'm guessing that ds_list gets deleted the step after, and the code to modify the light then crashes the game due to it not existing anymore.

I removed the code to draw the lighting, but doing a quick debug check, all the ds_lists in my game get deleted when it starts trying to handle lighting. I'm not sure if one of the "for" loops in light_draw might be destroying ds_lists that aren't associated with lighting.
Hey O.Stogden,

light_draw keeps track of the lights that have already been deleted and removes them from the lights ds_list but it does not destroy and ds_lists other than local ones. The only other place where lists get destroyed are in light_delete, light_caster_delete, and light_destroy.

Buff
 

Snewpy

Member
Ok, I did a little debugging and found a bug where the mask is drawn in the wrong location if the view size does not match the application_surface size. I was able to fix this by drawing the application_surface with the view size on line 295 in light_draw:

GML:
draw_surface_stretched(application_surface, (camera_get_view_x(view_camera[view_current]) - x_pos) * quality, (camera_get_view_y(view_camera[view_current]) - y_pos) * quality, camera_get_view_width(view_camera[view_current]) * quality, camera_get_view_height(view_camera[view_current]) * quality);
I have updated the package and the example project with this fix.
This helped the mask surface location problem, although one thing I'm worried about(that I have yet to experiment on) is that if the view size does not match the application surface, the mask surface won't be scaled to match the application surface, meaning there could be some artifacts when things are drawn on the surface, especially when rotating sprites.

Edit:I was able to fix it by simply scaling the masking surface and then scaling back down when drawing the surface.
 
Last edited:
Top