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


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


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



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


Направляющие идеи


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


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


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


Рутина наносит удар в пятак


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


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


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




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


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




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


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


Выбираем MinGW


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




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


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


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


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


Проверка возможности #1: простое окно


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


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


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


Проверка возможности #2: треугольник с шейдером


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


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


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


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


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


Мелочи и мусор


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


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


Заголовки и либы


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


Поэтому первое что нужно сделать — запустить установщик 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 ${LIBS})

Отсутствующие API


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


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

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


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


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




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


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




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




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


С одной стороны, это очень печально, потому что предвещает гемор в отношениях с 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.


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




Фидбек


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


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


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

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

Комментарии (14)


  1. Serge78rus
    01.10.2018 10:16
    +1

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

    И по ней видно, что имеет смысл смотреть только на Cygwin и Msys2.
    Как по ней видно, чем не устраивает MinGW?


    1. olegchir Автор
      01.10.2018 11:12

      Additional software in package manager, GCC version.

      От Msys2 ощущения как от работы с полноценным GNU/Linux: заходишь в терминал, и у тебя есть всё что душа пожелает. Самых свежих версий, включая GCC. Если версии несвежие или собранные не с теми флагами — есть внятное описание, как быстро забежать в PKGBUILD и пересобрать новое (это та же система, что в ArchLinux). Это просто космос, в отличие от красноглазия, которое начинается каждый раз в Windows, когда ты пытаешься что-то собрать так как тебе надо из исходников.


      1. Serge78rus
        01.10.2018 13:14
        +1

        С Msys2 понятно, неясно в чем, согласно приведенной таблицы, преимущества Cygwin перед MinGW.


        1. olegchir Автор
          01.10.2018 14:41

          Так вся таблица — это mingw, непонятен вопрос

          Ты имеешь в виду, чем он лучше, чем mingw, который идет отдельно? Ну тут к тебе вопрос: у него есть ли пакетный менеджер с репозиторием готовых бинарных пакетов? У cygwin есть, хоть там все и несколько по-некрофильски.

          Еще одна эксклюзивная фишка cygwin: он прочно обосновался во всевозможных туториалах по сборке чего-нибудь под Windows: там фигурируют вполне конкретные сигвино-специфичные названия пакетов, под него заточены сборочные скрипты. Например, OpenJDK при сборке из исходников под Windows почему-то сыпал странными ошибками, а в Cygwin работал норм. Если не ошибаюсь, они даже в мейке его поддержали, и когда падает сборка из-за недостатка заголовков, то советы какой пакет установить есть не только для Ubuntu и Fedora, но и для Cygwin


          1. playermet
            02.10.2018 12:27

            Ну тут к тебе вопрос: у него есть ли пакетный менеджер с репозиторием готовых бинарных пакетов?
            Ну вообще-то есть. Хотя он наверное еще более некрофильский чем у Cygwin. На скрине не все пакеты, они в соседней вкладке.
            image


  1. JeriX
    01.10.2018 11:20
    +1

    Спасибо за пост!
    У меня вопрос немного сбоку: а чем был обоснован выбор языка для разработки без «хрюмворков»?
    // отличное и ёмкое слово, кстати :)
    Почему именно C++? И почему не Rust?


    1. olegchir Автор
      01.10.2018 11:44

      Вдохновляюсь крутейшей серией видеокастов Handmade Hero, хочется сделать как у него, но по-другому.


      Возможно, как раз решив часть проблем с помощью Rust или Java. На Java скорей всего будет скриптовая система, JVM можно ембедить в крестовое приложение. Если будут идеи, зачем можно использовать Rust — напиши! Может, тоже скрипты?


      В любом случае, чтобы избавляться от проблем — нужно их вначале нажить :-)


      А еще просто хочется разобраться в C++. Зачем? Потому что моя специализация — Java. Чтобы изменять виртуальную машину Java — нужно понимание C++. Сейчас я исправляю баги в C++ коде, и это получается ОК совершенно без понимания. Чтобы его достичь, вероятно, нужно написать какое-нибудь приложение с нуля.


      1. JeriX
        01.10.2018 11:52
        +1

        Встречный вопрос: а почему хочется разобраться именно с C++? Чтобы научиться понимать код разных JVM? Или просто хочется что-нибудь нативного?
        Просто Rust тоже нативный, и хоть и гораздо сложнее в освоении в самом начале, зато проще после первого месяца-двух, а C++ для меня как был переусложнённым, так и остался


        1. olegchir Автор
          01.10.2018 12:15

          Не понимать код разных JVM, а разрабатывать эти JVM. Там легаси 20-летней давности. Плюс совершенно не на всех платформах есть компилятор Rust — там свежий С++ то не всегда есть, и нужен стандарт 98-ого года.


          Зачем это нужно на практике. Например, последнюю пару недель мы с друганом сражаемся с попыткой спортировать OpenJDK на новую процессорную архитектуру. Есть куча постов о кишках JVM (пример раз, пример два), доклады по GraalVM, итп. Чтобы их писать, нужно понимать что пишешь, рыться в коде. В принципе, большинство задач не требует именно написания чего-либо — достаточно понимать и мочь править баги "по смыслу". Но и общее ощущение составить хочется.


          Я знаю про Rust, это крутая штука, просто вряд ли он подходит именно мне. Если кто-то захочет сделать выделенный подкаст про Rust, это было бы неплохо!


  1. budda
    01.10.2018 17:43
    +2

    Если подкаст для начинающих и непрофессионалов, то почему не учли лицензию IDE :(
    Visual Studio Community бесплатный продукт, а в CLion нет Community версии, как для Java & Python, только 30 дневный trial. Поэтому интересует, что будет с CLion после 30 дней? Будут выдаваться сообщения, ограничения рабочей сессии или какие то другие прелести?


    1. olegchir Автор
      01.10.2018 22:02

      • Нужно будет отдельно объяснить, как билдить через другие IDE. То что это будет возможно — гарантируется тем, что для сборки используется CMake, не что-то IDE-специфичное. Можно писать хоть в блокноте и собирать из консоли. Я сделаю.


      • CLion сильно лучше для обучения. Особенно для тех, кто раньше писал на Java, PHP, Python, Ruby, .NET и других продуктах, где в качестве IDE лидируют продукты JetBrains. Если я ещё и IDE поменяю на VS, то буду чувствовать себя совсем униженным и сбитым с толку. В смысле, ну вот пишешь ты в блокноте или VSCode — будет то же самое, что в CLion, но без подсказок, поиска, рефакторингов, и так далее.


      • Когда закончится CLion, нужно будет скачать следующий EAP. Скорей всего, EAP ещё долго будут бесплатными. Кроме того, для студентов он вообще всегда бесплатный.


      • Для профессионалов Jetbrains Toolbox — вещь незаменимая. У меня он куплен на свои личные деньги, не работодателя. Окупается. Но этот момент дальше раскрывать не стану, чтобы кто-то не подумал, что это маркетинг JB.



  1. asm0dey
    01.10.2018 20:37

    Спасибо! До сих пор для меня плюсы были совсем магией, а вот ты их приделал к чему-то, что я даже енмножко понимаю. Чуть-чуть, но понимаю.


    1. olegchir Автор
      01.10.2018 21:52

      Ты бы знал, как в CLion проще для человека, который последние десять лет писал в Идее. Вещи находятся на привычных местах и работают привычным способом. Ну да, язык другой, зато всё остальное — понятное. Когда непонятны ни язык, ни среда, совсем нехорошо становится.


      1. asm0dey
        01.10.2018 22:35
        +1

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