MineOS/Documentation/doubleBuffering.md
2017-12-10 19:13:34 +03:00

26 KiB
Raw Blame History

Содержание
О библиотеке
Установка
Методы библиотеки
buffer.getResolution
buffer.setResolution
buffer.bindScreen
buffer.bindGPU
Методы отрисовки
buffer.draw
buffer.setDrawLimit
buffer.getDrawLimit
buffer.copy
buffer.paste
buffer.set
buffer.get
buffer.square
buffer.clear
buffer.text
buffer.formattedText
buffer.image
Методы полупиксельной отрисовки:
buffer.semiPixelSet
buffer.semiPixelSquare
buffer.semiPixelLine
buffer.semiPixelCircle
buffer.semiPixelBezierCurve
Вспомогательные методы:
buffer.flush
buffer.getIndexByCoordinates
buffer.getCoordinatesByIndex
buffer.rawSet
buffer.rawGet
Практический пример #1

О библиотеке

DoubleBuffering - низкоуровневая библиотека для эффективного использования ресурсов GPU и отрисовки содержимого экрана с предельно возможной скоростью. К примеру, с ее помощью реализован наш игровой движок с динамическим освещением сцен, а также небольшая игра на алгоритме рейкастинга, выдающие более чем достойные значения FPS:

Imgur

Imgur

Сама суть библиотеки очень проста: в оперативной памяти хранится два массива, содержащих информацию о пикселях на экране. Первый хранит то, что отображено в данный момент, а второй - то, что пользователь желает отрисовать. После осуществления всех операций отрисовки пользователь вызывает метод buffer.draw(), затем система автоматически определяет изменившиеся пиксели, группирует их в промежуточный буфер, чтобы число GPU-операций было минимальным, а затем выводит изменения на экран.

По сравнению с стандартной отрисовкой время отображения сокращается в сотни и тысячи раз. На рисунке ниже наглядно показана эффективность библиотеки:

meow

Цена таких космических скоростей - повышенный расход оперативной памяти. Чтобы предельно уменьшить его, мы используем одномерную структуру экранных массивов вместо трехмерной:

Imgur

Для получения данных о пикселях используются специальные методы, преобразующие экранные координаты в индексы экранного буфера и наоборот, подробнее об этом написано ниже в разделе "Вспомогательные методы".

Кроме того, библиотека не обращается ни к одной lua-таблице напрямую, заменяя их на переменные-аналоги и избегая при этом расчетов данных хеш-таблиц: к примеру, каждый метод GPU экранирован, и вместо gpu.setBackground используется GPUSetBackground(). При грамотной реализации такой подход колоссально увеличивает производительность, не нагружая при этом Lua GC.

Установка

Библиотека Функционал
advancedLua Дополнение стандартных библиотек Lua множеством функций: быстрой сериализацией таблиц, переносом строк, методами обработки бинарных данных и т.д.
color Экструзия цветовых каналов, альфа-блендинг, поддержка различных палитр и конвертации цвета в 8-битный формат
image Реализация стандарта изображений для OpenComputers и базовые методы их обработки: транспонирование, обрезка, поворот, отражение и т.д.
OCIF Модуль формата изображения OCIF (OpenComputers Image Format) для библиотеки image, написанный с учетом особенностей мода и реализующий эффективное сжатие пиксельных данных
doubleBuffering Данная библиотека

Вы можете использовать имеющиеся выше ссылки для установки зависимостей вручную или запустить автоматический установщик, загружающий все необходимые файлы за вас:

pastebin run vTM8nbSZ

Основные методы

buffer.getResolution(): int width, int height

Получить разрешение экранного буфера. Для удобства также имеются методы buffer.getWidth() и buffer.getHeight().

buffer.setResolution( width, height )

Тип Аргумент Описание
int width Ширина буфера
int height Высота буфера

Установить разрешение экранного буфера и GPU равным указанному. Содержимое буфера при этом будет заполнено черными пикселями с символом пробела.

buffer.bindScreen( address )

Тип Аргумент Описание
string address Адрес компонента экрана

Связать используемую буфером видеокарту с указанным адресом компонента экрана. Содержимое буфера при этом будет очищено черными пикселями с символом пробела.

buffer.bindGPU( address )

Тип Аргумент Описание
string address Адрес компонента видеокарты

Изменить используемую буфером видеокарту на указанную. Содержимое буфера при этом будет очищено черными пикселями с символом пробела.

buffer.getGPUProxy( ): table GPUProxy

Получить указатель на proxy используемого буфером компонента видеокарты.

Методы отрисовки

buffer.draw( [force] )

Тип Аргумент Описание
[boolean force] Принудительная отрисовка

Отрисовать содержимое буфера на экран. Если имеется опциональный аргумент force, то содержимое буфера будет отрисовано полностью и вне зависимости от изменившихся пикселей.

buffer.setDrawLimit( x1, y1, x2, y2 )

Тип Аргумент Описание
int x1 Координата первой точки лимита отрисовки по оси x
int y1 Координата первой точки лимита отрисовки по оси y
int x2 Координата второй точки лимита отрисовки по оси x
int y2 Координата второй точки лимита отрисовки по оси y

Установить лимит отрисовки буфера до указанного. При этом любые операции, выходящие за границы лимита, будут игнорироваться. По умолчанию буфер всегда имеет лимит отрисовки в диапазонах x ∈ [1; buffer.width] и y ∈ [1; buffer.height]

buffer.getDrawLimit( ): int x1, int y1, int x2, int y2

Получить текущий лимит отрисовки.

buffer.copy( x, y, width, height ): table pixelData

Тип Аргумент Описание
int x Координата копируемой области по оси x
int y Координата копируемой области по оси y
int width Ширина копируемой области
int height Высота копируемой области

Скопировать содержимое указанной области из буфера и выдать в виде таблицы. Впоследствии можно использовать с buffer.paste(...).

buffer.paste( x, y, pixelData )

Тип Аргумент Описание
int x Координата вставки по оси x
int y Координата вставки по оси y
table pixelData Таблица со скопированной ранее областью буфера

Вставить скопированное содержимое буфера по указанным координатам.

buffer.set( x, y, background, foreground, symbol )

Тип Аргумент Описание
int x Координата по оси x
int y Координата по оси y
int background Цвет фона
int foreground Цвет символа
char symbol Символ

Установить значение конкретного пикселя на экране. Полезно для мелкого и точного редактирования.

buffer.get( x, y ): int background, int foreground, char symbol

Тип Аргумент Описание
int x Координата по оси x
int y Координата по оси y

Получить значение конкретного пикселя на экране.

buffer.square( x, y, width, height, background, foreground, symbol, transparency )

Тип Аргумент Описание
int x Координата прямоугольника по оси x
int y Координата прямоугольника по оси y
int width Ширина прямоугольника
int height Высота прямоугольника
int background Цвет фона прямоугольника
int foreground Цвет символов прямоугольника
char symbol Символ, которым будет заполнен прямоугольник
[float transparency] Опциональная прозрачность прямоугольника

Заполнить прямоугольную область указанными данными. При указании прозрачности в диапазоне [0.0; 1.0] прямоугольник будет накладываться поверх существующей информации, словно прозрачное стеклышко.

buffer.clear( [color, transparency] )

Тип Аргумент Описание
[int background] Опциональный цвет фона
[float transparency] Опциональная прозрачность фона

Работает как buffer.square(...), однако применяется сразу ко всем пикселям буфера. Если аргументов не передается, то буфер заполняется стандартным черным цветом и символом пробела. Удобно для быстрой очистки содержимого буфера.

buffer.text( x, y, color, text, transparency )

Тип Аргумент Описание
int x Координата текста по оси x
int y Координата текста по оси y
int foreground Цвет текста
string text Текст
[float transparency] Опциональная прозрачность текста

Нарисовать текст указанного цвета поверх имеющихся пикселей. Цвет фона при этом остается прежним. Можно также указать опциональную прозрачность текста текста в диапазоне [0.0; 1.0].

buffer.formattedText( x, y, text )

Тип Аргумент Описание
int x Координата текста по оси x
int y Координата текста по оси y
string text Текст

Аналогичен методу buffer.text(), однако поддерживает цветовое форматирование. По умолчанию цвет текста имеет значение 0xFFFFFF, для его изменения используйте синтаксическую вставку вида #RRGGBB. К примеру, "Hello world, #FF00FFthis is formatted text!".

buffer.image( x, y, picture )

Тип Аргумент Описание
int x Координата изображения по оси x
int y Координата изображения по оси y
table picture Загруженное изображение

Нарисовать загруженное через image.load(string path) изображение. Альфа-канал изображения также поддерживается.

Методы полупиксельной отрисовки

Все методы полупиксельной отрисовки позволяют избежать эффекта удвоения высоты пикселя консольной графики, используя специальные символы наподобие "▄". При этом передаваемые координаты по оси Y должны принадлежать промежутку [0; buffer.height * 2].

buffer.semiPixelSet( x, y, color )

Тип Аргумент Описание
int x1 Координата пикселя по оси x
int y1 Координата пикселя по оси y
int color Цвет пикселя

Установка пиксельного значения в указанной точке.

buffer.semiPixelSquare( x, y, width, height, color )

Тип Аргумент Описание
int x Координата прямоугольника по оси x
int y Координата прямоугольника по оси y
int width Ширина прямоугольника
int height Высота прямоугольника
int color Цвет прямоугольника

Отрисовка прямоугольника с указанными параметрами.

buffer.semiPixelLine( x1, y1, x2, y2, color )

Тип Аргумент Описание
int x1 Координата первой точки линии по оси x
int y1 Координата первой точки линии по оси y
int x2 Координата второй точки линии по оси x
int y2 Координата второй точки линии по оси y
int color Цвет линии

Растеризация отрезка указанного цвета

buffer.semiPixelCircle( xCenter, yCenter, radius, color )

Тип Аргумент Описание
int xCenter Координата центральной точки окружности по оси x
int yCenter Координата центральной точки окружности по оси y
int radius Радиус окружности
int color Цвет окружности

buffer.semiPixelBezierCurve( points, color, precision )

Тип Аргумент Описание
table points Таблица вида {{x = 32, y = 2}, {x = 2, y = 2}, {x = 2, y = 98}}, содержащая опорные точки для отрисовки кривой Безье
int color Цвет кривой Безье
float precision Точность отрисовки кривой Безье. Чем меньше - тем точнее

Растеризация кривой Безье с указанным цветом.

Вспомогательные методы

Ниже перечислены методы, используемые самой библиотекой или приложениями, требующими максимального быстродействия и рассчитывающими пиксельные данные буфера вручную. В большинстве случаев они не пригождаются, однако для ознакомления указаны.

buffer.flush( [width, height] )

Тип Аргумент Описание
int width Ширина буфера
int height Высота буфера

Метод, устанавливающий разрешение экранного буфера равным указанному и заполняющий его черными пикселями с символом пробела. В отличие от buffer.setResolution не изменяет текущего разрешения GPU. Если опциональные аргументы не указаны, то размер буфера становится эквивалентным текущему разрешению GPU.

buffer.*getIndex( x, y ): int index

Тип Аргумент Описание
int x Координата пикселя экрана по оси x
int y Координата пикселя экрана по оси y

Метод, преобразующий экранные координаты в индекс экраннного буфера. К примеру, пиксель 2x1 имеет индекс буфера 4, а пиксель 3x1 имеет индекс буфера 7.

buffer.getCoordinates( index ): int x, int y

Тип Аргумент Описание
int index Индекс экранного буфера

Метод, преобразующий индекс буфера в соответствующие ему координаты на экране.

buffer.rawSet( index, background, foreground, symbol )

Тип Аргумент Описание
int index Индекс экранного буфера
int background Цвет фона
int foreground Цвет символа
char symbol Символ

Метод, устанавливающий соответствующие значения цветов и символа пикселю с указанным индексом.

buffer.rawGet( index ): int background, int foreground, char symbol

Тип Аргумент Описание
int index Индекс экранного буфера

Метод, возвращающий соответствующие значения цветов и символа пикселя с указанным индексом.

Практический пример

-- Подключаем библиотеки
local buffer = require("doubleBuffering")
local image = require("image")

-----------------------------------------------------------------------------------------------

-- Загружаем и рисуем изображение
buffer.image(1, 1, image.load("/MineOS/Pictures/Raspberry.pic"))
-- Заполняем буфер черным цветом с прозрачностью 0.6, чтобы изображение было чуть темнее
buffer.clear(0x0, 0.6)

-- Рисуем 10 квадратиков, заполненных случайным цветом
local x, y, xStep, yStep = 2, 2, 4, 2
for i = 1, 10 do
	buffer.square(x, y, 6, 3, math.random(0x0, 0xFFFFFF), 0x0, " ")
	x, y = x + xStep, y + yStep
end

-- Рисуем желтую окружность
buffer.semiPixelCircle(22, 22, 10, 0xFFDB40)
-- Рисуем белую линию
buffer.semiPixelLine(2, 36, 35, 3, 0xFFFFFF)
-- Рисуем зеленую кривую Безье с точностью 0.01
buffer.semiPixelBezierCurve(
	{
		{ x = 2, y = 63},
		{ x = 63, y = 63},
		{ x = 63, y = 2}
	},
	0x44FF44,
	0.01
)

-- Выводим содержимое буфера на экран
buffer.draw()

Результат:

Imgur