#include "osg/Image" #include "osg/Notify" #include #include "osg/GL" #include "osgDB/FileNameUtils" #include "osgDB/Registry" #include "osgDB/FileUtils" #include #include #include #ifndef SEEK_SET # define SEEK_SET 0 #endif #include #include #include "QTtexture.h" #include "QuicktimeImageStream.h" using namespace osg; class ReaderWriterQT : public osgDB::ReaderWriter { public: virtual const char* className() const { return "Default Quicktime Image Reader/Writer"; } virtual bool acceptsMovieExtension(const std::string& extension) const { return osgDB::equalCaseInsensitive(extension,"mov") || osgDB::equalCaseInsensitive(extension,"mpg") || osgDB::equalCaseInsensitive(extension,"mpv") || osgDB::equalCaseInsensitive(extension,"mp4") || osgDB::equalCaseInsensitive(extension,"m4v") || osgDB::equalCaseInsensitive(extension,"dv"); } virtual bool acceptsExtension(const std::string& extension) const { // this should be the only image importer required on the Mac // dont know what else it supports, but these will do return osgDB::equalCaseInsensitive(extension,"rgb") || osgDB::equalCaseInsensitive(extension,"rgba") || osgDB::equalCaseInsensitive(extension,"jpg") || osgDB::equalCaseInsensitive(extension,"jpeg") || osgDB::equalCaseInsensitive(extension,"tif") || osgDB::equalCaseInsensitive(extension,"tiff") || osgDB::equalCaseInsensitive(extension,"gif") || osgDB::equalCaseInsensitive(extension,"png") || osgDB::equalCaseInsensitive(extension,"pict") || osgDB::equalCaseInsensitive(extension,"pct") || osgDB::equalCaseInsensitive(extension,"tga") || osgDB::equalCaseInsensitive(extension,"psd") || acceptsMovieExtension(extension); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options*) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; // if the file is a movie file then load as an ImageStream. if (acceptsMovieExtension(ext)) { // note from Robert Osfield when integrating, we should probably have so // error handling mechanism here. Possibly move the load from // the constructor to a seperate load method, and have a valid // state on the ImageStream... will integrated as is right now // to get things off the ground. osg::QuicktimeImageStream* moov = new osg::QuicktimeImageStream(fileName); // moov->play(); return moov; } long origWidth, origHeight,buffWidth,buffHeight,buffDepth,origDepth; // NOTE - implememntation means that this will always return 32 bits, so it is hard to work out if // an image was monochrome. So it will waste texture memory unless it gets a monochrome hint. unsigned char *pixels = LoadBufferFromDarwinPath ( fileName.c_str(), &origWidth,&origHeight,&origDepth, &buffWidth,&buffHeight, &buffDepth); // IMPORTANT - // origDepth in BYTES, buffDepth in BITS if (pixels == 0) { osg::notify(osg::WARN) << "LoadBufferFromDarwinPath failed " << fileName.c_str() << QTfailureMessage() << std::endl; return 0; } unsigned int pixelFormat; switch(origDepth) { case 1 : pixelFormat = GL_RGB; break; case 2 : pixelFormat = GL_LUMINANCE_ALPHA; break; case 3 : pixelFormat = GL_RGB; break; case 4 : pixelFormat = GL_RGBA; break; default : osg::notify(osg::WARN) << "Unknown file type in " << fileName.c_str() << " with " << origDepth << std::endl; pixelFormat = (GLenum)-1; return 0; break; } { unsigned char *srcp=pixels, *dstp=pixels; int i, j; // swizzle entire image in-place unsigned char r, g, b, a; for (i=0; isetFileName(fileName.c_str()); image->setImage(buffWidth,buffHeight,1, buffDepth >> 3, pixelFormat, GL_UNSIGNED_BYTE, pixels, osg::Image::USE_NEW_DELETE ); notify(INFO) << "image read ok "< osFileTypes std::map extmap; extmap.insert(std::pair("jpg", kQTFileTypeJPEG)); extmap.insert(std::pair("jpeg", kQTFileTypeJPEG)); extmap.insert(std::pair("bmp", kQTFileTypeBMP)); extmap.insert(std::pair("tif", kQTFileTypeTIFF)); extmap.insert(std::pair("tiff", kQTFileTypeTIFF)); extmap.insert(std::pair("png", kQTFileTypePNG)); extmap.insert(std::pair("gif", kQTFileTypeGIF)); extmap.insert(std::pair("psd", kQTFileTypePhotoShop)); // extmap.insert(std::pair("tga", kQTFileTypeTargaImage)); extmap.insert(std::pair("sgi", kQTFileTypeSGIImage)); extmap.insert(std::pair("rgb", kQTFileTypeSGIImage)); extmap.insert(std::pair("rgba", kQTFileTypeSGIImage)); std::map::iterator cur = extmap.find(ext); // can not handle this type of file, perhaps a movie? if (cur == extmap.end()) return WriteResult::FILE_NOT_HANDLED; OSType desiredType = cur->second; GraphicsExportComponent geComp = NULL; OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, desiredType, &geComp); if (err != noErr) { osg::notify(osg::WARN) << "ReaderWriterQT: could not open Graphics epxorter for type " << ext << ", Err: " << err << std::endl; return WriteResult::FILE_NOT_HANDLED; } CGContextRef cg_context = NULL; // we are converting the images back to 32bit, it seems, that quicktime can't handle others // unsigned long desiredPixelFormat = k32ARGBPixelFormat; // we need to swizzle the colours again :) unsigned int numBytes = img.computeNumComponents(img.getPixelFormat()); unsigned int buffWidth = img.s(); unsigned int buffHeight = img.t(); char * pixels = (char*) malloc(buffHeight * buffWidth * 4); const unsigned char *srcp = img.data(); char *dstp=pixels; unsigned int i, j; for (i=0; i(fileName.c_str()) ); if (fileSpec == NULL) { osg::notify(osg::WARN) << "ReaderWriterQT: could not get FSSpec" << std::endl; throw err; } err = GraphicsExportSetInputCGBitmapContext(geComp, cg_context); if (err != noErr) { osg::notify(osg::WARN) << "ReaderWriterQT: could not set input gworld for type " << ext << ", Err: " << err << std::endl; throw err; } err = GraphicsExportSetOutputFile(geComp, fileSpec); if (err != noErr) { osg::notify(osg::WARN) << "ReaderWriterQT: could not set output file for type " << ext << ", Err: " << err << std::endl; throw err; } // Set the compression quality (needed for JPEG, not necessarily for other formats) if (desiredType == kQTFileTypeJPEG) { err = GraphicsExportSetCompressionQuality(geComp, codecLosslessQuality); if (err != noErr) { osg::notify(osg::WARN) << "ReaderWriterQT: could not set compression for type " << ext << ", Err: " << err << std::endl; throw err; } } if(32 == numBytes) { err = GraphicsExportSetDepth( geComp, k32ARGBPixelFormat ); // depth } // else k24RGBPixelFormat??? // do the export err = GraphicsExportDoExport(geComp, NULL); if (err != noErr) { osg::notify(osg::WARN) << "ReaderWriterQT: could not save file for type " << ext << ", Err: " << err << std::endl; throw err; } if (geComp != NULL) CloseComponent(geComp); CGContextRelease(cg_context); if (fileSpec != NULL ) free(fileSpec); if (pixels) free(pixels); return WriteResult::FILE_SAVED; } catch (...) { if (geComp != NULL) CloseComponent(geComp); if (cg_context != NULL) CGContextRelease(cg_context); if (fileSpec != NULL ) free(fileSpec); if (pixels) free(pixels); return WriteResult::ERROR_IN_WRITING_FILE; } } }; // now register with Registry to instantiate the above // reader/writer. osgDB::RegisterReaderWriterProxy g_readerWriter_QT_Proxy;