From James Athey, "I've attached a new osgDB ReaderWriter that can read Khronos Texture Files
(KTX). The KTX file format is straightforward and designed to be easy to use in OpenGL. http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ http://www.khronos.org/opengles/sdk/tools/KTX/ The attached plugin can read: * 1D, 2D, and 3D textures * uncompressed and compressed images * mipmapped and non-mipmapped textures * little-endian and big-endian files * textures from files as well as seekable istream objects It does not handle: * array textures (not supported by the ReaderWriter API) * cubemap textures (not supported by the ReaderWriter API) * the "KTXorientation" key-value pair; support could be added later (see the file format spec for more information) * non-seekable istream objects (would require more complicated memory management) "
This commit is contained in:
@@ -77,6 +77,7 @@ ADD_SUBDIRECTORY(tga)
|
||||
ADD_SUBDIRECTORY(hdr)
|
||||
ADD_SUBDIRECTORY(dot)
|
||||
ADD_SUBDIRECTORY(vtf)
|
||||
ADD_SUBDIRECTORY(ktx)
|
||||
|
||||
IF(JPEG_FOUND)
|
||||
ADD_SUBDIRECTORY(jpeg)
|
||||
|
||||
5
src/osgPlugins/ktx/CMakeLists.txt
Normal file
5
src/osgPlugins/ktx/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
SET(TARGET_SRC ReaderWriterKTX.cpp )
|
||||
SET(TARGET_H ReaderWriterKTX.h)
|
||||
|
||||
#### end var setup ###
|
||||
SETUP_PLUGIN(ktx)
|
||||
225
src/osgPlugins/ktx/ReaderWriterKTX.cpp
Normal file
225
src/osgPlugins/ktx/ReaderWriterKTX.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 2012 APX Labs, LLC
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ReaderWriterKTX.h"
|
||||
#include <osg/Endian>
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include <osgDB/FileUtils>
|
||||
#include <istream>
|
||||
|
||||
const unsigned char ReaderWriterKTX::FileSignature[12] = {
|
||||
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
|
||||
};
|
||||
|
||||
ReaderWriterKTX::ReaderWriterKTX()
|
||||
{
|
||||
supportsExtension("ktx", "KTX image format");
|
||||
}
|
||||
|
||||
const char* ReaderWriterKTX::className() const { return "KTX Image Reader/Writer"; }
|
||||
|
||||
bool ReaderWriterKTX::correctByteOrder(KTXTexHeader& header) const
|
||||
{
|
||||
if (header.endianness == MyEndian)
|
||||
return true;
|
||||
|
||||
if (header.endianness != NotMyEndian)
|
||||
return false;
|
||||
|
||||
for (uint32_t* ptr = &header.glType; ptr <= &header.bytesOfKeyValueData; ++ptr) {
|
||||
osg::swapBytes4(reinterpret_cast<char*>(ptr));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin) const
|
||||
{
|
||||
KTXTexHeader header;
|
||||
fin.seekg(0, std::ios::end);
|
||||
uint32_t fileLength = fin.tellg();
|
||||
fin.seekg(0, std::ios::beg);
|
||||
|
||||
//read in the data for the header and store it
|
||||
fin.read((char*)&header, sizeof(KTXTexHeader));
|
||||
if(!fin.good())
|
||||
{
|
||||
OSG_WARN << "Failed to read KTX header." << std::endl;
|
||||
return ReadResult(ReadResult::ERROR_IN_READING_FILE);
|
||||
}
|
||||
|
||||
//verify that the file is a ktx file from its identifier
|
||||
if (memcmp(header.identifier, FileSignature, sizeof(FileSignature)))
|
||||
{
|
||||
OSG_WARN << "Failed to verify KTX header." << std::endl;
|
||||
return ReadResult(ReadResult::FILE_NOT_HANDLED);
|
||||
}
|
||||
|
||||
//correct the byte order if the endianess doesn't match
|
||||
if(correctByteOrder(header) == false)
|
||||
{
|
||||
OSG_WARN << "Corrupt KTX header (invalid endianness marker)" << std::endl;
|
||||
return ReadResult(ReadResult::FILE_NOT_HANDLED);
|
||||
}
|
||||
|
||||
if(header.glFormat == 0)
|
||||
header.glFormat = header.glInternalFormat;
|
||||
|
||||
// KTX sets height to 0 for 1D textures, and depth to 0 for both 1D and 2D textures.
|
||||
// OpenSceneGraph expects textures to have non-zero dimensions
|
||||
if (header.pixelHeight == 0)
|
||||
header.pixelHeight = 1;
|
||||
if (header.pixelDepth == 0)
|
||||
header.pixelDepth = 1;
|
||||
|
||||
if(header.numberOfArrayElements != 0)
|
||||
{
|
||||
OSG_WARN << "Array textures in KTX files are not supported." << std::endl;
|
||||
return ReadResult(ReadResult::FILE_NOT_HANDLED);
|
||||
}
|
||||
|
||||
if(header.numberOfFaces != 1) //if this is a cube map
|
||||
{
|
||||
OSG_WARN << "Cube maps cannot be read directly from KTX files." << std::endl;
|
||||
return ReadResult(ReadResult::FILE_NOT_HANDLED);
|
||||
}
|
||||
|
||||
if (header.numberOfMipmapLevels == 0)
|
||||
header.numberOfMipmapLevels = 1;
|
||||
|
||||
//read keyvalue data. Will be ignoring for now
|
||||
fin.ignore(header.bytesOfKeyValueData);
|
||||
|
||||
uint32_t imageSize;
|
||||
uint32_t totalImageSize = fileLength -
|
||||
(sizeof(KTXTexHeader) + header.bytesOfKeyValueData +
|
||||
(sizeof(imageSize) * header.numberOfMipmapLevels));
|
||||
|
||||
unsigned char* totalImageData = new unsigned char[totalImageSize];
|
||||
if (!totalImageData)
|
||||
return ReadResult::INSUFFICIENT_MEMORY_TO_LOAD;
|
||||
|
||||
char* imageData = (char*)totalImageData;
|
||||
bool byteswapImageData = (header.glTypeSize > 1) && (header.endianness != MyEndian);
|
||||
|
||||
uint32_t totalOffset = 0;
|
||||
osg::Image::MipmapDataType mipmapData;
|
||||
|
||||
for(uint32_t mipmapLevel = 0; mipmapLevel < header.numberOfMipmapLevels; mipmapLevel++)
|
||||
{
|
||||
fin.read((char*)&imageSize, sizeof(imageSize));
|
||||
if(!fin.good())
|
||||
{
|
||||
OSG_WARN << "Failed to read Image Data." << std::endl;
|
||||
delete[] totalImageData;
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
if (header.endianness != MyEndian)
|
||||
osg::swapBytes4(reinterpret_cast<char*>(&imageSize));
|
||||
|
||||
fin.read(imageData, imageSize);
|
||||
if(!fin.good())
|
||||
{
|
||||
OSG_WARN << "Failed to read Image Data." << std::endl;
|
||||
delete[] totalImageData;
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
|
||||
if (byteswapImageData)
|
||||
{
|
||||
char* endData = imageData + imageSize;
|
||||
if (header.glTypeSize == 4)
|
||||
{
|
||||
for(char* longData = imageData; longData < endData; longData += 4)
|
||||
{
|
||||
osg::swapBytes4(longData);
|
||||
}
|
||||
}
|
||||
else if (header.glTypeSize == 2)
|
||||
{
|
||||
for(char* shortData = imageData; shortData < endData; shortData += 2)
|
||||
{
|
||||
osg::swapBytes2(shortData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mipmapLevel > 0)
|
||||
mipmapData.push_back(totalOffset);
|
||||
|
||||
//move the offset to the next imageSize data
|
||||
totalOffset += imageSize;
|
||||
|
||||
// advance buffer pointer to read next mipmap level
|
||||
imageData += imageSize;
|
||||
|
||||
if (mipmapLevel < (header.numberOfMipmapLevels - 1))
|
||||
{
|
||||
uint32_t mipPadding = 3 - (imageSize + 3) % 4;
|
||||
if (mipPadding > 0)
|
||||
{
|
||||
fin.read(imageData, mipPadding);
|
||||
imageData += mipPadding;
|
||||
totalOffset += mipPadding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Image> image = new osg::Image;
|
||||
if (!image.valid())
|
||||
{
|
||||
delete[] totalImageData;
|
||||
return ReadResult::INSUFFICIENT_MEMORY_TO_LOAD;
|
||||
}
|
||||
|
||||
image->setImage(header.pixelWidth, header.pixelHeight, header.pixelDepth,
|
||||
header.glInternalFormat, header.glFormat,
|
||||
header.glType, totalImageData, osg::Image::USE_NEW_DELETE);
|
||||
|
||||
if (header.numberOfMipmapLevels > 1)
|
||||
image->setMipmapLevels(mipmapData);
|
||||
|
||||
return image.get();
|
||||
}
|
||||
|
||||
|
||||
osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readImage(std::istream& fin,const osgDB::ReaderWriter::Options*) const
|
||||
{
|
||||
return readKTXStream(fin);
|
||||
}
|
||||
|
||||
|
||||
osgDB::ReaderWriter::ReadResult ReaderWriterKTX::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::ERROR_IN_READING_FILE;
|
||||
|
||||
ReadResult rr = readKTXStream(istream);
|
||||
if(rr.validImage())
|
||||
rr.getImage()->setFileName(file);
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
||||
// now register with Registry to instantiate the above
|
||||
// reader/writer.
|
||||
REGISTER_OSGPLUGIN(ktx, ReaderWriterKTX)
|
||||
52
src/osgPlugins/ktx/ReaderWriterKTX.h
Normal file
52
src/osgPlugins/ktx/ReaderWriterKTX.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 2012 APX Labs, LLC
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <osgDB/ReaderWriter>
|
||||
#include <stdint.h>
|
||||
|
||||
struct KTXTexHeader
|
||||
{
|
||||
uint8_t identifier[12];
|
||||
uint32_t endianness;
|
||||
uint32_t glType;
|
||||
uint32_t glTypeSize;
|
||||
uint32_t glFormat;
|
||||
uint32_t glInternalFormat;
|
||||
uint32_t glBaseInternalFormat;
|
||||
uint32_t pixelWidth;
|
||||
uint32_t pixelHeight;
|
||||
uint32_t pixelDepth;
|
||||
uint32_t numberOfArrayElements;
|
||||
uint32_t numberOfFaces;
|
||||
uint32_t numberOfMipmapLevels;
|
||||
uint32_t bytesOfKeyValueData;
|
||||
};
|
||||
|
||||
|
||||
class ReaderWriterKTX : public osgDB::ReaderWriter
|
||||
{
|
||||
public:
|
||||
static const unsigned char FileSignature[12];
|
||||
static const uint32_t MyEndian = 0x04030201;
|
||||
static const uint32_t NotMyEndian = 0x01020304;
|
||||
|
||||
ReaderWriterKTX();
|
||||
|
||||
virtual const char* className() const;
|
||||
virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const;
|
||||
virtual ReadResult readKTXStream(std::istream& fin) const;
|
||||
virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const;
|
||||
|
||||
private:
|
||||
bool correctByteOrder(KTXTexHeader& header) const;
|
||||
};
|
||||
Reference in New Issue
Block a user