I coded the following class that I can use to successfully display the following RGB image of a triangle. So, the image buffer is something like. 1 byte for each color component.
RGB RGB ...
RGB RGB ...
...
Then I decided to add the alpha channel to the image making the image buffer like, changing the types passed to the glTexImage2D command from GL_RGB to GL_RBGA, and I got the following distorted image.
RGBA RGBA ...
RGBA RGBA ...
...
Any idea what is going on?
#ifndef _SCREEN_H_
#define _SCREEN_H_
#include <GLFW/glfw3.h>
#include <stdint.h>
#include <string>
namespace Screen
{
class Screen
{
public:
Screen(){};
~Screen(){};
bool initialize(uint32_t ScreenWidth, uint32_t ScreenHeight, std::string& Title);
void display_image(uint8_t* ImageData, uint32_t ImageWidth, uint32_t ImageHeight);
void deinitialize();
private:
GLFWwindow* _window = nullptr;
uint32_t _shader_program = 0u;
uint32_t _object_vertex_array = 0u;
uint32_t _object_vertex_buffer = 0u;
uint32_t _object_element_buffer = 0u;
uint8_t* _image_data = nullptr;
};
}
#endif // _SCREEN_H_
#include <GL/glew.h>
#include <stdint.h>
#include <string>
#include "Screen.h"
namespace Screen
{
namespace
{
bool build_shader_vertex(uint32_t& ShaderVertex)
{
const char* source_shader_vertex =
"#version 330 core\n"
"layout (location = 0) in vec4 input_position;\n"
"layout (location = 1) in vec2 input_texture;\n"
"out vec2 output_texture;\n"
"void main()\n"
"{\n"
"gl_Position = input_position;\n"
"output_texture = input_texture;\n"
"}\n"
"\0";
ShaderVertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(ShaderVertex, 1, &source_shader_vertex, NULL);
glCompileShader(ShaderVertex);
GLint success = 0;
glGetShaderiv(ShaderVertex, GL_COMPILE_STATUS, &success);
if (!success)
{
fprintf(stderr, "%s:%d:%s: Failed to compile vertex shader\n", __FILE__, __LINE__, __FUNCTION__);
return false;
}
return true;
}
bool build_shader_fragment(uint32_t& ShaderFragment)
{
const char* source_shader_fragment =
"#version 330 core\n"
"out vec4 fragment_color;\n"
"in vec2 output_texture;\n"
"uniform sampler2D sampled_texture;\n"
"void main()\n"
"{\n"
"fragment_color = texture(sampled_texture, output_texture);\n"
"}\n"
"\0";
ShaderFragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(ShaderFragment, 1, &source_shader_fragment, NULL);
glCompileShader(ShaderFragment);
GLint success = 0;
glGetShaderiv(ShaderFragment, GL_COMPILE_STATUS, &success);
if (!success)
{
fprintf(stderr, "%s:%d:%s: Failed to compile fragment shader\n", __FILE__, __LINE__, __FUNCTION__);
return false;
}
return true;
}
bool build_program(uint32_t& ShaderProgram)
{
bool ret_val = true;
uint32_t shader_vertex = 0u;
uint32_t shader_fragment = 0u;
GLint success = 0;
if (!build_shader_vertex(shader_vertex))
{
fprintf(stderr, "%s:%d:%s: Failed to build shader\n", __FILE__, __LINE__, __FUNCTION__);
ret_val = false;
goto terminate;
}
if (!build_shader_fragment(shader_fragment))
{
fprintf(stderr, "%s:%d:%s: Failed to build shader\n", __FILE__, __LINE__, __FUNCTION__);
ret_val = false;
goto terminate;
}
ShaderProgram = glCreateProgram();
glAttachShader(ShaderProgram, shader_vertex);
glAttachShader(ShaderProgram, shader_fragment);
glLinkProgram(ShaderProgram);
glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
fprintf(stderr, "%s:%d:%s: Failed to link shader program\n", __FILE__, __LINE__, __FUNCTION__);
ret_val = false;
goto terminate;
}
terminate:
glDeleteShader(shader_vertex);
glDeleteShader(shader_fragment);
return ret_val;
}
}
bool Screen::initialize(uint32_t ScreenWidth, uint32_t ScreenHeight, std::string& Title)
{
constexpr int32_t major_number = 3;
constexpr int32_t minor_number = 3;
uint32_t shader_program = 0u;
if (glfwInit() != GLFW_TRUE)
{
fprintf(stderr, "%s:%d:%s: Failed to initialize GLFW\n", __FILE__, __LINE__, __FUNCTION__);
return false;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major_number);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor_number);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
_window = glfwCreateWindow(ScreenWidth, ScreenHeight, Title.c_str(), NULL, NULL);
if (!_window)
{
fprintf(stderr, "%s:%d:%s: Failed to create window\n", __FILE__, __LINE__, __FUNCTION__);
return false;
}
glfwMakeContextCurrent(_window);
if (glewInit() != GLEW_OK)
{
fprintf(stderr, "%s:%d:%s: Failed to initialize GLEW\n", __FILE__, __LINE__, __FUNCTION__);
return false;
}
if (!build_program(shader_program))
{
fprintf(stderr, "%s:%d:%s: Failed to initialize GLEW\n", __FILE__, __LINE__, __FUNCTION__);
return false;
}
float vertices[] =
{
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
};
unsigned int indices[] =
{
0, 1, 3,
1, 2, 3,
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(4 * sizeof(float)));
glEnableVertexAttribArray(1);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUseProgram(shader_program);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
return true;
}
void Screen::display_image(uint8_t* ImageData, uint32_t ImageWidth, uint32_t ImageHeight)
{
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ImageWidth, ImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, ImageData);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ImageWidth, ImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, ImageData);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(_window);
glfwPollEvents();
}
void Screen::deinitialize()
{
if (_image_data)
{
delete[] _image_data;
}
glDeleteVertexArrays(1, &_object_vertex_array);
glDeleteBuffers (1, &_object_vertex_buffer);
glDeleteBuffers (1, &_object_element_buffer);
_image_data = nullptr;
glfwTerminate();
}
}
I think that the image you're using only contains 3 channels: RGB. Thus forcing OpenGL to read its RGB data as RGBA causes misalignments in the process, and therefore the colors aren't accurately represented.
If you're image has 4 channels, RGBA, it should work fine. Visual Studio lets you change it I believe, when you open the image.