summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorK. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>2021-04-06 22:05:56 -0700
committerRémi Verschelde <rverschelde@gmail.com>2021-04-13 00:12:12 +0200
commitd840165a324b5c218ca3a4882f030986855c8383 (patch)
tree7c5f4b091ecc647f2b6ed48135945f84c6dc2de9
parentb895071895cffcbcda7f4156d7175ba5b8068852 (diff)
Add `etcpak` library for faster ETC/ETC2/S3TC imports.
- `etc` module was renamed to `etcpak` and modified to use the new library. - PKM importer is removed in the process, it's obsolete. - Old library `etc2comp` is removed. - S3TC compression no longer done via `squish` (but decompression still is). - Slight modifications to etcpak sources for MinGW compatibility, to fix LLVM `-Wc++11-narrowing` errors, and to allow using vendored or system libpng. Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
-rw-r--r--COPYRIGHT.txt8
-rw-r--r--modules/etc/SCsub48
-rw-r--r--modules/etc/image_compress_etc.cpp226
-rw-r--r--modules/etc/texture_loader_pkm.cpp114
-rw-r--r--modules/etc/texture_loader_pkm.h47
-rw-r--r--modules/etcpak/SCsub52
-rw-r--r--modules/etcpak/config.py (renamed from modules/etc/config.py)0
-rw-r--r--modules/etcpak/image_etcpak.cpp170
-rw-r--r--modules/etcpak/image_etcpak.h (renamed from modules/etc/register_types.cpp)33
-rw-r--r--modules/etcpak/register_types.cpp (renamed from modules/etc/image_compress_etc.h)16
-rw-r--r--modules/etcpak/register_types.h (renamed from modules/etc/register_types.h)9
-rw-r--r--modules/squish/image_compress_squish.cpp80
-rw-r--r--modules/squish/image_compress_squish.h1
-rw-r--r--modules/squish/register_types.cpp1
-rw-r--r--thirdparty/README.md20
-rw-r--r--thirdparty/etc2comp/AUTHORS7
-rw-r--r--thirdparty/etc2comp/Etc.cpp128
-rw-r--r--thirdparty/etc2comp/Etc.h71
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4.cpp425
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4.h172
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding.cpp261
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding.h148
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4EncodingBits.h315
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp1281
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h186
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp429
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h122
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp447
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h86
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp1730
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h96
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp1819
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h129
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp474
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h121
-rw-r--r--thirdparty/etc2comp/EtcColor.h64
-rw-r--r--thirdparty/etc2comp/EtcColorFloatRGBA.h321
-rw-r--r--thirdparty/etc2comp/EtcConfig.h67
-rw-r--r--thirdparty/etc2comp/EtcDifferentialTrys.cpp173
-rw-r--r--thirdparty/etc2comp/EtcDifferentialTrys.h97
-rw-r--r--thirdparty/etc2comp/EtcErrorMetric.h54
-rw-r--r--thirdparty/etc2comp/EtcFile.cpp390
-rw-r--r--thirdparty/etc2comp/EtcFile.h136
-rw-r--r--thirdparty/etc2comp/EtcFileHeader.cpp185
-rw-r--r--thirdparty/etc2comp/EtcFileHeader.h146
-rw-r--r--thirdparty/etc2comp/EtcFilter.cpp404
-rw-r--r--thirdparty/etc2comp/EtcFilter.h244
-rw-r--r--thirdparty/etc2comp/EtcImage.cpp685
-rw-r--r--thirdparty/etc2comp/EtcImage.h249
-rw-r--r--thirdparty/etc2comp/EtcIndividualTrys.cpp85
-rw-r--r--thirdparty/etc2comp/EtcIndividualTrys.h95
-rw-r--r--thirdparty/etc2comp/EtcMath.cpp64
-rw-r--r--thirdparty/etc2comp/EtcMath.h40
-rw-r--r--thirdparty/etc2comp/EtcSortedBlockList.cpp228
-rw-r--r--thirdparty/etc2comp/EtcSortedBlockList.h124
-rw-r--r--thirdparty/etc2comp/LICENSE202
-rw-r--r--thirdparty/etc2comp/README.md197
-rw-r--r--thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch224
-rw-r--r--thirdparty/etcpak/AUTHORS.txt3
-rw-r--r--thirdparty/etcpak/Bitmap.cpp216
-rw-r--r--thirdparty/etcpak/Bitmap.hpp50
-rw-r--r--thirdparty/etcpak/BitmapDownsampled.cpp86
-rw-r--r--thirdparty/etcpak/BitmapDownsampled.hpp13
-rw-r--r--thirdparty/etcpak/BlockData.cpp1296
-rw-r--r--thirdparty/etcpak/BlockData.hpp56
-rw-r--r--thirdparty/etcpak/ColorSpace.cpp114
-rw-r--r--thirdparty/etcpak/ColorSpace.hpp36
-rw-r--r--thirdparty/etcpak/DataProvider.cpp77
-rw-r--r--thirdparty/etcpak/DataProvider.hpp41
-rw-r--r--thirdparty/etcpak/Debug.cpp31
-rw-r--r--thirdparty/etcpak/Debug.hpp27
-rw-r--r--thirdparty/etcpak/Dither.cpp120
-rw-r--r--thirdparty/etcpak/Dither.hpp21
-rw-r--r--thirdparty/etcpak/Error.cpp48
-rw-r--r--thirdparty/etcpak/Error.hpp9
-rw-r--r--thirdparty/etcpak/ForceInline.hpp20
-rw-r--r--thirdparty/etcpak/LICENSE.txt26
-rw-r--r--thirdparty/etcpak/Math.hpp92
-rw-r--r--thirdparty/etcpak/MipMap.hpp11
-rw-r--r--thirdparty/etcpak/ProcessCommon.hpp50
-rw-r--r--thirdparty/etcpak/ProcessDxtc.cpp956
-rw-r--r--thirdparty/etcpak/ProcessDxtc.hpp11
-rw-r--r--thirdparty/etcpak/ProcessRGB.cpp3100
-rw-r--r--thirdparty/etcpak/ProcessRGB.hpp13
-rw-r--r--thirdparty/etcpak/Semaphore.hpp46
-rw-r--r--thirdparty/etcpak/System.cpp68
-rw-r--r--thirdparty/etcpak/System.hpp15
-rw-r--r--thirdparty/etcpak/Tables.cpp221
-rw-r--r--thirdparty/etcpak/Tables.hpp49
-rw-r--r--thirdparty/etcpak/TaskDispatch.cpp115
-rw-r--r--thirdparty/etcpak/TaskDispatch.hpp34
-rw-r--r--thirdparty/etcpak/Timing.cpp8
-rw-r--r--thirdparty/etcpak/Timing.hpp8
-rw-r--r--thirdparty/etcpak/Vector.hpp222
-rw-r--r--thirdparty/etcpak/lz4/lz4.c1516
-rw-r--r--thirdparty/etcpak/lz4/lz4.h360
-rw-r--r--thirdparty/etcpak/mmap.cpp38
-rw-r--r--thirdparty/etcpak/mmap.hpp19
-rw-r--r--thirdparty/etcpak/patches/libpng-unbundle.patch13
-rw-r--r--thirdparty/etcpak/patches/llvm-c++11-narrowing-errors.patch64
-rw-r--r--thirdparty/etcpak/patches/windows-mingw-fixes.patch63
101 files changed, 9648 insertions, 13480 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 6684978318..653ebd46cd 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -134,10 +134,10 @@ Comment: ENet
Copyright: 2002-2020, Lee Salzman
License: Expat
-Files: ./thirdparty/etc2comp/
-Comment: Etc2Comp
-Copyright: 2015, Etc2Comp Authors
-License: Apache-2.0
+Files: ./thirdparty/etcpak/
+Comment: etcpak
+Copyright: 2013-2021, Bartosz Taudul
+License: BSD-3-clause
Files: ./thirdparty/fonts/DroidSans*.ttf
Comment: DroidSans font
diff --git a/modules/etc/SCsub b/modules/etc/SCsub
deleted file mode 100644
index 9b46f17916..0000000000
--- a/modules/etc/SCsub
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_etc = env_modules.Clone()
-
-# Thirdparty source files
-
-thirdparty_obj = []
-
-# 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.Prepend(CPPPATH=[thirdparty_dir])
-
-env_thirdparty = env_etc.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
-env.modules_sources += thirdparty_obj
-
-# Godot source files
-
-module_obj = []
-
-env_etc.add_source_files(module_obj, "*.cpp")
-env.modules_sources += module_obj
-
-# Needed to force rebuilding the module files when the thirdparty library is updated.
-env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/image_compress_etc.cpp b/modules/etc/image_compress_etc.cpp
deleted file mode 100644
index 41cbbe3f54..0000000000
--- a/modules/etc/image_compress_etc.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*************************************************************************/
-/* image_compress_etc.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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_compress_etc.h"
-
-#include "core/io/image.h"
-#include "core/os/copymem.h"
-#include "core/os/os.h"
-#include "core/string/print_string.h"
-
-#include <Etc.h>
-#include <EtcFilter.h>
-
-static Image::Format _get_etc2_mode(Image::UsedChannels format) {
- switch (format) {
- case Image::USED_CHANNELS_R:
- return Image::FORMAT_ETC2_R11;
-
- case Image::USED_CHANNELS_RG:
- return Image::FORMAT_ETC2_RG11;
-
- case Image::USED_CHANNELS_RGB:
- return Image::FORMAT_ETC2_RGB8;
-
- case Image::USED_CHANNELS_RGBA:
- return Image::FORMAT_ETC2_RGBA8;
-
- // TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551
- default:
- // TODO: Kept for compatibility, but should be investigated whether it's correct or if it should error out
- return Image::FORMAT_ETC2_RGBA8;
- }
-}
-
-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;
-
- default:
- ERR_FAIL_V(Etc::Image::Format::UNKNOWN);
- }
-}
-
-static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_format, Image::UsedChannels p_channels) {
- Image::Format img_format = p_img->get_format();
-
- 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;
- }
-
- // FIXME: Commented out during Vulkan rebase.
- /*
- if (force_etc1_format) {
- // If VRAM compression is using ETC, but image has alpha, convert to RGBA4444 or LA8
- // This saves space while maintaining the alpha channel
- if (detected_channels == Image::USED_CHANNELS_RGBA) {
- if (p_img->has_mipmaps()) {
- // Image doesn't support mipmaps with RGBA4444 textures
- p_img->clear_mipmaps();
- }
- p_img->convert(Image::FORMAT_RGBA4444);
- return;
- } else if (detected_channels == Image::USE_CHANNELS_LA) {
- p_img->convert(Image::FORMAT_LA8);
- return;
- }
- }
- */
-
- uint32_t imgw = p_img->get_width(), imgh = p_img->get_height();
-
- Image::Format etc_format = force_etc1_format ? Image::FORMAT_ETC : _get_etc2_mode(p_channels);
-
- Ref<Image> img = p_img->duplicate();
-
- if (img->get_format() != Image::FORMAT_RGBA8) {
- img->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
- }
-
- if (img->has_mipmaps()) {
- if (next_power_of_2(imgw) != imgw || next_power_of_2(imgh) != imgh) {
- img->resize_to_po2();
- imgw = img->get_width();
- imgh = img->get_height();
- }
- } else {
- if (imgw % 4 != 0 || imgh % 4 != 0) {
- if (imgw % 4) {
- imgw += 4 - imgw % 4;
- }
- if (imgh % 4) {
- imgh += 4 - imgh % 4;
- }
-
- img->resize(imgw, imgh);
- }
- }
-
- const uint8_t *r = img->get_data().ptr();
- ERR_FAIL_COND(!r);
-
- unsigned int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps());
- int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0);
-
- Vector<uint8_t> dst_data;
- dst_data.resize(target_size);
-
- uint8_t *w = dst_data.ptrw();
-
- // prepare parameters to be passed to etc2comp
- int num_cpus = OS::get_singleton()->get_processor_count();
- int encoding_time = 0;
- float effort = 0.0; //default, reasonable time
-
- if (p_lossy_quality > 0.95) {
- effort = 80;
- } else if (p_lossy_quality > 0.85) {
- effort = 60;
- } else if (p_lossy_quality > 0.75) {
- effort = 40;
- }
-
- Etc::ErrorMetric error_metric = Etc::ErrorMetric::RGBX; // NOTE: we can experiment with other error metrics
- Etc::Image::Format etc2comp_etc_format = _image_format_to_etc2comp_format(etc_format);
-
- int wofs = 0;
-
- print_verbose("ETC: Begin encoding, format: " + Image::get_format_name(etc_format));
- uint64_t t = OS::get_singleton()->get_ticks_msec();
- for (int i = 0; i < mmc; 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 j = 0; j < mipmap_w * mipmap_h; j++) {
- int si = j * 4; // RGBA8
- src_rgba_f[j] = Etc::ColorFloatRGBA::ConvertFromRGBA8(src[si], src[si + 1], src[si + 2], src[si + 3]);
- }
-
- unsigned char *etc_data = nullptr;
- 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);
-
- CRASH_COND(wofs + etc_data_len > target_size);
- memcpy(&w[wofs], etc_data, etc_data_len);
- wofs += etc_data_len;
-
- delete[] etc_data;
- delete[] src_rgba_f;
- }
-
- print_verbose("ETC: Time encoding: " + rtos(OS::get_singleton()->get_ticks_msec() - t));
-
- p_img->create(imgw, imgh, p_img->has_mipmaps(), etc_format, dst_data);
-}
-
-static void _compress_etc1(Image *p_img, float p_lossy_quality) {
- _compress_etc(p_img, p_lossy_quality, true, Image::USED_CHANNELS_RGB);
-}
-
-static void _compress_etc2(Image *p_img, float p_lossy_quality, Image::UsedChannels p_channels) {
- _compress_etc(p_img, p_lossy_quality, false, p_channels);
-}
-
-void _register_etc_compress_func() {
- Image::_image_compress_etc1_func = _compress_etc1;
- Image::_image_compress_etc2_func = _compress_etc2;
-}
diff --git a/modules/etc/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp
deleted file mode 100644
index 95db9315d5..0000000000
--- a/modules/etc/texture_loader_pkm.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*************************************************************************/
-/* texture_loader_pkm.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "texture_loader_pkm.h"
-
-#include "core/os/file_access.h"
-#include <string.h>
-
-struct ETC1Header {
- char tag[6]; // "PKM 10"
- uint16_t format = 0; // Format == number of mips (== zero)
- uint16_t texWidth = 0; // Texture dimensions, multiple of 4 (big-endian)
- uint16_t texHeight = 0;
- uint16_t origWidth = 0; // Original dimensions (big-endian)
- uint16_t origHeight = 0;
-};
-
-RES ResourceFormatPKM::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- if (r_error) {
- *r_error = ERR_CANT_OPEN;
- }
-
- Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
- return RES();
- }
-
- FileAccessRef fref(f);
- if (r_error) {
- *r_error = ERR_FILE_CORRUPT;
- }
-
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Unable to open PKM texture file '" + p_path + "'.");
-
- // big endian
- f->set_endian_swap(true);
-
- ETC1Header h;
- f->get_buffer((uint8_t *)&h.tag, sizeof(h.tag));
- ERR_FAIL_COND_V_MSG(strncmp(h.tag, "PKM 10", sizeof(h.tag)), RES(), "Invalid or unsupported PKM texture file '" + p_path + "'.");
-
- h.format = f->get_16();
- h.texWidth = f->get_16();
- h.texHeight = f->get_16();
- h.origWidth = f->get_16();
- h.origHeight = f->get_16();
-
- Vector<uint8_t> src_data;
-
- uint32_t size = h.texWidth * h.texHeight / 2;
- src_data.resize(size);
- uint8_t *wb = src_data.ptrw();
- f->get_buffer(wb, size);
-
- int mipmaps = h.format;
- int width = h.origWidth;
- int height = h.origHeight;
-
- Ref<Image> img = memnew(Image(width, height, mipmaps, Image::FORMAT_ETC, src_data));
-
- Ref<ImageTexture> texture = memnew(ImageTexture);
- texture->create_from_image(img);
-
- if (r_error) {
- *r_error = OK;
- }
-
- f->close();
- memdelete(f);
- return texture;
-}
-
-void ResourceFormatPKM::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("pkm");
-}
-
-bool ResourceFormatPKM::handles_type(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Texture2D");
-}
-
-String ResourceFormatPKM::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "pkm") {
- return "ImageTexture";
- }
- return "";
-}
diff --git a/modules/etc/texture_loader_pkm.h b/modules/etc/texture_loader_pkm.h
deleted file mode 100644
index 2ed5e75807..0000000000
--- a/modules/etc/texture_loader_pkm.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*************************************************************************/
-/* texture_loader_pkm.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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. */
-/*************************************************************************/
-
-#ifndef TEXTURE_LOADER_PKM_H
-#define TEXTURE_LOADER_PKM_H
-
-#include "core/io/resource_loader.h"
-#include "scene/resources/texture.h"
-
-class ResourceFormatPKM : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-
- virtual ~ResourceFormatPKM() {}
-};
-
-#endif // TEXTURE_LOADER_PKM_H
diff --git a/modules/etcpak/SCsub b/modules/etcpak/SCsub
new file mode 100644
index 0000000000..821c6801b4
--- /dev/null
+++ b/modules/etcpak/SCsub
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_etcpak = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/etcpak/"
+thirdparty_sources = [
+ "Bitmap.cpp",
+ "BitmapDownsampled.cpp",
+ "BlockData.cpp",
+ "ColorSpace.cpp",
+ "DataProvider.cpp",
+ "Debug.cpp",
+ "Dither.cpp",
+ "Error.cpp",
+ "mmap.cpp",
+ "ProcessDxtc.cpp",
+ "ProcessRGB.cpp",
+ "System.cpp",
+ "Tables.cpp",
+ "TaskDispatch.cpp",
+ "Timing.cpp",
+ "lz4/lz4.c",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_etcpak.Prepend(CPPPATH=[thirdparty_dir])
+
+# Also requires libpng headers
+if env["builtin_libpng"]:
+ env_etcpak.Prepend(CPPPATH=["#thirdparty/libpng"])
+
+env_thirdparty = env_etcpak.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_etcpak.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/config.py b/modules/etcpak/config.py
index 53b8f2f2e3..53b8f2f2e3 100644
--- a/modules/etc/config.py
+++ b/modules/etcpak/config.py
diff --git a/modules/etcpak/image_etcpak.cpp b/modules/etcpak/image_etcpak.cpp
new file mode 100644
index 0000000000..251d2cd7b0
--- /dev/null
+++ b/modules/etcpak/image_etcpak.cpp
@@ -0,0 +1,170 @@
+/*************************************************************************/
+/* image_etcpak.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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_etcpak.h"
+
+#include "core/os/copymem.h"
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+
+#include "thirdparty/etcpak/ProcessDxtc.hpp"
+#include "thirdparty/etcpak/ProcessRGB.hpp"
+
+// thresholds for the early compression-mode decision scheme in QuickETC2
+// which can be changed by the option -e
+float ecmd_threshold[3] = { 0.03f, 0.09f, 0.38f };
+
+EtcpakType _determine_etc_type(Image::UsedChannels p_source) {
+ switch (p_source) {
+ case Image::USED_CHANNELS_L:
+ return EtcpakType::ETCPAK_TYPE_ETC1;
+ case Image::USED_CHANNELS_LA:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ case Image::USED_CHANNELS_R:
+ return EtcpakType::ETCPAK_TYPE_ETC2;
+ case Image::USED_CHANNELS_RG:
+ return EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG;
+ case Image::USED_CHANNELS_RGB:
+ return EtcpakType::ETCPAK_TYPE_ETC2;
+ case Image::USED_CHANNELS_RGBA:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ default:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ }
+}
+
+EtcpakType _determine_dxt_type(Image::UsedChannels p_source) {
+ switch (p_source) {
+ case Image::USED_CHANNELS_L:
+ return EtcpakType::ETCPAK_TYPE_DXT1;
+ case Image::USED_CHANNELS_LA:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_R:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_RG:
+ return EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG;
+ case Image::USED_CHANNELS_RGB:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_RGBA:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ default:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ }
+}
+void _compress_etc2(Image *p_img, float p_lossy_quality, Image::UsedChannels p_source) {
+ EtcpakType type = _determine_etc_type(p_source);
+ _compress_etcpak(type, p_img, p_lossy_quality, false, p_source);
+}
+void _compress_bc(Image *p_img, float p_lossy_quality, Image::UsedChannels p_source) {
+ EtcpakType type = _determine_dxt_type(p_source);
+ _compress_etcpak(type, p_img, p_lossy_quality, false, p_source);
+}
+void _compress_etc1(Image *p_img, float p_lossy_quality) {
+ _compress_etcpak(EtcpakType::ETCPAK_TYPE_ETC1, p_img, p_lossy_quality, true, Image::USED_CHANNELS_RGB);
+}
+
+void _compress_etcpak(EtcpakType p_compresstype, Image *p_img, float p_lossy_quality, bool force_etc1_format, Image::UsedChannels p_channels) {
+ uint64_t t = OS::get_singleton()->get_ticks_msec();
+ Image::Format img_format = p_img->get_format();
+
+ 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;
+ }
+
+ Image::Format format = Image::FORMAT_RGBA8;
+ if (p_img->get_format() != Image::FORMAT_RGBA8) {
+ p_img->convert(Image::FORMAT_RGBA8);
+ }
+ if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1 || force_etc1_format) {
+ format = Image::FORMAT_ETC;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2) {
+ format = Image::FORMAT_ETC2_RGB8;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) {
+ format = Image::FORMAT_ETC2_RA_AS_RG;
+ p_img->convert_rg_to_ra_rgba8();
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) {
+ format = Image::FORMAT_ETC2_RGBA8;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) {
+ format = Image::FORMAT_DXT1;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
+ format = Image::FORMAT_DXT5_RA_AS_RG;
+ p_img->convert_rg_to_ra_rgba8();
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) {
+ format = Image::FORMAT_DXT5;
+ } else {
+ ERR_FAIL();
+ }
+
+ const bool mipmap = p_img->has_mipmaps();
+ print_verbose("Encoding format: " + Image::get_format_name(format));
+
+ Ref<Image> new_img;
+ new_img.instance();
+ new_img->create(p_img->get_width(), p_img->get_height(), mipmap, format);
+ Vector<uint8_t> data = new_img->get_data();
+ uint8_t *wr = data.ptrw();
+
+ Ref<Image> image = p_img->duplicate();
+ int mmc = 1 + (mipmap ? Image::get_image_required_mipmaps(new_img->get_width(), new_img->get_height(), format) : 0);
+ for (int i = 0; i < mmc; i++) {
+ int ofs, size, mip_w, mip_h;
+ new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, mip_w, mip_h);
+ mip_w = (mip_w + 3) & ~3;
+ mip_h = (mip_h + 3) & ~3;
+ Vector<uint8_t> dst_data;
+ dst_data.resize(size);
+ int mipmap_ofs = image->get_mipmap_offset(i);
+
+ const uint32_t *image_read = (const uint32_t *)&image->get_data().ptr()[mipmap_ofs];
+ uint64_t *dst_write = (uint64_t *)dst_data.ptrw();
+ if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1 || force_etc1_format) {
+ CompressEtc1RgbDither(image_read, dst_write, mip_w * mip_h / 16, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2 || p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) {
+ CompressEtc2Rgb(image_read, dst_write, mip_w * mip_h / 16, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) {
+ CompressEtc2Rgba(image_read, dst_write, mip_w * mip_h / 16, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
+ CompressDxt5(image_read, dst_write, mip_w * mip_h / 16, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) {
+ CompressDxt1Dither(image_read, dst_write, mip_w * mip_h / 16, mip_w);
+ } else {
+ ERR_FAIL();
+ }
+ copymem(&wr[ofs], dst_data.ptr(), size);
+ }
+ p_img->create(new_img->get_width(), new_img->get_height(), mipmap, format, data);
+
+ print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - t)));
+}
diff --git a/modules/etc/register_types.cpp b/modules/etcpak/image_etcpak.h
index b165bccb3e..0137bab7cc 100644
--- a/modules/etc/register_types.cpp
+++ b/modules/etcpak/image_etcpak.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* register_types.cpp */
+/* image_etcpak.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,24 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "register_types.h"
+#ifndef IMAGE_ETCPAK_H
+#define IMAGE_ETCPAK_H
-#include "image_compress_etc.h"
-#include "texture_loader_pkm.h"
+#include "core/io/image.h"
-static Ref<ResourceFormatPKM> resource_loader_pkm;
+enum class EtcpakType {
+ ETCPAK_TYPE_ETC1,
+ ETCPAK_TYPE_ETC2,
+ ETCPAK_TYPE_ETC2_ALPHA,
+ ETCPAK_TYPE_ETC2_RA_AS_RG,
+ ETCPAK_TYPE_DXT1,
+ ETCPAK_TYPE_DXT5,
+ ETCPAK_TYPE_DXT5_RA_AS_RG,
+};
-void register_etc_types() {
- resource_loader_pkm.instance();
- ResourceLoader::add_resource_format_loader(resource_loader_pkm);
+void _compress_etcpak(EtcpakType p_compresstype, Image *p_img, float p_lossy_quality, bool force_etc1_format, Image::UsedChannels p_channels);
+void _compress_etc1(Image *p_img, float p_lossy_quality);
+void _compress_etc2(Image *p_img, float p_lossy_quality, Image::UsedChannels p_source);
+void _compress_bc(Image *p_img, float p_lossy_quality, Image::UsedChannels p_source);
- _register_etc_compress_func();
-}
-
-void unregister_etc_types() {
- ResourceLoader::remove_resource_format_loader(resource_loader_pkm);
- resource_loader_pkm.unref();
-}
+#endif // IMAGE_ETCPAK_H
diff --git a/modules/etc/image_compress_etc.h b/modules/etcpak/register_types.cpp
index 44a06194e9..fcc0bc8b6f 100644
--- a/modules/etc/image_compress_etc.h
+++ b/modules/etcpak/register_types.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_compress_etc.h */
+/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_COMPRESS_ETC_H
-#define IMAGE_COMPRESS_ETC_H
+#include "register_types.h"
-void _register_etc_compress_func();
+#include "image_etcpak.h"
-#endif // IMAGE_COMPRESS_ETC_H
+void register_etcpak_types() {
+ Image::_image_compress_etc1_func = _compress_etc1;
+ Image::_image_compress_etc2_func = _compress_etc2;
+ Image::_image_compress_bc_func = _compress_bc;
+}
+
+void unregister_etcpak_types() {
+}
diff --git a/modules/etc/register_types.h b/modules/etcpak/register_types.h
index e8cbb635ae..9b300a3275 100644
--- a/modules/etc/register_types.h
+++ b/modules/etcpak/register_types.h
@@ -28,10 +28,5 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ETC_REGISTER_TYPES_H
-#define ETC_REGISTER_TYPES_H
-
-void register_etc_types();
-void unregister_etc_types();
-
-#endif // ETC_REGISTER_TYPES_H
+void register_etcpak_types();
+void unregister_etcpak_types();
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp
index cce08034df..fb0c7aba1d 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_compress_squish.cpp
@@ -76,83 +76,3 @@ void image_decompress_squish(Image *p_image) {
p_image->convert_ra_rgba8_to_rg();
}
}
-
-void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels) {
- if (p_image->get_format() >= Image::FORMAT_DXT1) {
- return; //do not compress, already compressed
- }
-
- int w = p_image->get_width();
- int h = p_image->get_height();
-
- if (p_image->get_format() <= Image::FORMAT_RGBA8) {
- int squish_comp = squish::kColourRangeFit;
-
- if (p_lossy_quality > 0.85) {
- squish_comp = squish::kColourIterativeClusterFit;
- } else if (p_lossy_quality > 0.75) {
- squish_comp = squish::kColourClusterFit;
- }
-
- Image::Format target_format = Image::FORMAT_RGBA8;
-
- p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
-
- switch (p_channels) {
- case Image::USED_CHANNELS_L: {
- target_format = Image::FORMAT_DXT1;
- squish_comp |= squish::kDxt1;
- } break;
- case Image::USED_CHANNELS_LA: {
- target_format = Image::FORMAT_DXT5;
- squish_comp |= squish::kDxt5;
- } break;
- case Image::USED_CHANNELS_R: {
- target_format = Image::FORMAT_RGTC_R;
- squish_comp |= squish::kBc4;
- } break;
- case Image::USED_CHANNELS_RG: {
- target_format = Image::FORMAT_RGTC_RG;
- squish_comp |= squish::kBc5;
- } break;
- case Image::USED_CHANNELS_RGB: {
- target_format = Image::FORMAT_DXT1;
- squish_comp |= squish::kDxt1;
- } break;
- case Image::USED_CHANNELS_RGBA: {
- //TODO, should convert both, then measure which one does a better job
- target_format = Image::FORMAT_DXT5;
- squish_comp |= squish::kDxt5;
-
- } break;
- default: {
- ERR_PRINT("Unknown image format, defaulting to RGBA8");
- break;
- }
- }
-
- Vector<uint8_t> data;
- int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
- int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
- data.resize(target_size);
- int shift = Image::get_format_pixel_rshift(target_format);
-
- const uint8_t *rb = p_image->get_data().ptr();
- uint8_t *wb = data.ptrw();
-
- int dst_ofs = 0;
-
- for (int i = 0; i <= mm_count; i++) {
- int bw = w % 4 != 0 ? w + (4 - w % 4) : w;
- int bh = h % 4 != 0 ? h + (4 - h % 4) : h;
-
- int src_ofs = p_image->get_mipmap_offset(i);
- squish::CompressImage(&rb[src_ofs], w, h, &wb[dst_ofs], squish_comp);
- dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift;
- w = MAX(w / 2, 1);
- h = MAX(h / 2, 1);
- }
-
- p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
- }
-}
diff --git a/modules/squish/image_compress_squish.h b/modules/squish/image_compress_squish.h
index 301d30fcf1..ebc5a41887 100644
--- a/modules/squish/image_compress_squish.h
+++ b/modules/squish/image_compress_squish.h
@@ -33,7 +33,6 @@
#include "core/io/image.h"
-void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels);
void image_decompress_squish(Image *p_image);
#endif // IMAGE_COMPRESS_SQUISH_H
diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp
index 451e9d8e93..c51cdc9521 100644
--- a/modules/squish/register_types.cpp
+++ b/modules/squish/register_types.cpp
@@ -32,7 +32,6 @@
#include "image_compress_squish.h"
void register_squish_types() {
- Image::set_compress_bc_func(image_compress_squish);
Image::_image_decompress_bc = image_decompress_squish;
}
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 6dca29e856..cacc0275dd 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -86,21 +86,19 @@ It is still possible to build against a system wide ENet but doing so
will limit its functionality to IPv4 only.
-## etc2comp
+## etcpak
-- Upstream: https://github.com/google/etc2comp
-- Version: git (9cd0f9cae0f32338943699bb418107db61bb66f2, 2017)
-- License: Apache 2.0
-
-Files extracted from upstream source:
+- Upstream: https://github.com/wolfpld/etcpak
+- Version: git (403d38b3f1cb347c196d845d0a05e44a00d17169, 2021)
+- License: BSD-3-Clause
-- all .cpp and .h files in EtcLib/
-- README.md, LICENSE, AUTHORS
+Important: Some Godot-made changes, see `patches` folders.
-Important: Some files have Godot-made changes.
-They are marked with `// -- GODOT start --` and `// -- GODOT end --`
-comments.
+Files extracted from upstream source:
+- All `.cpp` and `.hpp` files in the root folder except `Application.cpp`.
+- `lz4` folder.
+- `AUTHORS.txt` and `LICENSE.txt`
## fonts
diff --git a/thirdparty/etc2comp/AUTHORS b/thirdparty/etc2comp/AUTHORS
deleted file mode 100644
index e78a7f4d21..0000000000
--- a/thirdparty/etc2comp/AUTHORS
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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.
diff --git a/thirdparty/etc2comp/Etc.cpp b/thirdparty/etc2comp/Etc.cpp
deleted file mode 100644
index a5ee706048..0000000000
--- a/thirdparty/etc2comp/Etc.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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;
- }
-
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-}
diff --git a/thirdparty/etc2comp/Etc.h b/thirdparty/etc2comp/Etc.h
deleted file mode 100644
index 439388d649..0000000000
--- a/thirdparty/etc2comp/Etc.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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);
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4.cpp b/thirdparty/etc2comp/EtcBlock4x4.cpp
deleted file mode 100644
index 3082fe60db..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * 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 "???";
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4.h b/thirdparty/etc2comp/EtcBlock4x4.h
deleted file mode 100644
index 0fd30c598d..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
deleted file mode 100644
index 7a9e68c4cf..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * 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
-
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.h b/thirdparty/etc2comp/EtcBlock4x4Encoding.h
deleted file mode 100644
index c14c3b8616..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h b/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
deleted file mode 100644
index 4065700379..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * 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;
-
- };
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
deleted file mode 100644
index a27f74c0d5..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
+++ /dev/null
@@ -1,1281 +0,0 @@
-/*
- * 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_ETC1.cpp
-
-Block4x4Encoding_ETC1 is the encoder to use when targetting file format ETC1. This encoder is also
-used for the ETC1 subset of file format RGB8, RGBA8 and RGB8A1
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_ETC1.h"
-
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcDifferentialTrys.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
-
- // pixel processing order if the flip bit = 0 (horizontal split)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip0[PIXELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
-
- // pixel processing order if the flip bit = 1 (vertical split)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip1[PIXELS] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 };
-
- // pixel processing order for horizontal scan (ETC normally does a vertical scan)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
-
- // pixel indices for different block halves
- const unsigned int Block4x4Encoding_ETC1::s_auiLeftPixelMapping[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
- const unsigned int Block4x4Encoding_ETC1::s_auiRightPixelMapping[8] = { 8, 9, 10, 11, 12, 13, 14, 15 };
- const unsigned int Block4x4Encoding_ETC1::s_auiTopPixelMapping[8] = { 0, 1, 4, 5, 8, 9, 12, 13 };
- const unsigned int Block4x4Encoding_ETC1::s_auiBottomPixelMapping[8] = { 2, 3, 6, 7, 10, 11, 14, 15 };
-
- // CW ranges that the ETC1 decoders use
- // CW is basically a contrast for the different selector bits, since these values are offsets to the base color
- // the first axis in the array is indexed by the CW in the encoding bits
- // the second axis in the array is indexed by the selector bits
- float Block4x4Encoding_ETC1::s_aafCwTable[CW_RANGES][SELECTORS] =
- {
- { 2.0f / 255.0f, 8.0f / 255.0f, -2.0f / 255.0f, -8.0f / 255.0f },
- { 5.0f / 255.0f, 17.0f / 255.0f, -5.0f / 255.0f, -17.0f / 255.0f },
- { 9.0f / 255.0f, 29.0f / 255.0f, -9.0f / 255.0f, -29.0f / 255.0f },
- { 13.0f / 255.0f, 42.0f / 255.0f, -13.0f / 255.0f, -42.0f / 255.0f },
- { 18.0f / 255.0f, 60.0f / 255.0f, -18.0f / 255.0f, -60.0f / 255.0f },
- { 24.0f / 255.0f, 80.0f / 255.0f, -24.0f / 255.0f, -80.0f / 255.0f },
- { 33.0f / 255.0f, 106.0f / 255.0f, -33.0f / 255.0f, -106.0f / 255.0f },
- { 47.0f / 255.0f, 183.0f / 255.0f, -47.0f / 255.0f, -183.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_ETC1::Block4x4Encoding_ETC1(void)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = false;
- m_boolFlip = false;
- m_frgbaColor1 = ColorFloatRGBA();
- m_frgbaColor2 = ColorFloatRGBA();
- m_uiCW1 = 0;
- m_uiCW2 = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = 0;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- m_boolMostLikelyFlip = false;
-
- m_fError = -1.0f;
-
- m_fError1 = -1.0f;
- m_fError2 = -1.0f;
- m_boolSeverelyBentDifferentialColors = false;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- }
-
- Block4x4Encoding_ETC1::~Block4x4Encoding_ETC1(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_ETC1::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- m_fError = -1.0f;
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(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_ETC1::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
- m_fError = -1.0f;
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- m_mode = MODE_ETC1;
- m_boolDiff = m_pencodingbitsRGB8->individual.diff;
- m_boolFlip = m_pencodingbitsRGB8->individual.flip;
- if (m_boolDiff)
- {
- int iR2 = (int)(m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2);
- if (iR2 < 0)
- {
- iR2 = 0;
- }
- else if (iR2 > 31)
- {
- iR2 = 31;
- }
-
- int iG2 = (int)(m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2);
- if (iG2 < 0)
- {
- iG2 = 0;
- }
- else if (iG2 > 31)
- {
- iG2 = 31;
- }
-
- int iB2 = (int)(m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2);
- if (iB2 < 0)
- {
- iB2 = 0;
- }
- else if (iB2 > 31)
- {
- iB2 = 31;
- }
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2);
-
- }
- else
- {
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red1, m_pencodingbitsRGB8->individual.green1, m_pencodingbitsRGB8->individual.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red2, m_pencodingbitsRGB8->individual.green2, m_pencodingbitsRGB8->individual.blue2);
- }
-
- m_uiCW1 = m_pencodingbitsRGB8->individual.cw1;
- m_uiCW2 = m_pencodingbitsRGB8->individual.cw2;
-
- InitFromEncodingBits_Selectors();
-
- Decode();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // init the selectors from a prior encoding
- //
- void Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(void)
- {
-
- unsigned char *paucSelectors = (unsigned char *)&m_pencodingbitsRGB8->individual.selectors;
-
- for (unsigned int iPixel = 0; iPixel < PIXELS; iPixel++)
- {
- unsigned int uiByteMSB = (unsigned int)(1 - (iPixel / 8));
- unsigned int uiByteLSB = (unsigned int)(3 - (iPixel / 8));
- unsigned int uiShift = (unsigned int)(iPixel & 7);
-
- unsigned int uiSelectorMSB = (unsigned int)((paucSelectors[uiByteMSB] >> uiShift) & 1);
- unsigned int uiSelectorLSB = (unsigned int)((paucSelectors[uiByteLSB] >> uiShift) & 1);
-
- m_auiSelectors[iPixel] = (uiSelectorMSB << 1) + uiSelectorLSB;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // 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_ETC1::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- TryIndividual(m_boolMostLikelyFlip, 1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 4:
- TryIndividual(!m_boolMostLikelyFlip, 1);
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- TryDegenerates1();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryDegenerates2();
- if (a_fEffort <= 89.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- TryDegenerates3();
- if (a_fEffort <= 99.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_ETC1::PerformFirstIteration(void)
- {
- CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
-
- TryIndividual(m_boolMostLikelyFlip, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryIndividual(!m_boolMostLikelyFlip, 0);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // algorithm:
- // create a source average color for the Left, Right, Top and Bottom halves using the 8 pixels in each half
- // note: the "gray line" is the line of equal delta RGB that goes thru the average color
- // for each half:
- // see how close each of the 8 pixels are to the "gray line" that goes thru the source average color
- // create an error value that is the sum of the distances from the gray line
- // h_error is the sum of Left and Right errors
- // v_error is the sum of Top and Bottom errors
- //
- void Block4x4Encoding_ETC1::CalculateMostLikelyFlip(void)
- {
- static const bool DEBUG_PRINT = false;
-
- CalculateSourceAverages();
-
- float fLeftGrayErrorSum = 0.0f;
- float fRightGrayErrorSum = 0.0f;
- float fTopGrayErrorSum = 0.0f;
- float fBottomGrayErrorSum = 0.0f;
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaLeft = &m_pafrgbaSource[uiPixel];
- ColorFloatRGBA *pfrgbaRight = &m_pafrgbaSource[uiPixel + 8];
- ColorFloatRGBA *pfrgbaTop = &m_pafrgbaSource[s_auiTopPixelMapping[uiPixel]];
- ColorFloatRGBA *pfrgbaBottom = &m_pafrgbaSource[s_auiBottomPixelMapping[uiPixel]];
-
- float fLeftGrayError = CalcGrayDistance2(*pfrgbaLeft, m_frgbaSourceAverageLeft);
- float fRightGrayError = CalcGrayDistance2(*pfrgbaRight, m_frgbaSourceAverageRight);
- float fTopGrayError = CalcGrayDistance2(*pfrgbaTop, m_frgbaSourceAverageTop);
- float fBottomGrayError = CalcGrayDistance2(*pfrgbaBottom, m_frgbaSourceAverageBottom);
-
- fLeftGrayErrorSum += fLeftGrayError;
- fRightGrayErrorSum += fRightGrayError;
- fTopGrayErrorSum += fTopGrayError;
- fBottomGrayErrorSum += fBottomGrayError;
- }
-
- if (DEBUG_PRINT)
- {
- printf("\n%.2f %.2f\n", fLeftGrayErrorSum + fRightGrayErrorSum, fTopGrayErrorSum + fBottomGrayErrorSum);
- }
-
- m_boolMostLikelyFlip = (fTopGrayErrorSum + fBottomGrayErrorSum) < (fLeftGrayErrorSum + fRightGrayErrorSum);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate source pixel averages for each 2x2 quadrant in a 4x4 block
- // these are used to determine the averages for each of the 4 different halves (left, right, top, bottom)
- // ignore pixels that have alpha == NAN (these are border pixels outside of the source image)
- // weight the averages based on a pixel's alpha
- //
- void Block4x4Encoding_ETC1::CalculateSourceAverages(void)
- {
- static const bool DEBUG_PRINT = false;
-
- bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX;
-
- if (m_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE || boolRGBX)
- {
- ColorFloatRGBA frgbaSumUL = m_pafrgbaSource[0] + m_pafrgbaSource[1] + m_pafrgbaSource[4] + m_pafrgbaSource[5];
- ColorFloatRGBA frgbaSumLL = m_pafrgbaSource[2] + m_pafrgbaSource[3] + m_pafrgbaSource[6] + m_pafrgbaSource[7];
- ColorFloatRGBA frgbaSumUR = m_pafrgbaSource[8] + m_pafrgbaSource[9] + m_pafrgbaSource[12] + m_pafrgbaSource[13];
- ColorFloatRGBA frgbaSumLR = m_pafrgbaSource[10] + m_pafrgbaSource[11] + m_pafrgbaSource[14] + m_pafrgbaSource[15];
-
- m_frgbaSourceAverageLeft = (frgbaSumUL + frgbaSumLL) * 0.125f;
- m_frgbaSourceAverageRight = (frgbaSumUR + frgbaSumLR) * 0.125f;
- m_frgbaSourceAverageTop = (frgbaSumUL + frgbaSumUR) * 0.125f;
- m_frgbaSourceAverageBottom = (frgbaSumLL + frgbaSumLR) * 0.125f;
- }
- else
- {
- float afSourceAlpha[PIXELS];
-
- // treat alpha NAN as 0.0f
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- afSourceAlpha[uiPixel] = isnan(m_pafrgbaSource[uiPixel].fA) ?
- 0.0f :
- m_pafrgbaSource[uiPixel].fA;
- }
-
- ColorFloatRGBA afrgbaAlphaWeightedSource[PIXELS];
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- afrgbaAlphaWeightedSource[uiPixel] = m_pafrgbaSource[uiPixel] * afSourceAlpha[uiPixel];
- }
-
- ColorFloatRGBA frgbaSumUL = afrgbaAlphaWeightedSource[0] +
- afrgbaAlphaWeightedSource[1] +
- afrgbaAlphaWeightedSource[4] +
- afrgbaAlphaWeightedSource[5];
-
- ColorFloatRGBA frgbaSumLL = afrgbaAlphaWeightedSource[2] +
- afrgbaAlphaWeightedSource[3] +
- afrgbaAlphaWeightedSource[6] +
- afrgbaAlphaWeightedSource[7];
-
- ColorFloatRGBA frgbaSumUR = afrgbaAlphaWeightedSource[8] +
- afrgbaAlphaWeightedSource[9] +
- afrgbaAlphaWeightedSource[12] +
- afrgbaAlphaWeightedSource[13];
-
- ColorFloatRGBA frgbaSumLR = afrgbaAlphaWeightedSource[10] +
- afrgbaAlphaWeightedSource[11] +
- afrgbaAlphaWeightedSource[14] +
- afrgbaAlphaWeightedSource[15];
-
- float fWeightSumUL = afSourceAlpha[0] +
- afSourceAlpha[1] +
- afSourceAlpha[4] +
- afSourceAlpha[5];
-
- float fWeightSumLL = afSourceAlpha[2] +
- afSourceAlpha[3] +
- afSourceAlpha[6] +
- afSourceAlpha[7];
-
- float fWeightSumUR = afSourceAlpha[8] +
- afSourceAlpha[9] +
- afSourceAlpha[12] +
- afSourceAlpha[13];
-
- float fWeightSumLR = afSourceAlpha[10] +
- afSourceAlpha[11] +
- afSourceAlpha[14] +
- afSourceAlpha[15];
-
- ColorFloatRGBA frgbaSumLeft = frgbaSumUL + frgbaSumLL;
- ColorFloatRGBA frgbaSumRight = frgbaSumUR + frgbaSumLR;
- ColorFloatRGBA frgbaSumTop = frgbaSumUL + frgbaSumUR;
- ColorFloatRGBA frgbaSumBottom = frgbaSumLL + frgbaSumLR;
-
- float fWeightSumLeft = fWeightSumUL + fWeightSumLL;
- float fWeightSumRight = fWeightSumUR + fWeightSumLR;
- float fWeightSumTop = fWeightSumUL + fWeightSumUR;
- float fWeightSumBottom = fWeightSumLL + fWeightSumLR;
-
- // check to see if there is at least 1 pixel with non-zero alpha
- // completely transparent block should not make it to this code
- assert((fWeightSumLeft + fWeightSumRight) > 0.0f);
- assert((fWeightSumTop + fWeightSumBottom) > 0.0f);
-
- if (fWeightSumLeft > 0.0f)
- {
- m_frgbaSourceAverageLeft = frgbaSumLeft * (1.0f/fWeightSumLeft);
- }
- if (fWeightSumRight > 0.0f)
- {
- m_frgbaSourceAverageRight = frgbaSumRight * (1.0f/fWeightSumRight);
- }
- if (fWeightSumTop > 0.0f)
- {
- m_frgbaSourceAverageTop = frgbaSumTop * (1.0f/fWeightSumTop);
- }
- if (fWeightSumBottom > 0.0f)
- {
- m_frgbaSourceAverageBottom = frgbaSumBottom * (1.0f/fWeightSumBottom);
- }
-
- if (fWeightSumLeft == 0.0f)
- {
- assert(fWeightSumRight > 0.0f);
- m_frgbaSourceAverageLeft = m_frgbaSourceAverageRight;
- }
- if (fWeightSumRight == 0.0f)
- {
- assert(fWeightSumLeft > 0.0f);
- m_frgbaSourceAverageRight = m_frgbaSourceAverageLeft;
- }
- if (fWeightSumTop == 0.0f)
- {
- assert(fWeightSumBottom > 0.0f);
- m_frgbaSourceAverageTop = m_frgbaSourceAverageBottom;
- }
- if (fWeightSumBottom == 0.0f)
- {
- assert(fWeightSumTop > 0.0f);
- m_frgbaSourceAverageBottom = m_frgbaSourceAverageTop;
- }
- }
-
-
-
- if (DEBUG_PRINT)
- {
- printf("\ntarget: [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f]\n",
- m_frgbaSourceAverageLeft.fR, m_frgbaSourceAverageLeft.fG, m_frgbaSourceAverageLeft.fB,
- m_frgbaSourceAverageRight.fR, m_frgbaSourceAverageRight.fG, m_frgbaSourceAverageRight.fB,
- m_frgbaSourceAverageTop.fR, m_frgbaSourceAverageTop.fG, m_frgbaSourceAverageTop.fB,
- m_frgbaSourceAverageBottom.fR, m_frgbaSourceAverageBottom.fG, m_frgbaSourceAverageBottom.fB);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding
- // use a_boolFlip to set the encoding F bit
- // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius]
- // use a_iGrayOffset1 and a_iGrayOffset2 to offset the basecolor to search for degenerate encodings
- // replace the encoding if the encoding error is less than previous encoding
- //
- void Block4x4Encoding_ETC1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2,
- a_uiRadius, a_iGrayOffset1, a_iGrayOffset2);
-
- Block4x4Encoding_ETC1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryDifferentialHalf(&trys.m_half1);
- encodingTry.TryDifferentialHalf(&trys.m_half2);
-
- // find best halves that are within differential range
- DifferentialTrys::Try *ptryBest1 = nullptr;
- DifferentialTrys::Try *ptryBest2 = nullptr;
- encodingTry.m_fError = FLT_MAX;
-
- // see if the best of each half are in differential range
- int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed;
- int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen;
- int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue;
- if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3)
- {
- ptryBest1 = trys.m_half1.m_ptryBest;
- ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
- }
- else
- {
- // else, find the next best halves that are in differential range
- for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0];
- ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys];
- ptry1++)
- {
- for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0];
- ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys];
- ptry2++)
- {
- iDRed = ptry2->m_iRed - ptry1->m_iRed;
- bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4;
- iDGreen = ptry2->m_iGreen - ptry1->m_iGreen;
- bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4;
- iDBlue = ptry2->m_iBlue - ptry1->m_iBlue;
- bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4;
-
- if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta)
- {
- float fError = ptry1->m_fError + ptry2->m_fError;
-
- if (fError < encodingTry.m_fError)
- {
- encodingTry.m_fError = fError;
-
- ptryBest1 = ptry1;
- ptryBest2 = ptry2;
- }
- }
-
- }
- }
- assert(encodingTry.m_fError < FLT_MAX);
- assert(ptryBest1 != nullptr);
- assert(ptryBest2 != nullptr);
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1];
- float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2];
-
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors;
- m_fError = m_fError1 + m_fError2;
-
- // sanity check
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- iDRed = iRed2 - iRed1;
- iDGreen = iGreen2 - iGreen1;
- iDBlue = iBlue2 - iBlue1;
-
- assert(iDRed >= -4 && iDRed < 4);
- assert(iDGreen >= -4 && iDGreen < 4);
- assert(iDBlue >= -4 && iDBlue < 4);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding for a half of a 4x4 block
- // vary the basecolor components using a radius
- //
- void Block4x4Encoding_ETC1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 31);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 31);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 31);
-
- DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 individual mode encoding
- // use a_boolFlip to set the encoding F bit
- // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius]
- // replace the encoding if the encoding error is less than previous encoding
- //
- void Block4x4Encoding_ETC1::TryIndividual(bool a_boolFlip, unsigned int a_uiRadius)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- IndividualTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, a_uiRadius);
-
- Block4x4Encoding_ETC1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryIndividualHalf(&trys.m_half1);
- encodingTry.TryIndividualHalf(&trys.m_half2);
-
- // use the best of each half
- IndividualTrys::Try *ptryBest1 = trys.m_half1.m_ptryBest;
- IndividualTrys::Try *ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = false;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1];
- float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2];
-
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_fError = m_fError1 + m_fError2;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding for a half of a 4x4 block
- // vary the basecolor components using a radius
- //
- void Block4x4Encoding_ETC1::TryIndividualHalf(IndividualTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 15);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 15);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 15);
-
- IndividualTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[IndividualTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 1 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates1(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 2 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates2(void)
- {
-
- TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 3 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates3(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 4 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates4(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 4);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -4);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best selector for each pixel based on a particular basecolor and CW that have been previously set
- // calculate the selectors for each half of the block separately
- // set the block error as the sum of each half's error
- //
- void Block4x4Encoding_ETC1::CalculateSelectors()
- {
- if (m_boolFlip)
- {
- CalculateHalfOfTheSelectors(0, s_auiTopPixelMapping);
- CalculateHalfOfTheSelectors(1, s_auiBottomPixelMapping);
- }
- else
- {
- CalculateHalfOfTheSelectors(0, s_auiLeftPixelMapping);
- CalculateHalfOfTheSelectors(1, s_auiRightPixelMapping);
- }
-
- m_fError = m_fError1 + m_fError2;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // choose best selectors for half of the block
- // calculate the error for half of the block
- //
- void Block4x4Encoding_ETC1::CalculateHalfOfTheSelectors(unsigned int a_uiHalf,
- const unsigned int *pauiPixelMapping)
- {
- static const bool DEBUG_PRINT = false;
-
- ColorFloatRGBA *pfrgbaColor = a_uiHalf ? &m_frgbaColor2 : &m_frgbaColor1;
- unsigned int *puiCW = a_uiHalf ? &m_uiCW2 : &m_uiCW1;
-
- float *pfHalfError = a_uiHalf ? &m_fError2 : &m_fError1;
- *pfHalfError = FLT_MAX;
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- if (DEBUG_PRINT)
- {
- printf("\ncw=%u\n", uiCW);
- }
-
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- if (DEBUG_PRINT)
- {
- printf("\tsource [%.2f,%.2f,%.2f]\n", m_pafrgbaSource[pauiPixelMapping[uiPixel]].fR,
- m_pafrgbaSource[pauiPixelMapping[uiPixel]].fG, m_pafrgbaSource[pauiPixelMapping[uiPixel]].fB);
- }
-
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- float fDeltaRGB = s_aafCwTable[uiCW][uiSelector];
-
- frgbaDecodedPixel = (*pfrgbaColor + fDeltaRGB).ClampRGB();
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (DEBUG_PRINT)
- {
- printf("\tpixel %u, index %u [%.2f,%.2f,%.2f], error %.2f", uiPixel, uiSelector,
- frgbaDecodedPixel.fR,
- frgbaDecodedPixel.fG,
- frgbaDecodedPixel.fB,
- fPixelError);
- }
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- if (DEBUG_PRINT)
- {
- printf(" *");
- }
-
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- if (DEBUG_PRINT)
- {
- printf("\n");
- }
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
- if (DEBUG_PRINT)
- {
- printf("\terror %.2f\n", fCWError);
- }
-
- // if best CW so far
- if (fCWError < *pfHalfError)
- {
- *pfHalfError = fCWError;
- *puiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- m_auiSelectors[pauiPixelMapping[uiPixel]] = auiPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[pauiPixelMapping[uiPixel]] = afrgbaDecodedPixels[uiPixel];
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_ETC1::SetEncodingBits(void)
- {
- assert(m_mode == MODE_ETC1);
-
- if (m_boolDiff)
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- int iDRed2 = iRed2 - iRed1;
- int iDGreen2 = iGreen2 - iGreen1;
- int iDBlue2 = iBlue2 - iBlue1;
-
- assert(iDRed2 >= -4 && iDRed2 < 4);
- assert(iDGreen2 >= -4 && iDGreen2 < 4);
- assert(iDBlue2 >= -4 && iDBlue2 < 4);
-
- m_pencodingbitsRGB8->differential.red1 = (unsigned int)iRed1;
- m_pencodingbitsRGB8->differential.green1 = (unsigned int)iGreen1;
- m_pencodingbitsRGB8->differential.blue1 = (unsigned int)iBlue1;
-
- m_pencodingbitsRGB8->differential.dred2 = iDRed2;
- m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2;
- m_pencodingbitsRGB8->differential.dblue2 = iDBlue2;
- }
- else
- {
- m_pencodingbitsRGB8->individual.red1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- m_pencodingbitsRGB8->individual.green1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- m_pencodingbitsRGB8->individual.blue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->individual.red2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- m_pencodingbitsRGB8->individual.green2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- m_pencodingbitsRGB8->individual.blue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
- }
-
- m_pencodingbitsRGB8->individual.cw1 = m_uiCW1;
- m_pencodingbitsRGB8->individual.cw2 = m_uiCW2;
-
- SetEncodingBits_Selectors();
-
- m_pencodingbitsRGB8->individual.diff = (unsigned int)m_boolDiff;
- m_pencodingbitsRGB8->individual.flip = (unsigned int)m_boolFlip;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the selectors in the encoding bits
- //
- void Block4x4Encoding_ETC1::SetEncodingBits_Selectors(void)
- {
-
- m_pencodingbitsRGB8->individual.selectors = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiSelector = m_auiSelectors[uiPixel];
-
- // set index msb
- m_pencodingbitsRGB8->individual.selectors |= (uiSelector >> 1) << (uiPixel ^ 8);
-
- // set index lsb
- m_pencodingbitsRGB8->individual.selectors |= (uiSelector & 1) << ((16 + uiPixel) ^ 8);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_ETC1::Decode(void)
- {
-
- const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++)
- {
- ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2;
- unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2;
-
- unsigned int uiPixel = pauiPixelOrder[uiPixelOrder];
-
- float fDelta = s_aafCwTable[uiCW][m_auiSelectors[uiPixel]];
- m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
deleted file mode 100644
index c0dc84d5d5..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
deleted file mode 100644
index 4c012fbbf1..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * 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;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
deleted file mode 100644
index b40c1e0036..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
deleted file mode 100644
index 417835db51..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * 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;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
deleted file mode 100644
index d4993b8c5f..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
deleted file mode 100644
index 5c7ebed788..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
+++ /dev/null
@@ -1,1730 +0,0 @@
-/*
- * 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_RGB8.cpp
-
-Block4x4Encoding_RGB8 is the encoder to use for the ETC2 extensions when targetting file format RGB8.
-This encoder is also used for the ETC2 subset of file format RGBA8.
-
-Block4x4Encoding_ETC1 encodes the ETC1 subset of RGB8.
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-#include "EtcMath.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
- float Block4x4Encoding_RGB8::s_afTHDistanceTable[TH_DISTANCES] =
- {
- 3.0f / 255.0f,
- 6.0f / 255.0f,
- 11.0f / 255.0f,
- 16.0f / 255.0f,
- 23.0f / 255.0f,
- 32.0f / 255.0f,
- 41.0f / 255.0f,
- 64.0f / 255.0f
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGB8::Block4x4Encoding_RGB8(void)
- {
-
- m_pencodingbitsRGB8 = nullptr;
-
- }
-
- Block4x4Encoding_RGB8::~Block4x4Encoding_RGB8(void) {}
- // ----------------------------------------------------------------------------------------------------
- // 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_RGB8::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- // handle ETC1 modes
- Block4x4Encoding_ETC1::InitFromEncodingBits(a_pblockParent,
- a_paucEncodingBits, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- // detect if there is a T, H or Planar mode present
- if (m_pencodingbitsRGB8->differential.diff)
- {
- int iRed1 = (int)m_pencodingbitsRGB8->differential.red1;
- int iDRed2 = m_pencodingbitsRGB8->differential.dred2;
- int iRed2 = iRed1 + iDRed2;
-
- int iGreen1 = (int)m_pencodingbitsRGB8->differential.green1;
- int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2;
- int iGreen2 = iGreen1 + iDGreen2;
-
- int iBlue1 = (int)m_pencodingbitsRGB8->differential.blue1;
- int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2;
- int iBlue2 = iBlue1 + iDBlue2;
-
- if (iRed2 < 0 || iRed2 > 31)
- {
- InitFromEncodingBits_T();
- }
- else if (iGreen2 < 0 || iGreen2 > 31)
- {
- InitFromEncodingBits_H();
- }
- else if (iBlue2 < 0 || iBlue2 > 31)
- {
- InitFromEncodingBits_Planar();
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if T mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_T(void)
- {
-
- m_mode = MODE_T;
-
- unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) +
- m_pencodingbitsRGB8->t.red1b);
- unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1;
- unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1;
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2;
- unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2;
- unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_T();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if H mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_H(void)
- {
-
- m_mode = MODE_H;
-
- unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1;
- unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) +
- m_pencodingbitsRGB8->h.green1b);
- unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) +
- (m_pencodingbitsRGB8->h.blue1b << 1) +
- m_pencodingbitsRGB8->h.blue1c);
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2;
- unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) +
- m_pencodingbitsRGB8->h.green2b);
- unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- // used to determine the LSB of the CW
- unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1);
- unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1);
- if (uiRGB1 >= uiRGB2)
- {
- m_uiCW1++;
- }
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_H();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if Planar mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_Planar(void)
- {
-
- m_mode = MODE_PLANAR;
-
- unsigned char ucOriginRed = m_pencodingbitsRGB8->planar.originRed;
- unsigned char ucOriginGreen = (unsigned char)((m_pencodingbitsRGB8->planar.originGreen1 << 6) +
- m_pencodingbitsRGB8->planar.originGreen2);
- unsigned char ucOriginBlue = (unsigned char)((m_pencodingbitsRGB8->planar.originBlue1 << 5) +
- (m_pencodingbitsRGB8->planar.originBlue2 << 3) +
- (m_pencodingbitsRGB8->planar.originBlue3 << 1) +
- m_pencodingbitsRGB8->planar.originBlue4);
-
- unsigned char ucHorizRed = (unsigned char)((m_pencodingbitsRGB8->planar.horizRed1 << 1) +
- m_pencodingbitsRGB8->planar.horizRed2);
- unsigned char ucHorizGreen = m_pencodingbitsRGB8->planar.horizGreen;
- unsigned char ucHorizBlue = (unsigned char)((m_pencodingbitsRGB8->planar.horizBlue1 << 5) +
- m_pencodingbitsRGB8->planar.horizBlue2);
-
- unsigned char ucVertRed = (unsigned char)((m_pencodingbitsRGB8->planar.vertRed1 << 3) +
- m_pencodingbitsRGB8->planar.vertRed2);
- unsigned char ucVertGreen = (unsigned char)((m_pencodingbitsRGB8->planar.vertGreen1 << 2) +
- m_pencodingbitsRGB8->planar.vertGreen2);
- unsigned char ucVertBlue = m_pencodingbitsRGB8->planar.vertBlue;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromR6G7B6(ucOriginRed, ucOriginGreen, ucOriginBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromR6G7B6(ucHorizRed, ucHorizGreen, ucHorizBlue);
- m_frgbaColor3 = ColorFloatRGBA::ConvertFromR6G7B6(ucVertRed, ucVertGreen, ucVertBlue);
-
- DecodePixels_Planar();
-
- 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_RGB8::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- Block4x4Encoding_ETC1::PerformFirstIteration();
- if (m_boolDone)
- {
- break;
- }
- TryPlanar(0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- break;
- }
- TryTAndH(0);
- break;
-
- case 1:
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- Block4x4Encoding_ETC1::TryIndividual(m_boolMostLikelyFlip, 1);
- break;
-
- case 3:
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 4:
- Block4x4Encoding_ETC1::TryIndividual(!m_boolMostLikelyFlip, 1);
- break;
-
- case 5:
- TryPlanar(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryTAndH(1);
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- Block4x4Encoding_ETC1::TryDegenerates1();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- Block4x4Encoding_ETC1::TryDegenerates2();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 9:
- Block4x4Encoding_ETC1::TryDegenerates3();
- if (a_fEffort <= 89.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 10:
- Block4x4Encoding_ETC1::TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
-
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in Planar mode
- // save this encoding if it improves the error
- //
- void Block4x4Encoding_RGB8::TryPlanar(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- encodingTry.CalculatePlanarCornerColors();
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (a_uiRadius > 0)
- {
- encodingTry.TwiddlePlanar();
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode or H mode
- // save this encoding if it improves the error
- //
- void Block4x4Encoding_RGB8::TryTAndH(unsigned int a_uiRadius)
- {
-
- CalculateBaseColorsForTAndH();
-
- TryT(a_uiRadius);
-
- TryH(a_uiRadius);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate original values for base colors
- // store them in m_frgbaOriginalColor1 and m_frgbaOriginalColor2
- //
- void Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH(void)
- {
-
- bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX;
-
- ColorFloatRGBA frgbaBlockAverage = (m_frgbaSourceAverageLeft + m_frgbaSourceAverageRight) * 0.5f;
-
- // find pixel farthest from average gray line
- unsigned int uiFarthestPixel = 0;
- float fFarthestGrayDistance2 = 0.0f;
- unsigned int uiTransparentPixels = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // don't count transparent
- if (m_pafrgbaSource[uiPixel].fA == 0.0f && !boolRGBX)
- {
- uiTransparentPixels++;
- }
- else
- {
- float fGrayDistance2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], frgbaBlockAverage);
-
- if (fGrayDistance2 > fFarthestGrayDistance2)
- {
- uiFarthestPixel = uiPixel;
- fFarthestGrayDistance2 = fGrayDistance2;
- }
- }
- }
- // a transparent block should not reach this method
- assert(uiTransparentPixels < PIXELS);
-
- // set the original base colors to:
- // half way to the farthest pixel and
- // the mirror color on the other side of the average
- ColorFloatRGBA frgbaOffset = (m_pafrgbaSource[uiFarthestPixel] - frgbaBlockAverage) * 0.5f;
- m_frgbaOriginalColor1_TAndH = (frgbaBlockAverage + frgbaOffset).QuantizeR4G4B4();
- m_frgbaOriginalColor2_TAndH = (frgbaBlockAverage - frgbaOffset).ClampRGB().QuantizeR4G4B4(); // the "other side" might be out of range
-
- // move base colors to find best fit
- for (unsigned int uiIteration = 0; uiIteration < 10; uiIteration++)
- {
- // find the center of pixels closest to each color
- float fPixelsCloserToColor1 = 0.0f;
- ColorFloatRGBA frgbSumPixelsCloserToColor1;
- float fPixelsCloserToColor2 = 0.0f;
- ColorFloatRGBA frgbSumPixelsCloserToColor2;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // don't count transparent pixels
- if (m_pafrgbaSource[uiPixel].fA == 0.0f)
- {
- continue;
- }
-
- float fGrayDistance2ToColor1 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor1_TAndH);
- float fGrayDistance2ToColor2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor2_TAndH);
-
- ColorFloatRGBA frgbaAlphaWeightedSource = m_pafrgbaSource[uiPixel] * m_pafrgbaSource[uiPixel].fA;
-
- if (fGrayDistance2ToColor1 <= fGrayDistance2ToColor2)
- {
- fPixelsCloserToColor1 += m_pafrgbaSource[uiPixel].fA;
- frgbSumPixelsCloserToColor1 = frgbSumPixelsCloserToColor1 + frgbaAlphaWeightedSource;
- }
- else
- {
- fPixelsCloserToColor2 += m_pafrgbaSource[uiPixel].fA;
- frgbSumPixelsCloserToColor2 = frgbSumPixelsCloserToColor2 + frgbaAlphaWeightedSource;
- }
- }
- if (fPixelsCloserToColor1 == 0.0f || fPixelsCloserToColor2 == 0.0f)
- {
- break;
- }
-
- ColorFloatRGBA frgbAvgColor1Pixels = (frgbSumPixelsCloserToColor1 * (1.0f / fPixelsCloserToColor1)).QuantizeR4G4B4();
- ColorFloatRGBA frgbAvgColor2Pixels = (frgbSumPixelsCloserToColor2 * (1.0f / fPixelsCloserToColor2)).QuantizeR4G4B4();
-
- if (frgbAvgColor1Pixels.fR == m_frgbaOriginalColor1_TAndH.fR &&
- frgbAvgColor1Pixels.fG == m_frgbaOriginalColor1_TAndH.fG &&
- frgbAvgColor1Pixels.fB == m_frgbaOriginalColor1_TAndH.fB &&
- frgbAvgColor2Pixels.fR == m_frgbaOriginalColor2_TAndH.fR &&
- frgbAvgColor2Pixels.fG == m_frgbaOriginalColor2_TAndH.fG &&
- frgbAvgColor2Pixels.fB == m_frgbaOriginalColor2_TAndH.fB)
- {
- break;
- }
-
- m_frgbaOriginalColor1_TAndH = frgbAvgColor1Pixels;
- m_frgbaOriginalColor2_TAndH = frgbAvgColor2Pixels;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently
- // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower
- //
- void Block4x4Encoding_RGB8::TryT(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_T;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor2_TAndH
- // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector
- //
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- }
- else
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH;
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
- }
- else
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryT
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8::TryT_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = m_frgbaColor1;
- afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = m_frgbaColor2;
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
-
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently
- // TWIDDLE_RADIUS of 2 is WAY too slow
- //
- void Block4x4Encoding_RGB8::TryH(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_H;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor2_TAndH
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryH
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8::TryH_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB();
- afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
-
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // use linear regression to find the best fit for colors along the edges of the 4x4 block
- //
- void Block4x4Encoding_RGB8::CalculatePlanarCornerColors(void)
- {
- ColorFloatRGBA afrgbaRegression[MAX_PLANAR_REGRESSION_SIZE];
- ColorFloatRGBA frgbaSlope;
- ColorFloatRGBA frgbaOffset;
-
- // top edge
- afrgbaRegression[0] = m_pafrgbaSource[0];
- afrgbaRegression[1] = m_pafrgbaSource[4];
- afrgbaRegression[2] = m_pafrgbaSource[8];
- afrgbaRegression[3] = m_pafrgbaSource[12];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor1 = frgbaOffset;
- m_frgbaColor2 = (frgbaSlope * 4.0f) + frgbaOffset;
-
- // left edge
- afrgbaRegression[0] = m_pafrgbaSource[0];
- afrgbaRegression[1] = m_pafrgbaSource[1];
- afrgbaRegression[2] = m_pafrgbaSource[2];
- afrgbaRegression[3] = m_pafrgbaSource[3];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor1 = (m_frgbaColor1 + frgbaOffset) * 0.5f; // average with top edge
- m_frgbaColor3 = (frgbaSlope * 4.0f) + frgbaOffset;
-
- // right edge
- afrgbaRegression[0] = m_pafrgbaSource[12];
- afrgbaRegression[1] = m_pafrgbaSource[13];
- afrgbaRegression[2] = m_pafrgbaSource[14];
- afrgbaRegression[3] = m_pafrgbaSource[15];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor2 = (m_frgbaColor2 + frgbaOffset) * 0.5f; // average with top edge
-
- // bottom edge
- afrgbaRegression[0] = m_pafrgbaSource[3];
- afrgbaRegression[1] = m_pafrgbaSource[7];
- afrgbaRegression[2] = m_pafrgbaSource[11];
- afrgbaRegression[3] = m_pafrgbaSource[15];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor3 = (m_frgbaColor3 + frgbaOffset) * 0.5f; // average with left edge
-
- // quantize corner colors to 6/7/6
- m_frgbaColor1 = m_frgbaColor1.QuantizeR6G7B6();
- m_frgbaColor2 = m_frgbaColor2.QuantizeR6G7B6();
- m_frgbaColor3 = m_frgbaColor3.QuantizeR6G7B6();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing R, G and B independently
- //
- // R, G and B decoding and errors are independent, so R, G and B twiddles can be independent
- //
- // return true if improvement
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanar(void)
- {
- bool boolImprovement = false;
-
- while (TwiddlePlanarR())
- {
- boolImprovement = true;
- }
-
- while (TwiddlePlanarG())
- {
- boolImprovement = true;
- }
-
- while (TwiddlePlanarB())
- {
- boolImprovement = true;
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing R
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarR()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginRed = encodingTry.m_frgbaColor1.IntRed(63.0f);
- int iHorizRed = encodingTry.m_frgbaColor2.IntRed(63.0f);
- int iVertRed = encodingTry.m_frgbaColor3.IntRed(63.0f);
-
- for (int iTryOriginRed = iOriginRed - 1; iTryOriginRed <= iOriginRed + 1; iTryOriginRed++)
- {
- // check for out of range
- if (iTryOriginRed < 0 || iTryOriginRed > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fR = ((iTryOriginRed << 2) + (iTryOriginRed >> 4)) / 255.0f;
-
- for (int iTryHorizRed = iHorizRed - 1; iTryHorizRed <= iHorizRed + 1; iTryHorizRed++)
- {
- // check for out of range
- if (iTryHorizRed < 0 || iTryHorizRed > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fR = ((iTryHorizRed << 2) + (iTryHorizRed >> 4)) / 255.0f;
-
- for (int iTryVertRed = iVertRed - 1; iTryVertRed <= iVertRed + 1; iTryVertRed++)
- {
- // check for out of range
- if (iTryVertRed < 0 || iTryVertRed > 63)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginRed == iOriginRed && iTryHorizRed == iHorizRed && iTryVertRed == iVertRed)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fR = ((iTryVertRed << 2) + (iTryVertRed >> 4)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing G
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarG()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginGreen = encodingTry.m_frgbaColor1.IntGreen(127.0f);
- int iHorizGreen = encodingTry.m_frgbaColor2.IntGreen(127.0f);
- int iVertGreen = encodingTry.m_frgbaColor3.IntGreen(127.0f);
-
- for (int iTryOriginGreen = iOriginGreen - 1; iTryOriginGreen <= iOriginGreen + 1; iTryOriginGreen++)
- {
- // check for out of range
- if (iTryOriginGreen < 0 || iTryOriginGreen > 127)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fG = ((iTryOriginGreen << 1) + (iTryOriginGreen >> 6)) / 255.0f;
-
- for (int iTryHorizGreen = iHorizGreen - 1; iTryHorizGreen <= iHorizGreen + 1; iTryHorizGreen++)
- {
- // check for out of range
- if (iTryHorizGreen < 0 || iTryHorizGreen > 127)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fG = ((iTryHorizGreen << 1) + (iTryHorizGreen >> 6)) / 255.0f;
-
- for (int iTryVertGreen = iVertGreen - 1; iTryVertGreen <= iVertGreen + 1; iTryVertGreen++)
- {
- // check for out of range
- if (iTryVertGreen < 0 || iTryVertGreen > 127)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginGreen == iOriginGreen &&
- iTryHorizGreen == iHorizGreen &&
- iTryVertGreen == iVertGreen)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fG = ((iTryVertGreen << 1) + (iTryVertGreen >> 6)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing B
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarB()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginBlue = encodingTry.m_frgbaColor1.IntBlue(63.0f);
- int iHorizBlue = encodingTry.m_frgbaColor2.IntBlue(63.0f);
- int iVertBlue = encodingTry.m_frgbaColor3.IntBlue(63.0f);
-
- for (int iTryOriginBlue = iOriginBlue - 1; iTryOriginBlue <= iOriginBlue + 1; iTryOriginBlue++)
- {
- // check for out of range
- if (iTryOriginBlue < 0 || iTryOriginBlue > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fB = ((iTryOriginBlue << 2) + (iTryOriginBlue >> 4)) / 255.0f;
-
- for (int iTryHorizBlue = iHorizBlue - 1; iTryHorizBlue <= iHorizBlue + 1; iTryHorizBlue++)
- {
- // check for out of range
- if (iTryHorizBlue < 0 || iTryHorizBlue > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fB = ((iTryHorizBlue << 2) + (iTryHorizBlue >> 4)) / 255.0f;
-
- for (int iTryVertBlue = iVertBlue - 1; iTryVertBlue <= iVertBlue + 1; iTryVertBlue++)
- {
- // check for out of range
- if (iTryVertBlue < 0 || iTryVertBlue > 63)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginBlue == iOriginBlue && iTryHorizBlue == iHorizBlue && iTryVertBlue == iVertBlue)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fB = ((iTryVertBlue << 2) + (iTryVertBlue >> 4)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGB8::SetEncodingBits(void)
- {
-
- switch (m_mode)
- {
- case MODE_ETC1:
- Block4x4Encoding_ETC1::SetEncodingBits();
- break;
-
- case MODE_T:
- SetEncodingBits_T();
- break;
-
- case MODE_H:
- SetEncodingBits_H();
- break;
-
- case MODE_PLANAR:
- SetEncodingBits_Planar();
- break;
-
- default:
- assert(false);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for T mode
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_T(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_T);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2;
- m_pencodingbitsRGB8->t.red1b = uiRed1;
- m_pencodingbitsRGB8->t.green1 = uiGreen1;
- m_pencodingbitsRGB8->t.blue1 = uiBlue1;
-
- m_pencodingbitsRGB8->t.red2 = uiRed2;
- m_pencodingbitsRGB8->t.green2 = uiGreen2;
- m_pencodingbitsRGB8->t.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1;
- m_pencodingbitsRGB8->t.db = m_uiCW1;
-
- m_pencodingbitsRGB8->t.diff = 1;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- if (iRed2 >= 4)
- {
- m_pencodingbitsRGB8->t.detect1 = 7;
- m_pencodingbitsRGB8->t.detect2 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
-
- // make sure red overflows
- assert(iRed2 < 0 || iRed2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for H mode
- //
- // colors and selectors may need to swap in order to generate lsb of distance index
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_H(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_H);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
- unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- bool boolOddDistance = m_uiCW1 & 1;
- bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance;
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.red1 = uiRed2;
- m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen2;
- m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue2;
-
- m_pencodingbitsRGB8->h.red2 = uiRed1;
- m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen1;
- m_pencodingbitsRGB8->h.blue2 = uiBlue1;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
- else
- {
- m_pencodingbitsRGB8->h.red1 = uiRed1;
- m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen1;
- m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue1;
-
- m_pencodingbitsRGB8->h.red2 = uiRed2;
- m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen2;
- m_pencodingbitsRGB8->h.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
-
- m_pencodingbitsRGB8->h.diff = 1;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF;
- }
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->h.detect1 = 0;
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->h.detect1 = 1;
- }
- if (iGreen2 >= 4)
- {
- m_pencodingbitsRGB8->h.detect2 = 7;
- m_pencodingbitsRGB8->h.detect3 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
-
- // make sure red doesn't overflow and green does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 < 0 || iGreen2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for Planar mode
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_Planar(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_PLANAR);
- assert(m_boolDiff == true);
-
- unsigned int uiOriginRed = (unsigned int)m_frgbaColor1.IntRed(63.0f);
- unsigned int uiOriginGreen = (unsigned int)m_frgbaColor1.IntGreen(127.0f);
- unsigned int uiOriginBlue = (unsigned int)m_frgbaColor1.IntBlue(63.0f);
-
- unsigned int uiHorizRed = (unsigned int)m_frgbaColor2.IntRed(63.0f);
- unsigned int uiHorizGreen = (unsigned int)m_frgbaColor2.IntGreen(127.0f);
- unsigned int uiHorizBlue = (unsigned int)m_frgbaColor2.IntBlue(63.0f);
-
- unsigned int uiVertRed = (unsigned int)m_frgbaColor3.IntRed(63.0f);
- unsigned int uiVertGreen = (unsigned int)m_frgbaColor3.IntGreen(127.0f);
- unsigned int uiVertBlue = (unsigned int)m_frgbaColor3.IntBlue(63.0f);
-
- m_pencodingbitsRGB8->planar.originRed = uiOriginRed;
- m_pencodingbitsRGB8->planar.originGreen1 = uiOriginGreen >> 6;
- m_pencodingbitsRGB8->planar.originGreen2 = uiOriginGreen;
- m_pencodingbitsRGB8->planar.originBlue1 = uiOriginBlue >> 5;
- m_pencodingbitsRGB8->planar.originBlue2 = uiOriginBlue >> 3;
- m_pencodingbitsRGB8->planar.originBlue3 = uiOriginBlue >> 1;
- m_pencodingbitsRGB8->planar.originBlue4 = uiOriginBlue;
-
- m_pencodingbitsRGB8->planar.horizRed1 = uiHorizRed >> 1;
- m_pencodingbitsRGB8->planar.horizRed2 = uiHorizRed;
- m_pencodingbitsRGB8->planar.horizGreen = uiHorizGreen;
- m_pencodingbitsRGB8->planar.horizBlue1 = uiHorizBlue >> 5;
- m_pencodingbitsRGB8->planar.horizBlue2 = uiHorizBlue;
-
- m_pencodingbitsRGB8->planar.vertRed1 = uiVertRed >> 3;
- m_pencodingbitsRGB8->planar.vertRed2 = uiVertRed;
- m_pencodingbitsRGB8->planar.vertGreen1 = uiVertGreen >> 2;
- m_pencodingbitsRGB8->planar.vertGreen2 = uiVertGreen;
- m_pencodingbitsRGB8->planar.vertBlue = uiVertBlue;
-
- m_pencodingbitsRGB8->planar.diff = 1;
-
- // create valid RG differentials and an invalid B differential to trigger planar mode
- m_pencodingbitsRGB8->planar.detect1 = 0;
- m_pencodingbitsRGB8->planar.detect2 = 0;
- m_pencodingbitsRGB8->planar.detect3 = 0;
- m_pencodingbitsRGB8->planar.detect4 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- int iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->planar.detect1 = 1;
- }
- if (iGreen2 < 0 || iGreen2 > 31)
- {
- m_pencodingbitsRGB8->planar.detect2 = 1;
- }
- if (iBlue2 >= 4)
- {
- m_pencodingbitsRGB8->planar.detect3 = 7;
- m_pencodingbitsRGB8->planar.detect4 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->planar.detect3 = 0;
- m_pencodingbitsRGB8->planar.detect4 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2;
-
- // make sure red and green don't overflow and blue does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 >= 0 && iGreen2 <= 31);
- assert(iBlue2 < 0 || iBlue2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for T mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_T(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- break;
-
- case 2:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2;
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for H mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_H(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB();
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB();
- break;
-
- case 2:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for Planar mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_Planar(void)
- {
-
- int iRO = (int)roundf(m_frgbaColor1.fR * 255.0f);
- int iGO = (int)roundf(m_frgbaColor1.fG * 255.0f);
- int iBO = (int)roundf(m_frgbaColor1.fB * 255.0f);
-
- int iRH = (int)roundf(m_frgbaColor2.fR * 255.0f);
- int iGH = (int)roundf(m_frgbaColor2.fG * 255.0f);
- int iBH = (int)roundf(m_frgbaColor2.fB * 255.0f);
-
- int iRV = (int)roundf(m_frgbaColor3.fR * 255.0f);
- int iGV = (int)roundf(m_frgbaColor3.fG * 255.0f);
- int iBV = (int)roundf(m_frgbaColor3.fB * 255.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- int iX = (int)(uiPixel >> 2);
- int iY = (int)(uiPixel & 3);
-
- int iR = (iX*(iRH - iRO) + iY*(iRV - iRO) + 4*iRO + 2) >> 2;
- int iG = (iX*(iGH - iGO) + iY*(iGV - iGO) + 4*iGO + 2) >> 2;
- int iB = (iX*(iBH - iBO) + iY*(iBV - iBO) + 4*iBO + 2) >> 2;
-
- ColorFloatRGBA frgba;
- frgba.fR = (float)iR / 255.0f;
- frgba.fG = (float)iG / 255.0f;
- frgba.fB = (float)iB / 255.0f;
- frgba.fA = 1.0f;
-
- m_afrgbaDecodedColors[uiPixel] = frgba.ClampRGB();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a linear regression for the a_uiPixels in a_pafrgbaPixels[]
- //
- // output the closest color line using a_pfrgbaSlope and a_pfrgbaOffset
- //
- void Block4x4Encoding_RGB8::ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels,
- ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset)
- {
- typedef struct
- {
- float f[4];
- } Float4;
-
- Float4 *paf4Pixels = (Float4 *)(a_pafrgbaPixels);
- Float4 *pf4Slope = (Float4 *)(a_pfrgbaSlope);
- Float4 *pf4Offset = (Float4 *)(a_pfrgbaOffset);
-
- float afX[MAX_PLANAR_REGRESSION_SIZE];
- float afY[MAX_PLANAR_REGRESSION_SIZE];
-
- // handle r, g and b separately. don't bother with a
- for (unsigned int uiComponent = 0; uiComponent < 3; uiComponent++)
- {
- for (unsigned int uiPixel = 0; uiPixel < a_uiPixels; uiPixel++)
- {
- afX[uiPixel] = (float)uiPixel;
- afY[uiPixel] = paf4Pixels[uiPixel].f[uiComponent];
-
- }
- Etc::Regression(afX, afY, a_uiPixels,
- &(pf4Slope->f[uiComponent]), &(pf4Offset->f[uiComponent]));
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
deleted file mode 100644
index 03754d5e3b..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
deleted file mode 100644
index b94b64e68c..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
+++ /dev/null
@@ -1,1819 +0,0 @@
-/*
- * 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_RGB8A1.cpp contains:
- Block4x4Encoding_RGB8A1
- Block4x4Encoding_RGB8A1_Opaque
- Block4x4Encoding_RGB8A1_Transparent
-
-These encoders are used when targetting file format RGB8A1.
-
-Block4x4Encoding_RGB8A1_Opaque is used when all pixels in the 4x4 block are opaque
-Block4x4Encoding_RGB8A1_Transparent is used when all pixels in the 4x4 block are transparent
-Block4x4Encoding_RGB8A1 is used when there is a mixture of alphas in the 4x4 block
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGB8A1.h"
-
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1
- // ####################################################################################################
-
- float Block4x4Encoding_RGB8A1::s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS] =
- {
- { 0.0f / 255.0f, 8.0f / 255.0f, 0.0f / 255.0f, -8.0f / 255.0f },
- { 0.0f / 255.0f, 17.0f / 255.0f, 0.0f / 255.0f, -17.0f / 255.0f },
- { 0.0f / 255.0f, 29.0f / 255.0f, 0.0f / 255.0f, -29.0f / 255.0f },
- { 0.0f / 255.0f, 42.0f / 255.0f, 0.0f / 255.0f, -42.0f / 255.0f },
- { 0.0f / 255.0f, 60.0f / 255.0f, 0.0f / 255.0f, -60.0f / 255.0f },
- { 0.0f / 255.0f, 80.0f / 255.0f, 0.0f / 255.0f, -80.0f / 255.0f },
- { 0.0f / 255.0f, 106.0f / 255.0f, 0.0f / 255.0f, -106.0f / 255.0f },
- { 0.0f / 255.0f, 183.0f / 255.0f, 0.0f / 255.0f, -183.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGB8A1::Block4x4Encoding_RGB8A1(void)
- {
- m_pencodingbitsRGB8 = nullptr;
- m_boolOpaque = false;
- m_boolTransparent = false;
- m_boolPunchThroughPixels = true;
-
- }
- Block4x4Encoding_RGB8A1::~Block4x4Encoding_RGB8A1(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_RGB8A1::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding_RGB8::InitFromSource(a_pblockParent,
- a_pafrgbaSource,
- a_paucEncodingBits,
- a_errormetric);
-
- m_boolOpaque = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE;
- m_boolTransparent = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::TRANSPARENT;
- m_boolPunchThroughPixels = a_pblockParent->HasPunchThroughPixels();
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- if (m_pafrgbaSource[uiPixel].fA >= 0.5f)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- else
- {
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // 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_RGB8A1::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
-
- InitFromEncodingBits_ETC1(a_pblockParent,
- a_paucEncodingBits,
- a_pafrgbaSource,
- a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- // detect if there is a T, H or Planar mode present
- int iRed1 = m_pencodingbitsRGB8->differential.red1;
- int iDRed2 = m_pencodingbitsRGB8->differential.dred2;
- int iRed2 = iRed1 + iDRed2;
-
- int iGreen1 = m_pencodingbitsRGB8->differential.green1;
- int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2;
- int iGreen2 = iGreen1 + iDGreen2;
-
- int iBlue1 = m_pencodingbitsRGB8->differential.blue1;
- int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2;
- int iBlue2 = iBlue1 + iDBlue2;
-
- if (iRed2 < 0 || iRed2 > 31)
- {
- InitFromEncodingBits_T();
- }
- else if (iGreen2 < 0 || iGreen2 > 31)
- {
- InitFromEncodingBits_H();
- }
- else if (iBlue2 < 0 || iBlue2 > 31)
- {
- Block4x4Encoding_RGB8::InitFromEncodingBits_Planar();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding assuming the encoding is an ETC1 mode.
- // if it isn't an ETC1 mode, this will be overwritten later
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,
- a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = m_pencodingbitsRGB8->differential.flip;
- m_boolOpaque = m_pencodingbitsRGB8->differential.diff;
-
- int iR2 = m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2;
- if (iR2 < 0)
- {
- iR2 = 0;
- }
- else if (iR2 > 31)
- {
- iR2 = 31;
- }
-
- int iG2 = m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2;
- if (iG2 < 0)
- {
- iG2 = 0;
- }
- else if (iG2 > 31)
- {
- iG2 = 31;
- }
-
- int iB2 = m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2;
- if (iB2 < 0)
- {
- iB2 = 0;
- }
- else if (iB2 > 31)
- {
- iB2 = 31;
- }
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2);
-
- m_uiCW1 = m_pencodingbitsRGB8->differential.cw1;
- m_uiCW2 = m_pencodingbitsRGB8->differential.cw2;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- Decode_ETC1();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if T mode is detected
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_T(void)
- {
- m_mode = MODE_T;
-
- unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) +
- m_pencodingbitsRGB8->t.red1b);
- unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1;
- unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1;
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2;
- unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2;
- unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_T();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if H mode is detected
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_H(void)
- {
- m_mode = MODE_H;
-
- unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1;
- unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) +
- m_pencodingbitsRGB8->h.green1b);
- unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) +
- (m_pencodingbitsRGB8->h.blue1b << 1) +
- m_pencodingbitsRGB8->h.blue1c);
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2;
- unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) +
- m_pencodingbitsRGB8->h.green2b);
- unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- // used to determine the LSB of the CW
- unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1);
- unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1);
- if (uiRGB1 >= uiRGB2)
- {
- m_uiCW1++;
- }
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_H();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for ETC1 modes, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::Decode_ETC1(void)
- {
-
- const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++)
- {
- ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2;
- unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2;
-
- unsigned int uiPixel = pauiPixelOrder[uiPixelOrder];
-
- float fDelta;
- if (m_boolOpaque)
- fDelta = Block4x4Encoding_ETC1::s_aafCwTable[uiCW][m_auiSelectors[uiPixel]];
- else
- fDelta = s_aafCwOpaqueUnsetTable[uiCW][m_auiSelectors[uiPixel]];
-
- if (m_boolOpaque == false && m_auiSelectors[uiPixel] == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for T mode, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::DecodePixels_T(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 2:
- if (m_boolOpaque == false)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for H mode, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::DecodePixels_H(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 2:
- if (m_boolOpaque == false)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
- }
-
- }
-
- }
-
-
- // ----------------------------------------------------------------------------------------------------
- // 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
- //
- // RGB8A1 can't use individual mode
- // RGB8A1 with transparent pixels can't use planar mode
- //
- void Block4x4Encoding_RGB8A1::PerformIteration(float a_fEffort)
- {
- assert(!m_boolOpaque);
- assert(!m_boolTransparent);
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- if (a_fEffort <= 39.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH();
- TryT(1);
- TryH(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 4:
- TryDegenerates1();
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- TryDegenerates2();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryDegenerates3();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
-
- SetDoneIfPerfect();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_RGB8A1::PerformFirstIteration(void)
- {
- Block4x4Encoding_ETC1::CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // mostly copied from ETC1
- // differences:
- // Block4x4Encoding_RGB8A1 encodingTry = *this;
- //
- void Block4x4Encoding_RGB8A1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2,
- a_uiRadius, a_iGrayOffset1, a_iGrayOffset2);
-
- Block4x4Encoding_RGB8A1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryDifferentialHalf(&trys.m_half1);
- encodingTry.TryDifferentialHalf(&trys.m_half2);
-
- // find best halves that are within differential range
- DifferentialTrys::Try *ptryBest1 = nullptr;
- DifferentialTrys::Try *ptryBest2 = nullptr;
- encodingTry.m_fError = FLT_MAX;
-
- // see if the best of each half are in differential range
- int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed;
- int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen;
- int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue;
- if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3)
- {
- ptryBest1 = trys.m_half1.m_ptryBest;
- ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
- }
- else
- {
- // else, find the next best halves that are in differential range
- for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0];
- ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys];
- ptry1++)
- {
- for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0];
- ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys];
- ptry2++)
- {
- iDRed = ptry2->m_iRed - ptry1->m_iRed;
- bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4;
- iDGreen = ptry2->m_iGreen - ptry1->m_iGreen;
- bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4;
- iDBlue = ptry2->m_iBlue - ptry1->m_iBlue;
- bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4;
-
- if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta)
- {
- float fError = ptry1->m_fError + ptry2->m_fError;
-
- if (fError < encodingTry.m_fError)
- {
- encodingTry.m_fError = fError;
-
- ptryBest1 = ptry1;
- ptryBest2 = ptry2;
- }
- }
-
- }
- }
- assert(encodingTry.m_fError < FLT_MAX);
- assert(ptryBest1 != nullptr);
- assert(ptryBest2 != nullptr);
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- m_fError = 0.0f;
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- if (uiSelector1 == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel1] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel1] = 0.0f;
- }
- else
- {
- float fDeltaRGB1 = s_aafCwOpaqueUnsetTable[m_uiCW1][uiSelector1];
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afDecodedAlphas[uiPixel1] = 1.0f;
- }
-
- if (uiSelector2 == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel2] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel2] = 0.0f;
- }
- else
- {
- float fDeltaRGB2 = s_aafCwOpaqueUnsetTable[m_uiCW2][uiSelector2];
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- m_afDecodedAlphas[uiPixel2] = 1.0f;
- }
-
- float fDeltaA1 = m_afDecodedAlphas[uiPixel1] - m_pafrgbaSource[uiPixel1].fA;
- m_fError += fDeltaA1 * fDeltaA1;
- float fDeltaA2 = m_afDecodedAlphas[uiPixel2] - m_pafrgbaSource[uiPixel2].fA;
- m_fError += fDeltaA2 * fDeltaA2;
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors;
- m_fError = m_fError1 + m_fError2;
-
- // sanity check
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- iDRed = iRed2 - iRed1;
- iDGreen = iGreen2 - iGreen1;
- iDBlue = iBlue2 - iBlue1;
-
- assert(iDRed >= -4 && iDRed < 4);
- assert(iDGreen >= -4 && iDGreen < 4);
- assert(iDBlue >= -4 && iDBlue < 4);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // mostly copied from ETC1
- // differences:
- // uses s_aafCwOpaqueUnsetTable
- // color for selector set to 0,0,0,0
- //
- void Block4x4Encoding_RGB8A1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 31);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 31);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 31);
-
- DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedColors[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = ColorFloatRGBA();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- if (pfrgbaSourcePixel->fA < 0.5f)
- {
- uiSelector = TRANSPARENT_SELECTOR;
- }
- else if (uiSelector == TRANSPARENT_SELECTOR)
- {
- continue;
- }
-
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedColors[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- if (uiSelector == TRANSPARENT_SELECTOR)
- {
- break;
- }
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently
- // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower
- //
- void Block4x4Encoding_RGB8A1::TryT(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8A1 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_T;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor2_TAndH
- // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector
- //
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- }
- else
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH;
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
- }
- else
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryT
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8A1::TryT_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = m_frgbaColor1;
- afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = ColorFloatRGBA();
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiMinSelector = 0;
- unsigned int uiMaxSelector = SELECTORS - 1;
-
- if (m_pafrgbaSource[uiPixel].fA < 0.5f)
- {
- uiMinSelector = 2;
- uiMaxSelector = 2;
- }
-
- for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++)
- {
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in H mode
- // save this encoding if it improves the error
- //
- // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently
- // TWIDDLE_RADIUS of 2 is WAY too slow
- //
- void Block4x4Encoding_RGB8A1::TryH(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8A1 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_H;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor2_TAndH
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryH
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8A1::TryH_BestSelectorCombination(void)
- {
-
- // abort if colors and CW will pose an encoding problem
- {
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(255.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(255.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(255.0f);
- unsigned int uiColorValue1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(255.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(255.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(255.0f);
- unsigned int uiColorValue2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- unsigned int uiCWLsb = m_uiCW1 & 1;
-
- if ((uiColorValue1 >= (uiColorValue2 & uiCWLsb)) == 0 ||
- (uiColorValue1 < (uiColorValue2 & uiCWLsb)) == 1)
- {
- return;
- }
- }
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB();
- afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = ColorFloatRGBA();;
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
-
- // try each selector
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiMinSelector = 0;
- unsigned int uiMaxSelector = SELECTORS - 1;
-
- if (m_pafrgbaSource[uiPixel].fA < 0.5f)
- {
- uiMinSelector = 2;
- uiMaxSelector = 2;
- }
-
- for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++)
- {
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 1 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates1(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 2 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates2(void)
- {
-
- TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 3 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates3(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 4 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates4(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 4);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -4);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits(void)
- {
- switch (m_mode)
- {
- case MODE_ETC1:
- SetEncodingBits_ETC1();
- break;
-
- case MODE_T:
- SetEncodingBits_T();
- break;
-
- case MODE_H:
- SetEncodingBits_H();
- break;
-
- case MODE_PLANAR:
- Block4x4Encoding_RGB8::SetEncodingBits_Planar();
- break;
-
- default:
- assert(false);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if ETC1 mode
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_ETC1(void)
- {
-
- // there is no individual mode in RGB8A1
- assert(m_boolDiff);
-
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- int iDRed2 = iRed2 - iRed1;
- int iDGreen2 = iGreen2 - iGreen1;
- int iDBlue2 = iBlue2 - iBlue1;
-
- assert(iDRed2 >= -4 && iDRed2 < 4);
- assert(iDGreen2 >= -4 && iDGreen2 < 4);
- assert(iDBlue2 >= -4 && iDBlue2 < 4);
-
- m_pencodingbitsRGB8->differential.red1 = iRed1;
- m_pencodingbitsRGB8->differential.green1 = iGreen1;
- m_pencodingbitsRGB8->differential.blue1 = iBlue1;
-
- m_pencodingbitsRGB8->differential.dred2 = iDRed2;
- m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2;
- m_pencodingbitsRGB8->differential.dblue2 = iDBlue2;
-
- m_pencodingbitsRGB8->individual.cw1 = m_uiCW1;
- m_pencodingbitsRGB8->individual.cw2 = m_uiCW2;
-
- SetEncodingBits_Selectors();
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- m_pencodingbitsRGB8->individual.flip = m_boolFlip;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if T mode
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_T(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_T);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2;
- m_pencodingbitsRGB8->t.red1b = uiRed1;
- m_pencodingbitsRGB8->t.green1 = uiGreen1;
- m_pencodingbitsRGB8->t.blue1 = uiBlue1;
-
- m_pencodingbitsRGB8->t.red2 = uiRed2;
- m_pencodingbitsRGB8->t.green2 = uiGreen2;
- m_pencodingbitsRGB8->t.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1;
- m_pencodingbitsRGB8->t.db = m_uiCW1;
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- if (iRed2 >= 4)
- {
- m_pencodingbitsRGB8->t.detect1 = 7;
- m_pencodingbitsRGB8->t.detect2 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
-
- // make sure red overflows
- assert(iRed2 < 0 || iRed2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if H mode
- //
- // colors and selectors may need to swap in order to generate lsb of distance index
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_H(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_H);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
- unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- bool boolOddDistance = m_uiCW1 & 1;
- bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance;
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.red1 = uiRed2;
- m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen2;
- m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue2;
-
- m_pencodingbitsRGB8->h.red2 = uiRed1;
- m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen1;
- m_pencodingbitsRGB8->h.blue2 = uiBlue1;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
- else
- {
- m_pencodingbitsRGB8->h.red1 = uiRed1;
- m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen1;
- m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue1;
-
- m_pencodingbitsRGB8->h.red2 = uiRed2;
- m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen2;
- m_pencodingbitsRGB8->h.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF;
- }
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->h.detect1 = 0;
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->h.detect1 = 1;
- }
- if (iGreen2 >= 4)
- {
- m_pencodingbitsRGB8->h.detect2 = 7;
- m_pencodingbitsRGB8->h.detect3 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
-
- // make sure red doesn't overflow and green does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 < 0 || iGreen2 > 31);
- }
-
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1_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_RGB8A1_Opaque::PerformIteration(float a_fEffort)
- {
- assert(!m_boolPunchThroughPixels);
- assert(!m_boolTransparent);
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 3:
- Block4x4Encoding_RGB8::TryPlanar(1);
- break;
-
- case 4:
- Block4x4Encoding_RGB8::TryTAndH(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- Block4x4Encoding_ETC1::TryDegenerates1();
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- Block4x4Encoding_ETC1::TryDegenerates2();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- Block4x4Encoding_ETC1::TryDegenerates3();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- Block4x4Encoding_ETC1::TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_RGB8A1_Opaque::PerformFirstIteration(void)
- {
-
- // set decoded alphas
- // calculate alpha error
- m_fError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
-
- float fDeltaA = 1.0f - m_pafrgbaSource[uiPixel].fA;
- m_fError += fDeltaA * fDeltaA;
- }
-
- CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_RGB8::TryPlanar(0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_RGB8::TryTAndH(0);
- SetDoneIfPerfect();
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1_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_RGB8A1_Transparent::PerformIteration(float )
- {
- assert(!m_boolOpaque);
- assert(m_boolTransparent);
- assert(!m_boolDone);
- assert(m_uiEncodingIterations == 0);
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = false;
-
- m_uiCW1 = 0;
- m_uiCW2 = 0;
-
- m_frgbaColor1 = ColorFloatRGBA();
- m_frgbaColor2 = ColorFloatRGBA();
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = TRANSPARENT_SELECTOR;
-
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
-
- CalcBlockError();
-
- m_boolDone = true;
- m_uiEncodingIterations++;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
deleted file mode 100644
index ff26e462f8..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
deleted file mode 100644
index 600c7ab405..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * 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;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
deleted file mode 100644
index 5765d36b90..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcColor.h b/thirdparty/etc2comp/EtcColor.h
deleted file mode 100644
index 7ceae05b65..0000000000
--- a/thirdparty/etc2comp/EtcColor.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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;
-
- };
-}
diff --git a/thirdparty/etc2comp/EtcColorFloatRGBA.h b/thirdparty/etc2comp/EtcColorFloatRGBA.h
deleted file mode 100644
index f2ca2c1f71..0000000000
--- a/thirdparty/etc2comp/EtcColorFloatRGBA.h
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * 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;
- };
-
-}
-
diff --git a/thirdparty/etc2comp/EtcConfig.h b/thirdparty/etc2comp/EtcConfig.h
deleted file mode 100644
index 3bfe1d99a8..0000000000
--- a/thirdparty/etc2comp/EtcConfig.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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>
-
diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.cpp b/thirdparty/etc2comp/EtcDifferentialTrys.cpp
deleted file mode 100644
index ef4cd103d9..0000000000
--- a/thirdparty/etc2comp/EtcDifferentialTrys.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.h b/thirdparty/etc2comp/EtcDifferentialTrys.h
deleted file mode 100644
index 71860908ff..0000000000
--- a/thirdparty/etc2comp/EtcDifferentialTrys.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcErrorMetric.h b/thirdparty/etc2comp/EtcErrorMetric.h
deleted file mode 100644
index df4dcab4fb..0000000000
--- a/thirdparty/etc2comp/EtcErrorMetric.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcFile.cpp b/thirdparty/etc2comp/EtcFile.cpp
deleted file mode 100644
index 831a3aac45..0000000000
--- a/thirdparty/etc2comp/EtcFile.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * 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);
-
-}
-
-// ----------------------------------------------------------------------------------------------------
-//
-
diff --git a/thirdparty/etc2comp/EtcFile.h b/thirdparty/etc2comp/EtcFile.h
deleted file mode 100644
index 69bf3b2d3a..0000000000
--- a/thirdparty/etc2comp/EtcFile.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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;
- };
-
-}
diff --git a/thirdparty/etc2comp/EtcFileHeader.cpp b/thirdparty/etc2comp/EtcFileHeader.cpp
deleted file mode 100644
index f02fcab011..0000000000
--- a/thirdparty/etc2comp/EtcFileHeader.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcFileHeader.h b/thirdparty/etc2comp/EtcFileHeader.h
deleted file mode 100644
index 55a9cb5d9d..0000000000
--- a/thirdparty/etc2comp/EtcFileHeader.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcFilter.cpp b/thirdparty/etc2comp/EtcFilter.cpp
deleted file mode 100644
index 1ec8acdf3f..0000000000
--- a/thirdparty/etc2comp/EtcFilter.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-#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 )
- {
- // -- GODOT start --
- free( contrib );
- // -- GODOT end --
- 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);
- }
- }
- }
-}
-
-
-} \ No newline at end of file
diff --git a/thirdparty/etc2comp/EtcFilter.h b/thirdparty/etc2comp/EtcFilter.h
deleted file mode 100644
index fcf125c6df..0000000000
--- a/thirdparty/etc2comp/EtcFilter.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#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;
-}
-
-
-} \ No newline at end of file
diff --git a/thirdparty/etc2comp/EtcImage.cpp b/thirdparty/etc2comp/EtcImage.cpp
deleted file mode 100644
index 7a1058844d..0000000000
--- a/thirdparty/etc2comp/EtcImage.cpp
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcImage.h b/thirdparty/etc2comp/EtcImage.h
deleted file mode 100644
index bd807ac32e..0000000000
--- a/thirdparty/etc2comp/EtcImage.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcIndividualTrys.cpp b/thirdparty/etc2comp/EtcIndividualTrys.cpp
deleted file mode 100644
index 56ff4c65ec..0000000000
--- a/thirdparty/etc2comp/EtcIndividualTrys.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcIndividualTrys.h b/thirdparty/etc2comp/EtcIndividualTrys.h
deleted file mode 100644
index 5fb12fbcf4..0000000000
--- a/thirdparty/etc2comp/EtcIndividualTrys.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcMath.cpp b/thirdparty/etc2comp/EtcMath.cpp
deleted file mode 100644
index 096d5f7ab9..0000000000
--- a/thirdparty/etc2comp/EtcMath.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcMath.h b/thirdparty/etc2comp/EtcMath.h
deleted file mode 100644
index c58c9a91bc..0000000000
--- a/thirdparty/etc2comp/EtcMath.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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);
- }
-
-
-}
diff --git a/thirdparty/etc2comp/EtcSortedBlockList.cpp b/thirdparty/etc2comp/EtcSortedBlockList.cpp
deleted file mode 100644
index bfa6b7b3fa..0000000000
--- a/thirdparty/etc2comp/EtcSortedBlockList.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/EtcSortedBlockList.h b/thirdparty/etc2comp/EtcSortedBlockList.h
deleted file mode 100644
index 960e8adc34..0000000000
--- a/thirdparty/etc2comp/EtcSortedBlockList.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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
diff --git a/thirdparty/etc2comp/LICENSE b/thirdparty/etc2comp/LICENSE
deleted file mode 100644
index d645695673..0000000000
--- a/thirdparty/etc2comp/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- 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.
diff --git a/thirdparty/etc2comp/README.md b/thirdparty/etc2comp/README.md
deleted file mode 100644
index 2f4363d042..0000000000
--- a/thirdparty/etc2comp/README.md
+++ /dev/null
@@ -1,197 +0,0 @@
-# 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.
diff --git a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch b/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
deleted file mode 100644
index ea9b5640b6..0000000000
--- a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
+++ /dev/null
@@ -1,224 +0,0 @@
-diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-index 5656556db9..5c7ebed788 100644
---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-@@ -508,7 +508,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -519,7 +519,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -530,7 +530,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -545,7 +545,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -556,7 +556,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -567,7 +567,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-@@ -761,7 +761,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -772,7 +772,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -783,7 +783,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -798,7 +798,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -809,7 +809,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -820,7 +820,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-index ba2b42fb05..b94b64e68c 100644
---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-@@ -847,7 +847,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -858,7 +858,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -869,7 +869,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -884,7 +884,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -895,7 +895,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -906,7 +906,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-@@ -1108,7 +1108,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -1119,7 +1119,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -1130,7 +1130,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -1145,7 +1145,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -1156,7 +1156,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -1167,7 +1167,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
diff --git a/thirdparty/etcpak/AUTHORS.txt b/thirdparty/etcpak/AUTHORS.txt
new file mode 100644
index 0000000000..e7bae62c85
--- /dev/null
+++ b/thirdparty/etcpak/AUTHORS.txt
@@ -0,0 +1,3 @@
+Bartosz Taudul <wolf@nereid.pl>
+Daniel Jungmann <el.3d.source@gmail.com>
+Florian Penzkofer <fp@nullptr.de>
diff --git a/thirdparty/etcpak/Bitmap.cpp b/thirdparty/etcpak/Bitmap.cpp
new file mode 100644
index 0000000000..ef318318ac
--- /dev/null
+++ b/thirdparty/etcpak/Bitmap.cpp
@@ -0,0 +1,216 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <png.h>
+#include "lz4/lz4.h"
+
+#include "Bitmap.hpp"
+#include "Debug.hpp"
+
+Bitmap::Bitmap( const char* fn, unsigned int lines, bool bgr )
+ : m_block( nullptr )
+ , m_lines( lines )
+ , m_alpha( true )
+ , m_sema( 0 )
+{
+ FILE* f = fopen( fn, "rb" );
+ assert( f );
+
+ char buf[4];
+ fread( buf, 1, 4, f );
+ if( memcmp( buf, "raw4", 4 ) == 0 )
+ {
+ uint8_t a;
+ fread( &a, 1, 1, f );
+ m_alpha = a == 1;
+ uint32_t d;
+ fread( &d, 1, 4, f );
+ m_size.x = d;
+ fread( &d, 1, 4, f );
+ m_size.y = d;
+ DBGPRINT( "Raw bitmap " << fn << " " << m_size.x << "x" << m_size.y );
+
+ assert( m_size.x % 4 == 0 );
+ assert( m_size.y % 4 == 0 );
+
+ int32_t csize;
+ fread( &csize, 1, 4, f );
+ char* cbuf = new char[csize];
+ fread( cbuf, 1, csize, f );
+ fclose( f );
+
+ m_block = m_data = new uint32_t[m_size.x*m_size.y];
+ m_linesLeft = m_size.y / 4;
+
+ LZ4_decompress_fast( cbuf, (char*)m_data, m_size.x*m_size.y*4 );
+ delete[] cbuf;
+
+ for( int i=0; i<m_size.y/4; i++ )
+ {
+ m_sema.unlock();
+ }
+ }
+ else
+ {
+ fseek( f, 0, SEEK_SET );
+
+ unsigned int sig_read = 0;
+ int bit_depth, color_type, interlace_type;
+
+ png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
+ png_infop info_ptr = png_create_info_struct( png_ptr );
+ setjmp( png_jmpbuf( png_ptr ) );
+
+ png_init_io( png_ptr, f );
+ png_set_sig_bytes( png_ptr, sig_read );
+
+ png_uint_32 w, h;
+
+ png_read_info( png_ptr, info_ptr );
+ png_get_IHDR( png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, &interlace_type, NULL, NULL );
+
+ m_size = v2i( w, h );
+
+ png_set_strip_16( png_ptr );
+ if( color_type == PNG_COLOR_TYPE_PALETTE )
+ {
+ png_set_palette_to_rgb( png_ptr );
+ }
+ else if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
+ {
+ png_set_expand_gray_1_2_4_to_8( png_ptr );
+ }
+ if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
+ {
+ png_set_tRNS_to_alpha( png_ptr );
+ }
+ if( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
+ {
+ png_set_gray_to_rgb(png_ptr);
+ }
+ if( bgr )
+ {
+ png_set_bgr(png_ptr);
+ }
+
+ switch( color_type )
+ {
+ case PNG_COLOR_TYPE_PALETTE:
+ if( !png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
+ {
+ png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
+ m_alpha = false;
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ png_set_gray_to_rgb( png_ptr );
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
+ m_alpha = false;
+ break;
+ default:
+ break;
+ }
+
+ DBGPRINT( "Bitmap " << fn << " " << w << "x" << h );
+
+ assert( w % 4 == 0 );
+ assert( h % 4 == 0 );
+
+ m_block = m_data = new uint32_t[w*h];
+ m_linesLeft = h / 4;
+
+ m_load = std::async( std::launch::async, [this, f, png_ptr, info_ptr]() mutable
+ {
+ auto ptr = m_data;
+ unsigned int lines = 0;
+ for( int i=0; i<m_size.y / 4; i++ )
+ {
+ for( int j=0; j<4; j++ )
+ {
+ png_read_rows( png_ptr, (png_bytepp)&ptr, NULL, 1 );
+ ptr += m_size.x;
+ }
+ lines++;
+ if( lines >= m_lines )
+ {
+ lines = 0;
+ m_sema.unlock();
+ }
+ }
+
+ if( lines != 0 )
+ {
+ m_sema.unlock();
+ }
+
+ png_read_end( png_ptr, info_ptr );
+ png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
+ fclose( f );
+ } );
+ }
+}
+
+Bitmap::Bitmap( const v2i& size )
+ : m_data( new uint32_t[size.x*size.y] )
+ , m_block( nullptr )
+ , m_lines( 1 )
+ , m_linesLeft( size.y / 4 )
+ , m_size( size )
+ , m_sema( 0 )
+{
+}
+
+Bitmap::Bitmap( const Bitmap& src, unsigned int lines )
+ : m_lines( lines )
+ , m_alpha( src.Alpha() )
+ , m_sema( 0 )
+{
+}
+
+Bitmap::~Bitmap()
+{
+ delete[] m_data;
+}
+
+void Bitmap::Write( const char* fn )
+{
+ FILE* f = fopen( fn, "wb" );
+ assert( f );
+
+ png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
+ png_infop info_ptr = png_create_info_struct( png_ptr );
+ setjmp( png_jmpbuf( png_ptr ) );
+ png_init_io( png_ptr, f );
+
+ png_set_IHDR( png_ptr, info_ptr, m_size.x, m_size.y, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );
+
+ png_write_info( png_ptr, info_ptr );
+
+ uint32_t* ptr = m_data;
+ for( int i=0; i<m_size.y; i++ )
+ {
+ png_write_rows( png_ptr, (png_bytepp)(&ptr), 1 );
+ ptr += m_size.x;
+ }
+
+ png_write_end( png_ptr, info_ptr );
+ png_destroy_write_struct( &png_ptr, &info_ptr );
+
+ fclose( f );
+}
+
+const uint32_t* Bitmap::NextBlock( unsigned int& lines, bool& done )
+{
+ std::lock_guard<std::mutex> lock( m_lock );
+ lines = std::min( m_lines, m_linesLeft );
+ auto ret = m_block;
+ m_sema.lock();
+ m_block += m_size.x * 4 * lines;
+ m_linesLeft -= lines;
+ done = m_linesLeft == 0;
+ return ret;
+}
diff --git a/thirdparty/etcpak/Bitmap.hpp b/thirdparty/etcpak/Bitmap.hpp
new file mode 100644
index 0000000000..fae8c936ed
--- /dev/null
+++ b/thirdparty/etcpak/Bitmap.hpp
@@ -0,0 +1,50 @@
+#ifndef __DARKRL__BITMAP_HPP__
+#define __DARKRL__BITMAP_HPP__
+
+#include <future>
+#include <memory>
+#include <mutex>
+#include <stdint.h>
+
+#include "Semaphore.hpp"
+#include "Vector.hpp"
+
+enum class Channels
+{
+ RGB,
+ Alpha
+};
+
+class Bitmap
+{
+public:
+ Bitmap( const char* fn, unsigned int lines, bool bgr );
+ Bitmap( const v2i& size );
+ virtual ~Bitmap();
+
+ void Write( const char* fn );
+
+ uint32_t* Data() { if( m_load.valid() ) m_load.wait(); return m_data; }
+ const uint32_t* Data() const { if( m_load.valid() ) m_load.wait(); return m_data; }
+ const v2i& Size() const { return m_size; }
+ bool Alpha() const { return m_alpha; }
+
+ const uint32_t* NextBlock( unsigned int& lines, bool& done );
+
+protected:
+ Bitmap( const Bitmap& src, unsigned int lines );
+
+ uint32_t* m_data;
+ uint32_t* m_block;
+ unsigned int m_lines;
+ unsigned int m_linesLeft;
+ v2i m_size;
+ bool m_alpha;
+ Semaphore m_sema;
+ std::mutex m_lock;
+ std::future<void> m_load;
+};
+
+typedef std::shared_ptr<Bitmap> BitmapPtr;
+
+#endif
diff --git a/thirdparty/etcpak/BitmapDownsampled.cpp b/thirdparty/etcpak/BitmapDownsampled.cpp
new file mode 100644
index 0000000000..0eb0d81185
--- /dev/null
+++ b/thirdparty/etcpak/BitmapDownsampled.cpp
@@ -0,0 +1,86 @@
+#include <string.h>
+#include <utility>
+
+#include "BitmapDownsampled.hpp"
+#include "Debug.hpp"
+
+BitmapDownsampled::BitmapDownsampled( const Bitmap& bmp, unsigned int lines )
+ : Bitmap( bmp, lines )
+{
+ m_size.x = std::max( 1, bmp.Size().x / 2 );
+ m_size.y = std::max( 1, bmp.Size().y / 2 );
+
+ int w = std::max( m_size.x, 4 );
+ int h = std::max( m_size.y, 4 );
+
+ DBGPRINT( "Subbitmap " << m_size.x << "x" << m_size.y );
+
+ m_block = m_data = new uint32_t[w*h];
+
+ if( m_size.x < w || m_size.y < h )
+ {
+ memset( m_data, 0, w*h*sizeof( uint32_t ) );
+ m_linesLeft = h / 4;
+ unsigned int lines = 0;
+ for( int i=0; i<h/4; i++ )
+ {
+ for( int j=0; j<4; j++ )
+ {
+ lines++;
+ if( lines > m_lines )
+ {
+ lines = 0;
+ m_sema.unlock();
+ }
+ }
+ }
+ if( lines != 0 )
+ {
+ m_sema.unlock();
+ }
+ }
+ else
+ {
+ m_linesLeft = h / 4;
+ m_load = std::async( std::launch::async, [this, &bmp, w, h]() mutable
+ {
+ auto ptr = m_data;
+ auto src1 = bmp.Data();
+ auto src2 = src1 + bmp.Size().x;
+ unsigned int lines = 0;
+ for( int i=0; i<h/4; i++ )
+ {
+ for( int j=0; j<4; j++ )
+ {
+ for( int k=0; k<m_size.x; k++ )
+ {
+ int r = ( ( *src1 & 0x000000FF ) + ( *(src1+1) & 0x000000FF ) + ( *src2 & 0x000000FF ) + ( *(src2+1) & 0x000000FF ) ) / 4;
+ int g = ( ( ( *src1 & 0x0000FF00 ) + ( *(src1+1) & 0x0000FF00 ) + ( *src2 & 0x0000FF00 ) + ( *(src2+1) & 0x0000FF00 ) ) / 4 ) & 0x0000FF00;
+ int b = ( ( ( *src1 & 0x00FF0000 ) + ( *(src1+1) & 0x00FF0000 ) + ( *src2 & 0x00FF0000 ) + ( *(src2+1) & 0x00FF0000 ) ) / 4 ) & 0x00FF0000;
+ int a = ( ( ( ( ( *src1 & 0xFF000000 ) >> 8 ) + ( ( *(src1+1) & 0xFF000000 ) >> 8 ) + ( ( *src2 & 0xFF000000 ) >> 8 ) + ( ( *(src2+1) & 0xFF000000 ) >> 8 ) ) / 4 ) & 0x00FF0000 ) << 8;
+ *ptr++ = r | g | b | a;
+ src1 += 2;
+ src2 += 2;
+ }
+ src1 += m_size.x * 2;
+ src2 += m_size.x * 2;
+ }
+ lines++;
+ if( lines >= m_lines )
+ {
+ lines = 0;
+ m_sema.unlock();
+ }
+ }
+
+ if( lines != 0 )
+ {
+ m_sema.unlock();
+ }
+ } );
+ }
+}
+
+BitmapDownsampled::~BitmapDownsampled()
+{
+}
diff --git a/thirdparty/etcpak/BitmapDownsampled.hpp b/thirdparty/etcpak/BitmapDownsampled.hpp
new file mode 100644
index 0000000000..b7313808df
--- /dev/null
+++ b/thirdparty/etcpak/BitmapDownsampled.hpp
@@ -0,0 +1,13 @@
+#ifndef __DARKRL__BITMAPDOWNSAMPLED_HPP__
+#define __DARKRL__BITMAPDOWNSAMPLED_HPP__
+
+#include "Bitmap.hpp"
+
+class BitmapDownsampled : public Bitmap
+{
+public:
+ BitmapDownsampled( const Bitmap& bmp, unsigned int lines );
+ ~BitmapDownsampled();
+};
+
+#endif
diff --git a/thirdparty/etcpak/BlockData.cpp b/thirdparty/etcpak/BlockData.cpp
new file mode 100644
index 0000000000..4906e69492
--- /dev/null
+++ b/thirdparty/etcpak/BlockData.cpp
@@ -0,0 +1,1296 @@
+#include <assert.h>
+#include <string.h>
+
+#include "BlockData.hpp"
+#include "ColorSpace.hpp"
+#include "Debug.hpp"
+#include "MipMap.hpp"
+#include "mmap.hpp"
+#include "ProcessRGB.hpp"
+#include "ProcessDxtc.hpp"
+#include "Tables.hpp"
+#include "TaskDispatch.hpp"
+
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+#if defined __SSE4_1__ || defined __AVX2__ || defined _MSC_VER
+# ifdef _MSC_VER
+# include <intrin.h>
+# include <Windows.h>
+# define _bswap(x) _byteswap_ulong(x)
+# define _bswap64(x) _byteswap_uint64(x)
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+#ifndef _bswap
+# define _bswap(x) __builtin_bswap32(x)
+# define _bswap64(x) __builtin_bswap64(x)
+#endif
+
+static uint8_t table59T58H[8] = { 3,6,11,16,23,32,41,64 };
+
+BlockData::BlockData( const char* fn )
+ : m_file( fopen( fn, "rb" ) )
+{
+ assert( m_file );
+ fseek( m_file, 0, SEEK_END );
+ m_maplen = ftell( m_file );
+ fseek( m_file, 0, SEEK_SET );
+ m_data = (uint8_t*)mmap( nullptr, m_maplen, PROT_READ, MAP_SHARED, fileno( m_file ), 0 );
+
+ auto data32 = (uint32_t*)m_data;
+ if( *data32 == 0x03525650 )
+ {
+ // PVR
+ switch( *(data32+2) )
+ {
+ case 6:
+ m_type = Etc1;
+ break;
+ case 7:
+ m_type = Dxt1;
+ break;
+ case 11:
+ m_type = Dxt5;
+ break;
+ case 22:
+ m_type = Etc2_RGB;
+ break;
+ case 23:
+ m_type = Etc2_RGBA;
+ break;
+ default:
+ assert( false );
+ break;
+ }
+
+ m_size.y = *(data32+6);
+ m_size.x = *(data32+7);
+ m_dataOffset = 52 + *(data32+12);
+ }
+ else if( *data32 == 0x58544BAB )
+ {
+ // KTX
+ switch( *(data32+7) )
+ {
+ case 0x9274:
+ m_type = Etc2_RGB;
+ break;
+ case 0x9278:
+ m_type = Etc2_RGBA;
+ break;
+ default:
+ assert( false );
+ break;
+ }
+
+ m_size.x = *(data32+9);
+ m_size.y = *(data32+10);
+ m_dataOffset = sizeof( uint32_t ) * 17 + *(data32+15);
+ }
+ else
+ {
+ assert( false );
+ }
+}
+
+static uint8_t* OpenForWriting( const char* fn, size_t len, const v2i& size, FILE** f, int levels, BlockData::Type type )
+{
+ *f = fopen( fn, "wb+" );
+ assert( *f );
+ fseek( *f, len - 1, SEEK_SET );
+ const char zero = 0;
+ fwrite( &zero, 1, 1, *f );
+ fseek( *f, 0, SEEK_SET );
+
+ auto ret = (uint8_t*)mmap( nullptr, len, PROT_WRITE, MAP_SHARED, fileno( *f ), 0 );
+ auto dst = (uint32_t*)ret;
+
+ *dst++ = 0x03525650; // version
+ *dst++ = 0; // flags
+ switch( type ) // pixelformat[0]
+ {
+ case BlockData::Etc1:
+ *dst++ = 6;
+ break;
+ case BlockData::Etc2_RGB:
+ *dst++ = 22;
+ break;
+ case BlockData::Etc2_RGBA:
+ *dst++ = 23;
+ break;
+ case BlockData::Dxt1:
+ *dst++ = 7;
+ break;
+ case BlockData::Dxt5:
+ *dst++ = 11;
+ break;
+ default:
+ assert( false );
+ break;
+ }
+ *dst++ = 0; // pixelformat[1]
+ *dst++ = 0; // colourspace
+ *dst++ = 0; // channel type
+ *dst++ = size.y; // height
+ *dst++ = size.x; // width
+ *dst++ = 1; // depth
+ *dst++ = 1; // num surfs
+ *dst++ = 1; // num faces
+ *dst++ = levels; // mipmap count
+ *dst++ = 0; // metadata size
+
+ return ret;
+}
+
+static int AdjustSizeForMipmaps( const v2i& size, int levels )
+{
+ int len = 0;
+ v2i current = size;
+ for( int i=1; i<levels; i++ )
+ {
+ assert( current.x != 1 || current.y != 1 );
+ current.x = std::max( 1, current.x / 2 );
+ current.y = std::max( 1, current.y / 2 );
+ len += std::max( 4, current.x ) * std::max( 4, current.y ) / 2;
+ }
+ assert( current.x == 1 && current.y == 1 );
+ return len;
+}
+
+BlockData::BlockData( const char* fn, const v2i& size, bool mipmap, Type type )
+ : m_size( size )
+ , m_dataOffset( 52 )
+ , m_maplen( m_size.x*m_size.y/2 )
+ , m_type( type )
+{
+ assert( m_size.x%4 == 0 && m_size.y%4 == 0 );
+
+ uint32_t cnt = m_size.x * m_size.y / 16;
+ DBGPRINT( cnt << " blocks" );
+
+ int levels = 1;
+
+ if( mipmap )
+ {
+ levels = NumberOfMipLevels( size );
+ DBGPRINT( "Number of mipmaps: " << levels );
+ m_maplen += AdjustSizeForMipmaps( size, levels );
+ }
+
+ if( type == Etc2_RGBA || type == Dxt5 ) m_maplen *= 2;
+
+ m_maplen += m_dataOffset;
+ m_data = OpenForWriting( fn, m_maplen, m_size, &m_file, levels, type );
+}
+
+BlockData::BlockData( const v2i& size, bool mipmap, Type type )
+ : m_size( size )
+ , m_dataOffset( 52 )
+ , m_file( nullptr )
+ , m_maplen( m_size.x*m_size.y/2 )
+ , m_type( type )
+{
+ assert( m_size.x%4 == 0 && m_size.y%4 == 0 );
+ if( mipmap )
+ {
+ const int levels = NumberOfMipLevels( size );
+ m_maplen += AdjustSizeForMipmaps( size, levels );
+ }
+
+ if( type == Etc2_RGBA || type == Dxt5 ) m_maplen *= 2;
+
+ m_maplen += m_dataOffset;
+ m_data = new uint8_t[m_maplen];
+}
+
+BlockData::~BlockData()
+{
+ if( m_file )
+ {
+ munmap( m_data, m_maplen );
+ fclose( m_file );
+ }
+ else
+ {
+ delete[] m_data;
+ }
+}
+
+void BlockData::Process( const uint32_t* src, uint32_t blocks, size_t offset, size_t width, Channels type, bool dither )
+{
+ auto dst = ((uint64_t*)( m_data + m_dataOffset )) + offset;
+
+ if( type == Channels::Alpha )
+ {
+ if( m_type != Etc1 )
+ {
+ CompressEtc2Alpha( src, dst, blocks, width );
+ }
+ else
+ {
+ CompressEtc1Alpha( src, dst, blocks, width );
+ }
+ }
+ else
+ {
+ switch( m_type )
+ {
+ case Etc1:
+ if( dither )
+ {
+ CompressEtc1RgbDither( src, dst, blocks, width );
+ }
+ else
+ {
+ CompressEtc1Rgb( src, dst, blocks, width );
+ }
+ break;
+ case Etc2_RGB:
+ CompressEtc2Rgb( src, dst, blocks, width );
+ break;
+ case Dxt1:
+ if( dither )
+ {
+ CompressDxt1Dither( src, dst, blocks, width );
+ }
+ else
+ {
+ CompressDxt1( src, dst, blocks, width );
+ }
+ break;
+ default:
+ assert( false );
+ break;
+ }
+ }
+}
+
+void BlockData::ProcessRGBA( const uint32_t* src, uint32_t blocks, size_t offset, size_t width )
+{
+ auto dst = ((uint64_t*)( m_data + m_dataOffset )) + offset * 2;
+
+ switch( m_type )
+ {
+ case Etc2_RGBA:
+ CompressEtc2Rgba( src, dst, blocks, width );
+ break;
+ case Dxt5:
+ CompressDxt5( src, dst, blocks, width );
+ break;
+ default:
+ assert( false );
+ break;
+ }
+}
+
+namespace
+{
+
+static etcpak_force_inline int32_t expand6(uint32_t value)
+{
+ return (value << 2) | (value >> 4);
+}
+
+static etcpak_force_inline int32_t expand7(uint32_t value)
+{
+ return (value << 1) | (value >> 6);
+}
+
+static etcpak_force_inline void DecodeT( uint64_t block, uint32_t* dst, uint32_t w )
+{
+ const auto r0 = ( block >> 24 ) & 0x1B;
+ const auto rh0 = ( r0 >> 3 ) & 0x3;
+ const auto rl0 = r0 & 0x3;
+ const auto g0 = ( block >> 20 ) & 0xF;
+ const auto b0 = ( block >> 16 ) & 0xF;
+
+ const auto r1 = ( block >> 12 ) & 0xF;
+ const auto g1 = ( block >> 8 ) & 0xF;
+ const auto b1 = ( block >> 4 ) & 0xF;
+
+ const auto cr0 = ( ( rh0 << 6 ) | ( rl0 << 4 ) | ( rh0 << 2 ) | rl0);
+ const auto cg0 = ( g0 << 4 ) | g0;
+ const auto cb0 = ( b0 << 4 ) | b0;
+
+ const auto cr1 = ( r1 << 4 ) | r1;
+ const auto cg1 = ( g1 << 4 ) | g1;
+ const auto cb1 = ( b1 << 4 ) | b1;
+
+ const auto codeword_hi = ( block >> 2 ) & 0x3;
+ const auto codeword_lo = block & 0x1;
+ const auto codeword = ( codeword_hi << 1 ) | codeword_lo;
+
+ const auto c2r = clampu8( cr1 + table59T58H[codeword] );
+ const auto c2g = clampu8( cg1 + table59T58H[codeword] );
+ const auto c2b = clampu8( cb1 + table59T58H[codeword] );
+
+ const auto c3r = clampu8( cr1 - table59T58H[codeword] );
+ const auto c3g = clampu8( cg1 - table59T58H[codeword] );
+ const auto c3b = clampu8( cb1 - table59T58H[codeword] );
+
+ const uint32_t col_tab[4] = {
+ uint32_t(cr0 | ( cg0 << 8 ) | ( cb0 << 16 ) | 0xFF000000),
+ uint32_t(c2r | ( c2g << 8 ) | ( c2b << 16 ) | 0xFF000000),
+ uint32_t(cr1 | ( cg1 << 8 ) | ( cb1 << 16 ) | 0xFF000000),
+ uint32_t(c3r | ( c3g << 8 ) | ( c3b << 16 ) | 0xFF000000)
+ };
+
+ const uint32_t indexes = ( block >> 32 ) & 0xFFFFFFFF;
+ for( uint8_t j = 0; j < 4; j++ )
+ {
+ for( uint8_t i = 0; i < 4; i++ )
+ {
+ //2bit indices distributed on two lane 16bit numbers
+ const uint8_t index = ( ( ( indexes >> ( j + i * 4 + 16 ) ) & 0x1 ) << 1) | ( ( indexes >> ( j + i * 4 ) ) & 0x1);
+ dst[j * w + i] = col_tab[index];
+ }
+ }
+}
+
+static etcpak_force_inline void DecodeTAlpha( uint64_t block, uint64_t alpha, uint32_t* dst, uint32_t w )
+{
+ const auto r0 = ( block >> 24 ) & 0x1B;
+ const auto rh0 = ( r0 >> 3 ) & 0x3;
+ const auto rl0 = r0 & 0x3;
+ const auto g0 = ( block >> 20 ) & 0xF;
+ const auto b0 = ( block >> 16 ) & 0xF;
+
+ const auto r1 = ( block >> 12 ) & 0xF;
+ const auto g1 = ( block >> 8 ) & 0xF;
+ const auto b1 = ( block >> 4 ) & 0xF;
+
+ const auto cr0 = ( ( rh0 << 6 ) | ( rl0 << 4 ) | ( rh0 << 2 ) | rl0);
+ const auto cg0 = ( g0 << 4 ) | g0;
+ const auto cb0 = ( b0 << 4 ) | b0;
+
+ const auto cr1 = ( r1 << 4 ) | r1;
+ const auto cg1 = ( g1 << 4 ) | g1;
+ const auto cb1 = ( b1 << 4 ) | b1;
+
+ const auto codeword_hi = ( block >> 2 ) & 0x3;
+ const auto codeword_lo = block & 0x1;
+ const auto codeword = (codeword_hi << 1) | codeword_lo;
+
+ const int32_t base = alpha >> 56;
+ const int32_t mul = ( alpha >> 52 ) & 0xF;
+ const auto tbl = g_alpha[( alpha >> 48 ) & 0xF];
+
+ const auto c2r = clampu8( cr1 + table59T58H[codeword] );
+ const auto c2g = clampu8( cg1 + table59T58H[codeword] );
+ const auto c2b = clampu8( cb1 + table59T58H[codeword] );
+
+ const auto c3r = clampu8( cr1 - table59T58H[codeword] );
+ const auto c3g = clampu8( cg1 - table59T58H[codeword] );
+ const auto c3b = clampu8( cb1 - table59T58H[codeword] );
+
+ const uint32_t col_tab[4] = {
+ uint32_t(cr0 | ( cg0 << 8 ) | ( cb0 << 16 )),
+ uint32_t(c2r | ( c2g << 8 ) | ( c2b << 16 )),
+ uint32_t(cr1 | ( cg1 << 8 ) | ( cb1 << 16 )),
+ uint32_t(c3r | ( c3g << 8 ) | ( c3b << 16 ))
+ };
+
+ const uint32_t indexes = ( block >> 32 ) & 0xFFFFFFFF;
+ for( uint8_t j = 0; j < 4; j++ )
+ {
+ for( uint8_t i = 0; i < 4; i++ )
+ {
+ //2bit indices distributed on two lane 16bit numbers
+ const uint8_t index = ( ( ( indexes >> ( j + i * 4 + 16 ) ) & 0x1 ) << 1 ) | ( ( indexes >> ( j + i * 4 ) ) & 0x1 );
+ const auto amod = tbl[( alpha >> ( 45 - j * 3 - i * 12 ) ) & 0x7];
+ const uint32_t a = clampu8( base + amod * mul );
+ dst[j * w + i] = col_tab[index] | ( a << 24 );
+ }
+ }
+}
+
+static etcpak_force_inline void DecodeH( uint64_t block, uint32_t* dst, uint32_t w )
+{
+ const uint32_t indexes = ( block >> 32 ) & 0xFFFFFFFF;
+
+ const auto r0444 = ( block >> 27 ) & 0xF;
+ const auto g0444 = ( ( block >> 20 ) & 0x1 ) | ( ( ( block >> 24 ) & 0x7 ) << 1 );
+ const auto b0444 = ( ( block >> 15 ) & 0x7 ) | ( ( ( block >> 19 ) & 0x1 ) << 3 );
+
+ const auto r1444 = ( block >> 11 ) & 0xF;
+ const auto g1444 = ( block >> 7 ) & 0xF;
+ const auto b1444 = ( block >> 3 ) & 0xF;
+
+ const auto r0 = ( r0444 << 4 ) | r0444;
+ const auto g0 = ( g0444 << 4 ) | g0444;
+ const auto b0 = ( b0444 << 4 ) | b0444;
+
+ const auto r1 = ( r1444 << 4 ) | r1444;
+ const auto g1 = ( g1444 << 4 ) | g1444;
+ const auto b1 = ( b1444 << 4 ) | b1444;
+
+ const auto codeword_hi = ( ( block & 0x1 ) << 1 ) | ( ( block & 0x4 ) );
+ const auto c0 = ( r0444 << 8 ) | ( g0444 << 4 ) | ( b0444 << 0 );
+ const auto c1 = ( block >> 3 ) & ( ( 1 << 12 ) - 1 );
+ const auto codeword_lo = ( c0 >= c1 ) ? 1 : 0;
+ const auto codeword = codeword_hi | codeword_lo;
+
+ const uint32_t col_tab[] = {
+ uint32_t(clampu8( r0 + table59T58H[codeword] ) | ( clampu8( g0 + table59T58H[codeword] ) << 8 ) | ( clampu8( b0 + table59T58H[codeword] ) << 16 )),
+ uint32_t(clampu8( r0 - table59T58H[codeword] ) | ( clampu8( g0 - table59T58H[codeword] ) << 8 ) | ( clampu8( b0 - table59T58H[codeword] ) << 16 )),
+ uint32_t(clampu8( r1 + table59T58H[codeword] ) | ( clampu8( g1 + table59T58H[codeword] ) << 8 ) | ( clampu8( b1 + table59T58H[codeword] ) << 16 )),
+ uint32_t(clampu8( r1 - table59T58H[codeword] ) | ( clampu8( g1 - table59T58H[codeword] ) << 8 ) | ( clampu8( b1 - table59T58H[codeword] ) << 16 ))
+ };
+
+ for( uint8_t j = 0; j < 4; j++ )
+ {
+ for( uint8_t i = 0; i < 4; i++ )
+ {
+ const uint8_t index = ( ( ( indexes >> ( j + i * 4 + 16 ) ) & 0x1 ) << 1 ) | ( ( indexes >> ( j + i * 4 ) ) & 0x1 );
+ dst[j * w + i] = col_tab[index] | 0xFF000000;
+ }
+ }
+}
+
+static etcpak_force_inline void DecodeHAlpha( uint64_t block, uint64_t alpha, uint32_t* dst, uint32_t w )
+{
+ const uint32_t indexes = ( block >> 32 ) & 0xFFFFFFFF;
+
+ const auto r0444 = ( block >> 27 ) & 0xF;
+ const auto g0444 = ( ( block >> 20 ) & 0x1 ) | ( ( ( block >> 24 ) & 0x7 ) << 1 );
+ const auto b0444 = ( ( block >> 15 ) & 0x7 ) | ( ( ( block >> 19 ) & 0x1 ) << 3 );
+
+ const auto r1444 = ( block >> 11 ) & 0xF;
+ const auto g1444 = ( block >> 7 ) & 0xF;
+ const auto b1444 = ( block >> 3 ) & 0xF;
+
+ const auto r0 = ( r0444 << 4 ) | r0444;
+ const auto g0 = ( g0444 << 4 ) | g0444;
+ const auto b0 = ( b0444 << 4 ) | b0444;
+
+ const auto r1 = ( r1444 << 4 ) | r1444;
+ const auto g1 = ( g1444 << 4 ) | g1444;
+ const auto b1 = ( b1444 << 4 ) | b1444;
+
+ const auto codeword_hi = ( ( block & 0x1 ) << 1 ) | ( ( block & 0x4 ) );
+ const auto c0 = ( r0444 << 8 ) | ( g0444 << 4 ) | ( b0444 << 0 );
+ const auto c1 = ( block >> 3 ) & ( ( 1 << 12 ) - 1 );
+ const auto codeword_lo = ( c0 >= c1 ) ? 1 : 0;
+ const auto codeword = codeword_hi | codeword_lo;
+
+ const int32_t base = alpha >> 56;
+ const int32_t mul = ( alpha >> 52 ) & 0xF;
+ const auto tbl = g_alpha[(alpha >> 48) & 0xF];
+
+ const uint32_t col_tab[] = {
+ uint32_t(clampu8( r0 + table59T58H[codeword] ) | ( clampu8( g0 + table59T58H[codeword] ) << 8 ) | ( clampu8( b0 + table59T58H[codeword] ) << 16 )),
+ uint32_t(clampu8( r0 - table59T58H[codeword] ) | ( clampu8( g0 - table59T58H[codeword] ) << 8 ) | ( clampu8( b0 - table59T58H[codeword] ) << 16 )),
+ uint32_t(clampu8( r1 + table59T58H[codeword] ) | ( clampu8( g1 + table59T58H[codeword] ) << 8 ) | ( clampu8( b1 + table59T58H[codeword] ) << 16 )),
+ uint32_t(clampu8( r1 - table59T58H[codeword] ) | ( clampu8( g1 - table59T58H[codeword] ) << 8 ) | ( clampu8( b1 - table59T58H[codeword] ) << 16 ))
+ };
+
+ for( uint8_t j = 0; j < 4; j++ )
+ {
+ for( uint8_t i = 0; i < 4; i++ )
+ {
+ const uint8_t index = ( ( ( indexes >> ( j + i * 4 + 16 ) ) & 0x1 ) << 1 ) | ( ( indexes >> ( j + i * 4 ) ) & 0x1 );
+ const auto amod = tbl[( alpha >> ( 45 - j * 3 - i * 12) ) & 0x7];
+ const uint32_t a = clampu8( base + amod * mul );
+ dst[j * w + i] = col_tab[index] | ( a << 24 );
+ }
+ }
+}
+
+static etcpak_force_inline void DecodePlanar( uint64_t block, uint32_t* dst, uint32_t w )
+{
+ const auto bv = expand6((block >> ( 0 + 32)) & 0x3F);
+ const auto gv = expand7((block >> ( 6 + 32)) & 0x7F);
+ const auto rv = expand6((block >> (13 + 32)) & 0x3F);
+
+ const auto bh = expand6((block >> (19 + 32)) & 0x3F);
+ const auto gh = expand7((block >> (25 + 32)) & 0x7F);
+
+ const auto rh0 = (block >> (32 - 32)) & 0x01;
+ const auto rh1 = ((block >> (34 - 32)) & 0x1F) << 1;
+ const auto rh = expand6(rh0 | rh1);
+
+ const auto bo0 = (block >> (39 - 32)) & 0x07;
+ const auto bo1 = ((block >> (43 - 32)) & 0x3) << 3;
+ const auto bo2 = ((block >> (48 - 32)) & 0x1) << 5;
+ const auto bo = expand6(bo0 | bo1 | bo2);
+ const auto go0 = (block >> (49 - 32)) & 0x3F;
+ const auto go1 = ((block >> (56 - 32)) & 0x01) << 6;
+ const auto go = expand7(go0 | go1);
+ const auto ro = expand6((block >> (57 - 32)) & 0x3F);
+
+#ifdef __ARM_NEON
+ uint64_t init = uint64_t(uint16_t(rh-ro)) | ( uint64_t(uint16_t(gh-go)) << 16 ) | ( uint64_t(uint16_t(bh-bo)) << 32 );
+ int16x8_t chco = vreinterpretq_s16_u64( vdupq_n_u64( init ) );
+ init = uint64_t(uint16_t( (rv-ro) - 4 * (rh-ro) )) | ( uint64_t(uint16_t( (gv-go) - 4 * (gh-go) )) << 16 ) | ( uint64_t(uint16_t( (bv-bo) - 4 * (bh-bo) )) << 32 );
+ int16x8_t cvco = vreinterpretq_s16_u64( vdupq_n_u64( init ) );
+ init = uint64_t(4*ro+2) | ( uint64_t(4*go+2) << 16 ) | ( uint64_t(4*bo+2) << 32 ) | ( uint64_t(0xFFF) << 48 );
+ int16x8_t col = vreinterpretq_s16_u64( vdupq_n_u64( init ) );
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ uint8x8_t c = vqshrun_n_s16( col, 2 );
+ vst1_lane_u32( dst+j*w+i, vreinterpret_u32_u8( c ), 0 );
+ col = vaddq_s16( col, chco );
+ }
+ col = vaddq_s16( col, cvco );
+ }
+#elif defined __AVX2__
+ const auto R0 = 4*ro+2;
+ const auto G0 = 4*go+2;
+ const auto B0 = 4*bo+2;
+ const auto RHO = rh-ro;
+ const auto GHO = gh-go;
+ const auto BHO = bh-bo;
+
+ __m256i cvco = _mm256_setr_epi16( rv - ro, gv - go, bv - bo, 0, rv - ro, gv - go, bv - bo, 0, rv - ro, gv - go, bv - bo, 0, rv - ro, gv - go, bv - bo, 0 );
+ __m256i col = _mm256_setr_epi16( R0, G0, B0, 0xFFF, R0+RHO, G0+GHO, B0+BHO, 0xFFF, R0+2*RHO, G0+2*GHO, B0+2*BHO, 0xFFF, R0+3*RHO, G0+3*GHO, B0+3*BHO, 0xFFF );
+
+ for( int j=0; j<4; j++ )
+ {
+ __m256i c = _mm256_srai_epi16( col, 2 );
+ __m128i s = _mm_packus_epi16( _mm256_castsi256_si128( c ), _mm256_extracti128_si256( c, 1 ) );
+ _mm_storeu_si128( (__m128i*)(dst+j*w), s );
+ col = _mm256_add_epi16( col, cvco );
+ }
+#elif defined __SSE4_1__
+ __m128i chco = _mm_setr_epi16( rh - ro, gh - go, bh - bo, 0, 0, 0, 0, 0 );
+ __m128i cvco = _mm_setr_epi16( (rv - ro) - 4 * (rh - ro), (gv - go) - 4 * (gh - go), (bv - bo) - 4 * (bh - bo), 0, 0, 0, 0, 0 );
+ __m128i col = _mm_setr_epi16( 4*ro+2, 4*go+2, 4*bo+2, 0xFFF, 0, 0, 0, 0 );
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ __m128i c = _mm_srai_epi16( col, 2 );
+ __m128i s = _mm_packus_epi16( c, c );
+ dst[j*w+i] = _mm_cvtsi128_si32( s );
+ col = _mm_add_epi16( col, chco );
+ }
+ col = _mm_add_epi16( col, cvco );
+ }
+#else
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ const uint32_t r = (i * (rh - ro) + j * (rv - ro) + 4 * ro + 2) >> 2;
+ const uint32_t g = (i * (gh - go) + j * (gv - go) + 4 * go + 2) >> 2;
+ const uint32_t b = (i * (bh - bo) + j * (bv - bo) + 4 * bo + 2) >> 2;
+ if( ( ( r | g | b ) & ~0xFF ) == 0 )
+ {
+ dst[j*w+i] = r | ( g << 8 ) | ( b << 16 ) | 0xFF000000;
+ }
+ else
+ {
+ const auto rc = clampu8( r );
+ const auto gc = clampu8( g );
+ const auto bc = clampu8( b );
+ dst[j*w+i] = rc | ( gc << 8 ) | ( bc << 16 ) | 0xFF000000;
+ }
+ }
+ }
+#endif
+}
+
+static etcpak_force_inline void DecodePlanarAlpha( uint64_t block, uint64_t alpha, uint32_t* dst, uint32_t w )
+{
+ const auto bv = expand6((block >> ( 0 + 32)) & 0x3F);
+ const auto gv = expand7((block >> ( 6 + 32)) & 0x7F);
+ const auto rv = expand6((block >> (13 + 32)) & 0x3F);
+
+ const auto bh = expand6((block >> (19 + 32)) & 0x3F);
+ const auto gh = expand7((block >> (25 + 32)) & 0x7F);
+
+ const auto rh0 = (block >> (32 - 32)) & 0x01;
+ const auto rh1 = ((block >> (34 - 32)) & 0x1F) << 1;
+ const auto rh = expand6(rh0 | rh1);
+
+ const auto bo0 = (block >> (39 - 32)) & 0x07;
+ const auto bo1 = ((block >> (43 - 32)) & 0x3) << 3;
+ const auto bo2 = ((block >> (48 - 32)) & 0x1) << 5;
+ const auto bo = expand6(bo0 | bo1 | bo2);
+ const auto go0 = (block >> (49 - 32)) & 0x3F;
+ const auto go1 = ((block >> (56 - 32)) & 0x01) << 6;
+ const auto go = expand7(go0 | go1);
+ const auto ro = expand6((block >> (57 - 32)) & 0x3F);
+
+ const int32_t base = alpha >> 56;
+ const int32_t mul = ( alpha >> 52 ) & 0xF;
+ const auto tbl = g_alpha[( alpha >> 48 ) & 0xF];
+
+#ifdef __ARM_NEON
+ uint64_t init = uint64_t(uint16_t(rh-ro)) | ( uint64_t(uint16_t(gh-go)) << 16 ) | ( uint64_t(uint16_t(bh-bo)) << 32 );
+ int16x8_t chco = vreinterpretq_s16_u64( vdupq_n_u64( init ) );
+ init = uint64_t(uint16_t( (rv-ro) - 4 * (rh-ro) )) | ( uint64_t(uint16_t( (gv-go) - 4 * (gh-go) )) << 16 ) | ( uint64_t(uint16_t( (bv-bo) - 4 * (bh-bo) )) << 32 );
+ int16x8_t cvco = vreinterpretq_s16_u64( vdupq_n_u64( init ) );
+ init = uint64_t(4*ro+2) | ( uint64_t(4*go+2) << 16 ) | ( uint64_t(4*bo+2) << 32 );
+ int16x8_t col = vreinterpretq_s16_u64( vdupq_n_u64( init ) );
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ const auto amod = tbl[(alpha >> ( 45 - j*3 - i*12 )) & 0x7];
+ const uint32_t a = clampu8( base + amod * mul );
+ uint8x8_t c = vqshrun_n_s16( col, 2 );
+ dst[j*w+i] = vget_lane_u32( vreinterpret_u32_u8( c ), 0 ) | ( a << 24 );
+ col = vaddq_s16( col, chco );
+ }
+ col = vaddq_s16( col, cvco );
+ }
+#elif defined __SSE4_1__
+ __m128i chco = _mm_setr_epi16( rh - ro, gh - go, bh - bo, 0, 0, 0, 0, 0 );
+ __m128i cvco = _mm_setr_epi16( (rv - ro) - 4 * (rh - ro), (gv - go) - 4 * (gh - go), (bv - bo) - 4 * (bh - bo), 0, 0, 0, 0, 0 );
+ __m128i col = _mm_setr_epi16( 4*ro+2, 4*go+2, 4*bo+2, 0, 0, 0, 0, 0 );
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ const auto amod = tbl[(alpha >> ( 45 - j*3 - i*12 )) & 0x7];
+ const uint32_t a = clampu8( base + amod * mul );
+ __m128i c = _mm_srai_epi16( col, 2 );
+ __m128i s = _mm_packus_epi16( c, c );
+ dst[j*w+i] = _mm_cvtsi128_si32( s ) | ( a << 24 );
+ col = _mm_add_epi16( col, chco );
+ }
+ col = _mm_add_epi16( col, cvco );
+ }
+#else
+ for (auto j = 0; j < 4; j++)
+ {
+ for (auto i = 0; i < 4; i++)
+ {
+ const uint32_t r = (i * (rh - ro) + j * (rv - ro) + 4 * ro + 2) >> 2;
+ const uint32_t g = (i * (gh - go) + j * (gv - go) + 4 * go + 2) >> 2;
+ const uint32_t b = (i * (bh - bo) + j * (bv - bo) + 4 * bo + 2) >> 2;
+ const auto amod = tbl[(alpha >> ( 45 - j*3 - i*12 )) & 0x7];
+ const uint32_t a = clampu8( base + amod * mul );
+ if( ( ( r | g | b ) & ~0xFF ) == 0 )
+ {
+ dst[j*w+i] = r | ( g << 8 ) | ( b << 16 ) | ( a << 24 );
+ }
+ else
+ {
+ const auto rc = clampu8( r );
+ const auto gc = clampu8( g );
+ const auto bc = clampu8( b );
+ dst[j*w+i] = rc | ( gc << 8 ) | ( bc << 16 ) | ( a << 24 );
+ }
+ }
+ }
+#endif
+}
+
+}
+
+BitmapPtr BlockData::Decode()
+{
+ switch( m_type )
+ {
+ case Etc1:
+ case Etc2_RGB:
+ return DecodeRGB();
+ case Etc2_RGBA:
+ return DecodeRGBA();
+ case Dxt1:
+ return DecodeDxt1();
+ case Dxt5:
+ return DecodeDxt5();
+ default:
+ assert( false );
+ return nullptr;
+ }
+}
+
+static etcpak_force_inline uint64_t ConvertByteOrder( uint64_t d )
+{
+ uint32_t word[2];
+ memcpy( word, &d, 8 );
+ word[0] = _bswap( word[0] );
+ word[1] = _bswap( word[1] );
+ memcpy( &d, word, 8 );
+ return d;
+}
+
+static etcpak_force_inline void DecodeRGBPart( uint64_t d, uint32_t* dst, uint32_t w )
+{
+ d = ConvertByteOrder( d );
+
+ uint32_t br[2], bg[2], bb[2];
+
+ if( d & 0x2 )
+ {
+ int32_t dr, dg, db;
+
+ uint32_t r0 = ( d & 0xF8000000 ) >> 27;
+ uint32_t g0 = ( d & 0x00F80000 ) >> 19;
+ uint32_t b0 = ( d & 0x0000F800 ) >> 11;
+
+ dr = ( int32_t(d) << 5 ) >> 29;
+ dg = ( int32_t(d) << 13 ) >> 29;
+ db = ( int32_t(d) << 21 ) >> 29;
+
+ int32_t r1 = int32_t(r0) + dr;
+ int32_t g1 = int32_t(g0) + dg;
+ int32_t b1 = int32_t(b0) + db;
+
+ // T mode
+ if ( (r1 < 0) || (r1 > 31) )
+ {
+ DecodeT( d, dst, w );
+ return;
+ }
+
+ // H mode
+ if ((g1 < 0) || (g1 > 31))
+ {
+ DecodeH( d, dst, w );
+ return;
+ }
+
+ // P mode
+ if( (b1 < 0) || (b1 > 31) )
+ {
+ DecodePlanar( d, dst, w );
+ return;
+ }
+
+ br[0] = ( r0 << 3 ) | ( r0 >> 2 );
+ br[1] = ( r1 << 3 ) | ( r1 >> 2 );
+ bg[0] = ( g0 << 3 ) | ( g0 >> 2 );
+ bg[1] = ( g1 << 3 ) | ( g1 >> 2 );
+ bb[0] = ( b0 << 3 ) | ( b0 >> 2 );
+ bb[1] = ( b1 << 3 ) | ( b1 >> 2 );
+ }
+ else
+ {
+ br[0] = ( ( d & 0xF0000000 ) >> 24 ) | ( ( d & 0xF0000000 ) >> 28 );
+ br[1] = ( ( d & 0x0F000000 ) >> 20 ) | ( ( d & 0x0F000000 ) >> 24 );
+ bg[0] = ( ( d & 0x00F00000 ) >> 16 ) | ( ( d & 0x00F00000 ) >> 20 );
+ bg[1] = ( ( d & 0x000F0000 ) >> 12 ) | ( ( d & 0x000F0000 ) >> 16 );
+ bb[0] = ( ( d & 0x0000F000 ) >> 8 ) | ( ( d & 0x0000F000 ) >> 12 );
+ bb[1] = ( ( d & 0x00000F00 ) >> 4 ) | ( ( d & 0x00000F00 ) >> 8 );
+ }
+
+ unsigned int tcw[2];
+ tcw[0] = ( d & 0xE0 ) >> 5;
+ tcw[1] = ( d & 0x1C ) >> 2;
+
+ uint32_t b1 = ( d >> 32 ) & 0xFFFF;
+ uint32_t b2 = ( d >> 48 );
+
+ b1 = ( b1 | ( b1 << 8 ) ) & 0x00FF00FF;
+ b1 = ( b1 | ( b1 << 4 ) ) & 0x0F0F0F0F;
+ b1 = ( b1 | ( b1 << 2 ) ) & 0x33333333;
+ b1 = ( b1 | ( b1 << 1 ) ) & 0x55555555;
+
+ b2 = ( b2 | ( b2 << 8 ) ) & 0x00FF00FF;
+ b2 = ( b2 | ( b2 << 4 ) ) & 0x0F0F0F0F;
+ b2 = ( b2 | ( b2 << 2 ) ) & 0x33333333;
+ b2 = ( b2 | ( b2 << 1 ) ) & 0x55555555;
+
+ uint32_t idx = b1 | ( b2 << 1 );
+
+ if( d & 0x1 )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ for( int j=0; j<4; j++ )
+ {
+ const auto mod = g_table[tcw[j/2]][idx & 0x3];
+ const auto r = br[j/2] + mod;
+ const auto g = bg[j/2] + mod;
+ const auto b = bb[j/2] + mod;
+ if( ( ( r | g | b ) & ~0xFF ) == 0 )
+ {
+ dst[j*w+i] = r | ( g << 8 ) | ( b << 16 ) | 0xFF000000;
+ }
+ else
+ {
+ const auto rc = clampu8( r );
+ const auto gc = clampu8( g );
+ const auto bc = clampu8( b );
+ dst[j*w+i] = rc | ( gc << 8 ) | ( bc << 16 ) | 0xFF000000;
+ }
+ idx >>= 2;
+ }
+ }
+ }
+ else
+ {
+ for( int i=0; i<4; i++ )
+ {
+ const auto tbl = g_table[tcw[i/2]];
+ const auto cr = br[i/2];
+ const auto cg = bg[i/2];
+ const auto cb = bb[i/2];
+
+ for( int j=0; j<4; j++ )
+ {
+ const auto mod = tbl[idx & 0x3];
+ const auto r = cr + mod;
+ const auto g = cg + mod;
+ const auto b = cb + mod;
+ if( ( ( r | g | b ) & ~0xFF ) == 0 )
+ {
+ dst[j*w+i] = r | ( g << 8 ) | ( b << 16 ) | 0xFF000000;
+ }
+ else
+ {
+ const auto rc = clampu8( r );
+ const auto gc = clampu8( g );
+ const auto bc = clampu8( b );
+ dst[j*w+i] = rc | ( gc << 8 ) | ( bc << 16 ) | 0xFF000000;
+ }
+ idx >>= 2;
+ }
+ }
+ }
+}
+
+static etcpak_force_inline void DecodeRGBAPart( uint64_t d, uint64_t alpha, uint32_t* dst, uint32_t w )
+{
+ d = ConvertByteOrder( d );
+ alpha = _bswap64( alpha );
+
+ uint32_t br[2], bg[2], bb[2];
+
+ if( d & 0x2 )
+ {
+ int32_t dr, dg, db;
+
+ uint32_t r0 = ( d & 0xF8000000 ) >> 27;
+ uint32_t g0 = ( d & 0x00F80000 ) >> 19;
+ uint32_t b0 = ( d & 0x0000F800 ) >> 11;
+
+ dr = ( int32_t(d) << 5 ) >> 29;
+ dg = ( int32_t(d) << 13 ) >> 29;
+ db = ( int32_t(d) << 21 ) >> 29;
+
+ int32_t r1 = int32_t(r0) + dr;
+ int32_t g1 = int32_t(g0) + dg;
+ int32_t b1 = int32_t(b0) + db;
+
+ // T mode
+ if ( (r1 < 0) || (r1 > 31) )
+ {
+ DecodeTAlpha( d, alpha, dst, w );
+ return;
+ }
+
+ // H mode
+ if ( (g1 < 0) || (g1 > 31) )
+ {
+ DecodeHAlpha( d, alpha, dst, w );
+ return;
+ }
+
+ // P mode
+ if ( (b1 < 0) || (b1 > 31) )
+ {
+ DecodePlanarAlpha( d, alpha, dst, w );
+ return;
+ }
+
+ br[0] = ( r0 << 3 ) | ( r0 >> 2 );
+ br[1] = ( r1 << 3 ) | ( r1 >> 2 );
+ bg[0] = ( g0 << 3 ) | ( g0 >> 2 );
+ bg[1] = ( g1 << 3 ) | ( g1 >> 2 );
+ bb[0] = ( b0 << 3 ) | ( b0 >> 2 );
+ bb[1] = ( b1 << 3 ) | ( b1 >> 2 );
+ }
+ else
+ {
+ br[0] = ( ( d & 0xF0000000 ) >> 24 ) | ( ( d & 0xF0000000 ) >> 28 );
+ br[1] = ( ( d & 0x0F000000 ) >> 20 ) | ( ( d & 0x0F000000 ) >> 24 );
+ bg[0] = ( ( d & 0x00F00000 ) >> 16 ) | ( ( d & 0x00F00000 ) >> 20 );
+ bg[1] = ( ( d & 0x000F0000 ) >> 12 ) | ( ( d & 0x000F0000 ) >> 16 );
+ bb[0] = ( ( d & 0x0000F000 ) >> 8 ) | ( ( d & 0x0000F000 ) >> 12 );
+ bb[1] = ( ( d & 0x00000F00 ) >> 4 ) | ( ( d & 0x00000F00 ) >> 8 );
+ }
+
+ unsigned int tcw[2];
+ tcw[0] = ( d & 0xE0 ) >> 5;
+ tcw[1] = ( d & 0x1C ) >> 2;
+
+ uint32_t b1 = ( d >> 32 ) & 0xFFFF;
+ uint32_t b2 = ( d >> 48 );
+
+ b1 = ( b1 | ( b1 << 8 ) ) & 0x00FF00FF;
+ b1 = ( b1 | ( b1 << 4 ) ) & 0x0F0F0F0F;
+ b1 = ( b1 | ( b1 << 2 ) ) & 0x33333333;
+ b1 = ( b1 | ( b1 << 1 ) ) & 0x55555555;
+
+ b2 = ( b2 | ( b2 << 8 ) ) & 0x00FF00FF;
+ b2 = ( b2 | ( b2 << 4 ) ) & 0x0F0F0F0F;
+ b2 = ( b2 | ( b2 << 2 ) ) & 0x33333333;
+ b2 = ( b2 | ( b2 << 1 ) ) & 0x55555555;
+
+ uint32_t idx = b1 | ( b2 << 1 );
+
+ const int32_t base = alpha >> 56;
+ const int32_t mul = ( alpha >> 52 ) & 0xF;
+ const auto atbl = g_alpha[( alpha >> 48 ) & 0xF];
+
+ if( d & 0x1 )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ for( int j=0; j<4; j++ )
+ {
+ const auto mod = g_table[tcw[j/2]][idx & 0x3];
+ const auto r = br[j/2] + mod;
+ const auto g = bg[j/2] + mod;
+ const auto b = bb[j/2] + mod;
+ const auto amod = atbl[(alpha >> ( 45 - j*3 - i*12 )) & 0x7];
+ const uint32_t a = clampu8( base + amod * mul );
+ if( ( ( r | g | b ) & ~0xFF ) == 0 )
+ {
+ dst[j*w+i] = r | ( g << 8 ) | ( b << 16 ) | ( a << 24 );
+ }
+ else
+ {
+ const auto rc = clampu8( r );
+ const auto gc = clampu8( g );
+ const auto bc = clampu8( b );
+ dst[j*w+i] = rc | ( gc << 8 ) | ( bc << 16 ) | ( a << 24 );
+ }
+ idx >>= 2;
+ }
+ }
+ }
+ else
+ {
+ for( int i=0; i<4; i++ )
+ {
+ const auto tbl = g_table[tcw[i/2]];
+ const auto cr = br[i/2];
+ const auto cg = bg[i/2];
+ const auto cb = bb[i/2];
+
+ for( int j=0; j<4; j++ )
+ {
+ const auto mod = tbl[idx & 0x3];
+ const auto r = cr + mod;
+ const auto g = cg + mod;
+ const auto b = cb + mod;
+ const auto amod = atbl[(alpha >> ( 45 - j*3 - i*12 )) & 0x7];
+ const uint32_t a = clampu8( base + amod * mul );
+ if( ( ( r | g | b ) & ~0xFF ) == 0 )
+ {
+ dst[j*w+i] = r | ( g << 8 ) | ( b << 16 ) | ( a << 24 );
+ }
+ else
+ {
+ const auto rc = clampu8( r );
+ const auto gc = clampu8( g );
+ const auto bc = clampu8( b );
+ dst[j*w+i] = rc | ( gc << 8 ) | ( bc << 16 ) | ( a << 24 );
+ }
+ idx >>= 2;
+ }
+ }
+ }
+}
+
+BitmapPtr BlockData::DecodeRGB()
+{
+ auto ret = std::make_shared<Bitmap>( m_size );
+
+ const uint64_t* src = (const uint64_t*)( m_data + m_dataOffset );
+ uint32_t* dst = ret->Data();
+
+ for( int y=0; y<m_size.y/4; y++ )
+ {
+ for( int x=0; x<m_size.x/4; x++ )
+ {
+ uint64_t d = *src++;
+ DecodeRGBPart( d, dst, m_size.x );
+ dst += 4;
+ }
+ dst += m_size.x*3;
+ }
+
+ return ret;
+}
+
+BitmapPtr BlockData::DecodeRGBA()
+{
+ auto ret = std::make_shared<Bitmap>( m_size );
+
+ const uint64_t* src = (const uint64_t*)( m_data + m_dataOffset );
+ uint32_t* dst = ret->Data();
+
+ for( int y=0; y<m_size.y/4; y++ )
+ {
+ for( int x=0; x<m_size.x/4; x++ )
+ {
+ uint64_t a = *src++;
+ uint64_t d = *src++;
+ DecodeRGBAPart( d, a, dst, m_size.x );
+ dst += 4;
+ }
+ dst += m_size.x*3;
+ }
+
+ return ret;
+}
+
+static etcpak_force_inline void DecodeDxt1Part( uint64_t d, uint32_t* dst, uint32_t w )
+{
+ uint8_t* in = (uint8_t*)&d;
+ uint16_t c0, c1;
+ uint32_t idx;
+ memcpy( &c0, in, 2 );
+ memcpy( &c1, in+2, 2 );
+ memcpy( &idx, in+4, 4 );
+
+ uint8_t r0 = ( ( c0 & 0xF800 ) >> 8 ) | ( ( c0 & 0xF800 ) >> 13 );
+ uint8_t g0 = ( ( c0 & 0x07E0 ) >> 3 ) | ( ( c0 & 0x07E0 ) >> 9 );
+ uint8_t b0 = ( ( c0 & 0x001F ) << 3 ) | ( ( c0 & 0x001F ) >> 2 );
+
+ uint8_t r1 = ( ( c1 & 0xF800 ) >> 8 ) | ( ( c1 & 0xF800 ) >> 13 );
+ uint8_t g1 = ( ( c1 & 0x07E0 ) >> 3 ) | ( ( c1 & 0x07E0 ) >> 9 );
+ uint8_t b1 = ( ( c1 & 0x001F ) << 3 ) | ( ( c1 & 0x001F ) >> 2 );
+
+ uint32_t dict[4];
+
+ dict[0] = 0xFF000000 | ( b0 << 16 ) | ( g0 << 8 ) | r0;
+ dict[1] = 0xFF000000 | ( b1 << 16 ) | ( g1 << 8 ) | r1;
+
+ uint32_t r, g, b;
+ if( c0 > c1 )
+ {
+ r = (2*r0+r1)/3;
+ g = (2*g0+g1)/3;
+ b = (2*b0+b1)/3;
+ dict[2] = 0xFF000000 | ( b << 16 ) | ( g << 8 ) | r;
+ r = (2*r1+r0)/3;
+ g = (2*g1+g0)/3;
+ b = (2*b1+b0)/3;
+ dict[3] = 0xFF000000 | ( b << 16 ) | ( g << 8 ) | r;
+ }
+ else
+ {
+ r = (int(r0)+r1)/2;
+ g = (int(g0)+g1)/2;
+ b = (int(b0)+b1)/2;
+ dict[2] = 0xFF000000 | ( b << 16 ) | ( g << 8 ) | r;
+ dict[3] = 0xFF000000;
+ }
+
+ memcpy( dst+0, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+1, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+2, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+3, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ dst += w;
+
+ memcpy( dst+0, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+1, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+2, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+3, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ dst += w;
+
+ memcpy( dst+0, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+1, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+2, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+3, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ dst += w;
+
+ memcpy( dst+0, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+1, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+2, dict + (idx & 0x3), 4 );
+ idx >>= 2;
+ memcpy( dst+3, dict + (idx & 0x3), 4 );
+}
+
+static etcpak_force_inline void DecodeDxt5Part( uint64_t a, uint64_t d, uint32_t* dst, uint32_t w )
+{
+ uint8_t* ain = (uint8_t*)&a;
+ uint8_t a0, a1;
+ uint64_t aidx = 0;
+ memcpy( &a0, ain, 1 );
+ memcpy( &a1, ain+1, 1 );
+ memcpy( &aidx, ain+2, 6 );
+
+ uint8_t* in = (uint8_t*)&d;
+ uint16_t c0, c1;
+ uint32_t idx;
+ memcpy( &c0, in, 2 );
+ memcpy( &c1, in+2, 2 );
+ memcpy( &idx, in+4, 4 );
+
+ uint32_t adict[8];
+ adict[0] = a0 << 24;
+ adict[1] = a1 << 24;
+ if( a0 > a1 )
+ {
+ adict[2] = ( (6*a0+1*a1)/7 ) << 24;
+ adict[3] = ( (5*a0+2*a1)/7 ) << 24;
+ adict[4] = ( (4*a0+3*a1)/7 ) << 24;
+ adict[5] = ( (3*a0+4*a1)/7 ) << 24;
+ adict[6] = ( (2*a0+5*a1)/7 ) << 24;
+ adict[7] = ( (1*a0+6*a1)/7 ) << 24;
+ }
+ else
+ {
+ adict[2] = ( (4*a0+1*a1)/5 ) << 24;
+ adict[3] = ( (3*a0+2*a1)/5 ) << 24;
+ adict[4] = ( (2*a0+3*a1)/5 ) << 24;
+ adict[5] = ( (1*a0+4*a1)/5 ) << 24;
+ adict[6] = 0;
+ adict[7] = 0xFF000000;
+ }
+
+ uint8_t r0 = ( ( c0 & 0xF800 ) >> 8 ) | ( ( c0 & 0xF800 ) >> 13 );
+ uint8_t g0 = ( ( c0 & 0x07E0 ) >> 3 ) | ( ( c0 & 0x07E0 ) >> 9 );
+ uint8_t b0 = ( ( c0 & 0x001F ) << 3 ) | ( ( c0 & 0x001F ) >> 2 );
+
+ uint8_t r1 = ( ( c1 & 0xF800 ) >> 8 ) | ( ( c1 & 0xF800 ) >> 13 );
+ uint8_t g1 = ( ( c1 & 0x07E0 ) >> 3 ) | ( ( c1 & 0x07E0 ) >> 9 );
+ uint8_t b1 = ( ( c1 & 0x001F ) << 3 ) | ( ( c1 & 0x001F ) >> 2 );
+
+ uint32_t dict[4];
+
+ dict[0] = ( b0 << 16 ) | ( g0 << 8 ) | r0;
+ dict[1] = ( b1 << 16 ) | ( g1 << 8 ) | r1;
+
+ uint32_t r, g, b;
+ if( c0 > c1 )
+ {
+ r = (2*r0+r1)/3;
+ g = (2*g0+g1)/3;
+ b = (2*b0+b1)/3;
+ dict[2] = ( b << 16 ) | ( g << 8 ) | r;
+ r = (2*r1+r0)/3;
+ g = (2*g1+g0)/3;
+ b = (2*b1+b0)/3;
+ dict[3] = ( b << 16 ) | ( g << 8 ) | r;
+ }
+ else
+ {
+ r = (int(r0)+r1)/2;
+ g = (int(g0)+g1)/2;
+ b = (int(b0)+b1)/2;
+ dict[2] = ( b << 16 ) | ( g << 8 ) | r;
+ dict[3] = 0;
+ }
+
+ dst[0] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[1] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[2] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[3] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst += w;
+
+ dst[0] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[1] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[2] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[3] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst += w;
+
+ dst[0] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[1] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[2] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[3] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst += w;
+
+ dst[0] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[1] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[2] = dict[idx & 0x3] | adict[aidx & 0x7];
+ idx >>= 2;
+ aidx >>= 3;
+ dst[3] = dict[idx & 0x3] | adict[aidx & 0x7];
+}
+
+BitmapPtr BlockData::DecodeDxt1()
+{
+ auto ret = std::make_shared<Bitmap>( m_size );
+
+ const uint64_t* src = (const uint64_t*)( m_data + m_dataOffset );
+ uint32_t* dst = ret->Data();
+
+ for( int y=0; y<m_size.y/4; y++ )
+ {
+ for( int x=0; x<m_size.x/4; x++ )
+ {
+ uint64_t d = *src++;
+ DecodeDxt1Part( d, dst, m_size.x );
+ dst += 4;
+ }
+ dst += m_size.x*3;
+ }
+
+ return ret;
+}
+
+BitmapPtr BlockData::DecodeDxt5()
+{
+ auto ret = std::make_shared<Bitmap>( m_size );
+
+ const uint64_t* src = (const uint64_t*)( m_data + m_dataOffset );
+ uint32_t* dst = ret->Data();
+
+ for( int y=0; y<m_size.y/4; y++ )
+ {
+ for( int x=0; x<m_size.x/4; x++ )
+ {
+ uint64_t a = *src++;
+ uint64_t d = *src++;
+ DecodeDxt5Part( a, d, dst, m_size.x );
+ dst += 4;
+ }
+ dst += m_size.x*3;
+ }
+
+ return ret;
+}
diff --git a/thirdparty/etcpak/BlockData.hpp b/thirdparty/etcpak/BlockData.hpp
new file mode 100644
index 0000000000..209e35b4e6
--- /dev/null
+++ b/thirdparty/etcpak/BlockData.hpp
@@ -0,0 +1,56 @@
+#ifndef __BLOCKDATA_HPP__
+#define __BLOCKDATA_HPP__
+
+#include <condition_variable>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <stdint.h>
+#include <stdio.h>
+#include <vector>
+
+#include "Bitmap.hpp"
+#include "ForceInline.hpp"
+#include "Vector.hpp"
+
+class BlockData
+{
+public:
+ enum Type
+ {
+ Etc1,
+ Etc2_RGB,
+ Etc2_RGBA,
+ Dxt1,
+ Dxt5
+ };
+
+ BlockData( const char* fn );
+ BlockData( const char* fn, const v2i& size, bool mipmap, Type type );
+ BlockData( const v2i& size, bool mipmap, Type type );
+ ~BlockData();
+
+ BitmapPtr Decode();
+
+ void Process( const uint32_t* src, uint32_t blocks, size_t offset, size_t width, Channels type, bool dither );
+ void ProcessRGBA( const uint32_t* src, uint32_t blocks, size_t offset, size_t width );
+
+ const v2i& Size() const { return m_size; }
+
+private:
+ etcpak_no_inline BitmapPtr DecodeRGB();
+ etcpak_no_inline BitmapPtr DecodeRGBA();
+ etcpak_no_inline BitmapPtr DecodeDxt1();
+ etcpak_no_inline BitmapPtr DecodeDxt5();
+
+ uint8_t* m_data;
+ v2i m_size;
+ size_t m_dataOffset;
+ FILE* m_file;
+ size_t m_maplen;
+ Type m_type;
+};
+
+typedef std::shared_ptr<BlockData> BlockDataPtr;
+
+#endif
diff --git a/thirdparty/etcpak/ColorSpace.cpp b/thirdparty/etcpak/ColorSpace.cpp
new file mode 100644
index 0000000000..0411541066
--- /dev/null
+++ b/thirdparty/etcpak/ColorSpace.cpp
@@ -0,0 +1,114 @@
+#include <math.h>
+#include <stdint.h>
+
+#include "Math.hpp"
+#include "ColorSpace.hpp"
+
+namespace Color
+{
+
+ static const XYZ white( v3b( 255, 255, 255 ) );
+ static const v3f rwhite( 1.f / white.x, 1.f / white.y, 1.f / white.z );
+
+
+ XYZ::XYZ( float _x, float _y, float _z )
+ : x( _x )
+ , y( _y )
+ , z( _z )
+ {
+ }
+
+ XYZ::XYZ( const v3b& rgb )
+ {
+ const float r = rgb.x / 255.f;
+ const float g = rgb.y / 255.f;
+ const float b = rgb.z / 255.f;
+
+ const float rl = sRGB2linear( r );
+ const float gl = sRGB2linear( g );
+ const float bl = sRGB2linear( b );
+
+ x = 0.4124f * rl + 0.3576f * gl + 0.1805f * bl;
+ y = 0.2126f * rl + 0.7152f * gl + 0.0722f * bl;
+ z = 0.0193f * rl + 0.1192f * gl + 0.9505f * bl;
+ }
+
+ static float revlab( float t )
+ {
+ const float p1 = 6.f/29.f;
+ const float p2 = 4.f/29.f;
+
+ if( t > p1 )
+ {
+ return t*t*t;
+ }
+ else
+ {
+ return 3 * sq( p1 ) * ( t - p2 );
+ }
+ }
+
+ XYZ::XYZ( const Lab& lab )
+ {
+ y = white.y * revlab( 1.f/116.f * ( lab.L + 16 ) );
+ x = white.x * revlab( 1.f/116.f * ( lab.L + 16 ) + 1.f/500.f * lab.a );
+ z = white.z * revlab( 1.f/116.f * ( lab.L + 16 ) - 1.f/200.f * lab.b );
+ }
+
+ v3i XYZ::RGB() const
+ {
+ const float rl = 3.2406f * x - 1.5372f * y - 0.4986f * z;
+ const float gl = -0.9689f * x + 1.8758f * y + 0.0415f * z;
+ const float bl = 0.0557f * x - 0.2040f * y + 1.0570f * z;
+
+ const float r = linear2sRGB( rl );
+ const float g = linear2sRGB( gl );
+ const float b = linear2sRGB( bl );
+
+ return v3i( clampu8( int32_t( r * 255 ) ), clampu8( int32_t( g * 255 ) ), clampu8( int32_t( b * 255 ) ) );
+ }
+
+
+ Lab::Lab()
+ : L( 0 )
+ , a( 0 )
+ , b( 0 )
+ {
+ }
+
+ Lab::Lab( float L, float a, float b )
+ : L( L )
+ , a( a )
+ , b( b )
+ {
+ }
+
+ static float labfunc( float t )
+ {
+ const float p1 = (6.f/29.f)*(6.f/29.f)*(6.f/29.f);
+ const float p2 = (1.f/3.f)*(29.f/6.f)*(29.f/6.f);
+ const float p3 = (4.f/29.f);
+
+ if( t > p1 )
+ {
+ return pow( t, 1.f/3.f );
+ }
+ else
+ {
+ return p2 * t + p3;
+ }
+ }
+
+ Lab::Lab( const XYZ& xyz )
+ {
+ L = 116 * labfunc( xyz.y * rwhite.y ) - 16;
+ a = 500 * ( labfunc( xyz.x * rwhite.x ) - labfunc( xyz.y * rwhite.y ) );
+ b = 200 * ( labfunc( xyz.y * rwhite.y ) - labfunc( xyz.z * rwhite.z ) );
+ }
+
+ Lab::Lab( const v3b& rgb )
+ {
+ new(this) Lab( XYZ( rgb ) );
+ }
+
+}
diff --git a/thirdparty/etcpak/ColorSpace.hpp b/thirdparty/etcpak/ColorSpace.hpp
new file mode 100644
index 0000000000..c9d0a9cf3f
--- /dev/null
+++ b/thirdparty/etcpak/ColorSpace.hpp
@@ -0,0 +1,36 @@
+#ifndef __DARKRL__COLORSPACE_HPP__
+#define __DARKRL__COLORSPACE_HPP__
+
+#include "Vector.hpp"
+
+namespace Color
+{
+
+ class Lab;
+
+ class XYZ
+ {
+ public:
+ XYZ( float x, float y, float z );
+ XYZ( const v3b& rgb );
+ XYZ( const Lab& lab );
+
+ v3i RGB() const;
+
+ float x, y, z;
+ };
+
+ class Lab
+ {
+ public:
+ Lab();
+ Lab( float L, float a, float b );
+ Lab( const XYZ& xyz );
+ Lab( const v3b& rgb );
+
+ float L, a, b;
+ };
+
+}
+
+#endif
diff --git a/thirdparty/etcpak/DataProvider.cpp b/thirdparty/etcpak/DataProvider.cpp
new file mode 100644
index 0000000000..6bd4b105ed
--- /dev/null
+++ b/thirdparty/etcpak/DataProvider.cpp
@@ -0,0 +1,77 @@
+#include <assert.h>
+#include <utility>
+
+#include "BitmapDownsampled.hpp"
+#include "DataProvider.hpp"
+#include "MipMap.hpp"
+
+DataProvider::DataProvider( const char* fn, bool mipmap, bool bgr )
+ : m_offset( 0 )
+ , m_mipmap( mipmap )
+ , m_done( false )
+ , m_lines( 32 )
+{
+ m_bmp.emplace_back( new Bitmap( fn, m_lines, bgr ) );
+ m_current = m_bmp[0].get();
+}
+
+DataProvider::~DataProvider()
+{
+}
+
+unsigned int DataProvider::NumberOfParts() const
+{
+ unsigned int parts = ( ( m_bmp[0]->Size().y / 4 ) + m_lines - 1 ) / m_lines;
+
+ if( m_mipmap )
+ {
+ v2i current = m_bmp[0]->Size();
+ int levels = NumberOfMipLevels( current );
+ unsigned int lines = m_lines;
+ for( int i=1; i<levels; i++ )
+ {
+ assert( current.x != 1 || current.y != 1 );
+ current.x = std::max( 1, current.x / 2 );
+ current.y = std::max( 1, current.y / 2 );
+ lines *= 2;
+ parts += ( ( std::max( 4, current.y ) / 4 ) + lines - 1 ) / lines;
+ }
+ assert( current.x == 1 && current.y == 1 );
+ }
+
+ return parts;
+}
+
+DataPart DataProvider::NextPart()
+{
+ assert( !m_done );
+
+ unsigned int lines = m_lines;
+ bool done;
+
+ const auto ptr = m_current->NextBlock( lines, done );
+ DataPart ret = {
+ ptr,
+ std::max<unsigned int>( 4, m_current->Size().x ),
+ lines,
+ m_offset
+ };
+
+ m_offset += m_current->Size().x / 4 * lines;
+
+ if( done )
+ {
+ if( m_mipmap && ( m_current->Size().x != 1 || m_current->Size().y != 1 ) )
+ {
+ m_lines *= 2;
+ m_bmp.emplace_back( new BitmapDownsampled( *m_current, m_lines ) );
+ m_current = m_bmp[m_bmp.size()-1].get();
+ }
+ else
+ {
+ m_done = true;
+ }
+ }
+
+ return ret;
+}
diff --git a/thirdparty/etcpak/DataProvider.hpp b/thirdparty/etcpak/DataProvider.hpp
new file mode 100644
index 0000000000..e773801ed6
--- /dev/null
+++ b/thirdparty/etcpak/DataProvider.hpp
@@ -0,0 +1,41 @@
+#ifndef __DATAPROVIDER_HPP__
+#define __DATAPROVIDER_HPP__
+
+#include <memory>
+#include <stdint.h>
+#include <vector>
+
+#include "Bitmap.hpp"
+
+struct DataPart
+{
+ const uint32_t* src;
+ unsigned int width;
+ unsigned int lines;
+ unsigned int offset;
+};
+
+class DataProvider
+{
+public:
+ DataProvider( const char* fn, bool mipmap, bool bgr );
+ ~DataProvider();
+
+ unsigned int NumberOfParts() const;
+
+ DataPart NextPart();
+
+ bool Alpha() const { return m_bmp[0]->Alpha(); }
+ const v2i& Size() const { return m_bmp[0]->Size(); }
+ const Bitmap& ImageData() const { return *m_bmp[0]; }
+
+private:
+ std::vector<std::unique_ptr<Bitmap>> m_bmp;
+ Bitmap* m_current;
+ unsigned int m_offset;
+ unsigned int m_lines;
+ bool m_mipmap;
+ bool m_done;
+};
+
+#endif
diff --git a/thirdparty/etcpak/Debug.cpp b/thirdparty/etcpak/Debug.cpp
new file mode 100644
index 0000000000..72dc4e0526
--- /dev/null
+++ b/thirdparty/etcpak/Debug.cpp
@@ -0,0 +1,31 @@
+#include <algorithm>
+#include <vector>
+#include "Debug.hpp"
+
+static std::vector<DebugLog::Callback*> s_callbacks;
+
+void DebugLog::Message( const char* msg )
+{
+ for( auto it = s_callbacks.begin(); it != s_callbacks.end(); ++it )
+ {
+ (*it)->OnDebugMessage( msg );
+ }
+}
+
+void DebugLog::AddCallback( Callback* c )
+{
+ const auto it = std::find( s_callbacks.begin(), s_callbacks.end(), c );
+ if( it == s_callbacks.end() )
+ {
+ s_callbacks.push_back( c );
+ }
+}
+
+void DebugLog::RemoveCallback( Callback* c )
+{
+ const auto it = std::find( s_callbacks.begin(), s_callbacks.end(), c );
+ if( it != s_callbacks.end() )
+ {
+ s_callbacks.erase( it );
+ }
+}
diff --git a/thirdparty/etcpak/Debug.hpp b/thirdparty/etcpak/Debug.hpp
new file mode 100644
index 0000000000..524eaa7baf
--- /dev/null
+++ b/thirdparty/etcpak/Debug.hpp
@@ -0,0 +1,27 @@
+#ifndef __DARKRL__DEBUG_HPP__
+#define __DARKRL__DEBUG_HPP__
+
+#ifdef DEBUG
+# include <sstream>
+# define DBGPRINT(msg) { std::stringstream __buf; __buf << msg; DebugLog::Message( __buf.str().c_str() ); }
+#else
+# define DBGPRINT(msg) ((void)0)
+#endif
+
+class DebugLog
+{
+public:
+ struct Callback
+ {
+ virtual void OnDebugMessage( const char* msg ) = 0;
+ };
+
+ static void Message( const char* msg );
+ static void AddCallback( Callback* c );
+ static void RemoveCallback( Callback* c );
+
+private:
+ DebugLog() {}
+};
+
+#endif
diff --git a/thirdparty/etcpak/Dither.cpp b/thirdparty/etcpak/Dither.cpp
new file mode 100644
index 0000000000..355686f26b
--- /dev/null
+++ b/thirdparty/etcpak/Dither.cpp
@@ -0,0 +1,120 @@
+#include <algorithm>
+#include <string.h>
+
+#include "Dither.hpp"
+#include "Math.hpp"
+#ifdef __SSE4_1__
+# ifdef _MSC_VER
+# include <intrin.h>
+# include <Windows.h>
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+#ifdef __AVX2__
+void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
+ static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
+ static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
+ static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
+
+ const __m256i BayerAdd0 = _mm256_setr_epi8(
+ a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
+ a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
+ );
+ const __m256i BayerAdd1 = _mm256_setr_epi8(
+ a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
+ a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
+ );
+ const __m256i BayerSub0 = _mm256_setr_epi8(
+ s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
+ s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
+ );
+ const __m256i BayerSub1 = _mm256_setr_epi8(
+ s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
+ s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
+ );
+
+ __m256i l0 = _mm256_inserti128_si256( _mm256_castsi128_si256( px0 ), px1, 1 );
+ __m256i l1 = _mm256_inserti128_si256( _mm256_castsi128_si256( px2 ), px3, 1 );
+
+ __m256i a0 = _mm256_adds_epu8( l0, BayerAdd0 );
+ __m256i a1 = _mm256_adds_epu8( l1, BayerAdd1 );
+ __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
+ __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
+
+ _mm256_storeu_si256( (__m256i*)(data ), s0 );
+ _mm256_storeu_si256( (__m256i*)(data+32), s1 );
+
+}
+#endif
+
+void Dither( uint8_t* data )
+{
+#ifdef __AVX2__
+ static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
+ static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
+ static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
+ static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
+
+ const __m256i BayerAdd0 = _mm256_setr_epi8(
+ a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
+ a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
+ );
+ const __m256i BayerAdd1 = _mm256_setr_epi8(
+ a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
+ a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
+ );
+ const __m256i BayerSub0 = _mm256_setr_epi8(
+ s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
+ s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
+ );
+ const __m256i BayerSub1 = _mm256_setr_epi8(
+ s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
+ s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
+ );
+
+ __m256i px0 = _mm256_loadu_si256( (__m256i*)(data ) );
+ __m256i px1 = _mm256_loadu_si256( (__m256i*)(data+32) );
+
+ __m256i a0 = _mm256_adds_epu8( px0, BayerAdd0 );
+ __m256i a1 = _mm256_adds_epu8( px1, BayerAdd1 );
+ __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
+ __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
+
+ _mm256_storeu_si256( (__m256i*)(data ), s0 );
+ _mm256_storeu_si256( (__m256i*)(data+32), s1 );
+#else
+ static constexpr int8_t Bayer31[16] = {
+ ( 0-8)*2/3, ( 8-8)*2/3, ( 2-8)*2/3, (10-8)*2/3,
+ (12-8)*2/3, ( 4-8)*2/3, (14-8)*2/3, ( 6-8)*2/3,
+ ( 3-8)*2/3, (11-8)*2/3, ( 1-8)*2/3, ( 9-8)*2/3,
+ (15-8)*2/3, ( 7-8)*2/3, (13-8)*2/3, ( 5-8)*2/3
+ };
+ static constexpr int8_t Bayer63[16] = {
+ ( 0-8)*2/6, ( 8-8)*2/6, ( 2-8)*2/6, (10-8)*2/6,
+ (12-8)*2/6, ( 4-8)*2/6, (14-8)*2/6, ( 6-8)*2/6,
+ ( 3-8)*2/6, (11-8)*2/6, ( 1-8)*2/6, ( 9-8)*2/6,
+ (15-8)*2/6, ( 7-8)*2/6, (13-8)*2/6, ( 5-8)*2/6
+ };
+
+ for( int i=0; i<16; i++ )
+ {
+ uint32_t col;
+ memcpy( &col, data, 4 );
+ uint8_t r = col & 0xFF;
+ uint8_t g = ( col >> 8 ) & 0xFF;
+ uint8_t b = ( col >> 16 ) & 0xFF;
+
+ r = clampu8( r + Bayer31[i] );
+ g = clampu8( g + Bayer63[i] );
+ b = clampu8( b + Bayer31[i] );
+
+ col = r | ( g << 8 ) | ( b << 16 );
+ memcpy( data, &col, 4 );
+ data += 4;
+ }
+#endif
+}
diff --git a/thirdparty/etcpak/Dither.hpp b/thirdparty/etcpak/Dither.hpp
new file mode 100644
index 0000000000..e43ce5676d
--- /dev/null
+++ b/thirdparty/etcpak/Dither.hpp
@@ -0,0 +1,21 @@
+#ifndef __DITHER_HPP__
+#define __DITHER_HPP__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __AVX2__
+# ifdef _MSC_VER
+# include <intrin.h>
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+void Dither( uint8_t* data );
+
+#ifdef __AVX2__
+void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 );
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/Error.cpp b/thirdparty/etcpak/Error.cpp
new file mode 100644
index 0000000000..014ecdab66
--- /dev/null
+++ b/thirdparty/etcpak/Error.cpp
@@ -0,0 +1,48 @@
+#include <stdint.h>
+
+#include "Error.hpp"
+#include "Math.hpp"
+
+float CalcMSE3( const Bitmap& bmp, const Bitmap& out )
+{
+ float err = 0;
+
+ const uint32_t* p1 = bmp.Data();
+ const uint32_t* p2 = out.Data();
+ size_t cnt = bmp.Size().x * bmp.Size().y;
+
+ for( size_t i=0; i<cnt; i++ )
+ {
+ uint32_t c1 = *p1++;
+ uint32_t c2 = *p2++;
+
+ err += sq( ( c1 & 0x000000FF ) - ( c2 & 0x000000FF ) );
+ err += sq( ( ( c1 & 0x0000FF00 ) >> 8 ) - ( ( c2 & 0x0000FF00 ) >> 8 ) );
+ err += sq( ( ( c1 & 0x00FF0000 ) >> 16 ) - ( ( c2 & 0x00FF0000 ) >> 16 ) );
+ }
+
+ err /= cnt * 3;
+
+ return err;
+}
+
+float CalcMSE1( const Bitmap& bmp, const Bitmap& out )
+{
+ float err = 0;
+
+ const uint32_t* p1 = bmp.Data();
+ const uint32_t* p2 = out.Data();
+ size_t cnt = bmp.Size().x * bmp.Size().y;
+
+ for( size_t i=0; i<cnt; i++ )
+ {
+ uint32_t c1 = *p1++;
+ uint32_t c2 = *p2++;
+
+ err += sq( ( c1 >> 24 ) - ( c2 & 0xFF ) );
+ }
+
+ err /= cnt;
+
+ return err;
+}
diff --git a/thirdparty/etcpak/Error.hpp b/thirdparty/etcpak/Error.hpp
new file mode 100644
index 0000000000..9817754b74
--- /dev/null
+++ b/thirdparty/etcpak/Error.hpp
@@ -0,0 +1,9 @@
+#ifndef __ERROR_HPP__
+#define __ERROR_HPP__
+
+#include "Bitmap.hpp"
+
+float CalcMSE3( const Bitmap& bmp, const Bitmap& out );
+float CalcMSE1( const Bitmap& bmp, const Bitmap& out );
+
+#endif
diff --git a/thirdparty/etcpak/ForceInline.hpp b/thirdparty/etcpak/ForceInline.hpp
new file mode 100644
index 0000000000..b6f012841b
--- /dev/null
+++ b/thirdparty/etcpak/ForceInline.hpp
@@ -0,0 +1,20 @@
+#ifndef __FORCEINLINE_HPP__
+#define __FORCEINLINE_HPP__
+
+#if defined(__GNUC__)
+# define etcpak_force_inline __attribute__((always_inline)) inline
+#elif defined(_MSC_VER)
+# define etcpak_force_inline __forceinline
+#else
+# define etcpak_force_inline inline
+#endif
+
+#if defined(__GNUC__)
+# define etcpak_no_inline __attribute__((noinline))
+#elif defined(_MSC_VER)
+# define etcpak_no_inline __declspec(noinline)
+#else
+# define etcpak_no_inline
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/LICENSE.txt b/thirdparty/etcpak/LICENSE.txt
new file mode 100644
index 0000000000..59e85d6ea5
--- /dev/null
+++ b/thirdparty/etcpak/LICENSE.txt
@@ -0,0 +1,26 @@
+etcpak, an extremely fast ETC compression utility (https://github.com/wolfpld/etcpak)
+
+Copyright (c) 2013-2021, Bartosz Taudul <wolf@nereid.pl>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/thirdparty/etcpak/Math.hpp b/thirdparty/etcpak/Math.hpp
new file mode 100644
index 0000000000..994e1ac4ea
--- /dev/null
+++ b/thirdparty/etcpak/Math.hpp
@@ -0,0 +1,92 @@
+#ifndef __DARKRL__MATH_HPP__
+#define __DARKRL__MATH_HPP__
+
+#include <algorithm>
+#include <cmath>
+#include <stdint.h>
+
+#include "ForceInline.hpp"
+
+template<typename T>
+static etcpak_force_inline T AlignPOT( T val )
+{
+ if( val == 0 ) return 1;
+ val--;
+ for( unsigned int i=1; i<sizeof( T ) * 8; i <<= 1 )
+ {
+ val |= val >> i;
+ }
+ return val + 1;
+}
+
+static etcpak_force_inline int CountSetBits( uint32_t val )
+{
+ val -= ( val >> 1 ) & 0x55555555;
+ val = ( ( val >> 2 ) & 0x33333333 ) + ( val & 0x33333333 );
+ val = ( ( val >> 4 ) + val ) & 0x0f0f0f0f;
+ val += val >> 8;
+ val += val >> 16;
+ return val & 0x0000003f;
+}
+
+static etcpak_force_inline int CountLeadingZeros( uint32_t val )
+{
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ return 32 - CountSetBits( val );
+}
+
+static etcpak_force_inline float sRGB2linear( float v )
+{
+ const float a = 0.055f;
+ if( v <= 0.04045f )
+ {
+ return v / 12.92f;
+ }
+ else
+ {
+ return pow( ( v + a ) / ( 1 + a ), 2.4f );
+ }
+}
+
+static etcpak_force_inline float linear2sRGB( float v )
+{
+ const float a = 0.055f;
+ if( v <= 0.0031308f )
+ {
+ return 12.92f * v;
+ }
+ else
+ {
+ return ( 1 + a ) * pow( v, 1/2.4f ) - a;
+ }
+}
+
+template<class T>
+static etcpak_force_inline T SmoothStep( T x )
+{
+ return x*x*(3-2*x);
+}
+
+static etcpak_force_inline uint8_t clampu8( int32_t val )
+{
+ if( ( val & ~0xFF ) == 0 ) return val;
+ return ( ( ~val ) >> 31 ) & 0xFF;
+}
+
+template<class T>
+static etcpak_force_inline T sq( T val )
+{
+ return val * val;
+}
+
+static etcpak_force_inline int mul8bit( int a, int b )
+{
+ int t = a*b + 128;
+ return ( t + ( t >> 8 ) ) >> 8;
+}
+
+#endif
diff --git a/thirdparty/etcpak/MipMap.hpp b/thirdparty/etcpak/MipMap.hpp
new file mode 100644
index 0000000000..d3b4bc9e7c
--- /dev/null
+++ b/thirdparty/etcpak/MipMap.hpp
@@ -0,0 +1,11 @@
+#ifndef __MIPMAP_HPP__
+#define __MIPMAP_HPP__
+
+#include "Vector.hpp"
+
+inline int NumberOfMipLevels( const v2i& size )
+{
+ return (int)floor( log2( std::max( size.x, size.y ) ) ) + 1;
+}
+
+#endif
diff --git a/thirdparty/etcpak/ProcessCommon.hpp b/thirdparty/etcpak/ProcessCommon.hpp
new file mode 100644
index 0000000000..657d68888f
--- /dev/null
+++ b/thirdparty/etcpak/ProcessCommon.hpp
@@ -0,0 +1,50 @@
+#ifndef __PROCESSCOMMON_HPP__
+#define __PROCESSCOMMON_HPP__
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+template<class T>
+static size_t GetLeastError( const T* err, size_t num )
+{
+ size_t idx = 0;
+ for( size_t i=1; i<num; i++ )
+ {
+ if( err[i] < err[idx] )
+ {
+ idx = i;
+ }
+ }
+ return idx;
+}
+
+static uint64_t FixByteOrder( uint64_t d )
+{
+ return ( ( d & 0x00000000FFFFFFFF ) ) |
+ ( ( d & 0xFF00000000000000 ) >> 24 ) |
+ ( ( d & 0x000000FF00000000 ) << 24 ) |
+ ( ( d & 0x00FF000000000000 ) >> 8 ) |
+ ( ( d & 0x0000FF0000000000 ) << 8 );
+}
+
+template<class T, class S>
+static uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id )
+{
+ size_t tidx[2];
+ tidx[0] = GetLeastError( terr[0], 8 );
+ tidx[1] = GetLeastError( terr[1], 8 );
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+ for( int i=0; i<16; i++ )
+ {
+ uint64_t t = tsel[i][tidx[id[i]%2]];
+ d |= ( t & 0x1 ) << ( i + 32 );
+ d |= ( t & 0x2 ) << ( i + 47 );
+ }
+
+ return d;
+}
+
+#endif
diff --git a/thirdparty/etcpak/ProcessDxtc.cpp b/thirdparty/etcpak/ProcessDxtc.cpp
new file mode 100644
index 0000000000..508d55fd75
--- /dev/null
+++ b/thirdparty/etcpak/ProcessDxtc.cpp
@@ -0,0 +1,956 @@
+#include "Dither.hpp"
+#include "ForceInline.hpp"
+#include "ProcessDxtc.hpp"
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+#if defined __AVX__ && !defined __SSE4_1__
+# define __SSE4_1__
+#endif
+
+#if defined __SSE4_1__ || defined __AVX2__
+# ifdef _MSC_VER
+# include <intrin.h>
+# else
+# include <x86intrin.h>
+# ifndef _mm256_cvtsi256_si32
+# define _mm256_cvtsi256_si32( v ) ( _mm_cvtsi128_si32( _mm256_castsi256_si128( v ) ) )
+# endif
+# endif
+#endif
+
+
+static etcpak_force_inline uint16_t to565( uint8_t r, uint8_t g, uint8_t b )
+{
+ return ( ( r & 0xF8 ) << 8 ) | ( ( g & 0xFC ) << 3 ) | ( b >> 3 );
+}
+
+static etcpak_force_inline uint16_t to565( uint32_t c )
+{
+ return
+ ( ( c & 0xF80000 ) >> 19 ) |
+ ( ( c & 0x00FC00 ) >> 5 ) |
+ ( ( c & 0x0000F8 ) << 8 );
+}
+
+static const uint8_t DxtcIndexTable[256] = {
+ 85, 87, 86, 84, 93, 95, 94, 92, 89, 91, 90, 88, 81, 83, 82, 80,
+ 117, 119, 118, 116, 125, 127, 126, 124, 121, 123, 122, 120, 113, 115, 114, 112,
+ 101, 103, 102, 100, 109, 111, 110, 108, 105, 107, 106, 104, 97, 99, 98, 96,
+ 69, 71, 70, 68, 77, 79, 78, 76, 73, 75, 74, 72, 65, 67, 66, 64,
+ 213, 215, 214, 212, 221, 223, 222, 220, 217, 219, 218, 216, 209, 211, 210, 208,
+ 245, 247, 246, 244, 253, 255, 254, 252, 249, 251, 250, 248, 241, 243, 242, 240,
+ 229, 231, 230, 228, 237, 239, 238, 236, 233, 235, 234, 232, 225, 227, 226, 224,
+ 197, 199, 198, 196, 205, 207, 206, 204, 201, 203, 202, 200, 193, 195, 194, 192,
+ 149, 151, 150, 148, 157, 159, 158, 156, 153, 155, 154, 152, 145, 147, 146, 144,
+ 181, 183, 182, 180, 189, 191, 190, 188, 185, 187, 186, 184, 177, 179, 178, 176,
+ 165, 167, 166, 164, 173, 175, 174, 172, 169, 171, 170, 168, 161, 163, 162, 160,
+ 133, 135, 134, 132, 141, 143, 142, 140, 137, 139, 138, 136, 129, 131, 130, 128,
+ 21, 23, 22, 20, 29, 31, 30, 28, 25, 27, 26, 24, 17, 19, 18, 16,
+ 53, 55, 54, 52, 61, 63, 62, 60, 57, 59, 58, 56, 49, 51, 50, 48,
+ 37, 39, 38, 36, 45, 47, 46, 44, 41, 43, 42, 40, 33, 35, 34, 32,
+ 5, 7, 6, 4, 13, 15, 14, 12, 9, 11, 10, 8, 1, 3, 2, 0
+};
+
+static const uint8_t AlphaIndexTable_SSE[64] = {
+ 9, 15, 14, 13, 12, 11, 10, 8, 57, 63, 62, 61, 60, 59, 58, 56,
+ 49, 55, 54, 53, 52, 51, 50, 48, 41, 47, 46, 45, 44, 43, 42, 40,
+ 33, 39, 38, 37, 36, 35, 34, 32, 25, 31, 30, 29, 28, 27, 26, 24,
+ 17, 23, 22, 21, 20, 19, 18, 16, 1, 7, 6, 5, 4, 3, 2, 0,
+};
+
+static const uint16_t DivTable[255*3+1] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xcccc, 0xaaaa, 0x9249, 0x8000, 0x71c7, 0x6666, 0x5d17, 0x5555, 0x4ec4, 0x4924, 0x4444, 0x4000,
+ 0x3c3c, 0x38e3, 0x35e5, 0x3333, 0x30c3, 0x2e8b, 0x2c85, 0x2aaa, 0x28f5, 0x2762, 0x25ed, 0x2492, 0x234f, 0x2222, 0x2108, 0x2000,
+ 0x1f07, 0x1e1e, 0x1d41, 0x1c71, 0x1bac, 0x1af2, 0x1a41, 0x1999, 0x18f9, 0x1861, 0x17d0, 0x1745, 0x16c1, 0x1642, 0x15c9, 0x1555,
+ 0x14e5, 0x147a, 0x1414, 0x13b1, 0x1352, 0x12f6, 0x129e, 0x1249, 0x11f7, 0x11a7, 0x115b, 0x1111, 0x10c9, 0x1084, 0x1041, 0x1000,
+ 0x0fc0, 0x0f83, 0x0f48, 0x0f0f, 0x0ed7, 0x0ea0, 0x0e6c, 0x0e38, 0x0e07, 0x0dd6, 0x0da7, 0x0d79, 0x0d4c, 0x0d20, 0x0cf6, 0x0ccc,
+ 0x0ca4, 0x0c7c, 0x0c56, 0x0c30, 0x0c0c, 0x0be8, 0x0bc5, 0x0ba2, 0x0b81, 0x0b60, 0x0b40, 0x0b21, 0x0b02, 0x0ae4, 0x0ac7, 0x0aaa,
+ 0x0a8e, 0x0a72, 0x0a57, 0x0a3d, 0x0a23, 0x0a0a, 0x09f1, 0x09d8, 0x09c0, 0x09a9, 0x0991, 0x097b, 0x0964, 0x094f, 0x0939, 0x0924,
+ 0x090f, 0x08fb, 0x08e7, 0x08d3, 0x08c0, 0x08ad, 0x089a, 0x0888, 0x0876, 0x0864, 0x0853, 0x0842, 0x0831, 0x0820, 0x0810, 0x0800,
+ 0x07f0, 0x07e0, 0x07d1, 0x07c1, 0x07b3, 0x07a4, 0x0795, 0x0787, 0x0779, 0x076b, 0x075d, 0x0750, 0x0743, 0x0736, 0x0729, 0x071c,
+ 0x070f, 0x0703, 0x06f7, 0x06eb, 0x06df, 0x06d3, 0x06c8, 0x06bc, 0x06b1, 0x06a6, 0x069b, 0x0690, 0x0685, 0x067b, 0x0670, 0x0666,
+ 0x065c, 0x0652, 0x0648, 0x063e, 0x0634, 0x062b, 0x0621, 0x0618, 0x060f, 0x0606, 0x05fd, 0x05f4, 0x05eb, 0x05e2, 0x05d9, 0x05d1,
+ 0x05c9, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0581, 0x0579, 0x0572, 0x056b, 0x0563, 0x055c, 0x0555,
+ 0x054e, 0x0547, 0x0540, 0x0539, 0x0532, 0x052b, 0x0525, 0x051e, 0x0518, 0x0511, 0x050b, 0x0505, 0x04fe, 0x04f8, 0x04f2, 0x04ec,
+ 0x04e6, 0x04e0, 0x04da, 0x04d4, 0x04ce, 0x04c8, 0x04c3, 0x04bd, 0x04b8, 0x04b2, 0x04ad, 0x04a7, 0x04a2, 0x049c, 0x0497, 0x0492,
+ 0x048d, 0x0487, 0x0482, 0x047d, 0x0478, 0x0473, 0x046e, 0x0469, 0x0465, 0x0460, 0x045b, 0x0456, 0x0452, 0x044d, 0x0448, 0x0444,
+ 0x043f, 0x043b, 0x0436, 0x0432, 0x042d, 0x0429, 0x0425, 0x0421, 0x041c, 0x0418, 0x0414, 0x0410, 0x040c, 0x0408, 0x0404, 0x0400,
+ 0x03fc, 0x03f8, 0x03f4, 0x03f0, 0x03ec, 0x03e8, 0x03e4, 0x03e0, 0x03dd, 0x03d9, 0x03d5, 0x03d2, 0x03ce, 0x03ca, 0x03c7, 0x03c3,
+ 0x03c0, 0x03bc, 0x03b9, 0x03b5, 0x03b2, 0x03ae, 0x03ab, 0x03a8, 0x03a4, 0x03a1, 0x039e, 0x039b, 0x0397, 0x0394, 0x0391, 0x038e,
+ 0x038b, 0x0387, 0x0384, 0x0381, 0x037e, 0x037b, 0x0378, 0x0375, 0x0372, 0x036f, 0x036c, 0x0369, 0x0366, 0x0364, 0x0361, 0x035e,
+ 0x035b, 0x0358, 0x0355, 0x0353, 0x0350, 0x034d, 0x034a, 0x0348, 0x0345, 0x0342, 0x0340, 0x033d, 0x033a, 0x0338, 0x0335, 0x0333,
+ 0x0330, 0x032e, 0x032b, 0x0329, 0x0326, 0x0324, 0x0321, 0x031f, 0x031c, 0x031a, 0x0317, 0x0315, 0x0313, 0x0310, 0x030e, 0x030c,
+ 0x0309, 0x0307, 0x0305, 0x0303, 0x0300, 0x02fe, 0x02fc, 0x02fa, 0x02f7, 0x02f5, 0x02f3, 0x02f1, 0x02ef, 0x02ec, 0x02ea, 0x02e8,
+ 0x02e6, 0x02e4, 0x02e2, 0x02e0, 0x02de, 0x02dc, 0x02da, 0x02d8, 0x02d6, 0x02d4, 0x02d2, 0x02d0, 0x02ce, 0x02cc, 0x02ca, 0x02c8,
+ 0x02c6, 0x02c4, 0x02c2, 0x02c0, 0x02be, 0x02bc, 0x02bb, 0x02b9, 0x02b7, 0x02b5, 0x02b3, 0x02b1, 0x02b0, 0x02ae, 0x02ac, 0x02aa,
+ 0x02a8, 0x02a7, 0x02a5, 0x02a3, 0x02a1, 0x02a0, 0x029e, 0x029c, 0x029b, 0x0299, 0x0297, 0x0295, 0x0294, 0x0292, 0x0291, 0x028f,
+ 0x028d, 0x028c, 0x028a, 0x0288, 0x0287, 0x0285, 0x0284, 0x0282, 0x0280, 0x027f, 0x027d, 0x027c, 0x027a, 0x0279, 0x0277, 0x0276,
+ 0x0274, 0x0273, 0x0271, 0x0270, 0x026e, 0x026d, 0x026b, 0x026a, 0x0268, 0x0267, 0x0265, 0x0264, 0x0263, 0x0261, 0x0260, 0x025e,
+ 0x025d, 0x025c, 0x025a, 0x0259, 0x0257, 0x0256, 0x0255, 0x0253, 0x0252, 0x0251, 0x024f, 0x024e, 0x024d, 0x024b, 0x024a, 0x0249,
+ 0x0247, 0x0246, 0x0245, 0x0243, 0x0242, 0x0241, 0x0240, 0x023e, 0x023d, 0x023c, 0x023b, 0x0239, 0x0238, 0x0237, 0x0236, 0x0234,
+ 0x0233, 0x0232, 0x0231, 0x0230, 0x022e, 0x022d, 0x022c, 0x022b, 0x022a, 0x0229, 0x0227, 0x0226, 0x0225, 0x0224, 0x0223, 0x0222,
+ 0x0220, 0x021f, 0x021e, 0x021d, 0x021c, 0x021b, 0x021a, 0x0219, 0x0218, 0x0216, 0x0215, 0x0214, 0x0213, 0x0212, 0x0211, 0x0210,
+ 0x020f, 0x020e, 0x020d, 0x020c, 0x020b, 0x020a, 0x0209, 0x0208, 0x0207, 0x0206, 0x0205, 0x0204, 0x0203, 0x0202, 0x0201, 0x0200,
+ 0x01ff, 0x01fe, 0x01fd, 0x01fc, 0x01fb, 0x01fa, 0x01f9, 0x01f8, 0x01f7, 0x01f6, 0x01f5, 0x01f4, 0x01f3, 0x01f2, 0x01f1, 0x01f0,
+ 0x01ef, 0x01ee, 0x01ed, 0x01ec, 0x01eb, 0x01ea, 0x01e9, 0x01e9, 0x01e8, 0x01e7, 0x01e6, 0x01e5, 0x01e4, 0x01e3, 0x01e2, 0x01e1,
+ 0x01e0, 0x01e0, 0x01df, 0x01de, 0x01dd, 0x01dc, 0x01db, 0x01da, 0x01da, 0x01d9, 0x01d8, 0x01d7, 0x01d6, 0x01d5, 0x01d4, 0x01d4,
+ 0x01d3, 0x01d2, 0x01d1, 0x01d0, 0x01cf, 0x01cf, 0x01ce, 0x01cd, 0x01cc, 0x01cb, 0x01cb, 0x01ca, 0x01c9, 0x01c8, 0x01c7, 0x01c7,
+ 0x01c6, 0x01c5, 0x01c4, 0x01c3, 0x01c3, 0x01c2, 0x01c1, 0x01c0, 0x01c0, 0x01bf, 0x01be, 0x01bd, 0x01bd, 0x01bc, 0x01bb, 0x01ba,
+ 0x01ba, 0x01b9, 0x01b8, 0x01b7, 0x01b7, 0x01b6, 0x01b5, 0x01b4, 0x01b4, 0x01b3, 0x01b2, 0x01b2, 0x01b1, 0x01b0, 0x01af, 0x01af,
+ 0x01ae, 0x01ad, 0x01ad, 0x01ac, 0x01ab, 0x01aa, 0x01aa, 0x01a9, 0x01a8, 0x01a8, 0x01a7, 0x01a6, 0x01a6, 0x01a5, 0x01a4, 0x01a4,
+ 0x01a3, 0x01a2, 0x01a2, 0x01a1, 0x01a0, 0x01a0, 0x019f, 0x019e, 0x019e, 0x019d, 0x019c, 0x019c, 0x019b, 0x019a, 0x019a, 0x0199,
+ 0x0198, 0x0198, 0x0197, 0x0197, 0x0196, 0x0195, 0x0195, 0x0194, 0x0193, 0x0193, 0x0192, 0x0192, 0x0191, 0x0190, 0x0190, 0x018f,
+ 0x018f, 0x018e, 0x018d, 0x018d, 0x018c, 0x018b, 0x018b, 0x018a, 0x018a, 0x0189, 0x0189, 0x0188, 0x0187, 0x0187, 0x0186, 0x0186,
+ 0x0185, 0x0184, 0x0184, 0x0183, 0x0183, 0x0182, 0x0182, 0x0181, 0x0180, 0x0180, 0x017f, 0x017f, 0x017e, 0x017e, 0x017d, 0x017d,
+ 0x017c, 0x017b, 0x017b, 0x017a, 0x017a, 0x0179, 0x0179, 0x0178, 0x0178, 0x0177, 0x0177, 0x0176, 0x0175, 0x0175, 0x0174, 0x0174,
+ 0x0173, 0x0173, 0x0172, 0x0172, 0x0171, 0x0171, 0x0170, 0x0170, 0x016f, 0x016f, 0x016e, 0x016e, 0x016d, 0x016d, 0x016c, 0x016c,
+ 0x016b, 0x016b, 0x016a, 0x016a, 0x0169, 0x0169, 0x0168, 0x0168, 0x0167, 0x0167, 0x0166, 0x0166, 0x0165, 0x0165, 0x0164, 0x0164,
+ 0x0163, 0x0163, 0x0162, 0x0162, 0x0161, 0x0161, 0x0160, 0x0160, 0x015f, 0x015f, 0x015e, 0x015e, 0x015d, 0x015d, 0x015d, 0x015c,
+ 0x015c, 0x015b, 0x015b, 0x015a, 0x015a, 0x0159, 0x0159, 0x0158, 0x0158, 0x0158, 0x0157, 0x0157, 0x0156, 0x0156
+};
+static const uint16_t DivTableNEON[255*3+1] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x1c71, 0x1af2, 0x1999, 0x1861, 0x1745, 0x1642, 0x1555, 0x147a, 0x13b1, 0x12f6, 0x1249, 0x11a7, 0x1111, 0x1084, 0x1000,
+ 0x0f83, 0x0f0f, 0x0ea0, 0x0e38, 0x0dd6, 0x0d79, 0x0d20, 0x0ccc, 0x0c7c, 0x0c30, 0x0be8, 0x0ba2, 0x0b60, 0x0b21, 0x0ae4, 0x0aaa,
+ 0x0a72, 0x0a3d, 0x0a0a, 0x09d8, 0x09a9, 0x097b, 0x094f, 0x0924, 0x08fb, 0x08d3, 0x08ad, 0x0888, 0x0864, 0x0842, 0x0820, 0x0800,
+ 0x07e0, 0x07c1, 0x07a4, 0x0787, 0x076b, 0x0750, 0x0736, 0x071c, 0x0703, 0x06eb, 0x06d3, 0x06bc, 0x06a6, 0x0690, 0x067b, 0x0666,
+ 0x0652, 0x063e, 0x062b, 0x0618, 0x0606, 0x05f4, 0x05e2, 0x05d1, 0x05c0, 0x05b0, 0x05a0, 0x0590, 0x0581, 0x0572, 0x0563, 0x0555,
+ 0x0547, 0x0539, 0x052b, 0x051e, 0x0511, 0x0505, 0x04f8, 0x04ec, 0x04e0, 0x04d4, 0x04c8, 0x04bd, 0x04b2, 0x04a7, 0x049c, 0x0492,
+ 0x0487, 0x047d, 0x0473, 0x0469, 0x0460, 0x0456, 0x044d, 0x0444, 0x043b, 0x0432, 0x0429, 0x0421, 0x0418, 0x0410, 0x0408, 0x0400,
+ 0x03f8, 0x03f0, 0x03e8, 0x03e0, 0x03d9, 0x03d2, 0x03ca, 0x03c3, 0x03bc, 0x03b5, 0x03ae, 0x03a8, 0x03a1, 0x039b, 0x0394, 0x038e,
+ 0x0387, 0x0381, 0x037b, 0x0375, 0x036f, 0x0369, 0x0364, 0x035e, 0x0358, 0x0353, 0x034d, 0x0348, 0x0342, 0x033d, 0x0338, 0x0333,
+ 0x032e, 0x0329, 0x0324, 0x031f, 0x031a, 0x0315, 0x0310, 0x030c, 0x0307, 0x0303, 0x02fe, 0x02fa, 0x02f5, 0x02f1, 0x02ec, 0x02e8,
+ 0x02e4, 0x02e0, 0x02dc, 0x02d8, 0x02d4, 0x02d0, 0x02cc, 0x02c8, 0x02c4, 0x02c0, 0x02bc, 0x02b9, 0x02b5, 0x02b1, 0x02ae, 0x02aa,
+ 0x02a7, 0x02a3, 0x02a0, 0x029c, 0x0299, 0x0295, 0x0292, 0x028f, 0x028c, 0x0288, 0x0285, 0x0282, 0x027f, 0x027c, 0x0279, 0x0276,
+ 0x0273, 0x0270, 0x026d, 0x026a, 0x0267, 0x0264, 0x0261, 0x025e, 0x025c, 0x0259, 0x0256, 0x0253, 0x0251, 0x024e, 0x024b, 0x0249,
+ 0x0246, 0x0243, 0x0241, 0x023e, 0x023c, 0x0239, 0x0237, 0x0234, 0x0232, 0x0230, 0x022d, 0x022b, 0x0229, 0x0226, 0x0224, 0x0222,
+ 0x021f, 0x021d, 0x021b, 0x0219, 0x0216, 0x0214, 0x0212, 0x0210, 0x020e, 0x020c, 0x020a, 0x0208, 0x0206, 0x0204, 0x0202, 0x0200,
+ 0x01fe, 0x01fc, 0x01fa, 0x01f8, 0x01f6, 0x01f4, 0x01f2, 0x01f0, 0x01ee, 0x01ec, 0x01ea, 0x01e9, 0x01e7, 0x01e5, 0x01e3, 0x01e1,
+ 0x01e0, 0x01de, 0x01dc, 0x01da, 0x01d9, 0x01d7, 0x01d5, 0x01d4, 0x01d2, 0x01d0, 0x01cf, 0x01cd, 0x01cb, 0x01ca, 0x01c8, 0x01c7,
+ 0x01c5, 0x01c3, 0x01c2, 0x01c0, 0x01bf, 0x01bd, 0x01bc, 0x01ba, 0x01b9, 0x01b7, 0x01b6, 0x01b4, 0x01b3, 0x01b2, 0x01b0, 0x01af,
+ 0x01ad, 0x01ac, 0x01aa, 0x01a9, 0x01a8, 0x01a6, 0x01a5, 0x01a4, 0x01a2, 0x01a1, 0x01a0, 0x019e, 0x019d, 0x019c, 0x019a, 0x0199,
+ 0x0198, 0x0197, 0x0195, 0x0194, 0x0193, 0x0192, 0x0190, 0x018f, 0x018e, 0x018d, 0x018b, 0x018a, 0x0189, 0x0188, 0x0187, 0x0186,
+ 0x0184, 0x0183, 0x0182, 0x0181, 0x0180, 0x017f, 0x017e, 0x017d, 0x017b, 0x017a, 0x0179, 0x0178, 0x0177, 0x0176, 0x0175, 0x0174,
+ 0x0173, 0x0172, 0x0171, 0x0170, 0x016f, 0x016e, 0x016d, 0x016c, 0x016b, 0x016a, 0x0169, 0x0168, 0x0167, 0x0166, 0x0165, 0x0164,
+ 0x0163, 0x0162, 0x0161, 0x0160, 0x015f, 0x015e, 0x015d, 0x015c, 0x015b, 0x015a, 0x0159, 0x0158, 0x0158, 0x0157, 0x0156, 0x0155,
+ 0x0154, 0x0153, 0x0152, 0x0151, 0x0150, 0x0150, 0x014f, 0x014e, 0x014d, 0x014c, 0x014b, 0x014a, 0x014a, 0x0149, 0x0148, 0x0147,
+ 0x0146, 0x0146, 0x0145, 0x0144, 0x0143, 0x0142, 0x0142, 0x0141, 0x0140, 0x013f, 0x013e, 0x013e, 0x013d, 0x013c, 0x013b, 0x013b,
+ 0x013a, 0x0139, 0x0138, 0x0138, 0x0137, 0x0136, 0x0135, 0x0135, 0x0134, 0x0133, 0x0132, 0x0132, 0x0131, 0x0130, 0x0130, 0x012f,
+ 0x012e, 0x012e, 0x012d, 0x012c, 0x012b, 0x012b, 0x012a, 0x0129, 0x0129, 0x0128, 0x0127, 0x0127, 0x0126, 0x0125, 0x0125, 0x0124,
+ 0x0123, 0x0123, 0x0122, 0x0121, 0x0121, 0x0120, 0x0120, 0x011f, 0x011e, 0x011e, 0x011d, 0x011c, 0x011c, 0x011b, 0x011b, 0x011a,
+ 0x0119, 0x0119, 0x0118, 0x0118, 0x0117, 0x0116, 0x0116, 0x0115, 0x0115, 0x0114, 0x0113, 0x0113, 0x0112, 0x0112, 0x0111, 0x0111,
+ 0x0110, 0x010f, 0x010f, 0x010e, 0x010e, 0x010d, 0x010d, 0x010c, 0x010c, 0x010b, 0x010a, 0x010a, 0x0109, 0x0109, 0x0108, 0x0108,
+ 0x0107, 0x0107, 0x0106, 0x0106, 0x0105, 0x0105, 0x0104, 0x0104, 0x0103, 0x0103, 0x0102, 0x0102, 0x0101, 0x0101, 0x0100, 0x0100,
+ 0x00ff, 0x00ff, 0x00fe, 0x00fe, 0x00fd, 0x00fd, 0x00fc, 0x00fc, 0x00fb, 0x00fb, 0x00fa, 0x00fa, 0x00f9, 0x00f9, 0x00f8, 0x00f8,
+ 0x00f7, 0x00f7, 0x00f6, 0x00f6, 0x00f5, 0x00f5, 0x00f4, 0x00f4, 0x00f4, 0x00f3, 0x00f3, 0x00f2, 0x00f2, 0x00f1, 0x00f1, 0x00f0,
+ 0x00f0, 0x00f0, 0x00ef, 0x00ef, 0x00ee, 0x00ee, 0x00ed, 0x00ed, 0x00ed, 0x00ec, 0x00ec, 0x00eb, 0x00eb, 0x00ea, 0x00ea, 0x00ea,
+ 0x00e9, 0x00e9, 0x00e8, 0x00e8, 0x00e7, 0x00e7, 0x00e7, 0x00e6, 0x00e6, 0x00e5, 0x00e5, 0x00e5, 0x00e4, 0x00e4, 0x00e3, 0x00e3,
+ 0x00e3, 0x00e2, 0x00e2, 0x00e1, 0x00e1, 0x00e1, 0x00e0, 0x00e0, 0x00e0, 0x00df, 0x00df, 0x00de, 0x00de, 0x00de, 0x00dd, 0x00dd,
+ 0x00dd, 0x00dc, 0x00dc, 0x00db, 0x00db, 0x00db, 0x00da, 0x00da, 0x00da, 0x00d9, 0x00d9, 0x00d9, 0x00d8, 0x00d8, 0x00d7, 0x00d7,
+ 0x00d7, 0x00d6, 0x00d6, 0x00d6, 0x00d5, 0x00d5, 0x00d5, 0x00d4, 0x00d4, 0x00d4, 0x00d3, 0x00d3, 0x00d3, 0x00d2, 0x00d2, 0x00d2,
+ 0x00d1, 0x00d1, 0x00d1, 0x00d0, 0x00d0, 0x00d0, 0x00cf, 0x00cf, 0x00cf, 0x00ce, 0x00ce, 0x00ce, 0x00cd, 0x00cd, 0x00cd, 0x00cc,
+ 0x00cc, 0x00cc, 0x00cb, 0x00cb, 0x00cb, 0x00ca, 0x00ca, 0x00ca, 0x00c9, 0x00c9, 0x00c9, 0x00c9, 0x00c8, 0x00c8, 0x00c8, 0x00c7,
+ 0x00c7, 0x00c7, 0x00c6, 0x00c6, 0x00c6, 0x00c5, 0x00c5, 0x00c5, 0x00c5, 0x00c4, 0x00c4, 0x00c4, 0x00c3, 0x00c3, 0x00c3, 0x00c3,
+ 0x00c2, 0x00c2, 0x00c2, 0x00c1, 0x00c1, 0x00c1, 0x00c1, 0x00c0, 0x00c0, 0x00c0, 0x00bf, 0x00bf, 0x00bf, 0x00bf, 0x00be, 0x00be,
+ 0x00be, 0x00bd, 0x00bd, 0x00bd, 0x00bd, 0x00bc, 0x00bc, 0x00bc, 0x00bc, 0x00bb, 0x00bb, 0x00bb, 0x00ba, 0x00ba, 0x00ba, 0x00ba,
+ 0x00b9, 0x00b9, 0x00b9, 0x00b9, 0x00b8, 0x00b8, 0x00b8, 0x00b8, 0x00b7, 0x00b7, 0x00b7, 0x00b7, 0x00b6, 0x00b6, 0x00b6, 0x00b6,
+ 0x00b5, 0x00b5, 0x00b5, 0x00b5, 0x00b4, 0x00b4, 0x00b4, 0x00b4, 0x00b3, 0x00b3, 0x00b3, 0x00b3, 0x00b2, 0x00b2, 0x00b2, 0x00b2,
+ 0x00b1, 0x00b1, 0x00b1, 0x00b1, 0x00b0, 0x00b0, 0x00b0, 0x00b0, 0x00af, 0x00af, 0x00af, 0x00af, 0x00ae, 0x00ae, 0x00ae, 0x00ae,
+ 0x00ae, 0x00ad, 0x00ad, 0x00ad, 0x00ad, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ab, 0x00ab, 0x00ab, 0x00ab,
+};
+
+static const uint16_t DivTableAlpha[256] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xe38e, 0xcccc, 0xba2e, 0xaaaa, 0x9d89, 0x9249, 0x8888, 0x8000,
+ 0x7878, 0x71c7, 0x6bca, 0x6666, 0x6186, 0x5d17, 0x590b, 0x5555, 0x51eb, 0x4ec4, 0x4bda, 0x4924, 0x469e, 0x4444, 0x4210, 0x4000,
+ 0x3e0f, 0x3c3c, 0x3a83, 0x38e3, 0x3759, 0x35e5, 0x3483, 0x3333, 0x31f3, 0x30c3, 0x2fa0, 0x2e8b, 0x2d82, 0x2c85, 0x2b93, 0x2aaa,
+ 0x29cb, 0x28f5, 0x2828, 0x2762, 0x26a4, 0x25ed, 0x253c, 0x2492, 0x23ee, 0x234f, 0x22b6, 0x2222, 0x2192, 0x2108, 0x2082, 0x2000,
+ 0x1f81, 0x1f07, 0x1e91, 0x1e1e, 0x1dae, 0x1d41, 0x1cd8, 0x1c71, 0x1c0e, 0x1bac, 0x1b4e, 0x1af2, 0x1a98, 0x1a41, 0x19ec, 0x1999,
+ 0x1948, 0x18f9, 0x18ac, 0x1861, 0x1818, 0x17d0, 0x178a, 0x1745, 0x1702, 0x16c1, 0x1681, 0x1642, 0x1605, 0x15c9, 0x158e, 0x1555,
+ 0x151d, 0x14e5, 0x14af, 0x147a, 0x1446, 0x1414, 0x13e2, 0x13b1, 0x1381, 0x1352, 0x1323, 0x12f6, 0x12c9, 0x129e, 0x1273, 0x1249,
+ 0x121f, 0x11f7, 0x11cf, 0x11a7, 0x1181, 0x115b, 0x1135, 0x1111, 0x10ec, 0x10c9, 0x10a6, 0x1084, 0x1062, 0x1041, 0x1020, 0x1000,
+ 0x0fe0, 0x0fc0, 0x0fa2, 0x0f83, 0x0f66, 0x0f48, 0x0f2b, 0x0f0f, 0x0ef2, 0x0ed7, 0x0ebb, 0x0ea0, 0x0e86, 0x0e6c, 0x0e52, 0x0e38,
+ 0x0e1f, 0x0e07, 0x0dee, 0x0dd6, 0x0dbe, 0x0da7, 0x0d90, 0x0d79, 0x0d62, 0x0d4c, 0x0d36, 0x0d20, 0x0d0b, 0x0cf6, 0x0ce1, 0x0ccc,
+ 0x0cb8, 0x0ca4, 0x0c90, 0x0c7c, 0x0c69, 0x0c56, 0x0c43, 0x0c30, 0x0c1e, 0x0c0c, 0x0bfa, 0x0be8, 0x0bd6, 0x0bc5, 0x0bb3, 0x0ba2,
+ 0x0b92, 0x0b81, 0x0b70, 0x0b60, 0x0b50, 0x0b40, 0x0b30, 0x0b21, 0x0b11, 0x0b02, 0x0af3, 0x0ae4, 0x0ad6, 0x0ac7, 0x0ab8, 0x0aaa,
+ 0x0a9c, 0x0a8e, 0x0a80, 0x0a72, 0x0a65, 0x0a57, 0x0a4a, 0x0a3d, 0x0a30, 0x0a23, 0x0a16, 0x0a0a, 0x09fd, 0x09f1, 0x09e4, 0x09d8,
+ 0x09cc, 0x09c0, 0x09b4, 0x09a9, 0x099d, 0x0991, 0x0986, 0x097b, 0x0970, 0x0964, 0x095a, 0x094f, 0x0944, 0x0939, 0x092f, 0x0924,
+ 0x091a, 0x090f, 0x0905, 0x08fb, 0x08f1, 0x08e7, 0x08dd, 0x08d3, 0x08ca, 0x08c0, 0x08b7, 0x08ad, 0x08a4, 0x089a, 0x0891, 0x0888,
+ 0x087f, 0x0876, 0x086d, 0x0864, 0x085b, 0x0853, 0x084a, 0x0842, 0x0839, 0x0831, 0x0828, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800,
+};
+
+static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src )
+{
+#ifdef __SSE4_1__
+ __m128i px0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i px1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i px2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i px3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i smask = _mm_set1_epi32( 0xF8FCF8 );
+ __m128i sd0 = _mm_and_si128( px0, smask );
+ __m128i sd1 = _mm_and_si128( px1, smask );
+ __m128i sd2 = _mm_and_si128( px2, smask );
+ __m128i sd3 = _mm_and_si128( px3, smask );
+
+ __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i sc0 = _mm_cmpeq_epi8(sd0, sc);
+ __m128i sc1 = _mm_cmpeq_epi8(sd1, sc);
+ __m128i sc2 = _mm_cmpeq_epi8(sd2, sc);
+ __m128i sc3 = _mm_cmpeq_epi8(sd3, sc);
+
+ __m128i sm0 = _mm_and_si128(sc0, sc1);
+ __m128i sm1 = _mm_and_si128(sc2, sc3);
+ __m128i sm = _mm_and_si128(sm0, sm1);
+
+ if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) )
+ {
+ uint32_t c;
+ memcpy( &c, src, 4 );
+ return uint64_t( to565( c ) ) << 16;
+ }
+
+ __m128i min0 = _mm_min_epu8( px0, px1 );
+ __m128i min1 = _mm_min_epu8( px2, px3 );
+ __m128i min2 = _mm_min_epu8( min0, min1 );
+
+ __m128i max0 = _mm_max_epu8( px0, px1 );
+ __m128i max1 = _mm_max_epu8( px2, px3 );
+ __m128i max2 = _mm_max_epu8( max0, max1 );
+
+ __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i min4 = _mm_min_epu8( min2, min3 );
+ __m128i max4 = _mm_max_epu8( max2, max3 );
+
+ __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i rmin = _mm_min_epu8( min4, min5 );
+ __m128i rmax = _mm_max_epu8( max4, max5 );
+
+ __m128i range1 = _mm_subs_epu8( rmax, rmin );
+ __m128i range2 = _mm_sad_epu8( rmax, rmin );
+
+ uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1;
+ __m128i range = _mm_set1_epi16( DivTable[vrange] );
+
+ __m128i inset1 = _mm_srli_epi16( range1, 4 );
+ __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) );
+ __m128i min = _mm_adds_epu8( rmin, inset );
+ __m128i max = _mm_subs_epu8( rmax, inset );
+
+ __m128i c0 = _mm_subs_epu8( px0, rmin );
+ __m128i c1 = _mm_subs_epu8( px1, rmin );
+ __m128i c2 = _mm_subs_epu8( px2, rmin );
+ __m128i c3 = _mm_subs_epu8( px3, rmin );
+
+ __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) );
+ __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) );
+ __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) );
+ __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) );
+
+ __m128i s0 = _mm_hadd_epi16( is0, is1 );
+ __m128i s1 = _mm_hadd_epi16( is2, is3 );
+
+ __m128i m0 = _mm_mulhi_epu16( s0, range );
+ __m128i m1 = _mm_mulhi_epu16( s1, range );
+
+ __m128i p0 = _mm_packus_epi16( m0, m1 );
+
+ __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) );
+ __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 );
+ __m128i p3 = _mm_or_si128( p1, p2 );
+ __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) );
+
+ uint32_t vmin = _mm_cvtsi128_si32( min );
+ uint32_t vmax = _mm_cvtsi128_si32( max );
+ uint32_t vp = _mm_cvtsi128_si32( p );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+#elif defined __ARM_NEON
+# ifdef __aarch64__
+ uint8x16x4_t px = vld4q_u8( src );
+
+ uint8x16_t lr = px.val[0];
+ uint8x16_t lg = px.val[1];
+ uint8x16_t lb = px.val[2];
+
+ uint8_t rmaxr = vmaxvq_u8( lr );
+ uint8_t rmaxg = vmaxvq_u8( lg );
+ uint8_t rmaxb = vmaxvq_u8( lb );
+
+ uint8_t rminr = vminvq_u8( lr );
+ uint8_t rming = vminvq_u8( lg );
+ uint8_t rminb = vminvq_u8( lb );
+
+ int rr = rmaxr - rminr;
+ int rg = rmaxg - rming;
+ int rb = rmaxb - rminb;
+
+ int vrange1 = rr + rg + rb;
+ uint16_t vrange2 = DivTableNEON[vrange1];
+
+ uint8_t insetr = rr >> 4;
+ uint8_t insetg = rg >> 4;
+ uint8_t insetb = rb >> 4;
+
+ uint8_t minr = rminr + insetr;
+ uint8_t ming = rming + insetg;
+ uint8_t minb = rminb + insetb;
+
+ uint8_t maxr = rmaxr - insetr;
+ uint8_t maxg = rmaxg - insetg;
+ uint8_t maxb = rmaxb - insetb;
+
+ uint8x16_t cr = vsubq_u8( lr, vdupq_n_u8( rminr ) );
+ uint8x16_t cg = vsubq_u8( lg, vdupq_n_u8( rming ) );
+ uint8x16_t cb = vsubq_u8( lb, vdupq_n_u8( rminb ) );
+
+ uint16x8_t is0l = vaddl_u8( vget_low_u8( cr ), vget_low_u8( cg ) );
+ uint16x8_t is0h = vaddl_u8( vget_high_u8( cr ), vget_high_u8( cg ) );
+ uint16x8_t is1l = vaddw_u8( is0l, vget_low_u8( cb ) );
+ uint16x8_t is1h = vaddw_u8( is0h, vget_high_u8( cb ) );
+
+ int16x8_t range = vdupq_n_s16( vrange2 );
+ uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1l ), range ) );
+ uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1h ), range ) );
+
+ uint8x8_t p00 = vmovn_u16( m0 );
+ uint8x8_t p01 = vmovn_u16( m1 );
+ uint8x16_t p0 = vcombine_u8( p00, p01 );
+
+ uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );
+ uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );
+ uint32x4_t p3 = vaddq_u32( p1, p2 );
+
+ uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );
+ uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );
+
+ uint32_t vp;
+ vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );
+
+ return uint64_t( ( uint64_t( to565( minr, ming, minb ) ) << 16 ) | to565( maxr, maxg, maxb ) | ( uint64_t( vp ) << 32 ) );
+# else
+ uint32x4_t px0 = vld1q_u32( (uint32_t*)src );
+ uint32x4_t px1 = vld1q_u32( (uint32_t*)src + 4 );
+ uint32x4_t px2 = vld1q_u32( (uint32_t*)src + 8 );
+ uint32x4_t px3 = vld1q_u32( (uint32_t*)src + 12 );
+
+ uint32x4_t smask = vdupq_n_u32( 0xF8FCF8 );
+ uint32x4_t sd0 = vandq_u32( smask, px0 );
+ uint32x4_t sd1 = vandq_u32( smask, px1 );
+ uint32x4_t sd2 = vandq_u32( smask, px2 );
+ uint32x4_t sd3 = vandq_u32( smask, px3 );
+
+ uint32x4_t sc = vdupq_n_u32( sd0[0] );
+
+ uint32x4_t sc0 = vceqq_u32( sd0, sc );
+ uint32x4_t sc1 = vceqq_u32( sd1, sc );
+ uint32x4_t sc2 = vceqq_u32( sd2, sc );
+ uint32x4_t sc3 = vceqq_u32( sd3, sc );
+
+ uint32x4_t sm0 = vandq_u32( sc0, sc1 );
+ uint32x4_t sm1 = vandq_u32( sc2, sc3 );
+ int64x2_t sm = vreinterpretq_s64_u32( vandq_u32( sm0, sm1 ) );
+
+ if( sm[0] == -1 && sm[1] == -1 )
+ {
+ return uint64_t( to565( src[0], src[1], src[2] ) ) << 16;
+ }
+
+ uint32x4_t mask = vdupq_n_u32( 0xFFFFFF );
+ uint8x16_t l0 = vreinterpretq_u8_u32( vandq_u32( mask, px0 ) );
+ uint8x16_t l1 = vreinterpretq_u8_u32( vandq_u32( mask, px1 ) );
+ uint8x16_t l2 = vreinterpretq_u8_u32( vandq_u32( mask, px2 ) );
+ uint8x16_t l3 = vreinterpretq_u8_u32( vandq_u32( mask, px3 ) );
+
+ uint8x16_t min0 = vminq_u8( l0, l1 );
+ uint8x16_t min1 = vminq_u8( l2, l3 );
+ uint8x16_t min2 = vminq_u8( min0, min1 );
+
+ uint8x16_t max0 = vmaxq_u8( l0, l1 );
+ uint8x16_t max1 = vmaxq_u8( l2, l3 );
+ uint8x16_t max2 = vmaxq_u8( max0, max1 );
+
+ uint8x16_t min3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( min2 ) ) );
+ uint8x16_t max3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( max2 ) ) );
+
+ uint8x16_t min4 = vminq_u8( min2, min3 );
+ uint8x16_t max4 = vmaxq_u8( max2, max3 );
+
+ uint8x16_t min5 = vcombine_u8( vget_high_u8( min4 ), vget_low_u8( min4 ) );
+ uint8x16_t max5 = vcombine_u8( vget_high_u8( max4 ), vget_low_u8( max4 ) );
+
+ uint8x16_t rmin = vminq_u8( min4, min5 );
+ uint8x16_t rmax = vmaxq_u8( max4, max5 );
+
+ uint8x16_t range1 = vsubq_u8( rmax, rmin );
+ uint8x8_t range2 = vget_low_u8( range1 );
+ uint8x8x2_t range3 = vzip_u8( range2, vdup_n_u8( 0 ) );
+ uint16x4_t range4 = vreinterpret_u16_u8( range3.val[0] );
+
+ uint16_t vrange1;
+ uint16x4_t range5 = vpadd_u16( range4, range4 );
+ uint16x4_t range6 = vpadd_u16( range5, range5 );
+ vst1_lane_u16( &vrange1, range6, 0 );
+
+ uint32_t vrange2 = ( 2 << 16 ) / uint32_t( vrange1 + 1 );
+ uint16x8_t range = vdupq_n_u16( vrange2 );
+
+ uint8x16_t inset = vshrq_n_u8( range1, 4 );
+ uint8x16_t min = vaddq_u8( rmin, inset );
+ uint8x16_t max = vsubq_u8( rmax, inset );
+
+ uint8x16_t c0 = vsubq_u8( l0, rmin );
+ uint8x16_t c1 = vsubq_u8( l1, rmin );
+ uint8x16_t c2 = vsubq_u8( l2, rmin );
+ uint8x16_t c3 = vsubq_u8( l3, rmin );
+
+ uint16x8_t is0 = vpaddlq_u8( c0 );
+ uint16x8_t is1 = vpaddlq_u8( c1 );
+ uint16x8_t is2 = vpaddlq_u8( c2 );
+ uint16x8_t is3 = vpaddlq_u8( c3 );
+
+ uint16x4_t is4 = vpadd_u16( vget_low_u16( is0 ), vget_high_u16( is0 ) );
+ uint16x4_t is5 = vpadd_u16( vget_low_u16( is1 ), vget_high_u16( is1 ) );
+ uint16x4_t is6 = vpadd_u16( vget_low_u16( is2 ), vget_high_u16( is2 ) );
+ uint16x4_t is7 = vpadd_u16( vget_low_u16( is3 ), vget_high_u16( is3 ) );
+
+ uint16x8_t s0 = vcombine_u16( is4, is5 );
+ uint16x8_t s1 = vcombine_u16( is6, is7 );
+
+ uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s0 ), vreinterpretq_s16_u16( range ) ) );
+ uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s1 ), vreinterpretq_s16_u16( range ) ) );
+
+ uint8x8_t p00 = vmovn_u16( m0 );
+ uint8x8_t p01 = vmovn_u16( m1 );
+ uint8x16_t p0 = vcombine_u8( p00, p01 );
+
+ uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );
+ uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );
+ uint32x4_t p3 = vaddq_u32( p1, p2 );
+
+ uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );
+ uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );
+
+ uint32_t vmin, vmax, vp;
+ vst1q_lane_u32( &vmin, vreinterpretq_u32_u8( min ), 0 );
+ vst1q_lane_u32( &vmax, vreinterpretq_u32_u8( max ), 0 );
+ vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+# endif
+#else
+ uint32_t ref;
+ memcpy( &ref, src, 4 );
+ uint32_t refMask = ref & 0xF8FCF8;
+ auto stmp = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ uint32_t px;
+ memcpy( &px, stmp, 4 );
+ if( ( px & 0xF8FCF8 ) != refMask ) break;
+ stmp += 4;
+ }
+ if( stmp == src + 64 )
+ {
+ return uint64_t( to565( ref ) ) << 16;
+ }
+
+ uint8_t min[3] = { src[0], src[1], src[2] };
+ uint8_t max[3] = { src[0], src[1], src[2] };
+ auto tmp = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ for( int j=0; j<3; j++ )
+ {
+ if( tmp[j] < min[j] ) min[j] = tmp[j];
+ else if( tmp[j] > max[j] ) max[j] = tmp[j];
+ }
+ tmp += 4;
+ }
+
+ const uint32_t range = DivTable[max[0] - min[0] + max[1] - min[1] + max[2] - min[2]];
+ const uint32_t rmin = min[0] + min[1] + min[2];
+ for( int i=0; i<3; i++ )
+ {
+ const uint8_t inset = ( max[i] - min[i] ) >> 4;
+ min[i] += inset;
+ max[i] -= inset;
+ }
+
+ uint32_t data = 0;
+ for( int i=0; i<16; i++ )
+ {
+ const uint32_t c = src[0] + src[1] + src[2] - rmin;
+ const uint8_t idx = ( c * range ) >> 16;
+ data |= idx << (i*2);
+ src += 4;
+ }
+
+ return uint64_t( ( uint64_t( to565( min[0], min[1], min[2] ) ) << 16 ) | to565( max[0], max[1], max[2] ) | ( uint64_t( data ) << 32 ) );
+#endif
+}
+
+#ifdef __AVX2__
+static etcpak_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst )
+{
+ __m256i px0 = _mm256_loadu_si256(((__m256i*)src) + 0);
+ __m256i px1 = _mm256_loadu_si256(((__m256i*)src) + 1);
+ __m256i px2 = _mm256_loadu_si256(((__m256i*)src) + 2);
+ __m256i px3 = _mm256_loadu_si256(((__m256i*)src) + 3);
+
+ __m256i smask = _mm256_set1_epi32( 0xF8FCF8 );
+ __m256i sd0 = _mm256_and_si256( px0, smask );
+ __m256i sd1 = _mm256_and_si256( px1, smask );
+ __m256i sd2 = _mm256_and_si256( px2, smask );
+ __m256i sd3 = _mm256_and_si256( px3, smask );
+
+ __m256i sc = _mm256_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m256i sc0 = _mm256_cmpeq_epi8(sd0, sc);
+ __m256i sc1 = _mm256_cmpeq_epi8(sd1, sc);
+ __m256i sc2 = _mm256_cmpeq_epi8(sd2, sc);
+ __m256i sc3 = _mm256_cmpeq_epi8(sd3, sc);
+
+ __m256i sm0 = _mm256_and_si256(sc0, sc1);
+ __m256i sm1 = _mm256_and_si256(sc2, sc3);
+ __m256i sm = _mm256_and_si256(sm0, sm1);
+
+ const int64_t solid0 = 1 - _mm_testc_si128( _mm256_castsi256_si128( sm ), _mm_set1_epi32( -1 ) );
+ const int64_t solid1 = 1 - _mm_testc_si128( _mm256_extracti128_si256( sm, 1 ), _mm_set1_epi32( -1 ) );
+
+ if( solid0 + solid1 == 0 )
+ {
+ const auto c0 = uint64_t( to565( src[0], src[1], src[2] ) );
+ const auto c1 = uint64_t( to565( src[16], src[17], src[18] ) );
+ memcpy( dst, &c0, 8 );
+ memcpy( dst+8, &c1, 8 );
+ dst += 16;
+ return;
+ }
+
+ __m256i min0 = _mm256_min_epu8( px0, px1 );
+ __m256i min1 = _mm256_min_epu8( px2, px3 );
+ __m256i min2 = _mm256_min_epu8( min0, min1 );
+
+ __m256i max0 = _mm256_max_epu8( px0, px1 );
+ __m256i max1 = _mm256_max_epu8( px2, px3 );
+ __m256i max2 = _mm256_max_epu8( max0, max1 );
+
+ __m256i min3 = _mm256_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m256i max3 = _mm256_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m256i min4 = _mm256_min_epu8( min2, min3 );
+ __m256i max4 = _mm256_max_epu8( max2, max3 );
+
+ __m256i min5 = _mm256_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m256i max5 = _mm256_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m256i rmin = _mm256_min_epu8( min4, min5 );
+ __m256i rmax = _mm256_max_epu8( max4, max5 );
+
+ __m256i range1 = _mm256_subs_epu8( rmax, rmin );
+ __m256i range2 = _mm256_sad_epu8( rmax, rmin );
+
+ uint16_t vrange0 = DivTable[_mm256_cvtsi256_si32( range2 ) >> 1];
+ uint16_t vrange1 = DivTable[_mm256_extract_epi16( range2, 8 ) >> 1];
+ __m256i range00 = _mm256_set1_epi16( vrange0 );
+ __m256i range = _mm256_inserti128_si256( range00, _mm_set1_epi16( vrange1 ), 1 );
+
+ __m256i inset1 = _mm256_srli_epi16( range1, 4 );
+ __m256i inset = _mm256_and_si256( inset1, _mm256_set1_epi8( 0xF ) );
+ __m256i min = _mm256_adds_epu8( rmin, inset );
+ __m256i max = _mm256_subs_epu8( rmax, inset );
+
+ __m256i c0 = _mm256_subs_epu8( px0, rmin );
+ __m256i c1 = _mm256_subs_epu8( px1, rmin );
+ __m256i c2 = _mm256_subs_epu8( px2, rmin );
+ __m256i c3 = _mm256_subs_epu8( px3, rmin );
+
+ __m256i is0 = _mm256_maddubs_epi16( c0, _mm256_set1_epi8( 1 ) );
+ __m256i is1 = _mm256_maddubs_epi16( c1, _mm256_set1_epi8( 1 ) );
+ __m256i is2 = _mm256_maddubs_epi16( c2, _mm256_set1_epi8( 1 ) );
+ __m256i is3 = _mm256_maddubs_epi16( c3, _mm256_set1_epi8( 1 ) );
+
+ __m256i s0 = _mm256_hadd_epi16( is0, is1 );
+ __m256i s1 = _mm256_hadd_epi16( is2, is3 );
+
+ __m256i m0 = _mm256_mulhi_epu16( s0, range );
+ __m256i m1 = _mm256_mulhi_epu16( s1, range );
+
+ __m256i p0 = _mm256_packus_epi16( m0, m1 );
+
+ __m256i p1 = _mm256_or_si256( _mm256_srai_epi32( p0, 6 ), _mm256_srai_epi32( p0, 12 ) );
+ __m256i p2 = _mm256_or_si256( _mm256_srai_epi32( p0, 18 ), p0 );
+ __m256i p3 = _mm256_or_si256( p1, p2 );
+ __m256i p =_mm256_shuffle_epi8( p3, _mm256_set1_epi32( 0x0C080400 ) );
+
+ __m256i mm0 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), min );
+ __m256i mm1 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), max );
+ __m256i mm2 = _mm256_unpacklo_epi64( mm1, mm0 );
+ __m256i mmr = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 11 ), 11 );
+ __m256i mmg = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 26 ), 5 );
+ __m256i mmb = _mm256_srli_epi64( _mm256_slli_epi64( mm2, 16 ), 59 );
+ __m256i mm3 = _mm256_or_si256( mmr, mmg );
+ __m256i mm4 = _mm256_or_si256( mm3, mmb );
+ __m256i mm5 = _mm256_shuffle_epi8( mm4, _mm256_set1_epi32( 0x09080100 ) );
+
+ __m256i d0 = _mm256_unpacklo_epi32( mm5, p );
+ __m256i d1 = _mm256_permute4x64_epi64( d0, _MM_SHUFFLE( 3, 2, 2, 0 ) );
+ __m128i d2 = _mm256_castsi256_si128( d1 );
+
+ __m128i mask = _mm_set_epi64x( 0xFFFF0000 | -solid1, 0xFFFF0000 | -solid0 );
+ __m128i d3 = _mm_and_si128( d2, mask );
+ _mm_storeu_si128( (__m128i*)dst, d3 );
+
+ for( int j=4; j<8; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]];
+ for( int j=12; j<16; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]];
+
+ dst += 16;
+}
+#endif
+
+static const uint8_t AlphaIndexTable[8] = { 1, 7, 6, 5, 4, 3, 2, 0 };
+
+static etcpak_force_inline uint64_t ProcessAlpha( const uint8_t* src )
+{
+ uint8_t solid8 = *src;
+ uint16_t solid16 = uint16_t( solid8 ) | ( uint16_t( solid8 ) << 8 );
+ uint32_t solid32 = uint32_t( solid16 ) | ( uint32_t( solid16 ) << 16 );
+ uint64_t solid64 = uint64_t( solid32 ) | ( uint64_t( solid32 ) << 32 );
+ if( memcmp( src, &solid64, 8 ) == 0 && memcmp( src+8, &solid64, 8 ) == 0 )
+ {
+ return solid8;
+ }
+
+ uint8_t min = src[0];
+ uint8_t max = min;
+ for( int i=1; i<16; i++ )
+ {
+ const auto v = src[i];
+ if( v > max ) max = v;
+ else if( v < min ) min = v;
+ }
+
+ uint32_t range = ( 8 << 13 ) / ( 1 + max - min );
+ uint64_t data = 0;
+ for( int i=0; i<16; i++ )
+ {
+ uint8_t a = src[i] - min;
+ uint64_t idx = AlphaIndexTable[( a * range ) >> 13];
+ data |= idx << (i*3);
+ }
+
+ return max | ( min << 8 ) | ( data << 16 );
+}
+
+#ifdef __SSE4_1__
+static etcpak_force_inline uint64_t ProcessRGB_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ __m128i smask = _mm_set1_epi32( 0xF8FCF8 );
+ __m128i sd0 = _mm_and_si128( px0, smask );
+ __m128i sd1 = _mm_and_si128( px1, smask );
+ __m128i sd2 = _mm_and_si128( px2, smask );
+ __m128i sd3 = _mm_and_si128( px3, smask );
+
+ __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i sc0 = _mm_cmpeq_epi8(sd0, sc);
+ __m128i sc1 = _mm_cmpeq_epi8(sd1, sc);
+ __m128i sc2 = _mm_cmpeq_epi8(sd2, sc);
+ __m128i sc3 = _mm_cmpeq_epi8(sd3, sc);
+
+ __m128i sm0 = _mm_and_si128(sc0, sc1);
+ __m128i sm1 = _mm_and_si128(sc2, sc3);
+ __m128i sm = _mm_and_si128(sm0, sm1);
+
+ if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) )
+ {
+ return uint64_t( to565( _mm_cvtsi128_si32( px0 ) ) ) << 16;
+ }
+
+ px0 = _mm_and_si128( px0, _mm_set1_epi32( 0xFFFFFF ) );
+ px1 = _mm_and_si128( px1, _mm_set1_epi32( 0xFFFFFF ) );
+ px2 = _mm_and_si128( px2, _mm_set1_epi32( 0xFFFFFF ) );
+ px3 = _mm_and_si128( px3, _mm_set1_epi32( 0xFFFFFF ) );
+
+ __m128i min0 = _mm_min_epu8( px0, px1 );
+ __m128i min1 = _mm_min_epu8( px2, px3 );
+ __m128i min2 = _mm_min_epu8( min0, min1 );
+
+ __m128i max0 = _mm_max_epu8( px0, px1 );
+ __m128i max1 = _mm_max_epu8( px2, px3 );
+ __m128i max2 = _mm_max_epu8( max0, max1 );
+
+ __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i min4 = _mm_min_epu8( min2, min3 );
+ __m128i max4 = _mm_max_epu8( max2, max3 );
+
+ __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i rmin = _mm_min_epu8( min4, min5 );
+ __m128i rmax = _mm_max_epu8( max4, max5 );
+
+ __m128i range1 = _mm_subs_epu8( rmax, rmin );
+ __m128i range2 = _mm_sad_epu8( rmax, rmin );
+
+ uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1;
+ __m128i range = _mm_set1_epi16( DivTable[vrange] );
+
+ __m128i inset1 = _mm_srli_epi16( range1, 4 );
+ __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) );
+ __m128i min = _mm_adds_epu8( rmin, inset );
+ __m128i max = _mm_subs_epu8( rmax, inset );
+
+ __m128i c0 = _mm_subs_epu8( px0, rmin );
+ __m128i c1 = _mm_subs_epu8( px1, rmin );
+ __m128i c2 = _mm_subs_epu8( px2, rmin );
+ __m128i c3 = _mm_subs_epu8( px3, rmin );
+
+ __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) );
+ __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) );
+ __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) );
+ __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) );
+
+ __m128i s0 = _mm_hadd_epi16( is0, is1 );
+ __m128i s1 = _mm_hadd_epi16( is2, is3 );
+
+ __m128i m0 = _mm_mulhi_epu16( s0, range );
+ __m128i m1 = _mm_mulhi_epu16( s1, range );
+
+ __m128i p0 = _mm_packus_epi16( m0, m1 );
+
+ __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) );
+ __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 );
+ __m128i p3 = _mm_or_si128( p1, p2 );
+ __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) );
+
+ uint32_t vmin = _mm_cvtsi128_si32( min );
+ uint32_t vmax = _mm_cvtsi128_si32( max );
+ uint32_t vp = _mm_cvtsi128_si32( p );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+}
+
+static etcpak_force_inline uint64_t ProcessAlpha_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 );
+
+ __m128i m0 = _mm_shuffle_epi8( px0, mask );
+ __m128i m1 = _mm_shuffle_epi8( px1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) );
+ __m128i m2 = _mm_shuffle_epi8( px2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) );
+ __m128i m3 = _mm_shuffle_epi8( px3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) );
+ __m128i m4 = _mm_or_si128( m0, m1 );
+ __m128i m5 = _mm_or_si128( m2, m3 );
+ __m128i a = _mm_or_si128( m4, m5 );
+
+ __m128i solidCmp = _mm_shuffle_epi8( a, _mm_setzero_si128() );
+ __m128i cmpRes = _mm_cmpeq_epi8( a, solidCmp );
+ if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) )
+ {
+ return _mm_cvtsi128_si32( a ) & 0xFF;
+ }
+
+ __m128i a1 = _mm_shuffle_epi32( a, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max1 = _mm_max_epu8( a, a1 );
+ __m128i min1 = _mm_min_epu8( a, a1 );
+ __m128i amax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i amin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max2 = _mm_max_epu8( max1, amax2 );
+ __m128i min2 = _mm_min_epu8( min1, amin2 );
+ __m128i amax3 = _mm_alignr_epi8( max2, max2, 2 );
+ __m128i amin3 = _mm_alignr_epi8( min2, min2, 2 );
+ __m128i max3 = _mm_max_epu8( max2, amax3 );
+ __m128i min3 = _mm_min_epu8( min2, amin3 );
+ __m128i amax4 = _mm_alignr_epi8( max3, max3, 1 );
+ __m128i amin4 = _mm_alignr_epi8( min3, min3, 1 );
+ __m128i max = _mm_max_epu8( max3, amax4 );
+ __m128i min = _mm_min_epu8( min3, amin4 );
+ __m128i minmax = _mm_unpacklo_epi8( max, min );
+
+ __m128i r = _mm_sub_epi8( max, min );
+ int range = _mm_cvtsi128_si32( r ) & 0xFF;
+ __m128i rv = _mm_set1_epi16( DivTableAlpha[range] );
+
+ __m128i v = _mm_sub_epi8( a, min );
+
+ __m128i lo16 = _mm_unpacklo_epi8( v, _mm_setzero_si128() );
+ __m128i hi16 = _mm_unpackhi_epi8( v, _mm_setzero_si128() );
+
+ __m128i lomul = _mm_mulhi_epu16( lo16, rv );
+ __m128i himul = _mm_mulhi_epu16( hi16, rv );
+
+ __m128i p0 = _mm_packus_epi16( lomul, himul );
+ __m128i p1 = _mm_or_si128( _mm_and_si128( p0, _mm_set1_epi16( 0x3F ) ), _mm_srai_epi16( _mm_and_si128( p0, _mm_set1_epi16( 0x3F00 ) ), 5 ) );
+ __m128i p2 = _mm_packus_epi16( p1, p1 );
+
+ uint64_t pi = _mm_cvtsi128_si64( p2 );
+ uint64_t data = 0;
+ for( int i=0; i<8; i++ )
+ {
+ uint64_t idx = AlphaIndexTable_SSE[(pi>>(i*8)) & 0x3F];
+ data |= idx << (i*6);
+ }
+ return (uint64_t)(uint16_t)_mm_cvtsi128_si32( minmax ) | ( data << 16 );
+}
+#endif
+
+void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+#ifdef __AVX2__
+ if( width%8 == 0 )
+ {
+ blocks /= 2;
+ uint32_t buf[8*4];
+ int i = 0;
+ char* dst8 = (char*)dst;
+
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 8*4 );
+ memcpy( tmp + 8*4, src + width * 1, 8*4 );
+ memcpy( tmp + 16*4, src + width * 2, 8*4 );
+ memcpy( tmp + 24*4, src + width * 3, 8*4 );
+ src += 8;
+ if( ++i == width/8 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ ProcessRGB_AVX( (uint8_t*)buf, dst8 );
+ }
+ while( --blocks );
+ }
+ else
+#endif
+ {
+ uint32_t buf[4*4];
+ int i = 0;
+
+ auto ptr = dst;
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ const auto c = ProcessRGB( (uint8_t*)buf );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+ }
+ while( --blocks );
+ }
+}
+
+void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ uint32_t buf[4*4];
+ int i = 0;
+
+ auto ptr = dst;
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ Dither( (uint8_t*)buf );
+
+ const auto c = ProcessRGB( (uint8_t*)buf );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+ }
+ while( --blocks );
+}
+
+void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int i = 0;
+ auto ptr = dst;
+ do
+ {
+#ifdef __SSE4_1__
+ __m128i px0 = _mm_loadu_si128( (__m128i*)( src + width * 0 ) );
+ __m128i px1 = _mm_loadu_si128( (__m128i*)( src + width * 1 ) );
+ __m128i px2 = _mm_loadu_si128( (__m128i*)( src + width * 2 ) );
+ __m128i px3 = _mm_loadu_si128( (__m128i*)( src + width * 3 ) );
+
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ *ptr++ = ProcessAlpha_SSE( px0, px1, px2, px3 );
+
+ const auto c = ProcessRGB_SSE( px0, px1, px2, px3 );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+#else
+ uint32_t rgba[4*4];
+ uint8_t alpha[4*4];
+
+ auto tmp = (char*)rgba;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ for( int i=0; i<16; i++ )
+ {
+ alpha[i] = rgba[i] >> 24;
+ rgba[i] &= 0xFFFFFF;
+ }
+ *ptr++ = ProcessAlpha( alpha );
+
+ const auto c = ProcessRGB( (uint8_t*)rgba );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+#endif
+ }
+ while( --blocks );
+}
diff --git a/thirdparty/etcpak/ProcessDxtc.hpp b/thirdparty/etcpak/ProcessDxtc.hpp
new file mode 100644
index 0000000000..8e0b12e4bd
--- /dev/null
+++ b/thirdparty/etcpak/ProcessDxtc.hpp
@@ -0,0 +1,11 @@
+#ifndef __PROCESSDXT1_HPP__
+#define __PROCESSDXT1_HPP__
+
+#include <stddef.h>
+#include <stdint.h>
+
+void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+
+#endif
diff --git a/thirdparty/etcpak/ProcessRGB.cpp b/thirdparty/etcpak/ProcessRGB.cpp
new file mode 100644
index 0000000000..7f4524d105
--- /dev/null
+++ b/thirdparty/etcpak/ProcessRGB.cpp
@@ -0,0 +1,3100 @@
+#include <array>
+#include <string.h>
+#include <limits>
+
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+#include "Dither.hpp"
+#include "ForceInline.hpp"
+#include "Math.hpp"
+#include "ProcessCommon.hpp"
+#include "ProcessRGB.hpp"
+#include "Tables.hpp"
+#include "Vector.hpp"
+#if defined __SSE4_1__ || defined __AVX2__ || defined _MSC_VER
+# ifdef _MSC_VER
+# include <intrin.h>
+# include <Windows.h>
+# define _bswap(x) _byteswap_ulong(x)
+# define _bswap64(x) _byteswap_uint64(x)
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+#ifndef _bswap
+# define _bswap(x) __builtin_bswap32(x)
+# define _bswap64(x) __builtin_bswap64(x)
+#endif
+
+namespace
+{
+
+#if defined _MSC_VER && !defined __clang__
+static etcpak_force_inline unsigned long _bit_scan_forward( unsigned long mask )
+{
+ unsigned long ret;
+ _BitScanForward( &ret, mask );
+ return ret;
+}
+#endif
+
+typedef std::array<uint16_t, 4> v4i;
+
+#ifdef __AVX2__
+static etcpak_force_inline __m256i Sum4_AVX2( const uint8_t* data) noexcept
+{
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF));
+
+ __m256i t0 = _mm256_cvtepu8_epi16(dm0);
+ __m256i t1 = _mm256_cvtepu8_epi16(dm1);
+ __m256i t2 = _mm256_cvtepu8_epi16(dm2);
+ __m256i t3 = _mm256_cvtepu8_epi16(dm3);
+
+ __m256i sum0 = _mm256_add_epi16(t0, t1);
+ __m256i sum1 = _mm256_add_epi16(t2, t3);
+
+ __m256i s0 = _mm256_permute2x128_si256(sum0, sum1, (0) | (3 << 4)); // 0, 0, 3, 3
+ __m256i s1 = _mm256_permute2x128_si256(sum0, sum1, (1) | (2 << 4)); // 1, 1, 2, 2
+
+ __m256i s2 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(1, 3, 0, 2));
+ __m256i s3 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(0, 2, 1, 3));
+ __m256i s4 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(3, 1, 0, 2));
+ __m256i s5 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(2, 0, 1, 3));
+
+ __m256i sum5 = _mm256_add_epi16(s2, s3); // 3, 0, 3, 0
+ __m256i sum6 = _mm256_add_epi16(s4, s5); // 2, 1, 1, 2
+ return _mm256_add_epi16(sum5, sum6); // 3+2, 0+1, 3+1, 3+2
+}
+
+static etcpak_force_inline __m256i Average_AVX2( const __m256i data) noexcept
+{
+ __m256i a = _mm256_add_epi16(data, _mm256_set1_epi16(4));
+
+ return _mm256_srli_epi16(a, 3);
+}
+
+static etcpak_force_inline __m128i CalcErrorBlock_AVX2( const __m256i data, const v4i a[8]) noexcept
+{
+ //
+ __m256i a0 = _mm256_load_si256((__m256i*)a[0].data());
+ __m256i a1 = _mm256_load_si256((__m256i*)a[4].data());
+
+ // err = 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) );
+ __m256i a4 = _mm256_madd_epi16(a0, a0);
+ __m256i a5 = _mm256_madd_epi16(a1, a1);
+
+ __m256i a6 = _mm256_hadd_epi32(a4, a5);
+ __m256i a7 = _mm256_slli_epi32(a6, 3);
+
+ __m256i a8 = _mm256_add_epi32(a7, _mm256_set1_epi32(0x3FFFFFFF)); // Big value to prevent negative values, but small enough to prevent overflow
+
+ // average is not swapped
+ // err -= block[0] * 2 * average[0];
+ // err -= block[1] * 2 * average[1];
+ // err -= block[2] * 2 * average[2];
+ __m256i a2 = _mm256_slli_epi16(a0, 1);
+ __m256i a3 = _mm256_slli_epi16(a1, 1);
+ __m256i b0 = _mm256_madd_epi16(a2, data);
+ __m256i b1 = _mm256_madd_epi16(a3, data);
+
+ __m256i b2 = _mm256_hadd_epi32(b0, b1);
+ __m256i b3 = _mm256_sub_epi32(a8, b2);
+ __m256i b4 = _mm256_hadd_epi32(b3, b3);
+
+ __m256i b5 = _mm256_permutevar8x32_epi32(b4, _mm256_set_epi32(0, 0, 0, 0, 5, 1, 4, 0));
+
+ return _mm256_castsi256_si128(b5);
+}
+
+static etcpak_force_inline void ProcessAverages_AVX2(const __m256i d, v4i a[8] ) noexcept
+{
+ __m256i t = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(31)), _mm256_set1_epi16(128));
+
+ __m256i c = _mm256_srli_epi16(_mm256_add_epi16(t, _mm256_srli_epi16(t, 8)), 8);
+
+ __m256i c1 = _mm256_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2));
+ __m256i diff = _mm256_sub_epi16(c, c1);
+ diff = _mm256_max_epi16(diff, _mm256_set1_epi16(-4));
+ diff = _mm256_min_epi16(diff, _mm256_set1_epi16(3));
+
+ __m256i co = _mm256_add_epi16(c1, diff);
+
+ c = _mm256_blend_epi16(co, c, 0xF0);
+
+ __m256i a0 = _mm256_or_si256(_mm256_slli_epi16(c, 3), _mm256_srli_epi16(c, 2));
+
+ _mm256_store_si256((__m256i*)a[4].data(), a0);
+
+ __m256i t0 = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(15)), _mm256_set1_epi16(128));
+ __m256i t1 = _mm256_srli_epi16(_mm256_add_epi16(t0, _mm256_srli_epi16(t0, 8)), 8);
+
+ __m256i t2 = _mm256_or_si256(t1, _mm256_slli_epi16(t1, 4));
+
+ _mm256_store_si256((__m256i*)a[0].data(), t2);
+}
+
+static etcpak_force_inline uint64_t EncodeAverages_AVX2( const v4i a[8], size_t idx ) noexcept
+{
+ uint64_t d = ( idx << 24 );
+ size_t base = idx << 1;
+
+ __m128i a0 = _mm_load_si128((const __m128i*)a[base].data());
+
+ __m128i r0, r1;
+
+ if( ( idx & 0x2 ) == 0 )
+ {
+ r0 = _mm_srli_epi16(a0, 4);
+
+ __m128i a1 = _mm_unpackhi_epi64(r0, r0);
+ r1 = _mm_slli_epi16(a1, 4);
+ }
+ else
+ {
+ __m128i a1 = _mm_and_si128(a0, _mm_set1_epi16(-8));
+
+ r0 = _mm_unpackhi_epi64(a1, a1);
+ __m128i a2 = _mm_sub_epi16(a1, r0);
+ __m128i a3 = _mm_srai_epi16(a2, 3);
+ r1 = _mm_and_si128(a3, _mm_set1_epi16(0x07));
+ }
+
+ __m128i r2 = _mm_or_si128(r0, r1);
+ // do missing swap for average values
+ __m128i r3 = _mm_shufflelo_epi16(r2, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128i r4 = _mm_packus_epi16(r3, _mm_setzero_si128());
+ d |= _mm_cvtsi128_si32(r4);
+
+ return d;
+}
+
+static etcpak_force_inline uint64_t CheckSolid_AVX2( const uint8_t* src ) noexcept
+{
+ __m256i d0 = _mm256_loadu_si256(((__m256i*)src) + 0);
+ __m256i d1 = _mm256_loadu_si256(((__m256i*)src) + 1);
+
+ __m256i c = _mm256_broadcastd_epi32(_mm256_castsi256_si128(d0));
+
+ __m256i c0 = _mm256_cmpeq_epi8(d0, c);
+ __m256i c1 = _mm256_cmpeq_epi8(d1, c);
+
+ __m256i m = _mm256_and_si256(c0, c1);
+
+ if (!_mm256_testc_si256(m, _mm256_set1_epi32(-1)))
+ {
+ return 0;
+ }
+
+ return 0x02000000 |
+ ( (unsigned int)( src[0] & 0xF8 ) << 16 ) |
+ ( (unsigned int)( src[1] & 0xF8 ) << 8 ) |
+ ( (unsigned int)( src[2] & 0xF8 ) );
+}
+
+static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const uint8_t* src) noexcept
+{
+ __m256i sum4 = Sum4_AVX2( src );
+
+ ProcessAverages_AVX2(Average_AVX2( sum4 ), a );
+
+ return CalcErrorBlock_AVX2( sum4, a);
+}
+
+static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const __m256i sum4) noexcept
+{
+ ProcessAverages_AVX2(Average_AVX2( sum4 ), a );
+
+ return CalcErrorBlock_AVX2( sum4, a);
+}
+
+static etcpak_force_inline void FindBestFit_4x2_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept
+{
+ __m256i sel0 = _mm256_setzero_si256();
+ __m256i sel1 = _mm256_setzero_si256();
+
+ for (unsigned int j = 0; j < 2; ++j)
+ {
+ unsigned int bid = offset + 1 - j;
+
+ __m256i squareErrorSum = _mm256_setzero_si256();
+
+ __m128i a0 = _mm_loadl_epi64((const __m128i*)a[bid].data());
+ __m256i a1 = _mm256_broadcastq_epi64(a0);
+
+ // Processing one full row each iteration
+ for (size_t i = 0; i < 8; i += 4)
+ {
+ __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4));
+
+ __m256i rgb16 = _mm256_cvtepu8_epi16(rgb);
+ __m256i d = _mm256_sub_epi16(a1, rgb16);
+
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14));
+ __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0);
+ __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1);
+ __m128i pixel3 = _mm256_castsi256_si128(pixel2);
+
+ __m128i pix0 = _mm_broadcastw_epi16(pixel3);
+ __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing first two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ // This produces slightly different results, but is significant faster
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8));
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo2);
+ sel1 = _mm256_or_si256(sel1, minIndexHi2);
+ }
+
+ pixel3 = _mm256_extracti128_si256(pixel2, 1);
+ pix0 = _mm_broadcastw_epi16(pixel3);
+ pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing second two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2);
+ __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2);
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo3);
+ sel1 = _mm256_or_si256(sel1, minIndexHi3);
+ }
+ }
+
+ data += 8 * 4;
+
+ _mm256_store_si256((__m256i*)terr[1 - j], squareErrorSum);
+ }
+
+ // Interleave selector bits
+ __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1);
+ __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1);
+
+ __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4));
+ __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4));
+
+ __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1);
+
+ __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2);
+
+ _mm256_store_si256((__m256i*)tsel, sel);
+}
+
+static etcpak_force_inline void FindBestFit_2x4_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept
+{
+ __m256i sel0 = _mm256_setzero_si256();
+ __m256i sel1 = _mm256_setzero_si256();
+
+ __m256i squareErrorSum0 = _mm256_setzero_si256();
+ __m256i squareErrorSum1 = _mm256_setzero_si256();
+
+ __m128i a0 = _mm_loadl_epi64((const __m128i*)a[offset + 1].data());
+ __m128i a1 = _mm_loadl_epi64((const __m128i*)a[offset + 0].data());
+
+ __m128i a2 = _mm_broadcastq_epi64(a0);
+ __m128i a3 = _mm_broadcastq_epi64(a1);
+ __m256i a4 = _mm256_insertf128_si256(_mm256_castsi128_si256(a2), a3, 1);
+
+ // Processing one full row each iteration
+ for (size_t i = 0; i < 16; i += 4)
+ {
+ __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4));
+
+ __m256i rgb16 = _mm256_cvtepu8_epi16(rgb);
+ __m256i d = _mm256_sub_epi16(a4, rgb16);
+
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14));
+ __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0);
+ __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1);
+ __m128i pixel3 = _mm256_castsi256_si128(pixel2);
+
+ __m128i pix0 = _mm_broadcastw_epi16(pixel3);
+ __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing first two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum0 = _mm256_add_epi32(squareErrorSum0, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i));
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo2);
+ sel1 = _mm256_or_si256(sel1, minIndexHi2);
+ }
+
+ pixel3 = _mm256_extracti128_si256(pixel2, 1);
+ pix0 = _mm_broadcastw_epi16(pixel3);
+ pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing second two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum1 = _mm256_add_epi32(squareErrorSum1, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i));
+ __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2);
+ __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2);
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo3);
+ sel1 = _mm256_or_si256(sel1, minIndexHi3);
+ }
+ }
+
+ _mm256_store_si256((__m256i*)terr[1], squareErrorSum0);
+ _mm256_store_si256((__m256i*)terr[0], squareErrorSum1);
+
+ // Interleave selector bits
+ __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1);
+ __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1);
+
+ __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4));
+ __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4));
+
+ __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1);
+
+ __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2);
+
+ _mm256_store_si256((__m256i*)tsel, sel);
+}
+
+static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate) noexcept
+{
+ size_t tidx[2];
+
+ // Get index of minimum error (terr[0] and terr[1])
+ __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]);
+ __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]);
+
+ __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4));
+ __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4));
+
+ __m256i errMin0 = _mm256_min_epu32(errLo, errHi);
+
+ __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1);
+
+ __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2);
+
+ __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4));
+ __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4));
+
+ __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0);
+ __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1);
+
+ uint32_t mask0 = _mm256_movemask_epi8(errMask0);
+ uint32_t mask1 = _mm256_movemask_epi8(errMask1);
+
+ tidx[0] = _bit_scan_forward(mask0) >> 2;
+ tidx[1] = _bit_scan_forward(mask1) >> 2;
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+
+ unsigned int t0 = tsel[tidx[0]];
+ unsigned int t1 = tsel[tidx[1]];
+
+ if (!rotate)
+ {
+ t0 &= 0xFF00FF00;
+ t1 &= 0x00FF00FF;
+ }
+ else
+ {
+ t0 &= 0xCCCCCCCC;
+ t1 &= 0x33333333;
+ }
+
+ // Flip selectors from sign bit
+ unsigned int t2 = (t0 | t1) ^ 0xFFFF0000;
+
+ return d | static_cast<uint64_t>(_bswap(t2)) << 32;
+}
+
+static etcpak_force_inline __m128i r6g7b6_AVX2(__m128 cof, __m128 chf, __m128 cvf) noexcept
+{
+ __m128i co = _mm_cvttps_epi32(cof);
+ __m128i ch = _mm_cvttps_epi32(chf);
+ __m128i cv = _mm_cvttps_epi32(cvf);
+
+ __m128i coh = _mm_packus_epi32(co, ch);
+ __m128i cv0 = _mm_packus_epi32(cv, _mm_setzero_si128());
+
+ __m256i cohv0 = _mm256_inserti128_si256(_mm256_castsi128_si256(coh), cv0, 1);
+ __m256i cohv1 = _mm256_min_epu16(cohv0, _mm256_set1_epi16(1023));
+
+ __m256i cohv2 = _mm256_sub_epi16(cohv1, _mm256_set1_epi16(15));
+ __m256i cohv3 = _mm256_srai_epi16(cohv2, 1);
+
+ __m256i cohvrb0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(11));
+ __m256i cohvrb1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(4));
+ __m256i cohvg0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(9));
+ __m256i cohvg1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(6));
+
+ __m256i cohvrb2 = _mm256_srai_epi16(cohvrb0, 7);
+ __m256i cohvrb3 = _mm256_srai_epi16(cohvrb1, 7);
+ __m256i cohvg2 = _mm256_srai_epi16(cohvg0, 8);
+ __m256i cohvg3 = _mm256_srai_epi16(cohvg1, 8);
+
+ __m256i cohvrb4 = _mm256_sub_epi16(cohvrb0, cohvrb2);
+ __m256i cohvrb5 = _mm256_sub_epi16(cohvrb4, cohvrb3);
+ __m256i cohvg4 = _mm256_sub_epi16(cohvg0, cohvg2);
+ __m256i cohvg5 = _mm256_sub_epi16(cohvg4, cohvg3);
+
+ __m256i cohvrb6 = _mm256_srai_epi16(cohvrb5, 3);
+ __m256i cohvg6 = _mm256_srai_epi16(cohvg5, 2);
+
+ __m256i cohv4 = _mm256_blend_epi16(cohvg6, cohvrb6, 0x55);
+
+ __m128i cohv5 = _mm_packus_epi16(_mm256_castsi256_si128(cohv4), _mm256_extracti128_si256(cohv4, 1));
+ return _mm_shuffle_epi8(cohv5, _mm_setr_epi8(6, 5, 4, -1, 2, 1, 0, -1, 10, 9, 8, -1, -1, -1, -1, -1));
+}
+
+struct Plane
+{
+ uint64_t plane;
+ uint64_t error;
+ __m256i sum4;
+};
+
+static etcpak_force_inline Plane Planar_AVX2(const uint8_t* src)
+{
+ __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i rgb0 = _mm_shuffle_epi8(d0, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb1 = _mm_shuffle_epi8(d1, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb2 = _mm_shuffle_epi8(d2, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb3 = _mm_shuffle_epi8(d3, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+
+ __m128i rg0 = _mm_unpacklo_epi32(rgb0, rgb1);
+ __m128i rg1 = _mm_unpacklo_epi32(rgb2, rgb3);
+ __m128i b0 = _mm_unpackhi_epi32(rgb0, rgb1);
+ __m128i b1 = _mm_unpackhi_epi32(rgb2, rgb3);
+
+ // swap channels
+ __m128i b8 = _mm_unpacklo_epi64(rg0, rg1);
+ __m128i g8 = _mm_unpackhi_epi64(rg0, rg1);
+ __m128i r8 = _mm_unpacklo_epi64(b0, b1);
+
+ __m128i t0 = _mm_sad_epu8(r8, _mm_setzero_si128());
+ __m128i t1 = _mm_sad_epu8(g8, _mm_setzero_si128());
+ __m128i t2 = _mm_sad_epu8(b8, _mm_setzero_si128());
+
+ __m128i r8s = _mm_shuffle_epi8(r8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+ __m128i g8s = _mm_shuffle_epi8(g8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+ __m128i b8s = _mm_shuffle_epi8(b8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+
+ __m128i s0 = _mm_sad_epu8(r8s, _mm_setzero_si128());
+ __m128i s1 = _mm_sad_epu8(g8s, _mm_setzero_si128());
+ __m128i s2 = _mm_sad_epu8(b8s, _mm_setzero_si128());
+
+ __m256i sr0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t0), s0, 1);
+ __m256i sg0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t1), s1, 1);
+ __m256i sb0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t2), s2, 1);
+
+ __m256i sr1 = _mm256_slli_epi64(sr0, 32);
+ __m256i sg1 = _mm256_slli_epi64(sg0, 16);
+
+ __m256i srb = _mm256_or_si256(sr1, sb0);
+ __m256i srgb = _mm256_or_si256(srb, sg1);
+
+ __m128i t3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(t0), _mm_castsi128_ps(t1), _MM_SHUFFLE(2, 0, 2, 0)));
+ __m128i t4 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3, 1, 2, 0));
+ __m128i t5 = _mm_hadd_epi32(t3, t4);
+ __m128i t6 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(1, 1, 1, 1));
+ __m128i t7 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(2, 2, 2, 2));
+
+ __m256i sr = _mm256_broadcastw_epi16(t5);
+ __m256i sg = _mm256_broadcastw_epi16(t6);
+ __m256i sb = _mm256_broadcastw_epi16(t7);
+
+ __m256i r08 = _mm256_cvtepu8_epi16(r8);
+ __m256i g08 = _mm256_cvtepu8_epi16(g8);
+ __m256i b08 = _mm256_cvtepu8_epi16(b8);
+
+ __m256i r16 = _mm256_slli_epi16(r08, 4);
+ __m256i g16 = _mm256_slli_epi16(g08, 4);
+ __m256i b16 = _mm256_slli_epi16(b08, 4);
+
+ __m256i difR0 = _mm256_sub_epi16(r16, sr);
+ __m256i difG0 = _mm256_sub_epi16(g16, sg);
+ __m256i difB0 = _mm256_sub_epi16(b16, sb);
+
+ __m256i difRyz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+ __m256i difGyz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+ __m256i difByz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+
+ __m256i difRxz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+ __m256i difGxz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+ __m256i difBxz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+
+ __m256i difRGyz = _mm256_hadd_epi32(difRyz, difGyz);
+ __m256i difByzxz = _mm256_hadd_epi32(difByz, difBxz);
+
+ __m256i difRGxz = _mm256_hadd_epi32(difRxz, difGxz);
+
+ __m128i sumRGyz = _mm_add_epi32(_mm256_castsi256_si128(difRGyz), _mm256_extracti128_si256(difRGyz, 1));
+ __m128i sumByzxz = _mm_add_epi32(_mm256_castsi256_si128(difByzxz), _mm256_extracti128_si256(difByzxz, 1));
+ __m128i sumRGxz = _mm_add_epi32(_mm256_castsi256_si128(difRGxz), _mm256_extracti128_si256(difRGxz, 1));
+
+ __m128i sumRGByz = _mm_hadd_epi32(sumRGyz, sumByzxz);
+ __m128i sumRGByzxz = _mm_hadd_epi32(sumRGxz, sumByzxz);
+
+ __m128i sumRGBxz = _mm_shuffle_epi32(sumRGByzxz, _MM_SHUFFLE(2, 3, 1, 0));
+
+ __m128 sumRGByzf = _mm_cvtepi32_ps(sumRGByz);
+ __m128 sumRGBxzf = _mm_cvtepi32_ps(sumRGBxz);
+
+ const float value = (255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f;
+
+ __m128 scale = _mm_set1_ps(-4.0f / value);
+
+ __m128 af = _mm_mul_ps(sumRGBxzf, scale);
+ __m128 bf = _mm_mul_ps(sumRGByzf, scale);
+
+ __m128 df = _mm_mul_ps(_mm_cvtepi32_ps(t5), _mm_set1_ps(4.0f / 16.0f));
+
+ // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
+ __m128 cof0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
+ __m128 chf0 = _mm_fnmadd_ps(af, _mm_set1_ps( 425.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
+ __m128 cvf0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps( 425.0f), df));
+
+ // convert to r6g7b6
+ __m128i cohv = r6g7b6_AVX2(cof0, chf0, cvf0);
+
+ uint64_t rgbho = _mm_extract_epi64(cohv, 0);
+ uint32_t rgbv0 = _mm_extract_epi32(cohv, 2);
+
+ // Error calculation
+ auto ro0 = (rgbho >> 48) & 0x3F;
+ auto go0 = (rgbho >> 40) & 0x7F;
+ auto bo0 = (rgbho >> 32) & 0x3F;
+ auto ro1 = (ro0 >> 4) | (ro0 << 2);
+ auto go1 = (go0 >> 6) | (go0 << 1);
+ auto bo1 = (bo0 >> 4) | (bo0 << 2);
+ auto ro2 = (ro1 << 2) + 2;
+ auto go2 = (go1 << 2) + 2;
+ auto bo2 = (bo1 << 2) + 2;
+
+ __m256i ro3 = _mm256_set1_epi16(ro2);
+ __m256i go3 = _mm256_set1_epi16(go2);
+ __m256i bo3 = _mm256_set1_epi16(bo2);
+
+ auto rh0 = (rgbho >> 16) & 0x3F;
+ auto gh0 = (rgbho >> 8) & 0x7F;
+ auto bh0 = (rgbho >> 0) & 0x3F;
+ auto rh1 = (rh0 >> 4) | (rh0 << 2);
+ auto gh1 = (gh0 >> 6) | (gh0 << 1);
+ auto bh1 = (bh0 >> 4) | (bh0 << 2);
+
+ auto rh2 = rh1 - ro1;
+ auto gh2 = gh1 - go1;
+ auto bh2 = bh1 - bo1;
+
+ __m256i rh3 = _mm256_set1_epi16(rh2);
+ __m256i gh3 = _mm256_set1_epi16(gh2);
+ __m256i bh3 = _mm256_set1_epi16(bh2);
+
+ auto rv0 = (rgbv0 >> 16) & 0x3F;
+ auto gv0 = (rgbv0 >> 8) & 0x7F;
+ auto bv0 = (rgbv0 >> 0) & 0x3F;
+ auto rv1 = (rv0 >> 4) | (rv0 << 2);
+ auto gv1 = (gv0 >> 6) | (gv0 << 1);
+ auto bv1 = (bv0 >> 4) | (bv0 << 2);
+
+ auto rv2 = rv1 - ro1;
+ auto gv2 = gv1 - go1;
+ auto bv2 = bv1 - bo1;
+
+ __m256i rv3 = _mm256_set1_epi16(rv2);
+ __m256i gv3 = _mm256_set1_epi16(gv2);
+ __m256i bv3 = _mm256_set1_epi16(bv2);
+
+ __m256i x = _mm256_set_epi16(3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0);
+
+ __m256i rh4 = _mm256_mullo_epi16(rh3, x);
+ __m256i gh4 = _mm256_mullo_epi16(gh3, x);
+ __m256i bh4 = _mm256_mullo_epi16(bh3, x);
+
+ __m256i y = _mm256_set_epi16(3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0);
+
+ __m256i rv4 = _mm256_mullo_epi16(rv3, y);
+ __m256i gv4 = _mm256_mullo_epi16(gv3, y);
+ __m256i bv4 = _mm256_mullo_epi16(bv3, y);
+
+ __m256i rxy = _mm256_add_epi16(rh4, rv4);
+ __m256i gxy = _mm256_add_epi16(gh4, gv4);
+ __m256i bxy = _mm256_add_epi16(bh4, bv4);
+
+ __m256i rp0 = _mm256_add_epi16(rxy, ro3);
+ __m256i gp0 = _mm256_add_epi16(gxy, go3);
+ __m256i bp0 = _mm256_add_epi16(bxy, bo3);
+
+ __m256i rp1 = _mm256_srai_epi16(rp0, 2);
+ __m256i gp1 = _mm256_srai_epi16(gp0, 2);
+ __m256i bp1 = _mm256_srai_epi16(bp0, 2);
+
+ __m256i rp2 = _mm256_max_epi16(_mm256_min_epi16(rp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+ __m256i gp2 = _mm256_max_epi16(_mm256_min_epi16(gp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+ __m256i bp2 = _mm256_max_epi16(_mm256_min_epi16(bp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+
+ __m256i rdif = _mm256_sub_epi16(r08, rp2);
+ __m256i gdif = _mm256_sub_epi16(g08, gp2);
+ __m256i bdif = _mm256_sub_epi16(b08, bp2);
+
+ __m256i rerr = _mm256_mullo_epi16(rdif, _mm256_set1_epi16(38));
+ __m256i gerr = _mm256_mullo_epi16(gdif, _mm256_set1_epi16(76));
+ __m256i berr = _mm256_mullo_epi16(bdif, _mm256_set1_epi16(14));
+
+ __m256i sum0 = _mm256_add_epi16(rerr, gerr);
+ __m256i sum1 = _mm256_add_epi16(sum0, berr);
+
+ __m256i sum2 = _mm256_madd_epi16(sum1, sum1);
+
+ __m128i sum3 = _mm_add_epi32(_mm256_castsi256_si128(sum2), _mm256_extracti128_si256(sum2, 1));
+
+ uint32_t err0 = _mm_extract_epi32(sum3, 0);
+ uint32_t err1 = _mm_extract_epi32(sum3, 1);
+ uint32_t err2 = _mm_extract_epi32(sum3, 2);
+ uint32_t err3 = _mm_extract_epi32(sum3, 3);
+
+ uint64_t error = err0 + err1 + err2 + err3;
+ /**/
+
+ uint32_t rgbv = ( rgbv0 & 0x3F ) | ( ( rgbv0 >> 2 ) & 0x1FC0 ) | ( ( rgbv0 >> 3 ) & 0x7E000 );
+ uint64_t rgbho0_ = ( rgbho & 0x3F0000003F ) | ( ( rgbho >> 2 ) & 0x1FC000001FC0 ) | ( ( rgbho >> 3 ) & 0x7E0000007E000 );
+ uint64_t rgbho0 = ( rgbho0_ & 0x7FFFF ) | ( ( rgbho0_ >> 13 ) & 0x3FFFF80000 );
+
+ uint32_t hi = rgbv | ((rgbho0 & 0x1FFF) << 19);
+ rgbho0 >>= 13;
+ uint32_t lo = ( rgbho0 & 0x1 ) | ( ( rgbho0 & 0x1FE ) << 1 ) | ( ( rgbho0 & 0x600 ) << 2 ) | ( ( rgbho0 & 0x3F800 ) << 5 ) | ( ( rgbho0 & 0x1FC0000 ) << 6 );
+
+ uint32_t idx = ( ( rgbho >> 33 ) & 0xF ) | ( ( rgbho >> 41 ) & 0x10 ) | ( ( rgbho >> 48 ) & 0x20 );
+ lo |= g_flags[idx];
+ uint64_t result = static_cast<uint32_t>(_bswap(lo));
+ result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32;
+
+ Plane plane;
+
+ plane.plane = result;
+ plane.error = error;
+ plane.sum4 = _mm256_permute4x64_epi64(srgb, _MM_SHUFFLE(2, 3, 0, 1));
+
+ return plane;
+}
+
+static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate, const uint64_t value, const uint32_t error) noexcept
+{
+ size_t tidx[2];
+
+ // Get index of minimum error (terr[0] and terr[1])
+ __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]);
+ __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]);
+
+ __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4));
+ __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4));
+
+ __m256i errMin0 = _mm256_min_epu32(errLo, errHi);
+
+ __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1);
+
+ __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2);
+
+ __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4));
+ __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4));
+
+ __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0);
+ __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1);
+
+ uint32_t mask0 = _mm256_movemask_epi8(errMask0);
+ uint32_t mask1 = _mm256_movemask_epi8(errMask1);
+
+ tidx[0] = _bit_scan_forward(mask0) >> 2;
+ tidx[1] = _bit_scan_forward(mask1) >> 2;
+
+ if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error)
+ {
+ return value;
+ }
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+
+ unsigned int t0 = tsel[tidx[0]];
+ unsigned int t1 = tsel[tidx[1]];
+
+ if (!rotate)
+ {
+ t0 &= 0xFF00FF00;
+ t1 &= 0x00FF00FF;
+ }
+ else
+ {
+ t0 &= 0xCCCCCCCC;
+ t1 &= 0x33333333;
+ }
+
+ // Flip selectors from sign bit
+ unsigned int t2 = (t0 | t1) ^ 0xFFFF0000;
+
+ return d | static_cast<uint64_t>(_bswap(t2)) << 32;
+}
+
+#endif
+
+static etcpak_force_inline void Average( const uint8_t* data, v4i* a )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i d0l = _mm_unpacklo_epi8(d0, _mm_setzero_si128());
+ __m128i d0h = _mm_unpackhi_epi8(d0, _mm_setzero_si128());
+ __m128i d1l = _mm_unpacklo_epi8(d1, _mm_setzero_si128());
+ __m128i d1h = _mm_unpackhi_epi8(d1, _mm_setzero_si128());
+ __m128i d2l = _mm_unpacklo_epi8(d2, _mm_setzero_si128());
+ __m128i d2h = _mm_unpackhi_epi8(d2, _mm_setzero_si128());
+ __m128i d3l = _mm_unpacklo_epi8(d3, _mm_setzero_si128());
+ __m128i d3h = _mm_unpackhi_epi8(d3, _mm_setzero_si128());
+
+ __m128i sum0 = _mm_add_epi16(d0l, d1l);
+ __m128i sum1 = _mm_add_epi16(d0h, d1h);
+ __m128i sum2 = _mm_add_epi16(d2l, d3l);
+ __m128i sum3 = _mm_add_epi16(d2h, d3h);
+
+ __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
+ __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
+ __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
+ __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
+ __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
+ __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
+ __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
+ __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
+
+ __m128i b0 = _mm_add_epi32(sum0l, sum0h);
+ __m128i b1 = _mm_add_epi32(sum1l, sum1h);
+ __m128i b2 = _mm_add_epi32(sum2l, sum2h);
+ __m128i b3 = _mm_add_epi32(sum3l, sum3h);
+
+ __m128i a0 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b2, b3), _mm_set1_epi32(4)), 3);
+ __m128i a1 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b1), _mm_set1_epi32(4)), 3);
+ __m128i a2 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b1, b3), _mm_set1_epi32(4)), 3);
+ __m128i a3 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b2), _mm_set1_epi32(4)), 3);
+
+ _mm_storeu_si128((__m128i*)&a[0], _mm_packus_epi32(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a1, _MM_SHUFFLE(3, 0, 1, 2))));
+ _mm_storeu_si128((__m128i*)&a[2], _mm_packus_epi32(_mm_shuffle_epi32(a2, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a3, _MM_SHUFFLE(3, 0, 1, 2))));
+#elif defined __ARM_NEON
+ uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t());
+ uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t());
+ uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t());
+ uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t());
+
+ uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) };
+ uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) };
+ uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) };
+ uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) };
+
+ uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ) ) ), uint16x8_t());
+ uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ) ) ), uint16x8_t());
+ uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ) ) ), uint16x8_t());
+ uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ) ) ), uint16x8_t());
+
+ uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) };
+ uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) };
+ uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) };
+ uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) };
+
+ uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]);
+ uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]);
+ uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]);
+ uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]);
+
+ uint32x4_t a0 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b2, b3), vdupq_n_u32(4)), 3);
+ uint32x4_t a1 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b1), vdupq_n_u32(4)), 3);
+ uint32x4_t a2 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b1, b3), vdupq_n_u32(4)), 3);
+ uint32x4_t a3 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b2), vdupq_n_u32(4)), 3);
+
+ uint16x8_t o0 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a0 )), vqmovun_s32(vreinterpretq_s32_u32( a1 )));
+ uint16x8_t o1 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a2 )), vqmovun_s32(vreinterpretq_s32_u32( a3 )));
+
+ a[0] = v4i{o0[2], o0[1], o0[0], 0};
+ a[1] = v4i{o0[6], o0[5], o0[4], 0};
+ a[2] = v4i{o1[2], o1[1], o1[0], 0};
+ a[3] = v4i{o1[6], o1[5], o1[4], 0};
+#else
+ uint32_t r[4];
+ uint32_t g[4];
+ uint32_t b[4];
+
+ memset(r, 0, sizeof(r));
+ memset(g, 0, sizeof(g));
+ memset(b, 0, sizeof(b));
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ int index = (j & 2) + (i >> 1);
+ b[index] += *data++;
+ g[index] += *data++;
+ r[index] += *data++;
+ data++;
+ }
+ }
+
+ a[0] = v4i{ uint16_t( (r[2] + r[3] + 4) / 8 ), uint16_t( (g[2] + g[3] + 4) / 8 ), uint16_t( (b[2] + b[3] + 4) / 8 ), 0};
+ a[1] = v4i{ uint16_t( (r[0] + r[1] + 4) / 8 ), uint16_t( (g[0] + g[1] + 4) / 8 ), uint16_t( (b[0] + b[1] + 4) / 8 ), 0};
+ a[2] = v4i{ uint16_t( (r[1] + r[3] + 4) / 8 ), uint16_t( (g[1] + g[3] + 4) / 8 ), uint16_t( (b[1] + b[3] + 4) / 8 ), 0};
+ a[3] = v4i{ uint16_t( (r[0] + r[2] + 4) / 8 ), uint16_t( (g[0] + g[2] + 4) / 8 ), uint16_t( (b[0] + b[2] + 4) / 8 ), 0};
+#endif
+}
+
+static etcpak_force_inline void CalcErrorBlock( const uint8_t* data, unsigned int err[4][4] )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF));
+
+ __m128i d0l = _mm_unpacklo_epi8(dm0, _mm_setzero_si128());
+ __m128i d0h = _mm_unpackhi_epi8(dm0, _mm_setzero_si128());
+ __m128i d1l = _mm_unpacklo_epi8(dm1, _mm_setzero_si128());
+ __m128i d1h = _mm_unpackhi_epi8(dm1, _mm_setzero_si128());
+ __m128i d2l = _mm_unpacklo_epi8(dm2, _mm_setzero_si128());
+ __m128i d2h = _mm_unpackhi_epi8(dm2, _mm_setzero_si128());
+ __m128i d3l = _mm_unpacklo_epi8(dm3, _mm_setzero_si128());
+ __m128i d3h = _mm_unpackhi_epi8(dm3, _mm_setzero_si128());
+
+ __m128i sum0 = _mm_add_epi16(d0l, d1l);
+ __m128i sum1 = _mm_add_epi16(d0h, d1h);
+ __m128i sum2 = _mm_add_epi16(d2l, d3l);
+ __m128i sum3 = _mm_add_epi16(d2h, d3h);
+
+ __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
+ __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
+ __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
+ __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
+ __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
+ __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
+ __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
+ __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
+
+ __m128i b0 = _mm_add_epi32(sum0l, sum0h);
+ __m128i b1 = _mm_add_epi32(sum1l, sum1h);
+ __m128i b2 = _mm_add_epi32(sum2l, sum2h);
+ __m128i b3 = _mm_add_epi32(sum3l, sum3h);
+
+ __m128i a0 = _mm_add_epi32(b2, b3);
+ __m128i a1 = _mm_add_epi32(b0, b1);
+ __m128i a2 = _mm_add_epi32(b1, b3);
+ __m128i a3 = _mm_add_epi32(b0, b2);
+
+ _mm_storeu_si128((__m128i*)&err[0], a0);
+ _mm_storeu_si128((__m128i*)&err[1], a1);
+ _mm_storeu_si128((__m128i*)&err[2], a2);
+ _mm_storeu_si128((__m128i*)&err[3], a3);
+#elif defined __ARM_NEON
+ uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t());
+ uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t());
+ uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t());
+ uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t());
+
+ uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) };
+ uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) };
+ uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) };
+ uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) };
+
+ uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ))), uint16x8_t());
+ uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ))), uint16x8_t());
+ uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ))), uint16x8_t());
+ uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ))), uint16x8_t());
+
+ uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) };
+ uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) };
+ uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) };
+ uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) };
+
+ uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]);
+ uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]);
+ uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]);
+ uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]);
+
+ uint32x4_t a0 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b2, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a1 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b1) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a2 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b1, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a3 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b2) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+
+ vst1q_u32(err[0], a0);
+ vst1q_u32(err[1], a1);
+ vst1q_u32(err[2], a2);
+ vst1q_u32(err[3], a3);
+#else
+ unsigned int terr[4][4];
+
+ memset(terr, 0, 16 * sizeof(unsigned int));
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ int index = (j & 2) + (i >> 1);
+ unsigned int d = *data++;
+ terr[index][0] += d;
+ d = *data++;
+ terr[index][1] += d;
+ d = *data++;
+ terr[index][2] += d;
+ data++;
+ }
+ }
+
+ for( int i=0; i<3; i++ )
+ {
+ err[0][i] = terr[2][i] + terr[3][i];
+ err[1][i] = terr[0][i] + terr[1][i];
+ err[2][i] = terr[1][i] + terr[3][i];
+ err[3][i] = terr[0][i] + terr[2][i];
+ }
+ for( int i=0; i<4; i++ )
+ {
+ err[i][3] = 0;
+ }
+#endif
+}
+
+static etcpak_force_inline unsigned int CalcError( const unsigned int block[4], const v4i& average )
+{
+ unsigned int err = 0x3FFFFFFF; // Big value to prevent negative values, but small enough to prevent overflow
+ err -= block[0] * 2 * average[2];
+ err -= block[1] * 2 * average[1];
+ err -= block[2] * 2 * average[0];
+ err += 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) );
+ return err;
+}
+
+static etcpak_force_inline void ProcessAverages( v4i* a )
+{
+#ifdef __SSE4_1__
+ for( int i=0; i<2; i++ )
+ {
+ __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data());
+
+ __m128i t = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(31)), _mm_set1_epi16(128));
+
+ __m128i c = _mm_srli_epi16(_mm_add_epi16(t, _mm_srli_epi16(t, 8)), 8);
+
+ __m128i c1 = _mm_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2));
+ __m128i diff = _mm_sub_epi16(c, c1);
+ diff = _mm_max_epi16(diff, _mm_set1_epi16(-4));
+ diff = _mm_min_epi16(diff, _mm_set1_epi16(3));
+
+ __m128i co = _mm_add_epi16(c1, diff);
+
+ c = _mm_blend_epi16(co, c, 0xF0);
+
+ __m128i a0 = _mm_or_si128(_mm_slli_epi16(c, 3), _mm_srli_epi16(c, 2));
+
+ _mm_storeu_si128((__m128i*)a[4+i*2].data(), a0);
+ }
+
+ for( int i=0; i<2; i++ )
+ {
+ __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data());
+
+ __m128i t0 = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(15)), _mm_set1_epi16(128));
+ __m128i t1 = _mm_srli_epi16(_mm_add_epi16(t0, _mm_srli_epi16(t0, 8)), 8);
+
+ __m128i t2 = _mm_or_si128(t1, _mm_slli_epi16(t1, 4));
+
+ _mm_storeu_si128((__m128i*)a[i*2].data(), t2);
+ }
+#elif defined __ARM_NEON
+ for( int i=0; i<2; i++ )
+ {
+ int16x8_t d = vld1q_s16((int16_t*)&a[i*2]);
+ int16x8_t t = vaddq_s16(vmulq_s16(d, vdupq_n_s16(31)), vdupq_n_s16(128));
+ int16x8_t c = vshrq_n_s16(vaddq_s16(t, vshrq_n_s16(t, 8)), 8);
+
+ int16x8_t c1 = vcombine_s16(vget_high_s16(c), vget_high_s16(c));
+ int16x8_t diff = vsubq_s16(c, c1);
+ diff = vmaxq_s16(diff, vdupq_n_s16(-4));
+ diff = vminq_s16(diff, vdupq_n_s16(3));
+
+ int16x8_t co = vaddq_s16(c1, diff);
+
+ c = vcombine_s16(vget_low_s16(co), vget_high_s16(c));
+
+ int16x8_t a0 = vorrq_s16(vshlq_n_s16(c, 3), vshrq_n_s16(c, 2));
+
+ vst1q_s16((int16_t*)&a[4+i*2], a0);
+ }
+
+ for( int i=0; i<2; i++ )
+ {
+ int16x8_t d = vld1q_s16((int16_t*)&a[i*2]);
+
+ int16x8_t t0 = vaddq_s16(vmulq_s16(d, vdupq_n_s16(15)), vdupq_n_s16(128));
+ int16x8_t t1 = vshrq_n_s16(vaddq_s16(t0, vshrq_n_s16(t0, 8)), 8);
+
+ int16x8_t t2 = vorrq_s16(t1, vshlq_n_s16(t1, 4));
+
+ vst1q_s16((int16_t*)&a[i*2], t2);
+ }
+#else
+ for( int i=0; i<2; i++ )
+ {
+ for( int j=0; j<3; j++ )
+ {
+ int32_t c1 = mul8bit( a[i*2+1][j], 31 );
+ int32_t c2 = mul8bit( a[i*2][j], 31 );
+
+ int32_t diff = c2 - c1;
+ if( diff > 3 ) diff = 3;
+ else if( diff < -4 ) diff = -4;
+
+ int32_t co = c1 + diff;
+
+ a[5+i*2][j] = ( c1 << 3 ) | ( c1 >> 2 );
+ a[4+i*2][j] = ( co << 3 ) | ( co >> 2 );
+ }
+ }
+
+ for( int i=0; i<4; i++ )
+ {
+ a[i][0] = g_avg2[mul8bit( a[i][0], 15 )];
+ a[i][1] = g_avg2[mul8bit( a[i][1], 15 )];
+ a[i][2] = g_avg2[mul8bit( a[i][2], 15 )];
+ }
+#endif
+}
+
+static etcpak_force_inline void EncodeAverages( uint64_t& _d, const v4i* a, size_t idx )
+{
+ auto d = _d;
+ d |= ( idx << 24 );
+ size_t base = idx << 1;
+
+ if( ( idx & 0x2 ) == 0 )
+ {
+ for( int i=0; i<3; i++ )
+ {
+ d |= uint64_t( a[base+0][i] >> 4 ) << ( i*8 );
+ d |= uint64_t( a[base+1][i] >> 4 ) << ( i*8 + 4 );
+ }
+ }
+ else
+ {
+ for( int i=0; i<3; i++ )
+ {
+ d |= uint64_t( a[base+1][i] & 0xF8 ) << ( i*8 );
+ int32_t c = ( ( a[base+0][i] & 0xF8 ) - ( a[base+1][i] & 0xF8 ) ) >> 3;
+ c &= ~0xFFFFFFF8;
+ d |= ((uint64_t)c) << ( i*8 );
+ }
+ }
+ _d = d;
+}
+
+static etcpak_force_inline uint64_t CheckSolid( const uint8_t* src )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i c = _mm_shuffle_epi32(d0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i c0 = _mm_cmpeq_epi8(d0, c);
+ __m128i c1 = _mm_cmpeq_epi8(d1, c);
+ __m128i c2 = _mm_cmpeq_epi8(d2, c);
+ __m128i c3 = _mm_cmpeq_epi8(d3, c);
+
+ __m128i m0 = _mm_and_si128(c0, c1);
+ __m128i m1 = _mm_and_si128(c2, c3);
+ __m128i m = _mm_and_si128(m0, m1);
+
+ if (!_mm_testc_si128(m, _mm_set1_epi32(-1)))
+ {
+ return 0;
+ }
+#elif defined __ARM_NEON
+ int32x4_t d0 = vld1q_s32((int32_t*)src + 0);
+ int32x4_t d1 = vld1q_s32((int32_t*)src + 4);
+ int32x4_t d2 = vld1q_s32((int32_t*)src + 8);
+ int32x4_t d3 = vld1q_s32((int32_t*)src + 12);
+
+ int32x4_t c = vdupq_n_s32(d0[0]);
+
+ int32x4_t c0 = vreinterpretq_s32_u32(vceqq_s32(d0, c));
+ int32x4_t c1 = vreinterpretq_s32_u32(vceqq_s32(d1, c));
+ int32x4_t c2 = vreinterpretq_s32_u32(vceqq_s32(d2, c));
+ int32x4_t c3 = vreinterpretq_s32_u32(vceqq_s32(d3, c));
+
+ int32x4_t m0 = vandq_s32(c0, c1);
+ int32x4_t m1 = vandq_s32(c2, c3);
+ int64x2_t m = vreinterpretq_s64_s32(vandq_s32(m0, m1));
+
+ if (m[0] != -1 || m[1] != -1)
+ {
+ return 0;
+ }
+#else
+ const uint8_t* ptr = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ if( memcmp( src, ptr, 4 ) != 0 )
+ {
+ return 0;
+ }
+ ptr += 4;
+ }
+#endif
+ return 0x02000000 |
+ ( (unsigned int)( src[0] & 0xF8 ) << 16 ) |
+ ( (unsigned int)( src[1] & 0xF8 ) << 8 ) |
+ ( (unsigned int)( src[2] & 0xF8 ) );
+}
+
+static etcpak_force_inline void PrepareAverages( v4i a[8], const uint8_t* src, unsigned int err[4] )
+{
+ Average( src, a );
+ ProcessAverages( a );
+
+ unsigned int errblock[4][4];
+ CalcErrorBlock( src, errblock );
+
+ for( int i=0; i<4; i++ )
+ {
+ err[i/2] += CalcError( errblock[i], a[i] );
+ err[2+i/2] += CalcError( errblock[i], a[i+4] );
+ }
+}
+
+static etcpak_force_inline void FindBestFit( uint64_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data )
+{
+ for( size_t i=0; i<16; i++ )
+ {
+ uint16_t* sel = tsel[i];
+ unsigned int bid = id[i];
+ uint64_t* ter = terr[bid%2];
+
+ uint8_t b = *data++;
+ uint8_t g = *data++;
+ uint8_t r = *data++;
+ data++;
+
+ int dr = a[bid][0] - r;
+ int dg = a[bid][1] - g;
+ int db = a[bid][2] - b;
+
+#ifdef __SSE4_1__
+ // Reference implementation
+
+ __m128i pix = _mm_set1_epi32(dr * 77 + dg * 151 + db * 28);
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ __m128i error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[0]));
+ __m128i error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[1]));
+ __m128i error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[0]));
+ __m128i error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[1]));
+
+ __m128i index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
+ __m128i minError0 = _mm_min_epi32(error0, error1);
+
+ __m128i index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
+ __m128i minError1 = _mm_min_epi32(error2, error3);
+
+ __m128i minIndex0 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
+ __m128i minError = _mm_min_epi32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ __m128i minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m128i squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
+ squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
+ _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
+ __m128i minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
+ __m128i squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
+ squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
+ _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[2]));
+ error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[3]));
+ error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[2]));
+ error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[3]));
+
+ index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
+ minError0 = _mm_min_epi32(error0, error1);
+
+ index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
+ minError1 = _mm_min_epi32(error2, error3);
+
+ __m128i minIndex1 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
+ minError = _mm_min_epi32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
+ squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 2));
+ _mm_storeu_si128(((__m128i*)ter) + 2, squareErrorLow);
+ minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
+ squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
+ squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 3));
+ _mm_storeu_si128(((__m128i*)ter) + 3, squareErrorHigh);
+ __m128i minIndex = _mm_packs_epi32(minIndex0, minIndex1);
+ _mm_storeu_si128((__m128i*)sel, minIndex);
+#elif defined __ARM_NEON
+ int32x4_t pix = vdupq_n_s32(dr * 77 + dg * 151 + db * 28);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ uint32x4_t error0 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[0])));
+ uint32x4_t error1 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[1])));
+ uint32x4_t error2 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[0])));
+ uint32x4_t error3 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[1])));
+
+ uint32x4_t index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1));
+ uint32x4_t minError0 = vminq_u32(error0, error1);
+
+ uint32x4_t index1 = vreinterpretq_u32_s32(vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2))));
+ uint32x4_t minError1 = vminq_u32(error2, error3);
+
+ uint32x4_t blendMask = vcltq_u32(minError1, minError0);
+ uint32x4_t minIndex0 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask));
+ uint32x4_t minError = vminq_u32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ uint32x4_t squareErrorLow = vmulq_u32(minError, minError);
+ uint32x4_t squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError))), 1);
+ uint32x4x2_t squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh);
+ uint64x2x2_t squareError = { vreinterpretq_u64_u32(squareErrorZip.val[0]), vreinterpretq_u64_u32(squareErrorZip.val[1]) };
+ squareError.val[0] = vaddq_u64(squareError.val[0], vld1q_u64(ter + 0));
+ squareError.val[1] = vaddq_u64(squareError.val[1], vld1q_u64(ter + 2));
+ vst1q_u64(ter + 0, squareError.val[0]);
+ vst1q_u64(ter + 2, squareError.val[1]);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ error0 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[2])));
+ error1 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[3])));
+ error2 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[2])));
+ error3 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[3])));
+
+ index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1));
+ minError0 = vminq_u32(error0, error1);
+
+ index1 = vreinterpretq_u32_s32( vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2))) );
+ minError1 = vminq_u32(error2, error3);
+
+ blendMask = vcltq_u32(minError1, minError0);
+ uint32x4_t minIndex1 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask));
+ minError = vminq_u32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ squareErrorLow = vmulq_u32(minError, minError);
+ squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32( vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError)) ), 1 );
+ squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh);
+ squareError.val[0] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[0] ), vld1q_u64(ter + 4));
+ squareError.val[1] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[1] ), vld1q_u64(ter + 6));
+ vst1q_u64(ter + 4, squareError.val[0]);
+ vst1q_u64(ter + 6, squareError.val[1]);
+
+ uint16x8_t minIndex = vcombine_u16(vqmovn_u32(minIndex0), vqmovn_u32(minIndex1));
+ vst1q_u16(sel, minIndex);
+#else
+ int pix = dr * 77 + dg * 151 + db * 28;
+
+ for( int t=0; t<8; t++ )
+ {
+ const int64_t* tab = g_table256[t];
+ unsigned int idx = 0;
+ uint64_t err = sq( tab[0] + pix );
+ for( int j=1; j<4; j++ )
+ {
+ uint64_t local = sq( tab[j] + pix );
+ if( local < err )
+ {
+ err = local;
+ idx = j;
+ }
+ }
+ *sel++ = idx;
+ *ter++ += err;
+ }
+#endif
+ }
+}
+
+#if defined __SSE4_1__ || defined __ARM_NEON
+// Non-reference implementation, but faster. Produces same results as the AVX2 version
+static etcpak_force_inline void FindBestFit( uint32_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data )
+{
+ for( size_t i=0; i<16; i++ )
+ {
+ uint16_t* sel = tsel[i];
+ unsigned int bid = id[i];
+ uint32_t* ter = terr[bid%2];
+
+ uint8_t b = *data++;
+ uint8_t g = *data++;
+ uint8_t r = *data++;
+ data++;
+
+ int dr = a[bid][0] - r;
+ int dg = a[bid][1] - g;
+ int db = a[bid][2] - b;
+
+#ifdef __SSE4_1__
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m128i pixel = _mm_set1_epi16(dr * 38 + dg * 76 + db * 14);
+ __m128i pix = _mm_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m128i error0 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[0]));
+ __m128i error1 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[1]));
+
+ __m128i index = _mm_and_si128(_mm_cmplt_epi16(error1, error0), _mm_set1_epi16(1));
+ __m128i minError = _mm_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ // This produces slightly different results, but is needed to produce same results as AVX2 implementation
+ __m128i indexBit = _mm_andnot_si128(_mm_srli_epi16(pixel, 15), _mm_set1_epi8(-1));
+ __m128i minIndex = _mm_or_si128(index, _mm_add_epi16(indexBit, indexBit));
+
+ // Squaring the minimum error to produce correct values when adding
+ __m128i squareErrorLo = _mm_mullo_epi16(minError, minError);
+ __m128i squareErrorHi = _mm_mulhi_epi16(minError, minError);
+
+ __m128i squareErrorLow = _mm_unpacklo_epi16(squareErrorLo, squareErrorHi);
+ __m128i squareErrorHigh = _mm_unpackhi_epi16(squareErrorLo, squareErrorHi);
+
+ squareErrorLow = _mm_add_epi32(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
+ _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
+ squareErrorHigh = _mm_add_epi32(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
+ _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
+
+ _mm_storeu_si128((__m128i*)sel, minIndex);
+#elif defined __ARM_NEON
+ int16x8_t pixel = vdupq_n_s16( dr * 38 + dg * 76 + db * 14 );
+ int16x8_t pix = vabsq_s16( pixel );
+
+ int16x8_t error0 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[0] ) );
+ int16x8_t error1 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[1] ) );
+
+ int16x8_t index = vandq_s16( vreinterpretq_s16_u16( vcltq_s16( error1, error0 ) ), vdupq_n_s16( 1 ) );
+ int16x8_t minError = vminq_s16( error0, error1 );
+
+ int16x8_t indexBit = vandq_s16( vmvnq_s16( vshrq_n_s16( pixel, 15 ) ), vdupq_n_s16( -1 ) );
+ int16x8_t minIndex = vorrq_s16( index, vaddq_s16( indexBit, indexBit ) );
+
+ int16x4_t minErrorLow = vget_low_s16( minError );
+ int16x4_t minErrorHigh = vget_high_s16( minError );
+
+ int32x4_t squareErrorLow = vmull_s16( minErrorLow, minErrorLow );
+ int32x4_t squareErrorHigh = vmull_s16( minErrorHigh, minErrorHigh );
+
+ int32x4_t squareErrorSumLow = vaddq_s32( squareErrorLow, vld1q_s32( (int32_t*)ter ) );
+ int32x4_t squareErrorSumHigh = vaddq_s32( squareErrorHigh, vld1q_s32( (int32_t*)ter + 4 ) );
+
+ vst1q_s32( (int32_t*)ter, squareErrorSumLow );
+ vst1q_s32( (int32_t*)ter + 4, squareErrorSumHigh );
+
+ vst1q_s16( (int16_t*)sel, minIndex );
+#endif
+ }
+}
+#endif
+
+static etcpak_force_inline uint8_t convert6(float f)
+{
+ int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
+ return (i + 11 - ((i + 11) >> 7) - ((i + 4) >> 7)) >> 3;
+}
+
+static etcpak_force_inline uint8_t convert7(float f)
+{
+ int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
+ return (i + 9 - ((i + 9) >> 8) - ((i + 6) >> 8)) >> 2;
+}
+
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar(const uint8_t* src)
+{
+ int32_t r = 0;
+ int32_t g = 0;
+ int32_t b = 0;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ b += src[i * 4 + 0];
+ g += src[i * 4 + 1];
+ r += src[i * 4 + 2];
+ }
+
+ int32_t difRyz = 0;
+ int32_t difGyz = 0;
+ int32_t difByz = 0;
+ int32_t difRxz = 0;
+ int32_t difGxz = 0;
+ int32_t difBxz = 0;
+
+ const int32_t scaling[] = { -255, -85, 85, 255 };
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int32_t difB = (static_cast<int>(src[i * 4 + 0]) << 4) - b;
+ int32_t difG = (static_cast<int>(src[i * 4 + 1]) << 4) - g;
+ int32_t difR = (static_cast<int>(src[i * 4 + 2]) << 4) - r;
+
+ difRyz += difR * scaling[i % 4];
+ difGyz += difG * scaling[i % 4];
+ difByz += difB * scaling[i % 4];
+
+ difRxz += difR * scaling[i / 4];
+ difGxz += difG * scaling[i / 4];
+ difBxz += difB * scaling[i / 4];
+ }
+
+ const float scale = -4.0f / ((255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f);
+
+ float aR = difRxz * scale;
+ float aG = difGxz * scale;
+ float aB = difBxz * scale;
+
+ float bR = difRyz * scale;
+ float bG = difGyz * scale;
+ float bB = difByz * scale;
+
+ float dR = r * (4.0f / 16.0f);
+ float dG = g * (4.0f / 16.0f);
+ float dB = b * (4.0f / 16.0f);
+
+ // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
+ float cofR = std::fma(aR, 255.0f, std::fma(bR, 255.0f, dR));
+ float cofG = std::fma(aG, 255.0f, std::fma(bG, 255.0f, dG));
+ float cofB = std::fma(aB, 255.0f, std::fma(bB, 255.0f, dB));
+ float chfR = std::fma(aR, -425.0f, std::fma(bR, 255.0f, dR));
+ float chfG = std::fma(aG, -425.0f, std::fma(bG, 255.0f, dG));
+ float chfB = std::fma(aB, -425.0f, std::fma(bB, 255.0f, dB));
+ float cvfR = std::fma(aR, 255.0f, std::fma(bR, -425.0f, dR));
+ float cvfG = std::fma(aG, 255.0f, std::fma(bG, -425.0f, dG));
+ float cvfB = std::fma(aB, 255.0f, std::fma(bB, -425.0f, dB));
+
+ // convert to r6g7b6
+ int32_t coR = convert6(cofR);
+ int32_t coG = convert7(cofG);
+ int32_t coB = convert6(cofB);
+ int32_t chR = convert6(chfR);
+ int32_t chG = convert7(chfG);
+ int32_t chB = convert6(chfB);
+ int32_t cvR = convert6(cvfR);
+ int32_t cvG = convert7(cvfG);
+ int32_t cvB = convert6(cvfB);
+
+ // Error calculation
+ auto ro0 = coR;
+ auto go0 = coG;
+ auto bo0 = coB;
+ auto ro1 = (ro0 >> 4) | (ro0 << 2);
+ auto go1 = (go0 >> 6) | (go0 << 1);
+ auto bo1 = (bo0 >> 4) | (bo0 << 2);
+ auto ro2 = (ro1 << 2) + 2;
+ auto go2 = (go1 << 2) + 2;
+ auto bo2 = (bo1 << 2) + 2;
+
+ auto rh0 = chR;
+ auto gh0 = chG;
+ auto bh0 = chB;
+ auto rh1 = (rh0 >> 4) | (rh0 << 2);
+ auto gh1 = (gh0 >> 6) | (gh0 << 1);
+ auto bh1 = (bh0 >> 4) | (bh0 << 2);
+
+ auto rh2 = rh1 - ro1;
+ auto gh2 = gh1 - go1;
+ auto bh2 = bh1 - bo1;
+
+ auto rv0 = cvR;
+ auto gv0 = cvG;
+ auto bv0 = cvB;
+ auto rv1 = (rv0 >> 4) | (rv0 << 2);
+ auto gv1 = (gv0 >> 6) | (gv0 << 1);
+ auto bv1 = (bv0 >> 4) | (bv0 << 2);
+
+ auto rv2 = rv1 - ro1;
+ auto gv2 = gv1 - go1;
+ auto bv2 = bv1 - bo1;
+
+ uint64_t error = 0;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int32_t cR = clampu8((rh2 * (i / 4) + rv2 * (i % 4) + ro2) >> 2);
+ int32_t cG = clampu8((gh2 * (i / 4) + gv2 * (i % 4) + go2) >> 2);
+ int32_t cB = clampu8((bh2 * (i / 4) + bv2 * (i % 4) + bo2) >> 2);
+
+ int32_t difB = static_cast<int>(src[i * 4 + 0]) - cB;
+ int32_t difG = static_cast<int>(src[i * 4 + 1]) - cG;
+ int32_t difR = static_cast<int>(src[i * 4 + 2]) - cR;
+
+ int32_t dif = difR * 38 + difG * 76 + difB * 14;
+
+ error += dif * dif;
+ }
+
+ /**/
+ uint32_t rgbv = cvB | (cvG << 6) | (cvR << 13);
+ uint32_t rgbh = chB | (chG << 6) | (chR << 13);
+ uint32_t hi = rgbv | ((rgbh & 0x1FFF) << 19);
+ uint32_t lo = (chR & 0x1) | 0x2 | ((chR << 1) & 0x7C);
+ lo |= ((coB & 0x07) << 7) | ((coB & 0x18) << 8) | ((coB & 0x20) << 11);
+ lo |= ((coG & 0x3F) << 17) | ((coG & 0x40) << 18);
+ lo |= coR << 25;
+
+ const auto idx = (coR & 0x20) | ((coG & 0x20) >> 1) | ((coB & 0x1E) >> 1);
+
+ lo |= g_flags[idx];
+
+ uint64_t result = static_cast<uint32_t>(_bswap(lo));
+ result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32;
+
+ return std::make_pair(result, error);
+}
+
+#ifdef __ARM_NEON
+
+static etcpak_force_inline int32x2_t Planar_NEON_DifXZ( int16x8_t dif_lo, int16x8_t dif_hi )
+{
+ int32x4_t dif0 = vmull_n_s16( vget_low_s16( dif_lo ), -255 );
+ int32x4_t dif1 = vmull_n_s16( vget_high_s16( dif_lo ), -85 );
+ int32x4_t dif2 = vmull_n_s16( vget_low_s16( dif_hi ), 85 );
+ int32x4_t dif3 = vmull_n_s16( vget_high_s16( dif_hi ), 255 );
+ int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) );
+
+#ifndef __aarch64__
+ int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) );
+ return vpadd_s32( dif5, dif5 );
+#else
+ return vdup_n_s32( vaddvq_s32( dif4 ) );
+#endif
+}
+
+static etcpak_force_inline int32x2_t Planar_NEON_DifYZ( int16x8_t dif_lo, int16x8_t dif_hi )
+{
+ int16x4_t scaling = { -255, -85, 85, 255 };
+ int32x4_t dif0 = vmull_s16( vget_low_s16( dif_lo ), scaling );
+ int32x4_t dif1 = vmull_s16( vget_high_s16( dif_lo ), scaling );
+ int32x4_t dif2 = vmull_s16( vget_low_s16( dif_hi ), scaling );
+ int32x4_t dif3 = vmull_s16( vget_high_s16( dif_hi ), scaling );
+ int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) );
+
+#ifndef __aarch64__
+ int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) );
+ return vpadd_s32( dif5, dif5 );
+#else
+ return vdup_n_s32( vaddvq_s32( dif4 ) );
+#endif
+}
+
+static etcpak_force_inline int16x8_t Planar_NEON_SumWide( uint8x16_t src )
+{
+ uint16x8_t accu8 = vpaddlq_u8( src );
+#ifndef __aarch64__
+ uint16x4_t accu4 = vpadd_u16( vget_low_u16( accu8 ), vget_high_u16( accu8 ) );
+ uint16x4_t accu2 = vpadd_u16( accu4, accu4 );
+ uint16x4_t accu1 = vpadd_u16( accu2, accu2 );
+ return vreinterpretq_s16_u16( vcombine_u16( accu1, accu1 ) );
+#else
+ return vdupq_n_s16( vaddvq_u16( accu8 ) );
+#endif
+}
+
+static etcpak_force_inline int16x8_t convert6_NEON( int32x4_t lo, int32x4_t hi )
+{
+ uint16x8_t x = vcombine_u16( vqmovun_s32( lo ), vqmovun_s32( hi ) );
+ int16x8_t i = vreinterpretq_s16_u16( vshrq_n_u16( vqshlq_n_u16( x, 6 ), 6) ); // clamp 0-1023
+ i = vhsubq_s16( i, vdupq_n_s16( 15 ) );
+
+ int16x8_t ip11 = vaddq_s16( i, vdupq_n_s16( 11 ) );
+ int16x8_t ip4 = vaddq_s16( i, vdupq_n_s16( 4 ) );
+
+ return vshrq_n_s16( vsubq_s16( vsubq_s16( ip11, vshrq_n_s16( ip11, 7 ) ), vshrq_n_s16( ip4, 7) ), 3 );
+}
+
+static etcpak_force_inline int16x4_t convert7_NEON( int32x4_t x )
+{
+ int16x4_t i = vreinterpret_s16_u16( vshr_n_u16( vqshl_n_u16( vqmovun_s32( x ), 6 ), 6 ) ); // clamp 0-1023
+ i = vhsub_s16( i, vdup_n_s16( 15 ) );
+
+ int16x4_t p9 = vadd_s16( i, vdup_n_s16( 9 ) );
+ int16x4_t p6 = vadd_s16( i, vdup_n_s16( 6 ) );
+ return vshr_n_s16( vsub_s16( vsub_s16( p9, vshr_n_s16( p9, 8 ) ), vshr_n_s16( p6, 8 ) ), 2 );
+}
+
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint8_t* src )
+{
+ uint8x16x4_t srcBlock = vld4q_u8( src );
+
+ int16x8_t bSumWide = Planar_NEON_SumWide( srcBlock.val[0] );
+ int16x8_t gSumWide = Planar_NEON_SumWide( srcBlock.val[1] );
+ int16x8_t rSumWide = Planar_NEON_SumWide( srcBlock.val[2] );
+
+ int16x8_t dif_R_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[2] ), 4) ), rSumWide );
+ int16x8_t dif_R_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[2] ), 4) ), rSumWide );
+
+ int16x8_t dif_G_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[1] ), 4 ) ), gSumWide );
+ int16x8_t dif_G_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[1] ), 4 ) ), gSumWide );
+
+ int16x8_t dif_B_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[0] ), 4) ), bSumWide );
+ int16x8_t dif_B_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[0] ), 4) ), bSumWide );
+
+ int32x2x2_t dif_xz_z = vzip_s32( vzip_s32( Planar_NEON_DifXZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifXZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifXZ( dif_G_lo, dif_G_hi ) );
+ int32x4_t dif_xz = vcombine_s32( dif_xz_z.val[0], dif_xz_z.val[1] );
+ int32x2x2_t dif_yz_z = vzip_s32( vzip_s32( Planar_NEON_DifYZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifYZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifYZ( dif_G_lo, dif_G_hi ) );
+ int32x4_t dif_yz = vcombine_s32( dif_yz_z.val[0], dif_yz_z.val[1] );
+
+ const float fscale = -4.0f / ( (255 * 255 * 8.0f + 85 * 85 * 8.0f ) * 16.0f );
+ float32x4_t fa = vmulq_n_f32( vcvtq_f32_s32( dif_xz ), fscale );
+ float32x4_t fb = vmulq_n_f32( vcvtq_f32_s32( dif_yz ), fscale );
+ int16x4_t bgrgSum = vzip_s16( vzip_s16( vget_low_s16( bSumWide ), vget_low_s16( rSumWide ) ).val[0], vget_low_s16( gSumWide ) ).val[0];
+ float32x4_t fd = vmulq_n_f32( vcvtq_f32_s32( vmovl_s16( bgrgSum ) ), 4.0f / 16.0f);
+
+ float32x4_t cof = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, 255.0f );
+ float32x4_t chf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, -425.0f );
+ float32x4_t cvf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, -425.0f ), fa, 255.0f );
+
+ int32x4_t coi = vcvtq_s32_f32( cof );
+ int32x4_t chi = vcvtq_s32_f32( chf );
+ int32x4_t cvi = vcvtq_s32_f32( cvf );
+
+ int32x4x2_t tr_hv = vtrnq_s32( chi, cvi );
+ int32x4x2_t tr_o = vtrnq_s32( coi, coi );
+
+ int16x8_t c_hvoo_br_6 = convert6_NEON( tr_hv.val[0], tr_o.val[0] );
+ int16x4_t c_hvox_g_7 = convert7_NEON( vcombine_s32( vget_low_s32( tr_hv.val[1] ), vget_low_s32( tr_o.val[1] ) ) );
+ int16x8_t c_hvoo_br_8 = vorrq_s16( vshrq_n_s16( c_hvoo_br_6, 4 ), vshlq_n_s16( c_hvoo_br_6, 2 ) );
+ int16x4_t c_hvox_g_8 = vorr_s16( vshr_n_s16( c_hvox_g_7, 6 ), vshl_n_s16( c_hvox_g_7, 1 ) );
+
+ int16x4_t rec_gxbr_o = vext_s16( c_hvox_g_8, vget_high_s16( c_hvoo_br_8 ), 3 );
+
+ rec_gxbr_o = vadd_s16( vshl_n_s16( rec_gxbr_o, 2 ), vdup_n_s16( 2 ) );
+ int16x8_t rec_ro_wide = vdupq_lane_s16( rec_gxbr_o, 3 );
+ int16x8_t rec_go_wide = vdupq_lane_s16( rec_gxbr_o, 0 );
+ int16x8_t rec_bo_wide = vdupq_lane_s16( rec_gxbr_o, 1 );
+
+ int16x4_t br_hv2 = vsub_s16( vget_low_s16( c_hvoo_br_8 ), vget_high_s16( c_hvoo_br_8 ) );
+ int16x4_t gg_hv2 = vsub_s16( c_hvox_g_8, vdup_lane_s16( c_hvox_g_8, 2 ) );
+
+ int16x8_t scaleh_lo = { 0, 0, 0, 0, 1, 1, 1, 1 };
+ int16x8_t scaleh_hi = { 2, 2, 2, 2, 3, 3, 3, 3 };
+ int16x8_t scalev = { 0, 1, 2, 3, 0, 1, 2, 3 };
+
+ int16x8_t rec_r_1 = vmlaq_lane_s16( rec_ro_wide, scalev, br_hv2, 3 );
+ int16x8_t rec_r_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_lo, br_hv2, 2 ), 2 ) ) );
+ int16x8_t rec_r_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_hi, br_hv2, 2 ), 2 ) ) );
+
+ int16x8_t rec_b_1 = vmlaq_lane_s16( rec_bo_wide, scalev, br_hv2, 1 );
+ int16x8_t rec_b_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_lo, br_hv2, 0 ), 2 ) ) );
+ int16x8_t rec_b_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_hi, br_hv2, 0 ), 2 ) ) );
+
+ int16x8_t rec_g_1 = vmlaq_lane_s16( rec_go_wide, scalev, gg_hv2, 1 );
+ int16x8_t rec_g_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_lo, gg_hv2, 0 ), 2 ) ) );
+ int16x8_t rec_g_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_hi, gg_hv2, 0 ), 2 ) ) );
+
+ int16x8_t dif_r_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[2] ) ) ), rec_r_lo );
+ int16x8_t dif_r_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[2] ) ) ), rec_r_hi );
+
+ int16x8_t dif_g_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[1] ) ) ), rec_g_lo );
+ int16x8_t dif_g_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[1] ) ) ), rec_g_hi );
+
+ int16x8_t dif_b_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[0] ) ) ), rec_b_lo );
+ int16x8_t dif_b_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[0] ) ) ), rec_b_hi );
+
+ int16x8_t dif_lo = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_lo, 38 ), dif_g_lo, 76 ), dif_b_lo, 14 );
+ int16x8_t dif_hi = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_hi, 38 ), dif_g_hi, 76 ), dif_b_hi, 14 );
+
+ int16x4_t tmpDif = vget_low_s16( dif_lo );
+ int32x4_t difsq_0 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_high_s16( dif_lo );
+ int32x4_t difsq_1 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_low_s16( dif_hi );
+ int32x4_t difsq_2 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_high_s16( dif_hi );
+ int32x4_t difsq_3 = vmull_s16( tmpDif, tmpDif );
+
+ uint32x4_t difsq_5 = vaddq_u32( vreinterpretq_u32_s32( difsq_0 ), vreinterpretq_u32_s32( difsq_1 ) );
+ uint32x4_t difsq_6 = vaddq_u32( vreinterpretq_u32_s32( difsq_2 ), vreinterpretq_u32_s32( difsq_3) );
+
+ uint64x2_t difsq_7 = vaddl_u32( vget_low_u32( difsq_5 ), vget_high_u32( difsq_5 ) );
+ uint64x2_t difsq_8 = vaddl_u32( vget_low_u32( difsq_6 ), vget_high_u32( difsq_6 ) );
+
+ uint64x2_t difsq_9 = vaddq_u64( difsq_7, difsq_8 );
+
+#ifdef __aarch64__
+ uint64_t error = vaddvq_u64( difsq_9 );
+#else
+ uint64_t error = vgetq_lane_u64( difsq_9, 0 ) + vgetq_lane_u64( difsq_9, 1 );
+#endif
+
+ int32_t coR = c_hvoo_br_6[6];
+ int32_t coG = c_hvox_g_7[2];
+ int32_t coB = c_hvoo_br_6[4];
+
+ int32_t chR = c_hvoo_br_6[2];
+ int32_t chG = c_hvox_g_7[0];
+ int32_t chB = c_hvoo_br_6[0];
+
+ int32_t cvR = c_hvoo_br_6[3];
+ int32_t cvG = c_hvox_g_7[1];
+ int32_t cvB = c_hvoo_br_6[1];
+
+ uint32_t rgbv = cvB | ( cvG << 6 ) | ( cvR << 13 );
+ uint32_t rgbh = chB | ( chG << 6 ) | ( chR << 13 );
+ uint32_t hi = rgbv | ( ( rgbh & 0x1FFF ) << 19 );
+ uint32_t lo = ( chR & 0x1 ) | 0x2 | ( ( chR << 1 ) & 0x7C );
+ lo |= ( ( coB & 0x07 ) << 7 ) | ( ( coB & 0x18 ) << 8 ) | ( ( coB & 0x20 ) << 11 );
+ lo |= ( ( coG & 0x3F) << 17) | ( (coG & 0x40 ) << 18 );
+ lo |= coR << 25;
+
+ const auto idx = ( coR & 0x20 ) | ( ( coG & 0x20 ) >> 1 ) | ( ( coB & 0x1E ) >> 1 );
+
+ lo |= g_flags[idx];
+
+ uint64_t result = static_cast<uint32_t>( _bswap(lo) );
+ result |= static_cast<uint64_t>( static_cast<uint32_t>( _bswap( hi ) ) ) << 32;
+
+ return std::make_pair( result, error );
+}
+
+#endif
+
+template<class T, class S>
+static etcpak_force_inline uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id, const uint64_t value, const uint64_t error)
+{
+ size_t tidx[2];
+ tidx[0] = GetLeastError( terr[0], 8 );
+ tidx[1] = GetLeastError( terr[1], 8 );
+
+ if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error)
+ {
+ return value;
+ }
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+ for( int i=0; i<16; i++ )
+ {
+ uint64_t t = tsel[i][tidx[id[i]%2]];
+ d |= ( t & 0x1 ) << ( i + 32 );
+ d |= ( t & 0x2 ) << ( i + 47 );
+ }
+
+ return FixByteOrder(d);
+}
+
+}
+
+static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src )
+{
+#ifdef __AVX2__
+ uint64_t d = CheckSolid_AVX2( src );
+ if( d != 0 ) return d;
+
+ alignas(32) v4i a[8];
+
+ __m128i err0 = PrepareAverages_AVX2( a, src );
+
+ // Get index of minimum error (err0)
+ __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i errMin0 = _mm_min_epu32(err0, err1);
+
+ __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i errMin2 = _mm_min_epu32(errMin1, errMin0);
+
+ __m128i errMask = _mm_cmpeq_epi32(errMin2, err0);
+
+ uint32_t mask = _mm_movemask_epi8(errMask);
+
+ uint32_t idx = _bit_scan_forward(mask) >> 2;
+
+ d |= EncodeAverages_AVX2( a, idx );
+
+ alignas(32) uint32_t terr[2][8] = {};
+ alignas(32) uint32_t tsel[8];
+
+ if ((idx == 0) || (idx == 2))
+ {
+ FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src );
+ }
+ else
+ {
+ FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src );
+ }
+
+ return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1 );
+#else
+ uint64_t d = CheckSolid( src );
+ if( d != 0 ) return d;
+
+ v4i a[8];
+ unsigned int err[4] = {};
+ PrepareAverages( a, src, err );
+ size_t idx = GetLeastError( err, 4 );
+ EncodeAverages( d, a, idx );
+
+#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION
+ uint32_t terr[2][8] = {};
+#else
+ uint64_t terr[2][8] = {};
+#endif
+ uint16_t tsel[16][8];
+ auto id = g_id[idx];
+ FindBestFit( terr, tsel, a, id, src );
+
+ return FixByteOrder( EncodeSelectors( d, terr, tsel, id ) );
+#endif
+}
+
+static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src )
+{
+#ifdef __AVX2__
+ uint64_t d = CheckSolid_AVX2( src );
+ if( d != 0 ) return d;
+
+ auto plane = Planar_AVX2( src );
+
+ alignas(32) v4i a[8];
+
+ __m128i err0 = PrepareAverages_AVX2( a, plane.sum4 );
+
+ // Get index of minimum error (err0)
+ __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i errMin0 = _mm_min_epu32(err0, err1);
+
+ __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i errMin2 = _mm_min_epu32(errMin1, errMin0);
+
+ __m128i errMask = _mm_cmpeq_epi32(errMin2, err0);
+
+ uint32_t mask = _mm_movemask_epi8(errMask);
+
+ size_t idx = _bit_scan_forward(mask) >> 2;
+
+ d = EncodeAverages_AVX2( a, idx );
+
+ alignas(32) uint32_t terr[2][8] = {};
+ alignas(32) uint32_t tsel[8];
+
+ if ((idx == 0) || (idx == 2))
+ {
+ FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src );
+ }
+ else
+ {
+ FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src );
+ }
+
+ return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1, plane.plane, plane.error );
+#else
+ uint64_t d = CheckSolid( src );
+ if (d != 0) return d;
+
+#ifdef __ARM_NEON
+ auto result = Planar_NEON( src );
+#else
+ auto result = Planar( src );
+#endif
+
+ v4i a[8];
+ unsigned int err[4] = {};
+ PrepareAverages( a, src, err );
+ size_t idx = GetLeastError( err, 4 );
+ EncodeAverages( d, a, idx );
+
+#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION
+ uint32_t terr[2][8] = {};
+#else
+ uint64_t terr[2][8] = {};
+#endif
+ uint16_t tsel[16][8];
+ auto id = g_id[idx];
+ FindBestFit( terr, tsel, a, id, src );
+
+ return EncodeSelectors( d, terr, tsel, id, result.first, result.second );
+#endif
+}
+
+#ifdef __SSE4_1__
+template<int K>
+static etcpak_force_inline __m128i Widen( const __m128i src )
+{
+ static_assert( K >= 0 && K <= 7, "Index out of range" );
+
+ __m128i tmp;
+ switch( K )
+ {
+ case 0:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 1:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 2:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 3:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 4:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 5:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 6:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 7:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ }
+}
+
+static etcpak_force_inline int GetMulSel( int sel )
+{
+ switch( sel )
+ {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ return 1;
+ case 4:
+ return 2;
+ case 5:
+ case 6:
+ case 7:
+ return 3;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ return 4;
+ case 14:
+ case 15:
+ return 5;
+ }
+}
+
+#endif
+
+#ifdef __ARM_NEON
+
+static constexpr etcpak_force_inline int GetMulSel(int sel)
+{
+ return ( sel < 1 ) ? 0 : ( sel < 4 ) ? 1 : ( sel < 5 ) ? 2 : ( sel < 8 ) ? 3 : ( sel < 14 ) ? 4 : 5;
+}
+
+static constexpr int ClampConstant( int x, int min, int max )
+{
+ return x < min ? min : x > max ? max : x;
+}
+
+template <int Index>
+etcpak_force_inline static uint16x8_t ErrorProbe_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock )
+{
+ uint8x8_t srcValWide;
+#ifndef __aarch64__
+ if( Index < 8 )
+ srcValWide = vdup_lane_u8( vget_low_u8( alphaBlock ), ClampConstant( Index, 0, 8 ) );
+ else
+ srcValWide = vdup_lane_u8( vget_high_u8( alphaBlock ), ClampConstant( Index - 8, 0, 8 ) );
+#else
+ srcValWide = vdup_laneq_u8( alphaBlock, Index );
+#endif
+
+ uint8x8_t deltaVal = vabd_u8( srcValWide, recVal );
+ return vmull_u8( deltaVal, deltaVal );
+}
+
+etcpak_force_inline static uint16_t MinError_EAC_NEON( uint16x8_t errProbe )
+{
+#ifndef __aarch64__
+ uint16x4_t tmpErr = vpmin_u16( vget_low_u16( errProbe ), vget_high_u16( errProbe ) );
+ tmpErr = vpmin_u16( tmpErr, tmpErr );
+ return vpmin_u16( tmpErr, tmpErr )[0];
+#else
+ return vminvq_u16( errProbe );
+#endif
+}
+
+template <int Index>
+etcpak_force_inline static uint64_t MinErrorIndex_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock )
+{
+ uint16x8_t errProbe = ErrorProbe_EAC_NEON<Index>( recVal, alphaBlock );
+ uint16x8_t minErrMask = vceqq_u16( errProbe, vdupq_n_u16( MinError_EAC_NEON( errProbe ) ) );
+ uint64_t idx = __builtin_ctzll( vget_lane_u64( vreinterpret_u64_u8( vqmovn_u16( minErrMask ) ), 0 ) );
+ idx >>= 3;
+ idx <<= 45 - Index * 3;
+
+ return idx;
+}
+
+template <int Index>
+etcpak_force_inline static int16x8_t WidenMultiplier_EAC_NEON( int16x8_t multipliers )
+{
+ constexpr int Lane = GetMulSel( Index );
+#ifndef __aarch64__
+ if( Lane < 4 )
+ return vdupq_lane_s16( vget_low_s16( multipliers ), ClampConstant( Lane, 0, 4 ) );
+ else
+ return vdupq_lane_s16( vget_high_s16( multipliers ), ClampConstant( Lane - 4, 0, 4 ) );
+#else
+ return vdupq_laneq_s16( multipliers, Lane );
+#endif
+}
+
+#endif
+
+static etcpak_force_inline uint64_t ProcessAlpha_ETC2( const uint8_t* src )
+{
+#if defined __SSE4_1__
+ // Check solid
+ __m128i s = _mm_loadu_si128( (__m128i*)src );
+ __m128i solidCmp = _mm_set1_epi8( src[0] );
+ __m128i cmpRes = _mm_cmpeq_epi8( s, solidCmp );
+ if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) )
+ {
+ return src[0];
+ }
+
+ // Calculate min, max
+ __m128i s1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max1 = _mm_max_epu8( s, s1 );
+ __m128i min1 = _mm_min_epu8( s, s1 );
+ __m128i smax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i smin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max2 = _mm_max_epu8( max1, smax2 );
+ __m128i min2 = _mm_min_epu8( min1, smin2 );
+ __m128i smax3 = _mm_alignr_epi8( max2, max2, 2 );
+ __m128i smin3 = _mm_alignr_epi8( min2, min2, 2 );
+ __m128i max3 = _mm_max_epu8( max2, smax3 );
+ __m128i min3 = _mm_min_epu8( min2, smin3 );
+ __m128i smax4 = _mm_alignr_epi8( max3, max3, 1 );
+ __m128i smin4 = _mm_alignr_epi8( min3, min3, 1 );
+ __m128i max = _mm_max_epu8( max3, smax4 );
+ __m128i min = _mm_min_epu8( min3, smin4 );
+ __m128i max16 = _mm_unpacklo_epi8( max, _mm_setzero_si128() );
+ __m128i min16 = _mm_unpacklo_epi8( min, _mm_setzero_si128() );
+
+ // src range, mid
+ __m128i srcRange = _mm_sub_epi16( max16, min16 );
+ __m128i srcRangeHalf = _mm_srli_epi16( srcRange, 1 );
+ __m128i srcMid = _mm_add_epi16( min16, srcRangeHalf );
+
+ // multiplier
+ __m128i mul1 = _mm_mulhi_epi16( srcRange, g_alphaRange_SIMD );
+ __m128i mul = _mm_add_epi16( mul1, _mm_set1_epi16( 1 ) );
+
+ // wide source
+ __m128i s16_1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 3, 2, 3, 2 ) );
+ __m128i s16[2] = { _mm_unpacklo_epi8( s, _mm_setzero_si128() ), _mm_unpacklo_epi8( s16_1, _mm_setzero_si128() ) };
+
+ __m128i sr[16] = {
+ Widen<0>( s16[0] ),
+ Widen<1>( s16[0] ),
+ Widen<2>( s16[0] ),
+ Widen<3>( s16[0] ),
+ Widen<4>( s16[0] ),
+ Widen<5>( s16[0] ),
+ Widen<6>( s16[0] ),
+ Widen<7>( s16[0] ),
+ Widen<0>( s16[1] ),
+ Widen<1>( s16[1] ),
+ Widen<2>( s16[1] ),
+ Widen<3>( s16[1] ),
+ Widen<4>( s16[1] ),
+ Widen<5>( s16[1] ),
+ Widen<6>( s16[1] ),
+ Widen<7>( s16[1] )
+ };
+
+#ifdef __AVX2__
+ __m256i srcRangeWide = _mm256_broadcastsi128_si256( srcRange );
+ __m256i srcMidWide = _mm256_broadcastsi128_si256( srcMid );
+
+ __m256i mulWide1 = _mm256_mulhi_epi16( srcRangeWide, g_alphaRange_AVX );
+ __m256i mulWide = _mm256_add_epi16( mulWide1, _mm256_set1_epi16( 1 ) );
+
+ __m256i modMul[8] = {
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ) ), _mm256_setzero_si256() ),
+ };
+
+ // find selector
+ __m256i mulErr = _mm256_setzero_si256();
+ for( int j=0; j<16; j++ )
+ {
+ __m256i s16Wide = _mm256_broadcastsi128_si256( sr[j] );
+ __m256i err1, err2;
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[0] );
+ __m256i localErr = _mm256_mullo_epi16( err1, err1 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[1] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[2] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[3] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[4] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[5] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[6] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[7] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ // note that this can overflow, but since we're looking for the smallest error, it shouldn't matter
+ mulErr = _mm256_adds_epu16( mulErr, localErr );
+ }
+ uint64_t minPos1 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_castsi256_si128( mulErr ) ) );
+ uint64_t minPos2 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_extracti128_si256( mulErr, 1 ) ) );
+ int sel = ( ( minPos1 & 0xFFFF ) < ( minPos2 & 0xFFFF ) ) ? ( minPos1 >> 16 ) : ( 8 + ( minPos2 >> 16 ) );
+
+ __m128i recVal16;
+ switch( sel )
+ {
+ case 0:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() );
+ break;
+ case 1:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() );
+ break;
+ case 2:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() );
+ break;
+ case 3:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() );
+ break;
+ case 4:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() );
+ break;
+ case 5:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() );
+ break;
+ case 6:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() );
+ break;
+ case 7:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() );
+ break;
+ case 8:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() );
+ break;
+ case 9:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() );
+ break;
+ case 10:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() );
+ break;
+ case 11:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() );
+ break;
+ case 12:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() );
+ break;
+ case 13:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() );
+ break;
+ case 14:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() );
+ break;
+ case 15:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() );
+ break;
+ default:
+ assert( false );
+ break;
+ }
+#else
+ // wide multiplier
+ __m128i rangeMul[16] = {
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() )
+ };
+
+ // find selector
+ int err = std::numeric_limits<int>::max();
+ int sel;
+ for( int r=0; r<16; r++ )
+ {
+ __m128i err1, err2, minerr;
+ __m128i recVal16 = rangeMul[r];
+ int rangeErr;
+
+ err1 = _mm_sub_epi16( sr[0], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr = _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[1], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[2], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[3], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[4], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[5], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[6], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[7], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[8], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[9], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[10], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[11], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[12], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[13], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[14], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[15], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ if( err == 0 ) break;
+ }
+ }
+
+ __m128i recVal16 = rangeMul[sel];
+#endif
+
+ // find indices
+ __m128i err1, err2, minerr;
+ uint64_t idx = 0, tmp;
+
+ err1 = _mm_sub_epi16( sr[0], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 15*3;
+
+ err1 = _mm_sub_epi16( sr[1], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 14*3;
+
+ err1 = _mm_sub_epi16( sr[2], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 13*3;
+
+ err1 = _mm_sub_epi16( sr[3], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 12*3;
+
+ err1 = _mm_sub_epi16( sr[4], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 11*3;
+
+ err1 = _mm_sub_epi16( sr[5], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 10*3;
+
+ err1 = _mm_sub_epi16( sr[6], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 9*3;
+
+ err1 = _mm_sub_epi16( sr[7], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 8*3;
+
+ err1 = _mm_sub_epi16( sr[8], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 7*3;
+
+ err1 = _mm_sub_epi16( sr[9], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 6*3;
+
+ err1 = _mm_sub_epi16( sr[10], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 5*3;
+
+ err1 = _mm_sub_epi16( sr[11], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 4*3;
+
+ err1 = _mm_sub_epi16( sr[12], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 3*3;
+
+ err1 = _mm_sub_epi16( sr[13], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 2*3;
+
+ err1 = _mm_sub_epi16( sr[14], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 1*3;
+
+ err1 = _mm_sub_epi16( sr[15], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 0*3;
+
+ uint16_t rm[8];
+ _mm_storeu_si128( (__m128i*)rm, mul );
+ uint16_t sm = _mm_cvtsi128_si64( srcMid );
+
+ uint64_t d = ( uint64_t( sm ) << 56 ) |
+ ( uint64_t( rm[GetMulSel( sel )] ) << 52 ) |
+ ( uint64_t( sel ) << 48 ) |
+ idx;
+
+ return _bswap64( d );
+#elif defined __ARM_NEON
+
+ int16x8_t srcMidWide, multipliers;
+ int srcMid;
+ uint8x16_t srcAlphaBlock = vld1q_u8( src );
+ {
+ uint8_t ref = src[0];
+ uint8x16_t a0 = vdupq_n_u8( ref );
+ uint8x16_t r = vceqq_u8( srcAlphaBlock, a0 );
+ int64x2_t m = vreinterpretq_s64_u8( r );
+ if( m[0] == -1 && m[1] == -1 )
+ return ref;
+
+ // srcRange
+#ifdef __aarch64__
+ uint8_t min = vminvq_u8( srcAlphaBlock );
+ uint8_t max = vmaxvq_u8( srcAlphaBlock );
+ uint8_t srcRange = max - min;
+ multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_n_s16( g_alphaRange_NEON, srcRange ), 1 ), vdupq_n_s16( 1 ) );
+ srcMid = min + srcRange / 2;
+ srcMidWide = vdupq_n_s16( srcMid );
+#else
+ uint8x8_t vmin = vpmin_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) );
+ vmin = vpmin_u8( vmin, vmin );
+ vmin = vpmin_u8( vmin, vmin );
+ vmin = vpmin_u8( vmin, vmin );
+ uint8x8_t vmax = vpmax_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) );
+ vmax = vpmax_u8( vmax, vmax );
+ vmax = vpmax_u8( vmax, vmax );
+ vmax = vpmax_u8( vmax, vmax );
+
+ int16x8_t srcRangeWide = vreinterpretq_s16_u16( vsubl_u8( vmax, vmin ) );
+ multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_s16( g_alphaRange_NEON, srcRangeWide ), 1 ), vdupq_n_s16( 1 ) );
+ srcMidWide = vsraq_n_s16( vreinterpretq_s16_u16(vmovl_u8(vmin)), srcRangeWide, 1);
+ srcMid = vgetq_lane_s16( srcMidWide, 0 );
+#endif
+ }
+
+ // calculate reconstructed values
+#define EAC_APPLY_16X( m ) m( 0 ) m( 1 ) m( 2 ) m( 3 ) m( 4 ) m( 5 ) m( 6 ) m( 7 ) m( 8 ) m( 9 ) m( 10 ) m( 11 ) m( 12 ) m( 13 ) m( 14 ) m( 15 )
+
+#define EAC_RECONSTRUCT_VALUE( n ) vqmovun_s16( vmlaq_s16( srcMidWide, g_alpha_NEON[n], WidenMultiplier_EAC_NEON<n>( multipliers ) ) ),
+ uint8x8_t recVals[16] = { EAC_APPLY_16X( EAC_RECONSTRUCT_VALUE ) };
+
+ // find selector
+ int err = std::numeric_limits<int>::max();
+ int sel = 0;
+ for( int r = 0; r < 16; r++ )
+ {
+ uint8x8_t recVal = recVals[r];
+
+ int rangeErr = 0;
+#define EAC_ACCUMULATE_ERROR( n ) rangeErr += MinError_EAC_NEON( ErrorProbe_EAC_NEON<n>( recVal, srcAlphaBlock ) );
+ EAC_APPLY_16X( EAC_ACCUMULATE_ERROR )
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ if ( err == 0 ) break;
+ }
+ }
+
+ // combine results
+ uint64_t d = ( uint64_t( srcMid ) << 56 ) |
+ ( uint64_t( multipliers[GetMulSel( sel )] ) << 52 ) |
+ ( uint64_t( sel ) << 48);
+
+ // generate indices
+ uint8x8_t recVal = recVals[sel];
+#define EAC_INSERT_INDEX(n) d |= MinErrorIndex_EAC_NEON<n>( recVal, srcAlphaBlock );
+ EAC_APPLY_16X( EAC_INSERT_INDEX )
+
+ return _bswap64( d );
+
+#undef EAC_APPLY_16X
+#undef EAC_INSERT_INDEX
+#undef EAC_ACCUMULATE_ERROR
+#undef EAC_RECONSTRUCT_VALUE
+
+#else
+ {
+ bool solid = true;
+ const uint8_t* ptr = src + 1;
+ const uint8_t ref = *src;
+ for( int i=1; i<16; i++ )
+ {
+ if( ref != *ptr++ )
+ {
+ solid = false;
+ break;
+ }
+ }
+ if( solid )
+ {
+ return ref;
+ }
+ }
+
+ uint8_t min = src[0];
+ uint8_t max = src[0];
+ for( int i=1; i<16; i++ )
+ {
+ if( min > src[i] ) min = src[i];
+ else if( max < src[i] ) max = src[i];
+ }
+ int srcRange = max - min;
+ int srcMid = min + srcRange / 2;
+
+ uint8_t buf[16][16];
+ int err = std::numeric_limits<int>::max();
+ int sel;
+ int selmul;
+ for( int r=0; r<16; r++ )
+ {
+ int mul = ( ( srcRange * g_alphaRange[r] ) >> 16 ) + 1;
+
+ int rangeErr = 0;
+ for( int i=0; i<16; i++ )
+ {
+ const auto srcVal = src[i];
+
+ int idx = 0;
+ const auto modVal = g_alpha[r][0] * mul;
+ const auto recVal = clampu8( srcMid + modVal );
+ int localErr = sq( srcVal - recVal );
+
+ if( localErr != 0 )
+ {
+ for( int j=1; j<8; j++ )
+ {
+ const auto modVal = g_alpha[r][j] * mul;
+ const auto recVal = clampu8( srcMid + modVal );
+ const auto errProbe = sq( srcVal - recVal );
+ if( errProbe < localErr )
+ {
+ localErr = errProbe;
+ idx = j;
+ }
+ }
+ }
+
+ buf[r][i] = idx;
+ rangeErr += localErr;
+ }
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ selmul = mul;
+ if( err == 0 ) break;
+ }
+ }
+
+ uint64_t d = ( uint64_t( srcMid ) << 56 ) |
+ ( uint64_t( selmul ) << 52 ) |
+ ( uint64_t( sel ) << 48 );
+
+ int offset = 45;
+ auto ptr = buf[sel];
+ for( int i=0; i<16; i++ )
+ {
+ d |= uint64_t( *ptr++ ) << offset;
+ offset -= 3;
+ }
+
+ return _bswap64( d );
+#endif
+}
+
+
+void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f );
+ __m128i p0 = _mm_shuffle_epi8( c0, mask );
+ __m128i p1 = _mm_shuffle_epi8( c1, mask );
+ __m128i p2 = _mm_shuffle_epi8( c2, mask );
+ __m128i p3 = _mm_shuffle_epi8( c3, mask );
+
+ _mm_store_si128( (__m128i*)(buf + 0), p0 );
+ _mm_store_si128( (__m128i*)(buf + 4), p1 );
+ _mm_store_si128( (__m128i*)(buf + 8), p2 );
+ _mm_store_si128( (__m128i*)(buf + 12), p3 );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ unsigned int a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f );
+ __m128i p0 = _mm_shuffle_epi8( c0, mask );
+ __m128i p1 = _mm_shuffle_epi8( c1, mask );
+ __m128i p2 = _mm_shuffle_epi8( c2, mask );
+ __m128i p3 = _mm_shuffle_epi8( c3, mask );
+
+ _mm_store_si128( (__m128i*)(buf + 0), p0 );
+ _mm_store_si128( (__m128i*)(buf + 4), p1 );
+ _mm_store_si128( (__m128i*)(buf + 8), p2 );
+ _mm_store_si128( (__m128i*)(buf + 12), p3 );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ unsigned int a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+#include <chrono>
+#include <thread>
+
+void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+# ifdef __AVX2__
+ DitherAvx2( (uint8_t*)buf, _mm_castps_si128( px0 ), _mm_castps_si128( px1 ), _mm_castps_si128( px2 ), _mm_castps_si128( px3 ) );
+# else
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ Dither( (uint8_t*)buf );
+# endif
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t rgba[4*4];
+ uint8_t alpha[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ _mm_store_si128( (__m128i*)(rgba + 0), c0 );
+ _mm_store_si128( (__m128i*)(rgba + 4), c1 );
+ _mm_store_si128( (__m128i*)(rgba + 8), c2 );
+ _mm_store_si128( (__m128i*)(rgba + 12), c3 );
+
+ __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 );
+
+ __m128i a0 = _mm_shuffle_epi8( c0, mask );
+ __m128i a1 = _mm_shuffle_epi8( c1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) );
+ __m128i a2 = _mm_shuffle_epi8( c2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) );
+ __m128i a3 = _mm_shuffle_epi8( c3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) );
+
+ __m128i s0 = _mm_or_si128( a0, a1 );
+ __m128i s1 = _mm_or_si128( a2, a3 );
+ __m128i s2 = _mm_or_si128( s0, s1 );
+
+ _mm_store_si128( (__m128i*)alpha, s2 );
+
+ src += 4;
+#else
+ auto ptr = rgba;
+ auto ptr8 = alpha;
+ for( int x=0; x<4; x++ )
+ {
+ auto v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessAlpha_ETC2( alpha );
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)rgba );
+ }
+ while( --blocks );
+}
diff --git a/thirdparty/etcpak/ProcessRGB.hpp b/thirdparty/etcpak/ProcessRGB.hpp
new file mode 100644
index 0000000000..c5555a5bb1
--- /dev/null
+++ b/thirdparty/etcpak/ProcessRGB.hpp
@@ -0,0 +1,13 @@
+#ifndef __PROCESSRGB_HPP__
+#define __PROCESSRGB_HPP__
+
+#include <stdint.h>
+
+void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+
+#endif
diff --git a/thirdparty/etcpak/Semaphore.hpp b/thirdparty/etcpak/Semaphore.hpp
new file mode 100644
index 0000000000..9e42dbb9e0
--- /dev/null
+++ b/thirdparty/etcpak/Semaphore.hpp
@@ -0,0 +1,46 @@
+#ifndef __DARKRL__SEMAPHORE_HPP__
+#define __DARKRL__SEMAPHORE_HPP__
+
+#include <condition_variable>
+#include <mutex>
+
+class Semaphore
+{
+public:
+ Semaphore( int count ) : m_count( count ) {}
+
+ void lock()
+ {
+ std::unique_lock<std::mutex> lock( m_mutex );
+ m_cv.wait( lock, [this](){ return m_count != 0; } );
+ m_count--;
+ }
+
+ void unlock()
+ {
+ std::lock_guard<std::mutex> lock( m_mutex );
+ m_count++;
+ m_cv.notify_one();
+ }
+
+ bool try_lock()
+ {
+ std::lock_guard<std::mutex> lock( m_mutex );
+ if( m_count == 0 )
+ {
+ return false;
+ }
+ else
+ {
+ m_count--;
+ return true;
+ }
+ }
+
+private:
+ std::mutex m_mutex;
+ std::condition_variable m_cv;
+ unsigned int m_count;
+};
+
+#endif
diff --git a/thirdparty/etcpak/System.cpp b/thirdparty/etcpak/System.cpp
new file mode 100644
index 0000000000..a09b289cb2
--- /dev/null
+++ b/thirdparty/etcpak/System.cpp
@@ -0,0 +1,68 @@
+#include <algorithm>
+#ifdef _WIN32
+# include <windows.h>
+#else
+# include <pthread.h>
+# include <unistd.h>
+#endif
+
+#include "System.hpp"
+
+unsigned int System::CPUCores()
+{
+ static unsigned int cores = 0;
+ if( cores == 0 )
+ {
+ int tmp;
+#ifdef _WIN32
+ SYSTEM_INFO info;
+ GetSystemInfo( &info );
+ tmp = (int)info.dwNumberOfProcessors;
+#else
+# ifndef _SC_NPROCESSORS_ONLN
+# ifdef _SC_NPROC_ONLN
+# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
+# elif defined _SC_CRAY_NCPU
+# define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
+# endif
+# endif
+ tmp = (int)(long)sysconf( _SC_NPROCESSORS_ONLN );
+#endif
+ cores = (unsigned int)std::max( tmp, 1 );
+ }
+ return cores;
+}
+
+void System::SetThreadName( std::thread& thread, const char* name )
+{
+#ifdef _MSC_VER
+ const DWORD MS_VC_EXCEPTION=0x406D1388;
+
+# pragma pack( push, 8 )
+ struct THREADNAME_INFO
+ {
+ DWORD dwType;
+ LPCSTR szName;
+ DWORD dwThreadID;
+ DWORD dwFlags;
+ };
+# pragma pack(pop)
+
+ DWORD ThreadId = GetThreadId( static_cast<HANDLE>( thread.native_handle() ) );
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = ThreadId;
+ info.dwFlags = 0;
+
+ __try
+ {
+ RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+#elif !defined(__APPLE__)
+ pthread_setname_np( thread.native_handle(), name );
+#endif
+}
diff --git a/thirdparty/etcpak/System.hpp b/thirdparty/etcpak/System.hpp
new file mode 100644
index 0000000000..1a09bb15e1
--- /dev/null
+++ b/thirdparty/etcpak/System.hpp
@@ -0,0 +1,15 @@
+#ifndef __DARKRL__SYSTEM_HPP__
+#define __DARKRL__SYSTEM_HPP__
+
+#include <thread>
+
+class System
+{
+public:
+ System() = delete;
+
+ static unsigned int CPUCores();
+ static void SetThreadName( std::thread& thread, const char* name );
+};
+
+#endif
diff --git a/thirdparty/etcpak/Tables.cpp b/thirdparty/etcpak/Tables.cpp
new file mode 100644
index 0000000000..5c7fd9cf61
--- /dev/null
+++ b/thirdparty/etcpak/Tables.cpp
@@ -0,0 +1,221 @@
+#include "Tables.hpp"
+
+const int32_t g_table[8][4] = {
+ { 2, 8, -2, -8 },
+ { 5, 17, -5, -17 },
+ { 9, 29, -9, -29 },
+ { 13, 42, -13, -42 },
+ { 18, 60, -18, -60 },
+ { 24, 80, -24, -80 },
+ { 33, 106, -33, -106 },
+ { 47, 183, -47, -183 }
+};
+
+const int64_t g_table256[8][4] = {
+ { 2*256, 8*256, -2*256, -8*256 },
+ { 5*256, 17*256, -5*256, -17*256 },
+ { 9*256, 29*256, -9*256, -29*256 },
+ { 13*256, 42*256, -13*256, -42*256 },
+ { 18*256, 60*256, -18*256, -60*256 },
+ { 24*256, 80*256, -24*256, -80*256 },
+ { 33*256, 106*256, -33*256, -106*256 },
+ { 47*256, 183*256, -47*256, -183*256 }
+};
+
+const uint32_t g_id[4][16] = {
+ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2 },
+ { 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4 },
+ { 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6 }
+};
+
+const uint32_t g_avg2[16] = {
+ 0x00,
+ 0x11,
+ 0x22,
+ 0x33,
+ 0x44,
+ 0x55,
+ 0x66,
+ 0x77,
+ 0x88,
+ 0x99,
+ 0xAA,
+ 0xBB,
+ 0xCC,
+ 0xDD,
+ 0xEE,
+ 0xFF
+};
+
+const uint32_t g_flags[64] = {
+ 0x80800402, 0x80800402, 0x80800402, 0x80800402,
+ 0x80800402, 0x80800402, 0x80800402, 0x8080E002,
+ 0x80800402, 0x80800402, 0x8080E002, 0x8080E002,
+ 0x80800402, 0x8080E002, 0x8080E002, 0x8080E002,
+ 0x80000402, 0x80000402, 0x80000402, 0x80000402,
+ 0x80000402, 0x80000402, 0x80000402, 0x8000E002,
+ 0x80000402, 0x80000402, 0x8000E002, 0x8000E002,
+ 0x80000402, 0x8000E002, 0x8000E002, 0x8000E002,
+ 0x00800402, 0x00800402, 0x00800402, 0x00800402,
+ 0x00800402, 0x00800402, 0x00800402, 0x0080E002,
+ 0x00800402, 0x00800402, 0x0080E002, 0x0080E002,
+ 0x00800402, 0x0080E002, 0x0080E002, 0x0080E002,
+ 0x00000402, 0x00000402, 0x00000402, 0x00000402,
+ 0x00000402, 0x00000402, 0x00000402, 0x0000E002,
+ 0x00000402, 0x00000402, 0x0000E002, 0x0000E002,
+ 0x00000402, 0x0000E002, 0x0000E002, 0x0000E002
+};
+
+const int32_t g_alpha[16][8] = {
+ { -3, -6, -9, -15, 2, 5, 8, 14 },
+ { -3, -7, -10, -13, 2, 6, 9, 12 },
+ { -2, -5, -8, -13, 1, 4, 7, 12 },
+ { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 },
+ { -3, -7, -9, -11, 2, 6, 8, 10 },
+ { -4, -7, -8, -11, 3, 6, 7, 10 },
+ { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 },
+ { -2, -5, -8, -10, 1, 4, 7, 9 },
+ { -2, -4, -8, -10, 1, 3, 7, 9 },
+ { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 },
+ { -1, -2, -3, -10, 0, 1, 2, 9 },
+ { -4, -6, -8, -9, 3, 5, 7, 8 },
+ { -3, -5, -7, -9, 2, 4, 6, 8 }
+};
+
+const int32_t g_alphaRange[16] = {
+ 0x100FF / ( 1 + g_alpha[0][7] - g_alpha[0][3] ),
+ 0x100FF / ( 1 + g_alpha[1][7] - g_alpha[1][3] ),
+ 0x100FF / ( 1 + g_alpha[2][7] - g_alpha[2][3] ),
+ 0x100FF / ( 1 + g_alpha[3][7] - g_alpha[3][3] ),
+ 0x100FF / ( 1 + g_alpha[4][7] - g_alpha[4][3] ),
+ 0x100FF / ( 1 + g_alpha[5][7] - g_alpha[5][3] ),
+ 0x100FF / ( 1 + g_alpha[6][7] - g_alpha[6][3] ),
+ 0x100FF / ( 1 + g_alpha[7][7] - g_alpha[7][3] ),
+ 0x100FF / ( 1 + g_alpha[8][7] - g_alpha[8][3] ),
+ 0x100FF / ( 1 + g_alpha[9][7] - g_alpha[9][3] ),
+ 0x100FF / ( 1 + g_alpha[10][7] - g_alpha[10][3] ),
+ 0x100FF / ( 1 + g_alpha[11][7] - g_alpha[11][3] ),
+ 0x100FF / ( 1 + g_alpha[12][7] - g_alpha[12][3] ),
+ 0x100FF / ( 1 + g_alpha[13][7] - g_alpha[13][3] ),
+ 0x100FF / ( 1 + g_alpha[14][7] - g_alpha[14][3] ),
+ 0x100FF / ( 1 + g_alpha[15][7] - g_alpha[15][3] ),
+};
+
+#ifdef __SSE4_1__
+const __m128i g_table_SIMD[2] =
+{
+ _mm_setr_epi16( 2, 5, 9, 13, 18, 24, 33, 47),
+ _mm_setr_epi16( 8, 17, 29, 42, 60, 80, 106, 183)
+};
+const __m128i g_table128_SIMD[2] =
+{
+ _mm_setr_epi16( 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128),
+ _mm_setr_epi16( 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128)
+};
+const __m128i g_table256_SIMD[4] =
+{
+ _mm_setr_epi32( 2*256, 5*256, 9*256, 13*256),
+ _mm_setr_epi32( 8*256, 17*256, 29*256, 42*256),
+ _mm_setr_epi32( 18*256, 24*256, 33*256, 47*256),
+ _mm_setr_epi32( 60*256, 80*256, 106*256, 183*256)
+};
+
+const __m128i g_alpha_SIMD[16] = {
+ _mm_setr_epi16( g_alpha[ 0][0], g_alpha[ 0][1], g_alpha[ 0][2], g_alpha[ 0][3], g_alpha[ 0][4], g_alpha[ 0][5], g_alpha[ 0][6], g_alpha[ 0][7] ),
+ _mm_setr_epi16( g_alpha[ 1][0], g_alpha[ 1][1], g_alpha[ 1][2], g_alpha[ 1][3], g_alpha[ 1][4], g_alpha[ 1][5], g_alpha[ 1][6], g_alpha[ 1][7] ),
+ _mm_setr_epi16( g_alpha[ 2][0], g_alpha[ 2][1], g_alpha[ 2][2], g_alpha[ 2][3], g_alpha[ 2][4], g_alpha[ 2][5], g_alpha[ 2][6], g_alpha[ 2][7] ),
+ _mm_setr_epi16( g_alpha[ 3][0], g_alpha[ 3][1], g_alpha[ 3][2], g_alpha[ 3][3], g_alpha[ 3][4], g_alpha[ 3][5], g_alpha[ 3][6], g_alpha[ 3][7] ),
+ _mm_setr_epi16( g_alpha[ 4][0], g_alpha[ 4][1], g_alpha[ 4][2], g_alpha[ 4][3], g_alpha[ 4][4], g_alpha[ 4][5], g_alpha[ 4][6], g_alpha[ 4][7] ),
+ _mm_setr_epi16( g_alpha[ 5][0], g_alpha[ 5][1], g_alpha[ 5][2], g_alpha[ 5][3], g_alpha[ 5][4], g_alpha[ 5][5], g_alpha[ 5][6], g_alpha[ 5][7] ),
+ _mm_setr_epi16( g_alpha[ 6][0], g_alpha[ 6][1], g_alpha[ 6][2], g_alpha[ 6][3], g_alpha[ 6][4], g_alpha[ 6][5], g_alpha[ 6][6], g_alpha[ 6][7] ),
+ _mm_setr_epi16( g_alpha[ 7][0], g_alpha[ 7][1], g_alpha[ 7][2], g_alpha[ 7][3], g_alpha[ 7][4], g_alpha[ 7][5], g_alpha[ 7][6], g_alpha[ 7][7] ),
+ _mm_setr_epi16( g_alpha[ 8][0], g_alpha[ 8][1], g_alpha[ 8][2], g_alpha[ 8][3], g_alpha[ 8][4], g_alpha[ 8][5], g_alpha[ 8][6], g_alpha[ 8][7] ),
+ _mm_setr_epi16( g_alpha[ 9][0], g_alpha[ 9][1], g_alpha[ 9][2], g_alpha[ 9][3], g_alpha[ 9][4], g_alpha[ 9][5], g_alpha[ 9][6], g_alpha[ 9][7] ),
+ _mm_setr_epi16( g_alpha[10][0], g_alpha[10][1], g_alpha[10][2], g_alpha[10][3], g_alpha[10][4], g_alpha[10][5], g_alpha[10][6], g_alpha[10][7] ),
+ _mm_setr_epi16( g_alpha[11][0], g_alpha[11][1], g_alpha[11][2], g_alpha[11][3], g_alpha[11][4], g_alpha[11][5], g_alpha[11][6], g_alpha[11][7] ),
+ _mm_setr_epi16( g_alpha[12][0], g_alpha[12][1], g_alpha[12][2], g_alpha[12][3], g_alpha[12][4], g_alpha[12][5], g_alpha[12][6], g_alpha[12][7] ),
+ _mm_setr_epi16( g_alpha[13][0], g_alpha[13][1], g_alpha[13][2], g_alpha[13][3], g_alpha[13][4], g_alpha[13][5], g_alpha[13][6], g_alpha[13][7] ),
+ _mm_setr_epi16( g_alpha[14][0], g_alpha[14][1], g_alpha[14][2], g_alpha[14][3], g_alpha[14][4], g_alpha[14][5], g_alpha[14][6], g_alpha[14][7] ),
+ _mm_setr_epi16( g_alpha[15][0], g_alpha[15][1], g_alpha[15][2], g_alpha[15][3], g_alpha[15][4], g_alpha[15][5], g_alpha[15][6], g_alpha[15][7] ),
+};
+
+const __m128i g_alphaRange_SIMD = _mm_setr_epi16(
+ g_alphaRange[0],
+ g_alphaRange[1],
+ g_alphaRange[4],
+ g_alphaRange[5],
+ g_alphaRange[8],
+ g_alphaRange[14],
+ 0,
+ 0 );
+#endif
+
+#ifdef __AVX2__
+const __m256i g_alpha_AVX[8] = {
+ _mm256_setr_epi16( g_alpha[ 0][0], g_alpha[ 1][0], g_alpha[ 2][0], g_alpha[ 3][0], g_alpha[ 4][0], g_alpha[ 5][0], g_alpha[ 6][0], g_alpha[ 7][0], g_alpha[ 8][0], g_alpha[ 9][0], g_alpha[10][0], g_alpha[11][0], g_alpha[12][0], g_alpha[13][0], g_alpha[14][0], g_alpha[15][0] ),
+ _mm256_setr_epi16( g_alpha[ 0][1], g_alpha[ 1][1], g_alpha[ 2][1], g_alpha[ 3][1], g_alpha[ 4][1], g_alpha[ 5][1], g_alpha[ 6][1], g_alpha[ 7][1], g_alpha[ 8][1], g_alpha[ 9][1], g_alpha[10][1], g_alpha[11][1], g_alpha[12][1], g_alpha[13][1], g_alpha[14][1], g_alpha[15][1] ),
+ _mm256_setr_epi16( g_alpha[ 0][2], g_alpha[ 1][2], g_alpha[ 2][2], g_alpha[ 3][2], g_alpha[ 4][2], g_alpha[ 5][2], g_alpha[ 6][2], g_alpha[ 7][2], g_alpha[ 8][2], g_alpha[ 9][2], g_alpha[10][2], g_alpha[11][2], g_alpha[12][2], g_alpha[13][2], g_alpha[14][2], g_alpha[15][2] ),
+ _mm256_setr_epi16( g_alpha[ 0][3], g_alpha[ 1][3], g_alpha[ 2][3], g_alpha[ 3][3], g_alpha[ 4][3], g_alpha[ 5][3], g_alpha[ 6][3], g_alpha[ 7][3], g_alpha[ 8][3], g_alpha[ 9][3], g_alpha[10][3], g_alpha[11][3], g_alpha[12][3], g_alpha[13][3], g_alpha[14][3], g_alpha[15][3] ),
+ _mm256_setr_epi16( g_alpha[ 0][4], g_alpha[ 1][4], g_alpha[ 2][4], g_alpha[ 3][4], g_alpha[ 4][4], g_alpha[ 5][4], g_alpha[ 6][4], g_alpha[ 7][4], g_alpha[ 8][4], g_alpha[ 9][4], g_alpha[10][4], g_alpha[11][4], g_alpha[12][4], g_alpha[13][4], g_alpha[14][4], g_alpha[15][4] ),
+ _mm256_setr_epi16( g_alpha[ 0][5], g_alpha[ 1][5], g_alpha[ 2][5], g_alpha[ 3][5], g_alpha[ 4][5], g_alpha[ 5][5], g_alpha[ 6][5], g_alpha[ 7][5], g_alpha[ 8][5], g_alpha[ 9][5], g_alpha[10][5], g_alpha[11][5], g_alpha[12][5], g_alpha[13][5], g_alpha[14][5], g_alpha[15][5] ),
+ _mm256_setr_epi16( g_alpha[ 0][6], g_alpha[ 1][6], g_alpha[ 2][6], g_alpha[ 3][6], g_alpha[ 4][6], g_alpha[ 5][6], g_alpha[ 6][6], g_alpha[ 7][6], g_alpha[ 8][6], g_alpha[ 9][6], g_alpha[10][6], g_alpha[11][6], g_alpha[12][6], g_alpha[13][6], g_alpha[14][6], g_alpha[15][6] ),
+ _mm256_setr_epi16( g_alpha[ 0][7], g_alpha[ 1][7], g_alpha[ 2][7], g_alpha[ 3][7], g_alpha[ 4][7], g_alpha[ 5][7], g_alpha[ 6][7], g_alpha[ 7][7], g_alpha[ 8][7], g_alpha[ 9][7], g_alpha[10][7], g_alpha[11][7], g_alpha[12][7], g_alpha[13][7], g_alpha[14][7], g_alpha[15][7] ),
+};
+
+const __m256i g_alphaRange_AVX = _mm256_setr_epi16(
+ g_alphaRange[ 0], g_alphaRange[ 1], g_alphaRange[ 2], g_alphaRange[ 3], g_alphaRange[ 4], g_alphaRange[ 5], g_alphaRange[ 6], g_alphaRange[ 7],
+ g_alphaRange[ 8], g_alphaRange[ 9], g_alphaRange[10], g_alphaRange[11], g_alphaRange[12], g_alphaRange[13], g_alphaRange[14], g_alphaRange[15]
+);
+#endif
+
+#ifdef __ARM_NEON
+const int16x8_t g_table128_NEON[2] =
+{
+ { 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128 },
+ { 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128 }
+};
+
+const int32x4_t g_table256_NEON[4] =
+{
+ { 2*256, 5*256, 9*256, 13*256 },
+ { 8*256, 17*256, 29*256, 42*256 },
+ { 18*256, 24*256, 33*256, 47*256 },
+ { 60*256, 80*256, 106*256, 183*256 }
+};
+
+const int16x8_t g_alpha_NEON[16] =
+{
+ { -3, -6, -9, -15, 2, 5, 8, 14 },
+ { -3, -7, -10, -13, 2, 6, 9, 12 },
+ { -2, -5, -8, -13, 1, 4, 7, 12 },
+ { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 },
+ { -3, -7, -9, -11, 2, 6, 8, 10 },
+ { -4, -7, -8, -11, 3, 6, 7, 10 },
+ { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 },
+ { -2, -5, -8, -10, 1, 4, 7, 9 },
+ { -2, -4, -8, -10, 1, 3, 7, 9 },
+ { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 },
+ { -1, -2, -3, -10, 0, 1, 2, 9 },
+ { -4, -6, -8, -9, 3, 5, 7, 8 },
+ { -3, -5, -7, -9, 2, 4, 6, 8 }
+};
+
+const int16x8_t g_alphaRange_NEON =
+{
+ (int16_t)g_alphaRange[0],
+ (int16_t)g_alphaRange[1],
+ (int16_t)g_alphaRange[4],
+ (int16_t)g_alphaRange[5],
+ (int16_t)g_alphaRange[8],
+ (int16_t)g_alphaRange[14],
+ 0,
+ 0
+};
+#endif
diff --git a/thirdparty/etcpak/Tables.hpp b/thirdparty/etcpak/Tables.hpp
new file mode 100644
index 0000000000..69d7e8aa07
--- /dev/null
+++ b/thirdparty/etcpak/Tables.hpp
@@ -0,0 +1,49 @@
+#ifndef __TABLES_HPP__
+#define __TABLES_HPP__
+
+#include <stdint.h>
+
+#ifdef __AVX2__
+# include <immintrin.h>
+#endif
+#ifdef __SSE4_1__
+# include <smmintrin.h>
+#endif
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+extern const int32_t g_table[8][4];
+extern const int64_t g_table256[8][4];
+
+extern const uint32_t g_id[4][16];
+
+extern const uint32_t g_avg2[16];
+
+extern const uint32_t g_flags[64];
+
+extern const int32_t g_alpha[16][8];
+extern const int32_t g_alphaRange[16];
+
+#ifdef __SSE4_1__
+extern const __m128i g_table_SIMD[2];
+extern const __m128i g_table128_SIMD[2];
+extern const __m128i g_table256_SIMD[4];
+
+extern const __m128i g_alpha_SIMD[16];
+extern const __m128i g_alphaRange_SIMD;
+#endif
+
+#ifdef __AVX2__
+extern const __m256i g_alpha_AVX[8];
+extern const __m256i g_alphaRange_AVX;
+#endif
+
+#ifdef __ARM_NEON
+extern const int16x8_t g_table128_NEON[2];
+extern const int32x4_t g_table256_NEON[4];
+extern const int16x8_t g_alpha_NEON[16];
+extern const int16x8_t g_alphaRange_NEON;
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/TaskDispatch.cpp b/thirdparty/etcpak/TaskDispatch.cpp
new file mode 100644
index 0000000000..7287da4de2
--- /dev/null
+++ b/thirdparty/etcpak/TaskDispatch.cpp
@@ -0,0 +1,115 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "Debug.hpp"
+#include "System.hpp"
+#include "TaskDispatch.hpp"
+
+static TaskDispatch* s_instance = nullptr;
+
+TaskDispatch::TaskDispatch( size_t workers )
+ : m_exit( false )
+ , m_jobs( 0 )
+{
+ assert( !s_instance );
+ s_instance = this;
+
+ assert( workers >= 1 );
+ workers--;
+
+ m_workers.reserve( workers );
+ for( size_t i=0; i<workers; i++ )
+ {
+ char tmp[16];
+ sprintf( tmp, "Worker %zu", i );
+#ifdef __APPLE__
+ auto worker = std::thread( [this, tmp]{
+ pthread_setname_np( tmp );
+ Worker();
+ } );
+#else
+ auto worker = std::thread( [this]{ Worker(); } );
+#endif
+ System::SetThreadName( worker, tmp );
+ m_workers.emplace_back( std::move( worker ) );
+ }
+
+ DBGPRINT( "Task dispatcher with " << m_workers.size() + 1 << " workers" );
+}
+
+TaskDispatch::~TaskDispatch()
+{
+ m_exit = true;
+ m_queueLock.lock();
+ m_cvWork.notify_all();
+ m_queueLock.unlock();
+
+ for( auto& worker : m_workers )
+ {
+ worker.join();
+ }
+
+ assert( s_instance );
+ s_instance = nullptr;
+}
+
+void TaskDispatch::Queue( const std::function<void(void)>& f )
+{
+ std::unique_lock<std::mutex> lock( s_instance->m_queueLock );
+ s_instance->m_queue.emplace_back( f );
+ const auto size = s_instance->m_queue.size();
+ lock.unlock();
+ if( size > 1 )
+ {
+ s_instance->m_cvWork.notify_one();
+ }
+}
+
+void TaskDispatch::Queue( std::function<void(void)>&& f )
+{
+ std::unique_lock<std::mutex> lock( s_instance->m_queueLock );
+ s_instance->m_queue.emplace_back( std::move( f ) );
+ const auto size = s_instance->m_queue.size();
+ lock.unlock();
+ if( size > 1 )
+ {
+ s_instance->m_cvWork.notify_one();
+ }
+}
+
+void TaskDispatch::Sync()
+{
+ std::unique_lock<std::mutex> lock( s_instance->m_queueLock );
+ while( !s_instance->m_queue.empty() )
+ {
+ auto f = s_instance->m_queue.back();
+ s_instance->m_queue.pop_back();
+ lock.unlock();
+ f();
+ lock.lock();
+ }
+ s_instance->m_cvJobs.wait( lock, []{ return s_instance->m_jobs == 0; } );
+}
+
+void TaskDispatch::Worker()
+{
+ for(;;)
+ {
+ std::unique_lock<std::mutex> lock( m_queueLock );
+ m_cvWork.wait( lock, [this]{ return !m_queue.empty() || m_exit; } );
+ if( m_exit ) return;
+ auto f = m_queue.back();
+ m_queue.pop_back();
+ m_jobs++;
+ lock.unlock();
+ f();
+ lock.lock();
+ m_jobs--;
+ bool notify = m_jobs == 0 && m_queue.empty();
+ lock.unlock();
+ if( notify )
+ {
+ m_cvJobs.notify_all();
+ }
+ }
+}
diff --git a/thirdparty/etcpak/TaskDispatch.hpp b/thirdparty/etcpak/TaskDispatch.hpp
new file mode 100644
index 0000000000..b513de4c0c
--- /dev/null
+++ b/thirdparty/etcpak/TaskDispatch.hpp
@@ -0,0 +1,34 @@
+#ifndef __DARKRL__TASKDISPATCH_HPP__
+#define __DARKRL__TASKDISPATCH_HPP__
+
+#include <atomic>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+class TaskDispatch
+{
+public:
+ TaskDispatch( size_t workers );
+ ~TaskDispatch();
+
+ static void Queue( const std::function<void(void)>& f );
+ static void Queue( std::function<void(void)>&& f );
+
+ static void Sync();
+
+private:
+ void Worker();
+
+ std::vector<std::function<void(void)>> m_queue;
+ std::mutex m_queueLock;
+ std::condition_variable m_cvWork, m_cvJobs;
+ std::atomic<bool> m_exit;
+ size_t m_jobs;
+
+ std::vector<std::thread> m_workers;
+};
+
+#endif
diff --git a/thirdparty/etcpak/Timing.cpp b/thirdparty/etcpak/Timing.cpp
new file mode 100644
index 0000000000..2af851f9a9
--- /dev/null
+++ b/thirdparty/etcpak/Timing.cpp
@@ -0,0 +1,8 @@
+#include <chrono>
+
+#include "Timing.hpp"
+
+uint64_t GetTime()
+{
+ return std::chrono::time_point_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now() ).time_since_epoch().count();
+}
diff --git a/thirdparty/etcpak/Timing.hpp b/thirdparty/etcpak/Timing.hpp
new file mode 100644
index 0000000000..3767e20f24
--- /dev/null
+++ b/thirdparty/etcpak/Timing.hpp
@@ -0,0 +1,8 @@
+#ifndef __DARKRL__TIMING_HPP__
+#define __DARKRL__TIMING_HPP__
+
+#include <stdint.h>
+
+uint64_t GetTime();
+
+#endif
diff --git a/thirdparty/etcpak/Vector.hpp b/thirdparty/etcpak/Vector.hpp
new file mode 100644
index 0000000000..3370a88aea
--- /dev/null
+++ b/thirdparty/etcpak/Vector.hpp
@@ -0,0 +1,222 @@
+#ifndef __DARKRL__VECTOR_HPP__
+#define __DARKRL__VECTOR_HPP__
+
+#include <assert.h>
+#include <algorithm>
+#include <math.h>
+#include <stdint.h>
+
+#include "Math.hpp"
+
+template<class T>
+struct Vector2
+{
+ Vector2() : x( 0 ), y( 0 ) {}
+ Vector2( T v ) : x( v ), y( v ) {}
+ Vector2( T _x, T _y ) : x( _x ), y( _y ) {}
+
+ bool operator==( const Vector2<T>& rhs ) const { return x == rhs.x && y == rhs.y; }
+ bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); }
+
+ Vector2<T>& operator+=( const Vector2<T>& rhs )
+ {
+ x += rhs.x;
+ y += rhs.y;
+ return *this;
+ }
+ Vector2<T>& operator-=( const Vector2<T>& rhs )
+ {
+ x -= rhs.x;
+ y -= rhs.y;
+ return *this;
+ }
+ Vector2<T>& operator*=( const Vector2<T>& rhs )
+ {
+ x *= rhs.x;
+ y *= rhs.y;
+ return *this;
+ }
+
+ T x, y;
+};
+
+template<class T>
+Vector2<T> operator+( const Vector2<T>& lhs, const Vector2<T>& rhs )
+{
+ return Vector2<T>( lhs.x + rhs.x, lhs.y + rhs.y );
+}
+
+template<class T>
+Vector2<T> operator-( const Vector2<T>& lhs, const Vector2<T>& rhs )
+{
+ return Vector2<T>( lhs.x - rhs.x, lhs.y - rhs.y );
+}
+
+template<class T>
+Vector2<T> operator*( const Vector2<T>& lhs, const float& rhs )
+{
+ return Vector2<T>( lhs.x * rhs, lhs.y * rhs );
+}
+
+template<class T>
+Vector2<T> operator/( const Vector2<T>& lhs, const T& rhs )
+{
+ return Vector2<T>( lhs.x / rhs, lhs.y / rhs );
+}
+
+
+typedef Vector2<int32_t> v2i;
+typedef Vector2<float> v2f;
+
+
+template<class T>
+struct Vector3
+{
+ Vector3() : x( 0 ), y( 0 ), z( 0 ) {}
+ Vector3( T v ) : x( v ), y( v ), z( v ) {}
+ Vector3( T _x, T _y, T _z ) : x( _x ), y( _y ), z( _z ) {}
+ template<class Y>
+ Vector3( const Vector3<Y>& v ) : x( T( v.x ) ), y( T( v.y ) ), z( T( v.z ) ) {}
+
+ T Luminance() const { return T( x * 0.3f + y * 0.59f + z * 0.11f ); }
+ void Clamp()
+ {
+ x = std::min( T(1), std::max( T(0), x ) );
+ y = std::min( T(1), std::max( T(0), y ) );
+ z = std::min( T(1), std::max( T(0), z ) );
+ }
+
+ bool operator==( const Vector3<T>& rhs ) const { return x == rhs.x && y == rhs.y && z == rhs.z; }
+ bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); }
+
+ T& operator[]( unsigned int idx ) { assert( idx < 3 ); return ((T*)this)[idx]; }
+ const T& operator[]( unsigned int idx ) const { assert( idx < 3 ); return ((T*)this)[idx]; }
+
+ Vector3<T> operator+=( const Vector3<T>& rhs )
+ {
+ x += rhs.x;
+ y += rhs.y;
+ z += rhs.z;
+ return *this;
+ }
+
+ Vector3<T> operator*=( const Vector3<T>& rhs )
+ {
+ x *= rhs.x;
+ y *= rhs.y;
+ z *= rhs.z;
+ return *this;
+ }
+
+ Vector3<T> operator*=( const float& rhs )
+ {
+ x *= rhs;
+ y *= rhs;
+ z *= rhs;
+ return *this;
+ }
+
+ T x, y, z;
+ T padding;
+};
+
+template<class T>
+Vector3<T> operator+( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z );
+}
+
+template<class T>
+Vector3<T> operator-( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z );
+}
+
+template<class T>
+Vector3<T> operator*( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z );
+}
+
+template<class T>
+Vector3<T> operator*( const Vector3<T>& lhs, const float& rhs )
+{
+ return Vector3<T>( T( lhs.x * rhs ), T( lhs.y * rhs ), T( lhs.z * rhs ) );
+}
+
+template<class T>
+Vector3<T> operator/( const Vector3<T>& lhs, const T& rhs )
+{
+ return Vector3<T>( lhs.x / rhs, lhs.y / rhs, lhs.z / rhs );
+}
+
+template<class T>
+bool operator<( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return lhs.Luminance() < rhs.Luminance();
+}
+
+typedef Vector3<int32_t> v3i;
+typedef Vector3<float> v3f;
+typedef Vector3<uint8_t> v3b;
+
+
+static inline v3b v3f_to_v3b( const v3f& v )
+{
+ return v3b( uint8_t( std::min( 1.f, v.x ) * 255 ), uint8_t( std::min( 1.f, v.y ) * 255 ), uint8_t( std::min( 1.f, v.z ) * 255 ) );
+}
+
+template<class T>
+Vector3<T> Mix( const Vector3<T>& v1, const Vector3<T>& v2, float amount )
+{
+ return v1 + ( v2 - v1 ) * amount;
+}
+
+template<>
+inline v3b Mix( const v3b& v1, const v3b& v2, float amount )
+{
+ return v3b( v3f( v1 ) + ( v3f( v2 ) - v3f( v1 ) ) * amount );
+}
+
+template<class T>
+Vector3<T> Desaturate( const Vector3<T>& v )
+{
+ T l = v.Luminance();
+ return Vector3<T>( l, l, l );
+}
+
+template<class T>
+Vector3<T> Desaturate( const Vector3<T>& v, float mul )
+{
+ T l = T( v.Luminance() * mul );
+ return Vector3<T>( l, l, l );
+}
+
+template<class T>
+Vector3<T> pow( const Vector3<T>& base, float exponent )
+{
+ return Vector3<T>(
+ pow( base.x, exponent ),
+ pow( base.y, exponent ),
+ pow( base.z, exponent ) );
+}
+
+template<class T>
+Vector3<T> sRGB2linear( const Vector3<T>& v )
+{
+ return Vector3<T>(
+ sRGB2linear( v.x ),
+ sRGB2linear( v.y ),
+ sRGB2linear( v.z ) );
+}
+
+template<class T>
+Vector3<T> linear2sRGB( const Vector3<T>& v )
+{
+ return Vector3<T>(
+ linear2sRGB( v.x ),
+ linear2sRGB( v.y ),
+ linear2sRGB( v.z ) );
+}
+
+#endif
diff --git a/thirdparty/etcpak/lz4/lz4.c b/thirdparty/etcpak/lz4/lz4.c
new file mode 100644
index 0000000000..08cf6b5cd7
--- /dev/null
+++ b/thirdparty/etcpak/lz4/lz4.c
@@ -0,0 +1,1516 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Copyright (C) 2011-2015, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 source repository : https://github.com/Cyan4973/lz4
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+
+
+/**************************************
+* Tuning parameters
+**************************************/
+/*
+ * HEAPMODE :
+ * Select how default compression functions will allocate memory for their hash table,
+ * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
+ */
+#define HEAPMODE 0
+
+/*
+ * ACCELERATION_DEFAULT :
+ * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0
+ */
+#define ACCELERATION_DEFAULT 1
+
+
+/**************************************
+* CPU Feature Detection
+**************************************/
+/*
+ * LZ4_FORCE_SW_BITCOUNT
+ * Define this parameter if your target system or compiler does not support hardware bit count
+ */
+#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */
+# define LZ4_FORCE_SW_BITCOUNT
+#endif
+
+
+/**************************************
+* Includes
+**************************************/
+#include "lz4.h"
+
+
+/**************************************
+* Compiler Options
+**************************************/
+#ifdef _MSC_VER /* Visual Studio */
+# define FORCE_INLINE static __forceinline
+# include <intrin.h>
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */
+#else
+# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
+# if defined(__GNUC__) || defined(__clang__)
+# define FORCE_INLINE static inline __attribute__((always_inline))
+# else
+# define FORCE_INLINE static inline
+# endif
+# else
+# define FORCE_INLINE static
+# endif /* __STDC_VERSION__ */
+#endif /* _MSC_VER */
+
+/* LZ4_GCC_VERSION is defined into lz4.h */
+#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
+# define expect(expr,value) (__builtin_expect ((expr),(value)) )
+#else
+# define expect(expr,value) (expr)
+#endif
+
+#define likely(expr) expect((expr) != 0, 1)
+#define unlikely(expr) expect((expr) != 0, 0)
+
+
+/**************************************
+* Memory routines
+**************************************/
+#include <stdlib.h> /* malloc, calloc, free */
+#define ALLOCATOR(n,s) calloc(n,s)
+#define FREEMEM free
+#include <string.h> /* memset, memcpy */
+#define MEM_INIT memset
+
+
+/**************************************
+* Basic Types
+**************************************/
+#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+#else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64;
+#endif
+
+
+/**************************************
+* Reading and writing into memory
+**************************************/
+#define STEPSIZE sizeof(size_t)
+
+static unsigned LZ4_64bits(void) { return sizeof(void*)==8; }
+
+static unsigned LZ4_isLittleEndian(void)
+{
+ const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
+ return one.c[0];
+}
+
+
+static U16 LZ4_read16(const void* memPtr)
+{
+ U16 val16;
+ memcpy(&val16, memPtr, 2);
+ return val16;
+}
+
+static U16 LZ4_readLE16(const void* memPtr)
+{
+ if (LZ4_isLittleEndian())
+ {
+ return LZ4_read16(memPtr);
+ }
+ else
+ {
+ const BYTE* p = (const BYTE*)memPtr;
+ return (U16)((U16)p[0] + (p[1]<<8));
+ }
+}
+
+static void LZ4_writeLE16(void* memPtr, U16 value)
+{
+ if (LZ4_isLittleEndian())
+ {
+ memcpy(memPtr, &value, 2);
+ }
+ else
+ {
+ BYTE* p = (BYTE*)memPtr;
+ p[0] = (BYTE) value;
+ p[1] = (BYTE)(value>>8);
+ }
+}
+
+static U32 LZ4_read32(const void* memPtr)
+{
+ U32 val32;
+ memcpy(&val32, memPtr, 4);
+ return val32;
+}
+
+static U64 LZ4_read64(const void* memPtr)
+{
+ U64 val64;
+ memcpy(&val64, memPtr, 8);
+ return val64;
+}
+
+static size_t LZ4_read_ARCH(const void* p)
+{
+ if (LZ4_64bits())
+ return (size_t)LZ4_read64(p);
+ else
+ return (size_t)LZ4_read32(p);
+}
+
+
+static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); }
+
+static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); }
+
+/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */
+static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
+{
+ BYTE* d = (BYTE*)dstPtr;
+ const BYTE* s = (const BYTE*)srcPtr;
+ BYTE* e = (BYTE*)dstEnd;
+ do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
+}
+
+
+/**************************************
+* Common Constants
+**************************************/
+#define MINMATCH 4
+
+#define COPYLENGTH 8
+#define LASTLITERALS 5
+#define MFLIMIT (COPYLENGTH+MINMATCH)
+static const int LZ4_minLength = (MFLIMIT+1);
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define MAXD_LOG 16
+#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
+
+#define ML_BITS 4
+#define ML_MASK ((1U<<ML_BITS)-1)
+#define RUN_BITS (8-ML_BITS)
+#define RUN_MASK ((1U<<RUN_BITS)-1)
+
+
+/**************************************
+* Common Utils
+**************************************/
+#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
+
+
+/**************************************
+* Common functions
+**************************************/
+static unsigned LZ4_NbCommonBytes (register size_t val)
+{
+ if (LZ4_isLittleEndian())
+ {
+ if (LZ4_64bits())
+ {
+# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanForward64( &r, (U64)val );
+ return (int)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctzll((U64)val) >> 3);
+# else
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+# endif
+ }
+ else /* 32 bits */
+ {
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r;
+ _BitScanForward( &r, (U32)val );
+ return (int)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctz((U32)val) >> 3);
+# else
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+# endif
+ }
+ }
+ else /* Big Endian CPU */
+ {
+ if (LZ4_64bits())
+ {
+# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse64( &r, val );
+ return (unsigned)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clzll((U64)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ }
+ else /* 32 bits */
+ {
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse( &r, (unsigned long)val );
+ return (unsigned)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clz((U32)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ }
+ }
+}
+
+static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
+{
+ const BYTE* const pStart = pIn;
+
+ while (likely(pIn<pInLimit-(STEPSIZE-1)))
+ {
+ size_t diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
+ if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
+ pIn += LZ4_NbCommonBytes(diff);
+ return (unsigned)(pIn - pStart);
+ }
+
+ if (LZ4_64bits()) if ((pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }
+ if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }
+ if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
+ return (unsigned)(pIn - pStart);
+}
+
+
+#ifndef LZ4_COMMONDEFS_ONLY
+/**************************************
+* Local Constants
+**************************************/
+#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
+#define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
+#define HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
+
+static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));
+static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */
+
+
+/**************************************
+* Local Structures and types
+**************************************/
+typedef struct {
+ U32 hashTable[HASH_SIZE_U32];
+ U32 currentOffset;
+ U32 initCheck;
+ const BYTE* dictionary;
+ BYTE* bufferStart; /* obsolete, used for slideInputBuffer */
+ U32 dictSize;
+} LZ4_stream_t_internal;
+
+typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;
+typedef enum { byPtr, byU32, byU16 } tableType_t;
+
+typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
+typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
+
+typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
+typedef enum { full = 0, partial = 1 } earlyEnd_directive;
+
+
+/**************************************
+* Local Utils
+**************************************/
+int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }
+int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); }
+int LZ4_sizeofState() { return LZ4_STREAMSIZE; }
+
+
+
+/********************************
+* Compression functions
+********************************/
+
+static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType)
+{
+ if (tableType == byU16)
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
+ else
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
+}
+
+static const U64 prime5bytes = 889523592379ULL;
+static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType)
+{
+ const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
+ const U32 hashMask = (1<<hashLog) - 1;
+ return ((sequence * prime5bytes) >> (40 - hashLog)) & hashMask;
+}
+
+static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType)
+{
+ if (LZ4_64bits())
+ return LZ4_hashSequence64(sequence, tableType);
+ return LZ4_hashSequence((U32)sequence, tableType);
+}
+
+static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); }
+
+static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)
+{
+ switch (tableType)
+ {
+ case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
+ case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
+ }
+}
+
+static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
+}
+
+static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
+ if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
+ { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
+}
+
+static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
+}
+
+FORCE_INLINE int LZ4_compress_generic(
+ void* const ctx,
+ const char* const source,
+ char* const dest,
+ const int inputSize,
+ const int maxOutputSize,
+ const limitedOutput_directive outputLimited,
+ const tableType_t tableType,
+ const dict_directive dict,
+ const dictIssue_directive dictIssue,
+ const U32 acceleration)
+{
+ LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx;
+
+ const BYTE* ip = (const BYTE*) source;
+ const BYTE* base;
+ const BYTE* lowLimit;
+ const BYTE* const lowRefLimit = ip - dictPtr->dictSize;
+ const BYTE* const dictionary = dictPtr->dictionary;
+ const BYTE* const dictEnd = dictionary + dictPtr->dictSize;
+ const size_t dictDelta = dictEnd - (const BYTE*)source;
+ const BYTE* anchor = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+ const BYTE* const mflimit = iend - MFLIMIT;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const olimit = op + maxOutputSize;
+
+ U32 forwardH;
+ size_t refDelta=0;
+
+ /* Init conditions */
+ if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
+ switch(dict)
+ {
+ case noDict:
+ default:
+ base = (const BYTE*)source;
+ lowLimit = (const BYTE*)source;
+ break;
+ case withPrefix64k:
+ base = (const BYTE*)source - dictPtr->currentOffset;
+ lowLimit = (const BYTE*)source - dictPtr->dictSize;
+ break;
+ case usingExtDict:
+ base = (const BYTE*)source - dictPtr->currentOffset;
+ lowLimit = (const BYTE*)source;
+ break;
+ }
+ if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
+ if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
+
+ /* First Byte */
+ LZ4_putPosition(ip, ctx, tableType, base);
+ ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+ /* Main Loop */
+ for ( ; ; )
+ {
+ const BYTE* match;
+ BYTE* token;
+ {
+ const BYTE* forwardIp = ip;
+ unsigned step = 1;
+ unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
+
+ /* Find a match */
+ do {
+ U32 h = forwardH;
+ ip = forwardIp;
+ forwardIp += step;
+ step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimit)) goto _last_literals;
+
+ match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+ if (dict==usingExtDict)
+ {
+ if (match<(const BYTE*)source)
+ {
+ refDelta = dictDelta;
+ lowLimit = dictionary;
+ }
+ else
+ {
+ refDelta = 0;
+ lowLimit = (const BYTE*)source;
+ }
+ }
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+ } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
+ || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+ || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
+ }
+
+ /* Catch up */
+ while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
+
+ {
+ /* Encode Literal length */
+ unsigned litLength = (unsigned)(ip - anchor);
+ token = op++;
+ if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
+ return 0; /* Check output limit */
+ if (litLength>=RUN_MASK)
+ {
+ int len = (int)litLength-RUN_MASK;
+ *token=(RUN_MASK<<ML_BITS);
+ for(; len >= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(litLength<<ML_BITS);
+
+ /* Copy Literals */
+ LZ4_wildCopy(op, anchor, op+litLength);
+ op+=litLength;
+ }
+
+_next_match:
+ /* Encode Offset */
+ LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
+
+ /* Encode MatchLength */
+ {
+ unsigned matchLength;
+
+ if ((dict==usingExtDict) && (lowLimit==dictionary))
+ {
+ const BYTE* limit;
+ match += refDelta;
+ limit = ip + (dictEnd-match);
+ if (limit > matchlimit) limit = matchlimit;
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
+ ip += MINMATCH + matchLength;
+ if (ip==limit)
+ {
+ unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit);
+ matchLength += more;
+ ip += more;
+ }
+ }
+ else
+ {
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+ ip += MINMATCH + matchLength;
+ }
+
+ if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit)))
+ return 0; /* Check output limit */
+ if (matchLength>=ML_MASK)
+ {
+ *token += ML_MASK;
+ matchLength -= ML_MASK;
+ for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; }
+ if (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+ *op++ = (BYTE)matchLength;
+ }
+ else *token += (BYTE)(matchLength);
+ }
+
+ anchor = ip;
+
+ /* Test end of chunk */
+ if (ip > mflimit) break;
+
+ /* Fill table */
+ LZ4_putPosition(ip-2, ctx, tableType, base);
+
+ /* Test next position */
+ match = LZ4_getPosition(ip, ctx, tableType, base);
+ if (dict==usingExtDict)
+ {
+ if (match<(const BYTE*)source)
+ {
+ refDelta = dictDelta;
+ lowLimit = dictionary;
+ }
+ else
+ {
+ refDelta = 0;
+ lowLimit = (const BYTE*)source;
+ }
+ }
+ LZ4_putPosition(ip, ctx, tableType, base);
+ if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
+ && (match+MAX_DISTANCE>=ip)
+ && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
+ { token=op++; *token=0; goto _next_match; }
+
+ /* Prepare next loop */
+ forwardH = LZ4_hashPosition(++ip, tableType);
+ }
+
+_last_literals:
+ /* Encode Last Literals */
+ {
+ const size_t lastRun = (size_t)(iend - anchor);
+ if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize))
+ return 0; /* Check output limit */
+ if (lastRun >= RUN_MASK)
+ {
+ size_t accumulator = lastRun - RUN_MASK;
+ *op++ = RUN_MASK << ML_BITS;
+ for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+ *op++ = (BYTE) accumulator;
+ }
+ else
+ {
+ *op++ = (BYTE)(lastRun<<ML_BITS);
+ }
+ memcpy(op, anchor, lastRun);
+ op += lastRun;
+ }
+
+ /* End */
+ return (int) (((char*)op)-dest);
+}
+
+
+int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_resetStream((LZ4_stream_t*)state);
+ if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
+
+ if (maxOutputSize >= LZ4_compressBound(inputSize))
+ {
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+ }
+ else
+ {
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+ }
+}
+
+
+int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+#if (HEAPMODE)
+ void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+#else
+ LZ4_stream_t ctx;
+ void* ctxPtr = &ctx;
+#endif
+
+ int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
+
+#if (HEAPMODE)
+ FREEMEM(ctxPtr);
+#endif
+ return result;
+}
+
+
+int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+ return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1);
+}
+
+
+/* hidden debug function */
+/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */
+int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_stream_t ctx;
+
+ LZ4_resetStream(&ctx);
+
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+}
+
+
+/********************************
+* destSize variant
+********************************/
+
+static int LZ4_compress_destSize_generic(
+ void* const ctx,
+ const char* const src,
+ char* const dst,
+ int* const srcSizePtr,
+ const int targetDstSize,
+ const tableType_t tableType)
+{
+ const BYTE* ip = (const BYTE*) src;
+ const BYTE* base = (const BYTE*) src;
+ const BYTE* lowLimit = (const BYTE*) src;
+ const BYTE* anchor = ip;
+ const BYTE* const iend = ip + *srcSizePtr;
+ const BYTE* const mflimit = iend - MFLIMIT;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ BYTE* op = (BYTE*) dst;
+ BYTE* const oend = op + targetDstSize;
+ BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */;
+ BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */);
+ BYTE* const oMaxSeq = oMaxLit - 1 /* token */;
+
+ U32 forwardH;
+
+
+ /* Init conditions */
+ if (targetDstSize < 1) return 0; /* Impossible to store anything */
+ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
+ if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
+ if (*srcSizePtr<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
+
+ /* First Byte */
+ *srcSizePtr = 0;
+ LZ4_putPosition(ip, ctx, tableType, base);
+ ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+ /* Main Loop */
+ for ( ; ; )
+ {
+ const BYTE* match;
+ BYTE* token;
+ {
+ const BYTE* forwardIp = ip;
+ unsigned step = 1;
+ unsigned searchMatchNb = 1 << LZ4_skipTrigger;
+
+ /* Find a match */
+ do {
+ U32 h = forwardH;
+ ip = forwardIp;
+ forwardIp += step;
+ step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimit))
+ goto _last_literals;
+
+ match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+ } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+ || (LZ4_read32(match) != LZ4_read32(ip)) );
+ }
+
+ /* Catch up */
+ while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
+
+ {
+ /* Encode Literal length */
+ unsigned litLength = (unsigned)(ip - anchor);
+ token = op++;
+ if (op + ((litLength+240)/255) + litLength > oMaxLit)
+ {
+ /* Not enough space for a last match */
+ op--;
+ goto _last_literals;
+ }
+ if (litLength>=RUN_MASK)
+ {
+ unsigned len = litLength - RUN_MASK;
+ *token=(RUN_MASK<<ML_BITS);
+ for(; len >= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(litLength<<ML_BITS);
+
+ /* Copy Literals */
+ LZ4_wildCopy(op, anchor, op+litLength);
+ op += litLength;
+ }
+
+_next_match:
+ /* Encode Offset */
+ LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
+
+ /* Encode MatchLength */
+ {
+ size_t matchLength;
+
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+
+ if (op + ((matchLength+240)/255) > oMaxMatch)
+ {
+ /* Match description too long : reduce it */
+ matchLength = (15-1) + (oMaxMatch-op) * 255;
+ }
+ //printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);
+ ip += MINMATCH + matchLength;
+
+ if (matchLength>=ML_MASK)
+ {
+ *token += ML_MASK;
+ matchLength -= ML_MASK;
+ while (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+ *op++ = (BYTE)matchLength;
+ }
+ else *token += (BYTE)(matchLength);
+ }
+
+ anchor = ip;
+
+ /* Test end of block */
+ if (ip > mflimit) break;
+ if (op > oMaxSeq) break;
+
+ /* Fill table */
+ LZ4_putPosition(ip-2, ctx, tableType, base);
+
+ /* Test next position */
+ match = LZ4_getPosition(ip, ctx, tableType, base);
+ LZ4_putPosition(ip, ctx, tableType, base);
+ if ( (match+MAX_DISTANCE>=ip)
+ && (LZ4_read32(match)==LZ4_read32(ip)) )
+ { token=op++; *token=0; goto _next_match; }
+
+ /* Prepare next loop */
+ forwardH = LZ4_hashPosition(++ip, tableType);
+ }
+
+_last_literals:
+ /* Encode Last Literals */
+ {
+ size_t lastRunSize = (size_t)(iend - anchor);
+ if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend)
+ {
+ /* adapt lastRunSize to fill 'dst' */
+ lastRunSize = (oend-op) - 1;
+ lastRunSize -= (lastRunSize+240)/255;
+ }
+ ip = anchor + lastRunSize;
+
+ if (lastRunSize >= RUN_MASK)
+ {
+ size_t accumulator = lastRunSize - RUN_MASK;
+ *op++ = RUN_MASK << ML_BITS;
+ for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+ *op++ = (BYTE) accumulator;
+ }
+ else
+ {
+ *op++ = (BYTE)(lastRunSize<<ML_BITS);
+ }
+ memcpy(op, anchor, lastRunSize);
+ op += lastRunSize;
+ }
+
+ /* End */
+ *srcSizePtr = (int) (((const char*)ip)-src);
+ return (int) (((char*)op)-dst);
+}
+
+
+static int LZ4_compress_destSize_extState (void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+ LZ4_resetStream((LZ4_stream_t*)state);
+
+ if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */
+ {
+ return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);
+ }
+ else
+ {
+ if (*srcSizePtr < LZ4_64Klimit)
+ return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16);
+ else
+ return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr);
+ }
+}
+
+
+int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+#if (HEAPMODE)
+ void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+#else
+ LZ4_stream_t ctxBody;
+ void* ctx = &ctxBody;
+#endif
+
+ int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);
+
+#if (HEAPMODE)
+ FREEMEM(ctx);
+#endif
+ return result;
+}
+
+
+
+/********************************
+* Streaming functions
+********************************/
+
+LZ4_stream_t* LZ4_createStream(void)
+{
+ LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+ LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
+ LZ4_resetStream(lz4s);
+ return lz4s;
+}
+
+void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
+{
+ MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
+}
+
+int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
+{
+ FREEMEM(LZ4_stream);
+ return (0);
+}
+
+
+#define HASH_UNIT sizeof(size_t)
+int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
+{
+ LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+ const BYTE* p = (const BYTE*)dictionary;
+ const BYTE* const dictEnd = p + dictSize;
+ const BYTE* base;
+
+ if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */
+ LZ4_resetStream(LZ4_dict);
+
+ if (dictSize < (int)HASH_UNIT)
+ {
+ dict->dictionary = NULL;
+ dict->dictSize = 0;
+ return 0;
+ }
+
+ if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
+ dict->currentOffset += 64 KB;
+ base = p - dict->currentOffset;
+ dict->dictionary = p;
+ dict->dictSize = (U32)(dictEnd - p);
+ dict->currentOffset += dict->dictSize;
+
+ while (p <= dictEnd-HASH_UNIT)
+ {
+ LZ4_putPosition(p, dict->hashTable, byU32, base);
+ p+=3;
+ }
+
+ return dict->dictSize;
+}
+
+
+static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
+{
+ if ((LZ4_dict->currentOffset > 0x80000000) ||
+ ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */
+ {
+ /* rescale hash table */
+ U32 delta = LZ4_dict->currentOffset - 64 KB;
+ const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
+ int i;
+ for (i=0; i<HASH_SIZE_U32; i++)
+ {
+ if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;
+ else LZ4_dict->hashTable[i] -= delta;
+ }
+ LZ4_dict->currentOffset = 64 KB;
+ if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;
+ LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;
+ }
+}
+
+
+int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream;
+ const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+ const BYTE* smallest = (const BYTE*) source;
+ if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */
+ if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd;
+ LZ4_renormDictT(streamPtr, smallest);
+ if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
+
+ /* Check overlapping input/dictionary space */
+ {
+ const BYTE* sourceEnd = (const BYTE*) source + inputSize;
+ if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd))
+ {
+ streamPtr->dictSize = (U32)(dictEnd - sourceEnd);
+ if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;
+ if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;
+ streamPtr->dictionary = dictEnd - streamPtr->dictSize;
+ }
+ }
+
+ /* prefix mode : source data follows dictionary */
+ if (dictEnd == (const BYTE*)source)
+ {
+ int result;
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration);
+ else
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration);
+ streamPtr->dictSize += (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+ return result;
+ }
+
+ /* external dictionary mode */
+ {
+ int result;
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration);
+ else
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration);
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+ return result;
+ }
+}
+
+
+/* Hidden debug function, to force external dictionary mode */
+int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize)
+{
+ LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict;
+ int result;
+ const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+ const BYTE* smallest = dictEnd;
+ if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
+ LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest);
+
+ result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
+
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+
+ return result;
+}
+
+
+int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
+{
+ LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+ const BYTE* previousDictEnd = dict->dictionary + dict->dictSize;
+
+ if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */
+ if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize;
+
+ memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
+
+ dict->dictionary = (const BYTE*)safeBuffer;
+ dict->dictSize = (U32)dictSize;
+
+ return dictSize;
+}
+
+
+
+/*******************************
+* Decompression functions
+*******************************/
+/*
+ * This generic decompression function cover all use cases.
+ * It shall be instantiated several times, using different sets of directives
+ * Note that it is essential this generic function is really inlined,
+ * in order to remove useless branches during compilation optimization.
+ */
+FORCE_INLINE int LZ4_decompress_generic(
+ const char* const source,
+ char* const dest,
+ int inputSize,
+ int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
+
+ int endOnInput, /* endOnOutputSize, endOnInputSize */
+ int partialDecoding, /* full, partial */
+ int targetOutputSize, /* only used if partialDecoding==partial */
+ int dict, /* noDict, withPrefix64k, usingExtDict */
+ const BYTE* const lowPrefix, /* == dest if dict == noDict */
+ const BYTE* const dictStart, /* only if dict==usingExtDict */
+ const size_t dictSize /* note : = 0 if noDict */
+ )
+{
+ /* Local Variables */
+ const BYTE* ip = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const oend = op + outputSize;
+ BYTE* cpy;
+ BYTE* oexit = op + targetOutputSize;
+ const BYTE* const lowLimit = lowPrefix - dictSize;
+
+ const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
+ const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
+ const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
+
+ const int safeDecode = (endOnInput==endOnInputSize);
+ const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
+
+
+ /* Special cases */
+ if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
+ if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
+ if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
+
+
+ /* Main Loop */
+ while (1)
+ {
+ unsigned token;
+ size_t length;
+ const BYTE* match;
+
+ /* get literal length */
+ token = *ip++;
+ if ((length=(token>>ML_BITS)) == RUN_MASK)
+ {
+ unsigned s;
+ do
+ {
+ s = *ip++;
+ length += s;
+ }
+ while (likely((endOnInput)?ip<iend-RUN_MASK:1) && (s==255));
+ if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error; /* overflow detection */
+ if ((safeDecode) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error; /* overflow detection */
+ }
+
+ /* copy literals */
+ cpy = op+length;
+ if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
+ || ((!endOnInput) && (cpy>oend-COPYLENGTH)))
+ {
+ if (partialDecoding)
+ {
+ if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
+ if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
+ }
+ else
+ {
+ if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
+ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
+ }
+ memcpy(op, ip, length);
+ ip += length;
+ op += length;
+ break; /* Necessarily EOF, due to parsing restrictions */
+ }
+ LZ4_wildCopy(op, ip, cpy);
+ ip += length; op = cpy;
+
+ /* get offset */
+ match = cpy - LZ4_readLE16(ip); ip+=2;
+ if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */
+
+ /* get matchlength */
+ length = token & ML_MASK;
+ if (length == ML_MASK)
+ {
+ unsigned s;
+ do
+ {
+ if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
+ s = *ip++;
+ length += s;
+ } while (s==255);
+ if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */
+ }
+ length += MINMATCH;
+
+ /* check external dictionary */
+ if ((dict==usingExtDict) && (match < lowPrefix))
+ {
+ if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
+
+ if (length <= (size_t)(lowPrefix-match))
+ {
+ /* match can be copied as a single segment from external dictionary */
+ match = dictEnd - (lowPrefix-match);
+ memmove(op, match, length); op += length;
+ }
+ else
+ {
+ /* match encompass external dictionary and current segment */
+ size_t copySize = (size_t)(lowPrefix-match);
+ memcpy(op, dictEnd - copySize, copySize);
+ op += copySize;
+ copySize = length - copySize;
+ if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */
+ {
+ BYTE* const endOfMatch = op + copySize;
+ const BYTE* copyFrom = lowPrefix;
+ while (op < endOfMatch) *op++ = *copyFrom++;
+ }
+ else
+ {
+ memcpy(op, lowPrefix, copySize);
+ op += copySize;
+ }
+ }
+ continue;
+ }
+
+ /* copy repeated sequence */
+ cpy = op + length;
+ if (unlikely((op-match)<8))
+ {
+ const size_t dec64 = dec64table[op-match];
+ op[0] = match[0];
+ op[1] = match[1];
+ op[2] = match[2];
+ op[3] = match[3];
+ match += dec32table[op-match];
+ LZ4_copy4(op+4, match);
+ op += 8; match -= dec64;
+ } else { LZ4_copy8(op, match); op+=8; match+=8; }
+
+ if (unlikely(cpy>oend-12))
+ {
+ if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */
+ if (op < oend-8)
+ {
+ LZ4_wildCopy(op, match, oend-8);
+ match += (oend-8) - op;
+ op = oend-8;
+ }
+ while (op<cpy) *op++ = *match++;
+ }
+ else
+ LZ4_wildCopy(op, match, cpy);
+ op=cpy; /* correction */
+ }
+
+ /* end of decoding */
+ if (endOnInput)
+ return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
+ else
+ return (int) (((const char*)ip)-source); /* Nb of input bytes read */
+
+ /* Overflow error detected */
+_output_error:
+ return (int) (-(((const char*)ip)-source))-1;
+}
+
+
+int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
+}
+
+int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0);
+}
+
+int LZ4_decompress_fast(const char* source, char* dest, int originalSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB);
+}
+
+
+/* streaming decompression functions */
+
+typedef struct
+{
+ const BYTE* externalDict;
+ size_t extDictSize;
+ const BYTE* prefixEnd;
+ size_t prefixSize;
+} LZ4_streamDecode_t_internal;
+
+/*
+ * If you prefer dynamic allocation methods,
+ * LZ4_createStreamDecode()
+ * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure.
+ */
+LZ4_streamDecode_t* LZ4_createStreamDecode(void)
+{
+ LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t));
+ return lz4s;
+}
+
+int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)
+{
+ FREEMEM(LZ4_stream);
+ return 0;
+}
+
+/*
+ * LZ4_setStreamDecode
+ * Use this function to instruct where to find the dictionary
+ * This function is not necessary if previous data is still available where it was decoded.
+ * Loading a size of 0 is allowed (same effect as no dictionary).
+ * Return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ lz4sd->prefixSize = (size_t) dictSize;
+ lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;
+ lz4sd->externalDict = NULL;
+ lz4sd->extDictSize = 0;
+ return 1;
+}
+
+/*
+*_continue() :
+ These decoding functions allow decompression of multiple blocks in "streaming" mode.
+ Previously decoded blocks must still be available at the memory position where they were decoded.
+ If it's not possible, save the relevant part of decoded data into a safe buffer,
+ and indicate where it stands using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ int result;
+
+ if (lz4sd->prefixEnd == (BYTE*)dest)
+ {
+ result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, full, 0,
+ usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += result;
+ lz4sd->prefixEnd += result;
+ }
+ else
+ {
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
+ result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, full, 0,
+ usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = result;
+ lz4sd->prefixEnd = (BYTE*)dest + result;
+ }
+
+ return result;
+}
+
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ int result;
+
+ if (lz4sd->prefixEnd == (BYTE*)dest)
+ {
+ result = LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, full, 0,
+ usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += originalSize;
+ lz4sd->prefixEnd += originalSize;
+ }
+ else
+ {
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize;
+ result = LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, full, 0,
+ usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = originalSize;
+ lz4sd->prefixEnd = (BYTE*)dest + originalSize;
+ }
+
+ return result;
+}
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+ These decoding functions work the same as "_continue" ones,
+ the dictionary must be explicitly provided within parameters
+*/
+
+FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize)
+{
+ if (dictSize==0)
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0);
+ if (dictStart+dictSize == dest)
+ {
+ if (dictSize >= (int)(64 KB - 1))
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0);
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);
+ }
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize);
+}
+
+int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize);
+}
+
+/* debug function */
+int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+
+/***************************************************
+* Obsolete Functions
+***************************************************/
+/* obsolete compression functions */
+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); }
+int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); }
+int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); }
+int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); }
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); }
+int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); }
+
+/*
+These function names are deprecated and should no longer be used.
+They are only provided here for compatibility with older user programs.
+- LZ4_uncompress is totally equivalent to LZ4_decompress_fast
+- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe
+*/
+int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
+int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
+
+
+/* Obsolete Streaming functions */
+
+int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }
+
+static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base)
+{
+ MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE);
+ lz4ds->bufferStart = base;
+}
+
+int LZ4_resetStreamState(void* state, char* inputBuffer)
+{
+ if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */
+ LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer);
+ return 0;
+}
+
+void* LZ4_create (char* inputBuffer)
+{
+ void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+ LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer);
+ return lz4ds;
+}
+
+char* LZ4_slideInputBuffer (void* LZ4_Data)
+{
+ LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data;
+ int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB);
+ return (char*)(ctx->bufferStart + dictSize);
+}
+
+/* Obsolete streaming decompression functions */
+
+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+#endif /* LZ4_COMMONDEFS_ONLY */
+
diff --git a/thirdparty/etcpak/lz4/lz4.h b/thirdparty/etcpak/lz4/lz4.h
new file mode 100644
index 0000000000..3e74002256
--- /dev/null
+++ b/thirdparty/etcpak/lz4/lz4.h
@@ -0,0 +1,360 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Header File
+ Copyright (C) 2011-2015, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 source repository : https://github.com/Cyan4973/lz4
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+#pragma once
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * lz4.h provides block compression functions, and gives full buffer control to programmer.
+ * If you need to generate inter-operable compressed data (respecting LZ4 frame specification),
+ * and can let the library handle its own memory, please use lz4frame.h instead.
+*/
+
+/**************************************
+* Version
+**************************************/
+#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
+#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
+#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */
+#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
+int LZ4_versionNumber (void);
+
+/**************************************
+* Tuning parameter
+**************************************/
+/*
+ * LZ4_MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
+ */
+#define LZ4_MEMORY_USAGE 14
+
+
+/**************************************
+* Simple Functions
+**************************************/
+
+int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
+int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+
+/*
+LZ4_compress_default() :
+ Compresses 'sourceSize' bytes from buffer 'source'
+ into already allocated 'dest' buffer of size 'maxDestSize'.
+ Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize).
+ It also runs faster, so it's a recommended setting.
+ If the function cannot compress 'source' into a more limited 'dest' budget,
+ compression stops *immediately*, and the function result is zero.
+ As a consequence, 'dest' content is not valid.
+ This function never writes outside 'dest' buffer, nor read outside 'source' buffer.
+ sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
+ maxDestSize : full or partial size of buffer 'dest' (which must be already allocated)
+ return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize)
+ or 0 if compression fails
+
+LZ4_decompress_safe() :
+ compressedSize : is the precise full size of the compressed block.
+ maxDecompressedSize : is the size of destination buffer, which must be already allocated.
+ return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize)
+ If destination buffer is not large enough, decoding will stop and output an error code (<0).
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function is protected against buffer overflow exploits, including malicious data packets.
+ It never writes outside output buffer, nor reads outside input buffer.
+*/
+
+
+/**************************************
+* Advanced Functions
+**************************************/
+#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
+#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
+
+/*
+LZ4_compressBound() :
+ Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
+ This function is primarily useful for memory allocation purposes (destination buffer size).
+ Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
+ Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize)
+ inputSize : max supported value is LZ4_MAX_INPUT_SIZE
+ return : maximum output size in a "worst case" scenario
+ or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
+*/
+int LZ4_compressBound(int inputSize);
+
+/*
+LZ4_compress_fast() :
+ Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
+ The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
+ It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
+ An acceleration value of "1" is the same as regular LZ4_compress_default()
+ Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
+*/
+int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_fast_extState() :
+ Same compression function, just using an externally allocated memory space to store compression state.
+ Use LZ4_sizeofState() to know how much memory must be allocated,
+ and allocate it on 8-bytes boundaries (using malloc() typically).
+ Then, provide it as 'void* state' to compression function.
+*/
+int LZ4_sizeofState(void);
+int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_destSize() :
+ Reverse the logic, by compressing as much data as possible from 'source' buffer
+ into already allocated buffer 'dest' of size 'targetDestSize'.
+ This function either compresses the entire 'source' content into 'dest' if it's large enough,
+ or fill 'dest' buffer completely with as much data as possible from 'source'.
+ *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'.
+ New value is necessarily <= old value.
+ return : Nb bytes written into 'dest' (necessarily <= targetDestSize)
+ or 0 if compression fails
+*/
+int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize);
+
+
+/*
+LZ4_decompress_fast() :
+ originalSize : is the original and therefore uncompressed size
+ return : the number of bytes read from the source buffer (in other words, the compressed size)
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
+ note : This function fully respect memory boundaries for properly formed compressed data.
+ It is a bit faster than LZ4_decompress_safe().
+ However, it does not provide any protection against intentionally modified data stream (malicious input).
+ Use this function in trusted environment only (data to decode comes from a trusted source).
+*/
+int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
+
+/*
+LZ4_decompress_safe_partial() :
+ This function decompress a compressed block of size 'compressedSize' at position 'source'
+ into destination buffer 'dest' of size 'maxDecompressedSize'.
+ The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
+ reducing decompression time.
+ return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
+ Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
+ Always control how many bytes were decoded.
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
+*/
+int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
+
+
+/***********************************************
+* Streaming Compression Functions
+***********************************************/
+#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
+#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long))
+/*
+ * LZ4_stream_t
+ * information structure to track an LZ4 stream.
+ * important : init this structure content before first use !
+ * note : only allocated directly the structure if you are statically linking LZ4
+ * If you are using liblz4 as a DLL, please use below construction methods instead.
+ */
+typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;
+
+/*
+ * LZ4_resetStream
+ * Use this function to init an allocated LZ4_stream_t structure
+ */
+void LZ4_resetStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_createStream will allocate and initialize an LZ4_stream_t structure
+ * LZ4_freeStream releases its memory.
+ * In the context of a DLL (liblz4), please use these methods rather than the static struct.
+ * They are more future proof, in case of a change of LZ4_stream_t size.
+ */
+LZ4_stream_t* LZ4_createStream(void);
+int LZ4_freeStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_loadDict
+ * Use this function to load a static dictionary into LZ4_stream.
+ * Any previous data will be forgotten, only 'dictionary' will remain in memory.
+ * Loading a size of 0 is allowed.
+ * Return : dictionary size, in bytes (necessarily <= 64 KB)
+ */
+int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
+
+/*
+ * LZ4_compress_fast_continue
+ * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio.
+ * Important : Previous data blocks are assumed to still be present and unmodified !
+ * 'dst' buffer must be already allocated.
+ * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
+ * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
+ */
+int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration);
+
+/*
+ * LZ4_saveDict
+ * If previously compressed data block is not guaranteed to remain available at its memory location
+ * save it into a safer place (char* safeBuffer)
+ * Note : you don't need to call LZ4_loadDict() afterwards,
+ * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue()
+ * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error
+ */
+int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize);
+
+
+/************************************************
+* Streaming Decompression Functions
+************************************************/
+
+#define LZ4_STREAMDECODESIZE_U64 4
+#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
+typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;
+/*
+ * LZ4_streamDecode_t
+ * information structure to track an LZ4 stream.
+ * init this structure content using LZ4_setStreamDecode or memset() before first use !
+ *
+ * In the context of a DLL (liblz4) please prefer usage of construction methods below.
+ * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future.
+ * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure
+ * LZ4_freeStreamDecode releases its memory.
+ */
+LZ4_streamDecode_t* LZ4_createStreamDecode(void);
+int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
+
+/*
+ * LZ4_setStreamDecode
+ * Use this function to instruct where to find the dictionary.
+ * Setting a size of 0 is allowed (same effect as reset).
+ * Return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
+
+/*
+*_continue() :
+ These decoding functions allow decompression of multiple blocks in "streaming" mode.
+ Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
+ In the case of a ring buffers, decoding buffer must be either :
+ - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)
+ In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).
+ - Larger than encoding buffer, by a minimum of maxBlockSize more bytes.
+ maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block.
+ In which case, encoding and decoding buffers do not need to be synchronized,
+ and encoding ring buffer can have any size, including small ones ( < 64 KB).
+ - _At least_ 64 KB + 8 bytes + maxBlockSize.
+ In which case, encoding and decoding buffers do not need to be synchronized,
+ and encoding ring buffer can have any size, including larger than decoding buffer.
+ Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,
+ and indicate where it is saved using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize);
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+ These decoding functions work the same as
+ a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue()
+ They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure.
+*/
+int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize);
+int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize);
+
+
+
+/**************************************
+* Obsolete Functions
+**************************************/
+/* Deprecate Warnings */
+/* Should these warnings messages be a problem,
+ it is generally possible to disable them,
+ with -Wno-deprecated-declarations for gcc
+ or _CRT_SECURE_NO_WARNINGS in Visual for example.
+ You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */
+#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK
+# define LZ4_DEPRECATE_WARNING_DEFBLOCK
+# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+# if (LZ4_GCC_VERSION >= 405) || defined(__clang__)
+# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
+# elif (LZ4_GCC_VERSION >= 301)
+# define LZ4_DEPRECATED(message) __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define LZ4_DEPRECATED(message) __declspec(deprecated(message))
+# else
+# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
+# define LZ4_DEPRECATED(message)
+# endif
+#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */
+
+/* Obsolete compression functions */
+/* These functions are planned to start generate warnings by r131 approximately */
+int LZ4_compress (const char* source, char* dest, int sourceSize);
+int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
+int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/* Obsolete decompression functions */
+/* These function names are completely deprecated and must no longer be used.
+ They are only provided here for compatibility with older programs.
+ - LZ4_uncompress is the same as LZ4_decompress_fast
+ - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
+ These function prototypes are now disabled; uncomment them only if you really need them.
+ It is highly recommended to stop using these prototypes and migrate to maintained ones */
+/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
+/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
+
+/* Obsolete streaming functions; use new streaming interface whenever possible */
+LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void);
+LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state);
+
+/* Obsolete streaming decoding functions */
+LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
+LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/thirdparty/etcpak/mmap.cpp b/thirdparty/etcpak/mmap.cpp
new file mode 100644
index 0000000000..c2460ee9e4
--- /dev/null
+++ b/thirdparty/etcpak/mmap.cpp
@@ -0,0 +1,38 @@
+#include "mmap.hpp"
+
+#ifdef _WIN32
+# include <io.h>
+# include <windows.h>
+
+void* mmap( void* addr, size_t length, int prot, int flags, int fd, off_t offset )
+{
+ HANDLE hnd;
+ void* map = nullptr;
+
+ switch( prot )
+ {
+ case PROT_READ:
+ if( hnd = CreateFileMapping( HANDLE( _get_osfhandle( fd ) ), nullptr, PAGE_READONLY, 0, DWORD( length ), nullptr ) )
+ {
+ map = MapViewOfFile( hnd, FILE_MAP_READ, 0, 0, length );
+ CloseHandle( hnd );
+ }
+ break;
+ case PROT_WRITE:
+ if( hnd = CreateFileMapping( HANDLE( _get_osfhandle( fd ) ), nullptr, PAGE_READWRITE, 0, DWORD( length ), nullptr ) )
+ {
+ map = MapViewOfFile( hnd, FILE_MAP_WRITE, 0, 0, length );
+ CloseHandle( hnd );
+ }
+ break;
+ }
+
+ return map ? (char*)map + offset : (void*)-1;
+}
+
+int munmap( void* addr, size_t length )
+{
+ return UnmapViewOfFile( addr ) != 0 ? 0 : -1;
+}
+
+#endif
diff --git a/thirdparty/etcpak/mmap.hpp b/thirdparty/etcpak/mmap.hpp
new file mode 100644
index 0000000000..e4cfe7759c
--- /dev/null
+++ b/thirdparty/etcpak/mmap.hpp
@@ -0,0 +1,19 @@
+#ifndef __MMAP_HPP__
+#define __MMAP_HPP__
+
+#ifndef _WIN32
+# include <sys/mman.h>
+#else
+# include <string.h>
+# include <sys/types.h>
+
+# define PROT_READ 1
+# define PROT_WRITE 2
+# define MAP_SHARED 0
+
+void* mmap( void* addr, size_t length, int prot, int flags, int fd, off_t offset );
+int munmap( void* addr, size_t length );
+
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/patches/libpng-unbundle.patch b/thirdparty/etcpak/patches/libpng-unbundle.patch
new file mode 100644
index 0000000000..e3c07412c6
--- /dev/null
+++ b/thirdparty/etcpak/patches/libpng-unbundle.patch
@@ -0,0 +1,13 @@
+diff --git a/thirdparty/etcpak/Bitmap.cpp b/thirdparty/etcpak/Bitmap.cpp
+index 6aa36f5caa..ef318318ac 100644
+--- a/thirdparty/etcpak/Bitmap.cpp
++++ b/thirdparty/etcpak/Bitmap.cpp
+@@ -3,7 +3,7 @@
+ #include <string.h>
+ #include <assert.h>
+
+-#include "libpng/png.h"
++#include <png.h>
+ #include "lz4/lz4.h"
+
+ #include "Bitmap.hpp"
diff --git a/thirdparty/etcpak/patches/llvm-c++11-narrowing-errors.patch b/thirdparty/etcpak/patches/llvm-c++11-narrowing-errors.patch
new file mode 100644
index 0000000000..ab0d1e63a2
--- /dev/null
+++ b/thirdparty/etcpak/patches/llvm-c++11-narrowing-errors.patch
@@ -0,0 +1,64 @@
+diff --git a/thirdparty/etcpak/BlockData.cpp b/thirdparty/etcpak/BlockData.cpp
+index bd738085f3..395b55246b 100644
+--- a/thirdparty/etcpak/BlockData.cpp
++++ b/thirdparty/etcpak/BlockData.cpp
+@@ -334,10 +334,10 @@ static etcpak_force_inline void DecodeT( uint64_t block, uint32_t* dst, uint32_t
+ const auto c3b = clampu8( cb1 - table59T58H[codeword] );
+
+ const uint32_t col_tab[4] = {
+- cr0 | ( cg0 << 8 ) | ( cb0 << 16 ) | 0xFF000000,
+- c2r | ( c2g << 8 ) | ( c2b << 16 ) | 0xFF000000,
+- cr1 | ( cg1 << 8 ) | ( cb1 << 16 ) | 0xFF000000,
+- c3r | ( c3g << 8 ) | ( c3b << 16 ) | 0xFF000000
++ uint32_t(cr0 | ( cg0 << 8 ) | ( cb0 << 16 ) | 0xFF000000),
++ uint32_t(c2r | ( c2g << 8 ) | ( c2b << 16 ) | 0xFF000000),
++ uint32_t(cr1 | ( cg1 << 8 ) | ( cb1 << 16 ) | 0xFF000000),
++ uint32_t(c3r | ( c3g << 8 ) | ( c3b << 16 ) | 0xFF000000)
+ };
+
+ const uint32_t indexes = ( block >> 32 ) & 0xFFFFFFFF;
+@@ -389,10 +389,10 @@ static etcpak_force_inline void DecodeTAlpha( uint64_t block, uint64_t alpha, ui
+ const auto c3b = clampu8( cb1 - table59T58H[codeword] );
+
+ const uint32_t col_tab[4] = {
+- cr0 | ( cg0 << 8 ) | ( cb0 << 16 ),
+- c2r | ( c2g << 8 ) | ( c2b << 16 ),
+- cr1 | ( cg1 << 8 ) | ( cb1 << 16 ),
+- c3r | ( c3g << 8 ) | ( c3b << 16 )
++ uint32_t(cr0 | ( cg0 << 8 ) | ( cb0 << 16 )),
++ uint32_t(c2r | ( c2g << 8 ) | ( c2b << 16 )),
++ uint32_t(cr1 | ( cg1 << 8 ) | ( cb1 << 16 )),
++ uint32_t(c3r | ( c3g << 8 ) | ( c3b << 16 ))
+ };
+
+ const uint32_t indexes = ( block >> 32 ) & 0xFFFFFFFF;
+@@ -436,10 +436,10 @@ static etcpak_force_inline void DecodeH( uint64_t block, uint32_t* dst, uint32_t
+ const auto codeword = codeword_hi | codeword_lo;
+
+ const uint32_t col_tab[] = {
+- clampu8( r0 + table59T58H[codeword] ) | ( clampu8( g0 + table59T58H[codeword] ) << 8 ) | ( clampu8( b0 + table59T58H[codeword] ) << 16 ),
+- clampu8( r0 - table59T58H[codeword] ) | ( clampu8( g0 - table59T58H[codeword] ) << 8 ) | ( clampu8( b0 - table59T58H[codeword] ) << 16 ),
+- clampu8( r1 + table59T58H[codeword] ) | ( clampu8( g1 + table59T58H[codeword] ) << 8 ) | ( clampu8( b1 + table59T58H[codeword] ) << 16 ),
+- clampu8( r1 - table59T58H[codeword] ) | ( clampu8( g1 - table59T58H[codeword] ) << 8 ) | ( clampu8( b1 - table59T58H[codeword] ) << 16 )
++ uint32_t(clampu8( r0 + table59T58H[codeword] ) | ( clampu8( g0 + table59T58H[codeword] ) << 8 ) | ( clampu8( b0 + table59T58H[codeword] ) << 16 )),
++ uint32_t(clampu8( r0 - table59T58H[codeword] ) | ( clampu8( g0 - table59T58H[codeword] ) << 8 ) | ( clampu8( b0 - table59T58H[codeword] ) << 16 )),
++ uint32_t(clampu8( r1 + table59T58H[codeword] ) | ( clampu8( g1 + table59T58H[codeword] ) << 8 ) | ( clampu8( b1 + table59T58H[codeword] ) << 16 )),
++ uint32_t(clampu8( r1 - table59T58H[codeword] ) | ( clampu8( g1 - table59T58H[codeword] ) << 8 ) | ( clampu8( b1 - table59T58H[codeword] ) << 16 ))
+ };
+
+ for( uint8_t j = 0; j < 4; j++ )
+@@ -483,10 +483,10 @@ static etcpak_force_inline void DecodeHAlpha( uint64_t block, uint64_t alpha, ui
+ const auto tbl = g_alpha[(alpha >> 48) & 0xF];
+
+ const uint32_t col_tab[] = {
+- clampu8( r0 + table59T58H[codeword] ) | ( clampu8( g0 + table59T58H[codeword] ) << 8 ) | ( clampu8( b0 + table59T58H[codeword] ) << 16 ),
+- clampu8( r0 - table59T58H[codeword] ) | ( clampu8( g0 - table59T58H[codeword] ) << 8 ) | ( clampu8( b0 - table59T58H[codeword] ) << 16 ),
+- clampu8( r1 + table59T58H[codeword] ) | ( clampu8( g1 + table59T58H[codeword] ) << 8 ) | ( clampu8( b1 + table59T58H[codeword] ) << 16 ),
+- clampu8( r1 - table59T58H[codeword] ) | ( clampu8( g1 - table59T58H[codeword] ) << 8 ) | ( clampu8( b1 - table59T58H[codeword] ) << 16 )
++ uint32_t(clampu8( r0 + table59T58H[codeword] ) | ( clampu8( g0 + table59T58H[codeword] ) << 8 ) | ( clampu8( b0 + table59T58H[codeword] ) << 16 )),
++ uint32_t(clampu8( r0 - table59T58H[codeword] ) | ( clampu8( g0 - table59T58H[codeword] ) << 8 ) | ( clampu8( b0 - table59T58H[codeword] ) << 16 )),
++ uint32_t(clampu8( r1 + table59T58H[codeword] ) | ( clampu8( g1 + table59T58H[codeword] ) << 8 ) | ( clampu8( b1 + table59T58H[codeword] ) << 16 )),
++ uint32_t(clampu8( r1 - table59T58H[codeword] ) | ( clampu8( g1 - table59T58H[codeword] ) << 8 ) | ( clampu8( b1 - table59T58H[codeword] ) << 16 ))
+ };
+
+ for( uint8_t j = 0; j < 4; j++ )
diff --git a/thirdparty/etcpak/patches/windows-mingw-fixes.patch b/thirdparty/etcpak/patches/windows-mingw-fixes.patch
new file mode 100644
index 0000000000..1da60e4a4f
--- /dev/null
+++ b/thirdparty/etcpak/patches/windows-mingw-fixes.patch
@@ -0,0 +1,63 @@
+diff --git a/thirdparty/etcpak/BlockData.cpp b/thirdparty/etcpak/BlockData.cpp
+index a2cd032c5b..bd738085f3 100644
+--- a/thirdparty/etcpak/BlockData.cpp
++++ b/thirdparty/etcpak/BlockData.cpp
+@@ -15,7 +15,7 @@
+ # include <arm_neon.h>
+ #endif
+
+-#ifdef __SSE4_1__
++#if defined __SSE4_1__ || defined __AVX2__ || defined _MSC_VER
+ # ifdef _MSC_VER
+ # include <intrin.h>
+ # include <Windows.h>
+@@ -24,12 +24,6 @@
+ # else
+ # include <x86intrin.h>
+ # endif
+-#else
+-# ifndef _MSC_VER
+-# include <byteswap.h>
+-# define _bswap(x) bswap_32(x)
+-# define _bswap64(x) bswap_64(x)
+-# endif
+ #endif
+
+ #ifndef _bswap
+diff --git a/thirdparty/etcpak/ProcessRGB.cpp b/thirdparty/etcpak/ProcessRGB.cpp
+index 220d5c55e2..9dc5a78b67 100644
+--- a/thirdparty/etcpak/ProcessRGB.cpp
++++ b/thirdparty/etcpak/ProcessRGB.cpp
+@@ -1,5 +1,6 @@
+ #include <array>
+ #include <string.h>
++#include <limits>
+
+ #ifdef __ARM_NEON
+ # include <arm_neon.h>
+@@ -21,12 +22,6 @@
+ # else
+ # include <x86intrin.h>
+ # endif
+-#else
+-# ifndef _MSC_VER
+-# include <byteswap.h>
+-# define _bswap(x) bswap_32(x)
+-# define _bswap64(x) bswap_64(x)
+-# endif
+ #endif
+
+ #ifndef _bswap
+diff --git a/thirdparty/etcpak/System.cpp b/thirdparty/etcpak/System.cpp
+index 1383d0ecd0..a09b289cb2 100644
+--- a/thirdparty/etcpak/System.cpp
++++ b/thirdparty/etcpak/System.cpp
+@@ -35,7 +35,7 @@ unsigned int System::CPUCores()
+
+ void System::SetThreadName( std::thread& thread, const char* name )
+ {
+-#ifdef _WIN32
++#ifdef _MSC_VER
+ const DWORD MS_VC_EXCEPTION=0x406D1388;
+
+ # pragma pack( push, 8 )