Skip to content

Instantly share code, notes, and snippets.

@lucatronica
Last active July 5, 2020 03:53
Show Gist options
  • Save lucatronica/55dc19dc4c2a7b9b456dd5d5cf241f6d to your computer and use it in GitHub Desktop.
Save lucatronica/55dc19dc4c2a7b9b456dd5d5cf241f6d to your computer and use it in GitHub Desktop.
-- gumtree.lua
-- coordinates: x,y = ground; z = vertical
-- camera
local gt_cam={
x=0,
y=0,
z=0,
-- spin angle
s=0,
-- tilt angle
t=1/8,
-- scale (1 means 1:1)
k=8,
-- perspective (number > 0, or nil for orthographic)
p=80,
}
-- buckets
local gt_mind=nil
local gt_maxd=nil
local gt_buckets={}
-- voxels
-- create a voxel object
function gt_voxel(x,y,z,w,c)
return {x=x,y=y,z=z,w=w,c=c}
end
-- create a voxel object and draw it
function gt_draw_new_voxel(x,y,z,w,c)
gt_draw_voxel({x=x,y=y,z=z,w=w,c=c})
end
-- draw a voxel object
function gt_draw_voxel(v)
-- transform
local cs=gt_cam.cs
local ss=gt_cam.ss
local ct=gt_cam.ct
local st=gt_cam.st
local k=gt_cam.k
local x=v.x-gt_cam.x
local y=v.y-gt_cam.y
local z=v.z-gt_cam.z
x,y=x*cs-y*ss,x*ss+y*cs
-- depth
local dz=(z*ct-y*st)*k
-- perspective
local p=gt_cam.p
if p then
if dz>=p then
v.r=false
return
else
k/=(1-dz/p)
end
end
v.r=true
-- save render position to object
v.rx=x*k+64
v.ry=(y*ct+z*st)*k+64
v.rw=v.w*k
-- save to bucket
-- depth resolution is int, can multiply
-- before flr() to increase resolution
-- (more buckets, but may perform worse)
local d=flr(dz)
if gt_mind==nil then
gt_mind=d
gt_maxd=d
else
gt_mind=min(gt_mind,d)
gt_maxd=max(gt_maxd,d)
end
local b=gt_buckets[d]
if not b then
b={}
gt_buckets[d]=b
end
add(b,v)
end
-- main functions
-- call at the start of _update, after camera parameters have been set
function gt_start()
gt_buckets={}
gt_mind=nil
gt_maxd=nil
gt_cam.cs=cos(gt_cam.s)
gt_cam.ss=sin(gt_cam.s)
gt_cam.ct=cos(gt_cam.t)
gt_cam.st=sin(gt_cam.t)
end
-- call at the end of _draw, after all draw calls have been made
function gt_end()
if gt_mind then
for d=gt_mind,gt_maxd do
local b=gt_buckets[d]
if b then
for i=1,#b do
local o=b[i]
local x=o.rx
local y=o.ry
local w=o.rw
rectfill(x-w,y-w,x+w,y+w,o.c)
-- debug stuff
-- draw voxel outline
--rect(x-w,y-w,x+w,y+w,0)
-- put a flip in it:
--if n%20==0 then flip() end
end
end
end
end
end
-- gumtree_test.lua
-- create input handler to move camera
-- call in update (before gt_start)
function gt_test_cam()
local ix,iy=0,0
if(btn(0))ix-=1
if(btn(1))ix+=1
if(btn(2))iy-=1
if(btn(3))iy+=1
local s=-gt_cam.s
local cs=cos(s)
local ss=sin(s)
local rix,riy=ix*cs-iy*ss,ix*ss+iy*cs
if btn(4) and btn(5) then
gt_cam.p+=ix
elseif btn(4) then
gt_cam.s-=ix/130
gt_cam.t+=iy/130
--cam.t=mid(0,cam.q,1/4)
elseif btn(5) then
gt_cam.k+=ix/4
gt_cam.z-=iy/8
else
gt_cam.x+=rix/8
gt_cam.y+=riy/8
end
end
-- kirby.p8
function lerp(t,a,b)
return a+(b-a)*t
end
function rot(x,y,a)
return x*cos(a)-y*sin(a),x*sin(a)+y*cos(a)
end
function _draw()
cls(7)
--gt_test_cam()
gt_cam.t=0.23
gt_cam.s=0.75+sin(t()/8)*0.09
gt_cam.k=6
gt_cam.p=100
gt_start()
kirby()
gt_end()
--?stat(1),1,1,8
end
function rnd2(a,b)
return a+rnd(b-a)
end
function sphc(r,a,b)
return
r*cos(a)*cos(b),
r*sin(a)*cos(b),
-r*sin(b)
end
function sph(r,a,b,w,c)
gt_draw_new_voxel(
r*cos(a)*cos(b),
r*sin(a)*cos(b),
-r*sin(b),
w,
c
)
end
dusts={}
frame=0
fillp(0x5a5a)
--debug: slow animation rate
--function t() return frame/200 end
function kirby()
--body radius
local r=4
--twist amount
local ta=sin(t()*3+0.25)*0.012
--vertical bobbing offset
local dz=sin(t()*6+0.6)*0.19
--dust
if frame%2==0 then
local dust=gt_voxel(
-2.5,
rnd2(-3.2,3.2),
-5,
0.7,
6+7*16
)
add(dusts,dust)
end
for dust in all(dusts) do
gt_draw_voxel(dust)
dust.w*=0.9
dust.x-=1.4
if dust.w<0.05 then
del(dusts,dust)
end
end
--body
for v=-0.98,0.98,0.1 do
local s=sqrt(1-v*v)
for a=0,1,0.1-s*0.05 do
a-=ta/3
local x2=v*r
local y2=s*cos(a)*r
local z2=s*sin(a)*r+dz
gt_draw_new_voxel(
x2,
y2,
z2,
0.55,
14*17
)
end
end
for i=-1,1,2 do
local ra=sin(t()*3+i/4)*0.13
local rb=i*ra*0.6
--eyes and blush
function face(r,a,b,w,c)
local x,y,z=sphc(r,a,b)
x,y=rot(x,y,ta)
z+=dz
gt_draw_new_voxel(x,y,z,w,c)
end
a=i/28
for j=0,1,0.1 do
--local j2=(1+j)/2
--local r1=sqrt(1.2-j*j)
--local r2=sqrt(max(0.33-(j-0.27)^2))*1.6
--local lr=sqrt(2-((j-.75)*7)^2)
--local kp=sqrt(1.1-(j*2-1)^2)*0.01
--for p=-1,1,.25 do
-- if abs(p)<r1 then
-- face(r+.6,a+p*0.01,lerp(j2,0.02,0.08),0.04,abs(p)<r2 and 7*17 or 17)
-- end
--end
--eye dark
face(r+.6,a,lerp(j,0.02,0.08),0.37-abs(j-0.5)*0.4,17)
--eye light
face(r+.85,a,lerp(j,0.047,0.073),0.22-abs(j-0.5)*0.3,7*17)
--blush
face(r+.4,a+i*lerp(j,0.03,0.07),0.01,0.3-abs(j-0.5)*0.3,14+8*16)
end
--arm
local y=i*4.5
for v=-1,1,0.25 do
local s=sqrt(1-v*v)
for a=0,0.9,0.1 do
local x2=1+s*cos(a)*0.6
local y2=y+v*1.2
local z2=s*sin(a)
y2,z2=rot(y2,z2,-i*0.08)
x2,y2=rot(x2,y2,rb*0.5-i*0.06)
gt_draw_new_voxel(
x2,
y2,
z2+dz,
0.3,
14*17
)
end
end
--feet
y=i*1.7
for v=-1,1,0.25 do
local s=sqrt(1-v*v)
for a=0,0.8,0.2 do
local x2=v*1.5
local y2=y+s*cos(a)*1
local z2=-5+s*sin(a)*0.4
x2,z2=rot(x2,z2,ra*1.2)
gt_draw_new_voxel(
x2,
y2,
z2+dz,
0.4,
8*17
)
end
end
end
--mouth
local x,y,z=sphc(r+0.5,0,0)
x,y=rot(x,y,ta)
gt_draw_new_voxel(x,y,z+dz,0.08,0)
frame+=1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment