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 fs = require("filesystem")
- local computer = require("computer")
- local SCREEN_WIDTH, SCREEN_HEIGHT = gpu.getResolution()
- local ASCII_CHARS = " .'`^\",:;Il!i><~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$"
- local SCENE_URL = "https://github.com/dabadab/st-niccc-2000-html5/raw/master/scene1.bin"
- local SCENE_FILE = "scene1.bin"
- local TARGET_FPS = 30
- gpu.setResolution(SCREEN_WIDTH, SCREEN_HEIGHT)
- local backBuffer = {}
- for y = 1, SCREEN_HEIGHT do
- backBuffer[y] = string.rep(" ", SCREEN_WIDTH)
- end
- local function downloadFile(url, filename)
- print("OC-NICCC: ST-NICCC 2000 Port For OpenComputers Created By nonogamer9")
- print("THIS IS")
- print("*NOT*")
- print("AN COMPUTERCRAFT DEMO")
- print("Downloading " .. filename .. "...")
- local result = ""
- for chunk in internet.request(url) do
- result = result .. chunk
- end
- local file = io.open(filename, "wb")
- file:write(result)
- file:close()
- print("Download complete! Enjoy The Demo!")
- end
- local function readBinaryFile(filename)
- local file = io.open(filename, "rb")
- if not file then return nil end
- local content = file:read("*all")
- file:close()
- return content
- end
- local function decode(raw)
- raw = raw & 0xF
- local bits = (raw >> 3) & 1
- bits = bits | ((raw << 1) & 0xE)
- return bits * 17
- end
- local function colorToAscii(r, g, b)
- local intensity = (0.299 * r + 0.587 * g + 0.114 * b) / 255
- local index = math.floor(intensity * (#ASCII_CHARS - 1)) + 1
- return ASCII_CHARS:sub(index, index)
- end
- local function clearBackBuffer()
- for y = 1, SCREEN_HEIGHT - 1 do
- backBuffer[y] = string.rep(" ", SCREEN_WIDTH)
- end
- end
- local function flushBackBuffer()
- for y = 1, SCREEN_HEIGHT - 1 do
- gpu.set(1, y, backBuffer[y])
- end
- end
- local function renderFrame(dataStream, colors)
- local align = false
- local flags = string.byte(dataStream:read(1))
- if flags & 2 > 0 then
- local colorsData = dataStream:read(2)
- local colorsValue = (string.byte(colorsData, 1) << 8) | string.byte(colorsData, 2)
- for i = 0, 15 do
- if colorsValue & (1 << (15 - i)) > 0 then
- local colorData = dataStream:read(2)
- local colorValue = (string.byte(colorData, 1) << 8) | string.byte(colorData, 2)
- colors[i + 1] = {
- red = decode(colorValue),
- green = decode(colorValue >> 4),
- blue = decode(colorValue >> 8)
- }
- end
- end
- end
- if flags & 1 > 0 then
- clearBackBuffer()
- end
- local function drawLine(x1, y1, x2, y2, char)
- local dx = math.abs(x2 - x1)
- local dy = math.abs(y2 - y1)
- local sx = x1 < x2 and 1 or -1
- local sy = y1 < y2 and 1 or -1
- local err = dx - dy
- while true do
- if x1 >= 1 and x1 <= SCREEN_WIDTH and y1 >= 1 and y1 <= SCREEN_HEIGHT - 1 then
- local row = backBuffer[y1]
- backBuffer[y1] = row:sub(1, x1 - 1) .. char .. row:sub(x1 + 1)
- end
- if x1 == x2 and y1 == y2 then break end
- local e2 = 2 * err
- if e2 > -dy then
- err = err - dy
- x1 = x1 + sx
- end
- if e2 < dx then
- err = err + dx
- y1 = y1 + sy
- end
- end
- end
- local function drawPolygon(polygon, char)
- for i = 1, #polygon do
- local p1 = polygon[i]
- local p2 = polygon[i % #polygon + 1]
- local x1, y1 = math.floor(p1.x * SCREEN_WIDTH / 320), math.floor(p1.y * (SCREEN_HEIGHT - 1) / 200)
- local x2, y2 = math.floor(p2.x * SCREEN_WIDTH / 320), math.floor(p2.y * (SCREEN_HEIGHT - 1) / 200)
- drawLine(x1, y1, x2, y2, char)
- end
- end
- if flags & 4 > 0 then
- local verticesCount = string.byte(dataStream:read(1))
- local points = {}
- for i = 1, verticesCount do
- local x = string.byte(dataStream:read(1))
- local y = string.byte(dataStream:read(1))
- points[i] = {x = x, y = y}
- end
- while true do
- local bits = string.byte(dataStream:read(1))
- if bits == 0xFF then
- align = false
- break
- elseif bits == 0xFE then
- align = true
- break
- elseif bits == 0xFD then
- return false
- else
- local polygon = {}
- for i = 1, (bits & 0xF) do
- local index = string.byte(dataStream:read(1))
- table.insert(polygon, points[index + 1])
- end
- local color = colors[(bits >> 4) + 1]
- local char = colorToAscii(color.red, color.green, color.blue)
- drawPolygon(polygon, char)
- end
- end
- else
- while true do
- local bits = string.byte(dataStream:read(1))
- if bits == 0xFF then
- align = false
- break
- elseif bits == 0xFE then
- align = true
- break
- elseif bits == 0xFD then
- return false
- else
- local polygon = {}
- for i = 1, (bits & 0xF) do
- local x = string.byte(dataStream:read(1))
- local y = string.byte(dataStream:read(1))
- table.insert(polygon, {x = x, y = y})
- end
- local color = colors[(bits >> 4) + 1]
- local char = colorToAscii(color.red, color.green, color.blue)
- drawPolygon(polygon, char)
- end
- end
- end
- if align then
- local position = dataStream:seek("cur", 0)
- position = (position + 0xFFFF) & ~0xFFFF
- dataStream:seek("set", position)
- end
- return true
- end
- local function main()
- if not fs.exists(SCENE_FILE) then
- downloadFile(SCENE_URL, SCENE_FILE)
- end
- local sceneData = readBinaryFile(SCENE_FILE)
- if not sceneData then
- print("Failed to read " .. SCENE_FILE)
- return
- end
- local dataStream = {
- data = sceneData,
- position = 1,
- read = function(self, count)
- local result = self.data:sub(self.position, self.position + count - 1)
- self.position = self.position + count
- return result
- end,
- seek = function(self, whence, offset)
- if whence == "set" then
- self.position = offset + 1
- elseif whence == "cur" then
- self.position = self.position + offset
- end
- return self.position - 1
- end
- }
- local colors = {}
- for i = 1, 16 do
- colors[i] = {red = 0, green = 0, blue = 0}
- end
- local frameCount = 0
- local lastTime = computer.uptime()
- local fpsUpdateInterval = 0.1
- local lastFpsUpdate = lastTime
- local frameTime = 1 / TARGET_FPS
- local currentFps = 0
- while renderFrame(dataStream, colors) do
- frameCount = frameCount + 1
- local currentTime = computer.uptime()
- if currentTime - lastFpsUpdate >= fpsUpdateInterval then
- currentFps = frameCount / (currentTime - lastFpsUpdate)
- frameCount = 0
- lastFpsUpdate = currentTime
- gpu.fill(1, SCREEN_HEIGHT, SCREEN_WIDTH, 1, " ")
- gpu.set(1, SCREEN_HEIGHT, string.format("FPS: %.1f", currentFps))
- end
- flushBackBuffer()
- local frameDuration = computer.uptime() - currentTime
- if frameDuration < frameTime then
- os.sleep(frameTime - frameDuration)
- end
- end
- end
- main()
Add Comment
Please, Sign In to add comment