1313
1414#include " ReaderWriterKTX.h"
1515#include < osg/Endian>
16+ #include < osg/ValueObject>
1617#include < osgDB/FileNameUtils>
1718#include < osgDB/FileUtils>
1819#include < istream>
1920#include < vector>
2021#include < cstring>
22+ #include < map>
2123
2224// Macro similar to what's in FLT/TRP plugins (except it uses wide char under Windows if OSG_USE_UTF8_FILENAME)
2325#if defined(_WIN32)
@@ -117,9 +119,8 @@ osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin
117119 if (header.numberOfMipmapLevels == 0 )
118120 header.numberOfMipmapLevels = 1 ;
119121
120- // Parse key-value metadata to check for KTXorientation
121- bool hasValidOrientation = true ; // Default to true for non-ASTC or when no metadata
122- std::string ktxOrientation;
122+ // Parse key-value metadata
123+ std::map<std::string, std::string> ktxMetadata;
123124
124125 if (header.bytesOfKeyValueData > 0 )
125126 {
@@ -158,20 +159,18 @@ osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin
158159 {
159160 key = std::string (kvData.data () + keyStart, keyEnd - keyStart);
160161
161- // Check for KTXorientation (note: some files incorrectly use KTXOrientation)
162- if (key == " KTXorientation" || key == " KTXOrientation" )
163- {
164- size_t valueStart = keyEnd + 1 ;
165- size_t valueSize = keyAndValueByteSize - (valueStart - keyStart);
166- ktxOrientation = std::string (kvData.data () + valueStart, valueSize);
162+ // Extract the value (everything after the null terminator)
163+ size_t valueStart = keyEnd + 1 ;
164+ size_t valueSize = keyAndValueByteSize - (valueStart - keyStart);
165+ std::string value (kvData.data () + valueStart, valueSize);
167166
168- // Remove any trailing null bytes
169- size_t nullPos = ktxOrientation .find (' \0 ' );
170- if (nullPos != std::string::npos)
171- ktxOrientation = ktxOrientation .substr (0 , nullPos);
167+ // Remove any trailing null bytes from the value
168+ size_t nullPos = value .find (' \0 ' );
169+ if (nullPos != std::string::npos)
170+ value = value .substr (0 , nullPos);
172171
173- OSG_INFO << " Found KTXorientation: " << ktxOrientation << std::endl;
174- }
172+ // Store the metadata
173+ ktxMetadata[key] = value;
175174 }
176175
177176 // Align to 4 bytes
@@ -186,20 +185,6 @@ osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin
186185 fin.ignore (0 );
187186 }
188187
189- // Warn about orientation issues
190- if (ktxOrientation.empty ())
191- {
192- OSG_WARN << " KTX file lacks KTXorientation metadata. OpenSceneGraph expects KTX textures "
193- << " in OpenGL orientation (S=r,T=u). Textures created for DirectX/Vulkan (S=r,T=d) "
194- << " may appear vertically flipped." << std::endl;
195- }
196- else if (ktxOrientation == " S=r,T=d" || ktxOrientation == " S=r,T=d,R=i" || ktxOrientation == " S=r,T=d,R=o" )
197- {
198- OSG_WARN << " KTX file has DirectX/Vulkan orientation (" << ktxOrientation
199- << " ). OpenSceneGraph expects OpenGL orientation (S=r,T=u). "
200- << " Texture may appear vertically flipped." << std::endl;
201- }
202-
203188 uint32_t imageSize;
204189 uint32_t totalImageSize = fileLength -
205190 (sizeof (KTXTexHeader) + header.bytesOfKeyValueData +
@@ -295,7 +280,13 @@ osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin
295280 // Set origin based on KTXorientation metadata
296281 // S=r,T=u means OpenGL orientation (bottom-left origin)
297282 // S=r,T=d means standard image orientation (top-left origin)
298- if (ktxOrientation == " S=r,T=u" || ktxOrientation == " S=r,T=u,R=o" )
283+ // Note: some files incorrectly use KTXOrientation with capital O
284+ auto orientIt = ktxMetadata.find (" KTXorientation" );
285+ if (orientIt == ktxMetadata.end ())
286+ orientIt = ktxMetadata.find (" KTXOrientation" );
287+
288+ if (orientIt != ktxMetadata.end () &&
289+ (orientIt->second == " S=r,T=u" || orientIt->second == " S=r,T=u,R=o" ))
299290 {
300291 image->setOrigin (osg::Image::BOTTOM_LEFT );
301292 }
@@ -308,6 +299,13 @@ osgDB::ReaderWriter::ReadResult ReaderWriterKTX::readKTXStream(std::istream& fin
308299 if (header.numberOfMipmapLevels > 1 )
309300 image->setMipmapLevels (mipmapData);
310301
302+ // Store all KTX metadata in the image's userdata with "KTX:" prefix
303+ // This avoids conflicts with other OSG metadata
304+ for (const auto & kv : ktxMetadata)
305+ {
306+ image->setUserValue (" KTX:" + kv.first , kv.second );
307+ }
308+
311309 return image.get ();
312310}
313311
0 commit comments