ZNZNCOOP

Hologram Editor

Oct 14th, 2014
1,049
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --         Hologram Editor
  2. -- by NEO, Totoro
  3. -- 10/14/2014, all right reserved =)
  4.  
  5. local unicode = require('unicode')
  6. local event = require('event')
  7. local term = require('term')
  8. local fs = require('filesystem')
  9. local com = require('component')
  10. local gpu = com.gpu
  11.  
  12. --   Константы   --
  13. HOLOH = 32
  14. HOLOW = 48
  15.  
  16. --     Цвета     --
  17. backcolor = 0x000000
  18. forecolor = 0xFFFFFF
  19. infocolor = 0x0066FF
  20. errorcolor = 0xFF0000
  21. helpcolor = 0x006600
  22. graycolor = 0x080808
  23. goldcolor = 0xFFDF00
  24. --      ***      --
  25.  
  26.  
  27. -- загружаем доп. оборудование
  28. function trytofind(name)
  29.   if com.isAvailable(name) then
  30.     return com.getPrimary(name)
  31.   else
  32.     return nil
  33.   end
  34. end
  35.  
  36. local h = trytofind('hologram')
  37.  
  38. -- ========================================= H O L O G R A P H I C S ========================================= --
  39. holo = {}
  40. function set(x, y, z, value)
  41.   if holo[x] == nil then holo[x] = {} end
  42.   if holo[x][y] == nil then holo[x][y] = {} end
  43.   holo[x][y][z] = value
  44. end
  45. function get(x, y, z)
  46.   if holo[x] ~= nil and holo[x][y] ~= nil and holo[x][y][z] ~= nil then
  47.     return holo[x][y][z]
  48.   else
  49.     return 0
  50.   end
  51. end
  52.  
  53. function save(filename)
  54.   -- сохраняем палитру
  55.   file = io.open(filename, 'wb')
  56.   for i=1, 3 do
  57.     for c=1, 3 do
  58.       file:write(string.char(colortable[i][c]))
  59.     end
  60.   end
  61.   -- сохраняем массив
  62.   for x=1, HOLOW do
  63.     for y=1, HOLOH do
  64.       for z=1, HOLOW, 4 do
  65.         a = get(x,y,z)
  66.         b = get(x,y,z+1)
  67.         c = get(x,y,z+2)
  68.         d = get(x,y,z+3)
  69.         byte = d*64 + c*16 + b*4 + a
  70.         file:write(string.char(byte))
  71.       end
  72.     end
  73.   end
  74.   file:close()
  75. end
  76.  
  77. function load(filename)
  78.   if fs.exists(filename) then
  79.     file = io.open(filename, 'rb')
  80.     -- загружаем палитру
  81.     for i=1, 3 do
  82.       for c=1, 3 do
  83.         colortable[i][c] = string.byte(file:read(1))
  84.       end
  85.       hexcolortable[i] =
  86.         rgb2hex(colortable[i][1],
  87.                 colortable[i][2],
  88.                 colortable[i][3])
  89.     end
  90.     -- загружаем массив
  91.     holo = {}
  92.     for x=1, HOLOW do
  93.       for y=1, HOLOH do
  94.         for z=1, HOLOW, 4 do
  95.           byte = string.byte(file:read(1))
  96.           for i=0, 3 do
  97.             a = byte % 4
  98.             byte = math.floor(byte / 4)
  99.             if a ~= 0 then set(x,y,z+i, a) end
  100.           end
  101.         end
  102.       end
  103.     end
  104.     file:close()
  105.     return true
  106.   else
  107.     --print("[ОШИБКА] Файл "..filename.." не найден.")
  108.     return false
  109.   end
  110. end
  111.  
  112.  
  113. -- ============================================= G R A P H I C S ============================================= --
  114. -- проверка разрешения экрана, для комфортной работы необходимо разрешение > HOLOW по высоте и ширине
  115. OLDWIDTH, OLDHEIGHT = gpu.getResolution()
  116. WIDTH, HEIGHT = gpu.maxResolution()
  117. if HEIGHT < HOLOW+2 then
  118.   error("[ОШИБКА] Ваш монитор/видеокарта не поддерживает требуемое разрешение.")
  119. else
  120.   WIDTH = HOLOW*2+40
  121.   HEIGHT = HOLOW+2
  122.   gpu.setResolution(WIDTH, HEIGHT)
  123. end
  124. gpu.setForeground(forecolor)
  125. gpu.setBackground(backcolor)
  126.  
  127. -- рисуем линию
  128. local strLine = "+"
  129. for i=1, WIDTH do
  130.   strLine = strLine..'-'
  131. end
  132. function line(x1, x2, y)
  133.   gpu.set(x1,y,string.sub(strLine, 1, x2-x1))
  134.   gpu.set(x2,y,'+')
  135. end
  136.  
  137. -- рисуем фрейм
  138. function frame(x1, y1, x2, y2, caption)
  139.   line(x1, x2, y1)
  140.   line(x1, x2, y2)
  141.  
  142.   if caption ~= nil then
  143.     gpu.set(x1+(x2-x1)/2-unicode.len(caption)/2, y1, caption)
  144.   end
  145. end
  146.  
  147. -- рисуем сетку
  148. local strGrid = ""
  149. for i=1, HOLOW/2 do
  150.   strGrid = strGrid.."██  "
  151. end
  152. function drawGrid(x, y)
  153.   gpu.fill(x, y, HOLOW, HOLOW, ' ')
  154.   gpu.setForeground(graycolor)
  155.   for i=0, HOLOW-1 do
  156.     gpu.set(x+(i%2)*2, y+i, strGrid)
  157.   end
  158.   gpu.setForeground(forecolor)
  159. end
  160.  
  161. -- рисуем цветной прямоугольник
  162. function drawRect(x, y, color)
  163.   gpu.set(x, y,   "╓──────╖")
  164.   gpu.set(x, y+1, "║      ║")
  165.   gpu.set(x, y+2, "╙──────╜")
  166.   gpu.setForeground(color)
  167.   gpu.set(x+2, y+1, "████")
  168.   gpu.setForeground(forecolor)
  169. end
  170.  
  171. MENUX = HOLOW*2+5
  172. BUTTONW = 12
  173.  
  174. -- рисуем меню выбора "кисти"
  175. function drawColorSelector()
  176.   frame(MENUX, 3, WIDTH-2, 16, "[ Палитра ]")
  177.   for i=0, 3 do
  178.     drawRect(MENUX+1+i*8, 5, hexcolortable[i])
  179.   end
  180.   gpu.set(MENUX+1, 10, "R:")
  181.   gpu.set(MENUX+1, 11, "G:")
  182.   gpu.set(MENUX+1, 12, "B:")
  183. end
  184. function drawColorCursor(force)
  185.   if brush.color*8 ~= brush.x then brush.x = brush.color*8 end
  186.   if force or brush.gx ~= brush.x then
  187.     gpu.set(MENUX+1+brush.gx, 8, "        ")
  188.     if brush.gx < brush.x then brush.gx = brush.gx + 1 end
  189.     if brush.gx > brush.x then brush.gx = brush.gx - 1 end
  190.     gpu.set(MENUX+1+brush.gx, 8, " -^--^- ")
  191.   end
  192. end
  193. function drawLayerSelector()
  194.   frame(MENUX, 16, WIDTH-2, 23, "[ Слой ]")
  195.   gpu.set(MENUX+13, 18, "Уровень голограммы:")
  196. end
  197. function drawButtonsPanel()
  198.   frame(MENUX, 23, WIDTH-2, 34, "[ Управление ]")
  199. end
  200.  
  201. function mainScreen()
  202.   term.clear()
  203.   frame(1,1, WIDTH, HEIGHT, "{ Hologram Editor }")
  204.   -- "холст"
  205.   drawLayer()
  206.   drawColorSelector()
  207.   drawColorCursor(true)
  208.   drawLayerSelector()
  209.   drawButtonsPanel()
  210.   buttonsDraw()
  211.   textboxesDraw()
  212.   -- "about" - коротко о создателях
  213.   gpu.setForeground(infocolor)
  214.   gpu.setBackground(graycolor)
  215.   gpu.set(MENUX+3, HEIGHT-13, " Hologram Editor v0.55 Alpha ")
  216.   gpu.setForeground(forecolor)
  217.   gpu.set(MENUX+3, HEIGHT-12, "            * * *            ")
  218.   gpu.set(MENUX+3, HEIGHT-11, " Программисты:               ")
  219.   gpu.set(MENUX+3, HEIGHT-10, "         NEO, Totoro         ")
  220.   gpu.set(MENUX+3, HEIGHT-9,  "            * * *            ")
  221.   gpu.set(MENUX+3, HEIGHT-8,  " Контакт:                    ")
  222.   gpu.set(MENUX+3, HEIGHT-7,  "   computercraft.ru/forum    ")
  223.   gpu.setBackground(backcolor)
  224.   -- выход
  225.   gpu.set(MENUX, HEIGHT-2, "Выход: 'Q' или ")
  226. end
  227.  
  228.  
  229. -- =============================================== L A Y E R S =============================================== --
  230. GRIDX = 3
  231. GRIDY = 2
  232. function drawLayer()
  233.   drawGrid(GRIDX, GRIDY)
  234.   for x=1, HOLOW do
  235.     for z=1, HOLOW do
  236.       n = get(x, layer, z)
  237.       if n ~= 0 then
  238.         gpu.setForeground(hexcolortable[n])
  239.         gpu.set((GRIDX-2) + x*2, (GRIDY-1) + z, "██")
  240.       end
  241.     end
  242.   end
  243.   gpu.setForeground(forecolor)
  244. end
  245. function fillLayer()
  246.   for x=1, HOLOW do
  247.     for z=1, HOLOW do
  248.       set(x, layer, z, brush.color)
  249.     end
  250.   end
  251.   drawLayer()
  252. end
  253. function clearLayer()
  254.   for x=1, HOLOW do
  255.     if holo[x] ~= nil then holo[x][layer] = nil end
  256.   end
  257.   drawLayer()
  258. end
  259.  
  260.  
  261. -- ============================================== B U T T O N S ============================================== --
  262. Button = {}
  263. Button.__index = Button
  264. function Button.new(func, x, y, text, color, width)
  265.   self = setmetatable({}, Button)
  266.  
  267.   self.form = '[ '
  268.   if width == nil then width = 0
  269.     else width = (width - unicode.len(text))-4 end
  270.   for i=1, math.floor(width/2) do
  271.     self.form = self.form.. ' '
  272.   end
  273.   self.form = self.form..text
  274.   for i=1, math.ceil(width/2) do
  275.     self.form = self.form.. ' '
  276.   end
  277.   self.form = self.form..' ]'
  278.  
  279.   self.func = func
  280.  
  281.   self.x = x; self.y = y
  282.   self.color = color
  283.   self.visible = true
  284.  
  285.   return self
  286. end
  287. function Button:draw(color)
  288.   if self.visible then
  289.     local color = color or self.color
  290.     gpu.setBackground(color)
  291.     if color > 0x888888 then gpu.setForeground(backcolor) end
  292.     gpu.set(self.x, self.y, self.form)
  293.     gpu.setBackground(backcolor)
  294.     if color > 0x888888 then gpu.setForeground(forecolor) end
  295.   end
  296. end
  297. function Button:click(x, y)
  298.   if self.visible then
  299.     if y == self.y then
  300.       if x >= self.x and x < self.x+unicode.len(self.form) then
  301.         self.func()
  302.         self:draw(self.color/2)
  303.         os.sleep(0.1)
  304.         self:draw()
  305.         return true
  306.       end
  307.     end
  308.   end
  309.   return false
  310. end
  311. buttons = {}
  312. function buttonsNew(func, x, y, text, color, width)
  313.   table.insert(buttons, Button.new(func, x, y, text, color, width))
  314. end
  315. function buttonsDraw()
  316.   for i=1, #buttons do
  317.     buttons[i]:draw()
  318.   end
  319. end
  320. function buttonsClick(x, y)
  321.   for i=1, #buttons do
  322.     buttons[i]:click(x, y)
  323.   end
  324. end
  325.  
  326. -- ================================ B U T T O N S   F U N C T I O N A L I T Y ================================ --
  327. function exit() running = false end
  328. function nextLayer()
  329.   if layer < HOLOH then
  330.     layer = layer + 1
  331.     tb_layer:setValue(layer)
  332.     tb_layer:draw(true)
  333.     drawLayer()
  334.   end
  335. end
  336. function prevLayer()
  337.   if layer > 1 then
  338.     layer = layer - 1
  339.     tb_layer:setValue(layer)
  340.     tb_layer:draw(true)
  341.     drawLayer()
  342.   end
  343. end
  344. function setLayer(value)
  345.   n = tonumber(value)
  346.   if n == nil or n < 1 or n > HOLOH then return false end
  347.   layer = n
  348.   drawLayer()
  349.   return true
  350. end
  351.  
  352. function setFilename(str)
  353.   if str ~= nil and str ~= '' and unicode.len(str)<30 then
  354.     return true
  355.   else
  356.     return false
  357.   end
  358. end
  359.  
  360. function rgb2hex(r,g,b)
  361.   return r*65536+g*256+b
  362. end
  363. function changeRed(value) return changeColor(1, value) end
  364. function changeGreen(value) return changeColor(2, value) end
  365. function changeBlue(value) return changeColor(3, value) end
  366. function changeColor(rgb, value)
  367.   if value == nil then return false end
  368.   n = tonumber(value)
  369.   if n == nil or n < 0 or n > 255 then return false end
  370.   -- сохраняем данные в таблицу
  371.   colortable[brush.color][rgb] = n
  372.   hexcolortable[brush.color] =
  373.       rgb2hex(colortable[brush.color][1],
  374.               colortable[brush.color][2],
  375.               colortable[brush.color][3])
  376.   -- обновляем цвета на панельке
  377.   for i=0, 3 do
  378.     drawRect(MENUX+1+i*8, 5, hexcolortable[i])
  379.   end
  380.   return true
  381. end
  382.  
  383. function drawHologram()
  384.   -- проверка на наличие проектора
  385.   h = trytofind('hologram')
  386.   if h ~= nil then
  387.     local depth = h.maxDepth()
  388.     -- очищаем
  389.     h.clear()
  390.     -- отправляем палитру
  391.     if depth == 3 then
  392.       for i=1, 3 do
  393.         h.setPaletteColor(i, hexcolortable[i])
  394.       end
  395.     else
  396.       h.setPaletteColor(1, hexcolortable[1])
  397.     end
  398.     -- отправляем массив
  399.     for x=1, HOLOW do
  400.       for y=1, HOLOH do
  401.         for z=1, HOLOW do
  402.           n = get(x,y,z)
  403.           if n ~= 0 then
  404.             if depth == 3 then
  405.               h.set(x,y,z,n)
  406.             else
  407.               h.set(x,y,z,1)
  408.             end
  409.           end
  410.         end
  411.       end      
  412.     end
  413.   end
  414. end
  415.  
  416. function newHologram()
  417.   holo = {}
  418.   drawLayer()
  419. end
  420.  
  421. function saveHologram()
  422.   local filename = tb_file:getValue()
  423.   if filename ~= FILE_REQUEST then
  424.     -- выводим предупреждение
  425.     showMessage('Файл сохраняется...', '[ Внимание ]', goldcolor)
  426.     -- добавляем фирменное расширение =)
  427.     if string.sub(filename, -3) ~= '.3d' then
  428.       filename = filename..'.3d'
  429.     end
  430.     -- сохраняем
  431.     save(filename)
  432.     -- выводим предупреждение
  433.     showMessage('   Файл сохранен!  ', '[ Завершено ]', goldcolor)
  434.     repaint = true
  435.   end
  436. end
  437.  
  438. function loadHologram()
  439.   local filename = tb_file:getValue()
  440.   if filename ~= FILE_REQUEST then
  441.     -- выводим предупреждение
  442.     showMessage('Файл загружается...', '[ Внимание ]', goldcolor)
  443.     -- добавляем фирменное расширение =)
  444.     if string.sub(filename, -3) ~= '.3d' then
  445.       filename = filename..'.3d'
  446.     end
  447.     -- загружаем
  448.     load(filename)
  449.     -- обновляем цвета на панельке
  450.     for i=0, 3 do
  451.       drawRect(MENUX+1+i*8, 5, hexcolortable[i])
  452.     end
  453.     -- обновляем слой
  454.     drawLayer()
  455.   end
  456. end
  457.  
  458. -- ============================================ T E X T B O X E S ============================================ --
  459. Textbox = {}
  460. Textbox.__index = Textbox
  461. function Textbox.new(func, x, y, value, width)
  462.   self = setmetatable({}, Textbox)
  463.  
  464.   self.form = '>'
  465.   if width == nil then width = 10 end
  466.   for i=1, width-1 do
  467.     self.form = self.form..' '
  468.   end
  469.  
  470.   self.func = func
  471.   self.value = tostring(value)
  472.  
  473.   self.x = x; self.y = y
  474.   self.visible = true
  475.  
  476.   return self
  477. end
  478. function Textbox:draw(content)
  479.   if self.visible then
  480.     if content then gpu.setBackground(graycolor) end
  481.     gpu.set(self.x, self.y, self.form)
  482.     if content then gpu.set(self.x+2, self.y, self.value) end
  483.     gpu.setBackground(backcolor)
  484.   end
  485. end
  486. function Textbox:click(x, y)
  487.   if self.visible then
  488.     if y == self.y then
  489.       if x >= self.x and x < self.x+unicode.len(self.form) then
  490.         self:draw(false)
  491.         term.setCursor(self.x+2, self.y)
  492.         value = string.sub(term.read({self.value}), 1, -2)
  493.         if self.func(value) then
  494.           self.value = value
  495.         end
  496.         self:draw(true)
  497.         return true
  498.       end
  499.     end
  500.   end
  501.   return false
  502. end
  503. function Textbox:setValue(value)
  504.   self.value = tostring(value)
  505. end
  506. function Textbox:getValue()
  507.   return self.value
  508. end
  509. textboxes = {}
  510. function textboxesNew(func, x, y, value, width)
  511.   textbox = Textbox.new(func, x, y, value, width)
  512.   table.insert(textboxes, textbox)
  513.   return textbox
  514. end
  515. function textboxesDraw()
  516.   for i=1, #textboxes do
  517.     textboxes[i]:draw(true)
  518.   end
  519. end
  520. function textboxesClick(x, y)
  521.   for i=1, #textboxes do
  522.     textboxes[i]:click(x, y)
  523.   end
  524. end
  525.  
  526.  
  527. -- ============================================= M E S S A G E S ============================================= --
  528. repaint = false
  529. function showMessage(text, caption, color)
  530.   local x = WIDTH/2 - unicode.len(text)/2 - 4
  531.   local y = HEIGHT/2 - 2
  532.   gpu.fill(x, y, unicode.len(text)+8, 5, ' ')
  533.   frame(x, y, x+unicode.len(text)+7, y+4, caption)
  534.   gpu.setForeground(color)
  535.   gpu.set(x+4,y+2, text)
  536.   gpu.setForeground(forecolor)
  537. end
  538.  
  539.  
  540. -- =========================================== M A I N   C Y C L E =========================================== --
  541. -- инициализация
  542. hexcolortable = {0xFF0000, 0x00FF00, 0x0066FF}
  543. hexcolortable[0] = 0x000000
  544. colortable = {{255, 0, 0}, {0, 255, 0}, {0, 102, 255}}
  545. colortable[0] = {0, 0, 0}
  546. brush = {color = 1, x = 8, gx = 8}
  547. layer = 1
  548. running = true
  549.  
  550. buttonsNew(exit, WIDTH-BUTTONW-2, HEIGHT-2, 'Выход', errorcolor, BUTTONW)
  551. buttonsNew(drawLayer, MENUX+1, 14, 'Обновить', goldcolor, BUTTONW)
  552. buttonsNew(prevLayer, MENUX+1, 19, '-', infocolor, 5)
  553. buttonsNew(nextLayer, MENUX+7, 19, '+', infocolor, 5)
  554. buttonsNew(clearLayer, MENUX+1, 21, 'Очистить', infocolor, BUTTONW)
  555. buttonsNew(fillLayer, MENUX+2+BUTTONW, 21, 'Залить', infocolor, BUTTONW)
  556. buttonsNew(drawHologram, MENUX+8, 25, 'На проектор', goldcolor, 16)
  557.  
  558. buttonsNew(saveHologram, MENUX+1, 28, 'Сохранить', helpcolor, BUTTONW)
  559. buttonsNew(loadHologram, MENUX+8+BUTTONW, 28, 'Загрузить', infocolor, BUTTONW)
  560. buttonsNew(newHologram, MENUX+1, 30, 'Новый файл', infocolor, BUTTONW)
  561.  
  562. tb_red = textboxesNew(changeRed, MENUX+5, 10, '255', WIDTH-MENUX-7)
  563. tb_green = textboxesNew(changeGreen, MENUX+5, 11, '0', WIDTH-MENUX-7)
  564. tb_blue = textboxesNew(changeBlue, MENUX+5, 12, '0', WIDTH-MENUX-7)
  565. tb_layer = textboxesNew(setLayer, MENUX+13, 19, '1', WIDTH-MENUX-15)
  566. FILE_REQUEST = 'Введите сюда имя файла'
  567. tb_file = textboxesNew(setFilename, MENUX+1, 27, FILE_REQUEST, WIDTH-MENUX-3)
  568. mainScreen()
  569.  
  570. while running do
  571.   if brush.x ~= brush.gx then name, add, x, y, b = event.pull(0.02)
  572.   else name, add, x, y, b = event.pull(1.0) end
  573.  
  574.   if name == 'key_down' then
  575.     -- если нажата 'Q' - выходим
  576.     if y == 16 then break end
  577.   elseif name == 'touch' then
  578.     -- проверка GUI
  579.     buttonsClick(x, y)
  580.     textboxesClick(x, y)
  581.     -- выбор цвета
  582.     if x>MENUX+1 and x<MENUX+37 then
  583.       if y>4 and y<8 then
  584.         brush.color = math.floor((x-MENUX-1)/8)
  585.         tb_red:setValue(colortable[brush.color][1]); tb_red:draw(true)
  586.         tb_green:setValue(colortable[brush.color][2]); tb_green:draw(true)
  587.         tb_blue:setValue(colortable[brush.color][3]); tb_blue:draw(true)
  588.       end
  589.     end
  590.   end
  591.   if name == 'touch' or name == 'drag' then
  592.     -- "рисование"
  593.     if x>=GRIDX and x<GRIDX+HOLOW*2 then
  594.       if y>=GRIDY and y<GRIDY+HOLOW then
  595.         -- перерисуем, если на экране был мессейдж
  596.         if repaint then drawLayer(); repaint = false end
  597.         -- рассчет клика
  598.         dx = math.floor((x-GRIDX)/2)+1
  599.         dy = y-GRIDY+1
  600.         if b == 0 then
  601.           set(dx, layer, dy, brush.color)
  602.           gpu.setForeground(hexcolortable[brush.color])
  603.         else
  604.           set(dx, layer, dy, 0)
  605.           gpu.setForeground(hexcolortable[0])
  606.         end
  607.         gpu.set((GRIDX-2) + dx*2, (GRIDY-1) + dy, "██")
  608.         gpu.setForeground(forecolor)
  609.       end
  610.     end
  611.   end
  612.  
  613.   drawColorCursor()
  614. end
  615.  
  616. -- завершение
  617. term.clear()
  618. gpu.setResolution(OLDWIDTH, OLDHEIGHT)
  619. gpu.setForeground(0xFFFFFF)
  620. gpu.setBackground(0x000000)
RAW Paste Data