Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- +local component = require("component")
- +local event = require("event")
- +local keyboard = require("keyboard")
- +local shell = require("shell")
- +local term = require("term")
- +local unicode = require("unicode")
- +local raytracer = require("raytracer")
- +
- +local args = shell.parse(...)
- +if #args < 1 then
- + io.write("Usage: print3d-view FILE [fov]\n")
- + os.exit(0)
- +end
- +
- +-- model loading
- +
- +local file, reason = io.open(args[1], "r")
- +if not file then
- + io.stderr:write("Failed opening file: " .. reason .. "\n")
- + os.exit(1)
- +end
- +
- +local rawdata = file:read("*all")
- +file:close()
- +local data, reason = load("return " .. rawdata)
- +if not data then
- + io.stderr:write("Failed loading model: " .. reason .. "\n")
- + os.exit(2)
- +end
- +data = data()
- +
- +-- set up raytracer
- +
- +local rt = raytracer.new()
- +rt.camera.position={-22+8,20+8,-22+8}
- +rt.camera.target={8,8,8}
- +rt.camera.fov=tonumber(args[2]) or 90
- +
- +local state
- +local function setState(value)
- + if state ~= value then
- + state = value
- + rt.model = {}
- + for _, shape in ipairs(data.shapes or {}) do
- + if not not shape.state == state then
- + table.insert(rt.model, shape)
- + end
- + end
- + if state and #rt.model < 1 then -- no shapes for active state
- + setState(false)
- + end
- + end
- +end
- +setState(false)
- +
- +-- set up gpu
- +
- +local gpu = component.gpu
- +local cfg, cbg
- +local function setForeground(color)
- + if cfg ~= color then
- + gpu.setForeground(color)
- + cfg = color
- + end
- +end
- +local function setBackground(color)
- + if cbg ~= color then
- + gpu.setBackground(color)
- + cbg = color
- + end
- +end
- +
- +-- helper functions
- +
- +local function vrotate(v, origin, angle)
- + local x, y = v[1]-origin[1], v[3]-origin[3]
- + local s = math.sin(angle)
- + local c = math.cos(angle)
- +
- + local rotx = x * c + y * s
- + local roty = -x * s + y * c
- + return {rotx+origin[1], v[2], roty+origin[3]}
- +end
- +
- +local function ambient(normal)
- + if math.abs(normal[1]) > 0.5 then
- + return 0.6
- + elseif math.abs(normal[3]) > 0.5 then
- + return 0.8
- + elseif normal[2] > 0 then
- + return 1.0
- + else
- + return 0.4
- + end
- +end
- +
- +local function hash(str)
- + local result = 7
- + for i=1,#str do
- + result = (result*31 + string.byte(str, i))%0xFFFFFFFF
- + end
- + return result
- +end
- +
- +local function multiply(color, brightness)
- + local r,b,g=(color/2^16)%256,(color/2^8)%256,color%256
- + r = r*brightness
- + g = g*brightness
- + b = b*brightness
- + return r*2^16+g*2^8+b
- +end
- +
- +local palette = {0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF, 0xFFFF00, 0xFFFFFF}
- +
- +-- render model
- +while true do
- + setForeground(0x000000)
- + setBackground(0x000000)
- + local rx, ry = gpu.getResolution()
- + gpu.fill(1, 1, rx, ry, unicode.char(0x2580))
- +
- + rt:render(rx, ry*2, function(x, y, shape, normal)
- + local sx, sy = x, math.ceil(y / 2)
- + local ch, fg, bg = gpu.get(sx, sy)
- + local brightness = ambient(normal)
- + local color = multiply(data.palette and data.palette[shape.texture] or palette[hash(shape.texture or "") % #palette + 1], brightness)
- + if color == 0x000000 then return end
- + if y % 2 == 1 then
- + setBackground(bg)
- + setForeground(color)
- + else
- + setBackground(color)
- + setForeground(fg)
- + end
- + gpu.set(sx, sy, ch)
- + end)
- +
- + gpu.setForeground(0xFFFFFF)
- + gpu.setBackground(0x000000)
- +
- + gpu.set(1, ry, "[q] Quit [left/right] Rotate [space] Toggle state")
- + os.sleep(0.1) -- consume events that arrived in the meantime
- + while true do
- + local _,_,_,code=event.pull("key_down")
- + if code == keyboard.keys.q then
- + term.clear()
- + os.exit(0)
- + elseif code == keyboard.keys.space then
- + setState(not state)
- + break
- + elseif code == keyboard.keys.left then
- + local step = 10
- + if keyboard.isShiftDown() then step = 90 end
- + rt.camera.position = vrotate(rt.camera.position, rt.camera.target, -step/180*math.pi)
- + break
- + elseif code == keyboard.keys.right then
- + local step = 10
- + if keyboard.isShiftDown() then step = 90 end
- + rt.camera.position = vrotate(rt.camera.position, rt.camera.target, step/180*math.pi)
- + break
- + end
- + end
- +end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement