OpenGL 2.0 Flip Pixel Data

closed account (N36fSL3A)
Alright, so I'm using OpenGL along with SDL for input and window handling. I'm also using SDL_image to load PNGs into my program.

It's all good, but one problem I have is my PNGs load upside down (Vertically flipped). I've looked all around to fix this, but all I see are fixes for OpenGL ES.

So here's my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Texture::Texture(char* location)
{
	// We use SDL_image's function to load the image
	SDL_Surface* img = IMG_Load(location);
	if(img == NULL) {std::cout << "Failed to load " << location << " - " << IMG_GetError() << "\n"; std::cin.get(); exit(4);}

	w = img->w; // We take the width and height from the SDL_Surface*
	h = img->h;

	glGenTextures(1, &texture); // Generate a texture
	glBindTexture(GL_TEXTURE_2D, texture); // Bind that texture temporarily

	int Mode = GL_RGB; // Set the mode

	if(img->format->BytesPerPixel == 4) // If the surface contains an alpha value, tell openGL
	{
		Mode = GL_RGBA;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Set how the texture looks
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // (Both should be linear)

	// Create the texture. We get the offsets from teh image, then we use it with the image's
	// pixel data to create it.
	glTexImage2D(GL_TEXTURE_2D, 0, Mode, img->w, img->h, 0, Mode, GL_UNSIGNED_BYTE, img->pixels);

	// Unbind the texture
	glBindTexture(GL_TEXTURE_2D, NULL);

	SDL_FreeSurface(img); // Free the SDL_Surface, as we no longer need it :)
}


This loads the PNG, then it converts the SDL_Surface* to an OpenGL texture. What I want to do is change the pixel data so it gets flipped right side up, but I don't know where to start.

Thanks in advance.
The simplest solution would be to load your image in an image editing program, flip it and save it.

Or, invert the y/v coordinate in your shader.

Manually flipping the image data before feeding it to glTexImage2D is also an option.
closed account (N36fSL3A)
cire wrote:
Manually flipping the image data before feeding it to glTexImage2D is also an option.
That's what I was looking to do, the problem is I don't know how to do it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

const unsigned rows =  6;
const unsigned cols = 12;

const char image [rows][cols] =
{
    { "     #     " },
    { "    # #    " },
    { "   #   #   " },
    { "  #     #  " },
    { " #       # " },
    { "###########" }
};

int main()
{
    char flippedImage[rows][cols];

    for (unsigned i = 0; i < rows; ++i)
        for (unsigned j = 0; j < cols; ++j)
            flippedImage[i][j] = image[rows-i-1][j];

    std::cout << "Original:\n";
    for (unsigned i = 0; i < rows; ++i)
        std::cout << image[i] << '\n';

    std::cout << "\nFlipped:\n";
    for (unsigned i = 0; i < rows; ++i)
        std::cout << flippedImage[i] << '\n';
}


http://ideone.com/sMzBe9

Except you're working with pixels instead of chars.
closed account (N36fSL3A)
But I have a void pointer of pixels. How would I do that?
Last edited on
Try setting the mode to GL_BGR

Edit: oops scratch that thought you meant colours are inverted.

Yes do what cire says, I would create a struct, then copy the pointer contents to the struct... And invert much cleaner that way.
Last edited on
But I have a void pointer of pixels. How would I do that?


You have the address of the pixels. You know functions and algorithms that work with pointers, right?

I don't have SDL installed, but from looking at the documentation, something like the following (obviously untested) code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Texture::Texture(char* location)
{
    // We use SDL_image's function to load the image
    SDL_Surface* img = IMG_Load(location);
    if (img == NULL) { std::cout << "Failed to load " << location << " - " << IMG_GetError() << "\n"; std::cin.get(); exit(4); }

    w = img->w; // We take the width and height from the SDL_Surface*
    h = img->h;

    typedef uint8_t byte_type;

    const unsigned bytesPerRow = img->pitch;
    const byte_type* originalRaw = static_cast<byte_type*>(img->pixels);
    byte_type* flippedRaw = new byte_type[bytesPerRow * img->h];

    for (unsigned i = 0; i < img->h; ++i)
    {
        const byte_type* srcBeg = originalRaw + (bytesPerRow *(img->h - i - 1));
        const byte_type* srcEnd = srcBeg + bytesPerRow;

        std::copy(srcBeg, srcEnd, flippedRaw + bytesPerRow * i);
    }

    glGenTextures(1, &texture); // Generate a texture
    glBindTexture(GL_TEXTURE_2D, texture); // Bind that texture temporarily

    int Mode = GL_RGB; // Set the mode

    if (img->format->BytesPerPixel == 4) // If the surface contains an alpha value, tell openGL
    {
        Mode = GL_RGBA;
    }

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Set how the texture looks
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // (Both should be linear)

    // Create the texture. We get the offsets from teh image, then we use it with the image's
    // pixel data to create it.
    glTexImage2D(GL_TEXTURE_2D, 0, Mode, img->w, img->h, 0, Mode, GL_UNSIGNED_BYTE, flippedRaw);    // *

    // Unbind the texture
    glBindTexture(GL_TEXTURE_2D, NULL);

    delete [] flippedRaw;                         // *
    SDL_FreeSurface(img);
}


[edit: spelling]
Last edited on
There is absolutly no reason to flip your image.

You dont show the code you use to actually render it to the screen.

I guess you follow this ?
http://www.sdltutorials.com/sdl-tip-sdl-surface-to-opengl-texture

Make sure that your texture coordinates are in the correct order ( glTexCoord2f() ).

I can post tomorrow the code I used.
Yep, my code is a little different than the code at that site:
1
2
3
4
5
6
glBegin(GL_QUADS);
    glTexCoord2f(0, 0); glVertex3f(rect.topLeft.x     , rect.topLeft.y    , 0); // 1
    glTexCoord2f(0, 1); glVertex3f(rect.topLeft.x     , rect.bottomRight.y, 0); // 4
    glTexCoord2f(1, 1); glVertex3f(rect.bottomRight.x , rect.bottomRight.y, 0); // 3
    glTexCoord2f(1, 0); glVertex3f(rect.bottomRight.x , rect.topLeft.y    , 0); // 2
glEnd();


Judging by my comments, I had trouble too :)
Last edited on
Yep, my code is a little different than the code at that site:


You inverted the texture v coordinate. I mentioned that as an option in my first post as something that could be done in the shader although I suppose it can just as easily be done in the coordinates you feed to the shader. (You were also using deprecated functions.)
(You were also using deprecated functions.)

For sure.

That was for drawing a texture in 2d space ( a UI element ), probably should have been using glDrawPixels() anyway.

... Such is the code when you try to do everything yourself.
Last edited on
closed account (N36fSL3A)
EDIT: Thanks cire, works perfectly. :D

This is off topic, but how do I save/load a float to/from a binary file? It has to work on both 64 and 32 bit machines.
Last edited on
closed account (N36fSL3A)
bump
Why are you bumping a thread to get an answer to a question that has nothing to do with the thread? Google "C++ float serialization."

http://stackoverflow.com/questions/4733147/portability-of-binary-serialization-of-double-float-type-in-c

And make a new topic if you have further questions.
Topic archived. No new replies allowed.