1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
local Pos = require"common.coords".Pos
local tau = 2*math.pi
math.randomseed(os.time())
local function random_unit_vec()
local theta = math.random()*tau
return Pos.make(math.cos(theta),math.sin(theta))
end
local function lerp(a,b,t) return (1-t)*a + t*b end
local function smoothstep(x)
if x<0 then return 0 end
if x>1 then return 1 end
return x*x*(3 - 2*x)
end
local function slerp(a,b,t) return lerp(a,b,smoothstep(t)) end
local NoiseGen = {}
NoiseGen.__index = NoiseGen
function NoiseGen.make()
local grid = {}
setmetatable(grid,{__index=function(t,k) t[k] = {} return t[k] end})
return setmetatable({grid=grid},NoiseGen)
end
function NoiseGen.vertex(self,ix,iy)
local v = self.grid[ix][iy]
if v then return v end
vv = random_unit_vec()
self.grid[ix][iy] = vv
return vv
end
function NoiseGen.at(self,x,y)
local x0 = math.floor(x)
local y0 = math.floor(y)
local x1 = x0 + 1
local y1 = y0 + 1
local v00 = self:vertex(x0,y0)
local v01 = self:vertex(x0,y1)
local v10 = self:vertex(x1,y0)
local v11 = self:vertex(x1,y1)
local p = Pos.make
local d00 = v00:dot(p(x-x0,y-y0))
local d01 = v01:dot(p(x-x0,y-y1))
local d10 = v10:dot(p(x-x1,y-y0))
local d11 = v11:dot(p(x-x1,y-y1))
local q0 = slerp(d00,d01,y-y0)
local q1 = slerp(d10,d11,y-y0)
local z = slerp(q0,q1,x-x0)
return z
end
local NoiseAgg = {}
NoiseAgg.__index = NoiseAgg
function NoiseAgg.make(things)
return setmetatable({things=things or {}},NoiseAgg)
end
function NoiseAgg.make_perlin_octaves(nocts)
local things = {}
for i=1,nocts do
table.insert(things,{amp=2^i,scale=2^(nocts-i),gen=NoiseGen.make()})
end
return NoiseAgg.make(things)
end
function NoiseAgg.at(self,x,y)
local n = 0
local t = 0
assert(#self.things>0,"can't generate noise with no noise things")
for _,thing in ipairs(self.things) do
local gen,scale,amp = thing.gen,thing.scale,thing.amp
n = n + amp
t = t + gen:at(x*scale,y*scale)*amp
end
return t/n
end
-- local chars = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
-- local scale = 3
-- for x=1,10-10/40,10/40 do
-- for y = 1,10-10/60,10/60 do
-- local n = at(1+(x-1)/scale,1+(y-1)/scale)
-- local nn = (n +1)/2
-- local nnn = 1+nn*#chars
-- local c = chars:sub(nnn,nnn)
-- io.write(c)
-- end
-- io.write("\n")
-- end
return {NoiseGen=NoiseGen,NoiseAgg=NoiseAgg}
|