#include "pixmap.h" #include "gpl_assert.h" #include /* Header file for standard file i/o. */ #include /* Header file for malloc/free. */ #include using namespace std; #include "default_pixmap.h" /* static */ Pixmap::Pixmap_data *Pixmap::default_pixmap_data = 0; /* static */ map Pixmap::m_pixmap_cache; // In OSX the bytes are read backwards, so must swap all bytes unsigned short int swap_byte_order(unsigned short int x) { #ifdef __APPLE__ char *a = (char *) &x; char b[2]; b[0] = a[1]; b[1] = a[0]; return *((unsigned short int*) b); #else return x; #endif } unsigned long swap_byte_order(unsigned long x) { #ifdef __APPLE__ char *a = (char *) &x; char b[4]; b[0] = a[3]; b[1] = a[2]; b[2] = a[1]; b[3] = a[0]; return *((unsigned long*) b); #else return x; #endif } Pixmap::Pixmap() { if (!default_pixmap_data) { default_pixmap_data = new Pixmap_data(default_width, default_height, default_data); } m_pixmap_data = 0; m_filename = ""; register_member_variable("filename", &m_filename); m_object_type_name = "Pixmap"; // width and height of a pixmap are derived --> user cannot change them Status status; status = mark_member_variable_as_derived("w"); assert(status == OK); status = mark_member_variable_as_derived("h"); assert(status == OK); m_tried_to_read_current_file = false; // the filename is not specified yet, so don't try to read file yet } void Pixmap::updated(string name) { // called with x,y or filename changes // if the filename changes, set flag that it hasn't been read yet if (name == "filename") m_tried_to_read_current_file = false; // this will cause a new display list to be created that will use new (x,y) m_display_list_dirty = true; } void Pixmap::build_display_list() { // if there is a pending file read, attempt to read file if (!m_tried_to_read_current_file) read_file(); // if the pixmap_data is not defined, file read must have failed // use the default if (!m_pixmap_data) { m_pixmap_data = default_pixmap_data; m_w = m_pixmap_data->m_width; m_h = m_pixmap_data->m_height; } // build the display list assert(m_display_list); assert(m_pixmap_data); glNewList(m_display_list, GL_COMPILE); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glRasterPos2i(m_x, m_y); glDrawPixels(m_pixmap_data->m_width, m_pixmap_data->m_height, GL_RGB, GL_UNSIGNED_BYTE, m_pixmap_data->m_data ); glPopMatrix(); glEndList(); } void Pixmap::read_file() { // special case that no filename has been specified yet if (m_filename == "") return; // flag that we have tried to read the file so that we don't attempt // to read bad files over and over m_tried_to_read_current_file = true; // If the pixmap in m_filename has already been read // get it out of the cache map::const_iterator iter; iter = m_pixmap_cache.find(m_filename); if (iter != m_pixmap_cache.end()) { m_pixmap_data = (*iter).second; m_w = m_pixmap_data->m_width; m_h = m_pixmap_data->m_height; return; } // set to NULL in case read fails m_pixmap_data = 0; FILE *file; unsigned long size; // size of the image in bytes unsigned long width; // width of image unsigned long height; // height of image char *bitmap_data; // will hold the pixels unsigned long i; // standard counter unsigned short int planes; // number of planes in image (must be 1) unsigned short int bpp; // number of bits per pixel (must be 24) char temp; // temporary color storage for bgr-rgb conversion. // make sure the file is there if ((file = fopen(m_filename.c_str(), "rb"))==NULL) { cerr << "Texture filename <" << m_filename << "> not found." << endl; return; } unsigned long data_offset; fseek(file, 10, SEEK_SET); if ((i = fread(&data_offset, 4, 1, file)) != 1) { cerr << "Error reading data_offset size from texture filename <" << m_filename << ">" << endl; return; } // on OSX must swap the btye order data_offset = swap_byte_order(data_offset); unsigned long header_size; // read the size of header if ((i = fread(&header_size, 4, 1, file)) != 1) { cerr << "Error reading header size from texture filename <" << m_filename << ">" << endl; return; } // read bitmap width if ((i = fread(&width, 4, 1, file)) != 1) { cerr << "Error reading width from texture filename <" << m_filename << ">" << endl; return; } // on OSX must swap the btye order width = swap_byte_order(width); // read bitmap height if ((i = fread(&height, 4, 1, file)) != 1) { cerr << "Error reading height from texture filename <" << m_filename << ">" << endl; return; } // on OSX must swap the btye order height = swap_byte_order(height); // calculate the size (assuming 24 bits or 3 bytes per pixel) size = width * height * 3; // read the planes if ((fread(&planes, 2, 1, file)) != 1) { cerr << "Error reading planes from texture filename <" << m_filename << ">" << endl; return; } // on OSX must swap the btye order planes = swap_byte_order(planes); // this code only works for bitmaps with 1 plane if (planes != 1) { cerr << "Error reading texture filename <" << m_filename << "> it has more than 1 plane" << endl; return; } // read the bits-per-plane if ((i = fread(&bpp, 2, 1, file)) != 1) { cerr << "Error reading bpp from texture filename <" << m_filename << endl; return; } // on OSX must swap the btye order bpp = swap_byte_order(bpp); // this code only works for bitmaps with 24 bits per plane if (bpp != 24) { cerr << "Error reading texture filename <" << m_filename << " Bpp != 24" << endl; return; } unsigned long compression; if ((i = fread(&compression, 4, 1, file)) != 1) { cerr << "Error reading compression from texture filename <" << m_filename << ">" << endl; return; } // on OSX must swap the btye order compression = swap_byte_order(compression); if (compression) { cerr << "Error reading texture filename <" << m_filename << "> the bitmap is compressed, gpl can't handle compressed" << " bitmaps" << endl; return; } unsigned long actual_size; if ((i = fread(&actual_size, 4, 1, file)) != 1) { cerr << "Error reading actual_size from texture filename <" << m_filename << ">" << endl; return; } // on OSX must swap the btye order actual_size = swap_byte_order(actual_size); // cerr << "actual_size = " << actual_size << endl; if (actual_size != 0) size = actual_size; /*** if (actual_size != size) { cerr << "Error reading texture filename <" << m_filename << ">. Size in file does not appear to be correct." << endl; return; } ***/ /* seek past the rest of the bitmap header. */ // fseek(file, 24, SEEK_CUR); // fseek(file, actual_size+8, SEEK_END); fseek(file, data_offset, SEEK_SET); /* read the data. */ bitmap_data = (char *) malloc(size); if ((i = fread(bitmap_data, size, 1, file)) != 1) { cerr << "Error reading image from texture filename <" << m_filename << ">" << endl; return; } // done reading .bmp file fclose(file); /* reverse all of the colors. (bgr -> rgb) */ for (i=0;im_width; m_h = m_pixmap_data->m_height; // insert new pixmap into the pixmap cache m_pixmap_cache[m_filename] = m_pixmap_data; /**** // DO NOT DELETE, keep it around in case we want a new default // this code was used to create default_pixmap.h // // to change default_pixmap.h to hold a new image // (1) uncomment this code // (2) create a gpl program with single pixmap // pixmap p(file = "newdefault.bmp") // (3) run gpl save stdout to file // (4) update default_pixmap.h with the output cout << "dumping bitmap ******************" << endl; cout << "width = " << m_width << endl; cout << "height= " << m_height<< endl; cout << "size = " << size << endl; cout << "data = " << endl; int in_row = 0; for (int i = 0; i < size; i++) { if (++in_row > 10) { cout << endl; in_row = 0; } cout << (unsigned short) m_data[i] << ","; } ****/ }