Added ImageProcessor interface class and plugin mechnanism for ImageProcessor implementations to osgDB::Registry.
Add NVidiaTextureTools based plugin that provides an ImageProcessor implementation within an nvtt plugin.
This commit is contained in:
parent
f61a6aa4e7
commit
1b67e3ad1f
@ -423,6 +423,7 @@ FIND_PACKAGE(Poppler-glib)
|
|||||||
FIND_PACKAGE(RSVG)
|
FIND_PACKAGE(RSVG)
|
||||||
FIND_PACKAGE(GtkGl)
|
FIND_PACKAGE(GtkGl)
|
||||||
FIND_PACKAGE(DirectInput)
|
FIND_PACKAGE(DirectInput)
|
||||||
|
FIND_PACKAGE(NVTT)
|
||||||
|
|
||||||
# Include macro utilities here
|
# Include macro utilities here
|
||||||
INCLUDE(OsgMacroUtils)
|
INCLUDE(OsgMacroUtils)
|
||||||
|
61
CMakeModules/FindNVTT.cmake
Normal file
61
CMakeModules/FindNVTT.cmake
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Locate nvidia-texture-tools
|
||||||
|
# This module defines
|
||||||
|
# NVTT_LIBRARY
|
||||||
|
# NVTT_FOUND, if false, do not try to link to nvtt
|
||||||
|
# NVTT_INCLUDE_DIR, where to find the headers
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
FIND_PATH(NVTT_INCLUDE_DIR nvtt/nvtt.h
|
||||||
|
PATHS
|
||||||
|
/usr/local
|
||||||
|
/usr
|
||||||
|
$ENV{NVTT_DIR}
|
||||||
|
${3rdPartyRoot}
|
||||||
|
PATH_SUFFIXES include
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(NVTT_LIBRARY
|
||||||
|
NAMES nvtt
|
||||||
|
PATHS
|
||||||
|
/usr/local
|
||||||
|
/usr
|
||||||
|
$ENV{NVTT_DIR}
|
||||||
|
${3rdPartyRoot}
|
||||||
|
PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(NVIMAGE_LIBRARY
|
||||||
|
NAMES nvimage
|
||||||
|
PATHS
|
||||||
|
/usr/local
|
||||||
|
/usr
|
||||||
|
$ENV{NVTT_DIR}
|
||||||
|
${3rdPartyRoot}
|
||||||
|
PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(NVMATH_LIBRARY
|
||||||
|
NAMES nvmath
|
||||||
|
PATHS
|
||||||
|
/usr/local
|
||||||
|
/usr
|
||||||
|
$ENV{NVTT_DIR}
|
||||||
|
${3rdPartyRoot}
|
||||||
|
PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(NVCORE_LIBRARY
|
||||||
|
NAMES nvcore
|
||||||
|
PATHS
|
||||||
|
/usr/local
|
||||||
|
/usr
|
||||||
|
$ENV{NVTT_DIR}
|
||||||
|
${3rdPartyRoot}
|
||||||
|
PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(NVTT_FOUND "NO")
|
||||||
|
IF(NVTT_LIBRARY AND NVTT_INCLUDE_DIR)
|
||||||
|
SET(NVTT_FOUND "YES")
|
||||||
|
ENDIF(NVTT_LIBRARY AND NVTT_INCLUDE_DIR)
|
54
include/osgDB/ImageProcessor
Normal file
54
include/osgDB/ImageProcessor
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||||
|
*
|
||||||
|
* This library is open source and may be redistributed and/or modified under
|
||||||
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||||
|
* (at your option) any later version. The full license is in LICENSE file
|
||||||
|
* included with this distribution, and on the openscenegraph.org website.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* OpenSceneGraph Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OSGDB_IMAGEPROCESSOR
|
||||||
|
#define OSGDB_IMAGEPROCESSOR 1
|
||||||
|
|
||||||
|
#include <osg/Object>
|
||||||
|
|
||||||
|
namespace osgDB {
|
||||||
|
|
||||||
|
class ImageProcessor : public osg::Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ImageProcessor():
|
||||||
|
osg::Object(true) {}
|
||||||
|
|
||||||
|
ImageProcessor(const ImageProcessor& rw,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
|
||||||
|
osg::Object(rw,copyop) {}
|
||||||
|
|
||||||
|
virtual ~ImageProcessor() {}
|
||||||
|
|
||||||
|
META_Object(osgDB,ImageProcessor);
|
||||||
|
|
||||||
|
enum CompressionMethod
|
||||||
|
{
|
||||||
|
USE_CPU, /// Use CPU for compression even when GPU compression is available
|
||||||
|
USE_GPU /// Use GPU for compression when available (i.e CUDA), otherwise fallback to CPU
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CompressionQuality
|
||||||
|
{
|
||||||
|
FASTEST,
|
||||||
|
NORMAL,
|
||||||
|
PRODUCTION,
|
||||||
|
HIGHEST
|
||||||
|
};
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
@ -27,6 +27,7 @@
|
|||||||
#include <osgDB/ObjectWrapper>
|
#include <osgDB/ObjectWrapper>
|
||||||
#include <osgDB/FileCache>
|
#include <osgDB/FileCache>
|
||||||
#include <osgDB/SharedStateManager>
|
#include <osgDB/SharedStateManager>
|
||||||
|
#include <osgDB/ImageProcessor>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -59,7 +60,6 @@ struct type_wrapper: basic_type_wrapper {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Registry is a singleton factory which stores
|
Registry is a singleton factory which stores
|
||||||
the reader/writers which are linked in
|
the reader/writers which are linked in
|
||||||
@ -101,6 +101,9 @@ class OSGDB_EXPORT Registry : public osg::Referenced
|
|||||||
void addReaderWriter(ReaderWriter* rw);
|
void addReaderWriter(ReaderWriter* rw);
|
||||||
void removeReaderWriter(ReaderWriter* rw);
|
void removeReaderWriter(ReaderWriter* rw);
|
||||||
|
|
||||||
|
void addImageProcessor(ImageProcessor* ip);
|
||||||
|
void removeImageProcessor(ImageProcessor* ip);
|
||||||
|
|
||||||
/** create the platform specific library name associated with file.*/
|
/** create the platform specific library name associated with file.*/
|
||||||
std::string createLibraryNameForFile(const std::string& fileName);
|
std::string createLibraryNameForFile(const std::string& fileName);
|
||||||
|
|
||||||
@ -142,6 +145,21 @@ class OSGDB_EXPORT Registry : public osg::Referenced
|
|||||||
const ReaderWriterList& getReaderWriterList() const { return _rwList; }
|
const ReaderWriterList& getReaderWriterList() const { return _rwList; }
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::vector< osg::ref_ptr<ImageProcessor> > ImageProcessorList;
|
||||||
|
|
||||||
|
/** get a image processor if available.*/
|
||||||
|
ImageProcessor* getImageProcessor();
|
||||||
|
|
||||||
|
/** get a image processor which is associated specified extension.*/
|
||||||
|
ImageProcessor* getImageProcessorForExtension(const std::string& ext);
|
||||||
|
|
||||||
|
/** get list of all registered ImageProcessors.*/
|
||||||
|
ImageProcessorList& getImageProcessorList() { return _ipList; }
|
||||||
|
|
||||||
|
/** get const list of all registered ImageProcessors.*/
|
||||||
|
const ImageProcessorList& getImageProcessorList() const { return _ipList; }
|
||||||
|
|
||||||
|
|
||||||
typedef class osgDB::FindFileCallback FindFileCallback;
|
typedef class osgDB::FindFileCallback FindFileCallback;
|
||||||
typedef class osgDB::ReadFileCallback ReadFileCallback;
|
typedef class osgDB::ReadFileCallback ReadFileCallback;
|
||||||
typedef class osgDB::WriteFileCallback WriteFileCallback;
|
typedef class osgDB::WriteFileCallback WriteFileCallback;
|
||||||
@ -555,6 +573,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced
|
|||||||
|
|
||||||
OpenThreads::ReentrantMutex _pluginMutex;
|
OpenThreads::ReentrantMutex _pluginMutex;
|
||||||
ReaderWriterList _rwList;
|
ReaderWriterList _rwList;
|
||||||
|
ImageProcessorList _ipList;
|
||||||
DynamicLibraryList _dlList;
|
DynamicLibraryList _dlList;
|
||||||
|
|
||||||
bool _openingLibrary;
|
bool _openingLibrary;
|
||||||
@ -624,6 +643,34 @@ class RegisterReaderWriterProxy
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Proxy class for automatic registration of reader/writers with the Registry.*/
|
||||||
|
template<class T>
|
||||||
|
class RegisterImageProcessorProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RegisterImageProcessorProxy()
|
||||||
|
{
|
||||||
|
if (Registry::instance())
|
||||||
|
{
|
||||||
|
_rw = new T;
|
||||||
|
Registry::instance()->addImageProcessor(_rw.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RegisterImageProcessorProxy()
|
||||||
|
{
|
||||||
|
if (Registry::instance())
|
||||||
|
{
|
||||||
|
Registry::instance()->removeImageProcessor(_rw.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T* get() { return _rw.get(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
osg::ref_ptr<T> _rw;
|
||||||
|
};
|
||||||
|
|
||||||
struct PluginFunctionProxy
|
struct PluginFunctionProxy
|
||||||
{
|
{
|
||||||
PluginFunctionProxy(CPluginFunction function) { (function)(); }
|
PluginFunctionProxy(CPluginFunction function) { (function)(); }
|
||||||
@ -657,6 +704,9 @@ struct PluginFunctionProxy
|
|||||||
extern "C" void osgdb_##ext(void) {} \
|
extern "C" void osgdb_##ext(void) {} \
|
||||||
static osgDB::RegisterReaderWriterProxy<classname> g_proxy_##classname;
|
static osgDB::RegisterReaderWriterProxy<classname> g_proxy_##classname;
|
||||||
|
|
||||||
|
#define REGISTER_OSGIMAGEPROCESSOR(ext, classname) \
|
||||||
|
extern "C" void osgdb_##ext(void) {} \
|
||||||
|
static osgDB::RegisterImageProcessorProxy<classname> g_proxy_##classname;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,6 +550,71 @@ void Registry::removeReaderWriter(ReaderWriter* rw)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageProcessor* Registry::getImageProcessor()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
|
||||||
|
if (!_ipList.empty())
|
||||||
|
{
|
||||||
|
return _ipList.front().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getImageProcessorForExtension("nvtt");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProcessor* Registry::getImageProcessorForExtension(const std::string& ext)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
|
||||||
|
if (!_ipList.empty())
|
||||||
|
{
|
||||||
|
return _ipList.front().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string libraryName = createLibraryNameForExtension(ext);
|
||||||
|
OSG_NOTICE << "Now checking for plug-in "<<libraryName<< std::endl;
|
||||||
|
if (loadLibrary(libraryName)==LOADED)
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
|
||||||
|
if (!_ipList.empty())
|
||||||
|
{
|
||||||
|
OSG_NOTICE << "Loaded plug-in "<<libraryName<<" and located ImageProcessor"<< std::endl;
|
||||||
|
return _ipList.front().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Registry::addImageProcessor(ImageProcessor* ip)
|
||||||
|
{
|
||||||
|
if (ip==0L) return;
|
||||||
|
|
||||||
|
OSG_NOTIFY(NOTICE) << "osg::Registry::addImageProcessor("<<ip->className()<<")"<< std::endl;
|
||||||
|
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
|
||||||
|
|
||||||
|
_ipList.push_back(ip);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Registry::removeImageProcessor(ImageProcessor* ip)
|
||||||
|
{
|
||||||
|
if (ip==0L) return;
|
||||||
|
|
||||||
|
OSG_NOTIFY(NOTICE) << "osg::Registry::removeImageProcessor();"<< std::endl;
|
||||||
|
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
|
||||||
|
|
||||||
|
ImageProcessorList::iterator ipitr = std::find(_ipList.begin(),_ipList.end(),ip);
|
||||||
|
if (ipitr!=_ipList.end())
|
||||||
|
{
|
||||||
|
_ipList.erase(ipitr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
|
void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
|
||||||
{
|
{
|
||||||
|
@ -215,6 +215,9 @@ IF(QTKIT_FOUND)
|
|||||||
ADD_SUBDIRECTORY(QTKit)
|
ADD_SUBDIRECTORY(QTKit)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
IF(NVTT_FOUND)
|
||||||
|
ADD_SUBDIRECTORY(nvtt)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
|
||||||
IF(FREETYPE_FOUND)
|
IF(FREETYPE_FOUND)
|
||||||
|
11
src/osgPlugins/nvtt/CMakeLists.txt
Normal file
11
src/osgPlugins/nvtt/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
INCLUDE_DIRECTORIES( ${NVTT_INCLUDE_DIR} )
|
||||||
|
|
||||||
|
|
||||||
|
SET(TARGET_SRC
|
||||||
|
NVTTImageProcessor.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(TARGET_LIBRARIES_VARS NVTT_LIBRARY)
|
||||||
|
|
||||||
|
#### end var setup ###
|
||||||
|
SETUP_PLUGIN(nvtt)
|
329
src/osgPlugins/nvtt/NVTTImageProcessor.cpp
Normal file
329
src/osgPlugins/nvtt/NVTTImageProcessor.cpp
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
|
||||||
|
#include <osg/Texture>
|
||||||
|
#include <osgDB/Registry>
|
||||||
|
|
||||||
|
#include <nvtt/nvtt.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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<unsigned char> MipMapData;
|
||||||
|
|
||||||
|
std::vector<MipMapData*> _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);
|
||||||
|
|
||||||
|
/// 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<unsigned char>& outputData, const unsigned char* inputData );
|
||||||
|
|
||||||
|
// Convert RGB to BGRA : nvtt only accepts BGRA pixel format
|
||||||
|
void convertRGBToBGRA( std::vector<unsigned char>& outputData, const unsigned char* inputData );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Error handler.
|
||||||
|
void NVTTProcessor::VPBErrorHandler::error(nvtt::Error e)
|
||||||
|
{
|
||||||
|
switch (e)
|
||||||
|
{
|
||||||
|
case nvtt::Error_Unknown:
|
||||||
|
OSG_WARN<<" NVTT : unknown error"<<std::endl;
|
||||||
|
break;
|
||||||
|
case nvtt::Error_InvalidInput:
|
||||||
|
OSG_WARN<<" NVTT : invalid input"<<std::endl;
|
||||||
|
break;
|
||||||
|
case nvtt::Error_UnsupportedFeature:
|
||||||
|
OSG_WARN<<" NVTT : unsupported feature"<<std::endl;
|
||||||
|
break;
|
||||||
|
case nvtt::Error_CudaError:
|
||||||
|
OSG_WARN<<" NVTT : cuda error"<<std::endl;
|
||||||
|
break;
|
||||||
|
case nvtt::Error_FileOpen:
|
||||||
|
OSG_WARN<<" NVTT : file open error"<<std::endl;
|
||||||
|
break;
|
||||||
|
case nvtt::Error_FileWrite:
|
||||||
|
OSG_WARN<<" NVTT : file write error"<<std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Output handler.
|
||||||
|
NVTTProcessor::OSGImageOutputHandler::OSGImageOutputHandler(nvtt::Format format, bool discardAlpha)
|
||||||
|
: _format(format), _discardAlpha(discardAlpha)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NVTTProcessor::OSGImageOutputHandler::~OSGImageOutputHandler()
|
||||||
|
{
|
||||||
|
for (unsigned int n=0; n<_mipmaps.size(); n++)
|
||||||
|
{
|
||||||
|
delete _mipmaps[n];
|
||||||
|
}
|
||||||
|
_mipmaps.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the osg image from the given format
|
||||||
|
bool NVTTProcessor::OSGImageOutputHandler::assignImage(osg::Image& image)
|
||||||
|
{
|
||||||
|
// convert nvtt format to OpenGL pixel format
|
||||||
|
GLint pixelFormat;
|
||||||
|
switch (_format)
|
||||||
|
{
|
||||||
|
case nvtt::Format_RGBA:
|
||||||
|
pixelFormat = _discardAlpha ? GL_RGB : GL_RGBA;
|
||||||
|
break;
|
||||||
|
case nvtt::Format_DXT1:
|
||||||
|
pixelFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||||
|
break;
|
||||||
|
case nvtt::Format_DXT1a:
|
||||||
|
pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||||
|
break;
|
||||||
|
case nvtt::Format_DXT3:
|
||||||
|
pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||||
|
break;
|
||||||
|
case nvtt::Format_DXT5:
|
||||||
|
pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSG_WARN<<" Invalid or not supported format"<<std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the total size and the mipmap offsets
|
||||||
|
osg::Image::MipmapDataType mipmapOffsets(_mipmaps.size()-1);
|
||||||
|
unsigned int totalSize = _mipmaps[0]->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<int>(_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<unsigned char>& 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<unsigned char>& outputData, const unsigned char* inputData )
|
||||||
|
{
|
||||||
|
for (unsigned n=0; n<outputData.size(); n += 4)
|
||||||
|
{
|
||||||
|
outputData[n] = inputData[n+2];
|
||||||
|
outputData[n+1] = inputData[n+1];
|
||||||
|
outputData[n+2] = inputData[n];
|
||||||
|
outputData[n+3] = inputData[n+3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert RGB to BGRA : nvtt only accepts BGRA pixel format
|
||||||
|
void NVTTProcessor::convertRGBToBGRA( std::vector<unsigned char>& outputData, const unsigned char* inputData )
|
||||||
|
{
|
||||||
|
unsigned int numberOfPixels = outputData.size()/4;
|
||||||
|
for (unsigned n=0; n<numberOfPixels; n++)
|
||||||
|
{
|
||||||
|
outputData[4*n] = inputData[3*n+2];
|
||||||
|
outputData[4*n+1] = inputData[3*n+1];
|
||||||
|
outputData[4*n+2] = inputData[3*n];
|
||||||
|
outputData[4*n+3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main interface with NVTT
|
||||||
|
void NVTTProcessor::process( osg::Image& image, nvtt::Format format, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality)
|
||||||
|
{
|
||||||
|
// Fill input options
|
||||||
|
nvtt::InputOptions inputOptions;
|
||||||
|
inputOptions.setTextureLayout(nvtt::TextureType_2D, image.s(), image.t() );
|
||||||
|
inputOptions.setNormalMap(false);
|
||||||
|
inputOptions.setConvertToNormalMap(false);
|
||||||
|
inputOptions.setGamma(2.2f, 2.2f);
|
||||||
|
inputOptions.setNormalizeMipmaps(false);
|
||||||
|
inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
|
||||||
|
if (resizeToPowerOfTwo)
|
||||||
|
{
|
||||||
|
inputOptions.setRoundMode(nvtt::RoundMode_ToNearestPowerOfTwo);
|
||||||
|
}
|
||||||
|
inputOptions.setMipmapGeneration(generateMipMap);
|
||||||
|
|
||||||
|
if (image.getPixelFormat() == GL_RGBA)
|
||||||
|
{
|
||||||
|
inputOptions.setAlphaMode( nvtt::AlphaMode_Transparency );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputOptions.setAlphaMode( nvtt::AlphaMode_None );
|
||||||
|
}
|
||||||
|
std::vector<unsigned char> imageData( image.s() * image.t() * 4 );
|
||||||
|
if (image.getPixelFormat() == GL_RGB)
|
||||||
|
{
|
||||||
|
convertRGBToBGRA( imageData, image.data() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
convertRGBAToBGRA( imageData, image.data() );
|
||||||
|
}
|
||||||
|
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."<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compressor.enableCudaAcceleration(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
compressor.process(inputOptions,compressionOptions,outputOptions);
|
||||||
|
|
||||||
|
outputHandler.assignImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NVTTProcessor::compress(osg::Image& image, osg::Texture::InternalFormatMode compressedFormat, bool generateMipMap, bool resizeToPowerOfTwo, CompressionMethod method, CompressionQuality quality)
|
||||||
|
{
|
||||||
|
nvtt::Format format;
|
||||||
|
switch (compressedFormat)
|
||||||
|
{
|
||||||
|
case osg::Texture::USE_S3TC_DXT1_COMPRESSION:
|
||||||
|
if (image.getPixelFormat() == GL_RGBA)
|
||||||
|
format = nvtt::Format_DXT1a;
|
||||||
|
else
|
||||||
|
format = nvtt::Format_DXT1;
|
||||||
|
break;
|
||||||
|
case osg::Texture::USE_S3TC_DXT3_COMPRESSION:
|
||||||
|
format = nvtt::Format_DXT3;
|
||||||
|
break;
|
||||||
|
case osg::Texture::USE_S3TC_DXT5_COMPRESSION:
|
||||||
|
format = nvtt::Format_DXT5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSG_WARN<<" Invalid or not supported compress format"<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process( image, format, generateMipMap, resizeToPowerOfTwo, method, quality );
|
||||||
|
}
|
||||||
|
|
||||||
|
void NVTTProcessor::generateMipMap(osg::Image& image, bool resizeToPowerOfTwo, CompressionMethod method)
|
||||||
|
{
|
||||||
|
process( image, nvtt::Format_RGBA, true, resizeToPowerOfTwo, method, NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_OSGIMAGEPROCESSOR(nvtt, NVTTProcessor)
|
Loading…
Reference in New Issue
Block a user