#include #include #include #include #include #include #include #include typedef int int32; typedef unsigned int uint32; /**************************************************************************** * * Follows is code written by GWM and translated to fit with the OSG Ethos. * * * Ported into the OSG as a plugin, Geoff Michel October 2001. * For patches, bugs and new features * please send them direct to the OSG dev team. * **********************************************************************/ #include #include #include enum { ERROR_NO_ERROR =0,ERROR_READING_HEADER,ERROR_READING_PALETTE, ERROR_MEMORY, ERROR_READ_ERROR, ERROR_NO_FILE,ERROR_READING_COLORS}; static int bmperror = ERROR_NO_ERROR; // BMP format bits - at start of file is 512 bytes of pure garbage enum ftype {MB=19778}; // magic number identifies a bmp file; actually chars 'B''M' // allowed ftypes are 'BM' for windoze; OS2 allows: //'BA' - Bitmap Array //'CI' - Color Icon //'CP' - Color Pointer (mouse cursor) //'IC' - Icon //'PT' - Pointer (mouse cursor) enum ncol { BW=1, IA, RGB, RGBA}; struct bmpheader { short FileType; //always MB unsigned short siz[2]; // a dword for whole file size - make unsigned Feb 2002 short Reserved1, Reserved2; //reserved for future purposes unsigned short offset[2]; //offset to image in bytes }; struct BMPInfo { int32 width; //width of the image in pixels int32 height; // height of the image in pixels short planes; //:word: number of planes (always 1) short Colorbits; //word: number of bits used to describe color in each pixel int32 compression; //compression used int32 ImageSize; //image size in bytes int32 XpixPerMeter; //pixels per meter in X int32 YpixPerMeter; //pixels per meter in Y int32 ColorUsed; //number of colors used int32 Important; //number of "important" colors // unsigned char rgbquad[4]; // long os2stuff[6]; // storage for os2.1 with 64 bytes to be read. Dont know what these are yet. }; int bmp_error(char *buffer, int bufferlen) { switch (bmperror) { case ERROR_READING_COLORS: strncpy(buffer, "BMP loader: Error reading colours", bufferlen); break; case ERROR_READING_HEADER: strncpy(buffer, "BMP loader: Error reading header", bufferlen); break; case ERROR_READING_PALETTE: strncpy(buffer, "BMP loader: Error reading palette", bufferlen); break; case ERROR_MEMORY: strncpy(buffer, "BMP loader: Out of memory error", bufferlen); break; case ERROR_READ_ERROR: strncpy(buffer, "BMP loader: Read error", bufferlen); break; } return bmperror; } /* byte order workarounds *sigh* */ void swapbyte(int32 *i) { char *vv=(char *)i; char tmp=vv[0]; vv[0]=vv[3]; vv[3]=tmp; tmp=vv[1]; vv[1]=vv[2]; vv[2]=tmp; } void swapbyte(uint32 *i) { char *vv=(char *)i; char tmp=vv[0]; vv[0]=vv[3]; vv[3]=tmp; tmp=vv[1]; vv[1]=vv[2]; vv[2]=tmp; } void swapbyte(float *i) { char *vv=(char *)i; char tmp=vv[0]; vv[0]=vv[3]; vv[3]=tmp; tmp=vv[1]; vv[1]=vv[2]; vv[2]=tmp; } void swapbyte(unsigned short *i) { char *vv=(char *)i; char tmp=vv[0]; vv[0]=vv[1]; vv[1]=tmp; } void swapbyte(short *i) { char *vv=(char *)i; char tmp=vv[0]; vv[0]=vv[1]; vv[1]=tmp; } unsigned char *bmp_load(std::istream& fin, int *width_ret, int *height_ret, int *numComponents_ret) { // the main area of changes from the pic format loader. // reads filename, and returns the buffer // bmp is very very simple format // even Master Gates could have invented it. // It is extremely expensive on disk space - every RGB pixel uses 3 bytes plus a header! // BMP - sponsored by Seagate. // unsigned char palette[256][3]; unsigned char *buffer=NULL; // returned to sender & as read from the disk long filelen; bmperror = ERROR_NO_FILE; fin.seekg(0, std::ios::end); filelen = fin.tellg(); // determine file size so we can fill it in later if FileSize == 0 fin.seekg(0, std::ios::beg); int ncolours; int ncomp=0; bool swap=false; // dont need to swap bytes // actual size of the bitmap header; 12=os2; 40 = normal; 64=os2.1 struct bmpheader hd; struct BMPInfo inf; bmperror = ERROR_NO_ERROR; fin.read((char*)&hd,sizeof(bmpheader)); if (hd.FileType != MB) { swapbyte(&(hd.FileType)); swap=true; if (hd.FileType != MB) { bmperror=ERROR_READING_HEADER; } } if (hd.FileType == MB) { int32 infsize; //size of BMPinfo in bytes unsigned char *cols=NULL; // dynamic colour palette unsigned char *imbuff; // returned to sender & as read from the disk fin.read((char*)&infsize,sizeof(int32)); // insert inside 'the file is bmp' clause if (swap) swapbyte(&infsize); unsigned char *hdr=new unsigned char[infsize]; // to hold the new header fin.read((char*)hdr,infsize-sizeof(int32)); int32 hsiz=sizeof(inf); // minimum of structure size & if(infsize<=hsiz) hsiz=infsize; memcpy(&inf,hdr, hsiz/*-sizeof(long)*/); // copy only the bytes I can cope with delete [] hdr; osg::notify(osg::INFO) << "loading bmp file "<>16; int npln = inf.height&0xffff; // number of planes int cbits = inf.height>>16; inf.width=wd; inf.height=ht; inf.planes=npln; inf.Colorbits=cbits; inf.ColorUsed=(int32)pow(2.0,(double)inf.Colorbits); // infer the colours } osg::notify(osg::INFO) << "readbmp " <setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); return pOsgImage; } virtual ReadResult readImage(std::istream& fin,const Options* =NULL) const { return readBMPStream(fin); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; std::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); if(!istream) return ReadResult::FILE_NOT_HANDLED; ReadResult rr = readBMPStream(istream); if(rr.validImage()) rr.getImage()->setFileName(file); return rr; } bool WriteBMPStream(const osg::Image &img, std::ostream& fout, const std::string &fileName) const { // its easier for me to write a binary write using stdio than streams struct bmpheader hd; uint32 nx=img.s(),ny=img.t(); // unsigned long ndep=img.r(); uint32 size, wordsPerScan; int32 infsize; //size of BMPinfo in bytes wordsPerScan=(nx*3+3)/4; // rounds up to next 32 bit boundary size=4*ny*wordsPerScan; // rounded to 4bytes * number of scan lines hd.FileType=MB; hd.Reserved1=hd.Reserved2=0; // offset to image hd.offset[0]=sizeof(int32)+sizeof(BMPInfo)+sizeof(hd); // 26; // offset to image hd.offset[1]=0; // offset to image // previous way round. // hd.siz[0]=(size&0xffff0000)>>16; // high word // hd.siz[1]=(size&0xffff); // low word // new round to be consistent with the swap in the size calclation in the reading code. hd.siz[0]=(size&0xffff); // low word hd.siz[1]=(size&0xffff0000)>>16; // high word fout.write((const char*)&hd, sizeof(hd)); struct BMPInfo inf; osg::notify(osg::INFO) << "sizes "<"); if(success) return WriteResult::FILE_SAVED; else return WriteResult::ERROR_IN_WRITING_FILE; } virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const { std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary); if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; bool success = WriteBMPStream(img, fout, fileName); if(success) return WriteResult::FILE_SAVED; else return WriteResult::ERROR_IN_WRITING_FILE; } }; // now register with Registry to instantiate the above // reader/writer. osgDB::RegisterReaderWriterProxy g_readerWriter_BMP_Proxy;