Merge pull request #8548 from tagcup/etc2comp
Add ETC1/ETC2 compression support though etc2comp.
This commit is contained in:
commit
a8e845a474
|
@ -1,5 +1,7 @@
|
|||
language: cpp
|
||||
|
||||
dist: trusty
|
||||
|
||||
sudo: false
|
||||
|
||||
compiler:
|
||||
|
@ -73,7 +75,6 @@ addons:
|
|||
# For style checks.
|
||||
- clang-format-3.9
|
||||
|
||||
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install scons; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$GODOT_TARGET" = "android" ]; then
|
||||
|
@ -86,5 +87,9 @@ script:
|
|||
- if [ "$STATIC_CHECKS" = "yes" ]; then
|
||||
sh ./misc/travis/clang-format.sh;
|
||||
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
|
||||
|
|
|
@ -1483,16 +1483,16 @@ Error Image::decompress() {
|
|||
_image_decompress_bc(this);
|
||||
else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc)
|
||||
_image_decompress_pvrtc(this);
|
||||
else if (format == FORMAT_ETC && _image_decompress_etc)
|
||||
_image_decompress_etc(this);
|
||||
else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc)
|
||||
else if (format == FORMAT_ETC && _image_decompress_etc1)
|
||||
_image_decompress_etc1(this);
|
||||
else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc1)
|
||||
_image_decompress_etc2(this);
|
||||
else
|
||||
return ERR_UNAVAILABLE;
|
||||
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) {
|
||||
|
||||
|
@ -1513,13 +1513,13 @@ Error Image::compress(CompressMode p_mode, bool p_for_srgb) {
|
|||
} break;
|
||||
case COMPRESS_ETC: {
|
||||
|
||||
ERR_FAIL_COND_V(!_image_compress_etc_func, ERR_UNAVAILABLE);
|
||||
_image_compress_etc_func(this);
|
||||
ERR_FAIL_COND_V(!_image_compress_etc1_func, ERR_UNAVAILABLE);
|
||||
_image_compress_etc1_func(this, p_lossy_quality);
|
||||
} break;
|
||||
case COMPRESS_ETC2: {
|
||||
|
||||
ERR_FAIL_COND_V(!_image_compress_etc_func, ERR_UNAVAILABLE);
|
||||
_image_compress_etc_func(this);
|
||||
ERR_FAIL_COND_V(!_image_compress_etc2_func, ERR_UNAVAILABLE);
|
||||
_image_compress_etc2_func(this, p_lossy_quality);
|
||||
} 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_pvrtc2_func)(Image *) = NULL;
|
||||
void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL;
|
||||
void (*Image::_image_compress_etc_func)(Image *) = NULL;
|
||||
void (*Image::_image_compress_etc2_func)(Image *) = NULL;
|
||||
void (*Image::_image_compress_etc1_func)(Image *, float) = NULL;
|
||||
void (*Image::_image_compress_etc2_func)(Image *, float) = NULL;
|
||||
void (*Image::_image_decompress_pvrtc)(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;
|
||||
|
||||
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_pvrtc2_func)(Image *);
|
||||
static void (*_image_compress_pvrtc4_func)(Image *);
|
||||
static void (*_image_compress_etc_func)(Image *);
|
||||
static void (*_image_compress_etc2_func)(Image *);
|
||||
static void (*_image_compress_etc1_func)(Image *, float);
|
||||
static void (*_image_compress_etc2_func)(Image *, float);
|
||||
|
||||
static void (*_image_decompress_pvrtc)(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 PoolVector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality);
|
||||
|
@ -267,7 +267,7 @@ public:
|
|||
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();
|
||||
bool is_compressed() const;
|
||||
|
||||
|
|
|
@ -110,6 +110,15 @@ public:
|
|||
static _ALWAYS_INLINE_ bool is_inf(double p_val) {
|
||||
#ifdef _MSC_VER
|
||||
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
|
||||
return isinf(p_val);
|
||||
#endif
|
||||
|
@ -118,6 +127,14 @@ public:
|
|||
static _ALWAYS_INLINE_ bool is_inf(float p_val) {
|
||||
#ifdef _MSC_VER
|
||||
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
|
||||
return isinf(p_val);
|
||||
#endif
|
||||
|
|
|
@ -18490,8 +18490,10 @@
|
|||
</return>
|
||||
<argument index="0" name="format" type="int" default="0">
|
||||
</argument>
|
||||
<argument index="0" name="quality" type="float" default="0">
|
||||
</argument>
|
||||
<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>
|
||||
</method>
|
||||
<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 {
|
||||
|
||||
if (p_option == "compress/lossy_quality" && int(p_options["compress/mode"]) != COMPRESS_LOSSY)
|
||||
return false;
|
||||
if (p_option == "compress/lossy_quality") {
|
||||
int compress_mode = int(p_options["compress/mode"]);
|
||||
if (compress_mode != COMPRESS_LOSSY && compress_mode != COMPRESS_VIDEO_RAM) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
image->convert(Image::FORMAT_RGBE9995);
|
||||
} 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();
|
||||
|
@ -382,8 +386,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
|||
//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);
|
||||
r_platform_variants->push_back("etc");
|
||||
//_save_stex(image,p_save_path+".etc2.stex",compress_mode,lossy,Image::COMPRESS_ETC2,mipmaps,tex_flags,stream);
|
||||
//r_platform_variants->push_back("etc2");
|
||||
_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");
|
||||
_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");
|
||||
|
||||
|
|
|
@ -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")
|
|
@ -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
|
||||
#define IMAGE_ETC1_H
|
||||
|
||||
void _register_etc1_compress_func();
|
||||
void _register_etc_compress_func();
|
||||
|
||||
#endif // IMAGE_ETC_H
|
|
@ -34,15 +34,15 @@
|
|||
|
||||
static ResourceFormatPKM *resource_loader_pkm = NULL;
|
||||
|
||||
void register_etc1_types() {
|
||||
void register_etc_types() {
|
||||
|
||||
resource_loader_pkm = memnew(ResourceFormatPKM);
|
||||
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);
|
||||
}
|
|
@ -27,5 +27,5 @@
|
|||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
void register_etc1_types();
|
||||
void unregister_etc1_types();
|
||||
void register_etc_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;
|
||||
}
|
|
@ -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.
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
- Upstream: ?
|
||||
|
@ -296,17 +308,6 @@ Files extracted from upstream source:
|
|||
- 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
|
||||
|
||||
- Upstream: http://www.music.mcgill.ca/~gary/rtaudio/
|
||||
|
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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 "???";
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
File diff suppressed because it is too large
Load Diff
|
@ -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 New Issue