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; ierr->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;vloadfile(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()); 
}