OpenGL 2.0 Flip Pixel Data

Aug 10, 2013 at 6:52pm
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.
Aug 10, 2013 at 7:22pm
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.
Aug 10, 2013 at 7:23pm
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.
Aug 10, 2013 at 8:16pm
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.
Aug 10, 2013 at 11:43pm
closed account (N36fSL3A)
But I have a void pointer of pixels. How would I do that?
Last edited on Aug 11, 2013 at 1:54am
Aug 11, 2013 at 12:54am
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 Aug 11, 2013 at 1:02am
Aug 11, 2013 at 3:24am
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 Aug 11, 2013 at 3:42am
Aug 11, 2013 at 4:07am
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.
Aug 11, 2013 at 3:10pm
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 Aug 11, 2013 at 3:12pm
Aug 11, 2013 at 3:36pm
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.)
Aug 11, 2013 at 5:26pm
(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 Aug 11, 2013 at 5:27pm
Aug 11, 2013 at 5:30pm
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 Aug 11, 2013 at 5:56pm
Aug 11, 2013 at 8:50pm
closed account (N36fSL3A)
bump
Aug 12, 2013 at 4:35am
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.