summaryrefslogtreecommitdiff
path: root/examples/2D_lights
diff options
context:
space:
mode:
Diffstat (limited to 'examples/2D_lights')
-rw-r--r--examples/2D_lights/main.lua241
1 files changed, 241 insertions, 0 deletions
diff --git a/examples/2D_lights/main.lua b/examples/2D_lights/main.lua
new file mode 100644
index 0000000..9c033eb
--- /dev/null
+++ b/examples/2D_lights/main.lua
@@ -0,0 +1,241 @@
+package.path = package.path..";"..RL.GetBasePath().."../resources/lib/?.lua"
+
+Util = require( "utillib" )
+Vector2 = require( "vector2" )
+Vector3 = require( "vector3" )
+Color = require( "color" )
+
+-- Defines
+local RESOLUTION = Vector2:new( 1280, 1024 )
+local TILE_SIZE_PX = 32
+local LIGHTRENDER_SIZE = 1024 -- Maxinum light size.
+local SHADOW_FOV = 45 -- Camera fov for shadow rendering.
+local WALL_MESH_HEIGHT = math.tan( RL.DEG2RAD * ( 90 - SHADOW_FOV / 2 ) ) * LIGHTRENDER_SIZE / TILE_SIZE_PX / 2
+
+local monitor = 0
+local monitorPos = Vector2:new( RL.GetMonitorPosition( monitor ) )
+local monitorSize = Vector2:new( RL.GetMonitorSize( monitor ) )
+local winScale = 1
+local winSize = Vector2:new( RESOLUTION.x * winScale, RESOLUTION.y * winScale )
+
+local tileTex = nil
+local lightTex = nil
+local lightTexSize = Vector2:new()
+local framebuffer = nil
+local lightMap = nil -- Final image of all lights.
+local lightRender = nil -- RenderTexture for individual light and shadow rendering.
+local ambientLight = Color:new( 40, 40, 40, 255 )
+local wallSegs = {}
+local shadowMesh = nil
+local lights = {}
+local camera = nil -- 3D camera for shadow rendering.
+
+-- Init.
+
+local function addLight( pos, color, radius )
+ table.insert( lights, {
+ pos = pos,
+ color = color,
+ radius = radius
+ } )
+end
+
+local function addWallSeg( p1, p2 )
+ table.insert( wallSegs, {
+ p1 = p1,
+ p2 = p2
+ } )
+end
+
+-- We will create 3D "wall" mesh for the shadows.
+local function createShadowMesh()
+ addWallSeg( Vector2:new( 0, 0 ), Vector2:new( 500, 160 ) )
+ addWallSeg( Vector2:new( 200, 230 ), Vector2:new( 400, 320 ) )
+ addWallSeg( Vector2:new( 600, 500 ), Vector2:new( 800, 360 ) )
+ addWallSeg( Vector2:new( 800, 360 ), Vector2:new( 900, 500 ) )
+ addWallSeg( Vector2:new( 500, 400 ), Vector2:new( 460, 600 ) )
+ addWallSeg( Vector2:new( 300, 600 ), Vector2:new( 360, 800 ) )
+ addWallSeg( Vector2:new( 360, 800 ), Vector2:new( 550, 900 ) )
+ addWallSeg( Vector2:new( 760, 600 ), Vector2:new( 900, 500 ) )
+ addWallSeg( Vector2:new( 960, 500 ), Vector2:new( 1200, 420 ) )
+ addWallSeg( Vector2:new( 840, 800 ), Vector2:new( 960, 950 ) )
+
+ -- Box.
+ addWallSeg( Vector2:new( 4 * 32, 15 * 32 ), Vector2:new( 5 * 32, 15 * 32 ) )
+ addWallSeg( Vector2:new( 4 * 32, 15 * 32 ), Vector2:new( 4 * 32, 16 * 32 ) )
+ addWallSeg( Vector2:new( 4 * 32, 16 * 32 ), Vector2:new( 5 * 32, 16 * 32 ) )
+ addWallSeg( Vector2:new( 5 * 32, 15 * 32 ), Vector2:new( 5 * 32, 16 * 32 ) )
+
+ -- Create wall mesh.
+ local meshData = { vertices = {} }
+
+ for _, s in ipairs( wallSegs ) do
+ local seg = {
+ p1 = Vector2:new( s.p1.x / TILE_SIZE_PX, s.p1.y / TILE_SIZE_PX ),
+ p2 = Vector2:new( s.p2.x / TILE_SIZE_PX, s.p2.y / TILE_SIZE_PX )
+ }
+ table.insert( meshData.vertices, Vector3:new( seg.p1.x, WALL_MESH_HEIGHT, seg.p1.y ) )
+ table.insert( meshData.vertices, Vector3:new( seg.p1.x, 0, seg.p1.y ) )
+ table.insert( meshData.vertices, Vector3:new( seg.p2.x, 0, seg.p2.y ) )
+ table.insert( meshData.vertices, Vector3:new( seg.p1.x, WALL_MESH_HEIGHT, seg.p1.y ) )
+ table.insert( meshData.vertices, Vector3:new( seg.p2.x, 0, seg.p2.y ) )
+ table.insert( meshData.vertices, Vector3:new( seg.p2.x, WALL_MESH_HEIGHT, seg.p2.y ) )
+ end
+ shadowMesh = RL.GenMeshCustom( meshData, false )
+end
+
+function RL.init()
+ RL.SetWindowState( RL.FLAG_WINDOW_RESIZABLE )
+ RL.SetWindowState( RL.FLAG_VSYNC_HINT )
+ RL.SetWindowSize( winSize )
+ RL.SetWindowPosition( { monitorPos.x + monitorSize.x / 2 - winSize.x / 2, monitorPos.y + monitorSize.y / 2 - winSize.y / 2 } )
+ RL.SetWindowTitle( "2D Lights" )
+
+ framebuffer = RL.LoadRenderTexture( RESOLUTION )
+ lightMap = RL.LoadRenderTexture( RESOLUTION )
+ lightRender = RL.LoadRenderTexture( { LIGHTRENDER_SIZE, LIGHTRENDER_SIZE } )
+ tileTex = RL.LoadTexture( RL.GetBasePath().."../resources/images/tile.png" )
+ lightTex = RL.LoadTexture( RL.GetBasePath().."../resources/images/light.png" )
+ lightTexSize = Vector2:new( RL.GetTextureSize( lightTex ) )
+
+ RL.SetTextureFilter( tileTex, RL.TEXTURE_FILTER_TRILINEAR )
+ RL.SetTextureFilter( lightTex, RL.TEXTURE_FILTER_TRILINEAR )
+
+ createShadowMesh()
+
+ addLight( Vector2:new( 230, 480 ), Color:new( RL.ORANGE ), 512 )
+ addLight( Vector2:new( 600, 200 ), Color:new( RL.RED ), 512 )
+ addLight( Vector2:new( 384, 520 ), Color:new( RL.GREEN ), 400 )
+ addLight( Vector2:new( 880, 750 ), Color:new( RL.BLUE ), 300 )
+ addLight( Vector2:new( 800, 500 ), Color:new( RL.PURPLE ), 512 )
+ addLight( Vector2:new( 200, 760 ), Color:new( RL.WHITE ), 400 )
+
+ -- Stress test
+
+ -- for i = 1, 300 do
+ -- addLight( Vector2:new( math.random( 20, RESOLUTION.x - 20 ), math.random( 20, RESOLUTION.y - 20 ) ),
+ -- Color:new( { math.random( 40, 255 ), math.random( 40, 255 ), math.random( 40, 255 ), 255 } ),
+ -- 128
+ -- )
+ -- end
+
+ -- Camera for shadow rendering.
+ camera = RL.CreateCamera3D()
+ RL.SetCamera3DPosition( camera, { 0, 5, 0 } )
+ RL.SetCamera3DTarget( camera, { 0, 0, -0.001 } )
+ RL.SetCamera3DUp( camera, { 0, 1, 0 } )
+ RL.SetCamera3DFovy( camera, SHADOW_FOV )
+
+ RL.SetMouseScale( { 1 / winScale, 1 / winScale } )
+ -- Render both sides of the shadow. Could be usefull to set off to prevent self shadowing.
+ RL.rlDisableBackfaceCulling()
+end
+
+-- Process.
+
+function RL.process( delta )
+ lights[1].pos = Vector2:new( RL.GetMousePosition() )
+end
+
+-- Drawing.
+
+local function drawLight( light )
+ RL.BeginTextureMode( lightRender )
+ RL.ClearBackground( RL.BLANK )
+ RL.DrawTexturePro(
+ lightTex,
+ { 0, 0, lightTexSize.x, lightTexSize.y },
+ { LIGHTRENDER_SIZE / 2, LIGHTRENDER_SIZE / 2, light.radius * 2, light.radius * 2 },
+ { light.radius, light.radius },
+ 0.0,
+ light.color
+ )
+ -- Draw shadows.
+ local cameraPos = Vector2:new( light.pos.x / TILE_SIZE_PX, light.pos.y / TILE_SIZE_PX )
+
+ RL.SetCamera3DPosition( camera, { 0, WALL_MESH_HEIGHT, 0 } )
+ RL.SetCamera3DTarget( camera, { 0, 0, -0.0001 } )
+
+ RL.rlSetBlendFactors( RL.RL_ZERO, RL.RL_ONE_MINUS_SRC_COLOR, RL.RL_FUNC_ADD )
+ RL.BeginBlendMode( RL.BLEND_CUSTOM )
+ RL.BeginMode3D( camera )
+ RL.DrawMesh(
+ shadowMesh,
+ RL.GetMaterialDefault(),
+ RL.MatrixMultiply(
+ RL.MatrixTranslate( { -cameraPos.x, 0, -cameraPos.y } ),
+ RL.MatrixScale( { 1, 1, -1 } ) -- Flip mesh.
+ )
+ )
+ RL.EndMode3D()
+ RL.EndBlendMode()
+ RL.EndTextureMode()
+ -- Draw light to lightmap.
+ RL.BeginTextureMode( lightMap )
+ RL.BeginBlendMode( RL.BLEND_ADDITIVE )
+ RL.DrawTexturePro(
+ RL.GetRenderTextureTexture( lightRender ),
+ { 0, 0, LIGHTRENDER_SIZE, LIGHTRENDER_SIZE },
+ { light.pos.x, light.pos.y, LIGHTRENDER_SIZE, LIGHTRENDER_SIZE },
+ { LIGHTRENDER_SIZE / 2, LIGHTRENDER_SIZE / 2 },
+ 0.0,
+ light.color
+ )
+ RL.EndBlendMode()
+ RL.EndTextureMode()
+end
+
+local function drawLights()
+ RL.BeginTextureMode( lightMap )
+ RL.ClearBackground( ambientLight )
+ RL.EndTextureMode()
+
+ for _, light in ipairs( lights ) do
+ drawLight( light )
+ end
+end
+
+function RL.draw()
+ RL.ClearBackground( RL.BLACK )
+
+ drawLights()
+ -- Draw to framebuffer.
+ RL.BeginTextureMode( framebuffer )
+ RL.ClearBackground( RL.BLACK )
+ -- Floor.
+ RL.DrawTextureRec(
+ tileTex,
+ { 0, 0, RESOLUTION.x, RESOLUTION.y },
+ { 0, 0 },
+ RL.WHITE
+ )
+ -- Wall lines.
+ for _, seg in ipairs( wallSegs ) do
+ RL.DrawLine( seg.p1, seg.p2, 3.0, RL.BLACK )
+ end
+ -- Lightmap.
+ RL.rlSetBlendFactors( RL.RL_DST_COLOR, RL.RL_SRC_COLOR, RL.RL_FUNC_ADD )
+ RL.BeginBlendMode( RL.BLEND_CUSTOM )
+ RL.DrawTexturePro(
+ RL.GetRenderTextureTexture( lightMap ),
+ { 0, 0, RESOLUTION.x, -RESOLUTION.y },
+ { 0, 0, RESOLUTION.x, RESOLUTION.y },
+ { 0, 0 },
+ 0.0,
+ RL.WHITE
+ )
+ RL.EndBlendMode()
+ RL.EndTextureMode()
+
+ -- Draw framebuffer to window.
+ RL.DrawTexturePro(
+ RL.GetRenderTextureTexture( framebuffer ),
+ { 0, 0, RESOLUTION.x, -RESOLUTION.y },
+ { 0, 0, winSize.x, winSize.y },
+ { 0, 0 },
+ 0.0,
+ RL.WHITE
+ )
+ -- RL.DrawRectangle( { 0, 0, 96, 32 }, RL.BLACK )
+ -- RL.DrawFPS( { 10, 10 } )
+end