Browse Source

Added the ability to use ASTC compressed textures, when the system supports them.

Alex Szpakowski 9 years ago
parent
commit
77998c707d

+ 2 - 0
CMakeLists.txt

@@ -355,6 +355,8 @@ set(LOVE_SRC_MODULE_IMAGE_ROOT
 )
 
 set(LOVE_SRC_MODULE_IMAGE_MAGPIE
+	src/modules/image/magpie/ASTCHandler.cpp
+	src/modules/image/magpie/ASTCHandler.h
 	src/modules/image/magpie/CompressedImageData.cpp
 	src/modules/image/magpie/CompressedImageData.h
 	src/modules/image/magpie/CompressedFormatHandler.h

+ 11 - 1
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -817,6 +817,9 @@
 		FA0B7EEA1A95902D000E1D17 /* wrap_Window.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7CCC1A95902C000E1D17 /* wrap_Window.h */; };
 		FA0B7EF21A959D2C000E1D17 /* ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7EF11A959D2C000E1D17 /* ios.mm */; };
 		FA317EBA18F28B6D00B0BCD7 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA317EB918F28B6D00B0BCD7 /* libz.dylib */; };
+		FA41A3C81C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; };
+		FA41A3C91C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; };
+		FA41A3CA1C0A1F950084430C /* ASTCHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA41A3C71C0A1F950084430C /* ASTCHandler.h */; };
 		FA4B66C91ABBCF1900558F15 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4B66C81ABBCF1900558F15 /* Timer.cpp */; };
 		FA4B66CA1ABBCF1900558F15 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4B66C81ABBCF1900558F15 /* Timer.cpp */; };
 		FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7916C71A1700860150 /* Cocoa.framework */; };
@@ -1474,6 +1477,8 @@
 		FA283EDC1B27CFAA00C70067 /* nogame.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = nogame.lua; sourceTree = "<group>"; };
 		FA283EDD1B27CFAA00C70067 /* nogame.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nogame.lua.h; sourceTree = "<group>"; };
 		FA317EB918F28B6D00B0BCD7 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+		FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTCHandler.cpp; sourceTree = "<group>"; };
+		FA41A3C71C0A1F950084430C /* ASTCHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTCHandler.h; sourceTree = "<group>"; };
 		FA4B66C81ABBCF1900558F15 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = "<group>"; };
 		FA577A6716C719D900860150 /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = "<absolute>"; };
 		FA577A6D16C719EA00860150 /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = /Library/Frameworks/Lua.framework; sourceTree = "<absolute>"; };
@@ -2298,9 +2303,11 @@
 		FA0B7BC81A95902C000E1D17 /* magpie */ = {
 			isa = PBXGroup;
 			children = (
+				FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */,
+				FA41A3C71C0A1F950084430C /* ASTCHandler.h */,
+				FA0B7BCB1A95902C000E1D17 /* CompressedFormatHandler.h */,
 				FA0B7BC91A95902C000E1D17 /* CompressedImageData.cpp */,
 				FA0B7BCA1A95902C000E1D17 /* CompressedImageData.h */,
-				FA0B7BCB1A95902C000E1D17 /* CompressedFormatHandler.h */,
 				FA0B7BCC1A95902C000E1D17 /* ddsHandler.cpp */,
 				FA0B7BCD1A95902C000E1D17 /* ddsHandler.h */,
 				FA0B7BCE1A95902C000E1D17 /* FormatHandler.cpp */,
@@ -3108,6 +3115,7 @@
 				FA0B7E171A95902C000E1D17 /* Joint.h in Headers */,
 				FA0B793F1A958E3B000E1D17 /* types.h in Headers */,
 				FA0B7AB31A958EA3000E1D17 /* b2Rope.h in Headers */,
+				FA41A3CA1C0A1F950084430C /* ASTCHandler.h in Headers */,
 				FA0B7D5D1A95902C000E1D17 /* wrap_Font.h in Headers */,
 				FA0B7ED31A95902C000E1D17 /* wrap_ThreadModule.h in Headers */,
 				FA0B7A511A958EA3000E1D17 /* b2GrowableStack.h in Headers */,
@@ -3336,6 +3344,7 @@
 				FA0B7A781A958EA3000E1D17 /* b2CircleContact.cpp in Sources */,
 				FA0B7D5F1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */,
 				FA0B7A9C1A958EA3000E1D17 /* b2MouseJoint.cpp in Sources */,
+				FA41A3C91C0A1F950084430C /* ASTCHandler.cpp in Sources */,
 				FA0B7E551A95902C000E1D17 /* wrap_GearJoint.cpp in Sources */,
 				FA0B7E791A95902C000E1D17 /* wrap_WheelJoint.cpp in Sources */,
 				FA0B7DDD1A95902C000E1D17 /* wrap_BezierCurve.cpp in Sources */,
@@ -3622,6 +3631,7 @@
 				FA0B7D5E1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */,
 				FA0B7A801A958EA3000E1D17 /* b2EdgeAndCircleContact.cpp in Sources */,
 				FA0B7E541A95902C000E1D17 /* wrap_GearJoint.cpp in Sources */,
+				FA41A3C81C0A1F950084430C /* ASTCHandler.cpp in Sources */,
 				FA0B7E781A95902C000E1D17 /* wrap_WheelJoint.cpp in Sources */,
 				FA0B7DDC1A95902C000E1D17 /* wrap_BezierCurve.cpp in Sources */,
 				FA0B7AF71A958EA3000E1D17 /* luasocket.c in Sources */,

+ 107 - 104
src/modules/graphics/opengl/Image.cpp

@@ -589,112 +589,101 @@ bool Image::isCompressed() const
 
 GLenum Image::getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const
 {
+	using image::CompressedImageData;
+
 	switch (cformat)
 	{
-	case image::CompressedImageData::FORMAT_DXT1:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
-		else
-			return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
-	case image::CompressedImageData::FORMAT_DXT3:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
-		else
-			return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-	case image::CompressedImageData::FORMAT_DXT5:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
-		else
-			return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-	case image::CompressedImageData::FORMAT_BC4:
+	case CompressedImageData::FORMAT_DXT1:
+		return isSRGB ? GL_COMPRESSED_SRGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+	case CompressedImageData::FORMAT_DXT3:
+		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+	case CompressedImageData::FORMAT_DXT5:
+		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+	case CompressedImageData::FORMAT_BC4:
 		isSRGB = false;
 		return GL_COMPRESSED_RED_RGTC1;
-	case image::CompressedImageData::FORMAT_BC4s:
+	case CompressedImageData::FORMAT_BC4s:
 		isSRGB = false;
 		return GL_COMPRESSED_SIGNED_RED_RGTC1;
-	case image::CompressedImageData::FORMAT_BC5:
+	case CompressedImageData::FORMAT_BC5:
 		isSRGB = false;
 		return GL_COMPRESSED_RG_RGTC2;
-	case image::CompressedImageData::FORMAT_BC5s:
+	case CompressedImageData::FORMAT_BC5s:
 		isSRGB = false;
 		return GL_COMPRESSED_SIGNED_RG_RGTC2;
-	case image::CompressedImageData::FORMAT_BC6H:
+	case CompressedImageData::FORMAT_BC6H:
 		isSRGB = false;
 		return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
-	case image::CompressedImageData::FORMAT_BC6Hs:
+	case CompressedImageData::FORMAT_BC6Hs:
 		isSRGB = false;
 		return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
-	case image::CompressedImageData::FORMAT_BC7:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
-		else
-			return GL_COMPRESSED_RGBA_BPTC_UNORM;
-	case image::CompressedImageData::FORMAT_ETC1:
+	case CompressedImageData::FORMAT_BC7:
+		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : GL_COMPRESSED_RGBA_BPTC_UNORM;
+	case CompressedImageData::FORMAT_PVR1_RGB2:
+		return isSRGB ? GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+	case CompressedImageData::FORMAT_PVR1_RGB4:
+		return isSRGB ? GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+	case CompressedImageData::FORMAT_PVR1_RGBA2:
+		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+	case CompressedImageData::FORMAT_PVR1_RGBA4:
+		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+	case CompressedImageData::FORMAT_ETC1:
 		// The ETC2 format can load ETC1 textures.
 		if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility)
-		{
-			if (isSRGB)
-				return GL_COMPRESSED_SRGB8_ETC2;
-			else
-				return GL_COMPRESSED_RGB8_ETC2;
-		}
+			return isSRGB ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2;
 		else
 		{
 			isSRGB = false;
 			return GL_ETC1_RGB8_OES;
 		}
-	case image::CompressedImageData::FORMAT_ETC2_RGB:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB8_ETC2;
-		else
-			return GL_COMPRESSED_RGB8_ETC2;
-	case image::CompressedImageData::FORMAT_ETC2_RGBA:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
-		else
-			return GL_COMPRESSED_RGBA8_ETC2_EAC;
-	case image::CompressedImageData::FORMAT_ETC2_RGBA1:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-		else
-			return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-	case image::CompressedImageData::FORMAT_EAC_R:
+	case CompressedImageData::FORMAT_ETC2_RGB:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2;
+	case CompressedImageData::FORMAT_ETC2_RGBA:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : GL_COMPRESSED_RGBA8_ETC2_EAC;
+	case CompressedImageData::FORMAT_ETC2_RGBA1:
+		return isSRGB ? GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+	case CompressedImageData::FORMAT_EAC_R:
 		isSRGB = false;
 		return GL_COMPRESSED_R11_EAC;
-	case image::CompressedImageData::FORMAT_EAC_Rs:
+	case CompressedImageData::FORMAT_EAC_Rs:
 		isSRGB = false;
 		return GL_COMPRESSED_SIGNED_R11_EAC;
-	case image::CompressedImageData::FORMAT_EAC_RG:
+	case CompressedImageData::FORMAT_EAC_RG:
 		isSRGB = false;
 		return GL_COMPRESSED_RG11_EAC;
-	case image::CompressedImageData::FORMAT_EAC_RGs:
+	case CompressedImageData::FORMAT_EAC_RGs:
 		isSRGB = false;
 		return GL_COMPRESSED_SIGNED_RG11_EAC;
-	case image::CompressedImageData::FORMAT_PVR1_RGB2:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT;
-		else
-			return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
-	case image::CompressedImageData::FORMAT_PVR1_RGB4:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT;
-		else
-			return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
-	case image::CompressedImageData::FORMAT_PVR1_RGBA2:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT;
-		else
-			return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
-	case image::CompressedImageData::FORMAT_PVR1_RGBA4:
-		if (isSRGB)
-			return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT;
-		else
-			return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+	case CompressedImageData::FORMAT_ASTC_4x4:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
+	case CompressedImageData::FORMAT_ASTC_5x4:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
+	case CompressedImageData::FORMAT_ASTC_5x5:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : GL_COMPRESSED_RGBA_ASTC_5x5_KHR;
+	case CompressedImageData::FORMAT_ASTC_6x5:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : GL_COMPRESSED_RGBA_ASTC_6x5_KHR;
+	case CompressedImageData::FORMAT_ASTC_6x6:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : GL_COMPRESSED_RGBA_ASTC_6x6_KHR;
+	case CompressedImageData::FORMAT_ASTC_8x5:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : GL_COMPRESSED_RGBA_ASTC_8x5_KHR;
+	case CompressedImageData::FORMAT_ASTC_8x6:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : GL_COMPRESSED_RGBA_ASTC_8x6_KHR;
+	case CompressedImageData::FORMAT_ASTC_8x8:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : GL_COMPRESSED_RGBA_ASTC_8x8_KHR;
+	case CompressedImageData::FORMAT_ASTC_10x5:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : GL_COMPRESSED_RGBA_ASTC_10x5_KHR;
+	case CompressedImageData::FORMAT_ASTC_10x6:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : GL_COMPRESSED_RGBA_ASTC_10x6_KHR;
+	case CompressedImageData::FORMAT_ASTC_10x8:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : GL_COMPRESSED_RGBA_ASTC_10x8_KHR;
+	case CompressedImageData::FORMAT_ASTC_10x10:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : GL_COMPRESSED_RGBA_ASTC_10x10_KHR;
+	case CompressedImageData::FORMAT_ASTC_12x10:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : GL_COMPRESSED_RGBA_ASTC_12x10_KHR;
+	case CompressedImageData::FORMAT_ASTC_12x12:
+		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : GL_COMPRESSED_RGBA_ASTC_12x12_KHR;
 	default:
-		if (isSRGB)
-			return GL_SRGB8_ALPHA8;
-		else
-			return GL_RGBA8;
+		return isSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
 	}
 }
 
@@ -705,42 +694,56 @@ bool Image::hasAnisotropicFilteringSupport()
 
 bool Image::hasCompressedTextureSupport(image::CompressedImageData::Format format, bool sRGB)
 {
+	using image::CompressedImageData;
+
 	switch (format)
 	{
-	case image::CompressedImageData::FORMAT_DXT1:
+	case CompressedImageData::FORMAT_DXT1:
 		return GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1;
-	case image::CompressedImageData::FORMAT_DXT3:
+	case CompressedImageData::FORMAT_DXT3:
 		return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3;
-	case image::CompressedImageData::FORMAT_DXT5:
+	case CompressedImageData::FORMAT_DXT5:
 		return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5;
-	case image::CompressedImageData::FORMAT_BC4:
-	case image::CompressedImageData::FORMAT_BC4s:
-	case image::CompressedImageData::FORMAT_BC5:
-	case image::CompressedImageData::FORMAT_BC5s:
+	case CompressedImageData::FORMAT_BC4:
+	case CompressedImageData::FORMAT_BC4s:
+	case CompressedImageData::FORMAT_BC5:
+	case CompressedImageData::FORMAT_BC5s:
 		return (GLAD_VERSION_3_0 || GLAD_ARB_texture_compression_rgtc || GLAD_EXT_texture_compression_rgtc);
-	case image::CompressedImageData::FORMAT_BC6H:
-	case image::CompressedImageData::FORMAT_BC6Hs:
-	case image::CompressedImageData::FORMAT_BC7:
+	case CompressedImageData::FORMAT_BC6H:
+	case CompressedImageData::FORMAT_BC6Hs:
+	case CompressedImageData::FORMAT_BC7:
 		return GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc;
-	case image::CompressedImageData::FORMAT_ETC1:
+	case CompressedImageData::FORMAT_PVR1_RGB2:
+	case CompressedImageData::FORMAT_PVR1_RGB4:
+	case CompressedImageData::FORMAT_PVR1_RGBA2:
+	case CompressedImageData::FORMAT_PVR1_RGBA4:
+		return sRGB ? GLAD_EXT_pvrtc_sRGB : GLAD_IMG_texture_compression_pvrtc;
+	case CompressedImageData::FORMAT_ETC1:
 		// ETC2 support guarantees ETC1 support as well.
 		return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture;
-	case image::CompressedImageData::FORMAT_ETC2_RGB:
-	case image::CompressedImageData::FORMAT_ETC2_RGBA:
-	case image::CompressedImageData::FORMAT_ETC2_RGBA1:
-	case image::CompressedImageData::FORMAT_EAC_R:
-	case image::CompressedImageData::FORMAT_EAC_Rs:
-	case image::CompressedImageData::FORMAT_EAC_RG:
-	case image::CompressedImageData::FORMAT_EAC_RGs:
+	case CompressedImageData::FORMAT_ETC2_RGB:
+	case CompressedImageData::FORMAT_ETC2_RGBA:
+	case CompressedImageData::FORMAT_ETC2_RGBA1:
+	case CompressedImageData::FORMAT_EAC_R:
+	case CompressedImageData::FORMAT_EAC_Rs:
+	case CompressedImageData::FORMAT_EAC_RG:
+	case CompressedImageData::FORMAT_EAC_RGs:
 		return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility;
-	case image::CompressedImageData::FORMAT_PVR1_RGB2:
-	case image::CompressedImageData::FORMAT_PVR1_RGB4:
-	case image::CompressedImageData::FORMAT_PVR1_RGBA2:
-	case image::CompressedImageData::FORMAT_PVR1_RGBA4:
-		if (sRGB)
-			return GLAD_EXT_pvrtc_sRGB;
-		else
-			return GLAD_IMG_texture_compression_pvrtc;
+	case CompressedImageData::FORMAT_ASTC_4x4:
+	case CompressedImageData::FORMAT_ASTC_5x4:
+	case CompressedImageData::FORMAT_ASTC_5x5:
+	case CompressedImageData::FORMAT_ASTC_6x5:
+	case CompressedImageData::FORMAT_ASTC_6x6:
+	case CompressedImageData::FORMAT_ASTC_8x5:
+	case CompressedImageData::FORMAT_ASTC_8x6:
+	case CompressedImageData::FORMAT_ASTC_8x8:
+	case CompressedImageData::FORMAT_ASTC_10x5:
+	case CompressedImageData::FORMAT_ASTC_10x6:
+	case CompressedImageData::FORMAT_ASTC_10x8:
+	case CompressedImageData::FORMAT_ASTC_10x10:
+	case CompressedImageData::FORMAT_ASTC_12x10:
+	case CompressedImageData::FORMAT_ASTC_12x12:
+		return /*GLAD_ES_VERSION_3_2 ||*/ GLAD_KHR_texture_compression_astc_ldr;
 	default:
 		return false;
 	}
@@ -763,8 +766,8 @@ bool Image::getConstant(FlagType in, const char *&out)
 
 StringMap<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM>::Entry Image::flagNameEntries[] =
 {
-	{"mipmaps", Image::FLAG_TYPE_MIPMAPS},
-	{"linear", Image::FLAG_TYPE_LINEAR},
+	{"mipmaps", FLAG_TYPE_MIPMAPS},
+	{"linear", FLAG_TYPE_LINEAR},
 };
 
 StringMap<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM> Image::flagNames(Image::flagNameEntries, sizeof(Image::flagNameEntries));

+ 18 - 4
src/modules/image/CompressedImageData.cpp

@@ -119,6 +119,10 @@ StringMap<CompressedImageData::Format, CompressedImageData::FORMAT_MAX_ENUM>::En
 	{"BC6h", FORMAT_BC6H},
 	{"BC6hs", FORMAT_BC6Hs},
 	{"BC7", FORMAT_BC7},
+	{"PVR1rgb2", FORMAT_PVR1_RGB2},
+	{"PVR1rgb4", FORMAT_PVR1_RGB4},
+	{"PVR1rgba2", FORMAT_PVR1_RGBA2},
+	{"PVR1rgba4", FORMAT_PVR1_RGBA4},
 	{"ETC1", FORMAT_ETC1},
 	{"ETC2rgb", FORMAT_ETC2_RGB},
 	{"ETC2rgba", FORMAT_ETC2_RGBA},
@@ -127,10 +131,20 @@ StringMap<CompressedImageData::Format, CompressedImageData::FORMAT_MAX_ENUM>::En
 	{"EACrs", FORMAT_EAC_Rs},
 	{"EACrg", FORMAT_EAC_RG},
 	{"EACrgs", FORMAT_EAC_RGs},
-	{"PVR1rgb2", FORMAT_PVR1_RGB2},
-	{"PVR1rgb4", FORMAT_PVR1_RGB4},
-	{"PVR1rgba2", FORMAT_PVR1_RGBA2},
-	{"PVR1rgba4", FORMAT_PVR1_RGBA4},
+	{"ASTC4x4", FORMAT_ASTC_4x4},
+	{"ASTC5x4", FORMAT_ASTC_5x4},
+	{"ASTC5x5", FORMAT_ASTC_5x5},
+	{"ASTC6x5", FORMAT_ASTC_6x5},
+	{"ASTC6x6", FORMAT_ASTC_6x6},
+	{"ASTC8x5", FORMAT_ASTC_8x5},
+	{"ASTC8x6", FORMAT_ASTC_8x6},
+	{"ASTC8x8", FORMAT_ASTC_8x8},
+	{"ASTC10x5", FORMAT_ASTC_10x5},
+	{"ASTC10x6", FORMAT_ASTC_10x6},
+	{"ASTC10x8", FORMAT_ASTC_10x8},
+	{"ASTC10x10", FORMAT_ASTC_10x10},
+	{"ASTC12x10", FORMAT_ASTC_12x10},
+	{"ASTC12x12", FORMAT_ASTC_12x12},
 };
 
 StringMap<CompressedImageData::Format, CompressedImageData::FORMAT_MAX_ENUM> CompressedImageData::formats(CompressedImageData::formatEntries, sizeof(CompressedImageData::formatEntries));

+ 18 - 4
src/modules/image/CompressedImageData.h

@@ -57,6 +57,10 @@ public:
 		FORMAT_BC6H,
 		FORMAT_BC6Hs,
 		FORMAT_BC7,
+		FORMAT_PVR1_RGB2,
+		FORMAT_PVR1_RGB4,
+		FORMAT_PVR1_RGBA2,
+		FORMAT_PVR1_RGBA4,
 		FORMAT_ETC1,
 		FORMAT_ETC2_RGB,
 		FORMAT_ETC2_RGBA,
@@ -65,10 +69,20 @@ public:
 		FORMAT_EAC_Rs,
 		FORMAT_EAC_RG,
 		FORMAT_EAC_RGs,
-		FORMAT_PVR1_RGB2,
-		FORMAT_PVR1_RGB4,
-		FORMAT_PVR1_RGBA2,
-		FORMAT_PVR1_RGBA4,
+		FORMAT_ASTC_4x4,
+		FORMAT_ASTC_5x4,
+		FORMAT_ASTC_5x5,
+		FORMAT_ASTC_6x5,
+		FORMAT_ASTC_6x6,
+		FORMAT_ASTC_8x5,
+		FORMAT_ASTC_8x6,
+		FORMAT_ASTC_8x8,
+		FORMAT_ASTC_10x5,
+		FORMAT_ASTC_10x6,
+		FORMAT_ASTC_10x8,
+		FORMAT_ASTC_10x10,
+		FORMAT_ASTC_12x10,
+		FORMAT_ASTC_12x12,
 		FORMAT_MAX_ENUM
 	};
 

+ 166 - 0
src/modules/image/magpie/ASTCHandler.cpp

@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+// LOVE
+#include "ASTCHandler.h"
+#include "common/int.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+namespace
+{
+
+static const uint32 ASTC_IDENTIFIER = 0x5CA1AB13;
+
+#pragma pack(push, 1)
+struct ASTCHeader
+{
+	uint8 identifier[4];
+	uint8 blockdimX;
+	uint8 blockdimY;
+	uint8 blockdimZ;
+	uint8 sizeX[3];
+	uint8 sizeY[3];
+	uint8 sizeZ[3];
+};
+#pragma pack(pop)
+
+static CompressedImageData::Format convertFormat(uint32 blockX, uint32 blockY, uint32 blockZ)
+{
+	if (blockZ > 1)
+		return CompressedImageData::FORMAT_UNKNOWN;
+
+	if (blockX == 4 && blockY == 4)
+		return CompressedImageData::FORMAT_ASTC_4x4;
+	else if (blockX == 5 && blockY == 4)
+		return CompressedImageData::FORMAT_ASTC_5x4;
+	else if (blockX == 5 && blockY == 5)
+		return CompressedImageData::FORMAT_ASTC_5x5;
+	else if (blockX == 6 && blockY == 5)
+		return CompressedImageData::FORMAT_ASTC_6x5;
+	else if (blockX == 6 && blockY == 6)
+		return CompressedImageData::FORMAT_ASTC_6x6;
+	else if (blockX == 8 && blockY == 5)
+		return CompressedImageData::FORMAT_ASTC_8x5;
+	else if (blockX == 8 && blockY == 6)
+		return CompressedImageData::FORMAT_ASTC_8x6;
+	else if (blockX == 8 && blockY == 8)
+		return CompressedImageData::FORMAT_ASTC_8x8;
+	else if (blockX == 10 && blockY == 5)
+		return CompressedImageData::FORMAT_ASTC_10x5;
+	else if (blockX == 10 && blockY == 6)
+		return CompressedImageData::FORMAT_ASTC_10x6;
+	else if (blockX == 10 && blockY == 8)
+		return CompressedImageData::FORMAT_ASTC_10x8;
+	else if (blockX == 10 && blockY == 10)
+		return CompressedImageData::FORMAT_ASTC_10x10;
+	else if (blockX == 12 && blockY == 10)
+		return CompressedImageData::FORMAT_ASTC_12x10;
+	else if (blockX == 12 && blockY == 12)
+		return CompressedImageData::FORMAT_ASTC_12x12;
+
+	return CompressedImageData::FORMAT_UNKNOWN;
+}
+
+} // Anonymous namespace.
+
+bool ASTCHandler::canParse(const filesystem::FileData *data)
+{
+	if (data->getSize() <= sizeof(ASTCHeader))
+		return false;
+
+	const ASTCHeader *header = (const ASTCHeader *) data->getData();
+
+	uint32 identifier =  (uint32) header->identifier[0]
+	                  + ((uint32) header->identifier[1] << 8)
+	                  + ((uint32) header->identifier[2] << 16)
+	                  + ((uint32) header->identifier[3] << 24);
+
+	if (identifier != ASTC_IDENTIFIER)
+		return false;
+
+	return true;
+}
+
+uint8 *ASTCHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB)
+{
+	if (!canParse(filedata))
+		throw love::Exception("Could not decode compressed data (not an .astc file?)");
+
+	ASTCHeader header = *(const ASTCHeader *) filedata->getData();
+
+	CompressedImageData::Format cformat = convertFormat(header.blockdimX, header.blockdimY, header.blockdimZ);
+
+	if (cformat == CompressedImageData::FORMAT_UNKNOWN)
+		throw love::Exception("Could not parse .astc file: unsupported ASTC format %dx%dx%d.", header.blockdimX, header.blockdimY, header.blockdimZ);
+
+	uint32 sizeX = header.sizeX[0] + (header.sizeX[1] << 8) + (header.sizeX[2] << 16);
+	uint32 sizeY = header.sizeY[0] + (header.sizeY[1] << 8) + (header.sizeY[2] << 16);
+	uint32 sizeZ = header.sizeZ[0] + (header.sizeZ[1] << 8) + (header.sizeZ[2] << 16);
+
+	uint32 blocksX = (sizeX + header.blockdimX - 1) / header.blockdimX;
+	uint32 blocksY = (sizeY + header.blockdimY - 1) / header.blockdimY;
+	uint32 blocksZ = (sizeZ + header.blockdimZ - 1) / header.blockdimZ;
+
+	size_t totalsize = blocksX * blocksY * blocksZ * 16;
+
+	if (totalsize + sizeof(header) > filedata->getSize())
+		throw love::Exception("Could not parse .astc file: file is too small.");
+
+	uint8 *data = nullptr;
+
+	try
+	{
+		data = new uint8[totalsize];
+	}
+	catch (std::bad_alloc &)
+	{
+		throw love::Exception("Out of memory.");
+	}
+
+	// .astc files only store a single mipmap level.
+	memcpy(data, (uint8 *) filedata->getData() + sizeof(ASTCHeader), totalsize);
+
+	CompressedImageData::SubImage mip;
+
+	mip.width = sizeX;
+	mip.height = sizeY;
+
+	mip.size = totalsize;
+	mip.data = data;
+
+	images.push_back(mip);
+
+	dataSize = totalsize;
+	format = cformat;
+	sRGB = false;
+
+	return data;
+}
+
+} // magpie
+} // image
+} // love
+

+ 54 - 0
src/modules/image/magpie/ASTCHandler.h

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IMAGE_MAGPIE_ASTC_HANDLER_H
+#define LOVE_IMAGE_MAGPIE_ASTC_HANDLER_H
+
+#include "common/config.h"
+#include "CompressedFormatHandler.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+/**
+ * Handles simple .astc files (generated by ARM's astcenc tool) with compressed
+ * ASTC data inside.
+ **/
+class ASTCHandler : public CompressedFormatHandler
+{
+public:
+
+	virtual ~ASTCHandler() {}
+
+	// Implements CompressedFormatHandler.
+	virtual bool canParse(const filesystem::FileData *data);
+	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB);
+
+}; // ASTCHandler
+
+} // magpie
+} // image
+} // love
+
+#endif // LOVE_IMAGE_MAGPIE_ASTC_HANDLER_H

+ 2 - 0
src/modules/image/magpie/Image.cpp

@@ -30,6 +30,7 @@
 #include "PVRHandler.h"
 #include "KTXHandler.h"
 #include "PKMHandler.h"
+#include "ASTCHandler.h"
 
 namespace love
 {
@@ -47,6 +48,7 @@ Image::Image()
 	compressedFormatHandlers.push_back(new PVRHandler);
 	compressedFormatHandlers.push_back(new KTXHandler);
 	compressedFormatHandlers.push_back(new PKMHandler);
+	compressedFormatHandlers.push_back(new ASTCHandler);
 }
 
 Image::~Image()

+ 88 - 1
src/modules/image/magpie/KTXHandler.cpp

@@ -87,13 +87,44 @@ enum KTXGLInternalFormat
 	// Same with DXT1/3/5.
 	KTX_GL_COMPRESSED_RGB_S3TC_DXT1_EXT  = 0x83F0,
 	KTX_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2,
-	KTX_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3
+	KTX_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3,
+
+	KTX_GL_COMPRESSED_RGBA_ASTC_4x4_KHR           = 0x93B0,
+	KTX_GL_COMPRESSED_RGBA_ASTC_5x4_KHR           = 0x93B1,
+	KTX_GL_COMPRESSED_RGBA_ASTC_5x5_KHR           = 0x93B2,
+	KTX_GL_COMPRESSED_RGBA_ASTC_6x5_KHR           = 0x93B3,
+	KTX_GL_COMPRESSED_RGBA_ASTC_6x6_KHR           = 0x93B4,
+	KTX_GL_COMPRESSED_RGBA_ASTC_8x5_KHR           = 0x93B5,
+	KTX_GL_COMPRESSED_RGBA_ASTC_8x6_KHR           = 0x93B6,
+	KTX_GL_COMPRESSED_RGBA_ASTC_8x8_KHR           = 0x93B7,
+	KTX_GL_COMPRESSED_RGBA_ASTC_10x5_KHR          = 0x93B8,
+	KTX_GL_COMPRESSED_RGBA_ASTC_10x6_KHR          = 0x93B9,
+	KTX_GL_COMPRESSED_RGBA_ASTC_10x8_KHR          = 0x93BA,
+	KTX_GL_COMPRESSED_RGBA_ASTC_10x10_KHR         = 0x93BB,
+	KTX_GL_COMPRESSED_RGBA_ASTC_12x10_KHR         = 0x93BC,
+	KTX_GL_COMPRESSED_RGBA_ASTC_12x12_KHR         = 0x93BD,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR   = 0x93D0,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR   = 0x93D1,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR   = 0x93D2,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR   = 0x93D3,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR   = 0x93D4,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR   = 0x93D5,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR   = 0x93D6,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR   = 0x93D7,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR  = 0x93D8,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR  = 0x93D9,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR  = 0x93DA,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC,
+	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD
 };
 
 CompressedImageData::Format convertFormat(uint32 glformat, bool &sRGB)
 {
 	sRGB = false;
 
+	// hnnngg ASTC...
+
 	switch (glformat)
 	{
 	case KTX_GL_ETC1_RGB8_OES:
@@ -135,6 +166,62 @@ CompressedImageData::Format convertFormat(uint32 glformat, bool &sRGB)
 		return CompressedImageData::FORMAT_DXT3;
 	case KTX_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
 		return CompressedImageData::FORMAT_DXT5;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
+		return CompressedImageData::FORMAT_ASTC_4x4;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
+		return CompressedImageData::FORMAT_ASTC_5x4;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
+		return CompressedImageData::FORMAT_ASTC_5x5;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
+		return CompressedImageData::FORMAT_ASTC_6x5;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
+		return CompressedImageData::FORMAT_ASTC_6x6;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
+		return CompressedImageData::FORMAT_ASTC_8x5;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
+		return CompressedImageData::FORMAT_ASTC_8x6;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
+		return CompressedImageData::FORMAT_ASTC_8x8;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
+		return CompressedImageData::FORMAT_ASTC_10x5;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
+		return CompressedImageData::FORMAT_ASTC_10x6;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
+		return CompressedImageData::FORMAT_ASTC_10x8;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
+		return CompressedImageData::FORMAT_ASTC_10x10;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
+		return CompressedImageData::FORMAT_ASTC_12x10;
+	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+		sRGB = true;
+	case KTX_GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
+		return CompressedImageData::FORMAT_ASTC_12x12;
 	default:
 		return CompressedImageData::FORMAT_UNKNOWN;
 	}

+ 102 - 26
src/modules/image/magpie/PVRHandler.cpp

@@ -237,20 +237,11 @@ static CompressedImageData::Format convertFormat(PVRV3PixelFormat format, PVRV3C
 	case ePVRTPF_DXT5:
 		return CompressedImageData::FORMAT_DXT5;
 	case ePVRTPF_BC4:
-		if (snorm)
-			return CompressedImageData::FORMAT_BC4s;
-		else
-			return CompressedImageData::FORMAT_BC4;
+		return snorm ? CompressedImageData::FORMAT_BC4s : CompressedImageData::FORMAT_BC4;
 	case ePVRTPF_BC5:
-		if (snorm)
-			return CompressedImageData::FORMAT_BC5s;
-		else
-			return CompressedImageData::FORMAT_BC5;
+		return snorm ? CompressedImageData::FORMAT_BC5s : CompressedImageData::FORMAT_BC5;
 	case ePVRTPF_BC6:
-		if (snorm)
-			return CompressedImageData::FORMAT_BC6Hs;
-		else
-			return CompressedImageData::FORMAT_BC6H;
+		return snorm ? CompressedImageData::FORMAT_BC6Hs : CompressedImageData::FORMAT_BC6H;
 	case ePVRTPF_BC7:
 		return CompressedImageData::FORMAT_BC7;
 	case ePVRTPF_ETC2_RGB:
@@ -260,15 +251,37 @@ static CompressedImageData::Format convertFormat(PVRV3PixelFormat format, PVRV3C
 	case ePVRTPF_ETC2_RGBA1:
 		return CompressedImageData::FORMAT_ETC2_RGBA1;
 	case ePVRTPF_EAC_R:
-		if (snorm)
-			return CompressedImageData::FORMAT_EAC_Rs;
-		else
-			return CompressedImageData::FORMAT_EAC_R;
+		return snorm ? CompressedImageData::FORMAT_EAC_Rs : CompressedImageData::FORMAT_EAC_R;
 	case ePVRTPF_EAC_RG:
-		if (snorm)
-			return CompressedImageData::FORMAT_EAC_RGs;
-		else
-			return CompressedImageData::FORMAT_EAC_RG;
+		return snorm ? CompressedImageData::FORMAT_EAC_RGs : CompressedImageData::FORMAT_EAC_RG;
+	case ePVRTPF_ASTC_4x4:
+		return CompressedImageData::FORMAT_ASTC_4x4;
+	case ePVRTPF_ASTC_5x4:
+		return CompressedImageData::FORMAT_ASTC_5x4;
+	case ePVRTPF_ASTC_5x5:
+		return CompressedImageData::FORMAT_ASTC_5x5;
+	case ePVRTPF_ASTC_6x5:
+		return CompressedImageData::FORMAT_ASTC_6x5;
+	case ePVRTPF_ASTC_6x6:
+		return CompressedImageData::FORMAT_ASTC_6x6;
+	case ePVRTPF_ASTC_8x5:
+		return CompressedImageData::FORMAT_ASTC_8x5;
+	case ePVRTPF_ASTC_8x6:
+		return CompressedImageData::FORMAT_ASTC_8x6;
+	case ePVRTPF_ASTC_8x8:
+		return CompressedImageData::FORMAT_ASTC_8x8;
+	case ePVRTPF_ASTC_10x5:
+		return CompressedImageData::FORMAT_ASTC_10x5;
+	case ePVRTPF_ASTC_10x6:
+		return CompressedImageData::FORMAT_ASTC_10x6;
+	case ePVRTPF_ASTC_10x8:
+		return CompressedImageData::FORMAT_ASTC_10x8;
+	case ePVRTPF_ASTC_10x10:
+		return CompressedImageData::FORMAT_ASTC_10x10;
+	case ePVRTPF_ASTC_12x10:
+		return CompressedImageData::FORMAT_ASTC_12x10;
+	case ePVRTPF_ASTC_12x12:
+		return CompressedImageData::FORMAT_ASTC_12x12;
 	default:
 		return CompressedImageData::FORMAT_UNKNOWN;
 	}
@@ -314,8 +327,10 @@ int getBitsPerPixel(uint64 pixelformat)
 	}
 }
 
-void getFormatMinDimensions(uint64 pixelformat, int &minX, int &minY)
+void getFormatMinDimensions(uint64 pixelformat, int &minX, int &minY, int &minZ)
 {
+	minZ = 1;
+
 	switch (pixelformat)
 	{
 	case ePVRTPF_PVRTCI_2bpp_RGB:
@@ -351,6 +366,62 @@ void getFormatMinDimensions(uint64 pixelformat, int &minX, int &minY)
 	case ePVRTPF_EAC_RG:
 		minX = minY = 4;
 		break;
+	case ePVRTPF_ASTC_4x4:
+		minX = 4;
+		minY = 4;
+		break;
+	case ePVRTPF_ASTC_5x4:
+		minX = 5;
+		minY = 4;
+		break;
+	case ePVRTPF_ASTC_5x5:
+		minX = 5;
+		minY = 5;
+		break;
+	case ePVRTPF_ASTC_6x5:
+		minX = 6;
+		minY = 5;
+		break;
+	case ePVRTPF_ASTC_6x6:
+		minX = 6;
+		minY = 6;
+		break;
+	case ePVRTPF_ASTC_8x5:
+		minX = 8;
+		minY = 5;
+		break;
+	case ePVRTPF_ASTC_8x6:
+		minX = 8;
+		minY = 6;
+		break;
+	case ePVRTPF_ASTC_8x8:
+		minX = 8;
+		minY = 8;
+		break;
+	case ePVRTPF_ASTC_10x5:
+		minX = 10;
+		minY = 5;
+		break;
+	case ePVRTPF_ASTC_10x6:
+		minX = 10;
+		minY = 6;
+		break;
+	case ePVRTPF_ASTC_10x8:
+		minX = 10;
+		minY = 8;
+		break;
+	case ePVRTPF_ASTC_10x10:
+		minX = 10;
+		minY = 10;
+		break;
+	case ePVRTPF_ASTC_12x10:
+		minX = 12;
+		minY = 10;
+		break;
+	case ePVRTPF_ASTC_12x12:
+		minX = 12;
+		minY = 12;
+		break;
 	default: // We don't handle all possible formats, but that's fine.
 		minX = minY = 1;
 		break;
@@ -361,17 +432,22 @@ size_t getMipLevelSize(const PVRTexHeaderV3 &header, int miplevel)
 {
 	int smallestwidth = 1;
 	int smallestheight = 1;
-	getFormatMinDimensions(header.pixelFormat, smallestwidth, smallestheight);
+	int smallestdepth = 1;
+	getFormatMinDimensions(header.pixelFormat, smallestwidth, smallestheight, smallestdepth);
 
 	int width = std::max((int) header.width >> miplevel, 1);
 	int height = std::max((int) header.height >> miplevel, 1);
 	int depth = std::max((int) header.depth >> miplevel, 1);
 
 	// Pad the dimensions.
-	width += (-width) % smallestwidth;
-	height += (-height) % smallestheight;
-
-	return getBitsPerPixel(header.pixelFormat) * width * height * depth / 8;
+	width = ((width + smallestwidth - 1) / smallestwidth) * smallestwidth;
+	height = ((height + smallestheight - 1) / smallestheight) * smallestheight;
+	depth = ((depth + smallestdepth - 1) / smallestdepth) * smallestdepth;
+
+	if (header.pixelFormat >= ePVRTPF_ASTC_4x4 && header.pixelFormat <= ePVRTPF_ASTC_12x12)
+		return (width / smallestwidth) * (height / smallestheight) * (depth / smallestdepth) * (128 / 8);
+	else
+		return getBitsPerPixel(header.pixelFormat) * width * height * depth / 8;
 }
 
 } // Anonymous namespace.