www.pudn.com > AndreasHalm-src.zip > texture.cpp
// ********************************************************************** // * \author Andreas Halm, Institute for Computer Graphics, * // * TU Braunschweig, Muehlenpfordtstrasse 23, * // * 38106 Braunschweig, Germany * // * http://www.cg.cs.tu-bs.de mailto:a.halm@tu-bs.de * // * \date 01.03.2000 * // ********************************************************************** //#ifdef WIN32 //#include "stdafx.h" //#endif #include "texture.h" #include#include #include #include #include #include using namespace std; #define SUPPORT_PNG #define SUPPORT_JPEG // ------------------------------------------------------------------------------ // // PNG stuff // // ------------------------------------------------------------------------------ namespace png { #ifdef SUPPORT_PNG #include #pragma comment (lib,"libpng.lib") #pragma comment (lib,"zlib.lib") unsigned char* memsrc; void read_from_memory( png_structp png_ptr, png_bytep data, unsigned int length ) { memcpy( data, memsrc, length ); memsrc += length; } unsigned char* read( const char* filename, unsigned int& i_width, unsigned int& i_height, GLenum& i_type, // a GL constant like GL_RGB bool fromfile, bool force_rgba ) // always force GL_RGBA { // vars we need png_structp png_ptr; png_infop info_ptr; FILE* file = 0; // some more unsigned char* img_data; unsigned int img_rowbytes; if (fromfile) { // open file file = fopen(filename,"rb"); // open file in "read binary" mode if (!file) throw "can't open png file"; } png_ptr = png_create_read_struct( // creates the default png structure PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); // use default error handling if (!png_ptr) { if (file) fclose(file); throw "can't create read struct"; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,NULL,NULL); if (file) fclose(file); throw "can't create info struct"; } // the libpng library uses a longjmp call if an error occurs if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr,&info_ptr,NULL); if (file) fclose(file); throw "error reading png file"; } if (fromfile) { // setup input code: the default for libpng is to use fread(), // so pass a valid FILE* here: png_init_io(png_ptr,file); } else { memsrc = (unsigned char*)filename; png_set_read_fn(png_ptr,NULL,read_from_memory); } // step skipped: we did not read anything from the file // step skipped: we do not need to know the progress, so no row callback // step skipped: in png files, the alpha channel is the level of opacity. // if the level of transparency is needed, // call png_set_invert_alpha() here. // step skipped: installation of user-defined transform function: not needed // read all file information up to the actual image data png_read_info(png_ptr,info_ptr); // get internal information unsigned int coltype, bitdepth; i_width = png_get_image_width(png_ptr,info_ptr); i_height = png_get_image_height(png_ptr,info_ptr); bitdepth = png_get_bit_depth(png_ptr,info_ptr); coltype = png_get_color_type(png_ptr,info_ptr); bool have_alpha = false; // handle the different possibilities // expand palette to rgb if ((coltype & PNG_COLOR_TYPE_PALETTE) && (bitdepth <= 8)) { png_set_palette_to_rgb(png_ptr); } // expand grayscale (1,2,4 bit) if ((coltype & PNG_COLOR_TYPE_GRAY) && (bitdepth < 8)) { png_set_gray_1_2_4_to_8(png_ptr); } // expand alpha palette to alpha channel if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); have_alpha = true; } // png files can have 16 bits per channel. // this is only allowed for png_color_type_gray_alpha // which then form a hilo texture. // strip all other down to 8 bits. if (bitdepth == 16) if (force_rgba || (!(coltype == PNG_COLOR_TYPE_GRAY_ALPHA))) png_set_strip_16(png_ptr); // convert all grayscale types to rgb if (force_rgba) { if ((coltype == PNG_COLOR_TYPE_GRAY) || (coltype == PNG_COLOR_TYPE_GRAY_ALPHA)) { png_set_gray_to_rgb(png_ptr); } } if (coltype & PNG_COLOR_MASK_ALPHA) { have_alpha = true; } // if colors are 3-bytes-per-pixel (no alpha info), // expand them to 4 bytes (RGBA) if (force_rgba) { if (!have_alpha) { png_set_filler(png_ptr,(unsigned char)255,PNG_FILLER_AFTER); } } // update data in the struct again png_read_update_info(png_ptr,info_ptr); bitdepth = png_get_bit_depth(png_ptr,info_ptr); coltype = png_get_color_type(png_ptr,info_ptr); // allocate memory img_rowbytes = png_get_rowbytes(png_ptr,info_ptr); img_data = new unsigned char [img_rowbytes*i_height]; if (!img_data) { // make sure we got the memory png_destroy_read_struct(&png_ptr,&info_ptr,NULL); if (file) fclose(file); throw "can't get memory"; } // read the whole picture, will handle interlaced images automatically! png_bytep* image = new png_bytep [i_height]; for (unsigned int i=0; i err->format_message) (cinfo, buffer); jpeg_destroy(cinfo); throw buffer; } unsigned char* memsrc; unsigned long memsize; void memsrc_init(j_decompress_ptr cinfo) { cinfo->src->next_input_byte = memsrc; cinfo->src->bytes_in_buffer = memsize; } unsigned char memsrc_fillbuffer(j_decompress_ptr cinfo) { return FALSE; } void memsrc_skipdata(j_decompress_ptr cinfo, long nbytes) { cinfo->src->next_input_byte += nbytes; cinfo->src->bytes_in_buffer -= nbytes; } void memsrc_term(j_decompress_ptr cinfo) { } jpeg_source_mgr memsrc_mgr; unsigned char* read( const char* filename, unsigned int& i_width, unsigned int& i_height, bool force_rgba, bool fromfile, unsigned long datasize ) { // vars we need jpeg_decompress_struct dec; jpeg_error_mgr jerr; FILE* file = 0; // some more unsigned char* img_data; if (fromfile) { // open file file = fopen(filename,"rb"); // open file in "read binary" mode if (!file) throw "can't open jpeg file"; } // we need a "throwing" error handler. the default would exit() dec.err = jpeg_std_error(&jerr); jerr.error_exit = throw_error; // setup decompression jpeg_create_decompress(&dec); if (fromfile) jpeg_stdio_src(&dec,file); else { memsrc = (unsigned char*)filename; memsize = datasize; memsrc_mgr.init_source = memsrc_init; memsrc_mgr.fill_input_buffer = memsrc_fillbuffer; memsrc_mgr.skip_input_data = memsrc_skipdata; memsrc_mgr.resync_to_restart = jpeg_resync_to_restart; memsrc_mgr.term_source = memsrc_term; dec.src = &memsrc_mgr; } jpeg_read_header(&dec,TRUE); // set default parameters dec.out_color_space = JCS_RGB; // always RGB jpeg_start_decompress(&dec); i_width = dec.image_width; i_height = dec.image_height; // allocate memory int linesize; if (force_rgba) linesize = i_width*4; else linesize = i_width*3; img_data = new unsigned char [linesize*i_height]; if (!img_data) { // make sure we got the memory jpeg_destroy_decompress(&dec); if (file) fclose(file); return NULL; } memset( img_data, 255, linesize*i_height ); JSAMPARRAY rows = new JSAMPROW [i_height]; JSAMPARRAY samparray = rows; for (unsigned int i=0;i =0;h-=i_width) { for (int w=i_width-1;w>0;w--) { memmove( img_data +(h+w)*4, img_data +h*4+w*3, 3 ); img_data [ (h+w)*4+3 ] = 255; } img_data [ h*4+3 ] = 255; } } jpeg_finish_decompress(&dec); if (file) fclose(file); jpeg_destroy_decompress(&dec); return img_data; } #endif } // end of jpeg namespace // --------------------------------------------------------------------------- // // Standard loading // // --------------------------------------------------------------------------- // // loading / determining file type // TextureData::TextureData() { v_ok = false; } TextureData::TextureData( const TextureData& other ) : v_ok( other.ok() ), v_width( other.width() ), v_height( other.height() ), v_type( other.type() ), v_texture_data( 0 ) { if (other.ok()) { unsigned int size = width() * height() * pixelsize(); v_texture_data = new unsigned char [ size ]; memcpy( v_texture_data, other.data(), size ); v_filename = other.v_filename; } } TextureData::~TextureData() { cleanup(); } void TextureData::cleanup() { if (v_ok) delete [] v_texture_data; v_ok = false; } bool TextureData::tile( const TextureData& data, unsigned int tile_u, unsigned int tile_v ) { // we tile into seperate data buffer // this will allow tiling ourself! if (!data.ok()) { // if original object has errors, invalidate this cleanup(); return false; } unsigned char* buffer = new unsigned char [ data.width()*data.height()*data.pixelsize()*tile_u*tile_v ]; for (unsigned int v=0;v loadfile(filename); if (!v_texture_data->ok()) return v_ok = false; v_owns_texture_data = true; glGenTextures(1,&v_texture_name); v_mipmaptype = 0; upload(); return v_ok = (glGetError() == GL_NO_ERROR); } // after creating a texture object (or loading it) // you should specify the default texture environment void Texture::setParameters( int environment, // GL_DECAL, GL_MODULATE int minfilter, // minification filter int magfilter, // magnification filter int wrap_s, // GL_CLAMP, GL_REPEAT int wrap_t) // GL_CLAMP, GL_REPEAT { activate(); setEnvMode(environment); setMinificationFilter(minfilter); setMagnificationFilter(magfilter); setWrapS(wrap_s); setWrapT(wrap_t); } void Texture::upload() const { //int max_texture_size; //glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_texture_size ); //if (v_texture_data[0]->width() > (unsigned int)max_texture_size) { // clog << "can't load texture into the current context, texture width too big" << endl; // return; //} //if (v_texture_data[0]->height() > (unsigned int)max_texture_size) { // clog << "can't load texture into the current context, texture height too big" << endl; // return; //} activate(); glTexImage2D(GL_TEXTURE_2D,0,type(), width(), height(), 0,type(),v_texture_data->datatype(), v_texture_data->data()); }