Last active
October 25, 2017 13:33
-
-
Save JettMonstersGoBoom/7786f813a24b2ed449d0de559d3035dc to your computer and use it in GitHub Desktop.
This file contains 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
-- 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