Added ETC1 texture support. Added KTX file format support.

This commit is contained in:
bkaradzic 2013-09-02 16:22:53 -07:00
parent 9537208d2f
commit 19dd4020f4
13 changed files with 1185 additions and 875 deletions

View file

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

View file

@ -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",
}

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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__

View file

@ -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
src/image.h Normal file
View file

@ -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__

View file

@ -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)

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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);
}
}
}