almost there with complex

This commit is contained in:
Tim Anema 2021-11-19 20:14:08 -05:00
parent b3527f188a
commit d9a88946cf
No known key found for this signature in database
GPG Key ID: 222D82A25F3857A4
71 changed files with 606 additions and 633 deletions

View File

@ -1,15 +1,21 @@
# light_world.lua # light_world.lua
This is the light modeling done by Priorblue [here](https://bitbucket.org/PriorBlue/love2d-light-and-shadow-engine), A library for Love2d to create a dynamic lighting system, supporting:
only it has been largely refactored and edited to allow for scaling and proper translation. - Shadows for any shape
- Normal maps for 3d like reflections
- Glow maps
- Postshader effects
- Animations with normal maps
*Supports love 11.2(master branch), 0.10.1(commit 414b9b74c0eb95bfb8b5e26a11caf2b32beccca0) All of this is base of a previous version made by [PriorBlue](https://bitbucket.org/PriorBlue/love2d-light-and-shadow-engine),
## Installation ## Installation
Copy and rename the lib folder into your project. Copy and rename the lib folder into your project.
## How to use ## How to use
For more information please check out the [wiki](https://github.com/tanema/light_world.lua/wiki) and see the examples directory to see how it is fully used.
This project can be run with love to see the demonstrations in action.
```lua ```lua
local LightWorld = require "lib" --the path to where light_world is (in this repo "lib") local LightWorld = require "lib" --the path to where light_world is (in this repo "lib")
@ -17,7 +23,7 @@ local LightWorld = require "lib" --the path to where light_world is (in this rep
--create light world --create light world
function love.load() function love.load()
lightWorld = LightWorld({ lightWorld = LightWorld({
ambient = {55/255,55/255,55/255}, --the general ambient light in the environment ambient = {0.21,0.21,0.21}, --the general ambient light in the environment
}) })
end end
@ -37,35 +43,6 @@ function love.draw()
end end
``` ```
For more information please check out the [wiki](https://github.com/tanema/light_world.lua/wiki) and see the examples directory to see how it is fully used. This project can be run with love to see the demonstrations in action.
### Gamera & HUMP
There are example in the example directory how to use both of these with the library.
## Features ##
* **[Preview (Video)](https://www.youtube.com/watch?v=6V5Dtsa6Nd4)**
* polygon shadow calculation [Preview](http://onepixelahead.de/love2d_polyshadow.png)
* circle shadow calculation
* image shadow calculation [Preview](http://onepixelahead.de/love2d_polyshadow18.png)
* shadow blur
* light color, range, smooth and glow [Preview](http://onepixelahead.de/love2d_polyshadow2.png)
* ambient light
* self shadowing on images with normal maps [Preview](http://onepixelahead.de/love2d_polyshadow_pixelshadow.png)
* dynamic glow effect on images and circle/poly objects [Preview](http://onepixelahead.de/love2d_polyshadow_glow.png) [Preview](http://onepixelahead.de/love2d_polyshadow15.gif)
* generate flat or gradient normal maps [Preview](http://onepixelahead.de/love2d_polyshadow7.png)
* convert height maps to normal maps [Preview](http://onepixelahead.de/love2d_polyshadow8.png)
* generate a normal map directly from the image (usually gives poor results)
* shadow color and alpha (glass) [Preview](http://onepixelahead.de/love2d_polyshadow9.png)
* directional light [Preview](http://onepixelahead.de/love2d_polyshadow12.png)
* refractions (moveable) [Preview](http://onepixelahead.de/love2d_polyshadow13.gif)
* chromatic aberration [Preview](http://onepixelahead.de/love2d_polyshadow16.gif)
* postshader with many included postshaders, plus easy to extend
* animations in tandem with normal maps thanks to [anim8](https://github.com/kikito/anim8)
## License
A License has been included in this project
## Contributors ## Contributors
- Jon @xiejiangzhi - Jon @xiejiangzhi
- Brandon Blanker Lim-it @flamendless - Brandon Blanker Lim-it @flamendless
@ -73,3 +50,5 @@ A License has been included in this project
- Gustavo Kishima @gukiboy - Gustavo Kishima @gukiboy
- Rose L. Liverman @TangentFoxy - Rose L. Liverman @TangentFoxy
- Kyle McLamb @Alloyed - Kyle McLamb @Alloyed
- @Buckle2000
- Benoit Giannangeli @giann

View File

@ -1,9 +1,9 @@
function love.conf(t) function love.conf(t)
t.identity = nil -- The name of the save directory (string) t.identity = nil -- The name of the save directory (string)
t.version = "11.2" -- The LÖVE version this game was made for (string) t.version = "11.3" -- The LÖVE version this game was made for (string)
t.console = true -- Attach a console (boolean, Windows only) t.console = true -- Attach a console (boolean, Windows only)
t.window.title = "Untitled" -- The window title (string) t.window.title = "Light & Shadow" -- The window title (string)
t.window.icon = nil -- Filepath to an image to use as the window's icon (string) t.window.icon = nil -- Filepath to an image to use as the window's icon (string)
t.window.width = 800 -- The window width (number) t.window.width = 800 -- The window width (number)
t.window.height = 600 -- The window height (number) t.window.height = 600 -- The window height (number)
@ -12,22 +12,22 @@ function love.conf(t)
t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) t.window.minwidth = 1 -- Minimum window width if the window is resizable (number)
t.window.minheight = 1 -- Minimum window height if the window is resizable (number) t.window.minheight = 1 -- Minimum window height if the window is resizable (number)
t.window.fullscreen = false -- Enable fullscreen (boolean) t.window.fullscreen = false -- Enable fullscreen (boolean)
t.window.fullscreentype = "desktop" -- Standard fullscreen or desktop fullscreen mode (string) t.window.fullscreentype = "desktop"-- Standard fullscreen or desktop fullscreen mode (string)
t.window.vsync = false -- Enable vertical sync (boolean) t.window.vsync = false -- Enable vertical sync (boolean)
t.window.fsaa = 0 -- The number of samples to use with multi-sampled antialiasing (number) t.window.fsaa = 0 -- The number of samples to use with multi-sampled antialiasing (number)
t.window.display = 1 -- Index of the monitor to show the window in (number) t.window.display = 1 -- Index of the monitor to show the window in (number)
t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean). Added in 0.9.1 t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean). Added in 0.9.1
t.window.srgb = false -- Enable sRGB gamma correction when drawing to the screen (boolean). Added in 0.9.1 t.window.srgb = false -- Enable sRGB gamma correction when drawing to the screen (boolean). Added in 0.9.1
t.modules.audio = true -- Enable the audio module (boolean) t.modules.audio = false -- Enable the audio module (boolean)
t.modules.event = true -- Enable the event module (boolean) t.modules.event = true -- Enable the event module (boolean)
t.modules.graphics = true -- Enable the graphics module (boolean) t.modules.graphics = true -- Enable the graphics module (boolean)
t.modules.image = true -- Enable the image module (boolean) t.modules.image = true -- Enable the image module (boolean)
t.modules.joystick = true -- Enable the joystick module (boolean) t.modules.joystick = false -- Enable the joystick module (boolean)
t.modules.keyboard = true -- Enable the keyboard module (boolean) t.modules.keyboard = true -- Enable the keyboard module (boolean)
t.modules.math = true -- Enable the math module (boolean) t.modules.math = true -- Enable the math module (boolean)
t.modules.mouse = true -- Enable the mouse module (boolean) t.modules.mouse = true -- Enable the mouse module (boolean)
t.modules.physics = true -- Enable the physics module (boolean) t.modules.physics = false -- Enable the physics module (boolean)
t.modules.sound = true -- Enable the sound module (boolean) t.modules.sound = true -- Enable the sound module (boolean)
t.modules.system = true -- Enable the system module (boolean) t.modules.system = true -- Enable the system module (boolean)
t.modules.timer = true -- Enable the timer module (boolean) t.modules.timer = true -- Enable the timer module (boolean)

View File

@ -3,8 +3,8 @@ local x, y, z, scale = 20, -55, 1, 3.5
local function load() local function load()
-- load images -- load images
image = love.graphics.newImage("examples/gfx/scott_pilgrim.png") image = love.graphics.newImage("examples/img/animation/scott_pilgrim.png")
image_normal = love.graphics.newImage("examples/gfx/scott_pilgrim_NRM.png") image_normal = love.graphics.newImage("examples/img/animation/scott_pilgrim_NRM.png")
-- create light world -- create light world
lightWorld = LightWorld({ambient = {0.49, 0.49, 0.49}}) lightWorld = LightWorld({ambient = {0.49, 0.49, 0.49}})
-- create light -- create light

View File

@ -1,172 +1,43 @@
local gamera = require "examples/vendor/gamera"
local LightWorld = require "lib" local LightWorld = require "lib"
local objects = {}
function initScene() local obj = require "examples.lib.object"
-- physic world local keyboard = require "examples.lib.keyboard"
physicWorld = love.physics.newWorld(0, 9.81 * 64, true) local cam, font, quadScreen, imgFloor, imgLight
wall1 = {} local lightRange = 300
wall1.body = love.physics.newBody(physicWorld, 400, 605, "static") local lightDirection = 0.0
wall1.shape = love.physics.newRectangleShape(0, 0, 800, 10) local colorAberration = 0.0
wall1.fixture = love.physics.newFixture(wall1.body, wall1.shape) local lightWorld, mouseLight
wall2 = {}
wall2.body = love.physics.newBody(physicWorld, -5, 300, "static")
wall2.shape = love.physics.newRectangleShape(0, 0, 10, 600)
wall2.fixture = love.physics.newFixture(wall2.body, wall2.shape)
wall3 = {}
wall3.body = love.physics.newBody(physicWorld, 805, 300, "static")
wall3.shape = love.physics.newRectangleShape(0, 0, 10, 600)
wall3.fixture = love.physics.newFixture(wall3.body, wall3.shape)
wall4 = {}
wall4.body = love.physics.newBody(physicWorld, 400, -5, "static")
wall4.shape = love.physics.newRectangleShape(0, 0, 800, 10)
wall4.fixture = love.physics.newFixture(wall4.body, wall4.shape)
phyCnt = 0
phyLight = {}
end
local function load() local function load()
math.randomseed(love.timer.getTime())
cam = gamera.new(0, 0, love.graphics.getWidth(), love.graphics.getHeight())
love.graphics.setBackgroundColor(0, 0, 0) love.graphics.setBackgroundColor(0, 0, 0)
love.graphics.setDefaultFilter("nearest", "nearest") love.graphics.setDefaultFilter("nearest", "nearest")
font = love.graphics.newImageFont("examples/img/complex/font.png", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?-+/():;%&`'*#=[]\"")
-- load image font
font = love.graphics.newImageFont("examples/gfx/font.png", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?-+/():;%&`'*#=[]\"")
love.graphics.setFont(font) love.graphics.setFont(font)
-- set background
quadScreen = love.graphics.newQuad(0, 0, love.graphics.getWidth() + 32, love.graphics.getHeight() + 24, 32, 24) quadScreen = love.graphics.newQuad(0, 0, love.graphics.getWidth() + 32, love.graphics.getHeight() + 24, 32, 24)
imgFloor = love.graphics.newImage("examples/gfx/floor.png") imgFloor = love.graphics.newImage("examples/img/complex/floor.png")
imgFloor:setWrap("repeat", "repeat") imgFloor:setWrap("repeat", "repeat")
imgLight = love.graphics.newImage("examples/img/complex/light.png")
-- load image examples lightWorld = LightWorld({ambient = {15,15,15}, refractionStrength = 16.0, reflectionVisibility = 0.75, shadowBlur = 2.0})
circle = love.graphics.newImage("examples/gfx/circle.png")
circle_normal = love.graphics.newImage("examples/gfx/circle_normal.png")
cone = love.graphics.newImage("examples/gfx/cone.png")
cone_large = love.graphics.newImage("examples/gfx/cone_large.png")
cone_large_normal = love.graphics.newImage("examples/gfx/cone_large_normal.png")
cone_normal = love.graphics.newImage("examples/gfx/cone_normal.png")
chest = love.graphics.newImage("examples/gfx/chest.png")
chest_normal = love.graphics.newImage("examples/gfx/chest_normal.png")
machine = love.graphics.newImage("examples/gfx/machine.png")
machine_normal = love.graphics.newImage("examples/gfx/machine_normal.png")
machine_glow = love.graphics.newImage("examples/gfx/machine_glow.png")
machine2 = love.graphics.newImage("examples/gfx/machine2.png")
machine2_normal = love.graphics.newImage("examples/gfx/machine2_normal.png")
machine2_glow = love.graphics.newImage("examples/gfx/machine2_glow.png")
blopp = love.graphics.newImage("examples/gfx/blopp.png")
tile = love.graphics.newImage("examples/gfx/tile.png")
tile_normal = love.graphics.newImage("examples/gfx/tile_normal.png")
tile_glow = love.graphics.newImage("examples/gfx/tile_glow.png")
refraction_normal = love.graphics.newImage("examples/gfx/refraction_normal.png")
water = love.graphics.newImage("examples/gfx/water.png")
led = love.graphics.newImage("examples/gfx/led.png")
led2 = love.graphics.newImage("examples/gfx/led2.png")
led3 = love.graphics.newImage("examples/gfx/led3.png")
led_normal = love.graphics.newImage("examples/gfx/led_normal.png")
led_glow = love.graphics.newImage("examples/gfx/led_glow.png")
led_glow2 = love.graphics.newImage("examples/gfx/led_glow2.png")
led_glow3 = love.graphics.newImage("examples/gfx/led_glow3.png")
ape = love.graphics.newImage("examples/gfx/ape.png")
ape_normal = love.graphics.newImage("examples/gfx/ape_normal.png")
ape_glow = love.graphics.newImage("examples/gfx/ape_glow.png")
imgLight = love.graphics.newImage("examples/gfx/light.png")
-- materials
material = {}
local files = love.filesystem.getDirectoryItems("examples/gfx/sphere")
for i, file in ipairs(files) do
material[i] = love.graphics.newImage("examples/gfx/sphere/" .. file)
end
-- light world
lightRange = 400
lightSmooth = 1.0
lightWorld = LightWorld({
ambient = {15,15,15},
refractionStrength = 16.0,
reflectionVisibility = 0.75,
shadowBlur = 2.0
})
mouseLight = lightWorld:newLight(0, 0, 1, 191/ 255, 0.5, lightRange) mouseLight = lightWorld:newLight(0, 0, 1, 191/ 255, 0.5, lightRange)
mouseLight:setGlowStrength(0.3) mouseLight:setGlowStrength(0.3)
mouseLight:setSmooth(lightSmooth)
mouseLight.z = 63 mouseLight.z = 63
lightDirection = 0.0
colorAberration = 0.0
-- init physic world
initScene()
helpOn = false
physicOn = false
lightOn = true
gravityOn = 1
shadowBlur = 2.0
bloomOn = 0.0
textureOn = true
normalOn = false
glowBlur = 1.0
effectOn = 0.0
offsetX = 0.0
offsetY = 0.0
scale = 1.0
offsetOldX = 0.0
offsetOldY = 0.0
offsetChanged = false
tileX = 0
tileY = 0
end end
local function update(dt) local function update(dt)
love.window.setTitle("Light vs. Shadow Engine (FPS:" .. love.timer.getFPS() .. ")") love.window.setTitle("Light vs. Shadow Engine (FPS:" .. love.timer.getFPS() .. ")")
local x, y, scale = keyboard.update(dt)
mx, my = (love.mouse.getX() - offsetX)/scale, (love.mouse.getY() - offsetY)/scale cam:setScale(scale)
cam:setPosition(x, y)
mouseLight:setPosition(mx, my, 1 + (math.sin(lightDirection)+1.0)) local mx, my = cam:toScreen(love.mouse.getX(),love.mouse.getY())
lightWorld:setTranslation(offsetX,offsetY, scale)
lightDirection = lightDirection + dt lightDirection = lightDirection + dt
mouseLight:setPosition(mx, my, 1 + (math.sin(lightDirection)+1.0))
for i, o in ipairs(objects) do o:update(dt) end
colorAberration = math.max(0.0, colorAberration - dt * 10.0) colorAberration = math.max(0.0, colorAberration - dt * 10.0)
if love.keyboard.isDown("up") then
offsetY = offsetY + dt * 200
elseif love.keyboard.isDown("down") then
offsetY = offsetY - dt * 200
end
if love.keyboard.isDown("left") then
offsetX = offsetX + dt * 200
elseif love.keyboard.isDown("right") then
offsetX = offsetX - dt * 200
end
if love.keyboard.isDown("-") then
scale = scale - 0.01
elseif love.keyboard.isDown("=") then
scale = scale + 0.01
end
for i = 1, lightWorld:getLightCount() do
lightWorld:getLight(i):setDirection(lightDirection)
end
tileX = tileX + dt * 32.0
tileY = tileY + dt * 8.0
for i = 1, phyCnt do
if phyLight[i]:getType() == "refraction" then
phyLight[i]:setNormalTileOffset(tileX, tileY)
end
end
-- draw shader
if colorAberration > 0.0 then if colorAberration > 0.0 then
-- vert / horz blur
lightWorld.post_shader:addEffect("blur", 2.0, 2.0) lightWorld.post_shader:addEffect("blur", 2.0, 2.0)
lightWorld.post_shader:addEffect("chromatic_aberration", lightWorld.post_shader:addEffect("chromatic_aberration",
{math.sin(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * colorAberration}, {math.sin(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * colorAberration},
@ -176,401 +47,76 @@ local function update(dt)
lightWorld.post_shader:removeEffect("blur") lightWorld.post_shader:removeEffect("blur")
lightWorld.post_shader:removeEffect("chromatic_aberration") lightWorld.post_shader:removeEffect("chromatic_aberration")
end end
if bloomOn > 0.0 then
-- blur, strength
lightWorld.post_shader:addEffect("bloom", 2.0, bloomOn)
else
lightWorld.post_shader:removeEffect("bloom")
end
lightWorld:update(dt) lightWorld:update(dt)
end end
local function draw() local function draw()
-- set shader buffer cam:draw(function(l,t,w,h)
lightWorld:setTranslation(offsetX,offsetY, scale) lightWorld:draw(function(l, t, w, h, s)
love.graphics.push() love.graphics.setBlendMode("alpha")
love.graphics.translate(offsetX, offsetY) love.graphics.setColor(1, 1, 1)
love.graphics.scale(scale) love.graphics.draw(imgFloor, quadScreen, 0,0)
lightWorld:draw(function(l, t, w, h, s) for i, ob in ipairs(objects) do ob:draw() end
love.graphics.setBlendMode("alpha") end)
if normalOn then local mx, my = cam:toScreen(love.mouse.getX(),love.mouse.getY())
love.graphics.setColor(0.5, 0.5, 1) love.graphics.draw(imgLight, mx - 5, (my - 5) - (16.0 + (math.sin(lightDirection) + 1.0) * 64.0))
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) end)
else love.graphics.setBlendMode("alpha")
love.graphics.setColor(1, 1, 1) love.graphics.setColor(0, 0.5, 1)
if textureOn then love.graphics.print("c: chromatic abberation", 4, love.graphics.getHeight() - 20 * 6)
love.graphics.draw(imgFloor, quadScreen, 0,0) love.graphics.print("F1-F9: Shaders", 4, love.graphics.getHeight() - 20 * 5)
else love.graphics.print("F10: Clear Bodies", 4, love.graphics.getHeight() - 20 * 4)
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) love.graphics.print("F11: Clear Lights", 4, love.graphics.getHeight() - 20 * 3)
end love.graphics.print("Arrow Keys: Move map", 4, love.graphics.getHeight() - 20 * 2)
end love.graphics.print("0-9 Keys: Add object", 4, love.graphics.getHeight() - 20 * 1)
love.graphics.setColor(1, 0.5, 0)
for i = 1, phyCnt do love.graphics.print("M.left: Add cube", love.graphics.getWidth() - 180, love.graphics.getHeight() - 20 * 3)
if phyLight[i]:getType() == "refraction" then love.graphics.print("M.middle: Add light", love.graphics.getWidth() - 180, love.graphics.getHeight() - 20 * 2)
if not normalOn then love.graphics.print("M.right: Add circle", love.graphics.getWidth() - 180, love.graphics.getHeight() - 20 * 1)
love.graphics.setBlendMode("alpha")
love.graphics.setColor(1, 1, 1, 191/255)
love.graphics.draw(water, phyLight[i].x - phyLight[i].ox, phyLight[i].y - phyLight[i].oy)
end
end
end
love.graphics.setBlendMode("alpha")
for i = 1, phyCnt do
if phyLight[i]:getType() == "polygon" then
math.randomseed(i)
love.graphics.setColor(math.random(), math.random(), math.random())
love.graphics.polygon("fill", phyLight[i]:getPoints())
elseif phyLight[i]:getType() == "circle" then
math.randomseed(i)
love.graphics.setColor(math.random(), math.random(), math.random())
local cx, cy = phyLight[i]:getPosition()
love.graphics.circle("fill", cx, cy, phyLight[i]:getRadius())
elseif phyLight[i]:getType() == "image" then
if normalOn and phyLight[i].normal then
love.graphics.setColor(1, 1, 1)
love.graphics.draw(phyLight[i].normal, phyLight[i].x - phyLight[i].nx, phyLight[i].y - phyLight[i].ny)
elseif not phyLight[i].material then
math.randomseed(i)
love.graphics.setColor(
math.random(127, 255) / 255, math.random(127, 255)/ 255, math.random(127, 255) / 255
)
love.graphics.draw(phyLight[i].img, phyLight[i].x - phyLight[i].ix, phyLight[i].y - phyLight[i].iy)
end
end
end
end)
love.graphics.pop()
love.graphics.draw(imgLight, mx - 5, (my - 5) - (16.0 + (math.sin(lightDirection) + 1.0) * 64.0))
-- draw help
if helpOn then
love.graphics.setBlendMode("alpha")
love.graphics.setColor(0, 0, 0, 191)
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), 44)
love.graphics.rectangle("fill", 0, love.graphics.getHeight() - 68, 240, 68)
love.graphics.rectangle("fill", love.graphics.getWidth() - 244, love.graphics.getHeight() - 84, 244, 84)
love.graphics.setColor(0, 1, 0)
love.graphics.print("F1: Help (on)", 4 + 152 * 0, 4)
if shadowBlur >= 1.0 then
love.graphics.setColor(0, 1, 0)
love.graphics.print("F5: Shadowblur (" .. shadowBlur .. ")", 4 + 152 * 4, 4)
else
love.graphics.setColor(1, 0, 0)
love.graphics.print("F5: Shadowblur (off)", 4 + 152 * 4, 4)
end
if bloomOn > 0.0 then
love.graphics.setColor(0, 1, 0)
love.graphics.print("F6: Bloom (" .. (bloomOn * 4) .. ")", 4 + 152 * 0, 4 + 20 * 1)
else
love.graphics.setColor(1, 0, 0)
love.graphics.print("F6: Bloom (off)", 4 + 152 * 0, 4 + 20 * 1)
end
if textureOn then
love.graphics.setColor(0, 1, 0)
love.graphics.print("F7: Texture (on)", 4 + 152 * 1, 4 + 20 * 1)
else
love.graphics.setColor(1, 0, 0)
love.graphics.print("F7: Texture (off)", 4 + 152 * 1, 4 + 20 * 1)
end
if normalOn then
love.graphics.setColor(0, 1, 0)
love.graphics.print("F8: Normal (on)", 4 + 152 * 2, 4 + 20 * 1)
else
love.graphics.setColor(1, 0, 0)
love.graphics.print("F8: Normal (off)", 4 + 152 * 2, 4 + 20 * 1)
end
if glowBlur >= 1.0 then
love.graphics.setColor(0, 1, 0)
love.graphics.print("F9: Glow Blur (" .. glowBlur .. ")", 4 + 152 * 3, 4 + 20 * 1)
else
love.graphics.setColor(1, 0, 0)
love.graphics.print("F9: Glow Blur (off)", 4 + 152 * 3, 4 + 20 * 1)
end
if effectOn >= 1.0 then
love.graphics.setColor(0, 1, 0)
love.graphics.print("F10: Effects (" .. effectOn .. ")", 4 + 152 * 4, 4 + 20 * 1)
else
love.graphics.setColor(1, 0, 0)
love.graphics.print("F10: Effects (off)", 4 + 152 * 4, 4 + 20 * 1)
end
love.graphics.setColor(1, 0, 1)
love.graphics.print("F11: Clear obj.", 4 + 152 * 4, 4 + 20 * 2)
love.graphics.print("F12: Clear lights", 4 + 152 * 4, 4 + 20 * 3)
love.graphics.setColor(0, 0.5, 1)
love.graphics.print("WASD Keys: Move objects", 4, love.graphics.getHeight() - 20 * 3)
love.graphics.print("Arrow Keys: Move map", 4, love.graphics.getHeight() - 20 * 2)
love.graphics.print("0-9 Keys: Add object", 4, love.graphics.getHeight() - 20 * 1)
love.graphics.setColor(1, 0.5, 0)
love.graphics.print("M.left: Add cube", love.graphics.getWidth() - 240, love.graphics.getHeight() - 20 * 4)
love.graphics.print("M.middle: Add light", love.graphics.getWidth() - 240, love.graphics.getHeight() - 20 * 3)
love.graphics.print("M.right: Add circle", love.graphics.getWidth() - 240, love.graphics.getHeight() - 20 * 2)
love.graphics.print("M.scroll: Change smooth", love.graphics.getWidth() - 240, love.graphics.getHeight() - 20 * 1)
love.graphics.setColor(1, 0.5, 0)
else
love.graphics.setColor(1, 1, 1, 191/255)
love.graphics.print("F1: Help", 4, 4)
end
end end
local function mousepressed(x, y, c) local function mousepressed(x, y, c)
if c == "m" then if c == 3 then
-- add light local light = lightWorld:newLight(x, y, math.random(), math.random(), math.random(), lightRange)
local r = lightWorld:getLightCount() % 3
local light
if r == 0 then
light = lightWorld:newLight(x, y, 31/ 255, 0.5, 63/ 255, lightRange)
elseif r == 1 then
light = lightWorld:newLight(x, y, 0.5, 63/255, 31/255, lightRange)
else
light = lightWorld:newLight(x, y, 31/255, 63/255, 127/255, lightRange)
end
light:setSmooth(lightSmooth)
light:setGlowStrength(0.3) light:setGlowStrength(0.3)
elseif c == "l" then if love.keyboard.isDown("rshift") or love.keyboard.isDown("lshift") then
-- add rectangle light:setAngle(math.random(1, 5) * 0.1 * math.pi)
math.randomseed(love.timer.getTime()) light:setDirection(math.random(1, 5) * 0.1 * math.pi)
phyCnt = phyCnt + 1
local w, h = math.random(32, 64), math.random(32, 64)
phyLight[phyCnt] = lightWorld:newPolygon(
x, y,
x+w, y,
x+w, y+h,
x, y+h
)
elseif c == "r" then
-- add circle
math.randomseed(love.timer.getTime())
cRadius = math.random(8, 32)
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newCircle(x, y, cRadius)
elseif c == "wu" then
if lightSmooth < 4.0 then
lightSmooth = lightSmooth * 1.1
mouseLight:setSmooth(lightSmooth)
end
elseif c == "wd" then
if lightSmooth > 0.5 then
lightSmooth = lightSmooth / 1.1
mouseLight:setSmooth(lightSmooth)
end end
elseif c == 1 then table.insert(objects, obj.Rect:new(lightWorld, x, y, math.random(32, 64), math.random(32, 64)))
elseif c == 2 then table.insert(objects, obj.Circle:new(lightWorld, x, y, math.random(8, 32)))
end end
end end
local function keypressed(k, u) local function keypressed(k, u)
-- debug options local mx, my = cam:toScreen(love.mouse.getX(),love.mouse.getY())
if k == "f1" then if k == "f1" then lightWorld.post_shader:toggleEffect("four_colors", {0.05, 0.21, 0.05}, {0.18, 0.38, 0.18}, {0.54, 0.67, 0.05}, {0.60, 0.73, 0.05})
helpOn = not helpOn elseif k == "f2" then lightWorld.post_shader:toggleEffect("scanlines")
elseif k == "f5" then elseif k == "f3" then lightWorld.post_shader:toggleEffect("bloom", 2.0, 0.25)
shadowBlur = math.max(1, shadowBlur * 2.0) elseif k == "f4" then lightWorld.post_shader:toggleEffect("black_and_white")
if shadowBlur > 8.0 then elseif k == "f5" then lightWorld.post_shader:toggleEffect("curvature")
shadowBlur = 0.0 elseif k == "f6" then lightWorld.post_shader:toggleEffect("edges")
end elseif k == "f7" then lightWorld.post_shader:toggleEffect("pip")
lightWorld:setShadowBlur(shadowBlur) elseif k == "f8" then lightWorld.post_shader:toggleEffect("pixellate")
elseif k == "f6" or k == "b" then elseif k == "f9" then lightWorld.post_shader:toggleEffect("waterpaint")
bloomOn = math.max(0.25, bloomOn * 2.0)
if bloomOn > 1.0 then
bloomOn = 0.0
end
elseif k == "f7" then
textureOn = not textureOn
elseif k == "f8" then
normalOn = not normalOn
elseif k == "f9" then
glowBlur = glowBlur + 1.0
if glowBlur > 8.0 then
glowBlur = 0.0
end
lightWorld:setGlowStrength(glowBlur)
elseif k == "f10" then elseif k == "f10" then
effectOn = effectOn + 1.0
if effectOn > 4.0 then
effectOn = 0.0
end
if effectOn == 1.0 then
lightWorld.post_shader:addEffect("four_colors", {15, 56, 15}, {48, 98, 48}, {139, 172, 15}, {155, 188, 15})
--lightWorld.post_shader:addEffect("4colors", {108, 108, 78}, {142, 139, 87}, {195, 196, 165}, {227, 230, 201})
else
lightWorld.post_shader:removeEffect("four_colors")
end
if effectOn == 2.0 then
lightWorld.post_shader:addEffect("monochrome")
else
lightWorld.post_shader:removeEffect("monochrome")
end
if effectOn == 3.0 then
lightWorld.post_shader:addEffect("scanlines")
else
lightWorld.post_shader:removeEffect("scanlines")
end
if effectOn == 4.0 then
lightWorld.post_shader:addEffect("tilt_shift", 4.0)
else
lightWorld.post_shader:removeEffect("tilt_shift")
end
elseif k == "f11" then
physicWorld:destroy()
lightWorld:clearBodies() lightWorld:clearBodies()
initScene() objects = {}
elseif k == "f12" then elseif k == "f11" then
lightWorld:clearLights() lightWorld:clearLights()
mouseLight = lightWorld:newLight(0, 0, 1, 191/255, 0.5, lightRange) mouseLight = lightWorld:newLight(0, 0, 1, 191/255, 0.5, lightRange)
mouseLight:setGlowStrength(0.3) mouseLight:setGlowStrength(0.3)
mouseLight:setSmooth(lightSmooth) elseif k == "1" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/ape", mx, my, "image"))
elseif k == "1" then elseif k == "2" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/chest", mx, my))
-- add image elseif k == "3" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/cone", mx, my, "circle"))
phyCnt = phyCnt + 1 elseif k == "4" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/cube", mx, my))
phyLight[phyCnt] = lightWorld:newImage(circle, mx, my) elseif k == "5" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/cylinder", mx, my, "circle"))
phyLight[phyCnt]:setNormalMap(circle_normal) elseif k == "6" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/screen1", mx, my))
phyLight[phyCnt]:setShadowType("circle", 16) elseif k == "7" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/screen2", mx, my))
elseif k == "2" then elseif k == "8" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/screen3", mx, my))
local r = lightWorld:getBodyCount() % 2 elseif k == "9" then table.insert(objects, obj.ImageObject:new(lightWorld, "examples/img/complex/tile", mx, my))
if r == 0 then elseif k == "0" then table.insert(objects, obj.Refraction:new(lightWorld, "examples/img/complex/water", mx, my))
-- add image elseif k == "c" then colorAberration = 3.0
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(cone, mx, my, 24, 12, 12, 16)
phyLight[phyCnt]:setNormalMap(cone_normal)
phyLight[phyCnt]:setShadowType("circle", 12)
elseif r == 1 then
-- add image
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(chest, mx, my, 32, 24, 16, 0)
phyLight[phyCnt]:setNormalMap(chest_normal)
end
elseif k == "3" then
-- add image
local r = lightWorld:getBodyCount() % #material
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(ape, mx, my, 160, 128, 80, 64)
phyLight[phyCnt]:setNormalMap(ape_normal)
if r == 3 then
phyLight[phyCnt]:setGlowMap(ape_glow)
end
phyLight[phyCnt]:setMaterial(material[r + 1])
phyLight[phyCnt]:setShadowType("image", 0, -16, 0.0)
elseif k == "4" then
-- add glow image
local r = lightWorld:getBodyCount() % 5
if r == 0 then
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(machine, mx, my, 32, 24, 16, 0)
phyLight[phyCnt]:setNormalMap(machine_normal)
phyLight[phyCnt]:setGlowMap(machine_glow)
elseif r == 1 then
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(machine2, mx, my, 24, 12, 12, -4)
phyLight[phyCnt]:setNormalMap(machine2_normal)
phyLight[phyCnt]:setGlowMap(machine2_glow)
elseif r == 2 then
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(led, mx, my, 32, 6, 16, -8)
phyLight[phyCnt]:setNormalMap(led_normal)
phyLight[phyCnt]:setGlowMap(led_glow)
elseif r == 3 then
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(led2, mx, my, 32, 6, 16, -8)
phyLight[phyCnt]:setNormalMap(led_normal)
phyLight[phyCnt]:setGlowMap(led_glow2)
elseif r == 4 then
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(led3, mx, my, 32, 6, 16, -8)
phyLight[phyCnt]:setNormalMap(led_normal)
phyLight[phyCnt]:setGlowMap(led_glow3)
end
elseif k == "5" then
-- add image
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(cone_large, mx, my, 24, 128, 12, 64)
phyLight[phyCnt]:setNormalMap(cone_large_normal)
phyLight[phyCnt]:setShadowType("image", 0, -6, 0.0)
elseif k == "6" then
-- add image
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(blopp, mx, my, 42, 16, 21, 0)
phyLight[phyCnt]:generateNormalMapGradient("gradient", "gradient")
phyLight[phyCnt]:setAlpha(0.5)
elseif k == "7" then
-- add image
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newImage(tile, mx, my)
phyLight[phyCnt]:setHeightMap(tile_normal, 2.0)
phyLight[phyCnt]:setGlowMap(tile_glow)
phyLight[phyCnt]:setShadow(false)
phyLight[phyCnt].reflective = false
elseif k == "8" then
-- add rectangle
phyCnt = phyCnt + 1
local w, h = math.random(32, 64), math.random(32, 64)
phyLight[phyCnt] = lightWorld:newPolygon(
mx, my,
mx+w, my,
mx+w, my+h,
mx, my+h
)
phyLight[phyCnt]:setAlpha(0.5)
phyLight[phyCnt]:setGlowStrength(1.0)
math.randomseed(phyCnt)
phyLight[phyCnt]:setGlowColor(math.random(), math.random(), math.random())
math.randomseed(phyCnt)
phyLight[phyCnt]:setColor(math.random(), math.random(), math.random())
elseif k == "9" then
-- add circle
math.randomseed(love.timer.getTime())
cRadius = math.random(8, 32)
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newCircle(mx, my, cRadius)
phyLight[phyCnt]:setAlpha(0.5)
phyLight[phyCnt]:setGlowStrength(1.0)
math.randomseed(phyCnt)
phyLight[phyCnt]:setGlowColor(math.random(), math.random(), math.random())
math.randomseed(phyCnt)
phyLight[phyCnt]:setColor(math.random(), math.random(), math.random())
elseif k == "0" then
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld:newRefraction(refraction_normal, mx, my)
phyLight[phyCnt]:setReflection(true)
elseif k == "k" then
-- add light
local r = lightWorld:getLightCount() % 3
local light
if r == 0 then
light = lightWorld:newLight(mx, my, 31/255, 127 / 255, 63 / 255, lightRange)
elseif r == 1 then
light = lightWorld:newLight(mx, my, 127 / 255, 63 / 255, 31 / 255, lightRange)
else
light = lightWorld:newLight(mx, my, 31 / 255, 63 / 255, 127 / 255, lightRange)
end
light:setSmooth(lightSmooth)
light:setGlowStrength(0.3)
elseif k == "l" then
-- add light
local r = lightWorld:getLightCount() % 3
local light
if r == 0 then
light = lightWorld:newLight(mx, my, 31/255, 127/255, 63/255, lightRange)
elseif r == 1 then
light = lightWorld:newLight(mx, my, 127/255, 63/255, 31/255, lightRange)
else
light = lightWorld:newLight(mx, my, 31, 63, 127, lightRange)
end
light:setSmooth(lightSmooth)
light:setGlowStrength(0.3)
math.randomseed(love.timer.getTime())
light:setAngle(math.random(1, 5) * 0.1 * math.pi)
elseif k == "c" then
if colorAberration == 0.0 then
colorAberration = 3.0
end
end end
end end

View File

@ -1,14 +1,14 @@
local List = require('examples.lib.list') local List = require('examples.lib.list')
local LightWorld = require('lib') local LightWorld = require('lib')
local examples = { local examples = {
["Animation Example"] = "animation.lua", {"Simple", "simple.lua"},
["Complex Example"] = "complex.lua", {"Gamera", "gamera.lua"},
["Gamera Example"] = "gamera.lua", {"Hump", "hump.lua"},
["Hump Example"] = "hump.lua", {"Normal Map", "normalMap.lua"},
["Normal Map Example"] = "normalMap.lua", {"Animation", "animation.lua"},
["Only Postshader Example"] = "postshaders.lua", {"STI Example", "simple_tiled_impl.lua"},
["Simple Example"] = "simple.lua", {"Only Postshader Example", "postshaders.lua"},
["STI Example"] = "simple_tiled_impl.lua", {"Complex Example", "complex.lua"},
} }
local list, smallfont, bigfont, bigball, lightWorld, lightMouse local list, smallfont, bigfont, bigball, lightWorld, lightMouse
@ -34,12 +34,9 @@ local function load()
smallfont = love.graphics.newFont(12) smallfont = love.graphics.newFont(12)
bigfont = love.graphics.newFont(24) bigfont = love.graphics.newFont(24)
list.font = smallfont list.font = smallfont
bigball = love.graphics.newImage("examples/gfx/love-big-ball.png") bigball = love.graphics.newImage("examples/img/love-big-ball.png")
local n = 0 for n, v in ipairs(examples) do
for c, v in pairs(examples) do list:add(string.format("%04d", n).." "..v[1].." ("..v[2]..")", function() start(v[2]) end)
n = n + 1
local title = string.format("%04d", n) .. " " .. c .. " (" .. v .. ")"
list:add(title, v, function() start(v) end)
end end
love.window.setTitle("LOVE Example Browser") love.window.setTitle("LOVE Example Browser")
lightWorld = LightWorld({ambient = {0.49, 0.49, 0.49}}) lightWorld = LightWorld({ambient = {0.49, 0.49, 0.49}})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 194 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 990 B

After

Width:  |  Height:  |  Size: 990 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 193 B

After

Width:  |  Height:  |  Size: 193 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 981 B

View File

Before

Width:  |  Height:  |  Size: 967 B

After

Width:  |  Height:  |  Size: 967 B

View File

Before

Width:  |  Height:  |  Size: 1019 B

After

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 981 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1018 B

After

Width:  |  Height:  |  Size: 1018 B

View File

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 1012 B

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 116 KiB

View File

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

View File

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -10,10 +10,10 @@ function List:new(x, y, w, h)
return o return o
end end
function List:add(item, file, cb) function List:add(label, cb)
local x, y = self.x+2, self.y+((self.h+1)*(#self.items-1)+1) local x, y = self.x+2, self.y+((self.h+1)*(#self.items-1)+1)
local w, h = self.w-3, self.h local w, h = self.w-3, self.h
table.insert(self.items, {item = item, file = file, cb = cb, x = x, y = y, w = w, h = h, hover = false}) table.insert(self.items, {label = label, cb = cb, x = x, y = y, w = w, h = h, hover = false})
end end
function List:update(dt) function List:update(dt)
@ -36,7 +36,7 @@ function List:draw()
love.graphics.setColor(0, 0, 0, item.hover and 0.49 or 0.24) love.graphics.setColor(0, 0, 0, item.hover and 0.49 or 0.24)
love.graphics.rectangle("fill", item.x+1, item.y+1, item.w-3, item.h) love.graphics.rectangle("fill", item.x+1, item.y+1, item.w-3, item.h)
love.graphics.setColor(1, 1, 1, item.hover and 1 or 0.49) love.graphics.setColor(1, 1, 1, item.hover and 1 or 0.49)
love.graphics.print(item.item, item.x+10, item.y+6) love.graphics.print(item.label, item.x+10, item.y+6)
end end
end end

120
examples/lib/object.lua Normal file
View File

@ -0,0 +1,120 @@
local inspect = require 'examples.vendor.inspect'
local ImageObject, Rect, Circle, Refraction = {}, {}, {}, {}
ImageObject.__index = ImageObject
Rect.__index = Rect
Circle.__index = Circle
Refraction.__index = Refraction
local imageCache = {}
local function loadImg(path)
if imageCache[path] == nil and love.filesystem.getInfo(path) ~= nil then
imageCache[path] = love.graphics.newImage(path)
end
return imageCache[path]
end
local function loadMaterials(path)
if imageCache[path] == nil and love.filesystem.getInfo(path) ~= nil then
imageCache[path] = {}
local files = love.filesystem.getDirectoryItems(path)
for i, file in ipairs(files) do
imageCache[path][i] = loadImg(path .."/" .. file)
end
end
return imageCache[path]
end
function ImageObject:new(lightWorld, path, x, y, shadowType)
o = {x = x, y = y, shadowType = shadowType}
setmetatable(o, self)
o.base = loadImg(path .. "/base.png")
o.normal = loadImg(path .. "/normal.png")
o.glow = loadImg(path .. "/glow.png")
o.materials = loadMaterials(path .. "/materials")
o.body = lightWorld:newImage(o.base, x, y)
o.x, o.y = o.x - o.base:getWidth() * 0.5, o.y - o.base:getHeight() * 0.5
if o.normal ~= nil then o.body:setNormalMap(o.normal) end
if o.glow ~= nil then o.body:setGlowMap(o.glow) end
if shadowType ~= nil then
o.body:setShadowType(shadowType)
end
if o.materials ~= nil and #o.materials > 0 then
o.body:setMaterial(o.materials[math.random(1, #o.materials-1)])
end
return o
end
function ImageObject:update(dt) end
function ImageObject:draw()
love.graphics.setColor(1, 1, 1)
love.graphics.draw(self.base, self.x, self.y)
end
function Rect:new(lightWorld, x, y, w, h)
local w, h = math.random(32, 64), math.random(32, 64)
local r, g, b = math.random(), math.random(), math.random()
o = {x = x, y = y, w = w, h = h, r = r, g = g, b = b}
setmetatable(o, self)
o.body = lightWorld:newRectangle(x, y, w, h)
o.x, o.y = o.x - o.w * 0.5, o.y - o.h * 0.5
o.body:setGlowStrength(1.0)
o.body:setGlowColor(math.random(), math.random(), math.random())
o.body:setColor(r, g, b)
return o
end
function Rect:update(dt) end
function Rect:draw()
love.graphics.setColor(self.r, self.g, self.b)
love.graphics.rectangle("fill", self.x, self.y, self.w, self.h)
end
function Circle:new(lightWorld, x, y, rad)
local r, g, b = math.random(), math.random(), math.random()
o = {x = x, y = y, rad = rad, r = r, g = g, b = b}
setmetatable(o, self)
o.body = lightWorld:newCircle(x, y, rad)
o.body:setGlowStrength(1.0)
o.body:setGlowColor(math.random(), math.random(), math.random())
o.body:setColor(r, g, b)
return o
end
function Circle:update(dt) end
function Circle:draw()
love.graphics.setColor(self.r, self.g, self.b)
love.graphics.circle("fill", self.x, self.y, self.rad)
end
function Refraction:new(lightWorld, path, x, y)
o = {x = x, y = y, tx = 0, ty = 0}
setmetatable(o, self)
o.base = loadImg(path .. "/base.png")
o.normal = loadImg(path .. "/normal.png")
o.body = lightWorld:newRefraction(o.normal, x, y)
o.x, o.y = o.x - o.base:getWidth() * 0.5, o.y - o.base:getHeight() * 0.5
o.body:setReflection(true)
return o
end
function Refraction:update(dt)
self.tx = self.tx + dt * 32.0
self.ty = self.ty + dt * 8.0
self.body:setNormalTileOffset(self.tx, self.ty)
end
function Refraction:draw()
love.graphics.setBlendMode("alpha")
love.graphics.setColor(1, 1, 1, 0.74)
love.graphics.draw(self.base, self.x, self.y)
end
return {
ImageObject = ImageObject,
Rect = Rect,
Circle = Circle,
Refraction = Refraction,
}

View File

@ -5,8 +5,8 @@ local lightWorld, lightMouse
local function load() local function load()
-- load images -- load images
image = love.graphics.newImage("examples/gfx/rock.png") image = love.graphics.newImage("examples/img/normalMap/rock.png")
image_normal = love.graphics.newImage("examples/gfx/rock_n.png") image_normal = love.graphics.newImage("examples/img/normalMap/normal.png")
-- create light world -- create light world
lightWorld = LightWorld({ambient = {0.21,0.21,0.21}}) lightWorld = LightWorld({ambient = {0.21,0.21,0.21}})
-- create light -- create light

View File

@ -6,7 +6,7 @@ local img
local function load() local function load()
post_shader = PostShader() post_shader = PostShader()
render_buffer = love.graphics.newCanvas(love.graphics.getWidth(), love.graphics.getHeight()) render_buffer = love.graphics.newCanvas(love.graphics.getWidth(), love.graphics.getHeight())
img = love.graphics.newImage("examples/gfx/kingscard.jpeg") img = love.graphics.newImage("examples/img/postshaders/kingscard.jpeg")
end end
local function keypressed(k) local function keypressed(k)

View File

@ -12,9 +12,9 @@ local box_locations = {
} }
local function load() local function load()
image = love.graphics.newImage("examples/gfx/machine.png") image = love.graphics.newImage("examples/img/simple/machine.png")
normal = love.graphics.newImage("examples/gfx/machine_normal.png") normal = love.graphics.newImage("examples/img/simple/machine_normal.png")
glow = love.graphics.newImage("examples/gfx/machine_glow.png") glow = love.graphics.newImage("examples/img/simple/machine_glow.png")
-- create light world -- create light world
lightWorld = LightWorld({ambient = {0.21,0.21,0.21}}) lightWorld = LightWorld({ambient = {0.21,0.21,0.21}})
-- create light -- create light

View File

@ -5,8 +5,8 @@ local lightWorld, map, image_normal, lightMouse
local function load() local function load()
-- create light world -- create light world
lightWorld = LightWorld({ambient = {0.49, 0.49, 0.49}}) lightWorld = LightWorld({ambient = {0.49, 0.49, 0.49}})
map = sti.new("examples/gfx/map.lua") map = sti.new("examples/img/sti/map.lua")
image_normal = love.graphics.newImage("examples/gfx/border_NRM.png") image_normal = love.graphics.newImage("examples/img/sti/border_NRM.png")
-- create light -- create light
lightMouse = lightWorld:newLight(0, 0, 1, 0.49, 0.24, 300) lightMouse = lightWorld:newLight(0, 0, 1, 0.49, 0.24, 300)
lightMouse:setGlowStrength(0.3) lightMouse:setGlowStrength(0.3)

330
examples/vendor/inspect.lua vendored Normal file
View File

@ -0,0 +1,330 @@
local inspect ={
_VERSION = 'inspect.lua 3.1.0',
_URL = 'http://github.com/kikito/inspect.lua',
_DESCRIPTION = 'human-readable representations of tables',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2013 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
local tostring = tostring
inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end})
inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end})
local function rawpairs(t)
return next, t, nil
end
-- Apostrophizes the string if it has quotes, but not aphostrophes
-- Otherwise, it returns a regular quoted string
local function smartQuote(str)
if str:match('"') and not str:match("'") then
return "'" .. str .. "'"
end
return '"' .. str:gsub('"', '\\"') .. '"'
end
-- \a => '\\a', \0 => nil
local shortControlCharEscapes = {
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\127"] = "\\127",
}
local longControlCharEscapes = {["\127"]="\127"} -- \a => nil, \0 => \000, 31 => \031
for i=0, 31 do
local ch = string.char(i)
if not shortControlCharEscapes[ch] then
shortControlCharEscapes[ch] = "\\"..i
longControlCharEscapes[ch] = string.format("\\%03d", i)
end
end
--longControlCharEscapes["\127"]="\\127"
local function escape(str)
return (str:gsub("\\", "\\\\")
:gsub("(%c)%f[0-9]", longControlCharEscapes)
:gsub("%c", shortControlCharEscapes))
end
local function isIdentifier(str)
return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" )
end
local function isSequenceKey(k, sequenceLength)
return type(k) == 'number'
and 1 <= k
and k <= sequenceLength
and math.floor(k) == k
end
local defaultTypeOrders = {
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
['function'] = 5, ['userdata'] = 6, ['thread'] = 7
}
local function sortKeys(a, b)
local ta, tb = type(a), type(b)
-- strings and numbers are sorted numerically/alphabetically
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
-- Two default types are compared according to the defaultTypeOrders table
if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
elseif dta then return true -- default types before custom ones
elseif dtb then return false -- custom types after default ones
end
-- custom types are sorted out alphabetically
return ta < tb
end
-- For implementation reasons, the behavior of rawlen & # is "undefined" when
-- tables aren't pure sequences. So we implement our own # operator.
local function getSequenceLength(t)
local len = 1
local v = rawget(t,len)
while v ~= nil do
len = len + 1
v = rawget(t,len)
end
return len - 1
end
local function getNonSequentialKeys(t)
local keys, keysLength = {}, 0
local sequenceLength = getSequenceLength(t)
for k,_ in rawpairs(t) do
if not isSequenceKey(k, sequenceLength) then
keysLength = keysLength + 1
keys[keysLength] = k
end
end
table.sort(keys, sortKeys)
return keys, keysLength, sequenceLength
end
local function countTableAppearances(t, tableAppearances)
tableAppearances = tableAppearances or {}
if type(t) == 'table' then
if not tableAppearances[t] then
tableAppearances[t] = 1
for k,v in rawpairs(t) do
countTableAppearances(k, tableAppearances)
countTableAppearances(v, tableAppearances)
end
countTableAppearances(getmetatable(t), tableAppearances)
else
tableAppearances[t] = tableAppearances[t] + 1
end
end
return tableAppearances
end
local copySequence = function(s)
local copy, len = {}, #s
for i=1, len do copy[i] = s[i] end
return copy, len
end
local function makePath(path, ...)
local keys = {...}
local newPath, len = copySequence(path)
for i=1, #keys do
newPath[len + i] = keys[i]
end
return newPath
end
local function processRecursive(process, item, path, visited)
if item == nil then return nil end
if visited[item] then return visited[item] end
local processed = process(item, path)
if type(processed) == 'table' then
local processedCopy = {}
visited[item] = processedCopy
local processedKey
for k,v in rawpairs(processed) do
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
if processedKey ~= nil then
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
end
end
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field
setmetatable(processedCopy, mt)
processed = processedCopy
end
return processed
end
-------------------------------------------------------------------
local Inspector = {}
local Inspector_mt = {__index = Inspector}
function Inspector:puts(...)
local args = {...}
local buffer = self.buffer
local len = #buffer
for i=1, #args do
len = len + 1
buffer[len] = args[i]
end
end
function Inspector:down(f)
self.level = self.level + 1
f()
self.level = self.level - 1
end
function Inspector:tabify()
self:puts(self.newline, string.rep(self.indent, self.level))
end
function Inspector:alreadyVisited(v)
return self.ids[v] ~= nil
end
function Inspector:getId(v)
local id = self.ids[v]
if not id then
local tv = type(v)
id = (self.maxIds[tv] or 0) + 1
self.maxIds[tv] = id
self.ids[v] = id
end
return tostring(id)
end
function Inspector:putKey(k)
if isIdentifier(k) then return self:puts(k) end
self:puts("[")
self:putValue(k)
self:puts("]")
end
function Inspector:putTable(t)
if t == inspect.KEY or t == inspect.METATABLE then
self:puts(tostring(t))
elseif self:alreadyVisited(t) then
self:puts('<table ', self:getId(t), '>')
elseif self.level >= self.depth then
self:puts('{...}')
else
if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
local mt = getmetatable(t)
self:puts('{')
self:down(function()
local count = 0
for i=1, sequenceLength do
if count > 0 then self:puts(',') end
self:puts(' ')
self:putValue(t[i])
count = count + 1
end
for i=1, nonSequentialKeysLength do
local k = nonSequentialKeys[i]
if count > 0 then self:puts(',') end
self:tabify()
self:putKey(k)
self:puts(' = ')
self:putValue(t[k])
count = count + 1
end
if type(mt) == 'table' then
if count > 0 then self:puts(',') end
self:tabify()
self:puts('<metatable> = ')
self:putValue(mt)
end
end)
if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing }
self:tabify()
elseif sequenceLength > 0 then -- array tables have one extra space before closing }
self:puts(' ')
end
self:puts('}')
end
end
function Inspector:putValue(v)
local tv = type(v)
if tv == 'string' then
self:puts(smartQuote(escape(v)))
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
tv == 'cdata' or tv == 'ctype' then
self:puts(tostring(v))
elseif tv == 'table' then
self:putTable(v)
else
self:puts('<', tv, ' ', self:getId(v), '>')
end
end
-------------------------------------------------------------------
function inspect.inspect(root, options)
options = options or {}
local depth = options.depth or math.huge
local newline = options.newline or '\n'
local indent = options.indent or ' '
local process = options.process
if process then
root = processRecursive(process, root, {}, {})
end
local inspector = setmetatable({
depth = depth,
level = 0,
buffer = {},
ids = {},
maxIds = {},
newline = newline,
indent = indent,
tableAppearances = countTableAppearances(root)
}, Inspector_mt)
inspector:putValue(root)
return table.concat(inspector.buffer)
end
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
return inspect

View File

@ -11,21 +11,21 @@ body.glowShader = love.graphics.newShader(_PACKAGE.."/shaders/glow.glsl")
body.materialShader = love.graphics.newShader(_PACKAGE.."/shaders/material.glsl") body.materialShader = love.graphics.newShader(_PACKAGE.."/shaders/material.glsl")
local function new(id, type, ...) local function new(id, type, ...)
local args = {...} local args = {...}
local obj = setmetatable({}, body) local obj = setmetatable({}, body)
obj.id = id obj.id = id
obj.type = type obj.type = type
obj.shine = true obj.shine = true
obj.red = 1.0 obj.red = 1.0
obj.green = 1.0 obj.green = 1.0
obj.blue = 1.0 obj.blue = 1.0
obj.alpha = 1.0 obj.alpha = 1.0
obj.glowRed = 1 obj.glowRed = 1
obj.glowGreen = 1 obj.glowGreen = 1
obj.glowBlue = 1 obj.glowBlue = 1
obj.glowStrength = 0.0 obj.glowStrength = 0.0
obj.tileX = 0 obj.tileX = 0
obj.tileY = 0 obj.tileY = 0
obj.zheight = 1 obj.zheight = 1
obj.rotation = 0 obj.rotation = 0
@ -36,9 +36,9 @@ local function new(id, type, ...)
obj.visible = true obj.visible = true
obj.is_on_screen = true obj.is_on_screen = true
if obj.type == "circle" then if obj.type == "circle" then
obj.x = args[1] or 0 obj.x = args[1] or 0
obj.y = args[2] or 0 obj.y = args[2] or 0
circle_canvas = love.graphics.newCanvas(args[3]*2, args[3]*2) circle_canvas = love.graphics.newCanvas(args[3]*2, args[3]*2)
util.drawto(circle_canvas, 0, 0, 1, false, function() util.drawto(circle_canvas, 0, 0, 1, false, function()
@ -52,44 +52,45 @@ local function new(id, type, ...)
obj:generateNormalMapFlat("top") obj:generateNormalMapFlat("top")
obj:setShadowType('circle', args[3], args[4], args[5]) obj:setShadowType('circle', args[3], args[4], args[5])
elseif obj.type == "rectangle" then elseif obj.type == "rectangle" then
local x = args[1] or 0 local x = args[1] or 0
local y = args[2] or 0 local y = args[2] or 0
local width = args[3] or 64 local width = args[3] or 64
local height = args[4] or 64 local height = args[4] or 64
local ox = args[5] or width * 0.5 local ox = args[5] or width * 0.5
local oy = args[6] or height * 0.5 local oy = args[6] or height * 0.5
obj.type = "polygon"
obj:setPoints( obj:setPoints(
x - ox, y - oy, x - ox, y - oy,
x - ox + width, y - oy, x - ox + width, y - oy,
x - ox + width, y - oy + height, x - ox + width, y - oy + height,
x - ox, y - oy + height x - ox, y - oy + height
) )
elseif obj.type == "polygon" then elseif obj.type == "polygon" then
obj:setPoints(...) obj:setPoints(...)
elseif obj.type == "image" then elseif obj.type == "image" then
obj.img = args[1] obj.img = args[1]
obj.x = args[2] or 0 obj.x = args[2] or 0
obj.y = args[3] or 0 obj.y = args[3] or 0
if obj.img then if obj.img then
obj.imgWidth = obj.img:getWidth() obj.imgWidth = obj.img:getWidth()
obj.imgHeight = obj.img:getHeight() obj.imgHeight = obj.img:getHeight()
obj.ix = obj.imgWidth * 0.5 obj.ix = obj.imgWidth * 0.5
obj.iy = obj.imgHeight * 0.5 obj.iy = obj.imgHeight * 0.5
end end
obj:generateNormalMapFlat("top") obj:generateNormalMapFlat("top")
obj:setShadowType('rectangle', args[4] or obj.imgWidth, args[5] or obj.imgHeight, args[6], args[7]) obj:setShadowType('rectangle', args[4] or obj.imgWidth, args[5] or obj.imgHeight, args[6], args[7])
obj.reflective = true obj.reflective = true
elseif obj.type == "animation" then elseif obj.type == "animation" then
obj.img = args[1] obj.img = args[1]
obj.x = args[2] or 0 obj.x = args[2] or 0
obj.y = args[3] or 0 obj.y = args[3] or 0
obj.animations = {} obj.animations = {}
obj.castsNoShadow = true obj.castsNoShadow = true
obj:generateNormalMapFlat("top") obj:generateNormalMapFlat("top")
obj.reflective = true obj.reflective = true
elseif obj.type == "refraction" then elseif obj.type == "refraction" then
obj.x = args[2] or 0 obj.x = args[2] or 0
obj.y = args[3] or 0 obj.y = args[3] or 0
obj:setNormalMap(args[1], args[4], args[5]) obj:setNormalMap(args[1], args[4], args[5])
@ -107,7 +108,7 @@ local function new(id, type, ...)
obj.ox = obj.width * 0.5 obj.ox = obj.width * 0.5
obj.oy = obj.height * 0.5 obj.oy = obj.height * 0.5
obj.reflection = true obj.reflection = true
end end
obj:commit_changes() obj:commit_changes()