Jump to content
  • Advertisement
Sign in to follow this  
SmashManiac

SDL_image to OpenGL texture

This topic is 4157 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was trying to create a C++ class that would load an image file with IMG_Load from SDL_image, and convert it into a usable format for OpenGL. I also wanted my class to auto-detect non power-of-two pictures and store how much the texture has to be streched before being applied to the texture. Also I needed to keep track of the alpha channel if there is one. I thought my code was working perfectly, until I noticed different results on different computers. PNGs seems to always work perfectly, but for JPGs it works correctly only on my PC. Here is my code. textureList.h
#ifndef TEXTURELIST_H
#define TEXTURELIST_H

#include <string>
#include <SDL/SDL_opengl.h>
#include <SDL/SDL_image.h>

class textureList {

private:

	int nbTextures;
	GLuint *textures;

	static int powerOfTwo(int input) {
		int value = 1;
		while (value < input) value <<= 1;
		return value;
	}

public:

	float *ratiosW;
	float *ratiosH;

	textureList();
	textureList(int, std::string *);
	~textureList();

	void load(int, std::string *);

	const GLuint *operator[](const int);

	static GLuint SDL_GL_LoadTexture(SDL_Surface *surface) {
		float temp1, temp2;
		return SDL_GL_LoadTexture(surface, temp1, temp2);
	}

	static GLuint SDL_GL_LoadTexture(SDL_Surface *surface, float &ratioW, float &ratioH) {
		GLuint texture;
		int w, h;
		SDL_Surface *image;
		SDL_Rect area;
		Uint32 saved_flags;
		Uint8  saved_alpha;

		// Use the surface width and height expanded to powers of 2
		w = powerOfTwo(surface->w);
		h = powerOfTwo(surface->h);

		ratioW = surface->w / (float) w;
		ratioH = surface->h / (float) h;

		image = SDL_CreateRGBSurface(
				SDL_SWSURFACE,
				w, h,
				32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN // OpenGL RGBA masks
				0x000000FF,
				0x0000FF00,
				0x00FF0000,
				0xFF000000
#else
				0xFF000000,
				0x00FF0000,
				0x0000FF00,
				0x000000FF
#endif
				);
		if (!image) return 0;

		// Save the alpha blending attributes
		saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
		saved_alpha = surface->format->alpha;
		if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
			SDL_SetAlpha(surface, 0, 0);

		// Copy the surface into the GL texture image
		area.x = 0;
		area.y = 0;
		area.w = surface->w;
		area.h = surface->h;
		SDL_BlitSurface(surface, &area, image, &area);

		// Restore the alpha blending attributes
		if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
			SDL_SetAlpha(surface, saved_flags, saved_alpha);

		// Create an OpenGL texture for the image
		glGenTextures(1, &texture);
		glBindTexture(GL_TEXTURE_2D, texture);
		// GL_NEAREST, GL_LINEAR
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D,
				 0,
				 GL_RGBA,
				 w, h,
				 0,
				 GL_RGBA,
				 GL_UNSIGNED_BYTE,
				 image->pixels
				 );
		SDL_FreeSurface(image); // No longer needed

		return texture;
	}

};

#endif


textureList.cpp

#include "textureList.h"

textureList::textureList() {
	nbTextures = 0;
	textures = NULL;
}

textureList::textureList(int n, std::string *filenames) {
	textures = NULL;
	load(n, filenames);
}

void textureList::load(int n, std::string *filenames) {
	if (textures) {
		delete []textures;
		delete []ratiosW;
		delete []ratiosH;
	}

	nbTextures = n;
	textures = new GLuint[nbTextures];
	ratiosW = new float[nbTextures];
	ratiosH = new float[nbTextures];

	SDL_Surface *temp, **TextureImage = new SDL_Surface*[nbTextures];
	for (int i = 0; i < nbTextures; i++) {

		TextureImage = NULL;

		if ((temp = IMG_Load(filenames.c_str()))) {
			TextureImage = SDL_DisplayFormatAlpha(temp);
			SDL_FreeSurface(temp);
			textures = SDL_GL_LoadTexture(TextureImage, ratiosW, ratiosH);
		}
		else {
			delete[] TextureImage;
			throw "loading textures";
		}

		if (TextureImage) SDL_FreeSurface(TextureImage);

	}

	delete[] TextureImage;
}

textureList::~textureList() {
	if (textures)
		delete[] textures;
}

const GLuint *textureList::operator[](const int i) {
	return &textures;
}



What's the problem? Since we're at it, should I write #if SDL_BYTEORDER == SDL_LIL_ENDIAN or if (SDL_BYTEORDER == SDL_LIL_ENDIAN)

Share this post


Link to post
Share on other sites
Advertisement
First creating SDL surfaces, and then using them to create OpenGL textures... it works but it's really unecessary and memory expensive. If you use OpenGL for rendering, then you actually never use the SDL surfaces!

This might spare you some trouble:
DevIL

That's what I use. It loads any fileformat and makes a nice OpenGL texture out of it. It also converts all image sizes to power of two, so you don't have to bother with it and can load whatever files you like. It also loads the alpha channel.

However I also have some trouble with PNG files. It loads them upside down, so I have to flip them right after loading them. Not sure how to fix that yet.

Share this post


Link to post
Share on other sites
Thanks for the suggestion, however it is a bad choice for the particular project that I'm working on.

First, more than 50% of my pics will be PNGs, and all of them will have an alpha channel. If DevIL does not load PNGs in the correct position, I can't rely on it for loading PNGs correctly at all.

Second, the class that I've written does not really converts pictures to power of two. What it actually does is merely stretch an invisible canvas of the picture, and then calculate the ratio that must be shown. I do this to avoid loss of quality due to resizing. Otherwise I get dirty results for the HUD and the interface.

As for the memory, it might be a bit slower to load, but it's not an issue.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!