I'm a noob to the OpenGL world and am picking up ideas through practice. I've been writing some code to build retro-arcade games recently and need to load textures to provide the graphic interface. I'm using OpenGL v4.6 with GLFW3 and the stb library to load images.
To load textures, I draw a box and define the texture coordinates of the image on the box. Only some of the png's that I use have loaded properly- often, the image is blurred and distorted. There were two things I tried so far-
Look exclusively for jpg files as these were loading properly. But most of the textures that I download of google are exclusively png
Convert the png into a jpg file. Since I was converting, I decided to use other file formats as well, cropping some of the images if need be. I used GIMP to export them in jpg format. However, when I try to load it OpenGL, I still get bad-poor results.
Another possible approach I'm considering is to convert them into dxt formats and see if that does the trick. However, this seems a tad too tedious and something I'd only go for if nothing else works.
Below is the code that I'm using to load the image.
int width, height, nrChannels;
unsigned char* data = stbi_load(file_path, &width, &height, &nrChannels, 0);
GLenum format{};
if (data)
{
if (nrChannels == 1)
format = GL_RED;
else if (nrChannels == 3)
format = GL_RGB;
else if (nrChannels == 4)
format = GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
I'm starting to spend a significant amount of time looking for images that will load properly and less time learning/implementing; this is quite concerning. Can someone please point out where I'm going wrong or a better way of skirting around this issue?
The image to the left is the original as loaded by OpenGL (jfif file format). The one to the bottom is the edited version (made with Gimp, stored as jpg). The image to the right is the render of the bottom image in OpenGL
Again, the image to the left is the output from Opengl while the one to the right is the original image. Note the inclination of the render and lack of colour in it.
Edit: Here are some of the implementation details-
I'm believe this portion should be correct because the render is perfect for .jpg files. rect is a vector to hold the box and texture coordinates and ind is a vector that holds the indices that are used by the element buffer to avoid repeat drawing. Both are initialised as arrays and converted into a vector (loop through array and push_back into vector).
PS. Apologies for the verbosity. I was trying to couch the drawing inside a class and this was my first attempt at it. So, please bear with me.
// Box container to hold images
// x y tex-x tex-y
const float rect[] = {
-0.2f, -0.2f, 0.0f, 0.0f,
0.2f, -0.2f, 1.0f, 0.0f,
0.2f, 0.2f, 1.0f, 1.0f,
-0.2f, 0.2f, 0.0f, 1.0f
};
int ind[] = {
0,1,2,
0,2,3
};
_num_attr_ is the number of attributes given to the vao, which in this case is 2. cumsum contains the sum of the number of attributes and is used to assign the stride and size of each attribute.
sizes = {2,2}; // initialized
cumsum = 0;
for (int i = 0; i < num_attr; ++i)
{
attr_num_cumsum.push_back(cumsum);
cumsum += sizes[i];
attr_size.push_back(sizes[i]);
}
attr_num_cumsum.push_back(cumsum);
At the end of this block, cumsum has a value of 4 and _attr_num_cumsum_ = {0,2,4} and _attr_size_ = {2,2}.
_vbo_data_ contains the values in rect while _ebo_data_ contains the values in ind Here is the buffer set-up for drawing-
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vbo_data.size()*sizeof(GL_FLOAT), &vbo_data[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ebo_data.size()*sizeof(GL_INT), &ebo_data[0], GL_DYNAMIC_DRAW);
for (int i = 0; i < num_attr; ++i)
{
glVertexAttribPointer(i, attr_size[i], GL_FLOAT, GL_FALSE, attr_num_cumsum[num_attr] * sizeof(GL_FLOAT), (void*)(attr_num_cumsum[i] * sizeof(GL_FLOAT)));
glEnableVertexAttribArray(i);
}
And the actual drawing
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, num_vertices, GL_UNSIGNED_INT, 0);
Vertex Shader
#version 460 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec2 tex;
out float C;
out vec2 Tex;
uniform mat4 model;
uniform float col;
void main()
{
gl_Position = model*vec4(aPos.x,aPos.y,0.0f, 1.0f);
C=col;
Tex=tex;
}
Fragment Shader
#version 460 core
out vec4 Fragcolor;
in float C;
in vec2 Tex;
uniform sampler2D texture1;
void main()
{
Fragcolor = texture(texture1,Tex);
}
glPixelStorei
would probably be the fix, but without knowing more details about the input texture, impossible to say what argumentsglPixelStorei
should take. $\endgroup$