Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Hologram Editor
- -- by NEO, Totoro (aka MoonlightOwl)
- -- 10/14/2014, all right reserved =)
- local unicode = require('unicode')
- local event = require('event')
- local term = require('term')
- local fs = require('filesystem')
- local com = require('component')
- local gpu = com.gpu
- -- Constants --
- HOLOH = 32
- HOLOW = 48
- -- Colors --
- backcolor = 0x000000
- forecolor = 0xFFFFFF
- infocolor = 0x0066FF
- errorcolor = 0xFF0000
- helpcolor = 0x006600
- graycolor = 0x080808
- goldcolor = 0xFFDF00
- -- *** --
- -- loading add. components
- function trytofind(name)
- if com.isAvailable(name) then
- return com.getPrimary(name)
- else
- return nil
- end
- end
- local h = trytofind('hologram')
- -- ========================================= H O L O G R A P H I C S ========================================= --
- holo = {}
- function set(x, y, z, value)
- if holo[x] == nil then holo[x] = {} end
- if holo[x][y] == nil then holo[x][y] = {} end
- holo[x][y][z] = value
- end
- function get(x, y, z)
- if holo[x] ~= nil and holo[x][y] ~= nil and holo[x][y][z] ~= nil then
- return holo[x][y][z]
- else
- return 0
- end
- end
- function save(filename)
- -- save palette
- file = io.open(filename, 'wb')
- for i=1, 3 do
- for c=1, 3 do
- file:write(string.char(colortable[i][c]))
- end
- end
- -- save voxel array
- for x=1, HOLOW do
- for y=1, HOLOH do
- for z=1, HOLOW, 4 do
- a = get(x,y,z)
- b = get(x,y,z+1)
- c = get(x,y,z+2)
- d = get(x,y,z+3)
- byte = d*64 + c*16 + b*4 + a
- file:write(string.char(byte))
- end
- end
- end
- file:close()
- end
- function load(filename)
- if fs.exists(filename) then
- file = io.open(filename, 'rb')
- -- load palette
- for i=1, 3 do
- for c=1, 3 do
- colortable[i][c] = string.byte(file:read(1))
- end
- setHexColor(i,colortable[i][1],
- colortable[i][2],
- colortable[i][3])
- end
- -- load voxel array
- holo = {}
- for x=1, HOLOW do
- for y=1, HOLOH do
- for z=1, HOLOW, 4 do
- byte = string.byte(file:read(1))
- for i=0, 3 do
- a = byte % 4
- byte = math.floor(byte / 4)
- if a ~= 0 then set(x,y,z+i, a) end
- end
- end
- end
- end
- file:close()
- return true
- else
- --print("[ERROR] File "..filename.." not found.")
- return false
- end
- end
- -- ============================================= G R A P H I C S ============================================= --
- -- check screen/graphics card resolution; for comfortable work necessary resolution is >=HOLOW in height and width
- OLDWIDTH, OLDHEIGHT = gpu.getResolution()
- WIDTH, HEIGHT = gpu.maxResolution()
- if HEIGHT < HOLOW+2 then
- error("[ERROR] Your screen/graphics card does not support the required resolution.")
- else
- WIDTH = HOLOW*2+40
- HEIGHT = HOLOW+2
- gpu.setResolution(WIDTH, HEIGHT)
- end
- gpu.setForeground(forecolor)
- gpu.setBackground(backcolor)
- -- draw a line
- local strLine = "+"
- for i=1, WIDTH do
- strLine = strLine..'-'
- end
- function line(x1, x2, y)
- gpu.set(x1,y,string.sub(strLine, 1, x2-x1))
- gpu.set(x2,y,'+')
- end
- -- draw a frame
- function frame(x1, y1, x2, y2, caption)
- line(x1, x2, y1)
- line(x1, x2, y2)
- if caption ~= nil then
- gpu.set(x1+(x2-x1)/2-unicode.len(caption)/2, y1, caption)
- end
- end
- -- draw grid
- local strGrid = ""
- for i=1, HOLOW/2 do
- strGrid = strGrid.."██ "
- end
- function drawGrid(x, y)
- gpu.fill(0, y, MENUX, HOLOW, ' ')
- gpu.setForeground(graycolor)
- for i=0, HOLOW-1 do
- if view>0 and i==HOLOH then
- gpu.setForeground(forecolor)
- line(1, MENUX-1, y+HOLOH)
- break
- end
- gpu.set(x+(i%2)*2, y+i, strGrid)
- end
- if view == 0 then gpu.setForeground(forecolor) end
- end
- -- draw colored rectangle
- function drawRect(x, y, color)
- gpu.set(x, y, "╓──────╖")
- gpu.set(x, y+1, "║ ║")
- gpu.set(x, y+2, "╙──────╜")
- gpu.setForeground(color)
- gpu.set(x+2, y+1, "████")
- gpu.setForeground(forecolor)
- end
- MENUX = HOLOW*2+5
- BUTTONW = 12
- -- draw "brush selector" menu
- function drawColorSelector()
- frame(MENUX, 3, WIDTH-2, 16, "[ Palette ]")
- for i=0, 3 do
- drawRect(MENUX+1+i*8, 5, hexcolortable[i])
- end
- gpu.set(MENUX+1, 10, "R:")
- gpu.set(MENUX+1, 11, "G:")
- gpu.set(MENUX+1, 12, "B:")
- end
- function drawColorCursor(force)
- if brush.color*8 ~= brush.x then brush.x = brush.color*8 end
- if force or brush.gx ~= brush.x then
- gpu.set(MENUX+1+brush.gx, 8, " ")
- if brush.gx < brush.x then brush.gx = brush.gx + 1 end
- if brush.gx > brush.x then brush.gx = brush.gx - 1 end
- gpu.set(MENUX+1+brush.gx, 8, " -^--^- ")
- end
- end
- function drawLayerSelector()
- frame(MENUX, 16, WIDTH-2, 28, "[ Layer ]")
- gpu.set(MENUX+13, 18, "Hologram layer:")
- gpu.set(MENUX+1, 23, "'Ghost' layer:")
- end
- function drawButtonsPanel()
- frame(MENUX, 28, WIDTH-2, 36, "[ Manage ]")
- end
- function mainScreen()
- term.clear()
- frame(1,1, WIDTH, HEIGHT, "{ Hologram Editor }")
- -- "canvas"
- drawLayer()
- drawColorSelector()
- drawColorCursor(true)
- drawLayerSelector()
- drawButtonsPanel()
- buttonsDraw()
- textboxesDraw()
- -- "about" info
- gpu.setForeground(infocolor)
- gpu.setBackground(graycolor)
- gpu.set(MENUX+3, HEIGHT-11, " Hologram Editor v0.60 Beta ")
- gpu.setForeground(forecolor)
- gpu.set(MENUX+3, HEIGHT-10, " * * * ")
- gpu.set(MENUX+3, HEIGHT-9, " Programmers: ")
- gpu.set(MENUX+3, HEIGHT-8, " NEO, Totoro ")
- gpu.set(MENUX+3, HEIGHT-7, " * * * ")
- gpu.set(MENUX+3, HEIGHT-6, " Contact: ")
- gpu.set(MENUX+3, HEIGHT-5, " computercraft.ru/forum ")
- gpu.setBackground(backcolor)
- -- exit program
- gpu.set(MENUX, HEIGHT-2, "Quit: 'Q' or ")
- end
- -- =============================================== L A Y E R S =============================================== --
- GRIDX = 3
- GRIDY = 2
- function drawLayer()
- drawGrid(GRIDX, GRIDY)
- -- top view (y)
- if view == 0 then
- for x=1, HOLOW do
- for z=1, HOLOW do
- gn = get(x, ghost_layer, z)
- n = get(x, layer, z)
- if n == 0 and gn ~= 0 then
- gpu.setForeground(darkhexcolors[gn])
- gpu.set((GRIDX-2) + x*2, (GRIDY-1) + z, "░░")
- end
- if n ~= 0 then
- gpu.setForeground(hexcolortable[n])
- gpu.set((GRIDX-2) + x*2, (GRIDY-1) + z, "██")
- end
- end
- end
- -- fore view (z)
- elseif view == 1 then
- for x=1, HOLOW do
- for y=1, HOLOH do
- n = get(x, y, layer)
- gn = get(x, y, ghost_layer)
- if n == 0 and gn ~= 0 then
- gpu.setForeground(darkhexcolors[gn])
- gpu.set((GRIDX-2) + x*2, (GRIDY+HOLOH) - y, "░░")
- end
- if n ~= 0 then
- gpu.setForeground(hexcolortable[n])
- gpu.set((GRIDX-2) + x*2, (GRIDY+HOLOH) - y, "██")
- end
- end
- end
- -- side view (x)
- else
- for z=1, HOLOW do
- for y=1, HOLOH do
- gn = get(ghost_layer, y, z)
- n = get(layer, y, z)
- if n == 0 and gn ~= 0 then
- gpu.setForeground(darkhexcolors[gn])
- gpu.set((GRIDX+HOLOW*2) - z*2, (GRIDY+HOLOH) - y, "░░")
- end
- if n ~= 0 then
- gpu.setForeground(hexcolortable[n])
- gpu.set((GRIDX+HOLOW*2) - z*2, (GRIDY+HOLOH) - y, "██")
- end
- end
- end
- end
- gpu.setForeground(forecolor)
- -- for messages
- repaint = false
- end
- function fillLayer()
- for x=1, HOLOW do
- for z=1, HOLOW do
- set(x, layer, z, brush.color)
- end
- end
- drawLayer()
- end
- function clearLayer()
- for x=1, HOLOW do
- if holo[x] ~= nil then holo[x][layer] = nil end
- end
- drawLayer()
- end
- -- ============================================== B U T T O N S ============================================== --
- Button = {}
- Button.__index = Button
- function Button.new(func, x, y, text, color, width)
- self = setmetatable({}, Button)
- self.form = '[ '
- if width == nil then width = 0
- else width = (width - unicode.len(text))-4 end
- for i=1, math.floor(width/2) do
- self.form = self.form.. ' '
- end
- self.form = self.form..text
- for i=1, math.ceil(width/2) do
- self.form = self.form.. ' '
- end
- self.form = self.form..' ]'
- self.func = func
- self.x = x; self.y = y
- self.color = color
- self.visible = true
- return self
- end
- function Button:draw(color)
- if self.visible then
- local color = color or self.color
- gpu.setBackground(color)
- if color > 0x888888 then gpu.setForeground(backcolor) end
- gpu.set(self.x, self.y, self.form)
- gpu.setBackground(backcolor)
- if color > 0x888888 then gpu.setForeground(forecolor) end
- end
- end
- function Button:click(x, y)
- if self.visible then
- if y == self.y then
- if x >= self.x and x < self.x+unicode.len(self.form) then
- self.func()
- self:draw(self.color/2)
- os.sleep(0.1)
- self:draw()
- return true
- end
- end
- end
- return false
- end
- buttons = {}
- function buttonsNew(func, x, y, text, color, width)
- table.insert(buttons, Button.new(func, x, y, text, color, width))
- end
- function buttonsDraw()
- for i=1, #buttons do
- buttons[i]:draw()
- end
- end
- function buttonsClick(x, y)
- for i=1, #buttons do
- buttons[i]:click(x, y)
- end
- end
- -- ================================ B U T T O N S F U N C T I O N A L I T Y ================================ --
- function exit() running = false end
- function nextLayer()
- -- different limits for different views
- local limit = HOLOH
- if view > 0 then limit = HOLOW end
- if layer < limit then
- layer = layer + 1
- tb_layer:setValue(layer)
- tb_layer:draw(true)
- moveGhost()
- drawLayer()
- end
- end
- function prevLayer()
- if layer > 1 then
- layer = layer - 1
- tb_layer:setValue(layer)
- tb_layer:draw(true)
- moveGhost()
- drawLayer()
- end
- end
- function setLayer(value)
- local n = tonumber(value)
- local limit = HOLOH
- if view > 0 then limit = HOLOW end
- if n == nil or n < 1 or n > limit then return false end
- layer = n
- moveGhost()
- drawLayer()
- return true
- end
- function nextGhost()
- local limit = HOLOH
- if view > 0 then limit = HOLOW end
- if ghost_layer_below then
- ghost_layer_below = false
- if ghost_layer < limit then
- ghost_layer = layer + 1
- else ghost_layer = limit end
- drawLayer()
- else
- if ghost_layer < limit then
- ghost_layer = ghost_layer + 1
- drawLayer()
- end
- end
- end
- function prevGhost()
- if not ghost_layer_below then
- ghost_layer_below = true
- if layer > 1 then
- ghost_layer = layer - 1
- else ghost_layer = 1 end
- drawLayer()
- else
- if ghost_layer > 1 then
- ghost_layer = ghost_layer - 1
- drawLayer()
- end
- end
- end
- function setGhostLayer(value)
- local n = tonumber(value)
- local limit = HOLOH
- if view > 0 then limit = HOLOW end
- if n == nil or n < 1 or n > limit then return false end
- ghost_layer = n
- drawLayer()
- return true
- end
- function moveGhost()
- if ghost_layer_below then
- if layer > 1 then ghost_layer = layer - 1
- else ghost_layer = 1 end
- else
- local limit = HOLOH
- if view > 0 then limit = HOLOW end
- if layer < limit then ghost_layer = layer + 1
- else ghost_layer = limit end
- end
- end
- function setFilename(str)
- if str ~= nil and str ~= '' and unicode.len(str)<30 then
- return true
- else
- return false
- end
- end
- function setHexColor(n, r, g, b)
- local hexcolor = rgb2hex(r,g,b)
- hexcolortable[n] = hexcolor
- darkhexcolors[n] = bit32.rshift(bit32.band(hexcolor, 0xfefefe), 1)
- end
- function rgb2hex(r,g,b)
- return r*65536+g*256+b
- end
- function changeRed(value) return changeColor(1, value) end
- function changeGreen(value) return changeColor(2, value) end
- function changeBlue(value) return changeColor(3, value) end
- function changeColor(rgb, value)
- if value == nil then return false end
- n = tonumber(value)
- if n == nil or n < 0 or n > 255 then return false end
- -- save data in table
- colortable[brush.color][rgb] = n
- setHexColor(brush.color, colortable[brush.color][1],
- colortable[brush.color][2],
- colortable[brush.color][3])
- -- refresh colors menu
- for i=0, 3 do
- drawRect(MENUX+1+i*8, 5, hexcolortable[i])
- end
- return true
- end
- function moveSelector(num)
- brush.color = num
- tb_red:setValue(colortable[num][1]); tb_red:draw(true)
- tb_green:setValue(colortable[num][2]); tb_green:draw(true)
- tb_blue:setValue(colortable[num][3]); tb_blue:draw(true)
- end
- function setTopView()
- view = 0
- -- top view has less layers
- if layer > HOLOH then layer = HOLOH end
- drawLayer()
- end
- function setFrontView() view = 1; drawLayer() end
- function setSideView() view = 2; drawLayer() end
- function drawHologram()
- -- check hologram projector availability
- h = trytofind('hologram')
- if h ~= nil then
- local depth = h.maxDepth()
- -- clear projector
- h.clear()
- -- send palette
- if depth == 2 then
- for i=1, 3 do
- h.setPaletteColor(i, hexcolortable[i])
- end
- else
- h.setPaletteColor(1, hexcolortable[1])
- end
- -- send voxel array
- for x=1, HOLOW do
- for y=1, HOLOH do
- for z=1, HOLOW do
- n = get(x,y,z)
- if n ~= 0 then
- if depth == 2 then
- h.set(x,y,z,n)
- else
- h.set(x,y,z,1)
- end
- end
- end
- end
- end
- end
- end
- function newHologram()
- holo = {}
- drawLayer()
- end
- function saveHologram()
- local filename = tb_file:getValue()
- if filename ~= FILE_REQUEST then
- -- warning
- showMessage('Saving... Please wait.', '[ Attention ]', goldcolor)
- -- add brand extension =)
- if string.sub(filename, -3) ~= '.3d' then
- filename = filename..'.3d'
- end
- -- save
- save(filename)
- -- done info
- showMessage(' The file is saved! ', '[ Done ]', goldcolor)
- repaint = true
- end
- end
- function loadHologram()
- local filename = tb_file:getValue()
- if filename ~= FILE_REQUEST then
- -- warning
- showMessage('Loading...', '[ Attention ]', goldcolor)
- -- add brand extension =)
- if string.sub(filename, -3) ~= '.3d' then
- filename = filename..'.3d'
- end
- -- load
- load(filename)
- -- refresh RGB textboxes
- tb_red:setValue(colortable[brush.color][1]); tb_red:draw(true)
- tb_green:setValue(colortable[brush.color][2]); tb_green:draw(true)
- tb_blue:setValue(colortable[brush.color][3]); tb_blue:draw(true)
- -- refresh colors menu
- for i=0, 3 do
- drawRect(MENUX+1+i*8, 5, hexcolortable[i])
- end
- -- refresh layer
- drawLayer()
- end
- end
- -- ============================================ T E X T B O X E S ============================================ --
- Textbox = {}
- Textbox.__index = Textbox
- function Textbox.new(func, x, y, value, width)
- self = setmetatable({}, Textbox)
- self.form = '>'
- if width == nil then width = 10 end
- for i=1, width-1 do
- self.form = self.form..' '
- end
- self.func = func
- self.value = tostring(value)
- self.x = x; self.y = y
- self.visible = true
- return self
- end
- function Textbox:draw(content)
- if self.visible then
- if content then gpu.setBackground(graycolor) end
- gpu.set(self.x, self.y, self.form)
- if content then gpu.set(self.x+2, self.y, self.value) end
- gpu.setBackground(backcolor)
- end
- end
- function Textbox:click(x, y)
- if self.visible then
- if y == self.y then
- if x >= self.x and x < self.x+unicode.len(self.form) then
- self:draw(false)
- term.setCursor(self.x+2, self.y)
- value = string.sub(term.read({self.value}), 1, -2)
- if self.func(value) then
- self.value = value
- end
- self:draw(true)
- return true
- end
- end
- end
- return false
- end
- function Textbox:setValue(value)
- self.value = tostring(value)
- end
- function Textbox:getValue()
- return self.value
- end
- textboxes = {}
- function textboxesNew(func, x, y, value, width)
- textbox = Textbox.new(func, x, y, value, width)
- table.insert(textboxes, textbox)
- return textbox
- end
- function textboxesDraw()
- for i=1, #textboxes do
- textboxes[i]:draw(true)
- end
- end
- function textboxesClick(x, y)
- for i=1, #textboxes do
- textboxes[i]:click(x, y)
- end
- end
- -- ============================================= M E S S A G E S ============================================= --
- repaint = false
- function showMessage(text, caption, color)
- local x = WIDTH/2 - unicode.len(text)/2 - 4
- local y = HEIGHT/2 - 2
- gpu.fill(x, y, unicode.len(text)+8, 5, ' ')
- frame(x, y, x+unicode.len(text)+7, y+4, caption)
- gpu.setForeground(color)
- gpu.set(x+4,y+2, text)
- gpu.setForeground(forecolor)
- end
- -- =========================================== M A I N C Y C L E =========================================== --
- -- init
- colortable = {{255, 0, 0}, {0, 255, 0}, {0, 102, 255}}
- colortable[0] = {0, 0, 0}
- hexcolortable = {}
- darkhexcolors = {}
- for i=0,3 do setHexColor(i, colortable[i][1], colortable[i][2], colortable[i][3]) end
- brush = {color = 1, x = 8, gx = 8}
- ghost_layer = 1
- ghost_layer_below = true
- layer = 1
- view = 0
- running = true
- buttonsNew(exit, WIDTH-BUTTONW-2, HEIGHT-2, 'Exit', errorcolor, BUTTONW)
- buttonsNew(drawLayer, MENUX+10, 14, 'Refresh', goldcolor, BUTTONW)
- buttonsNew(prevLayer, MENUX+1, 19, '-', infocolor, 5)
- buttonsNew(nextLayer, MENUX+7, 19, '+', infocolor, 5)
- buttonsNew(setTopView, MENUX+1, 21, 'Top', infocolor, 10)
- buttonsNew(setFrontView, MENUX+12, 21, 'Front', infocolor, 10)
- buttonsNew(setSideView, MENUX+24, 21, 'Side', infocolor, 9)
- buttonsNew(prevGhost, MENUX+1, 24, 'Below', infocolor, 5)
- buttonsNew(nextGhost, MENUX+11, 24, 'Above', infocolor, 5)
- buttonsNew(clearLayer, MENUX+1, 26, 'Clear', infocolor, BUTTONW)
- buttonsNew(fillLayer, MENUX+2+BUTTONW, 26, 'Fill', infocolor, BUTTONW)
- buttonsNew(drawHologram, MENUX+8, 30, 'To Projector', goldcolor, 16)
- buttonsNew(saveHologram, MENUX+1, 33, 'Save', helpcolor, BUTTONW)
- buttonsNew(loadHologram, MENUX+8+BUTTONW, 33, 'Load', infocolor, BUTTONW)
- buttonsNew(newHologram, MENUX+1, 35, 'New file', infocolor, BUTTONW)
- tb_red = textboxesNew(changeRed, MENUX+5, 10, '255', WIDTH-MENUX-7)
- tb_green = textboxesNew(changeGreen, MENUX+5, 11, '0', WIDTH-MENUX-7)
- tb_blue = textboxesNew(changeBlue, MENUX+5, 12, '0', WIDTH-MENUX-7)
- tb_layer = textboxesNew(setLayer, MENUX+13, 19, '1', WIDTH-MENUX-15)
- tb_ghostlayer = textboxesNew(setGhostLayer, MENUX+21, 24, ' ', WIDTH-MENUX-23)
- FILE_REQUEST = 'Enter file name here'
- tb_file = textboxesNew(setFilename, MENUX+1, 32, FILE_REQUEST, WIDTH-MENUX-3)
- mainScreen()
- while running do
- if brush.x ~= brush.gx then name, add, x, y, b = event.pull(0.02)
- else name, add, x, y, b = event.pull(1.0) end
- if name == 'key_down' then
- -- if pressed key is 'Q' - quit
- if y == 16 then break
- elseif y == 41 then
- moveSelector(0)
- elseif y>=2 and y<=4 then
- moveSelector(y-1)
- elseif y == 211 then
- clearLayer()
- end
- elseif name == 'touch' then
- -- checking GUI
- buttonsClick(x, y)
- textboxesClick(x, y)
- -- select color
- if x>MENUX+1 and x<MENUX+37 then
- if y>4 and y<8 then
- moveSelector(math.floor((x-MENUX-1)/8))
- end
- end
- end
- if name == 'touch' or name == 'drag' then
- -- "paint"
- local limit = HOLOW
- if view > 0 then limit = HOLOH end
- if x >= GRIDX and x < GRIDX+HOLOW*2 then
- if y >= GRIDY and y < GRIDY+limit then
- -- refresh, after message box
- if repaint then drawLayer() end
- -- mouse click
- if view == 0 then
- dx = math.floor((x-GRIDX)/2)+1; gx = dx
- dy = layer; gy = ghost_layer
- dz = y-GRIDY+1; gz = dz
- elseif view == 1 then
- dx = math.floor((x-GRIDX)/2)+1; gx = dx
- dy = HOLOH - (y-GRIDY); gy = dy
- dz = layer; gz = ghost_layer
- else
- dx = layer; gx = ghost_layer
- dy = HOLOH - (y-GRIDY); gy = dy
- dz = HOLOW - math.floor((x-GRIDX)/2); gz = dz
- end
- if b == 0 and brush.color ~= 0 then
- set(dx, dy, dz, brush.color)
- gpu.setForeground(hexcolortable[brush.color])
- gpu.set(x-(x-GRIDX)%2, y, "██")
- else
- set(dx, dy, dz, 0)
- gpu.setForeground(darkhexcolors[get(gx,gy,gz)])
- gpu.set(x-(x-GRIDX)%2, y, "░░")
- end
- gpu.setForeground(forecolor)
- end
- end
- end
- drawColorCursor()
- end
- -- finishing
- term.clear()
- gpu.setResolution(OLDWIDTH, OLDHEIGHT)
- gpu.setForeground(0xFFFFFF)
- gpu.setBackground(0x000000)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement