ComputerCraft Archive

perlin screensaver

computer utility LDDestroier github

Description

A collection of all my ComputerCraft programs and the APIs they use. This is mostly just to get them the fuck off of pastebin, and also to ensure that API owners don't change things to break my precious programs...!

Installation

Copy one of these commands into your ComputerCraft terminal:

wget:wget https://raw.githubusercontent.com/LDDestroier/CC/master/perlin-screensaver.lua perlin_screensaver
Archive:wget https://cc.shobie.xyz/cc/get/gh-LDDestroier-CC-perlin-screensaver perlin_screensaver
Quick Install: wget https://cc.shobie.xyz/cc/get/gh-LDDestroier-CC-perlin-screensaver perlin screensaver

Usage

Run: perlin-screensaver

Tags

none

Source

View Original Source

Code Preview

local perlin
do
	--[[
	    Implemented as described here:
	    http://flafla2.github.io/2014/08/09/perlinnoise.html
	]]--

	perlin = {}
	perlin.p = {}

	-- Hash lookup table as defined by Ken Perlin
	-- This is a randomly arranged array of all numbers from 0-255 inclusive
	local permutation = {151,160,137,91,90,15,
	  131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
	  190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
	  88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
	  77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
	  102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
	  135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
	  5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
	  223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
	  129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
	  251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
	  49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
	  138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
	}

	-- p is used to hash unit cube coordinates to [0, 255]
	for i=0,255 do
	    -- Convert to 0 based index table
	    perlin.p[i] = permutation[i+1]
	    -- Repeat the array to avoid buffer overflow in hash function
	    perlin.p[i+256] = permutation[i+1]
	end

	-- Return range: [-1, 1]
	function perlin:noise(x, y, z)
	    y = y or 0
	    z = z or 0

	    -- Calculate the "unit cube" that the point asked will be located in
	    local xi = bit32.band(math.floor(x),255)
	    local yi = bit32.band(math.floor(y),255)
	    local zi = bit32.band(math.floor(z),255)

	    -- Next we calculate the location (from 0 to 1) in that cube
	    x = x - math.floor(x)
	    y = y - math.floor(y)
	    z = z - math.floor(z)

	    -- We also fade the location to smooth the result
	    local u = self.fade(x)
	    local v = self.fade(y)
	    local w = self.fade(z)

	    -- Hash all 8 unit cube coordinates surrounding input coordinate
	    local p = self.p
	    local A, AA, AB, AAA, ABA, AAB, ABB, B, BA, BB, BAA, BBA, BAB, BBB
	    A   = p[xi  ] + yi
	    AA  = p[A   ] + zi
	    AB  = p[A+1 ] + zi
	    AAA = p[ AA ]
	    ABA = p[ AB ]
	    AAB = p[ AA+1 ]
	    ABB = p[ AB+1 ]

	    B   = p[xi+1] + yi
	    BA  = p[B   ] + zi
	    BB  = p[B+1 ] + zi
	    BAA = p[ BA ]
	    BBA = p[ BB ]
	    BAB = p[ BA+1 ]
	    BBB = p[ BB+1 ]

	    -- Take the weighted average between all 8 unit cube coordinates
	    return self.lerp(w,
	        self.lerp(v,
	            self.lerp(u,
	                self:grad(AAA,x,y,z),
	                self:grad(BAA,x-1,y,z)
	            ),
	            self.lerp(u,
	                self:grad(ABA,x,y-1,z),
	                self:grad(BBA,x-1,y-1,z)
	            )
	        ),
	        self.lerp(v,
	            self.lerp(u,
	                self:grad(AAB,x,y,z-1), self:grad(BAB,x-1,y,z-1)
	            ),
	            self.lerp(u,
	                self:grad(ABB,x,y-1,z-1), self:grad(BBB,x-1,y-1,z-1)
	            )
	        )
	    )
	end

	-- Gradient function finds dot product between pseudorandom gradient vector
	-- and the vector from input coordinate to a unit cube vertex
	perlin.dot_product = {
	    [0x0]=function(x,y,z) return  x + y end,
	    [0x1]=function(x,y,z) return -x + y end,
	    [0x2]=function(x,y,z) return  x - y end,
	    [0x3]=function(x,y,z) return -x - y end,
	    [0x4]=function(x,y,z) return  x + z end,
	    [0x5]=function(x,y,z) return -x + z end,
	    [0x6]=function(x,y,z) return  x - z end,
	    [0x7]=function(x,y,z) return -x - z end,
	    [0x8]=function(x,y,z) return  y + z end,
	    [0x9]=function(x,y,z) return -y + z end,
	    [0xA]=function(x,y,z) return  y - z end,
	    [0xB]=function(x,y,z) return -y - z end,
	    [0xC]=function(x,y,z) return  y + x end,
	    [0xD]=function(x,y,z) return -y + z end,
	    [0xE]=function(x,y,z) return  y - x end,
	    [0xF]=function(x,y,z) return -y - z end
	}
	function perlin:grad(hash, x, y, z)
	    return self.dot_product[bit32.band(hash,0xF)](x,y,z)
	end

	-- Fade function is used to smooth final output
	function perlin.fade(t)
	    return t * t * t * (t * (t * 6 - 15) + 10)
	end

	function perlin.lerp(t, a, b)
	    return a + t * (b - a)
	end
end

local tint = {
  2,
  0.7,
  0.1,
}

local setTintedPalette = function()
	for i = 0, 255 do
	    term.setPaletteColor(i,
	        i/ (255 / tint[1]),
	        i/ (255 / tint[2]),
	        i/ (255 / tint[3])
	    )
	end
end

local scr_x, scr_y = term.getSize()
scr_x = scr_x * 6 - 1
scr_y = scr_y * 9


local stringchar = string.char
local tableconcat = table.concat

local screen = {}
local genScreen = function(x, y)
	for yy = y, y + scr_y do
		screen[yy] = screen[yy] or {}
		for xx = x, x + scr_x do
			screen[yy][xx] = screen[yy][xx] or stringchar((perlin:noise(
				0.2 * xx,
				0.2 * yy,
				0.3
			) * 64) + 64)
		end
	end
end

local render = function(x, y, xPos, yPos, width, height)
	genScreen(x + xPos, y + yPos)
	local buffer = {}
    for yy = 1, height do
		buffer[yy] = tableconcat(
			screen[yy + y + yPos], nil,
			x + xPos,
			x + width + xPos
		)
    end
	term.drawPixels(xPos, yPos, buffer)
end

local getTintFromFile = function()
	local file = fs.open("/.noisegen_tint", "r")
	if file then
		tint = textutils.unserialize(file.readAll())
		file.close()
	else
		file = fs.open("/.noisegen_tint", "w")
		file.write(textutils.serialize(tint))
		file.close()
	end
	setTintedPalette()
end

local main = function()
	local i, ii, x, y = 1, 1, 1, 1
	local iLimit = 1000
	local evt, e1, e2, e3
	local t_tick = os.startTimer(0)
	local t_getTint = os.startTimer(2)
	local t_screenwipe = os.startTimer(1)

	term.setGraphicsMode(2)
	--getTintFromFile()

	local randTable = {}
	for a = 1, iLimit do
		randTable[a] = math.random(-2, 2)
	end
	local width = math.random(20, 100)
	local height = math.random(20, 100)
	local xPos = math.random(1, scr_x - width - 1)
	local yPos = math.random(1, scr_y - height - 1)

	term.setBackgroundColor(colors.black)
	term.clear()

	while true do
		evt, e1, e2, e3 = os.pullEvent()
		if i == iLimit then
			width = math.random(20, 100)
			height = math.random(20, 100)
			xPos = math.random(1, scr_x - width - 1)
			yPos = math.random(1, scr_y - height - 1)
			i = 1
		end
		if evt == "timer" then
			if e1 == t_tick then

				x = i + math.sin(math.rad(i * 2)) * 3
				y = math.cos(i / 50) * 10

				x, y = math.floor(x), math.floor(y)

			    render(x, y, xPos, yPos, width, height)
				i = i + 1
				ii = ii + 1
				t_tick = os.startTimer(0)

				tint = {
					math.sin(100 + ii / 200) / 2 + 1.2,
					math.sin(200 + ii / 300) / 2 + 1.2,
					math.sin(300 + ii / 600) / 2 + 1.2,
				}
				setTintedPalette()

			elseif e1 == t_getTint then
				--getTintFromFile()
				t_getTint = os.startTimer(2)

			end
		end
	end
end

local status, message = pcall(main)

term.setGraphicsMode(0)
for i = 0, 15 do
    term.setPaletteColor(2^i, term.nativePaletteColor(2^i))
end
term.setCursorPos(1, 1)

if not status then
	error(message)
end