Basic texturing w/ core (GLSL) problem

Hi! I need to port some deprecated code to Core and I have troubles with texturing. I simply can’t find a good tutorial for texturing with GLSL (tried the NeHe, Oranges, Superbible…).

I have a 2D puzzle-like image that consists of a few dozen quadratic tiles that should be textured. Think of it as a chessboard, or a quad 2D mesh. Following some examples I found, I’ve managed to get the things working for a single triangle, but I cannot port the solution to the ‘real thing’. Can anyone point me in the right direction, either in form of a tutorial or at least with a hint at what am I missing?
Thanks!

The code looks like this -

Vertex is a simple structure, the coordinates and indexes of the mesh are 100% ok.


typedef struct
{
	GLfloat loc[2]; //2 coordinates are enough for 2D
	GLfloat tex[2];//same here
} Vertex; 

The whole thing works correctly without shaders in this way:

In the pre-loop function setupRC() :


    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numberOfVertices, NULL, GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * numberOfVertices, myVertices);

    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(8));  
    glVertexPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0)); 

    glGenBuffers(1, &ibo); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, numberOfIndexes * sizeof(GLushort), myIndexes, GL_STATIC_DRAW);

and then in the paintGL:


        glEnable( GL_TEXTURE_2D );
        glBindTexture( GL_TEXTURE_2D, myTextureId );
        glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

 	glBindBuffer(GL_ARRAY_BUFFER, vbo);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    	
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    	glEnableClientState(GL_VERTEX_ARRAY);

    	glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(8));
    	glVertexPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));

    	glDrawElements(GL_TRIANGLES, numberOfIndexes, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);

        glDisable( GL_TEXTURE_2D );

However, if I use the vertex array object and shaders instead like this: (setupRC function):


glGenVertexArrays(1, &vao);
glBindVertexArray(vao);


glGenBuffers(2, bufferObjects); //2 buffers, vertex + texture interleaved and indexes
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[0]);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numberOfVertices, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * numberOfVertices, myVertices);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(8));

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*numberOfIndexes, myIndexes, GL_STATIC_DRAW);


glBindVertexArray(0);

myShader = loadShaderWithAttribs( 2, 0, "vVertex", 1, "vTexCoords"); //2 attributes, in index 0 comes 'vVertex' and in index 1 'vTexCoords'

with the shaders and the loadShaderWithAttribs function defined as:

 
GLuint loadShaderWithAttribs(int nAttribs, ...)
{
GLuint vs;
GLuint fs;
GLuint shader = 0;

//Vertex shader:
static std::string source_vs =
"#version 330
"
"in vec4 vVertex;
"
"in vec2 vTexCoords;
"
"smooth out vec2 vVaryingTexCoords;
"
"void main(void) 
"
"    { 
"
"    vVaryingTexCoords = vTexCoords;
"
"    gl_Position = vVertex;
"
"    }\0";

//Fragment shader:
static std::string source_fs =
"#version 330
"
"uniform sampler2D colorMap;
"
"out vec4 vFragColor;
"
"smooth in vec2 vVaryingTexCoords;
"
"void main(void)
"
"   { 
"
"   vFragColor = texture(colorMap, vVaryingTexCoords.st);
"
"   }\0";

const char * vsSource = source_vs.c_str();
const char * fsSource = source_fs.c_str();

vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vsSource, NULL);
glCompileShader(vs);

fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fsSource, NULL);
glCompileShader(fs);

shader = glCreateProgram();
glAttachShader(shader, vs);
glAttachShader(shader, fs);

//Binding the attributes...
va_list attributeList;
va_start(attributeList, nAttribs);

char *nextArg;
int iArgCount = va_arg(attributeList, int);
for(int i = 0; i < iArgCount; i++)
	{
	int index = va_arg(attributeList, int);
	nextArg = va_arg(attributeList, char*);
	glBindAttribLocation(shader, index, nextArg);
	}
va_end(attributeList);

glLinkProgram(shader);

glDeleteShader(vs);
glDeleteShader(fs);

return shader;
}

… now I suppose this is the part where I fail - painGL():


    	glUseProgram(myShader);
        glBindTexture(GL_TEXTURE_2D, myTextureId);
        GLint iTextureUniform = glGetUniformLocation(myShader, "colorMap");
    	glUniform1i(iTextureUniform, 0);

    	glBindVertexArray(vao);
    	glDrawElements(GL_TRIANGLES, numberOfIndexes, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

One thing I can spot is that you have:

glDrawElements(GL_TRIANGLES, numberTriangles, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

It should probably be:

glDrawElements(GL_TRIANGLES, numberTriangles * 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));// or numberOfIndexes?

Other than that, what problem do you have exactly? I can’t see anything else obviously wrong, but it might be easier to figure out what is wrong if the error message by glGetError() or unexpected result was mentioned.

If possible, I also wouldn’t use glGetUniformLocation(myShader, “colorMap”); every time you want to adjust the colorMap uniform, but instead would determine the location just once after linking.

Of course - my bad, it was a copy paste error. I’ve edited it.
Well, compiler reports no errors and no warnings, no segmentation faults, nothing. But instead of one centered (textured) image I get only a curious (non-textured) quad in the upper right corner of the image viewer window. If I comment out this:


    	glUseProgram(myShader);
        glBindTexture(GL_TEXTURE_2D, myTextureId);
        GLint iTextureUniform = glGetUniformLocation(myShader, "colorMap");
    	glUniform1i(iTextureUniform, 0);

and leave the glDrawElements I get the correct mesh grid, but no textures so I guess the vao/vbo/ibo are fine, but something else is rotten.

Do you suggest I put the above in the setupRC() instead of paintGL? I’ll try it immediately.

To be honest, I am not perfectly sure I understand how exactly does the getUniformLocation works. Any examples or tutorials would be great!

Edit: Moving the above code out of paintGL() produces exactly the same result

Do you suggest I put the above in the setupRC() instead of paintGL? I’ll try it immediately.

I would suggest that you change your shader to turn off texturing and see what happens. Just write a color to the output.

To be honest, I am not perfectly sure I understand how exactly does the getUniformLocation works. Any examples or tutorials would be great!

Why do you keep asking for “examples or tutorials” for how a function works? What you want is documentation. Copy-and-pasting from examples is precisely the reason you don’t know how the function works, yet you’re still using it.

For the record: uniforms have names. However, accessing data based on string names can take lots of time. Therefore, OpenGL programs assign a uniform location (a number) to every uniform in a program. glGetUniformLocation is how you get the uniform location from a uniform name. All of the glUniform* functions take uniform locations.

Thanks Alfonse! I will try it right away. Btw, I prefer a tutorial to documentation exactly because your explanation is much more understandable then: “glGetUniformLocation — Returns the location of a uniform variable” from
http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocation.xml

Please dont get me wrong, but I find the documentation pretty lousy, and a fine tutorial on GLSL texturing is hard to find :frowning:

Edit: changing the fragment shader:


--vFragColor = texture(colorMap, vVaryingTexCoords.st);"
++vFragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);

Makes the quad red (but the quad still has different coordinates then the original one).

That’s reference documentation. I was talking about documentation.

Now thats something else! Thanks for the link, its bookmarked. You were right, that was exactly what I was looking for, my bad. :slight_smile: I’ll see what I can work out now.

P.S. This is even better :slight_smile:

I think I found out why the program doesnt work correctly, at least the texturing. The deprecated program uses the texture combiner

glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

Which need to be ported correctly into shaders as stated here: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=295011

Got the issue fixed - there was a transformation in deprecated code that I oversaw (very stupid of me), so everything worked after I fixed the vertex shader.

Thanks for all suggestions and links, I learned a lot! :slight_smile: