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>
This commit is contained in:
parent
b895071895
commit
d840165a32
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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 "";
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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)));
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*************************************************************************/
|
||||
/* image_compress_etc.h */
|
||||
/* image_etcpak.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,9 +28,24 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMAGE_COMPRESS_ETC_H
|
||||
#define IMAGE_COMPRESS_ETC_H
|
||||
#ifndef IMAGE_ETCPAK_H
|
||||
#define IMAGE_ETCPAK_H
|
||||
|
||||
void _register_etc_compress_func();
|
||||
#include "core/io/image.h"
|
||||
|
||||
#endif // IMAGE_COMPRESS_ETC_H
|
||||
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 _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);
|
||||
|
||||
#endif // IMAGE_ETCPAK_H
|
|
@ -30,19 +30,13 @@
|
|||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "image_compress_etc.h"
|
||||
#include "texture_loader_pkm.h"
|
||||
#include "image_etcpak.h"
|
||||
|
||||
static Ref<ResourceFormatPKM> resource_loader_pkm;
|
||||
|
||||
void register_etc_types() {
|
||||
resource_loader_pkm.instance();
|
||||
ResourceLoader::add_resource_format_loader(resource_loader_pkm);
|
||||
|
||||
_register_etc_compress_func();
|
||||
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_etc_types() {
|
||||
ResourceLoader::remove_resource_format_loader(resource_loader_pkm);
|
||||
resource_loader_pkm.unref();
|
||||
void unregister_etcpak_types() {
|
||||
}
|
|
@ -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();
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
- Upstream: https://github.com/wolfpld/etcpak
|
||||
- Version: git (403d38b3f1cb347c196d845d0a05e44a00d17169, 2021)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
Important: Some Godot-made changes, see `patches` folders.
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
||||
- all .cpp and .h files in EtcLib/
|
||||
- README.md, LICENSE, AUTHORS
|
||||
|
||||
Important: Some files have Godot-made changes.
|
||||
They are marked with `// -- GODOT start --` and `// -- GODOT end --`
|
||||
comments.
|
||||
|
||||
- All `.cpp` and `.hpp` files in the root folder except `Application.cpp`.
|
||||
- `lz4` folder.
|
||||
- `AUTHORS.txt` and `LICENSE.txt`
|
||||
|
||||
## fonts
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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 "???";
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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++)
|
|
@ -0,0 +1,3 @@
|
|||
Bartosz Taudul <wolf@nereid.pl>
|
||||
Daniel Jungmann <el.3d.source@gmail.com>
|
||||
Florian Penzkofer <fp@nullptr.de>
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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()
|
||||
{
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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 ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __DARKRL__TIMING_HPP__
|
||||
#define __DARKRL__TIMING_HPP__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t GetTime();
|
||||
|
||||
#endif
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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++ )
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue