#include "Engine.h" #include "Sprite.h" #include #include #include #include namespace Engine { /* * Code is taken from http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures on * Sunday, March 14 2010. */ bool Sprite::LoadFromPNG (const std::string &filename) { LogDebug ("Loading png from %s", filename.c_str()); //header for testing if it is a png png_byte header[8]; //open file as binary FILE *fp = fopen(filename.c_str(), "rb"); if (!fp) { LogError ("Could not open file: %s", filename.c_str()); return false; } //read the header fread(header, 1, 8, fp); //test if png int is_png = !png_sig_cmp(header, 0, 8); if (!is_png) { LogError ("Error opening png file %s: file is not a png file!", filename.c_str()); fclose(fp); return false; } //create png struct png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { LogError ("Error opening png file %s: unable to read png header", filename.c_str()); fclose(fp); return (false); } //create png info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { LogError ("Error opening png file %s: unable to read png header", filename.c_str()); png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); fclose(fp); return (false); } //create png info struct png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { LogError ("Error opening png file %s: unable to read png header", filename.c_str()); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); fclose(fp); return (false); } //png error stuff, not sure libpng man suggests this. if (setjmp(png_jmpbuf(png_ptr))) { LogError ("Error opening png file %s: unable to read png header", filename.c_str()); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return (false); } //init png reading png_init_io(png_ptr, fp); //let libpng know you already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read all the info up to the image data png_read_info(png_ptr, info_ptr); //variables to pass to get info int bit_depth, color_type; png_uint_32 tmWidth, tmHeight; // get info about png png_get_IHDR(png_ptr, info_ptr, &tmWidth, &tmHeight, &bit_depth, &color_type, NULL, NULL, NULL); //update mWidth and mHeight based on png info mWidth = tmWidth; mHeight = tmHeight; // Update the png info struct. png_read_update_info(png_ptr, info_ptr); // Row size in bytes. int rowbytes = png_get_rowbytes(png_ptr, info_ptr); // Allocate the image_data as a big block, to be given to opengl png_byte *image_data = new png_byte[rowbytes * mHeight]; if (!image_data) { //clean up memory and close stuff png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return false; } //row_pointers is for pointing to image_data for reading the png with libpng png_bytep *row_pointers = new png_bytep[mHeight]; if (!row_pointers) { //clean up memory and close stuff png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; fclose(fp); return false; } // set the individual row_pointers to point at the correct offsets of image_data for (unsigned int i = 0; i < mHeight; ++i) row_pointers[mHeight - 1 - i] = image_data + i * rowbytes; //read the png into image_data through row_pointers png_read_image(png_ptr, row_pointers); //Now generate the OpenGL texture object glGenTextures(1, &mGLTextureName); glBindTexture(GL_TEXTURE_2D, mGLTextureName); bool mipmap = false; if (mipmap) { gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); } else { glTexImage2D(GL_TEXTURE_2D,0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } //clean up memory and close stuff png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] row_pointers; delete[] image_data; fclose(fp); return true; } void draw_sprite_helper (float u_start, float u_end, float width, float height) { /* // debug drawing with colors glBegin(GL_QUADS); glTexCoord2f (u_start, 0.f); glColor3f (1.f, 0.f, 0.f); glVertex3f (0.f, 0.f, 0.f); glTexCoord2f (u_end, 0.f); glColor3f (0.f, 1.f, 0.f); glVertex3f (0.f, 0.f, height); glTexCoord2f (u_end, 1.f); glColor3f (0.f, 0.f, 1.f); glVertex3f (width, 0.f, height); glTexCoord2f (u_start, 1.f); glColor3f (1.f, 0.f, 1.f); glVertex3f (width, 0.f,0.f); glEnd(); */ glBegin(GL_QUADS); glTexCoord2f (u_start, 0.f); glVertex3f (0.f, 0.f, 0.f); glTexCoord2f (u_end, 0.f); glVertex3f (0.f, 0.f, height); glTexCoord2f (u_end, 1.f); glVertex3f (width, 0.f, height); glTexCoord2f (u_start, 1.f); glVertex3f (width, 0.f,0.f); glEnd(); } void Sprite::DrawAt (float xpos, float ypos, float zpos) { float u_start = 0., u_end = 1.; if (mAnimation) { int frame_index = floor ( (mAnimationFrameRate) * mAnimationTimer); u_start = static_cast(frame_index) / mAnimationFrameCount; u_end = (frame_index + 1.) / mAnimationFrameCount; } glPushMatrix(); glTranslatef (xpos -mScale * mWidth * 0.5, ypos, zpos -mScale * mHeight * 0.5); glScalef (mScale, mScale, mScale); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture (GL_TEXTURE_2D, mGLTextureName); draw_sprite_helper (u_start, u_end, mWidth, mHeight); glPopMatrix(); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); } void Sprite::DrawAt2D (float xpos, float ypos) { float u_start = 0., u_end = 1.; if (mAnimation) { int frame_index = floor ( (mAnimationFrameRate) * mAnimationTimer); u_start = static_cast(frame_index) / mAnimationFrameCount; u_end = (frame_index + 1.) / mAnimationFrameCount; } glPushMatrix(); glTranslatef (xpos -mScale * mWidth * 0.5, ypos, 0.); glScalef (mScale, mScale, mScale); // \TODO Make 2d drawing of sprites a bit nicer, seems a bit overkill for such a simple function glRotatef (-90, 0., 0., 1.); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture (GL_TEXTURE_2D, mGLTextureName); glBegin (GL_QUADS); glTexCoord2f (u_start, 0.); glVertex2f (0., 0.); glTexCoord2f (u_end, 0.); glVertex2f (0., mHeight); glTexCoord2f (u_end, 1.); glVertex2f (mWidth, mHeight); glTexCoord2f (u_start, 1.); glVertex2f (mWidth,0.); glEnd (); glPopMatrix(); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); } void Sprite::DrawSubAt (unsigned int index, float xpos, float ypos, float zpos) { assert (index < mSubSpriteCount); float u_start = static_cast(index) / mSubSpriteCount; float u_end = (index + 1.) / mSubSpriteCount; glPushMatrix(); glTranslatef (xpos -mScale * mWidth * 0.5, ypos, zpos -mScale * mHeight * 0.5); glScalef (mScale, mScale, mScale); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture (GL_TEXTURE_2D, mGLTextureName); draw_sprite_helper (u_start, u_end, mWidth, mHeight); glPopMatrix(); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); } }