Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 months ago.
Improve this question
I have a fairly basic shader program but for some reason the shader program won't link. Code is below. The shader loader successfully loads the shaders but keep erroring when I attempt to link them with the program.
Shader Loader:
#include "Shaders.h"
#include <fstream>
#include <sstream>
#include <iostream>
namespace myEngine
{
bool Shaders::LoadShader(std::string _path, std::string _type)
{
std::fstream file(_path);
char* shadersSrc = nullptr;
if (file.is_open())
{
file.seekg(0, file.end);
int length = (int)file.tellg();
file.seekg(0, file.beg);
shadersSrc = new char[length];
file.read(shadersSrc, length);
if (!file.eof())
{
file.close();
std::cerr << "WARNING: COULD NOT READ SHADER" << std::endl;
return false;
}
length = (int)file.gcount();
shadersSrc[length] = 0;
file.close();
}
else
{
std::cerr << "WARNING: COULD NOT OPEN SHADER" << std::endl;
return false;
}
if (_type == "vertex")
{
m_vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(m_vertexShaderId, 1, &shadersSrc, NULL);
glCompileShader(m_vertexShaderId);
if (!CheckShader(m_vertexShaderId)) return false;
}
else if (_type == "fragment")
{
m_fragmentShaderId = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(m_fragmentShaderId, 1, &shadersSrc, NULL);
glCompileShader(m_fragmentShaderId);
if (!CheckShader(m_fragmentShaderId)) return false;
}
return true;
}
bool Shaders::LinkShaders()
{
m_programId = glCreateProgram();
glAttachShader(m_programId, m_vertexShaderId);
glAttachShader(m_programId, m_fragmentShaderId);
glBindAttribLocation(m_programId, 0, "in_position");
glLinkProgram(m_programId);
glGetProgramiv(m_programId, GL_LINK_STATUS, &m_success);
if (!m_success)
{
std::cerr << "WARNING: COULD NOT LINK PROGRAM" << std::endl;
//throw std::exception();
return false;
}
glDetachShader(m_programId, m_vertexShaderId);
glDeleteShader(m_vertexShaderId);
glDetachShader(m_programId, m_fragmentShaderId);
glDeleteShader(m_fragmentShaderId);
return true;
}
bool Shaders::CheckShader(GLuint _id)
{
glGetShaderiv(_id, GL_COMPILE_STATUS, &m_success);
if (!m_success)
{
std::cerr << "WARNING: COULD NOT COMPILE SHADER" << std::endl;
throw std::exception();
return false;
}
return true;
}
}
The Fragment Shader is:
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(0.0, 0.0, 1.0, 1.0);
}
The Vertex Shader is:
#version 330 core
layout(location = 0) in vec3 in_position;
void main()
{
gl_Position = vec4(in_position, 1.0);
}
any help is greatly appreciated as is for a university module.
Edit: the program doesn't throw any errors. It just says it can't link program which is on line 76.
Edit: this has now been resolved. It was just a typo on my part.
I made a typo on line 52. should have been GL_FRAGMENT_SHADER instead of GL_VERTEX_SHADER.
Related
I am trying to throw an exception and abort my program when something fails during shader compile and link. I have introduced a typo: naming the output variable from my vertex shader something different from the expected input variable in my fragment shader. I would expect this to fail on link, but everything works fine (and the value of the variable in the fragment shader just ends up being 0). In particular, glGetProgramiv(id, GL_LINK_STATUS, &success); is setting success to true. What is going on?
Vertex shader:
#version 330 core
layout (location = 0) in vec3 aPos;
out vec4 vertexColo; // NOTE THE MISSPELLING HERE
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
vertexColo = vec4(1.0 - aPos.y, 0.8 - aPos.y, aPos.x, 1.0);
}
Fragment shader:
#version 330 core
out vec4 FragColor;
in vec4 vertexColor;
void main()
{
FragColor = vertexColor;
}
Test code:
namespace btv {
namespace {
static void test_compile(unsigned id, const char* path)
{
int success;
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
if (!success) {
constexpr size_t BUF_SIZE = 1024;
char buf[BUF_SIZE];
glGetShaderInfoLog(id, BUF_SIZE, NULL, buf);
std::stringstream ss;
ss << "Shader at path: " << path << " failed with message: "
<< buf;
throw std::runtime_error(ss.str());
}
}
static void test_link(unsigned id, const char* v_path, const char* f_path)
{
int success;
glGetProgramiv(id, GL_LINK_STATUS, &success);
if (!success) {
constexpr size_t BUF_SIZE = 1024;
char buf[BUF_SIZE];
glGetProgramInfoLog(id, BUF_SIZE, NULL, buf);
std::stringstream ss;
ss << "Program with v shader: " << v_path << ", f shader: " << f_path
<< " failed with message: " << buf;
throw std::runtime_error(ss.str());
}
}
}
Program::Program(const char* v_path, const char* f_path)
{
std::string v_src = slurp(v_path);
std::string f_src = slurp(f_path);
const char *v_c = v_src.data();
const char *f_c = f_src.data();
unsigned v_shdr = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(v_shdr, 1, &v_c, nullptr);
glCompileShader(v_shdr);
test_compile(v_shdr, v_path);
unsigned f_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(f_shdr, 1, &f_c, nullptr);
glCompileShader(f_shdr);
test_compile(f_shdr, f_path);
id = glCreateProgram();
glAttachShader(id, v_shdr);
glAttachShader(id, f_shdr);
glLinkProgram(id);
test_link(id, v_path, f_path);
}
} // namespace btv
The issue is related to GLSL version. In the OpenGL Shading Language 4.60 Specification (4.3.4 Input Variables) it is clearly specified, that it is a link-time error, if an input variable is static used, but no corresponding output variable is declared in the previous stage.
This part of the specification is missing in the OpenGL Shading Language 3.30 Specification.
Change the GLSL version to (e.g.) 4.60 (#version 460 core) and you'll get the expected error.
e.g.
"error: "vertexColor" not declared as an output from the previous stage"
I am trying to compile a simple colored triangle example with OpenGL 3 (GLSL 130) but my fragment shader never compiles. The error reported is always
syntax error unexpected $end
My vertex shader compiles and shows the geometry but the fragment shader fails.
Here are the sources (very simple one):
Vertex.vs:
attribute vec3 vertex_position;
attribute vec3 vertex_color;
varying vec4 out_color;
void main(void)
{
gl_Position = vec4(vertex_position, 1.0);
out_color = vec4(vertex_color, 1.0);
}
And fragment.fs:
varying vec4 out_color;
void main(void)
{
gl_FragColor = out_color;
}
[EDIT] Here is my shader compile code:
char *loadShader(const char *fname)
{
FILE* fp = fopen(fname, "rb");
long size = 0;
if (!fp)
return NULL;
fseek(fp, 0, SEEK_END);
size = ftell(fp) + 1;
fseek(fp, 0, SEEK_SET);
char* data = (char*) malloc((sizeof(char) * size));
::fread(data, 1, size, fp);
data[size-1] = '\0';
fclose(fp);
return data;
}
Shader::Shader(const char *fname)
: m_data(NULL),
ID(0)
{
if (fname)
m_data = ilian::loadShader(fname);
}
Shader::Shader(const char *data, size_t size)
{
if (data && size >0)
{
m_data = (char*) malloc(sizeof(char) * size);
::memmove(m_data, data, size);
}
}
Shader::~Shader()
{
if (m_data)
{
free(m_data);
m_data = NULL;
}
glDeleteShader(ID);
std::cout << "~Shader()\n";
}
std::string Shader::data()
{
std::string s((char*)m_data);
return s;
}
GLuint &Shader::getID()
{
return ID;
}
void Shader::createShader(ShaderType type)
{
GLint res = -1;
switch (type)
{
case VERTEX:
ID = glCreateShader(GL_VERTEX_SHADER);
break;
case FRAGMENT:
ID = glCreateShader(GL_FRAGMENT_SHADER);
break;
default:
break;
}
const GLchar* source = (const GLchar*) data().c_str();
int shader_len = data().length();
glShaderSource(ID, 1, &source, &shader_len);
glCompileShader(ID);
glGetShaderiv(ID, GL_COMPILE_STATUS, &res);
if (res == GL_TRUE)
{
std::cout << "Shader Compile OK!\n";
}
else
{
std::cout << "Shader Compile FAIL!\n";
GLint maxLength = 0;
glGetShaderiv(ID, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(ID, maxLength, &maxLength, &infoLog[0]);
std::cout << (char*)infoLog.data() << "\n";
//We don't need the shader anymore.
glDeleteShader(ID);
}
}
GLProgram::GLProgram(const char *vs_source, const char *fs_source)
: ID(0), vs(nullptr), fs(nullptr)
{
vs = new Shader(vs_source);
fs = new Shader(fs_source);
vs->createShader(VERTEX);
fs->createShader(FRAGMENT);
}
GLProgram::~GLProgram()
{
if (vs)
delete vs;
if (fs)
delete fs;
}
VAO &GLProgram::getVertexArrayObject()
{
return vao;
}
bool GLProgram::createProgram()
{
static GLint msg;
ID = glCreateProgram();
glAttachShader(ID, vs->getID());
glAttachShader(ID, fs->getID());
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &msg);
std::cout << "Link status: (" <<msg
<< ")"<< std::endl;
if (!msg)
{
GLint infoLen = 0;
glGetProgramiv(ID, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = new char[infoLen];
glGetProgramInfoLog(ID, infoLen, NULL, infoLog);
printf("Error linking program:\n%s\n", infoLog);
delete [] infoLog;
}
}
}
void GLProgram::bind(int location, const char *attribyte)
{
glBindAttribLocation(ID, location, attribyte);
}
void GLProgram::useProgram()
{
glUseProgram(ID);
glBindVertexArray(vao.ID());
}
You are passing a pointer to an invalid memory address to glShaderSource. This happens because you try to get the c_str() pointer from a temporary string object in this line:
const GLchar* source = (const GLchar*) data().c_str();
Right after this line, the temporary string returned by data() gets deleted and the source pointer points to an invalid memory address.
The shortest (but ugly) fix to your code is to make sure that the string object still lives when you use the pointer by storing it:
auto data_str = data();
const GLchar* source = (const GLchar*)data_str.c_str();
But since the construction of the whole string object is completely useless in your code (and actually hurts performance because the string object creates a copy of the underlying char array), the better way is to return the char* instead of a new std::string in the data() function:
const char* Shader::data()
{
return m_data;
}
and use it with:
const GLchar* source = data();
Or even better: Do not use a char* with malloc in the first place and use the proper C++ methods to directly load a std::string from the file.
Well this is a bit of an embarrasing problem, I can't seem to load any sort of file through a program I made. My program fails everytime regardless of the file i try to load, so I'm not quite sure what's going on. Specifically, the program is supposed to be loading GLSL shaders, and it hasn't been working. Here is my code:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vCode,fCode;
std::ifstream vss(vert);
std::ifstream fss(frag);
if(vss.is_open())
{
std::string line;
while(std::getline(vss,line))
{
vCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING VERTEX SHADER\n");
}
if(fss.is_open())
{
std::string line;
while(std::getline(fss,line))
{
fCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING FRAGMENT SHADER\n");
}
vss.close();
fss.close();
char const* vsp = vCode.c_str();
char const* fsp = fCode.c_str();
glShaderSource(vertex,1,&vsp,NULL);
glShaderSource(fragment,1,&fsp,NULL);
OutputDebugStringA("Vertex Source:\n");
OutputDebugStringA(vsp + '\n');
OutputDebugStringA("Fragment Source:\n");
OutputDebugStringA(fsp + '\n');
glCompileShader(vertex);
glCompileShader(fragment);
GLuint prog = glCreateProgram();
glAttachShader(prog,vertex);
glAttachShader(prog,fragment);
glLinkProgram(prog);
char errbuf[1024];
GLsizei len;
glGetProgramInfoLog(prog,sizeof(errbuf),&len,errbuf);
OutputDebugStringA(errbuf);
glUseProgram(prog);
return prog;
}
vss.is_open() and fss.is_open() return false everytime. This problem only occurs with this program too, I have another that runs the exact same function listed and it works just fine.
How I am calling it:
GLuint program = Shader::GetProgram("v.vert","f.frag");
The directory:
Finally got it! Just had to use _getcwd(), move my files to that location and append the file names of the two shaders. Here is my code now:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
const char* dir = _getcwd(NULL,0);
std::string var1 = dir;
std::string vCode,fCode;
std::fstream vss;
std::fstream fss;
char* var2 = "/";
std::string vertpath = var1;
std::string fragpath = var1;
vertpath.append(var2);
fragpath.append(var2);
fragpath.append(frag);
vertpath.append(vert);
vss.open(vertpath);
fss.open(fragpath);
Help me with the error Source1.cpp(128): error C3861: 'InitShader': identifier not found when I have 2 files and one is InitShader.cpp. Both files compile. I believe that it is some setting in Visual Studio to make the one file find the other, since the InitShader is referenced by the other source file. The project looks like this in VS 2012
The code is
#include "Angel.h"
namespace Angel {
// Create a NULL-terminated string by reading the provided file
static char*
readShaderSource(const char* shaderFile)
{
FILE* fp = fopen(shaderFile, "r");
if ( fp == NULL ) { return NULL; }
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char* buf = new char[size + 1];
fread(buf, 1, size, fp);
buf[size] = '\0';
fclose(fp);
return buf;
}
// Create a GLSL program object from vertex and fragment shader files
GLuint
InitShader(const char* vShaderFile, const char* fShaderFile)
{
struct Shader {
const char* filename;
GLenum type;
GLchar* source;
} shaders[2] = {
{ vShaderFile, GL_VERTEX_SHADER, NULL },
{ fShaderFile, GL_FRAGMENT_SHADER, NULL }
};
GLuint program = glCreateProgram();
for ( int i = 0; i < 2; ++i ) {
Shader& s = shaders[i];
s.source = readShaderSource( s.filename );
if ( shaders[i].source == NULL ) {
std::cerr << "Failed to read " << s.filename << std::endl;
exit( EXIT_FAILURE );
}
GLuint shader = glCreateShader( s.type );
glShaderSource( shader, 1, (const GLchar**) &s.source, NULL );
glCompileShader( shader );
GLint compiled;
glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
if ( !compiled ) {
std::cerr << s.filename << " failed to compile:" << std::endl;
GLint logSize;
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &logSize );
char* logMsg = new char[logSize];
glGetShaderInfoLog( shader, logSize, NULL, logMsg );
std::cerr << logMsg << std::endl;
delete [] logMsg;
exit( EXIT_FAILURE );
}
delete [] s.source;
glAttachShader( program, shader );
}
/* link and error check */
glLinkProgram(program);
GLint linked;
glGetProgramiv( program, GL_LINK_STATUS, &linked );
if ( !linked ) {
std::cerr << "Shader program failed to link" << std::endl;
GLint logSize;
glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logSize);
char* logMsg = new char[logSize];
glGetProgramInfoLog( program, logSize, NULL, logMsg );
std::cerr << logMsg << std::endl;
delete [] logMsg;
exit( EXIT_FAILURE );
}
/* use program object */
glUseProgram(program);
return program;
}
} // Close namespace Angel block
The error sounds like it's coming from Source1.cpp not being communicating properly with InitShader.cpp
Since there doesn't appear to be a InitShader.h, I'm assuming you're trying to #include in Source1.cpp, which probably is where the error comes in, since it's expecting a header file.
I'd say try moving all your function definition from InitShader.cpp over to an InitShader.h file, and try including that in Source1.cpp. This is my best guess without seeing the actual code in Source1.cpp.
Alternate idea:
It appears that you're providing the function body in InitShader.cpp for the function prototypes I assume in Angel.h. Are you declaring functions in Angel.h that you then define in InitShader.cpp? If so, I'd highly recomend creating an Angel.cpp file and defining the Angel functions there instead. It would be much cleaner, and I have a hunch that it might end up being the problem you're facing.
I run into the following problem.I load my shaders from files.The shader program ,when trying to compile, throws these errors for the vertex and fragment shaders:
Vertex info
0(12) : error C0000: syntax error, unexpected $undefined at token ""
Fragment info
0(10) : error C0000: syntax error, unexpected $undefined at token ""
When inspecting the loaded content of the files I can see all kinds of garbage text is attached at the beginnings and the ends of the shader files.Like this one:
#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
smooth out vec4 theColor;
void main()
{
gl_Position = position;
theColor = color;
}ýýýý««««««««þîþîþîþ
The methods loading the shaders look as follows:
void ShaderLoader::loadShaders(char * vertexShaderFile,char *fragmentShaderFile){
vs = loadFile(vertexShaderFile,vlen);
fs = loadFile(fragmentShaderFile,flen);
}
char *ShaderLoader::loadFile(char *fname,GLint &fSize){
ifstream::pos_type size;
char * memblock;
string text;
// file read based on example in cplusplus.com tutorial
ifstream file (fname, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
fSize = (GLuint) size;
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "file " << fname << " loaded" << endl;
text.assign(memblock);
}
else
{
cout << "Unable to open file " << fname << endl;
exit(1);
}
return memblock;
}
I tried to change the encoding from UTF-8 top ANSI ,also tried to edit outside the visual studio but the problem still persists .Any help on this will be greatly appreciated.
You're using C++, so I suggest you leverage that. Instead of reading into a self allocated char array I suggest you read into a std::string:
#include <string>
#include <fstream>
std::string loadFileToString(char const * const fname)
{
std::ifstream ifile(fname);
std::string filetext;
while( ifile.good() ) {
std::string line;
std::getline(ifile, line);
filetext.append(line + "\n");
}
return filetext;
}
That automatically takes care of all memory allocation and proper delimiting -- the keyword is RAII: Resource Allocation Is Initialization. Later on you can upload the shader source with something like
void glcppShaderSource(GLuint shader, std::string const &shader_string)
{
GLchar const *shader_source = shader_string.c_str();
GLint const shader_length = shader_string.size();
glShaderSource(shader, 1, &shader_source, &shader_length);
}
void load_shader(GLuint shaderobject, char * const shadersourcefilename)
{
glcppShaderSource(shaderobject, loadFileToString(shadersourcefilename));
}
It looks like all you have to do is allocate one more byte of memory in which you can place a null ('\0'):
...
memblock = new char[1 + fSize];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
memblock[size] = '\0';
...
edit
I changed my code to use fSize in the array rather than size, since it is a GLint, which is just a typedef over an integer. Also, I tried this fix on my machine, and it works as far as I can tell - no junk at the beginning, and none at the end.