Как всегда, видеоверсия доклада доступна на официальном сайте Haxe.
Последний раз Джошуа выступал с докладом об OpenFL 5 лет назад в Париже. За эти годы OpenFL прошел большой путь.
Итак, в 2013 году OpenFL был представлен сообществу как попытка собрать в себя лучшее из того, что было предпринято для создания кроссплатформенного фреймворка, который бы одинаково вел себя и на десктопе, и на мобильных платформах и в браузерах. Напомню, что OpenFL появился как форк NME, в котором упор в основном делается на мобильные и настольные операционные системы, а поддержка html5 в настоящее время не является приоритетной (хотя скомпилировать приложение в js возможно двумя способами).
Значительным отличием OpenFL от NME является то, что большая часть функционала была переписана на Haxe. Т.к. существенная часть кода NME была написана на C++, то для поддержки html5 необходима своя версия “бэкэнда”, у которой были свои собственные баги и немного другое поведение. Джошуа со своей стороны хотел избежать таких проблем, максимально унифицировав кодовую базу и переписав ее на Haxe.
Такое решение переписать код было обусловлено также архитектурными ограничениями. Примерами таких ограничений являлись:
Что же было достигнуто за прошедшие 5 лет:
Далее Джошуа перечислил главные изменения в кодовой базе OpenFL за прошедшие 5 лет:
Как и ожидалось, Джошуа анонсировал и выпустил во время конференции восьмую версию OpenFL. Что же в ней нового?
Во-первых, в OpenFL 8 был переработан класс Tilemap, предназначенный для батчинга при отрисовке квадов. За счет этого работа с ним упростилась, а скорость значительно повысилась (примерно в 3 раза по сравнению с предыдущей версией).
Для группировки и построения иерархий тайлов добавлен класс TileContainer (аналог DisplayObjectContainer).
Однако работа над этим API еще не завершена, и Джошуа ищет пути его возможного улучшения, например, рассматривает возможность добавления метода hitTest() для отдельных тайлов, а также методов для автоматической “нарезки” изображений на тайлы.
Tilemap работает на всех платформах и со всеми рендерами, используя наиболее эффективные для них способы отрисовки.
Новыми свойствами объектов типа Tilemap, влияющими на скорость отрисовки, являются tileAlphaEnabled и tileColorTransformEnabled (по-умолчанию они включены).
Однако, в случае, если вам не нужна поддержка цветовых трансформаций тайлов, то установка tileColorTransformEnabled в false может дать ~30% прироста скорости (благодаря тому, что на GPU будет передаваться меньше данных), отключение tileAlphaEnabled также даст небольшой прирост.
В качестве обязательных параметров конструктора Tilemap необходимо передать его размеры (позже их можно будет изменить) - на платформах, где используется софтварный рендер, под объект Tilemap будет создан “холст” (BitmapData), на который будут рисоваться тайлы.
У Tilemap есть ряд методов для манипуляции иерархией тайлов, добавляемых в него. Эти методы как по названию, так и по поведению похожи на методы DisplayObjectContainer.
Тайлам для отрисовки изображений необходимы 2 свойства:
Помимо этих свойств у тайлов есть такие свойства как matrix, scaleX, scaleY, x, y, rotation, alpha, colorTransform и даже shader (но использование шейдеров “ломает” батчинг).
Так что Tilemap API довольно сильно изменился в лучшую сторону по сравнению с тем, каким он был год назад.
Новой фичей OpenFL 8 является новый метод drawQuads(), который предлагается как замена старому drawTiles() (хотя по моему мнению drawQuads() не сможет заменить его полностью, т.к. имеет меньше возможностей, но для этого у Джошуа были веские причины).
drawQuads() также может использоваться для батчинга, но за счет того, что он не поддерживает иерархии квадов, цветовые трансформации для отдельных квадов, и даже прозрачность, то работает он еще быстрее, чем Tilemap. Так что для простых случаев, когда вам нужна только трансформация квадов (положение, поворот, масштаб), то можно воспользоваться этим методом.
Данный метод также работает на всех платформах со всеми рендерами.
Как видно drawQuads() в чем-то похож на метод drawTriangles(): вы задаете метод заливки и вызываете данный метод, передавая ему массивы данных о прямоугольниках, индексы этих прямоугольников для отрисовки, а также трансформации отдельных квадов. При этом если для каждого квада в массиве transforms передавать по 2 значения, то они будут интерпретироваться как данные о положении квадов, если по 6 значений - то как коэффициенты матрицы трансформации, а можно просто не передавать этот массив - тогда квады будут отрисованы в том же положении, как и в исходном атласе.
Для сравнения скорости работы новых API Джошуа провел ряд тестов на своей машине, которые показали следующие результаты в BunnyMark с 200 тыс. кроликов:
Так что результаты явно в пользу нового OpenFL.
В OpenFL 8 также была переработана система шейдеров, в которой:
Пример наследования для шейдеров, с сохранением типизации кода:
Как видно у шейдеров есть 2 поля, заданных с помощью метаданных - @:glVertexSource и @:glFragmentSource. Используя эти метаданные, макрос создает типизированный код шейдера, такой код на С++ будет работать быстрее.
Для уменьшения дублирования кода в шейдерах добавлены директивы #pragma header и #pragma body. Макрос при нахождении этих директив подставит вместо них соответствующий код из родительского шейдера, таким образом сохранится совместимость с ним. Ну а далее вы можете добавить и собственный код. На слайде в коде шейдера модифицируется цвет, получаемый на выходе из него. Также видно, что в CustomShader не переопределяется метаданные @:glVertexSource, это значит, что код для вершинного шейдера будет взят из родителя - из DisplayObjectShader.
Пример наследования шейдеров с использованием свойств glVertexSource и glFragmentSource - такой метод также возможен, но теряется типизация кода - все становится “динамиком”.
Как уже говорилось, шейдеры можно можно использовать для DisplayObject’ов и Graphics.beginShaderFill(), а также для фильтров. Однако при использовании шейдеров в первых двух случаях отрисовка происходит в один проход, а при использовании фильтров с шейдерами всегда происходит сначала отрисовка в промежуточную текстуру, а затем отрисовка с использованием шейдера из фильтра.
Новой фичей OpenFL 8 является возможность вызывать собственный код при отрисовке объектов (пока что находится в состоянии беты, так что API может поменяться). Для этого необходимо подписаться на одно из следующих событий у DisplayObject’а: RenderEvent.RENDER_CAIRO, RenderEvent.RENDER_CANVAS, RenderEvent.RENDER_DOM или RenderEvent.RENDER_OPENGL.
При этом в событии RenderEvent приходит необходимая для отрисовки объекта информация: сам рендерер, матрица трансформации и цветовая трансформация объекта.
Предполагается, что новое API заменит собой OpenGLView.
Пример использования нового API: как видно, мы подписываемся на событие отрисовки спрайта с помощью Canvas.
Также Джошуа еще раз отметил, что начиная с 7 версии OpenFL стал доступен в NPM, таким образом OpenFL можно использовать и в JavaScript и в Dart проектах. При этом NPM-версия идентична haxelib-версии библиотеки (в контексте JS, конечно же).
Джошуа надеется, что публикация OpenFL в NPM поможет популяризовать не только сам OpenFL, но и Haxe, например, в случаях когда потребуется портировать приложение с OpenFL JS на нативные платформы без использования electron и подобных решений.
Также на сайте OpenFL появился раздел с документацией по использованию OpenFL в NPM - http://www.openfl.org/learn/npm/getting-started/
Плюсом NPM-версии OpenFL по мнению Джошуа является поддержка hot reloading - при изменении кода он автоматически пересобирается и страница с проектом перезапускается. И Джошуа надеется, что данную фичу можно будет перенести и в haxelib-версию библиотеки.
Разработка OpenFL не останавливается и основными ее целями являются:
Также продолжается работа по поддержке консолей. Примерами игр на OpenFL, которые вышли на консолях, являются “Papers, Please” (PS Vita) и “Defenders quest” (игра уже вышла на XBox One, PS4, PS Vita, и в данный момент ведется портирование на Nintendo Switch).
Код для поддержки консолей предоставляется бесплатно, для этого нужно быть зарегистрированным разработчиком на соответствующей платформе.
За деталями можно обратиться к Lars Doucet.
И, наконец, вышла версия HaxeFlixel 4.4.0, которая теперь совместима с OpenFL 8. Джошуа сильно помог в этом процессе.