0,]']±>Sï}WÿÍu§ðp8·d%qy)6o;]ÉA¦ösï÷ôôô”°ÂVl†33ãîîîîîîNDDäîîîîîîUUîîîîîîîffîîîî~wçîèîîîîîîž™™é™™©ªªê®ªê»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»«êDDááîî.BB"BD"îî>D3333DîîNDDDDUUUUåETîffffffFdwwwç~DçwˆˆDˆˆˆˆˆîîžDD™IDªDDªªDê»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»«îD@DDAADîî.DD$D"4îî>DD34CDîîNDDDDDTDDUETnFDfDDfDDtDDw~wwGD„Dˆ„HD”îîž™I”DI¤ªJ¤JDêî®»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»«îDDADDDîî.BB"BD3îî>D344DDîîNDDDTETDUTETnDfdDfdFtwDwt~DwD„ˆDDˆD„™îîžID™D¤¤JDªªDêî®»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»«îDDD$îî.DD$D24îî>D34CDDîîNDDTTETDUUEdfDfdDffFtwDww~D‡D„ˆDˆ„ˆD”îîžD™™Dª¤DªªªDºî®»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»«êDDADAD"îî.BB"BD3îî>DD3DDDîîNDDUEDTDåîUDdFDfDæîwDtDçî~DˆHD„Dˆ„DD™îîžDD”JDªDD¤JD´îª»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»êà!âîîî""â23ãîî>33ãDDDîîNDäîUUUUåînffffffæî~wwwçî~‡èˆˆˆˆˆˆ˜™éîîž™™©ªªªªªªªº»îº»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»«îîîîîîîîîîîîîîîîîîîîîîîîîîîîDDäîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî®»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªº»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»+""²»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»+""²»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»¶(-- title: Demo #8 Tree Gen -- author: parlortricks -- desc: Demonstrates tree generation -- website: http://tic80.com/dev?id=6589 -- script: lua -- saveid: parlortricks_demo8_1 -- SPDX-License-Identifier: GPL-3.0-or-later -- Copyright (c) 2021 parlortricks --constants local m = math local sin = m.sin local cos = m.cos local pi = m.pi local tau = 2*pi local floor = m.floor local ceil = m.ceil local rnd = m.random local t = time local screen_width = 240 local screen_height = 136 local debug=false local true_false = {true, false} local pause=false --end constants --start footer stuff local rainbow=0 local footer_duration=3 local footer_step=0 local footer_text="Demo #8 by Parlortricks 2021" local footer_y=126 --end footer stuff function footer(text) local text = text local x,y=2,footer_y local pxtext=#text*6 local cx=120-pxtext/2 circ(cx,y+2,5,10) circ(cx,y+2,4,14) circ(cx+pxtext-2,y+2,5,10) circ(cx+pxtext-2,y+2,4,14) rect(cx-2,y-3,pxtext+3,11,10) rect(cx-2,y-2,pxtext+3,9,14) for k1=-1,1 do for k2=-1,1 do print(text,cx+k1,y+k2,12,true) end end print(text,cx,y,4,true) for i=cx-1,cx+pxtext do for j=y-1,y+6 do if pix(i,j)==12 then pix(i,j,(i+j+rainbow)/16) end end end end function footer_draw() if footer_step < 180 then footer(footer_text) footer_step=footer_step+1 rainbow = rainbow + 1 elseif footer_y < 146 then footer(footer_text) footer_y=footer_y+1 rainbow = rainbow + 1 else end end FPS = {} function FPS:new(o) o = o or {} setmetatable(o, self) self.__index = self self.value = 0 self.frames = 0 self.lastTime = 0 return FPS end function FPS:getValue() if (time() - self.lastTime <= 1000) then self.frames = self.frames + 1 else self.value = self.frames self.frames = 0 self.lastTime = time() end return self.value end function stats() if debug then rect(0, 0, screen_width,5, 15) fpsv="FPS: " .. fps:getValue() print(fpsv, (screen_width / 2)-(#fpsv*6/2), 0, 11, false, 1, false) end end --[[ 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 = BitAND(math.floor(x),255) local yi = BitAND(math.floor(y),255) local zi = BitAND(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[BitAND(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 function nop(...) return ... end -------------------------------- -- simple object type local obj = {init = nop} obj.__index = obj function obj:__call(...) local o = setmetatable({}, self) return o, o:init(...) end -- subclassing function obj:extend(proto) proto = proto or {} proto.__call, proto.__index = self.__call, proto return setmetatable(proto, self) end local Vector = obj:extend{} function Vector:init(x, y) self.x, self.y =x or 0, y or x or 0 end function Vector:__add(v) return Vector(self.x + v.x, self.y + v.y) end function Vector:__sub(v) return Vector(self.x - v.x, self.y - v.y) end function Vector:__mul(n) return Vector(self.x * n, self.y * n) end function Vector:elemx(v) return Vector(self.x * v.x, self.y * v.y) end function Vector:unpack() return table.unpack({self.y, self.y}) end function Vector:iadd(v) self.x = self.x + v.x self.y = self.y + v.y end function mapv(value,start1,stop1,start2,stop2) --https://processing.org/reference/map_.html --https://stackoverflow.com/questions/3451553/value-remapping return start2+(stop2-start2)*((value-start1)/(stop1-start1)) end function BitAND(a,b)--Bitwise and local p,c=1,0 while a>0 and b>0 do local ra,rb=a%2,b%2 if ra+rb>1 then c=c+p end a,b,p=(a-ra)/2,(b-rb)/2,p*2 end return c end --random number between A and B, supports negative function nrand(a,b) return a+math.random()*(b-a) end function quad(x1,y1,x2,y2,x3,y3,x4,y4,col) line(x1,y1,x2,y2,col) line(x2,y2,x3,y3,col) line(x3,y3,x4,y4,col) line(x4,y4,x1,y1,col) end function clear_table(t) for i=0, #t do t[i]=nil end end local leafs={} local n=0 function branch(x,y,size,angle,length,pos,col) local n = n + 0.01 local ov local scale=5 local diam = perlin.lerp(size, 0.7*size, pos/length) --reduce diameter diam= mapv(perlin:noise(n),0,1,0.4,1.6) *scale--add noise elli(x,y,diam,diam,col) --draw branches if size > 0.6 then if pos < length then x = x+cos(angle+nrand(-pi/10, pi/10)) y = y+sin(angle+nrand(-pi/10, pi/10)) ov = Vector(x,y) branch(x,y,size,angle,length,pos+1,col) else table.insert(leafs,Vector(x,y)) local draw_left_branch = function() local v = rnd(1) if v > 0.2 then return true end end local draw_right_branch = function() local v = rnd(1) if v > 0.2 then return true end end if draw_left_branch then branch(x,y,nrand(0.5,0.7)*size,angle-nrand(pi/15,pi/5),nrand(0.6,0.8)*length,0,col) end if draw_right_branch then branch(x,y,nrand(0.5,0.7)*size,angle+nrand(pi/15,pi/5),nrand(0.6,0.8)*length,0,col) end --if none of the branchs are drawn, draw a tip if not draw_left_branch and not draw_right_branch then local v1,v2,v3,v4,ov local scale=2 ov=Vector(x,y) v1=Vector(0,-diam) + ov v2=Vector(2*diam,-diam/3) + ov v3=Vector(2*diam,diam/3) + ov v4=Vector(0,diam) + ov quad(v1.x,v1.y, v2.x,v2.y, v3.x,v3.y, v4.x,v4.y,col) end end end end function draw_leafs(min_diam, max_diam) local rcol=floor(nrand(0,2)) local col={5,6,7} if rcol ==0 then col = {5,6,7} end if rcol ==1 then col = {4,3,2} end for i=1,#leafs do local diam = nrand(min_diam, max_diam) local jitterx = nrand(-6,6) local jittery = nrand(-6,6) local x=leafs[i].x + jitterx local y=leafs[i].y + jittery --local col = mapv(rnd(0,3),0,3,5,7) elli(x, y, diam, diam,col[i%3+1]) end end function ground() end function create_tree() local rcol=floor(nrand(0,2)) local col={13,14,15} if rcol ==0 then col = {15,14,13} end if rcol ==1 then col = {15,1,2} end -- if rcol ==2 then col = {15,8,9} end for i=0,2 do branch(screen_width/2,screen_height,40,-pi/2,nrand(10,40),0,col[i+1]) end end function init() fps = FPS:new() end function input() if keyp(48) then pause = not pause end if keyp(49) then debug = not debug end end local wait=0 init() function TIC() input() cls(11) if not pause then if wait%60==0 then --draw_leafs(4,70) create_tree() draw_leafs(1,5) clear_table(leafs) memcpy(0x04000,0x0000,16384) end end memcpy(0x0000,0x04000,16384) wait=wait+1 footer_draw() stats() end