Browse Source

Add support of ASTC in the image loader

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
2685285c45

+ 2 - 0
AnKi/Importer/ImageImporter.cpp

@@ -527,6 +527,8 @@ static ANKI_USE_RESULT Error storeAnkiImage(const ImageImporterConfig& config, c
 	header.m_compressionMask = config.m_compressions;
 	header.m_compressionMask = config.m_compressions;
 	header.m_isNormal = false;
 	header.m_isNormal = false;
 	header.m_mipmapCount = ctx.m_mipmaps.getSize();
 	header.m_mipmapCount = ctx.m_mipmaps.getSize();
+	header.m_astcBlockSizeX = config.m_astcBlockSize.x();
+	header.m_astcBlockSizeY = config.m_astcBlockSize.y();
 	ANKI_CHECK(outFile.write(&header, sizeof(header)));
 	ANKI_CHECK(outFile.write(&header, sizeof(header)));
 
 
 	// Write RAW
 	// Write RAW

+ 5 - 1
AnKi/Resource/ImageBinary.h

@@ -63,7 +63,9 @@ public:
 	ImageBinaryDataCompression m_compressionMask;
 	ImageBinaryDataCompression m_compressionMask;
 	U32 m_isNormal;
 	U32 m_isNormal;
 	U32 m_mipmapCount;
 	U32 m_mipmapCount;
-	Array<U8, 88> m_padding;
+	U32 m_astcBlockSizeX;
+	U32 m_astcBlockSizeY;
+	Array<U8, 80> m_padding;
 
 
 	template<typename TSerializer, typename TClass>
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	static void serializeCommon(TSerializer& s, TClass self)
@@ -77,6 +79,8 @@ public:
 		s.doValue("m_compressionMask", offsetof(ImageBinaryHeader, m_compressionMask), self.m_compressionMask);
 		s.doValue("m_compressionMask", offsetof(ImageBinaryHeader, m_compressionMask), self.m_compressionMask);
 		s.doValue("m_isNormal", offsetof(ImageBinaryHeader, m_isNormal), self.m_isNormal);
 		s.doValue("m_isNormal", offsetof(ImageBinaryHeader, m_isNormal), self.m_isNormal);
 		s.doValue("m_mipmapCount", offsetof(ImageBinaryHeader, m_mipmapCount), self.m_mipmapCount);
 		s.doValue("m_mipmapCount", offsetof(ImageBinaryHeader, m_mipmapCount), self.m_mipmapCount);
+		s.doValue("m_astcBlockSizeX", offsetof(ImageBinaryHeader, m_astcBlockSizeX), self.m_astcBlockSizeX);
+		s.doValue("m_astcBlockSizeY", offsetof(ImageBinaryHeader, m_astcBlockSizeY), self.m_astcBlockSizeY);
 		s.doArray("m_padding", offsetof(ImageBinaryHeader, m_padding), &self.m_padding[0], self.m_padding.getSize());
 		s.doArray("m_padding", offsetof(ImageBinaryHeader, m_padding), &self.m_padding[0], self.m_padding.getSize());
 	}
 	}
 
 

+ 3 - 1
AnKi/Resource/ImageBinary.xml

@@ -54,7 +54,9 @@ ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ImageBinaryDataCompression)
 				<member name="m_compressionMask" type="ImageBinaryDataCompression"/>
 				<member name="m_compressionMask" type="ImageBinaryDataCompression"/>
 				<member name="m_isNormal" type="U32"/>
 				<member name="m_isNormal" type="U32"/>
 				<member name="m_mipmapCount" type="U32"/>
 				<member name="m_mipmapCount" type="U32"/>
-				<member name="m_padding" type="U8" array_size="88"/>
+				<member name="m_astcBlockSizeX" type="U32"/>
+				<member name="m_astcBlockSizeY" type="U32"/>
+				<member name="m_padding" type="U8" array_size="80"/>
 			</members>
 			</members>
 		</class>
 		</class>
 	</classes>
 	</classes>

+ 55 - 13
AnKi/Resource/ImageLoader.cpp

@@ -16,7 +16,7 @@ static const U8 tgaHeaderCompressed[12] = {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 
 /// Get the size in bytes of a single surface
 /// Get the size in bytes of a single surface
 static PtrSize calcSurfaceSize(const U32 width32, const U32 height32, const ImageBinaryDataCompression comp,
 static PtrSize calcSurfaceSize(const U32 width32, const U32 height32, const ImageBinaryDataCompression comp,
-							   const ImageBinaryColorFormat cf)
+							   const ImageBinaryColorFormat cf, UVec2 astcBlockSize)
 {
 {
 	const PtrSize width = width32;
 	const PtrSize width = width32;
 	const PtrSize height = height32;
 	const PtrSize height = height32;
@@ -35,6 +35,9 @@ static PtrSize calcSurfaceSize(const U32 width32, const U32 height32, const Imag
 	case ImageBinaryDataCompression::ETC:
 	case ImageBinaryDataCompression::ETC:
 		out = (width / 4) * (height / 4) * 8;
 		out = (width / 4) * (height / 4) * 8;
 		break;
 		break;
+	case ImageBinaryDataCompression::ASTC:
+		out = (width / astcBlockSize.x()) * (height / astcBlockSize.y()) * 16;
+		break;
 	default:
 	default:
 		ANKI_ASSERT(0);
 		ANKI_ASSERT(0);
 	}
 	}
@@ -97,7 +100,9 @@ static PtrSize calcSizeOfSegment(const ImageBinaryHeader& header, ImageBinaryDat
 
 
 		while(mips-- != 0)
 		while(mips-- != 0)
 		{
 		{
-			out += calcSurfaceSize(width, height, comp, header.m_colorFormat) * surfCountPerMip;
+			out += calcSurfaceSize(width, height, comp, header.m_colorFormat,
+								   UVec2(header.m_astcBlockSizeX, header.m_astcBlockSizeY))
+				   * surfCountPerMip;
 
 
 			width /= 2;
 			width /= 2;
 			height /= 2;
 			height /= 2;
@@ -375,12 +380,22 @@ Error ImageLoader::loadAnkiImage(FileInterface& file, U32 maxImageSize,
 		return Error::USER_DATA;
 		return Error::USER_DATA;
 	}
 	}
 
 
-	if((header.m_compressionMask & preferredCompression) == ImageBinaryDataCompression::NONE)
+	if(!!(header.m_compressionMask & ImageBinaryDataCompression::ASTC))
+	{
+		if((header.m_astcBlockSizeX != 8 && header.m_astcBlockSizeX != 4)
+		   || (header.m_astcBlockSizeY != 8 && header.m_astcBlockSizeY != 4))
+		{
+			ANKI_RESOURCE_LOGE("Incorrect header: ASTC block size");
+			return Error::USER_DATA;
+		}
+	}
+
+	if(!(header.m_compressionMask & preferredCompression))
 	{
 	{
 		// Fallback
 		// Fallback
 		preferredCompression = ImageBinaryDataCompression::RAW;
 		preferredCompression = ImageBinaryDataCompression::RAW;
 
 
-		if((header.m_compressionMask & preferredCompression) == ImageBinaryDataCompression::NONE)
+		if(!(header.m_compressionMask & preferredCompression))
 		{
 		{
 			ANKI_RESOURCE_LOGE("File does not contain raw compression");
 			ANKI_RESOURCE_LOGE("File does not contain raw compression");
 			return Error::USER_DATA;
 			return Error::USER_DATA;
@@ -424,6 +439,7 @@ Error ImageLoader::loadAnkiImage(FileInterface& file, U32 maxImageSize,
 	//
 	//
 	// Move file pointer
 	// Move file pointer
 	//
 	//
+	PtrSize skipSize = 0;
 
 
 	if(preferredCompression == ImageBinaryDataCompression::RAW)
 	if(preferredCompression == ImageBinaryDataCompression::RAW)
 	{
 	{
@@ -431,25 +447,50 @@ Error ImageLoader::loadAnkiImage(FileInterface& file, U32 maxImageSize,
 	}
 	}
 	else if(preferredCompression == ImageBinaryDataCompression::S3TC)
 	else if(preferredCompression == ImageBinaryDataCompression::S3TC)
 	{
 	{
-		if((header.m_compressionMask & ImageBinaryDataCompression::RAW) != ImageBinaryDataCompression::NONE)
+		if(!!(header.m_compressionMask & ImageBinaryDataCompression::RAW))
 		{
 		{
 			// If raw compression is present then skip it
 			// If raw compression is present then skip it
-			ANKI_CHECK(file.seek(calcSizeOfSegment(header, ImageBinaryDataCompression::RAW), FileSeekOrigin::CURRENT));
+			skipSize += calcSizeOfSegment(header, ImageBinaryDataCompression::RAW);
 		}
 		}
 	}
 	}
 	else if(preferredCompression == ImageBinaryDataCompression::ETC)
 	else if(preferredCompression == ImageBinaryDataCompression::ETC)
 	{
 	{
-		if((header.m_compressionMask & ImageBinaryDataCompression::RAW) != ImageBinaryDataCompression::NONE)
+		if(!!(header.m_compressionMask & ImageBinaryDataCompression::RAW))
+		{
+			// If raw compression is present then skip it
+			skipSize += calcSizeOfSegment(header, ImageBinaryDataCompression::RAW);
+		}
+
+		if(!!(header.m_compressionMask & ImageBinaryDataCompression::S3TC))
+		{
+			// If s3tc compression is present then skip it
+			skipSize += calcSizeOfSegment(header, ImageBinaryDataCompression::S3TC);
+		}
+	}
+	else if(preferredCompression == ImageBinaryDataCompression::ASTC)
+	{
+		if(!!(header.m_compressionMask & ImageBinaryDataCompression::RAW))
 		{
 		{
 			// If raw compression is present then skip it
 			// If raw compression is present then skip it
-			ANKI_CHECK(file.seek(calcSizeOfSegment(header, ImageBinaryDataCompression::RAW), FileSeekOrigin::CURRENT));
+			skipSize += calcSizeOfSegment(header, ImageBinaryDataCompression::RAW);
 		}
 		}
 
 
-		if((header.m_compressionMask & ImageBinaryDataCompression::S3TC) != ImageBinaryDataCompression::NONE)
+		if(!!(header.m_compressionMask & ImageBinaryDataCompression::S3TC))
 		{
 		{
 			// If s3tc compression is present then skip it
 			// If s3tc compression is present then skip it
-			ANKI_CHECK(file.seek(calcSizeOfSegment(header, ImageBinaryDataCompression::S3TC), FileSeekOrigin::CURRENT));
+			skipSize += calcSizeOfSegment(header, ImageBinaryDataCompression::S3TC);
 		}
 		}
+
+		if(!!(header.m_compressionMask & ImageBinaryDataCompression::ETC))
+		{
+			// If ETC compression is present then skip it
+			skipSize += calcSizeOfSegment(header, ImageBinaryDataCompression::ETC);
+		}
+	}
+
+	if(skipSize)
+	{
+		ANKI_CHECK(file.seek(skipSize, FileSeekOrigin::CURRENT));
 	}
 	}
 
 
 	//
 	//
@@ -470,7 +511,8 @@ Error ImageLoader::loadAnkiImage(FileInterface& file, U32 maxImageSize,
 				for(U32 f = 0; f < faceCount; ++f)
 				for(U32 f = 0; f < faceCount; ++f)
 				{
 				{
 					const U32 dataSize =
 					const U32 dataSize =
-						U32(calcSurfaceSize(mipWidth, mipHeight, preferredCompression, header.m_colorFormat));
+						U32(calcSurfaceSize(mipWidth, mipHeight, preferredCompression, header.m_colorFormat,
+											UVec2(header.m_astcBlockSizeX, header.m_astcBlockSizeY)));
 
 
 					// Check if this mipmap can be skipped because of size
 					// Check if this mipmap can be skipped because of size
 					if(max(mipWidth, mipHeight) <= maxImageSize || mip == header.m_mipmapCount - 1)
 					if(max(mipWidth, mipHeight) <= maxImageSize || mip == header.m_mipmapCount - 1)
@@ -642,8 +684,8 @@ Error ImageLoader::loadInternal(FileInterface& file, const CString& filename, U3
 	}
 	}
 	else if(ext == "ankitex")
 	else if(ext == "ankitex")
 	{
 	{
-#if 0
-		compression = ImageBinaryDataCompression::RAW;
+#if ANKI_OS_ANDROID
+		m_compression = ImageBinaryDataCompression::ASTC;
 #else
 #else
 		m_compression = ImageBinaryDataCompression::S3TC;
 		m_compression = ImageBinaryDataCompression::S3TC;
 #endif
 #endif