This commit is contained in:
Paul Liverman
2014-10-25 22:05:49 -07:00
parent b426edc1f1
commit b3df40f76c
38 changed files with 2690 additions and 0 deletions

2
run.bat Normal file
View File

@@ -0,0 +1,2 @@
@ECHO OFF
"C:\Program Files\LOVE\love.exe" "%cd%/src"

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

35
src/conf.lua Normal file
View File

@@ -0,0 +1,35 @@
function love.conf(t)
t.identity = "Thompson Was a Clone"
--t.title = "Thompson Was a Clone"
--t.author = "Guard13007"
t.version = "0.9.1"
t.console = false
t.window.title = "Thompson Was a Clone"
--t.window.icon = nil
t.window.width = 800
t.window.height = 450
t.window.borderless = false
t.window.resizable = false
t.window.fullscreen = false
--t.window.vsync = false
t.window.fsaa = 0
t.window.display = 1
t.window.highdpi = false
t.window.srgb = false
t.modules.audio = true
t.modules.event = true
t.modules.graphics = true
t.modules.image = true
t.modules.joystick = false --may change?
t.modules.keyboard = true
t.modules.math = true --may change ?
t.modules.mouse = true
t.modules.physics = false
t.modules.sound = true
t.modules.system = true
t.modules.timer = true
t.modules.window = true
end

651
src/lib/body.lua Normal file
View File

@@ -0,0 +1,651 @@
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
local class = require(_PACKAGE.."/class")
local normal_map = require(_PACKAGE..'/normal_map')
local vector = require(_PACKAGE..'/vector')
local shadowLength = 100000
local body = class()
body.glowShader = love.graphics.newShader(_PACKAGE.."/shaders/glow.glsl")
body.materialShader = love.graphics.newShader(_PACKAGE.."/shaders/material.glsl")
function body:init(id, type, ...)
local args = {...}
self.id = id
self.type = type
self.shine = true
self.red = 0
self.green = 0
self.blue = 0
self.alpha = 1.0
self.glowRed = 255
self.glowGreen = 255
self.glowBlue = 255
self.glowStrength = 0.0
self.tileX = 0
self.tileY = 0
if self.type == "circle" then
self.x = args[1] or 0
self.y = args[2] or 0
self:setShadowType('circle', args[3], args[4], args[5])
elseif self.type == "rectangle" then
self.x = args[1] or 0
self.y = args[2] or 0
self:setShadowType('rectangle', args[3], args[4])
elseif self.type == "polygon" then
self:setShadowType('polygon', ...)
elseif self.type == "image" then
self.img = args[1]
self.x = args[2] or 0
self.y = args[3] or 0
if self.img then
self.imgWidth = self.img:getWidth()
self.imgHeight = self.img:getHeight()
self.ix = self.imgWidth * 0.5
self.iy = self.imgHeight * 0.5
end
self:setShadowType('rectangle', args[4] or self.imgWidth, args[5] or self.imgHeight, args[6], args[7])
self.reflective = true
elseif self.type == "refraction" then
self:initNormal(...)
self.refraction = true
elseif self.type == "reflection" then
self:initNormal(...)
self.reflection = true
end
end
function body:initNormal(...)
local args = {...}
self.normal = args[1]
self.x = args[2] or 0
self.y = args[3] or 0
if self.normal then
self.normalWidth = self.normal:getWidth()
self.normalHeight = self.normal:getHeight()
self.width = args[4] or self.normalWidth
self.height = args[5] or self.normalHeight
self.nx = self.normalWidth * 0.5
self.ny = self.normalHeight * 0.5
self.normal:setWrap("repeat", "repeat")
self.normalVert = {
{0.0, 0.0, 0.0, 0.0},
{self.width, 0.0, 1.0, 0.0},
{self.width, self.height, 1.0, 1.0},
{0.0, self.height, 0.0, 1.0}
}
self.normalMesh = love.graphics.newMesh(self.normalVert, self.normal, "fan")
else
self.width = args[4] or 64
self.height = args[5] or 64
end
self.ox = self.width * 0.5
self.oy = self.height * 0.5
end
-- refresh
function body:refresh()
if self.x and self.y and self.width and self.height and self.ox and self.oy then
self.data = {
self.x - self.ox,
self.y - self.oy,
self.x - self.ox + self.width,
self.y - self.oy,
self.x - self.ox + self.width,
self.y - self.oy + self.height,
self.x - self.ox,
self.y - self.oy + self.height
}
end
end
-- set position
function body:setPosition(x, y)
if x ~= self.x or y ~= self.y then
self.x = x
self.y = y
self:refresh()
end
end
-- set x position
function body:setX(x)
if x ~= self.x then
self.x = x
self:refresh()
end
end
-- set y position
function body:setY(y)
if y ~= self.y then
self.y = y
self:refresh()
end
end
-- get x position
function body:getX()
return self.x
end
-- get y position
function body:getY(y)
return self.y
end
-- get width
function body:getWidth()
return self.width
end
-- get height
function body:getHeight()
return self.height
end
-- get image width
function body:getImageWidth()
return self.imgWidth
end
-- get image height
function body:getImageHeight()
return self.imgHeight
end
-- set dimension
function body:setDimension(width, height)
self.width = width
self.height = height
self:refresh()
end
-- set offset
function body:setOffset(ox, oy)
if ox ~= self.ox or oy ~= self.oy then
self.ox = ox
self.oy = oy
self:refresh()
end
end
-- set offset
function body:setImageOffset(ix, iy)
if ix ~= self.ix or iy ~= self.iy then
self.ix = ix
self.iy = iy
self:refresh()
end
end
-- set offset
function body:setNormalOffset(nx, ny)
if nx ~= self.nx or ny ~= self.ny then
self.nx = nx
self.ny = ny
self:refresh()
end
end
-- set glow color
function body:setGlowColor(red, green, blue)
self.glowRed = red
self.glowGreen = green
self.glowBlue = blue
end
-- set glow alpha
function body:setGlowStrength(strength)
self.glowStrength = strength
end
-- get radius
function body:getRadius()
return self.radius
end
-- set radius
function body:setRadius(radius)
if radius ~= self.radius then
self.radius = radius
end
end
-- set polygon data
function body:setPoints(...)
self.data = {...}
end
-- get polygon data
function body:getPoints()
return unpack(self.data)
end
-- set shadow on/off
function body:setShadow(b)
self.castsNoShadow = not b
end
-- set shine on/off
function body:setShine(b)
self.shine = b
end
-- set glass color
function body:setColor(red, green, blue)
self.red = red
self.green = green
self.blue = blue
end
-- set glass alpha
function body:setAlpha(alpha)
self.alpha = alpha
end
-- set reflection on/off
function body:setReflection(reflection)
self.reflection = reflection
end
-- set refraction on/off
function body:setRefraction(refraction)
self.refraction = refraction
end
-- set reflective on other objects on/off
function body:setReflective(reflective)
self.reflective = reflective
end
-- set refractive on other objects on/off
function body:setRefractive(refractive)
self.refractive = refractive
end
-- set image
function body:setImage(img)
if img then
self.img = img
self.imgWidth = self.img:getWidth()
self.imgHeight = self.img:getHeight()
self.ix = self.imgWidth * 0.5
self.iy = self.imgHeight * 0.5
end
end
-- set normal
function body:setNormalMap(normal, width, height, nx, ny)
if normal then
self.normal = normal
self.normal:setWrap("repeat", "repeat")
self.normalWidth = width or self.normal:getWidth()
self.normalHeight = height or self.normal:getHeight()
self.nx = nx or self.normalWidth * 0.5
self.ny = ny or self.normalHeight * 0.5
self.normalVert = {
{0.0, 0.0, 0.0, 0.0},
{self.normalWidth, 0.0, self.normalWidth / self.normal:getWidth(), 0.0},
{self.normalWidth, self.normalHeight, self.normalWidth / self.normal:getWidth(), self.normalHeight / self.normal:getHeight()},
{0.0, self.normalHeight, 0.0, self.normalHeight / self.normal:getHeight()}
}
self.normalMesh = love.graphics.newMesh(self.normalVert, self.normal, "fan")
else
self.normalMesh = nil
end
end
-- set height map
function body:setHeightMap(heightMap, strength)
self:setNormalMap(normal_map.fromHeightMap(heightMap, strength))
end
-- generate flat normal map
function body:generateNormalMapFlat(mode)
self:setNormalMap(normal_map.generateFlat(self.img, mode))
end
-- generate faded normal map
function body:generateNormalMapGradient(horizontalGradient, verticalGradient)
self:setNormalMap(normal_map.generateGradient(self.img, horizontalGradient, verticalGradient))
end
-- generate normal map
function body:generateNormalMap(strength)
self:setNormalMap(normal_map.fromHeightMap(self.img, strength))
end
-- set material
function body:setMaterial(material)
if material then
self.material = material
end
end
-- set normal
function body:setGlowMap(glow)
self.glow = glow
self.glowStrength = 1.0
end
-- set tile offset
function body:setNormalTileOffset(tx, ty)
self.tileX = tx / self.normalWidth
self.tileY = ty / self.normalHeight
self.normalVert = {
{0.0, 0.0, self.tileX, self.tileY},
{self.normalWidth, 0.0, self.tileX + 1.0, self.tileY},
{self.normalWidth, self.normalHeight, self.tileX + 1.0, self.tileY + 1.0},
{0.0, self.normalHeight, self.tileX, self.tileY + 1.0}
}
end
-- get type
function body:getType()
return self.type
end
-- get type
function body:setShadowType(type, ...)
self.shadowType = type
local args = {...}
if self.shadowType == "circle" then
self.radius = args[1] or 16
self.ox = args[2] or 0
self.oy = args[3] or 0
elseif self.shadowType == "rectangle" then
self.width = args[1] or 64
self.height = args[2] or 64
self.ox = args[3] or self.width * 0.5
self.oy = args[4] or self.height * 0.5
self:refresh()
elseif self.shadowType == "polygon" then
self.data = args or {0, 0, 0, 0, 0, 0}
elseif self.shadowType == "image" then
if self.img then
self.width = self.imgWidth
self.height = self.imgHeight
self.shadowVert = {
{0.0, 0.0, 0.0, 0.0},
{self.width, 0.0, 1.0, 0.0},
{self.width, self.height, 1.0, 1.0},
{0.0, self.height, 0.0, 1.0}
}
if not self.shadowMesh then
self.shadowMesh = love.graphics.newMesh(self.shadowVert, self.img, "fan")
self.shadowMesh:setVertexColors(true)
end
else
self.width = 64
self.height = 64
end
self.shadowX = args[1] or 0
self.shadowY = args[2] or 0
self.fadeStrength = args[3] or 0.0
end
end
function body:stencil()
if self.shadowType == "circle" then
love.graphics.circle("fill", self.x - self.ox, self.y - self.oy, self.radius)
elseif self.shadowType == "rectangle" then
love.graphics.rectangle("fill", self.x - self.ox, self.y - self.oy, self.width, self.height)
elseif self.shadowType == "polygon" then
love.graphics.polygon("fill", unpack(self.data))
elseif self.shadowType == "image" then
--love.graphics.rectangle("fill", self.x - self.ox, self.y - self.oy, self.width, self.height)
end
end
function body:drawShadow(light)
if self.alpha < 1.0 then
love.graphics.setBlendMode("multiplicative")
love.graphics.setColor(self.red, self.green, self.blue)
if self.shadowType == "circle" then
love.graphics.circle("fill", self.x - self.ox, self.y - self.oy, self.radius)
elseif self.shadowType == "rectangle" then
love.graphics.rectangle("fill", self.x - self.ox, self.y - self.oy, self.width, self.height)
elseif self.shadowType == "polygon" then
love.graphics.polygon("fill", unpack(self.data))
end
end
if self.shadowType == "image" and self.img then
love.graphics.setBlendMode("alpha")
local length = 1.0
local shadowRotation = math.atan2((self.x) - light.x, (self.y + self.oy) - light.y)
self.shadowVert = {
{
math.sin(shadowRotation) * self.imgHeight * length,
(length * math.cos(shadowRotation) + 1.0) * self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY,
0, 0,
self.red,
self.green,
self.blue,
self.alpha * self.fadeStrength * 255
},
{
self.imgWidth + math.sin(shadowRotation) * self.imgHeight * length,
(length * math.cos(shadowRotation) + 1.0) * self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY,
1, 0,
self.red,
self.green,
self.blue,
self.alpha * self.fadeStrength * 255
},
{
self.imgWidth,
self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY,
1, 1,
self.red,
self.green,
self.blue,
self.alpha * 255
},
{
0,
self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY,
0, 1,
self.red,
self.green,
self.blue,
self.alpha * 255
}
}
self.shadowMesh:setVertices(self.shadowVert)
love.graphics.draw(self.shadowMesh, self.x - self.ox, self.y - self.oy, 0, s, s)
end
end
function body:drawPixelShadow()
if self.type == "image" and self.normalMesh then
love.graphics.setColor(255, 255, 255)
love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny)
end
end
function body:drawGlow()
if self.glowStrength > 0.0 then
love.graphics.setColor(self.glowRed * self.glowStrength, self.glowGreen * self.glowStrength, self.glowBlue * self.glowStrength)
else
love.graphics.setColor(0, 0, 0)
end
if self.type == "circle" then
love.graphics.circle("fill", self.x, self.y, self.radius)
elseif self.type == "rectangle" then
love.graphics.rectangle("fill", self.x, self.y, self.width, self.height)
elseif self.type == "polygon" then
love.graphics.polygon("fill", unpack(self.data))
elseif self.type == "image" and self.img then
if self.glowStrength > 0.0 and self.glow then
love.graphics.setShader(self.glowShader)
self.glowShader:send("glowImage", self.glow)
self.glowShader:send("glowTime", love.timer.getTime() * 0.5)
love.graphics.setColor(255, 255, 255)
else
love.graphics.setShader()
love.graphics.setColor(0, 0, 0)
end
love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy)
end
love.graphics.setShader()
end
function body:drawRefraction()
if self.refraction and self.normal then
love.graphics.setColor(255, 255, 255)
if self.tileX == 0.0 and self.tileY == 0.0 then
love.graphics.draw(normal, self.x - self.nx, self.y - self.ny)
else
self.normalMesh:setVertices(self.normalVert)
love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny)
end
end
love.graphics.setColor(0, 0, 0)
if not self.refractive then
if self.type == "circle" then
love.graphics.circle("fill", self.x, self.y, self.radius)
elseif self.type == "rectangle" then
love.graphics.rectangle("fill", self.x, self.y, self.width, self.height)
elseif self.type == "polygon" then
love.graphics.polygon("fill", unpack(self.data))
elseif self.type == "image" and self.img then
love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy)
end
end
end
function body:drawReflection()
if self.reflection and self.normal then
love.graphics.setColor(255, 0, 0)
self.normalMesh:setVertices(self.normalVert)
love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny)
end
if self.reflective and self.img then
love.graphics.setColor(0, 255, 0)
love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy)
elseif not self.reflection and self.img then
love.graphics.setColor(0, 0, 0)
love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy)
end
end
function body:drawMaterial()
if self.material and self.normal then
love.graphics.setShader(self.materialShader)
love.graphics.setColor(255, 255, 255)
self.materialShader:send("material", self.material)
love.graphics.draw(self.normal, self.x - self.nx, self.y - self.ny)
love.graphics.setShader()
end
end
function body:calculateShadow(light)
if self.shadowType == "rectangle" or self.shadowType == "polygon" then
return self:calculatePolyShadow(light)
elseif self.shadowType == "circle" then
return self:calculateCircleShadow(light)
end
end
function body:calculatePolyShadow(light)
if self.castsNoShadow then
return nil
end
local curPolygon = self.data
local edgeFacingTo = {}
for k = 1, #curPolygon, 2 do
local indexOfNextVertex = (k + 2) % #curPolygon
local normal = {-curPolygon[indexOfNextVertex+1] + curPolygon[k + 1], curPolygon[indexOfNextVertex] - curPolygon[k]}
local lightToPoint = {curPolygon[k] - light.x, curPolygon[k + 1] - light.y}
normal = vector.normalize(normal)
lightToPoint = vector.normalize(lightToPoint)
local dotProduct = vector.dot(normal, lightToPoint)
if dotProduct > 0 then table.insert(edgeFacingTo, true)
else table.insert(edgeFacingTo, false) end
end
local curShadowGeometry = {}
for k = 1, #edgeFacingTo do
local nextIndex = (k + 1) % #edgeFacingTo
if nextIndex == 0 then nextIndex = #edgeFacingTo end
if edgeFacingTo[k] and not edgeFacingTo[nextIndex] then
curShadowGeometry[1] = curPolygon[nextIndex*2-1]
curShadowGeometry[2] = curPolygon[nextIndex*2]
local lightVecFrontBack = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y})
curShadowGeometry[3] = curShadowGeometry[1] + lightVecFrontBack[1] * shadowLength
curShadowGeometry[4] = curShadowGeometry[2] + lightVecFrontBack[2] * shadowLength
elseif not edgeFacingTo[k] and edgeFacingTo[nextIndex] then
curShadowGeometry[7] = curPolygon[nextIndex*2-1]
curShadowGeometry[8] = curPolygon[nextIndex*2]
local lightVecBackFront = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y})
curShadowGeometry[5] = curShadowGeometry[7] + lightVecBackFront[1] * shadowLength
curShadowGeometry[6] = curShadowGeometry[8] + lightVecBackFront[2] * shadowLength
end
end
if curShadowGeometry[1]
and curShadowGeometry[2]
and curShadowGeometry[3]
and curShadowGeometry[4]
and curShadowGeometry[5]
and curShadowGeometry[6]
and curShadowGeometry[7]
and curShadowGeometry[8]
then
curShadowGeometry.alpha = self.alpha
curShadowGeometry.red = self.red
curShadowGeometry.green = self.green
curShadowGeometry.blue = self.blue
return curShadowGeometry
else
return nil
end
end
function body:calculateCircleShadow(light)
if self.castsNoShadow then
return nil
end
local length = math.sqrt(math.pow(light.x - (self.x - self.ox), 2) + math.pow(light.y - (self.y - self.oy), 2))
if length >= self.radius and length <= light.range then
local curShadowGeometry = {}
local angle = math.atan2(light.x - (self.x - self.ox), (self.y - self.oy) - light.y) + math.pi / 2
local x2 = ((self.x - self.ox) + math.sin(angle) * self.radius)
local y2 = ((self.y - self.oy) - math.cos(angle) * self.radius)
local x3 = ((self.x - self.ox) - math.sin(angle) * self.radius)
local y3 = ((self.y - self.oy) + math.cos(angle) * self.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 = self.alpha
curShadowGeometry.red = self.red
curShadowGeometry.green = self.green
curShadowGeometry.blue = self.blue
return curShadowGeometry
else
return nil
end
end
return body

47
src/lib/class.lua Normal file
View File

@@ -0,0 +1,47 @@
-- class.lua
-- Compatible with Lua 5.1 (not 5.0).
local class = function(base, init)
local c = {} -- a new class instance
if not init and type(base) == 'function' then
init = base
base = nil
elseif type(base) == 'table' then
-- our new class is a shallow copy of the base class!
for i,v in pairs(base) do
c[i] = v
end
c._base = base
end
-- the class will be the metatable for all its objects,
-- and they will look up their methods in it.
c.__index = c
-- expose a constructor which can be called by <classname>(<args>)
local mt = {}
mt.__call = function(class_tbl, ...)
local obj = {}
setmetatable(obj,c)
if class_tbl.init then
class_tbl.init(obj,...)
else
-- make sure that any stuff from the base class is initialized!
if base and base.init then
base.init(obj, ...)
end
end
return obj
end
c.init = init
c.is_a = function(self, klass)
local m = getmetatable(self)
while m do
if m == klass then return true end
m = m._base
end
return false
end
setmetatable(c, mt)
return c
end
return class

225
src/lib/light.lua Normal file
View File

@@ -0,0 +1,225 @@
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
local class = require(_PACKAGE.."/class")
local stencils = require(_PACKAGE..'/stencils')
local util = require(_PACKAGE..'/util')
local light = class()
light.shader = love.graphics.newShader(_PACKAGE.."/shaders/poly_shadow.glsl")
light.normalShader = love.graphics.newShader(_PACKAGE.."/shaders/normal.glsl")
light.normalInvertShader = love.graphics.newShader(_PACKAGE.."/shaders/normal_invert.glsl")
function light:init(x, y, r, g, b, range)
self.direction = 0
self.angle = math.pi * 2.0
self.range = 0
self.x = x or 0
self.y = y or 0
self.z = 15
self.red = r or 255
self.green = g or 255
self.blue = b or 255
self.range = range or 300
self.smooth = 1.0
self.glowSize = 0.1
self.glowStrength = 0.0
self.visible = true
self:refresh()
end
function light:refresh(w, h)
w, h = w or love.window.getWidth(), h or love.window.getHeight()
self.shadow = love.graphics.newCanvas(w, h)
self.shine = love.graphics.newCanvas(w, h)
end
-- set position
function light:setPosition(x, y, z)
if x ~= self.x or y ~= self.y or (z and z ~= self.z) then
self.x = x
self.y = y
if z then
self.z = z
end
end
end
-- get x
function light:getX()
return self.x
end
-- get y
function light:getY()
return self.y
end
-- set x
function light:setX(x)
if x ~= self.x then
self.x = x
end
end
-- set y
function light:setY(y)
if y ~= self.y then
self.y = y
end
end
-- set color
function light:setColor(red, green, blue)
self.red = red
self.green = green
self.blue = blue
end
-- set range
function light:setRange(range)
if range ~= self.range then
self.range = range
end
end
-- set direction
function light:setDirection(direction)
if direction ~= self.direction then
if direction > math.pi * 2 then
self.direction = math.mod(direction, math.pi * 2)
elseif direction < 0.0 then
self.direction = math.pi * 2 - math.mod(math.abs(direction), math.pi * 2)
else
self.direction = direction
end
end
end
-- set angle
function light:setAngle(angle)
if angle ~= self.angle then
if angle > math.pi then
self.angle = math.mod(angle, math.pi)
elseif angle < 0.0 then
self.angle = math.pi - math.mod(math.abs(angle), math.pi)
else
self.angle = angle
end
end
end
-- set glow size
function light:setSmooth(smooth)
self.smooth = smooth
end
-- set glow size
function light:setGlowSize(size)
self.glowSize = size
end
-- set glow strength
function light:setGlowStrength(strength)
self.glowStrength = strength
end
function light:inRange(l,t,w,h)
return self.x + self.range > l and
self.x - self.range < (l+w) and
self.y + self.range > t and
self.y - self.range < (t+h)
end
function light:drawShadow(l,t,w,h,s,bodies, canvas)
if self.visible and self:inRange(l,t,w,h) then
-- calculate shadows
local shadow_geometry = {}
for i = 1, #bodies do
local current = bodies[i]:calculateShadow(self)
if current ~= nil then
shadow_geometry[#shadow_geometry + 1] = current
end
end
-- draw shadow
self.shadow:clear()
util.drawto(self.shadow, l, t, s, function()
self.shader:send("lightPosition", {self.x*s, (h/s - self.y)*s, self.z})
self.shader:send("lightRange", self.range*s)
self.shader:send("lightColor", {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
self.shader:send("lightSmooth", self.smooth)
self.shader:send("lightGlow", {1.0 - self.glowSize, self.glowStrength})
self.shader:send("lightAngle", math.pi - self.angle / 2.0)
self.shader:send("lightDirection", self.direction)
love.graphics.setShader(self.shader)
love.graphics.setInvertedStencil(stencils.shadow(shadow_geometry, bodies))
love.graphics.setBlendMode("additive")
love.graphics.rectangle("fill", -l/s,-t/s,w/s,h/s)
-- draw color shadows
love.graphics.setBlendMode("multiplicative")
love.graphics.setShader()
for k = 1,#shadow_geometry do
if shadow_geometry[k].alpha < 1.0 then
love.graphics.setColor(
shadow_geometry[k].red * (1.0 - shadow_geometry[k].alpha),
shadow_geometry[k].green * (1.0 - shadow_geometry[k].alpha),
shadow_geometry[k].blue * (1.0 - shadow_geometry[k].alpha)
)
love.graphics.polygon("fill", unpack(shadow_geometry[k]))
end
end
for k = 1, #bodies do
bodies[k]:drawShadow(self,l,t,w,h,s)
end
end)
love.graphics.setStencil()
love.graphics.setShader()
util.drawCanvasToCanvas(self.shadow, canvas, {blendmode = "additive"})
end
end
function light:drawShine(l,t,w,h,s,bodies,canvas)
if self.visible then
--update shine
self.shine:clear(255, 255, 255)
util.drawto(self.shine, l, t, s, function()
love.graphics.setShader(self.shader)
love.graphics.setBlendMode("alpha")
love.graphics.setStencil(stencils.shine(bodies))
love.graphics.rectangle("fill", -l/s,-t/s,w/s,h/s)
end)
love.graphics.setStencil()
love.graphics.setShader()
util.drawCanvasToCanvas(self.shine, canvas, {blendmode = "additive"})
end
end
function light:drawPixelShadow(l,t,w,h, normalMap, canvas)
if self.visible then
if self.normalInvert then
self.normalInvertShader:send('screenResolution', {w, h})
self.normalInvertShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
self.normalInvertShader:send('lightPosition',{self.x, lh - self.y, self.z / 255.0})
self.normalInvertShader:send('lightRange',{self.range})
self.normalInvertShader:send("lightSmooth", self.smooth)
self.normalInvertShader:send("lightAngle", math.pi - self.angle / 2.0)
self.normalInvertShader:send("lightDirection", self.direction)
util.drawCanvasToCanvas(normalMap, canvas, {shader = self.normalInvertShader})
else
self.normalShader:send('screenResolution', {w, h})
self.normalShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
self.normalShader:send('lightPosition',{self.x, h - self.y, self.z / 255.0})
self.normalShader:send('lightRange',{self.range})
self.normalShader:send("lightSmooth", self.smooth)
self.normalShader:send("lightAngle", math.pi - self.angle / 2.0)
self.normalShader:send("lightDirection", self.direction)
util.drawCanvasToCanvas(normalMap, canvas, {shader = self.normalShader})
end
end
end
return light

432
src/lib/light_world.lua Normal file
View File

@@ -0,0 +1,432 @@
--[[
The MIT License (MIT)
Copyright (c) 2014 Marcus Ihde
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
local class = require(_PACKAGE..'/class')
local Light = require(_PACKAGE..'/light')
local Body = require(_PACKAGE..'/body')
local util = require(_PACKAGE..'/util')
local normal_map = require(_PACKAGE..'/normal_map')
local PostShader = require(_PACKAGE..'/postshader')
require(_PACKAGE..'/postshader')
local light_world = class()
light_world.blurv = love.graphics.newShader(_PACKAGE.."/shaders/blurv.glsl")
light_world.blurh = love.graphics.newShader(_PACKAGE.."/shaders/blurh.glsl")
light_world.refractionShader = love.graphics.newShader(_PACKAGE.."/shaders/refraction.glsl")
light_world.reflectionShader = love.graphics.newShader(_PACKAGE.."/shaders/reflection.glsl")
function light_world:init(options)
self.lights = {}
self.body = {}
self.post_shader = PostShader()
self.ambient = {0, 0, 0}
self.normalInvert = false
self.refractionStrength = 8.0
self.reflectionStrength = 16.0
self.reflectionVisibility = 1.0
self.blur = 2.0
self.glowBlur = 1.0
self.glowTimer = 0.0
self.glowDown = false
self.drawBackground = function() end
self.drawForground = function() end
options = options or {}
for k, v in pairs(options) do self[k] = v end
self:refreshScreenSize()
end
function light_world:refreshScreenSize(w, h)
w, h = w or love.window.getWidth(), h or love.window.getHeight()
self.render_buffer = love.graphics.newCanvas(w, h)
self.shadow = love.graphics.newCanvas(w, h)
self.shadow2 = love.graphics.newCanvas(w, h)
self.pixelShadow = love.graphics.newCanvas(w, h)
self.pixelShadow2 = love.graphics.newCanvas(w, h)
self.shine = love.graphics.newCanvas(w, h)
self.shine2 = love.graphics.newCanvas(w, h)
self.normalMap = love.graphics.newCanvas(w, h)
self.glowMap = love.graphics.newCanvas(w, h)
self.glowMap2 = love.graphics.newCanvas(w, h)
self.refractionMap = love.graphics.newCanvas(w, h)
self.refractionMap2 = love.graphics.newCanvas(w, h)
self.reflectionMap = love.graphics.newCanvas(w, h)
self.reflectionMap2 = love.graphics.newCanvas(w, h)
self.blurv:send("screen", {w, h})
self.blurh:send("screen", {w, h})
self.refractionShader:send("screen", {w, h})
self.reflectionShader:send("screen", {w, h})
for i = 1, #self.lights do
self.lights[i]:refresh(w, h)
end
self.post_shader:refreshScreenSize(w, h)
end
function light_world:draw(l,t,s)
l,t,s = (l or 0), (t or 0), s or 1
local w, h = love.graphics.getWidth(), love.graphics.getHeight()
util.drawto(self.render_buffer, l, t, s, function()
self.drawBackground( l,t,w,h,s)
self:drawShadow( l,t,w,h,s)
self.drawForground( l,t,w,h,s)
self:drawMaterial( l,t,w,h,s)
self:drawShine( l,t,w,h,s)
self:drawPixelShadow(l,t,w,h,s)
self:drawGlow( l,t,w,h,s)
self:drawRefraction( l,t,w,h,s)
self:drawReflection( l,t,w,h,s)
end)
self.post_shader:drawWith(self.render_buffer, l, t, s)
end
function light_world:drawBlur(blendmode, blur, canvas, canvas2, l, t, w, h, s)
if blur <= 0 then
return
end
canvas2:clear()
self.blurv:send("steps", blur)
self.blurh:send("steps", blur)
util.drawCanvasToCanvas(canvas, canvas2, {shader = self.blurv, blendmode = blendmode})
util.drawCanvasToCanvas(canvas2, canvas, {shader = self.blurh, blendmode = blendmode})
end
-- draw shadow
function light_world:drawShadow(l,t,w,h,s)
if not self.isShadows and not self.isLight then
return
end
-- draw ambient
util.drawto(self.shadow, l, t, s, function()
love.graphics.setColor(unpack(self.ambient))
love.graphics.setBlendMode("alpha")
love.graphics.rectangle("fill", -l/s, -t/s, w/s, h/s)
for i = 1, #self.lights do
self.lights[i]:drawShadow(l,t,w,h,s,self.body, self.shadow)
end
end)
light_world:drawBlur("alpha", self.blur, self.shadow, self.shadow2, l, t, w, h, s)
util.drawCanvasToCanvas(self.shadow, self.render_buffer, {blendmode = "multiplicative"})
end
-- draw shine
function light_world:drawShine(l,t,w,h,s)
if not self.isShadows then
return
end
-- update shine
util.drawto(self.shine, l, t, s, function()
love.graphics.setColor(unpack(self.ambient))
love.graphics.setBlendMode("alpha")
love.graphics.rectangle("fill", -l/s, -t/s, w/s, h/s)
for i = 1, #self.lights do
self.lights[i]:drawShine(l,t,w,h,s,self.body,self.shine)
end
end)
--light_world:drawBlur("additive", self.blur, self.shine, self.shine2, l, t, w, h, s)
util.drawCanvasToCanvas(self.shine, self.render_buffer, {blendmode = "multiplicative"})
end
-- draw pixel shadow
function light_world:drawPixelShadow(l,t,w,h,s)
if not self.isShadows then
return
end
-- update pixel shadow
-- create normal map
self.normalMap:clear()
util.drawto(self.normalMap, l, t, s, function()
for i = 1, #self.body do
self.body[i]:drawPixelShadow()
end
end)
self.pixelShadow2:clear()
for i = 1, #self.lights do
self.lights[i]:drawPixelShadow(l,t,w,h, self.normalMap, self.pixelShadow2)
end
self.pixelShadow:clear(255, 255, 255)
util.drawCanvasToCanvas(self.pixelShadow2, self.pixelShadow, {blendmode = "alpha"})
util.drawto(self.pixelShadow, l, t, s, function()
love.graphics.setBlendMode("additive")
love.graphics.setColor({self.ambient[1], self.ambient[2], self.ambient[3]})
love.graphics.rectangle("fill", l/s,t/s,w/s,h/s)
end)
util.drawCanvasToCanvas(self.pixelShadow, self.render_buffer, {blendmode = "multiplicative"})
end
-- draw material
function light_world:drawMaterial(l,t,w,h,s)
for i = 1, #self.body do
self.body[i]:drawMaterial()
end
end
-- draw glow
function light_world:drawGlow(l,t,w,h,s)
if not self.isShadows then
return
end
-- create glow map
self.glowMap:clear(0, 0, 0)
util.drawto(self.glowMap, l, t, s, function()
if self.glowDown then
self.glowTimer = math.max(0.0, self.glowTimer - love.timer.getDelta())
if self.glowTimer == 0.0 then
self.glowDown = not self.glowDown
end
else
self.glowTimer = math.min(self.glowTimer + love.timer.getDelta(), 1.0)
if self.glowTimer == 1.0 then
self.glowDown = not self.glowDown
end
end
for i = 1, #self.body do
self.body[i]:drawGlow()
end
end)
light_world:drawBlur("alpha", self.glowBlur, self.glowMap, self.glowMap2, l, t, w, h, s)
util.drawCanvasToCanvas(self.glowMap, self.render_buffer, {blendmode = "additive"})
end
-- draw refraction
function light_world:drawRefraction(l,t,w,h,s)
if not self.isRefraction then
return
end
-- create refraction map
self.refractionMap:clear()
util.drawto(self.refractionMap, l, t, s, function()
for i = 1, #self.body do
self.body[i]:drawRefraction()
end
end)
util.drawCanvasToCanvas(self.render_buffer, self.refractionMap2)
self.refractionShader:send("backBuffer", self.refractionMap2)
self.refractionShader:send("refractionStrength", self.refractionStrength)
util.drawCanvasToCanvas(self.refractionMap, self.render_buffer, {shader = self.refractionShader})
end
-- draw reflection
function light_world:drawReflection(l,t,w,h,s)
if not self.isReflection then
return
end
-- create reflection map
self.reflectionMap:clear(0, 0, 0)
util.drawto(self.reflectionMap, l, t, s, function()
for i = 1, #self.body do
self.body[i]:drawReflection()
end
end)
util.drawCanvasToCanvas(self.render_buffer, self.reflectionMap2)
self.reflectionShader:send("backBuffer", self.reflectionMap2)
self.reflectionShader:send("reflectionStrength", self.reflectionStrength)
self.reflectionShader:send("reflectionVisibility", self.reflectionVisibility)
util.drawCanvasToCanvas(self.reflectionMap, self.render_buffer, {shader = self.reflectionShader})
end
-- new light
function light_world:newLight(x, y, red, green, blue, range)
self.lights[#self.lights + 1] = Light(x, y, red, green, blue, range)
self.isLight = true
return self.lights[#self.lights]
end
-- clear lights
function light_world:clearLights()
self.lights = {}
self.isLight = false
end
-- clear objects
function light_world:clearBodys()
self.body = {}
self.isShadows = false
self.isRefraction = false
self.isReflection = false
end
function light_world:setBackgroundMethod(fn)
self.drawBackground = fn or function() end
end
function light_world:setForegroundMethod(fn)
self.drawForground = fn or function() end
end
-- set ambient color
function light_world:setAmbientColor(red, green, blue)
self.ambient = {red, green, blue}
end
-- set ambient red
function light_world:setAmbientRed(red)
self.ambient[1] = red
end
-- set ambient green
function light_world:setAmbientGreen(green)
self.ambient[2] = green
end
-- set ambient blue
function light_world:setAmbientBlue(blue)
self.ambient[3] = blue
end
-- set normal invert
function light_world:setNormalInvert(invert)
self.normalInvert = invert
end
-- set blur
function light_world:setBlur(blur)
self.blur = blur
end
-- set blur
function light_world:setShadowBlur(blur)
self.blur = blur
end
-- set glow blur
function light_world:setGlowStrength(strength)
self.glowBlur = strength
end
-- set refraction blur
function light_world:setRefractionStrength(strength)
self.refractionStrength = strength
end
-- set reflection strength
function light_world:setReflectionStrength(strength)
self.reflectionStrength = strength
end
-- set reflection visibility
function light_world:setReflectionVisibility(visibility)
self.reflectionVisibility = visibility
end
-- new rectangle
function light_world:newRectangle(x, y, w, h)
self.isShadows = true
return self:newBody("rectangle", x, y, width, height)
end
-- new circle
function light_world:newCircle(x, y, r)
self.isShadows = true
return self:newBody("circle", x, y, r)
end
-- new polygon
function light_world:newPolygon(...)
self.isShadows = true
return self:newBody("polygon", ...)
end
-- new image
function light_world:newImage(img, x, y, width, height, ox, oy)
self.isShadows = true
return self:newBody("image", img, x, y, width, height, ox, oy)
end
-- new refraction
function light_world:newRefraction(normal, x, y, width, height)
self.isRefraction = true
return self:newBody("refraction", normal, x, y, width, height)
end
-- new refraction from height map
function light_world:newRefractionHeightMap(heightMap, x, y, strength)
local normal = normal_map.fromHeightMap(heightMap, strength)
self.isRefraction = true
return self.newRefraction(p, normal, x, y)
end
-- new reflection
function light_world:newReflection(normal, x, y, width, height)
self.isReflection = true
return self:newBody("reflection", normal, x, y, width, height)
end
-- new reflection from height map
function light_world:newReflectionHeightMap(heightMap, x, y, strength)
local normal = normal_map.fromHeightMap(heightMap, strength)
self.isReflection = true
return self.newReflection(p, normal, x, y)
end
-- new body
function light_world:newBody(type, ...)
local id = #self.body + 1
self.body[id] = Body(id, type, ...)
return self.body[#self.body]
end
-- get body count
function light_world:getBodyCount()
return #self.body
end
-- get light
function light_world:getBody(n)
return self.body[n]
end
-- get light count
function light_world:getLightCount()
return #self.lights
end
-- get light
function light_world:getLight(n)
return self.lights[n]
end
return light_world

123
src/lib/normal_map.lua Normal file
View File

@@ -0,0 +1,123 @@
normal_map = {}
function normal_map.fromHeightMap(heightMap, strength)
local imgData = heightMap:getData()
local imgData2 = love.image.newImageData(heightMap:getWidth(), heightMap:getHeight())
local red, green, blue, alpha
local x, y
local matrix = {}
matrix[1] = {}
matrix[2] = {}
matrix[3] = {}
strength = strength or 1.0
for i = 0, heightMap:getHeight() - 1 do
for k = 0, heightMap:getWidth() - 1 do
for l = 1, 3 do
for m = 1, 3 do
if k + (l - 1) < 1 then
x = heightMap:getWidth() - 1
elseif k + (l - 1) > heightMap:getWidth() - 1 then
x = 1
else
x = k + l - 1
end
if i + (m - 1) < 1 then
y = heightMap:getHeight() - 1
elseif i + (m - 1) > heightMap:getHeight() - 1 then
y = 1
else
y = i + m - 1
end
local red, green, blue, alpha = imgData:getPixel(x, y)
matrix[l][m] = red
end
end
red = (255 + ((matrix[1][2] - matrix[2][2]) + (matrix[2][2] - matrix[3][2])) * strength) / 2.0
green = (255 + ((matrix[2][2] - matrix[1][1]) + (matrix[2][3] - matrix[2][2])) * strength) / 2.0
blue = 192
imgData2:setPixel(k, i, red, green, blue)
end
end
return love.graphics.newImage(imgData2)
end
function normal_map.generateFlat(img, mode)
local imgData = img:getData()
local imgNormalData = love.image.newImageData(img:getWidth(), img:getHeight())
local color
if mode == "top" then
color = {127, 127, 255}
elseif mode == "front" then
color = {127, 0, 127}
elseif mode == "back" then
color = {127, 255, 127}
elseif mode == "left" then
color = {31, 0, 223}
elseif mode == "right" then
color = {223, 0, 127}
end
for i = 0, self.imgHeight - 1 do
for k = 0, self.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
return love.graphics.newImage(imgNormalData)
end
function normal_map.generateGradient(img, horizontalGradient, verticalGradient)
horizontalGradient = horizontalGradient or "gradient"
verticalGradient = verticalGradient or horizontalGradient
local imgData = img:getData()
local imgWidth, imgHeight = img:getWidth(), img:getHeight()
local imgNormalData = love.image.newImageData(imgWidth, imgHeight)
local dx = 255.0 / imgWidth
local dy = 255.0 / imgHeight
local nx
local ny
local nz
for i = 0, imgWidth - 1 do
for k = 0, 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
return love.graphics.newImage(imgNormalData)
end
return normal_map

183
src/lib/postshader.lua Normal file
View File

@@ -0,0 +1,183 @@
--[[
The MIT License (MIT)
Copyright (c) 2014 Marcus Ihde
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
local class = require(_PACKAGE..'/class')
local util = require(_PACKAGE..'/util')
local post_shader = class()
post_shader.blurv = love.graphics.newShader(_PACKAGE.."/shaders/blurv.glsl")
post_shader.blurh = love.graphics.newShader(_PACKAGE.."/shaders/blurh.glsl")
post_shader.contrast = love.graphics.newShader(_PACKAGE.."/shaders/postshaders/contrast.glsl")
post_shader.tilt_shift = love.graphics.newShader(_PACKAGE.."/shaders/postshaders/tilt_shift.glsl")
local files = love.filesystem.getDirectoryItems(_PACKAGE.."/shaders/postshaders")
local shaders = {}
for i,v in ipairs(files) do
local name = _PACKAGE.."/shaders/postshaders".."/"..v
if love.filesystem.isFile(name) then
local str = love.filesystem.read(name)
local effect = love.graphics.newShader(name)
local defs = {}
for vtype, extern in str:gmatch("extern (%w+) (%w+)") do
defs[extern] = true
end
local shaderName = name:match(".-([^\\|/]-[^%.]+)$"):gsub("%.glsl", "")
shaders[shaderName] = {effect, defs}
end
end
function post_shader:init()
self:refreshScreenSize()
self.effects = {}
end
function post_shader:refreshScreenSize(w, h)
w, h = w or love.window.getWidth(), h or love.window.getHeight()
self.render_buffer = love.graphics.newCanvas(w, h)
self.back_buffer = love.graphics.newCanvas(w, h)
post_shader.blurv:send("screen", {w, h})
post_shader.blurh:send("screen", {w, h})
for shaderName, v in pairs(shaders) do
for def in pairs(v[2]) do
if def == "screen" or def == "textureSize" or def == "inputSize" or def == "outputSize" then
v[1]:send(def, {w, h})
end
end
end
self.w = w
self.h = h
end
function post_shader:addEffect(shaderName, ...)
self.effects[shaderName] = {...}
end
function post_shader:removeEffect(shaderName)
self.effects[shaderName] = nil
end
function post_shader:toggleEffect(shaderName, ...)
if self.effects[shaderName] ~= nil then
self:removeEffect(shaderName)
else
self:addEffect(shaderName, ...)
end
end
function post_shader:drawWith(canvas)
for shader, args in pairs(self.effects) do
if shader == "bloom" then
self:drawBloom(canvas, args)
elseif shader == "blur" then
self:drawBlur(canvas, args)
elseif shader == "tilt_shift" then
self:drawTiltShift(canvas, args)
else
self:drawShader(shader, canvas, args)
end
end
util.drawCanvasToCanvas(canvas)
end
function post_shader:drawBloom(canvas, args)
post_shader.blurv:send("steps", args[1] or 2.0)
post_shader.blurh:send("steps", args[1] or 2.0)
util.drawCanvasToCanvas(canvas, self.back_buffer, {shader = post_shader.blurv})
util.drawCanvasToCanvas(self.back_buffer, self.back_buffer, {shader = post_shader.blurh})
util.drawCanvasToCanvas(self.back_buffer, self.back_buffer, {shader = post_shader.contrast})
util.drawCanvasToCanvas(canvas, canvas, {shader = post_shader.contrast})
util.drawCanvasToCanvas(self.back_buffer, canvas, {blendmode = "additive", color = {255, 255, 255, (args[2] or 0.25) * 255}})
end
function post_shader:drawBlur(canvas, args)
post_shader.blurv:send("steps", args[1] or 2.0)
post_shader.blurh:send("steps", args[2] or 2.0)
util.drawCanvasToCanvas(canvas, self.back_buffer, {shader = post_shader.blurv})
util.drawCanvasToCanvas(self.back_buffer, self.back_buffer, {shader = post_shader.blurh})
util.drawCanvasToCanvas(self.back_buffer, canvas)
end
function post_shader:drawTiltShift(canvas, args)
post_shader.blurv:send("steps", args[1] or 2.0)
post_shader.blurh:send("steps", args[2] or 2.0)
util.drawCanvasToCanvas(canvas, self.back_buffer, {shader = post_shader.blurv})
util.drawCanvasToCanvas(self.back_buffer, self.back_buffer, {shader = post_shader.blurh})
post_shader.tilt_shift:send("imgBuffer", canvas)
util.drawCanvasToCanvas(self.back_buffer, canvas, {shader = post_shader.tilt_shift})
end
function post_shader:drawShader(shaderName, canvas, args)
local w, h = love.graphics.getWidth(), love.graphics.getHeight()
local current_arg = 1
local effect = shaders[shaderName]
if effect == nil then
print("no shader called "..shaderName)
return
end
for def in pairs(effect[2]) do
if def == "time" then
effect[1]:send("time", love.timer.getTime())
elseif def == "palette" then
effect[1]:send("palette", unpack(process_palette({
args[current_arg],
args[current_arg + 1],
args[current_arg + 2],
args[current_arg + 3]
})))
current_arg = current_arg + 4
elseif def == "tint" then
effect[1]:send("tint", {process_tint(args[1], args[2], args[3])})
current_arg = current_arg + 3
elseif def == "imgBuffer" then
effect[1]:send("imgBuffer", canvas)
elseif def ~= "screen" and def ~= "textureSize" and def ~= "inputSize" and def ~= "outputSize" then
local value = args[current_arg]
if value ~= nil then
effect[1]:send(def, value)
end
current_arg = current_arg + 1
end
end
util.drawCanvasToCanvas(canvas, self.back_buffer, {shader = effect[1]})
util.drawCanvasToCanvas(self.back_buffer, canvas)
end
function process_tint(r, g, b)
return (r and r/255.0 or 1.0), (g and g/255.0 or 1.0), (b and b/255.0 or 1.0)
end
function process_palette(palette)
for i = 1, #palette do
palette[i] = {process_tint(unpack(palette[i]))}
end
return palette
end
return post_shader

View File

@@ -0,0 +1,13 @@
extern vec2 screen = vec2(800.0, 600.0);
extern float steps = 2.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);
for(int i = 1; i <= steps; i++) {
col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y - pSize.y * i));
col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y + pSize.y * i));
}
col = col / (steps * 2.0 + 1.0);
return vec4(col.r, col.g, col.b, 1.0);
}

View File

@@ -0,0 +1,13 @@
extern vec2 screen = vec2(800.0, 600.0);
extern float steps = 2.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);
for(int i = 1; i <= steps; i++) {
col = col + Texel(texture, vec2(texture_coords.x - pSize.x * i, texture_coords.y));
col = col + Texel(texture, vec2(texture_coords.x + pSize.x * i, texture_coords.y));
}
col = col / (steps * 2.0 + 1.0);
return vec4(col.r, col.g, col.b, 1.0);
}

20
src/lib/shaders/glow.glsl Normal file
View File

@@ -0,0 +1,20 @@
extern Image glowImage;
extern float glowTime;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec3 glowInfo = Texel(glowImage, texture_coords).rgb;
if(glowInfo.r != glowInfo.g) {
float glowStrength = glowTime + glowInfo.b;
if(mod(glowStrength, 2.0) < 1.0) {
glowInfo.b = mod(glowStrength, 1.0);
} else {
glowInfo.b = 1.0 - mod(glowStrength, 1.0);
}
return Texel(texture, texture_coords) * (glowInfo.g + glowInfo.b * (glowInfo.r - glowInfo.g));
}
return vec4(Texel(texture, texture_coords).rgb * glowInfo.r, 1.0);
}

View File

@@ -0,0 +1,10 @@
extern Image material;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec4 normal = Texel(texture, texture_coords);
if(normal.a == 1.0) {
return Texel(material, vec2(normal.x, normal.y));
} else {
return vec4(0.0);
}
}

View File

@@ -0,0 +1,50 @@
#define PI 3.1415926535897932384626433832795
extern vec2 screenResolution;
extern vec3 lightPosition;
extern vec3 lightColor;
extern float lightRange;
extern float lightSmooth;
extern float lightDirection;
extern float lightAngle;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec4 pixelColor = Texel(texture, texture_coords);
if(pixelColor.a > 0.0) {
if(lightAngle > 0.0) {
float angle2 = atan(lightPosition.x - pixel_coords.x, pixel_coords.y - lightPosition.y) + PI;
if(lightDirection - lightAngle > 0 && lightDirection + lightAngle < PI * 2) {
if(angle2 < mod(lightDirection + lightAngle, PI * 2) && angle2 > mod(lightDirection - lightAngle, PI * 2)) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
} else {
if(angle2 < mod(lightDirection + lightAngle, PI * 2) || angle2 > mod(lightDirection - lightAngle, PI * 2)) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
}
}
vec3 normal = pixelColor.rgb;
float dist = distance(lightPosition, vec3(pixel_coords, normal.b));
if(dist < lightRange) {
vec3 dir = vec3((lightPosition.xy - pixel_coords.xy) / screenResolution.xy, lightPosition.z);
dir.x *= screenResolution.x / screenResolution.y;
vec3 N = normalize(normal * 2.0 - 1.0);
vec3 L = normalize(dir);
vec3 diff = lightColor * max(dot(N, L), 0.0);
float att = clamp((1.0 - dist / lightRange) / lightSmooth, 0.0, 1.0);
return vec4(diff * att, 1.0);
} else {
return vec4(0.0, 0.0, 0.0, 1.0);
}
} else {
return vec4(0.0);
}
}

View File

@@ -0,0 +1,50 @@
#define PI 3.1415926535897932384626433832795
extern vec2 screenResolution;
extern vec3 lightPosition;
extern vec3 lightColor;
extern float lightRange;
extern float lightSmooth;
extern float lightDirection;
extern float lightAngle;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec4 pixelColor = Texel(texture, texture_coords);
if(pixelColor.a > 0.0) {
if(lightAngle > 0.0) {
float angle2 = atan(lightPosition.x - pixel_coords.x, pixel_coords.y - lightPosition.y) + PI;
if(lightDirection - lightAngle > 0 && lightDirection + lightAngle < PI * 2) {
if(angle2 < mod(lightDirection + lightAngle, PI * 2) && angle2 > mod(lightDirection - lightAngle, PI * 2)) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
} else {
if(angle2 < mod(lightDirection + lightAngle, PI * 2) || angle2 > mod(lightDirection - lightAngle, PI * 2)) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
}
}
vec3 normal = vec3(pixelColor.r, 1 - pixelColor.g, pixelColor.b);
float dist = distance(lightPosition, vec3(pixel_coords, normal.b));
if(dist < lightRange) {
vec3 dir = vec3((lightPosition.xy - pixel_coords.xy) / screenResolution.xy, lightPosition.z);
dir.x *= screenResolution.x / screenResolution.y;
vec3 N = normalize(normal * 2.0 - 1.0);
vec3 L = normalize(dir);
vec3 diff = lightColor * max(dot(N, L), 0.0);
float att = clamp((1.0 - dist / lightRange) / lightSmooth, 0.0, 1.0);
return vec4(diff * att, 1.0);
} else {
return vec4(0.0, 0.0, 0.0, 1.0);
}
} else {
return vec4(0.0);
}
}

View File

@@ -0,0 +1,41 @@
#define PI 3.1415926535897932384626433832795
extern vec3 lightPosition;
extern vec3 lightColor;
extern float lightRange;
extern float lightSmooth;
extern vec2 lightGlow;
extern float lightDirection;
extern float lightAngle;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){
vec4 pixel = Texel(texture, texture_coords);
vec3 lightToPixel = vec3(pixel_coords.x, pixel_coords.y, 0.0) - lightPosition;
float distance = length(lightToPixel);
float att = 1 - distance / lightRange;
if(lightAngle > 0.0) {
float angle2 = atan(lightPosition.x - pixel_coords.x, pixel_coords.y - lightPosition.y) + PI;
if(lightDirection - lightAngle > 0 && lightDirection + lightAngle < PI * 2) {
if(angle2 < mod(lightDirection + lightAngle, PI * 2) && angle2 > mod(lightDirection - lightAngle, PI * 2)) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
} else {
if(angle2 < mod(lightDirection + lightAngle, PI * 2) || angle2 > mod(lightDirection - lightAngle, PI * 2)) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
}
}
if (distance <= lightRange) {
if (lightGlow.x < 1.0 && lightGlow.y > 0.0) {
pixel.rgb = clamp(lightColor * pow(att, lightSmooth) + pow(smoothstep(lightGlow.x, 1.0, att), lightSmooth) * lightGlow.y, 0.0, 1.0);
} else {
pixel.rgb = lightColor * pow(att, lightSmooth);
}
} else {
return vec4(0.0, 0.0, 0.0, 1.0);
}
return pixel;
}

View File

@@ -0,0 +1,24 @@
extern float exposure = 0.7;
extern float brightness = 1.0;
extern vec3 lumacomponents = vec3(1.0, 1.0, 1.0);
// luma
//const vec3 lumcoeff = vec3(0.299,0.587,0.114);
const vec3 lumcoeff = vec3(0.212671, 0.715160, 0.072169);
vec4 effect(vec4 vcolor, Image texture, vec2 texcoord, vec2 pixel_coords)
{
vec4 input0 = Texel(texture, texcoord);
//exposure knee
input0 *= (exp2(input0)*vec4(exposure));
vec4 lumacomponents = vec4(lumcoeff * lumacomponents, 0.0 );
float luminance = dot(input0,lumacomponents);
vec4 luma = vec4(luminance);
return vec4(luma.rgb * brightness, 1.0);
}

View File

@@ -0,0 +1,13 @@
extern vec2 screen = vec2(800.0, 600.0);
extern vec2 redStrength = vec2(4.0, 3.0);
extern vec2 greenStrength = vec2(-2.0, -1.0);
extern vec2 blueStrength = vec2(1.0, -3.0);
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec2 pSize = vec2(1.0 / screen.x, 1.0 / screen.y);
float colRed = Texel(texture, vec2(texture_coords.x + pSize.x * redStrength.x, texture_coords.y - pSize.y * redStrength.y)).r;
float colGreen = Texel(texture, vec2(texture_coords.x + pSize.x * greenStrength.x, texture_coords.y - pSize.y * greenStrength.y)).g;
float colBlue = Texel(texture, vec2(texture_coords.x + pSize.x * blueStrength.x, texture_coords.y - pSize.y * blueStrength.y)).b;
return vec4(colRed, colGreen, colBlue, 1.0);
}

View File

@@ -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);
}

View File

@@ -0,0 +1,88 @@
extern vec2 inputSize;
extern vec2 textureSize;
#define distortion 0.2
/*
#define f 0.6
#define ox 0.5
#define oy 0.5
#define scale 0.8
#define k1 0.7
#define k2 -0.5
vec2 barrelDistort(vec2 coord)
{
vec2 xy = (coord - vec2(ox, oy))/vec2(f) * scale;
vec2 r = vec2(sqrt(dot(xy, xy)));
float r2 = float(r*r);
float r4 = r2*r2;
float coeff = (k1*r2 + k2*r4);
return ((xy+xy*coeff) * f) + vec2(ox, oy);
}
*/
vec2 radialDistortion(vec2 coord, const vec2 ratio)
{
float offsety = 1.0 - ratio.y;
coord.y -= offsety;
coord /= ratio;
vec2 cc = coord - 0.5;
float dist = dot(cc, cc) * distortion;
vec2 result = coord + cc * (1.0 + dist) * dist;
result *= ratio;
result.y += offsety;
return result;
}
/*
vec4 checkTexelBounds(Image texture, vec2 coords, vec2 bounds)
{
vec4 color = Texel(texture, coords) *
vec2 ss = step(coords, vec2(bounds.x, 1.0)) * step(vec2(0.0, bounds.y), coords);
color.rgb *= ss.x * ss.y;
color.a = step(color.a, ss.x * ss.y);
return color;
}*/
vec4 checkTexelBounds(Image texture, vec2 coords, vec2 bounds)
{
vec2 ss = step(coords, vec2(bounds.x, 1.0)) * step(vec2(0.0, bounds.y), coords);
return Texel(texture, coords) * ss.x * ss.y;
}
/*
vec4 checkTexelBounds(Image texture, vec2 coords)
{
vec2 bounds = vec2(inputSize.x / textureSize.x, 1.0 - inputSize.y / textureSize.y);
vec4 color;
if (coords.x > bounds.x || coords.x < 0.0 || coords.y > 1.0 || coords.y < bounds.y)
color = vec4(0.0, 0.0, 0.0, 1.0);
else
color = Texel(texture, coords);
return color;
}
*/
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
vec2 coords = radialDistortion(texture_coords, inputSize / textureSize);
vec4 texcolor = checkTexelBounds(texture, coords, vec2(inputSize.x / textureSize.x, 1.0 - inputSize.y / textureSize.y));
texcolor.a = 1.0;
return texcolor;
}

View File

@@ -0,0 +1,42 @@
/*
Edge shader
Author: Themaister
License: Public domain.
modified by slime73 for use with love2d and mari0
*/
extern vec2 textureSize;
vec3 grayscale(vec3 color)
{
return vec3(dot(color, vec3(0.3, 0.59, 0.11)));
}
vec4 effect(vec4 vcolor, Image texture, vec2 tex, vec2 pixel_coords)
{
vec4 texcolor = Texel(texture, tex);
float x = 0.5 / textureSize.x;
float y = 0.5 / textureSize.y;
vec2 dg1 = vec2( x, y);
vec2 dg2 = vec2(-x, y);
vec3 c00 = Texel(texture, tex - dg1).xyz;
vec3 c02 = Texel(texture, tex + dg2).xyz;
vec3 c11 = texcolor.xyz;
vec3 c20 = Texel(texture, tex - dg2).xyz;
vec3 c22 = Texel(texture, tex + dg1).xyz;
vec2 texsize = textureSize;
vec3 first = mix(c00, c20, fract(tex.x * texsize.x + 0.5));
vec3 second = mix(c02, c22, fract(tex.x * texsize.x + 0.5));
vec3 res = mix(first, second, fract(tex.y * texsize.y + 0.5));
vec4 final = vec4(5.0 * grayscale(abs(res - c11)), 1.0);
return clamp(final, 0.0, 1.0);
}

View File

@@ -0,0 +1,8 @@
extern vec3 palette[4];
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){
vec4 pixel = Texel(texture, texture_coords);
int index = int(min(0.9999, max(0.0001,(pixel.r + pixel.g + pixel.b) / 3.0)) * 4);
return vec4(palette[index], 1.0);
}

View File

@@ -0,0 +1,9 @@
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
vec4 rgb = Texel(texture, texture_coords);
vec4 intens = smoothstep(0.2,0.8,rgb) + normalize(vec4(rgb.xyz, 1.0));
if (fract(pixel_coords.y * 0.5) > 0.5) intens = rgb * 0.8;
intens.a = 1.0;
return intens;
}

View File

@@ -0,0 +1,13 @@
extern float time = 0.0;
extern vec3 tint = vec3(1.0, 1.0, 1.0);
extern float fudge = 0.1;
float rand(vec2 position, float seed) {
return fract(sin(dot(position.xy,vec2(12.9898, 78.233))) * seed);
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){
vec4 pixel = Texel(texture, texture_coords);
float intensity = (pixel.r + pixel.g + pixel.b) / 3.0 + (rand(texture_coords, time) - 0.5) * fudge;
return vec4(intensity * tint.r, intensity * tint.g, intensity * tint.b, 1.0);
}

View File

@@ -0,0 +1,159 @@
/*
caligari's scanlines
Copyright (C) 2011 caligari
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
(caligari gave their consent to have this shader distributed under the GPL
in this message:
http://board.byuu.org/viewtopic.php?p=36219#p36219
"As I said to Hyllian by PM, I'm fine with the GPL (not really a bi
deal...)"
)
*/
extern vec2 textureSize;
// 0.5 = the spot stays inside the original pixel
// 1.0 = the spot bleeds up to the center of next pixel
#define PHOSPHOR_WIDTH 0.9
#define PHOSPHOR_HEIGHT 0.65
// Used to counteract the desaturation effect of weighting.
#define COLOR_BOOST 1.9
// Constants used with gamma correction.
#define InputGamma 2.4
#define OutputGamma 2.2
// Uncomment to only draw every third pixel, which highlights the shape
// of individual (remaining) spots.
// #define DEBUG
// Uncomment one of these to choose a gamma correction method.
// If none are uncommented, no gamma correction is done.
// #define REAL_GAMMA
#define FAKE_GAMMA
// #define FAKER_GAMMA
#ifdef REAL_GAMMA
#define GAMMA_IN(color) pow(color, vec4(InputGamma))
#define GAMMA_OUT(color) pow(color, vec4(1.0 / OutputGamma))
#elif defined FAKE_GAMMA
/*
* Approximations:
* for 1<g<2 : x^g ~ ax + bx^2
* where a=6/(g+1)-2 and b=1-a
* for 2<g<3 : x^g ~ ax^2 + bx^3
* where a=12/(g+1)-3 and b=1-a
* for 1<g<2 : x^(1/g) ~ (sqrt(a^2+4bx)-a)
* where a=6/(g+1)-2 and b=1-a
* for 2<g<3 : x^(1/g) ~ (a sqrt(x) + b sqrt(sqrt(x)))
* where a = 6 - 15g / 2(g+1) and b = 1-a
*/
vec4 A_IN = vec4( 12.0/(InputGamma+1.0)-3.0 );
vec4 B_IN = vec4(1.0) - A_IN;
vec4 A_OUT = vec4(6.0 - 15.0 * OutputGamma / 2.0 / (OutputGamma+1.0));
vec4 B_OUT = vec4(1.0) - A_OUT;
#define GAMMA_IN(color) ( (A_IN + B_IN * color) * color * color )
#define GAMMA_OUT(color) ( A_OUT * sqrt(color) + B_OUT * sqrt( sqrt(color) ) )
#elif defined FAKER_GAMMA
vec4 A_IN = vec4(6.0/( InputGamma/OutputGamma + 1.0 ) - 2.0);
vec4 B_IN = vec4(1.0) - A_IN;
#define GAMMA_IN(color) ( (A_IN + B_IN * color) * color )
#define GAMMA_OUT(color) color
#else // No gamma correction
#define GAMMA_IN(color) color
#define GAMMA_OUT(color) color
#endif
#ifdef DEBUG
vec4 grid_color( vec2 coords )
{
vec2 snes = floor( coords * textureSize );
if ( (mod(snes.x, 3.0) == 0.0) && (mod(snes.y, 3.0) == 0.0) )
return texture2D(_tex0_, coords);
else
return vec4(0.0);
}
#define TEX2D(coords) GAMMA_IN( grid_color( coords ) )
#else // DEBUG
#define TEX2D(coords) GAMMA_IN( texture2D(_tex0_, coords) )
#endif // DEBUG
vec2 onex = vec2( 1.0/textureSize.x, 0.0 );
vec2 oney = vec2( 0.0, 1.0/textureSize.y );
vec4 effect(vec4 vcolor, Image texture, vec2 texCoord, vec2 pixel_coords)
{
vec2 coords = (texCoord * textureSize);
vec2 pixel_start = floor(coords);
coords -= pixel_start;
vec2 pixel_center = pixel_start + vec2(0.5);
vec2 texture_coords = pixel_center / textureSize;
vec4 color = vec4(0.0);
vec4 pixel;
vec3 centers = vec3(-0.25,-0.5,-0.75);
vec3 posx = vec3(coords.x);
vec3 hweight;
float vweight;
float dx,dy;
float w;
float i,j;
for (j = -1.0; j<=1.0; j++) {
// Vertical weight
dy = abs(coords.y - 0.5 - j );
vweight = smoothstep(1.0,0.0, dy / PHOSPHOR_HEIGHT);
if (vweight !=0.0 ) {
for ( i = -1.0; i<=1.0; i++ ) {
pixel = TEX2D(
texture_coords
+ i * onex
+ j * oney
);
/* Evaluate the distance (in x) from
* the pixel (posx) to the RGB centers
* (~centers):
* x_red = 0.25
* x_green = 0.5
* x_blue = 0.75
* if the distance > PHOSPHOR_WIDTH,
* this pixel doesn't contribute
* otherwise, smoothstep gives the
* weight of the contribution
*/
hweight = smoothstep(
1.0, 0.0,
abs((posx + centers - vec3(i))
/ vec3(PHOSPHOR_WIDTH))
);
color.rgb +=
pixel.rgb *
hweight *
vec3(vweight);
}
}
}
color *= vec4(COLOR_BOOST);
color.a = 1.0;
return clamp(GAMMA_OUT(color), 0.0, 1.0);
}

View File

@@ -0,0 +1,48 @@
/*
Plain (and obviously inaccurate) phosphor.
Author: Themaister
License: Public Domain
*/
// modified by slime73 for use with love pixeleffects
extern vec2 textureSize;
vec3 to_focus(float pixel)
{
pixel = mod(pixel + 3.0, 3.0);
if (pixel >= 2.0) // Blue
return vec3(pixel - 2.0, 0.0, 3.0 - pixel);
else if (pixel >= 1.0) // Green
return vec3(0.0, 2.0 - pixel, pixel - 1.0);
else // Red
return vec3(1.0 - pixel, pixel, 0.0);
}
vec4 effect(vec4 vcolor, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
float y = mod(texture_coords.y * textureSize.y, 1.0);
float intensity = exp(-0.2 * y);
vec2 one_x = vec2(1.0 / (3.0 * textureSize.x), 0.0);
vec3 color = Texel(texture, texture_coords - 0.0 * one_x).rgb;
vec3 color_prev = Texel(texture, texture_coords - 1.0 * one_x).rgb;
vec3 color_prev_prev = Texel(texture, texture_coords - 2.0 * one_x).rgb;
float pixel_x = 3.0 * texture_coords.x * textureSize.x;
vec3 focus = to_focus(pixel_x - 0.0);
vec3 focus_prev = to_focus(pixel_x - 1.0);
vec3 focus_prev_prev = to_focus(pixel_x - 2.0);
vec3 result =
0.8 * color * focus +
0.6 * color_prev * focus_prev +
0.3 * color_prev_prev * focus_prev_prev;
result = 2.3 * pow(result, vec3(1.4));
return vec4(intensity * result, 1.0);
}

View File

@@ -0,0 +1,66 @@
#define glarebasesize 0.896
#define power 0.50
extern vec2 textureSize;
extern vec2 outputSize;
extern float time;
const vec3 green = vec3(0.17, 0.62, 0.25);
float luminance(vec3 color)
{
return (0.212671 * color.r) + (0.715160 * color.g) + (0.072169 * color.b);
}
float scanline(float ypos)
{
float c = mod(time * 3.0 + ypos * 5.0, 15.0);
return 1.0 - smoothstep(0.0, 1.0, c);
}
vec4 effect(vec4 vcolor, Image texture, vec2 texcoord, vec2 pixel_coords)
{
vec4 texcolor = Texel(texture, texcoord);
vec4 sum = vec4(0.0);
vec4 bum = vec4(0.0);
vec2 glaresize = vec2(glarebasesize) / textureSize;
float y_one = 1.0 / outputSize.y;
int j;
int i;
for (i = -2; i < 2; i++)
{
for (j = -1; j < 1; j++)
{
sum += Texel(texture, texcoord + vec2(-i, j)*glaresize) * power;
bum += Texel(texture, texcoord + vec2(j, i)*glaresize) * power;
}
}
float a = (scanline(texcoord.y) + scanline(texcoord.y + y_one * 1.5) + scanline(texcoord.y - y_one * 1.5)) / 3.0;
vec4 finalcolor;
if (texcolor.r < 2.0)
{
finalcolor = sum*sum*sum*0.001+bum*bum*bum*0.0080 * (0.8 + 0.05 * a) + texcolor;
}
else
{
finalcolor = vec4(0.0, 0.0, 0.0, 1.0);
}
float lum = pow(luminance(finalcolor.rgb), 1.4);
finalcolor.rgb = lum * green + (a * 0.03);
finalcolor.a = 1.0;
return finalcolor;
}

View File

@@ -0,0 +1,13 @@
extern vec2 textureSize;
const float pixel_w = 2.0;
const float pixel_h = 2.0;
vec4 effect(vec4 vcolor, Image texture, vec2 uv, vec2 pixel_coords)
{
float dx = pixel_w*(1.0/textureSize.x);
float dy = pixel_h*(1.0/textureSize.y);
vec2 coord = vec2(dx*floor(uv.x/dx), dy*floor(uv.y/dy));
return Texel(texture, coord);
}

View File

@@ -0,0 +1,21 @@
#define nsamples 5
extern number blurstart = 1.0; // 0 to 1
extern number blurwidth = -0.02; // -1 to 1
vec4 effect(vec4 vcolor, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
vec4 c = vec4(0.0, 0.0, 0.0, 1.0);
int i;
for (i = 0; i < nsamples; i++)
{
number scale = blurstart + blurwidth * (i / float(nsamples-1));
c.rgb += Texel(texture, texture_coords * scale).rgb;
}
c.rgb /= nsamples;
return c;
}

View File

@@ -0,0 +1,33 @@
extern vec2 screen = vec2(800.0, 600.0);
extern float strength = 2.0;
extern float time = 0.0;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){
vec2 pSize = 1.0 / screen;
float brightness = 1.0;
float offsetX = sin(texture_coords.y * 10.0 + time * strength) * pSize.x;
float corner = 500.0;
if(texture_coords.x < 0.5) {
if(texture_coords.y < 0.5) {
brightness = min(texture_coords.x * texture_coords.y * corner, 1.0);
} else {
brightness = min(texture_coords.x * (1.0 - texture_coords.y) * corner, 1.0);
}
} else {
if(texture_coords.y < 0.5) {
brightness = min((1.0 - texture_coords.x) * texture_coords.y * corner, 1.0);
} else {
brightness = min((1.0 - texture_coords.x) * (1.0 - texture_coords.y) * corner, 1.0);
}
}
float red = Texel(texture, vec2(texture_coords.x + offsetX, texture_coords.y + pSize.y * 0.5)).r;
float green = Texel(texture, vec2(texture_coords.x + offsetX, texture_coords.y - pSize.y * 0.5)).g;
float blue = Texel(texture, vec2(texture_coords.x + offsetX, texture_coords.y)).b;
if(fract(gl_FragCoord.y * (0.5*4.0/3.0)) > 0.5) {
return vec4(vec3(red, green, blue) * brightness, 1.0);
} else {
return vec4(vec3(red * 0.75, green * 0.75, blue * 0.75) * brightness, 1.0);
}
}

View File

@@ -0,0 +1,12 @@
extern Image imgBuffer;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){
vec4 pixel = Texel(texture, texture_coords);
vec4 pixelBuffer = Texel(imgBuffer, texture_coords);
if(texture_coords.y > 0.5) {
return vec4(pixel.rgb * (texture_coords.y - 0.5) * 2.0 + pixelBuffer.rgb * (1.0 - texture_coords.y) * 2.0, 1.0);
} else {
return vec4(pixel.rgb * (0.5 - texture_coords.y) * 2.0 + pixelBuffer.rgb * texture_coords.y * 2.0, 1.0);
}
}

View File

@@ -0,0 +1,57 @@
/*
Themaister's Waterpaint shader
Placed in the public domain.
(From this thread: http://board.byuu.org/viewtopic.php?p=30483#p30483
PD declaration here: http://board.byuu.org/viewtopic.php?p=30542#p30542 )
modified by slime73 for use with love2d and mari0
*/
vec4 compress(vec4 in_color, float threshold, float ratio)
{
vec4 diff = in_color - vec4(threshold);
diff = clamp(diff, 0.0, 100.0);
return in_color - (diff * (1.0 - 1.0/ratio));
}
extern vec2 textureSize;
vec4 effect(vec4 vcolor, Image texture, vec2 tex, vec2 pixel_coords)
{
float x = 0.5 * (1.0 / textureSize.x);
float y = 0.5 * (1.0 / textureSize.y);
vec2 dg1 = vec2( x, y);
vec2 dg2 = vec2(-x, y);
vec2 dx = vec2(x, 0.0);
vec2 dy = vec2(0.0, y);
vec3 c00 = Texel(texture, tex - dg1).xyz;
vec3 c01 = Texel(texture, tex - dx).xyz;
vec3 c02 = Texel(texture, tex + dg2).xyz;
vec3 c10 = Texel(texture, tex - dy).xyz;
vec3 c11 = Texel(texture, tex).xyz;
vec3 c12 = Texel(texture, tex + dy).xyz;
vec3 c20 = Texel(texture, tex - dg2).xyz;
vec3 c21 = Texel(texture, tex + dx).xyz;
vec3 c22 = Texel(texture, tex + dg1).xyz;
vec2 texsize = textureSize;
vec3 first = mix(c00, c20, fract(tex.x * texsize.x + 0.5));
vec3 second = mix(c02, c22, fract(tex.x * texsize.x + 0.5));
vec3 mid_horiz = mix(c01, c21, fract(tex.x * texsize.x + 0.5));
vec3 mid_vert = mix(c10, c12, fract(tex.y * texsize.y + 0.5));
vec3 res = mix(first, second, fract(tex.y * texsize.y + 0.5));
vec4 final = vec4(0.26 * (res + mid_horiz + mid_vert) + 3.5 * abs(res - mix(mid_horiz, mid_vert, 0.5)), 1.0);
final = compress(final, 0.8, 5.0);
final.a = 1.0;
return final;
}

View File

@@ -0,0 +1,24 @@
extern Image backBuffer;
extern vec2 screen = vec2(800.0, 600.0);
extern float reflectionStrength;
extern float reflectionVisibility;
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.a > 0.0 && normal.r > 0.0) {
vec3 pColor = Texel(backBuffer, texture_coords).rgb;
vec4 pColor2;
for(int i = 0; i < reflectionStrength; i++) {
pColor2 = Texel(texture, vec2(texture_coords.x, texture_coords.y + pSize.y * i));
if(pColor2.a > 0.0 && pColor2.g > 0.0) {
vec3 rColor = Texel(backBuffer, vec2(texture_coords.x, texture_coords.y + pSize.y * i * 2.0)).rgb;
return vec4(rColor, (1.0 - i / reflectionStrength) * reflectionVisibility);
}
}
return vec4(0.0);
} else {
return vec4(0.0);
}
}

View File

@@ -0,0 +1,19 @@
extern Image backBuffer;
extern vec2 screen = vec2(800.0, 600.0);
extern float refractionStrength = 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) {
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.b > 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);
}
}

33
src/lib/stencils.lua Normal file
View File

@@ -0,0 +1,33 @@
local stencils = {}
function stencils.shadow(geometry, bodies)
return function()
--cast shadows
for i = 1,#geometry do
if geometry[i].alpha == 1.0 then
love.graphics.polygon("fill", unpack(geometry[i]))
end
end
-- underneath shadows
for i = 1, #bodies do
if not bodies[i].castsNoShadow then
bodies[i]:stencil()
end
end
end
end
function stencils.shine(bodies)
return function()
for i = 1, #bodies do
if bodies[i].shine and
(bodies[i].glowStrength == 0.0 or
(bodies[i].type == "image" and not bodies[i].normal))
then
bodies[i]:stencil()
end
end
end
end
return stencils

43
src/lib/util.lua Normal file
View File

@@ -0,0 +1,43 @@
local util = {}
function util.drawCanvasToCanvas(canvas, other_canvas, options)
options = options or {}
local last_buffer = love.graphics.getCanvas()
love.graphics.push()
love.graphics.origin()
love.graphics.setCanvas(other_canvas)
if options["blendmode"] then
love.graphics.setBlendMode(options["blendmode"])
end
if options["shader"] then
love.graphics.setShader(options["shader"])
end
if options["color"] then
love.graphics.setColor(unpack(options["color"]))
end
love.graphics.setColor(255,255,255)
love.graphics.draw(canvas,0,0)
love.graphics.setCanvas(last_buffer)
if options["blendmode"] then
love.graphics.setBlendMode("alpha")
end
if options["shader"] then
love.graphics.setShader()
end
love.graphics.pop()
end
function util.drawto(canvas, x, y, scale, cb)
local last_buffer = love.graphics.getCanvas()
love.graphics.push()
love.graphics.origin()
love.graphics.setCanvas(canvas)
love.graphics.translate(x, y)
love.graphics.scale(scale)
cb()
love.graphics.setCanvas(last_buffer)
love.graphics.pop()
end
return util

21
src/lib/vector.lua Normal file
View File

@@ -0,0 +1,21 @@
local vector = {}
-- vector functions
function vector.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 vector.dot(v1, v2)
return v1[1] * v2[1] + v1[2] * v2[2]
end
function vector.lengthSqr(v)
return v[1] * v[1] + v[2] * v[2]
end
function vector.length(v)
return math.sqrt(lengthSqr(v))
end
return vector

43
src/main.lua Normal file
View File

@@ -0,0 +1,43 @@
function drawBackground()
--love.graphics.setColor(48, 156, 225)
--love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
love.graphics.setColor(35, 65, 85)
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
end
function drawForground()
love.graphics.setColor(255, 0, 0) --red
love.graphics.rectangle("fill", 10, 10, 17, 27) --x,y,width,height
end
function love.load()
love.graphics.setBackgroundColor(35, 65, 85)
local LightWorld = require "lib.light_world"
lightWorld = LightWorld({
drawBackground = drawBackground,
drawForground = drawForground,
ambient = {55, 55, 55}
})
--box = lightWorld:newBox() ??
light = lightWorld:newLight(love.graphics.getWidth() / 2, love.graphics.getHeight() / 2, 255, 150, 100, 600) -- I don't know what any of these values do
--thompson = lightWorld:newRectangle(100, 100, 255, 0, 0, 17, 27)
thompson = lightWorld:newRectangle(100, 100, 17, 27)
lightWorld:newRectangle(700, 300, 10, 20)
lightWorld:newRectangle(200,5,5,5)
end
function love.update()
love.window.setTitle("Thompson Was a Clone (FPS:" .. love.timer.getFPS() .. ")")
end
function love.draw()
lightWorld:draw(0, 0, 1)
--[[love.graphics.push()
love.graphics.translate(0, 0)
love.graphics.scale(1)
lightWorld:draw(0, 0, 1)
love.graphics.pop()]]
end