It seems every time I try to get texturing working in my OpenGL apps I miss something obvious, and I end up spending many hours debugging. Well it happened again and even though I've been trying to compare my code with an older working app for quite some time, I'm still missing something because the texture just isn't displaying at all. The mesh shows up black. I'm not getting any OpenGL errors.
I would be very grateful for some help narrowing down the problem.
Here is part of my code, I'm pretty sure my mistake is in these areas of the code:
OpenGL.cpp:
bool OpenGL::enable_attribs_and_uniforms(GLuint program_id)
{
glGenVertexArrays(1, &this->vao_id);
glBindVertexArray(this->vao_id);
this->pos_a_loc = glGetAttribLocation(program_id, "pos_a");
this->uv_a_loc = glGetAttribLocation(program_id, "uv_a");
if (this->pos_a_loc == -1 || /*this->color_a_loc == -1 ||*/ this->uv_a_loc == -1)
{
std::cerr << "OpenGL Warning: Failed to get attribute locations, probably because at least one attribute isn't being used in the shader program. Attributes get optimized out if they don't affect the output of the shader program in any way.\n\n";
}
glEnableVertexAttribArray(this->pos_a_loc);
glEnableVertexAttribArray(this->uv_a_loc);
this->p_mat_u_loc = glGetUniformLocation(program_id, "p_mat_u");
this->v_mat_u_loc = glGetUniformLocation(program_id, "v_mat_u");
this->m_mat_u_loc = glGetUniformLocation(program_id, "m_mat_u");
this->mvp_mat_u_loc = glGetUniformLocation(program_id, "mvp_mat_u");
this->tex_samp_u_loc = glGetUniformLocation(program_id, "tex_samp_u");
if (this->p_mat_u_loc == -1 || this->v_mat_u_loc == -1 ||
this->m_mat_u_loc == -1 || this->mvp_mat_u_loc == -1 ||
this->tex_samp_u_loc == -1)
{
std::cerr << "OpenGL Warning: Failed to get all uniform locations, probably because at least one uniform isn't being used in the shader program. Uniforms get optimized out if they don't affect the output of the shader program in any way.\n\n";
}
check_gl_error();
return true;
}
void OpenGL::fill_buffers(std::vector<Object*>& objs)
{
std::vector<Object*>::iterator it;
for (it = objs.begin(); it != objs.end(); ++it)
{
GLuint vb_pos_id;
glGenBuffers(1, &vb_pos_id);
glBindBuffer(GL_ARRAY_BUFFER, vb_pos_id);
glBufferData(GL_ARRAY_BUFFER, (*it)->v_pos.size() * sizeof(glm::vec3), &(*it)->v_pos[0], GL_STATIC_DRAW);
this->vb_pos_ids.push_back(vb_pos_id);
(*it)->tex_filenames[0] = "some_texture.png";
SDL_Surface* tex_surface = IMG_Load((*it)->tex_filenames[0].c_str());
if (!tex_surface)
{
std::cerr << "Texture Error: Couldn't open texture file: " << (*it)->tex_filenames[0] << "\n\n";
return;
}
GLuint tex_samp_id;
glGenTextures(1, &tex_samp_id);
glBindTexture(GL_TEXTURE_2D, tex_samp_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_surface->w, tex_surface->h, 0,
GL_RGBA, GL_UNSIGNED_BYTE, tex_surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
this->tex_samp_ids.push_back(tex_samp_id);
GLuint vb_uv_id;
glGenBuffers(1, &vb_uv_id);
glBindBuffer(GL_ARRAY_BUFFER, vb_uv_id);
glBufferData(GL_ARRAY_BUFFER, (*it)->v_uv.size() * sizeof(glm::vec2), &(*it)->v_uv[0], GL_STATIC_DRAW);
this->vb_uv_ids.push_back(vb_uv_id);
}
check_gl_error();
return;
}
void OpenGL::draw(std::vector<Object*>& objs) // draws GL_TRIANGLES
{
std::vector<Object*>::iterator objs_it;
std::vector<GLuint>::iterator vb_pos_it;
std::vector<GLuint>::iterator vb_col_it;
std::vector<GLuint>::iterator vb_uv_it;
unsigned int i = 0;
for (objs_it = objs.begin(), vb_pos_it = this->vb_pos_ids.begin(),
vb_col_it = this->vb_col_ids.begin(), vb_uv_it = this->vb_uv_ids.begin();
objs_it != objs.end(); ++objs_it, ++vb_pos_it, ++vb_col_it, ++vb_uv_it, ++i)
{
(*objs_it)->m_mat = glm::rotate((*objs_it)->m_mat, 1.0f, glm::vec3(0.0f, 1.0f, 0.0f));
this->mvp_mat = this->p_mat * this->v_mat * (*objs_it)->m_mat;
// send attribs to vertex shader
glBindBuffer(GL_ARRAY_BUFFER, (*vb_pos_it));
glVertexAttribPointer(this->pos_a_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->tex_samp_ids[i]);
glBindBuffer(GL_ARRAY_BUFFER, (*vb_uv_it));
glVertexAttribPointer(this->uv_a_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
// send uniforms to vertex shader
glUniformMatrix4fv(this->p_mat_u_loc, 1, GL_FALSE, &this->p_mat[0][0]);
glUniformMatrix4fv(this->v_mat_u_loc, 1, GL_FALSE, &this->v_mat[0][0]);
glUniformMatrix4fv(this->m_mat_u_loc, 1, GL_FALSE, &(*objs_it)->m_mat[0][0]);
glUniformMatrix4fv(this->mvp_mat_u_loc, 1, GL_FALSE, &this->mvp_mat[0][0]);
glUniform1i(this->tex_samp_u_loc, 0);
// draw
glDrawArrays(GL_TRIANGLES, 0, (*objs_it)->v_pos.size());
check_gl_error();
glGetError(); // clear GL error before next iteration
}
return;
}
simple.vsh:
#version 330 core
in vec3 pos_a;
in vec2 uv_a;
uniform mat4 p_mat_u;
uniform mat4 v_mat_u;
uniform mat4 m_mat_u;
uniform mat4 mvp_mat_u;
out vec2 uv_v;
void main()
{
gl_Position = mvp_mat_u * vec4(pos_a, 1.0);
uv_v = uv_a;
}
simple.fsh:
#version 330 core
smooth in vec2 uv_v;
uniform sampler2D tex_samp_u;
out vec4 color_o;
void main()
{
color_o = texture2D(tex_samp_u, uv_v);
}