mirror of https://github.com/axmolengine/axmol.git
Add ktxv1.1 file format for etc2/etc1 support
This commit is contained in:
parent
9903a2223f
commit
014e4f20e0
|
@ -2,7 +2,8 @@
|
|||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
Copyright (c) 2020 c4games.com
|
||||
Copyright (c) 2020 C4games Ltd.
|
||||
Copyright (c) 2022 Bytedance Inc.
|
||||
|
||||
//
|
||||
// Copyright 2013 The ANGLE Project Authors. All rights reserved.
|
||||
|
@ -89,7 +90,7 @@ etc2_uint32 etc2_pkm_get_height(const etc2_byte* pHeader)
|
|||
return readBEUint16(pHeader + ETC2_PKM_HEIGHT_OFFSET);
|
||||
}
|
||||
|
||||
etc2_uint32 etc2_pkm_get_format(const uint8_t* pHeader)
|
||||
etc2_uint32 etc2_pkm_get_format(const etc2_byte* pHeader)
|
||||
{
|
||||
return readBEUint16(pHeader + ETC2_PKM_FORMAT_OFFSET);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
Copyright (c) 2020 c4games.com
|
||||
Copyright (c) 2020 C4games Ltd.
|
||||
|
||||
https://adxeproject.github.io/
|
||||
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2022 Bytedance Inc.
|
||||
|
||||
https://adxeproject.github.io/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define KTX_V1_HEADER_SIZE 64
|
||||
|
||||
#define KTX_V1_MAGIC "KTX 11"
|
||||
|
||||
// ktxv1 header, refer to: https://www.khronos.org/registry/KTX/specs/1.0/ktxspec_v1.html
|
||||
struct KTXv1Header
|
||||
{
|
||||
struct InternalFormat
|
||||
{
|
||||
enum
|
||||
{
|
||||
// ETC1
|
||||
ETC1_RGB8 = 0x8D64,
|
||||
ETC1_ALPHA8 = ETC1_RGB8,
|
||||
// ETC2
|
||||
ETC2_R11 = 0x9270,
|
||||
ETC2_SIGNED_R11 = 0x9271,
|
||||
ETC2_RG11 = 0x9272,
|
||||
ETC2_SIGNED_RG11 = 0x9273,
|
||||
ETC2_RGB8 = 0x9274,
|
||||
ETC2_SRGB8 = 0x9275,
|
||||
ETC2_RGB8A1 = 0x9276,
|
||||
ETC2_SRGB8_PUNCHTHROUGH_ALPHA1 = 0x9277,
|
||||
ETC2_RGBA8 = 0x9278,
|
||||
// ATITC
|
||||
ATC_RGB_AMD = 0x8C92,
|
||||
ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93,
|
||||
ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE,
|
||||
};
|
||||
};
|
||||
|
||||
// enum class BaseInternalFormat
|
||||
//{
|
||||
// ETC2_R11 = 0x1903,
|
||||
// ETC2_RG11 = 0x8227,
|
||||
// ETC1_RGB8 = 0x1907,
|
||||
// ETC1_ALPHA8 = ETC1_RGB8,
|
||||
// ETC2_RGB8 = 0x1907,
|
||||
// ETC2_RGB8A1 = 0x1908,
|
||||
// ETC2_RGBA8 = 0x1908,
|
||||
//};
|
||||
|
||||
uint8_t identifier[12];
|
||||
uint32_t endianness;
|
||||
uint32_t glType;
|
||||
uint32_t glTypeSize;
|
||||
uint32_t glFormat;
|
||||
uint32_t glInternalFormat;
|
||||
uint32_t glBaseInternalFormat;
|
||||
uint32_t pixelWidth;
|
||||
uint32_t pixelHeight;
|
||||
uint32_t pixelDepth;
|
||||
uint32_t numberOfArrayElements;
|
||||
uint32_t numberOfFaces;
|
||||
uint32_t numberOfMipmapLevels;
|
||||
uint32_t bytesOfKeyValueData;
|
||||
};
|
|
@ -103,6 +103,8 @@ struct dirent* readdir$INODE64(DIR* dir)
|
|||
#endif // CC_USE_JPEG
|
||||
} /* extern "C" */
|
||||
|
||||
#include "base/ktxspec_v1.h"
|
||||
|
||||
#include "base/s3tc.h"
|
||||
#include "base/atitc.h"
|
||||
#include "base/pvr.h"
|
||||
|
@ -414,32 +416,6 @@ struct S3TCTexHeader
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// struct and data for atitc(ktx) struct
|
||||
namespace
|
||||
{
|
||||
struct ATITCTexHeader
|
||||
{
|
||||
// HEADER
|
||||
char identifier[12];
|
||||
uint32_t endianness;
|
||||
uint32_t glType;
|
||||
uint32_t glTypeSize;
|
||||
uint32_t glFormat;
|
||||
uint32_t glInternalFormat;
|
||||
uint32_t glBaseInternalFormat;
|
||||
uint32_t pixelWidth;
|
||||
uint32_t pixelHeight;
|
||||
uint32_t pixelDepth;
|
||||
uint32_t numberOfArrayElements;
|
||||
uint32_t numberOfFaces;
|
||||
uint32_t numberOfMipmapLevels;
|
||||
uint32_t bytesOfKeyValueData;
|
||||
};
|
||||
} // namespace
|
||||
// atitc struct end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
typedef struct
|
||||
|
@ -801,13 +777,6 @@ bool Image::isS3TC(const uint8_t* data, ssize_t /*dataLen*/)
|
|||
return (strncmp(header->fileCode, "DDS", 3) == 0);
|
||||
}
|
||||
|
||||
bool Image::isATITC(const uint8_t* data, ssize_t /*dataLen*/)
|
||||
{
|
||||
ATITCTexHeader* header = (ATITCTexHeader*)data;
|
||||
|
||||
return (strncmp(&header->identifier[1], "KTX", 3) == 0);
|
||||
}
|
||||
|
||||
bool Image::isASTC(const uint8_t* data, ssize_t /*dataLen*/)
|
||||
{
|
||||
astc_header* hdr = (astc_header*)data;
|
||||
|
@ -890,18 +859,32 @@ Image::Format Image::detectFormat(const uint8_t* data, ssize_t dataLen)
|
|||
{
|
||||
return Format::S3TC;
|
||||
}
|
||||
else if (isATITC(data, dataLen))
|
||||
{
|
||||
return Format::ATITC;
|
||||
}
|
||||
else if (isASTC(data, dataLen))
|
||||
{
|
||||
return Format::ASTC;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Format::UNKNOWN;
|
||||
else if (dataLen >= KTX_V1_HEADER_SIZE)
|
||||
{ // Check whether ktxspec v1.1 file format
|
||||
auto header = (KTXv1Header*)data;
|
||||
if (memcmp(&header->identifier[1], KTX_V1_MAGIC, sizeof(KTX_V1_MAGIC) - 1) == 0)
|
||||
{
|
||||
switch (header->glInternalFormat)
|
||||
{
|
||||
case KTXv1Header::InternalFormat::ATC_RGB_AMD:
|
||||
case KTXv1Header::InternalFormat::ATC_RGBA_INTERPOLATED_ALPHA_AMD:
|
||||
case KTXv1Header::InternalFormat::ATC_RGBA_EXPLICIT_ALPHA_AMD:
|
||||
return Format::ATITC;
|
||||
case KTXv1Header::InternalFormat::ETC2_RGB8:
|
||||
case KTXv1Header::InternalFormat::ETC2_RGBA8:
|
||||
return Format::ETC2;
|
||||
case KTXv1Header::InternalFormat::ETC1_RGB8:
|
||||
return Format::ETC1;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Format::UNKNOWN;
|
||||
}
|
||||
|
||||
int Image::getBitPerPixel()
|
||||
|
@ -1715,19 +1698,26 @@ bool Image::initWithPVRv3Data(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
bool Image::initWithETCData(uint8_t* data, ssize_t dataLen, bool ownData)
|
||||
{
|
||||
const etc1_byte* header = static_cast<const etc1_byte*>(data);
|
||||
|
||||
uint32_t pixelOffset;
|
||||
// check the data
|
||||
if (!etc1_pkm_is_valid(header))
|
||||
if (etc1_pkm_is_valid(header))
|
||||
{
|
||||
return false;
|
||||
_width = etc1_pkm_get_width(header);
|
||||
_height = etc1_pkm_get_height(header);
|
||||
|
||||
if (0 == _width || 0 == _height)
|
||||
return false;
|
||||
pixelOffset = ETC_PKM_HEADER_SIZE;
|
||||
}
|
||||
else
|
||||
{ // we can safe trait as KTX v1 header
|
||||
auto header = (KTXv1Header*)data;
|
||||
_width = header->pixelWidth;
|
||||
_height = header->pixelHeight;
|
||||
|
||||
_width = etc1_pkm_get_width(header);
|
||||
_height = etc1_pkm_get_height(header);
|
||||
|
||||
if (0 == _width || 0 == _height)
|
||||
{
|
||||
return false;
|
||||
if (0 == _width || 0 == _height)
|
||||
return false;
|
||||
pixelOffset = KTX_V1_HEADER_SIZE + header->bytesOfKeyValueData + 4;
|
||||
}
|
||||
|
||||
// GL_ETC1_RGB8_OES is not available in any desktop GL extension but the compression
|
||||
|
@ -1743,7 +1733,7 @@ bool Image::initWithETCData(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
if (compressedFormat != backend::PixelFormat::NONE)
|
||||
{
|
||||
_pixelFormat = compressedFormat;
|
||||
forwardPixels(data, dataLen, ETC_PKM_HEADER_SIZE, ownData);
|
||||
forwardPixels(data, dataLen, pixelOffset, ownData);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -1752,7 +1742,7 @@ bool Image::initWithETCData(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
|
||||
_dataLen = _width * _height * 4;
|
||||
_data = static_cast<uint8_t*>(malloc(_dataLen));
|
||||
if (etc2_decode_image(ETC2_RGB_NO_MIPMAPS, static_cast<const uint8_t*>(data) + ETC2_PKM_HEADER_SIZE,
|
||||
if (etc2_decode_image(ETC2_RGB_NO_MIPMAPS, static_cast<const uint8_t*>(data) + pixelOffset,
|
||||
static_cast<etc2_byte*>(_data), _width, _height) == 0)
|
||||
{ // if it is not gles or device do not support ETC1, decode texture by software
|
||||
// directly decode ETC1_RGB to RGBA8888
|
||||
|
@ -1773,17 +1763,33 @@ bool Image::initWithETC2Data(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
|
||||
do
|
||||
{
|
||||
uint32_t format, pixelOffset;
|
||||
// check the data
|
||||
if (!etc2_pkm_is_valid(header))
|
||||
break;
|
||||
if (etc2_pkm_is_valid(header))
|
||||
{
|
||||
|
||||
_width = etc2_pkm_get_width(header);
|
||||
_height = etc2_pkm_get_height(header);
|
||||
_width = etc2_pkm_get_width(header);
|
||||
_height = etc2_pkm_get_height(header);
|
||||
|
||||
if (0 == _width || 0 == _height)
|
||||
break;
|
||||
if (0 == _width || 0 == _height)
|
||||
break;
|
||||
|
||||
etc2_uint32 format = etc2_pkm_get_format(header);
|
||||
format = etc2_pkm_get_format(header);
|
||||
pixelOffset = ETC2_PKM_HEADER_SIZE;
|
||||
}
|
||||
else
|
||||
{ // we can safe trait as KTX v1 header
|
||||
auto header = (KTXv1Header*)data;
|
||||
_width = header->pixelWidth;
|
||||
_height = header->pixelHeight;
|
||||
|
||||
if (0 == _width || 0 == _height)
|
||||
break;
|
||||
|
||||
format = header->glInternalFormat == KTXv1Header::InternalFormat::ETC2_RGBA8 ? ETC2_RGBA_NO_MIPMAPS
|
||||
: ETC2_RGB_NO_MIPMAPS;
|
||||
pixelOffset = KTX_V1_HEADER_SIZE + header->bytesOfKeyValueData + 4;
|
||||
}
|
||||
|
||||
// We only support ETC2_RGBA_NO_MIPMAPS and ETC2_RGB_NO_MIPMAPS
|
||||
assert(format == ETC2_RGBA_NO_MIPMAPS || format == ETC2_RGB_NO_MIPMAPS);
|
||||
|
@ -1793,7 +1799,7 @@ bool Image::initWithETC2Data(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
_pixelFormat =
|
||||
format == ETC2_RGBA_NO_MIPMAPS ? backend::PixelFormat::ETC2_RGBA : backend::PixelFormat::ETC2_RGB;
|
||||
|
||||
forwardPixels(data, dataLen, ETC2_PKM_HEADER_SIZE, ownData);
|
||||
forwardPixels(data, dataLen, pixelOffset, ownData);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1803,7 +1809,7 @@ bool Image::initWithETC2Data(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
// etc2_decode_image always decode to RGBA8888
|
||||
_dataLen = _width * _height * 4;
|
||||
_data = static_cast<uint8_t*>(malloc(_dataLen));
|
||||
if (UTILS_UNLIKELY(etc2_decode_image(format, static_cast<const uint8_t*>(data) + ETC2_PKM_HEADER_SIZE,
|
||||
if (UTILS_UNLIKELY(etc2_decode_image(format, static_cast<const uint8_t*>(data) + pixelOffset,
|
||||
static_cast<etc2_byte*>(_data), _width, _height) != 0))
|
||||
{
|
||||
// software decode fail, release pixels data
|
||||
|
@ -2038,10 +2044,10 @@ bool Image::initWithS3TCData(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
bool Image::initWithATITCData(uint8_t* data, ssize_t dataLen, bool ownData)
|
||||
{
|
||||
/* load the .ktx file */
|
||||
ATITCTexHeader* header = (ATITCTexHeader*)data;
|
||||
_width = header->pixelWidth;
|
||||
_height = header->pixelHeight;
|
||||
_numberOfMipmaps = header->numberOfMipmapLevels;
|
||||
KTXv1Header* header = (KTXv1Header*)data;
|
||||
_width = header->pixelWidth;
|
||||
_height = header->pixelHeight;
|
||||
_numberOfMipmaps = header->numberOfMipmapLevels;
|
||||
|
||||
int blockSize = 0;
|
||||
switch (header->glInternalFormat)
|
||||
|
@ -2060,7 +2066,7 @@ bool Image::initWithATITCData(uint8_t* data, ssize_t dataLen, bool ownData)
|
|||
}
|
||||
|
||||
/* pixelData point to the compressed data address */
|
||||
int pixelOffset = sizeof(ATITCTexHeader) + header->bytesOfKeyValueData + 4;
|
||||
int pixelOffset = KTX_V1_HEADER_SIZE + header->bytesOfKeyValueData + 4;
|
||||
uint8_t* pixelData = (uint8_t*)data + pixelOffset;
|
||||
|
||||
/* calculate the dataLen */
|
||||
|
|
|
@ -261,7 +261,6 @@ protected:
|
|||
bool isEtc1(const uint8_t* data, ssize_t dataLen);
|
||||
bool isEtc2(const uint8_t* data, ssize_t dataLen);
|
||||
bool isS3TC(const uint8_t* data, ssize_t dataLen);
|
||||
bool isATITC(const uint8_t* data, ssize_t dataLen);
|
||||
bool isASTC(const uint8_t* data, ssize_t dataLen);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue