0

I'm trying to simply draw an image with OpenGL's immediate mode functions. However, my output is kinda weird. I tried a few Texture parameters - but i get the same result, sometimes with different colors. I kinda can't figure out the problem, but i figure it's either the image loading or texture setup. I'll cut to the case, here is how i generate my texture (in a Texture2D class):

glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

A call to glTexImage2D follows, like this: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);, where data is an array of unsigned char set to 255, white. I then load a PNG file with CImg, like this:

CImg<unsigned char> image(_filename.c_str());
image.resize(m_Width, m_Height);
glBindTexture(GL_TEXTURE_2D, m_ID);
if(image.spectrum() == 4)
{
    unsigned char* data = image.data();
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_Width, m_Height, GL_RGBA,   GL_UNSIGNED_BYTE, data);
}
else if(image.spectrum() == 3)
{
    unsigned char* data = image.data();
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_Width, m_Height, GL_RGB, GL_UNSIGNED_BYTE, data);
}
glBindTexture(GL_TEXTURE_2D, 0);

But when i try to draw the texture in immediate mode like this (origin is upper left corner, notice the red rectangle arund the texture is intentional):

void SimpleRenderer::drawTexture(Texture2D* _texture, float _x, float _y, float _width, float _height)
{
    _texture->setActive(0);
    glBegin(GL_QUADS);
      glTexCoord2f(0.0f, 0.0f);
      glVertex2f(_x, _y);

      glTexCoord2f(1.0f, 0.0f);
      glVertex2f(_x + _width, _y);

      glTexCoord2f(1.0f, 1.0f);
      glVertex2f(_x + _width, _y + _height);

      glTexCoord2f(0.0f, 1.0f);
      glVertex2f(_x, _y + _height);
    glEnd();

    glBindTexture(GL_TEXTURE_2D, 0);

    glColor3ub(strokeR, strokeG, strokeB);
    glBegin(GL_LINE_LOOP);
      glVertex2f((GLfloat)_x, (GLfloat)_y);
      glVertex2f((GLfloat)_x+_width, (GLfloat)_y);
      glVertex2f((GLfloat)_x+_width, (GLfloat)_y+_height);
      glVertex2f((GLfloat)_x, (GLfloat)_y+_height);
    glEnd();
}

I expect an output like this within the rectangle (debugging the same PNG within the same program/thread with CImg):

Mario expected

But i get this:

Mario actual

Can anyone spot the problem with my code?

tubberd
  • 540
  • 5
  • 15

2 Answers2

1

From How pixel data are stored with CImg:

The values are not interleaved, and are ordered first along the X,Y,Z and V axis respectively (corresponding to the width,height,depth,dim dimensions), starting from the upper-left pixel to the bottom-right pixel of the instane image, with a classical scanline run.So, a color image with dim=3 and depth=1, will be stored in memory as :R1R2R3R4R5R6......G1G2G3G4G5G6.......B1B2B3B4B5B6.... (i.e following a 'planar' structure)and not as R1G1B1R2G2B2R3G3B3... (interleaved channels),

OpenGL does not work with planar data, it expects interleaved pixel data. Easiest solution is to use a library other than CImg.

This does not fix the scaling issues, but it's a good place to start.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • great. But CImg is so easy to use and work with :( and ive set up all my dependencies for it... Guess i should read the documentation more thoroughly next time. – tubberd Apr 08 '16 at 23:06
  • 1
    There are *tons* of image loading libraries out there. SDL_Image, DevIL, SOIL, etc. – Dietrich Epp Apr 08 '16 at 23:09
  • I'm currently looking at these. I dismissed SDL_Image as i don't want to use SDL (please don't ask why :D), i have problems trying to compile DevIL with MinGW 5.1, and SOIL seems to only load directly to OpenGL textures, which is unacceptable for me. – tubberd Apr 08 '16 at 23:12
  • Almost sounds like you're trying to fail on purpose... just download the DevIL binaries if you can't compile it, or use SDL even though you don't like it. – Dietrich Epp Apr 08 '16 at 23:15
  • Well, im not trying to fail on purpose, but trying to set up DevIL with CMAKE just throws project errors, and generating doesn't produce any Makefiles as a consequence^^ Well, i guess i have to use a bigger library then. Kinda liked CImg, especially with its integrated image manipulation functionalities. – tubberd Apr 08 '16 at 23:19
  • Does CImg provide any functionality to retrieve the data in interleaved format? Cannot check the documentation right now, i also guess i could just convert the image format myself. Shouldn't be too hard. – tubberd Apr 08 '16 at 23:22
  • You're using OpenGL, which is a hundred times better than CImg for doing image manipulation. If you want a smaller library, you can use WinCodec, but this will only work on Windows. – Dietrich Epp Apr 08 '16 at 23:22
  • Well yes, but then i'll have to write the algorithms myself xD – tubberd Apr 08 '16 at 23:26
0

Use CImg<T>::permute_axes() to transform your image buffer to interleaved format, like this :

CImg<unsigned char> img("imageRGB.png");
img.permute_axes("cxyz"); // Convert to interleaved representation
// Now, use img.data() here as a pointer for OpenGL functions.
img.permute_axes("yzcx");  // Go back to planar representation (if needed).

CImg is indeed a great library, so all these kind of transformations have been planned in the library.

bvalabas
  • 66
  • 1
  • Also beware than when you apply `CImg::permute_axes()` on your `CImg` instance, this also swaps its dimensions accordingly to the given permutation. So `img.spectrum()` becomes `img.width()`, etc.. (width()->height() and height()->depth()). – bvalabas Apr 09 '16 at 07:33