Dagon 10 лет!

Проект стартовал 9 октября 2016 года, ровно 10 лет назад. Конечно, это не первая моя разработка в сфере геймдева, и я начал писать движок далеко не с полного нуля — к тому моменту у меня был DGL, набор классов, упрощающий работу с OpenGL в D (а до этого я работал с OpenGL и писал разнообразные сопутствующие библиотеки на C++). Однако именно Dagon стал наиболее успешным.

Создание игрового движка — наверное, одна из самых интересных и нетривиальных задач в программировании. Есть устойчивое убеждение, что свой движок писать вообще не нужно, и я как-то раз написал статью о том, почему это скорее миф. Существуют примеры успешных проектов как на лицензированных движках, так и на эксклюзивных, оба варианта имеют свои плюсы и минусы. На мой взгляд, главное преимущество собственной технологии — независимость от чужих лицензионных условий и архитектурных решений. В современном мире большинство проектов делается на Unity и UE, в результате чего игры слишком похожи друг на друга. Собственный движок — это ваш уникальный почерк. Понятно, конечно, что с UE конкурировать практически невозможно — продукты, в которые вложены миллионы долларов, будут всегда впереди. Но UE — это движок-монстр, все возможности которого нужны далеко не каждому. Если речь об инди, то нелепо, когда рантайм игры весит, как все ее ресурсы (если не больше), а системные требования — как у AAA. Должны же быть и маленькие движки! Ну и, наконец, психологический фактор: игра на чужом движке воспринимается как не совсем твоя.

Я начал интересоваться геймдевом еще в далеком 2005 году, когда открыл для себя Game Maker, Blitz3D и другие популярные любительские технологии того времени. Затем я пробовал работать с Irrlicht, OGRE, Blender Game Engine, но с точки зрения архитектуры меня очень впечатлила GLScene, графическая библиотека для Delphi. Мои собственные разработки во многом вдохновлены классами GLScene, хотя напрямую я оттуда ничего не копировал. Я вообще почти не заглядываю в исходники чужих движков — не знаю, хорошо это или плохо, но у меня свое понимание того, что удобно, а что нет. Боже упаси создавать клон Unity или что-то подобное. Не мыслите шаблонами индустрии, изобретайте свои технологии!

Я никогда не писал на DirectX, как-то почти сразу освоил OpenGL и всю жизнь сидел на нем. В нулевых это были версии 1.x-2.x, еще с фиксированным конвейером, где шейдеры были необязательной частью. Потом — короткий период 3.x, и, наконец, к концу десятых — 4.x. Я проследил практически всю эволюцию OpenGL и использовал его до последнего, когда стало уже очевидно, что пора двигаться дальше и осваивать эксплицитные API. Я, однако, не фанат чистого Vulkan. На нем не надо писать приложения напрямую по той же причине, по которой не пишут напрямую на ассемблере. Vulkan — это машинно-ориентированный бэкенд, поверх которого нужна абстракция, удобная для человека. Я терпеливо ждал появления таких абстракций, они появились, и вот теперь можно со спокойной душой уходить с OpenGL.

Что еще могу сказать на основе десятилетнего опыта? Разрабатывая большую систему, такую, как игровой движок, рано или поздно приходишь к идее неизбежности компромисса между двумя силами, тянущими проект в две разные стороны — абстракцией и специализацией. Абстракция — это сокрытие деталей под высокоуровневым интерфейсом. Абстракция повышает удобство на стороне пользователя, но снижает гибкость и возможности оптимизации. Специализация, напротив, подразумевает, что пользователь сам должен предоставить реализацию некоего интерфейса — то есть, углубиться в детали и интегрировать в движок свое решение специфической задачи. Это дает гибкость и возможности оптимизации, но снижает удобство. Хорошая система включает в себя и то, и другое. Дзен в балансе: нужно постоянно решать, в какой степени система должна быть абстрактной, и в какой — специализированной. Например, один из первых 3D-движков, с которыми я работал — Xtreme3D для Game Maker 6 — имел очевидный приоритет абстракции над специализацией: в нем были готовые декодеры разных форматов 3D-моделей, но полное отсутствие возможности создать свой собственный (то есть, собрать модель вручную из вершин и индексов). А вот встроенный 3D-рендер Game Maker, наоборот, не включал практически никаких абстракций и вынуждал программировать графику на низком уровне, составляя списки отрисовки из отдельных полигонов. В первом случае удобно, но не гибко, во втором — гибко, но неудобно. Учтя эти особенности, я решил делать движок, который охватывает оба сценария использования. Если вам нужно просто загрузить glTF, то это легко. А если вы хотите создать свой формат сцен, то это, пусть и с оговорками и требованиями, но реализуемо. Я всегда подчеркиваю, что Dagon — это фреймворк, то есть, каркас игрового приложения. Его ядро включает только создание окна и контекста OpenGL, управление таймером главного цикла и очередью событий. Рендер — это уже надстройка; в Dagon можно не использовать встроенный рендер и написать свой. То же касается абсолютного большинства всех подсистем — они не прибиты гвоздями. Принципиальной основой работы в Dagon является инверсия контроля, как и во всех фреймворках, но ядро минималистично — оно не отвечает за все процессы, и вы можете заменить почти все, что угодно, на самописные компоненты.

Разработка не стоит на месте, я постоянно что-то улучшаю и переписываю, чему, главным образом, и посвящен этот блог. Не хочется загадывать, но надеюсь, что в следующем году доделаю Dagon 2.0 — начинается новая большая страница в истории движка.

RTLD — низкоуровневый рантайм для D

Я начал разработку dlib в далеком 2011 году, когда писал на старом добром OpenGL 1.x под 32-битным Linux. Тогда я и не помышлял об альтернативных архитектурах и кросс-компиляции, мне даже в голову не приходило, что у D когда-нибудь появится поддержка такого количества разнообразных платформ. Но к началу 20-х уже стало очевидно, что грядет эпоха ARM, и старичку x86 придется потесниться, а сегодня AArch64 на устройствах мощнее телефона — уже не причуда и экзотика, а обыденная реальность. Стоит это принять и начать уже думать об ARM не как о мобильной, а как о второй десктопной архитектуре. Это необычное положение дел, потому что на десктопе x86 всегда царил монопольно. Но я вообще-то люблю изучать все новое, и для меня как графического разработчика освоение еще одной процессорной архитектуры — интересный вызов. Надо ли прямо сейчас всем кидаться портировать весь софт на ARM? Я думаю, нет, но какие-то базовые штуки, полезные библиотеки, фреймворки — желательно. Вот и я решил не оставаться в стороне.

Хорошая новость состоит в том, что D, в лице компилятора LDC, отлично поддерживает ARM. LDC — это неявный кросс-компилятор, он умеет генерировать код почти под все платформы, поддерживаемые LLVM, и это можно делать на любой хост-системе, не пересобирая тулчейн. ARM существует в разных аппаратно-программных вариантах, я под ним буду подразумевать aarch64-linux-gnu — то есть, платформу с процессором AArch64, ядром Linux и окружением GNU. Проще говоря, установив LDC, вы можете на x86 собирать приложения под десктоп или сервер на базе AArch64, о чем я уже писал в предыдущем посте.

Плохая новость состоит в том, что для компиляции под нестандартные таргеты нужны соответствующие версии Phobos и druntime. Я боюсь представить, что это за квест — собрать их, и не имею никакого понятия о статусе Phobos для AArch64. Мне это даже не очень интересно, потому что Phobos я считаю не самой удачной стандартной библиотекой, я ее почти не использую — она сильно перегружена, половину можно было бы оттуда вынести в дополнительные DUB-пакеты, многие модули откровенно устарели, некоторые функции работают странно, а шаблоны порой не компилируются. Для меня уже привычен хардкорный путь — игнорировать Phobos и писать все свое. К тому же, под маломощными одноплатниками с маленькой памятью вам все равно GC не друг, и лучше все делать на @nogc-компонентах.

Все эти измышления подвели меня к идее создания новой библиотеки общего назначения, более низкоуровневой, чем dlib. Я ее назвал RTLD — Real-Time Library for D. Она основана на модулях, которые я изначально писал для dlib2/dcore, а также на прямых портах из dlib 1.x. В отличие от dlib, это будет настоящая замена Phobos. RTLD предоставляет самую базовую функциональность, работая поверх libc, WinAPI, POSIX, системных вызовов Linux, а также динамически загружаемых функций — X11 и OpenGL ES. По сути, это библиотека для тех, кто хочет писать на D как на C, не используя ничего лишнего. Однако я намеренно не стал делать ее BetterC, в отличие от dcore. Взвесив все «за» и «против», я решил, что от BetterC на десктопе толку мало — от классов никуда не деться, они все равно потребуются на определенном уровне абстракции, поэтому зачем изначально себя их лишать?

https://github.com/gecko0307/rtld

На данный момент RTLD поддерживает Windows и Linux, компилируется под x86_64 и AArch64. Некоторые ее модули платформонезависимы, и их можно использовать в системной разработке, под bare metal.

Текущий список фич:

  • rtld.core — ключевые функции: работа с динамической памятью, загрузчик библиотек, потоки, мьютексы, создание окна
  • rtld.gl— биндинг к OpenGL ES 2/3 и создание контекста (поддерживаются Windows и Linux/X11)
  • rtld.libc — функции библиотеки C
  • rtld.math — элементарные математические функции
  • rtld.random — генератор псевдослучайных чисел
  • rtld.sys.windows — функции WinAPI
  • rtld.sys.posix — функции POSIX
  • rtld.sys.linux — функции Linux
  • rtld.text — текстовые кодировки
  • rtld.time — функции даты-времени, наносекундный таймер.

Закономерен теперь вопрос архитектуры будущей dlib2. Я склоняюсь к мысли отказаться от dcore в пользу RTLD — это будет базовый бэкенд dlib2, реализующий львиную долю функциональности, которая не зависит от GC. К сожалению, полный отказ от GC в dlib невозможен по ряду причин, но я надеюсь сильно сократить его присутствие.

Заметка о преимуществах и недостатках эксплицитных API

Индустрия графической разработки окончательно повернулась в сторону эксплицитных («явных») API — то есть, таких, которые не содержат в своей реализации скрытых эвристик и не пытаются что-либо оптимизировать, строго следуя инструкциям программиста. Человек, плохо знакомый с принципами работы видеокарт, может удивиться: неужели классические OpenGL или Direct3D не подчиняются вашим инструкциям? Подчиняются, но фишка в том, что абстрактный графический конвейер, реализуемый OpenGL, на стороне пользователя не соответствует тому, что на самом деле происходит на низком уровне. К примеру, когда вы вызываете скромную, на первый взгляд, glEnable, видеодрайвер делает много вещей — сначала проверяет, что переданная константа действительна, и что вызов не происходит в недопустимом режиме, затем обновляет CPU-копию состояния, проверяя, не является ли вызов избыточным. Вместо того чтобы немедленно сообщать видеокарте о необходимости изменения, драйвер помечает состояние как измененное — фактическая аппаратная конфигурация конвейера меняется только при следующем вызове отрисовки (glDraw*). Некоторые изменения состояния — например, переключение шейдеров — приводят к значительным задержкам; кроме того, glEnable может заставить драйвер перекомпилировать внутренние скрытые шейдеры для обработки новой конфигурации, что крайне медленно (почитайте о таком явлении, как комбинаторный взрыв).

Эту проблему, вкупе с потоковой небезопасностью конвейера, новые API (Vulkan, Direct3D 12, Metal) решают путем использования неизменяемых PSO (pipeline state objects). Программист создает нужные ему конвейеры при инициализации приложения, заранее предоставляя всю необходимую конфигурацию — шейдеры, формат выводного буфера, настройки растеризации — которые в дальнейшем уже не меняются от кадра к кадру. Это позволяет драйверу производить валидацию состояния, компиляцию шейдеров в машинный код GPU и прочую тяжелую работу лишь один раз. PSO хранятся в видеопамяти, поэтому переключение с одного состояния на другое — дешевая операция, это всего лишь запись инструкции в командный буфер и никакого скрытого оверхеда. В оптимизированном рендере можно сократить переключения PSO на кадр до 15-20 и даже меньше, в зависимости от логики — для современных видеокарт это практически ничто. Вот это и есть главное, на мой взгляд, преимущество Vulkan и его родственников.

В чем же главный недостаток? А в том же самом — в неизменяемости конвейера! Если вы создаете классический Forward, вы уже не можете дать пользователям вашего движка возможность менять шейдер на уровне отдельного объекта внутри прохода. Новый шейдер — новый PSO. Создавать их на лету нельзя, нужно иметь всю информацию заранее и предусмотреть специальные проходы для всех кастомных шейдеров, если они есть. Как бы вы ни любили Forward за его гибкость, для Vulkan намного эффективнее строгий Deferred с его жестко заданными шейдерами и полным отстутствием вариативности состояния в маштабах прохода (либо Clustered Forward, но это уже другая история). Мир эксплицитных API — это мир строгих правил, где исключения обходятся слишком дорого. Если у вас есть талант придумывать хорошие правила и следовать им, то вы выиграете от этого, в противном случае вам будет тяжело и больно.

Dagon 2.0 на SDL3. Долгосрочные планы

Я пишу графику на OpenGL много лет (с 2009 года) и считаю, что этот классический API — до сих пор самый очевидный выбор, если вам нужно кроссплатформенно вывести что-то на экран. В сочетании с SDL это еще и очень просто — код приложения со всеми его ключевыми компонентами (окно, графика, ввод) получается на 99% независимый от операционной системы. Для 2D-проектов этой связки более чем достаточно, но в играх с продвинутой 3D-графикой, которая выжимает максимум из видеокарты, теперь, к сожалению, все сложнее.

Я выделяю три главные архитектурные проблемы OpenGL: однопоточность, частая синхронизация CPU и GPU и сложность управления глобальным состоянием конвейера. Новые низкоуровневые API решают все это, особенно последнее, жертвуя удобством написания приложений и вообще входным порогом в профессию графического разработчика (я не представляю, как можно изучить концепции и идиомы Vulkan с полного нуля — я бы рвал на себе волосы, если бы пришлось объяснять начинающим, что такое дескриптор-сеты, PSO и барьеры памяти). Долгое время между OpenGL и Vulkan была совершенно непреодолимая стена концептуальной несовместимости, мешающая портировать игры. OpenGL, между тем, хоть никуда и не делся, развиваться перестал. Под macOS — старая версия, под Windows — довольно серьезная проблема с вертикальной синхронизацией в оконном режиме, приводящая к статтерингу (это полноценно решается только путем работы поверх свопчейна DXGI, что требует нетривиального бойлерплейта в приложении, либо поддержки со стороны видеодрайвера). Ну и до кучи в OpenGL нет поддержки HDR-режима Windows, что некритично, но не круто.

Все это подводит к мысли, что OpenGL, каким бы он комфортным ни был, уже отжил свое. Но и на Vulkan переходить совершенно не хочется. Познакомившись с SDL GPU, я решил попробовать портировать на него некоторые ключевые части Dagon и быстро понял, что этот API — именно то, чего мне и не хватало в последние годы. WebGPU стал разочарованием из-за громоздкости интерфейсов и спорного синтаксиса WGSL, а здесь с этим проблем нет.

Исходники Dagon 2.0 доступны в отдельном репозитории на GitHub: https://github.com/gecko0307/dagon2. На данный момент перенесен dagon.core, реализованы G-буфер, базовый deferred-рендеринг, тонмаппинг и антиалиасинг. Движок загружает модели OBJ и текстуры в стандартных форматах, поддерживает кубические карты и DDS. Судя по всему, большая часть возможностей Dagon будет перенесена без серьезных изменений, картинка движка останется прежней, но не исключены архитектурные улучшения и CPU-оптимизации. Также изменится шейдерный API — на днях напишу отдельный пост об этом. Переход на Vulkan-бэкенд должен заметно ускорить рендер, а также позволит использовать HDR-свопчейн, если дисплей позволяет выводить в extended linear.

Я не уверен, что процесс портирования будет быстрым, но впечатления от работы пока весьма положительные, код для SDL GPU компактный и читаемый. Самая нетривиальная часть — воркфлоу компиляции шейдеров, но я уже смирился с тем, что от GLSLang в современных условиях никуда не денешься. Есть вероятность, что Dagon 1.0 я выпущу уже в ближайшее время, чтобы полностью сосредоточиться на порте.

Перлы из сабреддита /r/vulkan

К Vulkan я испытываю если не неприязнь, то во всяком случае изрядный скепсис. Это API для машин, а не для людей. Писать на нем напрямую — это ад, и веских причин пытать себя вулкановскими ужасами (во всяком случае, в инди-разработке) я за эти десять лет так и не увидел. Оптимизация CPU-bound частей рендера? Вы не Epic Games, чтобы этим заниматься — ресурсов не хватит. DLSS, трассировка лучей? В реальности все эти навороты в играх отключают первым делом, чтобы играть, а не смотреть слайдшоу, ибо видеокарты у большинства далеко не топовые.

Но вот что забавно: вулканисты сами признают, что использовать Vulkan необязательно! Если не верите, откройте Reddit. Вот что я там нашел:

pls use vk-bootstrap, dynamic rendering, VMA in big 2026. Don’t do raw vulkan. You will lose motivation sooner.

То есть, без разнообразных обвязок и прибамбасов писать на Vulkan принципиально не рекомендуется! Это прям классно — напомнило времена GLU, GLUT и тому подобного. Я и сам пробовал много всяких компромиссных вариантов — вкатывался в WebGPU, щупал LLGL и GPU API в SDL3, но везде одна и та же жопа в разных ракурсах: нужны дополнительные инструменты, как минимум для компиляции шейдеров и SPIR-V рефлексии. Оверхед по расходу памяти от всех этих обвязок немаленький, в WebGPU вообще память течет — привет растоманам. И я уж молчу про то, что обвязки систематически ломают обратную совместимость, так что писать на них — то еще удовольствие.

А вот это вообще анекдот:

Your options are basically:
— Learn Vulkan, but use AI to fill in the boilerplate.
— Use CUDA instead of Vulkan.

Без ИИ сегодня, конечно, вообще никуда 😂 А графическая разработка — такая уж область, ChatGPT ногу сломит. Ну и наконец:

OpenGL is perfectly viable in 2026 for hobby programmers and you’ll probably even get better performance out of it than not knowing how to use Vulkan and using it anyway. Hardware support is also completely fine. If you want to learn Vulkan, go do it. If you don’t, there’s better alternatives.

Занавес. Directed by Robert B. Weide.

Dagon 0.30.0 и 0.31.0

Выпустил подряд две версии движка. В ядро Dagon внесен фреймворк многопоточности и обмена сообщениями, о котором я подробно писал в предыдущем посте. EventManager.userEventQueue переименовано в EventManager.outboxEventQueue, EventManager.numUserEvents — в EventManager.numOutboxEvents. Также теперь рекомендуется использовать EventManager.queueEvent вместо EventManager.addUserEvent, EventManager.queueFileChangeEvent вместо EventManager.generateFileChangeEvent, EventManager.queueLogEvent вместо EventManager.asyncLog.

Заметно улучшен пакет dagon.collision, хотя он пока и далек от продакшн-уровня. Исправлены баги в модуле BVH, добавлена реализация GeomTriangle.boundingBox, а также экспериментальный алгоритм проверки столкновений GJK (dagon.collision.gjk). EPA пока не поддерживается, так что функция gjkTest не возвращает информацию о контакте — основным алгоритмом проверки столкновений остается MPR. Метод CollisionShape.supportPointGlobal теперь просто CollisionShape.supportPoint.

В Dagon 0.31.0 я продолжил улучшение пакета core. Добавлены свойства Application.path и Application.directory — соответственно, полный путь к исполняемому файлу и папка, в которой он лежит. Под Windows доступно свойство Application.hwnd для получения дескриптора окна игры. VFS теперь монтирует в качестве последнего источника данных папку, где хранится приложение, а не рабочую папку. Благодаря этому можно в командной строке запускать приложение не из текущей папки.

Экспериментальная фича: поддержка ввода с графических планшетов (пока только под Windows через Wintab). Абстрактный интерфейс InputDevice для добавления в EventManager кастомных устройств ввода. Новые типы событий EventType.PenMotion, EventType.JoystickAxisMotion, EventType.LocaleChange.

В deferred-рендер добавлена поддержка перспективных теневых карт (PSM) для конусных источников света.

Dagon 0.31.0 является последней версией, использующей OpenGL 4.0 — со следующей движок переходит на 4.3, что позволит добавить поддержку вычислительных шейдеров.

Texture Tools Exporter

Отличный бесплатный конвертер текстур от NVIDIA, о котором я узнал почему-то только недавно. Поддерживает системы сжатия BC1 (S3TC/DXT1), BC2 (S3TC/DXT3), BC3 (S3TC/DXT5), BC4/5 (RGTC), BC6/7 (BPTC), ASTC, а также несжатые 8-битные целочисленные форматы и 16- и 32-битные с плавающей запятой. Можно экспортировать как 2D текстуры, так и кубические карты. Список поддерживаемых контейнеров также внушителен: DDS, KTX2, OpenEXR, HDR и все обычные — PNG, JPEG, BMP, TGA, PPM и др.

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

Кубические карты из DDS

В следующей версии Dagon появится поддержка кубических карт в формате DDS. Чаще всего для кубических карт этот формат используется, если необходимо хранить предрассчитанные зеркальные лепестки (specular lobes) для разных уровней шероховатости — DDS позволяет хранить эти данные в mip-уровнях текстуры и быстро загружать их без промежуточного декодирования.

До этого единственным доступным вариантом была генерация mip-уровней в самом движке, но это делалось блочным фильтром, без учета BRDF. Теперь свертку карты окружения можно осуществлять при помощи внешних инструментов — я рекомендую, например, IBLBaker.

Dagon 0.9.0 и dlib 0.15.0

На днях вышли новые версии Dagon и dlib — 0.9.0 и 0.15.0 соответственно. Релиз Dagon — самый крупный со времени портирования движка на современный OpenGL: он содержит 190 коммитов, практически весь рендерер был переписан заново. Вот краткий список изменений:

  • Состоялся переход с прямого рендеринга (forward) на отложенный (deferred). Это должно было рано или поздно произойти, все современные движки в той или иной мере используют отложенные эффекты. В Dagon этот рефакторинг серьезно улучшил производительность и позволил полноценно реализовать SSAO. Количество динамических источников света теперь ограничено только fillrate’ом видеокарты. Ценой стало повышенное потребление видеопамяти, также при отложенном рендеринге невозможно эффективно реализовать прозрачность, поэтому все прозрачные объекты рендерятся в прямом fallback-режиме, и для них не учитываются точечные источники света.
  • Система шейдеров была переписана с нуля. Старая система с бэкендами материалов была заменена на шейдеры, все избыточные классы материалов были объединены в один, создавать новые материалы и передавать шейдерам параметры стало значительно проще. Все шейдеры используют GLSL 4.0 Core, ветвление в шейдерах было заменено на uniform-подпрограммы, что повысило производительность и сделало код более читаемым. Материалы с пользовательскими шейдерами также рендерятся в прямом режиме.
  • Была серьезно улучшена система частиц: появилась поддержка мягких частиц, освещения, отбрасывания теней. Также теперь можно создавать несколько эмиттеров в каждой системе. Опционально в качестве частиц можно рендерить любые объекты вместо биллбордов.
  • Добавлена поддержка Screen space ambient occlusion (SSAO).
  • Добавлены шейдер воды по методу Себастьяна Лагарда и модель неба по Рэлею (экспериментально).
  • Dagon теперь использует BindBC вместо Derelict.
  • Добавлена поддержка автоматического деплоя: при каждой сборке Dub копирует в проект все необходимые файлы для запуска, включая DLL’ки под Windows.

Полный список изменений смотрите на странице релиза. Также было обновлено и демонстрационное приложение.

Изменения в dlib по большей части носят исправляющий и косметический характер: я решил постепенно избавиться от устаревших компонентов, в связи с чем следующие модули пометил как deprecated:

  • dlib.image.parallel
  • dlib.math.fixed
  • dlib.functional.quantifiers
  • функции map, filter, reduce в dlib.functional.range.

Следующие модули были удалены:

  • dlib.container.aarray
  • dlib.math.affine
  • dlib.core.fiber (временно перенесен в отдельную ветку до завершения windows-порта)

Нововведения включают:

  • dlib.text.unmanagedstring — альтернативная реализация строк, не использующая сборщик мусора
  • Улучшенные декодеры текстовых кодировок, модуль dlib.text.encodings.
  • Также dlib теперь может быть собран компилятором GDC (за исключением модуля dlib.math.sse, который в этом случае не будет доступен).

Полный список изменений — на странице релиза.

Dagon + BindBC

На днях произошло два крупных события. Во-первых, вышла бета-версия LDC 1.13.0, которая теперь тоже самодостаточна — для сборки 64-битных приложений не нужны библиотеки из Visual Studio. По умолчанию используется линкер LLD.

Во-вторых, я решил отказаться от Derelict в пользу новой разработки Aldacron’а — BindBC. Это фреймворк для создания динамических биндингов, не использующий классы и сборщик мусора (@nogc), и потому отлично вписывающийся в мои принципы разработки. Из других преимуществ — поддержка OpenGL 4.6 и SDL 2.0.9, простота использования (вместо неинтуитивных DerelictGL3.load() и DerelictGL3.reload() теперь просто loadOpenGL()) и более простая обработка ошибок без исключений.

Из других значительных нововведений в Dagon отмечу рендеринг воды, новый шейдер неба по модели Рэлея и автоматический деплой — Dub теперь копирует библиотеки и внутренние данные движка в папку с проектом после каждой сборки.