Receiving a "Error compiling: 0:1(1): error: syntax error, unexpected $end" C++, GLSL, shader files

1

Here is my shader.cpp. In my AddShader function, I am able to pass the vertex and fragment shader fine if it is hardcoded as a string with '\n' and '\' at the end of it. However when I try to load them from a file I receive the error in the title. I have read titles similar to my problem, but they did not help.

#include "shader.h"

Shader::Shader()
{
  m_shaderProg = 0;
}

Shader::~Shader()
{
  for (std::vector<GLuint>::iterator it = m_shaderObjList.begin() ; it != m_shaderObjList.end() ; it++)
  {
    glDeleteShader(*it);
  }

  if (m_shaderProg != 0)
  {
    glDeleteProgram(m_shaderProg);
    m_shaderProg = 0;
  }
}

bool Shader::Initialize()
{
  m_shaderProg = glCreateProgram();

  if (m_shaderProg == 0)
  {
    std::cerr << "Error creating shader program\n";
    return false;
  }

  return true;
}

std::string Shader::readFile(GLenum ShaderType)
{
  std::ifstream finV("shader.vert");
  std::ifstream finF("shader.frag");
  std::string content;
  if(ShaderType == GL_VERTEX_SHADER)
  {
    // If the file was opened successfully, continue
    if(finV)
    {
      while(finV)
      {
        std::cout << content << std::endl;
        getline(finV, content);
      }
    }
  }
  else if (ShaderType == GL_FRAGMENT_SHADER)
  {
    if(finF)
    {
      while(finF)
      {
        std::cout << content << std::endl;
        getline(finF, content);
      }
    }
  }
  finV.close();
  finF.close();
  return content;
}

// Use this method to add shaders to the program. When finished - call finalize()
bool Shader::AddShader(GLenum ShaderType)
{

  if(ShaderType == GL_VERTEX_SHADER)
  {
    m_s = readFile(GL_VERTEX_SHADER);
  }
  else if(ShaderType == GL_FRAGMENT_SHADER)
  {
    m_s = readFile(GL_FRAGMENT_SHADER);
  }

  GLuint ShaderObj = glCreateShader(ShaderType);

  if (ShaderObj == 0)
  {
    std::cerr << "Error creating shader type " << ShaderType << std::endl;
    return false;
  }

  // Save the shader object - will be deleted in the destructor
  m_shaderObjList.push_back(ShaderObj);

  const GLchar* p[1];
  p[0] = m_s.c_str();
  GLint Lengths[1] = { (GLint)m_s.size() };

  glShaderSource(ShaderObj, 1, p, Lengths);

  glCompileShader(ShaderObj);

  GLint success;
  glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);

  if (!success)
  {
    GLchar InfoLog[1024];
    glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
    std::cerr << "Error compiling: " << InfoLog << std::endl;
    return false;
  }

  glAttachShader(m_shaderProg, ShaderObj);

  return true;
}


// After all the shaders have been added to the program call this function
// to link and validate the program.
bool Shader::Finalize()
{
  GLint Success = 0;
  GLchar ErrorLog[1024] = { 0 };

  glLinkProgram(m_shaderProg);

  glGetProgramiv(m_shaderProg, GL_LINK_STATUS, &Success);
  if (Success == 0)
  {
    glGetProgramInfoLog(m_shaderProg, sizeof(ErrorLog), NULL, ErrorLog);
    std::cerr << "Error linking shader program: " << ErrorLog << std::endl;
    return false;
  }

  glValidateProgram(m_shaderProg);
  glGetProgramiv(m_shaderProg, GL_VALIDATE_STATUS, &Success);
  if (!Success)
  {
    glGetProgramInfoLog(m_shaderProg, sizeof(ErrorLog), NULL, ErrorLog);
    std::cerr << "Invalid shader program: " << ErrorLog << std::endl;
    return false;
  }

  // Delete the intermediate shader objects that have been added to the program
  for (std::vector<GLuint>::iterator it = m_shaderObjList.begin(); it != m_shaderObjList.end(); it++)
  {
    glDeleteShader(*it);
  }

  m_shaderObjList.clear();

  return true;
}


void Shader::Enable()
{
    glUseProgram(m_shaderProg);
}


GLint Shader::GetUniformLocation(const char* pUniformName)
{
    GLuint Location = glGetUniformLocation(m_shaderProg, pUniformName);

    if (Location == INVALID_UNIFORM_LOCATION) {
        fprintf(stderr, "Warning! Unable to get the location of uniform '%s'\n", pUniformName);
    }

    return Location;
}

Here is my vertex and fragment shaders respectively.

#version 330

layout (location = 0) in vec3 v_position;
layout (location = 1) in vec3 v_color;

smooth out vec3 color;

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;

void main(void)
{
  vec4 v = vec4(v_position, 1.0);
  gl_Position = (projectionMatrix * viewMatrix * modelMatrix) * v;
  color = v_color;
}

#version 330

smooth in vec3 color;

out vec4 frag_color;

void main(void)
{
  frag_color = vec4(color.rgb, 1.0);
}

Here is my shader.h as well.

#ifndef SHADER_H
#define SHADER_H

#include <vector>
#include <string>
#include <fstream>

#include "graphics_headers.h"

class Shader
{
  public:
    Shader();
    ~Shader();
    bool Initialize();
    void Enable();
    bool AddShader(GLenum ShaderType);
    bool Finalize();
    GLint GetUniformLocation(const char* pUniformName);
    std::string readFile(GLenum ShaderType);

  private:
    GLuint m_shaderProg;
    std::vector<GLuint> m_shaderObjList;
    std::string m_s;
};

#endif  /* SHADER_H */

Here is my graphics_headers.h to be thorough.

#ifndef GRAPHICS_HEADERS_H
#define GRAPHICS_HEADERS_H

#include <iostream>

#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED

#if defined(__APPLE__) || defined(MACOSX)
  #include <OpenGL/gl3.h>
  #include <OpenGL/GLU.h>
#else //linux as default
  #include <GL/glew.h>
  //#include <GL/glu.h>
#endif

// GLM for matricies
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/rotate_vector.hpp>

#define INVALID_UNIFORM_LOCATION 0x7fffffff

struct Vertex
{
  glm::vec3 vertex;
  glm::vec3 color;

  Vertex(glm::vec3 v, glm::vec3 c): vertex(v), color(c) {}
};

#endif /* GRAPHICS_HEADERS_H */
c++
opengl
glsl
asked on Stack Overflow Sep 2, 2018 by carlos • edited Sep 2, 2018 by Rabbid76

2 Answers

1

std::getline dosen't append the read content to a std::string. The previous content of the std::string is replaced, by the newly extracted sequence.

If you want to read the entire text from a shader file, then you can use a std::istreambuf_iterator:

#include <fstream>
#include <iterator> // std::istreambuf_iterator

std::string content;

std::ifstream finV("shader.vert");
if ( finV.is_open() )
    content = std::string(
        std::istreambuf_iterator<char>(finV), std::istreambuf_iterator<char>());
answered on Stack Overflow Sep 2, 2018 by Rabbid76 • edited Sep 2, 2018 by Rabbid76
0

If you want really want to use std::getline, here is a small dirty hack, simply make buffer and then add it to content, like @up wrote std::getline resets whole content of std::string object and puts new line into it.

Definitely not the fastest solution:

std::string Shader::readFile(GLenum ShaderType)
{
    std::ifstream finV("shader.vert");
    std::ifstream finF("shader.frag");
    std::string content = "";
    if (ShaderType == GL_VERTEX_SHADER)
    {
        // If the file was opened successfully, continue
        if (finV)
        {
            while (finV)
            {
                std::string buffer = "";
                getline(finV, buffer);
                content += buffer + "\n";
            }
        }
    }
    else if (ShaderType == GL_FRAGMENT_SHADER)
    {
        if (finF)
        {
            while (finF)
            {
                std::string buffer = "";
                getline(finF, buffer);
                content += buffer + "\n";
            }
        }
    }
    finV.close();
    finF.close();
    std::cout << content << std::endl;

    return content;
}

Works for me.

answered on Stack Overflow Sep 2, 2018 by XoRdi

User contributions licensed under CC BY-SA 3.0