#include #include #include #include class NVTTProcessor : public osgDB::ImageProcessor { public: virtual void compress(osg::Image& image, osg::Texture::InternalFormatMode compressedFormat, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality); virtual void generateMipMap(osg::Image& image, bool resizeToPowerOfTwo, CompressionMethod method); protected: void process( osg::Image& texture, nvtt::Format format, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality); struct VPBErrorHandler : public nvtt::ErrorHandler { virtual void error(nvtt::Error e); }; struct OSGImageOutputHandler : public nvtt::OutputHandler { typedef std::vector MipMapData; std::vector _mipmaps; int _width; int _height; int _currentMipLevel; int _currentNumberOfWritenBytes; nvtt::Format _format; bool _discardAlpha; OSGImageOutputHandler(nvtt::Format format, bool discardAlpha); virtual ~OSGImageOutputHandler(); // create the osg image from the given format bool assignImage(osg::Image& image); /// Indicate the start of a new compressed image that's part of the final texture. virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel); virtual void endImage() {} /// Output data. Compressed data is output as soon as it's generated to minimize memory allocations. virtual bool writeData(const void * data, int size); }; // Convert RGBA to BGRA : nvtt only accepts BGRA pixel format void convertRGBAToBGRA( std::vector& outputData, const osg::Image& image ); // Convert RGB to BGRA : nvtt only accepts BGRA pixel format void convertRGBToBGRA( std::vector& outputData, const osg::Image& image ); }; /// Error handler. void NVTTProcessor::VPBErrorHandler::error(nvtt::Error e) { switch (e) { case nvtt::Error_Unknown: OSG_WARN<<" NVTT : unknown error"<size(); for (unsigned int n=1; n<_mipmaps.size(); n++) { mipmapOffsets[n-1] = totalSize; totalSize += _mipmaps[n]->size(); } // Allocate data and copy it unsigned char* data = new unsigned char[ totalSize ]; unsigned char* ptr = data; for (unsigned int n=0; n<_mipmaps.size(); n++) { memcpy( ptr, &(*_mipmaps[n])[0], _mipmaps[n]->size() ); ptr += _mipmaps[n]->size(); } image.setImage(_width,_height,1,pixelFormat,pixelFormat,GL_UNSIGNED_BYTE,data,osg::Image::USE_NEW_DELETE); image.setMipmapLevels(mipmapOffsets); return true; } /// Indicate the start of a new compressed image that's part of the final texture. void NVTTProcessor::OSGImageOutputHandler::beginImage(int size, int width, int height, int /*depth*/, int /*face*/, int miplevel) { // store the new width/height of the texture if (miplevel == 0) { _width = width; _height = height; } // prepare to receive mipmap data if (miplevel >= static_cast(_mipmaps.size())) { _mipmaps.resize(miplevel+1); } _mipmaps[miplevel] = new MipMapData(size); _currentMipLevel = miplevel; _currentNumberOfWritenBytes = 0; } /// Output data. Compressed data is output as soon as it's generated to minimize memory allocations. bool NVTTProcessor::OSGImageOutputHandler::writeData(const void * data, int size) { // Copy mipmap data std::vector& dstData = *_mipmaps[_currentMipLevel]; memcpy( &dstData[_currentNumberOfWritenBytes], data, size ); _currentNumberOfWritenBytes += size; return true; } // Convert RGBA to BGRA : nvtt only accepts BGRA pixel format void NVTTProcessor::convertRGBAToBGRA( std::vector& outputData, const osg::Image& image ) { unsigned int n=0; for(int row=0; row& outputData, const osg::Image& image ) { unsigned int n=0; for(int row=0; row imageData( image.s() * image.t() * 4 ); if (image.getPixelFormat() == GL_RGB) { convertRGBToBGRA( imageData, image ); } else { convertRGBAToBGRA( imageData, image ); } inputOptions.setMipmapData(&imageData[0],image.s(),image.t()); // Fill compression options nvtt::CompressionOptions compressionOptions; switch(quality) { case FASTEST: compressionOptions.setQuality( nvtt::Quality_Fastest ); break; case NORMAL: compressionOptions.setQuality( nvtt::Quality_Normal ); break; case PRODUCTION: compressionOptions.setQuality( nvtt::Quality_Production); break; case HIGHEST: compressionOptions.setQuality( nvtt::Quality_Highest); break; } compressionOptions.setFormat( format ); //compressionOptions.setQuantization(false,false,false); if (format == nvtt::Format_RGBA) { if (image.getPixelFormat() == GL_RGB) { compressionOptions.setPixelFormat(24,0xff,0xff00,0xff0000,0); } else { compressionOptions.setPixelFormat(32,0xff,0xff00,0xff0000,0xff000000); } } // Handler OSGImageOutputHandler outputHandler(format,image.getPixelFormat() == GL_RGB); VPBErrorHandler errorHandler; // Fill output options nvtt::OutputOptions outputOptions; outputOptions.setOutputHandler(&outputHandler); outputOptions.setErrorHandler(&errorHandler); outputOptions.setOutputHeader(false); // Process the compression now nvtt::Compressor compressor; if(method == USE_GPU) { compressor.enableCudaAcceleration(true); if(!compressor.isCudaAccelerationEnabled()) { OSG_WARN<< "CUDA acceleration was enabled but it is not available. CPU will be used."<