Add ETC1/ETC2 compression support though etc2comp.
Remove rg-etc1 code. Also updated travis to use ubuntu 14.04. Fixes #8457.
This commit is contained in:
parent
bd26fa7bf2
commit
6a9c990da7
61 changed files with 12981 additions and 2765 deletions
|
@ -1,5 +1,7 @@
|
||||||
language: cpp
|
language: cpp
|
||||||
|
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
compiler:
|
compiler:
|
||||||
|
@ -73,7 +75,6 @@ addons:
|
||||||
# For style checks.
|
# For style checks.
|
||||||
- clang-format-3.9
|
- clang-format-3.9
|
||||||
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install scons; fi
|
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install scons; fi
|
||||||
- if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$GODOT_TARGET" = "android" ]; then
|
- if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$GODOT_TARGET" = "android" ]; then
|
||||||
|
@ -86,5 +87,9 @@ script:
|
||||||
- if [ "$STATIC_CHECKS" = "yes" ]; then
|
- if [ "$STATIC_CHECKS" = "yes" ]; then
|
||||||
sh ./misc/travis/clang-format.sh;
|
sh ./misc/travis/clang-format.sh;
|
||||||
else
|
else
|
||||||
scons platform=$GODOT_TARGET CXX=$CXX openssl=builtin;
|
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||||
|
scons platform=$GODOT_TARGET CXX=$CXX openssl=builtin;
|
||||||
|
else
|
||||||
|
scons platform=$GODOT_TARGET bits=64 CXX=$CXX openssl=builtin;
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1483,16 +1483,16 @@ Error Image::decompress() {
|
||||||
_image_decompress_bc(this);
|
_image_decompress_bc(this);
|
||||||
else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc)
|
else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc)
|
||||||
_image_decompress_pvrtc(this);
|
_image_decompress_pvrtc(this);
|
||||||
else if (format == FORMAT_ETC && _image_decompress_etc)
|
else if (format == FORMAT_ETC && _image_decompress_etc1)
|
||||||
_image_decompress_etc(this);
|
_image_decompress_etc1(this);
|
||||||
else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc)
|
else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc1)
|
||||||
_image_decompress_etc2(this);
|
_image_decompress_etc2(this);
|
||||||
else
|
else
|
||||||
return ERR_UNAVAILABLE;
|
return ERR_UNAVAILABLE;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Image::compress(CompressMode p_mode, bool p_for_srgb) {
|
Error Image::compress(CompressMode p_mode, bool p_for_srgb, float p_lossy_quality) {
|
||||||
|
|
||||||
switch (p_mode) {
|
switch (p_mode) {
|
||||||
|
|
||||||
|
@ -1513,13 +1513,13 @@ Error Image::compress(CompressMode p_mode, bool p_for_srgb) {
|
||||||
} break;
|
} break;
|
||||||
case COMPRESS_ETC: {
|
case COMPRESS_ETC: {
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!_image_compress_etc_func, ERR_UNAVAILABLE);
|
ERR_FAIL_COND_V(!_image_compress_etc1_func, ERR_UNAVAILABLE);
|
||||||
_image_compress_etc_func(this);
|
_image_compress_etc1_func(this, p_lossy_quality);
|
||||||
} break;
|
} break;
|
||||||
case COMPRESS_ETC2: {
|
case COMPRESS_ETC2: {
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!_image_compress_etc_func, ERR_UNAVAILABLE);
|
ERR_FAIL_COND_V(!_image_compress_etc2_func, ERR_UNAVAILABLE);
|
||||||
_image_compress_etc_func(this);
|
_image_compress_etc2_func(this, p_lossy_quality);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1652,11 +1652,11 @@ Ref<Image> (*Image::_jpg_mem_loader_func)(const uint8_t *, int) = NULL;
|
||||||
void (*Image::_image_compress_bc_func)(Image *, bool) = NULL;
|
void (*Image::_image_compress_bc_func)(Image *, bool) = NULL;
|
||||||
void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL;
|
void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL;
|
||||||
void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL;
|
void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL;
|
||||||
void (*Image::_image_compress_etc_func)(Image *) = NULL;
|
void (*Image::_image_compress_etc1_func)(Image *, float) = NULL;
|
||||||
void (*Image::_image_compress_etc2_func)(Image *) = NULL;
|
void (*Image::_image_compress_etc2_func)(Image *, float) = NULL;
|
||||||
void (*Image::_image_decompress_pvrtc)(Image *) = NULL;
|
void (*Image::_image_decompress_pvrtc)(Image *) = NULL;
|
||||||
void (*Image::_image_decompress_bc)(Image *) = NULL;
|
void (*Image::_image_decompress_bc)(Image *) = NULL;
|
||||||
void (*Image::_image_decompress_etc)(Image *) = NULL;
|
void (*Image::_image_decompress_etc1)(Image *) = NULL;
|
||||||
void (*Image::_image_decompress_etc2)(Image *) = NULL;
|
void (*Image::_image_decompress_etc2)(Image *) = NULL;
|
||||||
|
|
||||||
PoolVector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = NULL;
|
PoolVector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = NULL;
|
||||||
|
|
|
@ -117,12 +117,12 @@ public:
|
||||||
static void (*_image_compress_bc_func)(Image *, bool p_srgb);
|
static void (*_image_compress_bc_func)(Image *, bool p_srgb);
|
||||||
static void (*_image_compress_pvrtc2_func)(Image *);
|
static void (*_image_compress_pvrtc2_func)(Image *);
|
||||||
static void (*_image_compress_pvrtc4_func)(Image *);
|
static void (*_image_compress_pvrtc4_func)(Image *);
|
||||||
static void (*_image_compress_etc_func)(Image *);
|
static void (*_image_compress_etc1_func)(Image *, float);
|
||||||
static void (*_image_compress_etc2_func)(Image *);
|
static void (*_image_compress_etc2_func)(Image *, float);
|
||||||
|
|
||||||
static void (*_image_decompress_pvrtc)(Image *);
|
static void (*_image_decompress_pvrtc)(Image *);
|
||||||
static void (*_image_decompress_bc)(Image *);
|
static void (*_image_decompress_bc)(Image *);
|
||||||
static void (*_image_decompress_etc)(Image *);
|
static void (*_image_decompress_etc1)(Image *);
|
||||||
static void (*_image_decompress_etc2)(Image *);
|
static void (*_image_decompress_etc2)(Image *);
|
||||||
|
|
||||||
static PoolVector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality);
|
static PoolVector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality);
|
||||||
|
@ -267,7 +267,7 @@ public:
|
||||||
COMPRESS_ETC2,
|
COMPRESS_ETC2,
|
||||||
};
|
};
|
||||||
|
|
||||||
Error compress(CompressMode p_mode = COMPRESS_S3TC, bool p_for_srgb = false);
|
Error compress(CompressMode p_mode = COMPRESS_S3TC, bool p_for_srgb = false, float p_lossy_quality = 0.7);
|
||||||
Error decompress();
|
Error decompress();
|
||||||
bool is_compressed() const;
|
bool is_compressed() const;
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,15 @@ public:
|
||||||
static _ALWAYS_INLINE_ bool is_inf(double p_val) {
|
static _ALWAYS_INLINE_ bool is_inf(double p_val) {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
return !_finite(p_val);
|
return !_finite(p_val);
|
||||||
|
// workaround for mingw builds on travis
|
||||||
|
#elif defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
union {
|
||||||
|
uint64_t u;
|
||||||
|
double f;
|
||||||
|
} ieee754;
|
||||||
|
ieee754.f = p_val;
|
||||||
|
return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
|
||||||
|
((unsigned)ieee754.u == 0);
|
||||||
#else
|
#else
|
||||||
return isinf(p_val);
|
return isinf(p_val);
|
||||||
#endif
|
#endif
|
||||||
|
@ -120,6 +129,14 @@ public:
|
||||||
static _ALWAYS_INLINE_ bool is_inf(float p_val) {
|
static _ALWAYS_INLINE_ bool is_inf(float p_val) {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
return !_finite(p_val);
|
return !_finite(p_val);
|
||||||
|
// workaround for mingw builds on travis
|
||||||
|
#elif defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
union {
|
||||||
|
uint32_t u;
|
||||||
|
float f;
|
||||||
|
} ieee754;
|
||||||
|
ieee754.f = p_val;
|
||||||
|
return (ieee754.u & 0x7fffffff) == 0x7f800000;
|
||||||
#else
|
#else
|
||||||
return isinf(p_val);
|
return isinf(p_val);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18490,8 +18490,10 @@
|
||||||
</return>
|
</return>
|
||||||
<argument index="0" name="format" type="int" default="0">
|
<argument index="0" name="format" type="int" default="0">
|
||||||
</argument>
|
</argument>
|
||||||
|
<argument index="0" name="quality" type="float" default="0">
|
||||||
|
</argument>
|
||||||
<description>
|
<description>
|
||||||
Return a new compressed [Image] from this [Image] using one of [Image].COMPRESS_*.
|
Return a new compressed [Image] from this [Image] using one of [Image].COMPRESS_*. Quality only affects ETC1 and ETC2 encoding.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="converted">
|
<method name="converted">
|
||||||
|
|
|
@ -144,8 +144,12 @@ String ResourceImporterTexture::get_resource_type() const {
|
||||||
|
|
||||||
bool ResourceImporterTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
|
bool ResourceImporterTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
|
||||||
|
|
||||||
if (p_option == "compress/lossy_quality" && int(p_options["compress/mode"]) != COMPRESS_LOSSY)
|
if (p_option == "compress/lossy_quality") {
|
||||||
return false;
|
int compress_mode = int(p_options["compress/mode"]);
|
||||||
|
if (compress_mode != COMPRESS_LOSSY && compress_mode != COMPRESS_VIDEO_RAM) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +281,7 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String
|
||||||
if (p_force_rgbe && image->get_format() >= Image::FORMAT_R8 && image->get_format() <= Image::FORMAT_RGBE9995) {
|
if (p_force_rgbe && image->get_format() >= Image::FORMAT_R8 && image->get_format() <= Image::FORMAT_RGBE9995) {
|
||||||
image->convert(Image::FORMAT_RGBE9995);
|
image->convert(Image::FORMAT_RGBE9995);
|
||||||
} else {
|
} else {
|
||||||
image->compress(p_vram_compression, p_texture_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR);
|
image->compress(p_vram_compression, p_texture_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR, p_lossy_quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
format |= image->get_format();
|
format |= image->get_format();
|
||||||
|
@ -382,8 +386,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||||
//Android, GLES 2.x
|
//Android, GLES 2.x
|
||||||
_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
||||||
r_platform_variants->push_back("etc");
|
r_platform_variants->push_back("etc");
|
||||||
//_save_stex(image,p_save_path+".etc2.stex",compress_mode,lossy,Image::COMPRESS_ETC2,mipmaps,tex_flags,stream);
|
_save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
||||||
//r_platform_variants->push_back("etc2");
|
r_platform_variants->push_back("etc2");
|
||||||
_save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
_save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe);
|
||||||
r_platform_variants->push_back("s3tc");
|
r_platform_variants->push_back("s3tc");
|
||||||
|
|
||||||
|
|
37
modules/etc/SCsub
Normal file
37
modules/etc/SCsub
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import('env')
|
||||||
|
Import('env_modules')
|
||||||
|
|
||||||
|
env_etc = env_modules.Clone()
|
||||||
|
|
||||||
|
# Thirdparty source files
|
||||||
|
# Not unbundled so far since not widespread as shared library
|
||||||
|
thirdparty_dir = "#thirdparty/etc2comp/"
|
||||||
|
thirdparty_sources = [
|
||||||
|
"EtcBlock4x4.cpp",
|
||||||
|
"EtcBlock4x4Encoding.cpp",
|
||||||
|
"EtcBlock4x4Encoding_ETC1.cpp",
|
||||||
|
"EtcBlock4x4Encoding_R11.cpp",
|
||||||
|
"EtcBlock4x4Encoding_RG11.cpp",
|
||||||
|
"EtcBlock4x4Encoding_RGB8A1.cpp",
|
||||||
|
"EtcBlock4x4Encoding_RGB8.cpp",
|
||||||
|
"EtcBlock4x4Encoding_RGBA8.cpp",
|
||||||
|
"Etc.cpp",
|
||||||
|
"EtcDifferentialTrys.cpp",
|
||||||
|
"EtcFilter.cpp",
|
||||||
|
"EtcImage.cpp",
|
||||||
|
"EtcIndividualTrys.cpp",
|
||||||
|
"EtcMath.cpp",
|
||||||
|
"EtcSortedBlockList.cpp",
|
||||||
|
]
|
||||||
|
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||||
|
|
||||||
|
env_etc.add_source_files(env.modules_sources, thirdparty_sources)
|
||||||
|
env_etc.Append(CPPPATH=[thirdparty_dir])
|
||||||
|
|
||||||
|
# Godot source files
|
||||||
|
env_etc.add_source_files(env.modules_sources, "*.cpp")
|
||||||
|
|
||||||
|
# upstream uses c++11
|
||||||
|
env_etc.Append(CXXFLAGS="-std=gnu++11")
|
181
modules/etc/image_etc.cpp
Normal file
181
modules/etc/image_etc.cpp
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* image_etc.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* http://www.godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* 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. */
|
||||||
|
/*************************************************************************/
|
||||||
|
#include "image_etc.h"
|
||||||
|
#include "Etc.h"
|
||||||
|
#include "EtcFilter.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "os/copymem.h"
|
||||||
|
#include "os/os.h"
|
||||||
|
#include "print_string.h"
|
||||||
|
|
||||||
|
static Image::Format _get_etc2_mode(Image::DetectChannels format) {
|
||||||
|
switch (format) {
|
||||||
|
case Image::DETECTED_L:
|
||||||
|
case Image::DETECTED_R:
|
||||||
|
return Image::FORMAT_ETC2_R11;
|
||||||
|
|
||||||
|
case Image::DETECTED_RG:
|
||||||
|
return Image::FORMAT_ETC2_RG11;
|
||||||
|
|
||||||
|
case Image::DETECTED_RGB:
|
||||||
|
return Image::FORMAT_ETC2_RGB8;
|
||||||
|
|
||||||
|
case Image::DETECTED_RGBA:
|
||||||
|
return Image::FORMAT_ETC2_RGBA8;
|
||||||
|
|
||||||
|
// TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(true, Image::FORMAT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Etc::Image::Format _image_format_to_etc2comp_format(Image::Format format) {
|
||||||
|
switch (format) {
|
||||||
|
case Image::FORMAT_ETC:
|
||||||
|
return Etc::Image::Format::ETC1;
|
||||||
|
|
||||||
|
case Image::FORMAT_ETC2_R11:
|
||||||
|
return Etc::Image::Format::R11;
|
||||||
|
|
||||||
|
case Image::FORMAT_ETC2_R11S:
|
||||||
|
return Etc::Image::Format::SIGNED_R11;
|
||||||
|
|
||||||
|
case Image::FORMAT_ETC2_RG11:
|
||||||
|
return Etc::Image::Format::RG11;
|
||||||
|
|
||||||
|
case Image::FORMAT_ETC2_RG11S:
|
||||||
|
return Etc::Image::Format::SIGNED_RG11;
|
||||||
|
|
||||||
|
case Image::FORMAT_ETC2_RGB8:
|
||||||
|
return Etc::Image::Format::RGB8;
|
||||||
|
|
||||||
|
case Image::FORMAT_ETC2_RGBA8:
|
||||||
|
return Etc::Image::Format::RGBA8;
|
||||||
|
|
||||||
|
case Image::FORMAT_ETC2_RGB8A1:
|
||||||
|
return Etc::Image::Format::RGB8A1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(true, Etc::Image::Format::UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _decompress_etc1(Image *p_img) {
|
||||||
|
// not implemented, to be removed
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _decompress_etc2(Image *p_img) {
|
||||||
|
// not implemented, to be removed
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_format) {
|
||||||
|
Image::Format img_format = p_img->get_format();
|
||||||
|
Image::DetectChannels detected_channels = p_img->get_detected_channels();
|
||||||
|
|
||||||
|
if (img_format >= Image::FORMAT_DXT1) {
|
||||||
|
return; //do not compress, already compressed
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img_format > Image::FORMAT_RGBA8) {
|
||||||
|
// TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int imgw = p_img->get_width(), imgh = p_img->get_height();
|
||||||
|
ERR_FAIL_COND(nearest_power_of_2(imgw) != imgw || nearest_power_of_2(imgh) != imgh);
|
||||||
|
|
||||||
|
Image::Format etc_format = force_etc1_format ? Image::FORMAT_ETC : _get_etc2_mode(detected_channels);
|
||||||
|
|
||||||
|
Ref<Image> img = p_img->duplicate();
|
||||||
|
|
||||||
|
if (img->get_format() != Image::FORMAT_RGBA8)
|
||||||
|
img->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
|
||||||
|
|
||||||
|
PoolVector<uint8_t>::Read r = img->get_data().read();
|
||||||
|
|
||||||
|
int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps() ? -1 : 0);
|
||||||
|
int mmc = p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0;
|
||||||
|
|
||||||
|
PoolVector<uint8_t> dst_data;
|
||||||
|
dst_data.resize(target_size);
|
||||||
|
|
||||||
|
PoolVector<uint8_t>::Write w = dst_data.write();
|
||||||
|
|
||||||
|
// prepare parameters to be passed to etc2comp
|
||||||
|
int num_cpus = OS::get_singleton()->get_processor_count();
|
||||||
|
int encoding_time = 0;
|
||||||
|
float effort = CLAMP(p_lossy_quality * 100, 0, 100);
|
||||||
|
Etc::ErrorMetric error_metric = Etc::ErrorMetric::BT709; // NOTE: we can experiment with other error metrics
|
||||||
|
Etc::Image::Format etc2comp_etc_format = _image_format_to_etc2comp_format(etc_format);
|
||||||
|
|
||||||
|
int wofs = 0;
|
||||||
|
for (int i = 0; i < mmc + 1; i++) {
|
||||||
|
// convert source image to internal etc2comp format (which is equivalent to Image::FORMAT_RGBAF)
|
||||||
|
// NOTE: We can alternatively add a case to Image::convert to handle Image::FORMAT_RGBAF conversion.
|
||||||
|
int mipmap_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0;
|
||||||
|
img->get_mipmap_offset_size_and_dimensions(i, mipmap_ofs, mipmap_size, mipmap_w, mipmap_h);
|
||||||
|
const uint8_t *src = &r[mipmap_ofs];
|
||||||
|
|
||||||
|
Etc::ColorFloatRGBA *src_rgba_f = new Etc::ColorFloatRGBA[mipmap_w * mipmap_h];
|
||||||
|
for (int i = 0; i < mipmap_w * mipmap_h; i++) {
|
||||||
|
int si = i * 4; // RGBA8
|
||||||
|
src_rgba_f[i] = Etc::ColorFloatRGBA::ConvertFromRGBA8(src[si], src[si + 1], src[si + 2], src[si + 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *etc_data = NULL;
|
||||||
|
unsigned int etc_data_len = 0;
|
||||||
|
unsigned int extended_width = 0, extended_height = 0;
|
||||||
|
Etc::Encode((float *)src_rgba_f, mipmap_w, mipmap_h, etc2comp_etc_format, error_metric, effort, num_cpus, num_cpus, &etc_data, &etc_data_len, &extended_width, &extended_height, &encoding_time);
|
||||||
|
|
||||||
|
memcpy(&w[wofs], etc_data, etc_data_len);
|
||||||
|
wofs += etc_data_len;
|
||||||
|
|
||||||
|
delete[] etc_data;
|
||||||
|
delete[] src_rgba_f;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_img->create(imgw, imgh, mmc > 1 ? true : false, etc_format, dst_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _compress_etc1(Image *p_img, float p_lossy_quality) {
|
||||||
|
_compress_etc(p_img, p_lossy_quality, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _compress_etc2(Image *p_img, float p_lossy_quality) {
|
||||||
|
_compress_etc(p_img, p_lossy_quality, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _register_etc_compress_func() {
|
||||||
|
|
||||||
|
Image::_image_compress_etc1_func = _compress_etc1;
|
||||||
|
//Image::_image_decompress_etc1 = _decompress_etc1;
|
||||||
|
|
||||||
|
Image::_image_compress_etc2_func = _compress_etc2;
|
||||||
|
//Image::_image_decompress_etc2 = _decompress_etc2;
|
||||||
|
}
|
|
@ -30,6 +30,6 @@
|
||||||
#ifndef IMAGE_ETC1_H
|
#ifndef IMAGE_ETC1_H
|
||||||
#define IMAGE_ETC1_H
|
#define IMAGE_ETC1_H
|
||||||
|
|
||||||
void _register_etc1_compress_func();
|
void _register_etc_compress_func();
|
||||||
|
|
||||||
#endif // IMAGE_ETC_H
|
#endif // IMAGE_ETC_H
|
|
@ -34,15 +34,15 @@
|
||||||
|
|
||||||
static ResourceFormatPKM *resource_loader_pkm = NULL;
|
static ResourceFormatPKM *resource_loader_pkm = NULL;
|
||||||
|
|
||||||
void register_etc1_types() {
|
void register_etc_types() {
|
||||||
|
|
||||||
resource_loader_pkm = memnew(ResourceFormatPKM);
|
resource_loader_pkm = memnew(ResourceFormatPKM);
|
||||||
ResourceLoader::add_resource_format_loader(resource_loader_pkm);
|
ResourceLoader::add_resource_format_loader(resource_loader_pkm);
|
||||||
|
|
||||||
_register_etc1_compress_func();
|
_register_etc_compress_func();
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister_etc1_types() {
|
void unregister_etc_types() {
|
||||||
|
|
||||||
memdelete(resource_loader_pkm);
|
memdelete(resource_loader_pkm);
|
||||||
}
|
}
|
|
@ -27,5 +27,5 @@
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
void register_etc1_types();
|
void register_etc_types();
|
||||||
void unregister_etc1_types();
|
void unregister_etc_types();
|
|
@ -1,20 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
Import('env')
|
|
||||||
Import('env_modules')
|
|
||||||
|
|
||||||
env_etc1 = env_modules.Clone()
|
|
||||||
|
|
||||||
# Thirdparty source files
|
|
||||||
# Not unbundled so far since not widespread as shared library
|
|
||||||
thirdparty_dir = "#thirdparty/rg-etc1/"
|
|
||||||
thirdparty_sources = [
|
|
||||||
"rg_etc1.cpp",
|
|
||||||
]
|
|
||||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
|
||||||
|
|
||||||
env_etc1.add_source_files(env.modules_sources, thirdparty_sources)
|
|
||||||
env_etc1.Append(CPPPATH=[thirdparty_dir])
|
|
||||||
|
|
||||||
# Godot source files
|
|
||||||
env_etc1.add_source_files(env.modules_sources, "*.cpp")
|
|
|
@ -1,183 +0,0 @@
|
||||||
/*************************************************************************/
|
|
||||||
/* image_etc.cpp */
|
|
||||||
/*************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* http://www.godotengine.org */
|
|
||||||
/*************************************************************************/
|
|
||||||
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
|
|
||||||
/* */
|
|
||||||
/* 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. */
|
|
||||||
/*************************************************************************/
|
|
||||||
#include "image_etc.h"
|
|
||||||
#include "image.h"
|
|
||||||
#include "os/copymem.h"
|
|
||||||
#include "print_string.h"
|
|
||||||
#include "rg_etc1.h"
|
|
||||||
static void _decompress_etc(Image *p_img) {
|
|
||||||
|
|
||||||
ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_ETC);
|
|
||||||
|
|
||||||
int imgw = p_img->get_width();
|
|
||||||
int imgh = p_img->get_height();
|
|
||||||
PoolVector<uint8_t> src = p_img->get_data();
|
|
||||||
PoolVector<uint8_t> dst;
|
|
||||||
|
|
||||||
PoolVector<uint8_t>::Read r = src.read();
|
|
||||||
|
|
||||||
int mmc = p_img->get_mipmap_count();
|
|
||||||
|
|
||||||
for (int i = 0; i <= mmc; i++) {
|
|
||||||
|
|
||||||
dst.resize(dst.size() + imgw * imgh * 3);
|
|
||||||
const uint8_t *srcbr = &r[p_img->get_mipmap_offset(i)];
|
|
||||||
PoolVector<uint8_t>::Write w = dst.write();
|
|
||||||
|
|
||||||
uint8_t *wptr = &w[dst.size() - imgw * imgh * 3];
|
|
||||||
|
|
||||||
int bw = MAX(imgw / 4, 1);
|
|
||||||
int bh = MAX(imgh / 4, 1);
|
|
||||||
|
|
||||||
for (int y = 0; y < bh; y++) {
|
|
||||||
|
|
||||||
for (int x = 0; x < bw; x++) {
|
|
||||||
|
|
||||||
uint8_t block[4 * 4 * 4];
|
|
||||||
|
|
||||||
rg_etc1::unpack_etc1_block(srcbr, (unsigned int *)block);
|
|
||||||
srcbr += 8;
|
|
||||||
|
|
||||||
int maxx = MIN(imgw, 4);
|
|
||||||
int maxy = MIN(imgh, 4);
|
|
||||||
|
|
||||||
for (int yy = 0; yy < maxy; yy++) {
|
|
||||||
|
|
||||||
for (int xx = 0; xx < maxx; xx++) {
|
|
||||||
|
|
||||||
uint32_t src_ofs = (yy * 4 + xx) * 4;
|
|
||||||
uint32_t dst_ofs = ((y * 4 + yy) * imgw + x * 4 + xx) * 3;
|
|
||||||
wptr[dst_ofs + 0] = block[src_ofs + 0];
|
|
||||||
wptr[dst_ofs + 1] = block[src_ofs + 1];
|
|
||||||
wptr[dst_ofs + 2] = block[src_ofs + 2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
imgw = MAX(1, imgw / 2);
|
|
||||||
imgh = MAX(1, imgh / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = PoolVector<uint8_t>::Read();
|
|
||||||
//print_line("Re Creating ETC into regular image: w "+itos(p_img->get_width())+" h "+itos(p_img->get_height())+" mm "+itos(p_img->get_mipmaps()));
|
|
||||||
bool needs_mipmaps = p_img->has_mipmaps();
|
|
||||||
p_img->create(p_img->get_width(), p_img->get_height(), p_img->has_mipmaps(), Image::FORMAT_RGB8, dst);
|
|
||||||
if (needs_mipmaps)
|
|
||||||
p_img->generate_mipmaps();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _compress_etc(Image *p_img) {
|
|
||||||
|
|
||||||
Ref<Image> img = p_img->duplicate();
|
|
||||||
|
|
||||||
int imgw = img->get_width(), imgh = img->get_height();
|
|
||||||
|
|
||||||
ERR_FAIL_COND(nearest_power_of_2(imgw) != imgw || nearest_power_of_2(imgh) != imgh);
|
|
||||||
|
|
||||||
if (img->get_format() != Image::FORMAT_RGB8)
|
|
||||||
img->convert(Image::FORMAT_RGB8);
|
|
||||||
|
|
||||||
PoolVector<uint8_t> res_data;
|
|
||||||
PoolVector<uint8_t> dst_data;
|
|
||||||
PoolVector<uint8_t>::Read r = img->get_data().read();
|
|
||||||
|
|
||||||
int target_size = Image::get_image_data_size(p_img->get_width(), p_img->get_height(), Image::FORMAT_ETC, p_img->has_mipmaps() ? -1 : 0);
|
|
||||||
int mmc = p_img->has_mipmaps() ? Image::get_image_required_mipmaps(p_img->get_width(), p_img->get_height(), Image::FORMAT_ETC) : 0;
|
|
||||||
|
|
||||||
dst_data.resize(target_size);
|
|
||||||
int mc = 0;
|
|
||||||
int ofs = 0;
|
|
||||||
PoolVector<uint8_t>::Write w = dst_data.write();
|
|
||||||
|
|
||||||
rg_etc1::etc1_pack_params pp;
|
|
||||||
pp.m_quality = rg_etc1::cLowQuality;
|
|
||||||
for (int i = 0; i <= mmc; i++) {
|
|
||||||
|
|
||||||
int bw = MAX(imgw / 4, 1);
|
|
||||||
int bh = MAX(imgh / 4, 1);
|
|
||||||
const uint8_t *src = &r[img->get_mipmap_offset(i)];
|
|
||||||
int mmsize = MAX(bw, 1) * MAX(bh, 1) * 8;
|
|
||||||
|
|
||||||
uint8_t *dst = &w[ofs];
|
|
||||||
ofs += mmsize;
|
|
||||||
|
|
||||||
//print_line("bh: "+itos(bh)+" bw: "+itos(bw));
|
|
||||||
|
|
||||||
for (int y = 0; y < bh; y++) {
|
|
||||||
|
|
||||||
for (int x = 0; x < bw; x++) {
|
|
||||||
|
|
||||||
//print_line("x: "+itos(x)+" y: "+itos(y));
|
|
||||||
|
|
||||||
uint8_t block[4 * 4 * 4];
|
|
||||||
zeromem(block, 4 * 4 * 4);
|
|
||||||
uint8_t cblock[8];
|
|
||||||
|
|
||||||
int maxy = MIN(imgh, 4);
|
|
||||||
int maxx = MIN(imgw, 4);
|
|
||||||
|
|
||||||
for (int yy = 0; yy < maxy; yy++) {
|
|
||||||
|
|
||||||
for (int xx = 0; xx < maxx; xx++) {
|
|
||||||
|
|
||||||
uint32_t dst_ofs = (yy * 4 + xx) * 4;
|
|
||||||
uint32_t src_ofs = ((y * 4 + yy) * imgw + x * 4 + xx) * 3;
|
|
||||||
block[dst_ofs + 0] = src[src_ofs + 0];
|
|
||||||
block[dst_ofs + 1] = src[src_ofs + 1];
|
|
||||||
block[dst_ofs + 2] = src[src_ofs + 2];
|
|
||||||
block[dst_ofs + 3] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rg_etc1::pack_etc1_block(cblock, (const unsigned int *)block, pp);
|
|
||||||
for (int j = 0; j < 8; j++) {
|
|
||||||
|
|
||||||
dst[j] = cblock[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
dst += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
imgw = MAX(1, imgw / 2);
|
|
||||||
imgh = MAX(1, imgh / 2);
|
|
||||||
mc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_img->create(p_img->get_width(), p_img->get_height(), (mc - 1) ? true : false, Image::FORMAT_ETC, dst_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _register_etc1_compress_func() {
|
|
||||||
|
|
||||||
rg_etc1::pack_etc1_block_init();
|
|
||||||
Image::_image_compress_etc_func = _compress_etc;
|
|
||||||
Image::_image_decompress_etc = _decompress_etc;
|
|
||||||
}
|
|
23
thirdparty/README.md
vendored
23
thirdparty/README.md
vendored
|
@ -37,6 +37,18 @@ Check the diff of enet.h, protocol.c, and host.c with the 1.3.13
|
||||||
tarball before the next update.
|
tarball before the next update.
|
||||||
|
|
||||||
|
|
||||||
|
## etc2comp
|
||||||
|
|
||||||
|
- Upstream: https://github.com/google/etc2comp
|
||||||
|
- Version: 9cd0f9c (git)
|
||||||
|
- License: Apache
|
||||||
|
|
||||||
|
Files extracted from upstream source:
|
||||||
|
|
||||||
|
- all .cpp and .h files in EtcLib/
|
||||||
|
- README.md, LICENSE, AUTHORS
|
||||||
|
|
||||||
|
|
||||||
## fonts
|
## fonts
|
||||||
|
|
||||||
- Upstream: ?
|
- Upstream: ?
|
||||||
|
@ -296,17 +308,6 @@ Files extracted from upstream source:
|
||||||
- LICENSE.TXT
|
- LICENSE.TXT
|
||||||
|
|
||||||
|
|
||||||
## rg-etc1
|
|
||||||
|
|
||||||
- Upstream: https://github.com/richgel999/rg-etc1
|
|
||||||
- Version: 1.04
|
|
||||||
- License: zlib
|
|
||||||
|
|
||||||
Files extracted from upstream source:
|
|
||||||
|
|
||||||
- `rg_etc1.{cpp,h}`
|
|
||||||
|
|
||||||
|
|
||||||
## rtaudio
|
## rtaudio
|
||||||
|
|
||||||
- Upstream: http://www.music.mcgill.ca/~gary/rtaudio/
|
- Upstream: http://www.music.mcgill.ca/~gary/rtaudio/
|
||||||
|
|
7
thirdparty/etc2comp/AUTHORS
vendored
Normal file
7
thirdparty/etc2comp/AUTHORS
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# This is the list of Etc2Comp authors for copyright purposes.
|
||||||
|
#
|
||||||
|
# This does not necessarily list everyone who has contributed code, since in
|
||||||
|
# some cases, their employer may be the copyright holder. To see the full list
|
||||||
|
# of contributors, see the revision history in source control.
|
||||||
|
Google Inc.
|
||||||
|
Blue Shift Inc.
|
128
thirdparty/etc2comp/Etc.cpp
vendored
Normal file
128
thirdparty/etc2comp/Etc.cpp
vendored
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "Etc.h"
|
||||||
|
#include "EtcFilter.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// C-style inteface to the encoder
|
||||||
|
//
|
||||||
|
void Encode(float *a_pafSourceRGBA,
|
||||||
|
unsigned int a_uiSourceWidth,
|
||||||
|
unsigned int a_uiSourceHeight,
|
||||||
|
Image::Format a_format,
|
||||||
|
ErrorMetric a_eErrMetric,
|
||||||
|
float a_fEffort,
|
||||||
|
unsigned int a_uiJobs,
|
||||||
|
unsigned int a_uiMaxJobs,
|
||||||
|
unsigned char **a_ppaucEncodingBits,
|
||||||
|
unsigned int *a_puiEncodingBitsBytes,
|
||||||
|
unsigned int *a_puiExtendedWidth,
|
||||||
|
unsigned int *a_puiExtendedHeight,
|
||||||
|
int *a_piEncodingTime_ms, bool a_bVerboseOutput)
|
||||||
|
{
|
||||||
|
|
||||||
|
Image image(a_pafSourceRGBA, a_uiSourceWidth,
|
||||||
|
a_uiSourceHeight,
|
||||||
|
a_eErrMetric);
|
||||||
|
image.m_bVerboseOutput = a_bVerboseOutput;
|
||||||
|
image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs);
|
||||||
|
|
||||||
|
*a_ppaucEncodingBits = image.GetEncodingBits();
|
||||||
|
*a_puiEncodingBitsBytes = image.GetEncodingBitsBytes();
|
||||||
|
*a_puiExtendedWidth = image.GetExtendedWidth();
|
||||||
|
*a_puiExtendedHeight = image.GetExtendedHeight();
|
||||||
|
*a_piEncodingTime_ms = image.GetEncodingTimeMs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EncodeMipmaps(float *a_pafSourceRGBA,
|
||||||
|
unsigned int a_uiSourceWidth,
|
||||||
|
unsigned int a_uiSourceHeight,
|
||||||
|
Image::Format a_format,
|
||||||
|
ErrorMetric a_eErrMetric,
|
||||||
|
float a_fEffort,
|
||||||
|
unsigned int a_uiJobs,
|
||||||
|
unsigned int a_uiMaxJobs,
|
||||||
|
unsigned int a_uiMaxMipmaps,
|
||||||
|
unsigned int a_uiMipFilterFlags,
|
||||||
|
RawImage* a_pMipmapImages,
|
||||||
|
int *a_piEncodingTime_ms,
|
||||||
|
bool a_bVerboseOutput)
|
||||||
|
{
|
||||||
|
auto mipWidth = a_uiSourceWidth;
|
||||||
|
auto mipHeight = a_uiSourceHeight;
|
||||||
|
int totalEncodingTime = 0;
|
||||||
|
for(unsigned int mip = 0; mip < a_uiMaxMipmaps && mipWidth >= 1 && mipHeight >= 1; mip++)
|
||||||
|
{
|
||||||
|
float* pImageData = nullptr;
|
||||||
|
float* pMipImage = nullptr;
|
||||||
|
|
||||||
|
if(mip == 0)
|
||||||
|
{
|
||||||
|
pImageData = a_pafSourceRGBA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pMipImage = new float[mipWidth*mipHeight*4];
|
||||||
|
if(FilterTwoPass(a_pafSourceRGBA, a_uiSourceWidth, a_uiSourceHeight, pMipImage, mipWidth, mipHeight, a_uiMipFilterFlags, Etc::FilterLanczos3) )
|
||||||
|
{
|
||||||
|
pImageData = pMipImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pImageData )
|
||||||
|
{
|
||||||
|
|
||||||
|
Image image(pImageData, mipWidth, mipHeight, a_eErrMetric);
|
||||||
|
|
||||||
|
image.m_bVerboseOutput = a_bVerboseOutput;
|
||||||
|
image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs);
|
||||||
|
|
||||||
|
a_pMipmapImages[mip].paucEncodingBits = std::shared_ptr<unsigned char>(image.GetEncodingBits(), [](unsigned char *p) { delete[] p; });
|
||||||
|
a_pMipmapImages[mip].uiEncodingBitsBytes = image.GetEncodingBitsBytes();
|
||||||
|
a_pMipmapImages[mip].uiExtendedWidth = image.GetExtendedWidth();
|
||||||
|
a_pMipmapImages[mip].uiExtendedHeight = image.GetExtendedHeight();
|
||||||
|
|
||||||
|
totalEncodingTime += image.GetEncodingTimeMs();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pMipImage)
|
||||||
|
{
|
||||||
|
delete[] pMipImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pImageData)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mipWidth >>= 1;
|
||||||
|
mipHeight >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*a_piEncodingTime_ms = totalEncodingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
71
thirdparty/etc2comp/Etc.h
vendored
Normal file
71
thirdparty/etc2comp/Etc.h
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcImage.h"
|
||||||
|
#include "EtcColor.h"
|
||||||
|
#include "EtcErrorMetric.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#define ETCCOMP_MIN_EFFORT_LEVEL (0.0f)
|
||||||
|
#define ETCCOMP_DEFAULT_EFFORT_LEVEL (40.0f)
|
||||||
|
#define ETCCOMP_MAX_EFFORT_LEVEL (100.0f)
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4EncodingBits;
|
||||||
|
|
||||||
|
struct RawImage
|
||||||
|
{
|
||||||
|
int uiExtendedWidth;
|
||||||
|
int uiExtendedHeight;
|
||||||
|
unsigned int uiEncodingBitsBytes;
|
||||||
|
std::shared_ptr<unsigned char> paucEncodingBits;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// C-style inteface to the encoder
|
||||||
|
void Encode(float *a_pafSourceRGBA,
|
||||||
|
unsigned int a_uiSourceWidth,
|
||||||
|
unsigned int a_uiSourceHeight,
|
||||||
|
Image::Format a_format,
|
||||||
|
ErrorMetric a_eErrMetric,
|
||||||
|
float a_fEffort,
|
||||||
|
unsigned int a_uiJobs,
|
||||||
|
unsigned int a_uimaxJobs,
|
||||||
|
unsigned char **a_ppaucEncodingBits,
|
||||||
|
unsigned int *a_puiEncodingBitsBytes,
|
||||||
|
unsigned int *a_puiExtendedWidth,
|
||||||
|
unsigned int *a_puiExtendedHeight,
|
||||||
|
int *a_piEncodingTime_ms, bool a_bVerboseOutput = false);
|
||||||
|
|
||||||
|
void EncodeMipmaps(float *a_pafSourceRGBA,
|
||||||
|
unsigned int a_uiSourceWidth,
|
||||||
|
unsigned int a_uiSourceHeight,
|
||||||
|
Image::Format a_format,
|
||||||
|
ErrorMetric a_eErrMetric,
|
||||||
|
float a_fEffort,
|
||||||
|
unsigned int a_uiJobs,
|
||||||
|
unsigned int a_uiMaxJobs,
|
||||||
|
unsigned int a_uiMaxMipmaps,
|
||||||
|
unsigned int a_uiMipFilterFlags,
|
||||||
|
RawImage* a_pMipmaps,
|
||||||
|
int *a_piEncodingTime_ms, bool a_bVerboseOutput = false);
|
||||||
|
|
||||||
|
}
|
425
thirdparty/etc2comp/EtcBlock4x4.cpp
vendored
Normal file
425
thirdparty/etc2comp/EtcBlock4x4.cpp
vendored
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcBlock4x4.cpp
|
||||||
|
|
||||||
|
Implements the state associated with each 4x4 block of pixels in an image
|
||||||
|
|
||||||
|
Source images that are not a multiple of 4x4 are extended to fill the Block4x4 using pixels with an
|
||||||
|
alpha of NAN
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcBlock4x4.h"
|
||||||
|
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcColor.h"
|
||||||
|
#include "EtcImage.h"
|
||||||
|
#include "EtcColorFloatRGBA.h"
|
||||||
|
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||||
|
#include "EtcBlock4x4Encoding_RGBA8.h"
|
||||||
|
#include "EtcBlock4x4Encoding_RGB8A1.h"
|
||||||
|
#include "EtcBlock4x4Encoding_R11.h"
|
||||||
|
#include "EtcBlock4x4Encoding_RG11.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
// ETC pixels are scanned vertically.
|
||||||
|
// this mapping is for when someone wants to scan the ETC pixels horizontally
|
||||||
|
const unsigned int Block4x4::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
Block4x4::Block4x4(void)
|
||||||
|
{
|
||||||
|
m_pimageSource = nullptr;
|
||||||
|
m_uiSourceH = 0;
|
||||||
|
m_uiSourceV = 0;
|
||||||
|
|
||||||
|
m_sourcealphamix = SourceAlphaMix::UNKNOWN;
|
||||||
|
m_boolBorderPixels = false;
|
||||||
|
m_boolPunchThroughPixels = false;
|
||||||
|
|
||||||
|
m_pencoding = nullptr;
|
||||||
|
|
||||||
|
m_errormetric = ErrorMetric::NUMERIC;
|
||||||
|
|
||||||
|
}
|
||||||
|
Block4x4::~Block4x4()
|
||||||
|
{
|
||||||
|
m_pimageSource = nullptr;
|
||||||
|
if (m_pencoding)
|
||||||
|
{
|
||||||
|
delete m_pencoding;
|
||||||
|
m_pencoding = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization prior to encoding from a source image
|
||||||
|
// [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
|
||||||
|
// a_paucEncodingBits is the place to store the final encoding
|
||||||
|
// a_errormetric is used for finding the best encoding
|
||||||
|
//
|
||||||
|
void Block4x4::InitFromSource(Image *a_pimageSource,
|
||||||
|
unsigned int a_uiSourceH, unsigned int a_uiSourceV,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
|
||||||
|
Block4x4();
|
||||||
|
|
||||||
|
m_pimageSource = a_pimageSource;
|
||||||
|
m_uiSourceH = a_uiSourceH;
|
||||||
|
m_uiSourceV = a_uiSourceV;
|
||||||
|
m_errormetric = a_errormetric;
|
||||||
|
|
||||||
|
SetSourcePixels();
|
||||||
|
|
||||||
|
// set block encoder function
|
||||||
|
switch (m_pimageSource->GetFormat())
|
||||||
|
{
|
||||||
|
case Image::Format::ETC1:
|
||||||
|
m_pencoding = new Block4x4Encoding_ETC1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGB8:
|
||||||
|
case Image::Format::SRGB8:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGB8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGBA8:
|
||||||
|
case Image::Format::SRGBA8:
|
||||||
|
if (a_errormetric == RGBX)
|
||||||
|
{
|
||||||
|
m_pencoding = new Block4x4Encoding_RGBA8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (m_sourcealphamix)
|
||||||
|
{
|
||||||
|
case SourceAlphaMix::OPAQUE:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGBA8_Opaque;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SourceAlphaMix::TRANSPARENT:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGBA8_Transparent;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SourceAlphaMix::TRANSLUCENT:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGBA8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGB8A1:
|
||||||
|
case Image::Format::SRGB8A1:
|
||||||
|
switch (m_sourcealphamix)
|
||||||
|
{
|
||||||
|
case SourceAlphaMix::OPAQUE:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SourceAlphaMix::TRANSPARENT:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGB8A1_Transparent;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SourceAlphaMix::TRANSLUCENT:
|
||||||
|
if (m_boolPunchThroughPixels)
|
||||||
|
{
|
||||||
|
m_pencoding = new Block4x4Encoding_RGB8A1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::R11:
|
||||||
|
case Image::Format::SIGNED_R11:
|
||||||
|
m_pencoding = new Block4x4Encoding_R11;
|
||||||
|
break;
|
||||||
|
case Image::Format::RG11:
|
||||||
|
case Image::Format::SIGNED_RG11:
|
||||||
|
m_pencoding = new Block4x4Encoding_RG11;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pencoding->InitFromSource(this, m_afrgbaSource,
|
||||||
|
a_paucEncodingBits, a_errormetric);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization of encoding state from a prior encoding using encoding bits
|
||||||
|
// [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
|
||||||
|
// a_paucEncodingBits is the place to read the prior encoding
|
||||||
|
// a_imageformat is used to determine how to interpret a_paucEncodingBits
|
||||||
|
// a_errormetric was used for the prior encoding
|
||||||
|
//
|
||||||
|
void Block4x4::InitFromEtcEncodingBits(Image::Format a_imageformat,
|
||||||
|
unsigned int a_uiSourceH, unsigned int a_uiSourceV,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
Image *a_pimageSource,
|
||||||
|
ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
Block4x4();
|
||||||
|
|
||||||
|
m_pimageSource = a_pimageSource;
|
||||||
|
m_uiSourceH = a_uiSourceH;
|
||||||
|
m_uiSourceV = a_uiSourceV;
|
||||||
|
m_errormetric = a_errormetric;
|
||||||
|
|
||||||
|
SetSourcePixels();
|
||||||
|
|
||||||
|
// set block encoder function
|
||||||
|
switch (a_imageformat)
|
||||||
|
{
|
||||||
|
case Image::Format::ETC1:
|
||||||
|
m_pencoding = new Block4x4Encoding_ETC1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGB8:
|
||||||
|
case Image::Format::SRGB8:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGB8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGBA8:
|
||||||
|
case Image::Format::SRGBA8:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGBA8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGB8A1:
|
||||||
|
case Image::Format::SRGB8A1:
|
||||||
|
m_pencoding = new Block4x4Encoding_RGB8A1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::R11:
|
||||||
|
case Image::Format::SIGNED_R11:
|
||||||
|
m_pencoding = new Block4x4Encoding_R11;
|
||||||
|
break;
|
||||||
|
case Image::Format::RG11:
|
||||||
|
case Image::Format::SIGNED_RG11:
|
||||||
|
m_pencoding = new Block4x4Encoding_RG11;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pencoding->InitFromEncodingBits(this, a_paucEncodingBits, m_afrgbaSource,
|
||||||
|
m_pimageSource->GetErrorMetric());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// set source pixels from m_pimageSource
|
||||||
|
// set m_alphamix
|
||||||
|
//
|
||||||
|
void Block4x4::SetSourcePixels(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
Image::Format imageformat = m_pimageSource->GetFormat();
|
||||||
|
|
||||||
|
// alpha census
|
||||||
|
unsigned int uiTransparentSourcePixels = 0;
|
||||||
|
unsigned int uiOpaqueSourcePixels = 0;
|
||||||
|
|
||||||
|
// copy source to consecutive memory locations
|
||||||
|
// convert from image horizontal scan to block vertical scan
|
||||||
|
unsigned int uiPixel = 0;
|
||||||
|
for (unsigned int uiBlockPixelH = 0; uiBlockPixelH < Block4x4::COLUMNS; uiBlockPixelH++)
|
||||||
|
{
|
||||||
|
unsigned int uiSourcePixelH = m_uiSourceH + uiBlockPixelH;
|
||||||
|
|
||||||
|
for (unsigned int uiBlockPixelV = 0; uiBlockPixelV < Block4x4::ROWS; uiBlockPixelV++)
|
||||||
|
{
|
||||||
|
unsigned int uiSourcePixelV = m_uiSourceV + uiBlockPixelV;
|
||||||
|
|
||||||
|
ColorFloatRGBA *pfrgbaSource = m_pimageSource->GetSourcePixel(uiSourcePixelH, uiSourcePixelV);
|
||||||
|
|
||||||
|
// if pixel extends beyond source image because of block padding
|
||||||
|
if (pfrgbaSource == nullptr)
|
||||||
|
{
|
||||||
|
m_afrgbaSource[uiPixel] = ColorFloatRGBA(0.0f, 0.0f, 0.0f, NAN); // denotes border pixel
|
||||||
|
m_boolBorderPixels = true;
|
||||||
|
uiTransparentSourcePixels++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//get teh current pixel data, and store some of the attributes
|
||||||
|
//before capping values to fit the encoder type
|
||||||
|
|
||||||
|
m_afrgbaSource[uiPixel] = (*pfrgbaSource).ClampRGBA();
|
||||||
|
|
||||||
|
if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_iNumOpaquePixels++;
|
||||||
|
}
|
||||||
|
else if (m_afrgbaSource[uiPixel].fA == 0.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_iNumTransparentPixels++;
|
||||||
|
}
|
||||||
|
else if(m_afrgbaSource[uiPixel].fA > 0.0f && m_afrgbaSource[uiPixel].fA < 1.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_iNumTranslucentPixels++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pimageSource->m_numOutOfRangeValues.fA++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_afrgbaSource[uiPixel].fR != 0.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_numColorValues.fR++;
|
||||||
|
//make sure we are getting a float between 0-1
|
||||||
|
if (m_afrgbaSource[uiPixel].fR - 1.0f > 0.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_numOutOfRangeValues.fR++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_afrgbaSource[uiPixel].fG != 0.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_numColorValues.fG++;
|
||||||
|
if (m_afrgbaSource[uiPixel].fG - 1.0f > 0.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_numOutOfRangeValues.fG++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_afrgbaSource[uiPixel].fB != 0.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_numColorValues.fB++;
|
||||||
|
if (m_afrgbaSource[uiPixel].fB - 1.0f > 0.0f)
|
||||||
|
{
|
||||||
|
m_pimageSource->m_numOutOfRangeValues.fB++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for formats with no alpha, set source alpha to 1
|
||||||
|
if (imageformat == Image::Format::ETC1 ||
|
||||||
|
imageformat == Image::Format::RGB8 ||
|
||||||
|
imageformat == Image::Format::SRGB8)
|
||||||
|
{
|
||||||
|
m_afrgbaSource[uiPixel].fA = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageformat == Image::Format::R11 ||
|
||||||
|
imageformat == Image::Format::SIGNED_R11)
|
||||||
|
{
|
||||||
|
m_afrgbaSource[uiPixel].fA = 1.0f;
|
||||||
|
m_afrgbaSource[uiPixel].fG = 0.0f;
|
||||||
|
m_afrgbaSource[uiPixel].fB = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageformat == Image::Format::RG11 ||
|
||||||
|
imageformat == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_afrgbaSource[uiPixel].fA = 1.0f;
|
||||||
|
m_afrgbaSource[uiPixel].fB = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// for RGB8A1, set source alpha to 0.0 or 1.0
|
||||||
|
// set punch through flag
|
||||||
|
if (imageformat == Image::Format::RGB8A1 ||
|
||||||
|
imageformat == Image::Format::SRGB8A1)
|
||||||
|
{
|
||||||
|
if (m_afrgbaSource[uiPixel].fA >= 0.5f)
|
||||||
|
{
|
||||||
|
m_afrgbaSource[uiPixel].fA = 1.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_afrgbaSource[uiPixel].fA = 0.0f;
|
||||||
|
m_boolPunchThroughPixels = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
|
||||||
|
{
|
||||||
|
uiOpaqueSourcePixels++;
|
||||||
|
}
|
||||||
|
else if (m_afrgbaSource[uiPixel].fA == 0.0f)
|
||||||
|
{
|
||||||
|
uiTransparentSourcePixels++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uiPixel += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiOpaqueSourcePixels == PIXELS)
|
||||||
|
{
|
||||||
|
m_sourcealphamix = SourceAlphaMix::OPAQUE;
|
||||||
|
}
|
||||||
|
else if (uiTransparentSourcePixels == PIXELS)
|
||||||
|
{
|
||||||
|
m_sourcealphamix = SourceAlphaMix::TRANSPARENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_sourcealphamix = SourceAlphaMix::TRANSLUCENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// return a name for the encoding mode
|
||||||
|
//
|
||||||
|
const char * Block4x4::GetEncodingModeName(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (m_pencoding->GetMode())
|
||||||
|
{
|
||||||
|
case Block4x4Encoding::MODE_ETC1:
|
||||||
|
return "ETC1";
|
||||||
|
case Block4x4Encoding::MODE_T:
|
||||||
|
return "T";
|
||||||
|
case Block4x4Encoding::MODE_H:
|
||||||
|
return "H";
|
||||||
|
case Block4x4Encoding::MODE_PLANAR:
|
||||||
|
return "PLANAR";
|
||||||
|
default:
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
172
thirdparty/etc2comp/EtcBlock4x4.h
vendored
Normal file
172
thirdparty/etc2comp/EtcBlock4x4.h
vendored
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcColor.h"
|
||||||
|
#include "EtcColorFloatRGBA.h"
|
||||||
|
#include "EtcErrorMetric.h"
|
||||||
|
#include "EtcImage.h"
|
||||||
|
#include "EtcBlock4x4Encoding.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4EncodingBits;
|
||||||
|
|
||||||
|
class Block4x4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int ROWS = 4;
|
||||||
|
static const unsigned int COLUMNS = 4;
|
||||||
|
static const unsigned int PIXELS = ROWS * COLUMNS;
|
||||||
|
|
||||||
|
// the alpha mix for a 4x4 block of pixels
|
||||||
|
enum class SourceAlphaMix
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
//
|
||||||
|
OPAQUE, // all 1.0
|
||||||
|
TRANSPARENT, // all 0.0 or NAN
|
||||||
|
TRANSLUCENT // not all opaque or transparent
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (Block4x4::*EncoderFunctionPtr)(void);
|
||||||
|
|
||||||
|
Block4x4(void);
|
||||||
|
~Block4x4();
|
||||||
|
void InitFromSource(Image *a_pimageSource,
|
||||||
|
unsigned int a_uiSourceH,
|
||||||
|
unsigned int a_uiSourceV,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
void InitFromEtcEncodingBits(Image::Format a_imageformat,
|
||||||
|
unsigned int a_uiSourceH,
|
||||||
|
unsigned int a_uiSourceV,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
Image *a_pimageSource,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
// return true if final iteration was performed
|
||||||
|
inline void PerformEncodingIteration(float a_fEffort)
|
||||||
|
{
|
||||||
|
m_pencoding->PerformIteration(a_fEffort);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetEncodingBitsFromEncoding(void)
|
||||||
|
{
|
||||||
|
m_pencoding->SetEncodingBits();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetSourceH(void)
|
||||||
|
{
|
||||||
|
return m_uiSourceH;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetSourceV(void)
|
||||||
|
{
|
||||||
|
return m_uiSourceV;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float GetError(void)
|
||||||
|
{
|
||||||
|
return m_pencoding->GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned int s_auiPixelOrderHScan[PIXELS];
|
||||||
|
|
||||||
|
inline ColorFloatRGBA * GetDecodedColors(void)
|
||||||
|
{
|
||||||
|
return m_pencoding->GetDecodedColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float * GetDecodedAlphas(void)
|
||||||
|
{
|
||||||
|
return m_pencoding->GetDecodedAlphas();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Block4x4Encoding::Mode GetEncodingMode(void)
|
||||||
|
{
|
||||||
|
return m_pencoding->GetMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool GetFlip(void)
|
||||||
|
{
|
||||||
|
return m_pencoding->GetFlip();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsDifferential(void)
|
||||||
|
{
|
||||||
|
return m_pencoding->IsDifferential();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA * GetSource()
|
||||||
|
{
|
||||||
|
return m_afrgbaSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ErrorMetric GetErrorMetric()
|
||||||
|
{
|
||||||
|
return m_errormetric;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * GetEncodingModeName(void);
|
||||||
|
|
||||||
|
inline Block4x4Encoding * GetEncoding(void)
|
||||||
|
{
|
||||||
|
return m_pencoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SourceAlphaMix GetSourceAlphaMix(void)
|
||||||
|
{
|
||||||
|
return m_sourcealphamix;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Image * GetImageSource(void)
|
||||||
|
{
|
||||||
|
return m_pimageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool HasBorderPixels(void)
|
||||||
|
{
|
||||||
|
return m_boolBorderPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool HasPunchThroughPixels(void)
|
||||||
|
{
|
||||||
|
return m_boolPunchThroughPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void SetSourcePixels(void);
|
||||||
|
|
||||||
|
Image *m_pimageSource;
|
||||||
|
unsigned int m_uiSourceH;
|
||||||
|
unsigned int m_uiSourceV;
|
||||||
|
ErrorMetric m_errormetric;
|
||||||
|
ColorFloatRGBA m_afrgbaSource[PIXELS]; // vertical scan
|
||||||
|
|
||||||
|
SourceAlphaMix m_sourcealphamix;
|
||||||
|
bool m_boolBorderPixels; // marked as rgba(NAN, NAN, NAN, NAN)
|
||||||
|
bool m_boolPunchThroughPixels; // RGB8A1 or SRGB8A1 with any pixels with alpha < 0.5
|
||||||
|
|
||||||
|
Block4x4Encoding *m_pencoding;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
261
thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
vendored
Normal file
261
thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
vendored
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcBlock4x4Encoding.cpp
|
||||||
|
|
||||||
|
Block4x4Encoding is the abstract base class for the different encoders. Each encoder targets a
|
||||||
|
particular file format (e.g. ETC1, RGB8, RGBA8, R11)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcBlock4x4Encoding.h"
|
||||||
|
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcBlock4x4.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
const float Block4x4Encoding::LUMA_WEIGHT = 3.0f;
|
||||||
|
const float Block4x4Encoding::CHROMA_BLUE_WEIGHT = 0.5f;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
Block4x4Encoding::Block4x4Encoding(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_pblockParent = nullptr;
|
||||||
|
|
||||||
|
m_pafrgbaSource = nullptr;
|
||||||
|
|
||||||
|
m_boolBorderPixels = false;
|
||||||
|
|
||||||
|
m_fError = -1.0f;
|
||||||
|
|
||||||
|
m_mode = MODE_UNKNOWN;
|
||||||
|
|
||||||
|
m_uiEncodingIterations = 0;
|
||||||
|
m_boolDone = false;
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
|
||||||
|
m_afDecodedAlphas[uiPixel] = -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialize the generic encoding for a 4x4 block
|
||||||
|
// a_pblockParent points to the block associated with this encoding
|
||||||
|
// a_errormetric is used to choose the best encoding
|
||||||
|
// init the decoded pixels to -1 to mark them as undefined
|
||||||
|
// init the error to -1 to mark it as undefined
|
||||||
|
//
|
||||||
|
void Block4x4Encoding::Init(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_pblockParent = a_pblockParent;
|
||||||
|
|
||||||
|
m_pafrgbaSource = a_pafrgbaSource;
|
||||||
|
|
||||||
|
m_boolBorderPixels = m_pblockParent->HasBorderPixels();
|
||||||
|
|
||||||
|
m_fError = -1.0f;
|
||||||
|
|
||||||
|
m_uiEncodingIterations = 0;
|
||||||
|
|
||||||
|
m_errormetric = a_errormetric;
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
|
||||||
|
m_afDecodedAlphas[uiPixel] = -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// calculate the error for the block by summing the pixel errors
|
||||||
|
//
|
||||||
|
void Block4x4Encoding::CalcBlockError(void)
|
||||||
|
{
|
||||||
|
m_fError = 0.0f;
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_fError += CalcPixelError(m_afrgbaDecodedColors[uiPixel], m_afDecodedAlphas[uiPixel],
|
||||||
|
m_pafrgbaSource[uiPixel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// calculate the error between the source pixel and the decoded pixel
|
||||||
|
// the error amount is base on the error metric
|
||||||
|
//
|
||||||
|
float Block4x4Encoding::CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
|
||||||
|
ColorFloatRGBA a_frgbaSourcePixel)
|
||||||
|
{
|
||||||
|
|
||||||
|
// if a border pixel
|
||||||
|
if (isnan(a_frgbaSourcePixel.fA))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_errormetric == ErrorMetric::RGBA)
|
||||||
|
{
|
||||||
|
assert(a_fDecodedAlpha >= 0.0f);
|
||||||
|
|
||||||
|
float fDRed = (a_fDecodedAlpha * a_frgbaDecodedColor.fR) -
|
||||||
|
(a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fR);
|
||||||
|
float fDGreen = (a_fDecodedAlpha * a_frgbaDecodedColor.fG) -
|
||||||
|
(a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fG);
|
||||||
|
float fDBlue = (a_fDecodedAlpha * a_frgbaDecodedColor.fB) -
|
||||||
|
(a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fB);
|
||||||
|
|
||||||
|
float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
|
||||||
|
|
||||||
|
return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
|
||||||
|
}
|
||||||
|
else if (m_errormetric == ErrorMetric::RGBX)
|
||||||
|
{
|
||||||
|
assert(a_fDecodedAlpha >= 0.0f);
|
||||||
|
|
||||||
|
float fDRed = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
|
||||||
|
float fDGreen = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
|
||||||
|
float fDBlue = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
|
||||||
|
float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
|
||||||
|
|
||||||
|
return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
|
||||||
|
}
|
||||||
|
else if (m_errormetric == ErrorMetric::REC709)
|
||||||
|
{
|
||||||
|
assert(a_fDecodedAlpha >= 0.0f);
|
||||||
|
|
||||||
|
float fLuma1 = a_frgbaSourcePixel.fR*0.2126f + a_frgbaSourcePixel.fG*0.7152f + a_frgbaSourcePixel.fB*0.0722f;
|
||||||
|
float fChromaR1 = 0.5f * ((a_frgbaSourcePixel.fR - fLuma1) * (1.0f / (1.0f - 0.2126f)));
|
||||||
|
float fChromaB1 = 0.5f * ((a_frgbaSourcePixel.fB - fLuma1) * (1.0f / (1.0f - 0.0722f)));
|
||||||
|
|
||||||
|
float fLuma2 = a_frgbaDecodedColor.fR*0.2126f +
|
||||||
|
a_frgbaDecodedColor.fG*0.7152f +
|
||||||
|
a_frgbaDecodedColor.fB*0.0722f;
|
||||||
|
float fChromaR2 = 0.5f * ((a_frgbaDecodedColor.fR - fLuma2) * (1.0f / (1.0f - 0.2126f)));
|
||||||
|
float fChromaB2 = 0.5f * ((a_frgbaDecodedColor.fB - fLuma2) * (1.0f / (1.0f - 0.0722f)));
|
||||||
|
|
||||||
|
float fDeltaL = a_frgbaSourcePixel.fA * fLuma1 - a_fDecodedAlpha * fLuma2;
|
||||||
|
float fDeltaCr = a_frgbaSourcePixel.fA * fChromaR1 - a_fDecodedAlpha * fChromaR2;
|
||||||
|
float fDeltaCb = a_frgbaSourcePixel.fA * fChromaB1 - a_fDecodedAlpha * fChromaB2;
|
||||||
|
|
||||||
|
float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
|
||||||
|
|
||||||
|
// Favor Luma accuracy over Chroma, and Red over Blue
|
||||||
|
return LUMA_WEIGHT*fDeltaL*fDeltaL +
|
||||||
|
fDeltaCr*fDeltaCr +
|
||||||
|
CHROMA_BLUE_WEIGHT*fDeltaCb*fDeltaCb +
|
||||||
|
fDAlpha*fDAlpha;
|
||||||
|
#if 0
|
||||||
|
float fDRed = a_frgbaDecodedPixel.fR - a_frgbaSourcePixel.fR;
|
||||||
|
float fDGreen = a_frgbaDecodedPixel.fG - a_frgbaSourcePixel.fG;
|
||||||
|
float fDBlue = a_frgbaDecodedPixel.fB - a_frgbaSourcePixel.fB;
|
||||||
|
return 2.0f * 3.0f * fDeltaL * fDeltaL + fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (m_errormetric == ErrorMetric::NORMALXYZ)
|
||||||
|
{
|
||||||
|
float fDecodedX = 2.0f * a_frgbaDecodedColor.fR - 1.0f;
|
||||||
|
float fDecodedY = 2.0f * a_frgbaDecodedColor.fG - 1.0f;
|
||||||
|
float fDecodedZ = 2.0f * a_frgbaDecodedColor.fB - 1.0f;
|
||||||
|
|
||||||
|
float fDecodedLength = sqrtf(fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ);
|
||||||
|
|
||||||
|
if (fDecodedLength < 0.5f)
|
||||||
|
{
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
else if (fDecodedLength == 0.0f)
|
||||||
|
{
|
||||||
|
fDecodedX = 1.0f;
|
||||||
|
fDecodedY = 0.0f;
|
||||||
|
fDecodedZ = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fDecodedX /= fDecodedLength;
|
||||||
|
fDecodedY /= fDecodedLength;
|
||||||
|
fDecodedZ /= fDecodedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fSourceX = 2.0f * a_frgbaSourcePixel.fR - 1.0f;
|
||||||
|
float fSourceY = 2.0f * a_frgbaSourcePixel.fG - 1.0f;
|
||||||
|
float fSourceZ = 2.0f * a_frgbaSourcePixel.fB - 1.0f;
|
||||||
|
|
||||||
|
float fSourceLength = sqrtf(fSourceX*fSourceX + fSourceY*fSourceY + fSourceZ*fSourceZ);
|
||||||
|
|
||||||
|
if (fSourceLength == 0.0f)
|
||||||
|
{
|
||||||
|
fSourceX = 1.0f;
|
||||||
|
fSourceY = 0.0f;
|
||||||
|
fSourceZ = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fSourceX /= fSourceLength;
|
||||||
|
fSourceY /= fSourceLength;
|
||||||
|
fSourceZ /= fSourceLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fDotProduct = fSourceX*fDecodedX + fSourceY*fDecodedY + fSourceZ*fDecodedZ;
|
||||||
|
float fNormalizedDotProduct = 1.0f - 0.5f * (fDotProduct + 1.0f);
|
||||||
|
float fDotProductError = fNormalizedDotProduct * fNormalizedDotProduct;
|
||||||
|
|
||||||
|
float fLength2 = fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ;
|
||||||
|
float fLength2Error = fabsf(1.0f - fLength2);
|
||||||
|
|
||||||
|
float fDeltaW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
|
||||||
|
float fErrorW = fDeltaW * fDeltaW;
|
||||||
|
|
||||||
|
return fDotProductError + fLength2Error + fErrorW;
|
||||||
|
}
|
||||||
|
else // ErrorMetric::NUMERIC
|
||||||
|
{
|
||||||
|
assert(a_fDecodedAlpha >= 0.0f);
|
||||||
|
|
||||||
|
float fDX = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
|
||||||
|
float fDY = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
|
||||||
|
float fDZ = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
|
||||||
|
float fDW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
|
||||||
|
|
||||||
|
return fDX*fDX + fDY*fDY + fDZ*fDZ + fDW*fDW;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
||||||
|
|
148
thirdparty/etc2comp/EtcBlock4x4Encoding.h
vendored
Normal file
148
thirdparty/etc2comp/EtcBlock4x4Encoding.h
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcColorFloatRGBA.h"
|
||||||
|
|
||||||
|
#include "EtcErrorMetric.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4;
|
||||||
|
|
||||||
|
// abstract base class for specific encodings
|
||||||
|
class Block4x4Encoding
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int ROWS = 4;
|
||||||
|
static const unsigned int COLUMNS = 4;
|
||||||
|
static const unsigned int PIXELS = ROWS * COLUMNS;
|
||||||
|
static const float LUMA_WEIGHT;
|
||||||
|
static const float CHROMA_BLUE_WEIGHT;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MODE_UNKNOWN,
|
||||||
|
//
|
||||||
|
MODE_ETC1,
|
||||||
|
MODE_T,
|
||||||
|
MODE_H,
|
||||||
|
MODE_PLANAR,
|
||||||
|
MODE_R11,
|
||||||
|
MODE_RG11,
|
||||||
|
//
|
||||||
|
MODES
|
||||||
|
} Mode;
|
||||||
|
|
||||||
|
Block4x4Encoding(void);
|
||||||
|
//virtual ~Block4x4Encoding(void) =0;
|
||||||
|
virtual ~Block4x4Encoding(void) {}
|
||||||
|
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) = 0;
|
||||||
|
|
||||||
|
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
ErrorMetric a_errormetric) = 0;
|
||||||
|
|
||||||
|
// perform an iteration of the encoding
|
||||||
|
// the first iteration must generate a complete, valid (if poor) encoding
|
||||||
|
virtual void PerformIteration(float a_fEffort) = 0;
|
||||||
|
|
||||||
|
void CalcBlockError(void);
|
||||||
|
|
||||||
|
inline float GetError(void)
|
||||||
|
{
|
||||||
|
assert(m_fError >= 0.0f);
|
||||||
|
|
||||||
|
return m_fError;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA * GetDecodedColors(void)
|
||||||
|
{
|
||||||
|
return m_afrgbaDecodedColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float * GetDecodedAlphas(void)
|
||||||
|
{
|
||||||
|
return m_afDecodedAlphas;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void) = 0;
|
||||||
|
|
||||||
|
virtual bool GetFlip(void) = 0;
|
||||||
|
|
||||||
|
virtual bool IsDifferential(void) = 0;
|
||||||
|
|
||||||
|
virtual bool HasSeverelyBentDifferentialColors(void) const = 0;
|
||||||
|
|
||||||
|
inline Mode GetMode(void)
|
||||||
|
{
|
||||||
|
return m_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsDone(void)
|
||||||
|
{
|
||||||
|
return m_boolDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetDoneIfPerfect()
|
||||||
|
{
|
||||||
|
if (GetError() == 0.0f)
|
||||||
|
{
|
||||||
|
m_boolDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
|
||||||
|
ColorFloatRGBA a_frgbaSourcePixel);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void Init(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
Block4x4 *m_pblockParent;
|
||||||
|
ColorFloatRGBA *m_pafrgbaSource;
|
||||||
|
|
||||||
|
bool m_boolBorderPixels; // if block has any border pixels
|
||||||
|
|
||||||
|
ColorFloatRGBA m_afrgbaDecodedColors[PIXELS]; // decoded RGB components, ignore Alpha
|
||||||
|
float m_afDecodedAlphas[PIXELS]; // decoded alpha component
|
||||||
|
float m_fError; // error for RGBA relative to m_pafrgbaSource
|
||||||
|
|
||||||
|
// intermediate encoding
|
||||||
|
Mode m_mode;
|
||||||
|
|
||||||
|
unsigned int m_uiEncodingIterations;
|
||||||
|
bool m_boolDone; // all iterations have been done
|
||||||
|
ErrorMetric m_errormetric;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
315
thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
vendored
Normal file
315
thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
vendored
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4EncodingBits
|
||||||
|
// Base class for Block4x4EncodingBits_XXXX
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4EncodingBits
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum class Format
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
//
|
||||||
|
RGB8,
|
||||||
|
RGBA8,
|
||||||
|
R11,
|
||||||
|
RG11,
|
||||||
|
RGB8A1,
|
||||||
|
//
|
||||||
|
FORMATS
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int GetBytesPerBlock(Format a_format)
|
||||||
|
{
|
||||||
|
switch (a_format)
|
||||||
|
{
|
||||||
|
case Format::RGB8:
|
||||||
|
case Format::R11:
|
||||||
|
case Format::RGB8A1:
|
||||||
|
return 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Format::RGBA8:
|
||||||
|
case Format::RG11:
|
||||||
|
return 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4EncodingBits_RGB8
|
||||||
|
// Encoding bits for the RGB portion of ETC1, RGB8, RGB8A1 and RGBA8
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4EncodingBits_RGB8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int BYTES_PER_BLOCK = 8;
|
||||||
|
|
||||||
|
inline Block4x4EncodingBits_RGB8(void)
|
||||||
|
{
|
||||||
|
assert(sizeof(Block4x4EncodingBits_RGB8) == BYTES_PER_BLOCK);
|
||||||
|
|
||||||
|
for (unsigned int uiByte = 0; uiByte < BYTES_PER_BLOCK; uiByte++)
|
||||||
|
{
|
||||||
|
auc[uiByte] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned red2 : 4;
|
||||||
|
unsigned red1 : 4;
|
||||||
|
//
|
||||||
|
unsigned green2 : 4;
|
||||||
|
unsigned green1 : 4;
|
||||||
|
//
|
||||||
|
unsigned blue2 : 4;
|
||||||
|
unsigned blue1 : 4;
|
||||||
|
//
|
||||||
|
unsigned flip : 1;
|
||||||
|
unsigned diff : 1;
|
||||||
|
unsigned cw2 : 3;
|
||||||
|
unsigned cw1 : 3;
|
||||||
|
//
|
||||||
|
unsigned int selectors;
|
||||||
|
} Individual;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
signed dred2 : 3;
|
||||||
|
unsigned red1 : 5;
|
||||||
|
//
|
||||||
|
signed dgreen2 : 3;
|
||||||
|
unsigned green1 : 5;
|
||||||
|
//
|
||||||
|
signed dblue2 : 3;
|
||||||
|
unsigned blue1 : 5;
|
||||||
|
//
|
||||||
|
unsigned flip : 1;
|
||||||
|
unsigned diff : 1;
|
||||||
|
unsigned cw2 : 3;
|
||||||
|
unsigned cw1 : 3;
|
||||||
|
//
|
||||||
|
unsigned int selectors;
|
||||||
|
} Differential;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned red1b : 2;
|
||||||
|
unsigned detect2 : 1;
|
||||||
|
unsigned red1a : 2;
|
||||||
|
unsigned detect1 : 3;
|
||||||
|
//
|
||||||
|
unsigned blue1 : 4;
|
||||||
|
unsigned green1 : 4;
|
||||||
|
//
|
||||||
|
unsigned green2 : 4;
|
||||||
|
unsigned red2 : 4;
|
||||||
|
//
|
||||||
|
unsigned db : 1;
|
||||||
|
unsigned diff : 1;
|
||||||
|
unsigned da : 2;
|
||||||
|
unsigned blue2 : 4;
|
||||||
|
//
|
||||||
|
unsigned int selectors;
|
||||||
|
} T;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned green1a : 3;
|
||||||
|
unsigned red1 : 4;
|
||||||
|
unsigned detect1 : 1;
|
||||||
|
//
|
||||||
|
unsigned blue1b : 2;
|
||||||
|
unsigned detect3 : 1;
|
||||||
|
unsigned blue1a : 1;
|
||||||
|
unsigned green1b : 1;
|
||||||
|
unsigned detect2 : 3;
|
||||||
|
//
|
||||||
|
unsigned green2a : 3;
|
||||||
|
unsigned red2 : 4;
|
||||||
|
unsigned blue1c : 1;
|
||||||
|
//
|
||||||
|
unsigned db : 1;
|
||||||
|
unsigned diff : 1;
|
||||||
|
unsigned da : 1;
|
||||||
|
unsigned blue2 : 4;
|
||||||
|
unsigned green2b : 1;
|
||||||
|
//
|
||||||
|
unsigned int selectors;
|
||||||
|
} H;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned originGreen1 : 1;
|
||||||
|
unsigned originRed : 6;
|
||||||
|
unsigned detect1 : 1;
|
||||||
|
//
|
||||||
|
unsigned originBlue1 : 1;
|
||||||
|
unsigned originGreen2 : 6;
|
||||||
|
unsigned detect2 : 1;
|
||||||
|
//
|
||||||
|
unsigned originBlue3 : 2;
|
||||||
|
unsigned detect4 : 1;
|
||||||
|
unsigned originBlue2 : 2;
|
||||||
|
unsigned detect3 : 3;
|
||||||
|
//
|
||||||
|
unsigned horizRed2 : 1;
|
||||||
|
unsigned diff : 1;
|
||||||
|
unsigned horizRed1 : 5;
|
||||||
|
unsigned originBlue4 : 1;
|
||||||
|
//
|
||||||
|
unsigned horizBlue1: 1;
|
||||||
|
unsigned horizGreen : 7;
|
||||||
|
//
|
||||||
|
unsigned vertRed1 : 3;
|
||||||
|
unsigned horizBlue2 : 5;
|
||||||
|
//
|
||||||
|
unsigned vertGreen1 : 5;
|
||||||
|
unsigned vertRed2 : 3;
|
||||||
|
//
|
||||||
|
unsigned vertBlue : 6;
|
||||||
|
unsigned vertGreen2 : 2;
|
||||||
|
} Planar;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
unsigned char auc[BYTES_PER_BLOCK];
|
||||||
|
unsigned long int ul;
|
||||||
|
Individual individual;
|
||||||
|
Differential differential;
|
||||||
|
T t;
|
||||||
|
H h;
|
||||||
|
Planar planar;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4EncodingBits_A8
|
||||||
|
// Encoding bits for the A portion of RGBA8
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4EncodingBits_A8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int BYTES_PER_BLOCK = 8;
|
||||||
|
static const unsigned int SELECTOR_BYTES = 6;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned base : 8;
|
||||||
|
unsigned table : 4;
|
||||||
|
unsigned multiplier : 4;
|
||||||
|
unsigned selectors0 : 8;
|
||||||
|
unsigned selectors1 : 8;
|
||||||
|
unsigned selectors2 : 8;
|
||||||
|
unsigned selectors3 : 8;
|
||||||
|
unsigned selectors4 : 8;
|
||||||
|
unsigned selectors5 : 8;
|
||||||
|
} Data;
|
||||||
|
|
||||||
|
Data data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4EncodingBits_R11
|
||||||
|
// Encoding bits for the R portion of R11
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4EncodingBits_R11
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int BYTES_PER_BLOCK = 8;
|
||||||
|
static const unsigned int SELECTOR_BYTES = 6;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned base : 8;
|
||||||
|
unsigned table : 4;
|
||||||
|
unsigned multiplier : 4;
|
||||||
|
unsigned selectors0 : 8;
|
||||||
|
unsigned selectors1 : 8;
|
||||||
|
unsigned selectors2 : 8;
|
||||||
|
unsigned selectors3 : 8;
|
||||||
|
unsigned selectors4 : 8;
|
||||||
|
unsigned selectors5 : 8;
|
||||||
|
} Data;
|
||||||
|
|
||||||
|
Data data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Block4x4EncodingBits_RG11
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int BYTES_PER_BLOCK = 16;
|
||||||
|
static const unsigned int SELECTOR_BYTES = 12;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
//Red portion
|
||||||
|
unsigned baseR : 8;
|
||||||
|
unsigned tableIndexR : 4;
|
||||||
|
unsigned multiplierR : 4;
|
||||||
|
unsigned selectorsR0 : 8;
|
||||||
|
unsigned selectorsR1 : 8;
|
||||||
|
unsigned selectorsR2 : 8;
|
||||||
|
unsigned selectorsR3 : 8;
|
||||||
|
unsigned selectorsR4 : 8;
|
||||||
|
unsigned selectorsR5 : 8;
|
||||||
|
//Green portion
|
||||||
|
unsigned baseG : 8;
|
||||||
|
unsigned tableIndexG : 4;
|
||||||
|
unsigned multiplierG : 4;
|
||||||
|
unsigned selectorsG0 : 8;
|
||||||
|
unsigned selectorsG1 : 8;
|
||||||
|
unsigned selectorsG2 : 8;
|
||||||
|
unsigned selectorsG3 : 8;
|
||||||
|
unsigned selectorsG4 : 8;
|
||||||
|
unsigned selectorsG5 : 8;
|
||||||
|
} Data;
|
||||||
|
|
||||||
|
Data data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
1281
thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
vendored
Normal file
1281
thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
186
thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
vendored
Normal file
186
thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
vendored
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcBlock4x4Encoding.h"
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcDifferentialTrys.h"
|
||||||
|
#include "EtcIndividualTrys.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// base class for Block4x4Encoding_RGB8
|
||||||
|
class Block4x4Encoding_ETC1 : public Block4x4Encoding
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Block4x4Encoding_ETC1(void);
|
||||||
|
virtual ~Block4x4Encoding_ETC1(void);
|
||||||
|
|
||||||
|
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
inline virtual bool GetFlip(void)
|
||||||
|
{
|
||||||
|
return m_boolFlip;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline virtual bool IsDifferential(void)
|
||||||
|
{
|
||||||
|
return m_boolDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
void Decode(void);
|
||||||
|
|
||||||
|
inline ColorFloatRGBA GetColor1(void) const
|
||||||
|
{
|
||||||
|
return m_frgbaColor1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA GetColor2(void) const
|
||||||
|
{
|
||||||
|
return m_frgbaColor2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const unsigned int * GetSelectors(void) const
|
||||||
|
{
|
||||||
|
return m_auiSelectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetCW1(void) const
|
||||||
|
{
|
||||||
|
return m_uiCW1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetCW2(void) const
|
||||||
|
{
|
||||||
|
return m_uiCW2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool HasSeverelyBentDifferentialColors(void) const
|
||||||
|
{
|
||||||
|
return m_boolSeverelyBentDifferentialColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
static const unsigned int s_auiPixelOrderFlip0[PIXELS];
|
||||||
|
static const unsigned int s_auiPixelOrderFlip1[PIXELS];
|
||||||
|
static const unsigned int s_auiPixelOrderHScan[PIXELS];
|
||||||
|
|
||||||
|
static const unsigned int s_auiLeftPixelMapping[8];
|
||||||
|
static const unsigned int s_auiRightPixelMapping[8];
|
||||||
|
static const unsigned int s_auiTopPixelMapping[8];
|
||||||
|
static const unsigned int s_auiBottomPixelMapping[8];
|
||||||
|
|
||||||
|
static const unsigned int SELECTOR_BITS = 2;
|
||||||
|
static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
|
||||||
|
|
||||||
|
static const unsigned int CW_BITS = 3;
|
||||||
|
static const unsigned int CW_RANGES = 1 << CW_BITS;
|
||||||
|
|
||||||
|
static float s_aafCwTable[CW_RANGES][SELECTORS];
|
||||||
|
static unsigned char s_aucDifferentialCwRange[256];
|
||||||
|
|
||||||
|
static const int MAX_DIFFERENTIAL = 3;
|
||||||
|
static const int MIN_DIFFERENTIAL = -4;
|
||||||
|
|
||||||
|
void InitFromEncodingBits_Selectors(void);
|
||||||
|
|
||||||
|
void PerformFirstIteration(void);
|
||||||
|
void CalculateMostLikelyFlip(void);
|
||||||
|
|
||||||
|
void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
|
||||||
|
int a_iGrayOffset1, int a_iGrayOffset2);
|
||||||
|
void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
|
||||||
|
|
||||||
|
void TryIndividual(bool a_boolFlip, unsigned int a_uiRadius);
|
||||||
|
void TryIndividualHalf(IndividualTrys::Half *a_phalf);
|
||||||
|
|
||||||
|
void TryDegenerates1(void);
|
||||||
|
void TryDegenerates2(void);
|
||||||
|
void TryDegenerates3(void);
|
||||||
|
void TryDegenerates4(void);
|
||||||
|
|
||||||
|
void CalculateSelectors();
|
||||||
|
void CalculateHalfOfTheSelectors(unsigned int a_uiHalf,
|
||||||
|
const unsigned int *pauiPixelMapping);
|
||||||
|
|
||||||
|
// calculate the distance2 of r_frgbaPixel from r_frgbaTarget's gray line
|
||||||
|
inline float CalcGrayDistance2(ColorFloatRGBA &r_frgbaPixel,
|
||||||
|
ColorFloatRGBA &r_frgbaTarget)
|
||||||
|
{
|
||||||
|
float fDeltaGray = ((r_frgbaPixel.fR - r_frgbaTarget.fR) +
|
||||||
|
(r_frgbaPixel.fG - r_frgbaTarget.fG) +
|
||||||
|
(r_frgbaPixel.fB - r_frgbaTarget.fB)) / 3.0f;
|
||||||
|
|
||||||
|
ColorFloatRGBA frgbaPointOnGrayLine = (r_frgbaTarget + fDeltaGray).ClampRGB();
|
||||||
|
|
||||||
|
float fDR = r_frgbaPixel.fR - frgbaPointOnGrayLine.fR;
|
||||||
|
float fDG = r_frgbaPixel.fG - frgbaPointOnGrayLine.fG;
|
||||||
|
float fDB = r_frgbaPixel.fB - frgbaPointOnGrayLine.fB;
|
||||||
|
|
||||||
|
return (fDR*fDR) + (fDG*fDG) + (fDB*fDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetEncodingBits_Selectors(void);
|
||||||
|
|
||||||
|
// intermediate encoding
|
||||||
|
bool m_boolDiff;
|
||||||
|
bool m_boolFlip;
|
||||||
|
ColorFloatRGBA m_frgbaColor1;
|
||||||
|
ColorFloatRGBA m_frgbaColor2;
|
||||||
|
unsigned int m_uiCW1;
|
||||||
|
unsigned int m_uiCW2;
|
||||||
|
unsigned int m_auiSelectors[PIXELS];
|
||||||
|
|
||||||
|
// state shared between iterations
|
||||||
|
ColorFloatRGBA m_frgbaSourceAverageLeft;
|
||||||
|
ColorFloatRGBA m_frgbaSourceAverageRight;
|
||||||
|
ColorFloatRGBA m_frgbaSourceAverageTop;
|
||||||
|
ColorFloatRGBA m_frgbaSourceAverageBottom;
|
||||||
|
bool m_boolMostLikelyFlip;
|
||||||
|
|
||||||
|
// stats
|
||||||
|
float m_fError1; // error for Etc1 half 1
|
||||||
|
float m_fError2; // error for Etc1 half 2
|
||||||
|
bool m_boolSeverelyBentDifferentialColors; // only valid if m_boolDiff;
|
||||||
|
|
||||||
|
// final encoding
|
||||||
|
Block4x4EncodingBits_RGB8 *m_pencodingbitsRGB8; // or RGB8 portion of Block4x4EncodingBits_RGB8A8
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void CalculateSourceAverages(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
429
thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
vendored
Normal file
429
thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
vendored
Normal file
|
@ -0,0 +1,429 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcBlock4x4Encoding_R11.cpp
|
||||||
|
|
||||||
|
Block4x4Encoding_R11 is the encoder to use when targetting file format R11 and SR11 (signed R11).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcBlock4x4Encoding_R11.h"
|
||||||
|
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcBlock4x4.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// modifier values to use for R11, SR11, RG11 and SRG11
|
||||||
|
float Block4x4Encoding_R11::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS]
|
||||||
|
{
|
||||||
|
{ -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
|
||||||
|
|
||||||
|
{ -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
|
||||||
|
{ -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||||
|
|
||||||
|
{ -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
|
||||||
|
{ -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
Block4x4Encoding_R11::Block4x4Encoding_R11(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_pencodingbitsR11 = nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Block4x4Encoding_R11::~Block4x4Encoding_R11(void) {}
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization prior to encoding
|
||||||
|
// a_pblockParent points to the block associated with this encoding
|
||||||
|
// a_errormetric is used to choose the best encoding
|
||||||
|
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||||
|
// a_paucEncodingBits points to the final encoding bits
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_R11::InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
|
||||||
|
|
||||||
|
m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization from the encoding bits of a previous encoding
|
||||||
|
// a_pblockParent points to the block associated with this encoding
|
||||||
|
// a_errormetric is used to choose the best encoding
|
||||||
|
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||||
|
// a_paucEncodingBits points to the final encoding bits of a previous encoding
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_R11::InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
|
||||||
|
|
||||||
|
// init RGB portion
|
||||||
|
Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
|
||||||
|
(unsigned char *)m_pencodingbitsR11,
|
||||||
|
a_pafrgbaSource,
|
||||||
|
a_errormetric);
|
||||||
|
|
||||||
|
// init R11 portion
|
||||||
|
{
|
||||||
|
m_mode = MODE_R11;
|
||||||
|
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_fRedBase = (float)(signed char)m_pencodingbitsR11->data.base;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_fRedBase = (float)(unsigned char)m_pencodingbitsR11->data.base;
|
||||||
|
}
|
||||||
|
m_fRedMultiplier = (float)m_pencodingbitsR11->data.multiplier;
|
||||||
|
m_uiRedModifierTableIndex = m_pencodingbitsR11->data.table;
|
||||||
|
|
||||||
|
unsigned long long int ulliSelectorBits = 0;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors0 << 40;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors1 << 32;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors2 << 24;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors3 << 16;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors4 << 8;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors5;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||||
|
m_auiRedSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (SELECTORS - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode the red channel
|
||||||
|
// calc red error
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
float fDecodedPixelData = 0.0f;
|
||||||
|
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||||
|
{
|
||||||
|
fDecodedPixelData = DecodePixelRed(m_fRedBase, m_fRedMultiplier,
|
||||||
|
m_uiRedModifierTableIndex,
|
||||||
|
m_auiRedSelectors[uiPixel]);
|
||||||
|
}
|
||||||
|
else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
fDecodedPixelData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier,
|
||||||
|
m_uiRedModifierTableIndex,
|
||||||
|
m_auiRedSelectors[uiPixel]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fDecodedPixelData, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
CalcBlockError();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// perform a single encoding iteration
|
||||||
|
// replace the encoding if a better encoding was found
|
||||||
|
// subsequent iterations generally take longer for each iteration
|
||||||
|
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_R11::PerformIteration(float a_fEffort)
|
||||||
|
{
|
||||||
|
assert(!m_boolDone);
|
||||||
|
m_mode = MODE_R11;
|
||||||
|
|
||||||
|
switch (m_uiEncodingIterations)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
m_fError = FLT_MAX;
|
||||||
|
m_fRedBlockError = FLT_MAX; // artificially high value
|
||||||
|
CalculateR11(8, 0.0f, 0.0f);
|
||||||
|
m_fError = m_fRedBlockError;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
CalculateR11(8, 2.0f, 1.0f);
|
||||||
|
m_fError = m_fRedBlockError;
|
||||||
|
if (a_fEffort <= 24.5f)
|
||||||
|
{
|
||||||
|
m_boolDone = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
CalculateR11(8, 12.0f, 1.0f);
|
||||||
|
m_fError = m_fRedBlockError;
|
||||||
|
if (a_fEffort <= 49.5f)
|
||||||
|
{
|
||||||
|
m_boolDone = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
CalculateR11(7, 6.0f, 1.0f);
|
||||||
|
m_fError = m_fRedBlockError;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
CalculateR11(6, 3.0f, 1.0f);
|
||||||
|
m_fError = m_fRedBlockError;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
CalculateR11(5, 1.0f, 0.0f);
|
||||||
|
m_fError = m_fRedBlockError;
|
||||||
|
m_boolDone = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_uiEncodingIterations++;
|
||||||
|
SetDoneIfPerfect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// find the best combination of base color, multiplier and selectors
|
||||||
|
//
|
||||||
|
// a_uiSelectorsUsed limits the number of selector combinations to try
|
||||||
|
// a_fBaseRadius limits the range of base colors to try
|
||||||
|
// a_fMultiplierRadius limits the range of multipliers to try
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_R11::CalculateR11(unsigned int a_uiSelectorsUsed,
|
||||||
|
float a_fBaseRadius, float a_fMultiplierRadius)
|
||||||
|
{
|
||||||
|
// maps from virtual (monotonic) selector to ETC selector
|
||||||
|
static const unsigned int auiVirtualSelectorMap[8] = {3, 2, 1, 0, 4, 5, 6, 7};
|
||||||
|
|
||||||
|
// find min/max red
|
||||||
|
float fMinRed = 1.0f;
|
||||||
|
float fMaxRed = 0.0f;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
// ignore border pixels
|
||||||
|
float fAlpha = m_pafrgbaSource[uiPixel].fA;
|
||||||
|
if (isnan(fAlpha))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fRed = m_pafrgbaSource[uiPixel].fR;
|
||||||
|
|
||||||
|
if (fRed < fMinRed)
|
||||||
|
{
|
||||||
|
fMinRed = fRed;
|
||||||
|
}
|
||||||
|
if (fRed > fMaxRed)
|
||||||
|
{
|
||||||
|
fMaxRed = fRed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(fMinRed <= fMaxRed);
|
||||||
|
|
||||||
|
float fRedRange = (fMaxRed - fMinRed);
|
||||||
|
|
||||||
|
// try each modifier table entry
|
||||||
|
for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
|
||||||
|
{
|
||||||
|
for (unsigned int uiMinVirtualSelector = 0;
|
||||||
|
uiMinVirtualSelector <= (8- a_uiSelectorsUsed);
|
||||||
|
uiMinVirtualSelector++)
|
||||||
|
{
|
||||||
|
unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
|
||||||
|
|
||||||
|
unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
|
||||||
|
unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
|
||||||
|
|
||||||
|
float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||||
|
|
||||||
|
float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
|
||||||
|
s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||||
|
|
||||||
|
float fCenterRatio = fTableEntryCenter / fTableEntryRange;
|
||||||
|
|
||||||
|
float fCenter = fMinRed + fCenterRatio*fRedRange;
|
||||||
|
fCenter = roundf(255.0f * fCenter) / 255.0f;
|
||||||
|
|
||||||
|
float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
|
||||||
|
if (fMinBase < 0.0f)
|
||||||
|
{
|
||||||
|
fMinBase = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
|
||||||
|
if (fMaxBase > 1.0f)
|
||||||
|
{
|
||||||
|
fMaxBase = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
|
||||||
|
{
|
||||||
|
float fRangeMultiplier = roundf(fRedRange / fTableEntryRange);
|
||||||
|
|
||||||
|
float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
|
||||||
|
if (fMinMultiplier < 1.0f)
|
||||||
|
{
|
||||||
|
fMinMultiplier = 0.0f;
|
||||||
|
}
|
||||||
|
else if (fMinMultiplier > 15.0f)
|
||||||
|
{
|
||||||
|
fMinMultiplier = 15.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
|
||||||
|
if (fMaxMultiplier < 1.0f)
|
||||||
|
{
|
||||||
|
fMaxMultiplier = 1.0f;
|
||||||
|
}
|
||||||
|
else if (fMaxMultiplier > 15.0f)
|
||||||
|
{
|
||||||
|
fMaxMultiplier = 15.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
|
||||||
|
{
|
||||||
|
// find best selector for each pixel
|
||||||
|
unsigned int auiBestSelectors[PIXELS];
|
||||||
|
float afBestRedError[PIXELS];
|
||||||
|
float afBestPixelRed[PIXELS];
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
float fBestPixelRedError = FLT_MAX;
|
||||||
|
|
||||||
|
for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
|
||||||
|
{
|
||||||
|
float fPixelRed = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
|
||||||
|
|
||||||
|
ColorFloatRGBA frgba(fPixelRed, m_pafrgbaSource[uiPixel].fG,0.0f,1.0f);
|
||||||
|
|
||||||
|
float fPixelRedError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
|
||||||
|
|
||||||
|
if (fPixelRedError < fBestPixelRedError)
|
||||||
|
{
|
||||||
|
fBestPixelRedError = fPixelRedError;
|
||||||
|
auiBestSelectors[uiPixel] = uiSelector;
|
||||||
|
afBestRedError[uiPixel] = fBestPixelRedError;
|
||||||
|
afBestPixelRed[uiPixel] = fPixelRed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float fBlockError = 0.0f;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
fBlockError += afBestRedError[uiPixel];
|
||||||
|
}
|
||||||
|
if (fBlockError < m_fRedBlockError)
|
||||||
|
{
|
||||||
|
m_fRedBlockError = fBlockError;
|
||||||
|
|
||||||
|
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||||
|
{
|
||||||
|
m_fRedBase = 255.0f * fBase;
|
||||||
|
}
|
||||||
|
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_fRedBase = (fBase * 255) - 128;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
m_fRedMultiplier = fMultiplier;
|
||||||
|
m_uiRedModifierTableIndex = uiTableEntry;
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_auiRedSelectors[uiPixel] = auiBestSelectors[uiPixel];
|
||||||
|
float fBestPixelRed = afBestPixelRed[uiPixel];
|
||||||
|
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fBestPixelRed, 0.0f, 0.0f, 1.0f);
|
||||||
|
m_afDecodedAlphas[uiPixel] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// set the encoding bits based on encoding state
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_R11::SetEncodingBits(void)
|
||||||
|
{
|
||||||
|
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||||
|
{
|
||||||
|
m_pencodingbitsR11->data.base = (unsigned char)roundf(m_fRedBase);
|
||||||
|
}
|
||||||
|
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_pencodingbitsR11->data.base = (signed char)roundf(m_fRedBase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
m_pencodingbitsR11->data.table = m_uiRedModifierTableIndex;
|
||||||
|
m_pencodingbitsR11->data.multiplier = (unsigned char)roundf(m_fRedMultiplier);
|
||||||
|
|
||||||
|
unsigned long long int ulliSelectorBits = 0;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||||
|
ulliSelectorBits |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pencodingbitsR11->data.selectors0 = ulliSelectorBits >> 40;
|
||||||
|
m_pencodingbitsR11->data.selectors1 = ulliSelectorBits >> 32;
|
||||||
|
m_pencodingbitsR11->data.selectors2 = ulliSelectorBits >> 24;
|
||||||
|
m_pencodingbitsR11->data.selectors3 = ulliSelectorBits >> 16;
|
||||||
|
m_pencodingbitsR11->data.selectors4 = ulliSelectorBits >> 8;
|
||||||
|
m_pencodingbitsR11->data.selectors5 = ulliSelectorBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
}
|
122
thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
vendored
Normal file
122
thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
vendored
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4EncodingBits_R11;
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_R11
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_R11 : public Block4x4Encoding_RGB8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Block4x4Encoding_R11(void);
|
||||||
|
virtual ~Block4x4Encoding_R11(void);
|
||||||
|
|
||||||
|
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
inline float GetRedBase(void) const
|
||||||
|
{
|
||||||
|
return m_fRedBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float GetRedMultiplier(void) const
|
||||||
|
{
|
||||||
|
return m_fRedMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int GetRedTableIndex(void) const
|
||||||
|
{
|
||||||
|
return m_uiRedModifierTableIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const unsigned int * GetRedSelectors(void) const
|
||||||
|
{
|
||||||
|
return m_auiRedSelectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
|
||||||
|
static const unsigned int SELECTOR_BITS = 3;
|
||||||
|
static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
|
||||||
|
|
||||||
|
static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS];
|
||||||
|
|
||||||
|
void CalculateR11(unsigned int a_uiSelectorsUsed,
|
||||||
|
float a_fBaseRadius, float a_fMultiplierRadius);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline float DecodePixelRed(float a_fBase, float a_fMultiplier,
|
||||||
|
unsigned int a_uiTableIndex, unsigned int a_uiSelector)
|
||||||
|
{
|
||||||
|
float fMultiplier = a_fMultiplier;
|
||||||
|
if (fMultiplier <= 0.0f)
|
||||||
|
{
|
||||||
|
fMultiplier = 1.0f / 8.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fPixelRed = a_fBase * 8 + 4 +
|
||||||
|
8 * fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]*255;
|
||||||
|
fPixelRed /= 2047.0f;
|
||||||
|
|
||||||
|
if (fPixelRed < 0.0f)
|
||||||
|
{
|
||||||
|
fPixelRed = 0.0f;
|
||||||
|
}
|
||||||
|
else if (fPixelRed > 1.0f)
|
||||||
|
{
|
||||||
|
fPixelRed = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fPixelRed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block4x4EncodingBits_R11 *m_pencodingbitsR11;
|
||||||
|
|
||||||
|
float m_fRedBase;
|
||||||
|
float m_fRedMultiplier;
|
||||||
|
float m_fRedBlockError;
|
||||||
|
unsigned int m_uiRedModifierTableIndex;
|
||||||
|
unsigned int m_auiRedSelectors[PIXELS];
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
447
thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
vendored
Normal file
447
thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
vendored
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcBlock4x4Encoding_RG11.cpp
|
||||||
|
|
||||||
|
Block4x4Encoding_RG11 is the encoder to use when targetting file format RG11 and SRG11 (signed RG11).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcBlock4x4Encoding_RG11.h"
|
||||||
|
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcBlock4x4.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
Block4x4Encoding_RG11::Block4x4Encoding_RG11(void)
|
||||||
|
{
|
||||||
|
m_pencodingbitsRG11 = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block4x4Encoding_RG11::~Block4x4Encoding_RG11(void) {}
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization prior to encoding
|
||||||
|
// a_pblockParent points to the block associated with this encoding
|
||||||
|
// a_errormetric is used to choose the best encoding
|
||||||
|
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||||
|
// a_paucEncodingBits points to the final encoding bits
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RG11::InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
|
||||||
|
|
||||||
|
m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization from the encoding bits of a previous encoding
|
||||||
|
// a_pblockParent points to the block associated with this encoding
|
||||||
|
// a_errormetric is used to choose the best encoding
|
||||||
|
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||||
|
// a_paucEncodingBits points to the final encoding bits of a previous encoding
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RG11::InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
|
||||||
|
|
||||||
|
// init RGB portion
|
||||||
|
Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
|
||||||
|
(unsigned char *)m_pencodingbitsRG11,
|
||||||
|
a_pafrgbaSource,
|
||||||
|
a_errormetric);
|
||||||
|
m_fError = 0.0f;
|
||||||
|
|
||||||
|
{
|
||||||
|
m_mode = MODE_RG11;
|
||||||
|
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_fRedBase = (float)(signed char)m_pencodingbitsRG11->data.baseR;
|
||||||
|
m_fGrnBase = (float)(signed char)m_pencodingbitsRG11->data.baseG;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_fRedBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseR;
|
||||||
|
m_fGrnBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseG;
|
||||||
|
}
|
||||||
|
m_fRedMultiplier = (float)m_pencodingbitsRG11->data.multiplierR;
|
||||||
|
m_fGrnMultiplier = (float)m_pencodingbitsRG11->data.multiplierG;
|
||||||
|
m_uiRedModifierTableIndex = m_pencodingbitsRG11->data.tableIndexR;
|
||||||
|
m_uiGrnModifierTableIndex = m_pencodingbitsRG11->data.tableIndexG;
|
||||||
|
|
||||||
|
unsigned long long int ulliSelectorBitsR = 0;
|
||||||
|
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR0 << 40;
|
||||||
|
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR1 << 32;
|
||||||
|
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR2 << 24;
|
||||||
|
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR3 << 16;
|
||||||
|
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR4 << 8;
|
||||||
|
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR5;
|
||||||
|
|
||||||
|
unsigned long long int ulliSelectorBitsG = 0;
|
||||||
|
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG0 << 40;
|
||||||
|
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG1 << 32;
|
||||||
|
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG2 << 24;
|
||||||
|
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG3 << 16;
|
||||||
|
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG4 << 8;
|
||||||
|
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG5;
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||||
|
m_auiRedSelectors[uiPixel] = (ulliSelectorBitsR >> uiShift) & (SELECTORS - 1);
|
||||||
|
m_auiGrnSelectors[uiPixel] = (ulliSelectorBitsG >> uiShift) & (SELECTORS - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
float fRedDecodedData = 0.0f;
|
||||||
|
float fGrnDecodedData = 0.0f;
|
||||||
|
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||||
|
{
|
||||||
|
fRedDecodedData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
|
||||||
|
fGrnDecodedData = DecodePixelRed(m_fGrnBase, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
|
||||||
|
}
|
||||||
|
else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
fRedDecodedData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
|
||||||
|
fGrnDecodedData = DecodePixelRed(m_fGrnBase + 128, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fRedDecodedData, fGrnDecodedData, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcBlockError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// perform a single encoding iteration
|
||||||
|
// replace the encoding if a better encoding was found
|
||||||
|
// subsequent iterations generally take longer for each iteration
|
||||||
|
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RG11::PerformIteration(float a_fEffort)
|
||||||
|
{
|
||||||
|
assert(!m_boolDone);
|
||||||
|
|
||||||
|
switch (m_uiEncodingIterations)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
m_fError = FLT_MAX;
|
||||||
|
m_fGrnBlockError = FLT_MAX; // artificially high value
|
||||||
|
m_fRedBlockError = FLT_MAX;
|
||||||
|
CalculateR11(8, 0.0f, 0.0f);
|
||||||
|
CalculateG11(8, 0.0f, 0.0f);
|
||||||
|
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
CalculateR11(8, 2.0f, 1.0f);
|
||||||
|
CalculateG11(8, 2.0f, 1.0f);
|
||||||
|
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||||
|
if (a_fEffort <= 24.5f)
|
||||||
|
{
|
||||||
|
m_boolDone = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
CalculateR11(8, 12.0f, 1.0f);
|
||||||
|
CalculateG11(8, 12.0f, 1.0f);
|
||||||
|
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||||
|
if (a_fEffort <= 49.5f)
|
||||||
|
{
|
||||||
|
m_boolDone = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
CalculateR11(7, 6.0f, 1.0f);
|
||||||
|
CalculateG11(7, 6.0f, 1.0f);
|
||||||
|
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
CalculateR11(6, 3.0f, 1.0f);
|
||||||
|
CalculateG11(6, 3.0f, 1.0f);
|
||||||
|
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
CalculateR11(5, 1.0f, 0.0f);
|
||||||
|
CalculateG11(5, 1.0f, 0.0f);
|
||||||
|
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||||
|
m_boolDone = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_uiEncodingIterations++;
|
||||||
|
SetDoneIfPerfect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// find the best combination of base color, multiplier and selectors
|
||||||
|
//
|
||||||
|
// a_uiSelectorsUsed limits the number of selector combinations to try
|
||||||
|
// a_fBaseRadius limits the range of base colors to try
|
||||||
|
// a_fMultiplierRadius limits the range of multipliers to try
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RG11::CalculateG11(unsigned int a_uiSelectorsUsed,
|
||||||
|
float a_fBaseRadius, float a_fMultiplierRadius)
|
||||||
|
{
|
||||||
|
// maps from virtual (monotonic) selector to etc selector
|
||||||
|
static const unsigned int auiVirtualSelectorMap[8] = { 3, 2, 1, 0, 4, 5, 6, 7 };
|
||||||
|
|
||||||
|
// find min/max Grn
|
||||||
|
float fMinGrn = 1.0f;
|
||||||
|
float fMaxGrn = 0.0f;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
// ignore border pixels
|
||||||
|
float fAlpha = m_pafrgbaSource[uiPixel].fA;
|
||||||
|
if (isnan(fAlpha))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fGrn = m_pafrgbaSource[uiPixel].fG;
|
||||||
|
|
||||||
|
if (fGrn < fMinGrn)
|
||||||
|
{
|
||||||
|
fMinGrn = fGrn;
|
||||||
|
}
|
||||||
|
if (fGrn > fMaxGrn)
|
||||||
|
{
|
||||||
|
fMaxGrn = fGrn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(fMinGrn <= fMaxGrn);
|
||||||
|
|
||||||
|
float fGrnRange = (fMaxGrn - fMinGrn);
|
||||||
|
|
||||||
|
// try each modifier table entry
|
||||||
|
for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
|
||||||
|
{
|
||||||
|
for (unsigned int uiMinVirtualSelector = 0;
|
||||||
|
uiMinVirtualSelector <= (8 - a_uiSelectorsUsed);
|
||||||
|
uiMinVirtualSelector++)
|
||||||
|
{
|
||||||
|
unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
|
||||||
|
|
||||||
|
unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
|
||||||
|
unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
|
||||||
|
|
||||||
|
float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||||
|
|
||||||
|
float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
|
||||||
|
s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||||
|
|
||||||
|
float fCenterRatio = fTableEntryCenter / fTableEntryRange;
|
||||||
|
|
||||||
|
float fCenter = fMinGrn + fCenterRatio*fGrnRange;
|
||||||
|
fCenter = roundf(255.0f * fCenter) / 255.0f;
|
||||||
|
|
||||||
|
float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
|
||||||
|
if (fMinBase < 0.0f)
|
||||||
|
{
|
||||||
|
fMinBase = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
|
||||||
|
if (fMaxBase > 1.0f)
|
||||||
|
{
|
||||||
|
fMaxBase = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
|
||||||
|
{
|
||||||
|
float fRangeMultiplier = roundf(fGrnRange / fTableEntryRange);
|
||||||
|
|
||||||
|
float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
|
||||||
|
if (fMinMultiplier < 1.0f)
|
||||||
|
{
|
||||||
|
fMinMultiplier = 0.0f;
|
||||||
|
}
|
||||||
|
else if (fMinMultiplier > 15.0f)
|
||||||
|
{
|
||||||
|
fMinMultiplier = 15.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
|
||||||
|
if (fMaxMultiplier < 1.0f)
|
||||||
|
{
|
||||||
|
fMaxMultiplier = 1.0f;
|
||||||
|
}
|
||||||
|
else if (fMaxMultiplier > 15.0f)
|
||||||
|
{
|
||||||
|
fMaxMultiplier = 15.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
|
||||||
|
{
|
||||||
|
// find best selector for each pixel
|
||||||
|
unsigned int auiBestSelectors[PIXELS];
|
||||||
|
float afBestGrnError[PIXELS];
|
||||||
|
float afBestPixelGrn[PIXELS];
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
float fBestPixelGrnError = FLT_MAX;
|
||||||
|
|
||||||
|
for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
|
||||||
|
{
|
||||||
|
//DecodePixelRed is not red channel specific
|
||||||
|
float fPixelGrn = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
|
||||||
|
|
||||||
|
ColorFloatRGBA frgba(m_pafrgbaSource[uiPixel].fR, fPixelGrn, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
float fPixelGrnError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
|
||||||
|
|
||||||
|
if (fPixelGrnError < fBestPixelGrnError)
|
||||||
|
{
|
||||||
|
fBestPixelGrnError = fPixelGrnError;
|
||||||
|
auiBestSelectors[uiPixel] = uiSelector;
|
||||||
|
afBestGrnError[uiPixel] = fBestPixelGrnError;
|
||||||
|
afBestPixelGrn[uiPixel] = fPixelGrn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float fBlockError = 0.0f;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
fBlockError += afBestGrnError[uiPixel];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fBlockError < m_fGrnBlockError)
|
||||||
|
{
|
||||||
|
m_fGrnBlockError = fBlockError;
|
||||||
|
|
||||||
|
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||||
|
{
|
||||||
|
m_fGrnBase = 255.0f * fBase;
|
||||||
|
}
|
||||||
|
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_fGrnBase = (fBase * 255) - 128;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
m_fGrnMultiplier = fMultiplier;
|
||||||
|
m_uiGrnModifierTableIndex = uiTableEntry;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_auiGrnSelectors[uiPixel] = auiBestSelectors[uiPixel];
|
||||||
|
m_afrgbaDecodedColors[uiPixel].fG = afBestPixelGrn[uiPixel];
|
||||||
|
m_afDecodedAlphas[uiPixel] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// set the encoding bits based on encoding state
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RG11::SetEncodingBits(void)
|
||||||
|
{
|
||||||
|
unsigned long long int ulliSelectorBitsR = 0;
|
||||||
|
unsigned long long int ulliSelectorBitsG = 0;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||||
|
ulliSelectorBitsR |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
|
||||||
|
ulliSelectorBitsG |= ((unsigned long long int)m_auiGrnSelectors[uiPixel]) << uiShift;
|
||||||
|
}
|
||||||
|
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||||
|
{
|
||||||
|
m_pencodingbitsRG11->data.baseR = (unsigned char)roundf(m_fRedBase);
|
||||||
|
}
|
||||||
|
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_pencodingbitsRG11->data.baseR = (signed char)roundf(m_fRedBase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
m_pencodingbitsRG11->data.tableIndexR = m_uiRedModifierTableIndex;
|
||||||
|
m_pencodingbitsRG11->data.multiplierR = (unsigned char)roundf(m_fRedMultiplier);
|
||||||
|
|
||||||
|
m_pencodingbitsRG11->data.selectorsR0 = ulliSelectorBitsR >> 40;
|
||||||
|
m_pencodingbitsRG11->data.selectorsR1 = ulliSelectorBitsR >> 32;
|
||||||
|
m_pencodingbitsRG11->data.selectorsR2 = ulliSelectorBitsR >> 24;
|
||||||
|
m_pencodingbitsRG11->data.selectorsR3 = ulliSelectorBitsR >> 16;
|
||||||
|
m_pencodingbitsRG11->data.selectorsR4 = ulliSelectorBitsR >> 8;
|
||||||
|
m_pencodingbitsRG11->data.selectorsR5 = ulliSelectorBitsR;
|
||||||
|
|
||||||
|
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||||
|
{
|
||||||
|
m_pencodingbitsRG11->data.baseG = (unsigned char)roundf(m_fGrnBase);
|
||||||
|
}
|
||||||
|
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||||
|
{
|
||||||
|
m_pencodingbitsRG11->data.baseG = (signed char)roundf(m_fGrnBase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
m_pencodingbitsRG11->data.tableIndexG = m_uiGrnModifierTableIndex;
|
||||||
|
m_pencodingbitsRG11->data.multiplierG = (unsigned char)roundf(m_fGrnMultiplier);
|
||||||
|
|
||||||
|
m_pencodingbitsRG11->data.selectorsG0 = ulliSelectorBitsG >> 40;
|
||||||
|
m_pencodingbitsRG11->data.selectorsG1 = ulliSelectorBitsG >> 32;
|
||||||
|
m_pencodingbitsRG11->data.selectorsG2 = ulliSelectorBitsG >> 24;
|
||||||
|
m_pencodingbitsRG11->data.selectorsG3 = ulliSelectorBitsG >> 16;
|
||||||
|
m_pencodingbitsRG11->data.selectorsG4 = ulliSelectorBitsG >> 8;
|
||||||
|
m_pencodingbitsRG11->data.selectorsG5 = ulliSelectorBitsG;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
}
|
86
thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
vendored
Normal file
86
thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||||
|
#include "EtcBlock4x4Encoding_R11.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4EncodingBits_RG11;
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_RG11
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_RG11 : public Block4x4Encoding_R11
|
||||||
|
{
|
||||||
|
float m_fGrnBase;
|
||||||
|
float m_fGrnMultiplier;
|
||||||
|
float m_fGrnBlockError;
|
||||||
|
unsigned int m_auiGrnSelectors[PIXELS];
|
||||||
|
unsigned int m_uiGrnModifierTableIndex;
|
||||||
|
public:
|
||||||
|
|
||||||
|
Block4x4Encoding_RG11(void);
|
||||||
|
virtual ~Block4x4Encoding_RG11(void);
|
||||||
|
|
||||||
|
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
Block4x4EncodingBits_RG11 *m_pencodingbitsRG11;
|
||||||
|
|
||||||
|
void CalculateG11(unsigned int a_uiSelectorsUsed, float a_fBaseRadius, float a_fMultiplierRadius);
|
||||||
|
|
||||||
|
inline float GetGrnBase(void) const
|
||||||
|
{
|
||||||
|
return m_fGrnBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float GetGrnMultiplier(void) const
|
||||||
|
{
|
||||||
|
return m_fGrnMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int GetGrnTableIndex(void) const
|
||||||
|
{
|
||||||
|
return m_uiGrnModifierTableIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const unsigned int * GetGrnSelectors(void) const
|
||||||
|
{
|
||||||
|
return m_auiGrnSelectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
1730
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
vendored
Normal file
1730
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
96
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
vendored
Normal file
96
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
vendored
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcBlock4x4Encoding_ETC1.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
class Block4x4Encoding_RGB8 : public Block4x4Encoding_ETC1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Block4x4Encoding_RGB8(void);
|
||||||
|
virtual ~Block4x4Encoding_RGB8(void);
|
||||||
|
|
||||||
|
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
inline ColorFloatRGBA GetColor3(void) const
|
||||||
|
{
|
||||||
|
return m_frgbaColor3;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
static const unsigned int PLANAR_CORNER_COLORS = 3;
|
||||||
|
static const unsigned int MAX_PLANAR_REGRESSION_SIZE = 4;
|
||||||
|
static const unsigned int TH_DISTANCES = 8;
|
||||||
|
|
||||||
|
static float s_afTHDistanceTable[TH_DISTANCES];
|
||||||
|
|
||||||
|
void TryPlanar(unsigned int a_uiRadius);
|
||||||
|
void TryTAndH(unsigned int a_uiRadius);
|
||||||
|
|
||||||
|
void InitFromEncodingBits_Planar(void);
|
||||||
|
|
||||||
|
ColorFloatRGBA m_frgbaColor3; // used for planar
|
||||||
|
|
||||||
|
void SetEncodingBits_T(void);
|
||||||
|
void SetEncodingBits_H(void);
|
||||||
|
void SetEncodingBits_Planar(void);
|
||||||
|
|
||||||
|
// state shared between iterations
|
||||||
|
ColorFloatRGBA m_frgbaOriginalColor1_TAndH;
|
||||||
|
ColorFloatRGBA m_frgbaOriginalColor2_TAndH;
|
||||||
|
|
||||||
|
void CalculateBaseColorsForTAndH(void);
|
||||||
|
void TryT(unsigned int a_uiRadius);
|
||||||
|
void TryT_BestSelectorCombination(void);
|
||||||
|
void TryH(unsigned int a_uiRadius);
|
||||||
|
void TryH_BestSelectorCombination(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void InitFromEncodingBits_T(void);
|
||||||
|
void InitFromEncodingBits_H(void);
|
||||||
|
|
||||||
|
void CalculatePlanarCornerColors(void);
|
||||||
|
|
||||||
|
void ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels,
|
||||||
|
ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset);
|
||||||
|
|
||||||
|
bool TwiddlePlanar(void);
|
||||||
|
bool TwiddlePlanarR();
|
||||||
|
bool TwiddlePlanarG();
|
||||||
|
bool TwiddlePlanarB();
|
||||||
|
|
||||||
|
void DecodePixels_T(void);
|
||||||
|
void DecodePixels_H(void);
|
||||||
|
void DecodePixels_Planar(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
1819
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
vendored
Normal file
1819
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
129
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
vendored
Normal file
129
thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
vendored
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||||
|
#include "EtcErrorMetric.h"
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_RGB8A1
|
||||||
|
// RGB8A1 if not completely opaque or transparent
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_RGB8A1 : public Block4x4Encoding_RGB8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int TRANSPARENT_SELECTOR = 2;
|
||||||
|
|
||||||
|
Block4x4Encoding_RGB8A1(void);
|
||||||
|
virtual ~Block4x4Encoding_RGB8A1(void);
|
||||||
|
|
||||||
|
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
void InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
void InitFromEncodingBits_T(void);
|
||||||
|
void InitFromEncodingBits_H(void);
|
||||||
|
|
||||||
|
void PerformFirstIteration(void);
|
||||||
|
|
||||||
|
void Decode_ETC1(void);
|
||||||
|
void DecodePixels_T(void);
|
||||||
|
void DecodePixels_H(void);
|
||||||
|
void SetEncodingBits_ETC1(void);
|
||||||
|
void SetEncodingBits_T(void);
|
||||||
|
void SetEncodingBits_H(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool m_boolOpaque; // all source pixels have alpha >= 0.5
|
||||||
|
bool m_boolTransparent; // all source pixels have alpha < 0.5
|
||||||
|
bool m_boolPunchThroughPixels; // some source pixels have alpha < 0.5
|
||||||
|
|
||||||
|
static float s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS];
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
|
||||||
|
int a_iGrayOffset1, int a_iGrayOffset2);
|
||||||
|
void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
|
||||||
|
|
||||||
|
void TryT(unsigned int a_uiRadius);
|
||||||
|
void TryT_BestSelectorCombination(void);
|
||||||
|
void TryH(unsigned int a_uiRadius);
|
||||||
|
void TryH_BestSelectorCombination(void);
|
||||||
|
|
||||||
|
void TryDegenerates1(void);
|
||||||
|
void TryDegenerates2(void);
|
||||||
|
void TryDegenerates3(void);
|
||||||
|
void TryDegenerates4(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_RGB8A1_Opaque
|
||||||
|
// RGB8A1 if all pixels have alpha==1
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_RGB8A1_Opaque : public Block4x4Encoding_RGB8A1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
void PerformFirstIteration(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_RGB8A1_Transparent
|
||||||
|
// RGB8A1 if all pixels have alpha==0
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_RGB8A1_Transparent : public Block4x4Encoding_RGB8A1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
474
thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
vendored
Normal file
474
thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
vendored
Normal file
|
@ -0,0 +1,474 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcBlock4x4Encoding_RGBA8.cpp contains:
|
||||||
|
Block4x4Encoding_RGBA8
|
||||||
|
Block4x4Encoding_RGBA8_Opaque
|
||||||
|
Block4x4Encoding_RGBA8_Transparent
|
||||||
|
|
||||||
|
These encoders are used when targetting file format RGBA8.
|
||||||
|
|
||||||
|
Block4x4Encoding_RGBA8_Opaque is used when all pixels in the 4x4 block are opaque
|
||||||
|
Block4x4Encoding_RGBA8_Transparent is used when all pixels in the 4x4 block are transparent
|
||||||
|
Block4x4Encoding_RGBA8 is used when there is a mixture of alphas in the 4x4 block
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcBlock4x4Encoding_RGBA8.h"
|
||||||
|
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcBlock4x4.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ####################################################################################################
|
||||||
|
// Block4x4Encoding_RGBA8
|
||||||
|
// ####################################################################################################
|
||||||
|
|
||||||
|
float Block4x4Encoding_RGBA8::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS]
|
||||||
|
{
|
||||||
|
{ -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
|
||||||
|
|
||||||
|
{ -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
|
||||||
|
{ -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||||
|
|
||||||
|
{ -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
|
||||||
|
{ -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
|
||||||
|
{ -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
|
||||||
|
{ -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
Block4x4Encoding_RGBA8::Block4x4Encoding_RGBA8(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_pencodingbitsA8 = nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
Block4x4Encoding_RGBA8::~Block4x4Encoding_RGBA8(void) {}
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization prior to encoding
|
||||||
|
// a_pblockParent points to the block associated with this encoding
|
||||||
|
// a_errormetric is used to choose the best encoding
|
||||||
|
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||||
|
// a_paucEncodingBits points to the final encoding bits
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8::InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
|
||||||
|
|
||||||
|
m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
|
||||||
|
m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// initialization from the encoding bits of a previous encoding
|
||||||
|
// a_pblockParent points to the block associated with this encoding
|
||||||
|
// a_errormetric is used to choose the best encoding
|
||||||
|
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||||
|
// a_paucEncodingBits points to the final encoding bits of a previous encoding
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8::InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
|
||||||
|
m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
|
||||||
|
|
||||||
|
// init RGB portion
|
||||||
|
Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
|
||||||
|
(unsigned char *) m_pencodingbitsRGB8,
|
||||||
|
a_pafrgbaSource,
|
||||||
|
a_errormetric);
|
||||||
|
|
||||||
|
// init A8 portion
|
||||||
|
// has to be done after InitFromEncodingBits()
|
||||||
|
{
|
||||||
|
m_fBase = m_pencodingbitsA8->data.base / 255.0f;
|
||||||
|
m_fMultiplier = (float)m_pencodingbitsA8->data.multiplier;
|
||||||
|
m_uiModifierTableIndex = m_pencodingbitsA8->data.table;
|
||||||
|
|
||||||
|
unsigned long long int ulliSelectorBits = 0;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors0 << 40;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors1 << 32;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors2 << 24;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors3 << 16;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors4 << 8;
|
||||||
|
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors5;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||||
|
m_auiAlphaSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (ALPHA_SELECTORS - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode the alphas
|
||||||
|
// calc alpha error
|
||||||
|
m_fError = 0.0f;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_afDecodedAlphas[uiPixel] = DecodePixelAlpha(m_fBase, m_fMultiplier,
|
||||||
|
m_uiModifierTableIndex,
|
||||||
|
m_auiAlphaSelectors[uiPixel]);
|
||||||
|
|
||||||
|
float fDeltaAlpha = m_afDecodedAlphas[uiPixel] - m_pafrgbaSource[uiPixel].fA;
|
||||||
|
m_fError += fDeltaAlpha * fDeltaAlpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// redo error calc to include alpha
|
||||||
|
CalcBlockError();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// perform a single encoding iteration
|
||||||
|
// replace the encoding if a better encoding was found
|
||||||
|
// subsequent iterations generally take longer for each iteration
|
||||||
|
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||||
|
//
|
||||||
|
// similar to Block4x4Encoding_RGB8_Base::Encode_RGB8(), but with alpha added
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8::PerformIteration(float a_fEffort)
|
||||||
|
{
|
||||||
|
assert(!m_boolDone);
|
||||||
|
|
||||||
|
if (m_uiEncodingIterations == 0)
|
||||||
|
{
|
||||||
|
if (a_fEffort < 24.9f)
|
||||||
|
{
|
||||||
|
CalculateA8(0.0f);
|
||||||
|
}
|
||||||
|
else if (a_fEffort < 49.9f)
|
||||||
|
{
|
||||||
|
CalculateA8(1.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CalculateA8(2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// find the best combination of base alpga, multiplier and selectors
|
||||||
|
//
|
||||||
|
// a_fRadius limits the range of base alpha to try
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8::CalculateA8(float a_fRadius)
|
||||||
|
{
|
||||||
|
|
||||||
|
// find min/max alpha
|
||||||
|
float fMinAlpha = 1.0f;
|
||||||
|
float fMaxAlpha = 0.0f;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
float fAlpha = m_pafrgbaSource[uiPixel].fA;
|
||||||
|
|
||||||
|
// ignore border pixels
|
||||||
|
if (isnan(fAlpha))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fAlpha < fMinAlpha)
|
||||||
|
{
|
||||||
|
fMinAlpha = fAlpha;
|
||||||
|
}
|
||||||
|
if (fAlpha > fMaxAlpha)
|
||||||
|
{
|
||||||
|
fMaxAlpha = fAlpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(fMinAlpha <= fMaxAlpha);
|
||||||
|
|
||||||
|
float fAlphaRange = fMaxAlpha - fMinAlpha;
|
||||||
|
|
||||||
|
// try each modifier table entry
|
||||||
|
m_fError = FLT_MAX; // artificially high value
|
||||||
|
for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
|
||||||
|
{
|
||||||
|
static const unsigned int MIN_VALUE_SELECTOR = 3;
|
||||||
|
static const unsigned int MAX_VALUE_SELECTOR = 7;
|
||||||
|
|
||||||
|
float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
|
||||||
|
|
||||||
|
float fTableEntryRange = s_aafModifierTable[uiTableEntry][MAX_VALUE_SELECTOR] -
|
||||||
|
s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
|
||||||
|
|
||||||
|
float fCenterRatio = fTableEntryCenter / fTableEntryRange;
|
||||||
|
|
||||||
|
float fCenter = fMinAlpha + fCenterRatio*fAlphaRange;
|
||||||
|
fCenter = roundf(255.0f * fCenter) / 255.0f;
|
||||||
|
|
||||||
|
float fMinBase = fCenter - (a_fRadius / 255.0f);
|
||||||
|
if (fMinBase < 0.0f)
|
||||||
|
{
|
||||||
|
fMinBase = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fMaxBase = fCenter + (a_fRadius / 255.0f);
|
||||||
|
if (fMaxBase > 1.0f)
|
||||||
|
{
|
||||||
|
fMaxBase = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
|
||||||
|
{
|
||||||
|
|
||||||
|
float fRangeMultiplier = roundf(fAlphaRange / fTableEntryRange);
|
||||||
|
|
||||||
|
float fMinMultiplier = fRangeMultiplier - a_fRadius;
|
||||||
|
if (fMinMultiplier < 1.0f)
|
||||||
|
{
|
||||||
|
fMinMultiplier = 1.0f;
|
||||||
|
}
|
||||||
|
else if (fMinMultiplier > 15.0f)
|
||||||
|
{
|
||||||
|
fMinMultiplier = 15.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fMaxMultiplier = fRangeMultiplier + a_fRadius;
|
||||||
|
if (fMaxMultiplier < 1.0f)
|
||||||
|
{
|
||||||
|
fMaxMultiplier = 1.0f;
|
||||||
|
}
|
||||||
|
else if (fMaxMultiplier > 15.0f)
|
||||||
|
{
|
||||||
|
fMaxMultiplier = 15.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
|
||||||
|
{
|
||||||
|
// find best selector for each pixel
|
||||||
|
unsigned int auiBestSelectors[PIXELS];
|
||||||
|
float afBestAlphaError[PIXELS];
|
||||||
|
float afBestDecodedAlphas[PIXELS];
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
float fBestPixelAlphaError = FLT_MAX;
|
||||||
|
for (unsigned int uiSelector = 0; uiSelector < ALPHA_SELECTORS; uiSelector++)
|
||||||
|
{
|
||||||
|
float fDecodedAlpha = DecodePixelAlpha(fBase, fMultiplier, uiTableEntry, uiSelector);
|
||||||
|
|
||||||
|
// border pixels (NAN) should have zero error
|
||||||
|
float fPixelDeltaAlpha = isnan(m_pafrgbaSource[uiPixel].fA) ?
|
||||||
|
0.0f :
|
||||||
|
fDecodedAlpha - m_pafrgbaSource[uiPixel].fA;
|
||||||
|
|
||||||
|
float fPixelAlphaError = fPixelDeltaAlpha * fPixelDeltaAlpha;
|
||||||
|
|
||||||
|
if (fPixelAlphaError < fBestPixelAlphaError)
|
||||||
|
{
|
||||||
|
fBestPixelAlphaError = fPixelAlphaError;
|
||||||
|
auiBestSelectors[uiPixel] = uiSelector;
|
||||||
|
afBestAlphaError[uiPixel] = fBestPixelAlphaError;
|
||||||
|
afBestDecodedAlphas[uiPixel] = fDecodedAlpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float fBlockError = 0.0f;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
fBlockError += afBestAlphaError[uiPixel];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fBlockError < m_fError)
|
||||||
|
{
|
||||||
|
m_fError = fBlockError;
|
||||||
|
|
||||||
|
m_fBase = fBase;
|
||||||
|
m_fMultiplier = fMultiplier;
|
||||||
|
m_uiModifierTableIndex = uiTableEntry;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_auiAlphaSelectors[uiPixel] = auiBestSelectors[uiPixel];
|
||||||
|
m_afDecodedAlphas[uiPixel] = afBestDecodedAlphas[uiPixel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// set the encoding bits based on encoding state
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8::SetEncodingBits(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// set the RGB8 portion
|
||||||
|
Block4x4Encoding_RGB8::SetEncodingBits();
|
||||||
|
|
||||||
|
// set the A8 portion
|
||||||
|
{
|
||||||
|
m_pencodingbitsA8->data.base = (unsigned char)roundf(255.0f * m_fBase);
|
||||||
|
m_pencodingbitsA8->data.table = m_uiModifierTableIndex;
|
||||||
|
m_pencodingbitsA8->data.multiplier = (unsigned char)roundf(m_fMultiplier);
|
||||||
|
|
||||||
|
unsigned long long int ulliSelectorBits = 0;
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||||
|
ulliSelectorBits |= ((unsigned long long int)m_auiAlphaSelectors[uiPixel]) << uiShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pencodingbitsA8->data.selectors0 = ulliSelectorBits >> 40;
|
||||||
|
m_pencodingbitsA8->data.selectors1 = ulliSelectorBits >> 32;
|
||||||
|
m_pencodingbitsA8->data.selectors2 = ulliSelectorBits >> 24;
|
||||||
|
m_pencodingbitsA8->data.selectors3 = ulliSelectorBits >> 16;
|
||||||
|
m_pencodingbitsA8->data.selectors4 = ulliSelectorBits >> 8;
|
||||||
|
m_pencodingbitsA8->data.selectors5 = ulliSelectorBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ####################################################################################################
|
||||||
|
// Block4x4Encoding_RGBA8_Opaque
|
||||||
|
// ####################################################################################################
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// perform a single encoding iteration
|
||||||
|
// replace the encoding if a better encoding was found
|
||||||
|
// subsequent iterations generally take longer for each iteration
|
||||||
|
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8_Opaque::PerformIteration(float a_fEffort)
|
||||||
|
{
|
||||||
|
assert(!m_boolDone);
|
||||||
|
|
||||||
|
if (m_uiEncodingIterations == 0)
|
||||||
|
{
|
||||||
|
m_fError = 0.0f;
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_afDecodedAlphas[uiPixel] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// set the encoding bits based on encoding state
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8_Opaque::SetEncodingBits(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// set the RGB8 portion
|
||||||
|
Block4x4Encoding_RGB8::SetEncodingBits();
|
||||||
|
|
||||||
|
// set the A8 portion
|
||||||
|
m_pencodingbitsA8->data.base = 255;
|
||||||
|
m_pencodingbitsA8->data.table = 15;
|
||||||
|
m_pencodingbitsA8->data.multiplier = 15;
|
||||||
|
m_pencodingbitsA8->data.selectors0 = 0xFF;
|
||||||
|
m_pencodingbitsA8->data.selectors1 = 0xFF;
|
||||||
|
m_pencodingbitsA8->data.selectors2 = 0xFF;
|
||||||
|
m_pencodingbitsA8->data.selectors3 = 0xFF;
|
||||||
|
m_pencodingbitsA8->data.selectors4 = 0xFF;
|
||||||
|
m_pencodingbitsA8->data.selectors5 = 0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ####################################################################################################
|
||||||
|
// Block4x4Encoding_RGBA8_Transparent
|
||||||
|
// ####################################################################################################
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// perform a single encoding iteration
|
||||||
|
// replace the encoding if a better encoding was found
|
||||||
|
// subsequent iterations generally take longer for each iteration
|
||||||
|
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8_Transparent::PerformIteration(float )
|
||||||
|
{
|
||||||
|
assert(!m_boolDone);
|
||||||
|
assert(m_uiEncodingIterations == 0);
|
||||||
|
|
||||||
|
m_mode = MODE_ETC1;
|
||||||
|
m_boolDiff = true;
|
||||||
|
m_boolFlip = false;
|
||||||
|
|
||||||
|
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||||
|
{
|
||||||
|
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
|
||||||
|
m_afDecodedAlphas[uiPixel] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fError = 0.0f;
|
||||||
|
|
||||||
|
m_boolDone = true;
|
||||||
|
m_uiEncodingIterations++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// set the encoding bits based on encoding state
|
||||||
|
//
|
||||||
|
void Block4x4Encoding_RGBA8_Transparent::SetEncodingBits(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
Block4x4Encoding_RGB8::SetEncodingBits();
|
||||||
|
|
||||||
|
// set the A8 portion
|
||||||
|
m_pencodingbitsA8->data.base = 0;
|
||||||
|
m_pencodingbitsA8->data.table = 0;
|
||||||
|
m_pencodingbitsA8->data.multiplier = 1;
|
||||||
|
m_pencodingbitsA8->data.selectors0 = 0;
|
||||||
|
m_pencodingbitsA8->data.selectors1 = 0;
|
||||||
|
m_pencodingbitsA8->data.selectors2 = 0;
|
||||||
|
m_pencodingbitsA8->data.selectors3 = 0;
|
||||||
|
m_pencodingbitsA8->data.selectors4 = 0;
|
||||||
|
m_pencodingbitsA8->data.selectors5 = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
}
|
121
thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
vendored
Normal file
121
thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
vendored
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4EncodingBits_A8;
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_RGBA8
|
||||||
|
// RGBA8 if not completely opaque or transparent
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_RGBA8 : public Block4x4Encoding_RGB8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Block4x4Encoding_RGBA8(void);
|
||||||
|
virtual ~Block4x4Encoding_RGBA8(void);
|
||||||
|
|
||||||
|
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||||
|
unsigned char *a_paucEncodingBits,
|
||||||
|
ColorFloatRGBA *a_pafrgbaSource,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
|
||||||
|
static const unsigned int ALPHA_SELECTOR_BITS = 3;
|
||||||
|
static const unsigned int ALPHA_SELECTORS = 1 << ALPHA_SELECTOR_BITS;
|
||||||
|
|
||||||
|
static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS];
|
||||||
|
|
||||||
|
void CalculateA8(float a_fRadius);
|
||||||
|
|
||||||
|
Block4x4EncodingBits_A8 *m_pencodingbitsA8; // A8 portion of Block4x4EncodingBits_RGBA8
|
||||||
|
|
||||||
|
float m_fBase;
|
||||||
|
float m_fMultiplier;
|
||||||
|
unsigned int m_uiModifierTableIndex;
|
||||||
|
unsigned int m_auiAlphaSelectors[PIXELS];
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
inline float DecodePixelAlpha(float a_fBase, float a_fMultiplier,
|
||||||
|
unsigned int a_uiTableIndex, unsigned int a_uiSelector)
|
||||||
|
{
|
||||||
|
float fPixelAlpha = a_fBase +
|
||||||
|
a_fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector];
|
||||||
|
if (fPixelAlpha < 0.0f)
|
||||||
|
{
|
||||||
|
fPixelAlpha = 0.0f;
|
||||||
|
}
|
||||||
|
else if (fPixelAlpha > 1.0f)
|
||||||
|
{
|
||||||
|
fPixelAlpha = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fPixelAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_RGBA8_Opaque
|
||||||
|
// RGBA8 if all pixels have alpha==1
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_RGBA8_Opaque : public Block4x4Encoding_RGBA8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ################################################################################
|
||||||
|
// Block4x4Encoding_RGBA8_Transparent
|
||||||
|
// RGBA8 if all pixels have alpha==0
|
||||||
|
// ################################################################################
|
||||||
|
|
||||||
|
class Block4x4Encoding_RGBA8_Transparent : public Block4x4Encoding_RGBA8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void PerformIteration(float a_fEffort);
|
||||||
|
|
||||||
|
virtual void SetEncodingBits(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
64
thirdparty/etc2comp/EtcColor.h
vendored
Normal file
64
thirdparty/etc2comp/EtcColor.h
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
inline float LogToLinear(float a_fLog)
|
||||||
|
{
|
||||||
|
static const float ALPHA = 0.055f;
|
||||||
|
static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
|
||||||
|
|
||||||
|
if (a_fLog <= 0.04045f)
|
||||||
|
{
|
||||||
|
return a_fLog / 12.92f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return powf((a_fLog + ALPHA) / ONE_PLUS_ALPHA, 2.4f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float LinearToLog(float &a_fLinear)
|
||||||
|
{
|
||||||
|
static const float ALPHA = 0.055f;
|
||||||
|
static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
|
||||||
|
|
||||||
|
if (a_fLinear <= 0.0031308f)
|
||||||
|
{
|
||||||
|
return 12.92f * a_fLinear;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ONE_PLUS_ALPHA * powf(a_fLinear, (1.0f/2.4f)) - ALPHA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ColorR8G8B8A8
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
unsigned char ucR;
|
||||||
|
unsigned char ucG;
|
||||||
|
unsigned char ucB;
|
||||||
|
unsigned char ucA;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
321
thirdparty/etc2comp/EtcColorFloatRGBA.h
vendored
Normal file
321
thirdparty/etc2comp/EtcColorFloatRGBA.h
vendored
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcColor.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
class ColorFloatRGBA
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ColorFloatRGBA(void)
|
||||||
|
{
|
||||||
|
fR = fG = fB = fA = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorFloatRGBA(float a_fR, float a_fG, float a_fB, float a_fA)
|
||||||
|
{
|
||||||
|
fR = a_fR;
|
||||||
|
fG = a_fG;
|
||||||
|
fB = a_fB;
|
||||||
|
fA = a_fA;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA operator+(ColorFloatRGBA& a_rfrgba)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
frgba.fR = fR + a_rfrgba.fR;
|
||||||
|
frgba.fG = fG + a_rfrgba.fG;
|
||||||
|
frgba.fB = fB + a_rfrgba.fB;
|
||||||
|
frgba.fA = fA + a_rfrgba.fA;
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA operator+(float a_f)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
frgba.fR = fR + a_f;
|
||||||
|
frgba.fG = fG + a_f;
|
||||||
|
frgba.fB = fB + a_f;
|
||||||
|
frgba.fA = fA;
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA operator-(float a_f)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
frgba.fR = fR - a_f;
|
||||||
|
frgba.fG = fG - a_f;
|
||||||
|
frgba.fB = fB - a_f;
|
||||||
|
frgba.fA = fA;
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA operator-(ColorFloatRGBA& a_rfrgba)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
frgba.fR = fR - a_rfrgba.fR;
|
||||||
|
frgba.fG = fG - a_rfrgba.fG;
|
||||||
|
frgba.fB = fB - a_rfrgba.fB;
|
||||||
|
frgba.fA = fA - a_rfrgba.fA;
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA operator*(float a_f)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
frgba.fR = fR * a_f;
|
||||||
|
frgba.fG = fG * a_f;
|
||||||
|
frgba.fB = fB * a_f;
|
||||||
|
frgba.fA = fA;
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA ScaleRGB(float a_f)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
frgba.fR = a_f * fR;
|
||||||
|
frgba.fG = a_f * fG;
|
||||||
|
frgba.fB = a_f * fB;
|
||||||
|
frgba.fA = fA;
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA RoundRGB(void)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
frgba.fR = roundf(fR);
|
||||||
|
frgba.fG = roundf(fG);
|
||||||
|
frgba.fB = roundf(fB);
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA ToLinear()
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgbaLinear;
|
||||||
|
frgbaLinear.fR = LogToLinear(fR);
|
||||||
|
frgbaLinear.fG = LogToLinear(fG);
|
||||||
|
frgbaLinear.fB = LogToLinear(fB);
|
||||||
|
frgbaLinear.fA = fA;
|
||||||
|
|
||||||
|
return frgbaLinear;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA ToLog(void)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgbaLog;
|
||||||
|
frgbaLog.fR = LinearToLog(fR);
|
||||||
|
frgbaLog.fG = LinearToLog(fG);
|
||||||
|
frgbaLog.fB = LinearToLog(fB);
|
||||||
|
frgbaLog.fA = fA;
|
||||||
|
|
||||||
|
return frgbaLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static ColorFloatRGBA ConvertFromRGBA8(unsigned char a_ucR,
|
||||||
|
unsigned char a_ucG, unsigned char a_ucB, unsigned char a_ucA)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
|
||||||
|
frgba.fR = (float)a_ucR / 255.0f;
|
||||||
|
frgba.fG = (float)a_ucG / 255.0f;
|
||||||
|
frgba.fB = (float)a_ucB / 255.0f;
|
||||||
|
frgba.fA = (float)a_ucA / 255.0f;
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static ColorFloatRGBA ConvertFromRGB4(unsigned char a_ucR4,
|
||||||
|
unsigned char a_ucG4,
|
||||||
|
unsigned char a_ucB4)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
|
||||||
|
unsigned char ucR8 = (unsigned char)((a_ucR4 << 4) + a_ucR4);
|
||||||
|
unsigned char ucG8 = (unsigned char)((a_ucG4 << 4) + a_ucG4);
|
||||||
|
unsigned char ucB8 = (unsigned char)((a_ucB4 << 4) + a_ucB4);
|
||||||
|
|
||||||
|
frgba.fR = (float)ucR8 / 255.0f;
|
||||||
|
frgba.fG = (float)ucG8 / 255.0f;
|
||||||
|
frgba.fB = (float)ucB8 / 255.0f;
|
||||||
|
frgba.fA = 1.0f;
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static ColorFloatRGBA ConvertFromRGB5(unsigned char a_ucR5,
|
||||||
|
unsigned char a_ucG5,
|
||||||
|
unsigned char a_ucB5)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
|
||||||
|
unsigned char ucR8 = (unsigned char)((a_ucR5 << 3) + (a_ucR5 >> 2));
|
||||||
|
unsigned char ucG8 = (unsigned char)((a_ucG5 << 3) + (a_ucG5 >> 2));
|
||||||
|
unsigned char ucB8 = (unsigned char)((a_ucB5 << 3) + (a_ucB5 >> 2));
|
||||||
|
|
||||||
|
frgba.fR = (float)ucR8 / 255.0f;
|
||||||
|
frgba.fG = (float)ucG8 / 255.0f;
|
||||||
|
frgba.fB = (float)ucB8 / 255.0f;
|
||||||
|
frgba.fA = 1.0f;
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static ColorFloatRGBA ConvertFromR6G7B6(unsigned char a_ucR6,
|
||||||
|
unsigned char a_ucG7,
|
||||||
|
unsigned char a_ucB6)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba;
|
||||||
|
|
||||||
|
unsigned char ucR8 = (unsigned char)((a_ucR6 << 2) + (a_ucR6 >> 4));
|
||||||
|
unsigned char ucG8 = (unsigned char)((a_ucG7 << 1) + (a_ucG7 >> 6));
|
||||||
|
unsigned char ucB8 = (unsigned char)((a_ucB6 << 2) + (a_ucB6 >> 4));
|
||||||
|
|
||||||
|
frgba.fR = (float)ucR8 / 255.0f;
|
||||||
|
frgba.fG = (float)ucG8 / 255.0f;
|
||||||
|
frgba.fB = (float)ucB8 / 255.0f;
|
||||||
|
frgba.fA = 1.0f;
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quantize to 4 bits, expand to 8 bits
|
||||||
|
inline ColorFloatRGBA QuantizeR4G4B4(void) const
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba = *this;
|
||||||
|
|
||||||
|
// quantize to 4 bits
|
||||||
|
frgba = frgba.ClampRGB().ScaleRGB(15.0f).RoundRGB();
|
||||||
|
unsigned int uiR4 = (unsigned int)frgba.fR;
|
||||||
|
unsigned int uiG4 = (unsigned int)frgba.fG;
|
||||||
|
unsigned int uiB4 = (unsigned int)frgba.fB;
|
||||||
|
|
||||||
|
// expand to 8 bits
|
||||||
|
frgba.fR = (float) ((uiR4 << 4) + uiR4);
|
||||||
|
frgba.fG = (float) ((uiG4 << 4) + uiG4);
|
||||||
|
frgba.fB = (float) ((uiB4 << 4) + uiB4);
|
||||||
|
|
||||||
|
frgba = frgba.ScaleRGB(1.0f/255.0f);
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quantize to 5 bits, expand to 8 bits
|
||||||
|
inline ColorFloatRGBA QuantizeR5G5B5(void) const
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba = *this;
|
||||||
|
|
||||||
|
// quantize to 5 bits
|
||||||
|
frgba = frgba.ClampRGB().ScaleRGB(31.0f).RoundRGB();
|
||||||
|
unsigned int uiR5 = (unsigned int)frgba.fR;
|
||||||
|
unsigned int uiG5 = (unsigned int)frgba.fG;
|
||||||
|
unsigned int uiB5 = (unsigned int)frgba.fB;
|
||||||
|
|
||||||
|
// expand to 8 bits
|
||||||
|
frgba.fR = (float)((uiR5 << 3) + (uiR5 >> 2));
|
||||||
|
frgba.fG = (float)((uiG5 << 3) + (uiG5 >> 2));
|
||||||
|
frgba.fB = (float)((uiB5 << 3) + (uiB5 >> 2));
|
||||||
|
|
||||||
|
frgba = frgba.ScaleRGB(1.0f / 255.0f);
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quantize to 6/7/6 bits, expand to 8 bits
|
||||||
|
inline ColorFloatRGBA QuantizeR6G7B6(void) const
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba = *this;
|
||||||
|
|
||||||
|
// quantize to 6/7/6 bits
|
||||||
|
ColorFloatRGBA frgba6 = frgba.ClampRGB().ScaleRGB(63.0f).RoundRGB();
|
||||||
|
ColorFloatRGBA frgba7 = frgba.ClampRGB().ScaleRGB(127.0f).RoundRGB();
|
||||||
|
unsigned int uiR6 = (unsigned int)frgba6.fR;
|
||||||
|
unsigned int uiG7 = (unsigned int)frgba7.fG;
|
||||||
|
unsigned int uiB6 = (unsigned int)frgba6.fB;
|
||||||
|
|
||||||
|
// expand to 8 bits
|
||||||
|
frgba.fR = (float)((uiR6 << 2) + (uiR6 >> 4));
|
||||||
|
frgba.fG = (float)((uiG7 << 1) + (uiG7 >> 6));
|
||||||
|
frgba.fB = (float)((uiB6 << 2) + (uiB6 >> 4));
|
||||||
|
|
||||||
|
frgba = frgba.ScaleRGB(1.0f / 255.0f);
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA ClampRGB(void)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba = *this;
|
||||||
|
if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
|
||||||
|
if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
|
||||||
|
if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
|
||||||
|
if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
|
||||||
|
if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
|
||||||
|
if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorFloatRGBA ClampRGBA(void)
|
||||||
|
{
|
||||||
|
ColorFloatRGBA frgba = *this;
|
||||||
|
if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
|
||||||
|
if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
|
||||||
|
if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
|
||||||
|
if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
|
||||||
|
if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
|
||||||
|
if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
|
||||||
|
if (frgba.fA < 0.0f) { frgba.fA = 0.0f; }
|
||||||
|
if (frgba.fA > 1.0f) { frgba.fA = 1.0f; }
|
||||||
|
|
||||||
|
return frgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int IntRed(float a_fScale)
|
||||||
|
{
|
||||||
|
return (int)roundf(fR * a_fScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int IntGreen(float a_fScale)
|
||||||
|
{
|
||||||
|
return (int)roundf(fG * a_fScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int IntBlue(float a_fScale)
|
||||||
|
{
|
||||||
|
return (int)roundf(fB * a_fScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int IntAlpha(float a_fScale)
|
||||||
|
{
|
||||||
|
return (int)roundf(fA * a_fScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fR, fG, fB, fA;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
67
thirdparty/etc2comp/EtcConfig.h
vendored
Normal file
67
thirdparty/etc2comp/EtcConfig.h
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define ETC_WINDOWS (1)
|
||||||
|
#else
|
||||||
|
#define ETC_WINDOWS (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
#define ETC_OSX (1)
|
||||||
|
#else
|
||||||
|
#define ETC_OSX (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __unix__
|
||||||
|
#define ETC_UNIX (1)
|
||||||
|
#else
|
||||||
|
#define ETC_UNIX (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// short names for common types
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int8_t i8;
|
||||||
|
typedef int16_t i16;
|
||||||
|
typedef int32_t i32;
|
||||||
|
typedef int64_t i64;
|
||||||
|
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
|
||||||
|
// Keep asserts enabled in release builds during development
|
||||||
|
#undef NDEBUG
|
||||||
|
|
||||||
|
// 0=disable. stb_image can be used if you need to compress
|
||||||
|
//other image formats like jpg
|
||||||
|
#define USE_STB_IMAGE_LOAD 0
|
||||||
|
|
||||||
|
#if ETC_WINDOWS
|
||||||
|
#include <sdkddkver.h>
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS (1)
|
||||||
|
#include <tchar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
173
thirdparty/etc2comp/EtcDifferentialTrys.cpp
vendored
Normal file
173
thirdparty/etc2comp/EtcDifferentialTrys.cpp
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcDifferentialTrys.cpp
|
||||||
|
|
||||||
|
Gathers the results of the various encoding trys for both halves of a 4x4 block for Differential mode
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcDifferentialTrys.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// construct a list of trys (encoding attempts)
|
||||||
|
//
|
||||||
|
// a_frgbaColor1 is the basecolor for the first half
|
||||||
|
// a_frgbaColor2 is the basecolor for the second half
|
||||||
|
// a_pauiPixelMapping1 is the pixel order for the first half
|
||||||
|
// a_pauiPixelMapping2 is the pixel order for the second half
|
||||||
|
// a_uiRadius is the amount to vary the base colors
|
||||||
|
//
|
||||||
|
DifferentialTrys::DifferentialTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
|
||||||
|
const unsigned int *a_pauiPixelMapping1,
|
||||||
|
const unsigned int *a_pauiPixelMapping2,
|
||||||
|
unsigned int a_uiRadius,
|
||||||
|
int a_iGrayOffset1, int a_iGrayOffset2)
|
||||||
|
{
|
||||||
|
assert(a_uiRadius <= MAX_RADIUS);
|
||||||
|
|
||||||
|
m_boolSeverelyBentColors = false;
|
||||||
|
|
||||||
|
ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR5G5B5();
|
||||||
|
ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR5G5B5();
|
||||||
|
|
||||||
|
// quantize base colors
|
||||||
|
// ensure that trys with a_uiRadius don't overflow
|
||||||
|
int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(31.0f)+a_iGrayOffset1, a_uiRadius);
|
||||||
|
int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(31.0f) + a_iGrayOffset1, a_uiRadius);
|
||||||
|
int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(31.0f) + a_iGrayOffset1, a_uiRadius);
|
||||||
|
int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(31.0f) + a_iGrayOffset2, a_uiRadius);
|
||||||
|
int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(31.0f) + a_iGrayOffset2, a_uiRadius);
|
||||||
|
int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(31.0f) + a_iGrayOffset2, a_uiRadius);
|
||||||
|
|
||||||
|
int iDeltaRed = iRed2 - iRed1;
|
||||||
|
int iDeltaGreen = iGreen2 - iGreen1;
|
||||||
|
int iDeltaBlue = iBlue2 - iBlue1;
|
||||||
|
|
||||||
|
// make sure components are within range
|
||||||
|
{
|
||||||
|
if (iDeltaRed > 3)
|
||||||
|
{
|
||||||
|
if (iDeltaRed > 7)
|
||||||
|
{
|
||||||
|
m_boolSeverelyBentColors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iRed1 += (iDeltaRed - 3) / 2;
|
||||||
|
iRed2 = iRed1 + 3;
|
||||||
|
iDeltaRed = 3;
|
||||||
|
}
|
||||||
|
else if (iDeltaRed < -4)
|
||||||
|
{
|
||||||
|
if (iDeltaRed < -8)
|
||||||
|
{
|
||||||
|
m_boolSeverelyBentColors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iRed1 += (iDeltaRed + 4) / 2;
|
||||||
|
iRed2 = iRed1 - 4;
|
||||||
|
iDeltaRed = -4;
|
||||||
|
}
|
||||||
|
assert(iRed1 >= (signed)(0 + a_uiRadius) && iRed1 <= (signed)(31 - a_uiRadius));
|
||||||
|
assert(iRed2 >= (signed)(0 + a_uiRadius) && iRed2 <= (signed)(31 - a_uiRadius));
|
||||||
|
assert(iDeltaRed >= -4 && iDeltaRed <= 3);
|
||||||
|
|
||||||
|
if (iDeltaGreen > 3)
|
||||||
|
{
|
||||||
|
if (iDeltaGreen > 7)
|
||||||
|
{
|
||||||
|
m_boolSeverelyBentColors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iGreen1 += (iDeltaGreen - 3) / 2;
|
||||||
|
iGreen2 = iGreen1 + 3;
|
||||||
|
iDeltaGreen = 3;
|
||||||
|
}
|
||||||
|
else if (iDeltaGreen < -4)
|
||||||
|
{
|
||||||
|
if (iDeltaGreen < -8)
|
||||||
|
{
|
||||||
|
m_boolSeverelyBentColors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iGreen1 += (iDeltaGreen + 4) / 2;
|
||||||
|
iGreen2 = iGreen1 - 4;
|
||||||
|
iDeltaGreen = -4;
|
||||||
|
}
|
||||||
|
assert(iGreen1 >= (signed)(0 + a_uiRadius) && iGreen1 <= (signed)(31 - a_uiRadius));
|
||||||
|
assert(iGreen2 >= (signed)(0 + a_uiRadius) && iGreen2 <= (signed)(31 - a_uiRadius));
|
||||||
|
assert(iDeltaGreen >= -4 && iDeltaGreen <= 3);
|
||||||
|
|
||||||
|
if (iDeltaBlue > 3)
|
||||||
|
{
|
||||||
|
if (iDeltaBlue > 7)
|
||||||
|
{
|
||||||
|
m_boolSeverelyBentColors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iBlue1 += (iDeltaBlue - 3) / 2;
|
||||||
|
iBlue2 = iBlue1 + 3;
|
||||||
|
iDeltaBlue = 3;
|
||||||
|
}
|
||||||
|
else if (iDeltaBlue < -4)
|
||||||
|
{
|
||||||
|
if (iDeltaBlue < -8)
|
||||||
|
{
|
||||||
|
m_boolSeverelyBentColors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iBlue1 += (iDeltaBlue + 4) / 2;
|
||||||
|
iBlue2 = iBlue1 - 4;
|
||||||
|
iDeltaBlue = -4;
|
||||||
|
}
|
||||||
|
assert(iBlue1 >= (signed)(0+a_uiRadius) && iBlue1 <= (signed)(31 - a_uiRadius));
|
||||||
|
assert(iBlue2 >= (signed)(0 + a_uiRadius) && iBlue2 <= (signed)(31 - a_uiRadius));
|
||||||
|
assert(iDeltaBlue >= -4 && iDeltaBlue <= 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
|
||||||
|
m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
void DifferentialTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||||
|
const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_iRed = a_iRed;
|
||||||
|
m_iGreen = a_iGreen;
|
||||||
|
m_iBlue = a_iBlue;
|
||||||
|
|
||||||
|
m_pauiPixelMapping = a_pauiPixelMapping;
|
||||||
|
m_uiRadius = a_uiRadius;
|
||||||
|
|
||||||
|
m_uiTrys = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
97
thirdparty/etc2comp/EtcDifferentialTrys.h
vendored
Normal file
97
thirdparty/etc2comp/EtcDifferentialTrys.h
vendored
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcColorFloatRGBA.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
class DifferentialTrys
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int MAX_RADIUS = 2;
|
||||||
|
|
||||||
|
DifferentialTrys(ColorFloatRGBA a_frgbaColor1,
|
||||||
|
ColorFloatRGBA a_frgbaColor2,
|
||||||
|
const unsigned int *a_pauiPixelMapping1,
|
||||||
|
const unsigned int *a_pauiPixelMapping2,
|
||||||
|
unsigned int a_uiRadius,
|
||||||
|
int a_iGrayOffset1, int a_iGrayOffset2);
|
||||||
|
|
||||||
|
inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
|
||||||
|
{
|
||||||
|
if (a_i < (0+ a_iDistance))
|
||||||
|
{
|
||||||
|
return (0 + a_iDistance);
|
||||||
|
}
|
||||||
|
else if (a_i > (31- a_iDistance))
|
||||||
|
{
|
||||||
|
return (31 - a_iDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return a_i;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Try
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
static const unsigned int SELECTORS = 8; // per half
|
||||||
|
|
||||||
|
int m_iRed;
|
||||||
|
int m_iGreen;
|
||||||
|
int m_iBlue;
|
||||||
|
unsigned int m_uiCW;
|
||||||
|
unsigned int m_auiSelectors[SELECTORS];
|
||||||
|
float m_fError;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Half
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int MAX_TRYS = 125;
|
||||||
|
|
||||||
|
void Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||||
|
const unsigned int *a_pauiPixelMapping,
|
||||||
|
unsigned int a_uiRadius);
|
||||||
|
|
||||||
|
// center of trys
|
||||||
|
int m_iRed;
|
||||||
|
int m_iGreen;
|
||||||
|
int m_iBlue;
|
||||||
|
|
||||||
|
const unsigned int *m_pauiPixelMapping;
|
||||||
|
unsigned int m_uiRadius;
|
||||||
|
|
||||||
|
unsigned int m_uiTrys;
|
||||||
|
Try m_atry[MAX_TRYS];
|
||||||
|
|
||||||
|
Try *m_ptryBest;
|
||||||
|
};
|
||||||
|
|
||||||
|
Half m_half1;
|
||||||
|
Half m_half2;
|
||||||
|
|
||||||
|
bool m_boolSeverelyBentColors;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
54
thirdparty/etc2comp/EtcErrorMetric.h
vendored
Normal file
54
thirdparty/etc2comp/EtcErrorMetric.h
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
enum ErrorMetric
|
||||||
|
{
|
||||||
|
RGBA,
|
||||||
|
RGBX,
|
||||||
|
REC709,
|
||||||
|
NUMERIC,
|
||||||
|
NORMALXYZ,
|
||||||
|
//
|
||||||
|
ERROR_METRICS,
|
||||||
|
//
|
||||||
|
BT709 = REC709
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char *ErrorMetricToString(ErrorMetric errorMetric)
|
||||||
|
{
|
||||||
|
switch (errorMetric)
|
||||||
|
{
|
||||||
|
case RGBA:
|
||||||
|
return "RGBA";
|
||||||
|
case RGBX:
|
||||||
|
return "RGBX";
|
||||||
|
case REC709:
|
||||||
|
return "REC709";
|
||||||
|
case NUMERIC:
|
||||||
|
return "NUMERIC";
|
||||||
|
case NORMALXYZ:
|
||||||
|
return "NORMALXYZ";
|
||||||
|
case ERROR_METRICS:
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Etc
|
390
thirdparty/etc2comp/EtcFile.cpp
vendored
Normal file
390
thirdparty/etc2comp/EtcFile.cpp
vendored
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "EtcFile.h"
|
||||||
|
|
||||||
|
#include "EtcFileHeader.h"
|
||||||
|
#include "EtcColor.h"
|
||||||
|
#include "Etc.h"
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
using namespace Etc;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
|
||||||
|
unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes,
|
||||||
|
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
|
||||||
|
unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight)
|
||||||
|
{
|
||||||
|
if (a_pstrFilename == nullptr)
|
||||||
|
{
|
||||||
|
m_pstrFilename = const_cast<char *>("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
|
||||||
|
strcpy(m_pstrFilename, a_pstrFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fileformat = a_fileformat;
|
||||||
|
if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
|
||||||
|
{
|
||||||
|
// ***** TODO: add this later *****
|
||||||
|
m_fileformat = Format::KTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_imageformat = a_imageformat;
|
||||||
|
|
||||||
|
m_uiNumMipmaps = 1;
|
||||||
|
m_pMipmapImages = new RawImage[m_uiNumMipmaps];
|
||||||
|
m_pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(a_paucEncodingBits, [](unsigned char *p) { delete[] p; } );
|
||||||
|
m_pMipmapImages[0].uiEncodingBitsBytes = a_uiEncodingBitsBytes;
|
||||||
|
m_pMipmapImages[0].uiExtendedWidth = a_uiExtendedWidth;
|
||||||
|
m_pMipmapImages[0].uiExtendedHeight = a_uiExtendedHeight;
|
||||||
|
|
||||||
|
m_uiSourceWidth = a_uiSourceWidth;
|
||||||
|
m_uiSourceHeight = a_uiSourceHeight;
|
||||||
|
|
||||||
|
switch (m_fileformat)
|
||||||
|
{
|
||||||
|
case Format::PKM:
|
||||||
|
m_pheader = new FileHeader_Pkm(this);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Format::KTX:
|
||||||
|
m_pheader = new FileHeader_Ktx(this);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
|
||||||
|
unsigned int a_uiNumMipmaps, RawImage *a_pMipmapImages,
|
||||||
|
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight)
|
||||||
|
{
|
||||||
|
if (a_pstrFilename == nullptr)
|
||||||
|
{
|
||||||
|
m_pstrFilename = const_cast<char *>("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
|
||||||
|
strcpy(m_pstrFilename, a_pstrFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fileformat = a_fileformat;
|
||||||
|
if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
|
||||||
|
{
|
||||||
|
// ***** TODO: add this later *****
|
||||||
|
m_fileformat = Format::KTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_imageformat = a_imageformat;
|
||||||
|
|
||||||
|
m_uiNumMipmaps = a_uiNumMipmaps;
|
||||||
|
m_pMipmapImages = new RawImage[m_uiNumMipmaps];
|
||||||
|
|
||||||
|
for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
|
||||||
|
{
|
||||||
|
m_pMipmapImages[mip] = a_pMipmapImages[mip];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_uiSourceWidth = a_uiSourceWidth;
|
||||||
|
m_uiSourceHeight = a_uiSourceHeight;
|
||||||
|
|
||||||
|
switch (m_fileformat)
|
||||||
|
{
|
||||||
|
case Format::PKM:
|
||||||
|
m_pheader = new FileHeader_Pkm(this);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Format::KTX:
|
||||||
|
m_pheader = new FileHeader_Ktx(this);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
File::File(const char *a_pstrFilename, Format a_fileformat)
|
||||||
|
{
|
||||||
|
if (a_pstrFilename == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
|
||||||
|
strcpy(m_pstrFilename, a_pstrFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fileformat = a_fileformat;
|
||||||
|
if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
|
||||||
|
{
|
||||||
|
// ***** TODO: add this later *****
|
||||||
|
m_fileformat = Format::KTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *pfile = fopen(m_pstrFilename, "rb");
|
||||||
|
if (pfile == nullptr)
|
||||||
|
{
|
||||||
|
printf("ERROR: Couldn't open %s", m_pstrFilename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fseek(pfile, 0, SEEK_END);
|
||||||
|
unsigned int fileSize = ftell(pfile);
|
||||||
|
fseek(pfile, 0, SEEK_SET);
|
||||||
|
size_t szResult;
|
||||||
|
|
||||||
|
m_pheader = new FileHeader_Ktx(this);
|
||||||
|
szResult = fread( ((FileHeader_Ktx*)m_pheader)->GetData(), 1, sizeof(FileHeader_Ktx::Data), pfile);
|
||||||
|
assert(szResult > 0);
|
||||||
|
|
||||||
|
m_uiNumMipmaps = 1;
|
||||||
|
m_pMipmapImages = new RawImage[m_uiNumMipmaps];
|
||||||
|
|
||||||
|
if (((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData > 0)
|
||||||
|
fseek(pfile, ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData, SEEK_CUR);
|
||||||
|
szResult = fread(&m_pMipmapImages->uiEncodingBitsBytes, 1, sizeof(unsigned int), pfile);
|
||||||
|
assert(szResult > 0);
|
||||||
|
|
||||||
|
m_pMipmapImages->paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[m_pMipmapImages->uiEncodingBitsBytes], [](unsigned char *p) { delete[] p; } );
|
||||||
|
assert(ftell(pfile) + m_pMipmapImages->uiEncodingBitsBytes <= fileSize);
|
||||||
|
szResult = fread(m_pMipmapImages->paucEncodingBits.get(), 1, m_pMipmapImages->uiEncodingBitsBytes, pfile);
|
||||||
|
assert(szResult == m_pMipmapImages->uiEncodingBitsBytes);
|
||||||
|
|
||||||
|
uint32_t uiInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlInternalFormat;
|
||||||
|
uint32_t uiBaseInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlBaseInternalFormat;
|
||||||
|
|
||||||
|
if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC1_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC1_RGB8)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::ETC1;
|
||||||
|
}
|
||||||
|
else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::RGB8;
|
||||||
|
}
|
||||||
|
else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8A1 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8A1)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::RGB8A1;
|
||||||
|
}
|
||||||
|
else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGBA8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGBA8)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::RGBA8;
|
||||||
|
}
|
||||||
|
else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::R11;
|
||||||
|
}
|
||||||
|
else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::SIGNED_R11;
|
||||||
|
}
|
||||||
|
else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::RG11;
|
||||||
|
}
|
||||||
|
else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::SIGNED_RG11;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_imageformat = Image::Format::UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_uiSourceWidth = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelWidth;
|
||||||
|
m_uiSourceHeight = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelHeight;
|
||||||
|
m_pMipmapImages->uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
|
||||||
|
m_pMipmapImages->uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
|
||||||
|
|
||||||
|
unsigned int uiBlocks = m_pMipmapImages->uiExtendedWidth * m_pMipmapImages->uiExtendedHeight / 16;
|
||||||
|
Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
|
||||||
|
unsigned int expectedbytes = uiBlocks * Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
|
||||||
|
assert(expectedbytes == m_pMipmapImages->uiEncodingBitsBytes);
|
||||||
|
|
||||||
|
fclose(pfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
File::~File()
|
||||||
|
{
|
||||||
|
if (m_pMipmapImages != nullptr)
|
||||||
|
{
|
||||||
|
delete [] m_pMipmapImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_pstrFilename != nullptr)
|
||||||
|
{
|
||||||
|
delete[] m_pstrFilename;
|
||||||
|
m_pstrFilename = nullptr;
|
||||||
|
}
|
||||||
|
if (m_pheader != nullptr)
|
||||||
|
{
|
||||||
|
delete m_pheader;
|
||||||
|
m_pheader = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::UseSingleBlock(int a_iPixelX, int a_iPixelY)
|
||||||
|
{
|
||||||
|
if (a_iPixelX <= -1 || a_iPixelY <= -1)
|
||||||
|
return;
|
||||||
|
if (a_iPixelX >(int) m_uiSourceWidth)
|
||||||
|
{
|
||||||
|
//if we are using a ktx thats the size of a single block or less
|
||||||
|
//then make sure we use the 4x4 image as the single block
|
||||||
|
if (m_uiSourceWidth <= 4)
|
||||||
|
{
|
||||||
|
a_iPixelX = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("blockAtHV: H coordinate out of range, capped to image width\n");
|
||||||
|
a_iPixelX = m_uiSourceWidth - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a_iPixelY >(int) m_uiSourceHeight)
|
||||||
|
{
|
||||||
|
//if we are using a ktx thats the size of a single block or less
|
||||||
|
//then make sure we use the 4x4 image as the single block
|
||||||
|
if (m_uiSourceHeight <= 4)
|
||||||
|
{
|
||||||
|
a_iPixelY= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("blockAtHV: V coordinate out of range, capped to image height\n");
|
||||||
|
a_iPixelY = m_uiSourceHeight - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int origWidth = m_uiSourceWidth;
|
||||||
|
unsigned int origHeight = m_uiSourceHeight;
|
||||||
|
|
||||||
|
m_uiSourceWidth = 4;
|
||||||
|
m_uiSourceHeight = 4;
|
||||||
|
|
||||||
|
Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
|
||||||
|
unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
|
||||||
|
|
||||||
|
int numMipmaps = 1;
|
||||||
|
RawImage* pMipmapImages = new RawImage[numMipmaps];
|
||||||
|
pMipmapImages[0].uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
|
||||||
|
pMipmapImages[0].uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
|
||||||
|
pMipmapImages[0].uiEncodingBitsBytes = 0;
|
||||||
|
pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[uiEncodingBitsBytesPerBlock], [](unsigned char *p) { delete[] p; });
|
||||||
|
|
||||||
|
//block position in pixels
|
||||||
|
// remove the bottom 2 bits to get the block coordinates
|
||||||
|
unsigned int iBlockPosX = (a_iPixelX & 0xFFFFFFFC);
|
||||||
|
unsigned int iBlockPosY = (a_iPixelY & 0xFFFFFFFC);
|
||||||
|
|
||||||
|
int numXBlocks = (origWidth / 4);
|
||||||
|
int numYBlocks = (origHeight / 4);
|
||||||
|
|
||||||
|
|
||||||
|
// block location
|
||||||
|
//int iBlockX = (a_iPixelX % 4) == 0 ? a_iPixelX / 4.0f : (a_iPixelX / 4) + 1;
|
||||||
|
//int iBlockY = (a_iPixelY % 4) == 0 ? a_iPixelY / 4.0f : (a_iPixelY / 4) + 1;
|
||||||
|
//m_paucEncodingBits += ((iBlockY * numXBlocks) + iBlockX) * uiEncodingBitsBytesPerBlock;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int num = numXBlocks*numYBlocks;
|
||||||
|
unsigned int uiH = 0, uiV = 0;
|
||||||
|
unsigned char* pEncodingBits = m_pMipmapImages[0].paucEncodingBits.get();
|
||||||
|
for (unsigned int uiBlock = 0; uiBlock < num; uiBlock++)
|
||||||
|
{
|
||||||
|
if (uiH == iBlockPosX && uiV == iBlockPosY)
|
||||||
|
{
|
||||||
|
memcpy(pMipmapImages[0].paucEncodingBits.get(),pEncodingBits, uiEncodingBitsBytesPerBlock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pEncodingBits += uiEncodingBitsBytesPerBlock;
|
||||||
|
uiH += 4;
|
||||||
|
|
||||||
|
if (uiH >= origWidth)
|
||||||
|
{
|
||||||
|
uiH = 0;
|
||||||
|
uiV += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] m_pMipmapImages;
|
||||||
|
m_pMipmapImages = pMipmapImages;
|
||||||
|
}
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
void File::Write()
|
||||||
|
{
|
||||||
|
|
||||||
|
FILE *pfile = fopen(m_pstrFilename, "wb");
|
||||||
|
if (pfile == nullptr)
|
||||||
|
{
|
||||||
|
printf("Error: couldn't open Etc file (%s)\n", m_pstrFilename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pheader->Write(pfile);
|
||||||
|
|
||||||
|
for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
|
||||||
|
{
|
||||||
|
if(m_fileformat == Format::KTX)
|
||||||
|
{
|
||||||
|
// Write u32 image size
|
||||||
|
uint32_t u32ImageSize = m_pMipmapImages[mip].uiEncodingBitsBytes;
|
||||||
|
uint32_t szBytesWritten = fwrite(&u32ImageSize, 1, sizeof(u32ImageSize), pfile);
|
||||||
|
assert(szBytesWritten == sizeof(u32ImageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int iResult = (int)fwrite(m_pMipmapImages[mip].paucEncodingBits.get(), 1, m_pMipmapImages[mip].uiEncodingBitsBytes, pfile);
|
||||||
|
if (iResult != m_pMipmapImages[mip].uiEncodingBitsBytes)
|
||||||
|
{
|
||||||
|
printf("Error: couldn't write Etc file (%s)\n", m_pstrFilename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(pfile);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
136
thirdparty/etc2comp/EtcFile.h
vendored
Normal file
136
thirdparty/etc2comp/EtcFile.h
vendored
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcColorFloatRGBA.h"
|
||||||
|
#include "EtcImage.h"
|
||||||
|
#include "Etc.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class FileHeader;
|
||||||
|
class SourceImage;
|
||||||
|
|
||||||
|
class File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum class Format
|
||||||
|
{
|
||||||
|
INFER_FROM_FILE_EXTENSION,
|
||||||
|
PKM,
|
||||||
|
KTX,
|
||||||
|
};
|
||||||
|
|
||||||
|
File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
|
||||||
|
unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes,
|
||||||
|
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
|
||||||
|
unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight);
|
||||||
|
|
||||||
|
File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
|
||||||
|
unsigned int a_uiNumMipmaps, RawImage *pMipmapImages,
|
||||||
|
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight );
|
||||||
|
|
||||||
|
File(const char *a_pstrFilename, Format a_fileformat);
|
||||||
|
~File();
|
||||||
|
const char *GetFilename(void) { return m_pstrFilename; }
|
||||||
|
|
||||||
|
void Read(const char *a_pstrFilename);
|
||||||
|
void Write(void);
|
||||||
|
|
||||||
|
inline unsigned int GetSourceWidth(void)
|
||||||
|
{
|
||||||
|
return m_uiSourceWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetSourceHeight(void)
|
||||||
|
{
|
||||||
|
return m_uiSourceHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetExtendedWidth(unsigned int mipmapIndex = 0)
|
||||||
|
{
|
||||||
|
if (mipmapIndex < m_uiNumMipmaps)
|
||||||
|
{
|
||||||
|
return m_pMipmapImages[mipmapIndex].uiExtendedWidth;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetExtendedHeight(unsigned int mipmapIndex = 0)
|
||||||
|
{
|
||||||
|
if (mipmapIndex < m_uiNumMipmaps)
|
||||||
|
{
|
||||||
|
return m_pMipmapImages[mipmapIndex].uiExtendedHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Image::Format GetImageFormat()
|
||||||
|
{
|
||||||
|
return m_imageformat;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetEncodingBitsBytes(unsigned int mipmapIndex = 0)
|
||||||
|
{
|
||||||
|
if (mipmapIndex < m_uiNumMipmaps)
|
||||||
|
{
|
||||||
|
return m_pMipmapImages[mipmapIndex].uiEncodingBitsBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned char* GetEncodingBits(unsigned int mipmapIndex = 0)
|
||||||
|
{
|
||||||
|
if( mipmapIndex < m_uiNumMipmaps)
|
||||||
|
{
|
||||||
|
return m_pMipmapImages[mipmapIndex].paucEncodingBits.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetNumMipmaps()
|
||||||
|
{
|
||||||
|
return m_uiNumMipmaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UseSingleBlock(int a_iPixelX = -1, int a_iPixelY = -1);
|
||||||
|
private:
|
||||||
|
|
||||||
|
char *m_pstrFilename; // includes directory path and file extension
|
||||||
|
Format m_fileformat;
|
||||||
|
Image::Format m_imageformat;
|
||||||
|
FileHeader *m_pheader;
|
||||||
|
unsigned int m_uiNumMipmaps;
|
||||||
|
RawImage* m_pMipmapImages;
|
||||||
|
unsigned int m_uiSourceWidth;
|
||||||
|
unsigned int m_uiSourceHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
185
thirdparty/etc2comp/EtcFileHeader.cpp
vendored
Normal file
185
thirdparty/etc2comp/EtcFileHeader.cpp
vendored
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcFileHeader.h"
|
||||||
|
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
FileHeader_Pkm::FileHeader_Pkm(File *a_pfile)
|
||||||
|
{
|
||||||
|
m_pfile = a_pfile;
|
||||||
|
|
||||||
|
static const char s_acMagicNumberData[4] = { 'P', 'K', 'M', ' ' };
|
||||||
|
static const char s_acVersionData[2] = { '1', '0' };
|
||||||
|
|
||||||
|
for (unsigned int ui = 0; ui < sizeof(s_acMagicNumberData); ui++)
|
||||||
|
{
|
||||||
|
m_data.m_acMagicNumber[ui] = s_acMagicNumberData[ui];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int ui = 0; ui < sizeof(s_acVersionData); ui++)
|
||||||
|
{
|
||||||
|
m_data.m_acVersion[ui] = s_acVersionData[ui];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.m_ucDataType_msb = 0; // ETC1_RGB_NO_MIPMAPS
|
||||||
|
m_data.m_ucDataType_lsb = 0;
|
||||||
|
|
||||||
|
m_data.m_ucOriginalWidth_msb = (unsigned char)(m_pfile->GetSourceWidth() >> 8);
|
||||||
|
m_data.m_ucOriginalWidth_lsb = m_pfile->GetSourceWidth() & 0xFF;
|
||||||
|
m_data.m_ucOriginalHeight_msb = (unsigned char)(m_pfile->GetSourceHeight() >> 8);
|
||||||
|
m_data.m_ucOriginalHeight_lsb = m_pfile->GetSourceHeight() & 0xFF;
|
||||||
|
|
||||||
|
m_data.m_ucExtendedWidth_msb = (unsigned char)(m_pfile->GetExtendedWidth() >> 8);
|
||||||
|
m_data.m_ucExtendedWidth_lsb = m_pfile->GetExtendedWidth() & 0xFF;
|
||||||
|
m_data.m_ucExtendedHeight_msb = (unsigned char)(m_pfile->GetExtendedHeight() >> 8);
|
||||||
|
m_data.m_ucExtendedHeight_lsb = m_pfile->GetExtendedHeight() & 0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
void FileHeader_Pkm::Write(FILE *a_pfile)
|
||||||
|
{
|
||||||
|
|
||||||
|
fwrite(&m_data, sizeof(Data), 1, a_pfile);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
FileHeader_Ktx::FileHeader_Ktx(File *a_pfile)
|
||||||
|
{
|
||||||
|
m_pfile = a_pfile;
|
||||||
|
|
||||||
|
static const uint8_t s_au8Itentfier[12] =
|
||||||
|
{
|
||||||
|
0xAB, 0x4B, 0x54, 0x58, // first four bytes of Byte[12] identifier
|
||||||
|
0x20, 0x31, 0x31, 0xBB, // next four bytes of Byte[12] identifier
|
||||||
|
0x0D, 0x0A, 0x1A, 0x0A // final four bytes of Byte[12] identifier
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unsigned int ui = 0; ui < sizeof(s_au8Itentfier); ui++)
|
||||||
|
{
|
||||||
|
m_data.m_au8Identifier[ui] = s_au8Itentfier[ui];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.m_u32Endianness = 0x04030201;
|
||||||
|
m_data.m_u32GlType = 0;
|
||||||
|
m_data.m_u32GlTypeSize = 1;
|
||||||
|
m_data.m_u32GlFormat = 0;
|
||||||
|
|
||||||
|
switch (m_pfile->GetImageFormat())
|
||||||
|
{
|
||||||
|
case Image::Format::RGB8:
|
||||||
|
case Image::Format::SRGB8:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGBA8:
|
||||||
|
case Image::Format::SRGBA8:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGBA8;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGBA8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGB8A1:
|
||||||
|
case Image::Format::SRGB8A1:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8A1;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8A1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::R11:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_R11;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::SIGNED_R11:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_R11;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RG11:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RG11;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::SIGNED_RG11:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_RG11;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC1_RGB8;
|
||||||
|
m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC1_RGB8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.m_u32PixelWidth = 0;
|
||||||
|
m_data.m_u32PixelHeight = 0;
|
||||||
|
m_data.m_u32PixelDepth = 0;
|
||||||
|
m_data.m_u32NumberOfArrayElements = 0;
|
||||||
|
m_data.m_u32NumberOfFaces = 0;
|
||||||
|
m_data.m_u32BytesOfKeyValueData = 0;
|
||||||
|
|
||||||
|
m_pkeyvaluepair = nullptr;
|
||||||
|
|
||||||
|
m_u32Images = 0;
|
||||||
|
m_u32KeyValuePairs = 0;
|
||||||
|
|
||||||
|
m_data.m_u32PixelWidth = m_pfile->GetSourceWidth();
|
||||||
|
m_data.m_u32PixelHeight = m_pfile->GetSourceHeight();
|
||||||
|
m_data.m_u32PixelDepth = 0;
|
||||||
|
m_data.m_u32NumberOfArrayElements = 0;
|
||||||
|
m_data.m_u32NumberOfFaces = 1;
|
||||||
|
m_data.m_u32NumberOfMipmapLevels = m_pfile->GetNumMipmaps();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
void FileHeader_Ktx::Write(FILE *a_pfile)
|
||||||
|
{
|
||||||
|
size_t szBytesWritten;
|
||||||
|
|
||||||
|
// Write header
|
||||||
|
szBytesWritten = fwrite(&m_data, 1, sizeof(Data), a_pfile);
|
||||||
|
assert(szBytesWritten == sizeof(Data));
|
||||||
|
|
||||||
|
// Write KeyAndValuePairs
|
||||||
|
if (m_u32KeyValuePairs)
|
||||||
|
{
|
||||||
|
fwrite(m_pkeyvaluepair, m_pkeyvaluepair->u32KeyAndValueByteSize, 1, a_pfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
FileHeader_Ktx::Data *FileHeader_Ktx::GetData()
|
||||||
|
{
|
||||||
|
return &m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
} // namespace Etc
|
146
thirdparty/etc2comp/EtcFileHeader.h
vendored
Normal file
146
thirdparty/etc2comp/EtcFileHeader.h
vendored
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcFile.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
class Image;
|
||||||
|
|
||||||
|
class FileHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void Write(FILE *a_pfile) = 0;
|
||||||
|
File GetFile();
|
||||||
|
virtual ~FileHeader(void) {}
|
||||||
|
protected:
|
||||||
|
|
||||||
|
File *m_pfile;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
class FileHeader_Pkm : public FileHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FileHeader_Pkm(File *a_pfile);
|
||||||
|
|
||||||
|
virtual void Write(FILE *a_pfile);
|
||||||
|
virtual ~FileHeader_Pkm(void) {}
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char m_acMagicNumber[4];
|
||||||
|
char m_acVersion[2];
|
||||||
|
unsigned char m_ucDataType_msb; // e.g. ETC1_RGB_NO_MIPMAPS
|
||||||
|
unsigned char m_ucDataType_lsb;
|
||||||
|
unsigned char m_ucExtendedWidth_msb; // padded to 4x4 blocks
|
||||||
|
unsigned char m_ucExtendedWidth_lsb;
|
||||||
|
unsigned char m_ucExtendedHeight_msb; // padded to 4x4 blocks
|
||||||
|
unsigned char m_ucExtendedHeight_lsb;
|
||||||
|
unsigned char m_ucOriginalWidth_msb;
|
||||||
|
unsigned char m_ucOriginalWidth_lsb;
|
||||||
|
unsigned char m_ucOriginalHeight_msb;
|
||||||
|
unsigned char m_ucOriginalHeight_lsb;
|
||||||
|
} Data;
|
||||||
|
|
||||||
|
Data m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
class FileHeader_Ktx : public FileHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t u32KeyAndValueByteSize;
|
||||||
|
} KeyValuePair;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t m_au8Identifier[12];
|
||||||
|
uint32_t m_u32Endianness;
|
||||||
|
uint32_t m_u32GlType;
|
||||||
|
uint32_t m_u32GlTypeSize;
|
||||||
|
uint32_t m_u32GlFormat;
|
||||||
|
uint32_t m_u32GlInternalFormat;
|
||||||
|
uint32_t m_u32GlBaseInternalFormat;
|
||||||
|
uint32_t m_u32PixelWidth;
|
||||||
|
uint32_t m_u32PixelHeight;
|
||||||
|
uint32_t m_u32PixelDepth;
|
||||||
|
uint32_t m_u32NumberOfArrayElements;
|
||||||
|
uint32_t m_u32NumberOfFaces;
|
||||||
|
uint32_t m_u32NumberOfMipmapLevels;
|
||||||
|
uint32_t m_u32BytesOfKeyValueData;
|
||||||
|
} Data;
|
||||||
|
|
||||||
|
enum class InternalFormat
|
||||||
|
{
|
||||||
|
ETC1_RGB8 = 0x8D64,
|
||||||
|
ETC1_ALPHA8 = ETC1_RGB8,
|
||||||
|
//
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
FileHeader_Ktx(File *a_pfile);
|
||||||
|
|
||||||
|
virtual void Write(FILE *a_pfile);
|
||||||
|
virtual ~FileHeader_Ktx(void) {}
|
||||||
|
|
||||||
|
void AddKeyAndValue(KeyValuePair *a_pkeyvaluepair);
|
||||||
|
|
||||||
|
Data* GetData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Data m_data;
|
||||||
|
KeyValuePair *m_pkeyvaluepair;
|
||||||
|
|
||||||
|
uint32_t m_u32Images;
|
||||||
|
uint32_t m_u32KeyValuePairs;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
401
thirdparty/etc2comp/EtcFilter.cpp
vendored
Normal file
401
thirdparty/etc2comp/EtcFilter.cpp
vendored
Normal file
|
@ -0,0 +1,401 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "EtcFilter.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
static const double PiConst = 3.14159265358979323846;
|
||||||
|
|
||||||
|
inline double sinc(double x)
|
||||||
|
{
|
||||||
|
if ( x == 0.0 )
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sin(PiConst * x) / (PiConst * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
//inline float sincf( float x )
|
||||||
|
//{
|
||||||
|
// x *= F_PI;
|
||||||
|
// if (x < 0.01f && x > -0.01f)
|
||||||
|
// {
|
||||||
|
// return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return sinf(x)/x;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//double bessel0(double x)
|
||||||
|
//{
|
||||||
|
// const double EPSILON_RATIO = 1E-16;
|
||||||
|
// double xh, sum, pow, ds;
|
||||||
|
// int k;
|
||||||
|
//
|
||||||
|
// xh = 0.5 * x;
|
||||||
|
// sum = 1.0;
|
||||||
|
// pow = 1.0;
|
||||||
|
// k = 0;
|
||||||
|
// ds = 1.0;
|
||||||
|
// while (ds > sum * EPSILON_RATIO)
|
||||||
|
// {
|
||||||
|
// ++k;
|
||||||
|
// pow = pow * (xh / k);
|
||||||
|
// ds = pow * pow;
|
||||||
|
// sum = sum + ds;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return sum;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//**--------------------------------------------------------------------------
|
||||||
|
//** Name: kaiser(double alpha, double half_width, double x)
|
||||||
|
//** Returns:
|
||||||
|
//** Description: Alpha controls shape of filter. We are using 4.
|
||||||
|
//**--------------------------------------------------------------------------
|
||||||
|
//inline double kaiser(double alpha, double half_width, double x)
|
||||||
|
//{
|
||||||
|
// double ratio = (x / half_width);
|
||||||
|
// return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//float Filter_Lanczos4Sinc(float x)
|
||||||
|
//{
|
||||||
|
// if (x <= -4.0f || x >= 4.0f) // half-width of 4
|
||||||
|
// {
|
||||||
|
// return 0.0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return sinc(0.875f * x) * sinc(0.25f * x);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//double Filter_Kaiser4( double t )
|
||||||
|
//{
|
||||||
|
// return kaiser( 4.0, 3.0, t);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//double Filter_KaiserOptimal( double t )
|
||||||
|
//{
|
||||||
|
// return kaiser( 8.93, 3.0f, t);
|
||||||
|
//}
|
||||||
|
|
||||||
|
double FilterLanczos3( double t )
|
||||||
|
{
|
||||||
|
if ( t <= -3.0 || t >= 3.0 )
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sinc( t ) * sinc( t / 3.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
double FilterBox( double t )
|
||||||
|
{
|
||||||
|
return ( t > -0.5 && t < 0.5) ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FilterLinear( double t )
|
||||||
|
{
|
||||||
|
if (t < 0.0) t = -t;
|
||||||
|
|
||||||
|
return (t < 1.0) ? (1.0 - t) : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//**--------------------------------------------------------------------------
|
||||||
|
//** Name: CalcContributions( int srcSize,
|
||||||
|
//** int destSize,
|
||||||
|
//** double filterSize,
|
||||||
|
//** bool wrap,
|
||||||
|
//** double (*FilterProc)(double),
|
||||||
|
//** FilterWeights contrib[] )
|
||||||
|
//** Returns: void
|
||||||
|
//** Description:
|
||||||
|
//**--------------------------------------------------------------------------
|
||||||
|
void CalcContributions( int srcSize, int destSize, double filterSize, bool wrap, double (*FilterProc)(double), FilterWeights contrib[] )
|
||||||
|
{
|
||||||
|
double scale;
|
||||||
|
double filterScale;
|
||||||
|
double center;
|
||||||
|
double totalWeight;
|
||||||
|
double weight;
|
||||||
|
int iRight;
|
||||||
|
int iLeft;
|
||||||
|
int iDest;
|
||||||
|
|
||||||
|
scale = (double)destSize / srcSize;
|
||||||
|
if ( scale < 1.0 )
|
||||||
|
{
|
||||||
|
filterSize = filterSize / scale;
|
||||||
|
filterScale = scale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filterScale = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( filterSize > (double)MaxFilterSize )
|
||||||
|
{
|
||||||
|
filterSize = (double)MaxFilterSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( iDest = 0; iDest < destSize; ++iDest )
|
||||||
|
{
|
||||||
|
center = (double)iDest / scale;
|
||||||
|
|
||||||
|
iLeft = (int)ceil(center - filterSize);
|
||||||
|
iRight = (int)floor(center + filterSize);
|
||||||
|
|
||||||
|
if ( !wrap )
|
||||||
|
{
|
||||||
|
if ( iLeft < 0 )
|
||||||
|
{
|
||||||
|
iLeft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( iRight >= srcSize )
|
||||||
|
{
|
||||||
|
iRight = srcSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numWeights = iRight - iLeft + 1;
|
||||||
|
|
||||||
|
contrib[iDest].first = iLeft;
|
||||||
|
contrib[iDest].numWeights = numWeights;
|
||||||
|
|
||||||
|
totalWeight = 0;
|
||||||
|
double t = ((double)iLeft - center) * filterScale;
|
||||||
|
for (int i = 0; i < numWeights; i++)
|
||||||
|
{
|
||||||
|
weight = (*FilterProc)(t) * filterScale;
|
||||||
|
totalWeight += weight;
|
||||||
|
contrib[iDest].weight[i] = weight;
|
||||||
|
t += filterScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
//**--------------------------------------------------------
|
||||||
|
//** Normalize weights by dividing by the sum of the weights
|
||||||
|
//**--------------------------------------------------------
|
||||||
|
if ( totalWeight > 0.0 )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < numWeights; i++)
|
||||||
|
{
|
||||||
|
contrib[iDest].weight[i] /= totalWeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//**-------------------------------------------------------------------------
|
||||||
|
//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
|
||||||
|
//** int srcWidth, int srcHeight,
|
||||||
|
//** RGBCOLOR *pDestImage,
|
||||||
|
//** int destWidth, int destHeight,
|
||||||
|
//** double (*FilterProc)(double) )
|
||||||
|
//** Returns: 0 on failure and 1 on success
|
||||||
|
//** Description: Filters a 2d image with a two pass filter by averaging the
|
||||||
|
//** weighted contributions of the pixels within the filter region. The
|
||||||
|
//** contributions are determined by a weighting function parameter.
|
||||||
|
//**-------------------------------------------------------------------------
|
||||||
|
int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
|
||||||
|
RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) )
|
||||||
|
{
|
||||||
|
FilterWeights *contrib;
|
||||||
|
RGBCOLOR *pPixel;
|
||||||
|
RGBCOLOR *pSrcPixel;
|
||||||
|
RGBCOLOR *pTempImage;
|
||||||
|
int iRow;
|
||||||
|
int iCol;
|
||||||
|
int iSrcCol;
|
||||||
|
int iSrcRow;
|
||||||
|
int iWeight;
|
||||||
|
double dRed;
|
||||||
|
double dGreen;
|
||||||
|
double dBlue;
|
||||||
|
double dAlpha;
|
||||||
|
double filterSize = 3.0;
|
||||||
|
|
||||||
|
int maxDim = (srcWidth>srcHeight)?srcWidth:srcHeight;
|
||||||
|
contrib = (FilterWeights*)malloc(maxDim * sizeof(FilterWeights));
|
||||||
|
|
||||||
|
//**------------------------------------------------------------------------
|
||||||
|
//** Need to create a temporary image to stuff the horizontally scaled image
|
||||||
|
//**------------------------------------------------------------------------
|
||||||
|
pTempImage = (RGBCOLOR *)malloc( destWidth * srcHeight * sizeof(RGBCOLOR) );
|
||||||
|
if ( pTempImage == NULL )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
//** Horizontally filter the image into the temporary image
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
|
||||||
|
CalcContributions( srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib );
|
||||||
|
for ( iRow = 0; iRow < srcHeight; iRow++ )
|
||||||
|
{
|
||||||
|
for ( iCol = 0; iCol < destWidth; iCol++ )
|
||||||
|
{
|
||||||
|
dRed = 0;
|
||||||
|
dGreen = 0;
|
||||||
|
dBlue = 0;
|
||||||
|
dAlpha = 0;
|
||||||
|
|
||||||
|
for ( iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++ )
|
||||||
|
{
|
||||||
|
iSrcCol = iWeight + contrib[iCol].first;
|
||||||
|
if (bWrapHorizontal)
|
||||||
|
{
|
||||||
|
iSrcCol = (iSrcCol < 0) ? (srcWidth + iSrcCol) : (iSrcCol >= srcWidth) ? (iSrcCol - srcWidth) : iSrcCol;
|
||||||
|
}
|
||||||
|
pSrcPixel = pSrcImage + (iRow * srcWidth) + iSrcCol;
|
||||||
|
dRed += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[0];
|
||||||
|
dGreen += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[1];
|
||||||
|
dBlue += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[2];
|
||||||
|
dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
pPixel = pTempImage + (iRow * destWidth) + iCol;
|
||||||
|
pPixel->rgba[0] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dRed)));
|
||||||
|
pPixel->rgba[1] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dGreen)));
|
||||||
|
pPixel->rgba[2] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dBlue)));
|
||||||
|
pPixel->rgba[3] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dAlpha)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
//** Vertically filter the image into the destination image
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
|
||||||
|
CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
|
||||||
|
for ( iCol = 0; iCol < destWidth; iCol++ )
|
||||||
|
{
|
||||||
|
for ( iRow = 0; iRow < destHeight; iRow++ )
|
||||||
|
{
|
||||||
|
dRed = 0;
|
||||||
|
dGreen = 0;
|
||||||
|
dBlue = 0;
|
||||||
|
dAlpha = 0;
|
||||||
|
|
||||||
|
for ( iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++ )
|
||||||
|
{
|
||||||
|
iSrcRow = iWeight + contrib[iRow].first;
|
||||||
|
if (bWrapVertical)
|
||||||
|
{
|
||||||
|
iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
|
||||||
|
}
|
||||||
|
pSrcPixel = pTempImage + (iSrcRow * destWidth) + iCol;
|
||||||
|
dRed += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[0];
|
||||||
|
dGreen += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[1];
|
||||||
|
dBlue += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[2];
|
||||||
|
dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
pPixel = pDestImage + (iRow * destWidth) + iCol;
|
||||||
|
pPixel->rgba[0] = (unsigned char)(std::max( 0.0, std::min( 255.0, dRed)));
|
||||||
|
pPixel->rgba[1] = (unsigned char)(std::max( 0.0, std::min( 255.0, dGreen)));
|
||||||
|
pPixel->rgba[2] = (unsigned char)(std::max( 0.0, std::min( 255.0, dBlue)));
|
||||||
|
pPixel->rgba[3] = (unsigned char)(std::max( 0.0, std::min( 255.0, dAlpha)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free( pTempImage );
|
||||||
|
free( contrib );
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//**-------------------------------------------------------------------------
|
||||||
|
//** Name: FilterResample(RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
|
||||||
|
//** RGBCOLOR *pDstImage, int dstWidth, int dstHeight)
|
||||||
|
//** Returns: 1
|
||||||
|
//** Description: This function runs a 2d box filter over the srouce image
|
||||||
|
//** to produce the destination image.
|
||||||
|
//**-------------------------------------------------------------------------
|
||||||
|
void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
|
||||||
|
RGBCOLOR *pDstImage, int dstWidth, int dstHeight )
|
||||||
|
{
|
||||||
|
int iRow;
|
||||||
|
int iCol;
|
||||||
|
int iSampleRow;
|
||||||
|
int iSampleCol;
|
||||||
|
int iFirstSampleRow;
|
||||||
|
int iFirstSampleCol;
|
||||||
|
int iLastSampleRow;
|
||||||
|
int iLastSampleCol;
|
||||||
|
int red;
|
||||||
|
int green;
|
||||||
|
int blue;
|
||||||
|
int alpha;
|
||||||
|
int samples;
|
||||||
|
float xScale;
|
||||||
|
float yScale;
|
||||||
|
|
||||||
|
RGBCOLOR *pSrcPixel;
|
||||||
|
RGBCOLOR *pDstPixel;
|
||||||
|
|
||||||
|
xScale = (float)srcWidth / dstWidth;
|
||||||
|
yScale = (float)srcHeight / dstHeight;
|
||||||
|
|
||||||
|
for ( iRow = 0; iRow < dstHeight; iRow++ )
|
||||||
|
{
|
||||||
|
for ( iCol = 0; iCol < dstWidth; iCol++ )
|
||||||
|
{
|
||||||
|
iFirstSampleRow = (int)(iRow * yScale);
|
||||||
|
iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
|
||||||
|
if ( iLastSampleRow >= srcHeight )
|
||||||
|
{
|
||||||
|
iLastSampleRow = srcHeight - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iFirstSampleCol = (int)(iCol * xScale);
|
||||||
|
iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
|
||||||
|
if ( iLastSampleCol >= srcWidth )
|
||||||
|
{
|
||||||
|
iLastSampleCol = srcWidth - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = 0;
|
||||||
|
red = 0;
|
||||||
|
green = 0;
|
||||||
|
blue = 0;
|
||||||
|
alpha = 0;
|
||||||
|
for ( iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++ )
|
||||||
|
{
|
||||||
|
for ( iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++ )
|
||||||
|
{
|
||||||
|
pSrcPixel = pSrcImage + iSampleRow * srcWidth + iSampleCol;
|
||||||
|
red += pSrcPixel->rgba[0];
|
||||||
|
green += pSrcPixel->rgba[1];
|
||||||
|
blue += pSrcPixel->rgba[2];
|
||||||
|
alpha += pSrcPixel->rgba[3];
|
||||||
|
|
||||||
|
samples++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pDstPixel = pDstImage + iRow * dstWidth + iCol;
|
||||||
|
if ( samples > 0 )
|
||||||
|
{
|
||||||
|
pDstPixel->rgba[0] = static_cast<uint8_t>(red / samples);
|
||||||
|
pDstPixel->rgba[1] = static_cast<uint8_t>(green / samples);
|
||||||
|
pDstPixel->rgba[2] = static_cast<uint8_t>(blue / samples);
|
||||||
|
pDstPixel->rgba[3] = static_cast<uint8_t>(alpha / samples);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pDstPixel->rgba[0] = static_cast<uint8_t>(red);
|
||||||
|
pDstPixel->rgba[1] = static_cast<uint8_t>(green);
|
||||||
|
pDstPixel->rgba[2] = static_cast<uint8_t>(blue);
|
||||||
|
pDstPixel->rgba[3] = static_cast<uint8_t>(alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
244
thirdparty/etc2comp/EtcFilter.h
vendored
Normal file
244
thirdparty/etc2comp/EtcFilter.h
vendored
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
enum FilterEnums
|
||||||
|
{
|
||||||
|
MaxFilterSize = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WrapFlags
|
||||||
|
{
|
||||||
|
FILTER_WRAP_NONE = 0,
|
||||||
|
FILTER_WRAP_X = 0x1,
|
||||||
|
FILTER_WRAP_Y = 0x2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct tagFilterWeights
|
||||||
|
{
|
||||||
|
int first;
|
||||||
|
int numWeights;
|
||||||
|
double weight[MaxFilterSize * 2 + 1];
|
||||||
|
} FilterWeights;
|
||||||
|
|
||||||
|
typedef struct tagRGBCOLOR
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t ulColor;
|
||||||
|
uint8_t rgba[4];
|
||||||
|
};
|
||||||
|
} RGBCOLOR;
|
||||||
|
|
||||||
|
|
||||||
|
double FilterBox( double t );
|
||||||
|
double FilterLinear( double t );
|
||||||
|
double FilterLanczos3( double t );
|
||||||
|
|
||||||
|
int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
|
||||||
|
RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) );
|
||||||
|
void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
|
||||||
|
RGBCOLOR *pDstImage, int dstWidth, int dstHeight );
|
||||||
|
|
||||||
|
|
||||||
|
void CalcContributions(int srcSize, int destSize, double filterSize, bool wrap, double(*FilterProc)(double), FilterWeights contrib[]);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void FilterResample(T *pSrcImage, int srcWidth, int srcHeight, T *pDstImage, int dstWidth, int dstHeight)
|
||||||
|
{
|
||||||
|
float xScale;
|
||||||
|
float yScale;
|
||||||
|
|
||||||
|
T *pSrcPixel;
|
||||||
|
T *pDstPixel;
|
||||||
|
|
||||||
|
xScale = (float)srcWidth / dstWidth;
|
||||||
|
yScale = (float)srcHeight / dstHeight;
|
||||||
|
|
||||||
|
for (int iRow = 0; iRow < dstHeight; iRow++)
|
||||||
|
{
|
||||||
|
for (int iCol = 0; iCol < dstWidth; iCol++)
|
||||||
|
{
|
||||||
|
int samples;
|
||||||
|
int iFirstSampleRow;
|
||||||
|
int iFirstSampleCol;
|
||||||
|
int iLastSampleRow;
|
||||||
|
int iLastSampleCol;
|
||||||
|
float red;
|
||||||
|
float green;
|
||||||
|
float blue;
|
||||||
|
float alpha;
|
||||||
|
|
||||||
|
iFirstSampleRow = (int)(iRow * yScale);
|
||||||
|
iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
|
||||||
|
if (iLastSampleRow >= srcHeight)
|
||||||
|
{
|
||||||
|
iLastSampleRow = srcHeight - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iFirstSampleCol = (int)(iCol * xScale);
|
||||||
|
iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
|
||||||
|
if (iLastSampleCol >= srcWidth)
|
||||||
|
{
|
||||||
|
iLastSampleCol = srcWidth - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = 0;
|
||||||
|
red = 0.f;
|
||||||
|
green = 0.f;
|
||||||
|
blue = 0.f;
|
||||||
|
alpha = 0.f;
|
||||||
|
for (int iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++)
|
||||||
|
{
|
||||||
|
for (int iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++)
|
||||||
|
{
|
||||||
|
pSrcPixel = pSrcImage + (iSampleRow * srcWidth + iSampleCol) * 4;
|
||||||
|
red += static_cast<float>(pSrcPixel[0]);
|
||||||
|
green += static_cast<float>(pSrcPixel[1]);
|
||||||
|
blue += static_cast<float>(pSrcPixel[2]);
|
||||||
|
alpha += static_cast<float>(pSrcPixel[3]);
|
||||||
|
|
||||||
|
samples++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pDstPixel = pDstImage + (iRow * dstWidth + iCol) * 4;
|
||||||
|
if (samples > 0)
|
||||||
|
{
|
||||||
|
pDstPixel[0] = static_cast<T>(red / samples);
|
||||||
|
pDstPixel[1] = static_cast<T>(green / samples);
|
||||||
|
pDstPixel[2] = static_cast<T>(blue / samples);
|
||||||
|
pDstPixel[3] = static_cast<T>(alpha / samples);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pDstPixel[0] = static_cast<T>(red);
|
||||||
|
pDstPixel[1] = static_cast<T>(green);
|
||||||
|
pDstPixel[2] = static_cast<T>(blue);
|
||||||
|
pDstPixel[3] = static_cast<T>(alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//**-------------------------------------------------------------------------
|
||||||
|
//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
|
||||||
|
//** int srcWidth, int srcHeight,
|
||||||
|
//** RGBCOLOR *pDestImage,
|
||||||
|
//** int destWidth, int destHeight,
|
||||||
|
//** double (*FilterProc)(double) )
|
||||||
|
//** Returns: 0 on failure and 1 on success
|
||||||
|
//** Description: Filters a 2d image with a two pass filter by averaging the
|
||||||
|
//** weighted contributions of the pixels within the filter region. The
|
||||||
|
//** contributions are determined by a weighting function parameter.
|
||||||
|
//**-------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
int FilterTwoPass(T *pSrcImage, int srcWidth, int srcHeight,
|
||||||
|
T *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double(*FilterProc)(double))
|
||||||
|
{
|
||||||
|
const int numComponents = 4;
|
||||||
|
FilterWeights *contrib;
|
||||||
|
T *pPixel;
|
||||||
|
T *pTempImage;
|
||||||
|
double dRed;
|
||||||
|
double dGreen;
|
||||||
|
double dBlue;
|
||||||
|
double dAlpha;
|
||||||
|
double filterSize = 3.0;
|
||||||
|
|
||||||
|
int maxDim = (srcWidth>srcHeight) ? srcWidth : srcHeight;
|
||||||
|
contrib = new FilterWeights[maxDim];
|
||||||
|
|
||||||
|
//**------------------------------------------------------------------------
|
||||||
|
//** Need to create a temporary image to stuff the horizontally scaled image
|
||||||
|
//**------------------------------------------------------------------------
|
||||||
|
pTempImage = new T[destWidth * srcHeight * numComponents];
|
||||||
|
if (pTempImage == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
//** Horizontally filter the image into the temporary image
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
|
||||||
|
CalcContributions(srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib);
|
||||||
|
for (int iRow = 0; iRow < srcHeight; iRow++)
|
||||||
|
{
|
||||||
|
for (int iCol = 0; iCol < destWidth; iCol++)
|
||||||
|
{
|
||||||
|
dRed = 0;
|
||||||
|
dGreen = 0;
|
||||||
|
dBlue = 0;
|
||||||
|
dAlpha = 0;
|
||||||
|
|
||||||
|
for (int iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++)
|
||||||
|
{
|
||||||
|
int iSrcCol = iWeight + contrib[iCol].first;
|
||||||
|
if(bWrapHorizontal)
|
||||||
|
{
|
||||||
|
iSrcCol = (iSrcCol < 0)?(srcWidth+iSrcCol):(iSrcCol >= srcWidth)?(iSrcCol-srcWidth):iSrcCol;
|
||||||
|
}
|
||||||
|
T* pSrcPixel = pSrcImage + ((iRow * srcWidth) + iSrcCol)*numComponents;
|
||||||
|
dRed += contrib[iCol].weight[iWeight] * pSrcPixel[0];
|
||||||
|
dGreen += contrib[iCol].weight[iWeight] * pSrcPixel[1];
|
||||||
|
dBlue += contrib[iCol].weight[iWeight] * pSrcPixel[2];
|
||||||
|
dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
pPixel = pTempImage + ((iRow * destWidth) + iCol)*numComponents;
|
||||||
|
pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
|
||||||
|
pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
|
||||||
|
pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
|
||||||
|
pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
//** Vertically filter the image into the destination image
|
||||||
|
//**-------------------------------------------------------
|
||||||
|
bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
|
||||||
|
CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
|
||||||
|
for (int iCol = 0; iCol < destWidth; iCol++)
|
||||||
|
{
|
||||||
|
for (int iRow = 0; iRow < destHeight; iRow++)
|
||||||
|
{
|
||||||
|
dRed = 0;
|
||||||
|
dGreen = 0;
|
||||||
|
dBlue = 0;
|
||||||
|
dAlpha = 0;
|
||||||
|
|
||||||
|
for (int iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++)
|
||||||
|
{
|
||||||
|
int iSrcRow = iWeight + contrib[iRow].first;
|
||||||
|
if (bWrapVertical)
|
||||||
|
{
|
||||||
|
iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
|
||||||
|
}
|
||||||
|
T* pSrcPixel = pTempImage + ((iSrcRow * destWidth) + iCol)*numComponents;
|
||||||
|
dRed += contrib[iRow].weight[iWeight] * pSrcPixel[0];
|
||||||
|
dGreen += contrib[iRow].weight[iWeight] * pSrcPixel[1];
|
||||||
|
dBlue += contrib[iRow].weight[iWeight] * pSrcPixel[2];
|
||||||
|
dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
pPixel = pDestImage + ((iRow * destWidth) + iCol)*numComponents;
|
||||||
|
pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
|
||||||
|
pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
|
||||||
|
pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
|
||||||
|
pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] pTempImage;
|
||||||
|
delete[] contrib;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
685
thirdparty/etc2comp/EtcImage.cpp
vendored
Normal file
685
thirdparty/etc2comp/EtcImage.cpp
vendored
Normal file
|
@ -0,0 +1,685 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcImage.cpp
|
||||||
|
|
||||||
|
Image is an array of 4x4 blocks that represent the encoding of the source image
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "EtcImage.h"
|
||||||
|
|
||||||
|
#include "Etc.h"
|
||||||
|
#include "EtcBlock4x4.h"
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcSortedBlockList.h"
|
||||||
|
|
||||||
|
#if ETC_WINDOWS
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
#include <ctime>
|
||||||
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// fix conflict with Block4x4::AlphaMix
|
||||||
|
#ifdef OPAQUE
|
||||||
|
#undef OPAQUE
|
||||||
|
#endif
|
||||||
|
#ifdef TRANSPARENT
|
||||||
|
#undef TRANSPARENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
Image::Image(void)
|
||||||
|
{
|
||||||
|
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||||
|
m_warningsToCapture = EncodingStatus::SUCCESS;
|
||||||
|
m_pafrgbaSource = nullptr;
|
||||||
|
|
||||||
|
m_pablock = nullptr;
|
||||||
|
|
||||||
|
m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
|
||||||
|
m_uiEncodingBitsBytes = 0;
|
||||||
|
m_paucEncodingBits = nullptr;
|
||||||
|
|
||||||
|
m_format = Format::UNKNOWN;
|
||||||
|
m_iNumOpaquePixels = 0;
|
||||||
|
m_iNumTranslucentPixels = 0;
|
||||||
|
m_iNumTransparentPixels = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// constructor using source image
|
||||||
|
// used to set state before Encode() is called
|
||||||
|
//
|
||||||
|
Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
|
||||||
|
unsigned int a_uiSourceHeight,
|
||||||
|
ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||||
|
m_warningsToCapture = EncodingStatus::SUCCESS;
|
||||||
|
m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA;
|
||||||
|
m_uiSourceWidth = a_uiSourceWidth;
|
||||||
|
m_uiSourceHeight = a_uiSourceHeight;
|
||||||
|
|
||||||
|
m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
|
||||||
|
m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
|
||||||
|
|
||||||
|
m_uiBlockColumns = m_uiExtendedWidth >> 2;
|
||||||
|
m_uiBlockRows = m_uiExtendedHeight >> 2;
|
||||||
|
|
||||||
|
m_pablock = new Block4x4[GetNumberOfBlocks()];
|
||||||
|
assert(m_pablock);
|
||||||
|
|
||||||
|
m_format = Format::UNKNOWN;
|
||||||
|
|
||||||
|
m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
|
||||||
|
m_uiEncodingBitsBytes = 0;
|
||||||
|
m_paucEncodingBits = nullptr;
|
||||||
|
|
||||||
|
m_errormetric = a_errormetric;
|
||||||
|
m_fEffort = 0.0f;
|
||||||
|
|
||||||
|
m_iEncodeTime_ms = -1;
|
||||||
|
|
||||||
|
m_iNumOpaquePixels = 0;
|
||||||
|
m_iNumTranslucentPixels = 0;
|
||||||
|
m_iNumTransparentPixels = 0;
|
||||||
|
m_bVerboseOutput = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// constructor using encoding bits
|
||||||
|
// recreates encoding state using a previously encoded image
|
||||||
|
//
|
||||||
|
Image::Image(Format a_format,
|
||||||
|
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
|
||||||
|
unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
|
||||||
|
Image *a_pimageSource, ErrorMetric a_errormetric)
|
||||||
|
{
|
||||||
|
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||||
|
m_pafrgbaSource = nullptr;
|
||||||
|
m_uiSourceWidth = a_uiSourceWidth;
|
||||||
|
m_uiSourceHeight = a_uiSourceHeight;
|
||||||
|
|
||||||
|
m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
|
||||||
|
m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
|
||||||
|
|
||||||
|
m_uiBlockColumns = m_uiExtendedWidth >> 2;
|
||||||
|
m_uiBlockRows = m_uiExtendedHeight >> 2;
|
||||||
|
|
||||||
|
unsigned int uiBlocks = GetNumberOfBlocks();
|
||||||
|
|
||||||
|
m_pablock = new Block4x4[uiBlocks];
|
||||||
|
assert(m_pablock);
|
||||||
|
|
||||||
|
m_format = a_format;
|
||||||
|
|
||||||
|
m_iNumOpaquePixels = 0;
|
||||||
|
m_iNumTranslucentPixels = 0;
|
||||||
|
m_iNumTransparentPixels = 0;
|
||||||
|
|
||||||
|
m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
|
||||||
|
if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
|
||||||
|
{
|
||||||
|
AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_uiEncodingBitsBytes = a_uiEncodingBitsBytes;
|
||||||
|
m_paucEncodingBits = a_paucEncidingBits;
|
||||||
|
|
||||||
|
m_errormetric = a_errormetric;
|
||||||
|
m_fEffort = 0.0f;
|
||||||
|
m_bVerboseOutput = false;
|
||||||
|
m_iEncodeTime_ms = -1;
|
||||||
|
|
||||||
|
unsigned char *paucEncodingBits = m_paucEncodingBits;
|
||||||
|
unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
|
||||||
|
|
||||||
|
unsigned int uiH = 0;
|
||||||
|
unsigned int uiV = 0;
|
||||||
|
for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++)
|
||||||
|
{
|
||||||
|
m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits,
|
||||||
|
a_pimageSource, a_errormetric);
|
||||||
|
paucEncodingBits += uiEncodingBitsBytesPerBlock;
|
||||||
|
uiH += 4;
|
||||||
|
if (uiH >= m_uiSourceWidth)
|
||||||
|
{
|
||||||
|
uiH = 0;
|
||||||
|
uiV += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
Image::~Image(void)
|
||||||
|
{
|
||||||
|
if (m_pablock != nullptr)
|
||||||
|
{
|
||||||
|
delete[] m_pablock;
|
||||||
|
m_pablock = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (m_paucEncodingBits != nullptr)
|
||||||
|
{
|
||||||
|
delete[] m_paucEncodingBits;
|
||||||
|
m_paucEncodingBits = nullptr;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// encode an image
|
||||||
|
// create a set of encoding bits that conforms to a_format
|
||||||
|
// find best fit using a_errormetric
|
||||||
|
// explore a range of possible encodings based on a_fEffort (range = [0:100])
|
||||||
|
// speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs)
|
||||||
|
//
|
||||||
|
Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||||
|
|
||||||
|
m_format = a_format;
|
||||||
|
m_errormetric = a_errormetric;
|
||||||
|
m_fEffort = a_fEffort;
|
||||||
|
|
||||||
|
if (m_errormetric < 0 || m_errormetric > ERROR_METRICS)
|
||||||
|
{
|
||||||
|
AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC);
|
||||||
|
return m_encodingStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL)
|
||||||
|
{
|
||||||
|
AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
|
||||||
|
m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL;
|
||||||
|
}
|
||||||
|
else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL)
|
||||||
|
{
|
||||||
|
AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
|
||||||
|
m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL;
|
||||||
|
}
|
||||||
|
if (a_uiJobs < 1)
|
||||||
|
{
|
||||||
|
a_uiJobs = 1;
|
||||||
|
AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
|
||||||
|
}
|
||||||
|
else if (a_uiJobs > a_uiMaxJobs)
|
||||||
|
{
|
||||||
|
a_uiJobs = a_uiMaxJobs;
|
||||||
|
AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
|
||||||
|
|
||||||
|
if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
|
||||||
|
{
|
||||||
|
AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
|
||||||
|
return m_encodingStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_paucEncodingBits == nullptr);
|
||||||
|
m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
|
||||||
|
m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes];
|
||||||
|
|
||||||
|
InitBlocksAndBlockSorter();
|
||||||
|
|
||||||
|
|
||||||
|
std::future<void> *handle = new std::future<void>[a_uiMaxJobs];
|
||||||
|
|
||||||
|
unsigned int uiNumThreadsNeeded = 0;
|
||||||
|
unsigned int uiUnfinishedBlocks = GetNumberOfBlocks();
|
||||||
|
|
||||||
|
uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||||
|
{
|
||||||
|
handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||||
|
{
|
||||||
|
handle[i].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform effort-based encoding
|
||||||
|
if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL)
|
||||||
|
{
|
||||||
|
unsigned int uiFinishedBlocks = 0;
|
||||||
|
unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks()));
|
||||||
|
|
||||||
|
if (m_bVerboseOutput)
|
||||||
|
{
|
||||||
|
printf("effortblocks = %d\n", uiTotalEffortBlocks);
|
||||||
|
}
|
||||||
|
unsigned int uiPass = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (m_bVerboseOutput)
|
||||||
|
{
|
||||||
|
uiPass++;
|
||||||
|
printf("pass %u\n", uiPass);
|
||||||
|
}
|
||||||
|
m_psortedblocklist->Sort();
|
||||||
|
uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks();
|
||||||
|
uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks;
|
||||||
|
if (m_bVerboseOutput)
|
||||||
|
{
|
||||||
|
printf(" %u unfinished blocks\n", uiUnfinishedBlocks);
|
||||||
|
// m_psortedblocklist->Print();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//stop enocding when we did enough to satify the effort percentage
|
||||||
|
if (uiFinishedBlocks >= uiTotalEffortBlocks)
|
||||||
|
{
|
||||||
|
if (m_bVerboseOutput)
|
||||||
|
{
|
||||||
|
printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int uiIteratedBlocks = 0;
|
||||||
|
unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks);
|
||||||
|
uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
|
||||||
|
|
||||||
|
if (uiNumThreadsNeeded <= 1)
|
||||||
|
{
|
||||||
|
//since we already how many blocks each thread will process
|
||||||
|
//cap the thread limit to do the proper amount of work, and not more
|
||||||
|
uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//we have a lot of work to do, so lets multi thread it
|
||||||
|
std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1];
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||||
|
{
|
||||||
|
handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded);
|
||||||
|
}
|
||||||
|
uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||||
|
{
|
||||||
|
uiIteratedBlocks += handleToBlockEncoders[i].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] handleToBlockEncoders;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_bVerboseOutput)
|
||||||
|
{
|
||||||
|
printf(" %u iterated blocks\n", uiIteratedBlocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate Etc2-compatible bit-format 4x4 blocks
|
||||||
|
for (int i = 0; i < (int)a_uiJobs - 1; i++)
|
||||||
|
{
|
||||||
|
handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs);
|
||||||
|
}
|
||||||
|
SetEncodingBits(a_uiJobs - 1, a_uiJobs);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)a_uiJobs - 1; i++)
|
||||||
|
{
|
||||||
|
handle[i].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end = std::chrono::steady_clock::now();
|
||||||
|
std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||||
|
m_iEncodeTime_ms = (int)elapsed.count();
|
||||||
|
|
||||||
|
delete[] handle;
|
||||||
|
delete m_psortedblocklist;
|
||||||
|
return m_encodingStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// iterate the encoding thru the blocks with the worst error
|
||||||
|
// stop when a_uiMaxBlocks blocks have been iterated
|
||||||
|
// split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride
|
||||||
|
//
|
||||||
|
unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
|
||||||
|
unsigned int a_uiMultithreadingOffset,
|
||||||
|
unsigned int a_uiMultithreadingStride)
|
||||||
|
{
|
||||||
|
assert(a_uiMultithreadingStride > 0);
|
||||||
|
unsigned int uiIteratedBlocks = a_uiMultithreadingOffset;
|
||||||
|
|
||||||
|
SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock();
|
||||||
|
for (plink = plink->Advance(a_uiMultithreadingOffset);
|
||||||
|
plink != nullptr;
|
||||||
|
plink = plink->Advance(a_uiMultithreadingStride) )
|
||||||
|
{
|
||||||
|
if (uiIteratedBlocks >= a_uiMaxBlocks)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
plink->GetBlock()->PerformEncodingIteration(m_fEffort);
|
||||||
|
|
||||||
|
uiIteratedBlocks += a_uiMultithreadingStride;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uiIteratedBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// determine which warnings to check for during Encode() based on encoding format
|
||||||
|
//
|
||||||
|
void Image::FindEncodingWarningTypesForCurFormat()
|
||||||
|
{
|
||||||
|
TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS);
|
||||||
|
TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1);
|
||||||
|
switch (m_format)
|
||||||
|
{
|
||||||
|
case Image::Format::ETC1:
|
||||||
|
case Image::Format::RGB8:
|
||||||
|
case Image::Format::SRGB8:
|
||||||
|
TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||||
|
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RGB8A1:
|
||||||
|
case Image::Format::SRGB8A1:
|
||||||
|
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||||
|
TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
|
||||||
|
break;
|
||||||
|
case Image::Format::RGBA8:
|
||||||
|
case Image::Format::SRGBA8:
|
||||||
|
TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::R11:
|
||||||
|
case Image::Format::SIGNED_R11:
|
||||||
|
TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||||
|
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||||
|
TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
|
||||||
|
TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Image::Format::RG11:
|
||||||
|
case Image::Format::SIGNED_RG11:
|
||||||
|
TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||||
|
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||||
|
TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
|
||||||
|
break;
|
||||||
|
case Image::Format::FORMATS:
|
||||||
|
case Image::Format::UNKNOWN:
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// examine source pixels to check for warnings
|
||||||
|
//
|
||||||
|
void Image::FindAndSetEncodingWarnings()
|
||||||
|
{
|
||||||
|
int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4);
|
||||||
|
if (m_iNumOpaquePixels == numPixels)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS);
|
||||||
|
}
|
||||||
|
if (m_iNumOpaquePixels < numPixels)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||||
|
}
|
||||||
|
if (m_iNumTranslucentPixels > 0)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||||
|
}
|
||||||
|
if (m_iNumTransparentPixels == numPixels)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS);
|
||||||
|
}
|
||||||
|
if (m_numColorValues.fB > 0.0f)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
|
||||||
|
}
|
||||||
|
if (m_numColorValues.fG > 0.0f)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
|
||||||
|
}
|
||||||
|
if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f)
|
||||||
|
{
|
||||||
|
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// return a string name for a given image format
|
||||||
|
//
|
||||||
|
const char * Image::EncodingFormatToString(Image::Format a_format)
|
||||||
|
{
|
||||||
|
switch (a_format)
|
||||||
|
{
|
||||||
|
case Image::Format::ETC1:
|
||||||
|
return "ETC1";
|
||||||
|
case Image::Format::RGB8:
|
||||||
|
return "RGB8";
|
||||||
|
case Image::Format::SRGB8:
|
||||||
|
return "SRGB8";
|
||||||
|
|
||||||
|
case Image::Format::RGB8A1:
|
||||||
|
return "RGB8A1";
|
||||||
|
case Image::Format::SRGB8A1:
|
||||||
|
return "SRGB8A1";
|
||||||
|
case Image::Format::RGBA8:
|
||||||
|
return "RGBA8";
|
||||||
|
case Image::Format::SRGBA8:
|
||||||
|
return "SRGBA8";
|
||||||
|
|
||||||
|
case Image::Format::R11:
|
||||||
|
return "R11";
|
||||||
|
case Image::Format::SIGNED_R11:
|
||||||
|
return "SIGNED_R11";
|
||||||
|
|
||||||
|
case Image::Format::RG11:
|
||||||
|
return "RG11";
|
||||||
|
case Image::Format::SIGNED_RG11:
|
||||||
|
return "SIGNED_RG11";
|
||||||
|
case Image::Format::FORMATS:
|
||||||
|
case Image::Format::UNKNOWN:
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// return a string name for the image's format
|
||||||
|
//
|
||||||
|
const char * Image::EncodingFormatToString(void)
|
||||||
|
{
|
||||||
|
return EncodingFormatToString(m_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// init image blocks prior to encoding
|
||||||
|
// init block sorter for subsequent sortings
|
||||||
|
// check for encoding warnings
|
||||||
|
//
|
||||||
|
void Image::InitBlocksAndBlockSorter(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
FindEncodingWarningTypesForCurFormat();
|
||||||
|
|
||||||
|
// init each block
|
||||||
|
Block4x4 *pblock = m_pablock;
|
||||||
|
unsigned char *paucEncodingBits = m_paucEncodingBits;
|
||||||
|
for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++)
|
||||||
|
{
|
||||||
|
unsigned int uiBlockV = uiBlockRow * 4;
|
||||||
|
|
||||||
|
for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++)
|
||||||
|
{
|
||||||
|
unsigned int uiBlockH = uiBlockColumn * 4;
|
||||||
|
|
||||||
|
pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric);
|
||||||
|
|
||||||
|
paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
|
||||||
|
|
||||||
|
pblock++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FindAndSetEncodingWarnings();
|
||||||
|
|
||||||
|
// init block sorter
|
||||||
|
{
|
||||||
|
m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100);
|
||||||
|
|
||||||
|
for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
|
||||||
|
{
|
||||||
|
pblock = &m_pablock[uiBlock];
|
||||||
|
m_psortedblocklist->AddBlock(pblock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// run the first pass of the encoder
|
||||||
|
// the encoder generally finds a reasonable, fast encoding
|
||||||
|
// this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding
|
||||||
|
//
|
||||||
|
void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride)
|
||||||
|
{
|
||||||
|
assert(a_uiMultithreadingStride > 0);
|
||||||
|
|
||||||
|
for (unsigned int uiBlock = a_uiMultithreadingOffset;
|
||||||
|
uiBlock < GetNumberOfBlocks();
|
||||||
|
uiBlock += a_uiMultithreadingStride)
|
||||||
|
{
|
||||||
|
Block4x4 *pblock = &m_pablock[uiBlock];
|
||||||
|
pblock->PerformEncodingIteration(m_fEffort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// set the encoding bits (for the output file) based on the best encoding for each block
|
||||||
|
//
|
||||||
|
void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset,
|
||||||
|
unsigned int a_uiMultithreadingStride)
|
||||||
|
{
|
||||||
|
assert(a_uiMultithreadingStride > 0);
|
||||||
|
|
||||||
|
for (unsigned int uiBlock = a_uiMultithreadingOffset;
|
||||||
|
uiBlock < GetNumberOfBlocks();
|
||||||
|
uiBlock += a_uiMultithreadingStride)
|
||||||
|
{
|
||||||
|
Block4x4 *pblock = &m_pablock[uiBlock];
|
||||||
|
pblock->SetEncodingBitsFromEncoding();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// return the image error
|
||||||
|
// image error is the sum of all block errors
|
||||||
|
//
|
||||||
|
float Image::GetError(void)
|
||||||
|
{
|
||||||
|
float fError = 0.0f;
|
||||||
|
|
||||||
|
for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
|
||||||
|
{
|
||||||
|
Block4x4 *pblock = &m_pablock[uiBlock];
|
||||||
|
fError += pblock->GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// determine the encoding bits format based on the encoding format
|
||||||
|
// the encoding bits format is a family of bit encodings that are shared across various encoding formats
|
||||||
|
//
|
||||||
|
Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format)
|
||||||
|
{
|
||||||
|
Block4x4EncodingBits::Format encodingbitsformat;
|
||||||
|
|
||||||
|
// determine encoding bits format from image format
|
||||||
|
switch (a_format)
|
||||||
|
{
|
||||||
|
case Format::ETC1:
|
||||||
|
case Format::RGB8:
|
||||||
|
case Format::SRGB8:
|
||||||
|
encodingbitsformat = Block4x4EncodingBits::Format::RGB8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Format::RGBA8:
|
||||||
|
case Format::SRGBA8:
|
||||||
|
encodingbitsformat = Block4x4EncodingBits::Format::RGBA8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Format::R11:
|
||||||
|
case Format::SIGNED_R11:
|
||||||
|
encodingbitsformat = Block4x4EncodingBits::Format::R11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Format::RG11:
|
||||||
|
case Format::SIGNED_RG11:
|
||||||
|
encodingbitsformat = Block4x4EncodingBits::Format::RG11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Format::RGB8A1:
|
||||||
|
case Format::SRGB8A1:
|
||||||
|
encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return encodingbitsformat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
249
thirdparty/etc2comp/EtcImage.h
vendored
Normal file
249
thirdparty/etc2comp/EtcImage.h
vendored
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//#include "Etc.h"
|
||||||
|
#include "EtcColorFloatRGBA.h"
|
||||||
|
#include "EtcBlock4x4EncodingBits.h"
|
||||||
|
#include "EtcErrorMetric.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4;
|
||||||
|
class EncoderSpec;
|
||||||
|
class SortedBlockList;
|
||||||
|
|
||||||
|
class Image
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
//the differnt warning and errors that can come up during encoding
|
||||||
|
enum EncodingStatus
|
||||||
|
{
|
||||||
|
SUCCESS = 0,
|
||||||
|
//
|
||||||
|
WARNING_THRESHOLD = 1 << 0,
|
||||||
|
//
|
||||||
|
WARNING_EFFORT_OUT_OF_RANGE = 1 << 1,
|
||||||
|
WARNING_JOBS_OUT_OF_RANGE = 1 << 2,
|
||||||
|
WARNING_SOME_NON_OPAQUE_PIXELS = 1 << 3,//just for opaque formats, etc1, rgb8, r11, rg11
|
||||||
|
WARNING_ALL_OPAQUE_PIXELS = 1 << 4,
|
||||||
|
WARNING_ALL_TRANSPARENT_PIXELS = 1 << 5,
|
||||||
|
WARNING_SOME_TRANSLUCENT_PIXELS = 1 << 6,//just for rgb8A1
|
||||||
|
WARNING_SOME_RGBA_NOT_0_TO_1 = 1 << 7,
|
||||||
|
WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO = 1 << 8,
|
||||||
|
WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO = 1 << 9,
|
||||||
|
//
|
||||||
|
ERROR_THRESHOLD = 1 << 16,
|
||||||
|
//
|
||||||
|
ERROR_UNKNOWN_FORMAT = 1 << 17,
|
||||||
|
ERROR_UNKNOWN_ERROR_METRIC = 1 << 18,
|
||||||
|
ERROR_ZERO_WIDTH_OR_HEIGHT = 1 << 19,
|
||||||
|
//
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Format
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
//
|
||||||
|
ETC1,
|
||||||
|
//
|
||||||
|
// ETC2 formats
|
||||||
|
RGB8,
|
||||||
|
SRGB8,
|
||||||
|
RGBA8,
|
||||||
|
SRGBA8,
|
||||||
|
R11,
|
||||||
|
SIGNED_R11,
|
||||||
|
RG11,
|
||||||
|
SIGNED_RG11,
|
||||||
|
RGB8A1,
|
||||||
|
SRGB8A1,
|
||||||
|
//
|
||||||
|
FORMATS,
|
||||||
|
//
|
||||||
|
DEFAULT = SRGB8
|
||||||
|
};
|
||||||
|
|
||||||
|
// constructor using source image
|
||||||
|
Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
|
||||||
|
unsigned int a_uiSourceHeight,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
// constructor using encoding bits
|
||||||
|
Image(Format a_format,
|
||||||
|
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
|
||||||
|
unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
|
||||||
|
Image *a_pimageSource,
|
||||||
|
ErrorMetric a_errormetric);
|
||||||
|
|
||||||
|
~Image(void);
|
||||||
|
|
||||||
|
EncodingStatus Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort,
|
||||||
|
unsigned int a_uiJobs, unsigned int a_uiMaxJobs);
|
||||||
|
|
||||||
|
inline void AddToEncodingStatus(EncodingStatus a_encStatus)
|
||||||
|
{
|
||||||
|
m_encodingStatus = (EncodingStatus)((unsigned int)m_encodingStatus | (unsigned int)a_encStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetSourceWidth(void)
|
||||||
|
{
|
||||||
|
return m_uiSourceWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetSourceHeight(void)
|
||||||
|
{
|
||||||
|
return m_uiSourceHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetExtendedWidth(void)
|
||||||
|
{
|
||||||
|
return m_uiExtendedWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetExtendedHeight(void)
|
||||||
|
{
|
||||||
|
return m_uiExtendedHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetNumberOfBlocks()
|
||||||
|
{
|
||||||
|
return m_uiBlockColumns * m_uiBlockRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Block4x4 * GetBlocks()
|
||||||
|
{
|
||||||
|
return m_pablock;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned char * GetEncodingBits(void)
|
||||||
|
{
|
||||||
|
return m_paucEncodingBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetEncodingBitsBytes(void)
|
||||||
|
{
|
||||||
|
return m_uiEncodingBitsBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int GetEncodingTimeMs(void)
|
||||||
|
{
|
||||||
|
return m_iEncodeTime_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetError(void);
|
||||||
|
|
||||||
|
inline ColorFloatRGBA * GetSourcePixel(unsigned int a_uiH, unsigned int a_uiV)
|
||||||
|
{
|
||||||
|
if (a_uiH >= m_uiSourceWidth || a_uiV >= m_uiSourceHeight)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &m_pafrgbaSource[a_uiV*m_uiSourceWidth + a_uiH];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Format GetFormat(void)
|
||||||
|
{
|
||||||
|
return m_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Block4x4EncodingBits::Format DetermineEncodingBitsFormat(Format a_format);
|
||||||
|
|
||||||
|
inline static unsigned short CalcExtendedDimension(unsigned short a_ushOriginalDimension)
|
||||||
|
{
|
||||||
|
return (unsigned short)((a_ushOriginalDimension + 3) & ~3);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ErrorMetric GetErrorMetric(void)
|
||||||
|
{
|
||||||
|
return m_errormetric;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * EncodingFormatToString(Image::Format a_format);
|
||||||
|
const char * EncodingFormatToString(void);
|
||||||
|
//used to get basic information about the image data
|
||||||
|
int m_iNumOpaquePixels;
|
||||||
|
int m_iNumTranslucentPixels;
|
||||||
|
int m_iNumTransparentPixels;
|
||||||
|
|
||||||
|
ColorFloatRGBA m_numColorValues;
|
||||||
|
ColorFloatRGBA m_numOutOfRangeValues;
|
||||||
|
|
||||||
|
bool m_bVerboseOutput;
|
||||||
|
private:
|
||||||
|
//add a warning or error to check for while encoding
|
||||||
|
inline void TrackEncodingWarning(EncodingStatus a_encStatus)
|
||||||
|
{
|
||||||
|
m_warningsToCapture = (EncodingStatus)((unsigned int)m_warningsToCapture | (unsigned int)a_encStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
//report the warning if it is something we care about for this encoding
|
||||||
|
inline void AddToEncodingStatusIfSignfigant(EncodingStatus a_encStatus)
|
||||||
|
{
|
||||||
|
if ((EncodingStatus)((unsigned int)m_warningsToCapture & (unsigned int)a_encStatus) == a_encStatus)
|
||||||
|
{
|
||||||
|
AddToEncodingStatus(a_encStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image(void);
|
||||||
|
void FindEncodingWarningTypesForCurFormat();
|
||||||
|
void FindAndSetEncodingWarnings();
|
||||||
|
|
||||||
|
void InitBlocksAndBlockSorter(void);
|
||||||
|
|
||||||
|
void RunFirstPass(unsigned int a_uiMultithreadingOffset,
|
||||||
|
unsigned int a_uiMultithreadingStride);
|
||||||
|
|
||||||
|
void SetEncodingBits(unsigned int a_uiMultithreadingOffset,
|
||||||
|
unsigned int a_uiMultithreadingStride);
|
||||||
|
|
||||||
|
unsigned int IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
|
||||||
|
unsigned int a_uiMultithreadingOffset,
|
||||||
|
unsigned int a_uiMultithreadingStride);
|
||||||
|
|
||||||
|
// inputs
|
||||||
|
ColorFloatRGBA *m_pafrgbaSource;
|
||||||
|
unsigned int m_uiSourceWidth;
|
||||||
|
unsigned int m_uiSourceHeight;
|
||||||
|
unsigned int m_uiExtendedWidth;
|
||||||
|
unsigned int m_uiExtendedHeight;
|
||||||
|
unsigned int m_uiBlockColumns;
|
||||||
|
unsigned int m_uiBlockRows;
|
||||||
|
// intermediate data
|
||||||
|
Block4x4 *m_pablock;
|
||||||
|
// encoding
|
||||||
|
Format m_format;
|
||||||
|
Block4x4EncodingBits::Format m_encodingbitsformat;
|
||||||
|
unsigned int m_uiEncodingBitsBytes; // for entire image
|
||||||
|
unsigned char *m_paucEncodingBits;
|
||||||
|
ErrorMetric m_errormetric;
|
||||||
|
float m_fEffort;
|
||||||
|
// stats
|
||||||
|
int m_iEncodeTime_ms;
|
||||||
|
|
||||||
|
SortedBlockList *m_psortedblocklist;
|
||||||
|
//this will hold any warning or errors that happen during encoding
|
||||||
|
EncodingStatus m_encodingStatus;
|
||||||
|
//these will be the warnings we are tracking
|
||||||
|
EncodingStatus m_warningsToCapture;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
85
thirdparty/etc2comp/EtcIndividualTrys.cpp
vendored
Normal file
85
thirdparty/etc2comp/EtcIndividualTrys.cpp
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcIndividualTrys.cpp
|
||||||
|
|
||||||
|
Gathers the results of the various encoding trys for both halves of a 4x4 block for Individual mode
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcIndividualTrys.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// construct a list of trys (encoding attempts)
|
||||||
|
//
|
||||||
|
// a_frgbaColor1 is the basecolor for the first half
|
||||||
|
// a_frgbaColor2 is the basecolor for the second half
|
||||||
|
// a_pauiPixelMapping1 is the pixel order for the first half
|
||||||
|
// a_pauiPixelMapping2 is the pixel order for the second half
|
||||||
|
// a_uiRadius is the amount to vary the base colors
|
||||||
|
//
|
||||||
|
IndividualTrys::IndividualTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
|
||||||
|
const unsigned int *a_pauiPixelMapping1,
|
||||||
|
const unsigned int *a_pauiPixelMapping2,
|
||||||
|
unsigned int a_uiRadius)
|
||||||
|
{
|
||||||
|
assert(a_uiRadius <= MAX_RADIUS);
|
||||||
|
|
||||||
|
ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR4G4B4();
|
||||||
|
ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR4G4B4();
|
||||||
|
|
||||||
|
// quantize base colors
|
||||||
|
// ensure that trys with a_uiRadius don't overflow
|
||||||
|
int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(15.0f), a_uiRadius);
|
||||||
|
int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(15.0f), a_uiRadius);
|
||||||
|
int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(15.0f), a_uiRadius);
|
||||||
|
int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(15.0f), a_uiRadius);
|
||||||
|
int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(15.0f), a_uiRadius);
|
||||||
|
int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(15.0f), a_uiRadius);
|
||||||
|
|
||||||
|
m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
|
||||||
|
m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
void IndividualTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||||
|
const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
|
||||||
|
{
|
||||||
|
|
||||||
|
m_iRed = a_iRed;
|
||||||
|
m_iGreen = a_iGreen;
|
||||||
|
m_iBlue = a_iBlue;
|
||||||
|
|
||||||
|
m_pauiPixelMapping = a_pauiPixelMapping;
|
||||||
|
m_uiRadius = a_uiRadius;
|
||||||
|
|
||||||
|
m_uiTrys = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
95
thirdparty/etc2comp/EtcIndividualTrys.h
vendored
Normal file
95
thirdparty/etc2comp/EtcIndividualTrys.h
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "EtcColorFloatRGBA.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
class IndividualTrys
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int MAX_RADIUS = 1;
|
||||||
|
|
||||||
|
IndividualTrys(ColorFloatRGBA a_frgbaColor1,
|
||||||
|
ColorFloatRGBA a_frgbaColor2,
|
||||||
|
const unsigned int *a_pauiPixelMapping1,
|
||||||
|
const unsigned int *a_pauiPixelMapping2,
|
||||||
|
unsigned int a_uiRadius);
|
||||||
|
|
||||||
|
inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
|
||||||
|
{
|
||||||
|
if (a_i < (0+ a_iDistance))
|
||||||
|
{
|
||||||
|
return (0 + a_iDistance);
|
||||||
|
}
|
||||||
|
else if (a_i > (15- a_iDistance))
|
||||||
|
{
|
||||||
|
return (15 - a_iDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return a_i;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Try
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
static const unsigned int SELECTORS = 8; // per half
|
||||||
|
|
||||||
|
int m_iRed;
|
||||||
|
int m_iGreen;
|
||||||
|
int m_iBlue;
|
||||||
|
unsigned int m_uiCW;
|
||||||
|
unsigned int m_auiSelectors[SELECTORS];
|
||||||
|
float m_fError;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Half
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const unsigned int MAX_TRYS = 27;
|
||||||
|
|
||||||
|
void Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||||
|
const unsigned int *a_pauiPixelMapping,
|
||||||
|
unsigned int a_uiRadius);
|
||||||
|
|
||||||
|
// center of trys
|
||||||
|
int m_iRed;
|
||||||
|
int m_iGreen;
|
||||||
|
int m_iBlue;
|
||||||
|
|
||||||
|
const unsigned int *m_pauiPixelMapping;
|
||||||
|
unsigned int m_uiRadius;
|
||||||
|
|
||||||
|
unsigned int m_uiTrys;
|
||||||
|
Try m_atry[MAX_TRYS];
|
||||||
|
|
||||||
|
Try *m_ptryBest;
|
||||||
|
};
|
||||||
|
|
||||||
|
Half m_half1;
|
||||||
|
Half m_half2;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
64
thirdparty/etc2comp/EtcMath.cpp
vendored
Normal file
64
thirdparty/etc2comp/EtcMath.cpp
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcMath.h"
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// calculate the line that best fits the set of XY points contained in a_afX[] and a_afY[]
|
||||||
|
// use a_fSlope and a_fOffset to define that line
|
||||||
|
//
|
||||||
|
bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
|
||||||
|
float *a_fSlope, float *a_fOffset)
|
||||||
|
{
|
||||||
|
float fPoints = (float)a_Points;
|
||||||
|
|
||||||
|
float fSumX = 0.0f;
|
||||||
|
float fSumY = 0.0f;
|
||||||
|
float fSumXY = 0.0f;
|
||||||
|
float fSumX2 = 0.0f;
|
||||||
|
|
||||||
|
for (unsigned int uiPoint = 0; uiPoint < a_Points; uiPoint++)
|
||||||
|
{
|
||||||
|
fSumX += a_afX[uiPoint];
|
||||||
|
fSumY += a_afY[uiPoint];
|
||||||
|
fSumXY += a_afX[uiPoint] * a_afY[uiPoint];
|
||||||
|
fSumX2 += a_afX[uiPoint] * a_afX[uiPoint];
|
||||||
|
}
|
||||||
|
|
||||||
|
float fDivisor = fPoints*fSumX2 - fSumX*fSumX;
|
||||||
|
|
||||||
|
// if vertical line
|
||||||
|
if (fDivisor == 0.0f)
|
||||||
|
{
|
||||||
|
*a_fSlope = 0.0f;
|
||||||
|
*a_fOffset = 0.0f;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*a_fSlope = (fPoints*fSumXY - fSumX*fSumY) / fDivisor;
|
||||||
|
*a_fOffset = (fSumY - (*a_fSlope)*fSumX) / fPoints;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
40
thirdparty/etc2comp/EtcMath.h
vendored
Normal file
40
thirdparty/etc2comp/EtcMath.h
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// return true if vertical line
|
||||||
|
bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
|
||||||
|
float *a_fSlope, float *a_fOffset);
|
||||||
|
|
||||||
|
inline float ConvertMSEToPSNR(float a_fMSE)
|
||||||
|
{
|
||||||
|
if (a_fMSE == 0.0f)
|
||||||
|
{
|
||||||
|
return INFINITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 10.0f * log10f(1.0f / a_fMSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
228
thirdparty/etc2comp/EtcSortedBlockList.cpp
vendored
Normal file
228
thirdparty/etc2comp/EtcSortedBlockList.cpp
vendored
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EtcSortedBlockList.cpp
|
||||||
|
|
||||||
|
SortedBlockList is a list of 4x4 blocks that can be used by the "effort" system to prioritize
|
||||||
|
the encoding of the 4x4 blocks.
|
||||||
|
|
||||||
|
The sorting is done with buckets, where each bucket is an indication of how much error each 4x4 block has
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EtcConfig.h"
|
||||||
|
#include "EtcSortedBlockList.h"
|
||||||
|
|
||||||
|
#include "EtcBlock4x4.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// construct an empty list
|
||||||
|
//
|
||||||
|
// allocate enough memory to add all of the image's 4x4 blocks later
|
||||||
|
// allocate enough buckets to sort the blocks
|
||||||
|
//
|
||||||
|
SortedBlockList::SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets)
|
||||||
|
{
|
||||||
|
m_uiImageBlocks = a_uiImageBlocks;
|
||||||
|
m_iBuckets = (int)a_uiBuckets;
|
||||||
|
|
||||||
|
m_uiAddedBlocks = 0;
|
||||||
|
m_uiSortedBlocks = 0;
|
||||||
|
m_palinkPool = new Link[m_uiImageBlocks];
|
||||||
|
m_pabucket = new Bucket[m_iBuckets];
|
||||||
|
m_fMaxError = 0.0f;
|
||||||
|
|
||||||
|
InitBuckets();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
SortedBlockList::~SortedBlockList(void)
|
||||||
|
{
|
||||||
|
delete[] m_palinkPool;
|
||||||
|
delete[] m_pabucket;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// add a 4x4 block to the list
|
||||||
|
// the 4x4 block will be sorted later
|
||||||
|
//
|
||||||
|
void SortedBlockList::AddBlock(Block4x4 *a_pblock)
|
||||||
|
{
|
||||||
|
assert(m_uiAddedBlocks < m_uiImageBlocks);
|
||||||
|
Link *plink = &m_palinkPool[m_uiAddedBlocks++];
|
||||||
|
plink->Init(a_pblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// sort all of the 4x4 blocks that have been added to the list
|
||||||
|
//
|
||||||
|
// first, determine the maximum error, then assign an error range to each bucket
|
||||||
|
// next, determine which bucket each 4x4 block belongs to based on the 4x4 block's error
|
||||||
|
// add the 4x4 block to the appropriate bucket
|
||||||
|
// lastly, walk thru the buckets and add each bucket to a sorted linked list
|
||||||
|
//
|
||||||
|
// the resultant sorting is an approximate sorting from most to least error
|
||||||
|
//
|
||||||
|
void SortedBlockList::Sort(void)
|
||||||
|
{
|
||||||
|
assert(m_uiAddedBlocks == m_uiImageBlocks);
|
||||||
|
InitBuckets();
|
||||||
|
|
||||||
|
// find max block error
|
||||||
|
m_fMaxError = -1.0f;
|
||||||
|
|
||||||
|
for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
|
||||||
|
{
|
||||||
|
Link *plinkBlock = &m_palinkPool[uiLink];
|
||||||
|
|
||||||
|
float fBlockError = plinkBlock->GetBlock()->GetError();
|
||||||
|
if (fBlockError > m_fMaxError)
|
||||||
|
{
|
||||||
|
m_fMaxError = fBlockError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prevent divide by zero or divide by negative
|
||||||
|
if (m_fMaxError <= 0.0f)
|
||||||
|
{
|
||||||
|
m_fMaxError = 1.0f;
|
||||||
|
}
|
||||||
|
//used for debugging
|
||||||
|
//int numDone = 0;
|
||||||
|
// put all of the blocks with unfinished encodings into the appropriate bucket
|
||||||
|
m_uiSortedBlocks = 0;
|
||||||
|
for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
|
||||||
|
{
|
||||||
|
Link *plinkBlock = &m_palinkPool[uiLink];
|
||||||
|
|
||||||
|
// if the encoding is done, don't add it to the list
|
||||||
|
if (plinkBlock->GetBlock()->GetEncoding()->IsDone())
|
||||||
|
{
|
||||||
|
//numDone++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the appropriate sort bucket
|
||||||
|
float fBlockError = plinkBlock->GetBlock()->GetError();
|
||||||
|
int iBucket = (int) floorf(m_iBuckets * fBlockError / m_fMaxError);
|
||||||
|
// clamp to bucket index
|
||||||
|
iBucket = iBucket < 0 ? 0 : iBucket >= m_iBuckets ? m_iBuckets - 1 : iBucket;
|
||||||
|
|
||||||
|
// add block to bucket
|
||||||
|
{
|
||||||
|
Bucket *pbucket = &m_pabucket[iBucket];
|
||||||
|
if (pbucket->plinkLast)
|
||||||
|
{
|
||||||
|
pbucket->plinkLast->SetNext(plinkBlock);
|
||||||
|
pbucket->plinkLast = plinkBlock;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pbucket->plinkFirst = pbucket->plinkLast = plinkBlock;
|
||||||
|
}
|
||||||
|
plinkBlock->SetNext(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_uiSortedBlocks++;
|
||||||
|
|
||||||
|
if (0)
|
||||||
|
{
|
||||||
|
printf("%u: e=%.3f\n", uiLink, fBlockError);
|
||||||
|
Print();
|
||||||
|
printf("\n\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//printf("num blocks already done: %d\n",numDone);
|
||||||
|
//link the blocks together across buckets
|
||||||
|
m_plinkFirst = nullptr;
|
||||||
|
m_plinkLast = nullptr;
|
||||||
|
for (int iBucket = m_iBuckets - 1; iBucket >= 0; iBucket--)
|
||||||
|
{
|
||||||
|
Bucket *pbucket = &m_pabucket[iBucket];
|
||||||
|
|
||||||
|
if (pbucket->plinkFirst)
|
||||||
|
{
|
||||||
|
if (m_plinkFirst == nullptr)
|
||||||
|
{
|
||||||
|
m_plinkFirst = pbucket->plinkFirst;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(pbucket->plinkLast->GetNext() == nullptr);
|
||||||
|
m_plinkLast->SetNext(pbucket->plinkFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_plinkLast = pbucket->plinkLast;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// clear all of the buckets. normally done in preparation for a sort
|
||||||
|
//
|
||||||
|
void SortedBlockList::InitBuckets(void)
|
||||||
|
{
|
||||||
|
for (int iBucket = 0; iBucket < m_iBuckets; iBucket++)
|
||||||
|
{
|
||||||
|
Bucket *pbucket = &m_pabucket[iBucket];
|
||||||
|
|
||||||
|
pbucket->plinkFirst = 0;
|
||||||
|
pbucket->plinkLast = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
// print out the list of sorted 4x4 blocks
|
||||||
|
// normally used for debugging
|
||||||
|
//
|
||||||
|
void SortedBlockList::Print(void)
|
||||||
|
{
|
||||||
|
for (int iBucket = m_iBuckets-1; iBucket >= 0; iBucket--)
|
||||||
|
{
|
||||||
|
Bucket *pbucket = &m_pabucket[iBucket];
|
||||||
|
|
||||||
|
unsigned int uiBlocks = 0;
|
||||||
|
for (Link *plink = pbucket->plinkFirst; plink != nullptr; plink = plink->GetNext() )
|
||||||
|
{
|
||||||
|
uiBlocks++;
|
||||||
|
|
||||||
|
if (plink == pbucket->plinkLast)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float fBucketError = m_fMaxError * iBucket / m_iBuckets;
|
||||||
|
float fBucketRMS = sqrtf(fBucketError / (4.0f*16.0f) );
|
||||||
|
printf("%3d: e=%.3f rms=%.6f %u\n", iBucket, fBucketError, fBucketRMS, uiBlocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
} // namespace Etc
|
124
thirdparty/etc2comp/EtcSortedBlockList.h
vendored
Normal file
124
thirdparty/etc2comp/EtcSortedBlockList.h
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 The Etc2Comp Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Etc
|
||||||
|
{
|
||||||
|
class Block4x4;
|
||||||
|
|
||||||
|
class SortedBlockList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class Link
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline void Init(Block4x4 *a_pblock)
|
||||||
|
{
|
||||||
|
m_pblock = a_pblock;
|
||||||
|
m_plinkNext = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Block4x4 * GetBlock(void)
|
||||||
|
{
|
||||||
|
return m_pblock;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetNext(Link *a_plinkNext)
|
||||||
|
{
|
||||||
|
m_plinkNext = a_plinkNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Link * GetNext(void)
|
||||||
|
{
|
||||||
|
return m_plinkNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Link * Advance(unsigned int a_uiSteps = 1)
|
||||||
|
{
|
||||||
|
Link *plink = this;
|
||||||
|
|
||||||
|
for (unsigned int uiStep = 0; uiStep < a_uiSteps; uiStep++)
|
||||||
|
{
|
||||||
|
if (plink == nullptr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
plink = plink->m_plinkNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plink;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Block4x4 *m_pblock;
|
||||||
|
Link *m_plinkNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets);
|
||||||
|
~SortedBlockList(void);
|
||||||
|
|
||||||
|
void AddBlock(Block4x4 *a_pblock);
|
||||||
|
|
||||||
|
void Sort(void);
|
||||||
|
|
||||||
|
inline Link * GetLinkToFirstBlock(void)
|
||||||
|
{
|
||||||
|
return m_plinkFirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetNumberOfAddedBlocks(void)
|
||||||
|
{
|
||||||
|
return m_uiAddedBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetNumberOfSortedBlocks(void)
|
||||||
|
{
|
||||||
|
return m_uiSortedBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Print(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void InitBuckets(void);
|
||||||
|
|
||||||
|
class Bucket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link *plinkFirst;
|
||||||
|
Link *plinkLast;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int m_uiImageBlocks;
|
||||||
|
int m_iBuckets;
|
||||||
|
|
||||||
|
unsigned int m_uiAddedBlocks;
|
||||||
|
unsigned int m_uiSortedBlocks;
|
||||||
|
Link *m_palinkPool;
|
||||||
|
Bucket *m_pabucket;
|
||||||
|
float m_fMaxError;
|
||||||
|
|
||||||
|
Link *m_plinkFirst;
|
||||||
|
Link *m_plinkLast;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Etc
|
202
thirdparty/etc2comp/LICENSE
vendored
Normal file
202
thirdparty/etc2comp/LICENSE
vendored
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
197
thirdparty/etc2comp/README.md
vendored
Normal file
197
thirdparty/etc2comp/README.md
vendored
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
# Etc2Comp - Texture to ETC2 compressor
|
||||||
|
|
||||||
|
Etc2Comp is a command line tool that converts textures (e.g. bitmaps)
|
||||||
|
into the [ETC2](https://en.wikipedia.org/wiki/Ericsson_Texture_Compression)
|
||||||
|
format. The tool is built with a focus on encoding performance
|
||||||
|
to reduce the amount of time required to compile asset heavy applications as
|
||||||
|
well as reduce overall application size.
|
||||||
|
|
||||||
|
This repo provides source code that can be compiled into a binary. The
|
||||||
|
binary can then be used to convert textures to the ETC2 format.
|
||||||
|
|
||||||
|
Important: This is not an official Google product. It is an experimental
|
||||||
|
library published as-is. Please see the CONTRIBUTORS.md file for information
|
||||||
|
about questions or issues.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
This project uses [CMake](https://cmake.org/) to generate platform-specific
|
||||||
|
build files:
|
||||||
|
- Linux: make files
|
||||||
|
- OS X: Xcode workspace files
|
||||||
|
- Microsoft Windows: Visual Studio solution files
|
||||||
|
- Note: CMake supports other formats, but this doc only provides steps for
|
||||||
|
one of each platform for brevity.
|
||||||
|
|
||||||
|
Refer to each platform's setup section to setup your environment and build
|
||||||
|
an Etc2Comp binary. Then skip to the usage section of this page for examples
|
||||||
|
of how to use the library.
|
||||||
|
|
||||||
|
### Setup for OS X
|
||||||
|
build tested on this config:
|
||||||
|
OS X 10.9.5 i7 16GB RAM
|
||||||
|
Xcode 5.1.1
|
||||||
|
cmake 3.2.3
|
||||||
|
|
||||||
|
Start by downloading and installing the following components if they are not
|
||||||
|
already installed on your development machine.
|
||||||
|
- *Xcode* version 5.1.1, or greater
|
||||||
|
- [CMake](https://cmake.org/download/) version 3.2.3, or greater
|
||||||
|
|
||||||
|
To build the Etc2Comp binary:
|
||||||
|
1. Open a *Terminal* window and navigate to the project directory.
|
||||||
|
1. Run `mkdir build_xcode`
|
||||||
|
1. Run `cd build_xcode`
|
||||||
|
1. Run `cmake -G Xcode ../`
|
||||||
|
1. Open *Xcode* and import the `build_xcode/EtcTest.xcodeproj` file.
|
||||||
|
1. Open the Product menu and choose Build For -> Running.
|
||||||
|
1. Once the build succeeds the binary located at `build_xcode/EtcTool/Debug/EtcTool`
|
||||||
|
can be executed.
|
||||||
|
|
||||||
|
Optional
|
||||||
|
Xcode EtcTool ‘Run’ preferences
|
||||||
|
note: if the build_xcode/EtcTest.xcodeproj is manually deleted then some Xcode preferences
|
||||||
|
will need to be set by hand after cmake is run (these prefs are retained across
|
||||||
|
cmake updates if the .xcodeproj is not deleted/removed)
|
||||||
|
|
||||||
|
1. Set the active scheme to ‘EtcTool’
|
||||||
|
1. Edit the scheme
|
||||||
|
1. Select option ‘Run EtcTool’, then tab ‘Arguments’.
|
||||||
|
Add this launch argument: ‘-argfile ../../EtcTool/args.txt’
|
||||||
|
1. Select tab ‘Options’ and set a custom working directory to: ‘$(SRCROOT)/Build_Xcode/EtcTool’
|
||||||
|
|
||||||
|
### SetUp for Windows
|
||||||
|
|
||||||
|
1. Open a *Terminal* window and navigate to the project directory.
|
||||||
|
1. Run `mkdir build_vs`
|
||||||
|
1. Run `cd build_vs`
|
||||||
|
1. Run CMAKE, noting what build version you need, and pointing to the parent directory as the source root;
|
||||||
|
For VS 2013 : `cmake -G "Visual Studio 12 2013 Win64" ../`
|
||||||
|
For VS 2015 : `cmake -G "Visual Studio 14 2015 Win64" ../`
|
||||||
|
NOTE: To see what supported Visual Studio outputs there are, run `cmake -G`
|
||||||
|
1. open the 'EtcTest' solution
|
||||||
|
1. make the 'EtcTool' project the start up project
|
||||||
|
1. (optional) in the project properties, under 'Debugging ->command arguments'
|
||||||
|
add the argfile textfile thats included in the EtcTool directory.
|
||||||
|
example: -argfile C:\etc2\EtcTool\Args.txt
|
||||||
|
|
||||||
|
### Setup For Linux
|
||||||
|
The Linux build was tested on this config:
|
||||||
|
Ubuntu desktop 14.04
|
||||||
|
gcc/g++ 4.8
|
||||||
|
cmake 2.8.12.2
|
||||||
|
|
||||||
|
1. Verify linux has cmake and C++-11 capable g++ installed
|
||||||
|
1. Open shell
|
||||||
|
1. Run `mkdir build_linux`
|
||||||
|
1. Run `cd build_linux`
|
||||||
|
1. Run `cmake ../`
|
||||||
|
1. Run `make`
|
||||||
|
1. navigate to the newly created EtcTool directory `cd EtcTool`
|
||||||
|
1. run the executable: `./EtcTool -argfile ../../EtcTool/args.txt`
|
||||||
|
|
||||||
|
Skip to the <a href="#usage">Usage</a> section for more information about using the
|
||||||
|
tool.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Command Line Usage
|
||||||
|
EtcTool can be run from the command line with the following usage:
|
||||||
|
etctool.exe source_image [options ...] -output encoded_image
|
||||||
|
|
||||||
|
The encoder will use an array of RGBA floats read from the source_image to create
|
||||||
|
an ETC1 or ETC2 encoded image in encoded_image. The RGBA floats should be in the
|
||||||
|
range [0:1].
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
-analyze <analysis_folder>
|
||||||
|
-argfile <arg_file> additional command line arguments read from a file
|
||||||
|
-blockAtHV <H V> encodes a single block that contains the
|
||||||
|
pixel specified by the H V coordinates
|
||||||
|
-compare <comparison_image> compares source_image to comparison_image
|
||||||
|
-effort <amount> number between 0 and 100 to specify the encoding quality
|
||||||
|
(100 is the highest quality)
|
||||||
|
-errormetric <error_metric> specify the error metric, the options are
|
||||||
|
rgba, rgbx, rec709, numeric and normalxyz
|
||||||
|
-format <etc_format> ETC1, RGB8, SRGB8, RGBA8, SRGB8, RGB8A1,
|
||||||
|
SRGB8A1 or R11
|
||||||
|
-help prints this message
|
||||||
|
-jobs or -j <thread_count> specifies the number of threads (default=1)
|
||||||
|
-normalizexyz normalize RGB to have a length of 1
|
||||||
|
-verbose or -v shows status information during the encoding
|
||||||
|
process
|
||||||
|
-mipmaps or -m <mip_count> sets the maximum number of mipaps to generate (default=1)
|
||||||
|
-mipwrap or -w <x|y|xy> sets the mipmap filter wrap mode (default=clamp)
|
||||||
|
|
||||||
|
* -analyze will run an analysis of the encoding and place it in folder
|
||||||
|
"analysis_folder" (e.g. ../analysis/kodim05). within the analysis_folder, a folder
|
||||||
|
will be created with a name of the current date/time (e.g. 20151204_153306). this
|
||||||
|
date/time folder is used to compare encodings of the same texture over time.
|
||||||
|
within the date/time folder is a text file with several encoding stats and a 2x png
|
||||||
|
image showing the encoding mode for each 4x4 block.
|
||||||
|
|
||||||
|
* -argfile allows additional command line arguments to be placed in a text file
|
||||||
|
|
||||||
|
* -blockAtHV selects the 4x4 pixel subset of the source image at position (H,V).
|
||||||
|
This is mainly used for debugging
|
||||||
|
|
||||||
|
* -compare compares the source image to the created encoded image. The encoding
|
||||||
|
will dictate what error analysis is used in the comparison.
|
||||||
|
|
||||||
|
* -effort uses an "amount" between 0 and 100 to determine how much additional effort
|
||||||
|
to apply during the encoding.
|
||||||
|
|
||||||
|
* -errormetric selects the fitting algorithm used by the encoder. "rgba" calculates
|
||||||
|
RMS error using RGB components that are weighted by A. "rgbx" calculates RMS error
|
||||||
|
using RGBA components, where A is treated as an additional data channel, instead of
|
||||||
|
as alpha. "rec709" is similar to "rgba", except the RGB components are also weighted
|
||||||
|
according to Rec709. "numeric" calculates RMS error using unweighted RGBA components.
|
||||||
|
"normalize" calculates error based on dot product and vector length for RGB and RMS
|
||||||
|
error for A.
|
||||||
|
|
||||||
|
* -help prints out the usage message
|
||||||
|
|
||||||
|
* -jobs enables multi-threading to speed up image encoding
|
||||||
|
|
||||||
|
* -normalizexyz normalizes the source RGB to have a length of 1.
|
||||||
|
|
||||||
|
* -verbose shows information on the current encoding process. It will then display the
|
||||||
|
PSNR and time time it took to encode the image.
|
||||||
|
|
||||||
|
* -mipmaps takes an argument that specifies how many mipmaps to generate from the
|
||||||
|
source image. The mipmaps are generated with a lanczos3 filter using edge clamping.
|
||||||
|
If the mipmaps option is not specified no mipmaps are created.
|
||||||
|
|
||||||
|
* -mipwrap takes an argument that specifies the mipmap filter wrap mode. The options
|
||||||
|
are "x", "y" and "xy" which specify wrapping in x only, y only or x and y respectively.
|
||||||
|
The default options are clamping in both x and y.
|
||||||
|
|
||||||
|
Note: Path names can use slashes or backslashes. The tool will convert the
|
||||||
|
slashes to the appropriate polarity for the current platform.
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
The library supports two different APIs - a C-like API that is not heavily
|
||||||
|
class-based and a class-based API.
|
||||||
|
|
||||||
|
main() in EtcTool.cpp contains an example of both APIs.
|
||||||
|
|
||||||
|
The Encode() method now returns an EncodingStatus that contains bit flags for
|
||||||
|
reporting various warnings and flags encountered when encoding.
|
||||||
|
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
Copyright 2015 Etc2Comp Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
2446
thirdparty/rg-etc1/rg_etc1.cpp
vendored
2446
thirdparty/rg-etc1/rg_etc1.cpp
vendored
File diff suppressed because it is too large
Load diff
76
thirdparty/rg-etc1/rg_etc1.h
vendored
76
thirdparty/rg-etc1/rg_etc1.h
vendored
|
@ -1,76 +0,0 @@
|
||||||
// File: rg_etc1.h - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
|
|
||||||
// Please see ZLIB license at the end of this file.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace rg_etc1
|
|
||||||
{
|
|
||||||
// Unpacks an 8-byte ETC1 compressed block to a block of 4x4 32bpp RGBA pixels.
|
|
||||||
// Returns false if the block is invalid. Invalid blocks will still be unpacked with clamping.
|
|
||||||
// This function is thread safe, and does not dynamically allocate any memory.
|
|
||||||
// If preserve_alpha is true, the alpha channel of the destination pixels will not be overwritten. Otherwise, alpha will be set to 255.
|
|
||||||
bool unpack_etc1_block(const void *pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha = false);
|
|
||||||
|
|
||||||
// Quality setting = the higher the quality, the slower.
|
|
||||||
// To pack large textures, it is highly recommended to call pack_etc1_block() in parallel, on different blocks, from multiple threads (particularly when using cHighQuality).
|
|
||||||
enum etc1_quality
|
|
||||||
{
|
|
||||||
cLowQuality,
|
|
||||||
cMediumQuality,
|
|
||||||
cHighQuality,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct etc1_pack_params
|
|
||||||
{
|
|
||||||
etc1_quality m_quality;
|
|
||||||
bool m_dithering;
|
|
||||||
|
|
||||||
inline etc1_pack_params()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_quality = cHighQuality;
|
|
||||||
m_dithering = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Important: pack_etc1_block_init() must be called before calling pack_etc1_block().
|
|
||||||
void pack_etc1_block_init();
|
|
||||||
|
|
||||||
// Packs a 4x4 block of 32bpp RGBA pixels to an 8-byte ETC1 block.
|
|
||||||
// 32-bit RGBA pixels must always be arranged as (R,G,B,A) (R first, A last) in memory, independent of platform endianness. A should always be 255.
|
|
||||||
// Returns squared error of result.
|
|
||||||
// This function is thread safe, and does not dynamically allocate any memory.
|
|
||||||
// pack_etc1_block() does not currently support "perceptual" colorspace metrics - it primarily optimizes for RGB RMSE.
|
|
||||||
unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params);
|
|
||||||
|
|
||||||
} // namespace rg_etc1
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// rg_etc1 uses the ZLIB license:
|
|
||||||
// http://opensource.org/licenses/Zlib
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012 Rich Geldreich
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
//------------------------------------------------------------------------------
|
|
Loading…
Reference in a new issue