Chapter 7. External data files, Windows

Now we are ready to start writing real (practically usable) shaders. Right now we have 2 sample (1 vertex and 1 fragment) shaders, that are hard-coded in TheGame.cpp. Obviously, not the best solution, but for simplicity's sake was quite reasonable. In our turn, we want to keep our shaders outside of the executable.

1. In Windows File Explorer (not in VS), in C:\CPP\engine\ folder add sub-folder “dt” (for "data"). Here we will keep all engine-related data files, particularly shaders. Inside of “dt” add sub-folder “shaders”.

In a Text Editor create a simple txt file for testing, just couple lines, such as

test 1
test 2


Save it as C:\CPP\engine\dt\shaders\test0.txt


2. Now we need to pass this file to the executable. There are couple options such as including files into "resources" or directly into the project. However, we don't want data files "inside" of the project. Instead, we will instruct Visual Studio to copy data folder to the same folder as executable.

Start Visual Studio, open C:\CPP\a999hello\p_windows\p_windows.sln solution.


3. Open p_windows project Properties, All Configurations / Win32, Configuration Properties -> Build events -> Post-Build Event, open Command Line -> Edit.

Add (copy-paste) following command:

xcopy "..\..\engine\dt\*.*" "$(TargetDir)dt\" /E /R /D /y

Then - Ok, Apply, Ok.

Clarification:

  • xcopy - doesn't really need an explanation (I guess)
  • "..\..\engine\dt\*.*" – copy what and from. Refers to C:\CPP\engine\dt, just in relative form from p_windows project root folder
  • "$(TargetDir)dt\" - copy to where. We want a copy of “dt” folder in the same place as executable

Keys:

  • /E - Copy directories and subdirectories, including empty ones
  • /R - Overwrite read-only files
  • /D – Copy files only if newer
  • /y - Don't ask if exists/overwrite

4. Now run the program (green arrow). Runs. Now - close the program OR: VS top menu -> Debug -> Stop Debugging.

Go to Windows File Explorer, open C:\CPP\a999hello\p_windows\Debug. Perfect, the copy of the "dt" folder with all it's content is there, in the same folder as OurProject.exe:


5. Now let's try to read our test file (test0.txt). For that we need to specify the file's full path. However, it can vary depending on where program was installed. So, will need to find it out, to detect application's root folder.

The code:

    //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());

Insert it in main.cpp right before theGame.run().

Also, add after include section:

#include <windows.h>
#include <string>
#include <fstream>      // std::ifstream

std::string filesRoot;

Run. Result:

App path = C:\CPP\a999hello\p_windows\Debug

Just what we need.


6. Now let's open our test file and read it.

After mylog(…) add following code:

    //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");

Run. Result:

App path = C:\CPP\a999hello\p_windows\Debug
test 1
test 2


7. After removing testing code, main.cpp (with new filesRoot variable and with corresponding code) is:

#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, "OurProject", 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);
}

Replace main.cpp code by this one.

Save All.

What's next? Finally, shaders?? No. First - external data files on Android.


Leave a Reply

Your email address will not be published. Required fields are marked *