Дальнейший рефакторинг

This commit is contained in:
igor 2017-11-02 04:14:08 +03:00
parent 405112381d
commit ebc975a162
3 changed files with 77 additions and 73 deletions

View File

@ -351,7 +351,7 @@
url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/doubleBuffering.lua",
type="Library",
preloadFile=true,
version=1.35,
version=1.36,
},
{
path="/lib/compressor.lua",

View File

@ -2,8 +2,8 @@
| ----- |
| [О библиотеке](#О-библиотеке) |
| [Установка](#Установка) |
| [Свойства библиотеки](#Параметры-библиотеки) |
| [Методы библиотеки](#Методы-библиотеки) |
| [buffer.getResolution](#buffergetresolution-int-width-int-height) |
| [buffer.setResolution](#buffersetresolution-width-height-) |
| [buffer.bindScreen](#bufferbindscreen-address-) |
| [buffer.bindGPU](#bufferbindgpu-address-) |
@ -18,6 +18,8 @@
| [buffer.square](#buffersquare-x-y-width-height-background-foreground-symbol-transparency-) |
| [buffer.clear](#bufferclear-color-transparency-) |
| [buffer.text](#buffertext-x-y-color-text-transparency-) |
| [buffer.formattedText](#bufferformattedtext-x-y-text-) |
| [buffer.image](#bufferimage-x-y-picture-) |
| [Методы полупиксельной отрисовки:](#Методы-полупиксельной-отрисовки) |
| [buffer.semiPixelSet](#buffersemipixelset-x-y-color-) |
| [buffer.semiPixelSquare](#buffersemipixelsquare-x-y-width-height-color-) |
@ -35,7 +37,7 @@
О библиотеке
======
DoubleBuffering - низкоуровневая библиотека для эффективного использования ресурсов GPU и отрисовки содержимого экрана с предельной скоростью. К примеру, с ее помощью реализован наш игровой движок с динамическим освещением сцен, а также небольшая игра на алгоритме рейкастинга, выдающие более чем достойные значения FPS:
DoubleBuffering - низкоуровневая библиотека для эффективного использования ресурсов GPU и отрисовки содержимого экрана с предельно возможной скоростью. К примеру, с ее помощью реализован наш игровой движок с динамическим освещением сцен, а также небольшая игра на алгоритме рейкастинга, выдающие более чем достойные значения FPS:
![Imgur](http://i.imgur.com/YgL9fCo.png?1)
@ -53,6 +55,7 @@ DoubleBuffering - низкоуровневая библиотека для эф
Для получения данных о пикселях используются специальные методы, преобразующие экранные координаты в индексы экранного буфера и наоборот, подробнее об этом написано ниже в разделе "**Вспомогательные методы**".
Кроме того, библиотека не обращается ни к одной lua-таблице напрямую, заменяя их на переменные-аналоги и избегая при этом расчетов данных хеш-таблиц: к примеру, каждый метод GPU экранирован, и вместо gpu.setBackground используется GPUSetBackground(). При грамотной реализации такой подход колоссально увеличивает производительность, не нагружая при этом Lua GC.
Установка
======
@ -68,20 +71,13 @@ DoubleBuffering - низкоуровневая библиотека для эф
pastebin run vTM8nbSZ
Свойства библиотеки
======
| Тип свойства | Свойство |Описание |
| ------ | ------ | ------ |
| *int* | buffer.**width**| Текущее разрешение буфера по ширине |
| *int* | buffer.**height**| Текущее разрешение буфера по высоте |
| *table* | buffer.**GPUProxy**| Указатель на proxy компонента видеокарты, с которой работает буфер |
| *table* | buffer.**currentFrame**| Указатель на таблицу с пиксельными данными, содержащая то, что в данный момент отображено на экране. Она имеет структуру ```{ 0xFFFFFF, 0x000000, "Q", 0xFFFFFF, 0x000000, "W", ... }```, где первый элемент - цвет фона, второй - цвет текста, третий - символ. И так до конца размера буфера |
| *table* | buffer.**newFrame**| Указатель на таблицу с пиксельными данными, содержащая то, что пользователь отрисовывает в него в данный момент. Структура аналогична предыдущей |
Основные методы
======
buffer.**getResolution**(): *int* width, *int* height
-----------------------------------------------------------
Получить разрешение экранного буфера. Для удобства также имеются методы buffer.**getWidth**() и buffer.**getHeight**().
buffer.**setResolution**( width, height )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
@ -97,7 +93,7 @@ buffer.**bindScreen**( address )
| ------ | ------ | ------ |
| *string* | address | Адрес компонента экрана |
Связать используемую буфером видеокарту с указанным компонентом экрана. Содержимое буфера при этом будет заполнено черными пикселями с символом пробела.
Связать используемую буфером видеокарту с указанным адресом компонента экрана. Содержимое буфера при этом будет очищено черными пикселями с символом пробела.
buffer.**bindGPU**( address )
-----------------------------------------------------------
@ -105,7 +101,11 @@ buffer.**bindGPU**( address )
| ------ | ------ | ------ |
| *string* | address | Адрес компонента видеокарты |
Изменить используемую буфером видеокарту на указанную. Содержимое буфера при этом будет заполнено черными пикселями с символом пробела.
Изменить используемую буфером видеокарту на указанную. Содержимое буфера при этом будет очищено черными пикселями с символом пробела.
buffer.**getGPUProxy**( ): *table* GPUProxy
-----------------------------------------------------------
Получить указатель на proxy используемого буфером компонента видеокарты.
Методы отрисовки
======
@ -211,6 +211,16 @@ buffer.**text**( x, y, color, text, transparency )
Нарисовать текст указанного цвета поверх имеющихся пикселей. Цвет фона при этом остается прежним. Можно также указать опциональную прозрачность текста текста в диапазоне [0; 100].
buffer.**formattedText**( x, y, text )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| *int* | x | Координата текста по оси x |
| *int* | y | Координата текста по оси y |
| *string* | text | Текст |
Аналогичен методу buffer.**text**(), однако поддерживает цветовое форматирование. По умолчанию цвет текста имеет значение 0xFFFFFF, для его изменения используйте синтаксическую вставку вида **\#RRGGBB**. К примеру, "Hello world, **\#FF00FF**this is formatted text!".
buffer.**image**( x, y, picture )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
@ -294,7 +304,7 @@ buffer.**flush**( [width, height] )
Метод, устанавливающий разрешение экранного буфера равным указанному и заполняющий его черными пикселями с символом пробела. В отличие от buffer.**setResolution** не изменяет текущего разрешения GPU. Если опциональные аргументы не указаны, то размер буфера становится эквивалентным текущему разрешению GPU.
buffer.**getIndexByCoordinates**( x, y ): int index
buffer.**getIndex*( x, y ): int index
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
@ -303,7 +313,7 @@ buffer.**getIndexByCoordinates**( x, y ): int index
Метод, преобразующий экранные координаты в индекс экраннного буфера. К примеру, пиксель 2x1 имеет индекс буфера 4, а пиксель 3x1 имеет индекс буфера 7.
buffer.**getCoordinatesByIndex**( index ): int x, int y
buffer.**getCoordinates**( index ): int x, int y
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
@ -330,17 +340,20 @@ buffer.**rawGet**( index ): int background, int foreground, char symbol
Метод, возвращающий соответствующие значения цветов и символа пикселя с указанным индексом.
Практический пример #1
Практический пример
======
```lua
-- Подключаем библиотеку
-- Подключаем библиотеки
local buffer = require("doubleBuffering")
local image = require("image")
-- Загружаем и рисуем изображение с лукошком с малиной
-----------------------------------------------------------------------------------------------
-- Загружаем и рисуем изображение
buffer.image(1, 1, image.load("/MineOS/Pictures/Raspberry.pic"))
-- Заполняем буфер черным цветом с прозрачностью 60%, чтобы малина на фоне была чуть темнее
buffer.clear(0x0, 60)
-- Заполняем буфер черным цветом с прозрачностью 60%, чтобы изображение было чуть темнее
buffer.clear(0x0, 0.6)
-- Рисуем 10 квадратиков, заполненных случайным цветом
local x, y, xStep, yStep = 2, 2, 4, 2

View File

@ -14,7 +14,7 @@ local drawLimitX1, drawLimitX2, drawLimitY1, drawLimitY2
local GPUProxy, GPUProxyGetResolution, GPUProxySetResolution, GPUProxyBind, GPUProxyGetBackground, GPUProxyGetForeground, GPUProxySetBackground, GPUProxySetForeground, GPUProxyGet, GPUProxySet
local mathCeil, mathFloor, mathModf, mathAbs = math.ceil, math.floor, math.modf, math.abs
local tableInsert = table.insert
local tableInsert, tableConcat = table.insert, table.concat
local colorBlend = color.blend
local unicodeLen, unicodeSub = unicode.len, unicode.sub
@ -554,64 +554,67 @@ local function info(...)
GPUProxySetBackground(0x0)
GPUProxySetForeground(0xFFFFFF)
GPUProxyFill(1, bufferHeight, bufferWidth, 1, " ")
GPUProxySet(2, bufferHeight, table.concat(text, ", "))
GPUProxySet(2, bufferHeight, tableConcat(text, ", "))
GPUProxySetBackground(b)
GPUProxySetForeground(f)
end
local function calculateDifference(index, indexPlus1, indexPlus2)
local somethingIsChanged =
currentFrame[index] ~= newFrame[index] or
currentFrame[indexPlus1] ~= newFrame[indexPlus1] or
currentFrame[indexPlus2] ~= newFrame[indexPlus2]
currentFrame[index] = newFrame[index]
currentFrame[indexPlus1] = newFrame[indexPlus1]
currentFrame[indexPlus2] = newFrame[indexPlus2]
return somethingIsChanged
end
local function draw(force)
-- local oldClock = os.clock()
local changes, index, indexStepOnEveryLine, indexPlus1, indexPlus2, sameCharArray, x, xCharCheck, indexCharCheck, indexCharCheckPlus1, indexCharCheckPlus2, currentForeground = {}, getIndex(drawLimitX1, drawLimitY1), (bufferWidth - drawLimitX2 + drawLimitX1 - 1) * 3
local changes, index, indexStepOnEveryLine, indexPlus1, indexPlus2, equalChars, x, charX, charIndex, charIndexPlus1, charIndexPlus2, currentForeground = {}, getIndex(drawLimitX1, drawLimitY1), (bufferWidth - drawLimitX2 + drawLimitX1 - 1) * 3
for y = drawLimitY1, drawLimitY2 do
x = drawLimitX1
while x <= drawLimitX2 do
indexPlus1, indexPlus2 = index + 1, index + 2
if calculateDifference(index, indexPlus1, indexPlus2) or force then
sameCharArray = { currentFrame[indexPlus2] }
xCharCheck, indexCharCheck = x + 1, index + 3
while xCharCheck <= drawLimitX2 do
indexCharCheckPlus1, indexCharCheckPlus2 = indexCharCheck + 1, indexCharCheck + 2
-- Determine if some pixel data was changed (or if <force> argument was passed)
if
currentFrame[index] ~= newFrame[index] or
currentFrame[indexPlus1] ~= newFrame[indexPlus1] or
currentFrame[indexPlus2] ~= newFrame[indexPlus2] or
force
then
-- Make pixel at both frames equal
currentFrame[index] = newFrame[index]
currentFrame[indexPlus1] = newFrame[indexPlus1]
currentFrame[indexPlus2] = newFrame[indexPlus2]
-- Look for pixels with equal chars from right of current pixel
equalChars = {currentFrame[indexPlus2]}
charX, charIndex = x + 1, index + 3
while charX <= drawLimitX2 do
charIndexPlus1, charIndexPlus2 = charIndex + 1, charIndex + 2
-- Pixels becomes equal only if they have same background and (whitespace char or same foreground)
if
currentFrame[index] == newFrame[indexCharCheck] and
currentFrame[index] == newFrame[charIndex] and
(
newFrame[indexCharCheckPlus2] == " " or
currentFrame[indexPlus1] == newFrame[indexCharCheckPlus1]
newFrame[charIndexPlus2] == " " or
currentFrame[indexPlus1] == newFrame[charIndexPlus1]
)
then
calculateDifference(indexCharCheck, indexCharCheckPlus1, indexCharCheckPlus2)
tableInsert(sameCharArray, currentFrame[indexCharCheckPlus2])
-- Make pixel at both frames equal
currentFrame[charIndex] = newFrame[charIndex]
currentFrame[charIndexPlus1] = newFrame[charIndexPlus1]
currentFrame[charIndexPlus2] = newFrame[charIndexPlus2]
tableInsert(equalChars, currentFrame[charIndexPlus2])
else
break
end
indexCharCheck, xCharCheck = indexCharCheck + 3, xCharCheck + 1
charIndex, charX = charIndex + 3, charX + 1
end
-- Group pixels that need to be drawn by background and foreground
changes[currentFrame[index]] = changes[currentFrame[index]] or {}
changes[currentFrame[index]][currentFrame[indexPlus1]] = changes[currentFrame[index]][currentFrame[indexPlus1]] or {}
tableInsert(changes[currentFrame[index]][currentFrame[indexPlus1]], x)
tableInsert(changes[currentFrame[index]][currentFrame[indexPlus1]], y)
tableInsert(changes[currentFrame[index]][currentFrame[indexPlus1]], table.concat(sameCharArray))
tableInsert(changes[currentFrame[index]][currentFrame[indexPlus1]], tableConcat(equalChars))
x, index = x + #sameCharArray - 1, index + #sameCharArray * 3 - 3
x, index = x + #equalChars - 1, index + (#equalChars - 1) * 3
end
x, index = x + 1, index + 3
@ -620,17 +623,18 @@ local function draw(force)
index = index + indexStepOnEveryLine
end
for background in pairs(changes) do
-- Draw grouped pixels on screen
for background, foregrounds in pairs(changes) do
GPUProxySetBackground(background)
for foreground in pairs(changes[background]) do
for foreground, pixels in pairs(foregrounds) do
if currentForeground ~= foreground then
GPUProxySetForeground(foreground)
currentForeground = foreground
end
for i = 1, #changes[background][foreground], 3 do
GPUProxySet(changes[background][foreground][i], changes[background][foreground][i + 1], changes[background][foreground][i + 2])
for i = 1, #pixels, 3 do
GPUProxySet(pixels[i], pixels[i + 1], pixels[i + 2])
end
end
end
@ -687,17 +691,4 @@ return {
scrollBar = scrollBar,
horizontalScrollBar = horizontalScrollBar,
customImage = customImage,
}
}