2014-09-26 16:48:46 +00:00
|
|
|
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
|
|
|
|
local class = require(_PACKAGE.."/class")
|
2014-09-26 22:11:23 +00:00
|
|
|
local stencils = require(_PACKAGE..'/stencils')
|
2014-10-22 02:48:19 +00:00
|
|
|
local util = require(_PACKAGE..'/util')
|
2014-09-26 16:48:46 +00:00
|
|
|
|
2014-09-26 20:52:16 +00:00
|
|
|
local light = class()
|
|
|
|
|
2014-09-29 14:03:15 +00:00
|
|
|
light.shader = love.graphics.newShader(_PACKAGE.."/shaders/poly_shadow.glsl")
|
|
|
|
light.normalShader = love.graphics.newShader(_PACKAGE.."/shaders/normal.glsl")
|
|
|
|
light.normalInvertShader = love.graphics.newShader(_PACKAGE.."/shaders/normal_invert.glsl")
|
|
|
|
|
2014-10-03 00:32:31 +00:00
|
|
|
function light:init(x, y, r, g, b, range)
|
2014-09-26 20:52:16 +00:00
|
|
|
self.direction = 0
|
|
|
|
self.angle = math.pi * 2.0
|
|
|
|
self.range = 0
|
|
|
|
self.x = x or 0
|
|
|
|
self.y = y or 0
|
|
|
|
self.z = 15
|
|
|
|
self.red = r or 255
|
|
|
|
self.green = g or 255
|
|
|
|
self.blue = b or 255
|
|
|
|
self.range = range or 300
|
|
|
|
self.smooth = 1.0
|
|
|
|
self.glowSize = 0.1
|
|
|
|
self.glowStrength = 0.0
|
|
|
|
self.visible = true
|
2014-10-08 12:55:05 +00:00
|
|
|
self:refresh()
|
2014-10-03 00:32:31 +00:00
|
|
|
end
|
|
|
|
|
2014-10-08 12:55:05 +00:00
|
|
|
function light:refresh(w, h)
|
|
|
|
w, h = w or love.window.getWidth(), h or love.window.getHeight()
|
|
|
|
|
2014-10-06 13:31:14 +00:00
|
|
|
self.shadow = love.graphics.newCanvas(w, h)
|
|
|
|
self.shine = love.graphics.newCanvas(w, h)
|
2014-10-29 00:47:46 +00:00
|
|
|
self.normalInvertShader:send('screenResolution', {w, h})
|
|
|
|
self.normalShader:send('screenResolution', {w, h})
|
2014-09-26 20:52:16 +00:00
|
|
|
end
|
2014-09-26 16:48:46 +00:00
|
|
|
|
|
|
|
-- set position
|
|
|
|
function light:setPosition(x, y, z)
|
|
|
|
if x ~= self.x or y ~= self.y or (z and z ~= self.z) then
|
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
if z then
|
|
|
|
self.z = z
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- get x
|
2014-10-26 19:27:35 +00:00
|
|
|
function light:getPosition()
|
2014-10-28 01:46:27 +00:00
|
|
|
return self.x, self.y, self.z
|
2014-09-26 16:48:46 +00:00
|
|
|
end
|
2014-10-03 00:32:31 +00:00
|
|
|
|
2014-09-26 16:48:46 +00:00
|
|
|
-- set color
|
|
|
|
function light:setColor(red, green, blue)
|
|
|
|
self.red = red
|
|
|
|
self.green = green
|
|
|
|
self.blue = blue
|
|
|
|
end
|
|
|
|
|
|
|
|
-- set range
|
|
|
|
function light:setRange(range)
|
|
|
|
if range ~= self.range then
|
|
|
|
self.range = range
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- set direction
|
|
|
|
function light:setDirection(direction)
|
|
|
|
if direction ~= self.direction then
|
|
|
|
if direction > math.pi * 2 then
|
|
|
|
self.direction = math.mod(direction, math.pi * 2)
|
|
|
|
elseif direction < 0.0 then
|
|
|
|
self.direction = math.pi * 2 - math.mod(math.abs(direction), math.pi * 2)
|
|
|
|
else
|
|
|
|
self.direction = direction
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-09-27 17:46:46 +00:00
|
|
|
|
2014-09-26 16:48:46 +00:00
|
|
|
-- set angle
|
|
|
|
function light:setAngle(angle)
|
|
|
|
if angle ~= self.angle then
|
|
|
|
if angle > math.pi then
|
|
|
|
self.angle = math.mod(angle, math.pi)
|
|
|
|
elseif angle < 0.0 then
|
|
|
|
self.angle = math.pi - math.mod(math.abs(angle), math.pi)
|
|
|
|
else
|
|
|
|
self.angle = angle
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-09-27 17:46:46 +00:00
|
|
|
|
2014-09-26 16:48:46 +00:00
|
|
|
-- set glow size
|
|
|
|
function light:setSmooth(smooth)
|
|
|
|
self.smooth = smooth
|
|
|
|
end
|
2014-09-27 17:46:46 +00:00
|
|
|
|
2014-09-26 16:48:46 +00:00
|
|
|
-- set glow size
|
|
|
|
function light:setGlowSize(size)
|
|
|
|
self.glowSize = size
|
|
|
|
end
|
2014-09-27 17:46:46 +00:00
|
|
|
|
2014-09-26 16:48:46 +00:00
|
|
|
-- set glow strength
|
|
|
|
function light:setGlowStrength(strength)
|
|
|
|
self.glowStrength = strength
|
|
|
|
end
|
|
|
|
|
2014-11-06 04:05:21 +00:00
|
|
|
function light:inRange(l,t,w,h,s)
|
|
|
|
local lx, ly, rs = (self.x + l/s) * s, (self.y + t/s) * s, self.range * s
|
|
|
|
|
|
|
|
return (lx + rs) > 0 and
|
|
|
|
(lx - rs) < w/s and
|
|
|
|
(ly + rs) > 0 and
|
|
|
|
(ly - rs) < h/s
|
2014-10-03 03:04:22 +00:00
|
|
|
end
|
|
|
|
|
2014-10-22 02:48:19 +00:00
|
|
|
function light:drawShadow(l,t,w,h,s,bodies, canvas)
|
2014-11-06 04:05:21 +00:00
|
|
|
if self.visible and self:inRange(l,t,w,h,s) then
|
2014-09-27 17:46:46 +00:00
|
|
|
-- calculate shadows
|
2014-10-03 14:18:06 +00:00
|
|
|
local shadow_geometry = {}
|
|
|
|
for i = 1, #bodies do
|
|
|
|
local current = bodies[i]:calculateShadow(self)
|
|
|
|
if current ~= nil then
|
|
|
|
shadow_geometry[#shadow_geometry + 1] = current
|
|
|
|
end
|
|
|
|
end
|
2014-09-27 17:46:46 +00:00
|
|
|
|
2014-10-22 02:48:19 +00:00
|
|
|
-- draw shadow
|
2014-10-23 12:25:12 +00:00
|
|
|
self.shadow:clear()
|
2014-10-22 02:48:19 +00:00
|
|
|
util.drawto(self.shadow, l, t, s, function()
|
2014-10-29 00:47:46 +00:00
|
|
|
|
2014-10-29 01:03:00 +00:00
|
|
|
self.shader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, self.z/255.0})
|
2014-10-24 17:34:44 +00:00
|
|
|
self.shader:send("lightRange", self.range*s)
|
2014-10-23 12:25:12 +00:00
|
|
|
self.shader:send("lightColor", {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
|
|
|
|
self.shader:send("lightSmooth", self.smooth)
|
|
|
|
self.shader:send("lightGlow", {1.0 - self.glowSize, self.glowStrength})
|
|
|
|
self.shader:send("lightAngle", math.pi - self.angle / 2.0)
|
|
|
|
self.shader:send("lightDirection", self.direction)
|
2014-10-22 02:48:19 +00:00
|
|
|
love.graphics.setShader(self.shader)
|
|
|
|
love.graphics.setInvertedStencil(stencils.shadow(shadow_geometry, bodies))
|
|
|
|
love.graphics.setBlendMode("additive")
|
2014-10-23 13:23:20 +00:00
|
|
|
love.graphics.rectangle("fill", -l/s,-t/s,w/s,h/s)
|
2014-10-22 02:48:19 +00:00
|
|
|
|
|
|
|
-- draw color shadows
|
|
|
|
love.graphics.setBlendMode("multiplicative")
|
|
|
|
love.graphics.setShader()
|
|
|
|
for k = 1,#shadow_geometry do
|
|
|
|
if shadow_geometry[k].alpha < 1.0 then
|
|
|
|
love.graphics.setColor(
|
|
|
|
shadow_geometry[k].red * (1.0 - shadow_geometry[k].alpha),
|
|
|
|
shadow_geometry[k].green * (1.0 - shadow_geometry[k].alpha),
|
|
|
|
shadow_geometry[k].blue * (1.0 - shadow_geometry[k].alpha)
|
|
|
|
)
|
|
|
|
love.graphics.polygon("fill", unpack(shadow_geometry[k]))
|
|
|
|
end
|
2014-09-26 22:11:23 +00:00
|
|
|
end
|
|
|
|
|
2014-10-22 02:48:19 +00:00
|
|
|
for k = 1, #bodies do
|
|
|
|
bodies[k]:drawShadow(self,l,t,w,h,s)
|
|
|
|
end
|
|
|
|
end)
|
2014-09-26 22:11:23 +00:00
|
|
|
|
2014-10-24 02:41:52 +00:00
|
|
|
love.graphics.setStencil()
|
|
|
|
love.graphics.setShader()
|
|
|
|
util.drawCanvasToCanvas(self.shadow, canvas, {blendmode = "additive"})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function light:drawShine(l,t,w,h,s,bodies,canvas)
|
2014-11-06 04:05:21 +00:00
|
|
|
if self.visible and self:inRange(l,t,w,h,s) then
|
2014-10-24 02:41:52 +00:00
|
|
|
--update shine
|
2014-10-23 12:25:12 +00:00
|
|
|
self.shine:clear(255, 255, 255)
|
2014-10-22 02:48:19 +00:00
|
|
|
util.drawto(self.shine, l, t, s, function()
|
|
|
|
love.graphics.setShader(self.shader)
|
|
|
|
love.graphics.setBlendMode("alpha")
|
2014-10-24 02:41:52 +00:00
|
|
|
love.graphics.setStencil(stencils.shine(bodies))
|
2014-10-23 13:23:20 +00:00
|
|
|
love.graphics.rectangle("fill", -l/s,-t/s,w/s,h/s)
|
2014-10-22 02:48:19 +00:00
|
|
|
end)
|
2014-10-03 00:32:31 +00:00
|
|
|
love.graphics.setStencil()
|
2014-10-22 02:48:19 +00:00
|
|
|
love.graphics.setShader()
|
2014-10-24 02:41:52 +00:00
|
|
|
util.drawCanvasToCanvas(self.shine, canvas, {blendmode = "additive"})
|
2014-09-26 22:11:23 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-10-29 01:03:00 +00:00
|
|
|
function light:drawPixelShadow(l,t,w,h,s, normalMap, canvas)
|
2014-11-06 04:05:21 +00:00
|
|
|
if self.visible and self:inRange(l,t,w,h,s) then
|
2014-09-26 22:11:23 +00:00
|
|
|
if self.normalInvert then
|
2014-09-29 14:03:15 +00:00
|
|
|
self.normalInvertShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
|
2014-10-29 01:03:00 +00:00
|
|
|
self.normalInvertShader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, self.z / 255.0})
|
2014-09-29 14:03:15 +00:00
|
|
|
self.normalInvertShader:send('lightRange',{self.range})
|
|
|
|
self.normalInvertShader:send("lightSmooth", self.smooth)
|
|
|
|
self.normalInvertShader:send("lightAngle", math.pi - self.angle / 2.0)
|
|
|
|
self.normalInvertShader:send("lightDirection", self.direction)
|
2014-10-22 12:37:19 +00:00
|
|
|
util.drawCanvasToCanvas(normalMap, canvas, {shader = self.normalInvertShader})
|
2014-09-26 22:11:23 +00:00
|
|
|
else
|
2014-09-29 14:03:15 +00:00
|
|
|
self.normalShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
|
2014-10-29 01:03:00 +00:00
|
|
|
self.normalShader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, self.z / 255.0})
|
2014-09-29 14:03:15 +00:00
|
|
|
self.normalShader:send('lightRange',{self.range})
|
|
|
|
self.normalShader:send("lightSmooth", self.smooth)
|
|
|
|
self.normalShader:send("lightAngle", math.pi - self.angle / 2.0)
|
|
|
|
self.normalShader:send("lightDirection", self.direction)
|
2014-10-22 12:37:19 +00:00
|
|
|
util.drawCanvasToCanvas(normalMap, canvas, {shader = self.normalShader})
|
2014-09-26 22:11:23 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-11-06 04:06:54 +00:00
|
|
|
function light:setVisible(visible)
|
|
|
|
self.visible = visible
|
|
|
|
end
|
|
|
|
|
2014-09-26 16:48:46 +00:00
|
|
|
return light
|