Advertisement
nonogamer9

OC-NICCC: ST-NICCC 2000 Port For OpenComputers (Version 0.85)

Jul 20th, 2024 (edited)
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.94 KB | Software | 0 0
  1. local component = require("component")
  2. local gpu = component.gpu
  3. local internet = require("internet")
  4. local fs = require("filesystem")
  5. local computer = require("computer")
  6.  
  7. local SCREEN_WIDTH, SCREEN_HEIGHT = gpu.getResolution()
  8. local ASCII_CHARS = " .'`^\",:;Il!i><~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$"
  9. local SCENE_URL = "https://github.com/dabadab/st-niccc-2000-html5/raw/master/scene1.bin"
  10. local SCENE_FILE = "scene1.bin"
  11. local TARGET_FPS = 30
  12.  
  13. gpu.setResolution(SCREEN_WIDTH, SCREEN_HEIGHT)
  14.  
  15. local backBuffer = {}
  16. for y = 1, SCREEN_HEIGHT do
  17.     backBuffer[y] = string.rep(" ", SCREEN_WIDTH)
  18. end
  19.  
  20. local function downloadFile(url, filename)
  21.     print("OC-NICCC: ST-NICCC 2000 Port For OpenComputers Created By nonogamer9")
  22.     print("THIS IS")
  23.     print("*NOT*")
  24.     print("AN COMPUTERCRAFT DEMO")
  25.     print("Downloading " .. filename .. "...")
  26.     local result = ""
  27.     for chunk in internet.request(url) do
  28.         result = result .. chunk
  29.     end
  30.     local file = io.open(filename, "wb")
  31.     file:write(result)
  32.     file:close()
  33.     print("Download complete! Enjoy The Demo!")
  34. end
  35.  
  36. local function readBinaryFile(filename)
  37.     local file = io.open(filename, "rb")
  38.     if not file then return nil end
  39.     local content = file:read("*all")
  40.     file:close()
  41.     return content
  42. end
  43.  
  44. local function decode(raw)
  45.     raw = raw & 0xF
  46.     local bits = (raw >> 3) & 1
  47.     bits = bits | ((raw << 1) & 0xE)
  48.     return bits * 17
  49. end
  50.  
  51. local function colorToAscii(r, g, b)
  52.     local intensity = (0.299 * r + 0.587 * g + 0.114 * b) / 255
  53.     local index = math.floor(intensity * (#ASCII_CHARS - 1)) + 1
  54.     return ASCII_CHARS:sub(index, index)
  55. end
  56.  
  57. local function clearBackBuffer()
  58.     for y = 1, SCREEN_HEIGHT - 1 do
  59.         backBuffer[y] = string.rep(" ", SCREEN_WIDTH)
  60.     end
  61. end
  62.  
  63. local function flushBackBuffer()
  64.     for y = 1, SCREEN_HEIGHT - 1 do
  65.         gpu.set(1, y, backBuffer[y])
  66.     end
  67. end
  68.  
  69. local function renderFrame(dataStream, colors)
  70.     local align = false
  71.     local flags = string.byte(dataStream:read(1))
  72.  
  73.     if flags & 2 > 0 then
  74.         local colorsData = dataStream:read(2)
  75.         local colorsValue = (string.byte(colorsData, 1) << 8) | string.byte(colorsData, 2)
  76.         for i = 0, 15 do
  77.             if colorsValue & (1 << (15 - i)) > 0 then
  78.                 local colorData = dataStream:read(2)
  79.                 local colorValue = (string.byte(colorData, 1) << 8) | string.byte(colorData, 2)
  80.                 colors[i + 1] = {
  81.                     red = decode(colorValue),
  82.                     green = decode(colorValue >> 4),
  83.                     blue = decode(colorValue >> 8)
  84.                 }
  85.             end
  86.         end
  87.     end
  88.  
  89.     if flags & 1 > 0 then
  90.         clearBackBuffer()
  91.     end
  92.  
  93.     local function drawLine(x1, y1, x2, y2, char)
  94.         local dx = math.abs(x2 - x1)
  95.         local dy = math.abs(y2 - y1)
  96.         local sx = x1 < x2 and 1 or -1
  97.         local sy = y1 < y2 and 1 or -1
  98.         local err = dx - dy
  99.  
  100.         while true do
  101.             if x1 >= 1 and x1 <= SCREEN_WIDTH and y1 >= 1 and y1 <= SCREEN_HEIGHT - 1 then
  102.                 local row = backBuffer[y1]
  103.                 backBuffer[y1] = row:sub(1, x1 - 1) .. char .. row:sub(x1 + 1)
  104.             end
  105.             if x1 == x2 and y1 == y2 then break end
  106.             local e2 = 2 * err
  107.             if e2 > -dy then
  108.                 err = err - dy
  109.                 x1 = x1 + sx
  110.             end
  111.             if e2 < dx then
  112.                 err = err + dx
  113.                 y1 = y1 + sy
  114.             end
  115.         end
  116.     end
  117.  
  118.     local function drawPolygon(polygon, char)
  119.         for i = 1, #polygon do
  120.             local p1 = polygon[i]
  121.             local p2 = polygon[i % #polygon + 1]
  122.             local x1, y1 = math.floor(p1.x * SCREEN_WIDTH / 320), math.floor(p1.y * (SCREEN_HEIGHT - 1) / 200)
  123.             local x2, y2 = math.floor(p2.x * SCREEN_WIDTH / 320), math.floor(p2.y * (SCREEN_HEIGHT - 1) / 200)
  124.             drawLine(x1, y1, x2, y2, char)
  125.         end
  126.     end
  127.  
  128.     if flags & 4 > 0 then
  129.         local verticesCount = string.byte(dataStream:read(1))
  130.         local points = {}
  131.         for i = 1, verticesCount do
  132.             local x = string.byte(dataStream:read(1))
  133.             local y = string.byte(dataStream:read(1))
  134.             points[i] = {x = x, y = y}
  135.         end
  136.         while true do
  137.             local bits = string.byte(dataStream:read(1))
  138.             if bits == 0xFF then
  139.                 align = false
  140.                 break
  141.             elseif bits == 0xFE then
  142.                 align = true
  143.                 break
  144.             elseif bits == 0xFD then
  145.                 return false
  146.             else
  147.                 local polygon = {}
  148.                 for i = 1, (bits & 0xF) do
  149.                     local index = string.byte(dataStream:read(1))
  150.                     table.insert(polygon, points[index + 1])
  151.                 end
  152.                 local color = colors[(bits >> 4) + 1]
  153.                 local char = colorToAscii(color.red, color.green, color.blue)
  154.                 drawPolygon(polygon, char)
  155.             end
  156.         end
  157.     else
  158.         while true do
  159.             local bits = string.byte(dataStream:read(1))
  160.             if bits == 0xFF then
  161.                 align = false
  162.                 break
  163.             elseif bits == 0xFE then
  164.                 align = true
  165.                 break
  166.             elseif bits == 0xFD then
  167.                 return false
  168.             else
  169.                 local polygon = {}
  170.                 for i = 1, (bits & 0xF) do
  171.                     local x = string.byte(dataStream:read(1))
  172.                     local y = string.byte(dataStream:read(1))
  173.                     table.insert(polygon, {x = x, y = y})
  174.                 end
  175.                 local color = colors[(bits >> 4) + 1]
  176.                 local char = colorToAscii(color.red, color.green, color.blue)
  177.                 drawPolygon(polygon, char)
  178.             end
  179.         end
  180.     end
  181.  
  182.     if align then
  183.         local position = dataStream:seek("cur", 0)
  184.         position = (position + 0xFFFF) & ~0xFFFF
  185.         dataStream:seek("set", position)
  186.     end
  187.  
  188.     return true
  189. end
  190.  
  191. local function main()
  192.     if not fs.exists(SCENE_FILE) then
  193.         downloadFile(SCENE_URL, SCENE_FILE)
  194.     end
  195.  
  196.     local sceneData = readBinaryFile(SCENE_FILE)
  197.     if not sceneData then
  198.         print("Failed to read " .. SCENE_FILE)
  199.         return
  200.     end
  201.  
  202.     local dataStream = {
  203.         data = sceneData,
  204.         position = 1,
  205.         read = function(self, count)
  206.             local result = self.data:sub(self.position, self.position + count - 1)
  207.             self.position = self.position + count
  208.             return result
  209.         end,
  210.         seek = function(self, whence, offset)
  211.             if whence == "set" then
  212.                 self.position = offset + 1
  213.             elseif whence == "cur" then
  214.                 self.position = self.position + offset
  215.             end
  216.             return self.position - 1
  217.         end
  218.     }
  219.  
  220.     local colors = {}
  221.     for i = 1, 16 do
  222.         colors[i] = {red = 0, green = 0, blue = 0}
  223.     end
  224.  
  225.     local frameCount = 0
  226.     local lastTime = computer.uptime()
  227.     local fpsUpdateInterval = 0.1
  228.     local lastFpsUpdate = lastTime
  229.     local frameTime = 1 / TARGET_FPS
  230.     local currentFps = 0
  231.  
  232.     while renderFrame(dataStream, colors) do
  233.         frameCount = frameCount + 1
  234.         local currentTime = computer.uptime()
  235.         if currentTime - lastFpsUpdate >= fpsUpdateInterval then
  236.             currentFps = frameCount / (currentTime - lastFpsUpdate)
  237.             frameCount = 0
  238.             lastFpsUpdate = currentTime
  239.             gpu.fill(1, SCREEN_HEIGHT, SCREEN_WIDTH, 1, " ")
  240.             gpu.set(1, SCREEN_HEIGHT, string.format("FPS: %.1f", currentFps))
  241.         end
  242.         flushBackBuffer()
  243.         local frameDuration = computer.uptime() - currentTime
  244.         if frameDuration < frameTime then
  245.             os.sleep(frameTime - frameDuration)
  246.         end
  247.     end
  248. end
  249.  
  250. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement