From 08e50a7b2a3daad0d731ff508499e7fbf62e8616 Mon Sep 17 00:00:00 2001 From: Tim Anema Date: Fri, 26 Sep 2014 18:11:23 -0400 Subject: [PATCH] refactor body and light code to minimize size of monolithic method --- lib/body.lua | 115 +++++++++++++++++ lib/light.lua | 196 +++++++++++++++++++++++++++++ lib/light_world.lua | 295 ++------------------------------------------ 3 files changed, 321 insertions(+), 285 deletions(-) diff --git a/lib/body.lua b/lib/body.lua index da085c7..daebbe5 100644 --- a/lib/body.lua +++ b/lib/body.lua @@ -523,4 +523,119 @@ function body:setShadowType(type, ...) end end +function body:drawShadow(light) + if self.alpha < 1.0 then + love.graphics.setBlendMode("multiplicative") + love.graphics.setColor(self.red, self.green, self.blue) + if self.shadowType == "circle" then + love.graphics.circle("fill", self.x - self.ox, self.y - self.oy, self.radius) + elseif self.shadowType == "rectangle" then + love.graphics.rectangle("fill", self.x - self.ox, self.y - self.oy, self.width, self.height) + elseif self.shadowType == "polygon" then + love.graphics.polygon("fill", unpack(self.data)) + end + end + + if self.shadowType == "image" and self.img then + love.graphics.setBlendMode("alpha") + local length = 1.0 + local shadowRotation = math.atan2((self.x) - light.x, (self.y + self.oy) - light.y) + + self.shadowVert = { + {math.sin(shadowRotation) * self.imgHeight * length, (length * math.cos(shadowRotation) + 1.0) * self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY, 0, 0, self.red, self.green, self.blue, self.alpha * self.fadeStrength * 255}, + {self.imgWidth + math.sin(shadowRotation) * self.imgHeight * length, (length * math.cos(shadowRotation) + 1.0) * self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY, 1, 0, self.red, self.green, self.blue, self.alpha * self.fadeStrength * 255}, + {self.imgWidth, self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY, 1, 1, self.red, self.green, self.blue, self.alpha * 255}, + {0, self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY, 0, 1, self.red, self.green, self.blue, self.alpha * 255} + } + + self.shadowMesh:setVertices(self.shadowVert) + love.graphics.draw(self.shadowMesh, self.x - self.ox + self.world.translate_x, self.y - self.oy + self.world.translate_y) + end +end + + +function body:drawPixelShadow() + if self.type == "image" and self.normalMesh then + love.graphics.setColor(255, 255, 255) + love.graphics.draw(self.normalMesh, self.x - self.nx + self.world.translate_x, self.y - self.ny + self.world.translate_y) + end +end + + +function body:drawGlow() + if self.glowStrength > 0.0 then + love.graphics.setColor(self.glowRed * self.glowStrength, self.glowGreen * self.glowStrength, self.glowBlue * self.glowStrength) + else + love.graphics.setColor(0, 0, 0) + end + + if self.type == "circle" then + love.graphics.circle("fill", self.x, self.y, self.radius) + elseif self.type == "rectangle" then + love.graphics.rectangle("fill", self.x, self.y, self.width, self.height) + elseif self.type == "polygon" then + love.graphics.polygon("fill", unpack(self.data)) + elseif self.type == "image" and self.img then + if self.glowStrength > 0.0 and self.glow then + love.graphics.setShader(self.world.glowShader) + self.world.glowShader:send("glowImage", self.glow) + self.world.glowShader:send("glowTime", love.timer.getTime() * 0.5) + love.graphics.setColor(255, 255, 255) + else + love.graphics.setShader() + love.graphics.setColor(0, 0, 0) + end + love.graphics.draw(self.img, self.x - self.ix + self.world.translate_x, self.y - self.iy + self.world.translate_y) + end +end + +function body:drawRefraction() + if self.refraction and self.normal then + love.graphics.setColor(255, 255, 255) + if self.tileX == 0.0 and self.tileY == 0.0 then + love.graphics.draw(normal, self.x - self.nx + self.world.translate_x, self.y - self.ny + self.world.translate_y) + else + self.normalMesh:setVertices(self.normalVert) + love.graphics.draw(self.normalMesh, self.x - self.nx + self.world.translate_x, self.y - self.ny + self.world.translate_y) + end + end + + love.graphics.setColor(0, 0, 0) + + if not self.refractive then + if self.type == "circle" then + love.graphics.circle("fill", self.x, self.y, self.radius) + elseif self.type == "rectangle" then + love.graphics.rectangle("fill", self.x, self.y, self.width, self.height) + elseif self.type == "polygon" then + love.graphics.polygon("fill", unpack(self.data)) + elseif self.type == "image" and self.img then + love.graphics.draw(self.img, self.x - self.ix + self.world.translate_x, self.y - self.iy + self.world.translate_y) + end + end +end + +function body:drawReflection() + if self.reflection and self.normal then + love.graphics.setColor(255, 0, 0) + self.normalMesh:setVertices(self.normalVert) + love.graphics.draw(self.normalMesh, self.x - self.nx + self.world.translate_x, self.y - self.ny + self.world.translate_y) + end + if self.reflective and self.img then + love.graphics.setColor(0, 255, 0) + love.graphics.draw(self.img, self.x - self.ix + self.world.translate_x, self.y - self.iy + self.world.translate_y) + elseif not self.reflection and self.img then + love.graphics.setColor(0, 0, 0) + love.graphics.draw(self.img, self.x - self.ix + self.world.translate_x, self.y - self.iy + self.world.translate_y) + end +end + +function body:drawMaterial() + if self.material and self.normal then + love.graphics.setColor(255, 255, 255) + self.world.materialShader:send("material", self.material) + love.graphics.draw(self.normal, self.x - self.nx + self.world.translate_x, self.y - self.ny + self.world.translate_y) + end +end + return body diff --git a/lib/light.lua b/lib/light.lua index 00635b8..51b793b 100644 --- a/lib/light.lua +++ b/lib/light.lua @@ -1,5 +1,7 @@ local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or "" local class = require(_PACKAGE.."/class") +local stencils = require(_PACKAGE..'/stencils') +local vector = require(_PACKAGE..'/vector') local light = class() @@ -122,4 +124,198 @@ function light:getType() return "light" end +function light:updateShadow() + if self.changed or self.changed then + if self.x + self.range > self.world.translate_x and self.x - self.range < love.graphics.getWidth() + self.world.translate_x + and self.y + self.range > self.world.translate_y and self.y - self.range < love.graphics.getHeight() + self.world.translate_y + then + local lightposrange = {self.x, love.graphics.getHeight() - self.y, self.range} + local light = self + self.world.direction = self.world.direction + 0.002 + self.world.shader:send("lightPosition", {self.x - self.world.translate_x, love.graphics.getHeight() - (self.y - self.world.translate_y), self.z}) + self.world.shader:send("lightRange", self.range) + self.world.shader:send("lightColor", {self.red / 255.0, self.green / 255.0, self.blue / 255.0}) + self.world.shader:send("lightSmooth", self.smooth) + self.world.shader:send("lightGlow", {1.0 - self.glowSize, self.glowStrength}) + self.world.shader:send("lightAngle", math.pi - self.angle / 2.0) + self.world.shader:send("lightDirection", self.direction) + + love.graphics.setCanvas(self.shadow) + love.graphics.clear() + + -- calculate shadows + local shadow_geometry = calculateShadows(light, self.world.body) + + -- draw shadow + love.graphics.setInvertedStencil(stencils.shadow(shadow_geometry, self.world.body)) + love.graphics.setBlendMode("additive") + -- FIND THIS TOOOO + love.graphics.rectangle("fill", self.world.translate_x, self.world.translate_y, love.graphics.getWidth(), love.graphics.getHeight()) + + -- 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 + end + + for k = 1, #self.world.body do + self.world.body[k]:drawShadow(self) + end + + love.graphics.setShader(self.world.shader) + + -- draw shine + love.graphics.setCanvas(self.shine) + self.shine:clear(255, 255, 255) + love.graphics.setBlendMode("alpha") + love.graphics.setStencil(stencils.poly(self.world.body)) + -- WHOA THIS MAY BE THE ISSUE HERE FIND THIS! + love.graphics.rectangle("fill", self.world.translate_x, self.world.translate_y, love.graphics.getWidth(), love.graphics.getHeight()) + + self.visible = true + else + self.visible = false + end + + self.changed = self.world.changed + end +end + +function light:drawShadow() + if self.visible then + love.graphics.draw(self.shadow, self.world.translate_x, self.world.translate_y) + end +end + +function light:drawShine() + if self.visible then + love.graphics.draw(self.shine, self.world.translate_x, self.world.translate_y) + end +end + +function calculateShadows(light, body) + local shadowGeometry = {} + local shadowLength = 100000 + + for i = 1, #body do + if body[i].shadowType == "rectangle" or body[i].shadowType == "polygon" then + curPolygon = body[i].data + if not body[i].castsNoShadow then + local edgeFacingTo = {} + for k = 1, #curPolygon, 2 do + local indexOfNextVertex = (k + 2) % #curPolygon + local normal = {-curPolygon[indexOfNextVertex+1] + curPolygon[k + 1], curPolygon[indexOfNextVertex] - curPolygon[k]} + local lightToPoint = {curPolygon[k] - light.x, curPolygon[k + 1] - light.y} + + normal = vector.normalize(normal) + lightToPoint = vector.normalize(lightToPoint) + + local dotProduct = vector.dot(normal, lightToPoint) + if dotProduct > 0 then table.insert(edgeFacingTo, true) + else table.insert(edgeFacingTo, false) end + end + + local curShadowGeometry = {} + for k = 1, #edgeFacingTo do + local nextIndex = (k + 1) % #edgeFacingTo + if nextIndex == 0 then nextIndex = #edgeFacingTo end + if edgeFacingTo[k] and not edgeFacingTo[nextIndex] then + curShadowGeometry[1] = curPolygon[nextIndex*2-1] + curShadowGeometry[2] = curPolygon[nextIndex*2] + + local lightVecFrontBack = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y}) + curShadowGeometry[3] = curShadowGeometry[1] + lightVecFrontBack[1] * shadowLength + curShadowGeometry[4] = curShadowGeometry[2] + lightVecFrontBack[2] * shadowLength + + elseif not edgeFacingTo[k] and edgeFacingTo[nextIndex] then + curShadowGeometry[7] = curPolygon[nextIndex*2-1] + curShadowGeometry[8] = curPolygon[nextIndex*2] + + local lightVecBackFront = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y}) + curShadowGeometry[5] = curShadowGeometry[7] + lightVecBackFront[1] * shadowLength + curShadowGeometry[6] = curShadowGeometry[8] + lightVecBackFront[2] * shadowLength + end + end + if curShadowGeometry[1] + and curShadowGeometry[2] + and curShadowGeometry[3] + and curShadowGeometry[4] + and curShadowGeometry[5] + and curShadowGeometry[6] + and curShadowGeometry[7] + and curShadowGeometry[8] + then + curShadowGeometry.alpha = body[i].alpha + curShadowGeometry.red = body[i].red + curShadowGeometry.green = body[i].green + curShadowGeometry.blue = body[i].blue + shadowGeometry[#shadowGeometry + 1] = curShadowGeometry + end + end + elseif body[i].shadowType == "circle" then + if not body[i].castsNoShadow then + local length = math.sqrt(math.pow(light.x - (body[i].x - body[i].ox), 2) + math.pow(light.y - (body[i].y - body[i].oy), 2)) + if length >= body[i].radius and length <= light.range then + local curShadowGeometry = {} + local angle = math.atan2(light.x - (body[i].x - body[i].ox), (body[i].y - body[i].oy) - light.y) + math.pi / 2 + local x2 = ((body[i].x - body[i].ox) + math.sin(angle) * body[i].radius) + local y2 = ((body[i].y - body[i].oy) - math.cos(angle) * body[i].radius) + local x3 = ((body[i].x - body[i].ox) - math.sin(angle) * body[i].radius) + local y3 = ((body[i].y - body[i].oy) + math.cos(angle) * body[i].radius) + + curShadowGeometry[1] = x2 + curShadowGeometry[2] = y2 + curShadowGeometry[3] = x3 + curShadowGeometry[4] = y3 + + curShadowGeometry[5] = x3 - (light.x - x3) * shadowLength + curShadowGeometry[6] = y3 - (light.y - y3) * shadowLength + curShadowGeometry[7] = x2 - (light.x - x2) * shadowLength + curShadowGeometry[8] = y2 - (light.y - y2) * shadowLength + curShadowGeometry.alpha = body[i].alpha + curShadowGeometry.red = body[i].red + curShadowGeometry.green = body[i].green + curShadowGeometry.blue = body[i].blue + shadowGeometry[#shadowGeometry + 1] = curShadowGeometry + end + end + end + end + + return shadowGeometry +end + +function light:drawPixelShadow() + if self.visible then + if self.normalInvert then + self.world.normalInvertShader:send('screenResolution', {love.graphics.getWidth(), love.graphics.getHeight()}) + self.world.normalInvertShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0}) + self.world.normalInvertShader:send('lightPosition',{self.x, love.graphics.getHeight() - self.y, self.z / 255.0}) + self.world.normalInvertShader:send('lightRange',{self.range}) + self.world.normalInvertShader:send("lightSmooth", self.smooth) + self.world.normalInvertShader:send("lightAngle", math.pi - self.angle / 2.0) + self.world.normalInvertShader:send("lightDirection", self.direction) + love.graphics.setShader(self.world.normalInvertShader) + else + self.world.normalShader:send('screenResolution', {love.graphics.getWidth(), love.graphics.getHeight()}) + self.world.normalShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0}) + self.world.normalShader:send('lightPosition',{self.x, love.graphics.getHeight() - self.y, self.z / 255.0}) + self.world.normalShader:send('lightRange',{self.range}) + self.world.normalShader:send("lightSmooth", self.smooth) + self.world.normalShader:send("lightAngle", math.pi - self.angle / 2.0) + self.world.normalShader:send("lightDirection", self.direction) + love.graphics.setShader(self.world.normalShader) + end + love.graphics.draw(self.world.normalMap, self.world.translate_x, self.world.translate_y) + end +end + return light diff --git a/lib/light_world.lua b/lib/light_world.lua index 06d827f..5659034 100644 --- a/lib/light_world.lua +++ b/lib/light_world.lua @@ -23,8 +23,6 @@ SOFTWARE. ]] local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or "" local class = require(_PACKAGE..'/class') -local stencils = require(_PACKAGE..'/stencils') -local vector = require(_PACKAGE..'/vector') local Light = require(_PACKAGE..'/light') local Body = require(_PACKAGE..'/body') @@ -111,97 +109,8 @@ function light_world:update() if self.optionShadows and (self.isShadows or self.isLight) then love.graphics.setShader(self.shader) - local lightsOnScreen = 0 for i = 1, #self.lights do - if self.lights[i].changed or self.changed then - if self.lights[i].x + self.lights[i].range > self.translate_x and self.lights[i].x - self.lights[i].range < love.graphics.getWidth() + self.translate_x - and self.lights[i].y + self.lights[i].range > self.translate_y and self.lights[i].y - self.lights[i].range < love.graphics.getHeight() + self.translate_y - then - local lightposrange = {self.lights[i].x, love.graphics.getHeight() - self.lights[i].y, self.lights[i].range} - local light = self.lights[i] - self.direction = self.direction + 0.002 - self.shader:send("lightPosition", {self.lights[i].x - self.translate_x, love.graphics.getHeight() - (self.lights[i].y - self.translate_y), self.lights[i].z}) - self.shader:send("lightRange", self.lights[i].range) - self.shader:send("lightColor", {self.lights[i].red / 255.0, self.lights[i].green / 255.0, self.lights[i].blue / 255.0}) - self.shader:send("lightSmooth", self.lights[i].smooth) - self.shader:send("lightGlow", {1.0 - self.lights[i].glowSize, self.lights[i].glowStrength}) - self.shader:send("lightAngle", math.pi - self.lights[i].angle / 2.0) - self.shader:send("lightDirection", self.lights[i].direction) - - love.graphics.setCanvas(self.lights[i].shadow) - love.graphics.clear() - - -- calculate shadows - local shadow_geometry = calculateShadows(light, self.body) - - -- draw shadow - love.graphics.setInvertedStencil(stencils.shadow(shadow_geometry, self.body)) - love.graphics.setBlendMode("additive") - love.graphics.rectangle("fill", self.translate_x, self.translate_y, love.graphics.getWidth(), love.graphics.getHeight()) - - -- 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 - end - - for k = 1, #self.body do - if self.body[k].alpha < 1.0 then - love.graphics.setBlendMode("multiplicative") - love.graphics.setColor(self.body[k].red, self.body[k].green, self.body[k].blue) - if self.body[k].shadowType == "circle" then - love.graphics.circle("fill", self.body[k].x - self.body[k].ox, self.body[k].y - self.body[k].oy, self.body[k].radius) - elseif self.body[k].shadowType == "rectangle" then - love.graphics.rectangle("fill", self.body[k].x - self.body[k].ox, self.body[k].y - self.body[k].oy, self.body[k].width, self.body[k].height) - elseif self.body[k].shadowType == "polygon" then - love.graphics.polygon("fill", unpack(self.body[k].data)) - end - end - - if self.body[k].shadowType == "image" and self.body[k].img then - love.graphics.setBlendMode("alpha") - local length = 1.0 - local shadowRotation = math.atan2((self.body[k].x) - self.lights[i].x, (self.body[k].y + self.body[k].oy) - self.lights[i].y) - --local alpha = math.abs(math.cos(shadowRotation)) - - self.body[k].shadowVert = { - {math.sin(shadowRotation) * self.body[k].imgHeight * length, (length * math.cos(shadowRotation) + 1.0) * self.body[k].imgHeight + (math.cos(shadowRotation) + 1.0) * self.body[k].shadowY, 0, 0, self.body[k].red, self.body[k].green, self.body[k].blue, self.body[k].alpha * self.body[k].fadeStrength * 255}, - {self.body[k].imgWidth + math.sin(shadowRotation) * self.body[k].imgHeight * length, (length * math.cos(shadowRotation) + 1.0) * self.body[k].imgHeight + (math.cos(shadowRotation) + 1.0) * self.body[k].shadowY, 1, 0, self.body[k].red, self.body[k].green, self.body[k].blue, self.body[k].alpha * self.body[k].fadeStrength * 255}, - {self.body[k].imgWidth, self.body[k].imgHeight + (math.cos(shadowRotation) + 1.0) * self.body[k].shadowY, 1, 1, self.body[k].red, self.body[k].green, self.body[k].blue, self.body[k].alpha * 255}, - {0, self.body[k].imgHeight + (math.cos(shadowRotation) + 1.0) * self.body[k].shadowY, 0, 1, self.body[k].red, self.body[k].green, self.body[k].blue, self.body[k].alpha * 255} - } - - self.body[k].shadowMesh:setVertices(self.body[k].shadowVert) - love.graphics.draw(self.body[k].shadowMesh, self.body[k].x - self.body[k].ox + self.translate_x, self.body[k].y - self.body[k].oy + self.translate_y) - end - end - - love.graphics.setShader(self.shader) - - -- draw shine - love.graphics.setCanvas(self.lights[i].shine) - self.lights[i].shine:clear(255, 255, 255) - love.graphics.setBlendMode("alpha") - love.graphics.setStencil(stencils.poly(self.body)) - love.graphics.rectangle("fill", self.translate_x, self.translate_y, love.graphics.getWidth(), love.graphics.getHeight()) - - lightsOnScreen = lightsOnScreen + 1 - - self.lights[i].visible = true - else - self.lights[i].visible = false - end - - self.lights[i].changed = self.changed - end + self.lights[i]:updateShadow() end -- update shadow @@ -214,9 +123,7 @@ function light_world:update() love.graphics.setColor(255, 255, 255) love.graphics.setBlendMode("additive") for i = 1, #self.lights do - if self.lights[i].visible then - love.graphics.draw(self.lights[i].shadow, self.translate_x, self.translate_y) - end + self.lights[i]:drawShadow() end self.isShadowBlur = false @@ -228,9 +135,7 @@ function light_world:update() love.graphics.setColor(255, 255, 255) love.graphics.setBlendMode("additive") for i = 1, #self.lights do - if self.lights[i].visible then - love.graphics.draw(self.lights[i].shine, self.translate_x, self.translate_y) - end + self.lights[i]:drawShine() end end @@ -243,10 +148,7 @@ function light_world:update() love.graphics.setShader() love.graphics.setCanvas(self.normalMap) for i = 1, #self.body do - if self.body[i].type == "image" and self.body[i].normalMesh then - love.graphics.setColor(255, 255, 255) - love.graphics.draw(self.body[i].normalMesh, self.body[i].x - self.body[i].nx + self.translate_x, self.body[i].y - self.body[i].ny + self.translate_y) - end + self.body[i]:drawPixelShadow() end love.graphics.setColor(255, 255, 255) love.graphics.setBlendMode("alpha") @@ -257,28 +159,7 @@ function light_world:update() love.graphics.setShader(self.shader2) for i = 1, #self.lights do - if self.lights[i].visible then - if self.normalInvert then - self.normalInvertShader:send('screenResolution', {love.graphics.getWidth(), love.graphics.getHeight()}) - self.normalInvertShader:send('lightColor', {self.lights[i].red / 255.0, self.lights[i].green / 255.0, self.lights[i].blue / 255.0}) - self.normalInvertShader:send('lightPosition',{self.lights[i].x, love.graphics.getHeight() - self.lights[i].y, self.lights[i].z / 255.0}) - self.normalInvertShader:send('lightRange',{self.lights[i].range}) - self.normalInvertShader:send("lightSmooth", self.lights[i].smooth) - self.normalInvertShader:send("lightAngle", math.pi - self.lights[i].angle / 2.0) - self.normalInvertShader:send("lightDirection", self.lights[i].direction) - love.graphics.setShader(self.normalInvertShader) - else - self.normalShader:send('screenResolution', {love.graphics.getWidth(), love.graphics.getHeight()}) - self.normalShader:send('lightColor', {self.lights[i].red / 255.0, self.lights[i].green / 255.0, self.lights[i].blue / 255.0}) - self.normalShader:send('lightPosition',{self.lights[i].x, love.graphics.getHeight() - self.lights[i].y, self.lights[i].z / 255.0}) - self.normalShader:send('lightRange',{self.lights[i].range}) - self.normalShader:send("lightSmooth", self.lights[i].smooth) - self.normalShader:send("lightAngle", math.pi - self.lights[i].angle / 2.0) - self.normalShader:send("lightDirection", self.lights[i].direction) - love.graphics.setShader(self.normalShader) - end - love.graphics.draw(self.normalMap, self.translate_x, self.translate_y) - end + self.lights[i]:drawPixelShadow() end love.graphics.setShader() @@ -310,64 +191,17 @@ function light_world:update() end for i = 1, #self.body do - if self.body[i].glowStrength > 0.0 then - love.graphics.setColor(self.body[i].glowRed * self.body[i].glowStrength, self.body[i].glowGreen * self.body[i].glowStrength, self.body[i].glowBlue * self.body[i].glowStrength) - else - love.graphics.setColor(0, 0, 0) - end - - if self.body[i].type == "circle" then - love.graphics.circle("fill", self.body[i].x, self.body[i].y, self.body[i].radius) - elseif self.body[i].type == "rectangle" then - love.graphics.rectangle("fill", self.body[i].x, self.body[i].y, self.body[i].width, self.body[i].height) - elseif self.body[i].type == "polygon" then - love.graphics.polygon("fill", unpack(self.body[i].data)) - elseif self.body[i].type == "image" and self.body[i].img then - if self.body[i].glowStrength > 0.0 and self.body[i].glow then - love.graphics.setShader(self.glowShader) - self.glowShader:send("glowImage", self.body[i].glow) - self.glowShader:send("glowTime", love.timer.getTime() * 0.5) - love.graphics.setColor(255, 255, 255) - else - love.graphics.setShader() - love.graphics.setColor(0, 0, 0) - end - love.graphics.draw(self.body[i].img, self.body[i].x - self.body[i].ix + self.translate_x, self.body[i].y - self.body[i].iy + self.translate_y) - end + self.body[i]:drawGlow() end end if self.optionRefraction and self.isRefraction then love.graphics.setShader() - -- create refraction map self.refractionMap:clear() love.graphics.setCanvas(self.refractionMap) for i = 1, #self.body do - if self.body[i].refraction and self.body[i].normal then - love.graphics.setColor(255, 255, 255) - if self.body[i].tileX == 0.0 and self.body[i].tileY == 0.0 then - love.graphics.draw(normal, self.body[i].x - self.body[i].nx + self.translate_x, self.body[i].y - self.body[i].ny + self.translate_y) - else - self.body[i].normalMesh:setVertices(self.body[i].normalVert) - love.graphics.draw(self.body[i].normalMesh, self.body[i].x - self.body[i].nx + self.translate_x, self.body[i].y - self.body[i].ny + self.translate_y) - end - end - end - - love.graphics.setColor(0, 0, 0) - for i = 1, #self.body do - if not self.body[i].refractive then - if self.body[i].type == "circle" then - love.graphics.circle("fill", self.body[i].x, self.body[i].y, self.body[i].radius) - elseif self.body[i].type == "rectangle" then - love.graphics.rectangle("fill", self.body[i].x, self.body[i].y, self.body[i].width, self.body[i].height) - elseif self.body[i].type == "polygon" then - love.graphics.polygon("fill", unpack(self.body[i].data)) - elseif self.body[i].type == "image" and self.body[i].img then - love.graphics.draw(self.body[i].img, self.body[i].x - self.body[i].ix + self.translate_x, self.body[i].y - self.body[i].iy + self.translate_y) - end - end + self.body[i]:drawRefraction() end end @@ -377,20 +211,7 @@ function light_world:update() self.reflectionMap:clear(0, 0, 0) love.graphics.setCanvas(self.reflectionMap) for i = 1, #self.body do - if self.body[i].reflection and self.body[i].normal then - love.graphics.setColor(255, 0, 0) - self.body[i].normalMesh:setVertices(self.body[i].normalVert) - love.graphics.draw(self.body[i].normalMesh, self.body[i].x - self.body[i].nx + self.translate_x, self.body[i].y - self.body[i].ny + self.translate_y) - end - end - for i = 1, #self.body do - if self.body[i].reflective and self.body[i].img then - love.graphics.setColor(0, 255, 0) - love.graphics.draw(self.body[i].img, self.body[i].x - self.body[i].ix + self.translate_x, self.body[i].y - self.body[i].iy + self.translate_y) - elseif not self.body[i].reflection and self.body[i].img then - love.graphics.setColor(0, 0, 0) - love.graphics.draw(self.body[i].img, self.body[i].x - self.body[i].ix + self.translate_x, self.body[i].y - self.body[i].iy + self.translate_y) - end + self.body[i]:drawReflection() end end end @@ -488,11 +309,7 @@ end function light_world:drawMaterial() love.graphics.setShader(self.materialShader) for i = 1, #self.body do - if self.body[i].material and self.body[i].normal then - love.graphics.setColor(255, 255, 255) - self.materialShader:send("material", self.body[i].material) - love.graphics.draw(self.body[i].normal, self.body[i].x - self.body[i].nx + self.translate_x, self.body[i].y - self.body[i].ny + self.translate_y) - end + self.body[i]:drawMaterial() end love.graphics.setShader() end @@ -563,7 +380,7 @@ function light_world:drawReflection() end -- new light function light_world:newLight(x, y, red, green, blue, range) - self.lights[#self.lights + 1] = Light(o, x, y, red, green, blue, range) + self.lights[#self.lights + 1] = Light(self, x, y, red, green, blue, range) self.isLight = true return self.lights[#self.lights] end @@ -739,98 +556,6 @@ function light_world:getType() return "world" end -function calculateShadows(light, body) - local shadowGeometry = {} - local shadowLength = 100000 - - for i = 1, #body do - if body[i].shadowType == "rectangle" or body[i].shadowType == "polygon" then - curPolygon = body[i].data - if not body[i].castsNoShadow then - local edgeFacingTo = {} - for k = 1, #curPolygon, 2 do - local indexOfNextVertex = (k + 2) % #curPolygon - local normal = {-curPolygon[indexOfNextVertex+1] + curPolygon[k + 1], curPolygon[indexOfNextVertex] - curPolygon[k]} - local lightToPoint = {curPolygon[k] - light.x, curPolygon[k + 1] - light.y} - - normal = vector.normalize(normal) - lightToPoint = vector.normalize(lightToPoint) - - local dotProduct = vector.dot(normal, lightToPoint) - if dotProduct > 0 then table.insert(edgeFacingTo, true) - else table.insert(edgeFacingTo, false) end - end - - local curShadowGeometry = {} - for k = 1, #edgeFacingTo do - local nextIndex = (k + 1) % #edgeFacingTo - if nextIndex == 0 then nextIndex = #edgeFacingTo end - if edgeFacingTo[k] and not edgeFacingTo[nextIndex] then - curShadowGeometry[1] = curPolygon[nextIndex*2-1] - curShadowGeometry[2] = curPolygon[nextIndex*2] - - local lightVecFrontBack = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y}) - curShadowGeometry[3] = curShadowGeometry[1] + lightVecFrontBack[1] * shadowLength - curShadowGeometry[4] = curShadowGeometry[2] + lightVecFrontBack[2] * shadowLength - - elseif not edgeFacingTo[k] and edgeFacingTo[nextIndex] then - curShadowGeometry[7] = curPolygon[nextIndex*2-1] - curShadowGeometry[8] = curPolygon[nextIndex*2] - - local lightVecBackFront = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y}) - curShadowGeometry[5] = curShadowGeometry[7] + lightVecBackFront[1] * shadowLength - curShadowGeometry[6] = curShadowGeometry[8] + lightVecBackFront[2] * shadowLength - end - end - if curShadowGeometry[1] - and curShadowGeometry[2] - and curShadowGeometry[3] - and curShadowGeometry[4] - and curShadowGeometry[5] - and curShadowGeometry[6] - and curShadowGeometry[7] - and curShadowGeometry[8] - then - curShadowGeometry.alpha = body[i].alpha - curShadowGeometry.red = body[i].red - curShadowGeometry.green = body[i].green - curShadowGeometry.blue = body[i].blue - shadowGeometry[#shadowGeometry + 1] = curShadowGeometry - end - end - elseif body[i].shadowType == "circle" then - if not body[i].castsNoShadow then - local length = math.sqrt(math.pow(light.x - (body[i].x - body[i].ox), 2) + math.pow(light.y - (body[i].y - body[i].oy), 2)) - if length >= body[i].radius and length <= light.range then - local curShadowGeometry = {} - local angle = math.atan2(light.x - (body[i].x - body[i].ox), (body[i].y - body[i].oy) - light.y) + math.pi / 2 - local x2 = ((body[i].x - body[i].ox) + math.sin(angle) * body[i].radius) - local y2 = ((body[i].y - body[i].oy) - math.cos(angle) * body[i].radius) - local x3 = ((body[i].x - body[i].ox) - math.sin(angle) * body[i].radius) - local y3 = ((body[i].y - body[i].oy) + math.cos(angle) * body[i].radius) - - curShadowGeometry[1] = x2 - curShadowGeometry[2] = y2 - curShadowGeometry[3] = x3 - curShadowGeometry[4] = y3 - - curShadowGeometry[5] = x3 - (light.x - x3) * shadowLength - curShadowGeometry[6] = y3 - (light.y - y3) * shadowLength - curShadowGeometry[7] = x2 - (light.x - x2) * shadowLength - curShadowGeometry[8] = y2 - (light.y - y2) * shadowLength - curShadowGeometry.alpha = body[i].alpha - curShadowGeometry.red = body[i].red - curShadowGeometry.green = body[i].green - curShadowGeometry.blue = body[i].blue - shadowGeometry[#shadowGeometry + 1] = curShadowGeometry - end - end - end - end - - return shadowGeometry -end - function HeightMapToNormalMap(heightMap, strength) local imgData = heightMap:getData() local imgData2 = love.image.newImageData(heightMap:getWidth(), heightMap:getHeight())