2
0
Эх сурвалжийг харах

Added ETC1 texture support. Added KTX file format support.

bkaradzic 12 жил өмнө
parent
commit
19dd4020f4

+ 1 - 0
include/bgfx.h

@@ -307,6 +307,7 @@ namespace bgfx
 			BC3, // DXT5
 			BC4, // LATC1/ATI1
 			BC5, // LATC2/ATI2
+			ETC1,
 			Unknown,
 			L8,
 			BGRX8,

+ 1 - 1
premake/texturec.lua

@@ -14,7 +14,7 @@ project "texturec"
 	}
 
 	files {
-		BGFX_DIR .. "src/dds.*",
+		BGFX_DIR .. "src/image.*",
 		BGFX_DIR .. "tools/texturec/**.cpp",
 		BGFX_DIR .. "tools/texturec/**.h",
 	}

+ 6 - 0
src/bgfx.cpp

@@ -1000,6 +1000,7 @@ namespace bgfx
 		8,  // BC3
 		4,  // BC4
 		8,  // BC5
+		4,  // ETC1
 		0,  // Unknown
 		8,  // L8
 		32, // BGRX8
@@ -1012,6 +1013,11 @@ namespace bgfx
 		32, // RGB10A2
 	};
 
+	uint32_t getBitsPerPixel(TextureFormat::Enum _format)
+	{
+		return s_bitsPerPixel[_format];
+	}
+
 	void calcTextureSize(TextureInfo& _info, uint16_t _width, uint16_t _height, uint16_t _depth, uint8_t _numMips, TextureFormat::Enum _format)
 	{
 		_width   = bx::uint32_max(1, _width);

+ 10 - 10
src/bgfx_p.h

@@ -72,7 +72,7 @@ namespace bgfx
 #include <bx/string.h>
 #include <bx/os.h>
 
-#include "dds.h"
+#include "image.h"
 
 #define BGFX_CHUNK_MAGIC_FSH BX_MAKEFOURCC('F', 'S', 'H', 0x1)
 #define BGFX_CHUNK_MAGIC_TEX BX_MAKEFOURCC('T', 'E', 'X', 0x0)
@@ -230,7 +230,7 @@ namespace bgfx
 	extern FreeFn g_free;
 
 	void release(const Memory* _mem);
-	void imageWriteTga(bx::WriterI* _writer, uint32_t _width, uint32_t _height, uint32_t _srcPitch, const void* _src, bool _grayscale = false, bool _yflip = false);
+	uint32_t getBitsPerPixel(TextureFormat::Enum _format);
 	const char* getAttribName(Attrib::Enum _attr);
 	bool renderFrame();
 
@@ -275,7 +275,7 @@ namespace bgfx
 		return _offset+align-(_offset%align);
 	}
 
-	BX_FORCE_INLINE uint32_t castfu(float _value)
+	inline uint32_t castfu(float _value)
 	{
 		union {	float fl; uint32_t ui; } un;
 		un.fl = _value;
@@ -2138,15 +2138,15 @@ namespace bgfx
 		{
 			if (NULL != _info)
 			{
-				Dds dds;
-				if (parseDds(dds, _mem) )
+				ImageContainer imageContainer;
+				if (imageParse(imageContainer, _mem->data, _mem->size) )
 				{
 					calcTextureSize(*_info
-						, (uint16_t)dds.m_width
-						, (uint16_t)dds.m_height
-						, (uint16_t)dds.m_depth
-						, dds.m_numMips
-						, dds.m_type
+						, (uint16_t)imageContainer.m_width
+						, (uint16_t)imageContainer.m_height
+						, (uint16_t)imageContainer.m_depth
+						, imageContainer.m_numMips
+						, imageContainer.m_type
 						);
 				}
 				else

+ 0 - 619
src/dds.cpp

@@ -1,619 +0,0 @@
-/*
- * Copyright 2011-2013 Branimir Karadzic. All rights reserved.
- * License: http://www.opensource.org/licenses/BSD-2-Clause
- */
-
-#include <math.h> // sqrtf
-
-#include "bgfx_p.h"
-#include "dds.h"
-
-namespace bgfx
-{
-
-#define DDS_MAGIC BX_MAKEFOURCC('D','D','S',' ')
-#define DDS_HEADER_SIZE 124
-#define DDS_IMAGE_DATA_OFFSET (DDS_HEADER_SIZE + 4)
-
-#define DDS_DXT1 BX_MAKEFOURCC('D', 'X', 'T', '1')
-#define DDS_DXT2 BX_MAKEFOURCC('D', 'X', 'T', '2')
-#define DDS_DXT3 BX_MAKEFOURCC('D', 'X', 'T', '3')
-#define DDS_DXT4 BX_MAKEFOURCC('D', 'X', 'T', '4')
-#define DDS_DXT5 BX_MAKEFOURCC('D', 'X', 'T', '5')
-#define DDS_ATI1 BX_MAKEFOURCC('A', 'T', 'I', '1')
-#define DDS_BC4U BX_MAKEFOURCC('B', 'C', '4', 'U')
-#define DDS_ATI2 BX_MAKEFOURCC('A', 'T', 'I', '2')
-#define DDS_BC5U BX_MAKEFOURCC('B', 'C', '5', 'U')
-
-#define D3DFMT_A16B16G16R16  36
-#define D3DFMT_A16B16G16R16F 113
-
-#define DDSD_CAPS                   0x00000001
-#define DDSD_HEIGHT                 0x00000002
-#define DDSD_WIDTH                  0x00000004
-#define DDSD_PITCH                  0x00000008
-#define DDSD_PIXELFORMAT            0x00001000
-#define DDSD_MIPMAPCOUNT            0x00020000
-#define DDSD_LINEARSIZE             0x00080000
-#define DDSD_DEPTH                  0x00800000
-
-#define DDPF_ALPHAPIXELS            0x00000001
-#define DDPF_ALPHA                  0x00000002
-#define DDPF_FOURCC                 0x00000004
-#define DDPF_INDEXED                0x00000020
-#define DDPF_RGB                    0x00000040
-#define DDPF_YUV                    0x00000200
-#define DDPF_LUMINANCE              0x00020000
-
-#define DDSCAPS_COMPLEX             0x00000008
-#define DDSCAPS_TEXTURE             0x00001000
-#define DDSCAPS_MIPMAP              0x00400000
-
-#define DDSCAPS2_CUBEMAP            0x00000200
-#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
-#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
-#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
-#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
-#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
-#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
-
-#define DDS_CUBEMAP_ALLFACES (DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX \
-							 |DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY \
-							 |DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ)
-
-#define DDSCAPS2_VOLUME             0x00200000
-
-bool isDds(const Memory* _mem)
-{
-	bx::MemoryReader reader(_mem->data, _mem->size);
-
-	uint32_t magic;
-	bx::read(&reader, magic);
-
-	return DDS_MAGIC == magic;
-}
-
-uint32_t bitRangeConvert(uint32_t _in, uint32_t _from, uint32_t _to)
-{
-	using namespace bx;
-	uint32_t tmp0   = uint32_sll(1, _to);
-	uint32_t tmp1   = uint32_sll(1, _from);
-	uint32_t tmp2   = uint32_dec(tmp0);
-	uint32_t tmp3   = uint32_dec(tmp1);
-	uint32_t tmp4   = uint32_mul(_in, tmp2);
-	uint32_t tmp5   = uint32_add(tmp3, tmp4);
-	uint32_t tmp6   = uint32_srl(tmp5, _from);
-	uint32_t tmp7   = uint32_add(tmp5, tmp6);
-	uint32_t result = uint32_srl(tmp7, _from);
-
-	return result;
-}
-
-void decodeBlockDxt(uint8_t _dst[16*4], const uint8_t _src[8])
-{
-	uint8_t colors[4*3];
-
-	uint32_t c0 = _src[0] | (_src[1] << 8);
-	colors[0] = bitRangeConvert( (c0>> 0)&0x1f, 5, 8);
-	colors[1] = bitRangeConvert( (c0>> 5)&0x3f, 6, 8);
-	colors[2] = bitRangeConvert( (c0>>11)&0x1f, 5, 8);
-
-	uint32_t c1 = _src[2] | (_src[3] << 8);
-	colors[3] = bitRangeConvert( (c1>> 0)&0x1f, 5, 8);
-	colors[4] = bitRangeConvert( (c1>> 5)&0x3f, 6, 8);
-	colors[5] = bitRangeConvert( (c1>>11)&0x1f, 5, 8);
-
-	colors[6] = (2*colors[0] + colors[3]) / 3;
-	colors[7] = (2*colors[1] + colors[4]) / 3;
-	colors[8] = (2*colors[2] + colors[5]) / 3;
-
-	colors[ 9] = (colors[0] + 2*colors[3]) / 3;
-	colors[10] = (colors[1] + 2*colors[4]) / 3;
-	colors[11] = (colors[2] + 2*colors[5]) / 3;
-
-	for (uint32_t ii = 0, next = 8*4; ii < 16*4; ii += 4, next += 2)
-	{
-		int idx = ( (_src[next>>3] >> (next & 7) ) & 3) * 3;
-		_dst[ii+0] = colors[idx+0];
-		_dst[ii+1] = colors[idx+1];
-		_dst[ii+2] = colors[idx+2];
-	}
-}
-
-void decodeBlockDxt1(uint8_t _dst[16*4], const uint8_t _src[8])
-{
-	uint8_t colors[4*4];
-
-	uint32_t c0 = _src[0] | (_src[1] << 8);
-	colors[0] = bitRangeConvert( (c0>> 0)&0x1f, 5, 8);
-	colors[1] = bitRangeConvert( (c0>> 5)&0x3f, 6, 8);
-	colors[2] = bitRangeConvert( (c0>>11)&0x1f, 5, 8);
-	colors[3] = 255;
-
-	uint32_t c1 = _src[2] | (_src[3] << 8);
-	colors[4] = bitRangeConvert( (c1>> 0)&0x1f, 5, 8);
-	colors[5] = bitRangeConvert( (c1>> 5)&0x3f, 6, 8);
-	colors[6] = bitRangeConvert( (c1>>11)&0x1f, 5, 8);
-	colors[7] = 255;
-
-	if (c0 > c1)
-	{
-		colors[ 8] = (2*colors[0] + colors[4]) / 3;
-		colors[ 9] = (2*colors[1] + colors[5]) / 3;
-		colors[10] = (2*colors[2] + colors[6]) / 3;
-		colors[11] = 255;
-
-		colors[12] = (colors[0] + 2*colors[4]) / 3;
-		colors[13] = (colors[1] + 2*colors[5]) / 3;
-		colors[14] = (colors[2] + 2*colors[6]) / 3;
-		colors[15] = 255;
-	}
-	else
-	{
-		colors[ 8] = (colors[0] + colors[4]) / 2;
-		colors[ 9] = (colors[1] + colors[5]) / 2;
-		colors[10] = (colors[2] + colors[6]) / 2;
-		colors[11] = 255;
-		
-		colors[12] = 0;
-		colors[13] = 0;
-		colors[14] = 0;
-		colors[15] = 0;
-	}
-
-	for (uint32_t ii = 0, next = 8*4; ii < 16*4; ii += 4, next += 2)
-	{
-		int idx = ( (_src[next>>3] >> (next & 7) ) & 3) * 4;
-		_dst[ii+0] = colors[idx+0];
-		_dst[ii+1] = colors[idx+1];
-		_dst[ii+2] = colors[idx+2];
-		_dst[ii+3] = colors[idx+3];
-	}
-}
-
-void decodeBlockDxt23A(uint8_t _dst[16*4], const uint8_t _src[8])
-{
-	for (uint32_t ii = 0, next = 0; ii < 16*4; ii += 4, next += 4)
-	{
-		uint32_t c0 = (_src[next>>3] >> (next&7) ) & 0xf;
-		_dst[ii] = bitRangeConvert(c0, 4, 8);
-	}
-}
-
-void decodeBlockDxt45A(uint8_t _dst[16*4], const uint8_t _src[8])
-{
-	uint8_t alpha[8];
-	alpha[0] = _src[0];
-	alpha[1] = _src[1];
-
-	if (alpha[0] > alpha[1])
-	{
-		alpha[2] = (6*alpha[0] + 1*alpha[1]) / 7;
-		alpha[3] = (5*alpha[0] + 2*alpha[1]) / 7;
-		alpha[4] = (4*alpha[0] + 3*alpha[1]) / 7;
-		alpha[5] = (3*alpha[0] + 4*alpha[1]) / 7;
-		alpha[6] = (2*alpha[0] + 5*alpha[1]) / 7;
-		alpha[7] = (1*alpha[0] + 6*alpha[1]) / 7;
-	}
-	else
-	{
-		alpha[2] = (4*alpha[0] + 1*alpha[1]) / 5;
-		alpha[3] = (3*alpha[0] + 2*alpha[1]) / 5;
-		alpha[4] = (2*alpha[0] + 3*alpha[1]) / 5;
-		alpha[5] = (1*alpha[0] + 4*alpha[1]) / 5;
-		alpha[6] = 0;
-		alpha[7] = 255;
-	}
-
-	uint32_t idx0 = _src[2];
-	uint32_t idx1 = _src[5];
-	idx0 |= uint32_t(_src[3])<<8;
-	idx1 |= uint32_t(_src[6])<<8;
-	idx0 |= uint32_t(_src[4])<<16;
-	idx1 |= uint32_t(_src[7])<<16;
-	for (uint32_t ii = 0; ii < 8*4; ii += 4)
-	{
-		_dst[ii]    = alpha[idx0&7];
-		_dst[ii+32] = alpha[idx1&7];
-		idx0 >>= 3;
-		idx1 >>= 3;
-	}
-}
-
-uint32_t Mip::getDecodedSize() const
-{
-	return m_width*m_height*4;
-}
-
-void Mip::decode(uint8_t* _dst)
-{
-	const uint8_t* src = m_data;
-
-	if (TextureFormat::Unknown > m_type)
-	{
-		uint32_t width = m_width/4;
-		uint32_t height = m_height/4;
-		uint32_t pitch = m_width*4;
-
-		uint8_t temp[16*4];
-
-		switch (m_type)
-		{
-		case TextureFormat::BC1:
-			for (uint32_t yy = 0; yy < height; ++yy)
-			{
-				for (uint32_t xx = 0; xx < width; ++xx)
-				{
-					decodeBlockDxt1(temp, src);
-					src += 8;
-
-					uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
-					memcpy(&dst[0*pitch], &temp[ 0], 16);
-					memcpy(&dst[1*pitch], &temp[16], 16);
-					memcpy(&dst[2*pitch], &temp[32], 16);
-					memcpy(&dst[3*pitch], &temp[48], 16);
-				}
-			}
-			break;
-
-		case TextureFormat::BC2:
-			for (uint32_t yy = 0; yy < height; ++yy)
-			{
-				for (uint32_t xx = 0; xx < width; ++xx)
-				{
-					decodeBlockDxt23A(temp+3, src);
-					src += 8;
-					decodeBlockDxt(temp, src);
-					src += 8;
-
-					uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
-					memcpy(&dst[0*pitch], &temp[ 0], 16);
-					memcpy(&dst[1*pitch], &temp[16], 16);
-					memcpy(&dst[2*pitch], &temp[32], 16);
-					memcpy(&dst[3*pitch], &temp[48], 16);
-				}
-			}
-			break;
-
-		case TextureFormat::BC3:
-			for (uint32_t yy = 0; yy < height; ++yy)
-			{
-				for (uint32_t xx = 0; xx < width; ++xx)
-				{
-					decodeBlockDxt45A(temp+3, src);
-					src += 8;
-					decodeBlockDxt(temp, src);
-					src += 8;
-
-					uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
-					memcpy(&dst[0*pitch], &temp[ 0], 16);
-					memcpy(&dst[1*pitch], &temp[16], 16);
-					memcpy(&dst[2*pitch], &temp[32], 16);
-					memcpy(&dst[3*pitch], &temp[48], 16);
-				}
-			}
-			break;
-
-		case TextureFormat::BC4:
-			for (uint32_t yy = 0; yy < height; ++yy)
-			{
-				for (uint32_t xx = 0; xx < width; ++xx)
-				{
-					decodeBlockDxt45A(temp, src);
-					src += 8;
-
-					uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
-					memcpy(&dst[0*pitch], &temp[ 0], 16);
-					memcpy(&dst[1*pitch], &temp[16], 16);
-					memcpy(&dst[2*pitch], &temp[32], 16);
-					memcpy(&dst[3*pitch], &temp[48], 16);
-				}
-			}
-			break;
-
-		case TextureFormat::BC5:
-			for (uint32_t yy = 0; yy < height; ++yy)
-			{
-				for (uint32_t xx = 0; xx < width; ++xx)
-				{
-					decodeBlockDxt45A(temp+1, src);
-					src += 8;
-					decodeBlockDxt45A(temp+2, src);
-					src += 8;
-
-					for (uint32_t ii = 0; ii < 16; ++ii)
-					{
-						float nx = temp[ii*4+2]*2.0f/255.0f - 1.0f;
-						float ny = temp[ii*4+1]*2.0f/255.0f - 1.0f;
-						float nz = sqrtf(1.0f - nx*nx - ny*ny);
-						temp[ii*4+0] = uint8_t( (nz + 1.0f)*255.0f/2.0f);
-						temp[ii*4+3] = 0;
-					}
-
-					uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
-					memcpy(&dst[0*pitch], &temp[ 0], 16);
-					memcpy(&dst[1*pitch], &temp[16], 16);
-					memcpy(&dst[2*pitch], &temp[32], 16);
-					memcpy(&dst[3*pitch], &temp[48], 16);
-				}
-			}
-			break;
-		}
-	}
-	else
-	{
-		uint32_t width = m_width;
-		uint32_t height = m_height;
-
-		if (m_bpp == 8
-		||  m_bpp == 32
-		||  m_bpp == 64)
-		{
-			uint32_t pitch = m_width*m_bpp/8;
-			memcpy(_dst, src, pitch*height);
-		}
-		else
-		{
-			uint32_t pitch = m_width*4;
-			for (uint32_t yy = 0; yy < height; ++yy)
-			{
-				uint8_t* dst = &_dst[yy*pitch];
-
-				for (uint32_t xx = 0; xx < width; ++xx)
-				{
-					memcpy(dst, src, 3);
-					dst[3] = 255;
-					dst += 4;
-					src += 3;
-				}
-			}
-		}
-	}
-}
-
-bool parseDds(Dds& _dds, const Memory* _mem)
-{
-	bx::MemoryReader reader(_mem->data, _mem->size);
-
-	uint32_t magic;
-	bx::read(&reader, magic);
-
-	if (DDS_MAGIC != magic)
-	{
-		return false;
-	}
-
-	uint32_t headerSize;
-	bx::read(&reader, headerSize);
-
-	if (headerSize < DDS_HEADER_SIZE)
-	{
-		return false;
-	}
-
-	uint32_t flags;
-	bx::read(&reader, flags);
-
-	if ( (flags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) ) != (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) )
-	{
-		return false;
-	}
-
-	uint32_t height;
-	bx::read(&reader, height);
-
-	uint32_t width;
-	bx::read(&reader, width);
-
-	uint32_t pitch;
-	bx::read(&reader, pitch);
-
-	uint32_t depth;
-	bx::read(&reader, depth);
-
-	uint32_t mips;
-	bx::read(&reader, mips);
-
-	bx::skip(&reader, 44); // reserved
-	bx::skip(&reader, 4); // pixel format size
-
-	uint32_t pixelFlags;
-	bx::read(&reader, pixelFlags);
-
-	uint32_t fourcc;
-	bx::read(&reader, fourcc);
-
-	uint32_t rgbCount;
-	bx::read(&reader, rgbCount);
-
-	uint32_t rbitmask;
-	bx::read(&reader, rbitmask);
-
-	uint32_t gbitmask;
-	bx::read(&reader, gbitmask);
-
-	uint32_t bbitmask;
-	bx::read(&reader, bbitmask);
-
-	uint32_t abitmask;
-	bx::read(&reader, abitmask);
-
-	uint32_t caps[4];
-	bx::read(&reader, caps);
-
-	if ( (caps[0] & DDSCAPS_TEXTURE) == 0)
-	{
-		return false;
-	}
-
-	bool cubeMap = 0 != (caps[1] & DDSCAPS2_CUBEMAP);
-	if (cubeMap)
-	{
-		if ( (caps[1] & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)
-		{
-			// parital cube map is not supported.
-			return false;
-		}
-	}
-
-	bx::skip(&reader, 4); // reserved
-
-	uint8_t bpp = 0;
-	uint8_t blockSize = 1;
-	TextureFormat::Enum type = TextureFormat::Unknown;
-	bool hasAlpha = pixelFlags & DDPF_ALPHAPIXELS;
-
-	if (pixelFlags & DDPF_FOURCC)
-	{
-		switch (fourcc)
-		{
-		case DDS_DXT1:
-			type = TextureFormat::BC1;
-			bpp = 4;
-			blockSize = 4*4*bpp/8;
-			break;
-
-		case DDS_DXT2:
-		case DDS_DXT3:
-			type = TextureFormat::BC2;
-			bpp = 8;
-			blockSize = 4*4*bpp/8;
-			break;
-
-		case DDS_DXT4:
-		case DDS_DXT5:
-			type = TextureFormat::BC3;
-			bpp = 8;
-			blockSize = 4*4*bpp/8;
-			break;
-
-		case DDS_ATI1:
-		case DDS_BC4U:
-			type = TextureFormat::BC4;
-			bpp = 4;
-			blockSize = 4*4*bpp/8;
-			break;
-
-		case DDS_ATI2:
-		case DDS_BC5U:
-			type = TextureFormat::BC5;
-			bpp = 8;
-			blockSize = 4*4*bpp/8;
-			break;
-
-		case D3DFMT_A16B16G16R16:
-			type = TextureFormat::RGBA16;
-			blockSize = 8;
-			bpp = 64;
-			break;
-
-		case D3DFMT_A16B16G16R16F:
-			type = TextureFormat::RGBA16F;
-			blockSize = 8;
-			bpp = 64;
-			break;
-		}
-	}
-	else
-	{
-		switch (pixelFlags)
-		{
-		case DDPF_RGB:
-			type = TextureFormat::BGRX8;
-			blockSize = 3;
-			bpp = 24;
-			break;
-
-		case DDPF_RGB|DDPF_ALPHAPIXELS:
-			type = TextureFormat::BGRA8;
-			blockSize = 4;
-			bpp = 32;
-			break;
-
-		case DDPF_INDEXED:
-		case DDPF_LUMINANCE:
-		case DDPF_ALPHA:
-			type = TextureFormat::L8;
-			bpp = 8;
-			break;
-
-// 			type = TextureFormat::A8;
-// 			bpp = 1;
-// 			break;
-
-		default:
-			bpp = 0;
-			break;
-		}
-	}
-
-	_dds.m_type = type;
-	_dds.m_width = width;
-	_dds.m_height = height;
-	_dds.m_depth = depth;
-	_dds.m_blockSize = blockSize;
-	_dds.m_numMips = (caps[0] & DDSCAPS_MIPMAP) ? mips : 1;
-	_dds.m_bpp = bpp;
-	_dds.m_hasAlpha = hasAlpha;
-	_dds.m_cubeMap = cubeMap;
-
-	return true;
-}
-
-bool getRawImageData(const Dds& _dds, uint8_t _side, uint8_t _lod, const Memory* _mem, Mip& _mip)
-{
-	uint32_t blockSize = _dds.m_blockSize;
-	uint32_t offset = DDS_IMAGE_DATA_OFFSET;
-	uint8_t bpp = _dds.m_bpp;
-	TextureFormat::Enum type = _dds.m_type;
-	bool hasAlpha = _dds.m_hasAlpha;
-
-	for (uint8_t side = 0, numSides = _dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
-	{
-		uint32_t width = _dds.m_width;
-		uint32_t height = _dds.m_height;
-		uint32_t depth = _dds.m_depth;
-
-		for (uint8_t lod = 0, num = _dds.m_numMips; lod < num; ++lod)
-		{
-			width = bx::uint32_max(1, width);
-			height = bx::uint32_max(1, height);
-			depth = bx::uint32_max(1, depth);
-
-			uint32_t size = width*height*depth*blockSize;
-			if (TextureFormat::Unknown > type)
-			{
-				width = bx::uint32_max(1, (width + 3)>>2);
-				height = bx::uint32_max(1, (height + 3)>>2);
-				size = width*height*depth*blockSize;
-
-				width <<= 2;
-				height <<= 2;
-			}
-
-			if (side == _side
-			&&  lod == _lod)
-			{
-				_mip.m_width = width;
-				_mip.m_height = height;
-				_mip.m_blockSize = blockSize;
-				_mip.m_size = size;
-				_mip.m_data = _mem->data + offset;
-				_mip.m_bpp = bpp;
-				_mip.m_type = type;
-				_mip.m_hasAlpha = hasAlpha;
-				return true;
-			}
-
-			offset += size;
-
-			width >>= 1;
-			height >>= 1;
-			depth >>= 1;
-		}
-	}
-
-	return false;
-}
-
-} // namespace bgfx

+ 0 - 47
src/dds.h

@@ -1,47 +0,0 @@
-/*
- * Copyright 2011-2013 Branimir Karadzic. All rights reserved.
- * License: http://www.opensource.org/licenses/BSD-2-Clause
- */
-
-#ifndef __DDS_H__
-#define __DDS_H__
-
-#include <stdint.h>
-
-namespace bgfx
-{
-	struct Dds
-	{
-		TextureFormat::Enum m_type;
-		uint32_t m_width;
-		uint32_t m_height;
-		uint32_t m_depth;
-		uint8_t m_blockSize;
-		uint8_t m_numMips;
-		uint8_t m_bpp;
-		bool m_hasAlpha;
-		bool m_cubeMap;
-	};
-
-	struct Mip
-	{
-		uint32_t m_width;
-		uint32_t m_height;
-		uint32_t m_blockSize;
-		uint32_t m_size;
-		uint8_t m_bpp;
-		uint8_t m_type;
-		bool m_hasAlpha;
-		const uint8_t* m_data;
-
-		uint32_t getDecodedSize() const;
-		void decode(uint8_t* _dst);
-	};
-
-	bool isDds(const Memory* _mem);
-	bool parseDds(Dds& _dds, const Memory* _mem);
-	bool getRawImageData(const Dds& _dds, uint8_t _side, uint8_t _index, const Memory* _mem, Mip& _mip);
-
-} // namespace bgfx
-
-#endif // __DDS_H__

+ 876 - 2
src/image.cpp

@@ -5,7 +5,83 @@
 
 #include "bgfx_p.h"
 #include <bx/float4_t.h>
-#include <math.h> // powf
+#include <math.h> // powf, sqrtf
+
+#include "image.h"
+
+#define DDS_MAGIC             BX_MAKEFOURCC('D', 'D', 'S', ' ')
+#define DDS_HEADER_SIZE       124
+#define DDS_IMAGE_DATA_OFFSET (DDS_HEADER_SIZE + 4)
+
+#define DDS_DXT1 BX_MAKEFOURCC('D', 'X', 'T', '1')
+#define DDS_DXT2 BX_MAKEFOURCC('D', 'X', 'T', '2')
+#define DDS_DXT3 BX_MAKEFOURCC('D', 'X', 'T', '3')
+#define DDS_DXT4 BX_MAKEFOURCC('D', 'X', 'T', '4')
+#define DDS_DXT5 BX_MAKEFOURCC('D', 'X', 'T', '5')
+#define DDS_ATI1 BX_MAKEFOURCC('A', 'T', 'I', '1')
+#define DDS_BC4U BX_MAKEFOURCC('B', 'C', '4', 'U')
+#define DDS_ATI2 BX_MAKEFOURCC('A', 'T', 'I', '2')
+#define DDS_BC5U BX_MAKEFOURCC('B', 'C', '5', 'U')
+
+#define D3DFMT_A16B16G16R16  36
+#define D3DFMT_A16B16G16R16F 113
+
+#define DDSD_CAPS                   0x00000001
+#define DDSD_HEIGHT                 0x00000002
+#define DDSD_WIDTH                  0x00000004
+#define DDSD_PITCH                  0x00000008
+#define DDSD_PIXELFORMAT            0x00001000
+#define DDSD_MIPMAPCOUNT            0x00020000
+#define DDSD_LINEARSIZE             0x00080000
+#define DDSD_DEPTH                  0x00800000
+
+#define DDPF_ALPHAPIXELS            0x00000001
+#define DDPF_ALPHA                  0x00000002
+#define DDPF_FOURCC                 0x00000004
+#define DDPF_INDEXED                0x00000020
+#define DDPF_RGB                    0x00000040
+#define DDPF_YUV                    0x00000200
+#define DDPF_LUMINANCE              0x00020000
+
+#define DDSCAPS_COMPLEX             0x00000008
+#define DDSCAPS_TEXTURE             0x00001000
+#define DDSCAPS_MIPMAP              0x00400000
+
+#define DDSCAPS2_CUBEMAP            0x00000200
+#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
+#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
+#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
+#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
+#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
+#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
+
+#define DDS_CUBEMAP_ALLFACES (DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX \
+							 |DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY \
+							 |DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ)
+
+#define DDSCAPS2_VOLUME             0x00200000
+
+#define KTX_MAGIC       BX_MAKEFOURCC(0xAB, 'K', 'T', 'X')
+#define KTX_HEADER_SIZE 64
+
+#define KTX_ETC1_RGB8_OES                             0x8D64
+#define KTX_COMPRESSED_R11_EAC                        0x9270
+#define KTX_COMPRESSED_SIGNED_R11_EAC                 0x9271
+#define KTX_COMPRESSED_RG11_EAC                       0x9272
+#define KTX_COMPRESSED_SIGNED_RG11_EAC                0x9273
+#define KTX_COMPRESSED_RGB8_ETC2                      0x9274
+#define KTX_COMPRESSED_SRGB8_ETC2                     0x9275
+#define KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2  0x9276
+#define KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define KTX_COMPRESSED_RGBA8_ETC2_EAC                 0x9278
+#define KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC          0x9279
+#define KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG           0x8C00
+#define KTX_COMPRESSED_RGB_PVRTC_2BPPV1_IMG           0x8C01
+#define KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG          0x8C02
+#define KTX_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG          0x8C03
+
+#define PKM_MAGIC       BX_MAKEFOURCC('P', 'K', 'M', 0)
+#define PKM_HEADER_SIZE 16
 
 namespace bgfx
 {
@@ -163,7 +239,7 @@ namespace bgfx
 		}
 	}
 
-	static void imageSwizzleBgra8Ref(uint32_t _width, uint32_t _height, const void* _src, void* _dst)
+	void imageSwizzleBgra8Ref(uint32_t _width, uint32_t _height, const void* _src, void* _dst)
 	{
 		const uint8_t* src = (uint8_t*) _src;
 		uint8_t* dst = (uint8_t*)_dst;
@@ -260,4 +336,802 @@ namespace bgfx
 		}
 	}
 
+	uint32_t bitRangeConvert(uint32_t _in, uint32_t _from, uint32_t _to)
+	{
+		using namespace bx;
+		uint32_t tmp0   = uint32_sll(1, _to);
+		uint32_t tmp1   = uint32_sll(1, _from);
+		uint32_t tmp2   = uint32_dec(tmp0);
+		uint32_t tmp3   = uint32_dec(tmp1);
+		uint32_t tmp4   = uint32_mul(_in, tmp2);
+		uint32_t tmp5   = uint32_add(tmp3, tmp4);
+		uint32_t tmp6   = uint32_srl(tmp5, _from);
+		uint32_t tmp7   = uint32_add(tmp5, tmp6);
+		uint32_t result = uint32_srl(tmp7, _from);
+
+		return result;
+	}
+
+	void decodeBlockDxt(uint8_t _dst[16*4], const uint8_t _src[8])
+	{
+		uint8_t colors[4*3];
+
+		uint32_t c0 = _src[0] | (_src[1] << 8);
+		colors[0] = bitRangeConvert( (c0>> 0)&0x1f, 5, 8);
+		colors[1] = bitRangeConvert( (c0>> 5)&0x3f, 6, 8);
+		colors[2] = bitRangeConvert( (c0>>11)&0x1f, 5, 8);
+
+		uint32_t c1 = _src[2] | (_src[3] << 8);
+		colors[3] = bitRangeConvert( (c1>> 0)&0x1f, 5, 8);
+		colors[4] = bitRangeConvert( (c1>> 5)&0x3f, 6, 8);
+		colors[5] = bitRangeConvert( (c1>>11)&0x1f, 5, 8);
+
+		colors[6] = (2*colors[0] + colors[3]) / 3;
+		colors[7] = (2*colors[1] + colors[4]) / 3;
+		colors[8] = (2*colors[2] + colors[5]) / 3;
+
+		colors[ 9] = (colors[0] + 2*colors[3]) / 3;
+		colors[10] = (colors[1] + 2*colors[4]) / 3;
+		colors[11] = (colors[2] + 2*colors[5]) / 3;
+
+		for (uint32_t ii = 0, next = 8*4; ii < 16*4; ii += 4, next += 2)
+		{
+			int idx = ( (_src[next>>3] >> (next & 7) ) & 3) * 3;
+			_dst[ii+0] = colors[idx+0];
+			_dst[ii+1] = colors[idx+1];
+			_dst[ii+2] = colors[idx+2];
+		}
+	}
+
+	void decodeBlockDxt1(uint8_t _dst[16*4], const uint8_t _src[8])
+	{
+		uint8_t colors[4*4];
+
+		uint32_t c0 = _src[0] | (_src[1] << 8);
+		colors[0] = bitRangeConvert( (c0>> 0)&0x1f, 5, 8);
+		colors[1] = bitRangeConvert( (c0>> 5)&0x3f, 6, 8);
+		colors[2] = bitRangeConvert( (c0>>11)&0x1f, 5, 8);
+		colors[3] = 255;
+
+		uint32_t c1 = _src[2] | (_src[3] << 8);
+		colors[4] = bitRangeConvert( (c1>> 0)&0x1f, 5, 8);
+		colors[5] = bitRangeConvert( (c1>> 5)&0x3f, 6, 8);
+		colors[6] = bitRangeConvert( (c1>>11)&0x1f, 5, 8);
+		colors[7] = 255;
+
+		if (c0 > c1)
+		{
+			colors[ 8] = (2*colors[0] + colors[4]) / 3;
+			colors[ 9] = (2*colors[1] + colors[5]) / 3;
+			colors[10] = (2*colors[2] + colors[6]) / 3;
+			colors[11] = 255;
+
+			colors[12] = (colors[0] + 2*colors[4]) / 3;
+			colors[13] = (colors[1] + 2*colors[5]) / 3;
+			colors[14] = (colors[2] + 2*colors[6]) / 3;
+			colors[15] = 255;
+		}
+		else
+		{
+			colors[ 8] = (colors[0] + colors[4]) / 2;
+			colors[ 9] = (colors[1] + colors[5]) / 2;
+			colors[10] = (colors[2] + colors[6]) / 2;
+			colors[11] = 255;
+			
+			colors[12] = 0;
+			colors[13] = 0;
+			colors[14] = 0;
+			colors[15] = 0;
+		}
+
+		for (uint32_t ii = 0, next = 8*4; ii < 16*4; ii += 4, next += 2)
+		{
+			int idx = ( (_src[next>>3] >> (next & 7) ) & 3) * 4;
+			_dst[ii+0] = colors[idx+0];
+			_dst[ii+1] = colors[idx+1];
+			_dst[ii+2] = colors[idx+2];
+			_dst[ii+3] = colors[idx+3];
+		}
+	}
+
+	void decodeBlockDxt23A(uint8_t _dst[16*4], const uint8_t _src[8])
+	{
+		for (uint32_t ii = 0, next = 0; ii < 16*4; ii += 4, next += 4)
+		{
+			uint32_t c0 = (_src[next>>3] >> (next&7) ) & 0xf;
+			_dst[ii] = bitRangeConvert(c0, 4, 8);
+		}
+	}
+
+	void decodeBlockDxt45A(uint8_t _dst[16*4], const uint8_t _src[8])
+	{
+		uint8_t alpha[8];
+		alpha[0] = _src[0];
+		alpha[1] = _src[1];
+
+		if (alpha[0] > alpha[1])
+		{
+			alpha[2] = (6*alpha[0] + 1*alpha[1]) / 7;
+			alpha[3] = (5*alpha[0] + 2*alpha[1]) / 7;
+			alpha[4] = (4*alpha[0] + 3*alpha[1]) / 7;
+			alpha[5] = (3*alpha[0] + 4*alpha[1]) / 7;
+			alpha[6] = (2*alpha[0] + 5*alpha[1]) / 7;
+			alpha[7] = (1*alpha[0] + 6*alpha[1]) / 7;
+		}
+		else
+		{
+			alpha[2] = (4*alpha[0] + 1*alpha[1]) / 5;
+			alpha[3] = (3*alpha[0] + 2*alpha[1]) / 5;
+			alpha[4] = (2*alpha[0] + 3*alpha[1]) / 5;
+			alpha[5] = (1*alpha[0] + 4*alpha[1]) / 5;
+			alpha[6] = 0;
+			alpha[7] = 255;
+		}
+
+		uint32_t idx0 = _src[2];
+		uint32_t idx1 = _src[5];
+		idx0 |= uint32_t(_src[3])<<8;
+		idx1 |= uint32_t(_src[6])<<8;
+		idx0 |= uint32_t(_src[4])<<16;
+		idx1 |= uint32_t(_src[7])<<16;
+		for (uint32_t ii = 0; ii < 8*4; ii += 4)
+		{
+			_dst[ii]    = alpha[idx0&7];
+			_dst[ii+32] = alpha[idx1&7];
+			idx0 >>= 3;
+			idx1 >>= 3;
+		}
+	}
+
+	static const int32_t s_mod[8][4] =
+	{
+		{  2,   8,  -2,   -8},
+		{ 15,  17, -15,  -17},
+		{  9,  29,  -9,  -29},
+		{ 13,  42, -13,  -42},
+		{ 18,  60, -18,  -60},
+		{ 24,  80, -24,  -80},
+		{ 33, 106, -33, -106},
+		{ 47, 183, -47, -183},
+	};
+
+	int8_t uint8_add2c(int32_t _a, int32_t _b)
+	{
+		return _b & 0x4
+			? _a - ( (~_b + 1) & 0x7)
+			: _a + _b
+			;
+	}
+
+	int8_t uint8_satadd(int32_t _a, int32_t _b)
+	{
+		using namespace bx;
+		const  int32_t add    = _a + _b;
+		const uint32_t min    = uint32_min(add, 255);
+		const uint32_t result = uint32_max(min, 0);
+		return result;
+	}
+
+	void decodeBlockEtc1(uint8_t _dst[16*4], const uint8_t _src[8])
+	{
+		bool flipBit = 0 != (_src[3] & 0x1);
+		bool diffBit = 0 != (_src[3] & 0x2);
+
+		uint8_t rgb[8];
+
+		if (diffBit)
+		{
+			rgb[0]  = _src[0] >> 3;
+			rgb[1]  = _src[1] >> 3;
+			rgb[2]  = _src[2] >> 3;
+
+			uint8_t diff[3];
+			diff[0] = _src[0] & 0x07;
+			diff[1] = _src[1] & 0x07;
+			diff[2] = _src[2] & 0x07;
+
+			rgb[4] = uint8_add2c(rgb[0], diff[0]);
+			rgb[5] = uint8_add2c(rgb[1], diff[1]);
+			rgb[6] = uint8_add2c(rgb[2], diff[2]);
+
+			rgb[0] = bitRangeConvert(rgb[0], 5, 8);
+			rgb[1] = bitRangeConvert(rgb[1], 5, 8);
+			rgb[2] = bitRangeConvert(rgb[2], 5, 8);
+			rgb[4] = bitRangeConvert(rgb[4], 5, 8);
+			rgb[5] = bitRangeConvert(rgb[5], 5, 8);
+			rgb[6] = bitRangeConvert(rgb[6], 5, 8);
+		}
+		else
+		{
+			rgb[0] = _src[0] >> 4;
+			rgb[1] = _src[1] >> 4;
+			rgb[2] = _src[2] >> 4;
+
+			rgb[4] = _src[0] & 0xf;
+			rgb[5] = _src[1] & 0xf;
+			rgb[6] = _src[2] & 0xf;
+
+			rgb[0] = bitRangeConvert(rgb[0], 4, 8);
+			rgb[1] = bitRangeConvert(rgb[1], 4, 8);
+			rgb[2] = bitRangeConvert(rgb[2], 4, 8);
+			rgb[4] = bitRangeConvert(rgb[4], 4, 8);
+			rgb[5] = bitRangeConvert(rgb[5], 4, 8);
+			rgb[6] = bitRangeConvert(rgb[6], 4, 8);
+		}
+
+		uint32_t table[2];
+		table[0] = (_src[3] >> 5) & 0x7;
+		table[1] = (_src[3] >> 2) & 0x7;
+
+		uint32_t indexBits = 0
+						| (_src[4]<<24)
+						| (_src[5]<<16)
+						| (_src[6]<< 8)
+						| (_src[7]    )
+						;
+
+		if (flipBit)
+		{
+			for (uint32_t ii = 0; ii < 16; ++ii)
+			{
+				const uint32_t block = (ii>>1)&1;
+				const uint32_t color = block<<2;
+				const uint32_t idx   = (ii&0xc) | ( (ii & 0x3)<<4);
+				const uint32_t lsbi  = (indexBits >> ii) & 1;
+				const uint32_t msbi  = (indexBits >> (16 + ii) ) & 1;
+				const  int32_t mod   = s_mod[table[block] ][lsbi + msbi*2];
+
+				_dst[idx + 0] = uint8_satadd(rgb[color+2], mod);
+				_dst[idx + 1] = uint8_satadd(rgb[color+1], mod);
+				_dst[idx + 2] = uint8_satadd(rgb[color+0], mod);
+			}
+		}
+		else
+		{
+			for (uint32_t ii = 0; ii < 16; ++ii)
+			{
+				const uint32_t block = ii>>3;
+				const uint32_t color = block<<2;
+				const uint32_t idx   = (ii&0xc) | ( (ii & 0x3)<<4);
+				const uint32_t lsbi  = (indexBits >> ii) & 1;
+				const uint32_t msbi  = (indexBits >> (16 + ii) ) & 1;
+				const  int32_t mod   = s_mod[table[block] ][lsbi + msbi*2];
+
+				_dst[idx + 0] = uint8_satadd(rgb[color+2], mod);
+				_dst[idx + 1] = uint8_satadd(rgb[color+1], mod);
+				_dst[idx + 2] = uint8_satadd(rgb[color+0], mod);
+			}
+		}
+	}
+
+	void Mip::decode(uint8_t* _dst)
+	{
+		const uint8_t* src = m_data;
+
+		if (TextureFormat::Unknown > m_type)
+		{
+			uint32_t width = m_width/4;
+			uint32_t height = m_height/4;
+			uint32_t pitch = m_width*4;
+
+			uint8_t temp[16*4];
+
+			switch (m_type)
+			{
+			case TextureFormat::BC1:
+				for (uint32_t yy = 0; yy < height; ++yy)
+				{
+					for (uint32_t xx = 0; xx < width; ++xx)
+					{
+						decodeBlockDxt1(temp, src);
+						src += 8;
+
+						uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
+						memcpy(&dst[0*pitch], &temp[ 0], 16);
+						memcpy(&dst[1*pitch], &temp[16], 16);
+						memcpy(&dst[2*pitch], &temp[32], 16);
+						memcpy(&dst[3*pitch], &temp[48], 16);
+					}
+				}
+				break;
+
+			case TextureFormat::BC2:
+				for (uint32_t yy = 0; yy < height; ++yy)
+				{
+					for (uint32_t xx = 0; xx < width; ++xx)
+					{
+						decodeBlockDxt23A(temp+3, src);
+						src += 8;
+						decodeBlockDxt(temp, src);
+						src += 8;
+
+						uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
+						memcpy(&dst[0*pitch], &temp[ 0], 16);
+						memcpy(&dst[1*pitch], &temp[16], 16);
+						memcpy(&dst[2*pitch], &temp[32], 16);
+						memcpy(&dst[3*pitch], &temp[48], 16);
+					}
+				}
+				break;
+
+			case TextureFormat::BC3:
+				for (uint32_t yy = 0; yy < height; ++yy)
+				{
+					for (uint32_t xx = 0; xx < width; ++xx)
+					{
+						decodeBlockDxt45A(temp+3, src);
+						src += 8;
+						decodeBlockDxt(temp, src);
+						src += 8;
+
+						uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
+						memcpy(&dst[0*pitch], &temp[ 0], 16);
+						memcpy(&dst[1*pitch], &temp[16], 16);
+						memcpy(&dst[2*pitch], &temp[32], 16);
+						memcpy(&dst[3*pitch], &temp[48], 16);
+					}
+				}
+				break;
+
+			case TextureFormat::BC4:
+				for (uint32_t yy = 0; yy < height; ++yy)
+				{
+					for (uint32_t xx = 0; xx < width; ++xx)
+					{
+						decodeBlockDxt45A(temp, src);
+						src += 8;
+
+						uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
+						memcpy(&dst[0*pitch], &temp[ 0], 16);
+						memcpy(&dst[1*pitch], &temp[16], 16);
+						memcpy(&dst[2*pitch], &temp[32], 16);
+						memcpy(&dst[3*pitch], &temp[48], 16);
+					}
+				}
+				break;
+
+			case TextureFormat::BC5:
+				for (uint32_t yy = 0; yy < height; ++yy)
+				{
+					for (uint32_t xx = 0; xx < width; ++xx)
+					{
+						decodeBlockDxt45A(temp+1, src);
+						src += 8;
+						decodeBlockDxt45A(temp+2, src);
+						src += 8;
+
+						for (uint32_t ii = 0; ii < 16; ++ii)
+						{
+							float nx = temp[ii*4+2]*2.0f/255.0f - 1.0f;
+							float ny = temp[ii*4+1]*2.0f/255.0f - 1.0f;
+							float nz = sqrtf(1.0f - nx*nx - ny*ny);
+							temp[ii*4+0] = uint8_t( (nz + 1.0f)*255.0f/2.0f);
+							temp[ii*4+3] = 0;
+						}
+
+						uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
+						memcpy(&dst[0*pitch], &temp[ 0], 16);
+						memcpy(&dst[1*pitch], &temp[16], 16);
+						memcpy(&dst[2*pitch], &temp[32], 16);
+						memcpy(&dst[3*pitch], &temp[48], 16);
+					}
+				}
+				break;
+
+			case TextureFormat::ETC1:
+				for (uint32_t yy = 0; yy < height; ++yy)
+				{
+					for (uint32_t xx = 0; xx < width; ++xx)
+					{
+						decodeBlockEtc1(temp, src);
+						src += 8;
+
+						uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
+						memcpy(&dst[0*pitch], &temp[ 0], 16);
+						memcpy(&dst[1*pitch], &temp[16], 16);
+						memcpy(&dst[2*pitch], &temp[32], 16);
+						memcpy(&dst[3*pitch], &temp[48], 16);
+					}
+				}
+				break;
+			}
+		}
+		else
+		{
+			uint32_t width = m_width;
+			uint32_t height = m_height;
+
+			if (m_bpp == 8
+			||  m_bpp == 32
+			||  m_bpp == 64)
+			{
+				uint32_t pitch = m_width*m_bpp/8;
+				memcpy(_dst, src, pitch*height);
+			}
+			else
+			{
+				uint32_t pitch = m_width*4;
+				for (uint32_t yy = 0; yy < height; ++yy)
+				{
+					uint8_t* dst = &_dst[yy*pitch];
+
+					for (uint32_t xx = 0; xx < width; ++xx)
+					{
+						memcpy(dst, src, 3);
+						dst[3] = 255;
+						dst += 4;
+						src += 3;
+					}
+				}
+			}
+		}
+	}
+
+	bool imageParseDds(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader)
+	{
+		uint32_t headerSize;
+		bx::read(_reader, headerSize);
+
+		if (headerSize < DDS_HEADER_SIZE)
+		{
+			return false;
+		}
+
+		uint32_t flags;
+		bx::read(_reader, flags);
+
+		if ( (flags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) ) != (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) )
+		{
+			return false;
+		}
+
+		uint32_t height;
+		bx::read(_reader, height);
+
+		uint32_t width;
+		bx::read(_reader, width);
+
+		uint32_t pitch;
+		bx::read(_reader, pitch);
+
+		uint32_t depth;
+		bx::read(_reader, depth);
+
+		uint32_t mips;
+		bx::read(_reader, mips);
+
+		bx::skip(_reader, 44); // reserved
+		bx::skip(_reader, 4); // pixel format size
+
+		uint32_t pixelFlags;
+		bx::read(_reader, pixelFlags);
+
+		uint32_t fourcc;
+		bx::read(_reader, fourcc);
+
+		uint32_t rgbCount;
+		bx::read(_reader, rgbCount);
+
+		uint32_t rbitmask;
+		bx::read(_reader, rbitmask);
+
+		uint32_t gbitmask;
+		bx::read(_reader, gbitmask);
+
+		uint32_t bbitmask;
+		bx::read(_reader, bbitmask);
+
+		uint32_t abitmask;
+		bx::read(_reader, abitmask);
+
+		uint32_t caps[4];
+		bx::read(_reader, caps);
+
+		if ( (caps[0] & DDSCAPS_TEXTURE) == 0)
+		{
+			return false;
+		}
+
+		bool cubeMap = 0 != (caps[1] & DDSCAPS2_CUBEMAP);
+		if (cubeMap)
+		{
+			if ( (caps[1] & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)
+			{
+				// parital cube map is not supported.
+				return false;
+			}
+		}
+
+		bx::skip(_reader, 4); // reserved
+
+		uint8_t bpp = 0;
+		uint8_t blockSize = 1;
+		TextureFormat::Enum type = TextureFormat::Unknown;
+		bool hasAlpha = pixelFlags & DDPF_ALPHAPIXELS;
+
+		if (pixelFlags & DDPF_FOURCC)
+		{
+			switch (fourcc)
+			{
+			case DDS_DXT1:
+				type = TextureFormat::BC1;
+				bpp = 4;
+				blockSize = 4*4*bpp/8;
+				break;
+
+			case DDS_DXT2:
+			case DDS_DXT3:
+				type = TextureFormat::BC2;
+				bpp = 8;
+				blockSize = 4*4*bpp/8;
+				break;
+
+			case DDS_DXT4:
+			case DDS_DXT5:
+				type = TextureFormat::BC3;
+				bpp = 8;
+				blockSize = 4*4*bpp/8;
+				break;
+
+			case DDS_ATI1:
+			case DDS_BC4U:
+				type = TextureFormat::BC4;
+				bpp = 4;
+				blockSize = 4*4*bpp/8;
+				break;
+
+			case DDS_ATI2:
+			case DDS_BC5U:
+				type = TextureFormat::BC5;
+				bpp = 8;
+				blockSize = 4*4*bpp/8;
+				break;
+
+			case D3DFMT_A16B16G16R16:
+				type = TextureFormat::RGBA16;
+				blockSize = 8;
+				bpp = 64;
+				break;
+
+			case D3DFMT_A16B16G16R16F:
+				type = TextureFormat::RGBA16F;
+				blockSize = 8;
+				bpp = 64;
+				break;
+			}
+		}
+		else
+		{
+			switch (pixelFlags)
+			{
+			case DDPF_RGB:
+				type = TextureFormat::BGRX8;
+				blockSize = 3;
+				bpp = 24;
+				break;
+
+			case DDPF_RGB|DDPF_ALPHAPIXELS:
+				type = TextureFormat::BGRA8;
+				blockSize = 4;
+				bpp = 32;
+				break;
+
+			case DDPF_INDEXED:
+			case DDPF_LUMINANCE:
+			case DDPF_ALPHA:
+				type = TextureFormat::L8;
+				bpp = 8;
+				break;
+
+	// 			type = TextureFormat::A8;
+	// 			bpp = 1;
+	// 			break;
+
+			default:
+				bpp = 0;
+				break;
+			}
+		}
+
+		_imageContainer.m_type = type;
+		_imageContainer.m_offset = DDS_IMAGE_DATA_OFFSET;
+		_imageContainer.m_width = width;
+		_imageContainer.m_height = height;
+		_imageContainer.m_depth = depth;
+		_imageContainer.m_blockSize = blockSize;
+		_imageContainer.m_numMips = (caps[0] & DDSCAPS_MIPMAP) ? mips : 1;
+		_imageContainer.m_bpp = bpp;
+		_imageContainer.m_hasAlpha = hasAlpha;
+		_imageContainer.m_cubeMap = cubeMap;
+		_imageContainer.m_ktx = false;
+
+		return TextureFormat::Unknown != type;
+	}
+
+	bool imageParseKtx(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader)
+	{
+		uint8_t identifier[8];
+		bx::read(_reader, identifier);
+
+		if (identifier[1] != '1'
+		&&  identifier[2] != '1')
+		{
+			return false;
+		}
+
+		uint32_t endianness;
+		bx::read(_reader, endianness);
+
+		bool fromLittleEndian = 0x04030201 == endianness;
+
+		uint32_t glType;
+		bx::readHE(_reader, glType, fromLittleEndian);
+
+		uint32_t glTypeSize;
+		bx::readHE(_reader, glTypeSize, fromLittleEndian);
+
+		uint32_t glFormat;
+		bx::readHE(_reader, glFormat, fromLittleEndian);
+
+		uint32_t glInternalFormat;
+		bx::readHE(_reader, glInternalFormat, fromLittleEndian);
+
+		uint32_t glBaseInternalFormat;
+		bx::readHE(_reader, glBaseInternalFormat, fromLittleEndian);
+
+		uint32_t pixelWidth;
+		bx::readHE(_reader, pixelWidth, fromLittleEndian);
+
+		uint32_t pixelHeight;
+		bx::readHE(_reader, pixelHeight, fromLittleEndian);
+
+		uint32_t pixelDepth;
+		bx::readHE(_reader, pixelDepth, fromLittleEndian);
+
+		uint32_t numberOfArrayElements;
+		bx::readHE(_reader, numberOfArrayElements, fromLittleEndian);
+
+		uint32_t numberOfFaces;
+		bx::readHE(_reader, numberOfFaces, fromLittleEndian);
+
+		uint32_t numberOfMipmapLevels;
+		bx::readHE(_reader, numberOfMipmapLevels, fromLittleEndian);
+
+		uint32_t bytesOfKeyValueData;
+		bx::readHE(_reader, bytesOfKeyValueData, fromLittleEndian);
+
+		// skip meta garbage...
+		int64_t offset = bx::skip(_reader, bytesOfKeyValueData);
+
+		uint8_t bpp = 0;
+		uint8_t blockSize = 1;
+		TextureFormat::Enum type = TextureFormat::Unknown;
+		bool hasAlpha = false;
+
+		switch (glInternalFormat)
+		{
+		case KTX_ETC1_RGB8_OES:
+			type = TextureFormat::ETC1;
+			bpp = 4;
+			blockSize = 4*4*bpp/8;
+			break;
+
+		case KTX_COMPRESSED_R11_EAC:
+		case KTX_COMPRESSED_SIGNED_R11_EAC:
+		case KTX_COMPRESSED_RG11_EAC:
+		case KTX_COMPRESSED_SIGNED_RG11_EAC:
+		case KTX_COMPRESSED_RGB8_ETC2:
+		case KTX_COMPRESSED_SRGB8_ETC2:
+		case KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+		case KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+		case KTX_COMPRESSED_RGBA8_ETC2_EAC:
+		case KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+		case KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+		case KTX_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+		case KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+		case KTX_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
+		default:
+			break;
+		}
+
+		_imageContainer.m_type = type;
+		_imageContainer.m_offset = (uint32_t)offset;
+		_imageContainer.m_width = pixelWidth;
+		_imageContainer.m_height = pixelHeight;
+		_imageContainer.m_depth = pixelDepth;
+		_imageContainer.m_blockSize = blockSize;
+		_imageContainer.m_numMips = numberOfMipmapLevels;
+		_imageContainer.m_bpp = bpp;
+		_imageContainer.m_hasAlpha = hasAlpha;
+		_imageContainer.m_cubeMap = numberOfFaces > 1;
+		_imageContainer.m_ktx = true;
+
+		return TextureFormat::Unknown != type;
+	}
+
+	bool imageParse(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader)
+	{
+		uint32_t magic;
+		bx::read(_reader, magic);
+
+		if (DDS_MAGIC == magic)
+		{
+			return imageParseDds(_imageContainer, _reader);
+		}
+		else if (KTX_MAGIC == magic)
+		{
+			return imageParseKtx(_imageContainer, _reader);
+		}
+
+		return false;
+	}
+
+	bool imageParse(ImageContainer& _imageContainer, const void* _data, uint32_t _size)
+	{
+		bx::MemoryReader reader(_data, _size);
+		return imageParse(_imageContainer, &reader);
+	}
+
+	bool imageGetRawData(const ImageContainer& _imageContainer, uint8_t _side, uint8_t _lod, const void* _data, uint32_t _size, Mip& _mip)
+	{
+		const uint32_t blockSize = _imageContainer.m_blockSize;
+		uint32_t offset = _imageContainer.m_offset;
+		const uint8_t bpp = _imageContainer.m_bpp;
+		TextureFormat::Enum type = _imageContainer.m_type;
+		bool hasAlpha = _imageContainer.m_hasAlpha;
+
+		for (uint8_t side = 0, numSides = _imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
+		{
+			uint32_t width  = _imageContainer.m_width;
+			uint32_t height = _imageContainer.m_height;
+			uint32_t depth  = _imageContainer.m_depth;
+
+			for (uint8_t lod = 0, num = _imageContainer.m_numMips; lod < num; ++lod)
+			{
+				// skip imageSize in KTX format.
+				offset += _imageContainer.m_ktx ? sizeof(uint32_t) : 0;
+
+				width  = bx::uint32_max(1, width);
+				height = bx::uint32_max(1, height);
+				depth  = bx::uint32_max(1, depth);
+
+				uint32_t size = width*height*depth*blockSize;
+				if (TextureFormat::Unknown > type)
+				{
+					width  = bx::uint32_max(1, (width + 3)>>2);
+					height = bx::uint32_max(1, (height + 3)>>2);
+					size   = width*height*depth*blockSize;
+
+					width  <<= 2;
+					height <<= 2;
+				}
+
+				if (side == _side
+				&&  lod == _lod)
+				{
+					_mip.m_width = width;
+					_mip.m_height = height;
+					_mip.m_blockSize = blockSize;
+					_mip.m_size = size;
+					_mip.m_data = (const uint8_t*)_data + offset;
+					_mip.m_bpp = bpp;
+					_mip.m_type = type;
+					_mip.m_hasAlpha = hasAlpha;
+					return true;
+				}
+
+				offset += size;
+
+				BX_CHECK(offset <= _size, "Reading past size of data buffer! (offset %d, size %d)", offset, _size);
+				BX_UNUSED(_size);
+
+				width  >>= 1;
+				height >>= 1;
+				depth  >>= 1;
+			}
+		}
+
+		return false;
+	}
+
 } // namespace bgfx

+ 68 - 0
src/image.h

@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011-2013 Branimir Karadzic. All rights reserved.
+ * License: http://www.opensource.org/licenses/BSD-2-Clause
+ */
+
+#ifndef __IMAGE_H__
+#define __IMAGE_H__
+
+#include <stdint.h>
+
+namespace bgfx
+{
+	struct ImageContainer
+	{
+		TextureFormat::Enum m_type;
+		uint32_t m_offset;
+		uint32_t m_width;
+		uint32_t m_height;
+		uint32_t m_depth;
+		uint8_t m_blockSize;
+		uint8_t m_numMips;
+		uint8_t m_bpp;
+		bool m_hasAlpha;
+		bool m_cubeMap;
+		bool m_ktx;
+	};
+
+	struct Mip
+	{
+		uint32_t m_width;
+		uint32_t m_height;
+		uint32_t m_blockSize;
+		uint32_t m_size;
+		uint8_t m_bpp;
+		uint8_t m_type;
+		bool m_hasAlpha;
+		const uint8_t* m_data;
+
+		void decode(uint8_t* _dst);
+	};
+
+	///
+	void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst);
+
+	///
+	void imageChessboard(uint32_t _width, uint32_t _height, uint32_t _step, uint32_t _0, uint32_t _1, void* _dst);
+
+	///
+	void imageRgba8Downsample2x2(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst);
+
+	///
+	void imageSwizzleBgra8(uint32_t _width, uint32_t _height, const void* _src, void* _dst);
+
+	///
+	void imageWriteTga(bx::WriterI* _writer, uint32_t _width, uint32_t _height, uint32_t _srcPitch, const void* _src, bool _grayscale, bool _yflip);
+
+	///
+	bool imageParse(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader);
+
+	///
+	bool imageParse(ImageContainer& _dds, const void* _data, uint32_t _size);
+
+	///
+	bool imageGetRawData(const ImageContainer& _dds, uint8_t _side, uint8_t _index, const void* _data, uint32_t _size, Mip& _mip);
+
+} // namespace bgfx
+
+#endif // __IMAGE_H__

+ 56 - 51
src/renderer_d3d11.cpp

@@ -172,7 +172,6 @@ namespace bgfx
 	struct TextureFormatInfo
 	{
 		DXGI_FORMAT m_fmt;
-		uint8_t m_bpp;
 	};
 
 #ifndef DXGI_FORMAT_B4G4R4A4_UNORM
@@ -184,21 +183,22 @@ namespace bgfx
 
 	static const TextureFormatInfo s_textureFormat[TextureFormat::Count] =
 	{
-		{ DXGI_FORMAT_BC1_UNORM,          4  },
-		{ DXGI_FORMAT_BC2_UNORM,          8  },
-		{ DXGI_FORMAT_BC3_UNORM,          8  },
-		{ DXGI_FORMAT_BC4_UNORM,          4  },
-		{ DXGI_FORMAT_BC5_UNORM,          8  },
-		{ DXGI_FORMAT_UNKNOWN,            0  },
-		{ DXGI_FORMAT_R8_UNORM,           8  },
-		{ DXGI_FORMAT_B8G8R8A8_UNORM,     32 },
-		{ DXGI_FORMAT_B8G8R8A8_UNORM,     32 },
-		{ DXGI_FORMAT_R16G16B16A16_UNORM, 64 },
-		{ DXGI_FORMAT_R16G16B16A16_FLOAT, 64 },
-		{ DXGI_FORMAT_B5G6R5_UNORM,       16 },
-		{ DXGI_FORMAT_B4G4R4A4_UNORM,     16 },
-		{ DXGI_FORMAT_B5G5R5A1_UNORM,     16 },
-		{ DXGI_FORMAT_R10G10B10A2_UNORM,  32 },
+		{ DXGI_FORMAT_BC1_UNORM          },
+		{ DXGI_FORMAT_BC2_UNORM          },
+		{ DXGI_FORMAT_BC3_UNORM          },
+		{ DXGI_FORMAT_BC4_UNORM          },
+		{ DXGI_FORMAT_BC5_UNORM          },
+		{ DXGI_FORMAT_UNKNOWN            },
+		{ DXGI_FORMAT_UNKNOWN            },
+		{ DXGI_FORMAT_R8_UNORM           },
+		{ DXGI_FORMAT_B8G8R8A8_UNORM     },
+		{ DXGI_FORMAT_B8G8R8A8_UNORM     },
+		{ DXGI_FORMAT_R16G16B16A16_UNORM },
+		{ DXGI_FORMAT_R16G16B16A16_FLOAT },
+		{ DXGI_FORMAT_B5G6R5_UNORM       },
+		{ DXGI_FORMAT_B4G4R4A4_UNORM     },
+		{ DXGI_FORMAT_B5G5R5A1_UNORM     },
+		{ DXGI_FORMAT_R10G10B10A2_UNORM  },
 	};
 
 	static const D3D11_INPUT_ELEMENT_DESC s_attrib[Attrib::Count] =
@@ -1630,17 +1630,19 @@ namespace bgfx
 	{
 		m_sampler = s_renderCtx.getSamplerState(_flags);
 
-		Dds dds;
+		ImageContainer imageContainer;
 
-		if (parseDds(dds, _mem) )
+		if (imageParse(imageContainer, _mem->data, _mem->size) )
 		{
-			bool decompress = false;
+			bool decompress = false
+				|| (TextureFormat::ETC1 == imageContainer.m_type)
+				;
 
-			if (dds.m_cubeMap)
+			if (imageContainer.m_cubeMap)
 			{
 				m_type = TextureCube;
 			}
-			else if (dds.m_depth > 1)
+			else if (imageContainer.m_depth > 1)
 			{
 				m_type = Texture3D;
 			}
@@ -1649,25 +1651,28 @@ namespace bgfx
 				m_type = Texture2D;
 			}
 
-			uint32_t numSrd = dds.m_numMips*(dds.m_cubeMap ? 6 : 1);
+			TextureFormat::Enum textureFormat = decompress ? TextureFormat::BGRA8 : imageContainer.m_type;
+			uint32_t numSrd = imageContainer.m_numMips*(imageContainer.m_cubeMap ? 6 : 1);
 			D3D11_SUBRESOURCE_DATA* srd = (D3D11_SUBRESOURCE_DATA*)alloca(numSrd*sizeof(D3D11_SUBRESOURCE_DATA) );
 
 			uint32_t kk = 0;
 			bool convert = false;
 
-			m_numMips = dds.m_numMips;
+			m_numMips = imageContainer.m_numMips;
 
 			if (decompress
-			||  TextureFormat::Unknown < dds.m_type)
+			||  TextureFormat::Unknown < imageContainer.m_type)
 			{
-				uint32_t bpp = s_textureFormat[dds.m_type].m_bpp;
-				convert = TextureFormat::BGRX8 == dds.m_type;
+				uint32_t bpp = getBitsPerPixel(textureFormat);
+				convert = decompress
+					|| TextureFormat::BGRX8 == textureFormat
+					;
 
-				for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+				for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 				{
-					uint32_t width  = dds.m_width;
-					uint32_t height = dds.m_height;
-					uint32_t depth  = dds.m_depth;
+					uint32_t width  = imageContainer.m_width;
+					uint32_t height = imageContainer.m_height;
+					uint32_t depth  = imageContainer.m_depth;
 
 					for (uint32_t lod = 0, num = m_numMips; lod < num; ++lod)
 					{
@@ -1676,7 +1681,7 @@ namespace bgfx
 						depth  = bx::uint32_max(1, depth);
 
 						Mip mip;
-						if (getRawImageData(dds, side, lod, _mem, mip) )
+						if (imageGetRawData(imageContainer, side, lod, _mem->data, _mem->size, mip) )
 						{
 							if (convert)
 							{
@@ -1704,15 +1709,15 @@ namespace bgfx
 			}
 			else
 			{
-				for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+				for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 				{
 					for (uint32_t lod = 0, num = m_numMips; lod < num; ++lod)
 					{
 						Mip mip;
-						if (getRawImageData(dds, side, lod, _mem, mip) )
+						if (imageGetRawData(imageContainer, side, lod, _mem->data, _mem->size, mip) )
 						{
 							srd[kk].pSysMem = mip.m_data;
-							if (TextureFormat::Unknown > dds.m_type)
+							if (TextureFormat::Unknown > imageContainer.m_type)
 							{
 								srd[kk].SysMemPitch = (mip.m_width/4)*mip.m_blockSize;
 								srd[kk].SysMemSlicePitch = (mip.m_height/4)*srd[kk].SysMemPitch;
@@ -1731,7 +1736,7 @@ namespace bgfx
 
 			D3D11_SHADER_RESOURCE_VIEW_DESC srvd;
 			memset(&srvd, 0, sizeof(srvd) );
-			srvd.Format = s_textureFormat[dds.m_type].m_fmt;
+			srvd.Format = s_textureFormat[textureFormat].m_fmt;
 
 			switch (m_type)
 			{
@@ -1739,29 +1744,29 @@ namespace bgfx
 			case TextureCube:
 				{
 					D3D11_TEXTURE2D_DESC desc;
-					desc.Width = dds.m_width;
-					desc.Height = dds.m_height;
-					desc.MipLevels = dds.m_numMips;
-					desc.Format = s_textureFormat[dds.m_type].m_fmt;
+					desc.Width = imageContainer.m_width;
+					desc.Height = imageContainer.m_height;
+					desc.MipLevels = imageContainer.m_numMips;
+					desc.Format = srvd.Format;
 					desc.SampleDesc.Count = 1;
 					desc.SampleDesc.Quality = 0;
 					desc.Usage = D3D11_USAGE_IMMUTABLE;
 					desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
 					desc.CPUAccessFlags = 0;
 
-					if (dds.m_cubeMap)
+					if (imageContainer.m_cubeMap)
 					{
 						desc.ArraySize = 6;
 						desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
 						srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
-						srvd.TextureCube.MipLevels = dds.m_numMips;
+						srvd.TextureCube.MipLevels = imageContainer.m_numMips;
 					}
 					else
 					{
 						desc.ArraySize = 1;
 						desc.MiscFlags = 0;
 						srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
-						srvd.Texture2D.MipLevels = dds.m_numMips;
+						srvd.Texture2D.MipLevels = imageContainer.m_numMips;
 					}
 
 					DX_CHECK(s_renderCtx.m_device->CreateTexture2D(&desc, srd, &m_texture2d) );
@@ -1771,18 +1776,18 @@ namespace bgfx
 			case Texture3D:
 				{
 					D3D11_TEXTURE3D_DESC desc;
-					desc.Width = dds.m_width;
-					desc.Height = dds.m_height;
-					desc.Depth = dds.m_depth;
-					desc.MipLevels = dds.m_numMips;
-					desc.Format = s_textureFormat[dds.m_type].m_fmt;
+					desc.Width = imageContainer.m_width;
+					desc.Height = imageContainer.m_height;
+					desc.Depth = imageContainer.m_depth;
+					desc.MipLevels = imageContainer.m_numMips;
+					desc.Format = srvd.Format;
 					desc.Usage = D3D11_USAGE_IMMUTABLE;
 					desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
 					desc.CPUAccessFlags = 0;
 					desc.MiscFlags = 0;
 
 					srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
-					srvd.Texture3D.MipLevels = dds.m_numMips;
+					srvd.Texture3D.MipLevels = imageContainer.m_numMips;
 
 					DX_CHECK(s_renderCtx.m_device->CreateTexture3D(&desc, srd, &m_texture3d) );
 				}
@@ -1794,9 +1799,9 @@ namespace bgfx
 			if (convert)
 			{
 				kk = 0;
-				for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+				for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 				{
-					for (uint32_t lod = 0, num = dds.m_numMips; lod < num; ++lod)
+					for (uint32_t lod = 0, num = imageContainer.m_numMips; lod < num; ++lod)
 					{
 						g_free(const_cast<void*>(srd[kk].pSysMem) );
 						++kk;
@@ -1854,7 +1859,7 @@ namespace bgfx
 					srvd.Texture2D.MipLevels = tc.m_numMips;
 
 					D3D11_SUBRESOURCE_DATA* srd = (D3D11_SUBRESOURCE_DATA*)alloca(tc.m_numMips*sizeof(D3D11_SUBRESOURCE_DATA) );
-					uint32_t bpp = s_textureFormat[tc.m_format].m_bpp;
+					uint32_t bpp = getBitsPerPixel(TextureFormat::Enum(tc.m_format) );
 					uint8_t* data = tc.m_mem->data;
 
 					for (uint8_t side = 0, numSides = tc.m_cubeMap ? 6 : 1; side < numSides; ++side)

+ 28 - 26
src/renderer_d3d9.cpp

@@ -194,6 +194,7 @@ namespace bgfx
 		{ D3DFMT_ATI1,           4 },
 		{ D3DFMT_ATI2,           8 },
 		{ D3DFMT_UNKNOWN,        0 },
+		{ D3DFMT_UNKNOWN,        0 },
 		{ D3DFMT_L8,             8 },
 		{ D3DFMT_X8R8G8B8,      32 },
 		{ D3DFMT_A8R8G8B8,      32 },
@@ -1504,51 +1505,52 @@ namespace bgfx
 	{
 		m_flags = _flags;
 
-		Dds dds;
+		ImageContainer imageContainer;
 
-		if (parseDds(dds, _mem) )
+		if (imageParse(imageContainer, _mem->data, _mem->size) )
 		{
-			m_format = dds.m_type;
-			const TextureFormatInfo& tfi = s_textureFormat[dds.m_type];
+			m_format = imageContainer.m_type;
+			const TextureFormatInfo& tfi = s_textureFormat[imageContainer.m_type];
 
 			bool decompress = false
-				|| (TextureFormat::BC4 == dds.m_type && !s_extendedFormats[ExtendedFormat::Ati1].m_supported)
-				|| (TextureFormat::BC5 == dds.m_type && !s_extendedFormats[ExtendedFormat::Ati2].m_supported)
+				|| (TextureFormat::BC4  == imageContainer.m_type && !s_extendedFormats[ExtendedFormat::Ati1].m_supported)
+				|| (TextureFormat::BC5  == imageContainer.m_type && !s_extendedFormats[ExtendedFormat::Ati2].m_supported)
+				|| (TextureFormat::ETC1 == imageContainer.m_type)
 				;
 
 			D3DFORMAT format = decompress ? D3DFMT_A8R8G8B8 : tfi.m_fmt;
 			uint8_t bpp = decompress ? 32 : tfi.m_bpp;
 
-			if (dds.m_cubeMap)
+			if (imageContainer.m_cubeMap)
 			{
-				createCubeTexture(dds.m_width, dds.m_numMips, format);
+				createCubeTexture(imageContainer.m_width, imageContainer.m_numMips, format);
 			}
-			else if (dds.m_depth > 1)
+			else if (imageContainer.m_depth > 1)
 			{
-				createVolumeTexture(dds.m_width, dds.m_height, dds.m_depth, dds.m_numMips, format);
+				createVolumeTexture(imageContainer.m_width, imageContainer.m_height, imageContainer.m_depth, imageContainer.m_numMips, format);
 			}
 			else
 			{
-				createTexture(dds.m_width, dds.m_height, dds.m_numMips, format);
+				createTexture(imageContainer.m_width, imageContainer.m_height, imageContainer.m_numMips, format);
 			}
 
 			if (decompress
-			||  TextureFormat::Unknown < dds.m_type)
+			||  TextureFormat::Unknown < imageContainer.m_type)
 			{
-				for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+				for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 				{
-					uint32_t width  = dds.m_width;
-					uint32_t height = dds.m_height;
-					uint32_t depth  = dds.m_depth;
+					uint32_t width  = imageContainer.m_width;
+					uint32_t height = imageContainer.m_height;
+					uint32_t depth  = imageContainer.m_depth;
 
-					for (uint32_t lod = 0, num = dds.m_numMips; lod < num; ++lod)
+					for (uint32_t lod = 0, num = imageContainer.m_numMips; lod < num; ++lod)
 					{
 						width  = bx::uint32_max(1, width);
 						height = bx::uint32_max(1, height);
 						depth  = bx::uint32_max(1, depth);
 
 						Mip mip;
-						if (getRawImageData(dds, side, lod, _mem, mip) )
+						if (imageGetRawData(imageContainer, side, lod, _mem->data, _mem->size, mip) )
 						{
 							uint32_t pitch;
 							uint32_t slicePitch;
@@ -1592,24 +1594,24 @@ namespace bgfx
 				// bytes. If actual mip size is used it causes memory corruption.
 				// http://www.aras-p.info/texts/D3D9GPUHacks.html#3dc
 				bool useMipSize = true
-						&& dds.m_type != TextureFormat::BC4
-						&& dds.m_type != TextureFormat::BC5
+						&& imageContainer.m_type != TextureFormat::BC4
+						&& imageContainer.m_type != TextureFormat::BC5
 						;
 
-				for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+				for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 				{
-					uint32_t width  = dds.m_width;
-					uint32_t height = dds.m_height;
-					uint32_t depth  = dds.m_depth;
+					uint32_t width  = imageContainer.m_width;
+					uint32_t height = imageContainer.m_height;
+					uint32_t depth  = imageContainer.m_depth;
 
-					for (uint32_t lod = 0, num = dds.m_numMips; lod < num; ++lod)
+					for (uint32_t lod = 0, num = imageContainer.m_numMips; lod < num; ++lod)
 					{
 						width  = bx::uint32_max(1, width);
 						height = bx::uint32_max(1, height);
 						depth  = bx::uint32_max(1, depth);
 
 						Mip mip;
-						if (getRawImageData(dds, 0, lod, _mem, mip) )
+						if (imageGetRawData(imageContainer, 0, lod, _mem->data, _mem->size, mip) )
 						{
 							uint32_t pitch;
 							uint32_t slicePitch;

+ 106 - 91
src/renderer_gl.cpp

@@ -189,27 +189,27 @@ namespace bgfx
 		GLenum m_internalFmt;
 		GLenum m_fmt;
 		GLenum m_type;
-		uint8_t m_bpp;
 		bool m_supported;
 	};
 
 	static TextureFormatInfo s_textureFormat[TextureFormat::Count] =
 	{
-		{ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_ZERO,                        4,  false },
-		{ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_ZERO,                        8,  false },
-		{ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_ZERO,                        8,  false },
-		{ GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_ZERO,                        4,  false },
-		{ GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_ZERO,                        8,  false },
-		{ GL_ZERO,                                 GL_ZERO,                                 GL_ZERO,                        0,  true  },
-		{ GL_LUMINANCE,                            GL_LUMINANCE,                            GL_UNSIGNED_BYTE,               8,  true  },
-		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               32, true  },
-		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               32, true  },
-		{ GL_RGBA16,                               GL_RGBA,                                 GL_UNSIGNED_BYTE,               64, true  },
-		{ GL_RGBA16F,                              GL_RGBA,                                 GL_HALF_FLOAT,                  64, true  },
-		{ GL_RGB565,                               GL_RGB,                                  GL_UNSIGNED_SHORT_5_6_5,        16, true  },
-		{ GL_RGBA4,                                GL_RGBA,                                 GL_UNSIGNED_SHORT_4_4_4_4,      16, true  },
-		{ GL_RGB5_A1,                              GL_RGBA,                                 GL_UNSIGNED_SHORT_5_5_5_1,      16, true  },
-		{ GL_RGB10_A2,                             GL_RGBA,                                 GL_UNSIGNED_INT_2_10_10_10_REV, 32, true  },
+		{ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_ZERO,                        false },
+		{ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_ZERO,                        false },
+		{ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_ZERO,                        false },
+		{ GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_ZERO,                        false },
+		{ GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_ZERO,                        false },
+		{ GL_ETC1_RGB8_OES,                        GL_ETC1_RGB8_OES,                        GL_ZERO,                        false },
+		{ GL_ZERO,                                 GL_ZERO,                                 GL_ZERO,                        true  },
+		{ GL_LUMINANCE,                            GL_LUMINANCE,                            GL_UNSIGNED_BYTE,               true  },
+		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               true  },
+		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               true  },
+		{ GL_RGBA16,                               GL_RGBA,                                 GL_UNSIGNED_BYTE,               true  },
+		{ GL_RGBA16F,                              GL_RGBA,                                 GL_HALF_FLOAT,                  true  },
+		{ GL_RGB565,                               GL_RGB,                                  GL_UNSIGNED_SHORT_5_6_5,        true  },
+		{ GL_RGBA4,                                GL_RGBA,                                 GL_UNSIGNED_SHORT_4_4_4_4,      true  },
+		{ GL_RGB5_A1,                              GL_RGBA,                                 GL_UNSIGNED_SHORT_5_5_5_1,      true  },
+		{ GL_RGB10_A2,                             GL_RGBA,                                 GL_UNSIGNED_INT_2_10_10_10_REV, true  },
 	};
 
 	struct Extension
@@ -255,7 +255,13 @@ namespace bgfx
 			EXT_texture_swizzle,
 			EXT_texture_type_2_10_10_10_REV,
 			EXT_timer_query,
+			IMG_multisampled_render_to_texture,
+			IMG_shader_binary,
+			IMG_texture_compression_pvrtc,
+			IMG_texture_format_BGRA8888,
 			NVX_gpu_memory_info,
+			OES_compressed_ETC1_RGB8_texture,
+			OES_depth_texture,
 			OES_get_program_binary,
 			OES_rgb8_rgba8,
 			OES_standard_derivatives,
@@ -277,56 +283,62 @@ namespace bgfx
 
 	static Extension s_extension[Extension::Count] =
 	{
-		{ "GL_ANGLE_instanced_arrays",            false,                             true  },
-		{ "GL_ANGLE_translated_shader_source",    false,                             true  },
-		{ "GL_ARB_debug_output",                  BGFX_CONFIG_RENDERER_OPENGL >= 43, true  },
-		{ "GL_ARB_depth_clamp",                   BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_ARB_framebuffer_sRGB",              false,                             true  },
-		{ "GL_ARB_get_program_binary",            BGFX_CONFIG_RENDERER_OPENGL >= 41, true  },
-		{ "GL_ARB_half_float_vertex",             false,                             true  },
-		{ "GL_ARB_instanced_arrays",              BGFX_CONFIG_RENDERER_OPENGL >= 33, true  },
-		{ "GL_ARB_multisample",                   false,                             true  },
-		{ "GL_ARB_sampler_objects",               BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_ARB_seamless_cube_map",             BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_ARB_texture_float",                 BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_ARB_texture_multisample",           false,                             true  },
-		{ "GL_ARB_texture_swizzle",               BGFX_CONFIG_RENDERER_OPENGL >= 33, true  },
-		{ "GL_ARB_timer_query",                   false,                             true  },
-		{ "GL_ARB_vertex_array_object",           BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_ARB_vertex_type_2_10_10_10_rev",    false,                             true  },
-		{ "GL_ATI_meminfo",                       false,                             true  },
-		{ "GL_CHROMIUM_framebuffer_multisample",  false,                             true  },
-		{ "GL_CHROMIUM_texture_compression_dxt3", false,                             true  },
-		{ "GL_CHROMIUM_texture_compression_dxt5", false,                             true  },
-		{ "GL_EXT_bgra",                          false,                             true  },
-		{ "GL_EXT_blend_color",                   BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_EXT_blend_minmax",                  BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_EXT_blend_subtract",                BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_EXT_framebuffer_blit",              BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_EXT_framebuffer_sRGB",              false,                             true  },
-		{ "GL_EXT_occlusion_query_boolean",       false,                             true  },
-		{ "GL_EXT_texture_compression_dxt1",      false,                             true  },
-		{ "GL_EXT_texture_compression_latc",      false,                             true  },
-		{ "GL_EXT_texture_compression_rgtc",      BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
-		{ "GL_EXT_texture_compression_s3tc",      false,                             true  },
-		{ "GL_EXT_texture_filter_anisotropic",    false,                             true  },
-		{ "GL_EXT_texture_format_BGRA8888",       false,                             true  },
-		{ "GL_EXT_texture_sRGB",                  false,                             true  },
-		{ "GL_EXT_texture_storage",               false,                             true  },
-		{ "GL_EXT_texture_swizzle",               false,                             true  },
-		{ "GL_EXT_texture_type_2_10_10_10_REV",   false,                             true  },
-		{ "GL_EXT_timer_query",                   false,                             true  },
-		{ "GL_NVX_gpu_memory_info",               false,                             true  },
-		{ "GL_OES_get_program_binary",            false,                             false },
-		{ "GL_OES_rgb8_rgba8",                    false,                             true  },
-		{ "GL_OES_standard_derivatives",          false,                             true  },
-		{ "GL_OES_texture_float",                 false,                             true  },
-		{ "GL_OES_texture_float_linear",          false,                             true  },
-		{ "GL_OES_texture_half_float",            false,                             true  },
-		{ "GL_OES_texture_half_float_linear",     false,                             true  },
-		{ "GL_OES_vertex_array_object",           false,                             !BX_PLATFORM_IOS },
-		{ "GL_OES_vertex_half_float",             false,                             true  },
-		{ "GL_OES_vertex_type_10_10_10_2",        false,                             true  },
+		{ "GL_ANGLE_instanced_arrays",             false,                             true  },
+		{ "GL_ANGLE_translated_shader_source",     false,                             true  },
+		{ "GL_ARB_debug_output",                   BGFX_CONFIG_RENDERER_OPENGL >= 43, true  },
+		{ "GL_ARB_depth_clamp",                    BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_ARB_framebuffer_sRGB",               false,                             true  },
+		{ "GL_ARB_get_program_binary",             BGFX_CONFIG_RENDERER_OPENGL >= 41, true  },
+		{ "GL_ARB_half_float_vertex",              false,                             true  },
+		{ "GL_ARB_instanced_arrays",               BGFX_CONFIG_RENDERER_OPENGL >= 33, true  },
+		{ "GL_ARB_multisample",                    false,                             true  },
+		{ "GL_ARB_sampler_objects",                BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_ARB_seamless_cube_map",              BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_ARB_texture_float",                  BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_ARB_texture_multisample",            false,                             true  },
+		{ "GL_ARB_texture_swizzle",                BGFX_CONFIG_RENDERER_OPENGL >= 33, true  },
+		{ "GL_ARB_timer_query",                    false,                             true  },
+		{ "GL_ARB_vertex_array_object",            BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_ARB_vertex_type_2_10_10_10_rev",     false,                             true  },
+		{ "GL_ATI_meminfo",                        false,                             true  },
+		{ "GL_CHROMIUM_framebuffer_multisample",   false,                             true  },
+		{ "GL_CHROMIUM_texture_compression_dxt3",  false,                             true  },
+		{ "GL_CHROMIUM_texture_compression_dxt5",  false,                             true  },
+		{ "GL_EXT_bgra",                           false,                             true  },
+		{ "GL_EXT_blend_color",                    BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_EXT_blend_minmax",                   BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_EXT_blend_subtract",                 BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_EXT_framebuffer_blit",               BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_EXT_framebuffer_sRGB",               false,                             true  },
+		{ "GL_EXT_occlusion_query_boolean",        false,                             true  },
+		{ "GL_EXT_texture_compression_dxt1",       false,                             true  },
+		{ "GL_EXT_texture_compression_latc",       false,                             true  },
+		{ "GL_EXT_texture_compression_rgtc",       BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
+		{ "GL_EXT_texture_compression_s3tc",       false,                             true  },
+		{ "GL_EXT_texture_filter_anisotropic",     false,                             true  },
+		{ "GL_EXT_texture_format_BGRA8888",        false,                             true  },
+		{ "GL_EXT_texture_sRGB",                   false,                             true  },
+		{ "GL_EXT_texture_storage",                false,                             true  },
+		{ "GL_EXT_texture_swizzle",                false,                             true  },
+		{ "GL_EXT_texture_type_2_10_10_10_REV",    false,                             true  },
+		{ "GL_EXT_timer_query",                    false,                             true  },
+		{ "GL_IMG_multisampled_render_to_texture", false,                             true  },
+		{ "GL_IMG_shader_binary",                  false,                             true  },
+		{ "GL_IMG_texture_compression_pvrtc",      false,                             true  },
+		{ "GL_IMG_texture_format_BGRA8888",        false,                             true  },
+		{ "GL_NVX_gpu_memory_info",                false,                             true  },
+		{ "GL_OES_compressed_ETC1_RGB8_texture",   false,                             true  },
+		{ "GL_OES_depth_texture",                  false,                             true  },
+		{ "GL_OES_get_program_binary",             false,                             false },
+		{ "GL_OES_rgb8_rgba8",                     false,                             true  },
+		{ "GL_OES_standard_derivatives",           false,                             true  },
+		{ "GL_OES_texture_float",                  false,                             true  },
+		{ "GL_OES_texture_float_linear",           false,                             true  },
+		{ "GL_OES_texture_half_float",             false,                             true  },
+		{ "GL_OES_texture_half_float_linear",      false,                             true  },
+		{ "GL_OES_vertex_array_object",            false,                             !BX_PLATFORM_IOS },
+		{ "GL_OES_vertex_half_float",              false,                             true  },
+		{ "GL_OES_vertex_type_10_10_10_2",         false,                             true  },
 	};
 
 #if BGFX_CONFIG_RENDERER_OPENGLES3
@@ -665,7 +677,9 @@ namespace bgfx
 
 		void setSamplerState(uint32_t _stage, uint32_t _numMips, uint32_t _flags)
 		{
-#if !BGFX_CONFIG_RENDERER_OPENGLES2
+#if BGFX_CONFIG_RENDERER_OPENGLES2
+			BX_UNUSED(_stage, _numMips, _flags);
+#else
 			if (0 == (BGFX_SAMPLER_DEFAULT_FLAGS & _flags) )
 			{
 				GLuint sampler = m_samplerStateCache.find(_flags);
@@ -697,7 +711,7 @@ namespace bgfx
 			{
 				GL_CHECK(glBindSampler(_stage, 0) );
 			}
-#endif // !BGFX_CONFIG_RENDERER_OPENGLES2
+#endif // BGFX_CONFIG_RENDERER_OPENGLES2
 		}
 
 		void updateCapture()
@@ -1373,18 +1387,18 @@ namespace bgfx
 
 	void Texture::create(const Memory* _mem, uint32_t _flags)
 	{
-		Dds dds;
+		ImageContainer imageContainer;
 
-		if (parseDds(dds, _mem) )
+		if (imageParse(imageContainer, _mem->data, _mem->size) )
 		{
-			uint8_t numMips = dds.m_numMips;
+			uint8_t numMips = imageContainer.m_numMips;
 
-			if (dds.m_cubeMap)
+			if (imageContainer.m_cubeMap)
 			{
 				init(GL_TEXTURE_CUBE_MAP, numMips, _flags);
 			}
 #if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-			else if (dds.m_depth > 1)
+			else if (imageContainer.m_depth > 1)
 			{
 				init(GL_TEXTURE_3D, numMips, _flags);
 			}
@@ -1394,23 +1408,23 @@ namespace bgfx
 				init(GL_TEXTURE_2D, numMips, _flags);
 			}
 
-			const TextureFormatInfo& tfi = s_textureFormat[dds.m_type];
+			const TextureFormatInfo& tfi = s_textureFormat[imageContainer.m_type];
 			GLenum internalFmt = tfi.m_internalFmt;
 			m_fmt = tfi.m_fmt;
 			m_type = tfi.m_type;
 
 			GLenum target = m_target;
-			if (dds.m_cubeMap)
+			if (imageContainer.m_cubeMap)
 			{
 				target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
 			}
 
 			if (!tfi.m_supported
-			||  TextureFormat::Unknown < dds.m_type)
+			||  TextureFormat::Unknown < imageContainer.m_type)
 			{
-				uint8_t textureFormat = dds.m_type;
+				TextureFormat::Enum textureFormat = imageContainer.m_type;
 				bool decompress = TextureFormat::Unknown > textureFormat;
-				uint32_t bpp = tfi.m_bpp;
+				uint32_t bpp = getBitsPerPixel(imageContainer.m_type);
 
 				if (decompress)
 				{
@@ -1419,7 +1433,7 @@ namespace bgfx
 					internalFmt = tfi.m_internalFmt;
 					m_fmt = tfi.m_fmt;
 					m_type = tfi.m_type;
-					bpp = tfi.m_bpp;
+					bpp = getBitsPerPixel(textureFormat);
 				}
 
 				bool swizzle = GL_RGBA == m_fmt;
@@ -1434,13 +1448,13 @@ namespace bgfx
 				}
 #endif // BGFX_CONFIG_RENDERER_OPENGL
 
-				uint8_t* bits = (uint8_t*)g_realloc(NULL, dds.m_width*dds.m_height*bpp/8);
+				uint8_t* bits = (uint8_t*)g_realloc(NULL, imageContainer.m_width*imageContainer.m_height*bpp/8);
 
-				for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+				for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 				{
-					uint32_t width = dds.m_width;
-					uint32_t height = dds.m_height;
-					uint32_t depth = dds.m_depth;
+					uint32_t width = imageContainer.m_width;
+					uint32_t height = imageContainer.m_height;
+					uint32_t depth = imageContainer.m_depth;
 
 					for (uint32_t lod = 0, num = numMips; lod < num; ++lod)
 					{
@@ -1449,7 +1463,7 @@ namespace bgfx
 						depth  = bx::uint32_max(1, depth);
 
 						Mip mip;
-						if (getRawImageData(dds, side, lod, _mem, mip) )
+						if (imageGetRawData(imageContainer, side, lod, _mem->data, _mem->size, mip) )
 						{
 							mip.decode(bits);
 
@@ -1483,11 +1497,11 @@ namespace bgfx
 			{
 				m_compressed = true;
 
-				for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+				for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 				{
-					uint32_t width  = dds.m_width;
-					uint32_t height = dds.m_height;
-					uint32_t depth  = dds.m_depth;
+					uint32_t width  = imageContainer.m_width;
+					uint32_t height = imageContainer.m_height;
+					uint32_t depth  = imageContainer.m_depth;
 
 					for (uint32_t ii = 0, num = numMips; ii < num; ++ii)
 					{
@@ -1496,7 +1510,7 @@ namespace bgfx
 						depth  = bx::uint32_max(1, depth);
 
 						Mip mip;
-						if (getRawImageData(dds, side, ii, _mem, mip) )
+						if (imageGetRawData(imageContainer, side, ii, _mem->data, _mem->size, mip) )
 						{
 							compressedTexImage(target+side
 								, ii
@@ -1558,7 +1572,7 @@ namespace bgfx
 					target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
 				}
 
-				uint32_t bpp = tfi.m_bpp;
+				uint32_t bpp = getBitsPerPixel(TextureFormat::Enum(tc.m_format) );
 				uint8_t* data = NULL != tc.m_mem ? tc.m_mem->data : NULL;
 				uint32_t min = m_compressed ? 4 : 1;
 				bool swizzle = GL_RGBA == m_fmt;
@@ -2462,6 +2476,7 @@ namespace bgfx
 			;
 		s_textureFormat[TextureFormat::BC4].m_supported = bc45Supported;
 		s_textureFormat[TextureFormat::BC5].m_supported = bc45Supported;
+		s_textureFormat[TextureFormat::ETC1].m_supported = s_extension[Extension::OES_compressed_ETC1_RGB8_texture].m_supported;
 
 		s_renderCtx.m_vaoSupport = !!BGFX_CONFIG_RENDERER_OPENGLES3
 			|| s_extension[Extension::ARB_vertex_array_object].m_supported

+ 4 - 0
src/renderer_gl.h

@@ -171,6 +171,10 @@ typedef void (*PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC)(GLuint shader, GLsizei b
 #		define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
 #	endif // GL_COMPRESSED_RED_GREEN_RGTC2_EXT
 
+#	ifndef GL_ETC1_RGB8_OES
+#		define GL_ETC1_RGB8_OES 0x8D64
+#	endif // GL_ETC1_RGB8_OES
+
 #	ifndef GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE
 #		define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
 #	endif // GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE

+ 29 - 28
tools/texturec/texturec.cpp

@@ -11,7 +11,7 @@
 #include "bgfx_p.h"
 using namespace bgfx;
 
-#include "dds.h"
+#include "image.h"
 
 #if 0
 #	define BX_TRACE(_format, ...) fprintf(stderr, "" _format "\n", ##__VA_ARGS__)
@@ -83,47 +83,45 @@ namespace bgfx
 	}
 }
 
-long int fsize(FILE* _file)
-{
-	long int pos = ftell(_file);
-	fseek(_file, 0L, SEEK_END);
-	long int size = ftell(_file);
-	fseek(_file, pos, SEEK_SET);
-	return size;
-}
-
 int main(int _argc, const char* _argv[])
 {
 	bx::CommandLine cmdLine(_argc, _argv);
 
-	FILE* file = fopen(_argv[1], "rb");
-	uint32_t size = fsize(file);
+	const char* inputFileName = cmdLine.findOption('i');
+
+	if (NULL == inputFileName)
+	{
+		return 0;
+	}
+
+	bx::CrtFileReader reader;
+	bx::open(&reader, inputFileName);
+	uint32_t size = (uint32_t)bx::getSize(&reader);
 	const Memory* mem = alloc(size);
-	size_t readSize = fread(mem->data, 1, size, file);
-	BX_UNUSED(readSize);
-	fclose(file);
+	bx::read(&reader, mem->data, mem->size);
+	bx::close(&reader);
 
-	Dds dds;
+	ImageContainer imageContainer;
 
-	if (parseDds(dds, mem) )
+	if (imageParse(imageContainer, mem->data, mem->size) )
 	{
 		bool decompress = cmdLine.hasArg('d');
 
 		if (decompress
-		||  0 == dds.m_type)
+		||  0 == imageContainer.m_type)
 		{
-			for (uint8_t side = 0, numSides = dds.m_cubeMap ? 6 : 1; side < numSides; ++side)
+			for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
 			{
-				uint32_t width = dds.m_width;
-				uint32_t height = dds.m_height;
+				uint32_t width = imageContainer.m_width;
+				uint32_t height = imageContainer.m_height;
 
-				for (uint32_t lod = 0, num = dds.m_numMips; lod < num; ++lod)
+				for (uint32_t lod = 0, num = imageContainer.m_numMips; lod < num; ++lod)
 				{
 					width = bx::uint32_max(1, width);
 					height = bx::uint32_max(1, height);
 
 					Mip mip;
-					if (getRawImageData(dds, side, lod, mem, mip) )
+					if (imageGetRawData(imageContainer, side, lod, mem->data, mem->size, mip) )
 					{
 						uint32_t dstpitch = width*4;
 						uint8_t* bits = (uint8_t*)malloc(dstpitch*height);
@@ -169,16 +167,19 @@ int main(int _argc, const char* _argv[])
 		}
 		else
 		{
-			for (uint32_t lod = 0, num = dds.m_numMips; lod < num; ++lod)
+			for (uint32_t lod = 0, num = imageContainer.m_numMips; lod < num; ++lod)
 			{
 				Mip mip;
-				if (getRawImageData(dds, 0, lod, mem, mip) )
+				if (imageGetRawData(imageContainer, 0, lod, mem->data, mem->size, mip) )
 				{
 					char filePath[256];
 					bx::snprintf(filePath, sizeof(filePath), "mip%d.bin", lod);
-					file = fopen(filePath, "wb");
-					fwrite(mip.m_data, 1, mip.m_size, file);
-					fclose(file);
+
+					bx::CrtFileWriter writer;
+					bx::open(&writer, filePath);
+					printf("mip%d, size %d\n", lod, mip.m_size);
+					bx::write(&writer, mip.m_data, mip.m_size);
+					bx::close(&writer);
 				}
 			}
 		}