From Per Fahlberg, "I have added support for PowerVR texture compression. osg::Texture and osg::Image have been modified to support the texture formats and I have added a plugin to load pvr files. All modified files are in the attached zip. "
This commit is contained in:
parent
4ced7dffc4
commit
d2a9f48054
@ -64,6 +64,13 @@
|
||||
#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
|
||||
#endif
|
||||
|
||||
#ifndef GL_IMG_texture_compression_pvrtc
|
||||
#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
|
||||
#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
|
||||
#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
|
||||
#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
|
||||
#endif
|
||||
|
||||
#ifndef GL_ARB_INTERNAL_TEXTURE_FORMAT
|
||||
#define GL_RGBA32F_ARB 0x8814
|
||||
#define GL_RGB32F_ARB 0x8815
|
||||
@ -642,6 +649,9 @@ class OSG_EXPORT Texture : public osg::StateAttribute
|
||||
void setTextureCompressionRGTCSupported(bool flag) { _isTextureCompressionRGTCSupported=flag; }
|
||||
bool isTextureCompressionRGTCSupported() const { return _isTextureCompressionRGTCSupported; }
|
||||
|
||||
void setTextureCompressionPVRTCSupported(bool flag) { _isTextureCompressionPVRTCSupported=flag; }
|
||||
bool isTextureCompressionPVRTCSupported() const { return _isTextureCompressionPVRTCSupported; }
|
||||
|
||||
void setTextureMirroredRepeatSupported(bool flag) { _isTextureMirroredRepeatSupported=flag; }
|
||||
bool isTextureMirroredRepeatSupported() const { return _isTextureMirroredRepeatSupported; }
|
||||
|
||||
@ -741,6 +751,7 @@ class OSG_EXPORT Texture : public osg::StateAttribute
|
||||
bool _isTextureCompressionARBSupported;
|
||||
bool _isTextureCompressionS3TCSupported;
|
||||
bool _isTextureCompressionRGTCSupported;
|
||||
bool _isTextureCompressionPVRTCSupported;
|
||||
bool _isTextureMirroredRepeatSupported;
|
||||
bool _isTextureEdgeClampSupported;
|
||||
bool _isTextureBorderClampSupported;
|
||||
|
@ -307,6 +307,10 @@ unsigned int Image::computeNumComponents(GLenum pixelFormat)
|
||||
case(GL_COMPRESSED_RED_RGTC1_EXT): return 1;
|
||||
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): return 2;
|
||||
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): return 2;
|
||||
case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): return 3;
|
||||
case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): return 3;
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): return 4;
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): return 4;
|
||||
case(GL_COLOR_INDEX): return 1;
|
||||
case(GL_STENCIL_INDEX): return 1;
|
||||
case(GL_DEPTH_COMPONENT): return 1;
|
||||
@ -417,6 +421,11 @@ unsigned int Image::computePixelSizeInBits(GLenum format,GLenum type)
|
||||
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): return 8;
|
||||
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): return 8;
|
||||
|
||||
case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): return 4;
|
||||
case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): return 2;
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): return 4;
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): return 2;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
@ -551,6 +560,10 @@ bool Image::isCompressed() const
|
||||
case(GL_COMPRESSED_RED_RGTC1_EXT):
|
||||
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
|
||||
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
|
||||
case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG):
|
||||
case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -135,6 +135,11 @@ void Texture::TextureProfile::computeSize()
|
||||
case(GL_COMPRESSED_RED_RGTC1_EXT): numBitsPerTexel = 4; break;
|
||||
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): numBitsPerTexel = 8; break;
|
||||
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): numBitsPerTexel = 8; break;
|
||||
|
||||
case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): numBitsPerTexel = 2; break;
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): numBitsPerTexel = 2; break;
|
||||
case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): numBitsPerTexel = 4; break;
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): numBitsPerTexel = 4; break;
|
||||
}
|
||||
|
||||
_size = (unsigned int)(ceil(double(_width * _height * _depth * numBitsPerTexel)/8.0));
|
||||
@ -1351,6 +1356,10 @@ bool Texture::isCompressedInternalFormat(GLint internalFormat)
|
||||
case(GL_COMPRESSED_RED_RGTC1_EXT):
|
||||
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
|
||||
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
|
||||
case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG):
|
||||
case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
|
||||
case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -1367,6 +1376,38 @@ void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height
|
||||
blockSize = 8;
|
||||
else if (internalFormat == GL_COMPRESSED_RED_GREEN_RGTC2_EXT || internalFormat == GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT)
|
||||
blockSize = 16;
|
||||
else if (internalFormat == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG || internalFormat == GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG)
|
||||
{
|
||||
blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
|
||||
GLint widthBlocks = width / 8;
|
||||
GLint heightBlocks = height / 4;
|
||||
GLint bpp = 2;
|
||||
|
||||
// Clamp to minimum number of blocks
|
||||
if(widthBlocks < 2)
|
||||
widthBlocks = 2;
|
||||
if(heightBlocks < 2)
|
||||
heightBlocks = 2;
|
||||
|
||||
size = widthBlocks * heightBlocks * ((blockSize * bpp) / 8);
|
||||
return;
|
||||
}
|
||||
else if (internalFormat == GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG || internalFormat == GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG)
|
||||
{
|
||||
blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
|
||||
GLint widthBlocks = width / 4;
|
||||
GLint heightBlocks = height / 4;
|
||||
GLint bpp = 4;
|
||||
|
||||
// Clamp to minimum number of blocks
|
||||
if(widthBlocks < 2)
|
||||
widthBlocks = 2;
|
||||
if(heightBlocks < 2)
|
||||
heightBlocks = 2;
|
||||
|
||||
size = widthBlocks * heightBlocks * ((blockSize * bpp) / 8);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_WARN<<"Texture::getCompressedSize(...) : cannot compute correct size of compressed format ("<<internalFormat<<") returning 0."<<std::endl;
|
||||
@ -2218,6 +2259,8 @@ Texture::Extensions::Extensions(unsigned int contextID)
|
||||
|
||||
_isTextureCompressionRGTCSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_compression_rgtc");
|
||||
|
||||
_isTextureCompressionPVRTCSupported = isGLExtensionSupported(contextID,"GL_IMG_texture_compression_pvrtc");
|
||||
|
||||
_isTextureMirroredRepeatSupported = builtInSupport ||
|
||||
isGLExtensionOrVersionSupported(contextID,"GL_IBM_texture_mirrored_repeat", 1.4f) ||
|
||||
isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_mirrored_repeat", 1.4f);
|
||||
|
@ -246,6 +246,8 @@ IF(LIBVNCSERVER_FOUND)
|
||||
ADD_SUBDIRECTORY(vnc)
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(pvr)
|
||||
|
||||
##########to get all the variables of Cmake
|
||||
#GET_CMAKE_PROPERTY(MYVARS VARIABLES)
|
||||
#FOREACH(myvar ${MYVARS})
|
||||
|
3
src/osgPlugins/pvr/CMakeLists.txt
Normal file
3
src/osgPlugins/pvr/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
SET(TARGET_SRC ReaderWriterPVR.cpp )
|
||||
#### end var setup ###
|
||||
SETUP_PLUGIN(pvr)
|
246
src/osgPlugins/pvr/ReaderWriterPVR.cpp
Normal file
246
src/osgPlugins/pvr/ReaderWriterPVR.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
// ReaderWriter for pvr images
|
||||
|
||||
#include <osg/Image>
|
||||
#include <osg/Notify>
|
||||
|
||||
#include <osg/Geode>
|
||||
|
||||
#include <osg/GL>
|
||||
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include <osgDB/FileUtils>
|
||||
#include <osgDB/Registry>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
using namespace osg;
|
||||
|
||||
#define PVR_TEXTURE_FLAG_TYPE_MASK 0xff
|
||||
|
||||
static char gPVRTexIdentifier[5] = "PVR!";
|
||||
|
||||
enum
|
||||
{
|
||||
kPVRTextureFlagTypePVRTC_2 = 12,
|
||||
kPVRTextureFlagTypePVRTC_4,
|
||||
kPVRTextureFlagTypeOGLPVRTC_2 = 24,
|
||||
kPVRTextureFlagTypeOGLPVRTC_4
|
||||
};
|
||||
|
||||
typedef struct _PVRTexHeader
|
||||
{
|
||||
uint32_t headerLength;
|
||||
uint32_t height;
|
||||
uint32_t width;
|
||||
uint32_t numMipmaps;
|
||||
uint32_t flags;
|
||||
uint32_t dataLength;
|
||||
uint32_t bpp;
|
||||
uint32_t bitmaskRed;
|
||||
uint32_t bitmaskGreen;
|
||||
uint32_t bitmaskBlue;
|
||||
uint32_t bitmaskAlpha;
|
||||
uint32_t pvrTag;
|
||||
uint32_t numSurfs;
|
||||
|
||||
typedef unsigned char * BytePtr;
|
||||
|
||||
bool needsBytesSwapped()
|
||||
{
|
||||
union {
|
||||
int testWord;
|
||||
char testByte[sizeof(int)];
|
||||
}endianTest;
|
||||
endianTest.testWord = 1;
|
||||
if( endianTest.testByte[0] == 1 )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void swapBytes( T &s )
|
||||
{
|
||||
if( sizeof( T ) == 1 )
|
||||
return;
|
||||
|
||||
T d = s;
|
||||
BytePtr sptr = (BytePtr)&s;
|
||||
BytePtr dptr = &(((BytePtr)&d)[sizeof(T)-1]);
|
||||
|
||||
for( unsigned int i = 0; i < sizeof(T); i++ )
|
||||
*(sptr++) = *(dptr--);
|
||||
}
|
||||
|
||||
void swapBytes()
|
||||
{
|
||||
swapBytes(headerLength);
|
||||
swapBytes(height);
|
||||
swapBytes(width);
|
||||
swapBytes(numMipmaps);
|
||||
swapBytes(flags);
|
||||
swapBytes(dataLength);
|
||||
swapBytes(bpp);
|
||||
swapBytes(bitmaskRed);
|
||||
swapBytes(bitmaskGreen);
|
||||
swapBytes(bitmaskBlue);
|
||||
swapBytes(bitmaskAlpha);
|
||||
swapBytes(pvrTag);
|
||||
swapBytes(numSurfs);
|
||||
}
|
||||
|
||||
} PVRTexHeader;
|
||||
|
||||
|
||||
class ReaderWriterPVR : public osgDB::ReaderWriter
|
||||
{
|
||||
public:
|
||||
|
||||
ReaderWriterPVR()
|
||||
{
|
||||
supportsExtension("pvr","PVR image format");
|
||||
}
|
||||
|
||||
virtual const char* className() const { return "PVR Image Reader/Writer"; }
|
||||
|
||||
|
||||
ReadResult readPVRStream(std::istream& fin) const
|
||||
{
|
||||
PVRTexHeader header;
|
||||
|
||||
fin.read((char*)&header, sizeof(PVRTexHeader));
|
||||
if(!fin.good()){
|
||||
osg::notify(osg::WARN) << "Failed to read pvr header." << std::endl;
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
|
||||
if(header.needsBytesSwapped())
|
||||
header.swapBytes();
|
||||
|
||||
if(gPVRTexIdentifier[0] != static_cast<char>((header.pvrTag >> 0) & 0xff) ||
|
||||
gPVRTexIdentifier[1] != static_cast<char>((header.pvrTag >> 8) & 0xff) ||
|
||||
gPVRTexIdentifier[2] != static_cast<char>((header.pvrTag >> 16) & 0xff) ||
|
||||
gPVRTexIdentifier[3] != static_cast<char>((header.pvrTag >> 24) & 0xff))
|
||||
{
|
||||
osg::notify(osg::WARN) << "Failed to verify pvr header: " << ((header.pvrTag >> 0) & 0xff) << ", " << ((header.pvrTag >> 8) & 0xff) << ", " << ((header.pvrTag >> 16) & 0xff) << ", " << ((header.pvrTag >> 24) & 0xff) << std::endl;
|
||||
return ReadResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
uint32_t formatFlags = header.flags & PVR_TEXTURE_FLAG_TYPE_MASK;
|
||||
GLenum internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
|
||||
uint32_t width, height;
|
||||
bool hasAlpha;
|
||||
|
||||
if(formatFlags == kPVRTextureFlagTypePVRTC_4 || formatFlags == kPVRTextureFlagTypePVRTC_2 ||
|
||||
formatFlags == kPVRTextureFlagTypeOGLPVRTC_4 || formatFlags == kPVRTextureFlagTypeOGLPVRTC_2){
|
||||
if(formatFlags == kPVRTextureFlagTypePVRTC_4 || formatFlags == kPVRTextureFlagTypeOGLPVRTC_4)
|
||||
internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
|
||||
else if(formatFlags == kPVRTextureFlagTypePVRTC_2 || formatFlags == kPVRTextureFlagTypeOGLPVRTC_2)
|
||||
internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
|
||||
|
||||
width = header.width;
|
||||
height = header.height;
|
||||
|
||||
if(header.bitmaskAlpha)
|
||||
hasAlpha = true;
|
||||
else
|
||||
hasAlpha = false;
|
||||
|
||||
osg::Image *image = new osg::Image;
|
||||
unsigned char *imageData = new unsigned char[header.dataLength];
|
||||
fin.read((char*)imageData, header.dataLength);
|
||||
if(!fin.good())
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
|
||||
image->setImage(header.width, header.height, 1,
|
||||
internalFormat, internalFormat,
|
||||
GL_UNSIGNED_BYTE,
|
||||
imageData,
|
||||
osg::Image::USE_NEW_DELETE);
|
||||
|
||||
uint32_t dataOffset = 0;
|
||||
uint32_t blockSize = 0, widthBlocks = 0, heightBlocks = 0;
|
||||
uint32_t bpp = 4;
|
||||
|
||||
osg::Image::MipmapDataType mipmapdata;
|
||||
|
||||
// Calculate the data size for each texture level and respect the minimum number of blocks
|
||||
while(dataOffset < header.dataLength){
|
||||
if(formatFlags == kPVRTextureFlagTypePVRTC_4 || formatFlags == kPVRTextureFlagTypeOGLPVRTC_4){
|
||||
blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
|
||||
widthBlocks = width / 4;
|
||||
heightBlocks = height / 4;
|
||||
bpp = 4;
|
||||
}else{
|
||||
blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
|
||||
widthBlocks = width / 8;
|
||||
heightBlocks = height / 4;
|
||||
bpp = 2;
|
||||
}
|
||||
|
||||
// Clamp to minimum number of blocks
|
||||
if(widthBlocks < 2)
|
||||
widthBlocks = 2;
|
||||
if(heightBlocks < 2)
|
||||
heightBlocks = 2;
|
||||
|
||||
if(dataOffset > 0)
|
||||
mipmapdata.push_back(dataOffset);
|
||||
|
||||
dataOffset += widthBlocks * heightBlocks * ((blockSize * bpp) / 8);
|
||||
|
||||
width = std::max(width >> 1, (uint32_t)1);
|
||||
height = std::max(height >> 1, (uint32_t)1);
|
||||
}
|
||||
|
||||
if(!mipmapdata.empty())
|
||||
image->setMipmapLevels(mipmapdata);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
osg::notify(osg::WARN) << "Failed to read pvr data." << std::endl;
|
||||
return ReadResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
|
||||
virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const
|
||||
{
|
||||
return readImage(fin, options);
|
||||
}
|
||||
|
||||
virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
|
||||
{
|
||||
return readImage(file, options);
|
||||
}
|
||||
|
||||
virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const
|
||||
{
|
||||
return readPVRStream(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 = readPVRStream(istream);
|
||||
if(rr.validImage()) rr.getImage()->setFileName(file);
|
||||
return rr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// now register with Registry to instantiate the above
|
||||
// reader/writer.
|
||||
REGISTER_OSGPLUGIN(pvr, ReaderWriterPVR)
|
Loading…
Reference in New Issue
Block a user