C++ OpenGL+LibPNG - Loading a PNG easily
Posted: Sat Apr 18, 2009 5:14 pm
SO. One of the things that always annoyed me about using openGL is that if I wanted to load an image I always had to do it through some bloated library like SDL_image or whatever, but of course in the end I tried to do it myself using libpng.
I actually had so many problems with libpng (call me a noob) that I gave up and asked for help, so all the libpng loading here actually belongs mostly to M_D_K.
You will need to download and install zlib and libpng to use this code.
Here is the rather large source code;
And here's how you use it;
To load a png into a texture, simply create a GLuint to store the texture's openGL name.
Then to load the image, simply use the function;
As you see, the function returns the openGL name of the texture so that you can use it. Here's the fun part; if the loading failed, it will return 0, which means that even if the loading fails, if you try to use the texture you will simply get the default white colour, instead of a segfault or crash.
To then use the texture in your opengl code, just bind your texture name
Thanks and hope it helps y'all
Although I still had problems with it; turns out M_D_K was an evil bastard and made it buggy on purpose so I could learn more xD
Extra thanks to; qphalcyon and Ginto8
I actually had so many problems with libpng (call me a noob) that I gave up and asked for help, so all the libpng loading here actually belongs mostly to M_D_K.
You will need to download and install zlib and libpng to use this code.
Here is the rather large source code;
Code: Select all
#ifndef PNGLOADEROPENGL
#define PNGLOADEROPENGL
#include <cstdio>
#include <cstdlib>
#include <png.h>
#include <gl/gl.h>
int GetTextureInfo(int ColourType)
{
int ret;
switch(ColourType)
{
case PNG_COLOR_TYPE_GRAY:
ret = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
ret = 2;
break;
case PNG_COLOR_TYPE_RGB:
ret = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
ret = 4;
break;
default:
ret = -1;//fucked
};
return ret;
};
GLuint loadImage(const char *filename)
{
GLuint texture;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_bytep *row_pointers = NULL;
int bitDepth, colourType;
FILE *pngFile = fopen(filename, "rb");
if(!pngFile)
return 0;
png_byte sig[8];
fread(&sig, 8, sizeof(png_byte), pngFile);
rewind(pngFile);//so when we init io it won't bitch
if(!png_check_sig(sig, 8))
return 0;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
if(!png_ptr)
return 0;
if(setjmp(png_jmpbuf(png_ptr)))
return 0;
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
return 0;
png_init_io(png_ptr, pngFile);
png_read_info(png_ptr, info_ptr);
bitDepth = png_get_bit_depth(png_ptr, info_ptr);
colourType = png_get_color_type(png_ptr, info_ptr);
if(colourType == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if(colourType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
png_set_gray_1_2_4_to_8(png_ptr);
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
if(bitDepth == 16)
png_set_strip_16(png_ptr);
else if(bitDepth < 8)
png_set_packing(png_ptr);
png_read_update_info(png_ptr, info_ptr);
png_uint_32 width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height,
&bitDepth, &colourType, NULL, NULL, NULL);
int components = GetTextureInfo(colourType);
if(components == -1)
{
if(png_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return 0;
}
GLubyte *pixels = (GLubyte *)malloc(sizeof(GLubyte) * (width * height * components));
row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for(int i = 0; i < height; ++i)
row_pointers[i] = (png_bytep)(pixels + (i * width * components));
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, NULL);
// make it
glGenTextures(1, &texture);
// bind it
glBindTexture(GL_TEXTURE_2D, texture);
// stretch it
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// technologic - I MEAN
// here we has the problems
GLuint glcolours;
(components==4) ? (glcolours = GL_RGBA): (0);
(components==3) ? (glcolours = GL_RGB): (0);
(components==2) ? (glcolours = GL_LUMINANCE_ALPHA): (0);
(components==1) ? (glcolours = GL_LUMINANCE): (0);
glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, glcolours, GL_UNSIGNED_BYTE, pixels);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(pngFile);
free(row_pointers);
free(pixels);
return texture;
};
#endif
To load a png into a texture, simply create a GLuint to store the texture's openGL name.
Code: Select all
GLuint myTexture;
Code: Select all
myTexture = loadImage("filepath.png")
To then use the texture in your opengl code, just bind your texture name
Code: Select all
glBindTexture(GL_TEXTURE_2D, myTexture);
Although I still had problems with it; turns out M_D_K was an evil bastard and made it buggy on purpose so I could learn more xD
Extra thanks to; qphalcyon and Ginto8