Skip to content

Instantly share code, notes, and snippets.

@luastoned
Created February 16, 2017 15:54
Show Gist options
  • Save luastoned/d0561b5691fd71e2a6b5d33edf11eb11 to your computer and use it in GitHub Desktop.
Save luastoned/d0561b5691fd71e2a6b5d33edf11eb11 to your computer and use it in GitHub Desktop.
local nw = require("nw")
local app = nw:app() -- get the app singleton
local win = app:window({ -- create a new window
w = 1280, h = 720, -- specify window"s frame size
title = "SndVis", -- specify window"s title
visible = false, -- dont show it yet
resizeable = false,
maximizable = false,
fullscreenable = false,
--transparent = true,
--frame = "none",
--corner_radius = 5,
})
function win:click(button, count) -- this is one way to bind events
if button == "left" and count == 3 then -- triple click
app:quit()
end
end
-- this is another way to bind events which allows setting multiple
-- handlers for the same event type.
win:on("keydown", function(self, key)
if key == "F11" then
self:fullscreen(not self:fullscreen()) -- toggle fullscreen state
end
end)
--[[
function getCurvePoints(pts, tension, isClosed, numOfSegments) {
-- use input value if provided, or use a default value
tension = (typeof tension != 'undefined') ? tension : 0.5;
isClosed = isClosed ? isClosed : false;
numOfSegments = numOfSegments ? numOfSegments : 16;
var _pts = [], res = [], -- clone array
x, y, -- our x,y coords
t1x, t2x, t1y, t2y, -- tension vectors
c1, c2, c3, c4, -- cardinal points
st, t, i; -- steps based on num. of segments
-- clone array so we don't change the original
--
_pts = pts.slice(0);
-- The algorithm require a previous and next point to the actual point array.
-- Check if we will draw closed or open curve.
-- If closed, copy end points to beginning and first points to end
-- If open, duplicate first points to befinning, end points to end
if (isClosed) {
_pts.unshift(pts[pts.length - 1]);
_pts.unshift(pts[pts.length - 2]);
_pts.unshift(pts[pts.length - 1]);
_pts.unshift(pts[pts.length - 2]);
_pts.push(pts[0]);
_pts.push(pts[1]);
}
else {
_pts.unshift(pts[1]); --copy 1. point and insert at beginning
_pts.unshift(pts[0]);
_pts.push(pts[pts.length - 2]); --copy last point and append
_pts.push(pts[pts.length - 1]);
}
-- ok, lets start..
-- 1. loop goes through point array
-- 2. loop goes through each segment between the 2 pts + 1e point before and after
for (i=2; i < (_pts.length - 4); i+=2) {
for (t=0; t <= numOfSegments; t++) {
-- calc tension vectors
t1x = (_pts[i+2] - _pts[i-2]) * tension;
t2x = (_pts[i+4] - _pts[i]) * tension;
t1y = (_pts[i+3] - _pts[i-1]) * tension;
t2y = (_pts[i+5] - _pts[i+1]) * tension;
-- calc step
st = t / numOfSegments;
-- calc cardinals
c1 = 2 * Math.pow(st, 3) - 3 * Math.pow(st, 2) + 1;
c2 = -(2 * Math.pow(st, 3)) + 3 * Math.pow(st, 2);
c3 = Math.pow(st, 3) - 2 * Math.pow(st, 2) + st;
c4 = Math.pow(st, 3) - Math.pow(st, 2);
-- calc x and y cords with common control vectors
x = c1 * _pts[i] + c2 * _pts[i+2] + c3 * t1x + c4 * t2x;
y = c1 * _pts[i+1] + c2 * _pts[i+3] + c3 * t1y + c4 * t2y;
--store points in array
res.push(x);
res.push(y);
}
}
return res;
}
]]
local function cardinalSpline(points, tension, numOfSeg, isClosed)
tension = tension or 0.5
numOfSeg = numOfSeg or 12
isClosed = isClosed or false
local pts, res = {}, {}
local x, y
local t1x, t2x, t1y, t2y -- tension
local c1, c2, c3, c4 -- cardinal points
local step, t, i
local length = #points
for k, point in pairs(points) do
table.insert(pts, point)
end
if (isClosed) then
-- add start to end and vice versa
table.insert(pts, 1, points[length])
table.insert(pts, points[1])
else
-- duplicate start and end
table.insert(pts, 1, points[1])
table.insert(pts, points[length])
end
local cache = {}
-- cache inner-loop calculations as they are based on t alone
for i = 0, numOfSeg - 1 do
step = i / numOfSeg
local st2 = step * step
local st3 = st2 * step
local st23 = st2 * 3
local st32 = st3 * 2
cache[i * 4 + 1] = st32 - st23 + 1 -- c1
cache[i * 4 + 2] = st23 - st32 -- c2
cache[i * 4 + 3] = st3 - 2 * st2 + step -- c3
cache[i * 4 + 4] = st3 - st2 -- c4
end
-- 1. loop goes through points
-- 2. loop goes through each segment between two points and 1 point before and after
for i = 2, length do
-- calc tension vectors
t1x = (pts[i + 1].x - pts[i - 1].x) * tension
t1y = (pts[i + 1].y - pts[i - 1].y) * tension
t2x = (pts[i + 2].x - pts[i].x) * tension
t2y = (pts[i + 2].y - pts[i].y) * tension
for t = 0, numOfSeg - 1 do
c1 = cache[t * 4 + 1]
c2 = cache[t * 4 + 2]
c3 = cache[t * 4 + 3]
c4 = cache[t * 4 + 4]
x = c1 * pts[i].x + c2 * pts[i + 1].x + c3 * t1x + c4 * t2x
y = c1 * pts[i].y + c2 * pts[i + 1].y + c3 * t1y + c4 * t2y
table.insert(res, {x = x, y = y})
end
end
table.insert(res, points[length])
return res
end
local t = {}
for i = 1, 3 do
local p = {x = i * 20, y = math.floor(math.random() * 20)}
print(i .. " -> (" .. p.x .. ", " .. p.y .. ")")
table.insert(t, p)
end
local tbl = cardinalSpline(t, 0.5, 3, false)
for k, p in pairs(tbl) do
print(k .. " -> (" .. p.x .. ", " .. p.y .. ")")
end
local sleepTime = 0.2
local deg_add = 0
function win:repaint() -- called when window needs repainting
local bmp = win:bitmap() -- get the window"s bitmap
bmp:clear()
local cr = bmp:cairo() -- get a cairo drawing context
local w, h = win:client_size()
-- draw red line
cr:rgba(1, 0, 0, 1)
cr:line_width(2)
cr:new_path()
cr:move_to(10, 10)
cr:line_to(w - 10, 10)
cr:close_path()
cr:stroke()
local fftTable = {}
for i = 1, 16 do
table.insert(fftTable, math.random())
end
cr:push_group()
cr:rgba(1, 1, 1, 1)
cr:line_width(2)
cr:new_path()
cr:move_to(400, 100)
--cr:rel_curve_to(0, 0, 0, -50, 100, 0)
cr:rel_quad_curve_to(50, 50, 100, 0)
--cr:curve_to(i * 50, h - 50 - off, i * 50, h - 50 - off, i * 50, h - 50 - off)
--cr:rel_curve_to(0, 0, 0, 0, 0, math.random() * 100)
cr:stroke()
cr:pop_group_to_source()
cr:paint()
cr:push_group()
cr:rgba(1, 1, 1, 1)
cr:line_width(2)
cr:new_path()
cr:move_to(50, h - 50)
for i = 1, 16 - 1 do
local x = i * 50 + 25
local y = (fftTable[i] + fftTable[i + 1]) / 2
cr:quad_curve_to(i * 50, h - 50 - fftTable[i] * 300, x, h - 50 - y * 300)
--cr:rectangle(i * 50, h - 50 - fftTable[i] * 200, 10, fftTable[i] * 200)
--cr:curve_to(i * 50, h - 50 - off, i * 50, h - 50 - off, i * 50, h - 50 - off)
--cr:rel_curve_to(0, 0, 0, 0, 0, math.random() * 100)
end
cr:quad_curve_to(16 * 50, h - 50 - fftTable[16] * 300, 16 * 50, h - 50)
--cr:line_to(16 * 50, h - 50)
--cr:close_path()
cr:stroke()
cr:pop_group_to_source()
cr:paint()
cr:push_group()
cr:rgba(0, 0, 1, 1)
cr:new_path()
for i = 1, 16 do
cr:rectangle(i * 50, h - 50 - fftTable[i] * 200, 10, fftTable[i] * 200)
end
cr:fill()
cr:rgba(1, 0, 0, 1)
cr:new_path()
for i = 1, 16 do
cr:rectangle(i * 50, h - 50 - fftTable[i] * 300, 10, 10)
end
cr:fill()
cr:pop_group_to_source()
cr:paint()
cr:push_group()
deg_add = deg_add + 15
cr:new_path()
cr:rotate_around(200, 200, math.rad(deg_add))
cr:rectangle(100, 100, 200, 200)
cr:rgba(0, 1, 0, 0.2)
cr:fill()
cr:pop_group_to_source()
cr:paint()
cr:rgba(0, 0, 1, 0.5)
cr:line_width(2)
cr:new_path()
cr:move_to(50, 50)
cr:line_to(w - 50, 50)
cr:close_path()
cr:stroke()
app:runafter(sleepTime, function()
win:invalidate()
end)
end
win:show() -- show it now that it was properly set up
app:run() -- start the event loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment