Last active
July 4, 2020 17:06
-
-
Save lucatronica/88a06e719172efe43984378354369a3a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- gumtree.lua | |
-- pico-8 3d/voxel library | |
-- | |
-- coordinates: x,y = ground; z = vertical | |
-- | |
-- how it works: | |
-- to make sure shapes in the right order, we need to sort them from back to front. | |
-- to do this shapes are drawn only once the scene has been populated. | |
-- we represent shapes as tables, created using gumtree functions. | |
-- | |
-- how to use: | |
-- function _draw() | |
-- -- setup camera | |
-- gt_cam.x=0 | |
-- gt_cam.y=0 | |
-- gt_cam.s=t()/4 | |
-- | |
-- -- call gt_ draw methods between gt_start() and gt_end(). | |
-- gt_start() | |
-- | |
-- for i=0,15 do | |
-- gt_draw_new_voxel(i*0.2,0,0,1,i) | |
-- end | |
-- | |
-- gt_end() | |
-- end | |
-- camera | |
local gt_cam={ | |
-- position | |
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, | |
} | |
-- [internal] buckets | |
local gt_mind=nil | |
local gt_maxd=nil | |
local gt_buckets={} | |
-- [internal] save an object to the gumtree buckets | |
function gt_save_bucket(o,z) | |
-- save to bucket | |
-- depth resolution is int, can multiply | |
-- before flr() to increase resolution | |
-- (more buckets, but may perform worse) | |
local d=flr(z) | |
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 b==nil then | |
b={} | |
gt_buckets[d]=b | |
end | |
add(b,o) | |
end | |
-- transform a 3D point to screen space | |
-- returns multiple values: (screen_x, screen_y, screen_z, scale) | |
-- returns nil if point is outside the screen | |
function gt_transform(x,y,z) | |
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 | |
x=x-gt_cam.x | |
y=y-gt_cam.y | |
z=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 | |
return | |
else | |
k/=(1-dz/p) | |
end | |
end | |
return x*k+64,(y*ct+z*st)*k+64,dz,k | |
end | |
-- voxels | |
-- create a voxel object | |
function gt_voxel(x,y,z,w,c) | |
return {x=x,y=y,z=z,w=w,c=c,t=0} | |
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,t=0}) | |
end | |
-- draw a voxel object | |
function gt_draw_voxel(v) | |
-- save render position to object | |
local z,k | |
v.rx,v.ry,z,k=gt_transform(v.x,v.y,v.z) | |
if k==nil then | |
v.r=false | |
return | |
end | |
v.r=true | |
v.rw=v.w*k | |
gt_save_bucket(v,z) | |
end | |
-- lines | |
-- lines uses the mid-point for ordering | |
-- create a line object | |
function gt_line(x1,y1,z1,x2,y2,z2,c) | |
return {x1=x1,y1=y1,z1=z1,x2=x2,y2=y2,z2=z2,c=c,t=1} | |
end | |
-- create and draw a line object | |
function gt_draw_new_line(x1,y1,z1,x2,y2,z2,c) | |
gt_draw_line({x1=x1,y1=y1,z1=z1,x2=x2,y2=y2,z2=z2,c=c,t=1}) | |
end | |
-- draw a line object | |
function gt_draw_line(l) | |
local z1,z2 | |
l.rx1,l.ry1,z1=gt_transform(l.x1,l.y1,l.z1) | |
l.rx2,l.ry2,z2=gt_transform(l.x2,l.y2,l.z2) | |
if z1==nil or z2==nil then | |
l.r=false | |
return | |
end | |
l.r=true | |
--use center of line for depth | |
gt_save_bucket(l,(z1+z2)/2) | |
end | |
-- main functions | |
-- call before drawing objects, 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 | |
-- draws objects to the screen. call 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 t=o.t | |
if t==0 then | |
--voxel | |
local x=o.rx | |
local y=o.ry | |
local w=o.rw | |
rectfill(x-w,y-w,x+w,y+w,o.c) | |
elseif t==1 then | |
--line | |
line(o.rx1,o.ry1,o.rx2,o.ry2,o.c) | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment