Хабрахабр

Хаброкаст «Заход Солнца Вручную» #1. Пытаемся настроить среду для разработки игрушки под Windows

Иначе с катушек можно съехать. Только что пришла в голову мысль — нужно найти какое-то хобби. После стрима запись публикуется на Хабре. А поскольку я весьма бесполезный человек, ничего кроме как тыкать кнопки не умеющий, хобби будет такое: не реже раза в неделю устраивать стрим с написанием игрушки. (Можно попробовать постить на Хабр прям лайв, но это сильно сложней).

Если есть предложения — постараюсь учитывать. Написание очень feedback driven — если кому-то нужны пояснения, то я могу пояснить как смогу. На хабре читаются все комментарии до последнего, в других местах — как получится.

Первый блин комом вот здесь:

Под катом — тезисное описание для тех, кому справедливо влом тратить на просмотр полтора часа.

Как обычный джавист делает? Первый интересный аспект в том, что хочется написать всё без хрюмворков. Цена этому — из-за подобного свинства проект превращается в свинарник, и никто не может в точности определить, что же происходит. Возникла проблема — фигачишь в зависимости хрюмворк, и он тебе решает вопрос. Возможно, это невозможно — пожалуйста, сообщите в комментариях. Хочется попробовать написать без этой свинофермы, чистенько и аккуратно.

Я всю жизнь кодил на Java и PHP. Второй аспет. Поэтому, по сути это будет шоу уродов — человек не разбирающийся в вопросе попробует как-то своими словами описать, что происходит. Был опыт разработки игрушек, но только серверной части с ответом по сети, и ни разу — настоящего десктопного приложения на C++.

Это чтобы не съехать с катушек, и чтобы мотивировать взрослых бородатых дяденек тоже взяться за клавиатуру и запилить какую-нибудь игрушку. Нет, никакого практического значения всё это не имеет.

Вначале происходит период болезненного копания в настройках среды и IDE. К сожалению, программирование никогда не начинается с легкого и приятного развлечения.

После Eclipse и IntelliJ IDEA всё, знаете ли, какое-то неестественное, сиреневенький бесперспективняк с переподвыподвертом. Первое что я понял относительно Visual Studio — это отличный инструмент для профессионала, но на новичка он производит очень фрустрирующее впечатление. Дело не в коем случае не в VS, дело во мне 🙂

И с плагинами постоянно какая-то беда.

Vim, Emacs и прочие редакторы, не понимающие структуры исходника — отправляются лесом. Поэтому волевым решением отказываемся от Вижуалки и смотрим, что ещё есть. Первая же попытка использовать Eclipse провалилась, поэтому инструментом был выбран CLion.

Если попробовать сделать что-нибудь в нём, то будет вот такое: Проблема с CLion в том, что он не всё ещё не умеет полноценно работать с компилятором Visual Studio.

Но мы их слушать, конечно не станем. Конечно, тут бы в тред набежать гошникам и начать кричать надрывным голосом, что отладочных принтов хватит всех.

Поэтому нужно то, что CLion умеет хорошо, и это MinGW.

Есть большая таблица версий.

Msys2 какой-то странноватый — у него мало коммитеров, пакеты лежат на личном гитхабе одного из авторов. И по ней видно, что имеет смысл смотреть только на Cygwin и Msys2. Это имеет решающее значение. С другой стороны, он действительно клёвый — там свежий компилятор и куча пакетов.

Установка заключается в прокликивании next-next-ok, и потом многократном выполнении команды обновления (pacman -Syu, как в Арчлинуксе) с перезапуском терминала Msys2, пока он не скажет, что всё получилось в лучшем виде.

Его нужно поставить самостоятельно, это делается командой pacman -S mingw-w64-x86_64-toolchain. Если просто установить Msys2 по инструкции и попробовать добавить его в CLion, не будет найдено ни одного тулчейна.

После установки этого пакета, CLion запускает helloworld (который генерится автоматически при создании нового проекта) и в нём работает отладка.

Всё-таки, это не родной PlatformSDK, а MinGW. Во-первых, хочется понять, запустится ли вообще хоть какое-то десктопное приложение.

Для этого подойдет незамысловатая прога, рисующая окно с помощью винапи.

А вот с тулчейном Visual Studio оно сыпет какими-то ошибками, но с ними разбираться я не стал, потому что — а зачем, если у нас уже работает целевая платформа? И да, с MinGW она запускается.

Это тормозно, неудобно, нет никаких модных штучек. Понятно, что для написания чего-то жизнеспособного недостаточно выводить пиксели на окне. Короче, нам нужен DirectX.

Если они не смогут юзать DirectX, то отправляются в помойку. Ключевой вопрос про CLion+MinGW — именно это.

Задача в том, чтобы запинать его работать. Для тестирования был нагуглен очень короткий туториал, состоящий всего из двух файлов: в одном весь код на C++, в другом — шейдер.

Возможно, эту статью стоит перевсти на Хабр (напишите в комментариях). Кроме однофайловости этот туториал очень хорош тем, что там на пальцах рассказывается, как он работает.

Здесь опишу, какие проблемы встретились. Готовый результат лежит вот здесь GitHub.

Можно поудалять буковки L. Много L-строк стали просто строками. Во многих местах нужно заменить NULL на 0 чтобы не падало.

Несмотря на то, что использовался set(CMAKE_CXX_STANDARD 17), этом плане ничего интересного не произошло вообще, ничего не развалилось.

DirectX теперь не находится в отдельном DirectX SDK как во времена нашей неоднозначной молодости, а засунут прямо в Windows SDK. Дело, конечно, в том, что этот пример — очень древний, написанный во времена задолго до Windows 10.

Поэтому первое что нужно сделать — запустить установщик Visual Studio и проверить, что установлена свежая версия Windows SDK.

Второй вопрос — в заголовках.

#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>

Их больше нет, нужно что-то вроде:

#include <d3d9.h>
#include <d3d10.h>
#include <d3d11.h>
#include <dxgi.h>

И потом в CMakeLists добавить поиск до них в конец файла:

set(LIBS d3d9 d3d11 d3dcompiler_43)
target_link_libraries(src $)

Раньше была вот такая структура:

typedef struct D3DXCOLOR { FLOAT r; FLOAT g; FLOAT b; FLOAT a;
} D3DXCOLOR, *LPD3DXCOLOR;

Впрочем, во всех местах, где она реально была нужна, получилось заменить D3DXCOLOR(0. И больше её нет. 2f, 0. 0f, 0. 0f) на {0. 4f, 1. 2f, 0. 0f, 0. 0f}. 4f, 1.

Её больше нет! Проблема интересней оказалась с D3DX11CompileFromFile.

В статье Living without D3DX её предложили заменить на D3DCompileFromFile.

Но вот проблемка, D3DCompileFromFile у нас тоже почему-то недоступно!

Небольшое расследование показало, что документация Microsoft предлагает воспользоваться очень новой версией API:

А MinGW отправляет нас в прошлое на несколько лет:

32 бита на, наверное, на фиг не сдались. Впрочем, в 32-битной версии есть более новый заголовок, но как его присобачить к 64-битам я не разобрался.

Интересно, кто мантейнеры всех этих дел. С одной стороны, это очень печально, потому что предвещает гемор в отношениях с MinGW в дальнейшем.

С другой стороны, если взять отсутствующую D3DCompile и присутствующую D3DCompileFromFile:

HRESULT WINAPI D3DCompileFromFile( in LPCWSTR pFileName, in_opt const D3D_SHADER_MACRO pDefines, in_opt ID3DInclude pInclude, in LPCSTR pEntrypoint, in LPCSTR pTarget, in UINT Flags1, in UINT Flags2, out ID3DBlob ppCode, out_opt ID3DBlob ppErrorMsgs
);

HRESULT WINAPI D3DCompile( in LPCVOID pSrcData, in SIZE_T SrcDataSize, in_opt LPCSTR pSourceName, in_opt const D3D_SHADER_MACRO pDefines, in_opt ID3DInclude pInclude, in_opt LPCSTR pEntrypoint, in LPCSTR pTarget, in UINT Flags1, in UINT Flags2, out ID3DBlob ppCode, out_opt ID3DBlob ppErrorMsgs
);

то окажется, что там разница только в следующем:

in LPCWSTR pFileName,

против

in LPCVOID pSrcData, in SIZE_T SrcDataSize, in_opt LPCSTR pSourceName,

К сожалению, я не знаю C++, поэтому наговнокодил как умел: просто добавил вычитывание файла и редирект этих данных в D3DCompile.

void WINAPI D3DCompileFromFile(const char *filename, const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages) { SIZE_T data_size; char* buffer; ifstream infile; infile.open(filename, ios::binary); infile.seekg(0, ios::end); data_size = infile.tellg(); infile.seekg(0, ios::beg); buffer = new char[data_size]; infile.read(buffer, data_size); infile.close(); D3DCompile(buffer, data_size,filename, defines, include,entrypoint, target, sflags, eflags, shader, error_messages);
}

Это что-то для асинхонности, возможно какой-то тредпул? Единственное важное различие между почившим в тьме веков D3DX11CompileFromFile и нашим самопальным D3DCompileFromFile — в отсутствии в новом API ID3DX11ThreadPump в качестве параметра. Впрочем, в туториале он и не использовался, там на его месте стоит 0.

Есть возможность не только использовать базовое винапи, но и рисовать, и даже с шейдерами. Связка DirectX + MinGW + Msys2 + CLion является достаточно жизнеспособной, чтобы запилить простую игру.

Напоминаю, что нехитрый результат лежит на GitHub. В общем-то, всё.

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

Ради этого всё и делается, послушать что вы скажете. Пожалуйста, пишите в комментариях ваши замечания и предложения. Обязательно найдо зайти и что-нибудь написать. Особенно если вы — матёрый игропрограммист, прямо зубр, бизон, и не помещаешься в тред по размерам.

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

олег родился в интернете
в почтенной геймерской семье
питался лайками и в гугол
за двойки ставили его

© Александр Раевский

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»