diff options
-rw-r--r-- | DevIL/src-IL/src/il_dds.cpp | 24 | ||||
-rw-r--r-- | DevIL/src-IL/src/il_ktx.cpp | 157 | ||||
-rw-r--r-- | DevIL/src-IL/src/il_states.cpp | 3 |
3 files changed, 158 insertions, 26 deletions
diff --git a/DevIL/src-IL/src/il_dds.cpp b/DevIL/src-IL/src/il_dds.cpp index daaec723..46e64344 100644 --- a/DevIL/src-IL/src/il_dds.cpp +++ b/DevIL/src-IL/src/il_dds.cpp @@ -409,33 +409,40 @@ ILboolean iLoadDdsInternal() CompData = NULL; Image = NULL; - if (iCurImage == NULL) { + if (iCurImage == NULL) + { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } - if (!iGetDdsHead(&Head)) { + if (!iGetDdsHead(&Head)) + { ilSetError(IL_INVALID_FILE_HEADER); return IL_FALSE; } - if (!iCheckDds(&Head)) { + if (!iCheckDds(&Head)) + { ilSetError(IL_INVALID_FILE_HEADER); return IL_FALSE; } BlockSize = DecodePixelFormat(&CompFormat); - if (CompFormat == PF_UNKNOWN) { + if (CompFormat == PF_UNKNOWN) + { ilSetError(IL_INVALID_FILE_HEADER); return IL_FALSE; } - if (CompFormat == PF_DX10) { + if (CompFormat == PF_DX10) + { IsDXT10 = IL_TRUE; - if (!iGetDXT10Head(&HeadDXT10)) { + if (!iGetDXT10Head(&HeadDXT10)) + { ilSetError(IL_INVALID_FILE_HEADER); return IL_FALSE; } - if (!iCheckDxt10(&HeadDXT10)) { + if (!iCheckDxt10(&HeadDXT10)) + { ilSetError(IL_INVALID_FILE_HEADER); return IL_FALSE; } @@ -1121,7 +1128,8 @@ ILboolean ReadMipmaps(ILuint CompFormat, ILboolean IsDXT10) } LastLinear = Head.LinearSize; - for (i = 0; i < Head.MipMapCount - 1; i++) { + for (i = 0; i < Head.MipMapCount - 1; i++) + { Depth = Depth / 2; Width = Width / 2; Height = Height / 2; diff --git a/DevIL/src-IL/src/il_ktx.cpp b/DevIL/src-IL/src/il_ktx.cpp index c424810a..51db2da6 100644 --- a/DevIL/src-IL/src/il_ktx.cpp +++ b/DevIL/src-IL/src/il_ktx.cpp @@ -19,6 +19,8 @@ ILboolean iIsValidKtx(void); ILboolean iLoadKtxInternal(); +ILboolean iKtxReadMipmaps(ILboolean Compressed, ILuint NumMips, ILenum Origin); +ILboolean iKtxKeyValueData(ILuint bytesOfKeyValueData, ILenum &Origin); #ifdef _MSC_VER @@ -185,7 +187,7 @@ ILboolean iLoadKtxInternal() { KTX_HEAD Header; ILuint imageSize; - ILenum Format, Type; + ILenum Format, Type, Origin; ILubyte Bpp, Bpc; ILboolean Compressed; char FileIdentifier[12] = { @@ -217,30 +219,31 @@ ILboolean iLoadKtxInternal() Header.numberOfFaces = GetLittleUInt(); Header.numberOfMipmapLevels = GetLittleUInt(); Header.bytesOfKeyValueData = GetLittleUInt(); - imageSize = GetLittleUInt(); if (memcmp(Header.identifier, FileIdentifier, 12) || Header.endianness != 0x04030201) { ilSetError(IL_ILLEGAL_FILE_VALUE); return IL_FALSE; } - if (Header.glTypeSize != 1) { //@TODO: Cases when this is different? + if (Header.glTypeSize != 1) //@TODO: Cases when this is different? + { ilSetError(IL_ILLEGAL_FILE_VALUE); return IL_FALSE; } //@TODO: Really needed? - /*if (Header.glInternalFormat != Header.glFormat || Header.glBaseInternalFormat != Header.glFormat) { + /*if (Header.glInternalFormat != Header.glFormat || Header.glBaseInternalFormat != Header.glFormat) + { ilSetError(IL_ILLEGAL_FILE_VALUE); return IL_FALSE; }*/ //@TODO: Mipmaps, etc. - if (Header.numberOfArrayElements != 0 || Header.numberOfFaces != 1 || Header.numberOfMipmapLevels != 1) { + if (Header.numberOfArrayElements != 0 || Header.numberOfFaces != 1 /*|| Header.numberOfMipmapLevels != 1*/) + { ilSetError(IL_ILLEGAL_FILE_VALUE); return IL_FALSE; } - //@TODO: Parse this data - if (iseek(Header.bytesOfKeyValueData, IL_SEEK_CUR)) + if (!iKtxKeyValueData(Header.bytesOfKeyValueData, Origin)) return IL_FALSE; //@TODO: Additional formats @@ -289,11 +292,6 @@ ILboolean iLoadKtxInternal() } } - if (!ilTexImage(Header.pixelWidth, Header.pixelHeight, 1, Bpp, Format, Type, NULL)) { - return IL_FALSE; - } - iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; - if (!Compressed) { //@TODO: Additional types @@ -307,20 +305,31 @@ ILboolean iLoadKtxInternal() Bpc = 2; Type = IL_HALF; break; + //case I_GL_SHORT: default: ilSetError(IL_ILLEGAL_FILE_VALUE); return IL_FALSE; } - if (imageSize != Header.pixelWidth * Header.pixelHeight * Bpp * Bpc) { + if (!ilTexImage(Header.pixelWidth, Header.pixelHeight, 1, Bpp, Format, Type, NULL)) + return IL_FALSE; + if (!iKtxReadMipmaps(Compressed, Header.numberOfMipmapLevels, Origin)) + return IL_FALSE; + } + else // Compressed formats require different handling + { + //@TODO: Add support for compressed mipmaps + if (Header.numberOfMipmapLevels != 1) + { ilSetError(IL_ILLEGAL_FILE_VALUE); return IL_FALSE; } - if (iread(iCurImage->Data, Bpp*Bpc, Header.pixelWidth * Header.pixelHeight) != Header.pixelWidth * Header.pixelHeight) + imageSize = GetLittleUInt(); + + if (!ilTexImage(Header.pixelWidth, Header.pixelHeight, 1, Bpp, Format, Type, NULL)) return IL_FALSE; - } - else { // Compressed formats require different handling + switch (Header.glInternalFormat) { case I_GL_ETC1_RGB8_OES: @@ -359,11 +368,125 @@ ILboolean iLoadKtxInternal() ifree(FullBuffer); break; } - //return IL_FALSE; + + iCurImage->Origin = Origin; //@TODO: Correct for all? } return ilFixImage(); } +// There are multiple items that can be in the key values, but all we care about +// right now is the orientation/origin data. +ILboolean iKtxKeyValueData(ILuint bytesOfKeyValueData, ILenum &Origin) +{ + ILubyte *KeyValueData; + ILuint Pos = 0, Length; + + Origin = IL_ORIGIN_UPPER_LEFT; // KTX specs declare that this is the default + + if (bytesOfKeyValueData == 0) + return IL_TRUE; + + KeyValueData = (ILubyte*)ialloc(bytesOfKeyValueData); + if (KeyValueData == NULL) + return IL_FALSE; + + if (iread(KeyValueData, 1, bytesOfKeyValueData) != bytesOfKeyValueData) + return IL_FALSE; + + // Just a very rudimentary check on the origin values + while (Pos < bytesOfKeyValueData) + { + Length = *((ILuint*)&KeyValueData[Pos]); + if (Length >= 22) // Size needed for the KTXorientation key + { + if (!strncmp((const char*)&KeyValueData[Pos+4], "KTXorientation", 14)) + { + // Found the orientation key we need + ILubyte TopDownOrient = KeyValueData[Pos+25]; + if (TopDownOrient == 'd') + Origin = IL_ORIGIN_UPPER_LEFT; + else if (TopDownOrient == 'u') + Origin = IL_ORIGIN_LOWER_LEFT; + } + } + + Pos += Length; + if (Pos >= bytesOfKeyValueData) + break; + } + + ifree(KeyValueData); + + return IL_TRUE; +} + + +ILboolean iKtxReadMipmaps(ILboolean Compressed, ILuint NumMips, ILenum Origin) +{ + ILimage *Image = iCurImage; + ILuint Width = iCurImage->Width, Height = iCurImage->Height; + ILuint imageSize, Padding, Pos; + + for (ILuint Mip = 0; Mip < NumMips; Mip++) + { + imageSize = GetLittleUInt(); + Padding = 3 - ((Image->Bps + 3) % 4); + + if (imageSize != Image->SizeOfData + Padding*Image->Height) + { + ilSetError(IL_ILLEGAL_FILE_VALUE); + goto mip_fail; + } + + // Note: The KTX spec at https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ + // seems to imply dword-alignment of the entire image, but this is per scanline. + if (Image->Bps % 4 == 0) // Required to be dword-aligned + { + if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData) + return IL_FALSE; + } + else // Since not dword-aligned, have to read each line separately. + { + Pos = 0; + for (ILuint h = 0; h < Height; h++) + { + if (iread(&Image->Data[Pos], 1, Image->Bps) != Image->Bps) + return IL_FALSE; + iseek(Padding, IL_SEEK_CUR); + Pos += Image->Bps; + } + } + + Image->Origin = Origin; + Width = Width / 2; + Height = Height / 2; + + if (Mip < NumMips - 1) + { + Image->Mipmaps = ilNewImage(Width, Height, 1, Image->Bpp, Image->Bpc); + if (Image->Mipmaps == NULL) + goto mip_fail; + Image->Mipmaps->Format = Image->Format; + Image->Mipmaps->Type = Image->Type; + Image = Image->Mipmaps; + } + } + + return IL_TRUE; + +mip_fail: + Image = iCurImage; + ILimage *StartImage = Image->Mipmaps, *TempImage; + while (StartImage) { + TempImage = StartImage; + StartImage = StartImage->Mipmaps; + ifree(TempImage); + } + + Image->Mipmaps = NULL; + return IL_FALSE; +} + #endif//IL_NO_KTX diff --git a/DevIL/src-IL/src/il_states.cpp b/DevIL/src-IL/src/il_states.cpp index 974ebe02..752624bd 100644 --- a/DevIL/src-IL/src/il_states.cpp +++ b/DevIL/src-IL/src/il_states.cpp @@ -419,7 +419,8 @@ void ILAPIENTRY ilGetIntegerv(ILenum Mode, ILint *Param) *Param = 0; - switch (Mode) { + switch (Mode) + { // Integer values case IL_COMPRESS_MODE: *Param = ilStates[ilCurrentPos].ilCompression; |