Search code examples
c++glsl

GLSL shader compilation fails becuse of non-existent character


I've been following the LearnOpenGL.com tutorial in C++, but since I didn't like to manually hard-code the shaders into the code I wrote a function that reads the shaders from a file:

const char* ReadShader(const char* p_ShaderLocation)
{
    std::ifstream ShaderStream;
    std::stringstream Buffer;

    ShaderStream.open(p_ShaderLocation);

    if (!ShaderStream)
    {
        std::cout << "File: " << p_ShaderLocation << " can't be opened!" << '\n';
        return 0;
    }

    if (ShaderStream.is_open())
    {
        Buffer << ShaderStream.rdbuf();
        ShaderStream.close();
        return Buffer.str().c_str();
    }
    else if (!ShaderStream.is_open())
    {
        std::cout << "File: " << p_ShaderLocation << " can't be read!" << '\n';
        return 0;
    }
}

I tried it the first time and it gave me this compilation error:

ERROR: Vertex Shader Compilaton Failed
ERROR: 0:2: 'Ç' : unexpected token
ERROR: 0:2: '' : compilation terminated
ERROR: 2 compilation errors.  No code generated.


ERROR: Fragment Shader Compilaton Failed
ERROR: 0:2: '' :  syntax error, unexpected IDENTIFIER
ERROR: 1 compilation errors.  No code generated.

I've no idea whats causing this, but I think it has something to do with the ReadShader function. Also the shaders are the exact same as the shaders from the tutorial.


Solution

  • Instead of

    const char* ReadShader(const char* p_ShaderLocation) 
    {
        return Buffer.str().c_str();
    }
    

    do

    std::string ReadShader(const char* p_ShaderLocation)
    {
        return { Buffer.str() };
    }
    

    See also https://en.cppreference.com/w/cpp/io/basic_stringstream/str

    Notes

    The copy of the underlying string returned by str is a temporary object that will be destructed at the end of the expression, so directly calling c_str() on the result of str() (for example in auto *ptr = out.str().c_str();) results in a dangling pointer.

    Once you have the shader code as a string object, you can pass the code to the gl function like this:

    auto shader_src = ReadShader();
    const char *shader_src_str = shader_src.c_str();
    GLint shader_src_len = shader_src.length();
    glShaderSource(shader, 1, &shader_src_str, &shader_src_len /* or nullptr */);