Develop #4

Merged
wariosolis merged 35 commits from develop into master 2017-01-04 00:04:34 +01:00
110 changed files with 4753 additions and 58 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+30 -9
View File
@@ -8,9 +8,9 @@ function arrows.load(game, stage, camera)
arrows.left_x = padding arrows.left_x = padding
arrows.left_y = (game.canvas.height / 2) - (arrows.img_left:getHeight() /2) arrows.left_y = (game.canvas.height / 2) - (arrows.img_left:getHeight() /2)
arrows.img_rigth = love.graphics.newImage('assets/sprites/arrows/rigth.png') arrows.img_right = love.graphics.newImage('assets/sprites/arrows/right.png')
arrows.rigth_x = (game.canvas.width - arrows.img_rigth:getWidth()) - padding arrows.right_x = (game.canvas.width - arrows.img_right:getWidth()) - padding
arrows.rigth_y = (game.canvas.height / 2) - (arrows.img_left:getHeight() /2) arrows.right_y = (game.canvas.height / 2) - (arrows.img_left:getHeight() /2)
arrows.game = game arrows.game = game
end end
@@ -22,13 +22,17 @@ function arrows.draw()
if arrows.game.level > 1 then if arrows.game.level > 1 then
love.graphics.draw(arrows.img_left, arrows.left_x, arrows.left_y) love.graphics.draw(arrows.img_left, arrows.left_x, arrows.left_y)
end end
if arrows.game.level ~= arrows.game.end_level then if arrows.game.level < arrows.game.end_level then
love.graphics.draw(arrows.img_rigth, arrows.rigth_x, arrows.rigth_y) love.graphics.draw(arrows.img_right, arrows.right_x, arrows.right_y)
end end
if arrows.game.level == arrows.game.end_level then
arrows.game.var_end = true
end
end end
function love.mousepressed(mx, my, button) function arrows.mousepressed(mx, my, button)
x1,y1,x2,y2,x3,y3,x4,y4 = camera.gcam:getVisibleCorners() x1,y1,x2,y2,x3,y3,x4,y4 = camera.gcam:getVisibleCorners()
wl, wt, ww, wh = camera.gcam:getWorld() wl, wt, ww, wh = camera.gcam:getWorld()
if button == 1 then if button == 1 then
@@ -39,12 +43,29 @@ function love.mousepressed(mx, my, button)
end end
end end
end end
if x2 >= (ww - arrows.img_rigth:getWidth()) then if x2 >= (ww - arrows.img_right:getWidth()) then
if mx >= (ww - x1 - arrows.img_rigth:getWidth()) and mx < (ww - arrows.img_rigth:getWidth()) then same_size = false
if my >= arrows.rigth_y and my < arrows.rigth_y + arrows.img_rigth:getHeight() then if ww == arrows.game.canvas.width and x1 == 0 then
-- Verify canvas == world
same_size = true
end
if same_size then
-- canvas == world
if mx >= arrows.right_x then
if my >= arrows.left_y and my < arrows.left_y + arrows.img_left:getHeight() then
arrows.game:nextLevel() arrows.game:nextLevel()
end end
end end
else
-- large world - scroll cam
if mx >= (ww - x1 - arrows.img_right:getWidth())
and mx <= (ww - arrows.img_right:getWidth())
or same_size then
if my >= arrows.right_y and my < arrows.right_y + arrows.img_right:getHeight() then
arrows.game:nextLevel()
end
end
end
end end
end end
end end
+151 -8
View File
@@ -3,42 +3,185 @@ local tools = require 'assets/scripts/tools'
local HC = require 'assets/scripts/vendor/HC' local HC = require 'assets/scripts/vendor/HC'
local bell = {} local bell = {}
local collision_debug = false
local collisions = {}
local cam_x, cam_y = nil
function bell.load(game, cam) function bell.load(game, cam)
local body = { sound_error = love.audio.newSource('assets/audio/fx/bills/campana_fallo.wav', 'static')
body = {
img = love.graphics.newImage('assets/sprites/bells/bell_vibrate.png'), img = love.graphics.newImage('assets/sprites/bells/bell_vibrate.png'),
num_frames = 10, num_frames = 10,
speed = 0.05, speed = 0.05,
active = false,
x = -game.canvas.width, x = -game.canvas.width,
y = -game.canvas.height y = -game.canvas.height
} }
g = anim8.newGrid(body.img:getWidth() / body.num_frames, body.img:getHeight(), body.img:getWidth(), body.img:getHeight()) g = anim8.newGrid(body.img:getWidth() / body.num_frames, body.img:getHeight(), body.img:getWidth(), body.img:getHeight())
body.animation = anim8.newAnimation(g('1-' .. body.num_frames, 1), body.speed, 'pauseAtEnd') body.animation = anim8.newAnimation(g('1-' .. body.num_frames, 1), body.speed)
body.animation:pause() body.animation:pause()
local cam_x, cam_y = cam:getVisible() cam_x, cam_y = cam.gcam:getVisible()
bell_1 = tools.clone_table(body) bell_1 = tools.clone_table(body)
bell_1.x = cam_x + (game.window.width / 4) - (bell_1.img:getWidth() / body.num_frames / 2) bell_1.x = cam_x + (game.window.width / 4) - (bell_1.img:getWidth() / body.num_frames / 2)
bell_1.y = (game.window.height / 2) - (bell_1.img:getHeight() / 2) bell_1.y = (game.window.height / 2) - (bell_1.img:getHeight() / 2)
bell_1.sound_loop = love.audio.newSource('assets/audio/fx/bills/campana_loop1.wav', 'static')
bell_1.sound_good = love.audio.newSource('assets/audio/fx/bills/campana_exito1.wav', 'static')
bell_2 = tools.clone_table(body) bell_2 = tools.clone_table(body)
bell_2.x = cam_x + (game.window.width / 4 * 2) - (bell_1.img:getWidth() / body.num_frames / 2) bell_2.x = cam_x + (game.window.width / 4 * 2) - (bell_1.img:getWidth() / body.num_frames / 2)
bell_2.y = bell_1.y bell_2.y = bell_1.y
bell_2.sound_loop = love.audio.newSource('assets/audio/fx/bills/campana_loop2.wav', 'static')
bell_2.sound_good = love.audio.newSource('assets/audio/fx/bills/campana_exito2.wav', 'static')
bell_3 = tools.clone_table(body) bell_3 = tools.clone_table(body)
bell_3.x = cam_x + (game.window.width / 4 * 3) - (bell_1.img:getWidth() / body.num_frames / 2) bell_3.x = cam_x + (game.window.width / 4 * 3) - (bell_1.img:getWidth() / body.num_frames / 2)
bell_3.y = bell_1.y bell_3.y = bell_1.y
bell_3.sound_loop = love.audio.newSource('assets/audio/fx/bills/campana_loop3.wav', 'static')
bell_3.sound_good = love.audio.newSource('assets/audio/fx/bills/campana_exito3.wav', 'static')
bells = {bell_1, bell_2, bell_3}
-- Collisions
collisions.size = 15
collisions.positions = {}
collisions.num = 15
collisions.correction = 45
-- Make positions collisions
for i = 1, collisions.num, 1 do
local tem_x, tem_y = tools.cicle_positions(0, 0, bell_1.img:getHeight() / 2, 360 / collisions.num * i)
collisions.positions[i] = {x=tem_x, y=tem_y}
end
-- Add collisions
for key, bell in pairs(bells) do
bell.collisions = {}
bell.enable = {}
for key, collision in pairs(collisions.positions) do
bell.collisions[key] = HC.circle(bell.x + collision.x, collision.y, collisions.size)
bell.enable[key] = false
end
end
end end
function bell.update(dt, game, cam) function bell.update(dt, game, cam)
if game.bells_enable then
-- Update cam position
cam_x, cam_y = cam.gcam:getVisible()
-- Ani bells
bell_1.animation:update(dt) bell_1.animation:update(dt)
bell_2.animation:update(dt) bell_2.animation:update(dt)
bell_3.animation:update(dt) bell_3.animation:update(dt)
-- Bells fix pos
bell_1.x = cam_x + (game.window.width / 4) - (bell_1.img:getWidth() / body.num_frames / 2)
bell_2.x = cam_x + (game.window.width / 4 * 2) - (bell_1.img:getWidth() / body.num_frames / 2)
bell_3.x = cam_x + (game.window.width / 4 * 3) - (bell_1.img:getWidth() / body.num_frames / 2)
-- Collisions fix pos
for key, bell in pairs(bells) do
for key, collision in pairs(collisions.positions) do
bell.collisions[key]:moveTo(collisions.positions[key].x + bell.x + (bell.img:getHeight() / 2) + collisions.correction, collisions.positions[key].y + bell.y + (bell.img:getHeight() / 2))
end
end
-- Check collisions
for key, bell in pairs(bells) do
for key, collision in pairs(bell.collisions) do
for shape, delta in pairs(HC.collisions(bell.collisions[key])) do
if bell.sound_loop:isPlaying() == false then
bell.sound_loop:play()
end
bell.enable[key] = true
end
end
end
for key, bell in pairs(bells) do
for key, collision in pairs(bell.collisions) do
for shape, delta in pairs(HC.collisions(bell.collisions[key])) do
bell.enable[key] = true
end
end
end
-- Logic
local num_enable = 0
for key, bell in pairs(bells) do
for key, item in pairs(bell.enable) do
-- Count enables
num_enable = num_enable + 1
end
if num_enable > 1 then
-- Search emptys
local count_singles = 0
for key, item in pairs(bell.enable) do
if key > 1 and bell.enable[key] and bell.enable[key - 1] == false then
count_singles = count_singles + 1
end
end
-- Bad. Restart
if count_singles >= 2 then
for key, bell in pairs(bells) do
bell.sound_loop:stop()
end
sound_error:play()
for key, item in pairs(bell.enable) do
bell.enable[key] = false
end
end
-- Check good
local good = true
for key, item in pairs(bell.enable) do
if bell.enable[key] == false then
good = false
end
end
-- Enable animation good
if good then
bell.active = true
bell.animation:resume()
bell.sound_good:play()
bell.animation:resume()
for key, item in pairs(bell.enable) do
bell.enable[key] = false
end
end
good = true
count_singles = 0
end
num_enable = 0
end
-- Game over
game_over = true
for key, bell in pairs(bells) do
if not bell.active then
game_over = false
end
end
for key, bell in pairs(bells) do
if game_over then
bell.animation:pauseAtEnd()
game.bells_enable = false
end
end
if game_over then
game.status = game.status + 1
end
end
end end
function bell.draw() function bell.draw(game)
if bells_enable then if game.bells_enable then
bell_1.animation:draw(bell_1.img, bell_1.x, bell_1.y) -- Bells
bell_2.animation:draw(bell_2.img, bell_2.x, bell_2.y) for key, bell in pairs(bells) do
bell_3.animation:draw(bell_3.img, bell_3.x, bell_3.y) bell.animation:draw(bell.img, bell.x, bell.y)
end
-- Collisions
if collision_debug then
for key, bell in pairs(bells) do
for key, collision in pairs(collisions.positions) do
if bell.enable[key] then
bell.collisions[key]:draw('fill')
else
bell.collisions[key]:draw('line')
end
end
end
end
end end
end end
+11 -3
View File
@@ -1,12 +1,15 @@
local controls = {} local HC = require 'assets/scripts/vendor/HC'
local controls = {}
local limit = 10 local limit = 10
function controls.load(game) function controls.load(game)
-- add a circle to the scene
controls.mouse = HC.circle(400,300, 1)
controls.mouse:moveTo(love.mouse.getPosition())
end end
function controls.update(dt, game) function controls.update(dt, game, camera)
control_up, control_right, control_left, control_quit = false, false, false, false control_up, control_right, control_left, control_quit = false, false, false, false
-- Keyboard -- Keyboard
if love.keyboard.isDown('escape') or love.keyboard.isDown('q') then if love.keyboard.isDown('escape') or love.keyboard.isDown('q') then
@@ -22,6 +25,11 @@ function controls.update(dt, game)
control_up = true control_up = true
end end
-- Mouse -- Mouse
-- move circle to mouse position
local cam_x, cam_y = camera.gcam:getPosition()
local mouse_x, mouse_y = love.mouse.getPosition()
controls.mouse:moveTo(cam_x + mouse_x - 640 , mouse_y)
if control_left then if control_left then
if game.canvas.x > game.window.width / 2 then if game.canvas.x > game.window.width / 2 then
game.canvas.x = game.canvas.x - limit game.canvas.x = game.canvas.x - limit
+47 -5
View File
@@ -1,4 +1,5 @@
local game = {} local game = {}
local gamera = require 'assets/scripts/vendor/gamera'
function game.load() function game.load()
-- Configuration -- Configuration
@@ -8,7 +9,8 @@ function game.load()
game.window = { width = width , height = height } game.window = { width = width , height = height }
game.canvas = { x = width / 2, y= 0, width = canvas_width, height = canvas_height } game.canvas = { x = width / 2, y= 0, width = canvas_width, height = canvas_height }
game.level = 1 game.level = 1
game.end_level = 2 game.end_level = 7
game.start_screen = true
love.window.setMode(game.window.width, game.window.height) love.window.setMode(game.window.width, game.window.height)
@@ -17,20 +19,60 @@ function game.load()
local gravity = 2 local gravity = 2
love.physics.setMeter(world_meter) -- Height earth in meters love.physics.setMeter(world_meter) -- Height earth in meters
game.world = love.physics.newWorld(0, gravity * world_meter, true) -- Make earth game.world = love.physics.newWorld(0, gravity * world_meter, true) -- Make earth
game.status = 1
-- Collisions
--game.collisions = HC.new(150)
-- Bells -- Bells
bells_enable = false game.bells_enable = false
game.music = love.audio.newSource("assets/audio/music/theme_biblia.wav")
game.stress = false
game.var_end = false
end
function game.update(dt)
if game.bells_enable then
game:stopMusic()
else
if game.var_end == false then
game:playMusic()
else
game:stopMusic()
end
end
end end
function game:nextLevel() function game:nextLevel()
if game.level == game.end_level then
game.level = 1
else
game.level = game.level + 1 game.level = game.level + 1
end
end end
function game:prevLevel() function game:prevLevel()
if game.level > 1 then
game.level = game.level - 1 game.level = game.level - 1
else
game.level = game.end_level
end
end
function game:setNewSizeWorld(canvas_width, canvas_height)
local width, height = 1280, 720
game.window = { width = width , height = height }
game.canvas = { x = width / 2, y= 0, width = canvas_width, height = canvas_height }
camera.gcam = gamera.new(0, 0, game.window.width, game.window.height)
camera.gcam:setWorld(0, 0, game.canvas.width, game.canvas.height)
end
function game:playMusic()
game.music:play()
end
function game:stopMusic()
game.music:stop()
end end
return game return game
+41
View File
@@ -0,0 +1,41 @@
require 'assets/scripts/vendor/MessageInABottle'
local messages = {}
messages.active = true
function messages.load()
ocean = Ocean:new()
end
function messages.update(dt, game)
ocean:update(dt)
if game.status == 1 and messages.active then
messages.new_message('welcome', 10)
messages.active = false
end
end
function messages.draw()
ocean:draw()
end
function messages.new_message(cap, time)
local texts = {}
texts.welcome = "I must make decision. I wont leave this room until Ive decided to kill my girlfriend or not. How has it come to this? Ive got little time. Her life is teetering through my fingers."
texts.cap1preview="Shes gorgeous in this picture. My mother has given me more than Ill ever be able to give her back. Not only did she give me the gift of life, but a reason to go on. Her lessons and strong character have made me become the man I am now. What I most want in this world is for her to be proud of me. Proud of my work and my partner. But a bitch had to screw it all up. She stepped on what I loved most. She attacked all my mother taught me and undermined my deepest beliefs. I dont believe half-way, like my siblings, but truly. And this girl did nothing but ridicule me. Make fun of me in front of my friends; call me a nutter in private; tell me I was wrong; brand me as a brute - a moron. But shes the moron! Shes just an immoral, sinful whore…I need to calm down, clear my mind. Listen to Gods Word. If I go out now, Ill kill her! I must settle down and think straight. God, speak to me!"
texts.cap2stage=" Corinthians 12:10 That is why, for Christ's sake, I delight in weaknesses, in insults, in hardships, in persecutions, in difficulties. For when I am weak, then I am strong uAs strong as she made me. She laughed at me in front of my friends, but to help me overcome my shyness. She said I was a nutter to help me overcome my issues, to make me realise the obsessions Id inherited from my mother. Brute when I wasnt tolerant with others. And I just got upset…like a moron. A part of my soul still belongs to her. But I mustnt forget where I first met her, where I bought her first kisses. My parents must never know the truth. My mother shall never know about the smokes, the drinks I had. I must destroy that sheet of paper. Nobody must see it."
texts.cap3stage="While the smoke went through my nostrils, I remembered the barbecue parties we threw every Saturday with my family. My cousins adored her and she got on really well with my uncle and aunt. She was completely integrated in my family, so we invited her to come to this barbecue party. And then, while we were saying grace, she started to eat. In the silence you could hear her chewing on a greasy sausage. In shock, they all looked at her, and then, at my grimace. I couldnt believe what was happening. I took her outside to the log cabin. She wont easily forget what I said to her. Id never met such an insensitive person, such a…and as an apology she gave us a fucking compact disc as a gift. Does she really think it would make up for what shed done? What a shitty gift!"
texts.cap4stage="I love this song. I remember now why she bought this one. It was our song. A hidden apology for me. Maybe I got too carried away. After all, shes not religious, shed never said grace. She hadnt even seen how its done. She did what anybody would have done: sit down and start to eat. Poor one. I shouldnt have accepted the album, her tears were more than enough. She meant no harm. But I did…and now I must kill her. I must do it before she starts telling lies about me and harms my family's reputation. I can't allow this to happen. I'm not gay. I'm not sick. I'm not using this key. I'll go out that door and I'll do her in. No more memories, I've made up my mind."
texts.endbad="Die, bitch."
texts.endgood="My bra. It's so uncomfortable. I've always hated wearing it. It makes my breasts hurt. On our first secret anniversary he bought me an outfit. He's got me. He's always helped me grow as a person. To break ties. Like the one I'm in now. Telling my mother I'm a woman who's into other...women. And that the Lord justs wants me to be happy. I've got to be strong. 2 Corinthians 12:10 That is why, for Christ's sake, I delight in weaknesses, in insults, in hardships, in persecutions, in difficulties. For when I am weak, then I am strong uAs strong as she made me. She laughed at me in front of my friends, but to help me overcome my shyness. She said I was a nutter to help me overcome my issues, to make me realise the obsessions Id inherited from my mother. Brute when I wasnt tolerant with others. And I just got upset…like a moron. A part of my soul still belongs to her. Thanks my love."
local bottle = TimeBottle:new(cap, texts['' .. cap], time)
bottle:setX(30)
bottle:setY(500)
bottle:setWidth(1220)
bottle:setHeight(140)
bottle:setVolume(0)
ocean:addBottle(bottle)
end
return messages
+3 -1
View File
@@ -6,7 +6,9 @@ local stage1 = {}
local image local image
function stage1.load(game, camera) function stage1.load(game, camera)
image = love.graphics.newImage('assets/sprites/background/bg.jpg') image = love.graphics.newImage('assets/sprites/background/fondo_puerta.jpg')
stage1.world = { w = image:getWidth(), h= 720}
game:setNewSizeWorld(stage1.world.w, stage1.world.h)
arrows.load(game, stage1, camera) arrows.load(game, stage1, camera)
game.canvas.x = game.window.width game.canvas.x = game.window.width
end end
+40 -4
View File
@@ -6,18 +6,54 @@ local stage2 = {}
local image local image
function stage2.load(game, camera) function stage2.load(game, camera)
image = love.graphics.newImage('assets/sprites/background/bg2.jpg') image_table = love.graphics.newImage('assets/sprites/table/table.jpg')
image_table_hover = love.graphics.newImage('assets/sprites/table/table_hover.jpg')
image_table_none = love.graphics.newImage('assets/sprites/table/table_none.jpg')
stage2.world = { w = image_table:getWidth(), h= 720}
game:setNewSizeWorld(stage2.world.w, stage2.world.h)
arrows.load(game, stage2, camera) arrows.load(game, stage2, camera)
game.canvas.x = game.canvas.width / 2 game.canvas.x = game.window.width / 2
end end
local count_time = 0
function stage2.update(dt, game) function stage2.update(dt, game)
arrows.update(dt) arrows.update(dt)
if game.status == 3 then
if count_time > 22 then
game.status = 4
game.bells_enable = true
else
count_time = dt + count_time
end
end
end end
function stage2.draw() function stage2.draw(game, camera)
love.graphics.draw(image) local mos_x, mos_y = love.mouse.getPosition()
-- No object
love.graphics.draw(image_table_none)
if game.status == 2 then
-- Normal
love.graphics.draw(image_table)
-- Hover
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 527 and mos_x + cam_x < 653 and mos_y - cam_y > 335 and mos_y - cam_y < 423 then
love.graphics.draw(image_table_hover)
end
end
arrows.draw() arrows.draw()
end end
function stage2.mousepressed(game, messages, camera)
local mos_x, mos_y = love.mouse.getPosition()
if game.status == 2 then
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 527 and mos_x + cam_x < 653 and mos_y - cam_y > 335 and mos_y - cam_y < 423 then
game.status = 5
messages.new_message('cap1preview', 10)
end
end
end
return stage2 return stage2
+64
View File
@@ -0,0 +1,64 @@
local anim8 = require 'assets/scripts/vendor/anim8'
local tools = require 'assets/scripts/tools'
local arrows = require 'assets/scripts/arrows'
local stage3 = {}
local image
function stage3.load(game, camera)
image_libreria = love.graphics.newImage('assets/sprites/libreria/libreria.jpg')
image_libreria_hover = love.graphics.newImage('assets/sprites/libreria/libreria_hover.jpg')
image_libreria_none = love.graphics.newImage('assets/sprites/libreria/libreria_none.jpg')
stage3.world = { w = image_libreria:getWidth(), h= 720}
game:setNewSizeWorld(stage3.world.w, stage3.world.h)
arrows.load(game, stage3, camera)
game.canvas.x = game.window.width / 2
end
local count_time = 0
function stage3.update(dt, game)
arrows.update(dt)
if game.status == 5 then
if count_time > 15 then
game.bells_enable = true
game.status = 6
else
count_time = dt + count_time
end
end
end
function stage3.draw(game)
local mos_x, mos_y = love.mouse.getPosition()
-- No object
if game.status > 5 then
love.graphics.draw(image_libreria_none)
else
love.graphics.draw(image_libreria)
end
if game.status == 5 then
-- Normal
love.graphics.draw(image_libreria)
-- Hover
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 709 and mos_x + cam_x < 791 and mos_y - cam_y > 202 and mos_y - cam_y < 354 then
love.graphics.draw(image_libreria_hover)
end
end
arrows.draw()
end
function stage3.mousepressed(game, messages, camera)
local mos_x, mos_y = love.mouse.getPosition()
if game.status == 5 then
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 709 and mos_x + cam_x < 791 and mos_y - cam_y > 202 and mos_y - cam_y < 354 then
game.status = 6
print 'game.status'
print(game.status)
messages.new_message('cap2stage', 15)
end
end
end
return stage3
+63
View File
@@ -0,0 +1,63 @@
local anim8 = require 'assets/scripts/vendor/anim8'
local tools = require 'assets/scripts/tools'
local arrows = require 'assets/scripts/arrows'
local stage4 = {}
local image
function stage4.load(game, camera)
image_libreria = love.graphics.newImage('assets/sprites/chimenea/chimenea.jpg')
image_libreria_hover = love.graphics.newImage('assets/sprites/chimenea/chimenea_hover.jpg')
image_libreria_none = love.graphics.newImage('assets/sprites/chimenea/chimenea_none.jpg')
stage4.world = { w = image_libreria:getWidth(), h= 720}
game:setNewSizeWorld(stage4.world.w, stage4.world.h)
arrows.load(game, stage4, camera)
game.canvas.x = game.window.width / 2
end
local count_time = 0
function stage4.update(dt, game)
arrows.update(dt)
if game.status == 6 then
if count_time > 15 then
game.bells_enable = true
game.status = 6
else
count_time = dt + count_time
end
end
end
function stage4.draw(game)
local mos_x, mos_y = love.mouse.getPosition()
-- No object
if game.status > 6 then
love.graphics.draw(image_libreria_none)
else
love.graphics.draw(image_libreria)
end
if game.status == 6 then
-- Normal
love.graphics.draw(image_libreria)
-- Hover
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 1050 and mos_x + cam_x < 2000 and mos_y - cam_y > 220 and mos_y - cam_y < 275 then
love.graphics.draw(image_libreria_hover)
end
end
arrows.draw()
end
function stage4.mousepressed(game, messages, camera)
local mos_x, mos_y = love.mouse.getPosition()
if game.status == 6 then
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 1050 and mos_x + cam_x < 2000 and mos_y - cam_y > 202 and mos_y - cam_y < 354 then
game.status = 7
messages.new_message('cap3stage', 15)
end
end
end
return stage4
+62
View File
@@ -0,0 +1,62 @@
local anim8 = require 'assets/scripts/vendor/anim8'
local tools = require 'assets/scripts/tools'
local arrows = require 'assets/scripts/arrows'
local stage5 = {}
local image
function stage5.load(game, camera)
image_tocadiscos = love.graphics.newImage('assets/sprites/tocadiscos/tocadiscos.jpg')
image_tocadiscos_hover = love.graphics.newImage('assets/sprites/tocadiscos/tocadiscos_hover.jpg')
image_tocadiscos_none = love.graphics.newImage('assets/sprites/tocadiscos/tocadiscos_none.jpg')
stage5.world = { w = image_tocadiscos:getWidth(), h= 720}
game:setNewSizeWorld(stage5.world.w, stage5.world.h)
arrows.load(game, stage5, camera)
game.canvas.x = game.window.width / 2
end
local count_time = 0
function stage5.update(dt, game)
arrows.update(dt)
if game.status == 7 then
if count_time > 15 then
game.bells_enable = true
game.status = 7
else
count_time = dt + count_time
end
end
end
function stage5.draw(game)
local mos_x, mos_y = love.mouse.getPosition()
-- No object
if game.status > 7 then
love.graphics.draw(image_tocadiscos_none)
else
love.graphics.draw(image_tocadiscos)
end
if game.status == 7 then
-- Normal
love.graphics.draw(image_tocadiscos)
-- Hover
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 1005 and mos_x + cam_x < 1150 and mos_y - cam_y > 470 and mos_y - cam_y < 505 then
love.graphics.draw(image_tocadiscos_hover)
end
end
arrows.draw()
end
function stage5.mousepressed(game, messages, camera)
local mos_x, mos_y = love.mouse.getPosition()
if game.status == 7 then
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 1005 and mos_x + cam_x < 1150 and mos_y - cam_y > 470 and mos_y - cam_y < 505 then
game.status = 8
messages.new_message('cap4stage', 15)
end
end
end
return stage5
+62
View File
@@ -0,0 +1,62 @@
local anim8 = require 'assets/scripts/vendor/anim8'
local tools = require 'assets/scripts/tools'
local arrows = require 'assets/scripts/arrows'
local stage6 = {}
local image
function stage6.load(game, camera)
image_sujetador = love.graphics.newImage('assets/sprites/sujetador/sujetador.jpg')
image_sujetador_hover = love.graphics.newImage('assets/sprites/sujetador/sujetador_hover.jpg')
image_sujetador_none = love.graphics.newImage('assets/sprites/sujetador/sujetador_none.jpg')
stage6.world = { w = image_sujetador:getWidth(), h= 720}
game:setNewSizeWorld(stage6.world.w, stage6.world.h)
arrows.load(game, stage6, camera)
game.canvas.x = game.window.width / 2
end
local count_time = 0
function stage6.update(dt, game)
arrows.update(dt)
if game.status == 8 then
if count_time > 15 then
game.bells_enable = true
game.status = 7
else
count_time = dt + count_time
end
end
end
function stage6.draw(game)
local mos_x, mos_y = love.mouse.getPosition()
-- No object
if game.status > 8 then
love.graphics.draw(image_sujetador_none)
else
love.graphics.draw(image_sujetador)
end
if game.status == 8 then
-- Normal
love.graphics.draw(image_sujetador)
-- Hover
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 462 and mos_x + cam_x < 648 and mos_y - cam_y > 165 and mos_y - cam_y < 560 then
love.graphics.draw(image_sujetador_hover)
end
end
arrows.draw()
end
function stage6.mousepressed(game, messages, camera)
local mos_x, mos_y = love.mouse.getPosition()
if game.status == 8 then
cam_x, cam_y = camera.gcam:getVisible()
if mos_x + cam_x > 462 and mos_x + cam_x < 648 and mos_y - cam_y > 165 and mos_y - cam_y < 560 then
game.status = 9
messages.new_message('cap5stage', 15)
end
end
end
return stage6
+37
View File
@@ -0,0 +1,37 @@
local anim8 = require 'assets/scripts/vendor/anim8'
local tools = require 'assets/scripts/tools'
local arrows = require 'assets/scripts/arrows'
local stage7 = {}
local image
function stage7.load(game, camera)
if game.status == 9 then
image = love.graphics.newImage('assets/sprites/background/final bueno_3.jpg')
stage7.music = love.audio.newSource("assets/audio/fx/door_win.wav")
stage7.music2 = love.audio.newSource("assets/audio/music/our_song_end.mp3")
else
image = love.graphics.newImage('assets/sprites/background/dead.jpg')
stage7.music = love.audio.newSource("assets/audio/fx/door_lose.wav")
end
game:stopMusic()
stage7.world = { w = image:getWidth(), h= 720}
game:setNewSizeWorld(stage7.world.w, stage7.world.h)
arrows.load(game, stage7, camera)
game.canvas.x = game.window.width / 2
stage7.music2:play()
stage7.music:play()
end
function stage7.update(dt, game)
arrows.update(dt)
end
function stage7.draw()
love.graphics.draw(image)
arrows.draw()
end
return stage7
+25
View File
@@ -0,0 +1,25 @@
local anim8 = require 'assets/scripts/vendor/anim8'
local tools = require 'assets/scripts/tools'
local arrows = require 'assets/scripts/arrows'
local stage8 = {}
local image
function stage8.load(game, camera)
image = love.graphics.newImage('assets/sprites/background/fondo_vacio.jpg')
stage8.world = { w = image:getWidth(), h= 720}
game:setNewSizeWorld(stage8.world.w, stage8.world.h)
arrows.load(game, stage8, camera)
game.canvas.x = game.window.width / 2
end
function stage8.update(dt, game)
arrows.update(dt)
end
function stage8.draw()
love.graphics.draw(image)
arrows.draw()
end
return stage8
+10 -3
View File
@@ -15,17 +15,24 @@ end
function stages.update(dt, game, camera) function stages.update(dt, game, camera)
if game.level ~= currentLevel then if game.level ~= currentLevel then
back_pressed = false
if game.level < currentLevel then
back_pressed = true
end
currentLevel = game.level currentLevel = game.level
dynamic_stage = require("assets/scripts/stage"..currentLevel) dynamic_stage = require("assets/scripts/stage"..currentLevel)
dynamic_stage.load(game, camera) dynamic_stage.load(game, camera, back_pressed)
if back_pressed then
game.canvas.x = dynamic_stage.world.w - (game.window.width / 2)
end
dynamic_stage.update(dt, game) dynamic_stage.update(dt, game)
else else
dynamic_stage.update(dt, game) dynamic_stage.update(dt, game)
end end
end end
function stages.draw() function stages.draw(game, camera)
dynamic_stage.draw() dynamic_stage.draw(game, camera)
end end
return stages return stages
+34
View File
@@ -0,0 +1,34 @@
local start = {}
function start.load(game)
start.img = love.graphics.newImage('assets/sprites/menu/start.jpg')
start.music = love.audio.newSource("assets/audio/music/main_theme_menu.mp3")
start.music:play()
start.status = 1
game:stopMusic()
end
function start.update(dt, game)
if game.status == start.status then
game:stopMusic()
end
end
function start.draw(game)
if game.status == start.status then
love.graphics.draw(start.img, 0, 0)
end
end
function start.mousepressed(game)
local mos_x, mos_y = love.mouse.getPosition()
if game.status == start.status then
if mos_x > 411 and mos_x < 578 and mos_y > 400 and mos_y < 479 then
game.status = start.status + 1
start.music:stop()
game:playMusic()
end
end
end
return start
+26
View File
@@ -0,0 +1,26 @@
local anim8 = require 'assets/scripts/vendor/anim8'
local tools = require 'assets/scripts/tools'
local arrows = require 'assets/scripts/arrows'
local stress = {}
local image
function stress.load(game, camera)
image = love.graphics.newImage('assets/sprites/stress/stress.png')
end
function stress.update(dt, game)
stress.stress = game.stress
arrows.update(dt)
end
function stress.draw()
if stress.stress == true then
cam_x, cam_y = camera.gcam:getVisible()
love.graphics.setColor(255, 255, 255, 90)
love.graphics.draw(image, cam_x, cam_y)
end
end
return stress
+8
View File
@@ -71,4 +71,12 @@ function tools.print_r(t)
print() print()
end end
-- Get positions from circle
function tools.cicle_positions(x, y, radius, angle)
local pos_x, pos_y = nil, nil
pos_x = x + radius * math.cos(math.rad(angle))
pos_y = y + radius * math.sin(math.rad(angle))
return pos_x, pos_y
end
return tools return tools
+30
View File
@@ -0,0 +1,30 @@
local stack = {}
function love.graphics.pushState()
--get state
local state = {}
state.blendMode = love.graphics.getBlendMode()
state.color = {love.graphics.getColor()}
state.font = love.graphics.getFont() or 12
state.lineStyle = love.graphics.getLineStyle()
state.scissor = love.graphics.getScissor() or
{love.graphics.getScissor()} or
{0,0,love.graphics.getWidth(), love.graphics.getHeight()}
-- push state
stack[#stack+1] = state
end
function love.graphics.popState()
-- restore state
local state = stack[#stack]
love.graphics.setBlendMode( state.blendMode )
love.graphics.setColor( unpack(state.color) )
love.graphics.setFont( state.font )
love.graphics.setScissor( unpack(state.scissor) )
-- pop state
stack[#stack] = nil
end
+463
View File
@@ -0,0 +1,463 @@
--[[
MessageInABottle.lua - 2010-11-08
http://bitbucket.org/dannyfritz/message-in-a-bottle/
Danny "TechnoCat" Fritz dannyfritz@gmail.com
Commons Attribution-ShareAlike 3.0
--]]
--An OO library for Lua by Kikito,
--can be found at https://github.com/kikito/middleclass
require 'assets/scripts/vendor/MiddleClass'
require 'assets/scripts/vendor/GraphicsStateStack'
MessageBottle = class('MessageBottle')
TimeBottle = MessageBottle:subclass('TimeBottle')
--[[
Default values
--]]
MessageBottle.DEFAULT_SOUND = 'assets/audio/fx/messages/blip.ogg'
MessageBottle.DEFAULT_VOLUME = 0.5
MessageBottle.DEFAULT_BUTTON = ' ' --Button to close/select
MessageBottle.DEFAULT_INDICATOR = love.graphics.newImage('assets/sprites/messages/input-indicator.png') --Image to
MessageBottle.DEFAULT_X = 20
MessageBottle.DEFAULT_Y = 180
MessageBottle.DEFAULT_WIDTH = 300
MessageBottle.DEFAULT_HEIGHT = 80
MessageBottle.DEFAULT_FONT = love.graphics.newFont(18)
MessageBottle.DEFAULT_ALIGN = 'left'
MessageBottle.DEFAULT_FGCOLOR = {r=255,g=255,b=255}
MessageBottle.DEFAULT_FGALPHA = 1
MessageBottle.DEFAULT_BGRADIUS = 10 --pixels to draw the rounded corners
MessageBottle.DEFAULT_BGRADIUSSEGMENTS = 32 --how precisely to draw the circle
MessageBottle.DEFAULT_BGCOLOR = {r=0,g=0,b=0}
MessageBottle.DEFAULT_BGALPHA = 0.3
MessageBottle.DEFAULT_EASETIME = 0.5 --seconds to ease
MessageBottle.DEFAULT_FADETIME = 0.3 --seconds to fade alpha
MessageBottle.DEFAULT_EASEOFFSET = 10
MessageBottle.DEFAULT_ID = "NO_ID"
MessageBottle.DEFAULT_TEXT = "Text is not set."
TimeBottle.TIMEOUT = 6 --seconds to keep the bottle alive
function MessageBottle:drawBackground()
--draw background
--self.bgAlpha
--self.alpha
love.graphics.pushState()
local r,g,b,a = self.bgColor.r, self.bgColor.g, self.bgColor.b
local a = self.bgAlpha * self.alpha
local r = self.bgRadius
local x,y = self.x, self.y
local w,h = self.width, self.height
local segments = self.bgRadiusSegments
love.graphics.setColor(r,g,b,a)
--center rectangle
love.graphics.rectangle("fill",
x, y,
w, h)
--top border
love.graphics.rectangle("fill",
x, y-r,
w, r)
-- right border
love.graphics.rectangle("fill",
x+w, y,
r, h)
--bottom border
love.graphics.rectangle("fill",
x, y+h,
w, r)
--left border
love.graphics.rectangle("fill",
x-r, y,
r, h)
--top left corner
love.graphics.setScissor(
x-r, y-r,
r, r)
love.graphics.circle("fill",
x, y,
r, segments)
--top right corner
love.graphics.setScissor(
x+w, y-r,
r, r)
love.graphics.circle("fill",
x+w, y,
r, segments)
--bottom right corner
love.graphics.setScissor(
x+w, y+h,
r, r)
love.graphics.circle("fill",
x+w, y+h,
r, segments)
--bottom left corner
love.graphics.setScissor(
x-r, y+h,
r, r)
love.graphics.circle("fill",
x, y+h,
r, segments)
love.graphics.popState()
end
--[[
Ocean
This is a class to store and invoke the focussed bottles
(A queue)
--]]
Ocean = class('Ocean')
function Ocean:initialize()
super.initialize(self)
self.bottles = {}
self.response = ""
self.responseTime = 0
self.responseID = ""
self.time = 0
end
function Ocean:update(dt)
if #self.bottles > 0 then
self.time = self.time + dt
local bottle = self.bottles[1]
if bottle.focusTime == 0 then
bottle:enterCallback()
end
local tmp = self.response
self.response = bottle:update(dt)
if self.response==nil then
self.response = tmp
else
self.responseTime = self.time
self.responseID = self.bottles[1].id
end
if not bottle.alive then
bottle:exitCallback(self.response)
table.remove(self.bottles,1)
end
end
end
function Ocean:draw()
if #self.bottles > 0 then
self.bottles[1]:draw()
end
end
function Ocean:addBottle(bottle)
local bottles = self.bottles
table.insert(bottles, #bottles+1, bottle)
end
--[[
Message Bottle
This is a default message bottle class
Bottle background is drawn here.
--]]
function MessageBottle:initialize(id, text)
super.initialize(self)
self.id = id or self.class.DEFAULT_ID
self.text = text or self.class.DEFAULT_TEXT
self.alive = true --Set to flag to mark for deletion
--Callbacks
self.enterCB = function() return end
self.exitCB = function(response) return end
--Sounds
self.sound = self.class.DEFAULT_SOUND
self.volume = self.class.DEFAULT_VOLUME
--Buttons
self.button = self.class.DEFAULT_BUTTON
self.buttonDown = false --Flag to make the button action happen on release
self.indicator = indicator or self.class.DEFAULT_INDICATOR
--Dimensions
self.x = self.class.DEFAULT_X
self.y = self.class.DEFAULT_Y
self.width = self.class.DEFAULT_WIDTH
self.height = self.class.DEFAULT_HEIGHT
--Foreground settings
self.fgColor = self.class.DEFAULT_FGCOLOR
self.fgAlpha = self.class.DEFAULT_FGALPHA
self.font = self.class.DEFAULT_FONT
self.align = self.class.DEFAULT_ALIGN
--Background settings
self.bgColor = self.class.DEFAULT_BGCOLOR
self.bgAlpha = self.class.DEFAULT_BGALPHA
self.bgRadius = self.class.DEFAULT_BGRADIUS
self.bgRadiusSegments = self.class.DEFAULT_RADIUSSEGMENTS
--Ease settings
self.easeTarget = self.class.DEFAULT_Y
self.easeOffset = self.class.DEFAULT_EASEOFFSET
self.easeTime = self.class.DEFAULT_EASETIME
--Fade settings
self.focusTime = 0 --seconds the message has been in focus
self.alpha = 0
self.fadeTime = self.class.DEFAULT_FADETIME
end
function MessageBottle:baseUpdate(dt, focusTime)
self.y = self:ease(focusTime,self.easeTime, self.easeTarget,self.easeOffset)
self.alpha = self:fade(focusTime,self.fadeTime, 0,255)
self.focusTime = self.focusTime + dt
end
function MessageBottle:enterCallback()
--Sound
self.source = love.audio.newSource(self.sound, "static")
self.source:setVolume(self.volume)
self.source:play()
self.enterCB()
end
function MessageBottle:exitCallback(response)
self.exitCB(response)
end
function MessageBottle:ease(t,d, a,b)
if d <= t then
function self:ease(t,d, a,b) return self.y end
end
local v = -(t/d)*(t/d-2)*b+a
return math.floor(v)
end
function MessageBottle:fade(t,d, a,b)
if d <= t then
function self:fade(t,d, a,b) return 255 end
end
local v = t/d*b+a
if v>=255 then
v=255
function self:fade(t,d, a,b) return 255 end
end
return v
end
function MessageBottle:setX(x)
self.x = x
end
function MessageBottle:setY(y)
self.easeTarget = y
self.y = y
end
function MessageBottle:setPosition(x, y)
self.x = x
self.y = y
self.easeTarget = y
end
function MessageBottle:setWidth(width)
self.width = width
end
function MessageBottle:setHeight(height)
self.height = height
end
function MessageBottle:setButton(button)
self.button = button
end
function MessageBottle:setEase(ease)
self.ease = ease
end
function MessageBottle:setEaseTime(easeTime)
self.easeTime = easeTime
end
function MessageBottle:setFade(fade)
self.fade = fade
end
function MessageBottle:setFadeTime(fadeTime)
self.fadeTime = fadeTime
end
function MessageBottle:setEnterCallback(enterCB)
self.enterCB = enterCB
end
function MessageBottle:setExitCallback(exitCB)
self.exitCB = exitCB
end
function MessageBottle:setSound(sound)
if sound==nil then
self.volume = 0
return
end
self.sound = sound
end
function MessageBottle:setVolume(volume)
self.volume = volume
end
function MessageBottle:setIndicator(indicator)
self.indicator = love.graphics.newImage(indicator)
end
function MessageBottle:setFgColor(r, g, b, a)
self.fgColor = {r, g, b, a}
end
function MessageBottle:setFont(font, size)
self.font = love.graphics.newFont(font,size)
end
function MessageBottle:setAlign(align)
self.align = align
end
function MessageBottle:setBgColor(r, g, b, a)
self.bgColor = {r, g, b, a}
end
function MessageBottle:setBgRadius(bgRadius)
self.bgRadius = bgRadius
end
function MessageBottle:setBgRadiusSegments(bgRadiusSegments)
self.bgRadiusSegments = bgRadiusSegments
end
--[[
Staying Bottle
This pops up a message bottle and
goes away after a button is pressed
--]]
StayBottle = MessageBottle:subclass('StayBottle')
function StayBottle:initialize(id, text)
super.initialize(self, id, text)
end
function StayBottle:update(dt)
self:baseUpdate(dt,self.focusTime)
if love.keyboard.isDown(self.button) and self.buttonDown==false then
self.buttonDown = true
elseif self.buttonDown==true and not love.keyboard.isDown(self.button) then
self.alive = false
return 0
end
end
function StayBottle:draw()
love.graphics.pushState()
self:drawBackground()
local color = self.fgColor
love.graphics.setColor(color.r,color.g,color.b,self.alpha)
love.graphics.setFont(self.font)
local text = ""
text = text..self.text..'\n'
local button = self.button
if button == " " then
button = "space"
end
if math.floor(self.focusTime)%2 == 0 then
text = text..'press \''..button..'\' to continue'
else
text = text..'press \''..button..'\' to continue...'
end
love.graphics.printf(text, self.x,self.y, self.width, self.align)
local floaty = math.sin(self.focusTime*3)*3
local y = self.y + self.height + floaty - self.indicator:getHeight()/2
love.graphics.draw(self.indicator,self.x+self.width/2, y)
love.graphics.popState()
end
--[[
Timed Bottle
This pops up a message bottle and
goes away after a set time duration
--]]
function TimeBottle:initialize(id, text, timeout)
super.initialize(self, id, text)
self.timeout = timeout or self.class.TIMEOUT
end
function TimeBottle:update(dt)
self:baseUpdate(dt,self.focusTime)
self.timeout = self.timeout - dt
if love.keyboard.isDown(self.button) and self.buttonDown==false then
self.buttonDown = true
elseif self.buttonDown==true and not love.keyboard.isDown(self.button) then
self.alive = false
return 0
end
if self.timeout <= 0 then --count down a timer
self.alive = false
return 1
end
end
function TimeBottle:draw()
love.graphics.pushState()
self:drawBackground()
local color = self.fgColor
love.graphics.setColor(color.r,color.g,color.b,self.alpha)
love.graphics.setFont(self.font)
love.graphics.printf(self.text, self.x,self.y, self.width, self.align)
love.graphics.popState()
end
function TimeBottle:setTimeout(timeout)
self.timeout = timeout
end
--[[
Choice Bottle
This pops up a message with choices bottle
and goes away after a choice is made
--]]
ChoiceBottle = MessageBottle:subclass('ChoiceBottle')
function ChoiceBottle:initialize(id, text, ...)
super.initialize(self, id, text)
end
function ChoiceBottle:update(dt)
--Draw text and choices along with cursor
--Check keyboard / mouse input for selection
end
function ChoiceBottle:draw()
end
+125
View File
@@ -0,0 +1,125 @@
-----------------------------------------------------------------------------------
-- MiddleClass.lua
-- Enrique García ( enrique.garcia.cota [AT] gmail [DOT] com ) - 19 Oct 2009
-- Based on YaciCode, from Julien Patte and LuaObject, from Sébastien Rocca-Serra
-----------------------------------------------------------------------------------
local _classes = setmetatable({}, {__mode = "k"}) -- weak table storing references to all declared _classes and their included modules
Object = { name = "Object" } -- The 'Object' class
_classes[Object] = { modules={} } -- adds Object to the list of _classes
-- creates a new instance
Object.new = function(theClass, ...)
assert(_classes[theClass]~=nil, "Use class:new instead of class.new")
local instance = setmetatable({ class = theClass }, theClass.__classDict)
instance:initialize(...)
return instance
end
local _metamethods = { '__add', '__sub', '__mul', '__div', '__mod', '__pow', '__unm',
'__lt', '__le', '__call', '__gc', '__tostring', '__concat' }
-- creates a subclass
Object.subclass = function(theClass, name)
assert(_classes[theClass]~=nil, "Use class:subclass instead of class.subclass")
assert( type(name)=="string", "You must provide a name(string) for your class")
local theSubclass = { name = name, superclass = theClass, __classDict = {} }
local classDict = theSubclass.__classDict
-- classDict is the instances' metatable. It "points to himself" so they start looking for methods there.
classDict.__index = classDict
-- metamethods & methods are "looked up" through implementation and __index
for _,m in ipairs(_metamethods) do
classDict[m]= function(...)
assert( type(theClass.__classDict[m])=='function', "Class " .. theSubclass.name .. " does not implement the " .. m .. " metamethod")
return theClass.__classDict[m](...)
end
end
setmetatable(classDict, {__index = theClass.__classDict})
-- control how the new methods are inserted on the subclass, and how they are looked up
setmetatable(theSubclass, {
__index = function(_,methodName)
-- search first on the subclass's classdict, then on the superclass
return classDict[methodName]~= nil and classDict[methodName] or theClass[methodName]
end,
__newindex = function(_, methodName, method) -- when adding new methods, include a "super" function
if type(method) == 'function' then
local fenv = getfenv(method)
local newenv = setmetatable( {super = theClass.__classDict}, {__index = fenv, __newindex = fenv} )
setfenv( method, newenv )
end
rawset(classDict, methodName, method)
end,
__tostring = function() return ("class ".. name) end,
__call = function(_, ...) return theSubclass:new(...) end
})
-- instance methods go after the setmetatable, so we can use "super"
theSubclass.initialize = function(instance,...) super.initialize(instance) end
_classes[theSubclass]={ modules={} } --registers the new class on the list of _classes
theClass:subclassed(theSubclass) -- hook method. By default it does nothing
return theSubclass
end
-- Mixin extension function - simulates very basically ruby's include(module)
-- module is a lua table of functions. The functions will be copied to the class
-- if present in the module, the included() method will be called
Object.include = function(theClass, module, ... )
assert(_classes[theClass]~=nil, "Use class:includes instead of class.includes")
for methodName,method in pairs(module) do
if methodName ~="included" then theClass[methodName] = method end
end
if type(module.included)=="function" then module:included(theClass, ... ) end
_classes[theClass].modules[module] = true
return theClass
end
-- built-in methods
Object.__classDict = {
initialize = function(instance, ...) end, -- empty method
destroy = function(instance) end, -- empty method
__tostring = function(instance) return ("instance of ".. instance.class.name) end,
subclassed = function(theClass, other) end -- empty method
}
Object.__classDict.__index = Object.__classDict -- instances of Object need this
-- This allows doing tostring(obj) and Object() instead of Object:new()
setmetatable(Object, { __index = Object.__classDict, __newindex = Object.__classDict,
__tostring = function() return ("class Object") end,
__call = Object.new
})
-- Returns true if aClass is a subclass of other, false otherwise
function subclassOf(other, aClass)
if _classes[aClass]==nil or _classes[other]==nil then return false end
if aClass.superclass==nil then return false end -- aClass is Object, or a non-class
return aClass.superclass == other or subclassOf(other, aClass.superclass)
end
-- Returns true if obj is an instance of aClass (or one of its subclasses) false otherwise
function instanceOf(aClass, obj)
if _classes[aClass]==nil or type(obj)~='table' or _classes[obj.class]==nil then return false end
if obj.class==aClass then return true end
return subclassOf(aClass, obj.class)
end
-- Returns true if the a module has already been included on a class (or a superclass of that class)
function includes(module, aClass)
if _classes[aClass]==nil or _classes[aClass].modules==nil then return false end
if _classes[aClass].modules[module] then return true end
return includes(module, aClass.superclass)
end
-- Creates a new class named 'name'. Uses Object if no baseClass is specified. Additional parameters for compatibility
function class(name, baseClass, ...)
baseClass = baseClass or Object
return baseClass:subclass(name, ...)
end
+724
View File
@@ -0,0 +1,724 @@
--
-- lovebird
--
-- Copyright (c) 2016 rxi
--
-- This library is free software; you can redistribute it and/or modify it
-- under the terms of the MIT license. See LICENSE for details.
--
local socket = require "socket"
local lovebird = { _version = "0.4.1" }
lovebird.loadstring = loadstring or load
lovebird.inited = false
lovebird.host = "*"
lovebird.buffer = ""
lovebird.lines = {}
lovebird.connections = {}
lovebird.pages = {}
lovebird.wrapprint = true
lovebird.timestamp = true
lovebird.allowhtml = false
lovebird.echoinput = true
lovebird.port = 8000
lovebird.whitelist = { "127.0.0.1" }
lovebird.maxlines = 200
lovebird.updateinterval = .5
lovebird.pages["index"] = [[
<?lua
-- Handle console input
if req.parsedbody.input then
local str = req.parsedbody.input
if lovebird.echoinput then
lovebird.pushline({ type = 'input', str = str })
end
if str:find("^=") then
str = "print(" .. str:sub(2) .. ")"
end
xpcall(function() assert(lovebird.loadstring(str, "input"))() end,
lovebird.onerror)
end
?>
<!doctype html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=Edge"/>
<title>lovebird</title>
<style>
body {
margin: 0px;
font-size: 14px;
font-family: helvetica, verdana, sans;
background: #FFFFFF;
}
form {
margin-bottom: 0px;
}
.timestamp {
color: #909090;
padding-right: 4px;
}
.repeatcount {
color: #F0F0F0;
background: #505050;
font-size: 11px;
font-weight: bold;
text-align: center;
padding-left: 4px;
padding-right: 4px;
padding-top: 0px;
padding-bottom: 0px;
border-radius: 7px;
display: inline-block;
}
.errormarker {
color: #F0F0F0;
background: #8E0000;
font-size: 11px;
font-weight: bold;
text-align: center;
border-radius: 8px;
width: 17px;
padding-top: 0px;
padding-bottom: 0px;
display: inline-block;
}
.greybordered {
margin: 12px;
background: #F0F0F0;
border: 1px solid #E0E0E0;
border-radius: 3px;
}
.inputline {
font-family: mono, courier;
font-size: 13px;
color: #606060;
}
.inputline:before {
content: '\00B7\00B7\00B7';
padding-right: 5px;
}
.errorline {
color: #8E0000;
}
#header {
background: #101010;
height: 25px;
color: #F0F0F0;
padding: 9px
}
#title {
float: left;
font-size: 20px;
}
#title a {
color: #F0F0F0;
text-decoration: none;
}
#title a:hover {
color: #FFFFFF;
}
#version {
font-size: 10px;
}
#status {
float: right;
font-size: 14px;
padding-top: 4px;
}
#main a {
color: #000000;
text-decoration: none;
background: #E0E0E0;
border: 1px solid #D0D0D0;
border-radius: 3px;
padding-left: 2px;
padding-right: 2px;
display: inline-block;
}
#main a:hover {
background: #D0D0D0;
border: 1px solid #C0C0C0;
}
#console {
position: absolute;
top: 40px; bottom: 0px; left: 0px; right: 312px;
}
#input {
position: absolute;
margin: 10px;
bottom: 0px; left: 0px; right: 0px;
}
#inputbox {
width: 100%;
font-family: mono, courier;
font-size: 13px;
}
#output {
overflow-y: scroll;
position: absolute;
margin: 10px;
line-height: 17px;
top: 0px; bottom: 36px; left: 0px; right: 0px;
}
#env {
position: absolute;
top: 40px; bottom: 0px; right: 0px;
width: 300px;
}
#envheader {
padding: 5px;
background: #E0E0E0;
}
#envvars {
position: absolute;
left: 0px; right: 0px; top: 25px; bottom: 0px;
margin: 10px;
overflow-y: scroll;
font-size: 12px;
}
</style>
</head>
<body>
<div id="header">
<div id="title">
<a href="https://github.com/rxi/lovebird">lovebird</a>
<span id="version"><?lua echo(lovebird._version) ?></span>
</div>
<div id="status"></div>
</div>
<div id="main">
<div id="console" class="greybordered">
<div id="output"> <?lua echo(lovebird.buffer) ?> </div>
<div id="input">
<form method="post"
onkeydown="return onInputKeyDown(event);"
onsubmit="onInputSubmit(); return false;">
<input id="inputbox" name="input" type="text"
autocomplete="off"></input>
</form>
</div>
</div>
<div id="env" class="greybordered">
<div id="envheader"></div>
<div id="envvars"></div>
</div>
</div>
<script>
document.getElementById("inputbox").focus();
var changeFavicon = function(href) {
var old = document.getElementById("favicon");
if (old) document.head.removeChild(old);
var link = document.createElement("link");
link.id = "favicon";
link.rel = "shortcut icon";
link.href = href;
document.head.appendChild(link);
}
var truncate = function(str, len) {
if (str.length <= len) return str;
return str.substring(0, len - 3) + "...";
}
var geturl = function(url, onComplete, onFail) {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState != 4) return;
if (req.status == 200) {
if (onComplete) onComplete(req.responseText);
} else {
if (onFail) onFail(req.responseText);
}
}
url += (url.indexOf("?") > -1 ? "&_=" : "?_=") + Math.random();
req.open("GET", url, true);
req.send();
}
var divContentCache = {}
var updateDivContent = function(id, content) {
if (divContentCache[id] != content) {
document.getElementById(id).innerHTML = content;
divContentCache[id] = content
return true;
}
return false;
}
var onInputSubmit = function() {
var b = document.getElementById("inputbox");
var req = new XMLHttpRequest();
req.open("POST", "/", true);
req.send("input=" + encodeURIComponent(b.value));
/* Do input history */
if (b.value && inputHistory[0] != b.value) {
inputHistory.unshift(b.value);
}
inputHistory.index = -1;
/* Reset */
b.value = "";
refreshOutput();
}
/* Input box history */
var inputHistory = [];
inputHistory.index = 0;
var onInputKeyDown = function(e) {
var key = e.which || e.keyCode;
if (key != 38 && key != 40) return true;
var b = document.getElementById("inputbox");
if (key == 38 && inputHistory.index < inputHistory.length - 1) {
/* Up key */
inputHistory.index++;
}
if (key == 40 && inputHistory.index >= 0) {
/* Down key */
inputHistory.index--;
}
b.value = inputHistory[inputHistory.index] || "";
b.selectionStart = b.value.length;
return false;
}
/* Output buffer and status */
var refreshOutput = function() {
geturl("/buffer", function(text) {
updateDivContent("status", "connected &#9679;");
if (updateDivContent("output", text)) {
var div = document.getElementById("output");
div.scrollTop = div.scrollHeight;
}
/* Update favicon */
changeFavicon("data:image/png;base64," +
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAP1BMVEUAAAAAAAAAAAD////19fUO"+
"Dg7v7+/h4eGzs7MlJSUeHh7n5+fY2NjJycnGxsa3t7eioqKfn5+QkJCHh4d+fn7zU+b5AAAAAnRS"+
"TlPlAFWaypEAAABRSURBVBjTfc9HDoAwDERRQ+w0ern/WQkZaUBC4e/mrWzppH9VJjbjZg1Ii2rM"+
"DyR1JZ8J0dVWggIGggcEwgbYCRbuPRqgyjHNpzUP+39GPu9fgloC5L9DO0sAAAAASUVORK5CYII="
);
},
function(text) {
updateDivContent("status", "disconnected &#9675;");
/* Update favicon */
changeFavicon("data:image/png;base64," +
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAYFBMVEUAAAAAAAAAAADZ2dm4uLgM"+
"DAz29vbz8/Pv7+/h4eHIyMiwsLBtbW0lJSUeHh4QEBDn5+fS0tLDw8O0tLSioqKfn5+QkJCHh4d+"+
"fn5ycnJmZmZgYGBXV1dLS0tFRUUGBgZ0He44AAAAAnRSTlPlAFWaypEAAABeSURBVBjTfY9HDoAw"+
"DAQD6Z3ey/9/iXMxkVDYw0g7F3tJReosUKHnwY4pCM+EtOEVXrb7wVRA0dMbaAcUwiVeDQq1Jp4a"+
"xUg5kE0ooqZu68Di2Tgbs/DiY/9jyGf+AyFKBAK7KD2TAAAAAElFTkSuQmCC"
);
});
}
setInterval(refreshOutput,
<?lua echo(lovebird.updateinterval) ?> * 1000);
/* Environment variable view */
var envPath = "";
var refreshEnv = function() {
geturl("/env.json?p=" + envPath, function(text) {
var json = eval("(" + text + ")");
/* Header */
var html = "<a href='#' onclick=\"setEnvPath('')\">env</a>";
var acc = "";
var p = json.path != "" ? json.path.split(".") : [];
for (var i = 0; i < p.length; i++) {
acc += "." + p[i];
html += " <a href='#' onclick=\"setEnvPath('" + acc + "')\">" +
truncate(p[i], 10) + "</a>";
}
updateDivContent("envheader", html);
/* Handle invalid table path */
if (!json.valid) {
updateDivContent("envvars", "Bad path");
return;
}
/* Variables */
var html = "<table>";
for (var i = 0; json.vars[i]; i++) {
var x = json.vars[i];
var fullpath = (json.path + "." + x.key).replace(/^\./, "");
var k = truncate(x.key, 15);
if (x.type == "table") {
k = "<a href='#' onclick=\"setEnvPath('" + fullpath + "')\">" +
k + "</a>";
}
var v = "<a href='#' onclick=\"insertVar('" +
fullpath.replace(/\.(-?[0-9]+)/g, "[$1]") +
"');\">" + x.value + "</a>"
html += "<tr><td>" + k + "</td><td>" + v + "</td></tr>";
}
html += "</table>";
updateDivContent("envvars", html);
});
}
var setEnvPath = function(p) {
envPath = p;
refreshEnv();
}
var insertVar = function(p) {
var b = document.getElementById("inputbox");
b.value += p;
b.focus();
}
setInterval(refreshEnv, <?lua echo(lovebird.updateinterval) ?> * 1000);
</script>
</body>
</html>
]]
lovebird.pages["buffer"] = [[ <?lua echo(lovebird.buffer) ?> ]]
lovebird.pages["env.json"] = [[
<?lua
local t = _G
local p = req.parsedurl.query.p or ""
p = p:gsub("%.+", "."):match("^[%.]*(.*)[%.]*$")
if p ~= "" then
for x in p:gmatch("[^%.]+") do
t = t[x] or t[tonumber(x)]
-- Return early if path does not exist
if type(t) ~= "table" then
echo('{ "valid": false, "path": ' .. string.format("%q", p) .. ' }')
return
end
end
end
?>
{
"valid": true,
"path": "<?lua echo(p) ?>",
"vars": [
<?lua
local keys = {}
for k in pairs(t) do
if type(k) == "number" or type(k) == "string" then
table.insert(keys, k)
end
end
table.sort(keys, lovebird.compare)
for _, k in pairs(keys) do
local v = t[k]
?>
{
"key": "<?lua echo(k) ?>",
"value": <?lua echo(
string.format("%q",
lovebird.truncate(
lovebird.htmlescape(
tostring(v)), 26))) ?>,
"type": "<?lua echo(type(v)) ?>",
},
<?lua end ?>
]
}
]]
function lovebird.init()
-- Init server
lovebird.server = assert(socket.bind(lovebird.host, lovebird.port))
lovebird.addr, lovebird.port = lovebird.server:getsockname()
lovebird.server:settimeout(0)
-- Wrap print
lovebird.origprint = print
if lovebird.wrapprint then
local oldprint = print
print = function(...)
oldprint(...)
lovebird.print(...)
end
end
-- Compile page templates
for k, page in pairs(lovebird.pages) do
lovebird.pages[k] = lovebird.template(page, "lovebird, req",
"pages." .. k)
end
lovebird.inited = true
end
function lovebird.template(str, params, chunkname)
params = params and ("," .. params) or ""
local f = function(x) return string.format(" echo(%q)", x) end
str = ("?>"..str.."<?lua"):gsub("%?>(.-)<%?lua", f)
str = "local echo " .. params .. " = ..." .. str
local fn = assert(lovebird.loadstring(str, chunkname))
return function(...)
local output = {}
local echo = function(str) table.insert(output, str) end
fn(echo, ...)
return table.concat(lovebird.map(output, tostring))
end
end
function lovebird.map(t, fn)
local res = {}
for k, v in pairs(t) do res[k] = fn(v) end
return res
end
function lovebird.trace(...)
local str = "[lovebird] " .. table.concat(lovebird.map({...}, tostring), " ")
print(str)
if not lovebird.wrapprint then lovebird.print(str) end
end
function lovebird.unescape(str)
local f = function(x) return string.char(tonumber("0x"..x)) end
return (str:gsub("%+", " "):gsub("%%(..)", f))
end
function lovebird.parseurl(url)
local res = {}
res.path, res.search = url:match("/([^%?]*)%??(.*)")
res.query = {}
for k, v in res.search:gmatch("([^&^?]-)=([^&^#]*)") do
res.query[k] = lovebird.unescape(v)
end
return res
end
function lovebird.htmlescape(str)
return str:gsub("<", "&lt;")
end
function lovebird.truncate(str, len)
if #str <= len then
return str
end
return str:sub(1, len - 3) .. "..."
end
function lovebird.compare(a, b)
local na, nb = tonumber(a), tonumber(b)
if na then
if nb then return na < nb end
return false
elseif nb then
return true
end
return tostring(a) < tostring(b)
end
function lovebird.checkwhitelist(addr)
if lovebird.whitelist == nil then return true end
for _, a in pairs(lovebird.whitelist) do
local ptn = "^" .. a:gsub("%.", "%%."):gsub("%*", "%%d*") .. "$"
if addr:match(ptn) then return true end
end
return false
end
function lovebird.clear()
lovebird.lines = {}
lovebird.buffer = ""
end
function lovebird.pushline(line)
line.time = os.time()
line.count = 1
table.insert(lovebird.lines, line)
if #lovebird.lines > lovebird.maxlines then
table.remove(lovebird.lines, 1)
end
lovebird.recalcbuffer()
end
function lovebird.recalcbuffer()
local function doline(line)
local str = line.str
if not lovebird.allowhtml then
str = lovebird.htmlescape(line.str):gsub("\n", "<br>")
end
if line.type == "input" then
str = '<span class="inputline">' .. str .. '</span>'
else
if line.type == "error" then
str = '<span class="errormarker">!</span> ' .. str
str = '<span class="errorline">' .. str .. '</span>'
end
if line.count > 1 then
str = '<span class="repeatcount">' .. line.count .. '</span> ' .. str
end
if lovebird.timestamp then
str = os.date('<span class="timestamp">%H:%M:%S</span> ', line.time) ..
str
end
end
return str
end
lovebird.buffer = table.concat(lovebird.map(lovebird.lines, doline), "<br>")
end
function lovebird.print(...)
local t = {}
for i = 1, select("#", ...) do
table.insert(t, tostring(select(i, ...)))
end
local str = table.concat(t, " ")
local last = lovebird.lines[#lovebird.lines]
if last and str == last.str then
-- Update last line if this line is a duplicate of it
last.time = os.time()
last.count = last.count + 1
lovebird.recalcbuffer()
else
-- Create new line
lovebird.pushline({ type = "output", str = str })
end
end
function lovebird.onerror(err)
lovebird.pushline({ type = "error", str = err })
if lovebird.wrapprint then
lovebird.origprint("[lovebird] ERROR: " .. err)
end
end
function lovebird.onrequest(req, client)
local page = req.parsedurl.path
page = page ~= "" and page or "index"
-- Handle "page not found"
if not lovebird.pages[page] then
return "HTTP/1.1 404\r\nContent-Length: 8\r\n\r\nBad page"
end
-- Handle page
local str
xpcall(function()
local data = lovebird.pages[page](lovebird, req)
str = "HTTP/1.1 200 OK\r\n" ..
"Content-Length: " .. #data .. "\r\n" ..
"\r\n" .. data
end, lovebird.onerror)
return str
end
function lovebird.receive(client, pattern)
while 1 do
local data, msg = client:receive(pattern)
if not data then
if msg == "timeout" then
-- Wait for more data
coroutine.yield(true)
else
-- Disconnected -- yielding nil means we're done
coroutine.yield(nil)
end
else
return data
end
end
end
function lovebird.send(client, data)
local idx = 1
while idx < #data do
local res, msg = client:send(data, idx)
if not res and msg == "closed" then
-- Handle disconnect
coroutine.yield(nil)
else
idx = idx + res
coroutine.yield(true)
end
end
end
function lovebird.onconnect(client)
-- Create request table
local requestptn = "(%S*)%s*(%S*)%s*(%S*)"
local req = {}
req.socket = client
req.addr, req.port = client:getsockname()
req.request = lovebird.receive(client, "*l")
req.method, req.url, req.proto = req.request:match(requestptn)
req.headers = {}
while 1 do
local line, msg = lovebird.receive(client, "*l")
if not line or #line == 0 then break end
local k, v = line:match("(.-):%s*(.*)$")
req.headers[k] = v
end
if req.headers["Content-Length"] then
req.body = lovebird.receive(client, req.headers["Content-Length"])
end
-- Parse body
req.parsedbody = {}
if req.body then
for k, v in req.body:gmatch("([^&]-)=([^&^#]*)") do
req.parsedbody[k] = lovebird.unescape(v)
end
end
-- Parse request line's url
req.parsedurl = lovebird.parseurl(req.url)
-- Handle request; get data to send and send
local data = lovebird.onrequest(req)
lovebird.send(client, data)
-- Clear up
client:close()
end
function lovebird.update()
if not lovebird.inited then lovebird.init() end
-- Handle new connections
while 1 do
-- Accept new connections
local client = lovebird.server:accept()
if not client then break end
client:settimeout(0)
local addr = client:getsockname()
if lovebird.checkwhitelist(addr) then
-- Connection okay -- create and add coroutine to set
local conn = coroutine.wrap(function()
xpcall(function() lovebird.onconnect(client) end, function() end)
end)
lovebird.connections[conn] = true
else
-- Reject connection not on whitelist
lovebird.trace("got non-whitelisted connection attempt: ", addr)
client:close()
end
end
-- Handle existing connections
for conn in pairs(lovebird.connections) do
-- Resume coroutine, remove if it has finished
local status = conn()
if status == nil then
lovebird.connections[conn] = nil
end
end
end
return lovebird
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 KiB

After

Width:  |  Height:  |  Size: 656 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

+36
View File
@@ -0,0 +1,36 @@
-- Configuration
function love.conf(t)
t.identity = nil -- The name of the save directory (string)
t.version = "0.10.0" -- The LÖVE version this game was made for (string)
t.console = true -- Attach a console (boolean, Windows only)
t.title = "Shall I Kill Her" -- The title of the window the game is in (string)
t.window.icon = nil -- Filepath to an image to use as the window's icon (string)
t.window.width = 1280 -- The window width (number)
t.window.height = 720 -- The window height (number)
t.window.borderless = false -- Remove all border visuals from the window (boolean)
t.window.resizable = false -- Let the window be user-resizable (boolean)
t.window.minwidth = 1 -- Minimum window width if the window is resizable (number)
t.window.minheight = 1 -- Minimum window height if the window is resizable (number)
t.window.fullscreen = false -- Enable fullscreen (boolean)
t.window.fullscreentype = "desktop" -- Standard fullscreen or desktop fullscreen mode (string)
t.window.vsync = false -- Enable vertical sync (boolean)
t.window.fsaa = 0 -- The number of samples to use with multi-sampled antialiasing (number)
t.window.display = 1 -- Index of the monitor to show the window in (number)
t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean). Added in 0.9.1
t.window.srgb = false -- Enable sRGB gamma correction when drawing to the screen (boolean). Added in 0.9.1
t.modules.audio = true -- Enable the audio module (boolean)
t.modules.event = true -- Enable the event module (boolean)
t.modules.graphics = true -- Enable the graphics module (boolean)
t.modules.image = true -- Enable the image module (boolean)
t.modules.joystick = true -- Enable the joystick module (boolean)
t.modules.keyboard = true -- Enable the keyboard module (boolean)
t.modules.math = true -- Enable the math module (boolean)
t.modules.mouse = true -- Enable the mouse module (boolean)
t.modules.physics = true -- Enable the physics module (boolean)
t.modules.sound = true -- Enable the sound module (boolean)
t.modules.system = true -- Enable the system module (boolean)
t.modules.timer = true -- Enable the timer module (boolean)
t.modules.window = true -- Enable the window module (boolean)
end
+288
View File
@@ -0,0 +1,288 @@
local anim8 = {
_VERSION = 'anim8 v2.1.0',
_DESCRIPTION = 'An animation library for LÖVE',
_URL = 'https://github.com/kikito/anim8',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2011 Enrique García Cota
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 Grid = {}
local _frames = {}
local function assertPositiveInteger(value, name)
if type(value) ~= 'number' then error(("%s should be a number, was %q"):format(name, tostring(value))) end
if value < 1 then error(("%s should be a positive number, was %d"):format(name, value)) end
if value ~= math.floor(value) then error(("%s should be an integer, was %d"):format(name, value)) end
end
local function createFrame(self, x, y)
local fw, fh = self.frameWidth, self.frameHeight
return love.graphics.newQuad(
self.left + (x-1) * fw + x * self.border,
self.top + (y-1) * fh + y * self.border,
fw,
fh,
self.imageWidth,
self.imageHeight
)
end
local function getGridKey(...)
return table.concat( {...} ,'-' )
end
local function getOrCreateFrame(self, x, y)
if x < 1 or x > self.width or y < 1 or y > self.height then
error(("There is no frame for x=%d, y=%d"):format(x, y))
end
local key = self._key
_frames[key] = _frames[key] or {}
_frames[key][x] = _frames[key][x] or {}
_frames[key][x][y] = _frames[key][x][y] or createFrame(self, x, y)
return _frames[key][x][y]
end
local function parseInterval(str)
if type(str) == "number" then return str,str,1 end
str = str:gsub('%s', '') -- remove spaces
local min, max = str:match("^(%d+)-(%d+)$")
assert(min and max, ("Could not parse interval from %q"):format(str))
min, max = tonumber(min), tonumber(max)
local step = min <= max and 1 or -1
return min, max, step
end
function Grid:getFrames(...)
local result, args = {}, {...}
local minx, maxx, stepx, miny, maxy, stepy
for i=1, #args, 2 do
minx, maxx, stepx = parseInterval(args[i])
miny, maxy, stepy = parseInterval(args[i+1])
for y = miny, maxy, stepy do
for x = minx, maxx, stepx do
result[#result+1] = getOrCreateFrame(self,x,y)
end
end
end
return result
end
local Gridmt = {
__index = Grid,
__call = Grid.getFrames
}
local function newGrid(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border)
assertPositiveInteger(frameWidth, "frameWidth")
assertPositiveInteger(frameHeight, "frameHeight")
assertPositiveInteger(imageWidth, "imageWidth")
assertPositiveInteger(imageHeight, "imageHeight")
left = left or 0
top = top or 0
border = border or 0
local key = getGridKey(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border)
local grid = setmetatable(
{ frameWidth = frameWidth,
frameHeight = frameHeight,
imageWidth = imageWidth,
imageHeight = imageHeight,
left = left,
top = top,
border = border,
width = math.floor(imageWidth/frameWidth),
height = math.floor(imageHeight/frameHeight),
_key = key
},
Gridmt
)
return grid
end
-----------------------------------------------------------
local Animation = {}
local function cloneArray(arr)
local result = {}
for i=1,#arr do result[i] = arr[i] end
return result
end
local function parseDurations(durations, frameCount)
local result = {}
if type(durations) == 'number' then
for i=1,frameCount do result[i] = durations end
else
local min, max, step
for key,duration in pairs(durations) do
assert(type(duration) == 'number', "The value [" .. tostring(duration) .. "] should be a number")
min, max, step = parseInterval(key)
for i = min,max,step do result[i] = duration end
end
end
if #result < frameCount then
error("The durations table has length of " .. tostring(#result) .. ", but it should be >= " .. tostring(frameCount))
end
return result
end
local function parseIntervals(durations)
local result, time = {0},0
for i=1,#durations do
time = time + durations[i]
result[i+1] = time
end
return result, time
end
local Animationmt = { __index = Animation }
local nop = function() end
local function newAnimation(frames, durations, onLoop)
local td = type(durations);
if (td ~= 'number' or durations <= 0) and td ~= 'table' then
error("durations must be a positive number. Was " .. tostring(durations) )
end
onLoop = onLoop or nop
durations = parseDurations(durations, #frames)
local intervals, totalDuration = parseIntervals(durations)
return setmetatable({
frames = cloneArray(frames),
durations = durations,
intervals = intervals,
totalDuration = totalDuration,
onLoop = onLoop,
timer = 0,
position = 1,
status = "playing",
flippedH = false,
flippedV = false
},
Animationmt
)
end
function Animation:clone()
local newAnim = newAnimation(self.frames, self.durations, self.onLoop)
newAnim.flippedH, newAnim.flippedV = self.flippedH, self.flippedV
return newAnim
end
function Animation:flipH()
self.flippedH = not self.flippedH
return self
end
function Animation:flipV()
self.flippedV = not self.flippedV
return self
end
local function seekFrameIndex(intervals, timer)
local high, low, i = #intervals-1, 1, 1
while(low <= high) do
i = math.floor((low + high) / 2)
if timer > intervals[i+1] then low = i + 1
elseif timer <= intervals[i] then high = i - 1
else
return i
end
end
return i
end
function Animation:update(dt)
if self.status ~= "playing" then return end
self.timer = self.timer + dt
local loops = math.floor(self.timer / self.totalDuration)
if loops ~= 0 then
self.timer = self.timer - self.totalDuration * loops
local f = type(self.onLoop) == 'function' and self.onLoop or self[self.onLoop]
f(self, loops)
end
self.position = seekFrameIndex(self.intervals, self.timer)
end
function Animation:pause()
self.status = "paused"
end
function Animation:gotoFrame(position)
self.position = position
self.timer = self.intervals[self.position]
end
function Animation:pauseAtEnd()
self.position = #self.frames
self.timer = self.totalDuration
self:pause()
end
function Animation:pauseAtStart()
self.position = 1
self.timer = 0
self:pause()
end
function Animation:resume()
self.status = "playing"
end
function Animation:draw(image, x, y, r, sx, sy, ox, oy, ...)
local frame = self.frames[self.position]
if self.flippedH or self.flippedV then
r,sx,sy,ox,oy = r or 0, sx or 1, sy or 1, ox or 0, oy or 0
local _,_,w,h = frame:getViewport()
if self.flippedH then
sx = sx * -1
ox = w - ox
end
if self.flippedV then
sy = sy * -1
oy = h - oy
end
end
love.graphics.draw(image, frame, x, y, r, sx, sy, ox, oy, ...)
end
-----------------------------------------------------------
anim8.newGrid = newGrid
anim8.newAnimation = newAnimation
return anim8
+781
View File
@@ -0,0 +1,781 @@
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
local normal_map = require(_PACKAGE..'/normal_map')
local util = require(_PACKAGE..'/util')
local anim8 = require(_PACKAGE..'/anim8')
local vector = require(_PACKAGE..'/vector')
local body = {}
body.__index = body
body.glowShader = love.graphics.newShader(_PACKAGE.."/shaders/glow.glsl")
body.materialShader = love.graphics.newShader(_PACKAGE.."/shaders/material.glsl")
local function new(id, type, ...)
local args = {...}
local obj = setmetatable({}, body)
obj.id = id
obj.type = type
obj.shine = true
obj.red = 1.0
obj.green = 1.0
obj.blue = 1.0
obj.alpha = 1.0
obj.glowRed = 255
obj.glowGreen = 255
obj.glowBlue = 255
obj.glowStrength = 0.0
obj.tileX = 0
obj.tileY = 0
obj.zheight = 1
obj.rotation = 0
obj.scalex = 1
obj.scaley = 1
obj.castsNoShadow = false
obj.visible = true
obj.is_on_screen = true
if obj.type == "circle" then
obj.x = args[1] or 0
obj.y = args[2] or 0
circle_canvas = love.graphics.newCanvas(args[3]*2, args[3]*2)
util.drawto(circle_canvas, 0, 0, 1, function()
love.graphics.circle('fill', args[3], args[3], args[3])
end)
obj.img = love.graphics.newImage(circle_canvas:newImageData())
obj.imgWidth = obj.img:getWidth()
obj.imgHeight = obj.img:getHeight()
obj.ix = obj.imgWidth * 0.5
obj.iy = obj.imgHeight * 0.5
obj:generateNormalMapFlat("top")
obj:setShadowType('circle', args[3], args[4], args[5])
elseif obj.type == "rectangle" then
local x = args[1] or 0
local y = args[2] or 0
local width = args[3] or 64
local height = args[4] or 64
local ox = args[5] or width * 0.5
local oy = args[6] or height * 0.5
obj:setPoints(
x - ox, y - oy,
x - ox + width, y - oy,
x - ox + width, y - oy + height,
x - ox, y - oy + height
)
elseif obj.type == "polygon" then
obj:setPoints(...)
elseif obj.type == "image" then
obj.img = args[1]
obj.x = args[2] or 0
obj.y = args[3] or 0
if obj.img then
obj.imgWidth = obj.img:getWidth()
obj.imgHeight = obj.img:getHeight()
obj.ix = obj.imgWidth * 0.5
obj.iy = obj.imgHeight * 0.5
end
obj:generateNormalMapFlat("top")
obj:setShadowType('rectangle', args[4] or obj.imgWidth, args[5] or obj.imgHeight, args[6], args[7])
obj.reflective = true
elseif obj.type == "animation" then
obj.img = args[1]
obj.x = args[2] or 0
obj.y = args[3] or 0
obj.animations = {}
obj.castsNoShadow = true
obj:generateNormalMapFlat("top")
obj.reflective = true
elseif obj.type == "refraction" then
obj.x = args[2] or 0
obj.y = args[3] or 0
obj:setNormalMap(args[1], args[4], args[5])
obj.width = args[4] or obj.normalWidth
obj.height = args[5] or obj.normalHeight
obj.ox = obj.width * 0.5
obj.oy = obj.height * 0.5
obj.refraction = true
elseif obj.type == "reflection" then
obj.x = args[2] or 0
obj.y = args[3] or 0
obj:setNormalMap(args[1], args[4], args[5])
obj.width = args[4] or obj.normalWidth
obj.height = args[5] or obj.normalHeight
obj.ox = obj.width * 0.5
obj.oy = obj.height * 0.5
obj.reflection = true
end
obj:commit_changes()
return obj
end
-- refresh
function body:refresh()
if self.shadowType == 'polygon' and self:has_changed() then
self.data = {unpack(self.unit_data)}
local center = vector(self.x, self.y)
for i = 1, #self.data, 2 do
local point = vector(self.data[i], self.data[i+1])
point = point:rotate(self.rotation)
point = point:scale(self.scalex, self.scaley)
self.data[i], self.data[i+1] = (point + center):unpack()
end
self:commit_changes()
end
end
function body:has_changed()
return self:position_changed() or
self:rotation_changed() or
self:scale_changed()
end
function body:position_changed()
return self.old_x ~= self.x or
self.old_y ~= self.y
end
function body:rotation_changed()
return self.old_rotation ~= self.rotation
end
function body:scale_changed()
return self.old_scalex ~= self.scalex or
self.old_scaley ~= self.scaley
end
function body:commit_changes()
self.old_x, self.old_y = self.x, self.y
self.old_rotation = self.rotation
self.old_scalex, self.old_scaley = self.scalex, self.scaley
end
function body:newGrid(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border)
return anim8.newGrid(
frameWidth, frameHeight,
imageWidth or self.img:getWidth(), imageHeight or self.img:getHeight(),
left, top, border
)
end
-- frameWidth, frameHeight, imageWidth, imageHeight, left, top, border
function body:addAnimation(name, frames, durations, onLoop)
self.animations[name] = anim8.newAnimation(frames, durations, onLoop)
if not self.current_animation_name then
self:setAnimation(name)
end
end
function body:setAnimation(name)
self.current_animation_name = name
self.animation = self.animations[self.current_animation_name]
local frame = self.animation.frames[self.animation.position]
_,_,self.width, self.height = frame:getViewport()
end
function body:gotoFrame(frame) self.animation:gotoFrame(frame) end
function body:pause() self.animation:pause() end
function body:resume() self.animation:resume() end
function body:flipH() self.animation:flipH() end
function body:flipV() self.animation:flipV() end
function body:pauseAtEnd() self.animation:pauseAtEnd() end
function body:pauseAtStart() self.animation:pauseAtStart() end
function body:update(dt)
self:refresh()
if self.type == "animation" and self.animation then
local frame = self.animation.frames[self.animation.position]
_,_,self.width, self.height = frame:getViewport()
self.imgWidth, self.imgHeight = self.width, self.height
self.normalWidth, self.normalHeight = self.width, self.height
self.ix, self.iy = self.imgWidth * 0.5,self.imgHeight * 0.5
self.nx, self.ny = self.ix, self.iy
self.animation:update(dt)
end
end
function body:rotate(angle)
self:setRotation(self.rotation + angle)
end
function body:setRotation(angle)
self.rotation = angle
end
function body:scale(sx, sy)
self.scalex = self.scalex + sx
self.scaley = self.scaley + (sy or sx)
end
function body:setScale(sx, sy)
self.scalex = sx
self.scaley = sy or sx
end
-- set position
function body:setPosition(x, y)
if x ~= self.x or y ~= self.y then
self.x = x
self.y = y
end
end
-- move position
function body:move(x, y)
if x then
self.x = self.x + x
end
if y then
self.y = self.y + y
end
end
-- get x position
function body:getPosition()
return self.x, 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 offset
function body:setOffset(ox, oy)
if ox ~= self.ox or oy ~= self.oy then
self.ox = ox
self.oy = oy
end
end
-- set offset
function body:setImageOffset(ix, iy)
if ix ~= self.ix or iy ~= self.iy then
self.ix = ix
self.iy = iy
end
end
-- set offset
function body:setNormalOffset(nx, ny)
if nx ~= self.nx or ny ~= self.ny then
self.nx = nx
self.ny = ny
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
function body:setVisible(visible)
self.visible = visible
end
-- get radius
function body:getRadius()
return self.radius * self.scalex
end
-- set radius
function body:setRadius(radius)
if radius ~= self.radius then
self.radius = radius
end
end
-- set polygon data
function body:setPoints(...)
self.unit_data = {...}
--calculate l,r,t,b
self.x, self.y, self.width, self.height = self.unit_data[1], self.unit_data[2], 0, 0
for i = 1, #self.unit_data, 2 do
local px, py = self.unit_data[i], self.unit_data[i+1]
if px < self.x then self.x = px end
if py < self.y then self.y = py end
if px > self.width then self.width = px end
if py > self.height then self.height = py end
end
-- normalize width and height
self.width = self.width - self.x
self.height = self.height - self.y
for i = 1, #self.unit_data, 2 do
self.unit_data[i], self.unit_data[i+1] = self.unit_data[i] - self.x, self.unit_data[i+1] - self.y
end
self.x = self.x + (self.width * 0.5)
self.y = self.y + (self.height * 0.5)
local poly_canvas = love.graphics.newCanvas(self.width, self.height)
util.drawto(poly_canvas, 0, 0, 1, function()
love.graphics.polygon('fill', self.unit_data)
end)
--normalize points to be around the center x y
for i = 1, #self.unit_data, 2 do
self.unit_data[i], self.unit_data[i+1] = self.unit_data[i] - self.width * 0.5, self.unit_data[i+1] - self.height * 0.5
end
if not self.img then
self.img = love.graphics.newImage(poly_canvas:newImageData())
self.imgWidth = self.img:getWidth()
self.imgHeight = self.img:getHeight()
self.ix = self.imgWidth * 0.5
self.iy = self.imgHeight * 0.5
self:generateNormalMapFlat("top")
end
--wrapping with polygon normals causes edges to show
--also we do not need wrapping for this default normal map
self.normal:setWrap("clamp", "clamp")
self.shadowType = "polygon"
self:refresh()
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, "fan")
self.normalMesh:setTexture(self.normal)
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.shadowType = "polygon"
local width = args[1] or 64
local height = args[2] or 64
self.ox = args[3] or width * 0.5
self.oy = args[4] or height * 0.5
self:setPoints(
self.x - self.ox, self.y - self.oy,
self.x - self.ox + width, self.y - self.oy,
self.x - self.ox + width, self.y - self.oy + height,
self.x - self.ox, self.y - self.oy + height
)
elseif self.shadowType == "polygon" then
self:setPoints(args)
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.shadowMesh:setTexture(self.img)
self.shadowMesh:setAttributeEnabled("VertexColor", 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:isVisible()
return self.visible and self.is_on_screen
end
function body:inLightRange(light)
local l, t, w = light.x - light.range, light.y - light.range, light.range*2
return self:inRange(l,t,w,w,1)
end
function body:inRange(l, t, w, h, s)
local radius
if self.type == 'circle' then
radius = self.radius * self.scalex
else
local sw = (self.width * self.scalex)
local sh = (self.height * self.scaley)
radius = (sw > sh and sw or sh)
end
local bx, by, bw, bh = self.x - radius, self.y - radius, radius * 2, radius * 2
return self.visible and (bx+bw) > (l/s) and bx < (l+w)/s and (by+bh) > (t/s) and by < (t+h)/s
end
function body:drawAnimation()
self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
end
function body:drawNormal()
if not self.refraction and not self.reflection and self.normalMesh then
love.graphics.setColor(255, 255, 255)
if self.type == 'animation' then
self.animation:draw(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny)
else
love.graphics.draw(self.normalMesh, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny)
end
end
end
function body:drawGlow()
love.graphics.setColor(self.glowRed * self.glowStrength, self.glowGreen * self.glowStrength, self.glowBlue * self.glowStrength)
if self.type == "circle" then
love.graphics.circle("fill", self.x, self.y, self.radius * self.scalex)
elseif self.type == "polygon" then
love.graphics.polygon("fill", unpack(self.data))
elseif (self.type == "image" or self.type == "animation") and self.img then
if 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.setColor(0, 0, 0)
end
if self.type == "animation" then
self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
else
love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
end
love.graphics.setShader()
end
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(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny)
else
self.normalMesh:setVertices(self.normalVert)
love.graphics.draw(self.normalMesh, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, 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 * self.scalex)
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.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
elseif self.type == 'animation' then
self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, 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.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny)
end
if self.reflective and self.img then
love.graphics.setColor(0, 255, 0)
if self.type == 'animation' then
self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
else
love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
end
elseif not self.reflection and self.img then
love.graphics.setColor(0, 0, 0)
if self.type == 'animation' then
self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
else
love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
end
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)
if self.type == 'animation' then
self.animation:draw(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny)
else
love.graphics.draw(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny)
end
love.graphics.setShader()
end
end
function body:drawStencil()
if not self.refraction and not self.reflection and not self.castsNoShadow then
love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy)
end
end
function body:drawShadow(light)
if self.castsNoShadow or (self.zheight - light.z) > 0 then
return
end
love.graphics.setColor(self.red, self.green, self.blue, self.alpha)
if self.shadowType == "polygon" then
self:drawPolyShadow(light)
elseif self.shadowType == "circle" then
self:drawCircleShadow(light)
elseif self.shadowType == "image" and self.img then
self:drawImageShadow(light)
end
end
--using shadow point calculations from this article
--http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html
function body:drawPolyShadow(light)
local lightPosition = vector(light.x, light.y)
local lh = lightPosition * self.zheight
local height_diff = (self.zheight - light.z)
if height_diff == 0 then -- prevent inf
height_diff = -0.001
end
for i = 1, #self.data, 2 do
local vertex = vector(self.data[i], self.data[i + 1])
local nextVertex = vector(self.data[(i + 2) % #self.data], self.data[(i + 2) % #self.data + 1])
local startToEnd = nextVertex - vertex
if vector(startToEnd.y, -startToEnd.x) * (vertex - lightPosition) > 0 then
local point1 = (lh - (vertex * light.z))/height_diff
local point2 = (lh - (nextVertex * light.z))/height_diff
love.graphics.polygon("fill",
vertex.x, vertex.y, point1.x, point1.y,
point2.x, point2.y, nextVertex.x, nextVertex.y)
end
end
end
--using shadow point calculations from this article
--http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html
function body:drawCircleShadow(light)
local selfPos = vector(self.x - self.ox, self.y - self.oy)
local lightPosition = vector(light.x, light.y)
local lh = lightPosition * self.zheight
local height_diff = (self.zheight - light.z)
local radius = self.radius * self.scalex
if height_diff == 0 then -- prevent inf
height_diff = -0.001
end
local angle = math.atan2(light.x - selfPos.x, selfPos.y - light.y) + math.pi / 2
local point1 = vector(selfPos.x + math.sin(angle) * radius,
selfPos.y - math.cos(angle) * radius)
local point2 = vector(selfPos.x - math.sin(angle) * radius,
selfPos.y + math.cos(angle) * radius)
local point3 = (lh - (point1 * light.z))/height_diff
local point4 = (lh - (point2 * light.z))/height_diff
local shadow_radius = point3:dist(point4)/2
local circleCenter = (point3 + point4)/2
if lightPosition:dist(selfPos) <= radius then
love.graphics.circle("fill", circleCenter.x, circleCenter.y, shadow_radius)
else
love.graphics.polygon("fill", point1.x, point1.y,
point2.x, point2.y,
point4.x, point4.y,
point3.x, point3.y)
if lightPosition:dist(circleCenter) < light.range then -- dont draw circle if way off screen
local angle1 = math.atan2(point3.y - circleCenter.y, point3.x - circleCenter.x)
local angle2 = math.atan2(point4.y - circleCenter.y, point4.x - circleCenter.x)
if angle1 < angle2 then
love.graphics.arc("fill", circleCenter.x, circleCenter.y, shadow_radius, angle1, angle2)
else
love.graphics.arc("fill", circleCenter.x, circleCenter.y, shadow_radius, angle1 - math.pi, angle2 - math.pi)
end
end
end
end
function body:drawImageShadow(light)
local height_diff = (light.z - self.zheight)
if height_diff <= 0.1 then -- prevent shadows from leaving thier person like peter pan.
height_diff = 0.1
end
local length = 1.0 / height_diff
local shadowRotation = math.atan2((self.x) - light.x, (self.y + self.oy) - light.y)
local shadowStartY = self.imgHeight + (math.cos(shadowRotation) + 1.0) * self.shadowY
local shadowX = math.sin(shadowRotation) * self.imgHeight * length
local shadowY = (length * math.cos(shadowRotation) + 1.0) * shadowStartY
self.shadowMesh:setVertices({
{shadowX, shadowY, 0, 0, self.red, self.green, self.blue, self.alpha},
{shadowX + self.imgWidth, shadowY, 1, 0, self.red, self.green, self.blue, self.alpha},
{self.imgWidth, shadowStartY, 1, 1, self.red, self.green, self.blue, self.alpha},
{0, shadowStartY, 0, 1, self.red, self.green, self.blue, self.alpha}
})
love.graphics.draw(self.shadowMesh, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ox, self.oy)
end
return setmetatable({new = new}, {__call = function(_, ...) return new(...) end})
+344
View File
@@ -0,0 +1,344 @@
--[[
The MIT License (MIT)
Copyright (c) 2014 Marcus Ihde, Tim Anema
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 = string.gsub(...,"%.","/") or ""
if string.len(_PACKAGE) > 0 then _PACKAGE = _PACKAGE .. "/" end
local Light = require(_PACKAGE..'light')
local Body = require(_PACKAGE..'body')
local util = require(_PACKAGE..'util')
local PostShader = require(_PACKAGE..'postshader')
local light_world = {}
light_world.__index = light_world
light_world.image_mask = love.graphics.newShader(_PACKAGE.."/shaders/image_mask.glsl")
light_world.shadowShader = love.graphics.newShader(_PACKAGE.."/shaders/shadow.glsl")
light_world.refractionShader = love.graphics.newShader(_PACKAGE.."shaders/refraction.glsl")
light_world.reflectionShader = love.graphics.newShader(_PACKAGE.."shaders/reflection.glsl")
local function new(options)
local obj = {}
obj.lights = {}
obj.bodies = {}
obj.post_shader = PostShader()
obj.l, obj.t, obj.s = 0, 0, 1
obj.ambient = {0, 0, 0}
obj.refractionStrength = 8.0
obj.reflectionStrength = 16.0
obj.reflectionVisibility = 1.0
obj.shadowBlur = 2.0
obj.glowBlur = 1.0
obj.glowTimer = 0.0
obj.glowDown = false
obj.disableGlow = false
obj.disableMaterial = false
obj.disableReflection = true
obj.disableRefraction = true
options = options or {}
for k, v in pairs(options) do obj[k] = v end
local world = setmetatable(obj, light_world)
world:refreshScreenSize()
return world
end
function light_world:refreshScreenSize(w, h)
w, h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
self.w, self.h = w, h
self.render_buffer = love.graphics.newCanvas(w, h)
self.shadow_buffer = love.graphics.newCanvas(w, h)
self.normalMap = love.graphics.newCanvas(w, h)
self.shadowMap = love.graphics.newCanvas(w, h)
self.glowMap = love.graphics.newCanvas(w, h)
self.refractionMap = love.graphics.newCanvas(w, h)
self.reflectionMap = love.graphics.newCanvas(w, h)
self.post_shader:refreshScreenSize(w, h)
end
function light_world:update(dt)
for i = 1, #self.bodies do
self.bodies[i].is_on_screen = self.bodies[i]:inRange(-self.l,-self.t,self.w,self.h,self.s)
if self.bodies[i]:isVisible() then
self.bodies[i]:update(dt)
end
end
for i = 1, #self.lights do
self.lights[i].is_on_screen = self.lights[i]:inRange(self.l,self.t,self.w,self.h,self.s)
end
end
function light_world:draw(cb)
util.drawto(self.render_buffer, self.l, self.t, self.s, function()
cb( self.l,self.t,self.w,self.h,self.s)
_ = self.disableMaterial or self:drawMaterial( self.l,self.t,self.w,self.h,self.s)
self:drawShadows( self.l,self.t,self.w,self.h,self.s)
_ = self.disableGlow or self:drawGlow( self.l,self.t,self.w,self.h,self.s)
_ = self.disableRefraction or self:drawRefraction( self.l,self.t,self.w,self.h,self.s)
_ = self.disableReflection or self:drawReflection( self.l,self.t,self.w,self.h,self.s)
end)
self.post_shader:drawWith(self.render_buffer, self.l, self.t, self.s)
end
-- draw normal shading
function light_world:drawShadows(l,t,w,h,s)
love.graphics.setCanvas( self.normalMap )
love.graphics.clear()
love.graphics.setCanvas()
util.drawto(self.normalMap, l, t, s, function()
for i = 1, #self.bodies do
if self.bodies[i]:isVisible() then
self.bodies[i]:drawNormal()
end
end
end)
self.shadowShader:send('normalMap', self.normalMap)
self.shadowShader:send("invert_normal", self.normalInvert == true)
love.graphics.setCanvas( self.shadow_buffer )
love.graphics.clear()
love.graphics.setCanvas()
for i = 1, #self.lights do
local light = self.lights[i]
if light:isVisible() then
-- create shadow map for this light
love.graphics.setCanvas( self.shadowMap )
love.graphics.clear()
love.graphics.setCanvas()
util.drawto(self.shadowMap, l, t, s, function()
--I dont know if it uses both or just calls both
love.graphics.stencil(function()
local angle = light.direction - (light.angle / 2.0)
love.graphics.arc("fill", light.x, light.y, light.range, angle, angle + light.angle)
end)
love.graphics.setStencilTest("greater",0)
love.graphics.stencil(function()
love.graphics.setShader(self.image_mask)
for k = 1, #self.bodies do
if self.bodies[k]:inLightRange(light) and self.bodies[k]:isVisible() then
self.bodies[k]:drawStencil()
end
end
love.graphics.setShader()
end)
love.graphics.setStencilTest("equal", 0)
for k = 1, #self.bodies do
if self.bodies[k]:inLightRange(light) and self.bodies[k]:isVisible() then
self.bodies[k]:drawShadow(light)
end
end
end)
-- draw scene for this light using normals and shadowmap
self.shadowShader:send('lightColor', {light.red / 255.0, light.green / 255.0, light.blue / 255.0})
self.shadowShader:send("lightPosition", {(light.x + l/s) * s, (light.y + t/s) * s, (light.z * 10) / 255.0})
self.shadowShader:send('lightRange',light.range * s)
self.shadowShader:send("lightSmooth", light.smooth)
self.shadowShader:send("lightGlow", {1.0 - light.glowSize, light.glowStrength})
util.drawCanvasToCanvas(self.shadowMap, self.shadow_buffer, {
blendmode = 'add',
shader = self.shadowShader,
stencil = function()
local angle = light.direction - (light.angle / 2.0)
love.graphics.arc("fill", (light.x + l/s) * s, (light.y + t/s) * s, light.range, angle, angle + light.angle)
end
})
end
end
-- add in ambient color
util.drawto(self.shadow_buffer, l, t, s, function()
love.graphics.setBlendMode("add")
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)
self.post_shader:drawBlur(self.shadow_buffer, {self.shadowBlur})
util.drawCanvasToCanvas(self.shadow_buffer, self.render_buffer, {blendmode = "multiply"})
love.graphics.setStencilTest()
end
-- draw material
function light_world:drawMaterial(l,t,w,h,s)
for i = 1, #self.bodies do
if self.bodies[i]:isVisible() then
self.bodies[i]:drawMaterial()
end
end
end
-- draw glow
function light_world:drawGlow(l,t,w,h,s)
if self.glowDown then
self.glowTimer = math.max(0.0, self.glowTimer - love.timer.getDelta())
else
self.glowTimer = math.min(self.glowTimer + love.timer.getDelta(), 1.0)
end
if self.glowTimer == 1.0 or self.glowTimer == 0.0 then
self.glowDown = not self.glowDown
end
local has_glow = false
-- create glow map
love.graphics.setCanvas( self.glowMap )
love.graphics.clear()
love.graphics.setCanvas()
util.drawto(self.glowMap, l, t, s, function()
for i = 1, #self.bodies do
if self.bodies[i]:isVisible() and self.bodies[i].glowStrength > 0.0 then
has_glow = true
self.bodies[i]:drawGlow()
end
end
end)
if has_glow then
self.post_shader:drawBlur(self.glowMap, {self.glowBlur})
util.drawCanvasToCanvas(self.glowMap, self.render_buffer, {blendmode = "add"})
end
end
-- draw refraction
function light_world:drawRefraction(l,t,w,h,s)
-- create refraction map
love.graphics.setCanvas( self.refractionMap )
love.graphics.clear()
love.graphics.setCanvas()
util.drawto(self.refractionMap, l, t, s, function()
for i = 1, #self.bodies do
if self.bodies[i]:isVisible() then
self.bodies[i]:drawRefraction()
end
end
end)
self.refractionShader:send("backBuffer", self.render_buffer)
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)
-- create reflection map
love.graphics.setCanvas( self.reflectionMap )
love.graphics.clear()
love.graphics.setCanvas()
util.drawto(self.reflectionMap, l, t, s, function()
for i = 1, #self.bodies do
if self.bodies[i]:isVisible() then
self.bodies[i]:drawReflection()
end
end
end)
self.reflectionShader:send("backBuffer", self.render_buffer)
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)
return self.lights[#self.lights]
end
function light_world:clear()
light_world:clearLights()
light_world:clearBodies()
end
function light_world:setTranslation(l, t, s)
self.l, self.t, self.s = l or self.l, t or self.t, s or self.s
end
function light_world:setScale(s) self.s = s end
function light_world:clearLights() self.lights = {} end
function light_world:clearBodies() self.bodies = {} end
function light_world:setAmbientColor(red, green, blue) self.ambient = {red, green, blue} end
function light_world:setShadowBlur(blur) self.shadowBlur = blur end
function light_world:setGlowStrength(strength) self.glowBlur = strength end
function light_world:setRefractionStrength(strength) self.refractionStrength = strength end
function light_world:setReflectionStrength(strength) self.reflectionStrength = strength end
function light_world:setReflectionVisibility(visibility) self.reflectionVisibility = visibility end
function light_world:getBodyCount() return #self.bodies end
function light_world:getBody(n) return self.bodies[n] end
function light_world:getLightCount() return #self.lights end
function light_world:getLight(n) return self.lights[n] end
function light_world:newRectangle(...) return self:newBody("rectangle", ...) end
function light_world:newAnimationGrid(...) return self:newBody("animation", ...) end
function light_world:newCircle(...) return self:newBody("circle", ...) end
function light_world:newPolygon(...) return self:newBody("polygon", ...) end
function light_world:newImage(...) return self:newBody("image", ...) end
function light_world:newRefraction(...)
self.disableRefraction = false
return self:newBody("refraction", ...)
end
function light_world:newReflection(normal, ...)
self.disableReflection = false
return self:newBody("reflection", ...)
end
-- new body
function light_world:newBody(type, ...)
local id = #self.bodies + 1
self.bodies[id] = Body(id, type, ...)
return self.bodies[#self.bodies]
end
function light_world:is_body(target)
return target.type ~= nil
end
function light_world:is_light(target)
return target.angle ~= nil
end
function light_world:remove(to_kill)
if self:is_body(to_kill) then
for i = 1, #self.bodies do
if self.bodies[i] == to_kill then
table.remove(self.bodies, i)
return true
end
end
elseif self:is_light(to_kill) then
for i = 1, #self.lights do
if self.lights[i] == to_kill then
table.remove(self.lights, i)
return true
end
end
end
-- failed to find it
return false
end
return setmetatable({new = new}, {__call = function(_, ...) return new(...) end})
+130
View File
@@ -0,0 +1,130 @@
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
local util = require(_PACKAGE..'/util')
local light = {}
light.__index = light
local function new(x, y, r, g, b, range)
local obj = {
direction = 0,
angle = math.pi * 2.0,
x = x or 0,
y = y or 0,
z = 1,
red = r or 255,
green = g or 255,
blue = b or 255,
range = range or 300,
smooth = 1.0,
glowSize = 0.1,
glowStrength = 0.0,
visible = true,
is_on_screen = true,
}
return setmetatable(obj, light)
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
-- move position
function light:move(x, y, z)
if x then
self.x = self.x + x
end
if y then
self.y = self.y + y
end
if z then
self.z = self.z + z
end
end
-- get position
function light:getPosition()
return self.x, self.y, self.z
end
-- set color
function light:setColor(red, green, blue)
self.red = red
self.green = green
self.blue = blue
end
-- get range
function light:getRange()
return self.range
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:isVisible()
return self.visible and self.is_on_screen
end
function light:inRange(l,t,w,h,s)
local lx, ly, rs = (self.x + l/s) * s, (self.y + t/s) * s, self.range * s
return self.visible and (lx + rs) > 0 and (lx - rs) < w/s and (ly + rs) > 0 and (ly - rs) < h/s
end
function light:setVisible(visible)
self.visible = visible
end
return setmetatable({new = new}, {__call = function(_, ...) return new(...) end})
+121
View File
@@ -0,0 +1,121 @@
local 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, img:getHeight() - 1 do
for k = 0, img:getWidth() - 1 do
local r, g, b, a = imgData:getPixel(k, i)
imgNormalData:setPixel(k, i, color[1], color[2], color[3], a)
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
+164
View File
@@ -0,0 +1,164 @@
--[[
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 util = require(_PACKAGE..'/util')
local post_shader = {}
post_shader.__index = post_shader
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
local function new()
local obj = {effects = {}}
local class = setmetatable(obj, post_shader)
class:refreshScreenSize()
return class
end
function post_shader:refreshScreenSize(w, h)
w, h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
self.back_buffer = love.graphics.newCanvas(w, 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)
shaders['blurv'][1]:send("steps", args[1] or 2.0)
shaders['blurh'][1]:send("steps", args[1] or 2.0)
util.drawCanvasToCanvas(canvas, self.back_buffer, {shader = shaders['blurv'][1]})
util.process(self.back_buffer, {shader = shaders['blurh'][1]})
util.process(self.back_buffer, {shader = shaders['contrast'][1]})
util.process(canvas, {shader = shaders['contrast'][1]})
util.drawCanvasToCanvas(self.back_buffer, canvas, {blendmode = "add", color = {255, 255, 255, (args[2] or 0.25) * 255}})
end
function post_shader:drawBlur(canvas, args)
shaders['blurv'][1]:send("steps", args[1] or 0.0)
shaders['blurh'][1]:send("steps", args[2] or args[1] or 0.0)
util.process(canvas, {shader = shaders['blurv'][1], blendmode = "alpha"})
util.process(canvas, {shader = shaders['blurh'][1], blendmode = "alpha"})
end
function post_shader:drawTiltShift(canvas, args)
shaders['blurv'][1]:send("steps", args[1] or 2.0)
shaders['blurh'][1]:send("steps", args[2] or 2.0)
util.drawCanvasToCanvas(canvas, self.back_buffer, {shader = shaders['blurv'][1]})
util.process(self.back_buffer, {shader = shaders['blurh'][1]})
shaders['tilt_shift'][1]:send("imgBuffer", canvas)
util.drawCanvasToCanvas(self.back_buffer, canvas, {shader = shaders['tilt_shift'][1]})
end
function post_shader:drawShader(shaderName, canvas, args)
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)
else
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 setmetatable({new = new}, {__call = function(_, ...) return new(...) end})
+19
View File
@@ -0,0 +1,19 @@
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);
}
+6
View File
@@ -0,0 +1,6 @@
//https://love2d.org/wiki/love.graphics.setStencil image mask
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
if (Texel(texture, texture_coords).rgb == vec3(0.0))
discard;
return vec4(1.0);
}
+10
View File
@@ -0,0 +1,10 @@
extern Image material;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec4 normal = Texel(texture, texture_coords);
if(normal.a == 1.0) {
return Texel(material, vec2(normal.x, normal.y));
} else {
return vec4(0.0);
}
}
@@ -0,0 +1,13 @@
extern float exposure = 0.7;
extern float brightness = 1.0;
extern vec3 lumacomponents = vec3(1.0, 1.0, 1.0);
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);
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);
}
+12
View File
@@ -0,0 +1,12 @@
extern float steps = 2.0;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec2 pSize = vec2(1.0 / love_ScreenSize.x, 1.0 / love_ScreenSize.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);
}
+12
View File
@@ -0,0 +1,12 @@
extern float steps = 2.0;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec2 pSize = vec2(1.0 / love_ScreenSize.x, 1.0 / love_ScreenSize.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);
}
@@ -0,0 +1,12 @@
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 / love_ScreenSize.x, 1.0 / love_ScreenSize.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);
}
+5
View File
@@ -0,0 +1,5 @@
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);
}
+18
View File
@@ -0,0 +1,18 @@
#define distortion 0.2
vec2 radialDistortion(vec2 coord) {
vec2 cc = coord - 0.5;
float dist = dot(cc, cc) * distortion;
return coord + cc * (1.0 + dist) * dist;
}
vec4 checkTexelBounds(Image texture, vec2 coords) {
vec2 ss = step(coords, vec2(1.0, 1.0)) * step(vec2(0.0, 0.0), coords);
return Texel(texture, coords) * ss.x * ss.y;
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec2 coords = radialDistortion(texture_coords);
vec4 texcolor = checkTexelBounds(texture, coords);
texcolor.a = 1.0;
return texcolor;
}
+39
View File
@@ -0,0 +1,39 @@
/*
Edge shader
Author: Themaister
License: Public domain.
modified by slime73 for use with love2d and mari0
*/
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 / love_ScreenSize.x;
float y = 0.5 / love_ScreenSize.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 = love_ScreenSize.xy;
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
View File
@@ -0,0 +1,8 @@
extern vec3 palette[4];
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){
vec4 pixel = Texel(texture, texture_coords);
int index = int(min(0.9999, max(0.0001,(pixel.r + pixel.g + pixel.b) / 3.0)) * 4);
return vec4(palette[index], 1.0);
}
+8
View File
@@ -0,0 +1,8 @@
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
View File
@@ -0,0 +1,13 @@
extern float time = 0.0;
extern vec3 tint = vec3(1.0, 1.0, 1.0);
extern float fudge = 0.1;
float rand(vec2 position, float seed) {
return fract(sin(dot(position.xy,vec2(12.9898, 78.233))) * seed);
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){
vec4 pixel = Texel(texture, texture_coords);
float intensity = (pixel.r + pixel.g + pixel.b) / 3.0 + (rand(texture_coords, time) - 0.5) * fudge;
return vec4(intensity * tint.r, intensity * tint.g, intensity * tint.b, 1.0);
}
+157
View File
@@ -0,0 +1,157 @@
/*
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...)"
)
*/
// 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 * love_ScreenSize );
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/love_ScreenSize.x, 0.0 );
vec2 oney = vec2( 0.0, 1.0/love_ScreenSize.y );
vec4 effect(vec4 vcolor, Image texture, vec2 texCoord, vec2 pixel_coords)
{
vec2 coords = (texCoord * love_ScreenSize.xy);
vec2 pixel_start = floor(coords);
coords -= pixel_start;
vec2 pixel_center = pixel_start + vec2(0.5);
vec2 texture_coords = pixel_center / love_ScreenSize.xy;
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);
}
+45
View File
@@ -0,0 +1,45 @@
/*
Plain (and obviously inaccurate) phosphor.
Author: Themaister
License: Public Domain
*/
// modified by slime73 for use with love pixeleffects
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 * love_ScreenSize.y, 1.0);
float intensity = exp(-0.2 * y);
vec2 one_x = vec2(1.0 / (3.0 * love_ScreenSize.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 * love_ScreenSize.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);
}
+62
View File
@@ -0,0 +1,62 @@
#define glarebasesize 0.896
#define power 0.50
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) / love_ScreenSize.xy;
float y_one = 1.0 / love_ScreenSize.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;
}
+10
View File
@@ -0,0 +1,10 @@
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/love_ScreenSize.x);
float dy = pixel_h*(1.0/love_ScreenSize.y);
vec2 coord = vec2(dx*floor(uv.x/dx), dy*floor(uv.y/dy));
return Texel(texture, coord);
}
+20
View File
@@ -0,0 +1,20 @@
#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;
}

Some files were not shown because too many files have changed in this diff Show More