init
This commit is contained in:
2
run.bat
Normal file
2
run.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
@ECHO OFF
|
||||
"C:\Program Files\LOVE\love.exe" "%cd%/src"
|
BIN
screenshots/something I am starting on.png
Normal file
BIN
screenshots/something I am starting on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
35
src/conf.lua
Normal file
35
src/conf.lua
Normal 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
651
src/lib/body.lua
Normal 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
47
src/lib/class.lua
Normal 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
225
src/lib/light.lua
Normal 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
432
src/lib/light_world.lua
Normal 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
123
src/lib/normal_map.lua
Normal 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
183
src/lib/postshader.lua
Normal 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
|
13
src/lib/shaders/blurh.glsl
Normal file
13
src/lib/shaders/blurh.glsl
Normal 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);
|
||||
}
|
13
src/lib/shaders/blurv.glsl
Normal file
13
src/lib/shaders/blurv.glsl
Normal 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
20
src/lib/shaders/glow.glsl
Normal 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);
|
||||
}
|
10
src/lib/shaders/material.glsl
Normal file
10
src/lib/shaders/material.glsl
Normal 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);
|
||||
}
|
||||
}
|
50
src/lib/shaders/normal.glsl
Normal file
50
src/lib/shaders/normal.glsl
Normal 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);
|
||||
}
|
||||
}
|
50
src/lib/shaders/normal_invert.glsl
Normal file
50
src/lib/shaders/normal_invert.glsl
Normal 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);
|
||||
}
|
||||
}
|
41
src/lib/shaders/poly_shadow.glsl
Normal file
41
src/lib/shaders/poly_shadow.glsl
Normal 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;
|
||||
}
|
24
src/lib/shaders/postshaders/black_and_white.glsl
Normal file
24
src/lib/shaders/postshaders/black_and_white.glsl
Normal 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);
|
||||
}
|
13
src/lib/shaders/postshaders/chromatic_aberration.glsl
Normal file
13
src/lib/shaders/postshaders/chromatic_aberration.glsl
Normal 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);
|
||||
}
|
6
src/lib/shaders/postshaders/contrast.glsl
Normal file
6
src/lib/shaders/postshaders/contrast.glsl
Normal 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);
|
||||
}
|
88
src/lib/shaders/postshaders/curvature.glsl
Normal file
88
src/lib/shaders/postshaders/curvature.glsl
Normal 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;
|
||||
}
|
||||
|
42
src/lib/shaders/postshaders/edges.glsl
Normal file
42
src/lib/shaders/postshaders/edges.glsl
Normal 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);
|
||||
}
|
||||
|
||||
|
8
src/lib/shaders/postshaders/four_colors.glsl
Normal file
8
src/lib/shaders/postshaders/four_colors.glsl
Normal 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);
|
||||
}
|
9
src/lib/shaders/postshaders/hdr_tv.glsl
Normal file
9
src/lib/shaders/postshaders/hdr_tv.glsl
Normal 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;
|
||||
}
|
13
src/lib/shaders/postshaders/monochrome.glsl
Normal file
13
src/lib/shaders/postshaders/monochrome.glsl
Normal 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);
|
||||
}
|
159
src/lib/shaders/postshaders/phosphor.glsl
Normal file
159
src/lib/shaders/postshaders/phosphor.glsl
Normal 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);
|
||||
}
|
48
src/lib/shaders/postshaders/phosphorish.glsl
Normal file
48
src/lib/shaders/postshaders/phosphorish.glsl
Normal 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);
|
||||
}
|
||||
|
66
src/lib/shaders/postshaders/pip.glsl
Normal file
66
src/lib/shaders/postshaders/pip.glsl
Normal 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;
|
||||
}
|
||||
|
13
src/lib/shaders/postshaders/pixellate.glsl
Normal file
13
src/lib/shaders/postshaders/pixellate.glsl
Normal 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);
|
||||
}
|
21
src/lib/shaders/postshaders/radialblur.glsl
Normal file
21
src/lib/shaders/postshaders/radialblur.glsl
Normal 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;
|
||||
}
|
33
src/lib/shaders/postshaders/scanlines.glsl
Normal file
33
src/lib/shaders/postshaders/scanlines.glsl
Normal 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);
|
||||
}
|
||||
}
|
12
src/lib/shaders/postshaders/tilt_shift.glsl
Normal file
12
src/lib/shaders/postshaders/tilt_shift.glsl
Normal 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);
|
||||
}
|
||||
}
|
57
src/lib/shaders/postshaders/waterpaint.glsl
Normal file
57
src/lib/shaders/postshaders/waterpaint.glsl
Normal 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;
|
||||
}
|
24
src/lib/shaders/reflection.glsl
Normal file
24
src/lib/shaders/reflection.glsl
Normal 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);
|
||||
}
|
||||
}
|
19
src/lib/shaders/refraction.glsl
Normal file
19
src/lib/shaders/refraction.glsl
Normal 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
33
src/lib/stencils.lua
Normal 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
43
src/lib/util.lua
Normal 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
21
src/lib/vector.lua
Normal 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
43
src/main.lua
Normal 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
|
Reference in New Issue
Block a user