Advertisement
nonogamer9

CC-NICCC: ST-NICCC 2000 Port For ComputerCraft Tweaked (Version 0.85)

Jul 21st, 2024 (edited)
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.21 KB | Software | 0 0
  1. -- Custom bit32 implementation for vanilla ComputerCraft
  2. local bit32 = {}
  3.  
  4. function bit32.band(a, b)
  5.     local result = 0
  6.     local bitval = 1
  7.     while a > 0 and b > 0 do
  8.         if a % 2 == 1 and b % 2 == 1 then
  9.             result = result + bitval
  10.         end
  11.         bitval = bitval * 2
  12.         a = math.floor(a / 2)
  13.         b = math.floor(b / 2)
  14.     end
  15.     return result
  16. end
  17.  
  18. function bit32.bor(a, b)
  19.     local result = 0
  20.     local bitval = 1
  21.     while a > 0 or b > 0 do
  22.         if a % 2 == 1 or b % 2 == 1 then
  23.             result = result + bitval
  24.         end
  25.         bitval = bitval * 2
  26.         a = math.floor(a / 2)
  27.         b = math.floor(b / 2)
  28.     end
  29.     return result
  30. end
  31.  
  32. function bit32.lshift(a, disp)
  33.     return a * (2 ^ disp)
  34. end
  35.  
  36. function bit32.rshift(a, disp)
  37.     return math.floor(a / (2 ^ disp))
  38. end
  39.  
  40. local function downloadFile(url, path)
  41.     print("Downloading " .. url .. "...")
  42.     local response = http.get(url)
  43.     if response then
  44.         local file = fs.open(path, "wb")
  45.         file.write(response.readAll())
  46.         file.close()
  47.         response.close()
  48.         print("Download complete!")
  49.         return true
  50.     end
  51.     print("Download failed!")
  52.     return false
  53. end
  54.  
  55. local sceneUrl = "https://github.com/pulkomandy/beniccc/raw/master/scene1.bin"
  56. local scenePath = "scene1.bin"
  57.  
  58. if not fs.exists(scenePath) and not downloadFile(sceneUrl, scenePath) then
  59.     error("Failed to download scene1.bin")
  60. end
  61.  
  62. local w, h = term.getSize()
  63. local DEMO_WIDTH, DEMO_HEIGHT = 256, 200
  64. local SCALE_X, SCALE_Y = w / DEMO_WIDTH, h / DEMO_HEIGHT
  65.  
  66. local frontBuffer, backBuffer = {}, {}
  67. for y = 1, h do
  68.     frontBuffer[y], backBuffer[y] = {}, {}
  69.     for x = 1, w do
  70.         frontBuffer[y][x] = {bg = colors.black, char = " "}
  71.         backBuffer[y][x] = {bg = colors.black, char = " "}
  72.     end
  73. end
  74.  
  75. local function decode(raw)
  76.     raw = bit32.band(raw, 0xF)
  77.     local bits = bit32.band(bit32.rshift(raw, 3), 1)
  78.     bits = bit32.bor(bits, bit32.band(bit32.lshift(raw, 1), 0xE))
  79.     return bits * 17
  80. end
  81.  
  82. local function rgbToTerminal(r, g, b)
  83.     local colors = {
  84.         [colors.white] = {240, 240, 240},
  85.         [colors.orange] = {242, 178, 51},
  86.         [colors.magenta] = {229, 127, 216},
  87.         [colors.lightBlue] = {153, 178, 242},
  88.         [colors.yellow] = {222, 222, 108},
  89.         [colors.lime] = {127, 204, 25},
  90.         [colors.pink] = {242, 178, 204},
  91.         [colors.gray] = {76, 76, 76},
  92.         [colors.lightGray] = {153, 153, 153},
  93.         [colors.cyan] = {76, 153, 178},
  94.         [colors.purple] = {178, 102, 229},
  95.         [colors.blue] = {51, 102, 204},
  96.         [colors.brown] = {127, 102, 76},
  97.         [colors.green] = {87, 166, 78},
  98.         [colors.red] = {204, 76, 76},
  99.         [colors.black] = {17, 17, 17}
  100.     }
  101.    
  102.     local minDist, bestColor = math.huge, colors.black
  103.     for color, rgb in pairs(colors) do
  104.         local dr, dg, db = r - rgb[1], g - rgb[2], b - rgb[3]
  105.         local dist = dr * dr + dg * dg + db * db
  106.         if dist < minDist then
  107.             minDist, bestColor = dist, color
  108.         end
  109.     end
  110.     return bestColor
  111. end
  112.  
  113. local file = fs.open(scenePath, "rb")
  114. local sceneData = file.readAll()
  115. file.close()
  116.  
  117. local position = 1
  118. local function readByte()
  119.     if position > #sceneData then
  120.         return nil
  121.     end
  122.     local byte = string.byte(sceneData:sub(position, position))
  123.     position = position + 1
  124.     return byte
  125. end
  126.  
  127. local function readWord()
  128.     local high, low = readByte(), readByte()
  129.     if not high or not low then return nil end
  130.     return bit32.bor(bit32.lshift(high, 8), low)
  131. end
  132.  
  133. local function drawPolygon(buffer, poly, color)
  134.     if not poly or #poly < 3 then
  135.         return  -- Not enough points to draw a polygon
  136.     end
  137.  
  138.     local minY, maxY = math.huge, -math.huge
  139.     for _, p in ipairs(poly) do
  140.         if p and p.y then
  141.             minY = math.min(minY, p.y)
  142.             maxY = math.max(maxY, p.y)
  143.         end
  144.     end
  145.  
  146.     if minY == math.huge or maxY == -math.huge then
  147.         return  -- No valid Y coordinates found
  148.     end
  149.  
  150.     for y = math.max(1, math.floor(minY * SCALE_Y)), math.min(h, math.ceil(maxY * SCALE_Y)) do
  151.         local nodeX = {}
  152.         local j = #poly
  153.         for i = 1, #poly do
  154.             local pi, pj = poly[i], poly[j]
  155.             if pi and pj and pi.x and pi.y and pj.x and pj.y then
  156.                 if (pi.y * SCALE_Y < y and pj.y * SCALE_Y >= y) or (pj.y * SCALE_Y < y and pi.y * SCALE_Y >= y) then
  157.                     if pj.y ~= pi.y then
  158.                         local x = pi.x + (y / SCALE_Y - pi.y) / (pj.y - pi.y) * (pj.x - pi.x)
  159.                         table.insert(nodeX, math.floor(x * SCALE_X))
  160.                     end
  161.                 end
  162.             end
  163.             j = i
  164.         end
  165.  
  166.         table.sort(nodeX)
  167.         for i = 1, #nodeX, 2 do
  168.             local startX, endX = nodeX[i], (nodeX[i+1] or w)
  169.             for x = math.max(1, startX), math.min(w, endX) do
  170.                 if buffer[y] and buffer[y][x] then
  171.                     buffer[y][x] = {bg = color, char = " "}
  172.                 end
  173.             end
  174.         end
  175.     end
  176. end
  177.  
  178. local palette = {}
  179. for i = 1, 16 do palette[i] = colors.black end
  180.  
  181. local frameCount, startTime = 0, os.clock()
  182. local targetFrameTime = 1 / 30
  183.  
  184. local shouldExit = false
  185.  
  186. while position <= #sceneData and not shouldExit do
  187.     local frameStartTime = os.clock()
  188.    
  189.     local flags = readByte()
  190.     if not flags then
  191.         print("End of data reached")
  192.         break
  193.     end
  194.    
  195.     if bit32.band(flags, 2) ~= 0 then
  196.         local colorMask = readWord()
  197.         if not colorMask then
  198.             print("End of data reached while reading color mask")
  199.             break
  200.         end
  201.         for i = 0, 15 do
  202.             if bit32.band(colorMask, bit32.lshift(1, 15 - i)) ~= 0 then
  203.                 local color = readWord()
  204.                 if not color then
  205.                     print("End of data reached while reading color")
  206.                     shouldExit = true
  207.                     break
  208.                 end
  209.                 local r = decode(color)
  210.                 local g = decode(bit32.rshift(color, 12))
  211.                 local b = decode(bit32.rshift(color, 8))
  212.                 palette[i + 1] = rgbToTerminal(r,g,b)
  213.             end
  214.         end
  215.     end
  216.    
  217.     if bit32.band(flags, 1) ~= 0 then
  218.         for y = 1, h do
  219.             for x = 1, w do
  220.                 backBuffer[y][x] = {bg = palette[1], char = " "}
  221.             end
  222.         end
  223.     end
  224.    
  225.     if bit32.band(flags, 4) ~= 0 then
  226.         local vertices = readByte()
  227.         if not vertices then
  228.             print("End of data reached")
  229.             break
  230.         end
  231.         local points = {}
  232.        
  233.         for i = 1, vertices do
  234.             local x, y = readByte(), readByte()
  235.             if not x or not y then
  236.                 print("End of data reached while reading vertices")
  237.                 shouldExit = true
  238.                 break
  239.             end
  240.             points[i] = {x = x, y = y}
  241.         end
  242.        
  243.         if shouldExit then break end
  244.        
  245.         while true do
  246.             local bits = readByte()
  247.             if not bits then
  248.                 print("End of data reached while reading bits")
  249.                 shouldExit = true
  250.                 break
  251.             end
  252.            
  253.             if bits == 0xFF then break  -- End of frame
  254.             elseif bits == 0xFE then
  255.                 position = bit32.band(position - 1 + 0x10000, 0xFFFF0000) + 1
  256.                 break
  257.             elseif bits == 0xFD then
  258.                 shouldExit = true
  259.                 break
  260.             else
  261.                 local color = palette[bit32.rshift(bits, 4) + 1]
  262.                 if not color then
  263.                     print("Invalid color index")
  264.                     shouldExit = true
  265.                     break
  266.                 end
  267.                 local numPoints = bit32.band(bits, 0xF)
  268.                 local poly = {}
  269.                
  270.                 for i = 1, numPoints do
  271.                     local index = readByte()
  272.                     if not index then
  273.                         print("End of data reached while reading polygon points")
  274.                         shouldExit = true
  275.                         break
  276.                     end
  277.                     index = index + 1
  278.                     if points[index] then
  279.                         table.insert(poly, points[index])
  280.                     end
  281.                 end
  282.                
  283.                 if shouldExit then break end
  284.                
  285.                 if #poly >= 3 then
  286.                     drawPolygon(backBuffer, poly, color)
  287.                 end
  288.             end
  289.         end
  290.     else
  291.         while true do
  292.             local bits = readByte()
  293.             if not bits then
  294.                 print("End of data reached while reading bits")
  295.                 shouldExit = true
  296.                 break
  297.             end
  298.            
  299.             if bits == 0xFF then break  -- End of frame
  300.             elseif bits == 0xFE then
  301.                 position = bit32.band(position - 1 + 0x10000, 0xFFFF0000) + 1
  302.                 break
  303.             elseif bits == 0xFD then
  304.                 shouldExit = true
  305.                 break
  306.             else
  307.                 local color = palette[bit32.rshift(bits, 4) + 1]
  308.                 if not color then
  309.                     print("Invalid color index")
  310.                     shouldExit = true
  311.                     break
  312.                 end
  313.                 local numPoints = bit32.band(bits, 0xF)
  314.                 local poly = {}
  315.                
  316.                 for i = 1, numPoints do
  317.                     local x, y = readByte(), readByte()
  318.                     if not x or not y then
  319.                         print("End of data reached while reading polygon points")
  320.                         shouldExit = true
  321.                         break
  322.                     end
  323.                     table.insert(poly, {x = x, y = y})
  324.                 end
  325.                
  326.                 if shouldExit then break end
  327.                
  328.                 if #poly >= 3 then
  329.                     drawPolygon(backBuffer, poly, color)
  330.                 end
  331.             end
  332.         end
  333.     end
  334.    
  335.     frontBuffer, backBuffer = backBuffer, frontBuffer
  336.    
  337.     for y = 1, h do
  338.         for x = 1, w do
  339.             term.setCursorPos(x, y)
  340.             term.setBackgroundColor(frontBuffer[y][x].bg)
  341.             term.write(frontBuffer[y][x].char)
  342.         end
  343.     end
  344.  
  345.     frameCount = frameCount + 1
  346.    
  347.     local currentTime = os.clock()
  348.     local fps = frameCount / (currentTime - startTime)
  349.     term.setCursorPos(1, 1)
  350.     term.setBackgroundColor(colors.black)
  351.     term.setTextColor(colors.white)
  352.     term.write(string.format("Frame: %d FPS: %.2f", frameCount, fps))
  353.    
  354.     local frameEndTime = os.clock()
  355.     local frameTime = frameEndTime - frameStartTime
  356.    
  357.     if frameTime < targetFrameTime then sleep(targetFrameTime - frameTime) end
  358. end
  359.  
  360. local endTime = os.clock()
  361. local totalTime = endTime - startTime  
  362. local avgFPS = frameCount / totalTime  
  363. print(string.format("Demo completed in %.2f seconds", totalTime))
  364. print(string.format("Total frames: %d", frameCount))
  365. print(string.format("Average FPS: %.2f", avgFPS))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement