From 6dfab31bc7c2013f931cbbe611115966f1727782 Mon Sep 17 00:00:00 2001 From: xYaroslavGTx Date: Sun, 11 Jun 2017 22:28:33 +0300 Subject: [PATCH] Create editor.lua --- xYaroslavGTx/hol-editor/editor.lua | 777 +++++++++++++++++++++++++++++ 1 file changed, 777 insertions(+) create mode 100644 xYaroslavGTx/hol-editor/editor.lua diff --git a/xYaroslavGTx/hol-editor/editor.lua b/xYaroslavGTx/hol-editor/editor.lua new file mode 100644 index 0000000..d176986 --- /dev/null +++ b/xYaroslavGTx/hol-editor/editor.lua @@ -0,0 +1,777 @@ +local unicode = require('unicode') +local event = require('event') +local term = require('term') +local fs = require('filesystem') +local com = require('component') +local gpu = com.gpu + +-- Константы -- +HOLOH = 32 +HOLOW = 48 + +-- Цвета -- +backcolor = 0x000000 +forecolor = 0xFFFFFF +infocolor = 0x0066FF +errorcolor = 0xFF0000 +helpcolor = 0x006600 +graycolor = 0x080808 +goldcolor = 0xFFDF00 +-- *** -- + + +-- загружаем доп. оборудование +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) + -- сохраняем палитру + file = io.open(filename, 'wb') + for i=1, 3 do + for c=1, 3 do + file:write(string.char(colortable[i][c])) + end + end + -- сохраняем массив + 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') + -- загружаем палитру + 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 + -- загружаем массив + 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("[ОШИБКА] Файл "..filename.." не найден.") + return false + end +end + + +-- ============================================= G R A P H I C S ============================================= -- +-- проверка разрешения экрана, для комфортной работы необходимо разрешение > HOLOW по высоте и ширине +OLDWIDTH, OLDHEIGHT = gpu.getResolution() +WIDTH, HEIGHT = gpu.maxResolution() +if HEIGHT < HOLOW+2 then + error("[ОШИБКА] Ваш монитор/видеокарта не поддерживает требуемое разрешение.") +else + WIDTH = HOLOW*2+40 + HEIGHT = HOLOW+2 + gpu.setResolution(WIDTH, HEIGHT) +end +gpu.setForeground(forecolor) +gpu.setBackground(backcolor) + +-- рисуем линию +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 + +-- рисуем фрейм +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 + +-- рисуем сетку +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 + +-- рисуем цветной прямоугольник +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 + +-- рисуем меню выбора "кисти" +function drawColorSelector() + frame(MENUX, 3, WIDTH-2, 16, "[ Палитра ]") + 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, "[ Слой ]") + gpu.set(MENUX+13, 18, "Уровень голограммы:") + gpu.set(MENUX+1, 23, "Направляющий уровень:") +end +function drawButtonsPanel() + frame(MENUX, 28, WIDTH-2, 36, "[ Управление ]") +end + +function mainScreen() + term.clear() + frame(1,1, WIDTH, HEIGHT, "{ Hologram Editor }") + -- "холст" + drawLayer() + drawColorSelector() + drawColorCursor(true) + drawLayerSelector() + drawButtonsPanel() + buttonsDraw() + textboxesDraw() + -- "about" - коротко о создателях + 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, " Программисты: ") + gpu.set(MENUX+3, HEIGHT-8, " NEO, Totoro ") + gpu.set(MENUX+3, HEIGHT-7, " * * * ") + gpu.set(MENUX+3, HEIGHT-6, " Контакт: ") + gpu.set(MENUX+3, HEIGHT-5, " computercraft.ru/forum ") + gpu.setBackground(backcolor) + -- выход + gpu.set(MENUX, HEIGHT-2, "Выход: 'Q' или ") +end + + +-- =============================================== L A Y E R S =============================================== -- +GRIDX = 3 +GRIDY = 2 +function drawLayer() + drawGrid(GRIDX, GRIDY) + -- вид сверху (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 + -- вид спереди (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 + -- вид сбоку (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() + -- ограничения разные для разных видов/проекций + 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 + -- сохраняем данные в таблицу + colortable[brush.color][rgb] = n + setHexColor(brush.color, colortable[brush.color][1], + colortable[brush.color][2], + colortable[brush.color][3]) + -- обновляем цвета на панельке + 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 + -- в виде сверху меньше слоев + if layer > HOLOH then layer = HOLOH end + drawLayer() +end +function setFrontView() view = 1; drawLayer() end +function setSideView() view = 2; drawLayer() end + +function drawHologram() + -- проверка на наличие проектора + h = trytofind('hologram') + if h ~= nil then + local depth = h.maxDepth() + -- очищаем + h.clear() + -- отправляем палитру + if depth == 2 then + for i=1, 3 do + h.setPaletteColor(i, hexcolortable[i]) + end + else + h.setPaletteColor(1, hexcolortable[1]) + end + -- отправляем массив + 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 + -- выводим предупреждение + showMessage('Файл сохраняется...', '[ Внимание ]', goldcolor) + -- добавляем фирменное расширение =) + if string.sub(filename, -3) ~= '.3d' then + filename = filename..'.3d' + end + -- сохраняем + save(filename) + -- выводим предупреждение + showMessage(' Файл сохранен! ', '[ Завершено ]', goldcolor) + repaint = true + end +end + +function loadHologram() + local filename = tb_file:getValue() + if filename ~= FILE_REQUEST then + -- выводим предупреждение + showMessage('Файл загружается...', '[ Внимание ]', goldcolor) + -- добавляем фирменное расширение =) + if string.sub(filename, -3) ~= '.3d' then + filename = filename..'.3d' + end + -- загружаем + load(filename) + -- обновляем значения в текстбоксах + 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) + -- обновляем цвета на панельке + for i=0, 3 do + drawRect(MENUX+1+i*8, 5, hexcolortable[i]) + end + -- обновляем слой + 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 =========================================== -- +-- инициализация +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, 'Выход', errorcolor, BUTTONW) +buttonsNew(drawLayer, MENUX+10, 14, 'Обновить', goldcolor, BUTTONW) +buttonsNew(prevLayer, MENUX+1, 19, '-', infocolor, 5) +buttonsNew(nextLayer, MENUX+7, 19, '+', infocolor, 5) +buttonsNew(setTopView, MENUX+1, 21, 'Сверху', infocolor, 10) +buttonsNew(setFrontView, MENUX+12, 21, 'Спереди', infocolor, 10) +buttonsNew(setSideView, MENUX+24, 21, 'Сбоку', infocolor, 9) + +buttonsNew(prevGhost, MENUX+1, 24, 'Ниже', infocolor, 6) +buttonsNew(nextGhost, MENUX+10, 24, 'Выше', infocolor, 6) + +buttonsNew(clearLayer, MENUX+1, 26, 'Очистить', infocolor, BUTTONW) +buttonsNew(fillLayer, MENUX+2+BUTTONW, 26, 'Залить', infocolor, BUTTONW) + +buttonsNew(drawHologram, MENUX+8, 30, 'На проектор', goldcolor, 16) +buttonsNew(saveHologram, MENUX+1, 33, 'Сохранить', helpcolor, BUTTONW) +buttonsNew(loadHologram, MENUX+8+BUTTONW, 33, 'Загрузить', infocolor, BUTTONW) +buttonsNew(newHologram, MENUX+1, 35, 'Новый файл', 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+19, 24, ' ', WIDTH-MENUX-21) +FILE_REQUEST = 'Введите сюда имя файла' +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 + -- если нажата 'Q' - выходим + 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 + -- проверка GUI + buttonsClick(x, y) + textboxesClick(x, y) + -- выбор цвета + if x>MENUX+1 and x4 and y<8 then + moveSelector(math.floor((x-MENUX-1)/8)) + end + end + end + if name == 'touch' or name == 'drag' then + -- "рисование" + 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 + -- перерисуем, если на экране был мессейдж + if repaint then drawLayer() end + -- рассчет клика + 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 + +-- завершение +term.clear() +gpu.setResolution(OLDWIDTH, OLDHEIGHT) +gpu.setForeground(0xFFFFFF) +gpu.setBackground(0x000000)