commit d1b1b3e0fa04304b4e5de5685727bd2667790bc4 Author: Marcus Ihde Date: Tue Mar 4 14:52:51 2014 +0100 Init project diff --git a/conf.lua b/conf.lua new file mode 100644 index 0000000..87841a8 --- /dev/null +++ b/conf.lua @@ -0,0 +1,35 @@ +function love.conf(t) + t.identity = nil -- The name of the save directory (string) + t.version = "0.9.0" -- The LÖVE version this game was made for (string) + t.console = true -- Attach a console (boolean, Windows only) + + t.window.title = "Untitled" -- The window title (string) + t.window.icon = nil -- Filepath to an image to use as the window's icon (string) + t.window.width = 800 -- The window width (number) + t.window.height = 600 -- The window height (number) + t.window.borderless = false -- Remove all border visuals from the window (boolean) + t.window.resizable = false -- Let the window be user-resizable (boolean) + t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) + t.window.minheight = 1 -- Minimum window height if the window is resizable (number) + t.window.fullscreen = false -- Enable fullscreen (boolean) + t.window.fullscreentype = "normal" -- Standard fullscreen or desktop fullscreen mode (string) + t.window.vsync = false -- Enable vertical sync (boolean) + t.window.fsaa = 0 -- The number of samples to use with multi-sampled antialiasing (number) + t.window.display = 1 -- Index of the monitor to show the window in (number) + t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean). Added in 0.9.1 + t.window.srgb = false -- Enable sRGB gamma correction when drawing to the screen (boolean). Added in 0.9.1 + + t.modules.audio = true -- Enable the audio module (boolean) + t.modules.event = true -- Enable the event module (boolean) + t.modules.graphics = true -- Enable the graphics module (boolean) + t.modules.image = true -- Enable the image module (boolean) + t.modules.joystick = true -- Enable the joystick module (boolean) + t.modules.keyboard = true -- Enable the keyboard module (boolean) + t.modules.math = true -- Enable the math module (boolean) + t.modules.mouse = true -- Enable the mouse module (boolean) + t.modules.physics = true -- Enable the physics module (boolean) + t.modules.sound = true -- Enable the sound module (boolean) + t.modules.system = true -- Enable the system module (boolean) + t.modules.timer = true -- Enable the timer module (boolean) + t.modules.window = true -- Enable the window module (boolean) +end \ No newline at end of file diff --git a/floor.png b/floor.png new file mode 100644 index 0000000..f11b5fa Binary files /dev/null and b/floor.png differ diff --git a/light.lua b/light.lua new file mode 100644 index 0000000..525594f --- /dev/null +++ b/light.lua @@ -0,0 +1,557 @@ +LOVE_LIGHT_CURRENT = nil +LOVE_LIGHT_CIRCLE = nil +LOVE_LIGHT_POLY = nil +LOVE_LIGHT_LAST_BUFFER = nil + +LOVE_LIGHT_BLURV = love.graphics.newShader("shader/blurv.glsl") +LOVE_LIGHT_BLURH = love.graphics.newShader("shader/blurh.glsl") + +love.light = {} + +-- light world +function love.light.newWorld() + local o = {} + o.lights = {} + o.ambient = {0, 0, 0} + o.poly = {} + o.circle = {} + o.shadow = love.graphics.newCanvas() + o.shine = love.graphics.newCanvas() + o.shader = love.graphics.newShader("shader/light.glsl") + o.changed = true + o.blur = true + -- update + o.update = function() + LOVE_LIGHT_LAST_BUFFER = love.graphics.getCanvas() + love.graphics.setShader(o.shader) + if o.changed then + love.graphics.setCanvas(o.shadow) + o.shadow:clear(unpack(o.ambient)) + love.graphics.setBlendMode("additive") + else + love.graphics.setColor(255,255,255) + love.graphics.setBlendMode("alpha") + end + + local lightsOnScreen = 0 + LOVE_LIGHT_POLY = o.poly + LOVE_LIGHT_CIRCLE = o.circle + for i = 1, #o.lights do + if o.lights[i].changed or o.changed then + local curLightX = o.lights[i].x + local curLightY = o.lights[i].y + local curLightRange = o.lights[i].range + local curLightColor = { + o.lights[i].red / 255.0, + o.lights[i].green / 255.0, + o.lights[i].blue / 255.0 + } + local curLightSmooth = o.lights[i].smooth + local curLightGlow = { + 1.0 - o.lights[i].glowSize, + o.lights[i].glowStrength + } + + if curLightX+curLightRange > 0 and curLightX-curLightRange < love.graphics.getWidth() + and curLightY+curLightRange > 0 and curLightY-curLightRange < love.graphics.getHeight() + then + local lightposrange = {curLightX, love.graphics.getHeight() - curLightY, curLightRange} + LOVE_LIGHT_CURRENT = o.lights[i] + o.shader:send("lightPositionRange", lightposrange) + o.shader:send("lightColor", curLightColor) + o.shader:send("smooth", curLightSmooth) + o.shader:send("glow", curLightGlow) + + if o.changed then + love.graphics.setCanvas(o.shadow) + else + love.graphics.setCanvas(o.lights[i].shadow) + love.graphics.clear() + end + + -- draw shadow + love.graphics.setInvertedStencil(shadowStencil) + love.graphics.setBlendMode("additive") + love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) + + -- draw shine + love.graphics.setCanvas(o.lights[i].shine) + o.lights[i].shine:clear(255, 255, 255) + love.graphics.setBlendMode("alpha") + love.graphics.setStencil(polyStencil) + love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) + + lightsOnScreen = lightsOnScreen + 1 + end + + o.lights[i].changed = o.changed + end + end + + 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", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) + love.graphics.setColor(255, 255, 255) + love.graphics.setBlendMode("additive") + for i = 1, #o.lights do + love.graphics.draw(o.lights[i].shadow) + end + end + + love.graphics.setCanvas(o.shine) + love.graphics.setColor(0,0,0) + love.graphics.setBlendMode("alpha") + love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) + love.graphics.setColor(255,255,255) + love.graphics.setBlendMode("additive") + for i = 1, #o.lights do + love.graphics.draw(o.lights[i].shine) + end + + love.graphics.setShader() + love.graphics.setBlendMode("alpha") + love.graphics.setStencil() + love.graphics.setCanvas(LOVE_LIGHT_LAST_BUFFER) + + o.changed = false + end + -- draw shadow + o.drawShadow = function() + love.graphics.setColor(255, 255, 255) + if o.blur then + LOVE_LIGHT_LAST_BUFFER = love.graphics.getCanvas() + love.graphics.setBlendMode("alpha") + love.graphics.setCanvas(o.shadow) + love.graphics.setShader(LOVE_LIGHT_BLURV) + love.graphics.draw(o.shadow) + love.graphics.setShader(LOVE_LIGHT_BLURH) + love.graphics.draw(o.shadow) + love.graphics.setCanvas(LOVE_LIGHT_LAST_BUFFER) + love.graphics.setBlendMode("multiplicative") + love.graphics.setShader() + love.graphics.draw(o.shadow) + love.graphics.setBlendMode("alpha") + else + love.graphics.setBlendMode("multiplicative") + love.graphics.setShader() + love.graphics.draw(o.shadow) + love.graphics.setBlendMode("alpha") + end + end + + -- draw shine + o.drawShine = function() + love.graphics.setColor(255, 255, 255) + love.graphics.setBlendMode("multiplicative") + love.graphics.setShader() + love.graphics.draw(o.shine) + love.graphics.setBlendMode("alpha") + end + -- new light + o.newLight = function(x, y, red, green, blue, range) + o.lights[#o.lights + 1] = love.light.newLight(o, x, y, red, green, blue, range) + + return o.lights[#o.lights] + end + -- clear lights + o.clearLights = function() + o.lights = {} + end + -- clear objects + o.clearObjects = function() + o.poly = {} + o.circle = {} + end + -- set ambient color + o.setAmbientColor = function(red, green, blue) + o.ambient = {red, green, blue} + end + -- set ambient red + o.setAmbientRed = function(red) + o.ambient[1] = red + end + -- set ambient green + o.setAmbientGreen = function(green) + o.ambient[2] = green + end + -- set ambient blue + o.setAmbientBlue = function(blue) + o.ambient[3] = blue + end + -- set blur + o.setBlur = function(blur) + o.blur = blur + o.changed = true + end + -- new rectangle + o.newRectangle = function(x, y, w, h) + return love.light.newRectangle(o, x, y, w, h) + end + -- new circle + o.newCircle = function(x, y, r) + return love.light.newCircle(o, x, y, r) + end + -- new polygon + o.newPolygon = function(...) + return love.light.newPolygon(o, ...) + end + -- set polygon data + o.setPoints = function(n, ...) + o.poly[n].data = {...} + end + -- get circle count + o.getCircleCount = function() + return #o.circle + end + -- get polygon count + o.getPolygonCount = function() + return #o.poly + end + -- get polygon + o.getPoints = function(n) + return unpack(o.poly[n].data) + end + -- get light count + o.getLightCount = function() + return #o.lights + end + -- get light x position + o.getLightX = function(n) + return o.lights[n].x + end + -- get light y position + o.getLightY = function(n) + return o.lights[n].y + end + + return o +end + +-- light object +function love.light.newLight(p, x, y, red, green, blue, range) + local o = {} + o.shadow = love.graphics.newCanvas() + o.shine = love.graphics.newCanvas() + o.x = x + o.y = y + o.red = red + o.green = green + o.blue = blue + o.range = range + o.smooth = 1.0 + o.glowSize = 0.1 + o.glowStrength = 0.0 + o.changed = true + -- set position + o.setPosition = function(x, y) + if x ~= o.x or y ~= o.y then + o.x = x + o.y = y + o.changed = true + end + end + -- set color + o.setColor = function(red, green, blue) + o.red = red + o.green = green + o.blue = blue + --p.changed = true + end + -- set range + o.setRange = function(range) + if range ~= o.range then + o.range = range + o.changed = true + end + end + -- set glow size + o.setSmooth = function(smooth) + o.smooth = smooth + o.changed = true + end + -- set glow size + o.setGlowSize = function(size) + o.glowSize = size + o.changed = true + end + -- set glow strength + o.setGlowStrength = function(strength) + o.glowStrength = strength + o.changed = true + end + -- get type + o.getType = function() + return "light" + end + + return o +end + +-- rectangle object +function love.light.newRectangle(p, x, y, w, h) + local o = {} + p.poly[#p.poly + 1] = o + o.id = #p.poly + o.x = x + o.y = y + o.w = w + o.h = h + o.ox = w / 2 + o.oy = h / 2 + o.shine = true + p.changed = true + o.data = { + o.x - o.ox, + o.y - o.oy, + o.x - o.ox + o.w, + o.y - o.oy, + o.x - o.ox + o.w, + o.y - o.oy + o.h, + o.x - o.ox, + o.y - o.oy + o.h + } + -- 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.w + o.data[4] = o.y - o.oy + o.data[5] = o.x - o.ox + o.w + o.data[6] = o.y - o.oy + o.h + o.data[7] = o.x - o.ox + o.data[8] = o.y - o.oy + o.h + 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 dimension + o.setDimension = function(w, h) + o.w = w + o.h = h + 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 + -- get type + o.getType = function() + return "rectangle" + 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 + o.y = y + o.radius = radius + o.shine = true + 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 radius + o.setRadius = function(radius) + if radius ~= o.radius then + o.radius = radius + p.changed = true + end + 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 "circle" + 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 + 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 + -- get polygon data + o.getPoints = function() + return unpack(o.data) + end + -- get type + o.getType = function() + return "polygon" + end + + return o +end + +-- vector functions +function normalize(v) + local len = math.sqrt(math.pow(v[1], 2) + math.pow(v[2], 2)) + local normalizedv = {v[1] / len, v[2] / len} + return normalizedv +end + +function dot(v1, v2) + return v1[1] * v2[1] + v1[2] * v2[2] +end + +function lengthSqr(v) + return v[1] * v[1] + v[2] * v[2] +end + +function length(v) + return math.sqrt(lengthSqr(v)) +end + +function calculateShadows(lightsource, geometry, circle) + 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} + + 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 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 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 + + elseif not curFacing 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 + 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 + 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 + shadowGeometry[#shadowGeometry + 1] = curShadowGeometry + end + + return shadowGeometry +end + +shadowStencil = function() + local shadowGeometry = calculateShadows(LOVE_LIGHT_CURRENT, LOVE_LIGHT_POLY, LOVE_LIGHT_CIRCLE) + for i=1,#shadowGeometry do + love.graphics.polygon("fill", unpack(shadowGeometry[i])) + end + for i=1, #LOVE_LIGHT_POLY do + love.graphics.polygon("fill", unpack(LOVE_LIGHT_POLY[i].data)) + end + for i=1, #LOVE_LIGHT_CIRCLE do + love.graphics.circle("fill", LOVE_LIGHT_CIRCLE[i].getX(), LOVE_LIGHT_CIRCLE[i].getY(), LOVE_LIGHT_CIRCLE[i].getRadius()) + end +end + +polyStencil = function() + for i=1, #LOVE_LIGHT_POLY do + if LOVE_LIGHT_POLY[i].shine then + love.graphics.polygon("fill", unpack(LOVE_LIGHT_POLY[i].data)) + end + end + for i=1, #LOVE_LIGHT_CIRCLE do + if LOVE_LIGHT_CIRCLE[i].shine then + love.graphics.circle("fill", LOVE_LIGHT_CIRCLE[i].getX(), LOVE_LIGHT_CIRCLE[i].getY(), LOVE_LIGHT_CIRCLE[i].getRadius()) + end + end +end \ No newline at end of file diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..c35104e --- /dev/null +++ b/main.lua @@ -0,0 +1,236 @@ +require "postshader" +require "light" + +function initScene() + -- physic world + physicWorld = love.physics.newWorld(0, 9.81 * 64, true) + wall1 = {} + wall1.body = love.physics.newBody(physicWorld, 400, 605, "static") + wall1.shape = love.physics.newRectangleShape(0, 0, 800, 10) + wall1.fixture = love.physics.newFixture(wall1.body, wall1.shape) + + wall2 = {} + wall2.body = love.physics.newBody(physicWorld, -5, 300, "static") + wall2.shape = love.physics.newRectangleShape(0, 0, 10, 600) + wall2.fixture = love.physics.newFixture(wall2.body, wall2.shape) + + wall3 = {} + wall3.body = love.physics.newBody(physicWorld, 805, 300, "static") + wall3.shape = love.physics.newRectangleShape(0, 0, 10, 600) + wall3.fixture = love.physics.newFixture(wall3.body, wall3.shape) + + wall4 = {} + wall4.body = love.physics.newBody(physicWorld, 400, -5, "static") + wall4.shape = love.physics.newRectangleShape(0, 0, 800, 10) + wall4.fixture = love.physics.newFixture(wall4.body, wall4.shape) + + myPoly1 = lightWorld.newPolygon(wall1.body:getWorldPoints(wall1.shape:getPoints())) + myPoly2 = lightWorld.newPolygon(wall2.body:getWorldPoints(wall2.shape:getPoints())) + myPoly3 = lightWorld.newPolygon(wall3.body:getWorldPoints(wall3.shape:getPoints())) + myPoly4 = lightWorld.newPolygon(wall4.body:getWorldPoints(wall4.shape:getPoints())) + + phyCnt = 0 + phyLight = {} + phyBody = {} + phyShape = {} + phyFixture = {} +end + +function love.load() + love.graphics.setBackgroundColor(0, 0, 0) + quadScreen = love.graphics.newQuad(0, 0, love.window.getWidth(), love.window.getHeight(), 32, 32) + imgFloor = love.graphics.newImage("floor.png") + imgFloor:setWrap("repeat", "repeat") + + -- light world + lightRange = 400 + lightSmooth = 1.0 + lightWorld = love.light.newWorld() + lightWorld.setAmbientColor(15, 15, 15) + mouseLight = lightWorld.newLight(0, 0, 255, 127, 63, lightRange) + mouseLight.setGlowStrength(0.3) + + -- init physic world + initScene() + + helpOn = true + physicOn = true + lightOn = true + gravityOn = 1 + shadowBlurOn = true + bloomOn = true + textureOn = true +end + +function love.update(dt) + love.window.setTitle("FPS:" .. love.timer.getFPS()) + mouseLight.setPosition(love.mouse.getX(), love.mouse.getY()) + + for i = 1, phyCnt do + if phyBody[i]:isAwake() then + if phyShape[i]:getType() == "polygon" then + phyLight[i].setPoints(phyBody[i]:getWorldPoints(phyShape[i]:getPoints())) + else + phyLight[i].setPosition(phyBody[i]:getX(), phyBody[i]:getY()) + end + end + end + + if love.keyboard.isDown("w") then + for i = 1, phyCnt do + phyBody[i]:applyForce(0, -2000) + end + elseif love.keyboard.isDown("s") then + for i = 1, phyCnt do + phyBody[i]:applyForce(0, 2000) + end + end + + if love.keyboard.isDown("a") then + for i = 1, phyCnt do + phyBody[i]:applyForce(-2000, 0) + end + elseif love.keyboard.isDown("d") then + for i = 1, phyCnt do + phyBody[i]:applyForce(2000, 0) + end + end + + if physicOn then + physicWorld:update(dt) + end + + -- update lightmap + if lightOn then + lightWorld.update(dt) + end +end + +function love.draw() + -- set shader buffer + if bloomOn then + love.postshader.setBuffer("render") + end + + love.graphics.setBlendMode("alpha") + love.graphics.setColor(255, 255, 255) + if textureOn then + love.graphics.draw(imgFloor, quadScreen) + else + love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight()) + end + -- draw lightmap shadows + if lightOn then + lightWorld.drawShadow() + end + + for i = 1, phyCnt do + love.graphics.setColor(math.sin(i) * 255, math.cos(i) * 255, math.tan(i) * 255) + if phyLight[i].getType() == "polygon" then + love.graphics.polygon("fill", phyLight[i].getPoints()) + else + love.graphics.circle("fill", phyLight[i].getX(), phyLight[i].getY(), phyLight[i].getRadius()) + end + end + + -- draw lightmap shine + if lightOn then + lightWorld.drawShine() + end + + -- draw help + if helpOn then + love.graphics.setColor(0, 0, 0, 191) + love.graphics.rectangle("fill", 8, 8, 210, 16 * 15) + love.graphics.setColor(255, 255, 255) + love.graphics.print("WASD: Move objects", 16, 16) + love.graphics.print("F1: Help on/off", 16, 32) + love.graphics.print("F2: Physic on/off", 16, 48) + love.graphics.print("F3: Light on/off", 16, 64) + love.graphics.print("F4: Clear objects", 16, 80) + love.graphics.print("F5: Clear lights", 16, 96) + love.graphics.print("F6: Gravity on/off", 16, 112) + love.graphics.print("F7: Shadowblur on/off", 16, 128) + love.graphics.print("F8: Bloom on/off", 16, 144) + love.graphics.print("F9: Texture on/off", 16, 160) + love.graphics.print("M.left: Add cube", 16, 176) + love.graphics.print("M.middle: Add light", 16, 192) + love.graphics.print("M.right: Add circle", 16, 208) + love.graphics.print("M.scroll: Change smooth", 16, 224) + end + + -- draw shader + if bloomOn then + love.postshader.draw("bloom") + end +end + +function love.mousepressed(x, y, c) + if c == "m" then + -- add light + local r = lightWorld.getLightCount() % 3 + local light + + if r == 0 then + light = lightWorld.newLight(x, y, 31, 127, 63, lightRange) + elseif r == 1 then + light = lightWorld.newLight(x, y, 127, 63, 31, lightRange) + else + light = lightWorld.newLight(x, y, 31, 63, 127, lightRange) + end + light.setSmooth(lightSmooth) + light.setGlowStrength(0.3) + elseif c == "l" then + -- add rectangle + phyCnt = phyCnt + 1 + phyLight[phyCnt] = lightWorld.newPolygon() + phyBody[phyCnt] = love.physics.newBody(physicWorld, x, y, "dynamic") + phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, math.random(32, 64), math.random(32, 64)) + phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) + phyFixture[phyCnt]:setRestitution(0.5) + elseif c == "r" then + -- add circle + cRadius = math.random(8, 32) + phyCnt = phyCnt + 1 + phyLight[phyCnt] = lightWorld.newCircle(x, y, cRadius) + phyBody[phyCnt] = love.physics.newBody(physicWorld, x, y, "dynamic") + phyShape[phyCnt] = love.physics.newCircleShape(0, 0, cRadius) + phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) + phyFixture[phyCnt]:setRestitution(0.5) + elseif c == "wu" then + lightSmooth = lightSmooth * 1.1 + mouseLight.setSmooth(lightSmooth) + elseif c == "wd" then + lightSmooth = lightSmooth / 1.1 + mouseLight.setSmooth(lightSmooth) + end +end + +function love.keypressed(k, u) + -- debug options + if k == "f1" then + helpOn = not helpOn + elseif k == "f2" then + physicOn = not physicOn + elseif k == "f3" then + lightOn = not lightOn + elseif k == "f4" then + physicWorld:destroy() + lightWorld.clearObjects() + initScene() + elseif k == "f5" then + lightWorld.clearLights() + mouseLight = lightWorld.newLight(0, 0, 127, 63, 0, lightRange) + mouseLight.setGlowStrength(0.3) + elseif k == "f6" then + gravityOn = 1 - gravityOn + physicWorld:setGravity(0, gravityOn * 9.81 * 64) + elseif k == "f7" then + shadowBlurOn = not shadowBlurOn + lightWorld.setBlur(shadowBlurOn) + elseif k == "f8" then + bloomOn = not bloomOn + elseif k == "f9" then + textureOn = not textureOn + end +end \ No newline at end of file diff --git a/postshader.lua b/postshader.lua new file mode 100644 index 0000000..0d8db31 --- /dev/null +++ b/postshader.lua @@ -0,0 +1,63 @@ +LOVE_POSTSHADER_BUFFER_RENDER = love.graphics.newCanvas() +LOVE_POSTSHADER_BUFFER_BACK = love.graphics.newCanvas() +LOVE_POSTSHADER_LAST_BUFFER = nil + +LOVE_POSTSHADER_BLURV = love.graphics.newShader("shader/blurv.glsl") +LOVE_POSTSHADER_BLURH = love.graphics.newShader("shader/blurh.glsl") +LOVE_POSTSHADER_CONTRAST = love.graphics.newShader("shader/contrast.glsl") + +LOVE_POSTSHADER_BLURV:send("screen", {love.window.getWidth(), love.window.getHeight()}) +LOVE_POSTSHADER_BLURH:send("screen", {love.window.getWidth(), love.window.getHeight()}) + +love.postshader = {} + +love.postshader.setBuffer = function(path) + if path == "back" then + love.graphics.setCanvas(LOVE_POSTSHADER_BUFFER_BACK) + else + love.graphics.setCanvas(LOVE_POSTSHADER_BUFFER_RENDER) + end +end + +love.postshader.draw = function(shader) + LOVE_POSTSHADER_LAST_BUFFER = love.graphics.getCanvas() + + if shader == "bloom" then + -- Bloom Shader + love.graphics.setCanvas(LOVE_POSTSHADER_BUFFER_BACK) + love.graphics.setBlendMode("alpha") + + love.graphics.setShader(LOVE_POSTSHADER_BLURV) + love.graphics.draw(LOVE_POSTSHADER_BUFFER_RENDER) + + love.graphics.setShader(LOVE_POSTSHADER_BLURH) + love.graphics.draw(LOVE_POSTSHADER_BUFFER_BACK) + + love.graphics.setShader(LOVE_POSTSHADER_CONTRAST) + love.graphics.draw(LOVE_POSTSHADER_BUFFER_BACK) + + love.graphics.setCanvas(LOVE_LIGHTMAP_LAST_BUFFER) + love.graphics.setShader() + 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.draw(LOVE_POSTSHADER_BUFFER_BACK) + love.graphics.setBlendMode("alpha") + elseif shader == "blur" then + -- Blur Shader + love.graphics.setCanvas(LOVE_POSTSHADER_BUFFER_BACK) + love.graphics.setBlendMode("alpha") + + love.graphics.setShader(LOVE_POSTSHADER_BLURV) + love.graphics.draw(LOVE_POSTSHADER_BUFFER_RENDER) + + love.graphics.setShader(LOVE_POSTSHADER_BLURH) + love.graphics.draw(LOVE_POSTSHADER_BUFFER_BACK) + + love.graphics.setCanvas(LOVE_LIGHTMAP_LAST_BUFFER) + love.graphics.setShader() + love.graphics.setColor(255, 255, 255) + love.graphics.draw(LOVE_POSTSHADER_BUFFER_BACK) + end +end \ No newline at end of file diff --git a/shader/blurh.glsl b/shader/blurh.glsl new file mode 100644 index 0000000..275c6bd --- /dev/null +++ b/shader/blurh.glsl @@ -0,0 +1,14 @@ +extern vec2 screen = vec2(800.0, 600.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 col = Texel(texture, texture_coords); + col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y - pSize.y)); + col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y + pSize.y)); + col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y - pSize.y * 2)); + col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y + pSize.y * 2)); + col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y - pSize.y * 3)); + col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y + pSize.y * 3)); + col = col / 7.0; + return vec4(col.r, col.g, col.b, 1.0); +} \ No newline at end of file diff --git a/shader/blurv.glsl b/shader/blurv.glsl new file mode 100644 index 0000000..645acc4 --- /dev/null +++ b/shader/blurv.glsl @@ -0,0 +1,14 @@ +extern vec2 screen = vec2(800.0, 600.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 col = Texel(texture, texture_coords); + col = col + Texel(texture, vec2(texture_coords.x - pSize.x, texture_coords.y)); + col = col + Texel(texture, vec2(texture_coords.x + pSize.x, texture_coords.y)); + col = col + Texel(texture, vec2(texture_coords.x - pSize.x * 2, texture_coords.y)); + col = col + Texel(texture, vec2(texture_coords.x + pSize.x * 2, texture_coords.y)); + col = col + Texel(texture, vec2(texture_coords.x - pSize.x * 3, texture_coords.y)); + col = col + Texel(texture, vec2(texture_coords.x + pSize.x * 3, texture_coords.y)); + col = col / 7.0; + return vec4(col.r, col.g, col.b, 1.0); +} \ No newline at end of file diff --git a/shader/contrast.glsl b/shader/contrast.glsl new file mode 100644 index 0000000..066a794 --- /dev/null +++ b/shader/contrast.glsl @@ -0,0 +1,6 @@ +vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) +{ + vec3 col = Texel(texture, texture_coords).rgb * 2.0; + col *= col; + return vec4(col, 1.0); +} \ No newline at end of file diff --git a/shader/light.glsl b/shader/light.glsl new file mode 100644 index 0000000..93fb397 --- /dev/null +++ b/shader/light.glsl @@ -0,0 +1,23 @@ +extern vec3 lightPositionRange; +extern vec3 lightColor; +extern float smooth = 1.0; +extern vec2 glow = vec2(0.95, 0.2); + +vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){ + vec4 pixel = Texel(texture, texture_coords); + vec2 lightToPixel = pixel_coords - lightPositionRange.xy; + float distance = length(lightToPixel); + float att = 1 - distance / lightPositionRange.z; + + if (distance <= lightPositionRange.z) { + if (glow.x < 1.0 && glow.y > 0.0) { + pixel.rgb = lightColor * pow(att, smooth) + pow(smoothstep(glow.x, 1.0, att), smooth) * glow.y; + } else { + pixel.rgb = lightColor * pow(att, smooth); + } + } else { + pixel.rgb = vec3(0, 0, 0); + } + + return pixel; +} \ No newline at end of file