SDL - upper-down image - very important thing in OpenGL

In SDL for example point (0.0) is upper left.
In OpenGL point (0.0) is lower left so when I load texture and use OpenGL coordinates I have upper down image. How can I change SDL coordinates on the same like in OpenGL ?

Are you using SDL 1.3?

If so, are you using SDL’s built-in hardware-accelerated rendering, or are you just creating an OpenGL context using SDL and then doing the rendering yourself?

Also, how are you loading the texture images?

Unless I’m missing something, the problem you’re seeing doesn’t really have anything to do with SDL.

As far as images go, SDL doesn’t really put the origin in the upper left, nor does OpenGL put the origin in the lower left.

Most image formats store the image data in row-major order (that is, row 0, then row 1, then row 2, etc.). Furthermore, most image editing programs (IMX, at least) interpret images as being stored ‘top-down’; that is, the 0’th row is the top row, and on down from there. So if you create a texture in an image editing program that has a clear ‘up’ and ‘down’, it’s likely that the first row will be the top row rather than the bottom row.

OpenGL itself doesn’t have any concept of how an image is oriented; how the image is oriented is determined by the texture coordinates, which in turn are determined by the data that you send to the API. So in other words, you determine how the image is oriented in OpenGL; OpenGL just does what you tell it to do.

That said, when specifying texture coordinates for, say, a quad in OpenGL, people do tend to place v = 0 at the bottom rather than the top. If the image hasn’t been adjusted in any way, this will result in the image appearing to be ‘upside-down’ relative to what you expect.

There’s at least a couple of solutions to the problem. One solution is to adjust the v components of all your texture coordinates appropriately (e.g. v = 1 - v). Another is to flip your image vertically before uploading it to OpenGL.

Unless I’m mistaken, IMG_Load() just loads the image as-is; it doesn’t impose any sort of coordinate system or orientation on it, so in that sense the issue has nothing to do with SDL or SDL_image. Rather, it’s just an issue of convention, which can be addressed (as mentioned above) by flipping the image vertically or modifying the texture coordinates appropriately.

badday wrote:

So when I copy code from this tutorial:

Code:

// Front Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad

I have upper-down image because for example: glTexCoord2f(0.0f, 0.0f); in opengl it is left down corner image but in SDL it is left upper image.

You might give my previous post another read. Again, OpenGL doesn’t specify how textures are oriented; rather, you determine how the texture is oriented by specifying appropriate texture coordinates.

I can’t really comment directly on the NeHe tutorial (among other things, it uses a bitmap-loading function that I’m not familiar with and about which there doesn’t seem to be much info online). I can tell you though that it’s fairly common to flip images vertically on load in order to compensate for the effect you’re describing, and that it’s also fairly common to ‘invert’ the v components of texture coordinates for the same reason.

Again, it’s not because SDL does it one way and OpenGL does it another way. SDL_image is just loading the image as it’s stored in the file, and OpenGL is just rendering what you tell it to render. Unless I’m mistaken, the issue has nothing to do with SDL; if you were to use another image loader, you’d likely run into the same problem. (It’s worth noting that some image loaders offer a ‘vertical flip’ option to compensate for this effect.)

One solution to the problem would be to flip the image after receiving it from SDL_image, and before uploading it to OpenGL.

I’m glad you solved your problem :slight_smile:

However, it seems you didn’t read any of my posts. The threads you linked to basically said (in one form or another) exactly what I’ve said here, and in fact the exact same solutions were proposed that I’ve proposed here. Note:

Jesse A. wrote:

One solution to the problem would be to flip the image after receiving it from SDL_image, and before uploading it to OpenGL.

badday wrote:

So the solution is to invert image:

So you basically ended up doing exactly what I suggested :slight_smile:

Still, it’s important to understand that this isn’t really an SDL issue; you could easily run into the same problem using another image loader. Furthermore, the problem isn’t that SDL puts the origin in the ‘upper left’ or that OpenGL puts it in the ‘lower left’, but rather that the conventions most typically used for image layout and texture coordinate layout happen to differ, meaning that in general, one or the other will need to be adjusted. This issue is independent of any particular image loading library, more or less.

But somebody should add this solution to SDL library - it is very important for OpenGL.

Well, more features are always nice :slight_smile: And there are indeed some image-loading libraries (FreeImage and SOIL come to mind) that offer a ‘vertical flip’ option for this very reason.

I don’t know if SDL_image is undergoing active development right now, but you could always submit a patch or a feature request. But, since flipping an image is a fairly straightforward process, it’s probably just as easy to use a custom function for this purpose (just as you’re doing currently).

"OpenGL doesn’t specify how textures are oriented; rather, you determine how the texture is oriented by specifying appropriate texture coordinates. " - other example - in opengl I can draw teapot or sphere without writing vertex coordinates using functions glutSolidTeapot() and glutSolidSphere() - in that case I CAN’T set textures coordinates so textures are always upside-down. This isn’t only my problem:
http://www.gamedev.net/topic/188170-opengl-texture-mapping-question-sdl/
http://bhsphd.spaces.live.com/blog/cns!1844003DFD14BA7D!312.entry

This is SDL problem - why ? Because I can write my own function to load textures:

Code:

GLuint LoadTexture(const char * filename, int width, int height)
{
GLuint texture;
unsigned char * data;
FILE * file;

file = fopen(filename, "rb"); 
if (file == NULL) return 0; 

data = (unsigned char *)malloc(width * height * 3); 
fread(data, width * height * 3, 1, file);

fclose(file);

glGenTextures(1, &texture);  
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 
free(data);

return texture;

}

and this problem with upper-down picture doesn’t exist.

Isn’t it really possible in some function in SDL change settings these coordinates ?

I HAVE FOUND SOLUTION HERE: http://www.gribblegames.com/articles/game_programming/sdlgl/invert_sdl_surfaces.html :smiley:

But somebody should add this solution to SDL library - it is very important for OpenGL.
So the solution is to invert image:

Code:

int invert_image(int pitch, int height, void* image_pixels)
{
int index;
void* temp_row;
int height_div_2;

temp_row = (void *)malloc(pitch);
if(NULL == temp_row)
{
	SDL_SetError("Not enough memory for image inversion");
	return -1;
}
//if height is odd, don't need to swap middle row
height_div_2 = (int) (height * .5);
for(index = 0; index < height_div_2; index++) 	{
	//uses string.h
	memcpy((Uint8 *)temp_row,
		(Uint8 *)(image_pixels) +
		pitch * index,
		pitch);

	memcpy(
		(Uint8 *)(image_pixels) +
		pitch * index,
		(Uint8 *)(image_pixels) +
		pitch * (height - index-1),
		pitch);
	memcpy(
		(Uint8 *)(image_pixels) +
		pitch * (height - index-1),
		temp_row,
		pitch);
}
free(temp_row);
return 0;

}

//This is the function you want to call!
int SDL_InvertSurface(SDL_Surface* image)
{
if(NULL == image)
{
SDL_SetError(“Surface is NULL”);
return -1;
}
return( invert_image(image->pitch, image->h,
image->pixels) );
}

//then:
//SDL_Surface* surface;
//surface = IMG_Load(filename)
//SDL_InvertSurface(surface);

Yes, I use SDL 1.3 - here is my code - this is function to load texture from path

Code:

GLuint LoadTexture(const char * filename)
{
GLuint texture;
GLint nOfColors;
GLenum texture_format;
SDL_Surface* surface;

if ( (surface = IMG_Load(filename)) ) 
{  
	// Check that the image's width is a power of 2
	if ( (surface->w & (surface->w - 1)) != 0 ) 
	{
		MessageBox(hWnd, TEXT("image width is not a power of 2"), TEXT("error"), MB_OK | MB_ICONINFORMATION);
	} 
	// Also check if the height is a power of 2
	if ( (surface->h & (surface->h - 1)) != 0 ) 
	{
		MessageBox(hWnd, TEXT("image height is not a power of 2"), TEXT("error"), MB_OK | MB_ICONINFORMATION);
	}

    // get the number of channels in the SDL surface
    nOfColors = surface->format->BytesPerPixel;
    if (nOfColors == 4)     // contains an alpha channel
    {
        if (surface->format->Rmask == 0x000000ff) texture_format = GL_RGBA;
        else texture_format = GL_BGRA;
    } 
	else if (nOfColors == 3)     // no alpha channel
    {
        if (surface->format->Rmask == 0x000000ff) texture_format = GL_RGB;
        else texture_format = GL_BGR;
    } 
	else 
	{
		MessageBox(hWnd, TEXT("the image is not truecolor.."), TEXT("error"), MB_OK | MB_ICONINFORMATION);
    }

	glGenTextures(1, &texture); 
	glBindTexture(GL_TEXTURE_2D, texture); 
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
	glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0, texture_format, GL_UNSIGNED_BYTE, surface->pixels); 
} 
else 
{
	MessageBox(hWnd, TEXT("SDL could not load image"), TEXT("error"), MB_OK | MB_ICONINFORMATION);
	SDL_Quit();
	return 1;
}    

SDL_FreeSurface(surface);
return texture;

}

For example I have square - here is link to nehe opengl tutorial with textures: http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06

"To properly map a texture onto a quad, you have to make sure the top right of the texture is mapped to the top right of the quad. The top left of the texture is mapped to the top left of the quad, the bottom right of the texture is mapped to the bottom right of the quad, and finally, the bottom left of the texture is mapped to the bottom left of the quad. If the corners of the texture do not match the same corners of the quad, the image may appear upside down, sideways, or not at all.

The first value of glTexCoord2f is the X coordinate. 0.0f is the left side of the texture. 0.5f is the middle of the texture, and 1.0f is the right side of the texture. The second value of glTexCoord2f is the Y coordinate. 0.0f is the bottom of the texture. 0.5f is the middle of the texture, and 1.0f is the top of the texture.

So now we know the top left coordinate of a texture is 0.0f on X and 1.0f on Y, and the top left vertex of a quad is -1.0f on X, and 1.0f on Y. Now all you have to do is match the other three texture coordinates up with the remaining three corners of the quad.

Try playing around with the x and y values of glTexCoord2f. Changing 1.0f to 0.5f will only draw the left half of a texture from 0.0f (left) to 0.5f (middle of the texture). Changing 0.0f to 0.5f will only draw the right half of a texture from 0.5f (middle) to 1.0f (right). "

So when I copy code from this tutorial:

Code:

// Front Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad

I have upper-down image because for example: glTexCoord2f(0.0f, 0.0f); in opengl it is left down corner image but in SDL it is left upper image.

thx for answer Jesse :smiley: