I'm following a tutorial to set up some VBOs for the modern OpenGL. I managed to get a mesh and shader running (shader set to make each pixel red).
The problem is, as soon as I push back texture coordinates. I see nothing! With them commented out, I see a dark cyan triangle on the center of the screen.
With the texture I expect a white brick texture to appear on that triangle, but nope...
I really have no idea what's wrong here! Hope some more experienced people have a clue. ;)
This is my mesh code (or VBO code):
Mesh::Mesh() {
//Generate vertex array
glGenVertexArrays(1, &arrayObject);
//Generate buffers
glGenBuffers(VBO_COUNT, buffers);
}
Mesh::Mesh(ObjectData *obj) {
//Initialize first
Mesh();
//Set object to parameter
setObject(obj);
}
Mesh::~Mesh() {
//Delete buffer
glDeleteBuffers(VBO_COUNT, buffers);
//Delete array
glDeleteVertexArrays(1, &arrayObject);
}
void Mesh::draw() {
//Tell OpenGL which array to use
glBindVertexArray(arrayObject);
glDrawArrays(GL_TRIANGLES, 0, object->vertices.size());
glBindVertexArray(NULL);
}
void Mesh::updateVBO() {
//Tell OpenGL which vertex array to use from now
glBindVertexArray(arrayObject);
//Set buffer data
glBindBuffer(GL_ARRAY_BUFFER, buffers[VBO_VERTEX]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * object->vertices.size(), &object->vertices.front(), GL_STATIC_DRAW);
//Set shader attribute data
glEnableVertexAttribArray(VBO_VERTEX);
glVertexAttribPointer(VBO_VERTEX, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
if (object->texCoords.size()) {
//Set buffer data
glBindBuffer(GL_ARRAY_BUFFER, buffers[VBO_TEXCORD]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * object->texCoords.size(), &object->texCoords.front(), GL_STATIC_DRAW);
//Set shader attribute data
glEnableVertexAttribArray(VBO_TEXCORD);
glVertexAttribPointer(VBO_TEXCORD, 2, GL_FLOAT, GL_FALSE, NULL, NULL);
}
//Unbind vertex array
glBindVertexArray(NULL);
}
void Mesh::setObject(ObjectData *obj) {
object = obj;
updateVBO();
}
Here is my shader code:
Shader::Shader(string fileName) {
m_program = glCreateProgram();
m_shaders[SHA_VERTEX] = createShader(loadShader(fileName + ".vs"), GL_VERTEX_SHADER);
m_shaders[SHA_FRAGMENT] = createShader(loadShader(fileName + ".fs"), GL_FRAGMENT_SHADER);
for (int i = 0; i < SHA_COUNT; i++) {
glAttachShader(m_program, m_shaders[i]);
}
glBindAttribLocation(m_program, VBO_VERTEX, "vertices");
glBindAttribLocation(m_program, VBO_TEXCORD, "texCoords");
glLinkProgram(m_program);
checkShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program");
glValidateProgram(m_program);
checkShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program");
}
Shader::~Shader() {
for (int i = 0; i < SHA_COUNT; i++) {
glDetachShader(m_program, m_shaders[i]);
glDeleteShader(m_shaders[i]);
}
glDeleteProgram(m_program);
}
string Shader::loadShader(string filePath) {
ifstream file;
file.open((filePath).c_str());
string output;
string line;
if(file.is_open()) {
while(file.good()) {
getline(file, line);
output.append(line + "\n");
}
}
else {
printf("Unable to load shader: %s\n", filePath.c_str());
}
return output;
}
void Shader::checkShaderError(GLuint shader, GLuint flag, bool isProgram, string errorMessage) {
GLint success = 0;
GLchar error[1024] = {0};
if (isProgram) {
glGetProgramiv(shader, flag, &success);
}
else {
glGetShaderiv(shader, flag, &success);
}
if (success == GL_FALSE) {
if(isProgram) {
glGetProgramInfoLog(shader, sizeof(error), NULL, error);
}
else {
glGetShaderInfoLog(shader, sizeof(error), NULL, error);
}
printf("%s: '%s'\n", errorMessage.c_str(), error);
}
}
GLuint Shader::createShader(string text, unsigned int type) {
GLuint shader = glCreateShader(type);
if (shader == 0) {
printf("Error compiling shader type %i\n", type);
}
const GLchar *p[1];
p[0] = text.c_str();
GLint lengths[1];
lengths[0] = text.length();
glShaderSource(shader, 1, p, lengths);
glCompileShader(shader);
checkShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!");
return shader;
}
void Shader::bind() {
glUseProgram(m_program);
}
Here is my vertices and texCoords:
//Create test objects
ObjectData *obj = new ObjectData();
obj->vertices.push_back(glm::vec3(-0.5, -0.5, 0));
obj->vertices.push_back(glm::vec3(0, 0.5, 0));
obj->vertices.push_back(glm::vec3(0.5, -0.5, 0));
//obj->texCoords.push_back(glm::vec2(0, 0));
//obj->texCoords.push_back(glm::vec2(0.5, 1));
//obj->texCoords.push_back(glm::vec2(1, 0));
Here is my object data:
struct ObjectData {
vector <glm::vec3> vertices;
vector <glm::vec2> texCoords;
ObjectData();
};
Vertex shader:
#version 120
attribute vec3 vertices;
attribute vec2 texCoords;
varying vec2 shared_texCoords;
void main() {
gl_Position = vec4(vertices, 1.0);
shared_texCoords = texCoords;
}
Fragment shader:
#version 120
uniform sampler2D diffuse;
varying vec2 shared_texCoords;
void main() {
gl_FragColor = texture2D(diffuse, shared_texCoords); //vec4(1.0, 0.0, 0.0, 1.0);
}
EDIT:
Texture loading:
Texture::Texture(string fileName) {
SDL_Surface *rawImage = IMG_Load(fileName.c_str());
if (rawImage == NULL) {
printf("Unable to load texture: %s\n", fileName.c_str());
}
else {
//Convert to a texture of pure color pixels for OpenGL
SDL_Surface *image = SDL_CreateRGBSurface(0, rawImage->w, rawImage->h, 24, 0xff000000, 0x00ff0000, 0x0000ff00, 0);
SDL_BlitSurface(rawImage, NULL, image, NULL);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
SDL_FreeSurface(rawImage);
SDL_FreeSurface(image);
}
}
Texture::~Texture() {
glDeleteTextures(1, &m_texture);
}
void Texture::bind() {
glBindTexture(GL_TEXTURE_2D, m_texture);
}