This is an old revision of the document!


BearLibTerminal / Общий дизайн

Основной целью библиотеки BearLibTerminal является (по крайней мере, так задумывалось) предоставление приложению окна, напоминающего внешним видом системную консоль, но куда более настраиваемого и заточенного больше под разработку roguelike игр. Вот, к примеру, как это окно может выглядеть. Найдите 10 отличий от оригиналов =)

Такое окно, впрочем, только лишь выглядит как терминал. То, как оно работает, сильно отличается от обычной системной консоли. Библиотека не предоставляет стандартных потоков ввода/вывода для чтения и записи. Вместо этого предоставляется сетка индивидуально адресуемых ячеек-знакомест, сцена.

Точнее, сцена это не одна сетка ячеек, а целый набор таких сеток, именуемых слоями. Для простой игры, вероятно, не потребуется более одного слоя, но иногда они могут быть незаменимы.

Каждая ячейка, в свою очередь, может содержать набор тайлов. Так как библиотека полностью поддерживает альфа-канал (прозрачность) изображений, возможность положить в ячейку несколько тайлов фактически означает возможность комбинации нескольких изображений в одно. Что сравнимо с генерацией изображение из частей на лету, например вместо подготовки всех возможных комбинаций. Следует отметить, что каждый тайл в “стопке” может иметь свой собственный цвет.

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

Теперь рассмотрим откуда эти тайлы берутся.

Тайлы и слоты

В библиотеке BearLibTerminal каждому коду символа может быть назначен свой тайл, например тайл для '@' или тайл для '#'. Диапазон кодов символов, используемый библиотекой – это basic multilingual plane Юникода. Это означает, что в наличии имеется около 65 тысяч слотов для тайлов.

Назначить одиночный тайл слоту очень просто:

terminal_set("0x5E: tile.png");

Что фактически замещает предыдущее содержимое слота новым изображением. В приведенном примере это был символ “циркумфлекс” или, по-простому, “крышечка”. С этого момента новый тайл может использоваться как и любой другой символ:

terminal_put(2, 1, 0x5E);
terminal_print(2, 2, "once again: ^");

Что даст примерно следующий результат:

Следует отметить, что размер тайла практически не ограничивается библиотекой. Можно использовать тайлы размером хоть с целое окно, например в качестве фонового изображения в меню. По умолчанию тайл выводится центрированным в ячейке, но это может быть легко переопределено.

Растровые тайлсеты

Назначение новых изображений-тайлов слотам поодиночке может быть утомительной задачей и вообще контрпродуктивно. BearLibTerminal позволяет загружать разом целые тайлсеты. Пусть есть некоторый тайлсет, состоящий из четырех изображений 16×16. Он может быть загружет практически так же, как и одиночный тайл:

terminal_set("0x1000: tileset.png, size=16x16");

Единственным отличием оказывается указание размера отдельного изображения в картинке-тайлсете. Библиотека разрежет картинку на кусочки и назначит их кодам символов. Порядок, в котором BearLibTerminal будет нарезать тайлсет фиксирован: строка за строкой, слева направо. По умолчанию тайлы назначаются последовательным слотам. В приведенном примере тайлы будут ассоциированы с четырьмя кодами символов, с 0x1000 по 0x1003 включительно.

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

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

terminal_set("0x5E: none; 0x1000: none");

Растровые шрифты и кодовые страницы

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

terminal_print("Unicode: β"); // UTF-8
Библиотека для вывода греческого символа “бета” попытается использовать тайл из слота U+03B2, по номеру назначенному стандартом Юникод. Но большинство растровых шрифтов представляют собой одну картинку с более-менее плотно упакованными символами, например:

Хотя символ “беты” имеет код 0x03B2 в Юникоде, в картинке шрифта он может располагаться где угодно. Например, в шрифтах для Dwarf Fortress, один из которых и продемонстрирован выше, символ “бета” располагается во второй колонке пятнадцатой строки, т. е. под номером 225. Что далеко от 0x03B2. И как ни выбирай стартовый код символа для тайлсета, расположить все символы в соответствии с их кодами по Юникоду не получится.

Для решения этой проблемы используются кодовые страницы, таблицы соответствия кодов символов двух кодовых пространств. В данном случае это таблица соответствия индексов тайлов в картинке кодам Юникода. Указав кодовую страницу при загрузке тайлсета можно заставить библиотеку разместить тайлы не в последовательных слотах, а в соответствии со списком:

terminal_set("font: Nobbins.png, size=9x12, codepage=437");

Коды в кодовой странице трактуются как смещение от стартового кода символа тайлсета. В приведенном примере библиотека возьмет соответсвие 225 индекса Юникоду (0x03B2 для кодовой страницы 437) и, добавив его к стартовому коду (где “font” это просто синоним числа ноль), поместит символ “беты” в корректный слот.

Так сложилось, что шрифты для Dwarf Fortress выполнены в кодовой странице 437. В библиотеку встроено несколько кодовых страниц, а именно 437, 866, 1250 and 1251. Однако, можно использовать любую кодовую страницу, например составленную вручную, указав имя файла с таблицей:

terminal_set("font: font.png, size=9x12, codepage=custom.txt");

Как можно заметить, используемый библиотекой основной шрифт – это просто тайлсет, загруженный со стартового кода символа “0”. В библиотеке имеется встроенный растровый шрифт, сгенерированный из шрифта Fixedsys Excelsior с кодовой страницей, идентичной набору символов WGL4. Этот шрифт устанавливается автоматически при инициализации библиотеки.

TrueType tilesets

Своеобразной киллер-фичей BearLibTerminal является возможность использовать шрифты TrueType в качестве источника для тайлсетов. Можно использовать их в качестве основного шрифта:

terminal_set("font: UbuntuMono-R.ttf, size=12");
И библиотека самостоятельно растеризует необходимые тайлы и поместит их в нужные слоты. Пример этого уже приводился в самом начале страницы:

TrueType тайлсеты работают практически так же, как и растровые. Можно загрузить несколько таких тайлсетов, назначив им разные стартовые коды символов. Однако, есть и различия.

Простейшее отличие заключается в том, как TrueType тайлсет понимает параметр “size”. В данном случае этот параметр означает размер, в который будет растеризован векторный глиф шрифта, и этот размер можно задать двумя способами:

  • size=12: задает среднюю высоту строчной буквы, в пикселях. Следует отметить, что в зависимости от гарнитуры, результирующий размер тайла может сильно отличаться.
  • size=8×16: задает непосредственно размер тайла. Библиотека постарается подобрать максимальный размер шрифта, который вписывается в указанные рамки.

Другим отличием является то, что смысл указываемой кодовой страницы фактически обратен таковому для растрового шрифта. Современные TrueType как правило имеют встроенную кодовую страницу для Юникода, так что библиотеке BearLibTerminal нет необходимости в помощи со стороны программиста, чтобы понять куда какие тайлы идут. Это также означает, что загрузка TrueType тайлсета начиная с какого-то произвольного стартового кода символа добавит смещение к изначально правильному расположению тайлов. Поэтому кодовая страница для TrueType-тайлсета описывает обратное соответствие: от кодов Юникода к относительным индексам. Это позволяет загрузить выбранный набор символов из TrueType шрифта в несколько последовательно расположенных слотов. Например:

terminal_set("0xE000: fontawesome.ttf, size=16x16, codepage=fontawesome.txt");
с учетом следующей “кодовой страницы”

0xF00C, 0xF062, 0xF001, 0xF0E7, 0xF013, 0xF043

поместит ровно шесть пиктограмм из шрифта FontAwesome в слоты с 0xE000 по 0xE005 включительно.

Tile alignment

As noted somewhere above, tiles have alignment property which affects how they are drawn relative to the position of a cell. All tiles in a tileset share the same alignment:

terminal_set("0xE000: tileset.png, size=10x20, align=center");
The default tile alignment is “center” and can be omitted when loading a tileset. This alignment is generally useful for character tiles because it places them in a usual way and allows for some size tolerance without visually breaking a line:

The other available tile alignments are: “top-left”, “bottom-left”, “top-right” and “bottom-right”. The top-left alignment is useful for tiles which are clearly bigger than one character cell, e. g. terrain tiles or monster pictures in a book:

The tile alignment can be further customized by specifying the size of an alignment region. The default size is 1×1 cell and can be overriden by the “bbox” attribute:

terminal_set("0xE000: tileset.png, size=20x20, align=center, bbox=2x1");
It can be useful for cases like multi-cell monsters or initial letters: