Теперь мы готовы приступить к написанию реальных (практически используемых) шейдеров. Сейчас у нас есть 2 (1 vertex и 1 fragment), встроенных (hard-coded) в код. Понятно, что не лучшее решение, но ради простоты примера – вполне оправданное. Мы же, в свою очередь, предпочтем держать их за пределами экзешника.
1. В Windows File Explorer-е (не в VS), в каталоге C:\CPP\engine\ добавим под-каталог “dt” (for “data”). В нем мы будем держать все engine-related файлы данных, в частности – шейдеры. Внутри “dt” добавим под-каталог “shaders”.
В Text Editor (в текстовом редакторе) создадим простой txt файл, просто пару строк, типа
test 1
test 2
Сохраним его как C:\CPP\engine\dt\shaders\test0.txt
2. Теперь надо как-то передать его экзешнику. Есть пара вариантов типа включить его в “ресурсы” или напрямую в проект. Однако, мы НЕ хотим его “внутри” проекта. Лучше мы проинструктируем Visual Studio скопировать каталог “dt” в тот же каталог, где и экзешник.
Запускаем Visual Studio, открываем C:\CPP\a999hello\p_windows\p_windows.sln solution.
3. Откроем p_windows project Properties, All Configurations / Win32, Configuration Properties -> Build events -> Post-Build Event, откроем Command Line -> Edit.
Добавим (copy-paste) следующую команду:
xcopy "..\..\engine\dt\*.*" "$(TargetDir)dt\" /E /R /D /y
Затем – Ok, Apply, Ok.
“Раскадровка”:
- xcopy – понятно, копировать
- “..\..\engine\dt\*.*” – копировать что и откуда. Это тот же C:\CPP\engine\dt, просто в относительной форме от корневого каталога p_windows проекта
- “$(TargetDir)dt\” – куда копировать. Мы хотим копию каталога “dt” там же где и экзешник
Ключи:
- /E – Копировать каталоги и под-каталоги, включая пустые
- /R – Переписывать read-only файлы тоже
- /D – Копировать только если новее
- /y – Не спрашивать переписывать ли существующие
4. Теперь запуск (зеленая стрелка). Работает. Теперь закроем программу ИЛИ: VS top menu -> Debug -> Stop Debugging.
Открываем Windows File Explorer, идем в C:\CPP\a999hello\p_windows\Debug. Отлично, копия каталога “dt” со всем его содержимым там, в том же каталоге что и OurProject.exe:
5. Теперь попробуем прочитать наш файл (test0.txt). Для этого нужно указать full path файла. Но он же может быть разным, смотря куда установлена программа. Значит, надо определить куда, то есть выяснить корневой каталог приложения.
Код:
//find application root folder
char path[256];
GetModuleFileNameA(NULL, path, 256);
filesRoot.assign(path);
int lastSlashPos = filesRoot.find_last_of('\\');
if (lastSlashPos < 0)
lastSlashPos = filesRoot.find_last_of('/');
filesRoot = filesRoot.substr(0, lastSlashPos);
mylog("App path = %s\n", filesRoot.c_str());
Вставим этот код в main.cpp непосредственно перед theGame.run().
Еще надо добавить после include секции:
#include <windows.h>
#include <string>
#include <fstream> // std::ifstream
std::string filesRoot;
Запускаем. Результат:
App path = C:\CPP\a999hello\p_windows\Debug
То, что надо.
6. Теперь прочитаем файл.
После mylog(…) добавим:
//reading test file
std::ifstream myFile(filesRoot + "/dt/shaders/test0.txt");
std::string line;
if (myFile.is_open())
{
while (getline(myFile, line))
mylog("%s\n", line.c_str());
}
else mylog("Unable to open file\n");
Запускаем. Результат:
App path = C:\CPP\a999hello\p_windows\Debug
test 1
test 2
7. После очистки от тестового кода, main.cpp (с новой переменной filesRoot и соответствующим кодом) будет:
#include <glad/glad.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include "TheGame.h"
#include "platform.h"
#include <windows.h>
#include <string>
std::string filesRoot;
static void error_callback(int error, const char* description)
{
mylog("Error: %s\n", description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
TheGame theGame;
GLFWwindow* myMainWindow;
int main(void)
{
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
myMainWindow = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!myMainWindow)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(myMainWindow, key_callback);
glfwMakeContextCurrent(myMainWindow);
gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress); //gladLoadGL(glfwGetProcAddress);
glfwSwapInterval(1);
//find application root folder
char path[256];
GetModuleFileNameA(NULL, path, 256);
filesRoot.assign(path);
int lastSlashPos = filesRoot.find_last_of('\\');
if (lastSlashPos < 0)
lastSlashPos = filesRoot.find_last_of('/');
filesRoot = filesRoot.substr(0, lastSlashPos);
mylog("App path = %s\n", filesRoot.c_str());
theGame.run();
glfwDestroyWindow(myMainWindow);
glfwTerminate();
exit(EXIT_SUCCESS);
}
Заменяем main.cpp код этим.
Save All.
Что дальше? Наконец, шейдеры?? Нет. Сначала – внешние файлы данных на Android-е.