root/OpenSceneGraph/trunk/src/osgPlugins/nvtt/NVTTImageProcessor.cpp @ 12292

Revision 12292, 10.7 kB (checked in by robert, 3 years ago)

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
Line 
1
2#include <osg/Texture>
3#include <osgDB/Registry>
4
5#include <nvtt/nvtt.h>
6#include <string.h>
7
8class NVTTProcessor : public osgDB::ImageProcessor
9{
10public:
11    virtual void compress(osg::Image& image, osg::Texture::InternalFormatMode compressedFormat, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality);
12    virtual void generateMipMap(osg::Image& image, bool resizeToPowerOfTwo, CompressionMethod method);
13
14protected:
15
16    void process( osg::Image& texture, nvtt::Format format, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality);
17
18    struct VPBErrorHandler : public nvtt::ErrorHandler
19    {
20        virtual void error(nvtt::Error e);
21    };
22
23    struct OSGImageOutputHandler : public nvtt::OutputHandler
24    {
25        typedef std::vector<unsigned char> MipMapData;
26
27        std::vector<MipMapData*> _mipmaps;
28        int _width;
29        int _height;
30        int _currentMipLevel;
31        int _currentNumberOfWritenBytes;
32        nvtt::Format _format;
33        bool _discardAlpha;
34
35        OSGImageOutputHandler(nvtt::Format format, bool discardAlpha);
36        virtual ~OSGImageOutputHandler();
37
38        // create the osg image from the given format
39        bool assignImage(osg::Image& image);
40
41        /// Indicate the start of a new compressed image that's part of the final texture.
42        virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel);
43
44        /// Output data. Compressed data is output as soon as it's generated to minimize memory allocations.
45        virtual bool writeData(const void * data, int size);
46    };
47
48    // Convert RGBA to BGRA : nvtt only accepts BGRA pixel format
49    void convertRGBAToBGRA( std::vector<unsigned char>& outputData, const unsigned char* inputData );
50
51    // Convert RGB to BGRA : nvtt only accepts BGRA pixel format
52    void convertRGBToBGRA( std::vector<unsigned char>& outputData, const unsigned char* inputData );
53
54};
55
56/// Error handler.
57void NVTTProcessor::VPBErrorHandler::error(nvtt::Error e)
58{
59    switch (e)
60    {
61    case nvtt::Error_Unknown:
62        OSG_WARN<<" NVTT : unknown error"<<std::endl;
63        break;
64    case nvtt::Error_InvalidInput:
65        OSG_WARN<<" NVTT : invalid input"<<std::endl;
66        break;
67    case nvtt::Error_UnsupportedFeature:
68        OSG_WARN<<" NVTT : unsupported feature"<<std::endl;
69        break;
70    case nvtt::Error_CudaError:
71        OSG_WARN<<" NVTT : cuda error"<<std::endl;
72        break;
73        case nvtt::Error_FileOpen:
74        OSG_WARN<<" NVTT : file open error"<<std::endl;
75        break;
76        case nvtt::Error_FileWrite:
77        OSG_WARN<<" NVTT : file write error"<<std::endl;
78        break;
79    }
80}
81
82/// Output handler.
83NVTTProcessor::OSGImageOutputHandler::OSGImageOutputHandler(nvtt::Format format, bool discardAlpha)
84    : _format(format), _discardAlpha(discardAlpha)
85{
86}
87
88NVTTProcessor::OSGImageOutputHandler::~OSGImageOutputHandler()
89{
90    for (unsigned int n=0; n<_mipmaps.size(); n++)
91    {
92        delete _mipmaps[n];
93    }
94    _mipmaps.clear();
95}
96
97// create the osg image from the given format
98bool NVTTProcessor::OSGImageOutputHandler::assignImage(osg::Image& image)
99{
100    // convert nvtt format to OpenGL pixel format
101    GLint pixelFormat;
102    switch (_format)
103    {
104    case nvtt::Format_RGBA:
105        pixelFormat = _discardAlpha ? GL_RGB : GL_RGBA;
106        break;
107    case nvtt::Format_DXT1:
108        pixelFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
109        break;
110    case nvtt::Format_DXT1a:
111        pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
112        break;
113    case nvtt::Format_DXT3:
114        pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
115        break;
116    case nvtt::Format_DXT5:
117        pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
118        break;
119    default:
120        OSG_WARN<<" Invalid or not supported format"<<std::endl;
121        return false;
122    }
123
124    // Compute the total size and the mipmap offsets
125    osg::Image::MipmapDataType mipmapOffsets(_mipmaps.size()-1);
126    unsigned int totalSize = _mipmaps[0]->size();
127    for (unsigned int n=1; n<_mipmaps.size(); n++)
128    {
129        mipmapOffsets[n-1] = totalSize;
130        totalSize += _mipmaps[n]->size();
131    }
132
133    // Allocate data and copy it
134    unsigned char* data = new unsigned char[ totalSize ];
135    unsigned char* ptr = data;
136    for (unsigned int n=0; n<_mipmaps.size(); n++)
137    {
138        memcpy( ptr, &(*_mipmaps[n])[0], _mipmaps[n]->size() );
139        ptr += _mipmaps[n]->size();
140    }
141
142    image.setImage(_width,_height,1,pixelFormat,pixelFormat,GL_UNSIGNED_BYTE,data,osg::Image::USE_NEW_DELETE);
143    image.setMipmapLevels(mipmapOffsets);
144
145    return true;
146}
147
148/// Indicate the start of a new compressed image that's part of the final texture.
149void NVTTProcessor::OSGImageOutputHandler::beginImage(int size, int width, int height, int depth, int face, int miplevel)
150{
151    // store the new width/height of the texture
152    if (miplevel == 0)
153    {
154        _width = width;
155        _height = height;
156    }
157    // prepare to receive mipmap data
158    if (miplevel >= static_cast<int>(_mipmaps.size()))
159    {
160        _mipmaps.resize(miplevel+1);
161    }
162    _mipmaps[miplevel] = new MipMapData(size);
163    _currentMipLevel = miplevel;
164    _currentNumberOfWritenBytes = 0;
165}
166
167/// Output data. Compressed data is output as soon as it's generated to minimize memory allocations.
168bool NVTTProcessor::OSGImageOutputHandler::writeData(const void * data, int size)
169{
170    // Copy mipmap data
171    std::vector<unsigned char>& dstData = *_mipmaps[_currentMipLevel];
172    memcpy( &dstData[_currentNumberOfWritenBytes], data, size );
173    _currentNumberOfWritenBytes += size;
174    return true;
175}
176
177// Convert RGBA to BGRA : nvtt only accepts BGRA pixel format
178void NVTTProcessor::convertRGBAToBGRA( std::vector<unsigned char>& outputData, const unsigned char* inputData )
179{
180    for (unsigned n=0; n<outputData.size(); n += 4)
181    {
182        outputData[n] = inputData[n+2];
183        outputData[n+1] = inputData[n+1];
184        outputData[n+2] = inputData[n];
185        outputData[n+3] = inputData[n+3];
186    }
187}
188
189// Convert RGB to BGRA : nvtt only accepts BGRA pixel format
190void NVTTProcessor::convertRGBToBGRA( std::vector<unsigned char>& outputData, const unsigned char* inputData )
191{
192    unsigned int numberOfPixels = outputData.size()/4;
193    for (unsigned n=0; n<numberOfPixels; n++)
194    {
195        outputData[4*n] = inputData[3*n+2];
196        outputData[4*n+1] = inputData[3*n+1];
197        outputData[4*n+2] = inputData[3*n];
198        outputData[4*n+3] = 255;
199    }
200}
201
202// Main interface with NVTT
203void NVTTProcessor::process( osg::Image& image, nvtt::Format format, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality)
204{
205    // Fill input options
206    nvtt::InputOptions inputOptions;
207    inputOptions.setTextureLayout(nvtt::TextureType_2D, image.s(), image.t() );
208    inputOptions.setNormalMap(false);
209    inputOptions.setConvertToNormalMap(false);
210    inputOptions.setGamma(2.2f, 2.2f);
211    inputOptions.setNormalizeMipmaps(false);
212    inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
213    if (resizeToPowerOfTwo)
214    {
215        inputOptions.setRoundMode(nvtt::RoundMode_ToNearestPowerOfTwo);
216    }
217    inputOptions.setMipmapGeneration(generateMipMap);
218
219    if (image.getPixelFormat() == GL_RGBA)
220    {
221        inputOptions.setAlphaMode( nvtt::AlphaMode_Transparency );
222    }
223    else
224    {
225        inputOptions.setAlphaMode( nvtt::AlphaMode_None );
226    }
227    std::vector<unsigned char> imageData( image.s() * image.t() * 4 );
228    if (image.getPixelFormat() == GL_RGB)
229    {
230        convertRGBToBGRA( imageData, image.data() );
231    }
232    else
233    {
234        convertRGBAToBGRA( imageData, image.data() );
235    }
236    inputOptions.setMipmapData(&imageData[0],image.s(),image.t());
237
238    // Fill compression options
239    nvtt::CompressionOptions compressionOptions;
240    switch(quality)
241    {
242      case FASTEST:
243        compressionOptions.setQuality( nvtt::Quality_Fastest );
244        break;
245      case NORMAL:
246        compressionOptions.setQuality( nvtt::Quality_Normal );
247        break;
248      case PRODUCTION:
249        compressionOptions.setQuality( nvtt::Quality_Production);
250        break;
251      case HIGHEST:
252        compressionOptions.setQuality( nvtt::Quality_Highest);
253        break;
254    }
255    compressionOptions.setFormat( format );
256    //compressionOptions.setQuantization(false,false,false);
257    if (format == nvtt::Format_RGBA)
258    {
259        if (image.getPixelFormat() == GL_RGB)
260        {
261            compressionOptions.setPixelFormat(24,0xff,0xff00,0xff0000,0);
262        }
263        else
264        {
265            compressionOptions.setPixelFormat(32,0xff,0xff00,0xff0000,0xff000000);
266        }
267    }
268
269    // Handler
270    OSGImageOutputHandler outputHandler(format,image.getPixelFormat() == GL_RGB);
271    VPBErrorHandler errorHandler;
272
273    // Fill output options
274    nvtt::OutputOptions outputOptions;
275    outputOptions.setOutputHandler(&outputHandler);
276    outputOptions.setErrorHandler(&errorHandler);
277    outputOptions.setOutputHeader(false);
278
279    // Process the compression now
280    nvtt::Compressor compressor;
281    if(method == USE_GPU)
282    {
283        compressor.enableCudaAcceleration(true);
284        if(!compressor.isCudaAccelerationEnabled())
285        {
286            OSG_WARN<< "CUDA acceleration was enabled but it is not available. CPU will be used."<<std::endl;
287        }
288    }
289    else
290    {
291        compressor.enableCudaAcceleration(false);
292    }
293
294    compressor.process(inputOptions,compressionOptions,outputOptions);
295
296    outputHandler.assignImage(image);
297}
298
299void NVTTProcessor::compress(osg::Image& image, osg::Texture::InternalFormatMode compressedFormat, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality)
300{
301    nvtt::Format format;
302    switch (compressedFormat)
303    {
304    case osg::Texture::USE_S3TC_DXT1_COMPRESSION:
305        if (image.getPixelFormat() == GL_RGBA)
306            format = nvtt::Format_DXT1a;
307        else
308            format = nvtt::Format_DXT1;
309        break;
310    case osg::Texture::USE_S3TC_DXT1c_COMPRESSION:
311        format = nvtt::Format_DXT1;
312        break;
313    case osg::Texture::USE_S3TC_DXT1a_COMPRESSION:
314        format = nvtt::Format_DXT1a;
315        break;
316    case osg::Texture::USE_S3TC_DXT3_COMPRESSION:
317        format = nvtt::Format_DXT3;
318        break;
319    case osg::Texture::USE_S3TC_DXT5_COMPRESSION:
320        format = nvtt::Format_DXT5;
321        break;
322    default:
323        OSG_WARN<<" Invalid or not supported compress format"<<std::endl;
324        return;
325    }
326
327    process( image, format, generateMipMap, resizeToPowerOfTwo, method, quality );
328}
329
330void NVTTProcessor::generateMipMap(osg::Image& image, bool resizeToPowerOfTwo, CompressionMethod method)
331{
332    process( image, nvtt::Format_RGBA, true, resizeToPowerOfTwo, method, NORMAL);
333}
334
335REGISTER_OSGIMAGEPROCESSOR(nvtt, NVTTProcessor)
Note: See TracBrowser for help on using the browser.