Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local component = require("component")
- local gpu = component.gpu
- local internet = require("internet")
- local event = require("event")
- local unicode = require("unicode")
- local computer = require("computer")
- local bit32 = require("bit32")
- local SCREEN_WIDTH, SCREEN_HEIGHT = 160, 50
- local ORIGINAL_WIDTH, ORIGINAL_HEIGHT = 256, 200
- local scaleX, scaleY = SCREEN_WIDTH / ORIGINAL_WIDTH, SCREEN_HEIGHT / ORIGINAL_HEIGHT
- local screenBuffer = {}
- for y = 1, SCREEN_HEIGHT do
- screenBuffer[y] = {}
- for x = 1, SCREEN_WIDTH do
- screenBuffer[y][x] = 0
- end
- end
- local function isLua53OrHigher()
- return _VERSION and _VERSION >= "Lua 5.3"
- end
- local function stringUnpack(format, str, pos)
- if isLua53OrHigher() then
- return table.unpack(table.pack(string.unpack(format, str, pos)))
- else
- error("String unpacking not supported in this Lua version")
- end
- end
- local function yieldIfNeeded()
- if computer.freeMemory() < 1024 then
- os.sleep(0)
- end
- end
- local function hasMagicalMemory()
- return computer.totalMemory() >= 2097152
- end
- local function decodeBMPMode2(imageData)
- local width = stringUnpack("<I4", imageData, 19)
- local height = stringUnpack("<I4", imageData, 23)
- local bitsPerPixel = stringUnpack("<I2", imageData, 29)
- local compression = stringUnpack("<I4", imageData, 31)
- local dataOffset = stringUnpack("<I4", imageData, 11)
- if bitsPerPixel ~= 24 or compression ~= 0 then
- error("Unsupported BMP format. Only 24-bit uncompressed BMPs are supported.")
- end
- local screenWidth, screenHeight = gpu.getResolution()
- local targetWidth = screenWidth * 2
- local targetHeight = screenHeight * 4
- local decodedImage = {}
- local rowSize = math.floor((bitsPerPixel * width + 31) / 32) * 4
- local xRatio = width / targetWidth
- local yRatio = height / targetHeight
- for y = 0, targetHeight - 1 do
- for x = 0, targetWidth - 1 do
- local srcX = math.floor(x * xRatio)
- local srcY = math.floor(y * yRatio)
- local rowStart = dataOffset + (height - 1 - srcY) * rowSize
- local pixelStart = rowStart + srcX * 3
- local b, g, r = stringUnpack("BBB", imageData, pixelStart + 1)
- table.insert(decodedImage, {r, g, b})
- yieldIfNeeded()
- end
- end
- return decodedImage, targetWidth, targetHeight
- end
- local function getBrailleCharacter(pixels)
- local brailleBase = 0x2800
- local pattern = 0
- local dotWeights = {1, 2, 4, 8, 16, 32, 64, 128}
- local function adjustBrightness(brightness)
- return math.pow(brightness / 255, 0.5) * 255
- end
- local thresholds = {}
- for i = 1, 8 do
- local brightness = (pixels[i][1] + pixels[i][2] + pixels[i][3]) / 3
- thresholds[i] = adjustBrightness(brightness)
- end
- local avgThreshold = 0
- for i = 1, 8 do
- avgThreshold = avgThreshold + thresholds[i]
- end
- avgThreshold = avgThreshold / 8
- for i = 1, 8 do
- if thresholds[i] > avgThreshold then
- pattern = bit32.bor(pattern, dotWeights[i])
- end
- end
- return unicode.char(brailleBase + pattern)
- end
- local function rgbToColor(r, g, b)
- return bit32.bor(bit32.lshift(r, 16), bit32.lshift(g, 8), b)
- end
- local function averageColor(colors)
- local r, g, b, count = 0, 0, 0, #colors
- for _, color in ipairs(colors) do
- r = r + color[1]
- g = g + color[2]
- b = b + color[3]
- end
- if count > 0 then
- return {math.floor(r / count), math.floor(g / count), math.floor(b / count)}
- else
- return {0, 0, 0}
- end
- end
- local function blendColors(c1, c2, factor)
- return {
- math.floor(c1[1] * (1 - factor) + c2[1] * factor),
- math.floor(c1[2] * (1 - factor) + c2[2] * factor),
- math.floor(c1[3] * (1 - factor) + c2[3] * factor)
- }
- end
- local function displayImageMode2(decodedImage, x, y, width, height)
- for py = 0, height / 4 - 1 do
- for px = 0, width / 2 - 1 do
- local pixels = {}
- local colors = {}
- for dy = 0, 3 do
- for dx = 0, 1 do
- local ix = px * 2 + dx
- local iy = py * 4 + dy
- local index = iy * width + ix + 1
- local pixel = decodedImage[index]
- pixels[dy * 2 + dx + 1] = pixel
- table.insert(colors, pixel)
- end
- end
- local char = getBrailleCharacter(pixels)
- local fgColor = averageColor(colors)
- local darkestColor = colors[1]
- for i = 2, #colors do
- if colors[i][1] + colors[i][2] + colors[i][3] < darkestColor[1] + darkestColor[2] + darkestColor[3] then
- darkestColor = colors[i]
- end
- end
- local avgColor = averageColor(colors)
- local bgColor = blendColors(darkestColor, avgColor, 0.3)
- gpu.setForeground(rgbToColor(fgColor[1], fgColor[2], fgColor[3]))
- gpu.setBackground(rgbToColor(bgColor[1], bgColor[2], bgColor[3]))
- gpu.set(x + px, y + py, char)
- end
- yieldIfNeeded()
- end
- end
- local function decodeBMPMode1(imageData)
- local width = stringUnpack("<I4", imageData, 19)
- local height = stringUnpack("<I4", imageData, 23)
- local bitsPerPixel = stringUnpack("<I2", imageData, 29)
- local compression = stringUnpack("<I4", imageData, 31)
- local dataOffset = stringUnpack("<I4", imageData, 11)
- if bitsPerPixel ~= 24 or compression ~= 0 then
- error("Unsupported BMP format. Only 24-bit uncompressed BMPs are supported.")
- end
- local decodedImage = {}
- local rowSize = math.floor((bitsPerPixel * width + 31) / 32) * 4
- local xRatio = width / 160
- local yRatio = height / 50
- for y = 0, 49 do
- for x = 0, 159 do
- local srcX = math.floor(x * xRatio)
- local srcY = math.floor(y * yRatio)
- local rowStart = dataOffset + (height - 1 - srcY) * rowSize
- local pixelStart = rowStart + srcX * 3
- local b, g, r = stringUnpack("BBB", imageData, pixelStart + 1)
- table.insert(decodedImage, {r, g, b})
- yieldIfNeeded()
- end
- end
- return decodedImage, 160, 50
- end
- local function decodeTIImageMode1(imageData)
- local width = stringUnpack("<I4", imageData, 5)
- local height = stringUnpack("<I4", imageData, 9)
- local pixelData = imageData:sub(21)
- local decodedImage = {}
- for i = 1, #pixelData, 2 do
- local pixel = stringUnpack("<I2", pixelData, i)
- local r = bit32.lshift(bit32.band(pixel, 0x7C00), 10) * 8
- local g = bit32.lshift(bit32.band(pixel, 0x03E0), 5) * 8
- local b = bit32.band(pixel, 0x001F) * 8
- table.insert(decodedImage, {r, g, b})
- yieldIfNeeded()
- end
- return decodedImage, width, height
- end
- local function decodeImageMode1(imageData)
- if not imageData or imageData == "" then
- error("No image data received")
- end
- local format = imageData:sub(1, 2)
- if format == "BM" then
- return decodeBMPMode1(imageData)
- elseif format == "TI" then
- return decodeTIImageMode1(imageData)
- else
- error("Unsupported image format")
- end
- end
- local function packColor(r, g, b)
- return bit32.bor(bit32.lshift(r, 16), bit32.lshift(g, 8), b)
- end
- local function displayImageMode1(decodedImage, x, y, width, height)
- for i = 1, #decodedImage do
- local pixel = decodedImage[i]
- local px = (i - 1) % width + x
- local py = math.floor((i - 1) / width) + y
- local color = packColor(pixel[1], pixel[2], pixel[3])
- gpu.setBackground(color)
- gpu.set(px, py, " ")
- yieldIfNeeded()
- end
- end
- local function downloadAndDisplayLoadingScreen()
- if not isLua53OrHigher() then
- print("Loading screen disabled for Lua versions below 5.3")
- return
- end
- print("Downloading loading screen image...")
- local url = "https://files.catbox.moe/qtxc7b.bmp"
- local response = internet.request(url)
- local imageData = ""
- for chunk in response do
- imageData = imageData .. chunk
- end
- print("Image downloaded. Decoding...")
- local decodedImage, width, height
- if hasMagicalMemory() then
- decodedImage, width, height = decodeBMPMode2(imageData)
- print("Image decoded. Displaying in Mode 2...")
- gpu.setResolution(160, 50)
- displayImageMode2(decodedImage, 1, 1, width, height)
- else
- decodedImage, width, height = decodeImageMode1(imageData)
- print("Image decoded. Displaying in Mode 1...")
- gpu.setResolution(160, 50)
- displayImageMode1(decodedImage, 1, 1, width, height)
- end
- gpu.setForeground(0xFFFFFF)
- print("OC-NICCC! A ST-NICCC 2000 Port For OpenComputers Made By nonogamer9!")
- print("This is")
- print("*NOT*")
- print("A ComputerCraft Demo")
- end
- local function downloadFile(url, path)
- if not component.filesystem.exists(path) then
- print("Downloading " .. url .. " to " .. path)
- local result = ""
- for chunk in internet.request(url) do
- result = result .. chunk
- end
- local file = io.open(path, "wb")
- file:write(result)
- file:close()
- print("Download complete")
- end
- end
- local function decode(raw)
- raw = bit32.band(raw, 0xF)
- local bits = bit32.band(bit32.rshift(raw, 3), 1)
- bits = bit32.bor(bits, bit32.band(bit32.lshift(raw, 1), 0xE))
- return bits * 17
- end
- local function readByte(file)
- return string.byte(file:read(1))
- end
- local function readWord(file)
- local b1, b2 = readByte(file), readByte(file)
- return bit32.bor(bit32.lshift(b1, 8), b2)
- end
- local function readColor(file)
- local color = readWord(file)
- local b = decode(bit32.band(color, 0xF))
- local g = decode(bit32.band(bit32.rshift(color, 4), 0xF))
- local r = decode(bit32.band(bit32.rshift(color, 8), 0xF))
- return bit32.bor(bit32.lshift(r, 16), bit32.lshift(g, 8), b)
- end
- local function scalePoint(x, y)
- return math.floor(x * scaleX) + 1, math.floor(y * scaleY) + 1
- end
- local function setPixel(x, y, color)
- if x >= 1 and x <= SCREEN_WIDTH and y >= 1 and y <= SCREEN_HEIGHT then
- screenBuffer[y][x] = color
- end
- end
- local function fillPolygon(points, color)
- if #points < 3 then return end
- local minY, maxY = math.huge, -math.huge
- local edges = {}
- for i = 1, #points do
- local j = i % #points + 1
- local p1, p2 = points[i], points[j]
- local x1, y1 = scalePoint(p1.x, p1.y)
- local x2, y2 = scalePoint(p2.x, p2.y)
- if y1 ~= y2 then
- if y1 > y2 then x1, y1, x2, y2 = x2, y2, x1, y1 end
- local dx = (x2 - x1) / (y2 - y1)
- table.insert(edges, {y = y1, x = x1, dx = dx, ymax = y2})
- minY = math.min(minY, y1)
- maxY = math.max(maxY, y2)
- end
- end
- for y = math.max(1, math.floor(minY)), math.min(SCREEN_HEIGHT, math.ceil(maxY)) do
- local active = {}
- for _, edge in ipairs(edges) do
- if y >= edge.y and y < edge.ymax then
- table.insert(active, edge.x)
- edge.x = edge.x + edge.dx
- end
- end
- table.sort(active)
- for i = 1, #active - 1, 2 do
- local x1, x2 = math.ceil(active[i]), math.floor(active[i+1])
- for x = math.max(1, x1), math.min(SCREEN_WIDTH, x2) do
- setPixel(x, y, color)
- end
- end
- end
- end
- local function renderBuffer()
- for y = 1, SCREEN_HEIGHT do
- local lastColor = screenBuffer[y][1]
- local startX = 1
- for x = 2, SCREEN_WIDTH do
- if screenBuffer[y][x] ~= lastColor then
- gpu.setBackground(lastColor)
- gpu.fill(startX, y, x - startX, 1, " ")
- lastColor = screenBuffer[y][x]
- startX = x
- end
- end
- gpu.setBackground(lastColor)
- gpu.fill(startX, y, SCREEN_WIDTH - startX + 1, 1, " ")
- end
- end
- local function main()
- if isLua53OrHigher() then
- downloadAndDisplayLoadingScreen()
- else
- print("OC-NICCC! A ST-NICCC 2000 Port For OpenComputers Made By nonogamer9!")
- print("This is")
- print("*NOT*")
- print("A ComputerCraft Demo")
- print("Loading screen disabled for Lua versions below 5.3")
- end
- downloadFile("https://raw.githubusercontent.com/pulkomandy/beniccc/master/scene1.bin", "scene1.bin")
- local file = io.open("scene1.bin", "rb")
- if not file then error("Could not open scene1.bin file") end
- gpu.setResolution(SCREEN_WIDTH, SCREEN_HEIGHT)
- local colors = {}
- for i = 1, 16 do colors[i] = 0x000000 end
- local running = true
- while running do
- local flags = readByte(file)
- local alignStream = false
- if bit32.band(flags, 2) ~= 0 then
- local colorMask = readWord(file)
- for i = 1, 16 do
- if bit32.band(colorMask, bit32.lshift(1, 16 - i)) ~= 0 then
- colors[i] = readColor(file)
- gpu.setPaletteColor(i - 1, colors[i])
- end
- end
- end
- if bit32.band(flags, 1) ~= 0 then
- for y = 1, SCREEN_HEIGHT do
- for x = 1, SCREEN_WIDTH do
- screenBuffer[y][x] = colors[1]
- end
- end
- end
- if bit32.band(flags, 4) ~= 0 then
- local vertexCount = readByte(file)
- local vertices = {}
- for i = 1, vertexCount do vertices[i] = {x=readByte(file), y=readByte(file)} end
- while true do
- local bits = readByte(file)
- if bits == 0xFF then
- alignStream = false
- break
- elseif bits == 0xFE then
- alignStream = true
- break
- elseif bits == 0xFD then
- running = false
- break
- else
- local colorIndex = bit32.rshift(bits, 4)
- local color = colors[colorIndex + 1]
- local polygon = {}
- for i = 1, bit32.band(bits, 0xF) do
- local index = readByte(file) + 1
- table.insert(polygon, vertices[index])
- end
- fillPolygon(polygon, color)
- end
- end
- else
- while true do
- local bits = readByte(file)
- if bits == 0xFF then
- alignStream = false
- break
- elseif bits == 0xFE then
- alignStream = true
- break
- elseif bits == 0xFD then
- running = false
- break
- else
- local colorIndex = bit32.rshift(bits, 4)
- local color = colors[colorIndex + 1]
- local polygon = {}
- for i = 1, bit32.band(bits, 0xF) do
- table.insert(polygon, {x = readByte(file), y = readByte(file)})
- end
- fillPolygon(polygon, color)
- end
- end
- end
- renderBuffer()
- if alignStream then
- local position = file:seek()
- position = bit32.bor(bit32.band(position, bit32.bnot(0xFFFF)), 0x10000)
- file:seek("set", position)
- end
- local _, _, _, code = event.pull(0, "key_down")
- if code == 16 then
- running = false
- end
- end
- file:close()
- end
- main()
Add Comment
Please, Sign In to add comment