From 8cbb10f80db390fa7458470b16c59eb63895adfe Mon Sep 17 00:00:00 2001 From: Tim Anema Date: Wed, 17 Dec 2014 23:16:29 -0500 Subject: [PATCH] hopefully some faster shadow calculations --- lib/body.lua | 94 ++++++++++++++++++++------------------------------ lib/class.lua | 22 ++++++------ lib/util.lua | 2 +- lib/vec2.lua | 27 --------------- lib/vector.lua | 46 ++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 95 deletions(-) delete mode 100644 lib/vec2.lua create mode 100644 lib/vector.lua diff --git a/lib/body.lua b/lib/body.lua index 99c056d..999cfc9 100644 --- a/lib/body.lua +++ b/lib/body.lua @@ -3,7 +3,7 @@ local class = require(_PACKAGE.."/class") local normal_map = require(_PACKAGE..'/normal_map') local util = require(_PACKAGE..'/util') local anim8 = require(_PACKAGE..'/anim8') -local vec2 = require(_PACKAGE..'/vec2') +local vector = require(_PACKAGE..'/vector') local body = class() body.glowShader = love.graphics.newShader(_PACKAGE.."/shaders/glow.glsl") @@ -626,85 +626,67 @@ function body:drawShadow(light) end end -local function isEdgeFacingLight(x1, y1, x2, y2, light) - return vec2(-y2 + y1, x2 - x1):dot(vec2(x1 - light.x, y1 - light.y)) > 0 -end - --using shadow point calculations from this article --http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html function body:drawPolyShadow(light) - local curShadowGeometry = {} - local lxh = (light.x * self.zheight) - local lyh = (light.y * self.zheight) + local lightPosition = vector(light.x, light.y) + local lh = lightPosition * self.zheight + local height_diff = (self.zheight - light.z) if height_diff == 0 then -- prevent inf height_diff = -0.001 end - local facingLight = {} for i = 1, #self.data, 2 do - local j, k = (i + 2) % #self.data, (i + 4) % #self.data - - facingLight[i] = facingLight[i] ~= nil and facingLight[i] or isEdgeFacingLight(self.data[i], self.data[i+1], self.data[j], self.data[j+1], light) - facingLight[j] = facingLight[j] ~= nil and facingLight[j] or isEdgeFacingLight(self.data[j], self.data[j+1], self.data[k], self.data[k+1], light) - - if facingLight[i] and not facingLight[j] then - curShadowGeometry[#curShadowGeometry+1] = self.data[j] - curShadowGeometry[#curShadowGeometry+1] = self.data[j+1] - curShadowGeometry[#curShadowGeometry+1] = (lxh - (self.data[j] * light.z))/height_diff - curShadowGeometry[#curShadowGeometry+1] = (lyh - (self.data[j+1] * light.z))/height_diff - elseif not facingLight[i] and not facingLight[j] then - curShadowGeometry[#curShadowGeometry+1] = (lxh - (self.data[j] * light.z))/height_diff - curShadowGeometry[#curShadowGeometry+1] = (lyh - (self.data[j+1] * light.z))/height_diff - elseif not facingLight[i] and facingLight[j] then - curShadowGeometry[#curShadowGeometry+1] = (lxh - (self.data[j] * light.z))/height_diff - curShadowGeometry[#curShadowGeometry+1] = (lyh - (self.data[j+1] * light.z))/height_diff - curShadowGeometry[#curShadowGeometry+1] = self.data[j] - curShadowGeometry[#curShadowGeometry+1] = self.data[j+1] + local vertex = vector(self.data[i], self.data[i + 1]) + local nextVertex = vector(self.data[(i + 2) % 8], self.data[(i + 2) % 8 + 1]) + local startToEnd = nextVertex - vertex + if vector(startToEnd.y, -startToEnd.x) * (vertex - lightPosition) > 0 then + local point1 = (lh - (vertex * light.z))/height_diff + local point2 = (lh - (nextVertex * light.z))/height_diff + love.graphics.polygon("fill", + vertex.x, vertex.y, point1.x, point1.y, + point2.x, point2.y, nextVertex.x, nextVertex.y) end end - - if #curShadowGeometry >= 6 then - love.graphics.polygon("fill", unpack(curShadowGeometry)) - end end --using shadow point calculations from this article --http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html function body:drawCircleShadow(light) - local curShadowGeometry = {} - local angle = math.atan2(light.x - (self.x - self.ox), (self.y - self.oy) - light.y) + math.pi / 2 - local x1 = ((self.x - self.ox) + math.sin(angle) * self.radius) - local y1 = ((self.y - self.oy) - math.cos(angle) * self.radius) - local x2 = ((self.x - self.ox) - math.sin(angle) * self.radius) - local y2 = ((self.y - self.oy) + math.cos(angle) * self.radius) - - local lxh = (light.x * self.zheight) - local lyh = (light.y * self.zheight) + local selfPos = vector(self.x - self.ox, self.y - self.oy) + local lightPosition = vector(light.x, light.y) + local lh = lightPosition * self.zheight local height_diff = (self.zheight - light.z) if height_diff == 0 then -- prevent inf height_diff = -0.001 end + + local angle = math.atan2(light.x - selfPos.x, selfPos.y - light.y) + math.pi / 2 + local point1 = vector(selfPos.x + math.sin(angle) * self.radius, + selfPos.y - math.cos(angle) * self.radius) + local point2 = vector(selfPos.x - math.sin(angle) * self.radius, + selfPos.y + math.cos(angle) * self.radius) + local point3 = (lh - (point1 * light.z))/height_diff + local point4 = (lh - (point2 * light.z))/height_diff - local x3 = (lxh - (x2 * light.z))/height_diff - local y3 = (lyh - (y2 * light.z))/height_diff - local x4 = (lxh - (x1 * light.z))/height_diff - local y4 = (lyh - (y1 * light.z))/height_diff + local radius = point3:dist(point4)/2 + local circleCenter = (point3 + point4)/2 - local radius = math.sqrt(math.pow(x4 - x3, 2) + math.pow(y4-y3, 2)) / 2 - local cx, cy = (x3 + x4)/2, (y3 + y4)/2 - - if math.sqrt(math.pow(light.x - self.x, 2) + math.pow(light.y - self.y, 2)) <= self.radius then - love.graphics.circle("fill", cx, cy, radius) + if lightPosition:dist(selfPos) <= self.radius then + love.graphics.circle("fill", circleCenter.x, circleCenter.y, radius) else - love.graphics.polygon("fill", x1, y1, x2, y2, x3, y3, x4, y4) - if math.sqrt(math.pow(light.x - cx, 2) + math.pow(light.y - cy, 2)) < light.range then -- dont draw circle if way off screen - local angle1 = math.atan2(y3 - cy, x3 - cx) - local angle2 = math.atan2(y4 - cy, x4 - cx) - if angle1 > angle2 then - love.graphics.arc("fill", cx, cy, radius, angle1, angle2) + love.graphics.polygon("fill", point1.x, point1.y, + point2.x, point2.y, + point4.x, point4.y, + point3.x, point3.y) + if lightPosition:dist(circleCenter) < light.range then -- dont draw circle if way off screen + local angle1 = math.atan2(point3.y - circleCenter.y, point3.x - circleCenter.x) + local angle2 = math.atan2(point4.y - circleCenter.y, point4.x - circleCenter.x) + if angle1 < angle2 then + love.graphics.arc("fill", circleCenter.x, circleCenter.y, radius, angle1, angle2) else - love.graphics.arc("fill", cx, cy, radius, angle1 - math.pi, angle2 - math.pi) + love.graphics.arc("fill", circleCenter.x, circleCenter.y, radius, angle1 - math.pi, angle2 - math.pi) end end end diff --git a/lib/class.lua b/lib/class.lua index 489ced4..11e7d0f 100644 --- a/lib/class.lua +++ b/lib/class.lua @@ -19,17 +19,17 @@ local class = function(base, init) -- expose a constructor which can be called by () local mt = {} mt.__call = function(class_tbl, ...) - local obj = {} - setmetatable(obj,c) - if class_tbl.init then - class_tbl.init(obj,...) - else - -- make sure that any stuff from the base class is initialized! - if base and base.init then - base.init(obj, ...) - end - end - return obj + local obj = {} + setmetatable(obj,c) + if class_tbl.init then + class_tbl.init(obj,...) + else + -- make sure that any stuff from the base class is initialized! + if base and base.init then + base.init(obj, ...) + end + end + return obj end c.init = init c.is_a = function(self, klass) diff --git a/lib/util.lua b/lib/util.lua index da73afa..8374ecb 100644 --- a/lib/util.lua +++ b/lib/util.lua @@ -14,7 +14,7 @@ function util.drawCanvasToCanvas(canvas, other_canvas, options) love.graphics.setInvertedStencil(options["stencil"]) end if options["istencil"] then - love.graphics.setInvertedStencil(options["stencil"]) + love.graphics.setInvertedStencil(options["istencil"]) end if options["color"] then love.graphics.setColor(unpack(options["color"])) diff --git a/lib/vec2.lua b/lib/vec2.lua deleted file mode 100644 index 06b682a..0000000 --- a/lib/vec2.lua +++ /dev/null @@ -1,27 +0,0 @@ -local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or "" -local class = require(_PACKAGE.."/class") - -local vec2 = class() - -function vec2:init(x, y) - self.x, self.y = x, y -end - -function vec2:normalize() - local len = self:length() - return vec2(self.x / len, self.y / len) -end - -function vec2:dot(v2) - return (self.x * v2.x) + (self.y * v2.y) -end - -function vec2:cross(v2) - return ((self.x * v2.y) - (self.y * v2.x)) -end - -function vec2:length() - return math.sqrt(self:dot(self)) -end - -return vec2 diff --git a/lib/vector.lua b/lib/vector.lua new file mode 100644 index 0000000..da10ba9 --- /dev/null +++ b/lib/vector.lua @@ -0,0 +1,46 @@ +local vector = {} +vector.__index = vector + +local function new(x, y) + if type(x) == "table" then + return setmetatable({ + x = x[1], + y = y[1] + }, vector) + else + return setmetatable({ + x = x or 0, + y = y or 0 + }, vector) + end +end + +function vector.__add(a, b) + return new(a.x + b.x, a.y + b.y) +end + +function vector.__sub(a, b) + return new(a.x - b.x, a.y - b.y) +end + +function vector.__mul(a, b) + if type(b) == "number" then + return new(a.x * b, a.y * b) + else + return a.x * b.x + a.y * b.y + end +end + +function vector.__div(a, b) + return new(a.x / b, a.y / b) +end + +function vector.__eq(a, b) + return a.x == b.x and a.y == b.y +end + +function vector:dist(b) + return math.sqrt(math.pow(b.x - self.x, 2) + math.pow(b.y-self.y, 2)) +end + +return setmetatable({new = new}, {__call = function(_, ...) return new(...) end})