PDA

View Full Version : Transparent textures using libpng



kieranlavelle
01-03-2017, 11:22 AM
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");

paul_g_griffiths
01-03-2017, 11:38 AM
// 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.

kieranlavelle
01-03-2017, 11:44 AM
// 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

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

paul_g_griffiths
01-03-2017, 11:59 AM
bool success = loadPngImage(filename, &width, &height, &hasAlpha, &textureImage);

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

kieranlavelle
01-03-2017, 12:13 PM
bool success = loadPngImage(filename, &width, &height, &hasAlpha, &textureImage);

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

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.

paul_g_griffiths
01-03-2017, 12:20 PM
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

kieranlavelle
01-03-2017, 12:55 PM
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.


im going to check soil out soon