pico-8 cartridge // http://www.pico-8.com version 34 __lua__ local colors = { [0]= 0x00,0x81,0x01, 0x82,0x85, 0x05,0x86,0x06,0x0f,0x07,0x07, 0x88,0x88,0x88,0x88,0x88 } local paltables= {} local framecounter= 0 local rotx= 0 local roty= 0 local moveu= 0 local movev= 0 local scaleu= 3.0 / 8.0 -- /8 because 8x8 sprite-size local scalev= 3.5 / 8.0 local fov= 1.8 -- field of view of the camera local radius= 5.0 -- radius of the cylinder (quite similar effect to fov) local rotation_y = 0.0 local rotation_x = 0.0 -- matrix 4x4 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- local matrix = {} -- "vtable" local mt_matrix= { __index = matrix } -- metatable for "matrix" -- identity matrix function matrix.identity() local mat = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 } setmetatable(mat, mt_matrix) return t end -- rotate x-axis function matrix.rotx(a) local s,c= sin(a),cos(a) local mat= { 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0 } setmetatable(mat, mt_matrix) return mat end -- rotate z-axis function matrix.roty(a) local s,c= sin(a),cos(a) local mat= { c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0 } setmetatable(mat, mt_matrix) return mat end -- rotate z-axis function matrix.rotz(a) local s,c= sin(a),cos(a) local mat= { c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0 } setmetatable(mat, mt_matrix) return mat end -- multiply mtrix a and b function mt_matrix.__mul(a, b) local mat={} for i=0,8,4 do local x,y,z,w=a[i+1],a[i+2],a[i+3],a[i+4] for j=1,4 do mat[i+j]= x*b[j] + y*b[j+4] + z*b[j+8] end mat[i+4]+=w end setmetatable(mat, mt_matrix) return mat end -- math helpers -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- approximate tanh -- tanh is useful as a soft saturation function which stays at +1 when the input goes > 1, or -1 when the input goes <-1 local function tanh(x) local x2 = x * x * 0.1 local a= x * (135.135 + x2 * (173.5 + x2 * (37.8 + x2))) local b= 135.135 + x2 * (623.70 + x2 * (315 + x2 * 28)) return a / b end -- effect code -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- calculate 8x8 grid points -- shoot a ray from the camera and intersect it with an infinite cylinder -- intersection calculating in simplified because rays always start at (0,0) on the center of the cylinder local function calc_grid(cam, cell_width, cell_height, scrollu, radius) -- number of cells in width and height local width= ceil(128 / cell_width) local height= ceil(128 / cell_height) local screenx= cam[3]*fov - cam[1] - cam[2] local screeny= cam[7]*fov - cam[5] - cam[6] local screenz= cam[11]*fov - cam[9] - cam[10] local scaley= 2.0 / width local deltaxx= cam[1] * scaley local deltaxy= cam[5] * scaley local deltaxz= cam[9] * scaley local deltayx= cam[2] * scaley local deltayy= cam[6] * scaley local deltayz= cam[10]* scaley local posz= scrollu & 0xff.ffff local grid = {} for y=0, height do local dirx,diry,dirz= screenx,screeny,screenz local row = {} for x=0, width do -- calc intersection with cylinder -- +0.0001 avoids division by 0 (ray along center of tunnel) local a = dirx*dirx + diry*diry + 0.0001 local t0= radius / sqrt( a ) -- todo: possibly approximate 1/sqrt local ix,iy,iz= t0*dirx, t0*diry, t0*dirz -- shading along z axis, factor changes darkness -- front half is completely white (keep number of palette changes low) local z= 90.0 - ( sqrt(abs(iz)) * 16 ) if (z>39.0) z= 39.0 if (z<0.0) z= 0.0 -- don't get negative. keep well above 0 to avoid glitches from interpolation precision row[x]= { x*cell_width, y*cell_height, atan2(ix, iy) * 128, -- u texture coordinate (posz-iz) * 2, -- v texture coordinate flr(z) -- z } dirx+= deltaxx diry+= deltaxy dirz+= deltaxz end grid[y]= row -- store row in 2d grid screenx += deltayx screeny += deltayy screenz += deltayz end return grid end -- fill all 8x8 cells function draw_grid(grid) local ul,ur,ll,lr local prevz= -1 -- uninitialised: make sure to set color remap table on first cell local function draw_cell() -- get uv coordinates from all 4 corners for interpolaiton local left_u,right_u= ul[3],ur[3] -- top local left_v,right_v= ul[4],ur[4] local x1,y1= ul[1],ul[2] local ll_u,lr_u= ll[3],lr[3] -- bottom local ll_v,lr_v= ll[4],lr[4] local x2,y2= lr[1],lr[2] -- fix u coordinate (because atan2 wraps from 2pi to 0) -- u= -32---+0----+32---+64---+96---+128---- u value range 0..128 -- |xxxxx|+++++|+++++|+++++|+++++|xxxxx -- 0 0 1 1 2 2 area= (u+32)/64 -- 1 1 2 2 4 4 quadrant flags: 2^area -- -1 0 1 2 3 4 5 6 7 8 9 u>>4 -- if we have u values in quadrant 1 *and* 4, move the values from quadrant 1 over to 4 -- get quadrant flags for each corner of the cell -- if ll_u < 32 then s1=1 elseif ll_u<96 then s1=2 else s1=4 end local s1= 1 << ((ll_u + 32) >> 6) local s2= 1 << ((lr_u + 32) >> 6) local s3= 1 << ((left_u + 32) >> 6) local s4= 1 << ((right_u + 32) >> 6) -- or-combination of all the flags if ( ((s1|s2|s3|s4) & 5) == 5) then -- both flags are used, cell crosses u-boundary! -- move the values from quadrant 1 over to 4 if (s1==1) then ll_u+=128 end if (s2==1) then lr_u+=128 end if (s3==1) then left_u+=128 end if (s4==1) then right_u+=128 end end -- perform uv scaling after wrap-fix (so we don't have to change the ranges above every time): left_u*=scaleu left_v*=scalev ll_u*=scaleu ll_v*=scalev right_u*=scaleu right_v*=scalev lr_u*=scaleu lr_v*=scalev -- delta down left side of 8x8 block: (bottom - right)/8 local left_du= (ll_u - left_u) / (y2-y1) local left_dv= (ll_v - left_v) / (y2-y1) local du= (right_u - left_u) / (x2-x1) local dv= (right_v - left_v) / (x2-x1) -- expecting integer coordinates for x,y (ignoring subpixel correction) -- expecting du,dv not to change very much (only for block near the center and we draw them black anyways) -- so we don't recalculate du,dv every scanline and we don't have to interpolate u,v along the right side -- set color remap table according to z for the whole 8x8 block -- doesn't look so nice. maybe draw lines of constant z instead? local z= ul[5] -- already rounded to integer if (z!=prevz) then pal(paltables[z], 2) prevz= z end left_u+=moveu for y=y1, y2-1 do tline(x1,y, x2-1,y, left_u,left_v, du,dv) -- update uv along left and right edge left_u += left_du left_v += left_dv end end for y=0, #grid-1 do local row1= grid[y] local row2= grid[y+1] ul,ll= row1[0],row2[0] -- fill one row of 8x8 blocks for x=1, #row1 do -- next upper/lower right ur,lr= row1[x],row2[x] draw_cell() -- old right edge becomes new left edge ul,ll= ur,lr end end end function draw_tunnel() -- tunnel rotation matrix local cam = matrix.roty(roty) * matrix.rotx(rotx) * matrix.rotz(0.0) -- cell size is 6x6: local grid = calc_grid(cam, 6,6, movev, radius) draw_grid(grid) -- draw the grid (fill the 8x8 cells) end -- pcio8 base functions -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- function _init() cls() -- calc shading tables for different depths for z=0,40 do local shade= {} for i=0,15 do -- textures uses a linear gradient of colors 0..9 (back -> white) local c= i*z/32-0.5 -- z=0: black z=32: original palette color if (c<0) c=0 if (c>9) c=9 -- include dither matrix alternatives for this and next brighter color index -- "0.75" controls strength of dithering shade[i]= flr(c+0.75)*16 + flr(c) end paltables[z]= shade end -- set up 128x128 texture and map poke(0x5F38, 16,16) -- repeat 16x16 tiles poke(0x5f36, 8) -- tile0 not transparent for y=0,15 do for x=0,15 do poke(0x2000+y*128+x, y*16+x) end end palt(0,false) -- no transparency because we want to overdraw everything fillp(0xa5a5.4) -- enable 2x2 dithering end function _update() local time= framecounter*0.03 if (btn(0)) moveu+=1.0 if (btn(1)) moveu-=1.0 if (btn(3)) movev+=1.0 if (btn(2)) movev-=1.5 if (btn(5)) roty-=0.005 rotx = cos(time*0.15)*0.08 roty = sin(time*0.10)*0.08 local flipback= tanh(cos(time*0.12)*3) -- toogle between +1/-1 with a soft flip over rotx += flipback*0.25+0.25 -- either 0.0: look forward or 0.5: look backward moveu+= 0.3 movev-= 1.0 pal(colors, 1) framecounter+=1.0 end function _draw() draw_tunnel() --[[ -- show palette for i=0,15 do color(i) rectfill(i*8,125,i*8+8,128) end ]] --[[ -- show cpu usage color(2) print( "cpu: "..stat(1), 0,0 ) ]] end __gfx__ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000000000000010101000000000000000000000 00000000000000000000000000000000000001000000000000000000111111110000000000000000000000000000000010011111111000001000011000000000 01000000000000000000000000000000000111110000100000000001111111111000000000000000000000001000100111112211111111111100111110000000 01110000000000000000000000000000011111111111110000001101111111111110000000000000000000011010111111111211121111111111111110000000 11110000000000000111110010001011111111111111111101111111111111111111000000000000000001011110111111211211121111112111111110100000 11111100010110011111111111111111111111111111111111111111111111111111100100000010000101111111111111212211122111112111111111100000 11111111111111111111111111111111111111111111111111111111111111111112111111001011100111111111111111112221111111111121221111110000 11111111111111111111111111111111111111111111111111111121112222111122111111111111111111111111111111123222212111111122222211111000 11111111111111111111111111111111111111111111111111111121222222222122111111111111111111111111111121223332222111122222222211111011 11111111111111111111111111122111111111111111111111111111222222222112211111121111111111111111111121233333322221222233322221111111 11111111111111111111111111222221111111111111111111111111222222222111211111122111111111111111111122233443332222223333333222112111 11111122111111111111111121222222111111111111111111111122222222222221111111122111111111111111111122334444432222223333433322212111 11111121111111111111111222222222211111111111111111112222222222222222122111111111111111111111111122334554433322234433444322212111 11121111111111111112212222222222221121222121111111112222222222222222222222111111111111121111111222344555443323334434444422222221 12222211111121111122222222222222221222222222111111112222222222222222222222121111111112221111111233345655444333345444444432221221 22222221221122211122222222222222222222222222211111222222222222333222222222222111111112221111112233446666554333345445554433222222 22222221222222222222222222222322222222222222221112222222222223333232222222222111111122222112122234446766554444456555555443222112 22222222222222222222222222223332222222222222222222222233222223333332222222222111111122222222222234556777554444456556655444322111 22222222222222222222222222223332222222222222222222222333222223333333322223222211121122222222222244557877755544556666755544332222 22223222222222222222222222223333222222222222222222222333322223333333322333332221122222222222222344557888755555567667776554332222 22333322222222222222222222233333222222222222222222223333322223333333332333332221122222222222223345569988765555668877776554432222 22333322222222222222222222233333222222222222232222233333323333333333333333332222122222222222323345579999876555678878777554443222 22333332222222222222232222333333222222322222332222233334333333444343333333432222222222222233333355579aa9876566678888877655443222 33333333222222222222233332334443322222332222333333333444333334444444333344433222222222222333343455679aba877766788888887755443332 3333333322222222222233333333444332222333222233333333344443333444444433334444322222222222233334445578bbbb998777789988987765443332 3333333322222322222233333333444433223333222333333333344443333444444433334444322222222222333344445678bbbba98777889999988765543333 3334333332222322222333333333444433333333323334433333444443333444444443344444322222222222333344455678bbbba9988789baaa998765544433 3334333332223322222334433333444433333433333344433333444443333444444443344554322222222223333355455789bccbb988889abaaa999866544433 333443333222333222333443333344443333344333334444333345444333344444444344455432222222223333445555678accccb9a9989abbbaa99876544443 334443333323333222333444333344444333344433334444333345554333344444444444455432222222223334455555689bccdcbba9999bbbbba99876544443 334443333333333322333444333344444333444433334444433445554333344545444444555432222222222334555555789bdcdccbbaaabbbbbbaa9976644443 334443333333333323334444333344444334444433344444433445554333345555444444555432222223222344566655789bddddcbbbabbcccbbba9977654443 33444333333334332333444433334544444444443334444443344555433334555554444455553222233322234456766688abddddcbbbabbccccbbaa977555444 44454333333344433333444433334554444444443334444443344555433334555555444456554222233322234556777689acdddddcbabbcddccbbba987555444 44454333333344433333444433334554444444444334444443444565533334555555444556553222333322344566877789bcdddddcbbbccddccbbbaa97655544 4445433433344443333344444333455444444444444445444444555553333455555544455655422233333234556788778abcdeeedccbccddddcbbbaa97655544 4445433433344443333444444333455444444444444445544444555553333455555544456755422233333234567788778abcdeeeddcbcdddddcbbbba98765544 4445433433344443333444444333455444444544444445554444555553333455555544456755422234433334567888878abdeeeeddcccdddddcbbbba98765554 4445433443344443333445444333455544444544444445554444555553333455555544456765422234443334577898878abdeeeeddcccdddddcbbbba98755554 4445433444344443333445444333455444444554444445554444566543333455555544556765422234443334577999979abdeeeeddcccddeddcbbbbb98756554 44454334443454433334454443334554444445544444455544445665533334555555445567654322344433455789a9889abdeeeedddcdddeddcbbbbb98766554 44454334444454433334555443334555444445544444455554455665533334555555445567654333354443446789a9989abdeeeedddcdddeddcbbbbb98866554 44444344444455433334555443334555444445544444455554455665533334555555444567654333355443456789ba989abdeeeedddcdddeddcbbbbb98865554 4444434444445543333455544333455544444554444445555445566553333455555544556765433345554345678aba989bbdeeeedddcdddeddcbbbbb99865654 4444334444445543333455544333455544444554444445555445566543333455555544556765433345554345688aba989bbdeeeedddcddeeddcbbbbb99865654 4444334444445543333455544333455544444554444445555445566543333445555544556765433345554345788abaa89bbdddddddddddeeddcbbbbba9865554 4444334444455543333455544333455544444554444445555445566543333444555544556765433345654345689bbba99bbdddddddddddeedccbbbbba9875554 4444334444455543333455544333455544444554444445555445566543333444565444556765433345654345689bbba9abcddddddddcdddedccbbbbba9865554 4444334444455543333455444333455544444554444445555445566543333444555444456765433346665345789bbba9abbddddddddcdddddccaaabb99865554 4443334444455543334555544333455544444554444445555445566543233444555444456755433346665345789bbba99bbddddddddcdddddccaaaba99865554 4333334444455543333555544333455544444554444445555445565543233444555444556755433346765445789bbbb99abddddddddcdddddcbaaaaaa9865654 4333334444455543334555544333455544444554444445555445565543233444455444455655443346765445789bcbb99bbdddddddccdddddcbaaaaaa8865554 3333334444455543334555444333455554444554444445555445565543223344455443455655443346775445789bcbb99abdddcddcccdddddcbaaaaa98865554 3333334444455543334555444333455554444554444445555445565543223344454433455655443347775445789bbbb99abdccccccccddddccbaaaaa98865554 3333334444455543334555444333455554444554444445555445565543223344454433455655444347775445789bbbb99abcccbbbbcccdddcbbaaaaa98866554 3223334444455543334555444333455554444554444445555444555543223344454433445554444447775445789bbbb99abcbbbbbbccccddcbba9aaa88866544 3222334444455543334555444333455554444554444445555444565543223334454433445554444447775445689bbbb999abbbbbbbcbccddcbba9aaa88765543 2222334444455543334555444333455554444554444445555444565543223334444433445554444447875445689bbbb989abbabbbbbbccccbba99a9a88765543 2222344444455543334555444333455554434544333344555444555543222333444333445544444447876445689bbbb989abbababbbbbbccbba99a9988755543 2222344344455543334554443333455554334444333344555444455543222333444333344544444447876445688bbbb888abaaaabbbbbbcbbba9999988755543 2112344334455443334554443333455554334444333344554444455443222333444333344544444447876445578abbb8889aaa9aabbbbbbbbaa9999977765443 2112344334454443334554443333455554334444333334454434454443222333443333344444444447876444568abbb9789a9999aabbabbbbb98999877665443 2112344334444443334554433333455554333444333334444333444433222333443333344444444447875444568abba9789999999abaabbbba98899877655443 1112334333444433334554333223455544333444333334444333444433222333343333344434444347876444568aaaa8789999889aaaaabbaa98889876654442 2112334333444433334544333223355543333443333334444333444432222333343333334433444347876344568aaaa8678998889aaa9abbaa98888776554432 22123343334444323344443332233455433334433333344443334443332223333433333344334443478763445579aaa7678988879aa99aaa9a87888776554432 222233333344443233444433322334554333344333333444433334433222223333333333333344434787533445799a975678877799a889aa9987778766654432 2222333233344432334443333223345443333443333333444333344332222233333333333333454347776334457999975678777789a8899a9987778755654432 222233323334443233444333322334444332343333333344333334333222223333333333333344434677533445699997556777668898899a9986777655544332 21223332333443322344433322233444432333333233234433333433322222333333333333334443467753344567999655676756889888999986677655543322 21222332233433322344433222233444432233333232233333323333322222233332223333334443467753344557898655666555889888989875667555543322 21222332233433222334432222223444432233332222233333223333322222223332223333334433467653334457888645665555788778888875566555543322 21222332223333222334332222223444432223332222233333223332322222222332223333334443367653334457787644555555788777888775556544543322 21222232223333222234332222223444432233332222223332222332222222222322223333334433367653334456777544555545777667888775555544443222 22222222223333222234322222223444332223332222223322222222222222222322223333334433356653333456666544555445677656887765555544443222 22222222223333222233322222223344332223332222222222222222222222222222222333334433356553333456666443454444667556777765555444443222 22222222223333222233321222223343332223332222222222222222222222222222222332334433356542333446556433444444566556777755555444443222 22222222222322222233221222222343332223322222222222222222222222222222222332334433356542233345555433444434566555666654445443433222 22222222222322222233221222222333332223322222222222222222222222222222222322334433355542233345555433444334456545666654444433333222 22222222222222222223211222222333322223222222222222222222222222222222222222334433355542222344554333343333455445555554444433333222 22222222222222222222211222222333322223222222222222222222222222222222222222333433345542222334444323333333455444555554444333332222 22222222222222221222212222222333322222222222222222222222221222222222222222333433345442222234444322333333455444555544443333332222 22222222222222221122112222222333322122222222222222222222221112222222222222333433344432222233333322323233444344555544343333332222 22222222222222221122112222222233321122222222222222222222222111222222222222333432344432222233333322223233444333454443333333332222 22222222222221221122112222222223221112211222222222222222222111222212222222333432344432222233333222222223344333454443333333332222 22222222222211221122111222222222221112211222222222222222222111222212222222233332234332222223233222222223343333444443333333322222 22222222222211221122111222122222221112211222222222222222222111222211222222233332234332222222223222222222333333444433333323322222 22222222222212221221111222112222221112211222122222222222222111222211122222233322234332222222222222222222333333344433333322322222 22222222222211221211111222111222212112221211112222222222222111222211122222233322233332222222222222222222333333344333333322222222 22222222222212122211111222111122212111221211112222222222222111222221122222233322233232222222222222222222333333343333333222222222 22222222222212111211111222111112112111222111111222222222212111121121122222233222223222222222222122222222233222333333333222222222 22222222222211111211111212111111112111122111111222222222212111121111122222233222223222222222122122222222222222333333223222222222 22222222222211111111111111111111112111121111111222222222111111111112122222233222222222222221112122222222222222333333222222222222 22222222222211111111111111111111111111121111111222222222111111111112222222232222222222222211111122222212222222333333222222222222 21222122222211111111111111111111111111121111111221122222111111111111222222222222222222212211111122222212222222233222222222222222 21221111222111111111111111111111111111111111111221112212111111111111212222222222222222211211111112222212222222232222222222222222 21221111221111111111111111111111111111111111111221112211111111111111112222222222222222211211111111222212222222232222222222221222 11121111121111111111111111111111111111111111111221112211111111111111112222222222222222211211111111222212222222232222222222221221 11111111111111111111111111111111111111111111111111111111111111111111112222222222222222211111111111222212222222222222222222221221 11111111111111111111111111111111111111111111111111111111111111111111112222222222222222111111111111122212222222222222222222221221 11111111111111111111111111111111111111111111111111111111111111111111111222222222222222111111111111122212222222222222222222211211 11111111111111111111111111111111111111111111111111111111111111111111111222222222212222111111111111122112221222222222222222111111 11111111111111111111111111111111111111111111111111111111111111111111111222222222212222111111111111122111221222222222222222111111 11111111111111111111111111111111111111111111111111111111111111111111111222222222212221111111111111122211221222222222222211111111 11111111111111111111111111111111111111111111111111111111111111111111111222222222112221111111111111122111121222222222222211111111 11111111111111111111111111111111111111111111111111111111111111111111111222222222111211111111111111112111121222222222222211111111 11111111111111111111111111111111111111111111111111111111111111111111111222222222111211111111111111112111121222222222222111111111 11111111111111111111111111111111111111111111111111111111111111111111111122222222111211111111111111112111111222222222222111111111 11111111111111111111111111111111111111111111111111111111111111111111111112222222111211111111111111111111111222222222222111111111 11111111111111111111111111111111111111111111111111111111111111111111111112222222111111111111111111111111111122222222222111111111 11111111111111111111111111111111111111111111111111111111111111111111111112222121111111111111111111111111111122222222222111111111 11111111111111111111111111111111111111111111111111111111111111111111111112222121111111111111111111111111111112222222122111111111 11111111111111111111111111111111111111111111111111111111111111111111111111212111111111121111111111111111111111222221121111111111 11111111111111111111111111111111111111111111111111111111111111111111111111212111111111121111111111111111111111222221121111111111 11111111111111111111111111111111111111111111111111111111111111111111111111112111111111121111111111111111111111122221111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111121111111111111111111111121121111111112111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111121111111111111111111111111111111111122211 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111121111111111111111111111111111111111222211 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111121111111111111111111111111111111112222211 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111121111111111111111111111111111111112222221 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111121111111111111111111111111111111112222221 11111111111111111111111111112111111111111111111111111111111221111111111111111111111111121111211111111111111111111111111112222221 11111111111111111111111111122211111111111111111111111111111222111111111111111111111111121112211111111111111111111111111112222221