Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/osg/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -806,15 +806,15 @@ unsigned int Image::computePixelSizeInBits(GLenum format,GLenum type)
{
osg::Vec3i footprint = computeBlockFootprint(format);
unsigned int pixelsPerBlock = footprint.x() * footprint.y();
unsigned int bitsPerBlock = computeBlockSize(format, 0);//16 x 8 = 128
unsigned int bitsPerBlock = computeBlockSize(format, 0) * 8; // Convert bytes to bits
unsigned int bitsPerPixel = bitsPerBlock / pixelsPerBlock;
if (bitsPerBlock == bitsPerPixel * pixelsPerBlock) {
OSG_WARN << "Image::computePixelSizeInBits(format,type) : bits per pixel (" << bitsPerPixel << ") is not an integer for GL_KHR_texture_compression_astc_hdr sizes other than 4x4 and 8x8." << std::endl;
// Integer division worked perfectly
return bitsPerPixel;
} else {
OSG_WARN << "Image::computePixelSizeInBits(format,type) : bits per pixel (" << bitsPerBlock << "/" << pixelsPerBlock << ") is not an integer for GL_KHR_texture_compression_astc_hdr size" << footprint.x() << "x" << footprint.y() << "." << std::endl;
return 0;
}
return 0;
}
default: break;
}
Expand Down Expand Up @@ -1827,6 +1827,7 @@ void Image::flipVertical()

const bool dxtc(dxtc_tool::isDXTC(_pixelFormat));
const bool rgtc(dxtc_tool::isRGTC(_pixelFormat));

if (_mipmapData.empty())
{
// no mipmaps,
Expand All @@ -1842,7 +1843,7 @@ void Image::flipVertical()
}
else
{
if (isCompressed()) OSG_NOTICE << "Notice Image::flipVertical(): image is compressed but normal v-flip is used" << std::endl;
if (isCompressed()) OSG_NOTICE << "Notice Image::flipVertical(): file=" << _fileName << " image is compressed but normal v-flip is used" << std::endl;
// its not a compressed image, so implement flip oursleves.
unsigned char* top = data(0,0,r);
unsigned char* bottom = top + (_t-1)*rowStep;
Expand Down
28 changes: 14 additions & 14 deletions src/osg/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1995,85 +1995,85 @@ void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_4x4_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR)
{
blockSize = 16;
size = ceil(width/4.0)*ceil(height/4.0)*blockSize;
size = ((width+3)/4)*((height+3)/4)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_5x4_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR)
{
blockSize = 16;
size = ceil(width/5.0)*ceil(height/4.0)*blockSize;
size = ((width+4)/5)*((height+3)/4)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_5x5_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR)
{
blockSize = 16;
size = ceil(width/5.0)*ceil(height/5.0)*blockSize;
size = ((width+4)/5)*((height+4)/5)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_6x5_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR)
{
blockSize = 16;
size = ceil(width/6.0)*ceil(height/5.0)*blockSize;
size = ((width+5)/6)*((height+4)/5)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_6x6_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR)
{
blockSize = 16;
size = ceil(width/6.0)*ceil(height/6.0)*blockSize;
size = ((width+5)/6)*((height+5)/6)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_8x5_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR)
{
blockSize = 16;
size = ceil(width/8.0)*ceil(height/5.0)*blockSize;
size = ((width+7)/8)*((height+4)/5)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_8x6_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR)
{
blockSize = 16;
size = ceil(width/8.0)*ceil(height/6.0)*blockSize;
size = ((width+7)/8)*((height+5)/6)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_8x8_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR)
{
blockSize = 16;
size = ceil(width/8.0)*ceil(height/8.0)*blockSize;
size = ((width+7)/8)*((height+7)/8)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_10x5_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR)
{
blockSize = 16;
size = ceil(width/10.0)*ceil(height/5.0)*blockSize;
size = ((width+9)/10)*((height+4)/5)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_10x6_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR)
{
blockSize = 16;
size = ceil(width/10.0)*ceil(height/6.0)*blockSize;
size = ((width+9)/10)*((height+5)/6)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_10x8_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR)
{
blockSize = 16;
size = ceil(width/10.0)*ceil(height/8.0)*blockSize;
size = ((width+9)/10)*((height+7)/8)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_10x10_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR)
{
blockSize = 16;
size = ceil(width/10.0)*ceil(height/10.0)*blockSize;
size = ((width+9)/10)*((height+9)/10)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_12x10_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR)
{
blockSize = 16;
size = ceil(width/12.0)*ceil(height/10.0)*blockSize;
size = ((width+11)/12)*((height+9)/10)*depth*blockSize;
return;
}
else if (internalFormat == GL_COMPRESSED_RGBA_ASTC_12x12_KHR || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR)
{
blockSize = 16;
size = ceil(width/12.0)*ceil(height/12.0)*blockSize;
size = ((width+11)/12)*((height+11)/12)*depth*blockSize;
return;
}
else
Expand Down
92 changes: 90 additions & 2 deletions src/osgPlugins/ktx/ReaderWriterKTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@

#include "ReaderWriterKTX.h"
#include <osg/Endian>
#include <osg/ValueObject>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <istream>
#include <vector>
#include <cstring>
#include <map>

// Macro similar to what's in FLT/TRP plugins (except it uses wide char under Windows if OSG_USE_UTF8_FILENAME)
#if defined(_WIN32)
Expand Down Expand Up @@ -115,8 +119,66 @@ osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin
if (header.numberOfMipmapLevels == 0)
header.numberOfMipmapLevels = 1;

//read keyvalue data. Will be ignoring for now
fin.ignore(header.bytesOfKeyValueData);
// Parse key-value metadata
std::map<std::string, std::string> ktxMetadata;

if (header.bytesOfKeyValueData > 0)
{
std::vector<char> kvData(header.bytesOfKeyValueData);
fin.read(kvData.data(), header.bytesOfKeyValueData);
if (!fin.good())
{
OSG_WARN << "Failed to read KTX key-value data." << std::endl;
return ReadResult(ReadResult::ERROR_IN_READING_FILE);
}

// Parse key-value pairs
size_t offset = 0;
while (offset < header.bytesOfKeyValueData)
{
if (offset + sizeof(uint32_t) > header.bytesOfKeyValueData)
break;

uint32_t keyAndValueByteSize;
memcpy(&keyAndValueByteSize, kvData.data() + offset, sizeof(uint32_t));
if (header.endianness != MyEndian)
osg::swapBytes4(reinterpret_cast<char*>(&keyAndValueByteSize));
offset += sizeof(uint32_t);

if (offset + keyAndValueByteSize > header.bytesOfKeyValueData)
break;

// Find the null terminator to separate key from value
std::string key;
size_t keyStart = offset;
size_t keyEnd = keyStart;
while (keyEnd < offset + keyAndValueByteSize && kvData[keyEnd] != '\0')
keyEnd++;

if (keyEnd < offset + keyAndValueByteSize)
{
key = std::string(kvData.data() + keyStart, keyEnd - keyStart);

// Extract the value (everything after the null terminator)
size_t valueStart = keyEnd + 1;
size_t valueSize = keyAndValueByteSize - (valueStart - keyStart);
std::string value(kvData.data() + valueStart, valueSize);

// Remove any trailing null bytes from the value
size_t nullPos = value.find('\0');
if (nullPos != std::string::npos)
value = value.substr(0, nullPos);

// Store the metadata
ktxMetadata[key] = value;
}

// Align to 4 bytes
offset += keyAndValueByteSize;
uint32_t padding = (4 - (keyAndValueByteSize % 4)) % 4;
offset += padding;
}
}

uint32_t imageSize;
uint32_t totalImageSize = fileLength -
Expand Down Expand Up @@ -210,9 +272,35 @@ osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin
header.glInternalFormat, header.glFormat,
header.glType, totalImageData, osg::Image::USE_NEW_DELETE);

// Set origin based on KTXorientation metadata
// S=r,T=u means OpenGL orientation (bottom-left origin)
// S=r,T=d means standard image orientation (top-left origin)
// Note: some files incorrectly use KTXOrientation with capital O
auto orientIt = ktxMetadata.find("KTXorientation");
if (orientIt == ktxMetadata.end())
orientIt = ktxMetadata.find("KTXOrientation");

if (orientIt != ktxMetadata.end() &&
(orientIt->second == "S=r,T=u" || orientIt->second == "S=r,T=u,R=o"))
{
image->setOrigin(osg::Image::BOTTOM_LEFT);
}
else
{
// Default to TOP_LEFT for S=r,T=d or when no orientation is specified
image->setOrigin(osg::Image::TOP_LEFT);
}

if (header.numberOfMipmapLevels > 1)
image->setMipmapLevels(mipmapData);

// Store all KTX metadata in the image's userdata with "KTX:" prefix
// This avoids conflicts with other OSG metadata
for (const auto& kv : ktxMetadata)
{
image->setUserValue("KTX:" + kv.first, kv.second);
}

return image.get();
}

Expand Down