Skip to content

Instantly share code, notes, and snippets.

@JettMonstersGoBoom
Last active October 25, 2017 13:33
Show Gist options
  • Save JettMonstersGoBoom/7786f813a24b2ed449d0de559d3035dc to your computer and use it in GitHub Desktop.
Save JettMonstersGoBoom/7786f813a24b2ed449d0de559d3035dc to your computer and use it in GitHub Desktop.
-- title: Mode7
-- author: MonstersGoBoom and Nopy
-- desc: Mode7
-- script: lua
-- utility scripts
local math_sin = math.sin
local math_cos = math.cos
local math_rad = math.rad
local math_min = math.min
local math_max = math.max
local math_abs = math.abs
local math_atan2 = math.atan2
local clock = 0
function pal(c0,c1) if(c0==nil and c1==nil)then for i=0,15 do poke4(0x3FF0*2+i,i)end else poke4(0x3FF0*2+c0,c1)end end
function findCloseRGB(a,b,c)local d=99999999;local e=0;for f=0,15 do local g=peek(0x3fc0+f*3)local h=peek(0x3fc0+f*3+1)local i=peek(0x3fc0+f*3+2)local j=math.sqrt(math.pow(a-g,2)+math.pow(b-h,2)+math.pow(c-i,2))if j<=d then d=j;e=f end end;return e end
function lerp(a,b,amount) return a + (b - a) * amount end
-- Here's the fzero/mario cart floor mode7
local cam =
{
x=0,
y=64,
z=20, -- elevation
r=0,
rs=0,
ms = 0,
horizon=60, --pitch
--fog = {32,128,200},
fog = {0x00,0x00,0x00},
-- fogFar = 3.,
-- fogOn = true,
rotationSpeed = 0.5,
movementSpeed = 0.2,
}
-- now call this First
function cam:Init()
cam.map = {}
for y=0,135 do
for x=0,239 do
cam.map[1 + (x + (y*240))] = mget(x,y)
end
end
cam:UpdateFog()
end
-- helpers
function cam:mget(x,y)
x=(x//1)%240
y=(y//1)%136
return cam.map[1 + (x + (y*240))] -- use cam.map now
end
function cam:mset(x,y,val)
x=(x//1)%240
y=(y//1)%136
cam.map[1 + (x + (y*240))] = val
end
-- transform 3d point to cam space
function cam:Transform(ox,oy,oz)
local c = cam.c
local s = cam.s
local dx,dy,dz = ox-cam.x,oy-cam.y,oz-cam.z
local z = dx*c + dy*-s
local tx = dx*s + dy*c
local ty = dz
if( z > 0 ) then
tx = (tx*120) / z + 120
ty = (ty*68) / -z + cam.horizon
if tx < -100 or
tx > 340 or
ty < -100 or
ty > 235 then
return false,-999,-999
end
return true,tx,ty,z
end
return false,-999,-999
end
-- draw ground
function cam:Render()
local s,c = math_sin(math_rad(cam.r)),math_cos(math_rad(cam.r))
cam.s = s
cam.c = c
rect(0,0,240,cam.horizon+2,cam.cls)
rect(0,cam.horizon+2,240,136-cam.horizon,0)
local sy_step = 1./68.
local sy = sy_step
-- split the view
-- top part is double wide pixels, and fogable
cam.horizon2 = cam.horizon + ((136-cam.horizon)/4)//1
for y=cam.horizon,cam.horizon2 do
local t = cam.z / sy
sy = sy+sy_step
local V,V_step = (-c - s)*t + cam.y,(4/240)*c*t
local U,U_step = (-s + c)*t + cam.x,(4/240)*s*t
cam:Fog(8-(t//cam.horizon))
for x=0,239,2 do
local iU =(U//1) -- quick floor
local iV =(V//1) --
local mU = math_abs(iU>>3)
local mV = math_abs(iV>>3)
if mU<240 and mV<136 then
local id = cam.map[1 + (mU + (mV*240))] -- use cam.map now
if id then
local spram_addr=2*0x4000+(id<<6)+(iU&7)+((iV&7)<<3)
co = peek4(spram_addr)
rect(x,y,2,1,co)
end
end
V = V + V_step
U = U + U_step
end
end
-- bottom part is normal and unfogged
local scr_addr=2*0x0000 + cam.horizon2*240
pal()
for y=cam.horizon2,135 do
local t = cam.z / sy
sy = sy+sy_step
local V,V_step = (-c - s)*t + cam.y,(2/240)*c*t
local U,U_step = (-s + c)*t + cam.x,(2/240)*s*t
for x=0,239 do
local iU =(U//1) -- quick floor
local iV =(V//1) --
local mU = math_abs(iU>>3)
local mV = math_abs(iV>>3)
if mU<240 and mV<136 then
local id = cam.map[1 + (mU + (mV*240))] -- use cam map
if id then
local spram_addr=2*0x4000+(id<<6)+(iU&7)+((iV&7)<<3)
co = peek4(spram_addr)
poke4(scr_addr,co) -- poke directly
end
end
scr_addr = scr_addr+1
V = V + V_step
U = U + U_step
end
end
end
-- build the fog tables
function cam:UpdateFog()
cam.fogLookup = {}
for y=1,8 do
cam.fogLookup[y] = {}
local amount = (8-y)/8
--trace(amount)
for x=1,16 do
local i = x -1
local dr = peek(0x3fc0+(i*3))
local dg = peek(0x3fc0+(i*3)+1)
local db = peek(0x3fc0+(i*3)+2)
local r =lerp( dr,cam.fog[1], amount)
local g =lerp( dg,cam.fog[2], amount)
local b =lerp( db,cam.fog[3], amount)
i = findCloseRGB(r//1,g//1,b//1)
-- trace(r .. "," .. g .. "," .. b .. "=" .. i)
cam.fogLookup[y][x] = i
end
end
-- this is the rect clear color
cam.cls = findCloseRGB(cam.fog[1],cam.fog[2],cam.fog[3])
end
function cam:Fog(i)
if i<1 then i = 1 end
if i>8 then i = 8 end
for x=1,16 do
local ind = x-1
poke4(0x3FF0*2+ind,cam.fogLookup[i][x])
end
end
-- rotating thingy
function rspr(sx,sy,scale,angle,mx,my,mw,mh,key,useMap)
-- this is fixed , to make a textured quad
-- X , Y , U , V
-- local svc ={{-1,-1, 0,0},
-- { 1,-1, 0.9999999,0},
-- {-1,1, 0,1.0},
-- { 1,1, 1.0,1.0}}
local sv ={{-1,-2, 0,0},
{ 1,-2, 0.9999999,0},
{-1,0, 0,1.0},
{ 1,0, 1.0,1.0}}
local rp = {} -- rotated points storage
local a = -angle
local s = math_sin(a)
local c = math_cos(a)
-- the scale is mw ( map width ) * 4 * scale
-- mapwidth is * 4 because we actually want HALF width to center the image
local scalex = (mw*4) * scale
local scaley = (mh<<2) * scale
-- rotate the quad points
for p=1,#sv do
-- apply scale
local _sx = sv[p][1] * scalex
local _sy = sv[p][2] * scaley
-- apply rotation
local rx = _sx * c - _sy * s
local ry = _sx * s + _sy * c
-- apply transform
sv[p][1] = rx + sx
sv[p][2] = ry + sy
-- scale UV's
sv[p][3] = ((mx*8) + (sv[p][3] * mw*8))//1
sv[p][4] = ((my*8) + (sv[p][4] * mh*8))//1
end
-- draw two triangles for the quad
textri( sv[1][1],sv[1][2],
sv[2][1],sv[2][2],
sv[3][1],sv[3][2],
sv[1][3],sv[1][4],
sv[2][3],sv[2][4],
sv[3][3],sv[3][4],
useMap,key)
textri( sv[2][1],sv[2][2],
sv[3][1],sv[3][2],
sv[4][1],sv[4][2],
sv[2][3],sv[2][4],
sv[3][3],sv[3][4],
sv[4][3],sv[4][4],
useMap,key)
end
cam:Init()
function TIC()
--elevate
if btn(6) then
cam.z = cam.z + 1
end
--descend
if btn(4) then
cam.z = math_max( 1, cam.z - 1)
end
--pitch
if btn(7) then
cam.horizon = math_min(135-20,cam.horizon + 1)
end
if btn(5) then
cam.horizon = math_max(20,cam.horizon - 1)
end
--rotation
if btn(2) then
cam.rs = cam.rs + cam.rotationSpeed
end
if btn(3) then
cam.rs = cam.rs - cam.rotationSpeed
end
cam.r = cam.r + cam.rs
cam.rs = cam.rs * 0.9
--movement
if btn(0) then
cam.ms = cam.ms + cam.movementSpeed
end
if btn(1) then
cam.ms = cam.ms - cam.movementSpeed
end
--update camera
local fwd = math_rad(cam.r+90)
cam.x = cam.x + (math_sin(fwd)*cam.ms)
cam.y = cam.y + (math_cos(fwd)*cam.ms)
cam.ms = cam.ms * 0.9
cam:Render()
--draw a sprites
-- inserting into sprite array
-- X,Y,Z,U,V,W,H,key
sprites = {}
for i = 1, 32 do
local ox,oy,oz = 64,64, 12 + math_sin(i*10+(clock*5))*16
local p = 1
ox = 256+math_sin(clock+i)*64
oy = 256+math_cos(clock+i)*64
if i&1==1 then p=3 end
local incam,tx,ty,tz= cam:Transform(ox,oy,oz)
if incam==true then
table.insert(sprites,{tx,ty,tz,0,p,2,2,0})
end
end
-- trees
for y = 0, 15 do
for x = 0, 15 do
local ox,oy,oz = 64+x*16,64+y*16, 0
local incam,tx,ty,tz= cam:Transform(ox,oy,oz)
if incam==true then
table.insert(sprites,{tx,ty,tz,0,5,2,2,0})
end
end
end
-- now sort them out , fog em
table.sort(sprites, function(a,b) return a[3]>b[3] end)
for i = 1, #sprites do
pos = sprites[i]
cam:Fog(8-(pos[3]//cam.horizon))
local w = pos[6]*8
rspr( pos[1], -- x
pos[2], -- y
w/pos[3], -- scaler
0, -- angle
pos[4], -- position in sprram U
pos[5], -- ^^ V
pos[6], -- width
pos[7], -- height
pos[8], -- colorkey
false)
end
-- reset indices
pal()
clock = clock + 0.01
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment