diff --git a/lib/body.lua b/lib/body.lua index c92f31f..40c57ac 100644 --- a/lib/body.lua +++ b/lib/body.lua @@ -13,9 +13,9 @@ function body:init(id, type, ...) self.id = id self.type = type self.shine = true - self.red = 0 - self.green = 0 - self.blue = 0 + self.red = 1.0 + self.green = 1.0 + self.blue = 1.0 self.alpha = 1.0 self.glowRed = 255 self.glowGreen = 255 @@ -447,7 +447,7 @@ function body:drawShadow(light) end end -function body:drawNormalShading() +function body:drawNormal() if self.type == "image" and self.normalMesh then love.graphics.setColor(255, 255, 255) love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny) @@ -534,7 +534,7 @@ function body:drawMaterial() end end -function body:calculateShadow(light) +function body:drawCalculatedShadow(light) if self.shadowType == "rectangle" or self.shadowType == "polygon" then return self:calculatePolyShadow(light) elseif self.shadowType == "circle" then @@ -593,13 +593,8 @@ function body:calculatePolyShadow(light) end end if #curShadowGeometry >= 6 then - curShadowGeometry.alpha = self.alpha - curShadowGeometry.red = self.red - curShadowGeometry.green = self.green - curShadowGeometry.blue = self.blue - return curShadowGeometry - else - return nil + love.graphics.setColor(self.red, self.green, self.blue, self.alpha) + love.graphics.polygon("fill", unpack(curShadowGeometry)) end end @@ -609,7 +604,7 @@ function body:calculateCircleShadow(light) if self.castsNoShadow or (self.zheight - light.z) > 0 then return nil end - + local curShadowGeometry = {} local angle = math.atan2(light.x - (self.x - self.ox), (self.y - self.oy) - light.y) + math.pi / 2 local x2 = ((self.x - self.ox) + math.sin(angle) * self.radius) @@ -641,22 +636,18 @@ function body:calculateCircleShadow(light) local distance1 = math.sqrt(math.pow(light.x - self.x, 2) + math.pow(light.y - self.y, 2)) / 2 local distance2 = math.sqrt(math.pow(light.x - cx, 2) + math.pow(light.y - cy, 2)) / 2 + love.graphics.setColor(self.red, self.green, self.blue, self.alpha) + love.graphics.polygon("fill", curShadowGeometry) + if distance1 <= self.radius then - curShadowGeometry.circle = {cx, cy, radius, 0, (math.pi * 2)} + love.graphics.arc("fill", cx, cy, radius, 0, (math.pi * 2)) elseif distance2 < light.range then -- dont draw circle if way off screen if angle1 > angle2 then - curShadowGeometry.circle = {cx, cy, radius, angle1, angle2} + love.graphics.arc("fill", cx, cy, radius, angle1, angle2) else - curShadowGeometry.circle = {cx, cy, radius, angle1 - math.pi, angle2 - math.pi} + love.graphics.arc("fill", cx, cy, radius, angle1 - math.pi, angle2 - math.pi) end end - - curShadowGeometry.red = self.red - curShadowGeometry.green = self.green - curShadowGeometry.blue = self.blue - curShadowGeometry.alpha = self.alpha - - return curShadowGeometry end return body diff --git a/lib/init.lua b/lib/init.lua index 443a987..e9347fc 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -70,13 +70,10 @@ function light_world:refreshScreenSize(w, h) w, h = w or love.window.getWidth(), h or love.window.getHeight() self.render_buffer = love.graphics.newCanvas(w, h) - self.shadow = love.graphics.newCanvas(w, h) - self.shadow2 = love.graphics.newCanvas(w, h) self.normal = love.graphics.newCanvas(w, h) self.normal2 = love.graphics.newCanvas(w, h) - self.shine = love.graphics.newCanvas(w, h) - self.shine2 = love.graphics.newCanvas(w, h) self.normalMap = love.graphics.newCanvas(w, h) + self.shadowMap = love.graphics.newCanvas(w, h) self.glowMap = love.graphics.newCanvas(w, h) self.glowMap2 = love.graphics.newCanvas(w, h) self.refractionMap = love.graphics.newCanvas(w, h) @@ -101,10 +98,8 @@ function light_world:draw(l,t,s) local w, h = love.graphics.getWidth(), love.graphics.getHeight() util.drawto(self.render_buffer, l, t, s, function() self.drawBackground( l,t,w,h,s) - --self:drawShadow( l,t,w,h,s) self.drawForeground( l,t,w,h,s) self:drawMaterial( l,t,w,h,s) - --self:drawShine( l,t,w,h,s) self:drawNormalShading( l,t,w,h,s) self:drawGlow( l,t,w,h,s) self:drawRefraction( l,t,w,h,s) @@ -124,46 +119,6 @@ function light_world:drawBlur(blendmode, blur, canvas, canvas2, l, t, w, h, s) util.drawCanvasToCanvas(canvas2, canvas, {shader = self.blurh, blendmode = blendmode}) end --- draw shadow -function light_world:drawShadow(l,t,w,h,s) - if not self.isShadows and not self.isLight then - return - end - - -- draw ambient - util.drawto(self.shadow, l, t, s, function() - love.graphics.setColor(unpack(self.ambient)) - love.graphics.setBlendMode("alpha") - love.graphics.rectangle("fill", -l/s, -t/s, w/s, h/s) - for i = 1, #self.lights do - self.lights[i]:drawShadow(l,t,w,h,s,self.body, self.shadow) - end - end) - - light_world:drawBlur("alpha", self.blur, self.shadow, self.shadow2, l, t, w, h, s) - util.drawCanvasToCanvas(self.shadow, self.render_buffer, {blendmode = "multiplicative"}) -end - --- draw shine -function light_world:drawShine(l,t,w,h,s) - if not self.isShadows then - return - end - - -- update shine - util.drawto(self.shine, l, t, s, function() - love.graphics.setColor(unpack(self.ambient)) - love.graphics.setBlendMode("alpha") - love.graphics.rectangle("fill", -l/s, -t/s, w/s, h/s) - for i = 1, #self.lights do - self.lights[i]:drawShine(l,t,w,h,s,self.body,self.shine) - end - end) - - --light_world:drawBlur("additive", self.blur, self.shine, self.shine2, l, t, w, h, s) - util.drawCanvasToCanvas(self.shine, self.render_buffer, {blendmode = "multiplicative"}) -end - -- draw normal shading function light_world:drawNormalShading(l,t,w,h,s) if not self.isShadows then @@ -173,13 +128,19 @@ function light_world:drawNormalShading(l,t,w,h,s) self.normalMap:clear() util.drawto(self.normalMap, l, t, s, function() for i = 1, #self.body do - self.body[i]:drawNormalShading() + self.body[i]:drawNormal() end end) self.normal2:clear() for i = 1, #self.lights do - self.lights[i]:drawNormalShading(l,t,w,h,s, self.normalMap, self.normal2) + self.shadowMap:clear() + util.drawto(self.shadowMap, l, t, s, function() + for k = 1, #self.body do + self.body[k]:drawCalculatedShadow(self.lights[i]) + end + end) + self.lights[i]:drawNormalShading(l,t,w,h,s, self.normalMap, self.shadowMap, self.normal2) end self.normal:clear(255, 255, 255) diff --git a/lib/light.lua b/lib/light.lua index cbae775..bfcd53e 100644 --- a/lib/light.lua +++ b/lib/light.lua @@ -5,8 +5,6 @@ local util = require(_PACKAGE..'/util') local light = class() -light.shineShader = love.graphics.newShader(_PACKAGE.."/shaders/shine.glsl") -light.normalShader = love.graphics.newShader(_PACKAGE.."/shaders/normal.glsl") light.shadowShader = love.graphics.newShader(_PACKAGE.."/shaders/shadow.glsl") function light:init(x, y, r, g, b, range) @@ -29,10 +27,6 @@ end function light:refresh(w, h) w, h = w or love.window.getWidth(), h or love.window.getHeight() - - self.shadow = love.graphics.newCanvas(w, h) - self.shine = love.graphics.newCanvas(w, h) - self.normalShader:send('screenResolution', {w, h}) self.shadowShader:send('screenResolution', {w, h}) end @@ -122,86 +116,12 @@ 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 (lx + rs) > 0 and - (lx - rs) < w/s and - (ly + rs) > 0 and - (ly - rs) < h/s + return (lx + rs) > 0 and (lx - rs) < w/s and (ly + rs) > 0 and (ly - rs) < h/s end -function light:drawShadow(l,t,w,h,s,bodies, canvas) - if self.visible and self:inRange(l,t,w,h,s) then - -- calculate shadows - 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 - - -- draw shadow - self.shadow:clear() - util.drawto(self.shadow, l, t, s, function() - - self.shineShader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, (self.z * 10)/255.0}) - self.shineShader:send("lightRange", self.range*s) - self.shineShader:send("lightColor", {self.red / 255.0, self.green / 255.0, self.blue / 255.0}) - self.shineShader:send("lightSmooth", self.smooth) - self.shineShader:send("lightGlow", {1.0 - self.glowSize, self.glowStrength}) - self.shineShader:send("lightAngle", math.pi - self.angle / 2.0) - self.shineShader:send("lightDirection", self.direction) - love.graphics.setShader(self.shineShader) - love.graphics.setInvertedStencil(stencils.shadow(shadow_geometry, bodies)) - love.graphics.setBlendMode("additive") - love.graphics.rectangle("fill", -l/s,-t/s,w/s,h/s) - - -- 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])) - if shadow_geometry[k].circle then - love.graphics.arc("fill", unpack(shadow_geometry[k].circle)) - end - end - end - - for k = 1, #bodies do - bodies[k]:drawShadow(self,l,t,w,h,s) - end - end) - - 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) - if self.visible and self:inRange(l,t,w,h,s) then - --update shine - self.shine:clear(255, 255, 255) - util.drawto(self.shine, l, t, s, function() - love.graphics.setShader(self.shineShader) - love.graphics.setBlendMode("alpha") - love.graphics.setStencil(stencils.shine(bodies)) - love.graphics.rectangle("fill", -l/s,-t/s,w/s,h/s) - end) - love.graphics.setStencil() - love.graphics.setShader() - util.drawCanvasToCanvas(self.shine, canvas, {blendmode = "additive"}) - end -end - -function light:drawNormalShading(l,t,w,h,s, normalMap, canvas) +function light:drawNormalShading(l,t,w,h,s, normalMap, shadowMap, canvas) if self.visible and self:inRange(l,t,w,h,s) then + self.shadowShader:send('shadowMap', shadowMap) self.shadowShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0}) self.shadowShader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, (self.z * 10) / 255.0}) self.shadowShader:send('lightRange',{self.range}) diff --git a/lib/shaders/shadow.glsl b/lib/shaders/shadow.glsl index 557681b..0c83dfa 100644 --- a/lib/shaders/shadow.glsl +++ b/lib/shaders/shadow.glsl @@ -1,6 +1,7 @@ #define PI 3.1415926535897932384626433832795 extern vec2 screenResolution; +extern Image shadowMap; extern vec3 lightPosition; extern vec3 lightColor; extern float lightRange; @@ -10,35 +11,9 @@ extern float lightDirection; extern float lightAngle; extern bool invert_normal; -float getHeightAt(Image texture, vec2 texture_coords) { - vec4 pixel = Texel(texture, texture_coords); - if(pixel.a > 0.0){ - return 0.0; - } else { - return pixel.g; - } -} - -bool is_in_shadow(Image texture, vec2 texture_coords, vec3 lightPosition, vec2 pixel_coords) { - vec3 coords = vec3(pixel_coords, 0.0); - vec3 lightVec = normalize(lightPosition - coords); - - float startHeight = getHeightAt(texture, texture_coords); - vec2 tx; - float currentHeight; - - for(int i = 0; i < 100; ++i) { - tx = texture_coords + lightVec.xy; - currentHeight = getHeightAt(texture, tx); - if(startHeight < currentHeight){ - return true; - } - } - return false; -} - vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) { vec4 pixelColor = Texel(texture, texture_coords); + vec4 shadowColor = Texel(shadowMap, texture_coords); //if the light is a slice and the pixel is not inside if(lightAngle > 0.0) { @@ -76,6 +51,10 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) { } else { val.rgb = lightColor * pow(att, lightSmooth); } + if(shadowColor.a > 0.0) { + shadowColor.a = 1.0 - shadowColor.a; + val = val * shadowColor; + } return val; } else { vec3 dir = vec3((lightPosition.xy - pixel_coords.xy) / screenResolution.xy, lightPosition.z);