Advertisement
MoonlightOwl

Hologram Editor v0.70 Beta

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