I've been working on this voxel renderer for a while. It works, I guess, but it only gets about 10 fps on my labtop (and the world is very small). I've done all the speed improvements to it that I can, all that I haven't been able to get working is the bresenham formula, which should speed it up well.
Here is the code. It requires Matrix1 Utilities and Advanced 2d (maybe more?)
Uncomment "`bresenham=1" to enable the bresenham renderer I have come up with so far.
Controls are qweasd to move, arrows to look.
I need help getting the bresenham to work right. I also noticed that when you look up or down, everything gets skewed. And of course I need help speeding it up.
#constant worldx 64
#constant worldy 32
#constant worldz 64
`Voxel renderer by Jackson C
local bresenham as boolean
`bresenham=1
set display mode 160,100,32
set window layout 0,0,1
maximize window
sync on : sync
dim screen(screen width(),screen height()) as dword
dim static(worldx,worldy,worldz) as dword
local x as integer
local y as integer
local z as integer
local n as integer
local doubleinteger as double integer
local fpstimer as double integer
local fps as float
local f as float
dim xtangent(screen width()) as float
for n=1 to screen width()
f=n
xtangent(n)=tan((f-(screen width()/2))*(screen width()/320.0)) `degrees per pixel
next
dim ytangent(screen height()) as float
for n=1 to screen height()
f=n
ytangent(n)=tan((f-(screen height()/2))*(screen width()/320.0)) `degrees per pixel
next
gosub makeworld
local camx as float =32.0
local camy as float =32.0
local camz as float =32.0
local camp as float =0.0
local camt as float =0.0
local camvd as float =300.0
local camsize as float =0.8
local vecx as float
local vecy as float
local vecz as float
local ptrx as float
local ptry as float
local ptrz as float
local trx as integer
local try as integer
local trz as integer
local camendx as float
local camendy as float
local camendz as float
local endx as float
local endy as float
local endz as float
local camxvecx as float
local camxvecz as float
local camyvecx as float
local camyvecy as float
local camyvecz as float
local camoriginx as float
local camoriginy as float
local camoriginz as float
local frames as dword
local back as boolean
local coscamp as float
local coscampvec as float
local intcamx as integer
local intcamy as integer
local intcamz as integer
local deltax as integer
local deltay as integer
local deltaz as integer
local deltamajor as integer
local deltaminor1 as integer
local deltaminor2 as integer
local major as byte
local minor1 as byte
local minor2 as byte
local minor1step as integer
local minor2step as integer
local minor1error as integer
local minor2error as integer
local majorpos as integer
local minor1pos as integer
local minor2pos as integer
local majormirror as boolean
local done as boolean
do
set window title str$(frames)
inc frames
cls 0
doubleinteger=hitimer(10000)
fps=(10000.0/(doubleinteger-fpstimer))
fpstimer=doubleinteger
if keystate(17) : inc camx,cos(camt)*(20.0/fps) : inc camz,sin(camt)*(20.0/fps) : endif
if keystate(31) : inc camx,cos(camt)*(-20.0/fps) : inc camz,sin(camt)*(-20.0/fps) : endif
if keystate(30) : inc camx,cos(camt-90.0)*(20.0/fps) : inc camz,sin(camt-90.0)*(20.0/fps) : endif
if keystate(32) : inc camx,cos(camt+90.0)*(20.0/fps) : inc camz,sin(camt+90.0)*(20.0/fps) : endif
if keystate(16) then inc camy,(20.0/fps)
if keystate(18) then inc camy,(-20.0/fps)
if upkey() then inc camp,(100.0/fps)
if downkey() then inc camp,(-100.0/fps)
if rightkey() then camt=wrapvalue(camt+(100.0/fps))
if leftkey() then camt=wrapvalue(camt-(100.0/fps))
if camx>worldx or camx<0 or camy>worldy or camy<0 or camz>worldz or camz<0 : camx=worldx/2 : camy=worldy/2 : camz=worldz/2 : camp=0.0 : camt=0.0 : endif
if camp>90.0 then camp=90.0
if camp<-90.0 then camp=-90.0
coscamp=cos(camp)
coscampvec=cos(camp-90.0)
camendx=camx+((cos(camt)*coscamp)*camvd)
camendy=camy+(sin(camp)*camvd)
camendz=camz+((sin(camt)*coscamp)*camvd)
camxvecx=cos(camt+90.0)*camsize
camxvecz=sin(camt+90.0)*camsize
camyvecx=cos(camt+90.0)*coscampvec*camsize
camyvecy=sin(camp-90.0)*camsize
camyvecz=sin(camt+90.0)*coscampvec*camsize
camoriginx=camendx+(camxvecx*(screen width()/-2))+(camyvecx*(screen height()/-2))
camoriginy=camendy+(camyvecy*(screen height()/-2))
camoriginz=camendz+(camxvecz*(screen width()/-2))+(camyvecz*(screen height()/-2))
intcamx=int(camx)
intcamy=int(camy)
intcamz=int(camz)
for x=1 to screen width()
for y=1 to screen height()
endx=camoriginx+(camxvecx*xtangent(x)*camvd)+(camyvecx*ytangent(y)*camvd)
endy=camoriginy+(camyvecy*ytangent(y)*camvd)
endz=camoriginz+(camxvecz*xtangent(x)*camvd)+(camyvecz*ytangent(y)*camvd)
`back=1
deltax=int(endx)-intcamx
deltay=int(endy)-intcamy
deltaz=int(endz)-intcamz
if bresenham
`x=1 y=2 z=3
if deltax>deltay and deltax>deltaz : major=1 : minor1=2 : minor2=3 : deltamajor=deltax : deltaminor1=deltay : deltaminor2=deltaz : endif
if deltay>deltaz and deltay>deltaz : major=2 : minor1=1 : minor2=3 : deltamajor=deltay : deltaminor1=deltax : deltaminor2=deltaz : endif
if deltaz>deltay and deltaz>deltax : major=3 : minor1=1 : minor2=2 : deltamajor=deltaz : deltaminor1=deltax : deltaminor2=deltay : endif
if deltamajor<0 : majormirror=1 : else : majormirror=0 : endif
if deltaminor1>0 : minor1step=1 : else : minor1step=-1 : endif
if deltaminor2>0 : minor2step=1 : else : minor2step=-1 : endif
deltamajor=abs(deltamajor)
deltaminor1=abs(deltaminor1)
deltaminor2=abs(deltaminor2)
minor1error=deltamajor/2
minor2error=minor1error
majorpos=0
minor1pos=0
minor2pos=0
done=0
repeat
inc majorpos
if majorpos>=deltamajor then done=1
dec minor1error,deltaminor1
dec minor2error,deltaminor2
if minor1error<0 : inc minor1pos,minor1step : inc minor1error,deltamajor : endif
if minor2error<0 : inc minor2pos,minor2step : inc minor2error,deltamajor : endif
if majormirror
if major=1 then trx=camx-majorpos
if major=2 then try=camy-majorpos
if major=3 then trz=camz-majorpos
else
if major=1 then trx=majorpos+camx
if major=2 then try=majorpos+camy
if major=3 then trz=majorpos+camz
endif
if minor1=1 then trx=minor1pos+camx
if minor1=2 then try=minor1pos+camy
if minor1=3 then trz=minor1pos+camz
if minor2=1 then trx=minor2pos+camx
if minor2=2 then try=minor2pos+camy
if minor2=3 then trz=minor2pos+camz
if trx<1 or trx>worldx : done=1 : trx=10 : endif
if try<1 or try>worldy : done=1 : try=10 : endif
if trz<1 or trz>worldz : done=1 : trz=10 : endif
until (static(trx,try,trz)>0) or done
else
f=distance(camx,camy,camz,endx,endy,endz)
vecx=deltax/f
vecy=deltay/f
vecz=deltaz/f
ptrx=camx
ptry=camy
ptrz=camz
n=0
repeat
inc n
inc ptrx,vecx
inc ptry,vecy
inc ptrz,vecz
trx=ptrx
try=ptry
trz=ptrz
if trx<1 or trx>worldx : n=301 : trx=10 : endif
if try<1 or try>worldy : n=301 : try=10 : endif
if trz<1 or trz>worldz : n=301 : trz=10 : endif
until (static(trx,try,trz)>0) or (n>300)
endif
if done or (n>300)
screen(x,y)=0
else
screen(x,y)=static(trx,try,trz)
endif
next
next
a2startdotbatch (screen width()*screen height())
for x=1 to screen width()
for y=1 to screen height()
if screen(x,y)>0 then a2dot x-1,y-1,screen(x,y)
next
next
a2endbatch
text 0,0,str$(screen fps())
sync
loop
function distance(x1 as float,y1 as float,z1 as float,x2 as float,y2 as float,z2 as float)
local output as float
output=sqrt(((x1-x2)^2)+((y1-y2)^2)+((z1-z2)^2))
endfunction output
makeworld:
for x=1 to worldx
for z=1 to worldz
if z<worldz/2
static(x,19,z)=0xffff0000
static(x,20,z)=0xffff0000
else
if rnd(1) then static(x,20,z)=0xff00ffff
endif
next
next
for x=10 to 30
for y=1 to worldy
for z=10 to 30
static(x,y,z)=0xff0000ff
next
next
next
static(32,18,32)=0xffff0000
static(32,17,32)=0xffff0000
static(32,16,30)=0xffff0000
static(32,16,31)=0xffff0000
static(32,16,32)=0xffff0000
static(32,16,33)=0xffff0000
static(32,16,34)=0xffff0000
static(32,15,32)=0xffff0000
static(32,14,32)=0xffff0000
static(32,32,32)=0xffffff00
text 0,0,"VOXELS"
for x=0 to text width("VOXELS")
for y=0 to text height("VOXELS")
if point(x,y) then static(worldx,worldy-y,x+1)=0xffffffff
next
next
return
"This plan is so perfect... it's retarded."