Files
TIC-80/demos/car.lua
Alice 81de993d66 Cleanup: remove all trailing spaces from the source code (#2664)
* `cmake`: Remove trailing spaces

* `build`, `src`: Remove trailing spaces

* `templates`: Remove trailing spaces

* `demos`: Remove trailing spaces

* `include`: Remove trailing spaces
2024-08-26 21:01:59 +02:00

297 lines
8.6 KiB
Lua

-- title: ModelRenderer
-- author: FlamingPandas
-- desc: Shows 3D models
-- script: lua
point={x=0,y=0,z=300}
fov=100
mesh={} -- Table that contains all the 3D points
polygon={} -- Table that contains all connections of 3D points to create triangle polygons, with their texture specified too
zorder={} -- Table used to know the rendering order of the triangles
rspeed=.1 -- Rotation speed, you can change it
tspeed=10 -- Translation speed, you can change it
function addMesh(mx,my,mz)
local m={x=mx,y=my,z=mz,u=0,v=0}
table.insert(mesh,m)
end
function addPolygon(pp1,pp2,pp3,pu1,pv1,pu2,pv2,pu3,pv3)
local p={p1=pp1,p2=pp2,p3=pp3,u1=pu1,v1=pv1,u2=pu2,v2=pv2,u3=pu3,v3=pv3,zOrd=0}
table.insert(polygon,p)
end
function addZOrder(polygon,zor)
local z={poly=polygon,zo=zor}
table.insert(zorder,z)
end
function init()
--"Loading" points and polygon data
local m=addMesh
m(-60,-60,5)
m(60,-60,5)
m(-60,-100,0)
m(60,-100,0)
m(-60,-105,-20)
m(60,-105,-20)
m(-60,-90,-30)
m(60,-90,-30)
m(-60,95,-30)
m(60,95,-30)
m(-60,100,-25)
m(60,100,-25)
m(-60,100,0)
m(60,100,0)
m(-60,50,5)
m(60,50,5)
m(-55,10,30)
m(55,10,30)
m(-55,-50,30)
m(55,-50,30)
local p=addPolygon
--UnderNeath Surface
p(7,8,10, 32,0,48,0,48,16)
p(7,10,9, 32,0,48,16,32,16)
--Back Protection
p(5,6,8, 16,12,32,12,32,16)
p(5,8,7, 16,12,32,16,16,16)
--Back lights
p(3,4,6, 16,8,32,8,32,12)
p(3,6,5, 16,8,32,12,16,12)
--Back Capo... maletera
p(1,2,4, 0,0,16,0,16,8)
p(1,4,3, 0,0,16,8,0,8)
--Back WindShield
p(19,20,2, 48,8,64,8,64,14)
p(19,2,1, 48,8,64,14,48,14)
--Roof
p(20,19,17, 0,7,16,7,16,16)
p(20,17,18, 0,7,16,16,0,16)
--Front WindShield
p(18,15,16, 48,0,64,8,48,8)
p(18,17,15, 48,0,64,0,64,8)
--Front Capo
p(16,13,14, 0,0,16,8,0,8)
p(16,15,13, 0,0,16,0,16,8)
--Front Lights
p(14,13,11, 16,0,32,0,32,4)
p(14,11,12, 16,0,32,4,16,4)
--Front Protection
p(12,11,9, 16,5,32,5,32,8)
p(12,9,10, 16,5,32,5,16,8)
--Left WindShield
p(16,20,18, 64,8,80,0,64,0)
p(16,2,20, 64,8,80,8,80,0)
--Right WindShield
p(15,17,19, 64,8,64,0,80,0)
p(15,19,1, 64,8,80,0,80,8)
--Right side
p(4,2,6, 32,24,24,24,32,28)
p(6,2,8, 32,28,24,24,28,32)
p(2,16,8, 24,24,10,24,28,32)
p(8,16,10, 28,32,10,24,1,32)
p(16,12,10, 10,24,0,31,1,32)
p(16,14,12, 10,24,0,24,0,31)
--Left side
p(1,3,5, 24,16,32,16,32,20)
p(1,5,7, 24,16,32,20,28,24)
p(15,1,7, 10,16,24,16,28,24)
p(15,7,9, 10,16,28,24,1,24)
p(15,9,11, 10,16,1,24,0,23)
p(15,11,13, 10,16,0,23,0,16)
for i,p in pairs(polygon) do
addZOrder(i,0)
end
end
init()
mode=1
function TIC()
if btn(6) then
if btn(0) then translate(0,-tspeed,0) end
if btn(1) then translate(0,tspeed,0) end
if btn(2) then translate(-tspeed,0,0) end
if btn(3) then translate(tspeed,0,0) end
else
if btn(0) then rotatateX(-rspeed) end
if btn(1) then rotatateX(rspeed) end
if btn(2) then rotatateY(-rspeed) end
if btn(3) then rotatateY(rspeed) end
end
if btn(4) then if fov<800 then fov=fov+10 end end
if btn(5) then if fov>10 then fov=fov-10 end end
if btnp(7) then if mode<3 then mode=mode+1 else mode=1 end end
cls(13)
--Shows info from the zorder table
-- for i,z in pairs(zorder) do
-- print(z.poly.." - "..z.zo,10,10*i)
-- end
calculateMeshUV()
calculateZOrder()
table.sort(zorder,function(a,b) return a.zo > b.zo end)
if mode==1 then showMesh() end
if mode==2 then showWireFrame() end
if mode==3 then showMesh() showWireFrame() end
end
--Given this 3D points calculate how they would look in a 2D screen
function calculateMeshUV()
for i,m in pairs(mesh) do
m.u=((m.x+point.x)*(fov/(m.z+point.z)))+120
m.v=((m.y+point.y)*(fov/(m.z+point.z)))+70
end
end
-- I made this up but not works... it gives the average of the depth of the three points of each triangle, it works good enough to know witch triangles to draw first (the further ones)
function calculateZOrder()
m=mesh
for i,p in pairs(polygon) do
p.zord=(m[p.p1].z+m[p.p2].z+m[p.p3].z)/3
updateZOrder(i,p.zord)
end
end
-- Once calculated the zorder you need to update the zorder table with those values
-- Why do we need this values in another table? well... lua can sort this table and now we have the order in witch to draw the triangles
function updateZOrder(polygon,zor)
for i,z in pairs(zorder) do
if z.poly==polygon then
z.zo=zor
end
end
end
-- Using the textri function you can show triangles with textures
-- This function draws all triangles that are facimg the camera with the textures defined on the init function
-- The function draws them in the zorder from further to closest so when a triangle is closer it shows "Above" othee triangles
function showMesh()
m=mesh
for i,z in pairs(zorder) do
p=polygon[z.poly]
-- If the triangle points are clockwise they are facing the camera
if isClockWise(p) then
--Draw the textured triangle
ttri(m[p.p1].u,m[p.p1].v,
m[p.p2].u,m[p.p2].v,
m[p.p3].u,m[p.p3].v,
p.u1,p.v1,
p.u2,p.v2,
p.u3,p.v3,
0,{},
(m[p.p1].z+point.z),
(m[p.p2].z+point.z),
(m[p.p3].z+point.z))
end
end
end
-- Given a triangle return true if it's points are clockwise false if they aren't
function isClockWise(poly)
p=poly
m=mesh
if ((m[p.p2].v-m[p.p1].v)*
(m[p.p3].u-m[p.p2].u))-
((m[p.p3].v-m[p.p2].v)*
(m[p.p2].u-m[p.p1].u))>0 then
return false
else
return true
end
end
--Function that draws all lines in the three points of a triangle (it just shpws the WireFrame and also the individual points)
function showWireFrame()
m=mesh
for i,p in pairs(polygon) do
line(m[p.p1].u,m[p.p1].v,m[p.p2].u,m[p.p2].v,15)
line(m[p.p2].u,m[p.p2].v,m[p.p3].u,m[p.p3].v,15)
line(m[p.p3].u,m[p.p3].v,m[p.p1].u,m[p.p1].v,15)
end
for i,m in pairs(mesh) do
circ(m.u,m.v,1,0)
print(i,m.u,m.v+5,3)
end
end
-- Rotates all pf the points in the mesh by an angle in the x axes
function rotatateX(angle)
cos=math.cos(angle)
sin=math.sin(angle)
for i,p in pairs(mesh) do
y=p.y*cos-p.z*sin
z=p.z*cos+p.y*sin
p.y=y
p.z=z
end
end
function rotatateY(angle)
cos=math.cos(angle)
sin=math.sin(angle)
for i,p in pairs(mesh) do
x=p.x*cos-p.z*sin
z=p.z*cos+p.x*sin
p.x=x
p.z=z
end
end
function rotatateZ(angle)
cos=math.cos(angle)
sin=math.sin(angle)
for i,p in pairs(mesh) do
x=p.x*cos-p.y*sin
y=p.y*cos+p.x*sin
p.x=x
p.y=y
end
end
-- Translate all of the points an x,y and z distance
function translate(dx,dy,dz)
point.x=point.x+dx
point.y=point.y+dy
point.z=point.z+dz
end
-- <TILES>
-- 000:66666ff666666ff666666ff666666ff666666ff666666ff666666ff666666ff6
-- 001:6ff666666ff666666ff666666ff666666ff666666ff666666ff666666ff66666
-- 002:66666ff66ee373736ee737376666666663333333633333336333333363333333
-- 003:6ff6666673737ee637373ee66666666633333336333333363333333633333336
-- 004:63337733633377336333377363333773633aaaa3633aaaa3633aaaa3633aaaa3
-- 005:337733363377333637733336377333363aaaa3363aaaa3363aaaa3363aaaa336
-- 006:66666ff66888dd33688ddd8868ddd8886ddd888d6dd888dd6d00000d66666ff6
-- 007:6ff6666633ddd8868ddd8886ddd88886dd888886d8888886800000866ff66666
-- 008:6666666668888888688888886888888868888888688888886888888866666666
-- 009:6666666688888886888888868888888688888886888888868888888666666666
-- 010:6666666666666666666666666666666666666666666666666666666666666666
-- 011:6666666666666666666666666666666666666666666666666666666666666666
-- 016:66666f00666660ff66660ff066660fff66660fff666660ff66666f0066666ff6
-- 017:00f66666ff0666660ff066660ff066660ff06666ff06666600f666666ff66666
-- 018:66666ff669996faa69996faa666600f663337733633377336333773363337733
-- 019:6ff66666aaf69996aaf699966f00666633773336337733363377333633773336
-- 020:6333337363333373633337336333373363333733633337336333333363333333
-- 021:3733333637333336337333363373333633733336337333363333333633333336
-- 022:66666ff66888ddd8688ddd8868ddd8886dd0000066666ff60000000000000000
-- 023:6ff6666688ddd8868ddd8886ddd88886dd8888866ff666660000000000000000
-- 026:6666666666666666666666666666666666666666666666666666666666666666
-- 027:6666666666666666666666666666666666666666666666666666666666666666
-- 032:6666666666666666666666666666666666666666666666336666630066663000
-- 033:6666666666666666666006666666666666666666336666660036666600036666
-- 034:6666666666666666666666666666666666666666666666336666630066663000
-- 035:6666666666666666666666666666666666666666336666660036666600036666
-- 048:6666666666666666666666666666666666666666666666336666630066663000
-- 049:6666666666666666666006666666666666666666336666660036666600036666
-- 050:6666666666666666666666666666666666666666666666336666630066663000
-- 051:6666666666666666666666666666666666666666336666660036666600036666
-- </TILES>
-- <PALETTE>
-- 000:140c1c44243430346d4e4a4e854c30346524d04648757161597dceb23c408595a16daa2cd2aa996dc2cadad45edeeed6
-- </PALETTE>