| Содержание |
| ----- |
| [О библиотеке](#О-библиотеке) |
| [Установка](#Установка) |
| [Свойства библиотеки](#Параметры-библиотеки) |
| [Методы библиотеки](#Методы-библиотеки) |
| [    buffer.setResolution](#buffersetresolution-width-height-) |
| [    buffer.bindScreen](#bufferbindscreen-address-) |
| [    buffer.bindGPU](#bufferbindgpu-address-) |
| [Методы отрисовки](#Методы-отрисовки) |
| [    buffer.draw](#bufferdraw-force-) |
| [    buffer.setDrawLimit](#buffersetdrawlimit-x1-y1-x2-y2-) |
| [    buffer.getDrawLimit](#buffergetdrawlimit--int-x1-int-y1-int-x2-int-y2) |
| [    buffer.copy](#buffercopy-x-y-width-height--table-pixeldata) |
| [    buffer.paste](#bufferpaste-x-y-pixeldata-) |
| [    buffer.set](#bufferpaste-x-y-pixeldata-) |
| [    buffer.get](#bufferpaste-x-y-pixeldata-) |
| [    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.semiPixelSet](#buffersemipixelset-x-y-color-) |
| [    buffer.semiPixelSquare](#buffersemipixelsquare-x-y-width-height-color-) |
| [    buffer.semiPixelLine](#buffersemipixelline-x1-y1-x2-y2-color-) |
| [    buffer.semiPixelCircle](#buffersemipixelcircle-xcenter-ycenter-radius-color-) |
| [    buffer.semiPixelBezierCurve](#buffersemipixelbeziercurve-points-color-precision-) |
| [Вспомогательные методы:](#Вспомогательные-методы) |
| [    buffer.flush](#bufferflush-width-height-) |
| [    buffer.getIndexByCoordinates](#buffergetindexbycoordinates-x-y--int-index) |
| [    buffer.getCoordinatesByIndex](#buffergetcoordinatesbyindex-index--int-x-int-y) |
| [    buffer.rawSet](#bufferrawset-index-background-foreground-symbol-) |
| [    buffer.rawGet](#bufferrawget-index--int-background-int-foreground-char-symbol) |
| [Практический пример #1](#Практический-пример-1) |


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

![Imgur](http://i.imgur.com/YgL9fCo.png?1)

![Imgur](http://i.imgur.com/yHEwiNo.png?1)

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

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

![meow](http://i60.fastpic.ru/big/2015/1026/8a/4c72bfcbe8fbee5993bfd7a058a5f88a.png)

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

![Imgur](http://i.imgur.com/2Pkne53.png)

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


Установка
======

| Библиотека | Функционал |
| ------ | ------ |
| *[doubleBuffering](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/doubleBuffering.lua)* | Данная библиотека |
| *[color](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/color.lua)* | Низкоуровневая библиотека для работы с цветом, предоставляющая методы получения цветовых каналов, различные палитры и конвертацию цвета в 8-битный формат |
| *[image](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/image.lua)* | Библиотека, реализующая стандарт изображений для OpenComputers и методы их обработки: транспонирование, обрезку, поворот, отражение и т.д. |
| *[OCIF](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/ImageFormatModules/OCIF.lua)* | Модуль формата изображения OCIF (OpenComputers Image Format) для библиотеки image, написанный с учетом особенностей мода и реализующий эффективное сжатие пиксельных данных |

Вы можете использовать имеющиеся выше ссылки для установки зависимостей вручную или запустить автоматический [установщик](https://pastebin.com/vTM8nbSZ), загружающий все необходимые файлы за вас:

    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.**setResolution**( width, height )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| *int* | width | Ширина буфера |
| *int* | height | Высота буфера |

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

buffer.**bindScreen**( address )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| *string* | address | Адрес компонента экрана |

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

buffer.**bindGPU**( address )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| *string* | address | Адрес компонента видеокарты |

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

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

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 | Символ, которым будет заполнен прямоугольник |
| [*int* | transparency] | Опциональная прозрачность прямоугольника |

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

buffer.**clear**( [color, transparency] )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| [*int* | background] | Опциональный цвет фона |
| [*int* | transparency] | Опциональная прозрачность фона |

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

buffer.**text**( x, y, color, text, transparency )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| *int* | x | Координата текста по оси x |
| *int* | y | Координата текста  по оси y |
| *int* | foreground | Цвет текста |
| *string* | text | Текст |
| [*int* | transparency] | Опциональная прозрачность текста |

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

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 | Точность отрисовки кривой Безье. Чем меньше - тем точнее |

Растеризация [кривой Безье](https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%B2%D0%B0%D1%8F_%D0%91%D0%B5%D0%B7%D1%8C%D0%B5) с указанным цветом.

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

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

buffer.**flush**( [width, height] )
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| *int* | width | Ширина буфера |
| *int* | height | Высота буфера |

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

buffer.**getIndexByCoordinates**( x, y ): int index
-----------------------------------------------------------
| Тип | Аргумент | Описание |
| ------ | ------ | ------ |
| *int* | x | Координата пикселя экрана по оси x |
| *int* | y | Координата пикселя экрана по оси y |

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

buffer.**getCoordinatesByIndex**( 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 | Индекс экранного буфера |

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

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

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

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

-- Рисуем 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](http://i.imgur.com/wvu0jeh.png?1)
