nonogamer9

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

Jul 20th, 2024 (edited)
724
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.30 KB | Software | 0 0
  1. local component = require("component")
  2. local event = require("event")
  3. local internet = require("internet")
  4. local unicode = require("unicode")
  5.  
  6. local gpu = component.gpu
  7. local w, h = gpu.getResolution()
  8.  
  9. local floor = math.floor
  10. local ceil = math.ceil
  11. local byte = string.byte
  12. local uchar = unicode.char
  13. local min = math.min
  14. local max = math.max
  15.  
  16. local vram_w = w * 2
  17. local vram_h = h * 4
  18. local vramSize = vram_w * vram_h
  19.  
  20. local scaleX = vram_w / 256
  21. local scaleY = vram_h / 200
  22.  
  23. local BRIGHTNESS_FACTOR = 1.7
  24.  
  25. local W1, W2, W3, W4 = 1, 8, 2, 16
  26. local W5, W6, W7, W8 = 4, 32, 64, 128
  27.  
  28. local brailleChars = {}
  29. for i = 0, 255 do
  30.     brailleChars[i] = uchar(0x2800 + i)
  31. end
  32.  
  33. local vram = {}
  34. for i = 1, vramSize do
  35.     vram[i] = 0
  36. end
  37.  
  38. local cacheBg, cacheFg, cacheChar = {}, {}, {}
  39. local colors = {}
  40. local points, poly = {}, {}
  41. local runChars = {}
  42.  
  43. local dirtyMinX, dirtyMaxX, dirtyMinY, dirtyMaxY
  44.  
  45. local function resetDirty()
  46.     dirtyMinX = vram_w
  47.     dirtyMaxX = -1
  48.     dirtyMinY = vram_h
  49.     dirtyMaxY = -1
  50. end
  51.  
  52. local function markDirtyFull()
  53.     dirtyMinX = 0
  54.     dirtyMaxX = vram_w - 1
  55.     dirtyMinY = 0
  56.     dirtyMaxY = vram_h - 1
  57. end
  58.  
  59. local buffer = nil
  60. local usingBuffer = false
  61.  
  62. if gpu.allocateBuffer then
  63.     buffer = gpu.allocateBuffer(w, h)
  64.     if buffer then
  65.         usingBuffer = true
  66.         gpu.setActiveBuffer(buffer)
  67.     end
  68. end
  69.  
  70. local function u16(str, pos)
  71.     local a, b = byte(str, pos, pos + 1)
  72.     return a + b * 256
  73. end
  74.  
  75. local function u32(str, pos)
  76.     local a, b, c, d = byte(str, pos, pos + 3)
  77.     return a + b * 256 + c * 65536 + d * 16777216
  78. end
  79.  
  80. local function brightenColor(r, g, b)
  81.     r = min(floor(r * BRIGHTNESS_FACTOR), 255)
  82.     g = min(floor(g * BRIGHTNESS_FACTOR), 255)
  83.     b = min(floor(b * BRIGHTNESS_FACTOR), 255)
  84.     return r * 65536 + g * 256 + b
  85. end
  86.  
  87. local function displayImageMode2(imageData, width, height, bitsPerPixel, dataOffset, rowSize)
  88.     if bitsPerPixel ~= 24 then return end
  89.  
  90.     local xRatio = width / vram_w
  91.     local yRatio = height / vram_h
  92.     local lastFg, lastBg = -1, -1
  93.     local _floor, _byte, _braille, _gpu = floor, byte, brailleChars, gpu
  94.  
  95.     for py = 0, h - 1 do
  96.         local iy = py * 4
  97.         for px = 0, w - 1 do
  98.             local ix = px * 2
  99.             local sumR, sumG, sumB = 0, 0, 0
  100.             local minLum, minR, minG, minB = 766, 0, 0, 0
  101.             local l1, l2, l3, l4, l5, l6, l7, l8
  102.             local n = 0
  103.  
  104.             for syOff = 0, 3 do
  105.                 local sy = _floor((iy + syOff) * yRatio)
  106.                 local rowBase = dataOffset + (height - 1 - sy) * rowSize
  107.                 for sxOff = 0, 1 do
  108.                     local sx = _floor((ix + sxOff) * xRatio)
  109.                     local p = rowBase + sx * 3 + 1
  110.                     local b, g, r = _byte(imageData, p, p + 2)
  111.                     local lum = r + g + b
  112.  
  113.                     sumR, sumG, sumB = sumR + r, sumG + g, sumB + b
  114.  
  115.                     if lum < minLum then
  116.                         minLum, minR, minG, minB = lum, r, g, b
  117.                     end
  118.  
  119.                     n = n + 1
  120.                     if n == 1 then l1 = lum
  121.                     elseif n == 2 then l2 = lum
  122.                     elseif n == 3 then l3 = lum
  123.                     elseif n == 4 then l4 = lum
  124.                     elseif n == 5 then l5 = lum
  125.                     elseif n == 6 then l6 = lum
  126.                     elseif n == 7 then l7 = lum
  127.                     else l8 = lum
  128.                     end
  129.                 end
  130.             end
  131.  
  132.             local avgLum = (sumR + sumG + sumB) * 0.125
  133.             local pattern = 0
  134.             if l1 > avgLum then pattern = pattern + W1 end
  135.             if l2 > avgLum then pattern = pattern + W2 end
  136.             if l3 > avgLum then pattern = pattern + W3 end
  137.             if l4 > avgLum then pattern = pattern + W4 end
  138.             if l5 > avgLum then pattern = pattern + W5 end
  139.             if l6 > avgLum then pattern = pattern + W6 end
  140.             if l7 > avgLum then pattern = pattern + W7 end
  141.             if l8 > avgLum then pattern = pattern + W8 end
  142.  
  143.             local avgR, avgG, avgB = _floor(sumR * 0.125), _floor(sumG * 0.125), _floor(sumB * 0.125)
  144.             local bgR = _floor(minR * 0.3 + avgR * 0.7)
  145.             local bgG = _floor(minG * 0.3 + avgG * 0.7)
  146.             local bgB = _floor(minB * 0.3 + avgB * 0.7)
  147.  
  148.             local fg = avgR * 65536 + avgG * 256 + avgB
  149.             local bg = bgR * 65536 + bgG * 256 + bgB
  150.  
  151.             if fg ~= lastFg then _gpu.setForeground(fg); lastFg = fg end
  152.             if bg ~= lastBg then _gpu.setBackground(bg); lastBg = bg end
  153.  
  154.             _gpu.set(px + 1, py + 1, _braille[pattern])
  155.         end
  156.     end
  157. end
  158.  
  159. local bmpHandle = internet.request("https://files.catbox.moe/fhp6jy.bmp")
  160. if bmpHandle then
  161.     local bmpChunks = {}
  162.     for chunk in bmpHandle do
  163.         bmpChunks[#bmpChunks + 1] = chunk
  164.     end
  165.     local bmpData = table.concat(bmpChunks)
  166.     bmpChunks = nil
  167.  
  168.     local width = u32(bmpData, 19)
  169.     local height = u32(bmpData, 23)
  170.     local bitsPerPixel = u16(bmpData, 29)
  171.     local dataOffset = u32(bmpData, 11)
  172.     local rowSize = floor((bitsPerPixel * width + 31) / 32) * 4
  173.  
  174.     gpu.setActiveBuffer(0)
  175.     displayImageMode2(bmpData, width, height, bitsPerPixel, dataOffset, rowSize)
  176.     bmpData = nil
  177. end
  178.  
  179. gpu.setForeground(0xFFFFFF)
  180. gpu.setBackground(0x000000)
  181. print("OC-NICCC! A ST-NICCC 2000 Port For OpenComputers Made By nonogamer9!")
  182. print("This is\n*NOT*\nA ComputerCraft Demo\nFetching scene.bin...")
  183.  
  184. if usingBuffer then
  185.     gpu.setActiveBuffer(buffer)
  186. end
  187.  
  188. local colorCount, colorStamp, colorTouched = {}, {}, {}
  189. local colorGeneration = 0
  190.  
  191. local function chooseColors(p1, p2, p3, p4, p5, p6, p7, p8)
  192.     colorGeneration = colorGeneration + 1
  193.     local generation = colorGeneration
  194.     local counts, stamps, touched = colorCount, colorStamp, colorTouched
  195.     local touchedCount = 0
  196.     local c
  197.  
  198.     for _, val in ipairs({p1, p2, p3, p4, p5, p6, p7, p8}) do
  199.         c = val
  200.         if stamps[c] ~= generation then
  201.             stamps[c] = generation
  202.             counts[c] = 1
  203.             touchedCount = touchedCount + 1
  204.             touched[touchedCount] = c
  205.         else
  206.             counts[c] = counts[c] + 1
  207.         end
  208.     end
  209.  
  210.     local bg = touched[1]
  211.     local fg = nil
  212.     local best, second = 0, 0
  213.  
  214.     for i = 1, touchedCount do
  215.         c = touched[i]
  216.         local count = counts[c]
  217.         if count > best then
  218.             second = best
  219.             best = count
  220.             fg = bg
  221.             bg = c
  222.         elseif count > second then
  223.             second = count
  224.             fg = c
  225.         end
  226.     end
  227.  
  228.     return bg, fg
  229. end
  230.  
  231. local edgeY0, edgeY1, edgeX, edgeDX = {}, {}, {}, {}
  232. local edgeOrder, activeEdges = {}, {}
  233.  
  234. local function fillPolygon(pts, count, color)
  235.     if count < 3 then return end
  236.  
  237.     local _floor, _ceil, _max, _min = floor, ceil, max, min
  238.     local _vram = vram
  239.     local _vramW, _vramH = vram_w, vram_h
  240.     local edgeCount = 0
  241.     local minY, maxY = _vramH, 0
  242.     local j = count
  243.  
  244.     for i = 1, count do
  245.         local x0, y0 = pts[j * 2 - 1], pts[j * 2]
  246.         local x1, y1 = pts[i * 2 - 1], pts[i * 2]
  247.  
  248.         if y0 ~= y1 then
  249.             local lowX, lowY, highX, highY
  250.             if y0 < y1 then
  251.                 lowX, lowY, highX, highY = x0, y0, x1, y1
  252.             else
  253.                 lowX, lowY, highX, highY = x1, y1, x0, y0
  254.             end
  255.  
  256.             local yStart = _ceil(lowY)
  257.             local yEnd = _ceil(highY) - 1
  258.  
  259.             if yStart <= yEnd and yEnd >= 0 and yStart < _vramH then
  260.                 if yStart < 0 then yStart = 0 end
  261.                 if yEnd >= _vramH then yEnd = _vramH - 1 end
  262.  
  263.                 if yStart <= yEnd then
  264.                     edgeCount = edgeCount + 1
  265.                     edgeY0[edgeCount] = yStart
  266.                     edgeY1[edgeCount] = yEnd
  267.                     local dxdy = (highX - lowX) / (highY - lowY)
  268.                     edgeDX[edgeCount] = dxdy
  269.                     edgeX[edgeCount] = lowX + (yStart - lowY) * dxdy
  270.  
  271.                     if yStart < minY then minY = yStart end
  272.                     if yEnd > maxY then maxY = yEnd end
  273.                 end
  274.             end
  275.         end
  276.         j = i
  277.     end
  278.  
  279.     if edgeCount < 2 then return end
  280.  
  281.     for i = 1, edgeCount do edgeOrder[i] = i end
  282.     for i = 2, edgeCount do
  283.         local key = edgeOrder[i]
  284.         local keyY = edgeY0[key]
  285.         local k = i - 1
  286.         while k > 0 and edgeY0[edgeOrder[k]] > keyY do
  287.             edgeOrder[k + 1] = edgeOrder[k]
  288.             k = k - 1
  289.         end
  290.         edgeOrder[k + 1] = key
  291.     end
  292.  
  293.     local activeCount = 0
  294.     local nextEdge = 1
  295.     local maxX = _vramW - 1
  296.  
  297.     for y = minY, maxY do
  298.         while nextEdge <= edgeCount do
  299.             local edge = edgeOrder[nextEdge]
  300.             if edgeY0[edge] > y then break end
  301.             if edgeY1[edge] >= y then
  302.                 activeCount = activeCount + 1
  303.                 activeEdges[activeCount] = edge
  304.             end
  305.             nextEdge = nextEdge + 1
  306.         end
  307.  
  308.         local write = 1
  309.         for i = 1, activeCount do
  310.             local edge = activeEdges[i]
  311.             if edgeY1[edge] >= y then
  312.                 activeEdges[write] = edge
  313.                 write = write + 1
  314.             end
  315.         end
  316.         activeCount = write - 1
  317.  
  318.         if activeCount >= 2 then
  319.             for i = 2, activeCount do
  320.                 local key = activeEdges[i]
  321.                 local keyX = edgeX[key]
  322.                 local k = i - 1
  323.                 while k > 0 and edgeX[activeEdges[k]] > keyX do
  324.                     activeEdges[k + 1] = activeEdges[k]
  325.                     k = k - 1
  326.                 end
  327.                 activeEdges[k + 1] = key
  328.             end
  329.  
  330.             local row = y * _vramW
  331.             local i = 1
  332.             while i < activeCount do
  333.                 local e1, e2 = activeEdges[i], activeEdges[i + 1]
  334.                 local startX = _max(_floor(edgeX[e1]), 0)
  335.                 local endX = _min(_floor(edgeX[e2]), maxX)
  336.  
  337.                 if startX <= endX then
  338.                     if startX < dirtyMinX then dirtyMinX = startX end
  339.                     if endX > dirtyMaxX then dirtyMaxX = endX end
  340.                     if y < dirtyMinY then dirtyMinY = y end
  341.                     if y > dirtyMaxY then dirtyMaxY = y end
  342.  
  343.                     local idx = row + startX + 1
  344.                     local stop = row + endX + 1
  345.                     while idx <= stop do
  346.                         _vram[idx] = color
  347.                         idx = idx + 1
  348.                     end
  349.                 end
  350.                 i = i + 2
  351.             end
  352.         end
  353.  
  354.         for i = 1, activeCount do
  355.             local edge = activeEdges[i]
  356.             edgeX[edge] = edgeX[edge] + edgeDX[edge]
  357.         end
  358.     end
  359. end
  360.  
  361. local function clearVRAM(color)
  362.     local _vram = vram
  363.     for i = 1, vramSize do _vram[i] = color end
  364.     markDirtyFull()
  365. end
  366.  
  367. local function blitVRAM()
  368.     if dirtyMinX > dirtyMaxX or dirtyMinY > dirtyMaxY then return end
  369.  
  370.     local _floor, _max, _min = floor, max, min
  371.     local _vram = vram
  372.     local _gpu = gpu
  373.     local _cacheBg, _cacheFg, _cacheChar = cacheBg, cacheFg, cacheChar
  374.     local _braille, _runChars = brailleChars, runChars
  375.     local vw = vram_w
  376.  
  377.     local cellMinX = _max(_floor(dirtyMinX * 0.5) + 1, 1)
  378.     local cellMaxX = _min(_floor(dirtyMaxX * 0.5) + 1, w)
  379.     local cellMinY = _max(_floor(dirtyMinY * 0.25) + 1, 1)
  380.     local cellMaxY = _min(_floor(dirtyMaxY * 0.25) + 1, h)
  381.  
  382.     for cy = cellMinY, cellMaxY do
  383.         local vY = (cy - 1) * 4
  384.         local cellBase = (cy - 1) * w
  385.         local r0 = vY * vw
  386.         local r1, r2, r3 = r0 + vw, r0 + vw * 2, r0 + vw * 3
  387.  
  388.         local lastBg, lastFg = -1, -1
  389.         local runStart, runBg, runFg, runLen = 0, -1, -1, 0
  390.  
  391.         for cx = cellMinX, cellMaxX do
  392.             local vX = (cx - 1) * 2 + 1
  393.             local p1, p2 = _vram[r0 + vX], _vram[r0 + vX + 1]
  394.             local p3, p4 = _vram[r1 + vX], _vram[r1 + vX + 1]
  395.             local p5, p6 = _vram[r2 + vX], _vram[r2 + vX + 1]
  396.             local p7, p8 = _vram[r3 + vX], _vram[r3 + vX + 1]
  397.  
  398.             local bg, fg, char
  399.  
  400.             if p1 == p2 and p1 == p3 and p1 == p4 and p1 == p5 and p1 == p6 and p1 == p7 and p1 == p8 then
  401.                 bg, fg, char = p1, p1, " "
  402.             else
  403.                 bg, fg = chooseColors(p1, p2, p3, p4, p5, p6, p7, p8)
  404.                 if fg == nil or fg == bg then
  405.                     fg, char = bg, " "
  406.                 else
  407.                     local pattern = 0
  408.                     if p1 == fg then pattern = pattern + W1 end
  409.                     if p2 == fg then pattern = pattern + W2 end
  410.                     if p3 == fg then pattern = pattern + W3 end
  411.                     if p4 == fg then pattern = pattern + W4 end
  412.                     if p5 == fg then pattern = pattern + W5 end
  413.                     if p6 == fg then pattern = pattern + W6 end
  414.                     if p7 == fg then pattern = pattern + W7 end
  415.                     if p8 == fg then pattern = pattern + W8 end
  416.                     char = _braille[pattern]
  417.                 end
  418.             end
  419.  
  420.             local cell = cellBase + cx
  421.             if _cacheBg[cell] ~= bg or _cacheFg[cell] ~= fg or _cacheChar[cell] ~= char then
  422.                 _cacheBg[cell], _cacheFg[cell], _cacheChar[cell] = bg, fg, char
  423.  
  424.                 if runLen > 0 and bg == runBg and fg == runFg and cx == runStart + runLen then
  425.                     runLen = runLen + 1
  426.                     _runChars[runLen] = char
  427.                 else
  428.                     if runLen > 0 then
  429.                         if runBg ~= lastBg then _gpu.setBackground(runBg); lastBg = runBg end
  430.                         if runFg ~= lastFg then _gpu.setForeground(runFg); lastFg = runFg end
  431.                         _gpu.set(runStart, cy, table.concat(_runChars, "", 1, runLen))
  432.                         runLen = 0
  433.                     end
  434.                     runStart, runBg, runFg, runLen = cx, bg, fg, 1
  435.                     _runChars[1] = char
  436.                 end
  437.             else
  438.                 if runLen > 0 then
  439.                     if runBg ~= lastBg then _gpu.setBackground(runBg); lastBg = runBg end
  440.                     if runFg ~= lastFg then _gpu.setForeground(runFg); lastFg = runFg end
  441.                     _gpu.set(runStart, cy, table.concat(_runChars, "", 1, runLen))
  442.                     runLen = 0
  443.                 end
  444.             end
  445.         end
  446.  
  447.         if runLen > 0 then
  448.             if runBg ~= lastBg then _gpu.setBackground(runBg); lastBg = runBg end
  449.             if runFg ~= lastFg then _gpu.setForeground(runFg); lastFg = runFg end
  450.             _gpu.set(runStart, cy, table.concat(_runChars, "", 1, runLen))
  451.             runLen = 0
  452.         end
  453.     end
  454. end
  455.  
  456. local function renderFrame(data, pos, dataLength)
  457.     resetDirty()
  458.     local flags = byte(data, pos)
  459.     if not flags then return dataLength + 1 end
  460.     pos = pos + 1
  461.  
  462.     if flags % 2 == 1 then
  463.         clearVRAM(colors[1] or 0)
  464.     end
  465.  
  466.     if flags % 4 >= 2 then
  467.         local m1, m2 = byte(data, pos, pos + 1)
  468.         local mask = m1 * 256 + m2
  469.         pos = pos + 2
  470.         local bit = 32768
  471.  
  472.         for i = 1, 16 do
  473.             if mask >= bit then
  474.                 mask = mask - bit
  475.                 local c1, c2 = byte(data, pos, pos + 1)
  476.                 pos = pos + 2
  477.                 local r = (c1 % 16) * 17
  478.                 local g = floor(c2 / 16) * 17
  479.                 local b = (c2 % 16) * 17
  480.                 colors[i] = brightenColor(r, g, b)
  481.             end
  482.             bit = bit * 0.5
  483.         end
  484.     end
  485.  
  486.     local hasVertexTable = flags % 8 >= 4
  487.     if hasVertexTable then
  488.         local vCount = byte(data, pos)
  489.         pos = pos + 1
  490.  
  491.         for i = 0, vCount - 1 do
  492.             local bx, by = byte(data, pos, pos + 1)
  493.             pos = pos + 2
  494.             local idx = i * 2 + 1
  495.             points[idx] = bx * scaleX + 0.5
  496.             points[idx + 1] = by * scaleY + 0.5
  497.         end
  498.     end
  499.  
  500.     while pos <= dataLength do
  501.         local command = byte(data, pos)
  502.         pos = pos + 1
  503.  
  504.         if not command or command >= 0xFD then
  505.             if command == 0xFE then
  506.                 pos = floor((pos - 1) / 65536) * 65536 + 65537
  507.             end
  508.             break
  509.         end
  510.  
  511.         local numPts = command % 16
  512.         local colIdx = floor(command / 16) + 1
  513.  
  514.         if numPts >= 3 then
  515.             if hasVertexTable then
  516.                 for i = 1, numPts do
  517.                     local idx = byte(data, pos)
  518.                     pos = pos + 1
  519.                     local src = idx * 2 + 1
  520.                     local dst = i * 2 - 1
  521.                     poly[dst] = points[src]
  522.                     poly[dst + 1] = points[src + 1]
  523.                 end
  524.             else
  525.                 for i = 1, numPts do
  526.                     local px, py = byte(data, pos, pos + 1)
  527.                     pos = pos + 2
  528.                     local dst = i * 2 - 1
  529.                     poly[dst] = px * scaleX + 0.5
  530.                     poly[dst + 1] = py * scaleY + 0.5
  531.                 end
  532.             end
  533.  
  534.             fillPolygon(poly, numPts, colors[colIdx] or 0)
  535.         else
  536.             pos = pos + (hasVertexTable and numPts or numPts * 2)
  537.         end
  538.     end
  539.  
  540.     blitVRAM()
  541.  
  542.     if usingBuffer then
  543.         gpu.bitblt(0, 1, 1, w, h, buffer, 1, 1)
  544.     end
  545.  
  546.     return pos
  547. end
  548.  
  549. local function runDemo()
  550.     local handle = internet.request("https://files.catbox.moe/r5mp9l.bin")
  551.     if not handle then
  552.         print("Failed to fetch scene.bin")
  553.         return
  554.     end
  555.  
  556.     local chunks = {}
  557.     for chunk in handle do
  558.         chunks[#chunks + 1] = chunk
  559.     end
  560.     local data = table.concat(chunks)
  561.     chunks = nil
  562.  
  563.     local dataLength = #data
  564.     local pos = 1
  565.     local frameCount = 0
  566.  
  567.     while pos <= dataLength do
  568.         local oldPos = pos
  569.         pos = renderFrame(data, pos, dataLength)
  570.         frameCount = frameCount + 1
  571.  
  572.         if frameCount % 8 == 0 then
  573.             if event.pull(0) == "interrupted" then
  574.                 break
  575.             end
  576.         end
  577.  
  578.         if pos <= oldPos then break end
  579.     end
  580.     data = nil
  581. end
  582.  
  583. runDemo()
  584.  
  585. if usingBuffer then
  586.     gpu.setActiveBuffer(0)
  587.     gpu.freeBuffer(buffer)
  588.     buffer = nil
  589. end
  590.  
  591. gpu.setBackground(0x000000)
  592. gpu.setForeground(0xFFFFFF)
  593. print("Finished Demo.")
Add Comment
Please, Sign In to add comment