Advertisement
serafim7

Hologram Editor v0.70 Beta [OpenComputers]

Jul 26th, 2016
411
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 38.28 KB | None | 0 0
  1. --http://computercraft.ru/topic/259-hologram-editor-opencomputers/
  2.  
  3. --       Hologram Editor v0.70
  4. -- by NEO, Totoro (aka MoonlightOwl)
  5. -- 10/14/2014, all right reserved =)
  6.  
  7. local unicode = require('unicode')
  8. local event = require('event')
  9. local term = require('term')
  10. local fs = require('filesystem')
  11. local com = require('component')
  12. local gpu = com.gpu
  13.  
  14. --     Цвета     --
  15. local color = {
  16.   back = 0x000000,
  17.   fore = 0xFFFFFF,
  18.   info = 0x335555,
  19.   error = 0xFF3333,
  20.   help = 0x336600,
  21.   gold = 0xFFCC33,
  22.   gray = 0x080808,
  23.   lightgray = 0x333333
  24. }
  25.  
  26. --  Локализация  --
  27. local loc = {
  28.   FILE_REQUEST = 'Введите сюда имя файла',
  29.   ERROR_CAPTION = 'Ошибка',
  30.   WARNING_CAPTION = 'Внимание',
  31.   DONE_CAPTION = 'Завершено',
  32.   PROJECTOR_UNAVAILABLE_MESSAGE = 'Проектор не подключен!',
  33.   SAVING_MESSAGE = 'Файл сохраняется...',
  34.   SAVED_MESSAGE = 'Файл сохранен!',
  35.   LOADING_MESSAGE = 'Файл загружается...',
  36.   LOADED_MESSAGE = 'Файл загружен!',
  37.   TOO_LOW_RESOLUTION_ERROR = '[ОШИБКА] Ваш монитор/видеокарта не поддерживает разрешение 80×25 или больше.',
  38.   TOO_LOW_SCREEN_TIER_ERROR = '[ОШИБКА] Для использования уменьшенного интерфейса, необходим алмазный монитор.',
  39.   FORMAT_READING_ERROR = 'Ошибка чтения формата!',
  40.   FILE_NOT_FOUND_ERROR = 'Файл не найден!',
  41.   CANNOT_OPEN_ERROR = 'Невозможно открыть файл!',
  42.   CANNOT_SAVE_ERROR = 'Невозможно записать файл!',
  43.   PALETTE_FRAME = 'Палитра',
  44.   VIEWPORT_FRAME = 'Проекция',
  45.   UTILS_FRAME = 'Управление',
  46.   LAYER_LABEL = 'Уровень голограммы:',
  47.   GHOST_LAYER_LABEL = 'Направляющий уровень:',
  48.   PROGRAMMERS_LABEL = 'Программисты:',
  49.   CONTACT_LABEL = 'Контакт:',
  50.   EXIT_LABEL = "Выход: 'Q' или ",
  51.   EXIT_BUTTON = 'Выход',
  52.   REFRESH_BUTTON = 'Обновить',
  53.   TOP_BUTTON = 'Сверху',
  54.   FRONT_BUTTON = 'Спереди',
  55.   SIDE_BUTTON = 'Сбоку',
  56.   BELOW_BUTTON = 'Ниже',
  57.   ABOVE_BUTTON = 'Выше',
  58.   CLEAR_BUTTON = 'Очистить',
  59.   FILL_BUTTON = 'Залить',
  60.   TO_PROJECTOR = 'На проектор',
  61.   SAVE_BUTTON = 'Сохранить',
  62.   LOAD_BUTTON = 'Загрузить',
  63.   NEW_FILE_BUTTON = 'Новый файл'
  64. }
  65. --      ***      --
  66.  
  67.  
  68. -- Загружаем доп. оборудование
  69. local function trytofind(name)
  70.   if com.isAvailable(name) then
  71.     return com.getPrimary(name)
  72.   else
  73.     return nil
  74.   end
  75. end
  76.  
  77. -- Программные константы --
  78. local OLDWIDTH, OLDHEIGHT = gpu.getResolution()
  79. local WIDTH, HEIGHT = gpu.maxResolution()
  80. local FULLSIZE = true
  81. local HOLOW, HOLOH = 48, 32        -- размеры голограммы
  82. local TOP, FRONT, SIDE = 0, 1, 2   -- проекции
  83. local MENUX = HOLOW*2+5            -- начало правой панели
  84. local BUTTONW = 12                 -- ширина кнопок
  85. local GRIDX, GRIDY = 3, 2
  86.  
  87. -- Переменные интерфейса --
  88. local buttons = {}
  89. local textboxes = {}
  90. local repaint = false
  91.  
  92. -- Состояние программы --
  93. local colortable = {}
  94. local hexcolortable = {}
  95. local darkhexcolors = {}
  96. local brush = {color = 1, x = 8, cx = 8, moving = false}
  97. local ghost_layer = 1
  98. local ghost_layer_below = true
  99. local layer = 1
  100. local view = TOP
  101. local running = true
  102.  
  103. -- Вспомогательные функции --
  104. local function rgb2hex(r,g,b)
  105.   return r*65536+g*256+b
  106. end
  107. local function setHexColor(n, r, g, b)
  108.   local hexcolor = rgb2hex(r,g,b)
  109.   hexcolortable[n] = hexcolor
  110.   darkhexcolors[n] = bit32.rshift(bit32.band(hexcolor, 0xfefefe), 1)
  111. end
  112.  
  113. -- ========================================= H O L O G R A P H I C S ========================================= --
  114. local holo = {}
  115. local function set(x, y, z, value)
  116.   if holo[x] == nil then holo[x] = {} end
  117.   if holo[x][y] == nil then holo[x][y] = {} end
  118.   holo[x][y][z] = value
  119. end
  120. local function get(x, y, z)
  121.   if holo[x] ~= nil and holo[x][y] ~= nil and holo[x][y][z] ~= nil then
  122.     return holo[x][y][z]
  123.   else
  124.     return 0
  125.   end
  126. end
  127.  
  128. local writer = {}
  129. function writer:init(file)
  130.   self.buffer = {}
  131.   self.file = file
  132. end
  133. function writer:write(sym)
  134.   table.insert(self.buffer, sym)
  135.   if #self.buffer >= 4 then self:finalize() end
  136. end
  137. function writer:finalize()
  138.   if #self.buffer > 0 then
  139.     local byte = 0
  140.     for i=4, 1, -1 do
  141.       local x = self.buffer[i] or 0
  142.       byte = byte * 4 + x
  143.     end
  144.     self.file:write(string.char(byte))
  145.     self.buffer = {}
  146.   end
  147. end
  148.  
  149. local function toBinary(x)
  150.   local data = {}
  151.   while x > 0 do
  152.     table.insert(data, x % 2)
  153.     x = math.floor(x / 2)
  154.   end
  155.   return data
  156. end
  157.  
  158. local function save(filename, compressed)
  159.   -- сохраняем палитру
  160.   local file = io.open(filename, 'wb')
  161.   if file ~= nil then
  162.     for i=1, 3 do
  163.       for c=1, 3 do
  164.         file:write(string.char(colortable[i][c]))
  165.       end
  166.     end
  167.     writer:init(file)
  168.     if compressed then
  169.       local function put(symbol, length)
  170.         if length > 0 then
  171.           writer:write(symbol)
  172.           local l = toBinary(length + 1)
  173.           l[#l] = nil
  174.           l[1] = l[1] + 2
  175.           for i=#l, 1, -1 do writer:write(l[i]) end
  176.         end
  177.       end
  178.       local len = 0
  179.       local sym = -1
  180.       -- сохраняем массив со сжатием данных
  181.       for x=1, HOLOW do
  182.         for y=1, HOLOH do
  183.           for z=1, HOLOW do
  184.             local a = get(x, y, z)
  185.             if sym == a then  -- очередной символ последовательности
  186.               len = len + 1
  187.             else              -- первый символ новой последовательности
  188.               put(sym, len)
  189.               len = 1
  190.               sym = a
  191.             end
  192.           end
  193.         end
  194.       end
  195.       put(sym, len)  -- последняя последовательность
  196.     else
  197.       -- сохраняем массив без сжатия
  198.       for x=1, HOLOW do
  199.         for y=1, HOLOH do
  200.           for z=1, HOLOW do
  201.             writer:write(get(x, y, z))
  202.           end
  203.         end
  204.       end
  205.     end
  206.     writer:finalize()
  207.     file:close()
  208.     return true
  209.   else
  210.     return false, filename..": "..loc.CANNOT_SAVE_ERROR
  211.   end
  212. end
  213.  
  214. local reader = {}
  215. function reader:init(file)
  216.   self.buffer = {}
  217.   self.file = file
  218. end
  219. function reader:read()
  220.   if #self.buffer == 0 then
  221.     if not self:fetch() then return nil end
  222.   end
  223.   -- вынимаем последний символ из буфера
  224.   local sym = self.buffer[#self.buffer]
  225.   self.buffer[#self.buffer] = nil
  226.   return sym
  227. end
  228. function reader:fetch()
  229.   self.buffer = {}
  230.   local char = file:read(1)
  231.   if char == nil then return false
  232.   else
  233.     local byte = string.byte(char)
  234.     for i=0, 3 do
  235.       local a = byte % 4
  236.       byte = math.floor(byte / 4)
  237.       self.buffer[4-i] = a   -- записываем байты в обратном порядке
  238.     end
  239.     return true
  240.   end
  241. end
  242.  
  243. local function load(filename, compressed)
  244.   if fs.exists(filename) then
  245.     file = io.open(filename, 'rb')
  246.     if file ~= nil then
  247.       -- загружаем палитру
  248.       for i=1, 3 do
  249.         for c=1, 3 do
  250.           colortable[i][c] = string.byte(file:read(1))
  251.         end
  252.         setHexColor(i,colortable[i][1],
  253.                       colortable[i][2],
  254.                       colortable[i][3])
  255.       end
  256.       -- загружаем массив
  257.       holo = {}
  258.       reader:init(file)
  259.       if compressed then          -- читаем сжатые данные
  260.         local x, y, z = 1, 1, 1
  261.         while true do
  262.           local a = reader:read() -- читаем значение символа
  263.           if a == nil then file:close(); return true end
  264.           local len = 1
  265.           while true do           -- читаем двоичное значение длины
  266.             local b = reader:read()
  267.             if b == nil then
  268.               file:close()
  269.               if a == 0 then return true
  270.               else return false, filename..": "..loc.FORMAT_READING_ERROR end
  271.             end
  272.             local fin = (b > 1)
  273.             if fin then b = b-2 end
  274.             len = bit32.lshift(len, 1)
  275.             len = len + b
  276.             if fin then break end
  277.           end
  278.           len = len - 1
  279.           -- записываем последовательность
  280.           for i=1, len do
  281.             -- пишем воксель
  282.             if a ~= 0 then set(x,y,z, a) end
  283.             -- сдвигаем координаты
  284.             z = z+1
  285.             if z > HOLOW then
  286.               y = y+1
  287.               if y > HOLOH then
  288.                 x = x+1
  289.                 if x > HOLOW then file:close(); return true end
  290.                 y = 1
  291.               end
  292.               z = 1
  293.             end  
  294.           end
  295.         end
  296.       else                        -- читаем несжатые данные
  297.         for x=1, HOLOW do
  298.           for y=1, HOLOH do
  299.             for z=1, HOLOW do
  300.               local a = reader:read()
  301.               if a ~= 0 and a ~= nil then
  302.                 set(x,y,z, a)
  303.               end
  304.             end
  305.           end
  306.         end
  307.       end
  308.       file:close()
  309.       return true
  310.     else
  311.       return false, filename..": "..loc.CANNOT_OPEN_ERROR
  312.     end
  313.   else
  314.     return false, filename..": "..loc.FILE_NOT_FOUND_ERROR
  315.   end
  316. end
  317.  
  318.  
  319. -- ============================================== B U T T O N S ============================================== --
  320. local Button = {}
  321. Button.__index = Button
  322. function Button.new(func, x, y, text, fore, back, width, nu)
  323.   self = setmetatable({}, Button)
  324.  
  325.   self.form = '[ '
  326.   if width == nil then width = 0
  327.     else width = (width - unicode.len(text))-4 end
  328.   for i=1, math.floor(width/2) do
  329.     self.form = self.form.. ' '
  330.   end
  331.   self.form = self.form..text
  332.   for i=1, math.ceil(width/2) do
  333.     self.form = self.form.. ' '
  334.   end
  335.   self.form = self.form..' ]'
  336.  
  337.   self.func = func
  338.  
  339.   self.x = math.floor(x); self.y = math.floor(y)
  340.   self.fore = fore
  341.   self.back = back
  342.   self.visible = true
  343.  
  344.   self.notupdate = nu or false
  345.  
  346.   return self
  347. end
  348. function Button:draw(fore, back)
  349.   if self.visible then
  350.     local fore = fore or self.fore
  351.     local back = back or self.back
  352.     gpu.setForeground(fore)
  353.     gpu.setBackground(back)
  354.     gpu.set(self.x, self.y, self.form)
  355.   end
  356. end
  357. function Button:click(x, y)
  358.   if self.visible then
  359.     if y == self.y then
  360.       if x >= self.x and x < self.x+unicode.len(self.form) then
  361.         self:draw(self.back, self.fore)
  362.         local data = self.func()
  363.         if not self.notupdate then self:draw() end
  364.         return true, data
  365.       end
  366.     end
  367.   end
  368.   return false
  369. end
  370.  
  371. local function buttonNew(buttons, func, x, y, text, fore, back, width, notupdate)
  372.   local button = Button.new(func, x, y, text, fore, back, width, notupdate)
  373.   table.insert(buttons, button)
  374.   return button
  375. end
  376. local function buttonsDraw(buttons)
  377.   for i=1, #buttons do
  378.     buttons[i]:draw()
  379.   end
  380. end
  381. local function buttonsClick(buttons, x, y)
  382.   for i=1, #buttons do
  383.     local ok, data = buttons[i]:click(x, y)
  384.     if ok then return data end
  385.   end
  386.   return nil
  387. end
  388.  
  389.  
  390. -- ============================================ T E X T B O X E S ============================================ --
  391. local Textbox = {}
  392. Textbox.__index = Textbox
  393. function Textbox.new(check, func, x, y, value, width)
  394.   self = setmetatable({}, Textbox)
  395.  
  396.   self.form = '>'
  397.   if width == nil then width = 10 end
  398.   for i=1, width-1 do
  399.     self.form = self.form..' '
  400.   end
  401.  
  402.   self.check = check
  403.   self.func = func
  404.   self.value = tostring(value)
  405.  
  406.   self.x = math.floor(x); self.y = math.floor(y)
  407.   self.width = width
  408.   self.visible = true
  409.  
  410.   return self
  411. end
  412. function Textbox:draw(content)
  413.   if self.visible then
  414.     gpu.setBackground(color.lightgray)
  415.     gpu.setForeground(color.fore)
  416.     gpu.set(self.x, self.y, self.form)
  417.     if content then gpu.set(self.x+2, self.y, self.value) end
  418.   end
  419. end
  420. function Textbox:click(x, y)
  421.   if self.visible then
  422.     if y == self.y then
  423.       if x >= self.x and x < self.x+self.width then
  424.         self:draw(false)
  425.         term.setCursor(self.x+2, self.y)
  426.         term.setCursorBlink(true)
  427.         local value = self.value
  428.         term.write(value)
  429.         -- читаем данные
  430.         while true do
  431.           name, a, char, code = event.pull()
  432.           if name == 'key_down' then
  433.             if char > 30 then
  434.               if unicode.len(value) < (self.width-3) then
  435.                 local letter = unicode.char(char)
  436.                 value = value .. letter
  437.                 term.write(letter)
  438.               end
  439.             else
  440.               -- enter
  441.               if code == 28 then
  442.                 -- проверяем корректность
  443.                 if self.check(value) then
  444.                   -- вызываем функцию
  445.                   self.value = value
  446.                   self.func(value)
  447.                 end
  448.                 break
  449.               -- backspace
  450.               elseif code == 14 then
  451.                 if unicode.len(value) > 0 then
  452.                   local x, y = term.getCursor()
  453.                   gpu.set(x-1, y, ' ')
  454.                   term.setCursor(x-1, y)
  455.                   value = unicode.sub(value, 1, -2)
  456.                 end
  457.               end
  458.             end
  459.           elseif name == 'touch' then
  460.             break
  461.           end
  462.         end
  463.         --
  464.         term.setCursorBlink(false)
  465.         self:draw(true)
  466.         gpu.setBackground(color.back)
  467.         return true
  468.       end
  469.     end
  470.   end
  471.   return false
  472. end
  473. function Textbox:setValue(value)
  474.   self.value = tostring(value)
  475. end
  476. function Textbox:getValue()
  477.   return self.value
  478. end
  479. function Textbox:setVisible(flag)
  480.   self.visible = flag
  481. end
  482. function Textbox:isVisible()
  483.   return self.visible
  484. end
  485.  
  486. local function textboxNew(textboxes, check, func, x, y, value, width)
  487.   textbox = Textbox.new(check, func, x, y, value, width)
  488.   table.insert(textboxes, textbox)
  489.   return textbox
  490. end
  491. local function textboxesDraw(textboxes)
  492.   for i=1, #textboxes do
  493.     textboxes[i]:draw(true)
  494.   end
  495. end
  496. local function textboxesClick(textboxes, x, y)
  497.   for i=1, #textboxes do
  498.     textboxes[i]:click(x, y)
  499.   end
  500. end
  501.  
  502.  
  503. -- ============================================= G R A P H I C S ============================================= --
  504. local gridLine1, gridLine2, gridLine1s, gridLine2s = nil, nil, nil, nil
  505. local strLine = "+"
  506. local colorCursorY, colorCursorWidth = 8, 8
  507. local function initGraphics()
  508.   -- заготовки для сетки
  509.   if FULLSIZE then gridLine1 = string.rep("██  ", HOLOW/2)
  510.   else
  511.     gridLine1 = string.rep("▀", HOLOW/2)
  512.     gridLine2 = string.rep("▄", HOLOW/2)
  513.     gridLine1s = string.rep("▀", HOLOH/2)
  514.     gridLine2s = string.rep("▄", HOLOH/2)
  515.   end
  516.   -- заготовки для линий
  517.   for i=1, WIDTH do
  518.     strLine = strLine..'-'
  519.   end
  520.   -- параметры курсора палитры
  521.   if not FULLSIZE then
  522.     colorCursorY, colorCursorWidth = 1, 7
  523.   end
  524. end
  525.  
  526. -- рисуем линию
  527. local function line(x1, x2, y)
  528.   gpu.set(x1,y,string.sub(strLine, 1, x2-x1))
  529.   gpu.set(x2,y,'+')
  530. end
  531.  
  532. -- рисуем фрейм
  533. local function frame(x1, y1, x2, y2, caption, nobottom)
  534.   line(x1, x2, y1)
  535.   if not nobottom then line(x1, x2, y2) end
  536.   if caption ~= nil then
  537.     gpu.set(x1 + math.ceil((x2-x1)/2) - math.ceil(unicode.len(caption)/2), y1, caption)
  538.   end
  539. end
  540.  
  541. -- рисуем сетку
  542. local function drawGrid(x, y)
  543.   gpu.setBackground(color.back)
  544.   gpu.setForeground(color.gray)
  545.   gpu.fill(0, y, MENUX, HOLOW, ' ')
  546.   if FULLSIZE then
  547.     for i=0, HOLOW-1 do
  548.       if view ~= TOP and i == HOLOH then
  549.         gpu.setForeground(color.fore)
  550.         line(1, MENUX-1, y+HOLOH)
  551.         break
  552.       end
  553.       gpu.set(x + (i%2)*2, y + i, gridLine1)
  554.     end
  555.   else
  556.     for i=0, HOLOW-1 do
  557.       if view == TOP then
  558.         if i%2==0 then gpu.set(x+i, y, gridLine1, true)
  559.         else gpu.set(x+i, y, gridLine2, true) end
  560.       else
  561.         if i%2==0 then gpu.set(x+i, y, gridLine1s, true)
  562.         else gpu.set(x+i, y, gridLine2s, true) end
  563.       end
  564.     end
  565.   end
  566. end
  567.  
  568. -- рисуем цветной прямоугольник
  569. local function drawRect(x, y, fill)
  570.   gpu.setForeground(color.fore)
  571.   gpu.setBackground(color.gray)
  572.   gpu.set(x, y,   "╓──────╖")
  573.   gpu.set(x, y+1, "║      ║")
  574.   gpu.set(x, y+2, "╙──────╜")
  575.   gpu.setForeground(fill)
  576.   gpu.set(x+2, y+1, "████")
  577. end
  578. local function drawSmallRect(x, y, fill)
  579.   gpu.setForeground(color.fore)
  580.   gpu.set(x, y,   "╓─────╖")
  581.   gpu.set(x, y+1, "║     ║")
  582.   gpu.set(x, y+2, "╙─────╜")
  583.   gpu.setForeground(fill)
  584.   gpu.set(x+2, y+1, "███")
  585. end
  586.  
  587. -- рисуем меню выбора "кисти"
  588. local function drawPaletteFrame()
  589.   gpu.setForeground(color.fore)
  590.   gpu.setBackground(color.back)
  591.   if FULLSIZE then
  592.     frame(MENUX, 3, WIDTH-2, 16, "[ "..loc.PALETTE_FRAME.." ]", true)
  593.     for i=0, 3 do
  594.       drawRect(MENUX+1+i*colorCursorWidth, 5, hexcolortable[i])
  595.     end
  596.     gpu.setForeground(0xFF0000); gpu.set(MENUX+1, 10, "R:")
  597.     gpu.setForeground(0x00FF00); gpu.set(MENUX+1, 11, "G:")
  598.     gpu.setForeground(0x0000FF); gpu.set(MENUX+1, 12, "B:")
  599.   else
  600.     for i=0, 3 do
  601.       drawSmallRect(MENUX+1+i*colorCursorWidth, 2, hexcolortable[i])
  602.     end
  603.     gpu.setForeground(0xFF0000); gpu.set(MENUX+1, 5, "R:")
  604.     gpu.setForeground(0x00FF00); gpu.set(MENUX+11, 5, "G:")
  605.     gpu.setForeground(0x0000FF); gpu.set(MENUX+21, 5, "B:")
  606.   end
  607. end
  608. -- рисуем и двигаем указатель кисти
  609. local function drawColorCursor(force)
  610.   if force or brush.moving then
  611.     gpu.setBackground(color.back)
  612.     gpu.setForeground(color.fore)
  613.     if FULLSIZE then gpu.set(MENUX+2+brush.cx, colorCursorY, "      ")
  614.     else gpu.set(MENUX+2+brush.cx, colorCursorY, "-----") end
  615.    
  616.     if brush.moving then
  617.       if brush.x ~= brush.color * colorCursorWidth then brush.x = brush.color*colorCursorWidth end
  618.       if brush.cx < brush.x then brush.cx = brush.cx + 1
  619.       elseif brush.cx > brush.x then brush.cx = brush.cx - 1
  620.       else brush.moving = false end
  621.     end
  622.    
  623.     if FULLSIZE then
  624.       gpu.setBackground(color.lightgray)
  625.       gpu.set(MENUX+2+brush.cx, colorCursorY, ":^^^^:")
  626.     else gpu.set(MENUX+2+brush.cx, colorCursorY, ":vvv:") end
  627.   end
  628. end
  629. local function drawLayerFrame()
  630.   gpu.setForeground(color.fore)
  631.   gpu.setBackground(color.back)
  632.   if FULLSIZE then
  633.     frame(MENUX, 16, WIDTH-2, 28, "[ "..loc.VIEWPORT_FRAME.." ]", true)
  634.     gpu.set(MENUX+13, 18, loc.LAYER_LABEL)
  635.     gpu.set(MENUX+1, 23, loc.GHOST_LAYER_LABEL)
  636.   else
  637.     gpu.set(MENUX+1, 8, loc.LAYER_LABEL)
  638.   end
  639. end
  640. local function drawUtilsFrame()
  641.   gpu.setForeground(color.fore)
  642.   gpu.setBackground(color.back)
  643.   frame(MENUX, 28, WIDTH-2, 36, "[ "..loc.UTILS_FRAME.." ]")
  644. end
  645.  
  646. local function mainScreen()
  647.   gpu.setForeground(color.fore)
  648.   gpu.setBackground(color.back)
  649.   term.clear()
  650.   frame(1,1, WIDTH, HEIGHT, "{ Hologram Editor }", not FULLSIZE)
  651.   -- "холст"
  652.   drawGrid(GRIDX, GRIDY)
  653.  
  654.   drawPaletteFrame()
  655.   drawLayerFrame()
  656.   drawUtilsFrame()
  657.  
  658.   drawColorCursor(true)
  659.   buttonsDraw(buttons)
  660.   textboxesDraw(textboxes)
  661.  
  662.   -- "about" - коротко о создателях
  663.   if FULLSIZE then
  664.     gpu.setForeground(color.info)
  665.     gpu.setBackground(color.gray)
  666.     gpu.set(MENUX+3, HEIGHT-11, " Hologram Editor v0.70 Beta  ")
  667.     gpu.setForeground(color.fore)
  668.     gpu.set(MENUX+3, HEIGHT-10, "            * * *            ")
  669.     gpu.set(MENUX+3, HEIGHT-9,  " "..loc.PROGRAMMERS_LABEL..string.rep(' ', 28-unicode.len(loc.PROGRAMMERS_LABEL)))
  670.     gpu.set(MENUX+3, HEIGHT-8,  "         NEO, Totoro         ")
  671.     gpu.set(MENUX+3, HEIGHT-7,  "            * * *            ")
  672.     gpu.set(MENUX+3, HEIGHT-6,  " "..loc.CONTACT_LABEL..string.rep(' ', 28-unicode.len(loc.CONTACT_LABEL)))
  673.     gpu.set(MENUX+3, HEIGHT-5,  "       computercraft.ru      ")
  674.     gpu.setForeground(color.fore)
  675.     gpu.setBackground(color.back)
  676.     gpu.set(MENUX+1, HEIGHT-2, loc.EXIT_LABEL)
  677.   else
  678.     gpu.setForeground(color.info)
  679.     gpu.setBackground(color.gray)
  680.     gpu.set(MENUX+1, HEIGHT-2,  "by Totoro © computercraft.ru")
  681.     gpu.setForeground(color.fore)
  682.     gpu.setBackground(color.back)
  683.     gpu.set(MENUX+1, HEIGHT, loc.EXIT_LABEL)
  684.   end
  685. end
  686.  
  687.  
  688. -- ============================================= M E S S A G E S ============================================= --
  689. local function showMessage(text, caption, textcolor)
  690.   local caption = '[ '..caption..' ]'
  691.   local x = MENUX/2 - unicode.len(text)/2 - 4
  692.   local y = HEIGHT/2 - 2
  693.   gpu.setBackground(color.back)
  694.   gpu.setForeground(color.fore)
  695.   gpu.fill(x, y, unicode.len(text)+9, 5, ' ')
  696.   frame(x, y, x+unicode.len(text)+8, y+4, caption)
  697.   gpu.setForeground(textcolor)
  698.   gpu.set(x+4,y+2, text)
  699.   -- "холст" надо будет перерисовать
  700.   repaint = true
  701. end
  702.  
  703.  
  704. -- =============================================== L A Y E R S =============================================== --
  705. local function project(x, y, layer, view)
  706.   if view == TOP then
  707.     return x, layer, y
  708.   elseif view == FRONT then
  709.     return x, HOLOH-y+1, layer
  710.   else
  711.     return layer, HOLOH-y+1, x
  712.   end
  713. end
  714. local function getVoxelColor(x, y, z, grid)
  715.   local voxel = get(x, y, z)
  716.   if voxel ~= 0 then return hexcolortable[voxel]
  717.   elseif grid then return color.gray
  718.   else return color.back end
  719. end
  720. local function drawVoxel(sx, sy, nogrid)
  721.   if FULLSIZE then
  722.     local voxel = get(project(sx, sy, layer, view))
  723.     local dx = (GRIDX-2) + sx*2
  724.     local dy = (GRIDY-1) + sy
  725.     if voxel ~= 0 then
  726.       gpu.setForeground(hexcolortable[voxel])
  727.       gpu.set(dx, dy, "██")
  728.     else  
  729.       local ghost = get(gx, gy, gz)
  730.       if ghost ~= 0 then
  731.         gpu.setForeground(darkhexcolors[ghost])
  732.         gpu.set(dx, dy, "░░")
  733.       elseif not nogrid then
  734.         if (sx+sy)%2 == 0 then gpu.setForeground(color.gray)
  735.         else gpu.setForeground(color.back) end
  736.         gpu.set(dx, dy, "██")
  737.       end
  738.     end
  739.   else
  740.     local sxUp, syUp = sx, sy
  741.     if syUp%2 == 0 then syUp = syUp-1 end
  742.     local sxDown, syDown = sxUp, syUp + 1
  743.     local dx, dy = (GRIDX-1) + sxUp, (GRIDY-1) + math.ceil(syUp/2)
  744.     local a, b, c = project(sxUp, syUp, layer, view)
  745.     gpu.setForeground(getVoxelColor(a, b, c, ((sxUp+syUp)%2 == 0)))
  746.     a, b, c = project(sxDown, syDown, layer, view)
  747.     gpu.setBackground(getVoxelColor(a, b, c, ((sxDown+syDown)%2 == 0)))
  748.     gpu.set(dx, dy, "▀")
  749.   end
  750. end
  751.  
  752. function drawLayer()
  753.   drawGrid(GRIDX, GRIDY)
  754.   local step, limit
  755.   if FULLSIZE then step = 1 else step = 2 end
  756.   if view == TOP then limit = HOLOW else limit = HOLOH end
  757.   for x=1, HOLOW do
  758.     for y=1, limit, step do drawVoxel(x, y, true) end
  759.   end
  760.   -- обновление экрана уже не требуется
  761.   repaint = false
  762. end
  763. local function fillLayer()
  764.   for x=1, HOLOW do
  765.     for z=1, HOLOW do
  766.       set(x, layer, z, brush.color)
  767.     end
  768.   end
  769.   drawLayer()
  770. end
  771. local function clearLayer()
  772.   for x=1, HOLOW do
  773.     if holo[x] ~= nil then holo[x][layer] = nil end
  774.   end
  775.   drawLayer()
  776. end
  777.  
  778.  
  779. -- ==================================== G U I   F U N C T I O N A L I T Y ==================================== --
  780. local function exit() running = false end
  781.  
  782. local function nextGhost()
  783.   local limit = HOLOH
  784.   if view ~= TOP then limit = HOLOW end
  785.  
  786.   if ghost_layer_below then
  787.     ghost_layer_below = false
  788.     if ghost_layer < limit then
  789.       ghost_layer = layer + 1
  790.     else ghost_layer = limit end
  791.     drawLayer()
  792.   else  
  793.     if ghost_layer < limit then
  794.       ghost_layer = ghost_layer + 1
  795.       drawLayer()
  796.     end
  797.   end
  798.   tb_ghostlayer:setValue(''); tb_ghostlayer:draw()
  799. end
  800. local function prevGhost()
  801.   if not ghost_layer_below then
  802.     ghost_layer_below = true
  803.     if layer > 1 then
  804.       ghost_layer = layer - 1
  805.     else ghost_layer = 1 end
  806.     drawLayer()
  807.   else
  808.     if ghost_layer > 1 then
  809.       ghost_layer = ghost_layer - 1
  810.       drawLayer()
  811.     end
  812.   end
  813.   tb_ghostlayer:setValue(''); tb_ghostlayer:draw()
  814. end
  815. local function setGhostLayer(value)
  816.   local n = tonumber(value)
  817.   local limit = HOLOH
  818.   if view ~= TOP then limit = HOLOW end
  819.   if n == nil or n < 1 or n > limit then return false end
  820.   ghost_layer = n
  821.   drawLayer()
  822.   return true
  823. end
  824. local function moveGhost()
  825.   if ghost_layer_below then
  826.     if layer > 1 then ghost_layer = layer - 1
  827.     else ghost_layer = 1 end
  828.   else
  829.     local limit = HOLOH
  830.     if view ~= TOP then limit = HOLOW end
  831.     if layer < limit then ghost_layer = layer + 1
  832.     else ghost_layer = limit end
  833.   end
  834. end
  835.  
  836. local function nextLayer()
  837.   -- ограничения разные для разных видов/проекций
  838.   local limit = HOLOH
  839.   if view ~= TOP then limit = HOLOW end
  840.  
  841.   if layer < limit then
  842.     layer = layer + 1
  843.     tb_layer:setValue(layer)
  844.     tb_layer:draw(true)
  845.     moveGhost()
  846.     drawLayer()
  847.   end
  848. end
  849. local function prevLayer()
  850.   if layer > 1 then
  851.     layer = layer - 1
  852.     tb_layer:setValue(layer)
  853.     tb_layer:draw(true)
  854.     moveGhost()
  855.     drawLayer()
  856.   end
  857. end
  858. local function setLayer(value)
  859.   local n = tonumber(value)
  860.   local limit = HOLOH
  861.   if view ~= TOP then limit = HOLOW end
  862.   if n == nil or n < 1 or n > limit then return false end
  863.   layer = n
  864.   moveGhost()
  865.   drawLayer()
  866.   tb_layer:setValue(layer)
  867.   tb_layer:draw(true)
  868.   return true
  869. end
  870.  
  871. local function setFilename(str)
  872.   if str ~= nil and str ~= '' and unicode.len(str)<30 then
  873.     return true
  874.   else
  875.     return false
  876.   end
  877. end
  878.  
  879. local function changeColor(rgb, value)
  880.   if value == nil then return false end
  881.   n = tonumber(value)
  882.   if n == nil or n < 0 or n > 255 then return false end
  883.   -- сохраняем данные в таблицу
  884.   colortable[brush.color][rgb] = n
  885.   setHexColor(brush.color, colortable[brush.color][1],
  886.                            colortable[brush.color][2],
  887.                            colortable[brush.color][3])
  888.   -- обновляем цвета на панельке
  889.   drawPaletteFrame()
  890.   return true
  891. end
  892. local function changeRed(value) return changeColor(1, value) end
  893. local function changeGreen(value) return changeColor(2, value) end
  894. local function changeBlue(value) return changeColor(3, value) end
  895.  
  896. local function moveSelector(num)
  897.   if num == 0 and brush.color ~= 0 then
  898.     tb_red:setVisible(false)
  899.     tb_green:setVisible(false)
  900.     tb_blue:setVisible(false)
  901.     gpu.setBackground(color.back)
  902.     if FULLSIZE then
  903.       gpu.fill(MENUX+3, 10, 45, 3, ' ')
  904.     else
  905.       gpu.set(MENUX+3, 5, '      ')
  906.       gpu.set(MENUX+13, 5, '      ')
  907.       gpu.set(MENUX+23, 5, '      ')
  908.     end
  909.   elseif num ~= 0 and brush.color == 0 then
  910.     tb_red:setVisible(true); tb_red:draw(true)
  911.     tb_green:setVisible(true); tb_green:draw(true)
  912.     tb_blue:setVisible(true); tb_blue:draw(true)
  913.   end
  914.   brush.color = num
  915.   brush.moving = true
  916.   tb_red:setValue(colortable[num][1]); tb_red:draw(true)
  917.   tb_green:setValue(colortable[num][2]); tb_green:draw(true)
  918.   tb_blue:setValue(colortable[num][3]); tb_blue:draw(true)
  919. end
  920.  
  921. local function setTopView(norefresh)
  922.   view = TOP
  923.   -- в виде сверху меньше слоев
  924.   if layer > HOLOH then layer = HOLOH end
  925.   if not norefresh then drawLayer() end
  926. end
  927. local function setFrontView() view = FRONT; drawLayer() end
  928. local function setSideView() view = SIDE; drawLayer() end
  929.  
  930. local function drawHologram()
  931.   -- проверка на наличие проектора
  932.   local projector = trytofind('hologram')
  933.   if projector ~= nil then
  934.     local depth = projector.maxDepth()
  935.     -- очищаем
  936.     projector.clear()
  937.     -- отправляем палитру
  938.     if depth == 2 then
  939.       for i=1, 3 do
  940.         projector.setPaletteColor(i, hexcolortable[i])
  941.       end
  942.     else
  943.       projector.setPaletteColor(1, hexcolortable[1])
  944.     end
  945.     -- отправляем массив
  946.     for x=1, HOLOW do
  947.       for y=1, HOLOH do
  948.         for z=1, HOLOW do
  949.           n = get(x,y,z)
  950.           if n ~= 0 then
  951.             if depth == 2 then
  952.               projector.set(x,y,z,n)
  953.             else
  954.               projector.set(x,y,z,1)
  955.             end
  956.           end
  957.         end
  958.       end      
  959.     end
  960.   else
  961.     showMessage(loc.PROJECTOR_UNAVAILABLE_MESSAGE, loc.ERROR_CAPTION, color.error)
  962.   end
  963. end
  964.  
  965. local function newHologram()
  966.   holo = {}
  967.   drawLayer()
  968. end
  969.  
  970. local function saveHologram()
  971.   local filename = tb_file:getValue()
  972.   if filename ~= loc.FILE_REQUEST then
  973.     -- выводим предупреждение
  974.     showMessage(loc.SAVING_MESSAGE, loc.WARNING_CAPTION, color.gold)
  975.     local compressed = true
  976.     -- добавляем фирменное расширение =)
  977.     if string.sub(filename, -3) == '.3d' then compressed = false
  978.     elseif string.sub(filename, -4) ~= '.3dx' then
  979.       filename = filename..'.3dx'
  980.     end
  981.     -- сохраняем
  982.     local ok, message = save(filename, compressed)
  983.     if ok then
  984.       showMessage(loc.SAVED_MESSAGE, loc.DONE_CAPTION, color.gold)
  985.     else
  986.       showMessage(message, loc.ERROR_CAPTION, color.error)
  987.     end
  988.   end
  989. end
  990.  
  991. local function loadHologram()
  992.   local filename = tb_file:getValue()
  993.   if filename ~= loc.FILE_REQUEST then
  994.     -- выводим предупреждение
  995.     showMessage(loc.LOADING_MESSAGE, loc.WARNING_CAPTION, color.gold)
  996.     local compressed = nil
  997.     -- добавляем фирменное расширение =)
  998.     if string.sub(filename, -3) == '.3d' then compressed = false
  999.     elseif string.sub(filename, -4) == '.3dx' then compressed = true end
  1000.     -- загружаем
  1001.     local ok, message = nil, nil
  1002.     if compressed ~= nil then
  1003.       ok, message = load(filename, compressed)
  1004.     else
  1005.       -- если расширение файла не было указано, пробуем по очереди оба варианта
  1006.       ok, message = load(filename..'.3dx', true)
  1007.       if not ok then
  1008.         ok, message = load(filename..'.3d', false)
  1009.       end
  1010.     end
  1011.     if ok then
  1012.       -- обновляем значения в текстбоксах
  1013.       tb_red:setValue(colortable[brush.color][1]); tb_red:draw(true)
  1014.       tb_green:setValue(colortable[brush.color][2]); tb_green:draw(true)
  1015.       tb_blue:setValue(colortable[brush.color][3]); tb_blue:draw(true)
  1016.       -- обновляем цвета на панельке
  1017.       drawPaletteFrame()
  1018.       -- сброс вьюпорта
  1019.       setTopView(true)
  1020.       setLayer(1)
  1021.     else
  1022.       showMessage(message, loc.ERROR_CAPTION, color.error)
  1023.     end
  1024.   end
  1025. end
  1026.  
  1027.  
  1028. -- =========================================== M A I N   C Y C L E =========================================== --
  1029. -- инициализация
  1030. -- проверка разрешения экрана; для комфортной работы необходима золотая или алмазная карта / монитор
  1031. if HEIGHT < HOLOW/2 then
  1032.   error(loc.TOO_LOW_RESOLUTION_ERROR)
  1033. elseif HEIGHT < HOLOW+2 then
  1034.   com.screen.setPrecise(true)
  1035.   if not com.screen.isPrecise() then error(loc.TOO_LOW_SCREEN_TIER) end
  1036.   FULLSIZE = false
  1037.   MENUX = HOLOW + 2
  1038.   color.gray = color.lightgray
  1039.   GRIDX = 1
  1040.   GRIDY = 2
  1041.   BUTTONW = 9
  1042. else
  1043.   com.screen.setPrecise(false)
  1044.   WIDTH = HOLOW*2 + 40
  1045.   HEIGHT = HOLOW + 2
  1046. end
  1047. gpu.setResolution(WIDTH, HEIGHT)
  1048. gpu.setForeground(color.fore)
  1049. gpu.setBackground(color.back)
  1050.  
  1051. -- установка дефолтной палитры
  1052. colortable = {{255, 0, 0}, {0, 255, 0}, {0, 102, 255}}
  1053. colortable[0] = {0, 0, 0}  -- стерка
  1054. for i=0, 3 do setHexColor(i, colortable[i][1], colortable[i][2], colortable[i][3]) end
  1055.  
  1056. initGraphics()
  1057.  
  1058. -- генерация интерфейса
  1059. if FULLSIZE then
  1060.   buttonNew(buttons, exit, WIDTH-BUTTONW-2, HEIGHT-2, loc.EXIT_BUTTON, color.back, color.error, BUTTONW)
  1061.   buttonNew(buttons, drawLayer, MENUX+11, 14, loc.REFRESH_BUTTON, color.back, color.gold, BUTTONW)
  1062.   buttonNew(buttons, prevLayer, MENUX+1, 19, '-', color.fore, color.info, 5)
  1063.   buttonNew(buttons, nextLayer, MENUX+7, 19, '+', color.fore, color.info, 5)
  1064.   buttonNew(buttons, setTopView, MENUX+1, 21, loc.TOP_BUTTON, color.fore, color.info, 10)
  1065.   buttonNew(buttons, setFrontView, MENUX+12, 21, loc.FRONT_BUTTON, color.fore, color.info, 10)
  1066.   buttonNew(buttons, setSideView, MENUX+24, 21, loc.SIDE_BUTTON, color.fore, color.info, 9)
  1067.  
  1068.   buttonNew(buttons, prevGhost, MENUX+1, 24, loc.BELOW_BUTTON, color.fore, color.info, 6)
  1069.   buttonNew(buttons, nextGhost, MENUX+10, 24, loc.ABOVE_BUTTON, color.fore, color.info, 6)
  1070.  
  1071.   buttonNew(buttons, clearLayer, MENUX+1, 26, loc.CLEAR_BUTTON, color.fore, color.info, BUTTONW)
  1072.   buttonNew(buttons, fillLayer, MENUX+2+BUTTONW, 26, loc.FILL_BUTTON, color.fore, color.info, BUTTONW)
  1073.  
  1074.   buttonNew(buttons, drawHologram, MENUX+9, 30, loc.TO_PROJECTOR, color.back, color.gold, 16)
  1075.   buttonNew(buttons, saveHologram, MENUX+1, 33, loc.SAVE_BUTTON, color.fore, color.help, BUTTONW)
  1076.   buttonNew(buttons, loadHologram, MENUX+8+BUTTONW, 33, loc.LOAD_BUTTON, color.fore, color.info, BUTTONW)
  1077.   buttonNew(buttons, newHologram, MENUX+1, 35, loc.NEW_FILE_BUTTON, color.fore, color.info, BUTTONW)
  1078. else
  1079.   buttonNew(buttons, exit, WIDTH-BUTTONW-1, HEIGHT, loc.EXIT_BUTTON, color.back, color.error, BUTTONW)
  1080.   buttonNew(buttons, drawLayer, MENUX+9, 6, loc.REFRESH_BUTTON, color.back, color.gold, BUTTONW)
  1081.   buttonNew(buttons, prevLayer, MENUX+1, 9, '-', color.fore, color.info, 5)
  1082.   buttonNew(buttons, nextLayer, MENUX+7, 9, '+', color.fore, color.info, 5)
  1083.   buttonNew(buttons, setTopView, MENUX+1, 11, loc.TOP_BUTTON, color.fore, color.info, 8)
  1084.   buttonNew(buttons, setFrontView, MENUX+10, 12, loc.FRONT_BUTTON, color.fore, color.info, 8)
  1085.   buttonNew(buttons, setSideView, MENUX+20, 13, loc.SIDE_BUTTON, color.fore, color.info, 8)
  1086.  
  1087.   buttonNew(buttons, clearLayer, MENUX+1, 15, loc.CLEAR_BUTTON, color.fore, color.info, BUTTONW)
  1088.   buttonNew(buttons, fillLayer, MENUX+14, 15, loc.FILL_BUTTON, color.fore, color.info, BUTTONW)
  1089.  
  1090.   buttonNew(buttons, drawHologram, MENUX+7, 17, loc.TO_PROJECTOR, color.back, color.gold, 16)
  1091.   buttonNew(buttons, saveHologram, MENUX+1, 20, loc.SAVE_BUTTON, color.fore, color.help, BUTTONW)
  1092.   buttonNew(buttons, loadHologram, MENUX+16, 20, loc.LOAD_BUTTON, color.fore, color.info, BUTTONW)
  1093.   buttonNew(buttons, newHologram, MENUX+1, 21, loc.NEW_FILE_BUTTON, color.fore, color.info, BUTTONW)
  1094. end
  1095.  
  1096. local function isNumber(value) if tonumber(value) ~= nil then return true else return false end end
  1097. local function correctLayer(value)
  1098.   local n = tonumber(value)
  1099.   if n~= nil then
  1100.     if view == TOP then
  1101.       if n > 0 and n <= HOLOH then return true end
  1102.     else
  1103.       if n > 0 and n <= HOLOW then return true end
  1104.     end
  1105.   end
  1106.   return false
  1107. end
  1108.  
  1109. tb_red, tb_green, tb_blue, tb_layer, tb_ghostlayer, tb_file = nil, nil, nil, nil, nil, nil
  1110. if FULLSIZE then
  1111.   tb_red = textboxNew(textboxes, isNumber, changeRed, MENUX+5, 10, '255', WIDTH-MENUX-7)
  1112.   tb_green = textboxNew(textboxes, isNumber, changeGreen, MENUX+5, 11, '0', WIDTH-MENUX-7)
  1113.   tb_blue = textboxNew(textboxes, isNumber, changeBlue, MENUX+5, 12, '0', WIDTH-MENUX-7)
  1114.   tb_layer = textboxNew(textboxes, correctLayer, setLayer, MENUX+13, 19, '1', WIDTH-MENUX-15)
  1115.   tb_ghostlayer = textboxNew(textboxes, correctLayer, setGhostLayer, MENUX+19, 24, '', WIDTH-MENUX-21)
  1116.   tb_file = textboxNew(textboxes, function() return true end, setFilename, MENUX+1, 32, loc.FILE_REQUEST, WIDTH-MENUX-3)
  1117. else
  1118.   tb_red = textboxNew(textboxes, isNumber, changeRed, MENUX+3, 5, '255', 6)
  1119.   tb_green = textboxNew(textboxes, isNumber, changeGreen, MENUX+13, 5, '0', 6)
  1120.   tb_blue = textboxNew(textboxes, isNumber, changeBlue, MENUX+23, 5, '0', 6)
  1121.   tb_layer = textboxNew(textboxes, correctLayer, setLayer, MENUX+13, 9, '1', WIDTH-MENUX-14)
  1122.   tb_file = textboxNew(textboxes, function() return true end, setFilename, MENUX+1, 19, loc.FILE_REQUEST, WIDTH-MENUX-2)
  1123. end
  1124.  
  1125. mainScreen()
  1126. moveSelector(1)
  1127.  
  1128. local function delay(active) if active then return 0.02 else return 2.0 end end
  1129.  
  1130. while running do
  1131.   local name, add, x, y, button = event.pull(delay(brush.moving))
  1132.  
  1133.   if name == 'key_down' then
  1134.     -- если нажата 'Q' - выходим
  1135.     if y == 16 then break
  1136.     elseif y == 41 then
  1137.       moveSelector(0)
  1138.     elseif y>=2 and y<=4 then
  1139.       moveSelector(y-1)
  1140.     elseif y == 211 then
  1141.       clearLayer()
  1142.     end
  1143.   elseif name == 'touch' or name == 'drag' then
  1144.   -- перерисуем, если на экране был мессейдж
  1145.     if repaint then drawLayer()
  1146.     else
  1147.       if name == 'touch' then
  1148.         -- проверка GUI
  1149.         buttonsClick(buttons, math.ceil(x), math.ceil(y))
  1150.         textboxesClick(textboxes, math.ceil(x), math.ceil(y))
  1151.         -- выбор цвета
  1152.         if x > MENUX+1 and x < MENUX+37 then
  1153.           if FULLSIZE then
  1154.             if y > 4 and y < 8 then
  1155.               moveSelector(math.floor((x-MENUX-1)/colorCursorWidth))
  1156.             end
  1157.           else
  1158.             if y > 1 and y < 4 and x < WIDTH-2 then
  1159.               moveSelector(math.floor((x-MENUX-1)/colorCursorWidth))
  1160.             end
  1161.           end
  1162.         end
  1163.       end
  1164.      
  1165.       -- "рисование"
  1166.       local limit
  1167.       if view == TOP then limit = HOLOW else limit = HOLOH end
  1168.      
  1169.       local dx, dy = nil, nil
  1170.       if FULLSIZE then
  1171.         if x >= GRIDX and x < GRIDX+HOLOW*2 then
  1172.           if y >= GRIDY and y < GRIDY+limit then
  1173.             dx, dy = math.floor((x-GRIDX)/2)+1, math.floor(y-GRIDY+1)
  1174.           end
  1175.         end
  1176.       else
  1177.         if x >= (GRIDX-1) and x <= GRIDX+HOLOW then
  1178.           if y >= (GRIDY-1) and y <= GRIDY+limit/2 then
  1179.             dx, dy = math.floor(x - GRIDX + 2), math.floor((y-GRIDY+1)*2)+1
  1180.           end
  1181.         end
  1182.       end
  1183.       if dx ~= nil then
  1184.         local a, b, c = project(dx, dy, layer, view)
  1185.         if button == 0 then set(a, b, c, brush.color)
  1186.         else set(a, b, c, 0) end
  1187.         drawVoxel(dx, dy)
  1188.       end
  1189.     end
  1190.   end
  1191.  
  1192.   drawColorCursor()
  1193. end
  1194.  
  1195. -- завершение
  1196. gpu.setResolution(OLDWIDTH, OLDHEIGHT)
  1197. gpu.setForeground(0xFFFFFF)
  1198. gpu.setBackground(0x000000)
  1199. term.clear()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement