Встроить файл на этапе компиляции

Тема в разделе "WASM.BEGINNERS", создана пользователем rxznve, 18 мар 2023.

Метки:
  1. rxznve

    rxznve New Member

    Публикаций:
    0
    Регистрация:
    27 фев 2023
    Сообщения:
    14
    Здравствуйте!

    Пишу исполняемое приложение на языке C/C++ с использованием Visual Studio (IDE) в котором используется отображение графики средствами OpenGL.

    Есть три файла, два из которых содержат код для шейдерной программы в текстовом виде, а третий это пустое изображение размером 1 на 1 пиксель.

    Все файлы лежат в соответствующих папках, в главной папке проекта.

    ../Project/Shaders/Vertex.glsl
    ../Project/Shaders/Fragment.glsl
    ../Project/Textures/Default.png

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

    Из того что смог найти, это всего три варианта.
    1. Запись в переменную-массив в виде текста/байт
    2. Использование директивы #include
    3. Использование ресурсов
    Реализация первого способа
    Код (Text):
    1.  
    2. constexpr char data[] =
    3. R"(
    4.     #version 150 core
    5.  
    6.     uniform mat4 uModel = mat4(1.0);
    7.     uniform mat4 uView = mat4(1.0);
    8.     uniform mat4 uProjection = mat4(1.0);
    9.  
    10.     int main()
    11.     {
    12.         // Какой-то код
    13.     }
    14. )";
    15.  
    Этот способ я использую на данный момент. Я помещаю этот код внутрь файла Vertex.glsl и подключаю его с помощью #include.

    Реализация второго способа
    Код (Text):
    1. constexpr char data[] {
    2. #include "Vertex.glsl"
    3. };
    Этот способ требует чтобы файл Vertex.glsl содержал текст внутри кавычек, иначе компилятор Visual Studio считает что это код, который нужно так же обработать.

    Реализация третьего способа
    Код (Text):
    1.  
    2. /*
    3.     Здесь всё довольно просто
    4.     1. Добавляем файл как ресурс
    5.     (ПКМ по свойствам проекта > Добавить > Ресурс)
    6.  
    7.     2. Используем в коде функции FindResource и LockResource для его поиска
    8. */
    9.  
    Этот способ мне не подходит, поскольку не позволяет аккуратно все отсортировать по папкам, создаёт огромную путаницу при большом количестве ресурсов и требует вызовов API функций. Все это для меня является огромным минусом.

    Первые два способа довольно неплохи, но мне бы хотелось чтобы файл Vertex.glsl содержал только код который относится непосредственно к шейдерной программе. Может быть кто-нибудь знает ещё какие-нибудь способы?
     
    Последнее редактирование: 18 мар 2023
  2. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Как вариант, написать утилитку-препроцессор, которую поставить в Pre-Build stage, и которая перед сборкой сгенерирует файлы, куда включит содержимое твоих шейдеров.
    Т.е., примерно так:
    1. Создаёшь файл, скажем, Shaders.cpp
    2. В файле пишешь примерно такое:
    Код (Text):
    1.  
    2. #include "Vertex.glsl.h"
    3. #include "Fragment.glsl.h"
    4. #include "Default.png.h"
    5.  
    Самих этих файлов-хедеров у тебя ещё нет.
    3. Пишешь утилитку, которая откроет файл Shaders.cpp, прочитает оттуда все инклуды с расширением "*.glsl.h", для каждого найдёт соответствующий файл с расширением .glsl, и создаст для каждого .glsl.h с содержанием, как в твоём первом варианте (массив байт с содержимым файла).
    4. Встраиваешь эту утилитку на pre-build, и она перед каждой сборкой будет генерировать хедеры с данными для всех инклудов в твоём Shaders.cpp, и дальше в коде просто обращаешься к сгенерированным массивам.

    А из коробки прямолинейным способом в VS/MSVC такое сделать нельзя.
     
    GRAFik и rxznve нравится это.
  3. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    352
    Круто. Я даже, честно говоря, и не понял. :) Понял, так в общих чертах и расплывчато - поскольку учился по учебникам и самоучителям, которые были в интернете, а на практике мне такое никогда не было нужно. В общем, век живи ... :)
     
  4. rxznve

    rxznve New Member

    Публикаций:
    0
    Регистрация:
    27 фев 2023
    Сообщения:
    14
    Оказалось что с файлами ресурсов работать не так уж и сложно, как я себе представлял.

    Внутри файла ресурсов (.rc) достаточно написать следующее
    Код (Text):
    1. // ИМЯ                 ТИП                 ПУТЬ
    2. Shaders/Default/Fragment glsl "Shaders\\Default\\Fragment.glsl"
    3. Shaders/Default/Vertex glsl "Shaders\\Default\\Vertex.glsl"
    4. Textures/Default png "Textures\\Default\\Default.png"
    Затем в коде достаточно написать следующее

    Код (Text):
    1. const HMODULE hModule = GetModuleHandleW(nullptr);
    2.  
    3. if (!hModule)
    4. return;
    5.  
    6. const HRSRC hResource = FindResourceW(hModule, L"Shaders/Default/Fragment", L"glsl");
    7.  
    8. if (!hResource)
    9. return;
    10.  
    11. const HGLOBAL hData = LoadResource(hModule, hResource);
    12.  
    13. if (!hData)
    14. return;
    15.  
    16. void* data = LockResource(hData);
    17. DWORD size = SizeofResource(hModule, hResource);
    Обратите внимание что этот код написан на скорую руку и может содержать какие-либо ошибки или уязвимости!
    --- Сообщение объединено, 19 мар 2023 ---
    HoShiMin, спасибо, как вариант.
     
  5. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    340
    rxznve,

    FreeResource() еще б хорошо подумать

    когда попользуетесь ресурсом
     
  6. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    861
    Я часто юзаю FASM типа такого:
    Код (ASM):
    1. format MS COFF
    2.  
    3. section '.test' data code readable executable
    4.  
    5. public SomeData as "_SomeData"
    6. public SizeOfSomeData as "_SizeOfSomeData"
    7.  
    8. SomeData: file 'file.bin'
    9. SizeOfSomeData: dd $-SomeData
    10.                                
    В коде потом:

    Код (C++):
    1. extern "C" unsigned char SomeData[];
    2. extern "C" const unsigned int SizeOfSomeData;
    3.  
    не знаю, удобно или нет для тебя будет. Для списка файлов можно написать простой макрос и получать по индексу.