PicoPicoGameEngine

Quick Links

Source Code

g=ppgraph
sc=ppscreen

sqrt=math.sqrt
tan=math.tan
sin=math.sin
cos=math.cos
rand=math.random

function v3print(s)
 print(s.x..","..s.y..","..s.z)
end

function v3(x,y,z)
local q={}
q.x=x
q.y=y
q.z=z
q.print=v3print
return q
end

function nml(p)
local q={}
local l
l=p.x*p.x+p.y*p.y+p.z*p.z
l=sqrt(l)
q.x=p.x/l
q.y=p.y/l
q.z=p.z/l
q.print=v3print
return q
end

function abs(a)
 if a<0 then
   a=-a
 end
 return a
end

function sgn(a)
 if a<0 then
   return -1
 end
 return 1
end

function add(a,b,r)
 local v
 v=v3(0,0,0)
 v.x=a.x+b.x*r
 v.y=a.y+b.y*r
 v.z=a.z+b.z*r
 return v
end

function sub(a,b)
return add(a,b,-1)
end

function dot(a,b)
local q={}
q.x=a.x*b.x
q.y=a.y*b.y
q.z=a.z*b.z
local r
r=q.x+q.y+q.z
return r
end

function plane(p,n)
local t={}
t.p=p
t.n=n
t.cross=function(s,a,b)
local p,n
p=s.p
n=s.n
local ad=dot(n,sub(a,p))
local bd=dot(n,sub(b,p))
if abs(ad)<0.00001
then ad=0 end
if abs(bd)<0.00001
then bd=0 end
local r={}
r.ad=ad
r.bd=bd
if ad==0 and bd==0 then
 return r
end
if (ad>=0 and bd<=0)
or (ad<=0 and bd>=0) then
ad=abs(ad)
bd=abs(bd)
local d=ad/(ad+bd)
b=add(b,a,-1)
b.x=b.x*d
b.y=b.y*d
b.z=b.z*d
r.p=add(a,b,1)
end
return r
end
return t
end

function
pmap(fov_h,fov_v,near,far)
local t={}
t.w=1/tan(fov_h*0.5)
t.h=1/tan(fov_v*0.5)
t.q=far/(far-near)
t.u=-t.q*near
t.mul=function(s,p)
local t={}
t.x=s.w*p.x
t.y=s.h*p.y
t.z=s.q*p.z+s.u
t.print=v3print
return t
end
return t
end

function rad(r)
r=math.pi*r/180
return r
end

function trans(v,p)
 local a={}
 a.x=v.x+p.x
 a.y=v.y+p.y
 a.z=v.z+p.z
 return a
end

function rotx(v,r)
 local a={}
 a.x=v.x
 a.y=v.y*cos(r)+v.z*sin(r)
 a.z=-v.y*sin(r)+v.z*cos(r)
 return a
end

function roty(v,r)
 local a={}
 a.x=v.x*cos(r)-v.z*sin(r)
 a.y=v.y
 a.z=v.x*sin(r)+v.z*cos(r)
 return a
end

function rotz(v,r)
 local a={}
 a.x=v.x*cos(r)+v.y*sin(r)
 a.y=-v.x*sin(r)+v.y*cos(r)
 a.z=v.z
 return a
end

proj=pmap(
  rad(90),rad(90),
  100,1000)

cube={
 v={
  v3(100,100,100),
  v3(-100,100,100),
  v3(100,-500,100),
  v3(-100,-500,100),
  v3(100,100,-100),
  v3(-100,100,-100),
  v3(100,-500,-100),
  v3(-100,-500,-100)
 },
 p={
 {1,2},
 {2,4},
 {4,3},
 {3,1},
 {5,6},
 {6,8},
 {8,7},
 {7,5},
 {1,5},
 {2,6},
 {3,7},
 {4,8}},
 t={
  -- {1,3,4,2,g.cyan},
  {5,6,8,7,{160,160,185}},
  -- {1,2,6,5,g.red},
  {3,7,8,4,{190,175,200}},
  {1,5,7,3,{120,120,150}},
  {2,4,8,6,{120,120,150}},
 }
}

cube2={
 v={
  v3(100,100,100),
  v3(-100,100,100),
  v3(100,-100,100),
  v3(-100,-100,100),
  v3(100,100,-100),
  v3(-100,100,-100),
  v3(100,-100,-100),
  v3(-100,-100,-100)
 },
 p={
 {1,2},
 {2,4},
 {4,3},
 {3,1},
 {5,6},
 {6,8},
 {8,7},
 {7,5},
 {1,5},
 {2,6},
 {3,7},
 {4,8}},
 t={
  -- {1,3,4,2,g.cyan},
  {5,6,8,7,{60,65,105}},
  -- {1,2,6,5,g.red},
  {3,7,8,4,{90,90,125}},
  {1,5,7,3,{35,30,60}},
  {2,4,8,6,{35,30,60}},
 }
}

star={
 v={
  v3(0,0,0)
 }
}

grid={
 v={
  v3(-300000,
      600000,2000),
  v3( 300000,
      600000,2000),
  v3( 300000,
           0,2000),
  v3(-300000,
           0,2000),
 },
 p={
  {1,2},
  {2,3},
  {3,4},
  {4,1}
 },
 t={
  {1,4,3,2,{75,210,123}},
 }
}

c=ppoffscreen.new()
c:create(1,1)
--c.y=100

s={}
s.x=500
s.y=500

function scr(v)
local t={}
t.x=(v.x/v.z)*s.x+160
t.y=(v.y/v.z)*s.y+240
return t
end

function drawpos(v)
 g:fill(v.p.x,
        v.p.y,2,2)
end

function drawline(p,v)
for i=1,#p do
local q=p[i]
local a,b,c
a=v[q[1]].w
b=v[q[2]].w
c=pln:cross(a,b)
if c.ad>0 and c.bd>0 then
else
if c.p~=nil then
 if c.ad>=0 then
   a=c.p
 else
   b=c.p
 end
end
g:line(
   scr(a),
   scr(b))
end
end
end

function culface(a,b,c)
local d={}
d.x=b.x-a.x
d.y=b.y-a.y
local e={}
e.x=c.x-a.x
e.y=c.y-a.y
d=d.x*e.y-d.y*e.x
return (d>0)
end

function drawtri(p1,p2,p3,col)
if culface(p1,p2,p3) then
g:triangleFan(
  {p1,p2,p3},col)
end
end

function clip(p1,p2,p3,col)
local c1,c2,c3
c1=pln:cross(p1.w,p2.w)
c2=pln:cross(p2.w,p3.w)
c3=pln:cross(p3.w,p1.w)
if c1.ad>=0 and c1.bd>=0 then
if c2.ad>=0 and c2.bd>=0 then
return
end
p1=scr(c3.p)
p2=scr(c2.p)
p3=p3.p
drawtri(p1,p2,p3,col)
else
if c1.p~=nil then
 c1.p=scr(c1.p)
 if c1.ad>=0 then
   if c2.p~=nil then
     c2.p=scr(c2.p)
     p1=c1.p
     p2=p2.p
     p3=c2.p
drawtri(p1,p2,p3,col)
   else
     c3.p=scr(c3.p)
     p1=c1.p
     p2=p2.p
     p3=p3.p
drawtri(p1,p2,p3,col)
     p1=c3.p
     p2=c1.p
--     p3
drawtri(p1,p2,p3,col)
   end
 else
   if c2.p~=nil then
     c2.p=scr(c2.p)
     p1=p1.p
     p2=c1.p
     p3=p3.p
drawtri(p1,p2,p3,col)
     p1=c1.p
     p2=c2.p
--     p3
drawtri(p1,p2,p3,col)
   else
     c3.p=scr(c3.p)
     p1=p1.p
     p2=c1.p
     p3=c3.p
drawtri(p1,p2,p3,col)
   end
 end
else
if c2.p~=nil then
c2.p=scr(c2.p)
c3.p=scr(c3.p)
p1=p1.p
p2=p2.p
p3=c2.p
drawtri(p1,p2,p3,col)
--p1
p2=c2.p
p3=c3.p
drawtri(p1,p2,p3,col)
else
p1=p1.p
p2=p2.p
p3=p3.p
drawtri(p1,p2,p3,col)
end
end
end
end

function drawpoly(t,v)
for i=1,#t do
local p=t[i]
clip(v[p[1]],
     v[p[2]],
     v[p[3]],p[5])
clip(v[p[1]],
     v[p[3]],
     v[p[4]],p[5])
end
end

function drawpoly2(t,v)
for i=1,#t do
local p=t[i]
p1=v[p[1]]
p2=v[p[2]]
p3=v[p[3]]
drawtri(p1.p,p2.p,p3.p,p[5])
p1=v[p[1]]
p2=v[p[3]]
p3=v[p[4]]
drawtri(p1.p,p2.p,p3.p,p[5])
end
end

function obj(shape,x,y,z)
local t={}
t.mv=v3(x,y,z)
t.r=v3(0,0,0)
t.shape=shape
t.idle=function(s)
s.mv=add(s.mv,view.z,-1)
s.mv.z=s.mv.z-10
if s.mv.z<0 then
s.mv.x=rand(-600,600)
s.mv.y=0
s.mv.z=4000
end
end
t.draw=function(s)
local v=s.shape.v
local t=s.shape.t
local q=s.shape.p
local rx=s.r.x
local ry=s.r.y
local rz=s.r.z
local mv={}
mv.x=s.mv.x+vp.x
mv.y=s.mv.y+vp.y
mv.z=s.mv.z
for i=1,#v do
local p
p=rotx(v[i],rx)
p=roty(p,ry)
p=rotz(p,rz)
p=trans(p,mv)
p=view:mul(p)
p=proj:mul(p)
v[i].w=p
v[i].p=scr(p)
end
if t then
if v[1].w.z>500 then
drawpoly2(t,v)
else
drawpoly(t,v)
end
end
end
return t
end

prim={}
for i=1,10 do
local t
local x,y,z
x=math.random(-600,600)
y=0
z=4000-i*400
if math.random(1,2)==1 then
t=obj(cube,x,y,z)
else
t=obj(cube2,x,y,z)
end
prim[#prim+1]=t
end

wall=function(s)
s.mv=add(s.mv,view.z,-1)
s.mv.z=s.mv.z-10
if s.mv.z<0 then
s.mv.z=4000
end
end

for i=1,5 do
local t
local x,y,z
x=-900
y=0
z=4000-i*800
t=obj(cube,x,y,z)
t.idle=wall
prim[#prim+1]=t
end
for i=1,5 do
local t
local x,y,z
x=900
y=0
z=4000-i*800
t=obj(cube,x,y,z)
t.idle=wall
prim[#prim+1]=t
end

pln=plane(
  v3(0,0,0),
  v3(0,0,-1))
pln.r=v3(0,0,0)

grd=obj(grid,0,0,2000)

view={}
view.x=v3(1,0,0)
view.y=v3(0,1,0)
view.z=v3(0,0,1)
view.shape=function(v)
local s=100
local t={}
t[#t+1]=v3(0,0,0)
t[#t+1]=v3(v.x.x*s,
           v.x.y*s,
           v.x.z*s)
t[#t+1]=v3(v.y.x*s,
           v.y.y*s,
           v.y.z*s)
t[#t+1]=v3(v.z.x*s,
           v.z.y*s,
           v.z.z*s)
local p={{1,2},{1,3},{1,4}}
return {v=t,p=p}
end
view.rotx=function(s,r)
 s.y=nml(add(s.y,s.z,-r))
 s.z=nml(add(s.z,s.y, r))
end
view.roty=function(s,r)
 s.x=nml(add(s.x,s.z,-r))
 s.z=nml(add(s.z,s.x, r))
end
view.rotz=function(s,r)
 s.x=nml(add(s.x,s.y, r))
 s.y=nml(add(s.y,s.x,-r))
end
view.mul=function(s,v)
local p=v3(0,0,0)
p.x= s.x.x*v.x
    +s.x.y*v.y
    +s.x.z*v.z
p.y= s.y.x*v.x
    +s.y.y*v.y
    +s.y.z*v.z
p.z= s.z.x*v.x
    +s.z.y*v.y
    +s.z.z*v.z
return p
end

axis=obj(view:shape(),0,0,400)
vp=v3(0,0,0)

function start()
 g:fill(sc:size(),{140,175,240})
 c:drag(pptouch())
 if #pptouch()==0 then
  c.x=c.x*0.95
  c.y=c.y*0.95
 end
 pln.p.z=10
 grd:draw()
 for i=1,#prim do
 local c
 c=prim[i]
 c:idle()
 end
 table.sort(prim,
  function(a,b)
    return (a.mv.z>b.mv.z)
  end)
 for i=1,#prim do
 local c
 c=prim[i]
 c:draw()
 end
 view.x=v3(1,0,0)
 view.y=v3(0,1,0)
 view.z=v3(0,0,1)
 local jd=c:pos()
 view:rotz(-c.x/500)
 if jd.x<-100 then jd.x=-100 end
 if jd.x> 100 then jd.x= 100 end
 if jd.y<-100 then jd.y=-100 end
 if jd.y> 100 then jd.y= 100 end
 vp.x=vp.x+jd.x/20
 vp.y=vp.y+jd.y/20
 if vp.x<-600 then vp.x=-600 end
 if vp.x> 600 then vp.x= 600 end
 if vp.y<-100 then vp.y=-100 end
 if vp.y> 400 then vp.y= 400 end
end