From f40ccd8e4ee60e904ee18816d23e1d9e2253baac Mon Sep 17 00:00:00 2001 From: Marcus Ihde Date: Sun, 23 Mar 2014 19:10:58 +0100 Subject: [PATCH] Added image shadow. --- example.lua | 86 +++ gfx/cone_large.png | Bin 0 -> 1563 bytes gfx/cone_large_normal.png | Bin 0 -> 1621 bytes light.lua | 1302 ++++++++++++++++--------------------- main.lua | 66 +- main_example.lua | 40 -- postshader.lua | 4 +- shader/refraction.glsl | 10 +- 8 files changed, 678 insertions(+), 830 deletions(-) create mode 100644 example.lua create mode 100644 gfx/cone_large.png create mode 100644 gfx/cone_large_normal.png delete mode 100644 main_example.lua diff --git a/example.lua b/example.lua new file mode 100644 index 0000000..5dc172d --- /dev/null +++ b/example.lua @@ -0,0 +1,86 @@ +require "postshader" +require "light" + +function love.load() + -- load images + image = love.graphics.newImage("gfx/machine2.png") + image_normal = love.graphics.newImage("gfx/cone_normal.png") + normal = love.graphics.newImage("gfx/refraction_normal.png") + glow = love.graphics.newImage("gfx/machine2_glow.png") + + -- create light world + lightWorld = love.light.newWorld() + lightWorld.setAmbientColor(15, 15, 31) + lightWorld.setRefractionStrength(32.0) + + -- create light + lightMouse = lightWorld.newLight(0, 0, 255, 127, 63, 300) + lightMouse.setGlowStrength(0.3) + --lightMouse.setSmooth(0.01) + + -- create shadow bodys + circleTest = lightWorld.newCircle(256, 256, 16) + rectangleTest = lightWorld.newRectangle(512, 512, 64, 64) + imageTest = lightWorld.newImage(image, 64, 64, 24, 6) + imageTest.setNormalMap(image_normal) + imageTest.setGlowMap(glow) + imageTest.setOffset(12, -10) + + -- create body object + objectTest = lightWorld.newBody("refraction", normal, 64, 64, 128, 128) + --objectTest.setShine(false) + --objectTest.setShadowType("rectangle") + --objectTest.setShadowDimension(64, 64) + objectTest.setReflection(true) + + -- set background + quadScreen = love.graphics.newQuad(0, 0, love.window.getWidth(), love.window.getHeight(), 32, 24) + imgFloor = love.graphics.newImage("gfx/floor.png") + imgFloor:setWrap("repeat", "repeat") +end + +function love.update(dt) + love.window.setTitle("Light vs. Shadow Engine (FPS:" .. love.timer.getFPS() .. ")") + lightMouse.setPosition(love.mouse.getX(), love.mouse.getY()) +end + +function love.draw() + -- update lightmap (doesn't need deltatime) + lightWorld.update() + + love.postshader.setBuffer("render") + + -- draw background + love.graphics.setColor(255, 255, 255) + love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) + --love.graphics.draw(imgFloor, quadScreen, 0, 0) + + -- draw lightmap shadows + lightWorld.drawShadow() + + -- draw scene objects + love.graphics.setColor(63, 255, 127) + love.graphics.circle("fill", circleTest.getX(), circleTest.getY(), circleTest.getRadius()) + love.graphics.polygon("fill", rectangleTest.getPoints()) + love.graphics.setColor(255, 255, 255) + love.graphics.draw(image, 64 - image:getWidth() * 0.5, 64 - image:getHeight() * 0.5) + + --love.graphics.rectangle("fill", 128 - 32, 128 - 32, 64, 64) + + -- draw lightmap shine + lightWorld.drawShine() + + -- draw pixel shadow + lightWorld.drawPixelShadow() + + -- draw glow + lightWorld.drawGlow() + + -- draw refraction + lightWorld.drawRefraction() + + -- draw reflection + lightWorld.drawReflection() + + love.postshader.draw() +end \ No newline at end of file diff --git a/gfx/cone_large.png b/gfx/cone_large.png new file mode 100644 index 0000000000000000000000000000000000000000..cf2a366cbb664709893e06a443badf95bf345fbc GIT binary patch literal 1563 zcmeAS@N?(olHy`uVBq!ia0vp^5h`A7x~!Qa_cficWk;1OBOz`(Z!gc&!QRp|f)B}-f*N`mv#O3D+9 zQW*jgGxJLH{9Hp6%8d0)^(@S-8)AW>*x>2n7~ZjXLL@_zj) zmE(_h3R)(LJJ8d{`)9Nc><+oRS^gX{eP+FKpNSLEThe^Lpc+Q!E-8tVGPc_H4 zSAH<^DQI$Wx>Rh=$6RgDXnWnbjr|;RUpvR4Js}r6HQfR`pJskPmtbzUNXl=m9^)l` z5oc?@q&Ymy5`iBbY|nqQbY%4_NDq&bi)(V2pdS>tzj@vv-E-@#-~Ka{SiaYCPV9$u zf!pqG<~#Jbr+VJ`|NHsA&X3;xEAivi_H9g49;)v>B&SoedUw&0pw*wP_I4Rgdr*?C z5~mAml||$H&{GrFgtnD+bwCmUWJYB+G|T2k)b5WFZln+ z1`NU9*;RqD!CBxDSzV3Vm|Hi*0z+|^r;B5VhxgmC=;&qx9^K28j;)7_y516k5ts{i8T@Jb~n{e zJXEptmCE|Hf#Le~*`99%g&2O>J@a8U6@Itp^??=PDf_23oPPF8jXC30sM_LiiL*KD zX36h3#Wzp(vHzx5kMHJ6>C}XL4$$y%Wvg;haqIU`TW~a>X>p{_^fy)tFBhD5m3`7C z5UHTl7IMklTGxx`o7R_g-T|5Nya5t^FK>wEI|N02&tuzNwuq%|KFj90w`!9%Xe|`p z`ygzEymEZDmy$SqtciSNP5yE~M^88YUu zHLMS;NmM@eNgyVSfn`T~8Si=dw8{{s1$_0gF0u@_%bEIO!@>_AI-d9Y)Pa+luRicx z`S?w!Ve{wivm4&Y%LN~J{e!(ixNv>ijY;>s*6Enekv+cQ&+(0Bym=Sxc#N{wp68Ok hT-nOD{m;)IEFUhgZP@G>cNCNxJzf1=);T3K0RV=0M7{t3 literal 0 HcmV?d00001 diff --git a/light.lua b/light.lua index 82b12bf..eed23b6 100644 --- a/light.lua +++ b/light.lua @@ -2,6 +2,7 @@ LOVE_LIGHT_CURRENT = nil LOVE_LIGHT_CIRCLE = nil LOVE_LIGHT_POLY = nil LOVE_LIGHT_IMAGE = nil +LOVE_LIGHT_BODY = nil LOVE_LIGHT_LAST_BUFFER = nil LOVE_LIGHT_SHADOW_GEOMETRY = nil @@ -25,6 +26,7 @@ function love.light.newWorld() o.circle = {} o.poly = {} o.img = {} + o.body = {} o.refraction = {} o.shadow = love.graphics.newCanvas() o.shadow2 = love.graphics.newCanvas() @@ -66,19 +68,14 @@ function love.light.newWorld() o.changed = true end - --if o.changed then - --love.graphics.setCanvas(o.shadow) - --o.shadow:clear() - --love.graphics.setBlendMode("additive") - --else - love.graphics.setColor(255, 255, 255) - love.graphics.setBlendMode("alpha") - --end + love.graphics.setColor(255, 255, 255) + love.graphics.setBlendMode("alpha") local lightsOnScreen = 0 LOVE_LIGHT_CIRCLE = o.circle LOVE_LIGHT_POLY = o.poly LOVE_LIGHT_IMAGE = o.img + LOVE_LIGHT_BODY = o.body for i = 1, #o.lights do if o.lights[i].changed or o.changed then if o.lights[i].x + o.lights[i].range > LOVE_LIGHT_TRANSLATE_X and o.lights[i].x - o.lights[i].range < love.graphics.getWidth() + LOVE_LIGHT_TRANSLATE_X @@ -95,15 +92,11 @@ function love.light.newWorld() o.shader:send("lightAngle", math.pi - o.lights[i].angle / 2.0) o.shader:send("lightDirection", o.lights[i].direction) - --if o.changed then - --love.graphics.setCanvas(o.shadow) - --else - love.graphics.setCanvas(o.lights[i].shadow) - love.graphics.clear() - --end + love.graphics.setCanvas(o.lights[i].shadow) + love.graphics.clear() -- calculate shadows - LOVE_LIGHT_SHADOW_GEOMETRY = calculateShadows(LOVE_LIGHT_CURRENT, LOVE_LIGHT_POLY, LOVE_LIGHT_CIRCLE) + LOVE_LIGHT_SHADOW_GEOMETRY = calculateShadows(LOVE_LIGHT_CURRENT, LOVE_LIGHT_BODY) -- draw shadow love.graphics.setInvertedStencil(shadowStencil) @@ -113,28 +106,44 @@ function love.light.newWorld() -- draw color shadows love.graphics.setBlendMode("multiplicative") love.graphics.setShader() - for i = 1,#LOVE_LIGHT_SHADOW_GEOMETRY do - if LOVE_LIGHT_SHADOW_GEOMETRY[i].alpha < 1.0 then + for k = 1,#LOVE_LIGHT_SHADOW_GEOMETRY do + if LOVE_LIGHT_SHADOW_GEOMETRY[k].alpha < 1.0 then love.graphics.setColor( - LOVE_LIGHT_SHADOW_GEOMETRY[i].red * (1.0 - LOVE_LIGHT_SHADOW_GEOMETRY[i].alpha), - LOVE_LIGHT_SHADOW_GEOMETRY[i].green * (1.0 - LOVE_LIGHT_SHADOW_GEOMETRY[i].alpha), - LOVE_LIGHT_SHADOW_GEOMETRY[i].blue * (1.0 - LOVE_LIGHT_SHADOW_GEOMETRY[i].alpha) + LOVE_LIGHT_SHADOW_GEOMETRY[k].red * (1.0 - LOVE_LIGHT_SHADOW_GEOMETRY[k].alpha), + LOVE_LIGHT_SHADOW_GEOMETRY[k].green * (1.0 - LOVE_LIGHT_SHADOW_GEOMETRY[k].alpha), + LOVE_LIGHT_SHADOW_GEOMETRY[k].blue * (1.0 - LOVE_LIGHT_SHADOW_GEOMETRY[k].alpha) ) - love.graphics.polygon("fill", unpack(LOVE_LIGHT_SHADOW_GEOMETRY[i])) + love.graphics.polygon("fill", unpack(LOVE_LIGHT_SHADOW_GEOMETRY[k])) end end - for i = 1, #LOVE_LIGHT_CIRCLE do - if LOVE_LIGHT_CIRCLE[i].glassAlpha < 1.0 then - love.graphics.setColor(LOVE_LIGHT_CIRCLE[i].red, LOVE_LIGHT_CIRCLE[i].green, LOVE_LIGHT_CIRCLE[i].blue) - love.graphics.circle("fill", LOVE_LIGHT_CIRCLE[i].x, LOVE_LIGHT_CIRCLE[i].y, LOVE_LIGHT_CIRCLE[i].radius) + for k = 1, #LOVE_LIGHT_BODY do + if LOVE_LIGHT_BODY[k].alpha < 1.0 then + love.graphics.setBlendMode("multiplicative") + love.graphics.setColor(LOVE_LIGHT_BODY[k].red, LOVE_LIGHT_BODY[k].green, LOVE_LIGHT_BODY[k].blue) + if LOVE_LIGHT_BODY[k].shadowType == "circle" then + love.graphics.circle("fill", LOVE_LIGHT_BODY[k].x - LOVE_LIGHT_BODY[k].ox, LOVE_LIGHT_BODY[k].y - LOVE_LIGHT_BODY[k].oy, LOVE_LIGHT_BODY[k].radius) + elseif LOVE_LIGHT_BODY[k].shadowType == "rectangle" then + love.graphics.rectangle("fill", LOVE_LIGHT_BODY[k].x - LOVE_LIGHT_BODY[k].ox, LOVE_LIGHT_BODY[k].y - LOVE_LIGHT_BODY[k].oy, LOVE_LIGHT_BODY[k].width, LOVE_LIGHT_BODY[k].height) + elseif LOVE_LIGHT_BODY[k].shadowType == "polygon" then + love.graphics.polygon("fill", unpack(LOVE_LIGHT_BODY[k].data)) + end end - end + if LOVE_LIGHT_BODY[k].shadowType == "image" and LOVE_LIGHT_BODY[k].img then + love.graphics.setBlendMode("alpha") + local length = 1.0 + local shadowRotation = math.atan2((LOVE_LIGHT_BODY[k].x) - o.lights[i].x, (LOVE_LIGHT_BODY[k].y + LOVE_LIGHT_BODY[k].oy) - o.lights[i].y) + --local alpha = math.abs(math.cos(shadowRotation)) - for i = 1, #LOVE_LIGHT_POLY do - if LOVE_LIGHT_POLY[i].glassAlpha < 1.0 then - love.graphics.setColor(LOVE_LIGHT_POLY[i].red, LOVE_LIGHT_POLY[i].green, LOVE_LIGHT_POLY[i].blue) - love.graphics.polygon("fill", unpack(LOVE_LIGHT_POLY[i].data)) + LOVE_LIGHT_BODY[k].shadowVert = { + {math.sin(shadowRotation) * LOVE_LIGHT_BODY[k].imgHeight * length, (length * math.cos(shadowRotation) + 1.0) * LOVE_LIGHT_BODY[k].imgHeight + (math.cos(shadowRotation) + 1.0) * LOVE_LIGHT_BODY[k].shadowY, 0, 0, LOVE_LIGHT_BODY[k].red, LOVE_LIGHT_BODY[k].green, LOVE_LIGHT_BODY[k].blue, LOVE_LIGHT_BODY[k].alpha * LOVE_LIGHT_BODY[k].fadeStrength * 255}, + {LOVE_LIGHT_BODY[k].imgWidth + math.sin(shadowRotation) * LOVE_LIGHT_BODY[k].imgHeight * length, (length * math.cos(shadowRotation) + 1.0) * LOVE_LIGHT_BODY[k].imgHeight + (math.cos(shadowRotation) + 1.0) * LOVE_LIGHT_BODY[k].shadowY, 1, 0, LOVE_LIGHT_BODY[k].red, LOVE_LIGHT_BODY[k].green, LOVE_LIGHT_BODY[k].blue, LOVE_LIGHT_BODY[k].alpha * LOVE_LIGHT_BODY[k].fadeStrength * 255}, + {LOVE_LIGHT_BODY[k].imgWidth, LOVE_LIGHT_BODY[k].imgHeight + (math.cos(shadowRotation) + 1.0) * LOVE_LIGHT_BODY[k].shadowY, 1, 1, LOVE_LIGHT_BODY[k].red, LOVE_LIGHT_BODY[k].green, LOVE_LIGHT_BODY[k].blue, LOVE_LIGHT_BODY[k].alpha * 255}, + {0, LOVE_LIGHT_BODY[k].imgHeight + (math.cos(shadowRotation) + 1.0) * LOVE_LIGHT_BODY[k].shadowY, 0, 1, LOVE_LIGHT_BODY[k].red, LOVE_LIGHT_BODY[k].green, LOVE_LIGHT_BODY[k].blue, LOVE_LIGHT_BODY[k].alpha * 255} + } + + LOVE_LIGHT_BODY[k].shadowMesh:setVertices(LOVE_LIGHT_BODY[k].shadowVert) + love.graphics.draw(LOVE_LIGHT_BODY[k].shadowMesh, LOVE_LIGHT_BODY[k].x - LOVE_LIGHT_BODY[k].ox + LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_BODY[k].y - LOVE_LIGHT_BODY[k].oy + LOVE_LIGHT_TRANSLATE_Y) end end @@ -160,21 +169,19 @@ function love.light.newWorld() -- update shadow love.graphics.setShader() - --if not o.changed then - love.graphics.setCanvas(o.shadow) - love.graphics.setStencil() - love.graphics.setColor(unpack(o.ambient)) - love.graphics.setBlendMode("alpha") - love.graphics.rectangle("fill", LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y, love.graphics.getWidth(), love.graphics.getHeight()) - love.graphics.setColor(255, 255, 255) - love.graphics.setBlendMode("additive") - for i = 1, #o.lights do - if o.lights[i].visible then - love.graphics.draw(o.lights[i].shadow, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) - end + love.graphics.setCanvas(o.shadow) + love.graphics.setStencil() + love.graphics.setColor(unpack(o.ambient)) + love.graphics.setBlendMode("alpha") + love.graphics.rectangle("fill", LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y, love.graphics.getWidth(), love.graphics.getHeight()) + love.graphics.setColor(255, 255, 255) + love.graphics.setBlendMode("additive") + for i = 1, #o.lights do + if o.lights[i].visible then + love.graphics.draw(o.lights[i].shadow, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) end - o.isShadowBlur = false - --end + end + o.isShadowBlur = false -- update shine love.graphics.setCanvas(o.shine) @@ -193,19 +200,17 @@ function love.light.newWorld() love.graphics.setBlendMode("alpha") -- create normal map - if o.changed then - o.normalMap:clear() - love.graphics.setShader() - love.graphics.setCanvas(o.normalMap) - for i = 1, #o.img do - if o.img[i].normal then - love.graphics.setColor(255, 255, 255) - love.graphics.draw(o.img[i].normal, o.img[i].x - o.img[i].ox2 + LOVE_LIGHT_TRANSLATE_X, o.img[i].y - o.img[i].oy2 + LOVE_LIGHT_TRANSLATE_Y) - end + o.normalMap:clear() + love.graphics.setShader() + love.graphics.setCanvas(o.normalMap) + for i = 1, #o.body do + if o.body[i].type == "image" and o.body[i].normal then + love.graphics.setColor(255, 255, 255) + love.graphics.draw(o.body[i].normal, o.body[i].x - o.body[i].nx + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].ny + LOVE_LIGHT_TRANSLATE_Y) end - love.graphics.setColor(255, 255, 255) - love.graphics.setBlendMode("alpha") end + love.graphics.setColor(255, 255, 255) + love.graphics.setBlendMode("alpha") o.pixelShadow2:clear() love.graphics.setCanvas(o.pixelShadow2) @@ -237,98 +242,102 @@ function love.light.newWorld() love.graphics.setBlendMode("alpha") -- create glow map - --if o.changed then - o.glowMap:clear(0, 0, 0) - love.graphics.setCanvas(o.glowMap) - for i = 1, #o.circle do - if o.circle[i].glowStrength > 0.0 then - love.graphics.setColor(o.circle[i].glowRed * o.circle[i].glowStrength, o.circle[i].glowGreen * o.circle[i].glowStrength, o.circle[i].glowBlue * o.circle[i].glowStrength) - love.graphics.circle("fill", o.circle[i].x, o.circle[i].y, o.circle[i].radius) - else - love.graphics.setColor(0, 0, 0) - love.graphics.circle("fill", o.circle[i].x, o.circle[i].y, o.circle[i].radius) - end - end - for i = 1, #o.poly do - if o.poly[i].glowStrength > 0.0 then - love.graphics.setColor(o.poly[i].glowRed * o.poly[i].glowStrength, o.poly[i].glowGreen * o.poly[i].glowStrength, o.poly[i].glowBlue * o.poly[i].glowStrength) - love.graphics.polygon("fill", unpack(o.poly[i].data)) - else - love.graphics.setColor(0, 0, 0) - love.graphics.polygon("fill", unpack(o.poly[i].data)) - end - end + o.glowMap:clear(0, 0, 0) + love.graphics.setCanvas(o.glowMap) - if o.glowDown then - o.glowTimer = math.max(0.0, o.glowTimer - love.timer.getDelta()) - if o.glowTimer == 0.0 then - o.glowDown = not o.glowDown - end + if o.glowDown then + o.glowTimer = math.max(0.0, o.glowTimer - love.timer.getDelta()) + if o.glowTimer == 0.0 then + o.glowDown = not o.glowDown + end + else + o.glowTimer = math.min(o.glowTimer + love.timer.getDelta(), 1.0) + if o.glowTimer == 1.0 then + o.glowDown = not o.glowDown + end + end + + for i = 1, #o.body do + if o.body[i].glowStrength > 0.0 then + love.graphics.setColor(o.body[i].glowRed * o.body[i].glowStrength, o.body[i].glowGreen * o.body[i].glowStrength, o.body[i].glowBlue * o.body[i].glowStrength) else - o.glowTimer = math.min(o.glowTimer + love.timer.getDelta(), 1.0) - if o.glowTimer == 1.0 then - o.glowDown = not o.glowDown - end + love.graphics.setColor(0, 0, 0) end - for i = 1, #o.img do - if o.img[i].glow then + if o.body[i].type == "circle" then + love.graphics.circle("fill", o.body[i].x, o.body[i].y, o.body[i].radius) + elseif o.body[i].type == "rectangle" then + love.graphics.rectangle("fill", o.body[i].x, o.body[i].y, o.body[i].width, o.body[i].height) + elseif o.body[i].type == "polygon" then + love.graphics.polygon("fill", unpack(o.body[i].data)) + elseif o.body[i].type == "image" and o.body[i].img then + if o.body[i].glowStrength > 0.0 and o.body[i].glow then love.graphics.setShader(o.glowShader) - o.glowShader:send("glowImage", o.img[i].glow) + o.glowShader:send("glowImage", o.body[i].glow) o.glowShader:send("glowTime", love.timer.getTime()) love.graphics.setColor(255, 255, 255) else love.graphics.setShader() love.graphics.setColor(0, 0, 0) end - love.graphics.draw(o.img[i].img, o.img[i].x - o.img[i].ox2 + LOVE_LIGHT_TRANSLATE_X, o.img[i].y - o.img[i].oy2 + LOVE_LIGHT_TRANSLATE_Y) + love.graphics.draw(o.body[i].img, o.body[i].x - o.body[i].ix + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].iy + LOVE_LIGHT_TRANSLATE_Y) end - love.graphics.setShader() - o.isGlowBlur = false - --end + end + + love.graphics.setShader() + o.isGlowBlur = false -- create refraction map - if o.changed then - o.refractionMap:clear() - love.graphics.setCanvas(o.refractionMap) - for i = 1, #o.refraction do - if o.refraction[i].strength > 0.0 and o.refraction[i].normal then - love.graphics.setColor(255, 255, 255) - o.refraction[i].mesh:setVertices(o.refraction[i].vertices) - love.graphics.draw(o.refraction[i].mesh, o.refraction[i].x - o.refraction[i].ox + LOVE_LIGHT_TRANSLATE_X, o.refraction[i].y - o.refraction[i].oy + LOVE_LIGHT_TRANSLATE_Y) + o.refractionMap:clear() + love.graphics.setCanvas(o.refractionMap) + for i = 1, #o.body do + if o.body[i].refraction and o.body[i].normal then + love.graphics.setColor(255, 255, 255) + if o.body[i].tileX == 0.0 and o.body[i].tileY == 0.0 then + love.graphics.draw(normal, o.body[i].x - o.body[i].nx + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].ny + LOVE_LIGHT_TRANSLATE_Y) else - love.graphics.setColor(0, 0, 0, 0) - love.graphics.rectangle("fill", o.refraction[i].x - o.refraction[i].ox + LOVE_LIGHT_TRANSLATE_X, o.refraction[i].y - o.refraction[i].oy, o.refraction[i].normalWidth, o.refraction[i].normalHeight + LOVE_LIGHT_TRANSLATE_Y) + o.body[i].normalMesh:setVertices(o.body[i].normalVert) + love.graphics.draw(o.body[i].normalMesh, o.body[i].x - o.body[i].nx + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].ny + LOVE_LIGHT_TRANSLATE_Y) end end - for i = 1, #o.img do - if not o.img[i].refractive and o.img[i].img then - love.graphics.setColor(0, 0, 0) - love.graphics.draw(o.img[i].img, o.img[i].x - o.img[i].ox2 + LOVE_LIGHT_TRANSLATE_X, o.img[i].y - o.img[i].oy2 + LOVE_LIGHT_TRANSLATE_Y) + end + + love.graphics.setBlendMode("replace") + love.graphics.setColor(0, 0, 0, 0) + for i = 1, #o.body do + if not o.body[i].refractive then + if o.body[i].type == "circle" then + love.graphics.circle("fill", o.body[i].x, o.body[i].y, o.body[i].radius) + elseif o.body[i].type == "rectangle" then + love.graphics.rectangle("fill", o.body[i].x, o.body[i].y, o.body[i].width, o.body[i].height) + elseif o.body[i].type == "polygon" then + love.graphics.polygon("fill", unpack(o.body[i].data)) + elseif o.body[i].type == "image" and o.body[i].img then + love.graphics.draw(o.body[i].img, o.body[i].x - o.body[i].ix + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].iy + LOVE_LIGHT_TRANSLATE_Y) end end end -- create reflection map + love.graphics.setBlendMode("alpha") if o.changed then o.reflectionMap:clear(0, 0, 0) love.graphics.setCanvas(o.reflectionMap) - for i = 1, #o.refraction do - if o.refraction[i].reflective and o.refraction[i].normal then + for i = 1, #o.body do + if o.body[i].reflection and o.body[i].normal then love.graphics.setColor(255, 0, 0) - else - love.graphics.setColor(0, 0, 0) + o.body[i].normalMesh:setVertices(o.body[i].normalVert) + love.graphics.draw(o.body[i].normalMesh, o.body[i].x - o.body[i].nx + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].ny + LOVE_LIGHT_TRANSLATE_Y) end - o.refraction[i].mesh:setVertices(o.refraction[i].vertices) - love.graphics.draw(o.refraction[i].mesh, o.refraction[i].x - o.refraction[i].ox + LOVE_LIGHT_TRANSLATE_X, o.refraction[i].y - o.refraction[i].oy + LOVE_LIGHT_TRANSLATE_Y) end - for i = 1, #o.img do - if o.img[i].reflective and o.img[i].img then + for i = 1, #o.body do + if o.body[i].reflective and o.body[i].img then love.graphics.setColor(0, 255, 0) - else + love.graphics.draw(o.body[i].img, o.body[i].x - o.body[i].ix + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].iy + LOVE_LIGHT_TRANSLATE_Y) + elseif not o.body[i].reflection and o.body[i].img then love.graphics.setColor(0, 0, 0) + love.graphics.draw(o.body[i].img, o.body[i].x - o.body[i].ix + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].iy + LOVE_LIGHT_TRANSLATE_Y) end - love.graphics.draw(o.img[i].img, o.img[i].x - o.img[i].ox2 + LOVE_LIGHT_TRANSLATE_X, o.img[i].y - o.img[i].oy2 + LOVE_LIGHT_TRANSLATE_Y) end end @@ -473,11 +482,8 @@ function love.light.newWorld() o.changed = true end -- clear objects - o.clearObjects = function() - o.poly = {} - o.circle = {} - o.img = {} - o.refraction = {} + o.clearBodys = function() + o.body = {} o.changed = true end -- set offset @@ -552,29 +558,23 @@ function love.light.newWorld() o.newRefractionHeightMap = function(heightMap, x, y, strength) return love.light.newRefractionHeightMap(o, heightMap, x, y, strength) end + -- new body + o.newBody = function(type, ...) + return love.light.newBody(o, type, ...) + end -- set polygon data o.setPoints = function(n, ...) - o.poly[n].data = {...} + o.body[n].data = {...} end -- get polygon count - o.getObjectCount = function() - return #o.poly + #o.circle + #o.img - end - -- get circle count - o.getCircleCount = function() - return #o.circle - end - -- get polygon count - o.getPolygonCount = function() - return #o.poly - end - -- get image count - o.getImageCount = function() - return #o.img + o.getBodyCount = function() + return #o.body end -- get polygon o.getPoints = function(n) - return unpack(o.poly[n].data) + if o.body[n].data then + return unpack(o.body[n].data) + end end -- set light position o.setLightPosition = function(n, x, y) @@ -729,370 +729,141 @@ function love.light.newLight(p, x, y, red, green, blue, range) return o end --- rectangle object -function love.light.newRectangle(p, x, y, width, height) +-- body object +function love.light.newBody(p, type, ...) + local args = {...} local o = {} - p.poly[#p.poly + 1] = o - o.id = #p.poly - o.x = x or 0 - o.y = y or 0 - o.width = width or 64 - o.height = height or 64 - o.ox = o.width / 2 - o.oy = o.height / 2 - o.shine = true - o.red = 255 - o.green = 255 - o.blue = 255 - o.glassAlpha = 1.0 - o.glowRed = 255 - o.glowGreen = 255 - o.glowBlue = 255 - o.glowStrength = 0.0 - o.type = "rectangle" + p.body[#p.body + 1] = o p.changed = true - o.data = { - o.x - o.ox, - o.y - o.oy, - o.x - o.ox + o.width, - o.y - o.oy, - o.x - o.ox + o.width, - o.y - o.oy + o.height, - o.x - o.ox, - o.y - o.oy + o.height - } - -- refresh - o.refresh = function() - o.data[1] = o.x - o.ox - o.data[2] = o.y - o.oy - o.data[3] = o.x - o.ox + o.width - o.data[4] = o.y - o.oy - o.data[5] = o.x - o.ox + o.width - o.data[6] = o.y - o.oy + o.height - o.data[7] = o.x - o.ox - o.data[8] = o.y - o.oy + o.height - end - -- set position - o.setPosition = function(x, y) - if x ~= o.x or y ~= o.y then - o.x = x - o.y = y - o.refresh() - p.changed = true - end - end - -- set x - o.setX = function(x) - if x ~= o.x then - o.x = x - o.refresh() - p.changed = true - end - end - -- set y - o.setY = function(y) - if y ~= o.y then - o.y = y - o.refresh() - p.changed = true - end - end - -- set dimension - o.setDimension = function(width, height) - o.width = width - o.height = height - o.refresh() - p.changed = true - end - -- set shadow on/off - o.setShadow = function(b) - o.castsNoShadow = not b - p.changed = true - end - -- set shine on/off - o.setShine = function(b) - o.shine = b - p.changed = true - end - -- set shadow color - o.setColor = function(red, green, blue) - o.red = red - o.green = green - o.blue = blue - p.changed = true - end - -- set shadow alpha - o.setAlpha = function(alpha) - o.glassAlpha = alpha - p.changed = true - end - -- set glow color - o.setGlowColor = function(red, green, blue) - o.glowRed = red - o.glowGreen = green - o.glowBlue = blue - p.changed = true - end - -- set glow alpha - o.setGlowStrength = function(strength) - o.glowStrength = strength - p.changed = true - end - -- get x - o.getX = function() - return o.x - end - -- get y - o.getY = function() - return o.y - end - -- get width - o.getWidth = function() - return o.width - end - -- get height - o.getHeight = function() - return o.height - end - -- get rectangle data - o.getPoints = function() - return unpack(o.data) - end - -- get type - o.getType = function() - return o.type - end - - return o -end - --- circle object -function love.light.newCircle(p, x, y, radius) - local o = {} - p.circle[#p.circle + 1] = o - o.id = #p.circle - o.x = x or 0 - o.y = y or 0 - o.radius = radius or 64 - o.shine = true - o.red = 255 - o.green = 255 - o.blue = 255 - o.glassAlpha = 1.0 - o.glowRed = 255 - o.glowGreen = 255 - o.glowBlue = 255 - o.glowStrength = 0.0 - o.type = "circle" - p.changed = true - -- set position - o.setPosition = function(x, y) - if x ~= o.x or y ~= o.y then - o.x = x - o.y = y - p.changed = true - end - end - -- set x - o.setX = function(x) - if x ~= o.x then - o.x = x - p.changed = true - end - end - -- set y - o.setY = function(y) - if y ~= o.y then - o.y = y - p.changed = true - end - end - -- set radius - o.setRadius = function(radius) - if radius ~= o.radius then - o.radius = radius - p.changed = true - end - end - -- set shadow on/off - o.setShadow = function(b) - o.castsNoShadow = not b - p.changed = true - end - -- set shine on/off - o.setShine = function(b) - o.shine = b - p.changed = true - end - -- set shadow color - o.setColor = function(red, green, blue) - o.red = red - o.green = green - o.blue = blue - p.changed = true - end - -- set shadow alpha - o.setAlpha = function(alpha) - o.glassAlpha = alpha - p.changed = true - end - -- set glow color - o.setGlowColor = function(red, green, blue) - o.glowRed = red - o.glowGreen = green - o.glowBlue = blue - p.changed = true - end - -- set glow alpha - o.setGlowStrength = function(strength) - o.glowStrength = strength - p.changed = true - end - -- get x - o.getX = function() - return o.x - end - -- get y - o.getY = function() - return o.y - end - -- get radius - o.getRadius = function() - return o.radius - end - -- get type - o.getType = function() - return o.type - end - - return o -end - --- poly object -function love.light.newPolygon(p, ...) - local o = {} - p.poly[#p.poly + 1] = o - o.id = #p.poly - o.shine = true - o.red = 255 - o.green = 255 - o.blue = 255 - o.glassAlpha = 1.0 - o.glowRed = 255 - o.glowGreen = 255 - o.glowBlue = 255 - o.glowStrength = 0.0 - o.type = "polygon" - p.changed = true - if ... then - o.data = {...} - else - o.data = {0, 0, 0, 0, 0, 0} - end - -- set polygon data - o.setPoints = function(...) - o.data = {...} - p.changed = true - end - -- set shadow on/off - o.setShadow = function(b) - o.castsNoShadow = not b - p.changed = true - end - -- set shine on/off - o.setShine = function(b) - o.shine = b - p.changed = true - end - -- set shadow color - o.setColor = function(red, green, blue) - o.red = red - o.green = green - o.blue = blue - p.changed = true - end - -- set shadow alpha - o.setAlpha = function(alpha) - o.glassAlpha = alpha - p.changed = true - end - -- set glow color - o.setGlowColor = function(red, green, blue) - o.glowRed = red - o.glowGreen = green - o.glowBlue = blue - p.changed = true - end - -- set glow alpha - o.setGlowStrength = function(strength) - o.glowStrength = strength - p.changed = true - end - -- get polygon data - o.getPoints = function() - return unpack(o.data) - end - -- get type - o.getType = function() - return o.type - end - - return o -end - --- image object -function love.light.newImage(p, img, x, y, width, height, ox, oy) - local o = {} - p.poly[#p.poly + 1] = o - p.img[#p.img + 1] = o - o.id = #p.img - o.img = img + o.id = #p.body + o.type = type o.normal = nil o.glow = nil - o.x = x or 0 - o.y = y or 0 - o.width = width or img:getWidth() - o.height = height or img:getHeight() - o.ox = o.width / 2.0 - o.oy = o.height / 2.0 - o.ox2 = ox or o.width / 2.0 - o.oy2 = oy or o.height / 2.0 - o.imgWidth = img:getWidth() - o.imgHeight = img:getHeight() + if o.type == "circle" then + o.x = args[1] or 0 + o.y = args[2] or 0 + o.radius = args[3] or 16 + o.ox = args[4] or 0 + o.oy = args[5] or 0 + o.shadowType = "circle" + o.reflection = false + o.reflective = false + o.refraction = false + o.refractive = false + elseif o.type == "rectangle" then + o.x = args[1] or 0 + o.y = args[2] or 0 + o.width = args[3] or 64 + o.height = args[4] or 64 + o.ox = o.width * 0.5 + o.oy = o.height * 0.5 + o.shadowType = "rectangle" + o.data = { + o.x - o.ox, + o.y - o.oy, + o.x - o.ox + o.width, + o.y - o.oy, + o.x - o.ox + o.width, + o.y - o.oy + o.height, + o.x - o.ox, + o.y - o.oy + o.height + } + o.reflection = false + o.reflective = false + o.refraction = false + o.refractive = false + elseif o.type == "polygon" then + o.shadowType = "polygon" + o.data = args or {0, 0, 0, 0, 0, 0} + o.reflection = false + o.reflective = false + o.refraction = false + o.refractive = false + elseif o.type == "image" then + o.img = args[1] + o.x = args[2] or 0 + o.y = args[3] or 0 + if o.img then + o.imgWidth = o.img:getWidth() + o.imgHeight = o.img:getHeight() + o.width = args[4] or o.imgWidth + o.height = args[5] or o.imgHeight + o.ix = o.imgWidth * 0.5 + o.iy = o.imgHeight * 0.5 + else + o.width = args[4] or 64 + o.height = args[5] or 64 + end + o.ox = args[6] or o.width * 0.5 + o.oy = args[7] or o.height * 0.5 + o.shadowType = "rectangle" + o.data = { + o.x - o.ox, + o.y - o.oy, + o.x - o.ox + o.width, + o.y - o.oy, + o.x - o.ox + o.width, + o.y - o.oy + o.height, + o.x - o.ox, + o.y - o.oy + o.height + } + o.reflection = false + o.reflective = true + o.refraction = false + o.refractive = false + elseif o.type == "refraction" then + o.normal = args[1] + o.x = args[2] or 0 + o.y = args[3] or 0 + if o.normal then + o.normalWidth = o.normal:getWidth() + o.normalHeight = o.normal:getHeight() + o.width = args[4] or o.normalWidth + o.height = args[5] or o.normalHeight + o.nx = o.normalWidth * 0.5 + o.ny = o.normalHeight * 0.5 + o.normal:setWrap("repeat", "repeat") + o.normalVert = { + {0.0, 0.0, 0.0, 0.0}, + {o.width, 0.0, 1.0, 0.0}, + {o.width, o.height, 1.0, 1.0}, + {0.0, o.height, 0.0, 1.0} + } + o.normalMesh = love.graphics.newMesh(o.normalVert, o.normal, "fan") + else + o.width = args[4] or 64 + o.height = args[5] or 64 + end + o.ox = o.width / 2.0 + o.oy = o.height / 2.0 + o.reflection = false + o.reflective = false + o.refraction = true + o.refractive = false + end o.shine = true - o.red = 255 - o.green = 255 - o.blue = 255 - o.glassAlpha = 1.0 + o.red = 0 + o.green = 0 + o.blue = 0 + o.alpha = 1.0 o.glowRed = 255 o.glowGreen = 255 o.glowBlue = 255 o.glowStrength = 0.0 - o.refractionStrength = 1.0 - o.reflective = true - o.refractive = false - o.type = "image" - p.changed = true - o.data = { - o.x - o.ox, - o.y - o.oy, - o.x - o.ox + o.width, - o.y - o.oy, - o.x - o.ox + o.width, - o.y - o.oy + o.height, - o.x - o.ox, - o.y - o.oy + o.height - } + o.tileX = 0 + o.tileY = 0 -- refresh o.refresh = function() - o.data[1] = o.x - o.ox - o.data[2] = o.y - o.oy - o.data[3] = o.x - o.ox + o.width - o.data[4] = o.y - o.oy - o.data[5] = o.x - o.ox + o.width - o.data[6] = o.y - o.oy + o.height - o.data[7] = o.x - o.ox - o.data[8] = o.y - o.oy + o.height + if o.data then + o.data[1] = o.x - o.ox + o.data[2] = o.y - o.oy + o.data[3] = o.x - o.ox + o.width + o.data[4] = o.y - o.oy + o.data[5] = o.x - o.ox + o.width + o.data[6] = o.y - o.oy + o.height + o.data[7] = o.x - o.ox + o.data[8] = o.y - o.oy + o.height + end end -- set position o.setPosition = function(x, y) @@ -1150,6 +921,72 @@ function love.light.newImage(p, img, x, y, width, height, ox, oy) o.refresh() p.changed = true end + -- set offset + o.setOffset = function(ox, oy) + if ox ~= o.ox or oy ~= o.oy then + o.ox = ox + o.oy = oy + if o.shadowType == "rectangle" then + o.refresh() + end + p.changed = true + end + end + -- set offset + o.setImageOffset = function(ix, iy) + if ix ~= o.ix or iy ~= o.iy then + o.ix = ix + o.iy = iy + o.refresh() + p.changed = true + end + end + -- set offset + o.setNormalOffset = function(nx, ny) + if nx ~= o.nx or ny ~= o.ny then + o.nx = nx + o.ny = ny + o.refresh() + p.changed = true + end + end + -- set glow color + o.setGlowColor = function(red, green, blue) + o.glowRed = red + o.glowGreen = green + o.glowBlue = blue + p.changed = true + end + -- set glow alpha + o.setGlowStrength = function(strength) + o.glowStrength = strength + p.changed = true + end + -- get radius + o.getRadius = function() + return o.radius + end + -- set radius + o.setRadius = function(radius) + if radius ~= o.radius then + o.radius = radius + p.changed = true + end + end + -- set polygon data + o.setPoints = function(...) + o.data = {...} + p.changed = true + end + -- get polygon data + o.getPoints = function() + return unpack(o.data) + end + -- set shadow on/off + o.setShadowType = function(type) + o.shadowType = type + p.changed = true + end -- set shadow on/off o.setShadow = function(b) o.castsNoShadow = not b @@ -1169,9 +1006,17 @@ function love.light.newImage(p, img, x, y, width, height, ox, oy) end -- set glass alpha o.setAlpha = function(alpha) - o.glassAlpha = alpha + o.alpha = alpha p.changed = true end + -- set reflection on/off + o.setReflection = function(reflection) + o.reflection = reflection + end + -- set refraction on/off + o.setRefraction = function(refraction) + o.refraction = refraction + end -- set reflective on other objects on/off o.setReflective = function(reflective) o.reflective = reflective @@ -1182,15 +1027,31 @@ function love.light.newImage(p, img, x, y, width, height, ox, oy) end -- set image o.setImage = function(img) - o.img = img + if img then + o.img = img + o.imgWidth = o.img:getWidth() + o.imgHeight = o.img:getHeight() + o.ix = o.imgWidth * 0.5 + o.iy = o.imgHeight * 0.5 + end end -- set normal o.setNormalMap = function(normal) - o.normal = normal + if normal then + o.normal = normal + o.normalWidth = o.normal:getWidth() + o.normalHeight = o.normal:getHeight() + o.nx = o.normalWidth * 0.5 + o.ny = o.normalHeight * 0.5 + end end -- set height map o.setHeightMap = function(heightMap, strength) o.normal = HeightMapToNormalMap(heightMap, strength) + o.normalWidth = o.normal:getWidth() + o.normalHeight = o.normal:getHeight() + o.nx = o.normalWidth * 0.5 + o.ny = o.normalHeight * 0.5 end -- generate flat normal map o.generateNormalMapFlat = function(mode) @@ -1220,6 +1081,10 @@ function love.light.newImage(p, img, x, y, width, height, ox, oy) end o.normal = love.graphics.newImage(imgNormalData) + o.normalWidth = o.normal:getWidth() + o.normalHeight = o.normal:getHeight() + o.nx = o.normalWidth * 0.5 + o.ny = o.normalHeight * 0.5 end -- generate faded normal map o.generateNormalMapGradient = function(horizontalGradient, verticalGradient) @@ -1260,204 +1125,123 @@ function love.light.newImage(p, img, x, y, width, height, ox, oy) end o.normal = love.graphics.newImage(imgNormalData) + o.normalWidth = o.normal:getWidth() + o.normalHeight = o.normal:getHeight() + o.nx = o.normalWidth * 0.5 + o.ny = o.normalHeight * 0.5 end -- generate normal map o.generateNormalMap = function(strength) o.normal = HeightMapToNormalMap(o.img, strength) + o.normalWidth = o.normal:getWidth() + o.normalHeight = o.normal:getHeight() + o.nx = o.normalWidth * 0.5 + o.ny = o.normalHeight * 0.5 end -- set normal o.setGlowMap = function(glow) o.glow = glow + o.glowStrength = 1.0 + end + -- set tile offset + o.setNormalTileOffset = function(tx, ty) + o.tileX = tx / o.normalWidth + o.tileY = ty / o.normalHeight + o.normalVert = { + {0.0, 0.0, o.tileX, o.tileY}, + {o.normalWidth, 0.0, o.tileX + 1.0, o.tileY}, + {o.normalWidth, o.normalHeight, o.tileX + 1.0, o.tileY + 1.0}, + {0.0, o.normalHeight, o.tileX, o.tileY + 1.0} + } + p.changed = true end -- get type o.getType = function() return o.type end + -- get type + o.setShadowType = function(type, ...) + o.shadowType = type + local args = {...} + if o.shadowType == "circle" then + o.radius = args[1] or 16 + o.ox = args[2] or 0 + o.oy = args[3] or 0 + elseif o.shadowType == "rectangle" then + o.width = args[1] or 64 + o.height = args[2] or 64 + o.ox = args[3] or o.width * 0.5 + o.oy = args[4] or o.height * 0.5 + o.data = { + o.x - o.ox, + o.y - o.oy, + o.x - o.ox + o.width, + o.y - o.oy, + o.x - o.ox + o.width, + o.y - o.oy + o.height, + o.x - o.ox, + o.y - o.oy + o.height + } + elseif o.shadowType == "polygon" then + o.data = args or {0, 0, 0, 0, 0, 0} + elseif o.shadowType == "image" then + if o.img then + o.width = o.imgWidth + o.height = o.imgHeight + o.shadowVert = { + {0.0, 0.0, 0.0, 0.0}, + {o.width, 0.0, 1.0, 0.0}, + {o.width, o.height, 1.0, 1.0}, + {0.0, o.height, 0.0, 1.0} + } + if not o.shadowMesh then + o.shadowMesh = love.graphics.newMesh(o.shadowVert, o.img, "fan") + o.shadowMesh:setVertexColors(true) + end + else + o.width = 64 + o.height = 64 + end + o.shadowX = args[1] or 0 + o.shadowY = args[2] or 0 + o.fadeStrength = args[3] or 0.0 + end + end return o end +-- rectangle object +function love.light.newRectangle(p, x, y, width, height) + return p.newBody("rectangle", x, y, width, height) +end + +-- circle object +function love.light.newCircle(p, x, y, radius) + return p.newBody("circle", x, y, radius) +end + +-- poly object +function love.light.newPolygon(p, ...) + return p.newBody("polygon", ...) +end + +-- image object +function love.light.newImage(p, img, x, y, width, height, ox, oy) + return p.newBody("image", img, x, y, width, height, ox, oy) +end + +-- refraction object +function love.light.newRefraction(p, normal, x, y, width, height) + return p.newBody("refraction", normal, x, y, width, height) +end + -- refraction object (height map) function love.light.newRefractionHeightMap(p, heightMap, x, y, strength) local normal = HeightMapToNormalMap(heightMap, strength) return love.light.newRefraction(p, normal, x, y) end --- refraction object -function love.light.newRefraction(p, normal, x, y) - local o = {} - p.refraction[#p.refraction + 1] = o - o.id = #p.refraction - o.normal = normal - o.normal:setWrap("repeat", "repeat") - o.x = x or 0 - o.y = y or 0 - o.width = width or normal:getWidth() - o.height = height or normal:getHeight() - o.ox = o.width / 2.0 - o.oy = o.height / 2.0 - o.tileX = 0 - o.tileY = 0 - o.vertices = { - {0.0, 0.0, 0.0, 0.0}, - {o.width, 0.0, 1.0, 0.0}, - {o.width, o.height, 1.0, 1.0}, - {0.0, o.height, 0.0, 1.0} - } - o.mesh = love.graphics.newMesh(o.vertices, o.normal, "fan") - o.normalWidth = normal:getWidth() - o.normalHeight = normal:getHeight() - o.strength = strength or 1.0 - o.reflective = true - o.type = "refraction" - p.changed = true - -- set position - o.setPosition = function(x, y) - if x ~= o.x or y ~= o.y then - o.x = x - o.y = y - p.changed = true - end - end - -- set x position - o.setX = function(x) - if x ~= o.x then - o.x = x - p.changed = true - end - end - -- set y position - o.setY = function(y) - if y ~= o.y then - o.y = y - p.changed = true - end - end - -- set tile offset - o.setTileOffset = function(tx, ty) - o.tileX = tx / o.width - o.tileY = ty / o.height - o.vertices = { - {0.0, 0.0, o.tileX, o.tileY}, - {o.width, 0.0, o.tileX + 1.0, o.tileY}, - {o.width, o.height, o.tileX + 1.0, o.tileY + 1.0}, - {0.0, o.height, o.tileX, o.tileY + 1.0} - } - p.changed = true - end - -- get x position - o.getX = function() - return o.x - end - -- get y position - o.getY = function(y) - return o.y - end - -- get width - o.getWidth = function() - return o.width - end - -- get height - o.getHeight = function() - return o.height - end - -- get image width - o.getImageWidth = function() - return o.imgWidth - end - -- get image height - o.getImageHeight = function() - return o.imgHeight - end - -- set normal - o.setNormalMap = function(normal) - o.normal = normal - end - -- set height map - o.setHeightMap = function(heightMap, strength) - o.normal = HeightMapToNormalMap(heightMap, strength) - end - -- generate flat normal map - o.generateNormalMapFlat = function(mode) - local imgData = o.img:getData() - local imgNormalData = love.image.newImageData(o.imgWidth, o.imgHeight) - local color - - if mode == "top" then - color = {127, 127, 255} - elseif mode == "front" then - color = {127, 255, 127} - elseif mode == "back" then - color = {127, 0, 127} - elseif mode == "left" then - color = {31, 255, 223} - elseif mode == "right" then - color = {223, 223, 127} - end - - for i = 0, o.imgHeight - 1 do - for k = 0, o.imgWidth - 1 do - local r, g, b, a = imgData:getPixel(k, i) - if a > 0 then - imgNormalData:setPixel(k, i, color[1], color[2], color[3], 255) - end - end - end - - o.normal = love.graphics.newImage(imgNormalData) - end - -- generate faded normal map - o.generateNormalMapGradient = function(horizontalGradient, verticalGradient) - local imgData = o.img:getData() - local imgNormalData = love.image.newImageData(o.imgWidth, o.imgHeight) - local dx = 255.0 / o.imgWidth - local dy = 255.0 / o.imgHeight - local nx - local ny - local nz - - for i = 0, o.imgWidth - 1 do - for k = 0, o.imgHeight - 1 do - local r, g, b, a = imgData:getPixel(i, k) - if a > 0 then - if horizontalGradient == "gradient" then - nx = i * dx - elseif horizontalGradient == "inverse" then - nx = 255 - i * dx - else - nx = 127 - end - - if verticalGradient == "gradient" then - ny = 127 + k * dy * 0.5 - nz = 255 - k * dy * 0.5 - elseif verticalGradient == "inverse" then - ny = 127 - k * dy * 0.5 - nz = 127 - k * dy * 0.25 - else - ny = 255 - nz = 127 - end - - imgNormalData:setPixel(i, k, nx, ny, nz, 255) - end - end - end - - o.normal = love.graphics.newImage(imgNormalData) - end - -- generate normal map - o.generateNormalMap = function(strength) - o.normal = HeightMapToNormalMap(o.img, strength) - end - -- get type - o.getType = function() - return o.type - end - - return o -end - -- vector functions function normalize(v) local len = math.sqrt(math.pow(v[1], 2) + math.pow(v[2], 2)) @@ -1477,129 +1261,129 @@ function length(v) return math.sqrt(lengthSqr(v)) end -function calculateShadows(lightsource, geometry, circle, image) +function calculateShadows(light, body) local shadowGeometry = {} local shadowLength = 10000 - for i, v in pairs(geometry) do - curPolygon = v.data - if not v.castsNoShadow then - local edgeFacingTo = {} - for j=1,#curPolygon,2 do - local indexOfNextVertex = (j+2) % #curPolygon - local normal = {-curPolygon[indexOfNextVertex+1] + curPolygon[j+1], curPolygon[indexOfNextVertex] - curPolygon[j]} - local lightToPoint = {curPolygon[j] - lightsource.x, curPolygon[j+1] - lightsource.y} + 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 = normalize(normal) - lightToPoint = normalize(lightToPoint) + normal = normalize(normal) + lightToPoint = normalize(lightToPoint) - local dotProduct = dot(normal, lightToPoint) - if dotProduct > 0 then table.insert(edgeFacingTo, true) - else table.insert(edgeFacingTo, false) end - end + local dotProduct = dot(normal, lightToPoint) + if dotProduct > 0 then table.insert(edgeFacingTo, true) + else table.insert(edgeFacingTo, false) end + end - local curShadowGeometry = {} - for j, curFacing in pairs(edgeFacingTo) do - local nextIndex = (j+1) % #edgeFacingTo; if nextIndex == 0 then nextIndex = #edgeFacingTo end - if curFacing and not edgeFacingTo[nextIndex] then - curShadowGeometry[1] = curPolygon[nextIndex*2-1] - curShadowGeometry[2] = curPolygon[nextIndex*2] + 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 = normalize({curPolygon[nextIndex*2-1] - lightsource.x, curPolygon[nextIndex*2] - lightsource.y}) - curShadowGeometry[3] = curShadowGeometry[1] + lightVecFrontBack[1] * shadowLength - curShadowGeometry[4] = curShadowGeometry[2] + lightVecFrontBack[2] * shadowLength + local lightVecFrontBack = 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 curFacing and edgeFacingTo[nextIndex] then - curShadowGeometry[7] = curPolygon[nextIndex*2-1] - curShadowGeometry[8] = curPolygon[nextIndex*2] + elseif not edgeFacingTo[k] and edgeFacingTo[nextIndex] then + curShadowGeometry[7] = curPolygon[nextIndex*2-1] + curShadowGeometry[8] = curPolygon[nextIndex*2] - local lightVecBackFront = normalize({curPolygon[nextIndex*2-1] - lightsource.x, curPolygon[nextIndex*2] - lightsource.y}) - curShadowGeometry[5] = curShadowGeometry[7] + lightVecBackFront[1] * shadowLength - curShadowGeometry[6] = curShadowGeometry[8] + lightVecBackFront[2] * shadowLength + local lightVecBackFront = 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 - 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 = v.glassAlpha - curShadowGeometry.red = v.red - curShadowGeometry.green = v.green - curShadowGeometry.blue = v.blue + elseif body[i].shadowType == "circle" 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 - for i, v in pairs(circle) do - local curShadowGeometry = {} - local angle = math.atan2(lightsource.x - v.x, v.y - lightsource.y) + math.pi / 2 - local x2 = (v.x + math.sin(angle) * v.radius) - local y2 = (v.y - math.cos(angle) * v.radius) - local x3 = (v.x - math.sin(angle) * v.radius) - local y3 = (v.y + math.cos(angle) * v.radius) - - curShadowGeometry[1] = x2 - curShadowGeometry[2] = y2 - curShadowGeometry[3] = x3 - curShadowGeometry[4] = y3 - - curShadowGeometry[5] = x3 - (lightsource.x - x3) * shadowLength - curShadowGeometry[6] = y3 - (lightsource.y - y3) * shadowLength - curShadowGeometry[7] = x2 - (lightsource.x - x2) * shadowLength - curShadowGeometry[8] = y2 - (lightsource.y - y2) * shadowLength - curShadowGeometry.alpha = v.glassAlpha - curShadowGeometry.red = v.red - curShadowGeometry.green = v.green - curShadowGeometry.blue = v.blue - shadowGeometry[#shadowGeometry + 1] = curShadowGeometry - end - return shadowGeometry end shadowStencil = function() for i = 1,#LOVE_LIGHT_SHADOW_GEOMETRY do if LOVE_LIGHT_SHADOW_GEOMETRY[i].alpha == 1.0 then - --love.graphics.setBlendMode("replace") - --love.graphics.setColor(0,0,0) love.graphics.polygon("fill", unpack(LOVE_LIGHT_SHADOW_GEOMETRY[i])) end end - for i = 1, #LOVE_LIGHT_POLY do - if LOVE_LIGHT_POLY[i].glassAlpha == 1.0 then - love.graphics.polygon("fill", unpack(LOVE_LIGHT_POLY[i].data)) + for i = 1, #LOVE_LIGHT_BODY do + if LOVE_LIGHT_BODY[i].shadowType == "circle" then + love.graphics.circle("fill", LOVE_LIGHT_BODY[i].x - LOVE_LIGHT_BODY[i].ox, LOVE_LIGHT_BODY[i].y - LOVE_LIGHT_BODY[i].oy, LOVE_LIGHT_BODY[i].radius) + elseif LOVE_LIGHT_BODY[i].shadowType == "rectangle" then + love.graphics.rectangle("fill", LOVE_LIGHT_BODY[i].x - LOVE_LIGHT_BODY[i].ox, LOVE_LIGHT_BODY[i].y - LOVE_LIGHT_BODY[i].oy, LOVE_LIGHT_BODY[i].width, LOVE_LIGHT_BODY[i].height) + elseif LOVE_LIGHT_BODY[i].shadowType == "polygon" then + love.graphics.polygon("fill", unpack(LOVE_LIGHT_BODY[i].data)) + elseif LOVE_LIGHT_BODY[i].shadowType == "image" then + --love.graphics.rectangle("fill", LOVE_LIGHT_BODY[i].x - LOVE_LIGHT_BODY[i].ox, LOVE_LIGHT_BODY[i].y - LOVE_LIGHT_BODY[i].oy, LOVE_LIGHT_BODY[i].width, LOVE_LIGHT_BODY[i].height) end - end - for i = 1, #LOVE_LIGHT_CIRCLE do - love.graphics.circle("fill", LOVE_LIGHT_CIRCLE[i].x, LOVE_LIGHT_CIRCLE[i].y, LOVE_LIGHT_CIRCLE[i].radius) end - for i = 1, #LOVE_LIGHT_IMAGE do - --love.graphics.rectangle("fill", LOVE_LIGHT_IMAGE[i].x, LOVE_LIGHT_IMAGE[i].y, LOVE_LIGHT_IMAGE[i].width, LOVE_LIGHT_IMAGE[i].height) - end end polyStencil = function() - for i = 1, #LOVE_LIGHT_CIRCLE do - if LOVE_LIGHT_CIRCLE[i].shine and LOVE_LIGHT_CIRCLE[i].glowStrength == 0.0 then - love.graphics.circle("fill", LOVE_LIGHT_CIRCLE[i].x, LOVE_LIGHT_CIRCLE[i].y, LOVE_LIGHT_CIRCLE[i].radius) + for i = 1, #LOVE_LIGHT_BODY do + if LOVE_LIGHT_BODY[i].shine and (LOVE_LIGHT_BODY[i].glowStrength == 0.0 or (LOVE_LIGHT_BODY[i].type == "image" and not LOVE_LIGHT_BODY[i].normal)) then + if LOVE_LIGHT_BODY[i].shadowType == "circle" then + love.graphics.circle("fill", LOVE_LIGHT_BODY[i].x - LOVE_LIGHT_BODY[i].ox, LOVE_LIGHT_BODY[i].y - LOVE_LIGHT_BODY[i].oy, LOVE_LIGHT_BODY[i].radius) + elseif LOVE_LIGHT_BODY[i].shadowType == "rectangle" then + love.graphics.rectangle("fill", LOVE_LIGHT_BODY[i].x - LOVE_LIGHT_BODY[i].ox, LOVE_LIGHT_BODY[i].y - LOVE_LIGHT_BODY[i].oy, LOVE_LIGHT_BODY[i].width, LOVE_LIGHT_BODY[i].height) + elseif LOVE_LIGHT_BODY[i].shadowType == "polygon" then + love.graphics.polygon("fill", unpack(LOVE_LIGHT_BODY[i].data)) + elseif LOVE_LIGHT_BODY[i].shadowType == "image" then + --love.graphics.rectangle("fill", LOVE_LIGHT_BODY[i].x - LOVE_LIGHT_BODY[i].ox, LOVE_LIGHT_BODY[i].y - LOVE_LIGHT_BODY[i].oy, LOVE_LIGHT_BODY[i].width, LOVE_LIGHT_BODY[i].height) + end end end - for i = 1, #LOVE_LIGHT_POLY do - if LOVE_LIGHT_POLY[i].shine and LOVE_LIGHT_POLY[i].glowStrength == 0.0 then - love.graphics.polygon("fill", unpack(LOVE_LIGHT_POLY[i].data)) - end - end - for i = 1, #LOVE_LIGHT_IMAGE do - if LOVE_LIGHT_IMAGE[i].shine then - --love.graphics.rectangle("fill", LOVE_LIGHT_IMAGE[i].x, LOVE_LIGHT_IMAGE[i].y, LOVE_LIGHT_IMAGE[i].width, LOVE_LIGHT_IMAGE[i].height) - end - end end function HeightMapToNormalMap(heightMap, strength) diff --git a/main.lua b/main.lua index 04436ac..5d64c4e 100644 --- a/main.lua +++ b/main.lua @@ -48,6 +48,8 @@ function love.load() circle = love.graphics.newImage("gfx/circle.png") circle_normal = love.graphics.newImage("gfx/circle_normal.png") cone = love.graphics.newImage("gfx/cone.png") + cone_large = love.graphics.newImage("gfx/cone_large.png") + cone_large_normal = love.graphics.newImage("gfx/cone_large_normal.png") cone_normal = love.graphics.newImage("gfx/cone_normal.png") chest = love.graphics.newImage("gfx/chest.png") chest_normal = love.graphics.newImage("gfx/chest_normal.png") @@ -92,7 +94,7 @@ function love.load() lightOn = true gravityOn = 1 shadowBlur = 2.0 - bloomOn = true + bloomOn = 0.25 textureOn = true normalOn = false glowBlur = 1.0 @@ -189,7 +191,7 @@ function love.update(dt) end if phyLight[i].getType() == "refraction" then --if math.mod(i, 2) == 0 then - phyLight[i].setTileOffset(tileX, tileY) + phyLight[i].setNormalTileOffset(tileX, tileY) --end if offsetChanged then phyLight[i].setPosition(phyLight[i].getX() + (offsetX - offsetOldX), phyLight[i].getY() + (offsetY - offsetOldY)) @@ -272,10 +274,10 @@ function love.draw() if not normalOn then math.randomseed(i) love.graphics.setColor(math.random(127, 255), math.random(127, 255), math.random(127, 255)) - love.graphics.draw(phyLight[i].img, phyLight[i].x - phyLight[i].ox2, phyLight[i].y - phyLight[i].oy2) + love.graphics.draw(phyLight[i].img, phyLight[i].x - phyLight[i].ix, phyLight[i].y - phyLight[i].iy) elseif phyLight[i].normal then love.graphics.setColor(255, 255, 255) - love.graphics.draw(phyLight[i].normal, phyLight[i].x - phyLight[i].ox2, phyLight[i].y - phyLight[i].oy2) + love.graphics.draw(phyLight[i].normal, phyLight[i].x - phyLight[i].nx, phyLight[i].y - phyLight[i].ny) end end end @@ -333,9 +335,9 @@ function love.draw() love.graphics.setColor(255, 0, 0) love.graphics.print("F5: Shadowblur (off)", 4 + 152 * 4, 4) end - if bloomOn then + if bloomOn > 0.0 then love.graphics.setColor(0, 255, 0) - love.graphics.print("F6: Bloom (on)", 4 + 152 * 0, 4 + 20 * 1) + love.graphics.print("F6: Bloom (" .. (bloomOn * 4) .. ")", 4 + 152 * 0, 4 + 20 * 1) else love.graphics.setColor(255, 0, 0) love.graphics.print("F6: Bloom (off)", 4 + 152 * 0, 4 + 20 * 1) @@ -380,14 +382,18 @@ function love.draw() end -- draw shader - if bloomOn then - if colorAberration > 0.0 then - love.postshader.addEffect("blur", 2.0, 2.0) - love.postshader.addEffect("chromatic", math.sin(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * colorAberration, math.sin(lightDirection * 10.0) * -colorAberration, math.sin(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * -colorAberration) - end - love.postshader.addEffect("bloom") - love.postshader.draw() + if colorAberration > 0.0 then + -- vert / horz blur + love.postshader.addEffect("blur", 2.0, 2.0) + love.postshader.addEffect("chromatic", math.sin(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * colorAberration, math.sin(lightDirection * 10.0) * -colorAberration, math.sin(lightDirection * 10.0) * colorAberration, math.cos(lightDirection * 10.0) * -colorAberration) end + + if bloomOn > 0.0 then + -- blur, strength + love.postshader.addEffect("bloom", 2.0, bloomOn) + end + + love.postshader.draw() end function love.mousepressed(x, y, c) @@ -453,7 +459,10 @@ function love.keypressed(k, u) end lightWorld.setBlur(shadowBlur) elseif k == "f6" or k == "b" then - bloomOn = not bloomOn + bloomOn = math.max(0.25, bloomOn * 2.0) + if bloomOn > 1.0 then + bloomOn = 0.0 + end elseif k == "f7" then textureOn = not textureOn elseif k == "f8" then @@ -466,7 +475,7 @@ function love.keypressed(k, u) lightWorld.setGlowStrength(glowBlur) elseif k == "f11" then physicWorld:destroy() - lightWorld.clearObjects() + lightWorld.clearBodys() initScene() elseif k == "f12" then lightWorld.clearLights() @@ -478,6 +487,7 @@ function love.keypressed(k, u) phyCnt = phyCnt + 1 phyLight[phyCnt] = lightWorld.newImage(circle, mx, my) phyLight[phyCnt].setNormalMap(circle_normal) + phyLight[phyCnt].setShadowType("circle", 16) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 32, 32) phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) @@ -485,8 +495,9 @@ function love.keypressed(k, u) elseif k == "2" then -- add image phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(cone, mx, my, 24, 12, 12, 28) + phyLight[phyCnt] = lightWorld.newImage(cone, mx, my, 24, 12, 12, 16) phyLight[phyCnt].setNormalMap(cone_normal) + --phyLight[phyCnt].setShadowType("circle", 12, 0, -8) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 24, 32) phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) @@ -494,7 +505,7 @@ function love.keypressed(k, u) elseif k == "3" then -- add image phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(chest, mx, my, 32, 24, 16, 36) + phyLight[phyCnt] = lightWorld.newImage(chest, mx, my, 32, 24, 16, 0) phyLight[phyCnt].setNormalMap(chest_normal) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 32, 24) @@ -502,10 +513,10 @@ function love.keypressed(k, u) phyFixture[phyCnt]:setRestitution(0.5) elseif k == "4" then -- add glow image - local r = lightWorld.getImageCount() % 5 + local r = lightWorld.getBodyCount() % 5 if r == 0 then phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(machine, mx, my, 32, 24, 16, 36) + phyLight[phyCnt] = lightWorld.newImage(machine, mx, my, 32, 24, 16, 0) phyLight[phyCnt].setNormalMap(machine_normal) phyLight[phyCnt].setGlowMap(machine_glow) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") @@ -514,7 +525,7 @@ function love.keypressed(k, u) phyFixture[phyCnt]:setRestitution(0.5) elseif r == 1 then phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(machine2, mx, my, 24, 12, 12, 28) + phyLight[phyCnt] = lightWorld.newImage(machine2, mx, my, 24, 12, 12, -4) phyLight[phyCnt].setNormalMap(machine2_normal) phyLight[phyCnt].setGlowMap(machine2_glow) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") @@ -523,7 +534,7 @@ function love.keypressed(k, u) phyFixture[phyCnt]:setRestitution(0.5) elseif r == 2 then phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(led, mx, my, 32, 6, 16, 27) + phyLight[phyCnt] = lightWorld.newImage(led, mx, my, 32, 6, 16, -8) phyLight[phyCnt].setNormalMap(led_normal) phyLight[phyCnt].setGlowMap(led_glow) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") @@ -532,7 +543,7 @@ function love.keypressed(k, u) phyFixture[phyCnt]:setRestitution(0.5) elseif r == 3 then phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(led2, mx, my, 32, 6, 16, 27) + phyLight[phyCnt] = lightWorld.newImage(led2, mx, my, 32, 6, 16, -8) phyLight[phyCnt].setNormalMap(led_normal) phyLight[phyCnt].setGlowMap(led_glow2) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") @@ -541,7 +552,7 @@ function love.keypressed(k, u) phyFixture[phyCnt]:setRestitution(0.5) elseif r == 4 then phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(led3, mx, my, 32, 6, 16, 27) + phyLight[phyCnt] = lightWorld.newImage(led3, mx, my, 32, 6, 16, -8) phyLight[phyCnt].setNormalMap(led_normal) phyLight[phyCnt].setGlowMap(led_glow3) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") @@ -552,9 +563,9 @@ function love.keypressed(k, u) elseif k == "5" then -- add image phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(machine2, mx, my, 24, 12, 12, 28) - phyLight[phyCnt].setNormalMap(machine2_normal) - phyLight[phyCnt].setGlowMap(machine2_glow) + phyLight[phyCnt] = lightWorld.newImage(cone_large, mx, my, 24, 128, 12, 64) + phyLight[phyCnt].setNormalMap(cone_large_normal) + phyLight[phyCnt].setShadowType("image", 0, -6, 0.0) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 24, 32) phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) @@ -562,7 +573,7 @@ function love.keypressed(k, u) elseif k == "6" then -- add image phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(blopp, mx, my, 42, 16, 21, 20) + phyLight[phyCnt] = lightWorld.newImage(blopp, mx, my, 42, 16, 21, 0) phyLight[phyCnt].generateNormalMapGradient("gradient", "gradient") phyLight[phyCnt].setAlpha(0.5) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") @@ -615,6 +626,7 @@ function love.keypressed(k, u) elseif k == "0" then phyCnt = phyCnt + 1 phyLight[phyCnt] = lightWorld.newRefraction(refraction_normal, mx, my) + phyLight[phyCnt].setReflection(true) elseif k == "l" then -- add light local r = lightWorld.getLightCount() % 3 diff --git a/main_example.lua b/main_example.lua deleted file mode 100644 index 80f10c3..0000000 --- a/main_example.lua +++ /dev/null @@ -1,40 +0,0 @@ -require "light" - -function love.load() - -- create light world - lightWorld = love.light.newWorld() - lightWorld.setAmbientColor(15, 15, 31) - - -- create light - lightMouse = lightWorld.newLight(0, 0, 255, 127, 63, 300) - lightMouse.setGlowStrength(0.3) - - -- create shadow bodys - circleTest = lightWorld.newCircle(256, 256, 32) - rectangleTest = lightWorld.newRectangle(512, 512, 64, 64) -end - -function love.update(dt) - love.window.setTitle("Light vs. Shadow Engine (FPS:" .. love.timer.getFPS() .. ")") - lightMouse.setPosition(love.mouse.getX(), love.mouse.getY()) -end - -function love.draw() - -- update lightmap (doesn't need deltatime) - lightWorld.update() - - -- draw background - love.graphics.setColor(255, 255, 255) - love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) - - -- draw lightmap shadows - lightWorld.drawShadow() - - -- draw scene objects - love.graphics.setColor(63, 255, 127) - love.graphics.circle("fill", circleTest.getX(), circleTest.getY(), circleTest.getRadius()) - love.graphics.polygon("fill", rectangleTest.getPoints()) - - -- draw lightmap shine - lightWorld.drawShine() -end \ No newline at end of file diff --git a/postshader.lua b/postshader.lua index 28aaa3d..81361c3 100644 --- a/postshader.lua +++ b/postshader.lua @@ -27,6 +27,8 @@ love.postshader.addEffect = function(shader, ...) if shader == "bloom" then -- Bloom Shader + LOVE_POSTSHADER_BLURV:send("steps", args[1] or 2.0) + LOVE_POSTSHADER_BLURH:send("steps", args[1] or 2.0) love.graphics.setCanvas(LOVE_POSTSHADER_BUFFER_BACK) love.graphics.setBlendMode("alpha") @@ -44,7 +46,7 @@ love.postshader.addEffect = function(shader, ...) love.graphics.setColor(255, 255, 255) love.graphics.draw(LOVE_POSTSHADER_BUFFER_RENDER) love.graphics.setBlendMode("additive") - love.graphics.setColor(255, 255, 255, 63) + love.graphics.setColor(255, 255, 255, (args[2] or 0.25) * 255) love.graphics.draw(LOVE_POSTSHADER_BUFFER_BACK) love.graphics.setBlendMode("alpha") elseif shader == "blur" then diff --git a/shader/refraction.glsl b/shader/refraction.glsl index c6b4d24..7dc534f 100644 --- a/shader/refraction.glsl +++ b/shader/refraction.glsl @@ -2,13 +2,17 @@ extern Image backBuffer; extern vec2 screen = vec2(800.0, 600.0); extern float refractionStrength = 1.0; -extern vec3 refractionColor = vec3(1.0, 1.0, 1.0); vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) { vec2 pSize = vec2(1.0 / screen.x, 1.0 / screen.y); vec4 normal = Texel(texture, texture_coords); - if(normal.b > 0.0) { - return vec4(Texel(backBuffer, vec2(texture_coords.x + (normal.x - 0.5) * pSize.x * refractionStrength, texture_coords.y + (normal.y - 0.5) * pSize.y * refractionStrength)).rgb * refractionColor, 1.0); + if(normal.a > 0.0) { + vec4 normalOffset = Texel(texture, vec2(texture_coords.x + (normal.x - 0.5) * pSize.x * refractionStrength, texture_coords.y + (normal.y - 0.5) * pSize.y * refractionStrength)); + if(normalOffset.a > 0.0) { + return Texel(backBuffer, vec2(texture_coords.x + (normal.x - 0.5) * pSize.x * refractionStrength, texture_coords.y + (normal.y - 0.5) * pSize.y * refractionStrength)); + } else { + return Texel(backBuffer, texture_coords); + } } else { return vec4(0.0); }