Problem compiling glsl shader at run time

I am working on a project using OpenGL 4.0 shaders.

I need to send a call to glShaderSource () with an array of char arrays, which is the source of the shader.

Shader compilation does not work with the following errors:

(0) : error C0206: invalid token "<null atom>" in version line (0) : error C0000: syntax error, unexpected $end at token "<EOF>" 

Here's my (hello world) shader - right from the OpenGL 4.0 shaded language cookbook

 #version 400 in vec3 VertexPosition; in vec3 VertexColor; out vec3 Color; void main() { Color = VertexColor; gl_Position = vec4( VertexColor, 1.0 ); } 

And here is my code to read the shader file in my C ++ code and compile the shader at runtime:

 const int nMaxLineSize = 1024; char sLineBuffer[nMaxLineSize]; ifstream stream; vector<string> vsLines; GLchar** ppSrc; GLint* pnSrcLineLen; int nNumLines; stream.open( m_sShaderFile.c_str(), std::ios::in ); while( (stream.good()) && (stream.getline(sLineBuffer, nMaxLineSize)) ) { if( strlen(sLineBuffer) > 0 ) vsLines.push_back( string(sLineBuffer) ); } stream.close(); nNumLines = vsLines.size(); pnSrcLineLen = new GLint[nNumLines]; ppSrc = new GLchar*[nNumLines]; for( int n = 0; n < nNumLines; n ++ ) { string & sLine = vsLines.at(n); int nLineLen = sLine.length(); char * pNext = new char[nLineLen+1]; memcpy( (void*)pNext, sLine.c_str(), nLineLen ); pNext[nLineLen] = '\0'; ppSrc[n] = pNext; pnSrcLineLen[n] = nLineLen+1; } vsLines.clear(); // just for debugging purposes (lines print out just fine..) for( int n = 0; n < nNumLines; n ++ ) ATLTRACE( "line %d: %s\r\n", n, ppSrc[n] ); // Create the shader m_nShaderId = glCreateShader( m_nShaderType ); // Compile the shader glShaderSource( m_nShaderId, nNumLines, (const GLchar**)ppSrc, (GLint*) pnSrcLineLen ); glCompileShader( m_nShaderId ); // Determine compile status GLint nResult = GL_FALSE; glGetShaderiv( m_nShaderId, GL_COMPILE_STATUS, &nResult ); 

C ++ code executes as expected, but shader compilation fails. Can anyone determine what I can do wrong?

I have a feeling that this may be somehow connected with the characters of the end of the line, but since this is my first attempt to create a shader, I'm stuck!

I read other SO answers on shader compilation, but they seem to relate to Java / other languages, not C ++. If this helps, I'm on a win32 platform.

+4
source share
3 answers

Just fast:

Have you tried calling glShaderSource with NULL as a length parameter? In this case, OpenGL will consider your code to be null.

(Edited due to stupidity)

+1
source

You made a mistake that others made. This is the definition of glShaderSource :

 void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length); 

string is an array of strings. It is not intended to create an array of strings in your shader. The way the compiler will interpret this array of strings is to combine them with each other, one after another. No translation lines.

Since stream.getline will not put the \n character on a line, each of the shader lines you create will not have a new line at the end. Therefore, when glShaderSource them, your shader will look like this:

 #version 400in vec3 VertexPosition;in vec3 VertexColor;out vec3 Color;... 

This is not legal GLSL.

The right way to do this is to upload the file as a string.

 std::ifstream shaderFile(m_sShaderFile.c_str()); if(!shaderFile) //Error out here. std::stringstream shaderData; shaderData << shaderFile.rdbuf(); //Loads the entire string into a string stream. shaderFile.close(); const std::string &shaderString = shaderData.str(); //Get the string stream as a std::string. 

Then you can simply pass this glShaderSource value quite easily:

 m_nShaderId = glCreateShader( m_nShaderType ); const char *strShaderVar = shaderString.c_str(); GLint iShaderLen = shaderString.size(); glShaderSource( m_nShaderId, 1, (const GLchar**)&strShaderVar, (GLint*)&iShaderLen ); glCompileShader( m_nShaderId ); 

If you copied this download code from somewhere, I highly recommend that you find another place to learn about OpenGL . Because it's terrible coding.

+14
source

glShaderSource (m_nShaderId, nNumLines, (const GLchar **) ppSrc, (GLint *) pnSrcLineLen);

I know that the signature of glShaderSource looks tempting to send each line of the shader separately. But now this is what it is for. The sending point is multiple arrays, so you can combine several primitive shader sources into one shader, for example, include files. Understanding this makes it much easier to read in the shader file - and avoids such unpleasant errors.

Using C ++, you can do it much better and cleaner. I already wrote follwing in Getting garbage characters when reading GLSL files


You are using C ++, so I suggest you use this. Instead of reading into a dedicated dedicated char array, I suggest you read 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; } 

This automatically takes care of all the memory allocation and the correct demarcation - the key word is RAII: resource allocation is initialization. You can later load 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); } 

You can use these two functions together as follows:

 void load_shader(GLuint shaderobject, char * const shadersourcefilename) { glcppShaderSource(shaderobject, loadFileToString(shadersourcefilename)); } 
+2
source

Source: https://habr.com/ru/post/1379828/


All Articles