问题
It seems I can't have my GLSL shaders compiled. Once in a while (mainly after editing a file), I get following error while compiling:
----- SRC ----- (150 B)
#version 330 core
uniform mat4 mvpMatrix;
in vec4 vertexPosition_modelspace;
void main() {
gl_Position = mvpMatrix * vertexPosition_modelspace;
}
gp!
----- END -----
SimpleTransform.vertexshader:Vertex shader failed to compile with the following errors:
ERROR: 0:10: error(#132) Syntax error: 'gp' parse error
ERROR: error(#273) 1 compilation errors. No code generated
It's quite strange since I swear the file doesn't contain that awkward gp!
part. Nevertheless I investigated it with cat
#version 330 core
uniform mat4 mvpMatrix;
in vec4 vertexPosition_modelspace;
void main() {
gl_Position = mvpMatrix * vertexPosition_modelspace;
}
and less
#version 330 core
uniform mat4 mvpMatrix;
in vec4 vertexPosition_modelspace;
void main() {
gl_Position = mvpMatrix * vertexPosition_modelspace;
}
and both of them proved me right.
I wonder what's causing this strange behaviour.
Here's link to my project. You should be able to easily compile it by entering src directory and typing make
(Linux only). It requires GLFW, GLEW, GLM and GL3.
And the code itself:
Loading shader files
GLuint shader_load(GLenum type, const char filename[]) {
if ((type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) || !filename) return 0;
/* wczytywanie pliku shadera */
FILE *file = fopen(filename, "rb");
//okreslenie rozmiaru pliku
fseek(file, 0, SEEK_END);
uint32 iFileSize = ftell(file);
fseek(file, 0, SEEK_SET);
//wczytywanie
char *tmp = new char[iFileSize];
memset(tmp, 0, sizeof(tmp));
uint32 iBytes = (uint32) fread(tmp, sizeof(char), iFileSize, file);
fclose(file);
if (iBytes != iFileSize) printf("Warning: reading error possible!\n");
#ifdef _DEBUG_
printf("----- SRC ----- (%d B)\n%s\n----- END -----\n", iBytes, tmp);
#endif
/* przygotowanie shadera */
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, const_cast<const GLchar**>(&tmp), NULL);
delete[] tmp;
glCompileShader(shader); //kompilacja shadera
/* sprawdzenie statusu kompilacji */
int status = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
int logsize = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logsize);
char *log = new char[logsize];
glGetShaderInfoLog(shader, logsize, NULL, log);
printf("%s:%s", filename, log);
delete[] log;
if (status != GL_TRUE) return 0;
return shader;
}
回答1:
FIRST OFF Switch to C++ instead of C-with-a-cpp extension to avoid shipwrecks like this.
Analysis:
Running under valgrind shows
==15579== Invalid read of size 1
==15579== at 0x5B95C65: vfprintf (vfprintf.c:1623)
==15579== by 0x5B9E768: printf (printf.c:35)
==15579== by 0x4019C1: shader_load(unsigned int, char const*) (shaders.cpp:88)
==15579== by 0x401B30: program_create(char const*, char const*) (shaders.cpp:120)
==15579== by 0x401D65: main (in /tmp/ogl-jg-3/test)
==15579== Address 0xb3018a6 is 0 bytes after a block of size 150 alloc'd
==15579== at 0x4C2864B: operator new[](unsigned long) (vg_replace_malloc.c:305)
==15579== by 0x401961: shader_load(unsigned int, char const*) (shaders.cpp:81)
==15579== by 0x401B30: program_create(char const*, char const*) (shaders.cpp:120)
==15579== by 0x401D65: main (in /tmp/ogl-jg-3/test)
It tells you exactly that it tries to read beyond the end of the buffer tmp
which is allocated in line 81. It seems you are somehow assuming it is null-terminated. Which it isn't. Add that:
//wczytywanie
char *tmp = new char[iFileSize+1];
memset(tmp, 0, (iFileSize+1)*sizeof(char));
uint32 iBytes = (uint32) fread(tmp, sizeof(char), iFileSize, file);
fclose(file);
if (iBytes != iFileSize) printf("Warning: reading error possible!\n");
#ifdef _DEBUG_
printf("----- SRC ----- (%d B)\n%s\n----- END -----\n", iBytes, tmp);
#endif
And I get semi-decent output. The GL window stays blank, though
Update
To make it clearer what I meant by switch to C++ here's the idea:
GLuint shader_load(GLenum type, const char filename[]) {
if ((type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) || !filename) return 0;
GLuint shader = glCreateShader(type);
std::string src;
{
/* wczytywanie pliku shadera */
std::ifstream ifs(filename, std::ios::binary);
if (!std::getline(ifs, src, '\0'))
std::cerr << "Warning: reading error possible!\n";
}
#ifdef _DEBUG_
std::cout << "----- SRC ----- " << src.size() << " B \n" << src << "\n----- END -----\n";
#endif
/* przygotowanie shadera */
const GLchar* sources[] = { src.c_str() };
glShaderSource(shader, 1, sources, NULL);
glCompileShader(shader); //kompilacja shadera
来源:https://stackoverflow.com/questions/12117720/reading-file-corrupted-data