nonogamer9

The Nono Demo! (A ComputerCraft Demo That Uses Mode 7!)

Apr 22nd, 2025
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 22.04 KB | Software | 0 0
  1. local BMP_URL = "https://files.catbox.moe/52gj0y.bmp"
  2. local BMP_FILE = "demo.bmp"
  3. local PCM_URL = "https://files.catbox.moe/ae17k1.raw"
  4. local PCM_FILE = "demo.raw"
  5. local PCM_SAMPLE_RATE = 32000
  6. local PCM_UNSIGNED = true
  7. local DEMO_TIME = 8
  8.  
  9. local function readBMP(filename)
  10.   local file = fs.open(filename, "rb")
  11.   if not file then return nil, "Failed to open file" end
  12.   local header = file.read(54)
  13.   local width = string.byte(header, 19) + string.byte(header, 20) * 256
  14.   local height = string.byte(header, 23) + string.byte(header, 24) * 256
  15.   local pixels = {}
  16.   for y = height, 1, -1 do
  17.     pixels[y] = {}
  18.     for x = 1, width do
  19.       local b = file.read(1)
  20.       local g = file.read(1)
  21.       local r = file.read(1)
  22.       pixels[y][x] = {r = string.byte(r), g = string.byte(g), b = string.byte(b)}
  23.     end
  24.     if y % 10 == 0 then os.queueEvent("yield") os.pullEvent("yield") end
  25.   end
  26.   file.close()
  27.   return {width = width, height = height, pixels = pixels}
  28. end
  29.  
  30. local function mapColor256(r, g, b)
  31.   local cubeSize = 6
  32.   local rIndex = math.floor(r / (255 / (cubeSize - 1)))
  33.   local gIndex = math.floor(g / (255 / (cubeSize - 1)))
  34.   local bIndex = math.floor(b / (255 / (cubeSize - 1)))
  35.   return 16 + rIndex * cubeSize * cubeSize + gIndex * cubeSize + bIndex
  36. end
  37.  
  38. local function set256Palette()
  39.   local cubeSize = 6
  40.   for i = 16, 231 do
  41.     local index = i - 16
  42.     local rIndex = math.floor(index / (cubeSize * cubeSize))
  43.     local gIndex = math.floor((index % (cubeSize * cubeSize)) / cubeSize)
  44.     local bIndex = index % cubeSize
  45.     local r = math.floor(rIndex * 255 / (cubeSize - 1))
  46.     local g = math.floor(gIndex * 255 / (cubeSize - 1))
  47.     local b = math.floor(bIndex * 255 / (cubeSize - 1))
  48.     term.setPaletteColor(i, r / 255, g / 255, b / 255)
  49.   end
  50.   for i = 232, 255 do
  51.     local gray = math.floor((i - 232) * 255 / 23)
  52.     term.setPaletteColor(i, gray / 255, gray / 255, gray / 255)
  53.   end
  54. end
  55.  
  56. local function savePalette()
  57.   local t = {}
  58.   for i = 0, 255 do t[i] = {term.getPaletteColor(i)} end
  59.   return t
  60. end
  61. local function restorePalette(t)
  62.   for i = 0, 255 do term.setPaletteColor(i, table.unpack(t[i])) end
  63. end
  64.  
  65. local function makeBuffer(width, height)
  66.   local buf = {}
  67.   for y = 0, height-1 do
  68.     buf[y] = {}
  69.     for x = 0, width-1 do buf[y][x] = 0 end
  70.   end
  71.   return buf
  72. end
  73. local function swapBuffers(a, b) return b, a end
  74. local function blitBuffer(buf, output)
  75.   for y = 0, #buf do
  76.     for x = 0, #(buf[y]) do
  77.       output.setPixel(x, y, buf[y][x])
  78.     end
  79.   end
  80. end
  81.  
  82. local function downloadContent(url, filename, contentType)
  83.   print("Downloading " .. contentType .. "...")
  84.   local response = http.get(url, nil, true)
  85.   if not response then error("Failed to download " .. contentType .. ": " .. url) end
  86.   local file = fs.open(filename, "wb")
  87.   local content = response.readAll()
  88.   for i = 1, #content, 8192 do
  89.     file.write(content:sub(i, i + 8191))
  90.     os.queueEvent("yield")
  91.     os.pullEvent("yield")
  92.   end
  93.   file.close()
  94.   response.close()
  95.   print("Downloaded " .. contentType .. ".")
  96. end
  97.  
  98. local function playPCM(filename, inputSampleRate, isUnsigned, volume)
  99.   local speaker = peripheral.find("speaker")
  100.   if not speaker then print("No speaker attached!") return end
  101.   local file = fs.open(filename, "rb")
  102.   if not file then print("Could not open file: " .. filename) return end
  103.   local samples = {}
  104.   local sum = 0
  105.   local count = 0
  106.   while true do
  107.     local byte = file.read()
  108.     if not byte then break end
  109.     if isUnsigned then byte = byte - 128 end
  110.     samples[#samples + 1] = byte
  111.     sum = sum + byte
  112.     count = count + 1
  113.   end
  114.   file.close()
  115.   if #samples == 0 then print("File is empty or unreadable.") return end
  116.   local avg = sum / count
  117.   for i = 1, #samples do samples[i] = samples[i] - avg end
  118.   local outputSampleRate = 48000
  119.   if inputSampleRate ~= outputSampleRate then
  120.     local resampled = {}
  121.     local ratio = inputSampleRate / outputSampleRate
  122.     for i = 1, math.floor(#samples / ratio) do
  123.       local src = (i - 1) * ratio + 1
  124.       local idx = math.floor(src)
  125.       local frac = src - idx
  126.       local s1 = samples[idx] or 0
  127.       local s2 = samples[idx + 1] or s1
  128.       resampled[i] = s1 + (s2 - s1) * frac
  129.     end
  130.     samples = resampled
  131.   end
  132.   local chunkSize = 128 * 1024
  133.   local totalSamples = #samples
  134.   local playedSamples = 0
  135.   while playedSamples < totalSamples do
  136.     local chunk = {}
  137.     for i = 1, chunkSize do
  138.       local idx = playedSamples + i
  139.       if idx > totalSamples then break end
  140.       local sample = math.floor(samples[idx] * volume + 0.5)
  141.       if sample > 127 then sample = 127 end
  142.       if sample < -128 then sample = -128 end
  143.       chunk[i] = sample
  144.     end
  145.     if #chunk == 0 then break end
  146.     while not speaker.playAudio(chunk) do
  147.       os.pullEvent("speaker_audio_empty")
  148.     end
  149.     playedSamples = playedSamples + #chunk
  150.   end
  151. end
  152.  
  153. local function waterdropTransition(image, output, duration)
  154.   local screenWidth, screenHeight = output.getSize()
  155.   local pxw, pxh = screenWidth * 6, screenHeight * 9
  156.   local imageWidth, imageHeight = image.width, image.height
  157.   local bufA = makeBuffer(pxw, pxh)
  158.   local bufB = makeBuffer(pxw, pxh)
  159.   local front, back = bufA, bufB
  160.   local cx, cy = pxw/2, pxh/2
  161.   local t0 = os.epoch("utc")
  162.   local tEnd = t0 + duration*1000
  163.   while os.epoch("utc") < tEnd do
  164.     local t = (os.epoch("utc")-t0)/1000
  165.     for y = 0, pxh-1 do
  166.       for x = 0, pxw-1 do
  167.         local dx, dy = x-cx, y-cy
  168.         local dist = math.sqrt(dx*dx+dy*dy)
  169.         local ripple = 8*math.sin(dist/16-t*8)/(dist/16+1)
  170.         local sx = math.floor((x + ripple) * image.width / pxw) + 1
  171.         local sy = math.floor((y + ripple) * image.height / pxh) + 1
  172.         if sx >= 1 and sx <= image.width and sy >= 1 and sy <= image.height then
  173.           local pixel = image.pixels[sy][sx]
  174.           back[y][x] = mapColor256(pixel.r, pixel.g, pixel.b)
  175.         else
  176.           back[y][x] = 0
  177.         end
  178.       end
  179.     end
  180.     front, back = swapBuffers(front, back)
  181.     blitBuffer(front, output)
  182.     os.queueEvent("yield")
  183.     os.pullEvent("yield")
  184.   end
  185. end
  186.  
  187. local function mode7_spinzoom()
  188.   return function(frame, sw, sh, iw, ih)
  189.     local t = frame / 60
  190.     local scale = 0.5 + 0.5 * math.sin(t)
  191.     local angle = t
  192.     local a = math.cos(angle) * scale
  193.     local b = -math.sin(angle) * scale
  194.     local c = math.sin(angle) * scale
  195.     local d = math.cos(angle) * scale
  196.     return {a=a, b=b, c=c, d=d, x0=(sw*6)/2, y0=(sh*9)/2, u0=iw/2, v0=ih/2}
  197.   end
  198. end
  199.  
  200. local function mode7_wave()
  201.   return function(frame, sw, sh, iw, ih)
  202.     local scale = 0.7
  203.     local angle = 0
  204.     return {
  205.       a=math.cos(angle)*scale, b=-math.sin(angle)*scale,
  206.       c=math.sin(angle)*scale, d=math.cos(angle)*scale,
  207.       x0=(sw*6)/2, y0=(sh*9)/2, u0=iw/2, v0=ih/2,
  208.       scanline=function(sy,a,b,c,d,frame)
  209.         local t = frame / 30
  210.         local wave = 0.2 * math.sin((sy / 30) + t)
  211.         local sa = a + wave
  212.         local sd = d + wave
  213.         return sa, b, c, sd
  214.       end
  215.     }
  216.   end
  217. end
  218.  
  219. local function mode7_barrel()
  220.   return function(frame, sw, sh, iw, ih)
  221.     local scale = 0.7
  222.     local t = frame / 40
  223.     return {
  224.       a=math.cos(t)*scale, b=-math.sin(t)*scale,
  225.       c=math.sin(t)*scale, d=math.cos(t)*scale,
  226.       x0=(sw*6)/2, y0=(sh*9)/2, u0=iw/2, v0=ih/2,
  227.       scanline=function(sy,a,b,c,d,frame)
  228.         local t2 = frame / 15
  229.         local roll = 0.3 * math.sin(t2 + sy / 40)
  230.         local sa = a * math.cos(roll) - b * math.sin(roll)
  231.         local sb = a * math.sin(roll) + b * math.cos(roll)
  232.         local sc = c * math.cos(roll) - d * math.sin(roll)
  233.         local sd = c * math.sin(roll) + d * math.cos(roll)
  234.         return sa, sb, sc, sd
  235.       end
  236.     }
  237.   end
  238. end
  239.  
  240. local function mode7_fzero()
  241.   return function(frame, sw, sh, iw, ih)
  242.     local t = frame / 40
  243.     local scale = 0.3 + 0.7 * (1 - (frame % 120) / 120)
  244.     local angle = 0.15 * math.sin(t)
  245.     return {
  246.       a=math.cos(angle)*scale, b=-math.sin(angle)*scale,
  247.       c=math.sin(angle)*scale, d=math.cos(angle)*scale,
  248.       x0=(sw*6)/2, y0=(sh*9)*0.75, u0=iw/2, v0=ih*0.7,
  249.     }
  250.   end
  251. end
  252.  
  253. local function mode7_floor()
  254.   return function(frame, sw, sh, iw, ih)
  255.     local cam_x = iw/2
  256.     local cam_y = ih/2
  257.     local cam_angle = frame/60
  258.     local cam_height = 120
  259.     local horizon = math.floor((sh*9) * 0.45)
  260.     local focal_length = 170
  261.     return {
  262.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  263.       scanline=function(sy,a,b,c,d,frame) return a,b,c,d end,
  264.       floor=function(sx,sy)
  265.         if sy < horizon then return nil,nil end
  266.         local pxw = sw*6
  267.         local dx = sx - pxw/2
  268.         local dy = sy - horizon
  269.         local angle = cam_angle
  270.         local distance = cam_height * focal_length / (dy+1)
  271.         local world_x = cam_x + math.cos(angle)*distance + math.sin(angle)*dx*distance/focal_length
  272.         local world_y = cam_y + math.sin(angle)*distance - math.cos(angle)*dx*distance/focal_length
  273.         local tx = ((math.floor(world_x)-1) % iw) + 1
  274.         local ty = ((math.floor(world_y)-1) % ih) + 1
  275.         return tx, ty
  276.       end,
  277.       horizon = horizon
  278.     }
  279.   end
  280. end
  281.  
  282. local function mode7_zoom()
  283.   return function(frame, sw, sh, iw, ih)
  284.     local scale = 0.5 + math.sin(frame / 100) * 0.5
  285.     return {
  286.       a = scale, b = 0, c = 0, d = scale,
  287.       x0 = (sw * 6) / 2, y0 = (sh * 9) / 2,
  288.       u0 = iw / 2, v0 = ih / 2
  289.     }
  290.   end
  291. end
  292.  
  293. local function mode7_pan()
  294.   return function(frame, sw, sh, iw, ih)
  295.     local panX = math.sin(frame / 120) * iw / 4
  296.     local panY = math.cos(frame / 150) * ih / 4
  297.     return {
  298.       a = 1, b = 0, c = 0, d = 1,
  299.       x0 = (sw * 6) / 2, y0 = (sh * 9) / 2,
  300.       u0 = iw / 2 + panX, v0 = ih / 2 + panY
  301.     }
  302.   end
  303. end
  304.  
  305. local function mode7_rotate()
  306.   return function(frame, sw, sh, iw, ih)
  307.     local angle = frame / 100
  308.     local a = math.cos(angle)
  309.     local b = -math.sin(angle)
  310.     local c = math.sin(angle)
  311.     local d = math.cos(angle)
  312.     return {
  313.       a = a, b = b, c = c, d = d,
  314.       x0 = (sw * 6) / 2, y0 = (sh * 9) / 2,
  315.       u0 = iw / 2, v0 = ih / 2
  316.     }
  317.   end
  318. end
  319.  
  320. local function mode7_waterreflection()
  321.   return function(frame, sw, sh, iw, ih)
  322.     local cam_x = iw/2
  323.     local cam_y = ih/2
  324.     local cam_angle = frame/60
  325.     local cam_height = 120
  326.     local horizon = math.floor((sh*9) * 0.45)
  327.     local focal_length = 170
  328.     return {
  329.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  330.       floor=function(sx,sy)
  331.         local pxw = sw*6
  332.         if sy >= horizon then
  333.           local dx = sx - pxw/2
  334.           local dy = sy - horizon
  335.           local angle = cam_angle
  336.           local distance = cam_height * focal_length / (dy+1)
  337.           local world_x = cam_x + math.cos(angle)*distance + math.sin(angle)*dx*distance/focal_length
  338.           local world_y = cam_y + math.sin(angle)*distance - math.cos(angle)*dx*distance/focal_length
  339.           local tx = ((math.floor(world_x)-1) % iw) + 1
  340.           local ty = ((math.floor(world_y)-1) % ih) + 1
  341.           return tx, ty
  342.         else
  343.           local dx = sx - pxw/2
  344.           local dy = horizon - sy
  345.           local angle = cam_angle
  346.           local distance = cam_height * focal_length / (dy+1)
  347.           local world_x = cam_x + math.cos(angle)*distance + math.sin(angle)*dx*distance/focal_length
  348.           local world_y = cam_y + math.sin(angle)*distance - math.cos(angle)*dx*distance/focal_length
  349.           local tx = ((math.floor(world_x)-1) % iw) + 1
  350.           local ty = ((math.floor(world_y)-1) % ih) + 1
  351.           local ripple = math.sin(frame/10 + dx/20) * 4
  352.           ty = math.max(1, math.min(ih, math.floor(ty + ripple)))
  353.           return tx, ty
  354.         end
  355.       end,
  356.       horizon = horizon
  357.     }
  358.   end
  359. end
  360.  
  361. local function mode7_tunnel()
  362.   return function(frame, sw, sh, iw, ih)
  363.     return {
  364.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  365.       floor=function(sx,sy)
  366.         local pxw, pxh = sw*6, sh*9
  367.         local cx, cy = pxw/2, pxh/2
  368.         local dx = sx - cx
  369.         local dy = sy - cy
  370.         local angle = math.atan2(dy, dx) + frame/60
  371.         local radius = math.sqrt(dx*dx+dy*dy)
  372.         local u = ((angle/(2*math.pi)) % 1) * iw
  373.         local v = ((frame*4 + radius*2) % ih) + 1
  374.         return math.floor(u)+1, math.floor(v)
  375.       end,
  376.       horizon = 0
  377.     }
  378.   end
  379. end
  380.  
  381. local function mode7_plasma()
  382.   return function(frame, sw, sh, iw, ih)
  383.     return {
  384.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  385.       floor=function(sx,sy)
  386.         local pxw, pxh = sw*6, sh*9
  387.         local u = sx / pxw * iw
  388.         local v = sy / pxh * ih
  389.         local t = frame/20
  390.         local offset = math.sin(v/8 + t)*8 + math.cos(u/16 + t)*8
  391.         u = u + offset
  392.         v = v + offset
  393.         return ((math.floor(u)-1)%iw)+1, ((math.floor(v)-1)%ih)+1
  394.       end,
  395.       horizon = 0
  396.     }
  397.   end
  398. end
  399.  
  400. local function mode7_ripple()
  401.   return function(frame, sw, sh, iw, ih)
  402.     local cx, cy = (sw*6)/2, (sh*9)/2
  403.     return {
  404.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  405.       floor=function(sx,sy)
  406.         local dx, dy = sx-cx, sy-cy
  407.         local dist = math.sqrt(dx*dx+dy*dy)
  408.         local ripple = math.sin(dist/8-frame/4)*8
  409.         local u = ((sx + ripple) / (sw*6)) * iw
  410.         local v = ((sy + ripple) / (sh*9)) * ih
  411.         return math.floor(u)+1, math.floor(v)+1
  412.       end,
  413.       horizon = 0
  414.     }
  415.   end
  416. end
  417.  
  418. local function mode7_checkerboard()
  419.   return function(frame, sw, sh, iw, ih)
  420.     return {
  421.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  422.       floor=function(sx,sy)
  423.         local pxw, pxh = sw*6, sh*9
  424.         local u = sx / pxw * 16
  425.         local v = sy / pxh * 16
  426.         local scale = 1 + math.sin(frame/30) * 0.5
  427.         u = u * scale
  428.         v = v * scale
  429.         local check = ((math.floor(u) + math.floor(v)) % 2 == 0)
  430.         if check then
  431.           return 1, 1
  432.         else
  433.           return iw, ih
  434.         end
  435.       end,
  436.       horizon = 0
  437.     }
  438.   end
  439. end
  440.  
  441. local function mode7_infinitezoom()
  442.   return function(frame, sw, sh, iw, ih)
  443.     local zoom = 1 + math.sin(frame/40)*0.8
  444.     return {
  445.       a=zoom, b=0, c=0, d=zoom,
  446.       x0=(sw*6)/2, y0=(sh*9)/2, u0=iw/2, v0=ih/2
  447.     }
  448.   end
  449. end
  450.  
  451. local function mode7_parallax()
  452.   return function(frame, sw, sh, iw, ih)
  453.     return {
  454.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  455.       multilayer = true,
  456.       floor=function(sx,sy,layer)
  457.         local pxw, pxh = sw*6, sh*9
  458.         local u = sx / pxw * iw
  459.         local v = sy / pxh * ih
  460.         if layer == 1 then
  461.           u = u + math.sin(frame/30)*10
  462.         else
  463.           v = v + math.cos(frame/40)*10
  464.         end
  465.         return ((math.floor(u)-1)%iw)+1, ((math.floor(v)-1)%ih)+1
  466.       end,
  467.       horizon = 0
  468.     }
  469.   end
  470. end
  471.  
  472. local function mode7_road()
  473.   return function(frame, sw, sh, iw, ih)
  474.     local cam_x = iw/2
  475.     local cam_y = ih/2
  476.     local cam_angle = 0.1*math.sin(frame/50)
  477.     local cam_height = 120
  478.     local horizon = math.floor((sh*9) * 0.45)
  479.     local focal_length = 170
  480.     return {
  481.       a=1, b=0, c=0, d=1, x0=0, y0=0, u0=0, v0=0,
  482.       floor=function(sx,sy)
  483.         if sy < horizon then return nil,nil end
  484.         local pxw = sw*6
  485.         local dx = sx - pxw/2
  486.         local dy = sy - horizon
  487.         local curve = math.sin(dy/40 + frame/30)*40
  488.         local angle = cam_angle + curve/1000
  489.         local distance = cam_height * focal_length / (dy+1)
  490.         local world_x = cam_x + math.cos(angle)*distance + math.sin(angle)*dx*distance/focal_length
  491.         local world_y = cam_y + math.sin(angle)*distance - math.cos(angle)*dx*distance/focal_length
  492.         local tx = ((math.floor(world_x)-1) % iw) + 1
  493.         local ty = ((math.floor(world_y)-1) % ih) + 1
  494.         return tx, ty
  495.       end,
  496.       horizon = horizon
  497.     }
  498.   end
  499. end
  500.  
  501. local function mode7_starfield()
  502.   local stars = {}
  503.   for i=1,128 do
  504.     stars[i] = {x=math.random(),y=math.random(),z=math.random()}
  505.   end
  506.   return function(frame, sw, sh, iw, ih)
  507.     local base = mode7_floor()(frame, sw, sh, iw, ih)
  508.     base.starfield = function(buf)
  509.       local pxw, pxh = sw*6, sh*9
  510.       for _,star in ipairs(stars) do
  511.         star.z = star.z - 0.01
  512.         if star.z <= 0 then
  513.           star.x = math.random()
  514.           star.y = math.random()
  515.           star.z = 1
  516.         end
  517.         local sx = math.floor((star.x-0.5)*pxw/star.z + pxw/2)
  518.         local sy = math.floor((star.y-0.5)*pxh/star.z + pxh/2)
  519.         if sx >= 0 and sx < pxw and sy >= 0 and sy < pxh then
  520.           buf[sy][sx] = 231
  521.         end
  522.       end
  523.     end
  524.     return base
  525.   end
  526. end
  527.  
  528. local DEMOS = {
  529.   {name="SpinZoom", param=mode7_spinzoom(), animate=true},
  530.   {name="Wave", param=mode7_wave(), animate=true},
  531.   {name="Barrel", param=mode7_barrel(), animate=true},
  532.   {name="FZero", param=mode7_fzero(), animate=true},
  533.   {name="Floor", param=mode7_floor(), animate=true},
  534.   {name="Zoom In/Out", param=mode7_zoom(), animate=true},
  535.   {name="Panning", param=mode7_pan(), animate=true},
  536.   {name="Rotating", param=mode7_rotate(), animate=true},
  537.   {name="WaterReflection", param=mode7_waterreflection(), animate=true},
  538.   {name="Tunnel", param=mode7_tunnel(), animate=true},
  539.   {name="Plasma", param=mode7_plasma(), animate=true},
  540.   {name="Rippled Pool", param=mode7_ripple(), animate=true},
  541.   {name="Checkerboard", param=mode7_checkerboard(), animate=true},
  542.   {name="Infinite Zoom", param=mode7_infinitezoom(), animate=true},
  543.   {name="Parallax", param=mode7_parallax(), animate=true},
  544.   {name="Curved Road", param=mode7_road(), animate=true},
  545.   {name="Starfield", param=mode7_starfield(), animate=true},
  546. }
  547.  
  548. local function displayBMPMode7Affine(image, output, paramFunc, animate, duration)
  549.   local screenWidth, screenHeight = output.getSize()
  550.   local pxw, pxh = screenWidth * 6, screenHeight * 9
  551.   local imageWidth, imageHeight = image.width, image.height
  552.   local originalPalette = savePalette()
  553.   local originalGraphicsMode = term.getGraphicsMode()
  554.   local originalBackgroundColor = term.getBackgroundColor()
  555.   local originalTextColor = term.getTextColor()
  556.   term.setGraphicsMode(2)
  557.   set256Palette()
  558.   local bufA = makeBuffer(pxw, pxh)
  559.   local bufB = makeBuffer(pxw, pxh)
  560.   local front, back = bufA, bufB
  561.   local numBands = 4
  562.   local bands = {}
  563.   local bandHeight = math.floor(pxh / numBands)
  564.   for i = 1, numBands do
  565.     local y0 = (i-1)*bandHeight
  566.     local y1 = (i==numBands) and (pxh-1) or (i*bandHeight-1)
  567.     bands[i] = {y0=y0, y1=y1}
  568.   end
  569.   local frame = 0
  570.   local t0 = os.epoch("utc")
  571.   local tEnd = t0 + (duration or 8)*1000
  572.   while os.epoch("utc") < tEnd do
  573.     frame = frame + 1
  574.     local params = paramFunc(frame, screenWidth, screenHeight, imageWidth, imageHeight)
  575.     local a, b, c, d = params.a, params.b, params.c, params.d
  576.     local x0, y0 = params.x0, params.y0
  577.     local u0, v0 = params.u0, params.v0
  578.     local floorFunc = params.floor
  579.     local horizon = params.horizon or 0
  580.     for bandIdx = 1, #bands do
  581.       local band = bands[bandIdx]
  582.       for sy = band.y0, band.y1 do
  583.         for sx = 0, pxw-1 do
  584.           local color = 0
  585.           if floorFunc then
  586.             local tx, ty
  587.             if params.multilayer then
  588.               tx, ty = floorFunc(sx, sy, 1)
  589.             else
  590.               tx, ty = floorFunc(sx, sy)
  591.             end
  592.             if tx and ty and tx >= 1 and tx <= imageWidth and ty >= 1 and ty <= imageHeight then
  593.               local pixel = image.pixels[ty][tx]
  594.               color = mapColor256(pixel.r, pixel.g, pixel.b)
  595.             else
  596.               color = 0
  597.             end
  598.           else
  599.             local sa, sb, sc, sd = a, b, c, d
  600.             if params.scanline then
  601.               sa, sb, sc, sd = params.scanline(sy, a, b, c, d, frame)
  602.             end
  603.             local dx = sx - x0
  604.             local dy = sy - y0
  605.             local u = sa * dx + sb * dy + u0
  606.             local v = sc * dx + sd * dy + v0
  607.             local srcX = math.floor(u + 0.5)
  608.             local srcY = math.floor(v + 0.5)
  609.             if srcX >= 1 and srcX <= imageWidth and srcY >= 1 and srcY <= imageHeight then
  610.               local pixel = image.pixels[srcY][srcX]
  611.               color = mapColor256(pixel.r, pixel.g, pixel.b)
  612.             else
  613.               color = 0
  614.             end
  615.           end
  616.           back[sy][sx] = color
  617.         end
  618.         if params.multilayer then
  619.           local tx, ty = params.floor(band.y0, sy, 2)
  620.           if tx and ty and tx >= 1 and tx <= imageWidth and ty >= 1 and ty <= imageHeight then
  621.             for sx = 0, pxw-1 do
  622.               local pixel = image.pixels[ty][tx]
  623.               back[sy][sx] = math.max(back[sy][sx], mapColor256(pixel.r, pixel.g, pixel.b))
  624.             end
  625.           end
  626.         end
  627.         if sy % 10 == 0 then os.queueEvent("yield") os.pullEvent("yield") end
  628.       end
  629.     end
  630.     if params.starfield then params.starfield(back) end
  631.     front, back = swapBuffers(front, back)
  632.     blitBuffer(front, output)
  633.     os.queueEvent("yield")
  634.     os.pullEvent("yield")
  635.   end
  636.   term.setGraphicsMode(originalGraphicsMode)
  637.   restorePalette(originalPalette)
  638.   term.setBackgroundColor(originalBackgroundColor)
  639.   term.setTextColor(originalTextColor)
  640.   term.clear()
  641.   term.setCursorPos(1, 1)
  642. end
  643.  
  644. local function runDemoSequence(image, output)
  645.   while true do
  646.     for i = 1, #DEMOS do
  647.       local demo = DEMOS[i]
  648.       print("Now running: " .. demo.name)
  649.       displayBMPMode7Affine(image, output, demo.param, demo.animate, DEMO_TIME)
  650.       if i < #DEMOS then
  651.         waterdropTransition(image, output, 1.5)
  652.         os.queueEvent("yield")
  653.         os.pullEvent("yield")
  654.       end
  655.     end
  656.   end
  657. end
  658.  
  659. local output = term
  660. print("The Nono Demo!")
  661. print("by nonogamer9!")
  662. print("Wow! Mode 7 In A Minecraft Mod?")
  663. print("Downloading demo files if missing...")
  664. if not fs.exists(BMP_FILE) then downloadContent(BMP_URL, BMP_FILE, "demo image") end
  665. if not fs.exists(PCM_FILE) then downloadContent(PCM_URL, PCM_FILE, "PCM audio") end
  666. local image, err = readBMP(BMP_FILE)
  667. if not image then print("Error reading BMP file:", err) return end
  668. parallel.waitForAny(
  669.   function() playPCM(PCM_FILE, PCM_SAMPLE_RATE, PCM_UNSIGNED, 0.2) end,
  670.   function() runDemoSequence(image, output) end
  671. )
  672.  
Add Comment
Please, Sign In to add comment