Здравствуйте! Пишу исполняемое приложение на языке C/C++ с использованием Visual Studio (IDE) в котором используется отображение графики средствами OpenGL. Есть три файла, два из которых содержат код для шейдерной программы в текстовом виде, а третий это пустое изображение размером 1 на 1 пиксель. Все файлы лежат в соответствующих папках, в главной папке проекта. ../Project/Shaders/Vertex.glsl ../Project/Shaders/Fragment.glsl ../Project/Textures/Default.png Мне нужно сделать так, чтобы данные из этих файлов были записаны в конечную программу на этапе компиляции, чтобы я мог передавать на них указатели в коде. Из того что смог найти, это всего три варианта. Запись в переменную-массив в виде текста/байт Использование директивы #include Использование ресурсов Реализация первого способа Код (Text): constexpr char data[] = R"( #version 150 core uniform mat4 uModel = mat4(1.0); uniform mat4 uView = mat4(1.0); uniform mat4 uProjection = mat4(1.0); int main() { // Какой-то код } )"; Этот способ я использую на данный момент. Я помещаю этот код внутрь файла Vertex.glsl и подключаю его с помощью #include. Реализация второго способа Код (Text): constexpr char data[] { #include "Vertex.glsl" }; Этот способ требует чтобы файл Vertex.glsl содержал текст внутри кавычек, иначе компилятор Visual Studio считает что это код, который нужно так же обработать. Реализация третьего способа Код (Text): /* Здесь всё довольно просто 1. Добавляем файл как ресурс (ПКМ по свойствам проекта > Добавить > Ресурс) 2. Используем в коде функции FindResource и LockResource для его поиска */ Этот способ мне не подходит, поскольку не позволяет аккуратно все отсортировать по папкам, создаёт огромную путаницу при большом количестве ресурсов и требует вызовов API функций. Все это для меня является огромным минусом. Первые два способа довольно неплохи, но мне бы хотелось чтобы файл Vertex.glsl содержал только код который относится непосредственно к шейдерной программе. Может быть кто-нибудь знает ещё какие-нибудь способы?
Как вариант, написать утилитку-препроцессор, которую поставить в Pre-Build stage, и которая перед сборкой сгенерирует файлы, куда включит содержимое твоих шейдеров. Т.е., примерно так: 1. Создаёшь файл, скажем, Shaders.cpp 2. В файле пишешь примерно такое: Код (Text): #include "Vertex.glsl.h" #include "Fragment.glsl.h" #include "Default.png.h" Самих этих файлов-хедеров у тебя ещё нет. 3. Пишешь утилитку, которая откроет файл Shaders.cpp, прочитает оттуда все инклуды с расширением "*.glsl.h", для каждого найдёт соответствующий файл с расширением .glsl, и создаст для каждого .glsl.h с содержанием, как в твоём первом варианте (массив байт с содержимым файла). 4. Встраиваешь эту утилитку на pre-build, и она перед каждой сборкой будет генерировать хедеры с данными для всех инклудов в твоём Shaders.cpp, и дальше в коде просто обращаешься к сгенерированным массивам. А из коробки прямолинейным способом в VS/MSVC такое сделать нельзя.
Круто. Я даже, честно говоря, и не понял. Понял, так в общих чертах и расплывчато - поскольку учился по учебникам и самоучителям, которые были в интернете, а на практике мне такое никогда не было нужно. В общем, век живи ...
Оказалось что с файлами ресурсов работать не так уж и сложно, как я себе представлял. Внутри файла ресурсов (.rc) достаточно написать следующее Код (Text): // ИМЯ ТИП ПУТЬ Shaders/Default/Fragment glsl "Shaders\\Default\\Fragment.glsl" Shaders/Default/Vertex glsl "Shaders\\Default\\Vertex.glsl" Textures/Default png "Textures\\Default\\Default.png" Затем в коде достаточно написать следующее Код (Text): const HMODULE hModule = GetModuleHandleW(nullptr); if (!hModule) return; const HRSRC hResource = FindResourceW(hModule, L"Shaders/Default/Fragment", L"glsl"); if (!hResource) return; const HGLOBAL hData = LoadResource(hModule, hResource); if (!hData) return; void* data = LockResource(hData); DWORD size = SizeofResource(hModule, hResource); Обратите внимание что этот код написан на скорую руку и может содержать какие-либо ошибки или уязвимости! --- Сообщение объединено, 19 мар 2023 в 01:37 --- HoShiMin, спасибо, как вариант.
Я часто юзаю FASM типа такого: Код (ASM): format MS COFF section '.test' data code readable executable public SomeData as "_SomeData" public SizeOfSomeData as "_SizeOfSomeData" SomeData: file 'file.bin' SizeOfSomeData: dd $-SomeData В коде потом: Код (C++): extern "C" unsigned char SomeData[]; extern "C" const unsigned int SizeOfSomeData; не знаю, удобно или нет для тебя будет. Для списка файлов можно написать простой макрос и получать по индексу.