diff --git a/README.md b/README.md index f98c30b..258356e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ function love.load() end function love.update(dt) - lightWorld:update(dt) --only needed for animation + lightWorld:update(dt) lightWorld:setTranslation(x, y, scale) end diff --git a/examples/animation.lua b/examples/animation.lua index fbd4e2c..e1f3e31 100644 --- a/examples/animation.lua +++ b/examples/animation.lua @@ -62,7 +62,7 @@ function love.update(dt) end animation2:update(dt) - lightWorld:update(dt) --only needed for animation + lightWorld:update(dt) lightMouse:setPosition((love.mouse.getX() - x)/scale, (love.mouse.getY() - y)/scale, z) end diff --git a/examples/complex.lua b/examples/complex.lua index 5bded83..d1479c1 100644 --- a/examples/complex.lua +++ b/examples/complex.lua @@ -96,6 +96,7 @@ function love.load() ambient = {15,15,15}, refractionStrength = 16.0, reflectionVisibility = 0.75, + shadowBlur = 2.0 }) mouseLight = lightWorld:newLight(0, 0, 255, 191, 127, lightRange) @@ -235,6 +236,7 @@ function love.update(dt) else lightWorld.post_shader:removeEffect("bloom") end + lightWorld:update(dt) end function love.draw() diff --git a/examples/gamera.lua b/examples/gamera.lua index 8c54bbe..2a86953 100644 --- a/examples/gamera.lua +++ b/examples/gamera.lua @@ -63,6 +63,7 @@ function love.update(dt) cam:setScale(scale) cam:setPosition(x, y) + lightWorld:update(dt) lightWorld:setTranslation(x, y, scale) end diff --git a/examples/hump.lua b/examples/hump.lua index 5d5d612..04b69cd 100644 --- a/examples/hump.lua +++ b/examples/hump.lua @@ -63,6 +63,7 @@ function love.update(dt) cam:lookAt(x, y) cam:zoom(scale) + lightWorld:update(dt) lightWorld:setTranslation(x, y, scale) end diff --git a/examples/normalMap.lua b/examples/normalMap.lua index 8230c55..f7e26f9 100644 --- a/examples/normalMap.lua +++ b/examples/normalMap.lua @@ -48,6 +48,7 @@ function love.update(dt) scale = scale + 0.01 end + lightWorld:update(dt) lightMouse:setPosition(love.mouse.getX()/scale, love.mouse.getY()/scale) end diff --git a/examples/short.lua b/examples/short.lua index 9ee1423..62d385a 100644 --- a/examples/short.lua +++ b/examples/short.lua @@ -136,6 +136,7 @@ function love.update(dt) lightWorld.post_shader:removeEffect("chromatic_aberration") end + lightWorld:update(dt) lightMouse:setPosition((love.mouse.getX() - x)/scale, (love.mouse.getY() - y)/scale, z) end diff --git a/examples/simple_tiled_impl.lua b/examples/simple_tiled_impl.lua index 4f2e086..4d9314d 100644 --- a/examples/simple_tiled_impl.lua +++ b/examples/simple_tiled_impl.lua @@ -56,6 +56,7 @@ function love.update(dt) end map:update(dt) + lightWorld:update(dt) lightMouse:setPosition((love.mouse.getX() - x)/scale, (love.mouse.getY() - y)/scale, z) end diff --git a/lib/body.lua b/lib/body.lua index f26139b..2d2cd62 100644 --- a/lib/body.lua +++ b/lib/body.lua @@ -28,6 +28,7 @@ function body:init(id, type, ...) self.castsNoShadow = false self.visible = true + self.is_on_screen = true if self.type == "circle" then self.x = args[1] or 0 @@ -449,12 +450,16 @@ function body:setShadowType(type, ...) end end -function body:isInLightRange(light) - local l, t, w = light.x - light.range, light.y - light.range, light.range*2 - return self:isInRange(l,t,w,w,1) +function body:isVisible() + return self.visible and self.is_on_screen end -function body:isInRange(l, t, w, h, s) +function body:inLightRange(light) + local l, t, w = light.x - light.range, light.y - light.range, light.range*2 + return self:inRange(l,t,w,w,1) +end + +function body:inRange(l, t, w, h, s) local radius if self.type == 'circle' then radius = self.radius diff --git a/lib/init.lua b/lib/init.lua index 52349fb..a5e5a0e 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -37,7 +37,7 @@ light_world.reflectionShader = love.graphics.newShader(_PACKAGE.."shaders/refl function light_world:init(options) self.lights = {} - self.body = {} + self.bodies = {} self.post_shader = PostShader() self.l, self.t, self.s = 0, 0, 1 @@ -77,19 +77,22 @@ function light_world:refreshScreenSize(w, h) end function light_world:update(dt) - for i = 1, #self.body do - if self.body[i]:isInRange(-self.l,-self.t,self.w,self.h,self.s) and - self.body[i].type == 'animation' then - self.body[i]:update(dt) + for i = 1, #self.bodies do + self.bodies[i].is_on_screen = self.bodies[i]:inRange(-self.l,-self.t,self.w,self.h,self.s) + if self.bodies[i]:isVisible() then + self.bodies[i]:update(dt) end end + for i = 1, #self.lights do + self.lights[i].is_on_screen = self.lights[i]:inRange(self.l,self.t,self.w,self.h,self.s) + end end function light_world:draw(cb) util.drawto(self.render_buffer, self.l, self.t, self.s, function() cb( self.l,self.t,self.w,self.h,self.s) _ = self.disableMaterial or self:drawMaterial( self.l,self.t,self.w,self.h,self.s) - self:drawNormalShading( self.l,self.t,self.w,self.h,self.s) + self:drawShadows( self.l,self.t,self.w,self.h,self.s) _ = self.disableGlow or self:drawGlow( self.l,self.t,self.w,self.h,self.s) _ = self.disableRefraction or self:drawRefraction( self.l,self.t,self.w,self.h,self.s) _ = self.disableReflection or self:drawReflection( self.l,self.t,self.w,self.h,self.s) @@ -98,13 +101,13 @@ function light_world:draw(cb) end -- draw normal shading -function light_world:drawNormalShading(l,t,w,h,s) +function light_world:drawShadows(l,t,w,h,s) -- create normal map self.normalMap:clear() util.drawto(self.normalMap, l, t, s, function() - for i = 1, #self.body do - if self.body[i]:isInRange(-l,-t,w,h,s) then - self.body[i]:drawNormal() + for i = 1, #self.bodies do + if self.bodies[i]:isVisible() then + self.bodies[i]:drawNormal() end end end) @@ -115,23 +118,19 @@ function light_world:drawNormalShading(l,t,w,h,s) self.shadow_buffer:clear() for i = 1, #self.lights do local light = self.lights[i] - if self.lights[i]:inRange(l,t,w,h,s) then + if self.lights[i]:isVisible() then -- create shadow map for this light self.shadowMap:clear() util.drawto(self.shadowMap, l, t, s, function() love.graphics.setStencil(function() - love.graphics.circle('fill', light.x, light.y, light.range) + local angle = light.direction - (math.pi - light.angle / 2.0) + love.graphics.arc("fill", light.x, light.y, light.range, angle, angle + light.angle) end) - for k = 1, #self.body do - if self.body[k]:isInLightRange(self.lights[i]) and self.body[k]:isInRange(-l,-t,w,h,s) then - self.body[k]:drawShadow(self.lights[i]) + for k = 1, #self.bodies do + if self.bodies[k]:inLightRange(self.lights[i]) and self.bodies[k]:isVisible() then + self.bodies[k]:drawShadow(self.lights[i]) end end - if light.angle > 0 then - local angle = math.pi - light.angle / 2.0 - love.graphics.setColor(0, 0, 0) - love.graphics.arc("fill", light.x, light.y, light.range, light.direction - angle, light.direction + angle) - end end) -- draw scene for this light using normals and shadowmap self.shadowShader:send('lightColor', {light.red / 255.0, light.green / 255.0, light.blue / 255.0}) @@ -143,7 +142,8 @@ function light_world:drawNormalShading(l,t,w,h,s) blendmode = 'additive', shader = self.shadowShader, stencil = function() - love.graphics.circle('fill', (light.x + l/s) * s, (light.y + t/s) * s, light.range) + local angle = light.direction - (math.pi - light.angle / 2.0) + love.graphics.arc("fill", (light.x + l/s) * s, (light.y + t/s) * s, light.range, angle, angle + light.angle) end }) end @@ -162,9 +162,9 @@ end -- draw material function light_world:drawMaterial(l,t,w,h,s) - for i = 1, #self.body do - if self.body[i]:isInRange(-l,-t,w,h,s) then - self.body[i]:drawMaterial() + for i = 1, #self.bodies do + if self.bodies[i]:isVisible() then + self.bodies[i]:drawMaterial() end end end @@ -185,10 +185,10 @@ function light_world:drawGlow(l,t,w,h,s) -- create glow map self.glowMap:clear(0, 0, 0) util.drawto(self.glowMap, l, t, s, function() - for i = 1, #self.body do - if self.body[i]:isInRange(-l,-t,w,h,s) and self.body[i].glowStrength > 0.0 then + for i = 1, #self.bodies do + if self.bodies[i]:isVisible() and self.bodies[i].glowStrength > 0.0 then has_glow = true - self.body[i]:drawGlow() + self.bodies[i]:drawGlow() end end end) @@ -203,9 +203,9 @@ function light_world:drawRefraction(l,t,w,h,s) -- create refraction map self.refractionMap:clear() util.drawto(self.refractionMap, l, t, s, function() - for i = 1, #self.body do - if self.body[i]:isInRange(-l,-t,w,h,s) then - self.body[i]:drawRefraction() + for i = 1, #self.bodies do + if self.bodies[i]:isVisible() then + self.bodies[i]:drawRefraction() end end end) @@ -220,9 +220,9 @@ function light_world:drawReflection(l,t,w,h,s) -- create reflection map self.reflectionMap:clear(0, 0, 0) util.drawto(self.reflectionMap, l, t, s, function() - for i = 1, #self.body do - if self.body[i]:isInRange(-l,-t,w,h,s) then - self.body[i]:drawReflection() + for i = 1, #self.bodies do + if self.bodies[i]:isVisible() then + self.bodies[i]:drawReflection() end end end) @@ -250,15 +250,15 @@ end function light_world:setScale(s) self.s = s end function light_world:clearLights() self.lights = {} end -function light_world:clearBodies() self.body = {} end +function light_world:clearBodies() self.bodies = {} end function light_world:setAmbientColor(red, green, blue) self.ambient = {red, green, blue} end function light_world:setShadowBlur(blur) self.shadowBlur = blur end function light_world:setGlowStrength(strength) self.glowBlur = strength end function light_world:setRefractionStrength(strength) self.refractionStrength = strength end function light_world:setReflectionStrength(strength) self.reflectionStrength = strength end function light_world:setReflectionVisibility(visibility) self.reflectionVisibility = visibility end -function light_world:getBodyCount() return #self.body end -function light_world:getBody(n) return self.body[n] end +function light_world:getBodyCount() return #self.bodies end +function light_world:getBody(n) return self.bodies[n] end function light_world:getLightCount() return #self.lights end function light_world:getLight(n) return self.lights[n] end function light_world:newRectangle(...) return self:newBody("rectangle", ...) end @@ -278,16 +278,16 @@ end -- new body function light_world:newBody(type, ...) - local id = #self.body + 1 - self.body[id] = Body(id, type, ...) - return self.body[#self.body] + local id = #self.bodies + 1 + self.bodies[id] = Body(id, type, ...) + return self.bodies[#self.bodies] end function light_world:remove(to_kill) if to_kill:is_a(Body) then - for i = 1, #self.body do - if self.body[i] == to_kill then - table.remove(self.body, i) + for i = 1, #self.bodies do + if self.bodies[i] == to_kill then + table.remove(self.bodies, i) return true end end diff --git a/lib/light.lua b/lib/light.lua index f331700..75fd17e 100644 --- a/lib/light.lua +++ b/lib/light.lua @@ -18,6 +18,7 @@ function light:init(x, y, r, g, b, range) self.glowSize = 0.1 self.glowStrength = 0.0 self.visible = true + self.is_on_screen = true end -- set position @@ -104,6 +105,10 @@ function light:setGlowStrength(strength) self.glowStrength = strength end +function light:isVisible() + return self.visible and self.is_on_screen +end + 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 self.visible and (lx + rs) > 0 and (lx - rs) < w/s and (ly + rs) > 0 and (ly - rs) < h/s