diff --git a/include/bgfx.h b/include/bgfx.h index b0653e571..1eb6468ba 100644 --- a/include/bgfx.h +++ b/include/bgfx.h @@ -307,6 +307,7 @@ namespace bgfx BC3, // DXT5 BC4, // LATC1/ATI1 BC5, // LATC2/ATI2 + ETC1, Unknown, L8, BGRX8, diff --git a/premake/texturec.lua b/premake/texturec.lua index 7bb4eea58..8b48c3dd8 100644 --- a/premake/texturec.lua +++ b/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", } diff --git a/src/bgfx.cpp b/src/bgfx.cpp index bc666a538..df5b9e8cb 100755 --- a/src/bgfx.cpp +++ b/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); diff --git a/src/bgfx_p.h b/src/bgfx_p.h index c6f9b8bf9..11ba2fd56 100755 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -72,7 +72,7 @@ namespace bgfx #include #include -#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 diff --git a/src/dds.cpp b/src/dds.cpp deleted file mode 100644 index f3fb89b15..000000000 --- a/src/dds.cpp +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Copyright 2011-2013 Branimir Karadzic. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#include // 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 diff --git a/src/dds.h b/src/dds.h deleted file mode 100644 index 72bcc605d..000000000 --- a/src/dds.h +++ /dev/null @@ -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 - -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__ diff --git a/src/image.cpp b/src/image.cpp index a325cdaf3..4b328facb 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -5,7 +5,83 @@ #include "bgfx_p.h" #include -#include // powf +#include // 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 diff --git a/src/image.h b/src/image.h new file mode 100644 index 000000000..c21f99385 --- /dev/null +++ b/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 + +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__ diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 555ed7310..1909786b1 100644 --- a/src/renderer_d3d11.cpp +++ b/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(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) diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index 11ec631eb..e433013a6 100644 --- a/src/renderer_d3d9.cpp +++ b/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; diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 52eaf9910..74d042dbf 100644 --- a/src/renderer_gl.cpp +++ b/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 diff --git a/src/renderer_gl.h b/src/renderer_gl.h index 9e4b03a3d..fa4009161 100755 --- a/src/renderer_gl.h +++ b/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 diff --git a/tools/texturec/texturec.cpp b/tools/texturec/texturec.cpp index 229fe877d..f5e861dbe 100644 --- a/tools/texturec/texturec.cpp +++ b/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); } } }