4

I've got some problems while trying to load smaller textures for my pixel-art game using SOIL. This is the result while loading a 40 x 40 image: enter image description here

enter image description here

But when I switch to 30 x 40: enter image description here

enter image description here

I checked my code if there are any problems when width is smaller than height, and for 40 x 50 everything is alright. I checked that 30 x 40 with Windows' image viewer, and it seems alright there too. Single thing that may influence in any way the loader is when using the coordinate axis to set the position, but, it works right. This is the code for loading the texture:

glGenTextures(1, &actor.texture);
glBindTexture(GL_TEXTURE_2D, actor.texture);
unsigned char* image = SOIL_load_image(("App/Textures/" + name + ".png").c_str(), &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Popescu Flaviu
  • 95
  • 2
  • 11
  • If you save the image with `SOIL_save_image` and open it in windows, is it correct? What happens to small square images and big rectangular ones? – Quimby Mar 17 '19 at 15:15
  • Also did any OpenGL fail? check `glError` and if everything seems OK so far then how do you draw it? – Quimby Mar 17 '19 at 15:18
  • I never tried to save, but I tried that and I don't get any file in both cases: `unsigned char* image = SOIL_load_image(("App/Textures/" + name + ".png").c_str(), &width, &height, 0, SOIL_LOAD_RGB); SOIL_save_image("test.bmp", SOIL_SAVE_TYPE_BMP, width, height, 0, image);` – Popescu Flaviu Mar 17 '19 at 15:25
  • I also get no OpenGL errors. – Popescu Flaviu Mar 17 '19 at 15:26
  • When saving, put 3 as the third parameter - number of channels. You can write 0 while loading because it is set by the fourth parameter. – Quimby Mar 17 '19 at 15:27
  • No more need, solved. I will also keep that in mind. – Popescu Flaviu Mar 17 '19 at 15:29
  • That's okay, glad you got it working :) – Quimby Mar 17 '19 at 15:30

2 Answers2

6

When the image is loaded to a texture object, then GL_UNPACK_ALIGNMENT has to be set to 1:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); 

Note, by default the parameter is 4. This means that each line of the image is assumed to be aligned to a size which is a multiple of 4. Since the image data are tightly packed and each pixel has a size of 3 bytes, the alignment has to be changed.

When the size of the image is 40 x 50 then the size of a line in bytes is 120, which is divisible by 4.
But if the size of the image is 30 x 40, the the size of a line in bytes is 90, which is not divisible by 4.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
5

The problem does not lie in the small size, but that 30 isn't divisible by 4: 30 = 2 * 3 * 5. The default pixel store setting OpenGL assumes, that rows are aligned to 4-byte boundaries. For the 40×40 image that condition happens to be fulfilled, because no matter what pixel format you use, there's a factor 4 in the width.

The solution is to tell OpenGL, that pixel rows start at a different n-byte boundary:

unsigned char* image = SOIL_load_image(…);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(…);
datenwolf
  • 159,371
  • 13
  • 185
  • 298