Browse Source

Added BC6H decoding.

Branimir Karadžić 7 years ago
parent
commit
a9a745e6a2
5 changed files with 643 additions and 101 deletions
  1. 6 3
      include/bimg/bimg.h
  2. 2 1
      include/bimg/encode.h
  3. 616 86
      src/image.cpp
  4. 7 7
      src/image_encode.cpp
  5. 12 4
      tools/texturec/texturec.cpp

+ 6 - 3
include/bimg/bimg.h

@@ -404,7 +404,8 @@ namespace bimg
 
 	///
 	bool imageConvert(
-		  void* _dst
+		  bx::AllocatorI* _allocator
+		, void* _dst
 		, TextureFormat::Enum _dstFormat
 		, const void* _src
 		, TextureFormat::Enum _srcFormat
@@ -575,7 +576,8 @@ namespace bimg
 
 	///
 	void imageDecodeToBgra8(
-		  void* _dst
+		  bx::AllocatorI* _allocator
+		, void* _dst
 		, const void* _src
 		, uint32_t _width
 		, uint32_t _height
@@ -585,7 +587,8 @@ namespace bimg
 
 	///
 	void imageDecodeToRgba8(
-		  void* _dst
+		  bx::AllocatorI* _allocator
+		, void* _dst
 		, const void* _src
 		, uint32_t _width
 		, uint32_t _height

+ 2 - 1
include/bimg/encode.h

@@ -24,7 +24,8 @@ namespace bimg
 
 	///
 	void imageEncodeFromRgba8(
-		  void* _dst
+		  bx::AllocatorI* _allocator
+		, void* _dst
 		, const void* _src
 		, uint32_t _width
 		, uint32_t _height

+ 616 - 86
src/image.cpp

@@ -969,7 +969,7 @@ namespace bimg
 		}
 	}
 
-	bool imageConvert(void* _dst, TextureFormat::Enum _dstFormat, const void* _src, TextureFormat::Enum _srcFormat, uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _srcPitch)
+	bool imageConvert(bx::AllocatorI* _allocator, void* _dst, TextureFormat::Enum _dstFormat, const void* _src, TextureFormat::Enum _srcFormat, uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _srcPitch)
 	{
 		UnpackFn unpack = s_packUnpack[_srcFormat].unpack;
 		PackFn   pack   = s_packUnpack[_dstFormat].pack;
@@ -979,18 +979,15 @@ namespace bimg
 			switch (_dstFormat)
 			{
 			case TextureFormat::RGBA8:
-				imageDecodeToRgba8(_dst, _src, _width, _height, _width*4, _srcFormat);
+				imageDecodeToRgba8(_allocator, _dst, _src, _width, _height, _width*4, _srcFormat);
 				return true;
 
 			case TextureFormat::BGRA8:
-				imageDecodeToBgra8(_dst, _src, _width, _height, _width*4, _srcFormat);
+				imageDecodeToBgra8(_allocator, _dst, _src, _width, _height, _width*4, _srcFormat);
 				return true;
 
 			case TextureFormat::RGBA32F:
-				{
-					bx::DefaultAllocator allocator;
-					imageDecodeToRgba32f(&allocator, _dst, _src, _width, _height, 1, _width*16, _srcFormat);
-				}
+				imageDecodeToRgba32f(_allocator, _dst, _src, _width, _height, 1, _width*16, _srcFormat);
 				return true;
 
 			default:
@@ -1007,7 +1004,7 @@ namespace bimg
 		return true;
 	}
 
-	bool imageConvert(void* _dst, TextureFormat::Enum _dstFormat, const void* _src, TextureFormat::Enum _srcFormat, uint32_t _width, uint32_t _height, uint32_t _depth)
+	bool imageConvert(bx::AllocatorI* _allocator, void* _dst, TextureFormat::Enum _dstFormat, const void* _src, TextureFormat::Enum _srcFormat, uint32_t _width, uint32_t _height, uint32_t _depth)
 	{
 		const uint32_t srcBpp = s_imageBlockInfo[_srcFormat].bitsPerPixel;
 
@@ -1017,7 +1014,7 @@ namespace bimg
 			return true;
 		}
 
-		return imageConvert(_dst, _dstFormat, _src, _srcFormat, _width, _height, _depth, _width*srcBpp/8);
+		return imageConvert(_allocator, _dst, _dstFormat, _src, _srcFormat, _width, _height, _depth, _width*srcBpp/8);
 	}
 
 	ImageContainer* imageConvert(bx::AllocatorI* _allocator, TextureFormat::Enum _dstFormat, const ImageContainer& _input)
@@ -1045,14 +1042,16 @@ namespace bimg
 					imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
 					uint8_t* dstData = const_cast<uint8_t*>(dstMip.m_data);
 
-					bool ok = imageConvert(dstData
-							, _dstFormat
-							, mip.m_data
-							, mip.m_format
-							, mip.m_width
-							, mip.m_height
-							, mip.m_depth
-							);
+					bool ok = imageConvert(
+						  _allocator
+						, dstData
+						, _dstFormat
+						, mip.m_data
+						, mip.m_format
+						, mip.m_width
+						, mip.m_height
+						, mip.m_depth
+						);
 					BX_CHECK(ok, "Conversion from %s to %s failed!"
 							, getName(_input.m_format)
 							, getName(output->m_format)
@@ -1447,7 +1446,579 @@ namespace bimg
 		{  0,  4,  9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 },
 	};
 
-	struct BptcModeInfo
+	struct BitReader
+	{
+		BitReader(const uint8_t* _data, uint16_t _bitPos = 0)
+			: m_data(_data)
+			, m_bitPos(_bitPos)
+		{
+		}
+
+		uint16_t read(uint8_t _numBits)
+		{
+			const uint16_t pos   = m_bitPos / 8;
+			const uint16_t shift = m_bitPos & 7;
+			uint32_t data = 0;
+			bx::memCopy(&data, &m_data[pos], bx::min(4, 16-pos) );
+			m_bitPos += _numBits;
+			return uint16_t( (data >> shift) & ( (1 << _numBits)-1) );
+		}
+
+		uint16_t peek(uint16_t _offset, uint8_t _numBits)
+		{
+			const uint16_t bitPos = m_bitPos + _offset;
+			const uint16_t shift  = bitPos & 7;
+			uint16_t pos  = bitPos / 8;
+			uint32_t data = 0;
+			bx::memCopy(&data, &m_data[pos], bx::min(4, 16-pos) );
+			return uint8_t( (data >> shift) & ( (1 << _numBits)-1) );
+		}
+
+		const uint8_t* m_data;
+		uint16_t m_bitPos;
+	};
+
+	uint16_t bc6hUnquantize(uint16_t _value, bool _signed, uint8_t _endpointBits)
+	{
+		const uint16_t maxValue = 1<<(_endpointBits-1);
+
+		if (_signed)
+		{
+			if (_endpointBits >= 16)
+			{
+				return _value;
+			}
+
+			const bool sign = _value & 0x8000;
+			_value &= 0x7fff;
+
+			uint16_t unq;
+
+			if (0 == _value)
+			{
+				unq = 0;
+			}
+			else if (_value >= maxValue-1)
+			{
+				unq = 0x7fff;
+			}
+			else
+			{
+				unq = ( (_value<<15) + 0x4000) >> (_endpointBits-1);
+			}
+
+			return sign ? -unq : unq;
+		}
+
+		if (_endpointBits >= 15)
+		{
+			return _value;
+		}
+
+		if (0 == _value)
+		{
+			return 0;
+		}
+
+		if (_value == maxValue)
+		{
+			return UINT16_MAX;
+		}
+
+		return ( (_value<<15) + 0x4000) >> (_endpointBits-1);
+	}
+
+	uint16_t bc6hUnquantizeFinal(uint16_t _value, bool _signed)
+	{
+		if (_signed)
+		{
+			const uint16_t sign = _value & 0x8000;
+			_value &= 0x7fff;
+
+			return ( (_value * 31) >> 5) | sign;
+		}
+
+		return (_value * 31) >> 6;
+	}
+
+	uint16_t signExtend(uint16_t _value, uint8_t _numBits)
+	{
+		const uint16_t mask   = 1 << (_numBits - 1);
+		const uint16_t result = (_value ^ mask) - mask;
+
+		return result;
+	}
+
+	struct Bc6hModeInfo
+	{
+		uint8_t transformed;
+		uint8_t partitionBits;
+		uint8_t endpointBits;
+		uint8_t deltaBits[3];
+	};
+
+	static const Bc6hModeInfo s_bc6hModeInfo[] =
+	{ //  +--------------------------- transformed
+	  //  |  +------------------------ partition bits
+	  //  |  |  +--------------------- endpoint bits
+	  //  |  |  |      +-------------- delta bits
+		{ 1, 5, 10, {  5,  5,  5 } }, // 00    2-bits
+		{ 1, 5,  7, {  6,  6,  6 } }, // 01
+		{ 1, 5, 11, {  5,  4,  4 } }, // 00010 5-bits
+		{ 0, 0, 10, { 10, 10, 10 } }, // 00011
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 1, 5, 11, {  4,  5,  4 } }, // 00110
+		{ 1, 0, 11, {  9,  9,  9 } }, // 00010
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 1, 5, 11, {  4,  4,  5 } }, // 00010
+		{ 1, 0, 12, {  8,  8,  8 } }, // 00010
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 1, 5,  9, {  5,  5,  5 } }, // 00010
+		{ 1, 0, 16, {  4,  4,  4 } }, // 00010
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 1, 5,  8, {  6,  5,  5 } }, // 00010
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 1, 5,  8, {  5,  6,  5 } }, // 00010
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 1, 5,  8, {  5,  5,  6 } }, // 00010
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+		{ 0, 5,  6, {  6,  6,  6 } }, // 00010
+		{ 0, 0,  0, {  0,  0,  0 } }, // -
+	};
+
+	void decodeBlockBc6h(uint16_t _dst[16*3], const uint8_t _src[16], bool _signed)
+	{
+		BitReader bit(_src);
+
+		uint8_t mode = uint8_t(bit.read(2) );
+		if (mode & 2)
+		{
+			// 5-bit mode
+			mode |= bit.read(3) << 2;
+		}
+
+		const Bc6hModeInfo& mi = s_bc6hModeInfo[mode];
+		if (0 == mi.endpointBits)
+		{
+			bx::memSet(_dst, 0, 16*3*2);
+			return;
+		}
+
+		uint16_t epR[4] = { /* rw, rx, ry, rz */ };
+		uint16_t epG[4] = { /* gw, gx, gy, gz */ };
+		uint16_t epB[4] = { /* bw, bx, by, bz */ };
+
+		switch (mode)
+		{
+		case 0:
+			epG[2] |= bit.read( 1) <<  4;
+			epB[2] |= bit.read( 1) <<  4;
+			epB[3] |= bit.read( 1) <<  4;
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read( 5) <<  0;
+			epG[3] |= bit.read( 1) <<  4;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  2;
+			epR[3] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  3;
+			break;
+
+		case 1:
+			epG[2] |= bit.read( 1) <<  5;
+			epG[3] |= bit.read( 1) <<  4;
+			epG[3] |= bit.read( 1) <<  5;
+			epR[0] |= bit.read( 7) <<  0;
+			epB[3] |= bit.read( 1) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 1) <<  4;
+			epG[0] |= bit.read( 7) <<  0;
+			epB[2] |= bit.read( 1) <<  5;
+			epB[3] |= bit.read( 1) <<  2;
+			epG[2] |= bit.read( 1) <<  4;
+			epB[0] |= bit.read( 7) <<  0;
+			epB[3] |= bit.read( 1) <<  3;
+			epB[3] |= bit.read( 1) <<  5;
+			epB[3] |= bit.read( 1) <<  4;
+			epR[1] |= bit.read( 6) <<  0;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 6) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 6) <<  0;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 6) <<  0;
+			epR[3] |= bit.read( 6) <<  0;
+			break;
+
+		case 2:
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read( 5) <<  0;
+			epR[0] |= bit.read( 1) << 10;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 4) <<  0;
+			epG[0] |= bit.read( 1) << 10;
+			epB[3] |= bit.read( 1) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 4) <<  0;
+			epB[0] |= bit.read( 1) << 10;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  2;
+			epR[3] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  3;
+			break;
+
+		case 3:
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read(10) <<  0;
+			epG[1] |= bit.read(10) <<  0;
+			epB[1] |= bit.read(10) <<  0;
+			break;
+
+		case 6:
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read( 4) <<  0;
+			epR[0] |= bit.read( 1) << 10;
+			epG[3] |= bit.read( 1) <<  4;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 5) <<  0;
+			epG[0] |= bit.read( 1) << 10;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 4) <<  0;
+			epB[0] |= bit.read( 1) << 10;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 4) <<  0;
+			epB[3] |= bit.read( 1) <<  0;
+			epB[3] |= bit.read( 1) <<  2;
+			epR[3] |= bit.read( 4) <<  0;
+			epG[2] |= bit.read( 1) <<  4;
+			epB[3] |= bit.read( 1) <<  3;
+			break;
+
+		case 7:
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read( 9) <<  0;
+			epR[0] |= bit.read( 1) << 10;
+			epG[1] |= bit.read( 9) <<  0;
+			epG[0] |= bit.read( 1) << 10;
+			epB[1] |= bit.read( 9) <<  0;
+			epB[0] |= bit.read( 1) << 10;
+			break;
+
+		case 10:
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read( 4) <<  0;
+			epR[0] |= bit.read( 1) << 10;
+			epB[2] |= bit.read( 1) <<  4;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 4) <<  0;
+			epG[0] |= bit.read( 1) << 10;
+			epB[3] |= bit.read( 1) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 5) <<  0;
+			epB[0] |= bit.read( 1) << 10;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 4) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[3] |= bit.read( 1) <<  2;
+			epR[3] |= bit.read( 4) <<  0;
+			epB[3] |= bit.read( 1) <<  4;
+			epB[3] |= bit.read( 1) <<  3;
+			break;
+
+		case 11:
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read( 8) <<  0;
+			epR[0] |= bit.read( 1) << 11;
+			epR[0] |= bit.read( 1) << 10;
+			epG[1] |= bit.read( 8) <<  0;
+			epG[0] |= bit.read( 1) << 11;
+			epG[0] |= bit.read( 1) << 10;
+			epB[1] |= bit.read( 8) <<  0;
+			epB[0] |= bit.read( 1) << 11;
+			epB[0] |= bit.read( 1) << 10;
+			break;
+
+		case 14:
+			epR[0] |= bit.read( 9) <<  0;
+			epB[2] |= bit.read( 1) <<  4;
+			epG[0] |= bit.read( 9) <<  0;
+			epG[2] |= bit.read( 1) <<  4;
+			epB[0] |= bit.read( 9) <<  0;
+			epB[3] |= bit.read( 1) <<  4;
+			epR[1] |= bit.read( 5) <<  0;
+			epG[3] |= bit.read( 1) <<  4;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  2;
+			epR[3] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  3;
+			break;
+
+		case 15:
+			epR[0] |= bit.read(10) <<  0;
+			epG[0] |= bit.read(10) <<  0;
+			epB[0] |= bit.read(10) <<  0;
+			epR[1] |= bit.read( 4) <<  0;
+			epR[0] |= bit.read( 1) << 15;
+			epR[0] |= bit.read( 1) << 14;
+			epR[0] |= bit.read( 1) << 13;
+			epR[0] |= bit.read( 1) << 12;
+			epR[0] |= bit.read( 1) << 11;
+			epR[0] |= bit.read( 1) << 10;
+			epG[1] |= bit.read( 4) <<  0;
+			epG[0] |= bit.read( 1) << 15;
+			epG[0] |= bit.read( 1) << 14;
+			epG[0] |= bit.read( 1) << 13;
+			epG[0] |= bit.read( 1) << 12;
+			epG[0] |= bit.read( 1) << 11;
+			epG[0] |= bit.read( 1) << 10;
+			epB[1] |= bit.read( 4) <<  0;
+			epB[0] |= bit.read( 1) << 15;
+			epB[0] |= bit.read( 1) << 14;
+			epB[0] |= bit.read( 1) << 13;
+			epB[0] |= bit.read( 1) << 12;
+			epB[0] |= bit.read( 1) << 11;
+			epB[0] |= bit.read( 1) << 10;
+			break;
+
+		case 18:
+			epR[0] |= bit.read( 8) <<  0;
+			epG[3] |= bit.read( 1) <<  4;
+			epB[2] |= bit.read( 1) <<  4;
+			epG[0] |= bit.read( 8) <<  0;
+			epB[3] |= bit.read( 1) <<  2;
+			epG[2] |= bit.read( 1) <<  4;
+			epB[0] |= bit.read( 8) <<  0;
+			epB[3] |= bit.read( 1) <<  3;
+			epB[3] |= bit.read( 1) <<  4;
+			epR[1] |= bit.read( 6) <<  0;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 6) <<  0;
+			epR[3] |= bit.read( 6) <<  0;
+			break;
+
+		case 22:
+			epR[0] |= bit.read( 8) <<  0;
+			epB[3] |= bit.read( 1) <<  0;
+			epB[2] |= bit.read( 1) <<  4;
+			epG[0] |= bit.read( 8) <<  0;
+			epG[2] |= bit.read( 1) <<  5;
+			epG[2] |= bit.read( 1) <<  4;
+			epB[0] |= bit.read( 8) <<  0;
+			epG[3] |= bit.read( 1) <<  5;
+			epB[3] |= bit.read( 1) <<  4;
+			epR[1] |= bit.read( 5) <<  0;
+			epG[3] |= bit.read( 1) <<  4;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 6) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  2;
+			epR[3] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  3;
+			break;
+
+		case 26:
+			epR[0] |= bit.read( 8) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 1) <<  4;
+			epG[0] |= bit.read( 8) <<  0;
+			epB[2] |= bit.read( 1) <<  5;
+			epG[2] |= bit.read( 1) <<  4;
+			epB[0] |= bit.read( 8) <<  0;
+			epB[3] |= bit.read( 1) <<  5;
+			epB[3] |= bit.read( 1) <<  4;
+			epR[1] |= bit.read( 5) <<  0;
+			epG[3] |= bit.read( 1) <<  4;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 6) <<  0;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  2;
+			epR[3] |= bit.read( 5) <<  0;
+			epB[3] |= bit.read( 1) <<  3;
+			break;
+
+		case 30:
+			epR[0] |= bit.read( 6) <<  0;
+			epG[3] |= bit.read( 1) <<  4;
+			epB[3] |= bit.read( 1) <<  0;
+			epB[3] |= bit.read( 1) <<  1;
+			epB[2] |= bit.read( 1) <<  4;
+			epG[0] |= bit.read( 6) <<  0;
+			epG[2] |= bit.read( 1) <<  5;
+			epB[2] |= bit.read( 1) <<  5;
+			epB[3] |= bit.read( 1) <<  2;
+			epG[2] |= bit.read( 1) <<  4;
+			epB[0] |= bit.read( 6) <<  0;
+			epG[3] |= bit.read( 1) <<  5;
+			epB[3] |= bit.read( 1) <<  3;
+			epB[3] |= bit.read( 1) <<  5;
+			epB[3] |= bit.read( 1) <<  4;
+			epR[1] |= bit.read( 6) <<  0;
+			epG[2] |= bit.read( 4) <<  0;
+			epG[1] |= bit.read( 6) <<  0;
+			epG[3] |= bit.read( 4) <<  0;
+			epB[1] |= bit.read( 6) <<  0;
+			epB[2] |= bit.read( 4) <<  0;
+			epR[2] |= bit.read( 6) <<  0;
+			epR[3] |= bit.read( 6) <<  0;
+			break;
+
+		default:
+			break;
+		}
+
+		if (_signed)
+		{
+			epR[0] = signExtend(epR[0], mi.endpointBits);
+			epG[0] = signExtend(epG[0], mi.endpointBits);
+			epB[0] = signExtend(epB[0], mi.endpointBits);
+		}
+
+		const uint8_t numSubsets = !!mi.partitionBits + 1;
+
+		for (uint8_t ii = 1, num = numSubsets*2; ii < num; ++ii)
+		{
+			if (_signed
+			||  mi.transformed)
+			{
+				epR[ii] = signExtend(epR[ii], mi.deltaBits[0]);
+				epG[ii] = signExtend(epG[ii], mi.deltaBits[1]);
+				epB[ii] = signExtend(epB[ii], mi.deltaBits[2]);
+			}
+
+			if (mi.transformed)
+			{
+				const uint16_t mask = (1<<mi.endpointBits) - 1;
+
+				epR[ii] = (epR[ii] + epR[0]) & mask;
+				epG[ii] = (epG[ii] + epG[0]) & mask;
+				epB[ii] = (epB[ii] + epB[0]) & mask;
+
+				if (_signed)
+				{
+					epR[ii] = signExtend(epR[ii], mi.endpointBits);
+					epG[ii] = signExtend(epG[ii], mi.endpointBits);
+					epB[ii] = signExtend(epB[ii], mi.endpointBits);
+				}
+			}
+		}
+
+		for (uint8_t ii = 0, num = numSubsets*2; ii < num; ++ii)
+		{
+			epR[ii] = bc6hUnquantize(epR[ii], _signed, mi.endpointBits);
+			epG[ii] = bc6hUnquantize(epG[ii], _signed, mi.endpointBits);
+			epB[ii] = bc6hUnquantize(epB[ii], _signed, mi.endpointBits);
+		}
+
+		const uint8_t partitionSetIdx = uint8_t(mi.partitionBits ? bit.read(5) : 0);
+		const uint8_t indexBits = mi.partitionBits ? 3 : 4;
+		const uint8_t* factors  = s_bptcFactors[indexBits-2];
+
+		for (uint8_t yy = 0; yy < 4; ++yy)
+		{
+			for (uint8_t xx = 0; xx < 4; ++xx)
+			{
+				const uint8_t idx = yy*4+xx;
+
+				uint8_t subsetIndex = 0;
+				uint8_t indexAnchor = 0;
+
+				if (0 != mi.partitionBits)
+				{
+					subsetIndex = (s_bptcP2[partitionSetIdx] >> idx) & 1;
+					indexAnchor = subsetIndex ? s_bptcA2[partitionSetIdx] : 0;
+				}
+
+				const uint8_t anchor = idx == indexAnchor;
+				const uint8_t num    = indexBits - anchor;
+				const uint8_t index  = (uint8_t)bit.read(num);
+
+				const uint8_t fc  = factors[index];
+				const uint8_t fca = 64 - fc;
+				const uint8_t fcb = fc;
+
+				subsetIndex *= 2;
+				uint16_t rr = bc6hUnquantizeFinal( (epR[subsetIndex]*fca + epR[subsetIndex + 1]*fcb + 32) >> 6, _signed);
+				uint16_t gg = bc6hUnquantizeFinal( (epG[subsetIndex]*fca + epG[subsetIndex + 1]*fcb + 32) >> 6, _signed);
+				uint16_t bb = bc6hUnquantizeFinal( (epB[subsetIndex]*fca + epB[subsetIndex + 1]*fcb + 32) >> 6, _signed);
+
+				uint16_t* rgba = &_dst[idx*3];
+				rgba[0] = rr;
+				rgba[1] = gg;
+				rgba[2] = bb;
+			}
+		}
+	}
+
+	void decodeBlockBc6h(float _dst[16*4], const uint8_t _src[16])
+	{
+		uint16_t tmp[16*3];
+
+		decodeBlockBc6h(tmp, _src, true);
+
+		for (uint32_t ii = 0; ii < 16; ++ii)
+		{
+			_dst[ii*4+0] = bx::halfToFloat(tmp[ii*3+0]);
+			_dst[ii*4+1] = bx::halfToFloat(tmp[ii*3+1]);
+			_dst[ii*4+2] = bx::halfToFloat(tmp[ii*3+2]);
+			_dst[ii*4+3] = 1.0f;
+		}
+	}
+
+	struct Bc7ModeInfo
 	{
 		uint8_t numSubsets;
 		uint8_t partitionBits;
@@ -1460,7 +2031,7 @@ namespace bimg
 		uint8_t indexBits[2];
 	};
 
-	static const BptcModeInfo s_bptcModeInfo[] =
+	static const Bc7ModeInfo s_bp7ModeInfo[] =
 	{ //  +---------------------------- num subsets
 	  //  |  +------------------------- partition bits
 	  //  |  |  +---------------------- rotation bits
@@ -1480,47 +2051,6 @@ namespace bimg
 		{ 2, 6, 0, 0, 5, 5, 1, 0, { 2, 0 } }, // 7
 	};
 
-	struct BitReader
-	{
-		BitReader(const uint8_t* _data, uint16_t _bitPos = 0)
-			: m_data(_data)
-			, m_bitPos(_bitPos)
-		{
-		}
-
-		uint8_t read(uint8_t _numBits)
-		{
-			const uint16_t pos   = m_bitPos / 8;
-			const uint16_t shift = m_bitPos & 7;
-			const uint16_t data  = 15 > pos
-				? *( (uint16_t*)&m_data[pos])
-				:       uint16_t(m_data[pos])
-				;
-			m_bitPos += _numBits;
-			return uint8_t( (data >> shift) & ( (1 << _numBits)-1) );
-		}
-
-		uint8_t peek(uint16_t _offset, uint8_t _numBits)
-		{
-			const uint16_t bitPos = m_bitPos + _offset;
-			const uint16_t pos    = bitPos / 8;
-			const uint16_t shift  = bitPos & 7;
-			const uint16_t data   = 15 > pos
-				? *( (uint16_t*)&m_data[pos])
-				:       uint16_t(m_data[pos])
-				;
-			return uint8_t( (data >> shift) & ( (1 << _numBits)-1) );
-		}
-
-		const uint8_t* m_data;
-		uint16_t m_bitPos;
-	};
-
-	void decodeBlockBc6(float _dst[16*4], const uint8_t _src[16])
-	{
-		BX_UNUSED(_dst, _src);
-	}
-
 	void decodeBlockBc7(uint8_t _dst[16*4], const uint8_t _src[16])
 	{
 		BitReader bit(_src);
@@ -1536,15 +2066,15 @@ namespace bimg
 			return;
 		}
 
-		const BptcModeInfo& mi  = s_bptcModeInfo[mode];
+		const Bc7ModeInfo& mi  = s_bp7ModeInfo[mode];
 		const uint8_t modePBits = 0 != mi.endpointPBits
 			? mi.endpointPBits
 			: mi.sharedPBits
 			;
 
-		const uint8_t partitionSetIdx    = bit.read(mi.partitionBits);
-		const uint8_t rotationMode       = bit.read(mi.rotationBits);
-		const uint8_t indexSelectionMode = bit.read(mi.indexSelectionBits);
+		const uint8_t partitionSetIdx    = uint8_t(bit.read(mi.partitionBits) );
+		const uint8_t rotationMode       = uint8_t(bit.read(mi.rotationBits) );
+		const uint8_t indexSelectionMode = uint8_t(bit.read(mi.indexSelectionBits) );
 
 		uint8_t epR[6];
 		uint8_t epG[6];
@@ -1553,28 +2083,28 @@ namespace bimg
 
 		for (uint8_t ii = 0; ii < mi.numSubsets; ++ii)
 		{
-			epR[ii*2+0] = bit.read(mi.colorBits) << modePBits;
-			epR[ii*2+1] = bit.read(mi.colorBits) << modePBits;
+			epR[ii*2+0] = uint8_t(bit.read(mi.colorBits) << modePBits);
+			epR[ii*2+1] = uint8_t(bit.read(mi.colorBits) << modePBits);
 		}
 
 		for (uint8_t ii = 0; ii < mi.numSubsets; ++ii)
 		{
-			epG[ii*2+0] = bit.read(mi.colorBits) << modePBits;
-			epG[ii*2+1] = bit.read(mi.colorBits) << modePBits;
+			epG[ii*2+0] = uint8_t(bit.read(mi.colorBits) << modePBits);
+			epG[ii*2+1] = uint8_t(bit.read(mi.colorBits) << modePBits);
 		}
 
 		for (uint8_t ii = 0; ii < mi.numSubsets; ++ii)
 		{
-			epB[ii*2+0] = bit.read(mi.colorBits) << modePBits;
-			epB[ii*2+1] = bit.read(mi.colorBits) << modePBits;
+			epB[ii*2+0] = uint8_t(bit.read(mi.colorBits) << modePBits);
+			epB[ii*2+1] = uint8_t(bit.read(mi.colorBits) << modePBits);
 		}
 
 		if (mi.alphaBits)
 		{
 			for (uint8_t ii = 0; ii < mi.numSubsets; ++ii)
 			{
-				epA[ii*2+0] = bit.read(mi.alphaBits) << modePBits;
-				epA[ii*2+1] = bit.read(mi.alphaBits) << modePBits;
+				epA[ii*2+0] = uint8_t(bit.read(mi.alphaBits) << modePBits);
+				epA[ii*2+1] = uint8_t(bit.read(mi.alphaBits) << modePBits);
 			}
 		}
 		else
@@ -1586,8 +2116,8 @@ namespace bimg
 		{
 			for (uint8_t ii = 0; ii < mi.numSubsets; ++ii)
 			{
-				const uint8_t pda = bit.read(modePBits);
-				const uint8_t pdb = 0 == mi.sharedPBits ? bit.read(modePBits) : pda;
+				const uint8_t pda = uint8_t(                      bit.read(modePBits)      );
+				const uint8_t pdb = uint8_t(0 == mi.sharedPBits ? bit.read(modePBits) : pda);
 
 				epR[ii*2+0] |= pda;
 				epR[ii*2+1] |= pdb;
@@ -1670,8 +2200,8 @@ namespace bimg
 
 				const uint8_t index[2] =
 				{
-					                bit.peek(offset[0], num[0]),
-					hasIndexBits1 ? bit.peek(offset[1], num[1]) : index[0],
+					                (uint8_t)bit.peek(offset[0], num[0]),
+					hasIndexBits1 ? (uint8_t)bit.peek(offset[1], num[1]) : index[0],
 				};
 
 				offset[0] += num[0];
@@ -3379,18 +3909,18 @@ namespace bimg
 			{
 				uint32_t size = imageGetSize(NULL, uint16_t(_width), uint16_t(_height), 0, false, false, 1, TextureFormat::RGBA8);
 				void* temp = BX_ALLOC(_allocator, size);
-				imageDecodeToRgba8(temp, _src, _width, _height, _width*4, _srcFormat);
-				imageConvert(dst, TextureFormat::R8, temp, TextureFormat::RGBA8, _width, _height, 1, _width*4);
+				imageDecodeToRgba8(_allocator, temp, _src, _width, _height, _width*4, _srcFormat);
+				imageConvert(_allocator, dst, TextureFormat::R8, temp, TextureFormat::RGBA8, _width, _height, 1, _width*4);
 				BX_FREE(_allocator, temp);
 			}
 			else
 			{
-				imageConvert(dst, TextureFormat::R8, src, _srcFormat, _width, _height, 1, srcPitch);
+				imageConvert(_allocator, dst, TextureFormat::R8, src, _srcFormat, _width, _height, 1, srcPitch);
 			}
 		}
 	}
 
-	void imageDecodeToBgra8(void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _dstPitch, TextureFormat::Enum _srcFormat)
+	void imageDecodeToBgra8(bx::AllocatorI* _allocator, void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _dstPitch, TextureFormat::Enum _srcFormat)
 	{
 		const uint8_t* src = (const uint8_t*)_src;
 		uint8_t* dst = (uint8_t*)_dst;
@@ -3618,7 +4148,7 @@ namespace bimg
 			{
 				const uint32_t srcBpp   = s_imageBlockInfo[_srcFormat].bitsPerPixel;
 				const uint32_t srcPitch = _width * srcBpp / 8;
-				if (!imageConvert(_dst, TextureFormat::BGRA8, _src, _srcFormat, _width, _height, 1, srcPitch) )
+				if (!imageConvert(_allocator, _dst, TextureFormat::BGRA8, _src, _srcFormat, _width, _height, 1, srcPitch) )
 				{
 					// Failed to convert, just make ugly red-yellow checkerboard texture.
 					imageCheckerboard(_dst, _width, _height, 16, UINT32_C(0xffff0000), UINT32_C(0xffffff00) );
@@ -3628,7 +4158,7 @@ namespace bimg
 		}
 	}
 
-	void imageDecodeToRgba8(void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _dstPitch, TextureFormat::Enum _srcFormat)
+	void imageDecodeToRgba8(bx::AllocatorI* _allocator, void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _dstPitch, TextureFormat::Enum _srcFormat)
 	{
 		switch (_srcFormat)
 		{
@@ -3650,7 +4180,7 @@ namespace bimg
 		default:
 			{
 				const uint32_t srcPitch = _width * 4;
-				imageDecodeToBgra8(_dst, _src, _width, _height, _dstPitch, _srcFormat);
+				imageDecodeToBgra8(_allocator, _dst, _src, _width, _height, _dstPitch, _srcFormat);
 				imageSwizzleBgra8(_dst, _dstPitch, _width, _height, _dst, srcPitch);
 			}
 			break;
@@ -3781,7 +4311,7 @@ namespace bimg
 						for (uint32_t xx = 0; xx < width; ++xx)
 						{
 							float tmp[16*4];
-							decodeBlockBc6(tmp, srcData);
+							decodeBlockBc6h(tmp, srcData);
 							srcData += 16;
 
 							uint8_t* block = (uint8_t*)&dst[yy*_dstPitch*4 + xx*64];
@@ -3803,13 +4333,13 @@ namespace bimg
 				{
 					uint32_t size = imageGetSize(NULL, uint16_t(_width), uint16_t(_height), 0, false, false, 1, TextureFormat::RGBA8);
 					void* temp = BX_ALLOC(_allocator, size);
-					imageDecodeToRgba8(temp, src, _width, _height, _width*4, _srcFormat);
+					imageDecodeToRgba8(_allocator, temp, src, _width, _height, _width*4, _srcFormat);
 					imageRgba8ToRgba32f(dst, _width, _height, _width*4, temp);
 					BX_FREE(_allocator, temp);
 				}
 				else
 				{
-					imageConvert(dst, TextureFormat::RGBA32F, src, _srcFormat, _width, _height, 1, srcPitch);
+					imageConvert(_allocator, dst, TextureFormat::RGBA32F, src, _srcFormat, _width, _height, 1, srcPitch);
 				}
 				break;
 			}

+ 7 - 7
src/image_encode.cpp

@@ -35,7 +35,7 @@ namespace bimg
 	};
 	BX_STATIC_ASSERT(Quality::Count == BX_COUNTOF(s_squishQuality) );
 
-	void imageEncodeFromRgba8(void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _depth, TextureFormat::Enum _format, Quality::Enum _quality, bx::Error* _err)
+	void imageEncodeFromRgba8(bx::AllocatorI* _allocator, void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _depth, TextureFormat::Enum _format, Quality::Enum _quality, bx::Error* _err)
 	{
 		const uint8_t* src = (const uint8_t*)_src;
 		uint8_t* dst = (uint8_t*)_dst;
@@ -131,7 +131,7 @@ namespace bimg
 				break;
 
 			default:
-				if (!imageConvert(dst, _format, src, TextureFormat::RGBA8, _width, _height, 1) )
+				if (!imageConvert(_allocator, dst, _format, src, TextureFormat::RGBA8, _width, _height, 1) )
 				{
 					BX_ERROR_SET(_err, BIMG_ERROR, "Unable to convert between input/output formats!");
 				}
@@ -157,10 +157,10 @@ namespace bimg
 			break;
 
 		default:
-			if (!imageConvert(_dst, _dstFormat, _src, TextureFormat::RGBA32F, _width, _height, _depth) )
+			if (!imageConvert(_allocator, _dst, _dstFormat, _src, TextureFormat::RGBA32F, _width, _height, _depth) )
 			{
 				uint8_t* temp = (uint8_t*)BX_ALLOC(_allocator, _width*_height*_depth*4);
-				if (imageConvert(temp, TextureFormat::RGBA8, _src, TextureFormat::RGBA32F, _width, _height, _depth) )
+				if (imageConvert(_allocator, temp, TextureFormat::RGBA8, _src, TextureFormat::RGBA32F, _width, _height, _depth) )
 				{
 					for (uint32_t zz = 0; zz < _depth; ++zz)
 					{
@@ -183,7 +183,7 @@ namespace bimg
 						}
 					}
 
-					imageEncodeFromRgba8(_dst, temp, _width, _height, _depth, _dstFormat, _quality, _err);
+					imageEncodeFromRgba8(_allocator, _dst, temp, _width, _height, _depth, _dstFormat, _quality, _err);
 				}
 				else
 				{
@@ -211,8 +211,8 @@ namespace bimg
 			case bimg::TextureFormat::PTC14A:
 				{
 					uint8_t* temp = (uint8_t*)BX_ALLOC(_allocator, _width*_height*_depth*4);
-					imageDecodeToRgba8(temp, _src, _width, _height, _width*4, _srcFormat);
-					imageEncodeFromRgba8(_dst, temp, _width, _height, _depth, _dstFormat, _quality, _err);
+					imageDecodeToRgba8(_allocator, temp, _src, _width, _height, _width*4, _srcFormat);
+					imageEncodeFromRgba8(_allocator, _dst, temp, _width, _height, _depth, _dstFormat, _quality, _err);
 					BX_FREE(_allocator, temp);
 				}
 				break;

+ 12 - 4
tools/texturec/texturec.cpp

@@ -559,7 +559,9 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData
 					temp = BX_ALLOC(_allocator, size);
 					uint8_t* rgba = (uint8_t*)temp;
 
-					bimg::imageDecodeToRgba8(rgba
+					bimg::imageDecodeToRgba8(
+						  _allocator
+						, rgba
 						, mip.m_data
 						, mip.m_width
 						, mip.m_height
@@ -600,7 +602,9 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData
 					bimg::imageGetRawData(*output, side, 0, output->m_data, output->m_size, dstMip);
 					dstData = const_cast<uint8_t*>(dstMip.m_data);
 
-					bimg::imageEncodeFromRgba8(dstData
+					bimg::imageEncodeFromRgba8(
+						  _allocator
+						, dstData
 						, rgba
 						, dstMip.m_width
 						, dstMip.m_height
@@ -647,7 +651,9 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData
 						bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
 						dstData = const_cast<uint8_t*>(dstMip.m_data);
 
-						bimg::imageEncodeFromRgba8(dstData
+						bimg::imageEncodeFromRgba8(
+							  _allocator
+							, dstData
 							, rgba
 							, dstMip.m_width
 							, dstMip.m_height
@@ -660,7 +666,9 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData
 
 					if (NULL != ref)
 					{
-						bimg::imageDecodeToRgba8(rgba
+						bimg::imageDecodeToRgba8(
+							  _allocator
+							, rgba
 							, output->m_data
 							, mip.m_width
 							, mip.m_height