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}