Так, вроде все. Мультискрины-хуины терь хоть на гуйке пашут. Ну и на хуй оно надо? - спросишь ты. А это все Семен пердел, мол, ЧОЗА НИГРАФОННН. К нему предъявы

This commit is contained in:
Igor Timofeev
2018-08-26 18:54:15 +03:00
parent 22e1824a39
commit 67e90cd926
2 changed files with 267 additions and 580 deletions

View File

@@ -1,313 +1,295 @@
require("advancedLua")
local ecs = require("ECSAPI")
local components = require("component")
local serialization = require("serialization")
local fs = require("filesystem")
local component = require("component")
local color = require("color")
local buffer = require("doubleBuffering")
local GUI = require("GUI")
local bit32 = require("bit32")
local event = require("event")
local unicode = require("unicode")
local bit32 = require("bit32")
local color = require("color")
local gpu = components.gpu
local fs = require("filesystem")
--------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local mainScreenAddress = gpu.getScreen()
local pathToConfigFile = "/MultiScreen.cfg"
local configPath = "/MultiScreen.cfg"
local elementWidth = 48
local baseResolutionWidth = 146
local baseResolutionHeight = 54
local GPUProxy = buffer.getGPUProxy()
local mainScreenAddress = GPUProxy.getScreen()
local colors = {
background = 0x262626,
foreground = 0xDDDDDD,
currentScreen = ecs.colors.green,
screen = 0xDDDDDD,
local config = {
backgroundColor = 0x0,
}
local baseResolution = {
width = 146,
height = 54,
}
--------------------------------------------------------------------------------
local monitors = {}
--------------------------------------------------------------------------------------------------------------------------------------------
local currentBackground, currentForeground, currentAddress = 0x000000, 0xffffff, ""
local function multiScreenSet(x, y, background, foreground, text)
local xMonitor = math.ceil(x / monitors.screenResolutionByWidth)
local yMonitor = math.ceil(y / monitors.screenResolutionByHeight)
if monitors[xMonitor] and monitors[xMonitor][yMonitor] then
if currentAddress ~= monitors[xMonitor][yMonitor].address then
gpu.bind(monitors[xMonitor][yMonitor].address, false)
gpu.setBackground(background)
gpu.setForeground(foreground)
currentBackground, currentForeground = background, foreground
currentAddress = monitors[xMonitor][yMonitor].address
end
if currentBackground ~= background then
gpu.setBackground(background)
currentBackground = background
end
if currentForeground ~= foreground then
gpu.setForeground(foreground)
currentForeground = foreground
end
gpu.set(x - (xMonitor - 1) * monitors.screenResolutionByWidth, y - (yMonitor - 1) * monitors.screenResolutionByHeight, text)
end
end
local function multiScreenClear(color)
for address in components.list("screen") do
if address ~= mainScreenAddress then
gpu.bind(address, false)
gpu.setResolution(baseResolution.width, baseResolution.height)
gpu.setDepth(8)
gpu.setBackground(0x0)
gpu.setForeground(0xffffff)
gpu.fill(1, 1, baseResolution.width, baseResolution.height, " ")
end
end
gpu.bind(mainScreenAddress, false)
end
--------------------------------------------------------------------------------------------------------------------------------------------
local function getAllConnectedScreens()
local massiv = {}
for address in pairs(components.list("screen")) do
table.insert(massiv, address)
end
return massiv
end
local function configurator()
fs.makeDirectory(fs.path(pathToConfigFile))
local data = ecs.universalWindow("auto", "auto", 40, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, "Здорово, ебана!"}, {"EmptyLine"}, {"WrappedText", 0x262626, "Добро пожаловать в программу конфигурации мультимонитора. Вам необходимо указать количество мониторов по ширине и высоте, которые вы желаете объединить, а также выбрать желаемый масштаб."}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, "Ширина"}, {"Input", 0x262626, 0x880000, "Высота"}, {"Slider", 0x262626, 0x880000, 1, 100, 100, "Масштаб: ", "%"}, {"EmptyLine"}, {"Button", {ecs.colors.orange, 0xffffff, "Подтвердить"}, {0x777777, 0xffffff, "Отмена"}})
local width, height, scale = tonumber(data[1]), tonumber(data[2]), tonumber(data[3]) / 100
if data[4] == "Отмена" then
ecs.prepareToExit()
print("Калибровка отменена!")
os.exit()
end
baseResolution.width, baseResolution.height = math.floor(baseResolution.width * scale), math.floor(baseResolution.height * scale)
-- ecs.error(baseResolution.width .. "x" ..baseResolution.height .. " ccale = " ..scale)
local countOfConnectedScreens = #getAllConnectedScreens()
while ((countOfConnectedScreens - 1) < width * height) do
data = ecs.universalWindow("auto", "auto", 44, 0xeeeeee, true, {"EmptyLine"}, {"WrappedText", 0x262626, "Теперь вам необходимо подключить внешние мониторы. Вы указали, что собираетесь сделать мультимонитор из " .. width*height .. " мониторов, но на данный момент вы подключили " .. countOfConnectedScreens - 1 .. " мониторов. Так что подключайте все так, как указали, и жмите \"Далее\"."}, {"EmptyLine"}, {"Button", {ecs.colors.orange, 0xffffff, "Далее"}, {0x777777, 0xffffff, "Отмена"}})
if data[1] == "Отмена" then
ecs.prepareToExit()
print("Калибровка отменена!")
os.exit()
end
countOfConnectedScreens = #getAllConnectedScreens()
end
----
local w, h = 8, 3
local xC, yC = 1, 1
local xSize, ySize = gpu.getResolution()
local function drawMonitors()
ecs.clearScreen(colors.background)
local x, y = 3, 2
local xPos, yPos = x, y
for j = 1, height do
for i = 1, width do
if j == yC and i == xC then
ecs.square(xPos, yPos, w, h, colors.currentScreen)
else
ecs.square(xPos, yPos, w, h, colors.screen)
end
xPos = xPos + w + 2
end
yPos = yPos + h + 1
xPos = x
end
gpu.setBackground(colors.background)
gpu.setForeground(colors.foreground)
ecs.centerText("x", ySize - 5, "Начинаем процесс калибровки. Коснитесь монитора, подсвеченного зеленым цветом.")
ecs.centerText("x", ySize - 4, "Не нарушайте порядок прокосновений!")
end
ecs.prepareToExit()
print("Идет подготовка мониторов...")
multiScreenClear(0x0)
monitors = {}
local monitorCount = width * height
local counter = 1
while counter <= monitorCount do
drawMonitors()
local e = {event.pull("touch")}
if e[2] ~= mainScreenAddress then
local exists = false
for x = 1, #monitors do
for y = 1, #monitors[x] do
if monitors[x][y].address == e[2] then
ecs.error("Ты уже кликал на этот монитор. Совсем уебок штоле?")
exists = true
end
end
end
if not exists then
gpu.bind(e[2], false)
gpu.setResolution(baseResolution.width, baseResolution.height)
gpu.setDepth(8)
local color = color.HSBToInteger(counter / monitorCount * 360, 1, 1)
gpu.setBackground(color)
gpu.setForeground(0xffffff - color)
gpu.fill(1, 1, baseResolution.width, baseResolution.height, " ")
ecs.centerText("xy", 0, "Монитор " .. xC .. "x" .. yC .. " откалиброван!")
gpu.bind(mainScreenAddress, false)
monitors[xC] = monitors[xC] or {}
monitors[xC][yC] = {address = e[2]}
xC = xC + 1
if xC > width and yC < height then
xC, yC = 1, yC + 1
end
end
else
ecs.error("Ну что ты за мудак криворукий! Сказано же, каких мониторов касаться. Не трогай этот монитор.")
end
counter = counter + 1
end
monitors.countOfScreensByWidth = width
monitors.countOfScreensByHeight = height
monitors.screenResolutionByWidth = baseResolution.width
monitors.screenResolutionByHeight = baseResolution.height
monitors.totalResolutionByWidth = baseResolution.width * width
monitors.totalResolutionByHeight = baseResolution.height * height
ecs.prepareToExit()
ecs.universalWindow("auto", "auto", 40, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x262626, "Калибровка успешно завершена!"}, {"EmptyLine"}, {"Button", {ecs.colors.orange, 0xffffff, "Отлично"}})
ecs.prepareToExit()
if fs.exists(configPath) then
config = table.fromFile(configPath)
end
local function saveConfig()
local file = io.open(pathToConfigFile, "w")
file:write(serialization.serialize(monitors))
file:close()
table.toFile(configPath, config, true)
end
local function loadConfig()
if fs.exists(pathToConfigFile) then
local file = io.open(pathToConfigFile, "r")
monitors = serialization.unserialize(file:read("*a"))
file:close()
print(" ")
print("Файл конфигурации мультимонитора загружен")
print(" ")
print("Количество экранов: " .. monitors.countOfScreensByWidth .. "x" .. monitors.countOfScreensByHeight .. " шт")
print("Разрешение каждого экрана: " .. monitors.screenResolutionByWidth .. "x" .. monitors.screenResolutionByHeight .. " px")
print("Суммарное разрешение кластера: " .. monitors.totalResolutionByWidth .. "x" .. monitors.totalResolutionByHeight .. " px")
-- print("Суммарное разрешение кластера через шрифт Брайля: ".. monitors.totalResolutionByWidth * 2 .. "x" .. monitors.totalResolutionByHeight * 4 .. " px")
print(" ")
else
configurator()
saveConfig()
loadConfig()
end
end
local mainContainer = GUI.fullScreenContainer()
mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D))
--------------------------------------------------------------------------------------------------------------------------------------------
local layout = mainContainer:addChild(GUI.layout(1, 1, mainContainer.width, mainContainer.height, 1, 1))
--Прочитать n байтов из файла, возвращает прочитанные байты как число, если не удалось прочитать, то возвращает 0
local function readNumber(file, count)
return bit32.byteArrayToNumber({string.byte(file:read(count), 1, count)})
end
local function drawBigImageFromOCIFRawFile(x, y, path)
local file = io.open(path, "rb")
print("Открываем файл " .. path)
local signature = file:read(4)
print("Читаем сигнатуру файла: " .. signature)
local encodingMethod = string.byte(file:read(1))
print("Читаем метод кодирования: " .. tostring(encodingMethod))
if encodingMethod ~= 5 then
print("Неподдерживаемый метод кодирования. Откройте конвертер, измените формат на OCIF5 (Multiscreen) и повторите попытку")
file:close()
end
local width = readNumber(file, 2)
local height = readNumber(file, 2)
print("Ширина пикчи: " .. tostring(width))
print("Высота пикчи: " .. tostring(height))
print("Начинаю отросовку пикчи...")
for j = 1, height do
for i = 1, width do
local background = color.to24Bit(string.byte(file:read(1)))
local foreground = color.to24Bit(string.byte(file:read(1)))
file:read(1)
local symbol = fs.readUnicodeChar(file)
multiScreenSet(x + i - 1, y + j - 1, background, foreground, symbol)
local function clearScreens()
for address in component.list("screen") do
if address ~= mainScreenAddress then
GPUProxy.bind(address, false)
GPUProxy.setResolution(baseResolutionWidth, baseResolutionHeight)
GPUProxy.setBackground(config.backgroundColor)
GPUProxy.fill(1, 1, baseResolutionWidth, baseResolutionHeight, " ")
end
end
file:close()
gpu.bind(mainScreenAddress, false)
print("Отрисовка пикчи завершена")
GPUProxy.bind(mainScreenAddress, false)
end
--------------------------------------------------------------------------------------------------------------------------------------------
local function addButton(text)
return layout:addChild(GUI.button(1, 1, elementWidth, 3, 0x4B4B4B, 0xD2D2D2, 0xD2D2D2, 0x4B4B4B, text))
end
local args = {...}
local function addTextBox(lines)
local textBox = layout:addChild(GUI.textBox(1, 1, elementWidth, 16, nil, 0x969696, lines, 1, 0, 0, true, true))
textBox.eventHandler = nil
if args[1] == "draw" and args[2] then
loadConfig()
print("Идет очистка мониторов...")
multiScreenClear(0x000000)
if fs.exists(args[2]) then
drawBigImageFromOCIFRawFile(1, 1, args[2])
return textBox
end
local function mainMenu(force)
layout:removeChildren()
local lines = {
{color = 0xE1E1E1, text = "Welcome to MultiScreen software"},
" ",
"Here you can combine multiple screens into a single cluster and draw huge images saved in OCIF5 format. There's some useful tips for best experience:",
"• Use maximum size constructions for each screen (8x6 blocks)",
"• Connect more power sources to screens if they're blinking",
" "
}
if config.map then
table.insert(lines, {color = 0xE1E1E1, text = "Current cluster properties:"})
table.insert(lines, " ")
local width, height = #config.map[1], #config.map
table.insert(lines, width .. "x" .. height .. " screen blocks")
table.insert(lines, width * baseResolutionWidth .. "x" .. height * baseResolutionHeight .. " OpenComputers pixels")
table.insert(lines, width * baseResolutionWidth * 2 .. "x" .. height * baseResolutionHeight * 4 .. " pixels using Braille font")
else
print("Файл " .. tostring(args[2]) .. " не найден. Используйте абсолютный путь к файлу, добавив / в начало")
table.insert(lines, {color = 0xE1E1E1, text = "Calibrate your system before starting"})
end
elseif args[1] == "calibrate" then
fs.remove(pathToConfigFile)
loadConfig()
elseif args[1] == "clear" then
loadConfig()
multiScreenClear(tonumber(args[2] or 0x000000))
else
loadConfig()
print("Использование программы:")
print(" MultiScreen calibrate - перекалибровать мониторы")
print(" MultiScreen draw <путь к изображению> - отобразить изображение из файла на мониторах")
print(" MultiScreen clear <цвет> - очистить мониторы с указанным цветом (черным по умолчанию)")
addTextBox(lines)
local actionComboBox = layout:addChild(GUI.comboBox(1, 1, elementWidth, 3, 0xEEEEEE, 0x2D2D2D, 0x3C3C3C, 0x888888))
actionComboBox:addItem("Draw image")
actionComboBox:addItem("Clear screens")
actionComboBox:addItem("Calibrate")
local filesystemChooser = layout:addChild(GUI.filesystemChooser(1, 1, elementWidth, 3, 0xE1E1E1, 0x888888, 0x3C3C3C, 0x888888, nil, "Open", "Cancel", "Choose file", "/"))
filesystemChooser:setMode(GUI.IO_MODE_OPEN, GUI.IO_MODE_FILE)
filesystemChooser:addExtensionFilter(".pic")
local colorSelector = layout:addChild(GUI.colorSelector(2, 2, elementWidth, 3, config.backgroundColor, "Choose color"))
local actionButton = addButton("Next")
actionComboBox.onItemSelected = function()
filesystemChooser.hidden = actionComboBox.selectedItem ~= 1
colorSelector.hidden = actionComboBox.selectedItem ~= 2
actionButton.disabled = actionComboBox.selectedItem == 1 and (not filesystemChooser.path or not config.map)
end
filesystemChooser.onSubmit = function()
actionComboBox.onItemSelected()
mainContainer:drawOnScreen()
end
actionButton.onTouch = function()
if actionComboBox.selectedItem == 1 then
local file = io.open(filesystemChooser.path, "rb")
local signature = file:read(4)
if signature == "OCIF" then
local encodingMethod = string.byte(file:read(1))
if encodingMethod == 5 then
local width = bit32.byteArrayToNumber({string.byte(file:read(2), 1, 2)})
local height = bit32.byteArrayToNumber({string.byte(file:read(2), 1, 2)})
clearScreens()
local background, foreground, currentBackground, currentForeground, currentAddress
for y = 1, height do
for x = 1, width do
background = color.to24Bit(string.byte(file:read(1)))
foreground = color.to24Bit(string.byte(file:read(1)))
file:read(1)
local xMonitor = math.ceil(x / baseResolutionWidth)
local yMonitor = math.ceil(y / baseResolutionHeight)
if config.map[yMonitor] and config.map[yMonitor][xMonitor] then
if currentAddress ~= config.map[yMonitor][xMonitor] then
GPUProxy.bind(config.map[yMonitor][xMonitor], false)
GPUProxy.setBackground(background)
GPUProxy.setForeground(foreground)
currentAddress, currentBackground, currentForeground = config.map[yMonitor][xMonitor], background, foreground
end
if currentBackground ~= background then
GPUProxy.setBackground(background)
currentBackground = background
end
if currentForeground ~= foreground then
GPUProxy.setForeground(foreground)
currentForeground = foreground
end
GPUProxy.set(x - (xMonitor - 1) * baseResolutionWidth, y - (yMonitor - 1) * baseResolutionHeight, fs.readUnicodeChar(file))
end
end
end
file:close()
GPUProxy.bind(mainScreenAddress, false)
GUI.alert("Done.")
else
file:close()
GUI.alert("Wrong encodingMethod: " .. tostring(encodingMethod))
end
else
file:close()
GUI.alert("Wrong signature: " .. tostring(signature))
end
elseif actionComboBox.selectedItem == 2 then
config.backgroundColor = colorSelector.color
saveConfig()
clearScreens()
else
layout:removeChildren()
addTextBox({
{color = 0xE1E1E1, text = "Screen cluster calibration"},
" ",
"Specify required count of screens (not screen blocks, screens!) by horizontal and vertical"
})
local hSlider = layout:addChild(GUI.slider(1, 1, elementWidth, 0x66DB80, 0x0, 0xFFFFFF, 0xAAAAAA, 1, 10, 5, false, "Screens by horizontal: ", ""))
hSlider.roundValues = true
hSlider.height = 2
local vSlider = layout:addChild(GUI.slider(1, 1, elementWidth, 0x66DB80, 0x0, 0xFFFFFF, 0xAAAAAA, 1, 10, 4, false, "Screens by vertical: ", ""))
vSlider.roundValues = true
vSlider.height = 2
addButton("Next").onTouch = function()
local connectedCount = -1
for address in component.list("screen") do
connectedCount = connectedCount + 1
end
hSlider.value, vSlider.value = math.floor(hSlider.value), math.floor(vSlider.value)
local specifiedCount = hSlider.value * vSlider.value
if specifiedCount <= connectedCount then
layout:removeChildren()
addTextBox({
{color = 0xE1E1E1, text = "Screen cluster calibration"},
" ",
"Touch highlighted screen with your hand once. After touching all of screens calibration will be finished"
})
local SSX, SSY = 1, 1
local function screenObjectDraw(object)
buffer.drawRectangle(object.x, object.y, object.width, object.height, (SSX == object.SX and SSY == object.SY) and 0x22FF22 or 0xE1E1E1, 0x0, " ")
end
local function newScreen(SX, SY)
local object = GUI.object(1, 1, 8, 3)
object.draw = screenObjectDraw
object.SX = SX
object.SY = SY
return object
end
local function newScreenLine(SY)
local lineLayout = GUI.layout(1, 1, layout.width, 3, 1, 1)
lineLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)
lineLayout:setSpacing(1, 1, 2)
for SX = 1, hSlider.value do
lineLayout:addChild(newScreen(SX, SY))
end
return lineLayout
end
for SY = 1, vSlider.value do
layout:addChild(newScreenLine(SY))
end
mainContainer:drawOnScreen()
clearScreens(0x0)
config.map = {}
local hue, hueStep = 0, 360 / specifiedCount
while true do
local e1, e2 = event.pull("touch")
if e2 ~= mainScreenAddress then
GPUProxy.bind(e2, false)
GPUProxy.setResolution(baseResolutionWidth, baseResolutionHeight)
GPUProxy.setBackground(color.HSBToInteger(hue, 1, 1))
GPUProxy.setForeground(0x0)
GPUProxy.fill(1, 1, baseResolutionWidth, baseResolutionHeight, " ")
local text = "Screen " .. SSX .. "x" .. SSY .. " has been calibrated"
GPUProxy.set(math.floor(baseResolutionWidth / 2 - unicode.len(text) / 2), math.floor(baseResolutionHeight / 2), text)
GPUProxy.bind(mainScreenAddress, false)
config.map[SSY] = config.map[SSY] or {}
config.map[SSY][SSX] = e2
SSX, hue = SSX + 1, hue + hueStep
if SSX > hSlider.value then
SSX, SSY = 1, SSY + 1
if SSY > vSlider.value then
saveConfig()
break
end
end
mainContainer:drawOnScreen()
end
end
GUI.alert("All screens has been successfully calibrated")
mainMenu()
else
GUI.alert("Invalid count of connected screens. You're specified " .. specifiedCount .. " of screens, but there's " .. connectedCount .. " connected screens")
end
end
mainContainer:drawOnScreen()
end
end
actionComboBox.onItemSelected()
mainContainer:drawOnScreen(force)
end
--------------------------------------------------------------------------------------------------------------------------------------------
return multiScreen
--------------------------------------------------------------------------------
mainMenu(true)
mainContainer:startEventHandling()