Transparent textures using libpng

I am trying to use libpng to apply a transparent texture to some objects however I have not yet managed to get it working. I have managed to load textures using libpng and I will post the code how I do so below however despite me trying I have not managed to load transaparent images.

My two main questions are:

  1. What format should my PNG be in?
  2. What is wrong with my code - Is there a good online piece of sample code

png load code:


bool loadPngImage(char *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData) {
    png_structp png_ptr;
    png_infop info_ptr;
    unsigned int sig_read = 0;
    int color_type, interlace_type;
    FILE *fp;
 
    if ((fp = fopen(name, "rb")) == NULL)
        return false;
 
    /* Create and initialize the png_struct
     * with the desired error handler
     * functions.  If you want to use the
     * default stderr and longjump method,
     * you can supply NULL for the last
     * three parameters.  We also supply the
     * the compiler header file version, so
     * that we know if the application
     * was compiled with a compatible version
     * of the library.  REQUIRED
     */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                     NULL, NULL, NULL);
 
    if (png_ptr == NULL) {
        fclose(fp);
        return false;
    }
 
    /* Allocate/initialize the memory
     * for image information.  REQUIRED. */
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fclose(fp);
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return false;
    }
 
    /* Set error handling if you are
     * using the setjmp/longjmp method
     * (this is the normal method of
     * doing things with libpng).
     * REQUIRED unless you  set up
     * your own error handlers in
     * the png_create_read_struct()
     * earlier.
     */
    if (setjmp(png_jmpbuf(png_ptr))) {
        /* Free all of the memory associated
         * with the png_ptr and info_ptr */
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        fclose(fp);
        /* If we get here, we had a
         * problem reading the file */
        return false;
    }
 
    /* Set up the output control if
     * you are using standard C streams */
    png_init_io(png_ptr, fp);
 
    /* If we have already
     * read some of the signature */
    png_set_sig_bytes(png_ptr, sig_read);
 
    /*
     * If you have enough memory to read
     * in the entire image at once, and
     * you need to specify only
     * transforms that can be controlled
     * with one of the PNG_TRANSFORM_*
     * bits (this presently excludes
     * dithering, filling, setting
     * background, and doing gamma
     * adjustment), then you can read the
     * entire image (including pixels)
     * into the info structure with this
     * call
     *
     * PNG_TRANSFORM_STRIP_16 |
     * PNG_TRANSFORM_PACKING  forces 8 bit
     * PNG_TRANSFORM_EXPAND forces to
     *  expand a palette into RGB
     */
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);

    png_uint_32 width, height;
    int bit_depth;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
                 &interlace_type, NULL, NULL);
    outWidth = width;
    outHeight = height;
 
    unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
    *outData = (unsigned char*) malloc(row_bytes * outHeight);
 
    png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
 
    for (int i = 0; i < outHeight; i++) {
        // note that png is ordered top to
        // bottom, but OpenGL expect it bottom to top
        // so the order or swapped
        memcpy(*outData+(row_bytes * (outHeight-1-i)), row_pointers[i], row_bytes);
    }
 
    /* Clean up after the read,
     * and free any memory allocated */
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
    /* Close the file */
    fclose(fp);
 
    /* That's it */
    return true;
}


unsigned int load_and_bind_texture(char * filename_in)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    // The following two lines enable semi transparent
    glEnable(GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
    int width, height;
    bool hasAlpha;
    char * filename = filename_in;
    bool success = loadPngImage(filename, width, height, hasAlpha, &textureImage);
    if (!success) {
        std::cout << "Unable to load png file" << std::endl;
        return 0;
    }
    std::cout << "Image loaded " << width << " " << height << " alpha " << hasAlpha << std::endl;

    unsigned int tex_handle = 0;
    glGenTextures(1, &tex_handle); 
    glBindTexture(GL_TEXTURE_2D, tex_handle);


    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width,
                 height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
                 textureImage);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_FLAT);

	return tex_handle;
}

Texture then made as such:


an_face_texture = load_and_bind_texture("images/pngclock.png");

// The following two lines enable semi transparent
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

These calls are for rendering, not loading of textures.
Will make all your model semi transparent.

try SOIL library.

[QUOTE=paul_g_griffiths;1285262]// The following two lines enable semi transparent
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

These calls are for rendering, not loading of textures.

hasAlpha ? 4 : 3
Try 16 : 24[/QUOTE]

I have moved the two lines to my rendering:


			glPushMatrix();

			    glEnable(GL_BLEND);
    			glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    			
				glTranslatef(256.0f, 256.0f, 0.0f);
				glRotatef(min_angle, 0.0f, 0.0f, 1.0f);
				glScalef(x_minScale, y_minScale, 1.0f);

				glEnable(GL_TEXTURE_2D);
			    glBindTexture(GL_TEXTURE_2D, min_hand_texture);

				glBegin(GL_POLYGON);
					glTexCoord2f(0.0f, 0.0f);
					glVertex2f(-0.05f, 0.0f); //bottom left

					glTexCoord2f(1.0f, 0.0f);
					glVertex2f(0.05f, 0.0f); //bottom right

					glTexCoord2f(1.0f, 1.0f);
					glVertex2f(0.05f, 1.5f); //top right

					glTexCoord2f(0.0f, 1.0f);
					glVertex2f(-0.05f, 1.5f); //top left
				glEnd();

				//glCallList(min_hand);
			glPopMatrix();

The texture was still rendered incorrectly. Any ideas? I tried it in RGBA format and Indexed

bool success = loadPngImage(filename, &width, &height, &hasAlpha, &textureImage);

theres your problem. needs to be a pointers to be set by the function.

[QUOTE=paul_g_griffiths;1285264]bool success = loadPngImage(filename, &width, &height, &hasAlpha, &textureImage);

theres your problem. needs to be a pointers to be set by the function.[/QUOTE]

Sorry im fairly new to C++ I understand I cant just change width, height and hasAlpha to be pointers as then I will get an error at the other end as they are not expecting pointers. How do I solve this?

Thank you by the way, you have already shedded a lot of light on to the situation.

They probably are expecting pointers,
if not change function vars to int *width, int *height, bool *hasAlpha

To be honest I would try SOIL library, has no errors.
http://lonesock.net/soil.html

[QUOTE=paul_g_griffiths;1285266]They probably are expecting pointers,
if not change function vars to int *width, int *height, bool *hasAlpha

To be honest I would try SOIL library, has no errors.[/quote]

im going to check soil out soon