diff options
Diffstat (limited to 'thirdparty')
147 files changed, 7162 insertions, 13982 deletions
diff --git a/thirdparty/README.md b/thirdparty/README.md index 6dca29e856..97f21f8539 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -86,20 +86,20 @@ 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 (f27daea656ff77671580f838a889e33049430ebd, 2021) +- License: BSD-3-Clause 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. +- Only the files relevant for compression (i.e. `Process*.cpp` and their deps): + ``` + Dither.{cpp,hpp} ForceInline.hpp Math.hpp ProcessCommon.hpp ProcessRGB.{cpp,hpp} + ProcessDxtc.{cpp,hpp} Tables.{cpp,hpp} Vector.hpp + ``` +- `AUTHORS.txt` and `LICENSE.txt` ## fonts @@ -186,17 +186,17 @@ Files extracted from upstream source: ## icu4c - Upstream: https://github.com/unicode-org/icu -- Version: 68.2 (84e1f26ea77152936e70d53178a816dbfbf69989, 2020) +- Version: 69.1 (0e7b4428866f3133b4abba2d932ee3faa708db1d, 2021) - License: Unicode Files extracted from upstream source: - the `common` folder -- `APIChangeReport.md`, `LICENSE` +- `LICENSE` Files generated from upstream source: -- the `icudt68l.dat` built with the provided `godot_data.json` config file (see +- the `icudt69l.dat` built with the provided `godot_data.json` config file (see https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md for instructions) @@ -344,7 +344,7 @@ File extracted from upstream release tarball: ## meshoptimizer - Upstream: https://github.com/zeux/meshoptimizer -- Version: git (e3f53f66e7a35b9b8764bee478589d79e34fa698, 2021) +- Version: 0.16 (95893c0566646434dd675b708d293fcb2d526d08, 2021) - License: MIT Files extracted from upstream repository: diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp index 6873a95d90..c79623bd57 100644 --- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp +++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp @@ -80,7 +80,6 @@ struct ClipVertex btVector3 v; int id; //b2ContactID id; - //b2ContactID id; }; #define b2Dot(a, b) (a).dot(b) diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp index fec9b03213..4372489fa1 100644 --- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp +++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp @@ -43,7 +43,6 @@ void btMultiBodyJointMotor::finalizeMultiDof() unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF); // row 0: the lower bound - // row 0: the lower bound jacobianA(0)[offset] = 1; m_numDofsFinalized = m_jacSizeBoth; diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp index 25ddd539bf..5c20d2a0d4 100644 --- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp +++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp @@ -45,7 +45,6 @@ void btMultiBodySphericalJointMotor::finalizeMultiDof() unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF); // row 0: the lower bound - // row 0: the lower bound jacobianA(0)[offset] = 1; m_numDofsFinalized = m_jacSizeBoth; diff --git a/thirdparty/etc2comp/AUTHORS b/thirdparty/etc2comp/AUTHORS deleted file mode 100644 index e78a7f4d21..0000000000 --- a/thirdparty/etc2comp/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -# This is the list of Etc2Comp authors for copyright purposes. -# -# This does not necessarily list everyone who has contributed code, since in -# some cases, their employer may be the copyright holder. To see the full list -# of contributors, see the revision history in source control. -Google Inc. -Blue Shift Inc. diff --git a/thirdparty/etc2comp/Etc.cpp b/thirdparty/etc2comp/Etc.cpp deleted file mode 100644 index a5ee706048..0000000000 --- a/thirdparty/etc2comp/Etc.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "EtcConfig.h" -#include "Etc.h" -#include "EtcFilter.h" - -#include <string.h> - -namespace Etc -{ - // ---------------------------------------------------------------------------------------------------- - // C-style inteface to the encoder - // - void Encode(float *a_pafSourceRGBA, - unsigned int a_uiSourceWidth, - unsigned int a_uiSourceHeight, - Image::Format a_format, - ErrorMetric a_eErrMetric, - float a_fEffort, - unsigned int a_uiJobs, - unsigned int a_uiMaxJobs, - unsigned char **a_ppaucEncodingBits, - unsigned int *a_puiEncodingBitsBytes, - unsigned int *a_puiExtendedWidth, - unsigned int *a_puiExtendedHeight, - int *a_piEncodingTime_ms, bool a_bVerboseOutput) - { - - Image image(a_pafSourceRGBA, a_uiSourceWidth, - a_uiSourceHeight, - a_eErrMetric); - image.m_bVerboseOutput = a_bVerboseOutput; - image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs); - - *a_ppaucEncodingBits = image.GetEncodingBits(); - *a_puiEncodingBitsBytes = image.GetEncodingBitsBytes(); - *a_puiExtendedWidth = image.GetExtendedWidth(); - *a_puiExtendedHeight = image.GetExtendedHeight(); - *a_piEncodingTime_ms = image.GetEncodingTimeMs(); - } - - void EncodeMipmaps(float *a_pafSourceRGBA, - unsigned int a_uiSourceWidth, - unsigned int a_uiSourceHeight, - Image::Format a_format, - ErrorMetric a_eErrMetric, - float a_fEffort, - unsigned int a_uiJobs, - unsigned int a_uiMaxJobs, - unsigned int a_uiMaxMipmaps, - unsigned int a_uiMipFilterFlags, - RawImage* a_pMipmapImages, - int *a_piEncodingTime_ms, - bool a_bVerboseOutput) - { - auto mipWidth = a_uiSourceWidth; - auto mipHeight = a_uiSourceHeight; - int totalEncodingTime = 0; - for(unsigned int mip = 0; mip < a_uiMaxMipmaps && mipWidth >= 1 && mipHeight >= 1; mip++) - { - float* pImageData = nullptr; - float* pMipImage = nullptr; - - if(mip == 0) - { - pImageData = a_pafSourceRGBA; - } - else - { - pMipImage = new float[mipWidth*mipHeight*4]; - if(FilterTwoPass(a_pafSourceRGBA, a_uiSourceWidth, a_uiSourceHeight, pMipImage, mipWidth, mipHeight, a_uiMipFilterFlags, Etc::FilterLanczos3) ) - { - pImageData = pMipImage; - } - } - - if ( pImageData ) - { - - Image image(pImageData, mipWidth, mipHeight, a_eErrMetric); - - image.m_bVerboseOutput = a_bVerboseOutput; - image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs); - - a_pMipmapImages[mip].paucEncodingBits = std::shared_ptr<unsigned char>(image.GetEncodingBits(), [](unsigned char *p) { delete[] p; }); - a_pMipmapImages[mip].uiEncodingBitsBytes = image.GetEncodingBitsBytes(); - a_pMipmapImages[mip].uiExtendedWidth = image.GetExtendedWidth(); - a_pMipmapImages[mip].uiExtendedHeight = image.GetExtendedHeight(); - - totalEncodingTime += image.GetEncodingTimeMs(); - } - - if(pMipImage) - { - delete[] pMipImage; - } - - if (!pImageData) - { - break; - } - - mipWidth >>= 1; - mipHeight >>= 1; - } - - *a_piEncodingTime_ms = totalEncodingTime; - } - - - // ---------------------------------------------------------------------------------------------------- - // - -} diff --git a/thirdparty/etc2comp/Etc.h b/thirdparty/etc2comp/Etc.h deleted file mode 100644 index 439388d649..0000000000 --- a/thirdparty/etc2comp/Etc.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcConfig.h" -#include "EtcImage.h" -#include "EtcColor.h" -#include "EtcErrorMetric.h" -#include <memory> - -#define ETCCOMP_MIN_EFFORT_LEVEL (0.0f) -#define ETCCOMP_DEFAULT_EFFORT_LEVEL (40.0f) -#define ETCCOMP_MAX_EFFORT_LEVEL (100.0f) - -namespace Etc -{ - class Block4x4EncodingBits; - - struct RawImage - { - int uiExtendedWidth; - int uiExtendedHeight; - unsigned int uiEncodingBitsBytes; - std::shared_ptr<unsigned char> paucEncodingBits; - }; - - - - // C-style inteface to the encoder - void Encode(float *a_pafSourceRGBA, - unsigned int a_uiSourceWidth, - unsigned int a_uiSourceHeight, - Image::Format a_format, - ErrorMetric a_eErrMetric, - float a_fEffort, - unsigned int a_uiJobs, - unsigned int a_uimaxJobs, - unsigned char **a_ppaucEncodingBits, - unsigned int *a_puiEncodingBitsBytes, - unsigned int *a_puiExtendedWidth, - unsigned int *a_puiExtendedHeight, - int *a_piEncodingTime_ms, bool a_bVerboseOutput = false); - - void EncodeMipmaps(float *a_pafSourceRGBA, - unsigned int a_uiSourceWidth, - unsigned int a_uiSourceHeight, - Image::Format a_format, - ErrorMetric a_eErrMetric, - float a_fEffort, - unsigned int a_uiJobs, - unsigned int a_uiMaxJobs, - unsigned int a_uiMaxMipmaps, - unsigned int a_uiMipFilterFlags, - RawImage* a_pMipmaps, - int *a_piEncodingTime_ms, bool a_bVerboseOutput = false); - -} diff --git a/thirdparty/etc2comp/EtcBlock4x4.cpp b/thirdparty/etc2comp/EtcBlock4x4.cpp deleted file mode 100644 index 3082fe60db..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4.cpp - -Implements the state associated with each 4x4 block of pixels in an image - -Source images that are not a multiple of 4x4 are extended to fill the Block4x4 using pixels with an -alpha of NAN - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4.h" - -#include "EtcBlock4x4EncodingBits.h" -#include "EtcColor.h" -#include "EtcImage.h" -#include "EtcColorFloatRGBA.h" -#include "EtcBlock4x4Encoding_RGB8.h" -#include "EtcBlock4x4Encoding_RGBA8.h" -#include "EtcBlock4x4Encoding_RGB8A1.h" -#include "EtcBlock4x4Encoding_R11.h" -#include "EtcBlock4x4Encoding_RG11.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> - -namespace Etc -{ - // ETC pixels are scanned vertically. - // this mapping is for when someone wants to scan the ETC pixels horizontally - const unsigned int Block4x4::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 }; - - // ---------------------------------------------------------------------------------------------------- - // - Block4x4::Block4x4(void) - { - m_pimageSource = nullptr; - m_uiSourceH = 0; - m_uiSourceV = 0; - - m_sourcealphamix = SourceAlphaMix::UNKNOWN; - m_boolBorderPixels = false; - m_boolPunchThroughPixels = false; - - m_pencoding = nullptr; - - m_errormetric = ErrorMetric::NUMERIC; - - } - Block4x4::~Block4x4() - { - m_pimageSource = nullptr; - if (m_pencoding) - { - delete m_pencoding; - m_pencoding = nullptr; - } - } - // ---------------------------------------------------------------------------------------------------- - // initialization prior to encoding from a source image - // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource - // a_paucEncodingBits is the place to store the final encoding - // a_errormetric is used for finding the best encoding - // - void Block4x4::InitFromSource(Image *a_pimageSource, - unsigned int a_uiSourceH, unsigned int a_uiSourceV, - unsigned char *a_paucEncodingBits, - ErrorMetric a_errormetric) - { - - Block4x4(); - - m_pimageSource = a_pimageSource; - m_uiSourceH = a_uiSourceH; - m_uiSourceV = a_uiSourceV; - m_errormetric = a_errormetric; - - SetSourcePixels(); - - // set block encoder function - switch (m_pimageSource->GetFormat()) - { - case Image::Format::ETC1: - m_pencoding = new Block4x4Encoding_ETC1; - break; - - case Image::Format::RGB8: - case Image::Format::SRGB8: - m_pencoding = new Block4x4Encoding_RGB8; - break; - - case Image::Format::RGBA8: - case Image::Format::SRGBA8: - if (a_errormetric == RGBX) - { - m_pencoding = new Block4x4Encoding_RGBA8; - } - else - { - switch (m_sourcealphamix) - { - case SourceAlphaMix::OPAQUE: - m_pencoding = new Block4x4Encoding_RGBA8_Opaque; - break; - - case SourceAlphaMix::TRANSPARENT: - m_pencoding = new Block4x4Encoding_RGBA8_Transparent; - break; - - case SourceAlphaMix::TRANSLUCENT: - m_pencoding = new Block4x4Encoding_RGBA8; - break; - - default: - assert(0); - break; - } - break; - } - break; - - case Image::Format::RGB8A1: - case Image::Format::SRGB8A1: - switch (m_sourcealphamix) - { - case SourceAlphaMix::OPAQUE: - m_pencoding = new Block4x4Encoding_RGB8A1_Opaque; - break; - - case SourceAlphaMix::TRANSPARENT: - m_pencoding = new Block4x4Encoding_RGB8A1_Transparent; - break; - - case SourceAlphaMix::TRANSLUCENT: - if (m_boolPunchThroughPixels) - { - m_pencoding = new Block4x4Encoding_RGB8A1; - } - else - { - m_pencoding = new Block4x4Encoding_RGB8A1_Opaque; - } - break; - - default: - assert(0); - break; - } - break; - - case Image::Format::R11: - case Image::Format::SIGNED_R11: - m_pencoding = new Block4x4Encoding_R11; - break; - case Image::Format::RG11: - case Image::Format::SIGNED_RG11: - m_pencoding = new Block4x4Encoding_RG11; - break; - default: - assert(0); - break; - } - - m_pencoding->InitFromSource(this, m_afrgbaSource, - a_paucEncodingBits, a_errormetric); - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization of encoding state from a prior encoding using encoding bits - // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource - // a_paucEncodingBits is the place to read the prior encoding - // a_imageformat is used to determine how to interpret a_paucEncodingBits - // a_errormetric was used for the prior encoding - // - void Block4x4::InitFromEtcEncodingBits(Image::Format a_imageformat, - unsigned int a_uiSourceH, unsigned int a_uiSourceV, - unsigned char *a_paucEncodingBits, - Image *a_pimageSource, - ErrorMetric a_errormetric) - { - Block4x4(); - - m_pimageSource = a_pimageSource; - m_uiSourceH = a_uiSourceH; - m_uiSourceV = a_uiSourceV; - m_errormetric = a_errormetric; - - SetSourcePixels(); - - // set block encoder function - switch (a_imageformat) - { - case Image::Format::ETC1: - m_pencoding = new Block4x4Encoding_ETC1; - break; - - case Image::Format::RGB8: - case Image::Format::SRGB8: - m_pencoding = new Block4x4Encoding_RGB8; - break; - - case Image::Format::RGBA8: - case Image::Format::SRGBA8: - m_pencoding = new Block4x4Encoding_RGBA8; - break; - - case Image::Format::RGB8A1: - case Image::Format::SRGB8A1: - m_pencoding = new Block4x4Encoding_RGB8A1; - break; - - case Image::Format::R11: - case Image::Format::SIGNED_R11: - m_pencoding = new Block4x4Encoding_R11; - break; - case Image::Format::RG11: - case Image::Format::SIGNED_RG11: - m_pencoding = new Block4x4Encoding_RG11; - break; - default: - assert(0); - break; - } - - m_pencoding->InitFromEncodingBits(this, a_paucEncodingBits, m_afrgbaSource, - m_pimageSource->GetErrorMetric()); - - } - - // ---------------------------------------------------------------------------------------------------- - // set source pixels from m_pimageSource - // set m_alphamix - // - void Block4x4::SetSourcePixels(void) - { - - Image::Format imageformat = m_pimageSource->GetFormat(); - - // alpha census - unsigned int uiTransparentSourcePixels = 0; - unsigned int uiOpaqueSourcePixels = 0; - - // copy source to consecutive memory locations - // convert from image horizontal scan to block vertical scan - unsigned int uiPixel = 0; - for (unsigned int uiBlockPixelH = 0; uiBlockPixelH < Block4x4::COLUMNS; uiBlockPixelH++) - { - unsigned int uiSourcePixelH = m_uiSourceH + uiBlockPixelH; - - for (unsigned int uiBlockPixelV = 0; uiBlockPixelV < Block4x4::ROWS; uiBlockPixelV++) - { - unsigned int uiSourcePixelV = m_uiSourceV + uiBlockPixelV; - - ColorFloatRGBA *pfrgbaSource = m_pimageSource->GetSourcePixel(uiSourcePixelH, uiSourcePixelV); - - // if pixel extends beyond source image because of block padding - if (pfrgbaSource == nullptr) - { - m_afrgbaSource[uiPixel] = ColorFloatRGBA(0.0f, 0.0f, 0.0f, NAN); // denotes border pixel - m_boolBorderPixels = true; - uiTransparentSourcePixels++; - } - else - { - //get teh current pixel data, and store some of the attributes - //before capping values to fit the encoder type - - m_afrgbaSource[uiPixel] = (*pfrgbaSource).ClampRGBA(); - - if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX) - { - m_pimageSource->m_iNumOpaquePixels++; - } - else if (m_afrgbaSource[uiPixel].fA == 0.0f) - { - m_pimageSource->m_iNumTransparentPixels++; - } - else if(m_afrgbaSource[uiPixel].fA > 0.0f && m_afrgbaSource[uiPixel].fA < 1.0f) - { - m_pimageSource->m_iNumTranslucentPixels++; - } - else - { - m_pimageSource->m_numOutOfRangeValues.fA++; - } - - if (m_afrgbaSource[uiPixel].fR != 0.0f) - { - m_pimageSource->m_numColorValues.fR++; - //make sure we are getting a float between 0-1 - if (m_afrgbaSource[uiPixel].fR - 1.0f > 0.0f) - { - m_pimageSource->m_numOutOfRangeValues.fR++; - } - } - - if (m_afrgbaSource[uiPixel].fG != 0.0f) - { - m_pimageSource->m_numColorValues.fG++; - if (m_afrgbaSource[uiPixel].fG - 1.0f > 0.0f) - { - m_pimageSource->m_numOutOfRangeValues.fG++; - } - } - if (m_afrgbaSource[uiPixel].fB != 0.0f) - { - m_pimageSource->m_numColorValues.fB++; - if (m_afrgbaSource[uiPixel].fB - 1.0f > 0.0f) - { - m_pimageSource->m_numOutOfRangeValues.fB++; - } - } - // for formats with no alpha, set source alpha to 1 - if (imageformat == Image::Format::ETC1 || - imageformat == Image::Format::RGB8 || - imageformat == Image::Format::SRGB8) - { - m_afrgbaSource[uiPixel].fA = 1.0f; - } - - if (imageformat == Image::Format::R11 || - imageformat == Image::Format::SIGNED_R11) - { - m_afrgbaSource[uiPixel].fA = 1.0f; - m_afrgbaSource[uiPixel].fG = 0.0f; - m_afrgbaSource[uiPixel].fB = 0.0f; - } - - if (imageformat == Image::Format::RG11 || - imageformat == Image::Format::SIGNED_RG11) - { - m_afrgbaSource[uiPixel].fA = 1.0f; - m_afrgbaSource[uiPixel].fB = 0.0f; - } - - - // for RGB8A1, set source alpha to 0.0 or 1.0 - // set punch through flag - if (imageformat == Image::Format::RGB8A1 || - imageformat == Image::Format::SRGB8A1) - { - if (m_afrgbaSource[uiPixel].fA >= 0.5f) - { - m_afrgbaSource[uiPixel].fA = 1.0f; - } - else - { - m_afrgbaSource[uiPixel].fA = 0.0f; - m_boolPunchThroughPixels = true; - } - } - - if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX) - { - uiOpaqueSourcePixels++; - } - else if (m_afrgbaSource[uiPixel].fA == 0.0f) - { - uiTransparentSourcePixels++; - } - - } - - uiPixel += 1; - } - } - - if (uiOpaqueSourcePixels == PIXELS) - { - m_sourcealphamix = SourceAlphaMix::OPAQUE; - } - else if (uiTransparentSourcePixels == PIXELS) - { - m_sourcealphamix = SourceAlphaMix::TRANSPARENT; - } - else - { - m_sourcealphamix = SourceAlphaMix::TRANSLUCENT; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // return a name for the encoding mode - // - const char * Block4x4::GetEncodingModeName(void) - { - - switch (m_pencoding->GetMode()) - { - case Block4x4Encoding::MODE_ETC1: - return "ETC1"; - case Block4x4Encoding::MODE_T: - return "T"; - case Block4x4Encoding::MODE_H: - return "H"; - case Block4x4Encoding::MODE_PLANAR: - return "PLANAR"; - default: - return "???"; - } - } - - // ---------------------------------------------------------------------------------------------------- - // - -} diff --git a/thirdparty/etc2comp/EtcBlock4x4.h b/thirdparty/etc2comp/EtcBlock4x4.h deleted file mode 100644 index 0fd30c598d..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcColor.h" -#include "EtcColorFloatRGBA.h" -#include "EtcErrorMetric.h" -#include "EtcImage.h" -#include "EtcBlock4x4Encoding.h" - -namespace Etc -{ - class Block4x4EncodingBits; - - class Block4x4 - { - public: - - static const unsigned int ROWS = 4; - static const unsigned int COLUMNS = 4; - static const unsigned int PIXELS = ROWS * COLUMNS; - - // the alpha mix for a 4x4 block of pixels - enum class SourceAlphaMix - { - UNKNOWN, - // - OPAQUE, // all 1.0 - TRANSPARENT, // all 0.0 or NAN - TRANSLUCENT // not all opaque or transparent - }; - - typedef void (Block4x4::*EncoderFunctionPtr)(void); - - Block4x4(void); - ~Block4x4(); - void InitFromSource(Image *a_pimageSource, - unsigned int a_uiSourceH, - unsigned int a_uiSourceV, - unsigned char *a_paucEncodingBits, - ErrorMetric a_errormetric); - - void InitFromEtcEncodingBits(Image::Format a_imageformat, - unsigned int a_uiSourceH, - unsigned int a_uiSourceV, - unsigned char *a_paucEncodingBits, - Image *a_pimageSource, - ErrorMetric a_errormetric); - - // return true if final iteration was performed - inline void PerformEncodingIteration(float a_fEffort) - { - m_pencoding->PerformIteration(a_fEffort); - } - - inline void SetEncodingBitsFromEncoding(void) - { - m_pencoding->SetEncodingBits(); - } - - inline unsigned int GetSourceH(void) - { - return m_uiSourceH; - } - - inline unsigned int GetSourceV(void) - { - return m_uiSourceV; - } - - inline float GetError(void) - { - return m_pencoding->GetError(); - } - - static const unsigned int s_auiPixelOrderHScan[PIXELS]; - - inline ColorFloatRGBA * GetDecodedColors(void) - { - return m_pencoding->GetDecodedColors(); - } - - inline float * GetDecodedAlphas(void) - { - return m_pencoding->GetDecodedAlphas(); - } - - inline Block4x4Encoding::Mode GetEncodingMode(void) - { - return m_pencoding->GetMode(); - } - - inline bool GetFlip(void) - { - return m_pencoding->GetFlip(); - } - - inline bool IsDifferential(void) - { - return m_pencoding->IsDifferential(); - } - - inline ColorFloatRGBA * GetSource() - { - return m_afrgbaSource; - } - - inline ErrorMetric GetErrorMetric() - { - return m_errormetric; - } - - const char * GetEncodingModeName(void); - - inline Block4x4Encoding * GetEncoding(void) - { - return m_pencoding; - } - - inline SourceAlphaMix GetSourceAlphaMix(void) - { - return m_sourcealphamix; - } - - inline Image * GetImageSource(void) - { - return m_pimageSource; - } - - inline bool HasBorderPixels(void) - { - return m_boolBorderPixels; - } - - inline bool HasPunchThroughPixels(void) - { - return m_boolPunchThroughPixels; - } - - private: - - void SetSourcePixels(void); - - Image *m_pimageSource; - unsigned int m_uiSourceH; - unsigned int m_uiSourceV; - ErrorMetric m_errormetric; - ColorFloatRGBA m_afrgbaSource[PIXELS]; // vertical scan - - SourceAlphaMix m_sourcealphamix; - bool m_boolBorderPixels; // marked as rgba(NAN, NAN, NAN, NAN) - bool m_boolPunchThroughPixels; // RGB8A1 or SRGB8A1 with any pixels with alpha < 0.5 - - Block4x4Encoding *m_pencoding; - - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp deleted file mode 100644 index 7a9e68c4cf..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4Encoding.cpp - -Block4x4Encoding is the abstract base class for the different encoders. Each encoder targets a -particular file format (e.g. ETC1, RGB8, RGBA8, R11) - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4Encoding.h" - -#include "EtcBlock4x4EncodingBits.h" -#include "EtcBlock4x4.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> - -namespace Etc -{ - // ---------------------------------------------------------------------------------------------------- - // - const float Block4x4Encoding::LUMA_WEIGHT = 3.0f; - const float Block4x4Encoding::CHROMA_BLUE_WEIGHT = 0.5f; - - // ---------------------------------------------------------------------------------------------------- - // - Block4x4Encoding::Block4x4Encoding(void) - { - - m_pblockParent = nullptr; - - m_pafrgbaSource = nullptr; - - m_boolBorderPixels = false; - - m_fError = -1.0f; - - m_mode = MODE_UNKNOWN; - - m_uiEncodingIterations = 0; - m_boolDone = false; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f); - m_afDecodedAlphas[uiPixel] = -1.0f; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // initialize the generic encoding for a 4x4 block - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // init the decoded pixels to -1 to mark them as undefined - // init the error to -1 to mark it as undefined - // - void Block4x4Encoding::Init(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - - m_pblockParent = a_pblockParent; - - m_pafrgbaSource = a_pafrgbaSource; - - m_boolBorderPixels = m_pblockParent->HasBorderPixels(); - - m_fError = -1.0f; - - m_uiEncodingIterations = 0; - - m_errormetric = a_errormetric; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f); - m_afDecodedAlphas[uiPixel] = -1.0f; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // calculate the error for the block by summing the pixel errors - // - void Block4x4Encoding::CalcBlockError(void) - { - m_fError = 0.0f; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_fError += CalcPixelError(m_afrgbaDecodedColors[uiPixel], m_afDecodedAlphas[uiPixel], - m_pafrgbaSource[uiPixel]); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // calculate the error between the source pixel and the decoded pixel - // the error amount is base on the error metric - // - float Block4x4Encoding::CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha, - ColorFloatRGBA a_frgbaSourcePixel) - { - - // if a border pixel - if (isnan(a_frgbaSourcePixel.fA)) - { - return 0.0f; - } - - if (m_errormetric == ErrorMetric::RGBA) - { - assert(a_fDecodedAlpha >= 0.0f); - - float fDRed = (a_fDecodedAlpha * a_frgbaDecodedColor.fR) - - (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fR); - float fDGreen = (a_fDecodedAlpha * a_frgbaDecodedColor.fG) - - (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fG); - float fDBlue = (a_fDecodedAlpha * a_frgbaDecodedColor.fB) - - (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fB); - - float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA; - - return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha; - } - else if (m_errormetric == ErrorMetric::RGBX) - { - assert(a_fDecodedAlpha >= 0.0f); - - float fDRed = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR; - float fDGreen = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG; - float fDBlue = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB; - float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA; - - return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha; - } - else if (m_errormetric == ErrorMetric::REC709) - { - assert(a_fDecodedAlpha >= 0.0f); - - float fLuma1 = a_frgbaSourcePixel.fR*0.2126f + a_frgbaSourcePixel.fG*0.7152f + a_frgbaSourcePixel.fB*0.0722f; - float fChromaR1 = 0.5f * ((a_frgbaSourcePixel.fR - fLuma1) * (1.0f / (1.0f - 0.2126f))); - float fChromaB1 = 0.5f * ((a_frgbaSourcePixel.fB - fLuma1) * (1.0f / (1.0f - 0.0722f))); - - float fLuma2 = a_frgbaDecodedColor.fR*0.2126f + - a_frgbaDecodedColor.fG*0.7152f + - a_frgbaDecodedColor.fB*0.0722f; - float fChromaR2 = 0.5f * ((a_frgbaDecodedColor.fR - fLuma2) * (1.0f / (1.0f - 0.2126f))); - float fChromaB2 = 0.5f * ((a_frgbaDecodedColor.fB - fLuma2) * (1.0f / (1.0f - 0.0722f))); - - float fDeltaL = a_frgbaSourcePixel.fA * fLuma1 - a_fDecodedAlpha * fLuma2; - float fDeltaCr = a_frgbaSourcePixel.fA * fChromaR1 - a_fDecodedAlpha * fChromaR2; - float fDeltaCb = a_frgbaSourcePixel.fA * fChromaB1 - a_fDecodedAlpha * fChromaB2; - - float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA; - - // Favor Luma accuracy over Chroma, and Red over Blue - return LUMA_WEIGHT*fDeltaL*fDeltaL + - fDeltaCr*fDeltaCr + - CHROMA_BLUE_WEIGHT*fDeltaCb*fDeltaCb + - fDAlpha*fDAlpha; - #if 0 - float fDRed = a_frgbaDecodedPixel.fR - a_frgbaSourcePixel.fR; - float fDGreen = a_frgbaDecodedPixel.fG - a_frgbaSourcePixel.fG; - float fDBlue = a_frgbaDecodedPixel.fB - a_frgbaSourcePixel.fB; - return 2.0f * 3.0f * fDeltaL * fDeltaL + fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue; -#endif - } - else if (m_errormetric == ErrorMetric::NORMALXYZ) - { - float fDecodedX = 2.0f * a_frgbaDecodedColor.fR - 1.0f; - float fDecodedY = 2.0f * a_frgbaDecodedColor.fG - 1.0f; - float fDecodedZ = 2.0f * a_frgbaDecodedColor.fB - 1.0f; - - float fDecodedLength = sqrtf(fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ); - - if (fDecodedLength < 0.5f) - { - return 1.0f; - } - else if (fDecodedLength == 0.0f) - { - fDecodedX = 1.0f; - fDecodedY = 0.0f; - fDecodedZ = 0.0f; - } - else - { - fDecodedX /= fDecodedLength; - fDecodedY /= fDecodedLength; - fDecodedZ /= fDecodedLength; - } - - float fSourceX = 2.0f * a_frgbaSourcePixel.fR - 1.0f; - float fSourceY = 2.0f * a_frgbaSourcePixel.fG - 1.0f; - float fSourceZ = 2.0f * a_frgbaSourcePixel.fB - 1.0f; - - float fSourceLength = sqrtf(fSourceX*fSourceX + fSourceY*fSourceY + fSourceZ*fSourceZ); - - if (fSourceLength == 0.0f) - { - fSourceX = 1.0f; - fSourceY = 0.0f; - fSourceZ = 0.0f; - } - else - { - fSourceX /= fSourceLength; - fSourceY /= fSourceLength; - fSourceZ /= fSourceLength; - } - - float fDotProduct = fSourceX*fDecodedX + fSourceY*fDecodedY + fSourceZ*fDecodedZ; - float fNormalizedDotProduct = 1.0f - 0.5f * (fDotProduct + 1.0f); - float fDotProductError = fNormalizedDotProduct * fNormalizedDotProduct; - - float fLength2 = fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ; - float fLength2Error = fabsf(1.0f - fLength2); - - float fDeltaW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA; - float fErrorW = fDeltaW * fDeltaW; - - return fDotProductError + fLength2Error + fErrorW; - } - else // ErrorMetric::NUMERIC - { - assert(a_fDecodedAlpha >= 0.0f); - - float fDX = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR; - float fDY = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG; - float fDZ = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB; - float fDW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA; - - return fDX*fDX + fDY*fDY + fDZ*fDZ + fDW*fDW; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc - diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.h b/thirdparty/etc2comp/EtcBlock4x4Encoding.h deleted file mode 100644 index c14c3b8616..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcColorFloatRGBA.h" - -#include "EtcErrorMetric.h" - -#include <assert.h> -#include <float.h> - -namespace Etc -{ - class Block4x4; - - // abstract base class for specific encodings - class Block4x4Encoding - { - public: - - static const unsigned int ROWS = 4; - static const unsigned int COLUMNS = 4; - static const unsigned int PIXELS = ROWS * COLUMNS; - static const float LUMA_WEIGHT; - static const float CHROMA_BLUE_WEIGHT; - - typedef enum - { - MODE_UNKNOWN, - // - MODE_ETC1, - MODE_T, - MODE_H, - MODE_PLANAR, - MODE_R11, - MODE_RG11, - // - MODES - } Mode; - - Block4x4Encoding(void); - //virtual ~Block4x4Encoding(void) =0; - virtual ~Block4x4Encoding(void) {} - virtual void InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) = 0; - - virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - - ErrorMetric a_errormetric) = 0; - - // perform an iteration of the encoding - // the first iteration must generate a complete, valid (if poor) encoding - virtual void PerformIteration(float a_fEffort) = 0; - - void CalcBlockError(void); - - inline float GetError(void) - { - assert(m_fError >= 0.0f); - - return m_fError; - } - - inline ColorFloatRGBA * GetDecodedColors(void) - { - return m_afrgbaDecodedColors; - } - - inline float * GetDecodedAlphas(void) - { - return m_afDecodedAlphas; - } - - virtual void SetEncodingBits(void) = 0; - - virtual bool GetFlip(void) = 0; - - virtual bool IsDifferential(void) = 0; - - virtual bool HasSeverelyBentDifferentialColors(void) const = 0; - - inline Mode GetMode(void) - { - return m_mode; - } - - inline bool IsDone(void) - { - return m_boolDone; - } - - inline void SetDoneIfPerfect() - { - if (GetError() == 0.0f) - { - m_boolDone = true; - } - } - - float CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha, - ColorFloatRGBA a_frgbaSourcePixel); - - protected: - - void Init(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - - ErrorMetric a_errormetric); - - Block4x4 *m_pblockParent; - ColorFloatRGBA *m_pafrgbaSource; - - bool m_boolBorderPixels; // if block has any border pixels - - ColorFloatRGBA m_afrgbaDecodedColors[PIXELS]; // decoded RGB components, ignore Alpha - float m_afDecodedAlphas[PIXELS]; // decoded alpha component - float m_fError; // error for RGBA relative to m_pafrgbaSource - - // intermediate encoding - Mode m_mode; - - unsigned int m_uiEncodingIterations; - bool m_boolDone; // all iterations have been done - ErrorMetric m_errormetric; - - private: - - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h b/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h deleted file mode 100644 index 4065700379..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <assert.h> - -namespace Etc -{ - - // ################################################################################ - // Block4x4EncodingBits - // Base class for Block4x4EncodingBits_XXXX - // ################################################################################ - - class Block4x4EncodingBits - { - public: - - enum class Format - { - UNKNOWN, - // - RGB8, - RGBA8, - R11, - RG11, - RGB8A1, - // - FORMATS - }; - - static unsigned int GetBytesPerBlock(Format a_format) - { - switch (a_format) - { - case Format::RGB8: - case Format::R11: - case Format::RGB8A1: - return 8; - break; - - case Format::RGBA8: - case Format::RG11: - return 16; - break; - - default: - return 0; - break; - } - - } - - }; - - // ################################################################################ - // Block4x4EncodingBits_RGB8 - // Encoding bits for the RGB portion of ETC1, RGB8, RGB8A1 and RGBA8 - // ################################################################################ - - class Block4x4EncodingBits_RGB8 - { - public: - - static const unsigned int BYTES_PER_BLOCK = 8; - - inline Block4x4EncodingBits_RGB8(void) - { - assert(sizeof(Block4x4EncodingBits_RGB8) == BYTES_PER_BLOCK); - - for (unsigned int uiByte = 0; uiByte < BYTES_PER_BLOCK; uiByte++) - { - auc[uiByte] = 0; - } - - } - - typedef struct - { - unsigned red2 : 4; - unsigned red1 : 4; - // - unsigned green2 : 4; - unsigned green1 : 4; - // - unsigned blue2 : 4; - unsigned blue1 : 4; - // - unsigned flip : 1; - unsigned diff : 1; - unsigned cw2 : 3; - unsigned cw1 : 3; - // - unsigned int selectors; - } Individual; - - typedef struct - { - signed dred2 : 3; - unsigned red1 : 5; - // - signed dgreen2 : 3; - unsigned green1 : 5; - // - signed dblue2 : 3; - unsigned blue1 : 5; - // - unsigned flip : 1; - unsigned diff : 1; - unsigned cw2 : 3; - unsigned cw1 : 3; - // - unsigned int selectors; - } Differential; - - typedef struct - { - unsigned red1b : 2; - unsigned detect2 : 1; - unsigned red1a : 2; - unsigned detect1 : 3; - // - unsigned blue1 : 4; - unsigned green1 : 4; - // - unsigned green2 : 4; - unsigned red2 : 4; - // - unsigned db : 1; - unsigned diff : 1; - unsigned da : 2; - unsigned blue2 : 4; - // - unsigned int selectors; - } T; - - typedef struct - { - unsigned green1a : 3; - unsigned red1 : 4; - unsigned detect1 : 1; - // - unsigned blue1b : 2; - unsigned detect3 : 1; - unsigned blue1a : 1; - unsigned green1b : 1; - unsigned detect2 : 3; - // - unsigned green2a : 3; - unsigned red2 : 4; - unsigned blue1c : 1; - // - unsigned db : 1; - unsigned diff : 1; - unsigned da : 1; - unsigned blue2 : 4; - unsigned green2b : 1; - // - unsigned int selectors; - } H; - - typedef struct - { - unsigned originGreen1 : 1; - unsigned originRed : 6; - unsigned detect1 : 1; - // - unsigned originBlue1 : 1; - unsigned originGreen2 : 6; - unsigned detect2 : 1; - // - unsigned originBlue3 : 2; - unsigned detect4 : 1; - unsigned originBlue2 : 2; - unsigned detect3 : 3; - // - unsigned horizRed2 : 1; - unsigned diff : 1; - unsigned horizRed1 : 5; - unsigned originBlue4 : 1; - // - unsigned horizBlue1: 1; - unsigned horizGreen : 7; - // - unsigned vertRed1 : 3; - unsigned horizBlue2 : 5; - // - unsigned vertGreen1 : 5; - unsigned vertRed2 : 3; - // - unsigned vertBlue : 6; - unsigned vertGreen2 : 2; - } Planar; - - union - { - unsigned char auc[BYTES_PER_BLOCK]; - unsigned long int ul; - Individual individual; - Differential differential; - T t; - H h; - Planar planar; - }; - - }; - - // ################################################################################ - // Block4x4EncodingBits_A8 - // Encoding bits for the A portion of RGBA8 - // ################################################################################ - - class Block4x4EncodingBits_A8 - { - public: - - static const unsigned int BYTES_PER_BLOCK = 8; - static const unsigned int SELECTOR_BYTES = 6; - - typedef struct - { - unsigned base : 8; - unsigned table : 4; - unsigned multiplier : 4; - unsigned selectors0 : 8; - unsigned selectors1 : 8; - unsigned selectors2 : 8; - unsigned selectors3 : 8; - unsigned selectors4 : 8; - unsigned selectors5 : 8; - } Data; - - Data data; - - }; - - // ################################################################################ - // Block4x4EncodingBits_R11 - // Encoding bits for the R portion of R11 - // ################################################################################ - - class Block4x4EncodingBits_R11 - { - public: - - static const unsigned int BYTES_PER_BLOCK = 8; - static const unsigned int SELECTOR_BYTES = 6; - - typedef struct - { - unsigned base : 8; - unsigned table : 4; - unsigned multiplier : 4; - unsigned selectors0 : 8; - unsigned selectors1 : 8; - unsigned selectors2 : 8; - unsigned selectors3 : 8; - unsigned selectors4 : 8; - unsigned selectors5 : 8; - } Data; - - Data data; - - }; - - class Block4x4EncodingBits_RG11 - { - public: - - static const unsigned int BYTES_PER_BLOCK = 16; - static const unsigned int SELECTOR_BYTES = 12; - - typedef struct - { - //Red portion - unsigned baseR : 8; - unsigned tableIndexR : 4; - unsigned multiplierR : 4; - unsigned selectorsR0 : 8; - unsigned selectorsR1 : 8; - unsigned selectorsR2 : 8; - unsigned selectorsR3 : 8; - unsigned selectorsR4 : 8; - unsigned selectorsR5 : 8; - //Green portion - unsigned baseG : 8; - unsigned tableIndexG : 4; - unsigned multiplierG : 4; - unsigned selectorsG0 : 8; - unsigned selectorsG1 : 8; - unsigned selectorsG2 : 8; - unsigned selectorsG3 : 8; - unsigned selectorsG4 : 8; - unsigned selectorsG5 : 8; - } Data; - - Data data; - - }; - -} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp deleted file mode 100644 index a27f74c0d5..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp +++ /dev/null @@ -1,1281 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4Encoding_ETC1.cpp - -Block4x4Encoding_ETC1 is the encoder to use when targetting file format ETC1. This encoder is also -used for the ETC1 subset of file format RGB8, RGBA8 and RGB8A1 - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4Encoding_ETC1.h" - -#include "EtcBlock4x4.h" -#include "EtcBlock4x4EncodingBits.h" -#include "EtcDifferentialTrys.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <float.h> -#include <limits> - -namespace Etc -{ - - // pixel processing order if the flip bit = 0 (horizontal split) - const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip0[PIXELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - - // pixel processing order if the flip bit = 1 (vertical split) - const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip1[PIXELS] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 }; - - // pixel processing order for horizontal scan (ETC normally does a vertical scan) - const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 }; - - // pixel indices for different block halves - const unsigned int Block4x4Encoding_ETC1::s_auiLeftPixelMapping[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - const unsigned int Block4x4Encoding_ETC1::s_auiRightPixelMapping[8] = { 8, 9, 10, 11, 12, 13, 14, 15 }; - const unsigned int Block4x4Encoding_ETC1::s_auiTopPixelMapping[8] = { 0, 1, 4, 5, 8, 9, 12, 13 }; - const unsigned int Block4x4Encoding_ETC1::s_auiBottomPixelMapping[8] = { 2, 3, 6, 7, 10, 11, 14, 15 }; - - // CW ranges that the ETC1 decoders use - // CW is basically a contrast for the different selector bits, since these values are offsets to the base color - // the first axis in the array is indexed by the CW in the encoding bits - // the second axis in the array is indexed by the selector bits - float Block4x4Encoding_ETC1::s_aafCwTable[CW_RANGES][SELECTORS] = - { - { 2.0f / 255.0f, 8.0f / 255.0f, -2.0f / 255.0f, -8.0f / 255.0f }, - { 5.0f / 255.0f, 17.0f / 255.0f, -5.0f / 255.0f, -17.0f / 255.0f }, - { 9.0f / 255.0f, 29.0f / 255.0f, -9.0f / 255.0f, -29.0f / 255.0f }, - { 13.0f / 255.0f, 42.0f / 255.0f, -13.0f / 255.0f, -42.0f / 255.0f }, - { 18.0f / 255.0f, 60.0f / 255.0f, -18.0f / 255.0f, -60.0f / 255.0f }, - { 24.0f / 255.0f, 80.0f / 255.0f, -24.0f / 255.0f, -80.0f / 255.0f }, - { 33.0f / 255.0f, 106.0f / 255.0f, -33.0f / 255.0f, -106.0f / 255.0f }, - { 47.0f / 255.0f, 183.0f / 255.0f, -47.0f / 255.0f, -183.0f / 255.0f } - }; - - // ---------------------------------------------------------------------------------------------------- - // - Block4x4Encoding_ETC1::Block4x4Encoding_ETC1(void) - { - m_mode = MODE_ETC1; - m_boolDiff = false; - m_boolFlip = false; - m_frgbaColor1 = ColorFloatRGBA(); - m_frgbaColor2 = ColorFloatRGBA(); - m_uiCW1 = 0; - m_uiCW2 = 0; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = 0; - m_afDecodedAlphas[uiPixel] = 1.0f; - } - - m_boolMostLikelyFlip = false; - - m_fError = -1.0f; - - m_fError1 = -1.0f; - m_fError2 = -1.0f; - m_boolSeverelyBentDifferentialColors = false; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afDecodedAlphas[uiPixel] = 1.0f; - } - - } - - Block4x4Encoding_ETC1::~Block4x4Encoding_ETC1(void) {} - - // ---------------------------------------------------------------------------------------------------- - // initialization prior to encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits - // - void Block4x4Encoding_ETC1::InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) - { - - Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afDecodedAlphas[uiPixel] = 1.0f; - } - - m_fError = -1.0f; - - m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits); - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits of a previous encoding - // - void Block4x4Encoding_ETC1::InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - - Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); - m_fError = -1.0f; - - m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; - - m_mode = MODE_ETC1; - m_boolDiff = m_pencodingbitsRGB8->individual.diff; - m_boolFlip = m_pencodingbitsRGB8->individual.flip; - if (m_boolDiff) - { - int iR2 = (int)(m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2); - if (iR2 < 0) - { - iR2 = 0; - } - else if (iR2 > 31) - { - iR2 = 31; - } - - int iG2 = (int)(m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2); - if (iG2 < 0) - { - iG2 = 0; - } - else if (iG2 > 31) - { - iG2 = 31; - } - - int iB2 = (int)(m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2); - if (iB2 < 0) - { - iB2 = 0; - } - else if (iB2 > 31) - { - iB2 = 31; - } - - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2); - - } - else - { - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red1, m_pencodingbitsRGB8->individual.green1, m_pencodingbitsRGB8->individual.blue1); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red2, m_pencodingbitsRGB8->individual.green2, m_pencodingbitsRGB8->individual.blue2); - } - - m_uiCW1 = m_pencodingbitsRGB8->individual.cw1; - m_uiCW2 = m_pencodingbitsRGB8->individual.cw2; - - InitFromEncodingBits_Selectors(); - - Decode(); - - CalcBlockError(); - } - - // ---------------------------------------------------------------------------------------------------- - // init the selectors from a prior encoding - // - void Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(void) - { - - unsigned char *paucSelectors = (unsigned char *)&m_pencodingbitsRGB8->individual.selectors; - - for (unsigned int iPixel = 0; iPixel < PIXELS; iPixel++) - { - unsigned int uiByteMSB = (unsigned int)(1 - (iPixel / 8)); - unsigned int uiByteLSB = (unsigned int)(3 - (iPixel / 8)); - unsigned int uiShift = (unsigned int)(iPixel & 7); - - unsigned int uiSelectorMSB = (unsigned int)((paucSelectors[uiByteMSB] >> uiShift) & 1); - unsigned int uiSelectorLSB = (unsigned int)((paucSelectors[uiByteLSB] >> uiShift) & 1); - - m_auiSelectors[iPixel] = (uiSelectorMSB << 1) + uiSelectorLSB; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_ETC1::PerformIteration(float a_fEffort) - { - assert(!m_boolDone); - - switch (m_uiEncodingIterations) - { - case 0: - PerformFirstIteration(); - break; - - case 1: - TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); - break; - - case 2: - TryIndividual(m_boolMostLikelyFlip, 1); - if (a_fEffort <= 49.5f) - { - m_boolDone = true; - } - break; - - case 3: - TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); - if (a_fEffort <= 59.5f) - { - m_boolDone = true; - } - break; - - case 4: - TryIndividual(!m_boolMostLikelyFlip, 1); - if (a_fEffort <= 69.5f) - { - m_boolDone = true; - } - break; - - case 5: - TryDegenerates1(); - if (a_fEffort <= 79.5f) - { - m_boolDone = true; - } - break; - - case 6: - TryDegenerates2(); - if (a_fEffort <= 89.5f) - { - m_boolDone = true; - } - break; - - case 7: - TryDegenerates3(); - if (a_fEffort <= 99.5f) - { - m_boolDone = true; - } - break; - - case 8: - TryDegenerates4(); - m_boolDone = true; - break; - - default: - assert(0); - break; - } - - m_uiEncodingIterations++; - SetDoneIfPerfect(); - } - - // ---------------------------------------------------------------------------------------------------- - // find best initial encoding to ensure block has a valid encoding - // - void Block4x4Encoding_ETC1::PerformFirstIteration(void) - { - CalculateMostLikelyFlip(); - - m_fError = FLT_MAX; - - TryDifferential(m_boolMostLikelyFlip, 0, 0, 0); - SetDoneIfPerfect(); - if (m_boolDone) - { - return; - } - - TryIndividual(m_boolMostLikelyFlip, 0); - SetDoneIfPerfect(); - if (m_boolDone) - { - return; - } - TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0); - SetDoneIfPerfect(); - if (m_boolDone) - { - return; - } - TryIndividual(!m_boolMostLikelyFlip, 0); - - } - - // ---------------------------------------------------------------------------------------------------- - // algorithm: - // create a source average color for the Left, Right, Top and Bottom halves using the 8 pixels in each half - // note: the "gray line" is the line of equal delta RGB that goes thru the average color - // for each half: - // see how close each of the 8 pixels are to the "gray line" that goes thru the source average color - // create an error value that is the sum of the distances from the gray line - // h_error is the sum of Left and Right errors - // v_error is the sum of Top and Bottom errors - // - void Block4x4Encoding_ETC1::CalculateMostLikelyFlip(void) - { - static const bool DEBUG_PRINT = false; - - CalculateSourceAverages(); - - float fLeftGrayErrorSum = 0.0f; - float fRightGrayErrorSum = 0.0f; - float fTopGrayErrorSum = 0.0f; - float fBottomGrayErrorSum = 0.0f; - - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - ColorFloatRGBA *pfrgbaLeft = &m_pafrgbaSource[uiPixel]; - ColorFloatRGBA *pfrgbaRight = &m_pafrgbaSource[uiPixel + 8]; - ColorFloatRGBA *pfrgbaTop = &m_pafrgbaSource[s_auiTopPixelMapping[uiPixel]]; - ColorFloatRGBA *pfrgbaBottom = &m_pafrgbaSource[s_auiBottomPixelMapping[uiPixel]]; - - float fLeftGrayError = CalcGrayDistance2(*pfrgbaLeft, m_frgbaSourceAverageLeft); - float fRightGrayError = CalcGrayDistance2(*pfrgbaRight, m_frgbaSourceAverageRight); - float fTopGrayError = CalcGrayDistance2(*pfrgbaTop, m_frgbaSourceAverageTop); - float fBottomGrayError = CalcGrayDistance2(*pfrgbaBottom, m_frgbaSourceAverageBottom); - - fLeftGrayErrorSum += fLeftGrayError; - fRightGrayErrorSum += fRightGrayError; - fTopGrayErrorSum += fTopGrayError; - fBottomGrayErrorSum += fBottomGrayError; - } - - if (DEBUG_PRINT) - { - printf("\n%.2f %.2f\n", fLeftGrayErrorSum + fRightGrayErrorSum, fTopGrayErrorSum + fBottomGrayErrorSum); - } - - m_boolMostLikelyFlip = (fTopGrayErrorSum + fBottomGrayErrorSum) < (fLeftGrayErrorSum + fRightGrayErrorSum); - - } - - // ---------------------------------------------------------------------------------------------------- - // calculate source pixel averages for each 2x2 quadrant in a 4x4 block - // these are used to determine the averages for each of the 4 different halves (left, right, top, bottom) - // ignore pixels that have alpha == NAN (these are border pixels outside of the source image) - // weight the averages based on a pixel's alpha - // - void Block4x4Encoding_ETC1::CalculateSourceAverages(void) - { - static const bool DEBUG_PRINT = false; - - bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX; - - if (m_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE || boolRGBX) - { - ColorFloatRGBA frgbaSumUL = m_pafrgbaSource[0] + m_pafrgbaSource[1] + m_pafrgbaSource[4] + m_pafrgbaSource[5]; - ColorFloatRGBA frgbaSumLL = m_pafrgbaSource[2] + m_pafrgbaSource[3] + m_pafrgbaSource[6] + m_pafrgbaSource[7]; - ColorFloatRGBA frgbaSumUR = m_pafrgbaSource[8] + m_pafrgbaSource[9] + m_pafrgbaSource[12] + m_pafrgbaSource[13]; - ColorFloatRGBA frgbaSumLR = m_pafrgbaSource[10] + m_pafrgbaSource[11] + m_pafrgbaSource[14] + m_pafrgbaSource[15]; - - m_frgbaSourceAverageLeft = (frgbaSumUL + frgbaSumLL) * 0.125f; - m_frgbaSourceAverageRight = (frgbaSumUR + frgbaSumLR) * 0.125f; - m_frgbaSourceAverageTop = (frgbaSumUL + frgbaSumUR) * 0.125f; - m_frgbaSourceAverageBottom = (frgbaSumLL + frgbaSumLR) * 0.125f; - } - else - { - float afSourceAlpha[PIXELS]; - - // treat alpha NAN as 0.0f - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - afSourceAlpha[uiPixel] = isnan(m_pafrgbaSource[uiPixel].fA) ? - 0.0f : - m_pafrgbaSource[uiPixel].fA; - } - - ColorFloatRGBA afrgbaAlphaWeightedSource[PIXELS]; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - afrgbaAlphaWeightedSource[uiPixel] = m_pafrgbaSource[uiPixel] * afSourceAlpha[uiPixel]; - } - - ColorFloatRGBA frgbaSumUL = afrgbaAlphaWeightedSource[0] + - afrgbaAlphaWeightedSource[1] + - afrgbaAlphaWeightedSource[4] + - afrgbaAlphaWeightedSource[5]; - - ColorFloatRGBA frgbaSumLL = afrgbaAlphaWeightedSource[2] + - afrgbaAlphaWeightedSource[3] + - afrgbaAlphaWeightedSource[6] + - afrgbaAlphaWeightedSource[7]; - - ColorFloatRGBA frgbaSumUR = afrgbaAlphaWeightedSource[8] + - afrgbaAlphaWeightedSource[9] + - afrgbaAlphaWeightedSource[12] + - afrgbaAlphaWeightedSource[13]; - - ColorFloatRGBA frgbaSumLR = afrgbaAlphaWeightedSource[10] + - afrgbaAlphaWeightedSource[11] + - afrgbaAlphaWeightedSource[14] + - afrgbaAlphaWeightedSource[15]; - - float fWeightSumUL = afSourceAlpha[0] + - afSourceAlpha[1] + - afSourceAlpha[4] + - afSourceAlpha[5]; - - float fWeightSumLL = afSourceAlpha[2] + - afSourceAlpha[3] + - afSourceAlpha[6] + - afSourceAlpha[7]; - - float fWeightSumUR = afSourceAlpha[8] + - afSourceAlpha[9] + - afSourceAlpha[12] + - afSourceAlpha[13]; - - float fWeightSumLR = afSourceAlpha[10] + - afSourceAlpha[11] + - afSourceAlpha[14] + - afSourceAlpha[15]; - - ColorFloatRGBA frgbaSumLeft = frgbaSumUL + frgbaSumLL; - ColorFloatRGBA frgbaSumRight = frgbaSumUR + frgbaSumLR; - ColorFloatRGBA frgbaSumTop = frgbaSumUL + frgbaSumUR; - ColorFloatRGBA frgbaSumBottom = frgbaSumLL + frgbaSumLR; - - float fWeightSumLeft = fWeightSumUL + fWeightSumLL; - float fWeightSumRight = fWeightSumUR + fWeightSumLR; - float fWeightSumTop = fWeightSumUL + fWeightSumUR; - float fWeightSumBottom = fWeightSumLL + fWeightSumLR; - - // check to see if there is at least 1 pixel with non-zero alpha - // completely transparent block should not make it to this code - assert((fWeightSumLeft + fWeightSumRight) > 0.0f); - assert((fWeightSumTop + fWeightSumBottom) > 0.0f); - - if (fWeightSumLeft > 0.0f) - { - m_frgbaSourceAverageLeft = frgbaSumLeft * (1.0f/fWeightSumLeft); - } - if (fWeightSumRight > 0.0f) - { - m_frgbaSourceAverageRight = frgbaSumRight * (1.0f/fWeightSumRight); - } - if (fWeightSumTop > 0.0f) - { - m_frgbaSourceAverageTop = frgbaSumTop * (1.0f/fWeightSumTop); - } - if (fWeightSumBottom > 0.0f) - { - m_frgbaSourceAverageBottom = frgbaSumBottom * (1.0f/fWeightSumBottom); - } - - if (fWeightSumLeft == 0.0f) - { - assert(fWeightSumRight > 0.0f); - m_frgbaSourceAverageLeft = m_frgbaSourceAverageRight; - } - if (fWeightSumRight == 0.0f) - { - assert(fWeightSumLeft > 0.0f); - m_frgbaSourceAverageRight = m_frgbaSourceAverageLeft; - } - if (fWeightSumTop == 0.0f) - { - assert(fWeightSumBottom > 0.0f); - m_frgbaSourceAverageTop = m_frgbaSourceAverageBottom; - } - if (fWeightSumBottom == 0.0f) - { - assert(fWeightSumTop > 0.0f); - m_frgbaSourceAverageBottom = m_frgbaSourceAverageTop; - } - } - - - - if (DEBUG_PRINT) - { - printf("\ntarget: [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f]\n", - m_frgbaSourceAverageLeft.fR, m_frgbaSourceAverageLeft.fG, m_frgbaSourceAverageLeft.fB, - m_frgbaSourceAverageRight.fR, m_frgbaSourceAverageRight.fG, m_frgbaSourceAverageRight.fB, - m_frgbaSourceAverageTop.fR, m_frgbaSourceAverageTop.fG, m_frgbaSourceAverageTop.fB, - m_frgbaSourceAverageBottom.fR, m_frgbaSourceAverageBottom.fG, m_frgbaSourceAverageBottom.fB); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try an ETC1 differential mode encoding - // use a_boolFlip to set the encoding F bit - // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius] - // use a_iGrayOffset1 and a_iGrayOffset2 to offset the basecolor to search for degenerate encodings - // replace the encoding if the encoding error is less than previous encoding - // - void Block4x4Encoding_ETC1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, - int a_iGrayOffset1, int a_iGrayOffset2) - { - - ColorFloatRGBA frgbaColor1; - ColorFloatRGBA frgbaColor2; - - const unsigned int *pauiPixelMapping1; - const unsigned int *pauiPixelMapping2; - - if (a_boolFlip) - { - frgbaColor1 = m_frgbaSourceAverageTop; - frgbaColor2 = m_frgbaSourceAverageBottom; - - pauiPixelMapping1 = s_auiTopPixelMapping; - pauiPixelMapping2 = s_auiBottomPixelMapping; - } - else - { - frgbaColor1 = m_frgbaSourceAverageLeft; - frgbaColor2 = m_frgbaSourceAverageRight; - - pauiPixelMapping1 = s_auiLeftPixelMapping; - pauiPixelMapping2 = s_auiRightPixelMapping; - } - - DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, - a_uiRadius, a_iGrayOffset1, a_iGrayOffset2); - - Block4x4Encoding_ETC1 encodingTry = *this; - encodingTry.m_boolFlip = a_boolFlip; - - encodingTry.TryDifferentialHalf(&trys.m_half1); - encodingTry.TryDifferentialHalf(&trys.m_half2); - - // find best halves that are within differential range - DifferentialTrys::Try *ptryBest1 = nullptr; - DifferentialTrys::Try *ptryBest2 = nullptr; - encodingTry.m_fError = FLT_MAX; - - // see if the best of each half are in differential range - int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed; - int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen; - int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue; - if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3) - { - ptryBest1 = trys.m_half1.m_ptryBest; - ptryBest2 = trys.m_half2.m_ptryBest; - encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError; - } - else - { - // else, find the next best halves that are in differential range - for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0]; - ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys]; - ptry1++) - { - for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0]; - ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys]; - ptry2++) - { - iDRed = ptry2->m_iRed - ptry1->m_iRed; - bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4; - iDGreen = ptry2->m_iGreen - ptry1->m_iGreen; - bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4; - iDBlue = ptry2->m_iBlue - ptry1->m_iBlue; - bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4; - - if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta) - { - float fError = ptry1->m_fError + ptry2->m_fError; - - if (fError < encodingTry.m_fError) - { - encodingTry.m_fError = fError; - - ptryBest1 = ptry1; - ptryBest2 = ptry2; - } - } - - } - } - assert(encodingTry.m_fError < FLT_MAX); - assert(ptryBest1 != nullptr); - assert(ptryBest2 != nullptr); - } - - if (encodingTry.m_fError < m_fError) - { - m_mode = MODE_ETC1; - m_boolDiff = true; - m_boolFlip = encodingTry.m_boolFlip; - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue); - m_uiCW1 = ptryBest1->m_uiCW; - m_uiCW2 = ptryBest2->m_uiCW; - - for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++) - { - unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder]; - unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder]; - - unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder]; - unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder]; - - m_auiSelectors[uiPixel1] = uiSelector1; - m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder]; - - float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1]; - float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2]; - - m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB(); - m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB(); - } - - m_fError1 = ptryBest1->m_fError; - m_fError2 = ptryBest2->m_fError; - m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors; - m_fError = m_fError1 + m_fError2; - - // sanity check - { - int iRed1 = m_frgbaColor1.IntRed(31.0f); - int iGreen1 = m_frgbaColor1.IntGreen(31.0f); - int iBlue1 = m_frgbaColor1.IntBlue(31.0f); - - int iRed2 = m_frgbaColor2.IntRed(31.0f); - int iGreen2 = m_frgbaColor2.IntGreen(31.0f); - int iBlue2 = m_frgbaColor2.IntBlue(31.0f); - - iDRed = iRed2 - iRed1; - iDGreen = iGreen2 - iGreen1; - iDBlue = iBlue2 - iBlue1; - - assert(iDRed >= -4 && iDRed < 4); - assert(iDGreen >= -4 && iDGreen < 4); - assert(iDBlue >= -4 && iDBlue < 4); - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try an ETC1 differential mode encoding for a half of a 4x4 block - // vary the basecolor components using a radius - // - void Block4x4Encoding_ETC1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf) - { - - a_phalf->m_ptryBest = nullptr; - float fBestTryError = FLT_MAX; - - a_phalf->m_uiTrys = 0; - for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius; - iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius; - iRed++) - { - assert(iRed >= 0 && iRed <= 31); - - for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius; - iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius; - iGreen++) - { - assert(iGreen >= 0 && iGreen <= 31); - - for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius; - iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius; - iBlue++) - { - assert(iBlue >= 0 && iBlue <= 31); - - DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys]; - assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]); - - ptry->m_iRed = iRed; - ptry->m_iGreen = iGreen; - ptry->m_iBlue = iBlue; - ptry->m_fError = FLT_MAX; - ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue); - - // try each CW - for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) - { - unsigned int auiPixelSelectors[PIXELS / 2]; - ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2]; - float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - - // pre-compute decoded pixels for each selector - ColorFloatRGBA afrgbaSelectors[SELECTORS]; - assert(SELECTORS == 4); - afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB(); - afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB(); - afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB(); - afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB(); - - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]]; - ColorFloatRGBA frgbaDecodedPixel; - - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - frgbaDecodedPixel = afrgbaSelectors[uiSelector]; - - float fPixelError; - - fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]], - *pfrgbaSourcePixel); - - if (fPixelError < afPixelErrors[uiPixel]) - { - auiPixelSelectors[uiPixel] = uiSelector; - afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel; - afPixelErrors[uiPixel] = fPixelError; - } - - } - } - - // add up all pixel errors - float fCWError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - fCWError += afPixelErrors[uiPixel]; - } - - // if best CW so far - if (fCWError < ptry->m_fError) - { - ptry->m_uiCW = uiCW; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel]; - } - ptry->m_fError = fCWError; - } - - } - - if (ptry->m_fError < fBestTryError) - { - a_phalf->m_ptryBest = ptry; - fBestTryError = ptry->m_fError; - } - - assert(ptry->m_fError < FLT_MAX); - - a_phalf->m_uiTrys++; - } - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try an ETC1 individual mode encoding - // use a_boolFlip to set the encoding F bit - // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius] - // replace the encoding if the encoding error is less than previous encoding - // - void Block4x4Encoding_ETC1::TryIndividual(bool a_boolFlip, unsigned int a_uiRadius) - { - - ColorFloatRGBA frgbaColor1; - ColorFloatRGBA frgbaColor2; - - const unsigned int *pauiPixelMapping1; - const unsigned int *pauiPixelMapping2; - - if (a_boolFlip) - { - frgbaColor1 = m_frgbaSourceAverageTop; - frgbaColor2 = m_frgbaSourceAverageBottom; - - pauiPixelMapping1 = s_auiTopPixelMapping; - pauiPixelMapping2 = s_auiBottomPixelMapping; - } - else - { - frgbaColor1 = m_frgbaSourceAverageLeft; - frgbaColor2 = m_frgbaSourceAverageRight; - - pauiPixelMapping1 = s_auiLeftPixelMapping; - pauiPixelMapping2 = s_auiRightPixelMapping; - } - - IndividualTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, a_uiRadius); - - Block4x4Encoding_ETC1 encodingTry = *this; - encodingTry.m_boolFlip = a_boolFlip; - - encodingTry.TryIndividualHalf(&trys.m_half1); - encodingTry.TryIndividualHalf(&trys.m_half2); - - // use the best of each half - IndividualTrys::Try *ptryBest1 = trys.m_half1.m_ptryBest; - IndividualTrys::Try *ptryBest2 = trys.m_half2.m_ptryBest; - encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError; - - if (encodingTry.m_fError < m_fError) - { - m_mode = MODE_ETC1; - m_boolDiff = false; - m_boolFlip = encodingTry.m_boolFlip; - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue); - m_uiCW1 = ptryBest1->m_uiCW; - m_uiCW2 = ptryBest2->m_uiCW; - - for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++) - { - unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder]; - unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder]; - - unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder]; - unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder]; - - m_auiSelectors[uiPixel1] = uiSelector1; - m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder]; - - float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1]; - float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2]; - - m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB(); - m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB(); - } - - m_fError1 = ptryBest1->m_fError; - m_fError2 = ptryBest2->m_fError; - m_fError = m_fError1 + m_fError2; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try an ETC1 differential mode encoding for a half of a 4x4 block - // vary the basecolor components using a radius - // - void Block4x4Encoding_ETC1::TryIndividualHalf(IndividualTrys::Half *a_phalf) - { - - a_phalf->m_ptryBest = nullptr; - float fBestTryError = FLT_MAX; - - a_phalf->m_uiTrys = 0; - for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius; - iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius; - iRed++) - { - assert(iRed >= 0 && iRed <= 15); - - for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius; - iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius; - iGreen++) - { - assert(iGreen >= 0 && iGreen <= 15); - - for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius; - iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius; - iBlue++) - { - assert(iBlue >= 0 && iBlue <= 15); - - IndividualTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys]; - assert(ptry < &a_phalf->m_atry[IndividualTrys::Half::MAX_TRYS]); - - ptry->m_iRed = iRed; - ptry->m_iGreen = iGreen; - ptry->m_iBlue = iBlue; - ptry->m_fError = FLT_MAX; - ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue); - - // try each CW - for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) - { - unsigned int auiPixelSelectors[PIXELS / 2]; - ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2]; - float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - - // pre-compute decoded pixels for each selector - ColorFloatRGBA afrgbaSelectors[SELECTORS]; - assert(SELECTORS == 4); - afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB(); - afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB(); - afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB(); - afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB(); - - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]]; - ColorFloatRGBA frgbaDecodedPixel; - - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - frgbaDecodedPixel = afrgbaSelectors[uiSelector]; - - float fPixelError; - - fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]], - *pfrgbaSourcePixel); - - if (fPixelError < afPixelErrors[uiPixel]) - { - auiPixelSelectors[uiPixel] = uiSelector; - afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel; - afPixelErrors[uiPixel] = fPixelError; - } - - } - } - - // add up all pixel errors - float fCWError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - fCWError += afPixelErrors[uiPixel]; - } - - // if best CW so far - if (fCWError < ptry->m_fError) - { - ptry->m_uiCW = uiCW; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel]; - } - ptry->m_fError = fCWError; - } - - } - - if (ptry->m_fError < fBestTryError) - { - a_phalf->m_ptryBest = ptry; - fBestTryError = ptry->m_fError; - } - - assert(ptry->m_fError < FLT_MAX); - - a_phalf->m_uiTrys++; - } - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 1 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_ETC1::TryDegenerates1(void) - { - - TryDifferential(m_boolMostLikelyFlip, 1, -2, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 2, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 0, 2); - TryDifferential(m_boolMostLikelyFlip, 1, 0, -2); - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 2 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_ETC1::TryDegenerates2(void) - { - - TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0); - TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0); - TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2); - TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2); - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 3 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_ETC1::TryDegenerates3(void) - { - - TryDifferential(m_boolMostLikelyFlip, 1, -2, -2); - TryDifferential(m_boolMostLikelyFlip, 1, -2, 2); - TryDifferential(m_boolMostLikelyFlip, 1, 2, -2); - TryDifferential(m_boolMostLikelyFlip, 1, 2, 2); - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 4 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_ETC1::TryDegenerates4(void) - { - - TryDifferential(m_boolMostLikelyFlip, 1, -4, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 4, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 0, 4); - TryDifferential(m_boolMostLikelyFlip, 1, 0, -4); - - } - - // ---------------------------------------------------------------------------------------------------- - // find the best selector for each pixel based on a particular basecolor and CW that have been previously set - // calculate the selectors for each half of the block separately - // set the block error as the sum of each half's error - // - void Block4x4Encoding_ETC1::CalculateSelectors() - { - if (m_boolFlip) - { - CalculateHalfOfTheSelectors(0, s_auiTopPixelMapping); - CalculateHalfOfTheSelectors(1, s_auiBottomPixelMapping); - } - else - { - CalculateHalfOfTheSelectors(0, s_auiLeftPixelMapping); - CalculateHalfOfTheSelectors(1, s_auiRightPixelMapping); - } - - m_fError = m_fError1 + m_fError2; - } - - // ---------------------------------------------------------------------------------------------------- - // choose best selectors for half of the block - // calculate the error for half of the block - // - void Block4x4Encoding_ETC1::CalculateHalfOfTheSelectors(unsigned int a_uiHalf, - const unsigned int *pauiPixelMapping) - { - static const bool DEBUG_PRINT = false; - - ColorFloatRGBA *pfrgbaColor = a_uiHalf ? &m_frgbaColor2 : &m_frgbaColor1; - unsigned int *puiCW = a_uiHalf ? &m_uiCW2 : &m_uiCW1; - - float *pfHalfError = a_uiHalf ? &m_fError2 : &m_fError1; - *pfHalfError = FLT_MAX; - - // try each CW - for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) - { - if (DEBUG_PRINT) - { - printf("\ncw=%u\n", uiCW); - } - - unsigned int auiPixelSelectors[PIXELS / 2]; - ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2]; - float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - if (DEBUG_PRINT) - { - printf("\tsource [%.2f,%.2f,%.2f]\n", m_pafrgbaSource[pauiPixelMapping[uiPixel]].fR, - m_pafrgbaSource[pauiPixelMapping[uiPixel]].fG, m_pafrgbaSource[pauiPixelMapping[uiPixel]].fB); - } - - ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[pauiPixelMapping[uiPixel]]; - ColorFloatRGBA frgbaDecodedPixel; - - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - float fDeltaRGB = s_aafCwTable[uiCW][uiSelector]; - - frgbaDecodedPixel = (*pfrgbaColor + fDeltaRGB).ClampRGB(); - - float fPixelError; - - fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[pauiPixelMapping[uiPixel]], - *pfrgbaSourcePixel); - - if (DEBUG_PRINT) - { - printf("\tpixel %u, index %u [%.2f,%.2f,%.2f], error %.2f", uiPixel, uiSelector, - frgbaDecodedPixel.fR, - frgbaDecodedPixel.fG, - frgbaDecodedPixel.fB, - fPixelError); - } - - if (fPixelError < afPixelErrors[uiPixel]) - { - if (DEBUG_PRINT) - { - printf(" *"); - } - - auiPixelSelectors[uiPixel] = uiSelector; - afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel; - afPixelErrors[uiPixel] = fPixelError; - } - - if (DEBUG_PRINT) - { - printf("\n"); - } - } - } - - // add up all pixel errors - float fCWError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - fCWError += afPixelErrors[uiPixel]; - } - if (DEBUG_PRINT) - { - printf("\terror %.2f\n", fCWError); - } - - // if best CW so far - if (fCWError < *pfHalfError) - { - *pfHalfError = fCWError; - *puiCW = uiCW; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - m_auiSelectors[pauiPixelMapping[uiPixel]] = auiPixelSelectors[uiPixel]; - m_afrgbaDecodedColors[pauiPixelMapping[uiPixel]] = afrgbaDecodedPixels[uiPixel]; - } - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_ETC1::SetEncodingBits(void) - { - assert(m_mode == MODE_ETC1); - - if (m_boolDiff) - { - int iRed1 = m_frgbaColor1.IntRed(31.0f); - int iGreen1 = m_frgbaColor1.IntGreen(31.0f); - int iBlue1 = m_frgbaColor1.IntBlue(31.0f); - - int iRed2 = m_frgbaColor2.IntRed(31.0f); - int iGreen2 = m_frgbaColor2.IntGreen(31.0f); - int iBlue2 = m_frgbaColor2.IntBlue(31.0f); - - int iDRed2 = iRed2 - iRed1; - int iDGreen2 = iGreen2 - iGreen1; - int iDBlue2 = iBlue2 - iBlue1; - - assert(iDRed2 >= -4 && iDRed2 < 4); - assert(iDGreen2 >= -4 && iDGreen2 < 4); - assert(iDBlue2 >= -4 && iDBlue2 < 4); - - m_pencodingbitsRGB8->differential.red1 = (unsigned int)iRed1; - m_pencodingbitsRGB8->differential.green1 = (unsigned int)iGreen1; - m_pencodingbitsRGB8->differential.blue1 = (unsigned int)iBlue1; - - m_pencodingbitsRGB8->differential.dred2 = iDRed2; - m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2; - m_pencodingbitsRGB8->differential.dblue2 = iDBlue2; - } - else - { - m_pencodingbitsRGB8->individual.red1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); - m_pencodingbitsRGB8->individual.green1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); - m_pencodingbitsRGB8->individual.blue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); - - m_pencodingbitsRGB8->individual.red2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); - m_pencodingbitsRGB8->individual.green2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); - m_pencodingbitsRGB8->individual.blue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); - } - - m_pencodingbitsRGB8->individual.cw1 = m_uiCW1; - m_pencodingbitsRGB8->individual.cw2 = m_uiCW2; - - SetEncodingBits_Selectors(); - - m_pencodingbitsRGB8->individual.diff = (unsigned int)m_boolDiff; - m_pencodingbitsRGB8->individual.flip = (unsigned int)m_boolFlip; - - } - - // ---------------------------------------------------------------------------------------------------- - // set the selectors in the encoding bits - // - void Block4x4Encoding_ETC1::SetEncodingBits_Selectors(void) - { - - m_pencodingbitsRGB8->individual.selectors = 0; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiSelector = m_auiSelectors[uiPixel]; - - // set index msb - m_pencodingbitsRGB8->individual.selectors |= (uiSelector >> 1) << (uiPixel ^ 8); - - // set index lsb - m_pencodingbitsRGB8->individual.selectors |= (uiSelector & 1) << ((16 + uiPixel) ^ 8); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the decoded colors and decoded alpha based on the encoding state - // - void Block4x4Encoding_ETC1::Decode(void) - { - - const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0; - - for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++) - { - ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2; - unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2; - - unsigned int uiPixel = pauiPixelOrder[uiPixelOrder]; - - float fDelta = s_aafCwTable[uiCW][m_auiSelectors[uiPixel]]; - m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h deleted file mode 100644 index c0dc84d5d5..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcBlock4x4Encoding.h" -#include "EtcBlock4x4EncodingBits.h" -#include "EtcDifferentialTrys.h" -#include "EtcIndividualTrys.h" - -namespace Etc -{ - - // base class for Block4x4Encoding_RGB8 - class Block4x4Encoding_ETC1 : public Block4x4Encoding - { - public: - - Block4x4Encoding_ETC1(void); - virtual ~Block4x4Encoding_ETC1(void); - - virtual void InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - - unsigned char *a_paucEncodingBits, - ErrorMetric a_errormetric); - - virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - - ErrorMetric a_errormetric); - - virtual void PerformIteration(float a_fEffort); - - inline virtual bool GetFlip(void) - { - return m_boolFlip; - } - - inline virtual bool IsDifferential(void) - { - return m_boolDiff; - } - - virtual void SetEncodingBits(void); - - void Decode(void); - - inline ColorFloatRGBA GetColor1(void) const - { - return m_frgbaColor1; - } - - inline ColorFloatRGBA GetColor2(void) const - { - return m_frgbaColor2; - } - - inline const unsigned int * GetSelectors(void) const - { - return m_auiSelectors; - } - - inline unsigned int GetCW1(void) const - { - return m_uiCW1; - } - - inline unsigned int GetCW2(void) const - { - return m_uiCW2; - } - - inline bool HasSeverelyBentDifferentialColors(void) const - { - return m_boolSeverelyBentDifferentialColors; - } - - protected: - - static const unsigned int s_auiPixelOrderFlip0[PIXELS]; - static const unsigned int s_auiPixelOrderFlip1[PIXELS]; - static const unsigned int s_auiPixelOrderHScan[PIXELS]; - - static const unsigned int s_auiLeftPixelMapping[8]; - static const unsigned int s_auiRightPixelMapping[8]; - static const unsigned int s_auiTopPixelMapping[8]; - static const unsigned int s_auiBottomPixelMapping[8]; - - static const unsigned int SELECTOR_BITS = 2; - static const unsigned int SELECTORS = 1 << SELECTOR_BITS; - - static const unsigned int CW_BITS = 3; - static const unsigned int CW_RANGES = 1 << CW_BITS; - - static float s_aafCwTable[CW_RANGES][SELECTORS]; - static unsigned char s_aucDifferentialCwRange[256]; - - static const int MAX_DIFFERENTIAL = 3; - static const int MIN_DIFFERENTIAL = -4; - - void InitFromEncodingBits_Selectors(void); - - void PerformFirstIteration(void); - void CalculateMostLikelyFlip(void); - - void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, - int a_iGrayOffset1, int a_iGrayOffset2); - void TryDifferentialHalf(DifferentialTrys::Half *a_phalf); - - void TryIndividual(bool a_boolFlip, unsigned int a_uiRadius); - void TryIndividualHalf(IndividualTrys::Half *a_phalf); - - void TryDegenerates1(void); - void TryDegenerates2(void); - void TryDegenerates3(void); - void TryDegenerates4(void); - - void CalculateSelectors(); - void CalculateHalfOfTheSelectors(unsigned int a_uiHalf, - const unsigned int *pauiPixelMapping); - - // calculate the distance2 of r_frgbaPixel from r_frgbaTarget's gray line - inline float CalcGrayDistance2(ColorFloatRGBA &r_frgbaPixel, - ColorFloatRGBA &r_frgbaTarget) - { - float fDeltaGray = ((r_frgbaPixel.fR - r_frgbaTarget.fR) + - (r_frgbaPixel.fG - r_frgbaTarget.fG) + - (r_frgbaPixel.fB - r_frgbaTarget.fB)) / 3.0f; - - ColorFloatRGBA frgbaPointOnGrayLine = (r_frgbaTarget + fDeltaGray).ClampRGB(); - - float fDR = r_frgbaPixel.fR - frgbaPointOnGrayLine.fR; - float fDG = r_frgbaPixel.fG - frgbaPointOnGrayLine.fG; - float fDB = r_frgbaPixel.fB - frgbaPointOnGrayLine.fB; - - return (fDR*fDR) + (fDG*fDG) + (fDB*fDB); - } - - void SetEncodingBits_Selectors(void); - - // intermediate encoding - bool m_boolDiff; - bool m_boolFlip; - ColorFloatRGBA m_frgbaColor1; - ColorFloatRGBA m_frgbaColor2; - unsigned int m_uiCW1; - unsigned int m_uiCW2; - unsigned int m_auiSelectors[PIXELS]; - - // state shared between iterations - ColorFloatRGBA m_frgbaSourceAverageLeft; - ColorFloatRGBA m_frgbaSourceAverageRight; - ColorFloatRGBA m_frgbaSourceAverageTop; - ColorFloatRGBA m_frgbaSourceAverageBottom; - bool m_boolMostLikelyFlip; - - // stats - float m_fError1; // error for Etc1 half 1 - float m_fError2; // error for Etc1 half 2 - bool m_boolSeverelyBentDifferentialColors; // only valid if m_boolDiff; - - // final encoding - Block4x4EncodingBits_RGB8 *m_pencodingbitsRGB8; // or RGB8 portion of Block4x4EncodingBits_RGB8A8 - - private: - - void CalculateSourceAverages(void); - - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp deleted file mode 100644 index 4c012fbbf1..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4Encoding_R11.cpp - -Block4x4Encoding_R11 is the encoder to use when targetting file format R11 and SR11 (signed R11). - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4Encoding_R11.h" - -#include "EtcBlock4x4EncodingBits.h" -#include "EtcBlock4x4.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <float.h> -#include <limits> - -namespace Etc -{ - - // modifier values to use for R11, SR11, RG11 and SRG11 - float Block4x4Encoding_R11::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS] - { - { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f }, - { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f }, - { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f }, - { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f }, - - { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f }, - { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f }, - { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, - { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, - - { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, - { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, - { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, - { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, - - { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, - { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f }, - { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f }, - { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f } - }; - - // ---------------------------------------------------------------------------------------------------- - // - Block4x4Encoding_R11::Block4x4Encoding_R11(void) - { - - m_pencodingbitsR11 = nullptr; - - } - - Block4x4Encoding_R11::~Block4x4Encoding_R11(void) {} - // ---------------------------------------------------------------------------------------------------- - // initialization prior to encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits - // - void Block4x4Encoding_R11::InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) - { - Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); - - m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits; - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits of a previous encoding - // - void Block4x4Encoding_R11::InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits; - - // init RGB portion - Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent, - (unsigned char *)m_pencodingbitsR11, - a_pafrgbaSource, - a_errormetric); - - // init R11 portion - { - m_mode = MODE_R11; - if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - m_fRedBase = (float)(signed char)m_pencodingbitsR11->data.base; - } - else - { - m_fRedBase = (float)(unsigned char)m_pencodingbitsR11->data.base; - } - m_fRedMultiplier = (float)m_pencodingbitsR11->data.multiplier; - m_uiRedModifierTableIndex = m_pencodingbitsR11->data.table; - - unsigned long long int ulliSelectorBits = 0; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors0 << 40; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors1 << 32; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors2 << 24; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors3 << 16; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors4 << 8; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors5; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiShift = 45 - (3 * uiPixel); - m_auiRedSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (SELECTORS - 1); - } - - // decode the red channel - // calc red error - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - float fDecodedPixelData = 0.0f; - if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) - { - fDecodedPixelData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, - m_uiRedModifierTableIndex, - m_auiRedSelectors[uiPixel]); - } - else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - fDecodedPixelData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, - m_uiRedModifierTableIndex, - m_auiRedSelectors[uiPixel]); - } - else - { - assert(0); - } - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fDecodedPixelData, 0.0f, 0.0f, 1.0f); - } - CalcBlockError(); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_R11::PerformIteration(float a_fEffort) - { - assert(!m_boolDone); - m_mode = MODE_R11; - - switch (m_uiEncodingIterations) - { - case 0: - m_fError = FLT_MAX; - m_fRedBlockError = FLT_MAX; // artificially high value - CalculateR11(8, 0.0f, 0.0f); - m_fError = m_fRedBlockError; - break; - - case 1: - CalculateR11(8, 2.0f, 1.0f); - m_fError = m_fRedBlockError; - if (a_fEffort <= 24.5f) - { - m_boolDone = true; - } - break; - - case 2: - CalculateR11(8, 12.0f, 1.0f); - m_fError = m_fRedBlockError; - if (a_fEffort <= 49.5f) - { - m_boolDone = true; - } - break; - - case 3: - CalculateR11(7, 6.0f, 1.0f); - m_fError = m_fRedBlockError; - break; - - case 4: - CalculateR11(6, 3.0f, 1.0f); - m_fError = m_fRedBlockError; - break; - - case 5: - CalculateR11(5, 1.0f, 0.0f); - m_fError = m_fRedBlockError; - m_boolDone = true; - break; - - default: - assert(0); - break; - } - - m_uiEncodingIterations++; - SetDoneIfPerfect(); - } - - // ---------------------------------------------------------------------------------------------------- - // find the best combination of base color, multiplier and selectors - // - // a_uiSelectorsUsed limits the number of selector combinations to try - // a_fBaseRadius limits the range of base colors to try - // a_fMultiplierRadius limits the range of multipliers to try - // - void Block4x4Encoding_R11::CalculateR11(unsigned int a_uiSelectorsUsed, - float a_fBaseRadius, float a_fMultiplierRadius) - { - // maps from virtual (monotonic) selector to ETC selector - static const unsigned int auiVirtualSelectorMap[8] = {3, 2, 1, 0, 4, 5, 6, 7}; - - // find min/max red - float fMinRed = 1.0f; - float fMaxRed = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - // ignore border pixels - float fAlpha = m_pafrgbaSource[uiPixel].fA; - if (isnan(fAlpha)) - { - continue; - } - - float fRed = m_pafrgbaSource[uiPixel].fR; - - if (fRed < fMinRed) - { - fMinRed = fRed; - } - if (fRed > fMaxRed) - { - fMaxRed = fRed; - } - } - assert(fMinRed <= fMaxRed); - - float fRedRange = (fMaxRed - fMinRed); - - // try each modifier table entry - for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++) - { - for (unsigned int uiMinVirtualSelector = 0; - uiMinVirtualSelector <= (8- a_uiSelectorsUsed); - uiMinVirtualSelector++) - { - unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1; - - unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector]; - unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector]; - - float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector]; - - float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] - - s_aafModifierTable[uiTableEntry][uiMinSelector]; - - float fCenterRatio = fTableEntryCenter / fTableEntryRange; - - float fCenter = fMinRed + fCenterRatio*fRedRange; - fCenter = roundf(255.0f * fCenter) / 255.0f; - - float fMinBase = fCenter - (a_fBaseRadius / 255.0f); - if (fMinBase < 0.0f) - { - fMinBase = 0.0f; - } - - float fMaxBase = fCenter + (a_fBaseRadius / 255.0f); - if (fMaxBase > 1.0f) - { - fMaxBase = 1.0f; - } - - for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f)) - { - float fRangeMultiplier = roundf(fRedRange / fTableEntryRange); - - float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius; - if (fMinMultiplier < 1.0f) - { - fMinMultiplier = 0.0f; - } - else if (fMinMultiplier > 15.0f) - { - fMinMultiplier = 15.0f; - } - - float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius; - if (fMaxMultiplier < 1.0f) - { - fMaxMultiplier = 1.0f; - } - else if (fMaxMultiplier > 15.0f) - { - fMaxMultiplier = 15.0f; - } - - for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f) - { - // find best selector for each pixel - unsigned int auiBestSelectors[PIXELS]; - float afBestRedError[PIXELS]; - float afBestPixelRed[PIXELS]; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - float fBestPixelRedError = FLT_MAX; - - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - float fPixelRed = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector); - - ColorFloatRGBA frgba(fPixelRed, m_pafrgbaSource[uiPixel].fG,0.0f,1.0f); - - float fPixelRedError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]); - - if (fPixelRedError < fBestPixelRedError) - { - fBestPixelRedError = fPixelRedError; - auiBestSelectors[uiPixel] = uiSelector; - afBestRedError[uiPixel] = fBestPixelRedError; - afBestPixelRed[uiPixel] = fPixelRed; - } - } - } - float fBlockError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - fBlockError += afBestRedError[uiPixel]; - } - if (fBlockError < m_fRedBlockError) - { - m_fRedBlockError = fBlockError; - - if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) - { - m_fRedBase = 255.0f * fBase; - } - else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - m_fRedBase = (fBase * 255) - 128; - } - else - { - assert(0); - } - m_fRedMultiplier = fMultiplier; - m_uiRedModifierTableIndex = uiTableEntry; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiRedSelectors[uiPixel] = auiBestSelectors[uiPixel]; - float fBestPixelRed = afBestPixelRed[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fBestPixelRed, 0.0f, 0.0f, 1.0f); - m_afDecodedAlphas[uiPixel] = 1.0f; - } - } - } - } - - } - } - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_R11::SetEncodingBits(void) - { - if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) - { - m_pencodingbitsR11->data.base = (unsigned char)roundf(m_fRedBase); - } - else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - m_pencodingbitsR11->data.base = (signed char)roundf(m_fRedBase); - } - else - { - assert(0); - } - m_pencodingbitsR11->data.table = m_uiRedModifierTableIndex; - m_pencodingbitsR11->data.multiplier = (unsigned char)roundf(m_fRedMultiplier); - - unsigned long long int ulliSelectorBits = 0; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiShift = 45 - (3 * uiPixel); - ulliSelectorBits |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift; - } - - m_pencodingbitsR11->data.selectors0 = ulliSelectorBits >> 40; - m_pencodingbitsR11->data.selectors1 = ulliSelectorBits >> 32; - m_pencodingbitsR11->data.selectors2 = ulliSelectorBits >> 24; - m_pencodingbitsR11->data.selectors3 = ulliSelectorBits >> 16; - m_pencodingbitsR11->data.selectors4 = ulliSelectorBits >> 8; - m_pencodingbitsR11->data.selectors5 = ulliSelectorBits; - } - - // ---------------------------------------------------------------------------------------------------- - // -} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h deleted file mode 100644 index b40c1e0036..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcBlock4x4Encoding_RGB8.h" - -namespace Etc -{ - class Block4x4EncodingBits_R11; - - // ################################################################################ - // Block4x4Encoding_R11 - // ################################################################################ - - class Block4x4Encoding_R11 : public Block4x4Encoding_RGB8 - { - public: - - Block4x4Encoding_R11(void); - virtual ~Block4x4Encoding_R11(void); - - virtual void InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric); - - virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric); - - virtual void PerformIteration(float a_fEffort); - - virtual void SetEncodingBits(void); - - inline float GetRedBase(void) const - { - return m_fRedBase; - } - - inline float GetRedMultiplier(void) const - { - return m_fRedMultiplier; - } - - inline int GetRedTableIndex(void) const - { - return m_uiRedModifierTableIndex; - } - - inline const unsigned int * GetRedSelectors(void) const - { - return m_auiRedSelectors; - } - - protected: - - static const unsigned int MODIFIER_TABLE_ENTRYS = 16; - static const unsigned int SELECTOR_BITS = 3; - static const unsigned int SELECTORS = 1 << SELECTOR_BITS; - - static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS]; - - void CalculateR11(unsigned int a_uiSelectorsUsed, - float a_fBaseRadius, float a_fMultiplierRadius); - - - - - inline float DecodePixelRed(float a_fBase, float a_fMultiplier, - unsigned int a_uiTableIndex, unsigned int a_uiSelector) - { - float fMultiplier = a_fMultiplier; - if (fMultiplier <= 0.0f) - { - fMultiplier = 1.0f / 8.0f; - } - - float fPixelRed = a_fBase * 8 + 4 + - 8 * fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]*255; - fPixelRed /= 2047.0f; - - if (fPixelRed < 0.0f) - { - fPixelRed = 0.0f; - } - else if (fPixelRed > 1.0f) - { - fPixelRed = 1.0f; - } - - return fPixelRed; - } - - Block4x4EncodingBits_R11 *m_pencodingbitsR11; - - float m_fRedBase; - float m_fRedMultiplier; - float m_fRedBlockError; - unsigned int m_uiRedModifierTableIndex; - unsigned int m_auiRedSelectors[PIXELS]; - - - }; - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp deleted file mode 100644 index 417835db51..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4Encoding_RG11.cpp - -Block4x4Encoding_RG11 is the encoder to use when targetting file format RG11 and SRG11 (signed RG11). - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4Encoding_RG11.h" - -#include "EtcBlock4x4EncodingBits.h" -#include "EtcBlock4x4.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <float.h> -#include <limits> - -namespace Etc -{ - // ---------------------------------------------------------------------------------------------------- - // - Block4x4Encoding_RG11::Block4x4Encoding_RG11(void) - { - m_pencodingbitsRG11 = nullptr; - } - - Block4x4Encoding_RG11::~Block4x4Encoding_RG11(void) {} - // ---------------------------------------------------------------------------------------------------- - // initialization prior to encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits - // - void Block4x4Encoding_RG11::InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) - { - Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); - - m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits; - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits of a previous encoding - // - void Block4x4Encoding_RG11::InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - - m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits; - - // init RGB portion - Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent, - (unsigned char *)m_pencodingbitsRG11, - a_pafrgbaSource, - a_errormetric); - m_fError = 0.0f; - - { - m_mode = MODE_RG11; - if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - m_fRedBase = (float)(signed char)m_pencodingbitsRG11->data.baseR; - m_fGrnBase = (float)(signed char)m_pencodingbitsRG11->data.baseG; - } - else - { - m_fRedBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseR; - m_fGrnBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseG; - } - m_fRedMultiplier = (float)m_pencodingbitsRG11->data.multiplierR; - m_fGrnMultiplier = (float)m_pencodingbitsRG11->data.multiplierG; - m_uiRedModifierTableIndex = m_pencodingbitsRG11->data.tableIndexR; - m_uiGrnModifierTableIndex = m_pencodingbitsRG11->data.tableIndexG; - - unsigned long long int ulliSelectorBitsR = 0; - ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR0 << 40; - ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR1 << 32; - ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR2 << 24; - ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR3 << 16; - ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR4 << 8; - ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR5; - - unsigned long long int ulliSelectorBitsG = 0; - ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG0 << 40; - ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG1 << 32; - ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG2 << 24; - ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG3 << 16; - ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG4 << 8; - ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG5; - - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiShift = 45 - (3 * uiPixel); - m_auiRedSelectors[uiPixel] = (ulliSelectorBitsR >> uiShift) & (SELECTORS - 1); - m_auiGrnSelectors[uiPixel] = (ulliSelectorBitsG >> uiShift) & (SELECTORS - 1); - } - - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - float fRedDecodedData = 0.0f; - float fGrnDecodedData = 0.0f; - if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) - { - fRedDecodedData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]); - fGrnDecodedData = DecodePixelRed(m_fGrnBase, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]); - } - else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - fRedDecodedData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]); - fGrnDecodedData = DecodePixelRed(m_fGrnBase + 128, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]); - } - else - { - assert(0); - } - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fRedDecodedData, fGrnDecodedData, 0.0f, 1.0f); - } - - } - - CalcBlockError(); - } - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_RG11::PerformIteration(float a_fEffort) - { - assert(!m_boolDone); - - switch (m_uiEncodingIterations) - { - case 0: - m_fError = FLT_MAX; - m_fGrnBlockError = FLT_MAX; // artificially high value - m_fRedBlockError = FLT_MAX; - CalculateR11(8, 0.0f, 0.0f); - CalculateG11(8, 0.0f, 0.0f); - m_fError = (m_fGrnBlockError + m_fRedBlockError); - break; - - case 1: - CalculateR11(8, 2.0f, 1.0f); - CalculateG11(8, 2.0f, 1.0f); - m_fError = (m_fGrnBlockError + m_fRedBlockError); - if (a_fEffort <= 24.5f) - { - m_boolDone = true; - } - break; - - case 2: - CalculateR11(8, 12.0f, 1.0f); - CalculateG11(8, 12.0f, 1.0f); - m_fError = (m_fGrnBlockError + m_fRedBlockError); - if (a_fEffort <= 49.5f) - { - m_boolDone = true; - } - break; - - case 3: - CalculateR11(7, 6.0f, 1.0f); - CalculateG11(7, 6.0f, 1.0f); - m_fError = (m_fGrnBlockError + m_fRedBlockError); - break; - - case 4: - CalculateR11(6, 3.0f, 1.0f); - CalculateG11(6, 3.0f, 1.0f); - m_fError = (m_fGrnBlockError + m_fRedBlockError); - break; - - case 5: - CalculateR11(5, 1.0f, 0.0f); - CalculateG11(5, 1.0f, 0.0f); - m_fError = (m_fGrnBlockError + m_fRedBlockError); - m_boolDone = true; - break; - - default: - assert(0); - break; - } - - m_uiEncodingIterations++; - SetDoneIfPerfect(); - } - - // ---------------------------------------------------------------------------------------------------- - // find the best combination of base color, multiplier and selectors - // - // a_uiSelectorsUsed limits the number of selector combinations to try - // a_fBaseRadius limits the range of base colors to try - // a_fMultiplierRadius limits the range of multipliers to try - // - void Block4x4Encoding_RG11::CalculateG11(unsigned int a_uiSelectorsUsed, - float a_fBaseRadius, float a_fMultiplierRadius) - { - // maps from virtual (monotonic) selector to etc selector - static const unsigned int auiVirtualSelectorMap[8] = { 3, 2, 1, 0, 4, 5, 6, 7 }; - - // find min/max Grn - float fMinGrn = 1.0f; - float fMaxGrn = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - // ignore border pixels - float fAlpha = m_pafrgbaSource[uiPixel].fA; - if (isnan(fAlpha)) - { - continue; - } - - float fGrn = m_pafrgbaSource[uiPixel].fG; - - if (fGrn < fMinGrn) - { - fMinGrn = fGrn; - } - if (fGrn > fMaxGrn) - { - fMaxGrn = fGrn; - } - } - assert(fMinGrn <= fMaxGrn); - - float fGrnRange = (fMaxGrn - fMinGrn); - - // try each modifier table entry - for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++) - { - for (unsigned int uiMinVirtualSelector = 0; - uiMinVirtualSelector <= (8 - a_uiSelectorsUsed); - uiMinVirtualSelector++) - { - unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1; - - unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector]; - unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector]; - - float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector]; - - float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] - - s_aafModifierTable[uiTableEntry][uiMinSelector]; - - float fCenterRatio = fTableEntryCenter / fTableEntryRange; - - float fCenter = fMinGrn + fCenterRatio*fGrnRange; - fCenter = roundf(255.0f * fCenter) / 255.0f; - - float fMinBase = fCenter - (a_fBaseRadius / 255.0f); - if (fMinBase < 0.0f) - { - fMinBase = 0.0f; - } - - float fMaxBase = fCenter + (a_fBaseRadius / 255.0f); - if (fMaxBase > 1.0f) - { - fMaxBase = 1.0f; - } - - for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f)) - { - float fRangeMultiplier = roundf(fGrnRange / fTableEntryRange); - - float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius; - if (fMinMultiplier < 1.0f) - { - fMinMultiplier = 0.0f; - } - else if (fMinMultiplier > 15.0f) - { - fMinMultiplier = 15.0f; - } - - float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius; - if (fMaxMultiplier < 1.0f) - { - fMaxMultiplier = 1.0f; - } - else if (fMaxMultiplier > 15.0f) - { - fMaxMultiplier = 15.0f; - } - - for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f) - { - // find best selector for each pixel - unsigned int auiBestSelectors[PIXELS]; - float afBestGrnError[PIXELS]; - float afBestPixelGrn[PIXELS]; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - float fBestPixelGrnError = FLT_MAX; - - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - //DecodePixelRed is not red channel specific - float fPixelGrn = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector); - - ColorFloatRGBA frgba(m_pafrgbaSource[uiPixel].fR, fPixelGrn, 0.0f, 1.0f); - - float fPixelGrnError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]); - - if (fPixelGrnError < fBestPixelGrnError) - { - fBestPixelGrnError = fPixelGrnError; - auiBestSelectors[uiPixel] = uiSelector; - afBestGrnError[uiPixel] = fBestPixelGrnError; - afBestPixelGrn[uiPixel] = fPixelGrn; - } - } - } - float fBlockError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - fBlockError += afBestGrnError[uiPixel]; - } - - if (fBlockError < m_fGrnBlockError) - { - m_fGrnBlockError = fBlockError; - - if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) - { - m_fGrnBase = 255.0f * fBase; - } - else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - m_fGrnBase = (fBase * 255) - 128; - } - else - { - assert(0); - } - m_fGrnMultiplier = fMultiplier; - m_uiGrnModifierTableIndex = uiTableEntry; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiGrnSelectors[uiPixel] = auiBestSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel].fG = afBestPixelGrn[uiPixel]; - m_afDecodedAlphas[uiPixel] = 1.0f; - } - } - } - } - - } - } - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_RG11::SetEncodingBits(void) - { - unsigned long long int ulliSelectorBitsR = 0; - unsigned long long int ulliSelectorBitsG = 0; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiShift = 45 - (3 * uiPixel); - ulliSelectorBitsR |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift; - ulliSelectorBitsG |= ((unsigned long long int)m_auiGrnSelectors[uiPixel]) << uiShift; - } - if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) - { - m_pencodingbitsRG11->data.baseR = (unsigned char)roundf(m_fRedBase); - } - else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - m_pencodingbitsRG11->data.baseR = (signed char)roundf(m_fRedBase); - } - else - { - assert(0); - } - m_pencodingbitsRG11->data.tableIndexR = m_uiRedModifierTableIndex; - m_pencodingbitsRG11->data.multiplierR = (unsigned char)roundf(m_fRedMultiplier); - - m_pencodingbitsRG11->data.selectorsR0 = ulliSelectorBitsR >> 40; - m_pencodingbitsRG11->data.selectorsR1 = ulliSelectorBitsR >> 32; - m_pencodingbitsRG11->data.selectorsR2 = ulliSelectorBitsR >> 24; - m_pencodingbitsRG11->data.selectorsR3 = ulliSelectorBitsR >> 16; - m_pencodingbitsRG11->data.selectorsR4 = ulliSelectorBitsR >> 8; - m_pencodingbitsRG11->data.selectorsR5 = ulliSelectorBitsR; - - if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11) - { - m_pencodingbitsRG11->data.baseG = (unsigned char)roundf(m_fGrnBase); - } - else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11) - { - m_pencodingbitsRG11->data.baseG = (signed char)roundf(m_fGrnBase); - } - else - { - assert(0); - } - m_pencodingbitsRG11->data.tableIndexG = m_uiGrnModifierTableIndex; - m_pencodingbitsRG11->data.multiplierG = (unsigned char)roundf(m_fGrnMultiplier); - - m_pencodingbitsRG11->data.selectorsG0 = ulliSelectorBitsG >> 40; - m_pencodingbitsRG11->data.selectorsG1 = ulliSelectorBitsG >> 32; - m_pencodingbitsRG11->data.selectorsG2 = ulliSelectorBitsG >> 24; - m_pencodingbitsRG11->data.selectorsG3 = ulliSelectorBitsG >> 16; - m_pencodingbitsRG11->data.selectorsG4 = ulliSelectorBitsG >> 8; - m_pencodingbitsRG11->data.selectorsG5 = ulliSelectorBitsG; - - } - - // ---------------------------------------------------------------------------------------------------- - // -} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h deleted file mode 100644 index d4993b8c5f..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcBlock4x4Encoding_RGB8.h" -#include "EtcBlock4x4Encoding_R11.h" - -namespace Etc -{ - class Block4x4EncodingBits_RG11; - - // ################################################################################ - // Block4x4Encoding_RG11 - // ################################################################################ - - class Block4x4Encoding_RG11 : public Block4x4Encoding_R11 - { - float m_fGrnBase; - float m_fGrnMultiplier; - float m_fGrnBlockError; - unsigned int m_auiGrnSelectors[PIXELS]; - unsigned int m_uiGrnModifierTableIndex; - public: - - Block4x4Encoding_RG11(void); - virtual ~Block4x4Encoding_RG11(void); - - virtual void InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric); - - virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - - ErrorMetric a_errormetric); - - virtual void PerformIteration(float a_fEffort); - - virtual void SetEncodingBits(void); - - Block4x4EncodingBits_RG11 *m_pencodingbitsRG11; - - void CalculateG11(unsigned int a_uiSelectorsUsed, float a_fBaseRadius, float a_fMultiplierRadius); - - inline float GetGrnBase(void) const - { - return m_fGrnBase; - } - - inline float GetGrnMultiplier(void) const - { - return m_fGrnMultiplier; - } - - inline int GetGrnTableIndex(void) const - { - return m_uiGrnModifierTableIndex; - } - - inline const unsigned int * GetGrnSelectors(void) const - { - return m_auiGrnSelectors; - } - - }; - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp deleted file mode 100644 index 5c7ebed788..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp +++ /dev/null @@ -1,1730 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4Encoding_RGB8.cpp - -Block4x4Encoding_RGB8 is the encoder to use for the ETC2 extensions when targetting file format RGB8. -This encoder is also used for the ETC2 subset of file format RGBA8. - -Block4x4Encoding_ETC1 encodes the ETC1 subset of RGB8. - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4Encoding_RGB8.h" - -#include "EtcBlock4x4EncodingBits.h" -#include "EtcBlock4x4.h" -#include "EtcMath.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <float.h> -#include <limits> - -namespace Etc -{ - float Block4x4Encoding_RGB8::s_afTHDistanceTable[TH_DISTANCES] = - { - 3.0f / 255.0f, - 6.0f / 255.0f, - 11.0f / 255.0f, - 16.0f / 255.0f, - 23.0f / 255.0f, - 32.0f / 255.0f, - 41.0f / 255.0f, - 64.0f / 255.0f - }; - - // ---------------------------------------------------------------------------------------------------- - // - Block4x4Encoding_RGB8::Block4x4Encoding_RGB8(void) - { - - m_pencodingbitsRGB8 = nullptr; - - } - - Block4x4Encoding_RGB8::~Block4x4Encoding_RGB8(void) {} - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits of a previous encoding - // - void Block4x4Encoding_RGB8::InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - - // handle ETC1 modes - Block4x4Encoding_ETC1::InitFromEncodingBits(a_pblockParent, - a_paucEncodingBits, a_pafrgbaSource,a_errormetric); - - m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; - - // detect if there is a T, H or Planar mode present - if (m_pencodingbitsRGB8->differential.diff) - { - int iRed1 = (int)m_pencodingbitsRGB8->differential.red1; - int iDRed2 = m_pencodingbitsRGB8->differential.dred2; - int iRed2 = iRed1 + iDRed2; - - int iGreen1 = (int)m_pencodingbitsRGB8->differential.green1; - int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2; - int iGreen2 = iGreen1 + iDGreen2; - - int iBlue1 = (int)m_pencodingbitsRGB8->differential.blue1; - int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2; - int iBlue2 = iBlue1 + iDBlue2; - - if (iRed2 < 0 || iRed2 > 31) - { - InitFromEncodingBits_T(); - } - else if (iGreen2 < 0 || iGreen2 > 31) - { - InitFromEncodingBits_H(); - } - else if (iBlue2 < 0 || iBlue2 > 31) - { - InitFromEncodingBits_Planar(); - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding if T mode is detected - // - void Block4x4Encoding_RGB8::InitFromEncodingBits_T(void) - { - - m_mode = MODE_T; - - unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) + - m_pencodingbitsRGB8->t.red1b); - unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1; - unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1; - - unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2; - unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2; - unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2; - - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); - - m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db; - - Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); - - DecodePixels_T(); - - CalcBlockError(); - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding if H mode is detected - // - void Block4x4Encoding_RGB8::InitFromEncodingBits_H(void) - { - - m_mode = MODE_H; - - unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1; - unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) + - m_pencodingbitsRGB8->h.green1b); - unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) + - (m_pencodingbitsRGB8->h.blue1b << 1) + - m_pencodingbitsRGB8->h.blue1c); - - unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2; - unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) + - m_pencodingbitsRGB8->h.green2b); - unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2; - - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); - - // used to determine the LSB of the CW - unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1); - unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2); - - m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1); - if (uiRGB1 >= uiRGB2) - { - m_uiCW1++; - } - - Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); - - DecodePixels_H(); - - CalcBlockError(); - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding if Planar mode is detected - // - void Block4x4Encoding_RGB8::InitFromEncodingBits_Planar(void) - { - - m_mode = MODE_PLANAR; - - unsigned char ucOriginRed = m_pencodingbitsRGB8->planar.originRed; - unsigned char ucOriginGreen = (unsigned char)((m_pencodingbitsRGB8->planar.originGreen1 << 6) + - m_pencodingbitsRGB8->planar.originGreen2); - unsigned char ucOriginBlue = (unsigned char)((m_pencodingbitsRGB8->planar.originBlue1 << 5) + - (m_pencodingbitsRGB8->planar.originBlue2 << 3) + - (m_pencodingbitsRGB8->planar.originBlue3 << 1) + - m_pencodingbitsRGB8->planar.originBlue4); - - unsigned char ucHorizRed = (unsigned char)((m_pencodingbitsRGB8->planar.horizRed1 << 1) + - m_pencodingbitsRGB8->planar.horizRed2); - unsigned char ucHorizGreen = m_pencodingbitsRGB8->planar.horizGreen; - unsigned char ucHorizBlue = (unsigned char)((m_pencodingbitsRGB8->planar.horizBlue1 << 5) + - m_pencodingbitsRGB8->planar.horizBlue2); - - unsigned char ucVertRed = (unsigned char)((m_pencodingbitsRGB8->planar.vertRed1 << 3) + - m_pencodingbitsRGB8->planar.vertRed2); - unsigned char ucVertGreen = (unsigned char)((m_pencodingbitsRGB8->planar.vertGreen1 << 2) + - m_pencodingbitsRGB8->planar.vertGreen2); - unsigned char ucVertBlue = m_pencodingbitsRGB8->planar.vertBlue; - - m_frgbaColor1 = ColorFloatRGBA::ConvertFromR6G7B6(ucOriginRed, ucOriginGreen, ucOriginBlue); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromR6G7B6(ucHorizRed, ucHorizGreen, ucHorizBlue); - m_frgbaColor3 = ColorFloatRGBA::ConvertFromR6G7B6(ucVertRed, ucVertGreen, ucVertBlue); - - DecodePixels_Planar(); - - CalcBlockError(); - - } - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_RGB8::PerformIteration(float a_fEffort) - { - assert(!m_boolDone); - - switch (m_uiEncodingIterations) - { - case 0: - Block4x4Encoding_ETC1::PerformFirstIteration(); - if (m_boolDone) - { - break; - } - TryPlanar(0); - SetDoneIfPerfect(); - if (m_boolDone) - { - break; - } - TryTAndH(0); - break; - - case 1: - Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); - break; - - case 2: - Block4x4Encoding_ETC1::TryIndividual(m_boolMostLikelyFlip, 1); - break; - - case 3: - Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); - break; - - case 4: - Block4x4Encoding_ETC1::TryIndividual(!m_boolMostLikelyFlip, 1); - break; - - case 5: - TryPlanar(1); - if (a_fEffort <= 49.5f) - { - m_boolDone = true; - } - break; - - case 6: - TryTAndH(1); - if (a_fEffort <= 59.5f) - { - m_boolDone = true; - } - break; - - case 7: - Block4x4Encoding_ETC1::TryDegenerates1(); - if (a_fEffort <= 69.5f) - { - m_boolDone = true; - } - break; - - case 8: - Block4x4Encoding_ETC1::TryDegenerates2(); - if (a_fEffort <= 79.5f) - { - m_boolDone = true; - } - break; - - case 9: - Block4x4Encoding_ETC1::TryDegenerates3(); - if (a_fEffort <= 89.5f) - { - m_boolDone = true; - } - break; - - case 10: - Block4x4Encoding_ETC1::TryDegenerates4(); - m_boolDone = true; - break; - - default: - assert(0); - break; - } - - m_uiEncodingIterations++; - - SetDoneIfPerfect(); - } - - // ---------------------------------------------------------------------------------------------------- - // try encoding in Planar mode - // save this encoding if it improves the error - // - void Block4x4Encoding_RGB8::TryPlanar(unsigned int a_uiRadius) - { - Block4x4Encoding_RGB8 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_PLANAR; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - } - - encodingTry.CalculatePlanarCornerColors(); - - encodingTry.DecodePixels_Planar(); - - encodingTry.CalcBlockError(); - - if (a_uiRadius > 0) - { - encodingTry.TwiddlePlanar(); - } - - if (encodingTry.m_fError < m_fError) - { - m_mode = MODE_PLANAR; - m_boolDiff = true; - m_boolFlip = false; - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_frgbaColor3 = encodingTry.m_frgbaColor3; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try encoding in T mode or H mode - // save this encoding if it improves the error - // - void Block4x4Encoding_RGB8::TryTAndH(unsigned int a_uiRadius) - { - - CalculateBaseColorsForTAndH(); - - TryT(a_uiRadius); - - TryH(a_uiRadius); - - } - - // ---------------------------------------------------------------------------------------------------- - // calculate original values for base colors - // store them in m_frgbaOriginalColor1 and m_frgbaOriginalColor2 - // - void Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH(void) - { - - bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX; - - ColorFloatRGBA frgbaBlockAverage = (m_frgbaSourceAverageLeft + m_frgbaSourceAverageRight) * 0.5f; - - // find pixel farthest from average gray line - unsigned int uiFarthestPixel = 0; - float fFarthestGrayDistance2 = 0.0f; - unsigned int uiTransparentPixels = 0; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - // don't count transparent - if (m_pafrgbaSource[uiPixel].fA == 0.0f && !boolRGBX) - { - uiTransparentPixels++; - } - else - { - float fGrayDistance2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], frgbaBlockAverage); - - if (fGrayDistance2 > fFarthestGrayDistance2) - { - uiFarthestPixel = uiPixel; - fFarthestGrayDistance2 = fGrayDistance2; - } - } - } - // a transparent block should not reach this method - assert(uiTransparentPixels < PIXELS); - - // set the original base colors to: - // half way to the farthest pixel and - // the mirror color on the other side of the average - ColorFloatRGBA frgbaOffset = (m_pafrgbaSource[uiFarthestPixel] - frgbaBlockAverage) * 0.5f; - m_frgbaOriginalColor1_TAndH = (frgbaBlockAverage + frgbaOffset).QuantizeR4G4B4(); - m_frgbaOriginalColor2_TAndH = (frgbaBlockAverage - frgbaOffset).ClampRGB().QuantizeR4G4B4(); // the "other side" might be out of range - - // move base colors to find best fit - for (unsigned int uiIteration = 0; uiIteration < 10; uiIteration++) - { - // find the center of pixels closest to each color - float fPixelsCloserToColor1 = 0.0f; - ColorFloatRGBA frgbSumPixelsCloserToColor1; - float fPixelsCloserToColor2 = 0.0f; - ColorFloatRGBA frgbSumPixelsCloserToColor2; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - // don't count transparent pixels - if (m_pafrgbaSource[uiPixel].fA == 0.0f) - { - continue; - } - - float fGrayDistance2ToColor1 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor1_TAndH); - float fGrayDistance2ToColor2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor2_TAndH); - - ColorFloatRGBA frgbaAlphaWeightedSource = m_pafrgbaSource[uiPixel] * m_pafrgbaSource[uiPixel].fA; - - if (fGrayDistance2ToColor1 <= fGrayDistance2ToColor2) - { - fPixelsCloserToColor1 += m_pafrgbaSource[uiPixel].fA; - frgbSumPixelsCloserToColor1 = frgbSumPixelsCloserToColor1 + frgbaAlphaWeightedSource; - } - else - { - fPixelsCloserToColor2 += m_pafrgbaSource[uiPixel].fA; - frgbSumPixelsCloserToColor2 = frgbSumPixelsCloserToColor2 + frgbaAlphaWeightedSource; - } - } - if (fPixelsCloserToColor1 == 0.0f || fPixelsCloserToColor2 == 0.0f) - { - break; - } - - ColorFloatRGBA frgbAvgColor1Pixels = (frgbSumPixelsCloserToColor1 * (1.0f / fPixelsCloserToColor1)).QuantizeR4G4B4(); - ColorFloatRGBA frgbAvgColor2Pixels = (frgbSumPixelsCloserToColor2 * (1.0f / fPixelsCloserToColor2)).QuantizeR4G4B4(); - - if (frgbAvgColor1Pixels.fR == m_frgbaOriginalColor1_TAndH.fR && - frgbAvgColor1Pixels.fG == m_frgbaOriginalColor1_TAndH.fG && - frgbAvgColor1Pixels.fB == m_frgbaOriginalColor1_TAndH.fB && - frgbAvgColor2Pixels.fR == m_frgbaOriginalColor2_TAndH.fR && - frgbAvgColor2Pixels.fG == m_frgbaOriginalColor2_TAndH.fG && - frgbAvgColor2Pixels.fB == m_frgbaOriginalColor2_TAndH.fB) - { - break; - } - - m_frgbaOriginalColor1_TAndH = frgbAvgColor1Pixels; - m_frgbaOriginalColor2_TAndH = frgbAvgColor2Pixels; - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try encoding in T mode - // save this encoding if it improves the error - // - // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently - // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower - // - void Block4x4Encoding_RGB8::TryT(unsigned int a_uiRadius) - { - Block4x4Encoding_RGB8 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_T; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - encodingTry.m_fError = FLT_MAX; - } - - int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); - int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); - int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); - - int iMinRed1 = iColor1Red - (int)a_uiRadius; - if (iMinRed1 < 0) - { - iMinRed1 = 0; - } - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { - iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; - if (iMinGreen1 < 0) - { - iMinGreen1 = 0; - } - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { - iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; - if (iMinBlue1 < 0) - { - iMinBlue1 = 0; - } - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { - iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); - int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); - int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); - - int iMinRed2 = iColor2Red - (int)a_uiRadius; - if (iMinRed2 < 0) - { - iMinRed2 = 0; - } - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { - iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; - if (iMinGreen2 < 0) - { - iMinGreen2 = 0; - } - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { - iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; - if (iMinBlue2 < 0) - { - iMinBlue2 = 0; - } - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { - iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) - { - encodingTry.m_uiCW1 = uiDistance; - - // twiddle m_frgbaOriginalColor2_TAndH - // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector - // - for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) - { - for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) - { - for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) - { - for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) - { - if (uiBaseColorSwaps == 0) - { - encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; - encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); - } - else - { - encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); - encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH; - } - - encodingTry.TryT_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - } - - // twiddle m_frgbaOriginalColor1_TAndH - for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) - { - for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) - { - for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) - { - for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) - { - if (uiBaseColorSwaps == 0) - { - encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); - encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; - } - else - { - encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH; - encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); - } - - encodingTry.TryT_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // find best selector combination for TryT - // called on an encodingTry - // - void Block4x4Encoding_RGB8::TryT_BestSelectorCombination(void) - { - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - - unsigned int auiBestPixelSelectors[PIXELS]; - float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; - ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; - - assert(SELECTORS == 4); - afrgbaDecodedPixel[0] = m_frgbaColor1; - afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB(); - afrgbaDecodedPixel[2] = m_frgbaColor2; - afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); - - // try each selector - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - - float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], - m_pafrgbaSource[uiPixel]); - - if (fPixelError < afBestPixelErrors[uiPixel]) - { - afBestPixelErrors[uiPixel] = fPixelError; - auiBestPixelSelectors[uiPixel] = uiSelector; - afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; - } - } - } - - - // add up all of the pixel errors - float fBlockError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - fBlockError += afBestPixelErrors[uiPixel]; - } - - if (fBlockError < m_fError) - { - m_fError = fBlockError; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try encoding in T mode - // save this encoding if it improves the error - // - // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently - // TWIDDLE_RADIUS of 2 is WAY too slow - // - void Block4x4Encoding_RGB8::TryH(unsigned int a_uiRadius) - { - Block4x4Encoding_RGB8 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_H; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - encodingTry.m_fError = FLT_MAX; - } - - int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); - int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); - int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); - - int iMinRed1 = iColor1Red - (int)a_uiRadius; - if (iMinRed1 < 0) - { - iMinRed1 = 0; - } - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { - iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; - if (iMinGreen1 < 0) - { - iMinGreen1 = 0; - } - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { - iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; - if (iMinBlue1 < 0) - { - iMinBlue1 = 0; - } - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { - iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); - int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); - int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); - - int iMinRed2 = iColor2Red - (int)a_uiRadius; - if (iMinRed2 < 0) - { - iMinRed2 = 0; - } - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { - iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; - if (iMinGreen2 < 0) - { - iMinGreen2 = 0; - } - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { - iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; - if (iMinBlue2 < 0) - { - iMinBlue2 = 0; - } - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { - iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) - { - encodingTry.m_uiCW1 = uiDistance; - - // twiddle m_frgbaOriginalColor1_TAndH - for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) - { - for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) - { - for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) - { - encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); - encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; - - // if color1 == color2, H encoding issues can pop up, so abort - if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue) - { - continue; - } - - encodingTry.TryH_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - - // twiddle m_frgbaOriginalColor2_TAndH - for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) - { - for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) - { - for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) - { - encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; - encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); - - // if color1 == color2, H encoding issues can pop up, so abort - if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue) - { - continue; - } - - encodingTry.TryH_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // find best selector combination for TryH - // called on an encodingTry - // - void Block4x4Encoding_RGB8::TryH_BestSelectorCombination(void) - { - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - - unsigned int auiBestPixelSelectors[PIXELS]; - float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; - ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; - - assert(SELECTORS == 4); - afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB(); - afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB(); - afrgbaDecodedPixel[2] = (m_frgbaColor2 + fDistance).ClampRGB(); - afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); - - // try each selector - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - - float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], - m_pafrgbaSource[uiPixel]); - - if (fPixelError < afBestPixelErrors[uiPixel]) - { - afBestPixelErrors[uiPixel] = fPixelError; - auiBestPixelSelectors[uiPixel] = uiSelector; - afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; - } - } - } - - - // add up all of the pixel errors - float fBlockError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - fBlockError += afBestPixelErrors[uiPixel]; - } - - if (fBlockError < m_fError) - { - m_fError = fBlockError; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // use linear regression to find the best fit for colors along the edges of the 4x4 block - // - void Block4x4Encoding_RGB8::CalculatePlanarCornerColors(void) - { - ColorFloatRGBA afrgbaRegression[MAX_PLANAR_REGRESSION_SIZE]; - ColorFloatRGBA frgbaSlope; - ColorFloatRGBA frgbaOffset; - - // top edge - afrgbaRegression[0] = m_pafrgbaSource[0]; - afrgbaRegression[1] = m_pafrgbaSource[4]; - afrgbaRegression[2] = m_pafrgbaSource[8]; - afrgbaRegression[3] = m_pafrgbaSource[12]; - ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); - m_frgbaColor1 = frgbaOffset; - m_frgbaColor2 = (frgbaSlope * 4.0f) + frgbaOffset; - - // left edge - afrgbaRegression[0] = m_pafrgbaSource[0]; - afrgbaRegression[1] = m_pafrgbaSource[1]; - afrgbaRegression[2] = m_pafrgbaSource[2]; - afrgbaRegression[3] = m_pafrgbaSource[3]; - ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); - m_frgbaColor1 = (m_frgbaColor1 + frgbaOffset) * 0.5f; // average with top edge - m_frgbaColor3 = (frgbaSlope * 4.0f) + frgbaOffset; - - // right edge - afrgbaRegression[0] = m_pafrgbaSource[12]; - afrgbaRegression[1] = m_pafrgbaSource[13]; - afrgbaRegression[2] = m_pafrgbaSource[14]; - afrgbaRegression[3] = m_pafrgbaSource[15]; - ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); - m_frgbaColor2 = (m_frgbaColor2 + frgbaOffset) * 0.5f; // average with top edge - - // bottom edge - afrgbaRegression[0] = m_pafrgbaSource[3]; - afrgbaRegression[1] = m_pafrgbaSource[7]; - afrgbaRegression[2] = m_pafrgbaSource[11]; - afrgbaRegression[3] = m_pafrgbaSource[15]; - ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset); - m_frgbaColor3 = (m_frgbaColor3 + frgbaOffset) * 0.5f; // average with left edge - - // quantize corner colors to 6/7/6 - m_frgbaColor1 = m_frgbaColor1.QuantizeR6G7B6(); - m_frgbaColor2 = m_frgbaColor2.QuantizeR6G7B6(); - m_frgbaColor3 = m_frgbaColor3.QuantizeR6G7B6(); - - } - - // ---------------------------------------------------------------------------------------------------- - // try different corner colors by slightly changing R, G and B independently - // - // R, G and B decoding and errors are independent, so R, G and B twiddles can be independent - // - // return true if improvement - // - bool Block4x4Encoding_RGB8::TwiddlePlanar(void) - { - bool boolImprovement = false; - - while (TwiddlePlanarR()) - { - boolImprovement = true; - } - - while (TwiddlePlanarG()) - { - boolImprovement = true; - } - - while (TwiddlePlanarB()) - { - boolImprovement = true; - } - - return boolImprovement; - } - - // ---------------------------------------------------------------------------------------------------- - // try different corner colors by slightly changing R - // - bool Block4x4Encoding_RGB8::TwiddlePlanarR() - { - bool boolImprovement = false; - - Block4x4Encoding_RGB8 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_PLANAR; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - } - - int iOriginRed = encodingTry.m_frgbaColor1.IntRed(63.0f); - int iHorizRed = encodingTry.m_frgbaColor2.IntRed(63.0f); - int iVertRed = encodingTry.m_frgbaColor3.IntRed(63.0f); - - for (int iTryOriginRed = iOriginRed - 1; iTryOriginRed <= iOriginRed + 1; iTryOriginRed++) - { - // check for out of range - if (iTryOriginRed < 0 || iTryOriginRed > 63) - { - continue; - } - - encodingTry.m_frgbaColor1.fR = ((iTryOriginRed << 2) + (iTryOriginRed >> 4)) / 255.0f; - - for (int iTryHorizRed = iHorizRed - 1; iTryHorizRed <= iHorizRed + 1; iTryHorizRed++) - { - // check for out of range - if (iTryHorizRed < 0 || iTryHorizRed > 63) - { - continue; - } - - encodingTry.m_frgbaColor2.fR = ((iTryHorizRed << 2) + (iTryHorizRed >> 4)) / 255.0f; - - for (int iTryVertRed = iVertRed - 1; iTryVertRed <= iVertRed + 1; iTryVertRed++) - { - // check for out of range - if (iTryVertRed < 0 || iTryVertRed > 63) - { - continue; - } - - // don't bother with null twiddle - if (iTryOriginRed == iOriginRed && iTryHorizRed == iHorizRed && iTryVertRed == iVertRed) - { - continue; - } - - encodingTry.m_frgbaColor3.fR = ((iTryVertRed << 2) + (iTryVertRed >> 4)) / 255.0f; - - encodingTry.DecodePixels_Planar(); - - encodingTry.CalcBlockError(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = MODE_PLANAR; - m_boolDiff = true; - m_boolFlip = false; - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_frgbaColor3 = encodingTry.m_frgbaColor3; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - - boolImprovement = true; - } - } - } - } - - return boolImprovement; - } - - // ---------------------------------------------------------------------------------------------------- - // try different corner colors by slightly changing G - // - bool Block4x4Encoding_RGB8::TwiddlePlanarG() - { - bool boolImprovement = false; - - Block4x4Encoding_RGB8 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_PLANAR; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - } - - int iOriginGreen = encodingTry.m_frgbaColor1.IntGreen(127.0f); - int iHorizGreen = encodingTry.m_frgbaColor2.IntGreen(127.0f); - int iVertGreen = encodingTry.m_frgbaColor3.IntGreen(127.0f); - - for (int iTryOriginGreen = iOriginGreen - 1; iTryOriginGreen <= iOriginGreen + 1; iTryOriginGreen++) - { - // check for out of range - if (iTryOriginGreen < 0 || iTryOriginGreen > 127) - { - continue; - } - - encodingTry.m_frgbaColor1.fG = ((iTryOriginGreen << 1) + (iTryOriginGreen >> 6)) / 255.0f; - - for (int iTryHorizGreen = iHorizGreen - 1; iTryHorizGreen <= iHorizGreen + 1; iTryHorizGreen++) - { - // check for out of range - if (iTryHorizGreen < 0 || iTryHorizGreen > 127) - { - continue; - } - - encodingTry.m_frgbaColor2.fG = ((iTryHorizGreen << 1) + (iTryHorizGreen >> 6)) / 255.0f; - - for (int iTryVertGreen = iVertGreen - 1; iTryVertGreen <= iVertGreen + 1; iTryVertGreen++) - { - // check for out of range - if (iTryVertGreen < 0 || iTryVertGreen > 127) - { - continue; - } - - // don't bother with null twiddle - if (iTryOriginGreen == iOriginGreen && - iTryHorizGreen == iHorizGreen && - iTryVertGreen == iVertGreen) - { - continue; - } - - encodingTry.m_frgbaColor3.fG = ((iTryVertGreen << 1) + (iTryVertGreen >> 6)) / 255.0f; - - encodingTry.DecodePixels_Planar(); - - encodingTry.CalcBlockError(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = MODE_PLANAR; - m_boolDiff = true; - m_boolFlip = false; - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_frgbaColor3 = encodingTry.m_frgbaColor3; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - - boolImprovement = true; - } - } - } - } - - return boolImprovement; - } - - // ---------------------------------------------------------------------------------------------------- - // try different corner colors by slightly changing B - // - bool Block4x4Encoding_RGB8::TwiddlePlanarB() - { - bool boolImprovement = false; - - Block4x4Encoding_RGB8 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_PLANAR; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - } - - int iOriginBlue = encodingTry.m_frgbaColor1.IntBlue(63.0f); - int iHorizBlue = encodingTry.m_frgbaColor2.IntBlue(63.0f); - int iVertBlue = encodingTry.m_frgbaColor3.IntBlue(63.0f); - - for (int iTryOriginBlue = iOriginBlue - 1; iTryOriginBlue <= iOriginBlue + 1; iTryOriginBlue++) - { - // check for out of range - if (iTryOriginBlue < 0 || iTryOriginBlue > 63) - { - continue; - } - - encodingTry.m_frgbaColor1.fB = ((iTryOriginBlue << 2) + (iTryOriginBlue >> 4)) / 255.0f; - - for (int iTryHorizBlue = iHorizBlue - 1; iTryHorizBlue <= iHorizBlue + 1; iTryHorizBlue++) - { - // check for out of range - if (iTryHorizBlue < 0 || iTryHorizBlue > 63) - { - continue; - } - - encodingTry.m_frgbaColor2.fB = ((iTryHorizBlue << 2) + (iTryHorizBlue >> 4)) / 255.0f; - - for (int iTryVertBlue = iVertBlue - 1; iTryVertBlue <= iVertBlue + 1; iTryVertBlue++) - { - // check for out of range - if (iTryVertBlue < 0 || iTryVertBlue > 63) - { - continue; - } - - // don't bother with null twiddle - if (iTryOriginBlue == iOriginBlue && iTryHorizBlue == iHorizBlue && iTryVertBlue == iVertBlue) - { - continue; - } - - encodingTry.m_frgbaColor3.fB = ((iTryVertBlue << 2) + (iTryVertBlue >> 4)) / 255.0f; - - encodingTry.DecodePixels_Planar(); - - encodingTry.CalcBlockError(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = MODE_PLANAR; - m_boolDiff = true; - m_boolFlip = false; - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_frgbaColor3 = encodingTry.m_frgbaColor3; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - - boolImprovement = true; - } - } - } - } - - return boolImprovement; - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_RGB8::SetEncodingBits(void) - { - - switch (m_mode) - { - case MODE_ETC1: - Block4x4Encoding_ETC1::SetEncodingBits(); - break; - - case MODE_T: - SetEncodingBits_T(); - break; - - case MODE_H: - SetEncodingBits_H(); - break; - - case MODE_PLANAR: - SetEncodingBits_Planar(); - break; - - default: - assert(false); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state for T mode - // - void Block4x4Encoding_RGB8::SetEncodingBits_T(void) - { - static const bool SANITY_CHECK = true; - - assert(m_mode == MODE_T); - assert(m_boolDiff == true); - - unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); - unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); - unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); - - unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); - unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); - unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); - - m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2; - m_pencodingbitsRGB8->t.red1b = uiRed1; - m_pencodingbitsRGB8->t.green1 = uiGreen1; - m_pencodingbitsRGB8->t.blue1 = uiBlue1; - - m_pencodingbitsRGB8->t.red2 = uiRed2; - m_pencodingbitsRGB8->t.green2 = uiGreen2; - m_pencodingbitsRGB8->t.blue2 = uiBlue2; - - m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1; - m_pencodingbitsRGB8->t.db = m_uiCW1; - - m_pencodingbitsRGB8->t.diff = 1; - - Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); - - // create an invalid R differential to trigger T mode - m_pencodingbitsRGB8->t.detect1 = 0; - m_pencodingbitsRGB8->t.detect2 = 0; - int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - if (iRed2 >= 4) - { - m_pencodingbitsRGB8->t.detect1 = 7; - m_pencodingbitsRGB8->t.detect2 = 0; - } - else - { - m_pencodingbitsRGB8->t.detect1 = 0; - m_pencodingbitsRGB8->t.detect2 = 1; - } - - if (SANITY_CHECK) - { - iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - - // make sure red overflows - assert(iRed2 < 0 || iRed2 > 31); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state for H mode - // - // colors and selectors may need to swap in order to generate lsb of distance index - // - void Block4x4Encoding_RGB8::SetEncodingBits_H(void) - { - static const bool SANITY_CHECK = true; - - assert(m_mode == MODE_H); - assert(m_boolDiff == true); - - unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); - unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); - unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); - - unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); - unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); - unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); - - unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1; - unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2; - - bool boolOddDistance = m_uiCW1 & 1; - bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance; - - if (boolSwapColors) - { - m_pencodingbitsRGB8->h.red1 = uiRed2; - m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1; - m_pencodingbitsRGB8->h.green1b = uiGreen2; - m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3; - m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1; - m_pencodingbitsRGB8->h.blue1c = uiBlue2; - - m_pencodingbitsRGB8->h.red2 = uiRed1; - m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1; - m_pencodingbitsRGB8->h.green2b = uiGreen1; - m_pencodingbitsRGB8->h.blue2 = uiBlue1; - - m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; - m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; - } - else - { - m_pencodingbitsRGB8->h.red1 = uiRed1; - m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1; - m_pencodingbitsRGB8->h.green1b = uiGreen1; - m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3; - m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1; - m_pencodingbitsRGB8->h.blue1c = uiBlue1; - - m_pencodingbitsRGB8->h.red2 = uiRed2; - m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1; - m_pencodingbitsRGB8->h.green2b = uiGreen2; - m_pencodingbitsRGB8->h.blue2 = uiBlue2; - - m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; - m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; - } - - m_pencodingbitsRGB8->h.diff = 1; - - Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); - - if (boolSwapColors) - { - m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF; - } - - // create an invalid R differential to trigger T mode - m_pencodingbitsRGB8->h.detect1 = 0; - m_pencodingbitsRGB8->h.detect2 = 0; - m_pencodingbitsRGB8->h.detect3 = 0; - int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; - if (iRed2 < 0 || iRed2 > 31) - { - m_pencodingbitsRGB8->h.detect1 = 1; - } - if (iGreen2 >= 4) - { - m_pencodingbitsRGB8->h.detect2 = 7; - m_pencodingbitsRGB8->h.detect3 = 0; - } - else - { - m_pencodingbitsRGB8->h.detect2 = 0; - m_pencodingbitsRGB8->h.detect3 = 1; - } - - if (SANITY_CHECK) - { - iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; - - // make sure red doesn't overflow and green does - assert(iRed2 >= 0 && iRed2 <= 31); - assert(iGreen2 < 0 || iGreen2 > 31); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state for Planar mode - // - void Block4x4Encoding_RGB8::SetEncodingBits_Planar(void) - { - static const bool SANITY_CHECK = true; - - assert(m_mode == MODE_PLANAR); - assert(m_boolDiff == true); - - unsigned int uiOriginRed = (unsigned int)m_frgbaColor1.IntRed(63.0f); - unsigned int uiOriginGreen = (unsigned int)m_frgbaColor1.IntGreen(127.0f); - unsigned int uiOriginBlue = (unsigned int)m_frgbaColor1.IntBlue(63.0f); - - unsigned int uiHorizRed = (unsigned int)m_frgbaColor2.IntRed(63.0f); - unsigned int uiHorizGreen = (unsigned int)m_frgbaColor2.IntGreen(127.0f); - unsigned int uiHorizBlue = (unsigned int)m_frgbaColor2.IntBlue(63.0f); - - unsigned int uiVertRed = (unsigned int)m_frgbaColor3.IntRed(63.0f); - unsigned int uiVertGreen = (unsigned int)m_frgbaColor3.IntGreen(127.0f); - unsigned int uiVertBlue = (unsigned int)m_frgbaColor3.IntBlue(63.0f); - - m_pencodingbitsRGB8->planar.originRed = uiOriginRed; - m_pencodingbitsRGB8->planar.originGreen1 = uiOriginGreen >> 6; - m_pencodingbitsRGB8->planar.originGreen2 = uiOriginGreen; - m_pencodingbitsRGB8->planar.originBlue1 = uiOriginBlue >> 5; - m_pencodingbitsRGB8->planar.originBlue2 = uiOriginBlue >> 3; - m_pencodingbitsRGB8->planar.originBlue3 = uiOriginBlue >> 1; - m_pencodingbitsRGB8->planar.originBlue4 = uiOriginBlue; - - m_pencodingbitsRGB8->planar.horizRed1 = uiHorizRed >> 1; - m_pencodingbitsRGB8->planar.horizRed2 = uiHorizRed; - m_pencodingbitsRGB8->planar.horizGreen = uiHorizGreen; - m_pencodingbitsRGB8->planar.horizBlue1 = uiHorizBlue >> 5; - m_pencodingbitsRGB8->planar.horizBlue2 = uiHorizBlue; - - m_pencodingbitsRGB8->planar.vertRed1 = uiVertRed >> 3; - m_pencodingbitsRGB8->planar.vertRed2 = uiVertRed; - m_pencodingbitsRGB8->planar.vertGreen1 = uiVertGreen >> 2; - m_pencodingbitsRGB8->planar.vertGreen2 = uiVertGreen; - m_pencodingbitsRGB8->planar.vertBlue = uiVertBlue; - - m_pencodingbitsRGB8->planar.diff = 1; - - // create valid RG differentials and an invalid B differential to trigger planar mode - m_pencodingbitsRGB8->planar.detect1 = 0; - m_pencodingbitsRGB8->planar.detect2 = 0; - m_pencodingbitsRGB8->planar.detect3 = 0; - m_pencodingbitsRGB8->planar.detect4 = 0; - int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; - int iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2; - if (iRed2 < 0 || iRed2 > 31) - { - m_pencodingbitsRGB8->planar.detect1 = 1; - } - if (iGreen2 < 0 || iGreen2 > 31) - { - m_pencodingbitsRGB8->planar.detect2 = 1; - } - if (iBlue2 >= 4) - { - m_pencodingbitsRGB8->planar.detect3 = 7; - m_pencodingbitsRGB8->planar.detect4 = 0; - } - else - { - m_pencodingbitsRGB8->planar.detect3 = 0; - m_pencodingbitsRGB8->planar.detect4 = 1; - } - - if (SANITY_CHECK) - { - iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; - iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2; - - // make sure red and green don't overflow and blue does - assert(iRed2 >= 0 && iRed2 <= 31); - assert(iGreen2 >= 0 && iGreen2 <= 31); - assert(iBlue2 < 0 || iBlue2 > 31); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the decoded colors and decoded alpha based on the encoding state for T mode - // - void Block4x4Encoding_RGB8::DecodePixels_T(void) - { - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - switch (m_auiSelectors[uiPixel]) - { - case 0: - m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1; - break; - - case 1: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); - break; - - case 2: - m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2; - break; - - case 3: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); - break; - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the decoded colors and decoded alpha based on the encoding state for H mode - // - void Block4x4Encoding_RGB8::DecodePixels_H(void) - { - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - switch (m_auiSelectors[uiPixel]) - { - case 0: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB(); - break; - - case 1: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB(); - break; - - case 2: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); - break; - - case 3: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); - break; - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the decoded colors and decoded alpha based on the encoding state for Planar mode - // - void Block4x4Encoding_RGB8::DecodePixels_Planar(void) - { - - int iRO = (int)roundf(m_frgbaColor1.fR * 255.0f); - int iGO = (int)roundf(m_frgbaColor1.fG * 255.0f); - int iBO = (int)roundf(m_frgbaColor1.fB * 255.0f); - - int iRH = (int)roundf(m_frgbaColor2.fR * 255.0f); - int iGH = (int)roundf(m_frgbaColor2.fG * 255.0f); - int iBH = (int)roundf(m_frgbaColor2.fB * 255.0f); - - int iRV = (int)roundf(m_frgbaColor3.fR * 255.0f); - int iGV = (int)roundf(m_frgbaColor3.fG * 255.0f); - int iBV = (int)roundf(m_frgbaColor3.fB * 255.0f); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - int iX = (int)(uiPixel >> 2); - int iY = (int)(uiPixel & 3); - - int iR = (iX*(iRH - iRO) + iY*(iRV - iRO) + 4*iRO + 2) >> 2; - int iG = (iX*(iGH - iGO) + iY*(iGV - iGO) + 4*iGO + 2) >> 2; - int iB = (iX*(iBH - iBO) + iY*(iBV - iBO) + 4*iBO + 2) >> 2; - - ColorFloatRGBA frgba; - frgba.fR = (float)iR / 255.0f; - frgba.fG = (float)iG / 255.0f; - frgba.fB = (float)iB / 255.0f; - frgba.fA = 1.0f; - - m_afrgbaDecodedColors[uiPixel] = frgba.ClampRGB(); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // perform a linear regression for the a_uiPixels in a_pafrgbaPixels[] - // - // output the closest color line using a_pfrgbaSlope and a_pfrgbaOffset - // - void Block4x4Encoding_RGB8::ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels, - ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset) - { - typedef struct - { - float f[4]; - } Float4; - - Float4 *paf4Pixels = (Float4 *)(a_pafrgbaPixels); - Float4 *pf4Slope = (Float4 *)(a_pfrgbaSlope); - Float4 *pf4Offset = (Float4 *)(a_pfrgbaOffset); - - float afX[MAX_PLANAR_REGRESSION_SIZE]; - float afY[MAX_PLANAR_REGRESSION_SIZE]; - - // handle r, g and b separately. don't bother with a - for (unsigned int uiComponent = 0; uiComponent < 3; uiComponent++) - { - for (unsigned int uiPixel = 0; uiPixel < a_uiPixels; uiPixel++) - { - afX[uiPixel] = (float)uiPixel; - afY[uiPixel] = paf4Pixels[uiPixel].f[uiComponent]; - - } - Etc::Regression(afX, afY, a_uiPixels, - &(pf4Slope->f[uiComponent]), &(pf4Offset->f[uiComponent])); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // -} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h deleted file mode 100644 index 03754d5e3b..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcBlock4x4Encoding_ETC1.h" - -namespace Etc -{ - - class Block4x4Encoding_RGB8 : public Block4x4Encoding_ETC1 - { - public: - - Block4x4Encoding_RGB8(void); - virtual ~Block4x4Encoding_RGB8(void); - - virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - - ErrorMetric a_errormetric); - - virtual void PerformIteration(float a_fEffort); - - virtual void SetEncodingBits(void); - - inline ColorFloatRGBA GetColor3(void) const - { - return m_frgbaColor3; - } - - protected: - - static const unsigned int PLANAR_CORNER_COLORS = 3; - static const unsigned int MAX_PLANAR_REGRESSION_SIZE = 4; - static const unsigned int TH_DISTANCES = 8; - - static float s_afTHDistanceTable[TH_DISTANCES]; - - void TryPlanar(unsigned int a_uiRadius); - void TryTAndH(unsigned int a_uiRadius); - - void InitFromEncodingBits_Planar(void); - - ColorFloatRGBA m_frgbaColor3; // used for planar - - void SetEncodingBits_T(void); - void SetEncodingBits_H(void); - void SetEncodingBits_Planar(void); - - // state shared between iterations - ColorFloatRGBA m_frgbaOriginalColor1_TAndH; - ColorFloatRGBA m_frgbaOriginalColor2_TAndH; - - void CalculateBaseColorsForTAndH(void); - void TryT(unsigned int a_uiRadius); - void TryT_BestSelectorCombination(void); - void TryH(unsigned int a_uiRadius); - void TryH_BestSelectorCombination(void); - - private: - - void InitFromEncodingBits_T(void); - void InitFromEncodingBits_H(void); - - void CalculatePlanarCornerColors(void); - - void ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels, - ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset); - - bool TwiddlePlanar(void); - bool TwiddlePlanarR(); - bool TwiddlePlanarG(); - bool TwiddlePlanarB(); - - void DecodePixels_T(void); - void DecodePixels_H(void); - void DecodePixels_Planar(void); - - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp deleted file mode 100644 index b94b64e68c..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp +++ /dev/null @@ -1,1819 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4Encoding_RGB8A1.cpp contains: - Block4x4Encoding_RGB8A1 - Block4x4Encoding_RGB8A1_Opaque - Block4x4Encoding_RGB8A1_Transparent - -These encoders are used when targetting file format RGB8A1. - -Block4x4Encoding_RGB8A1_Opaque is used when all pixels in the 4x4 block are opaque -Block4x4Encoding_RGB8A1_Transparent is used when all pixels in the 4x4 block are transparent -Block4x4Encoding_RGB8A1 is used when there is a mixture of alphas in the 4x4 block - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4Encoding_RGB8A1.h" - -#include "EtcBlock4x4.h" -#include "EtcBlock4x4EncodingBits.h" -#include "EtcBlock4x4Encoding_RGB8.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> - -namespace Etc -{ - - // #################################################################################################### - // Block4x4Encoding_RGB8A1 - // #################################################################################################### - - float Block4x4Encoding_RGB8A1::s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS] = - { - { 0.0f / 255.0f, 8.0f / 255.0f, 0.0f / 255.0f, -8.0f / 255.0f }, - { 0.0f / 255.0f, 17.0f / 255.0f, 0.0f / 255.0f, -17.0f / 255.0f }, - { 0.0f / 255.0f, 29.0f / 255.0f, 0.0f / 255.0f, -29.0f / 255.0f }, - { 0.0f / 255.0f, 42.0f / 255.0f, 0.0f / 255.0f, -42.0f / 255.0f }, - { 0.0f / 255.0f, 60.0f / 255.0f, 0.0f / 255.0f, -60.0f / 255.0f }, - { 0.0f / 255.0f, 80.0f / 255.0f, 0.0f / 255.0f, -80.0f / 255.0f }, - { 0.0f / 255.0f, 106.0f / 255.0f, 0.0f / 255.0f, -106.0f / 255.0f }, - { 0.0f / 255.0f, 183.0f / 255.0f, 0.0f / 255.0f, -183.0f / 255.0f } - }; - - // ---------------------------------------------------------------------------------------------------- - // - Block4x4Encoding_RGB8A1::Block4x4Encoding_RGB8A1(void) - { - m_pencodingbitsRGB8 = nullptr; - m_boolOpaque = false; - m_boolTransparent = false; - m_boolPunchThroughPixels = true; - - } - Block4x4Encoding_RGB8A1::~Block4x4Encoding_RGB8A1(void) {} - // ---------------------------------------------------------------------------------------------------- - // initialization prior to encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits - // - void Block4x4Encoding_RGB8A1::InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, - ErrorMetric a_errormetric) - { - - Block4x4Encoding_RGB8::InitFromSource(a_pblockParent, - a_pafrgbaSource, - a_paucEncodingBits, - a_errormetric); - - m_boolOpaque = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE; - m_boolTransparent = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::TRANSPARENT; - m_boolPunchThroughPixels = a_pblockParent->HasPunchThroughPixels(); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - if (m_pafrgbaSource[uiPixel].fA >= 0.5f) - { - m_afDecodedAlphas[uiPixel] = 1.0f; - } - else - { - m_afDecodedAlphas[uiPixel] = 0.0f; - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits of a previous encoding - // - void Block4x4Encoding_RGB8A1::InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - - - InitFromEncodingBits_ETC1(a_pblockParent, - a_paucEncodingBits, - a_pafrgbaSource, - a_errormetric); - - m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; - - // detect if there is a T, H or Planar mode present - int iRed1 = m_pencodingbitsRGB8->differential.red1; - int iDRed2 = m_pencodingbitsRGB8->differential.dred2; - int iRed2 = iRed1 + iDRed2; - - int iGreen1 = m_pencodingbitsRGB8->differential.green1; - int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2; - int iGreen2 = iGreen1 + iDGreen2; - - int iBlue1 = m_pencodingbitsRGB8->differential.blue1; - int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2; - int iBlue2 = iBlue1 + iDBlue2; - - if (iRed2 < 0 || iRed2 > 31) - { - InitFromEncodingBits_T(); - } - else if (iGreen2 < 0 || iGreen2 > 31) - { - InitFromEncodingBits_H(); - } - else if (iBlue2 < 0 || iBlue2 > 31) - { - Block4x4Encoding_RGB8::InitFromEncodingBits_Planar(); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding assuming the encoding is an ETC1 mode. - // if it isn't an ETC1 mode, this will be overwritten later - // - void Block4x4Encoding_RGB8A1::InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource, - a_errormetric); - - m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits; - - m_mode = MODE_ETC1; - m_boolDiff = true; - m_boolFlip = m_pencodingbitsRGB8->differential.flip; - m_boolOpaque = m_pencodingbitsRGB8->differential.diff; - - int iR2 = m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2; - if (iR2 < 0) - { - iR2 = 0; - } - else if (iR2 > 31) - { - iR2 = 31; - } - - int iG2 = m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2; - if (iG2 < 0) - { - iG2 = 0; - } - else if (iG2 > 31) - { - iG2 = 31; - } - - int iB2 = m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2; - if (iB2 < 0) - { - iB2 = 0; - } - else if (iB2 > 31) - { - iB2 = 31; - } - - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2); - - m_uiCW1 = m_pencodingbitsRGB8->differential.cw1; - m_uiCW2 = m_pencodingbitsRGB8->differential.cw2; - - Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); - - Decode_ETC1(); - - CalcBlockError(); - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding if T mode is detected - // - void Block4x4Encoding_RGB8A1::InitFromEncodingBits_T(void) - { - m_mode = MODE_T; - - unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) + - m_pencodingbitsRGB8->t.red1b); - unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1; - unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1; - - unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2; - unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2; - unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2; - - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); - - m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db; - - Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); - - DecodePixels_T(); - - CalcBlockError(); - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding if H mode is detected - // - void Block4x4Encoding_RGB8A1::InitFromEncodingBits_H(void) - { - m_mode = MODE_H; - - unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1; - unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) + - m_pencodingbitsRGB8->h.green1b); - unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) + - (m_pencodingbitsRGB8->h.blue1b << 1) + - m_pencodingbitsRGB8->h.blue1c); - - unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2; - unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) + - m_pencodingbitsRGB8->h.green2b); - unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2; - - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2); - - // used to determine the LSB of the CW - unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1); - unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2); - - m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1); - if (uiRGB1 >= uiRGB2) - { - m_uiCW1++; - } - - Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(); - - DecodePixels_H(); - - CalcBlockError(); - } - - // ---------------------------------------------------------------------------------------------------- - // for ETC1 modes, set the decoded colors and decoded alpha based on the encoding state - // - void Block4x4Encoding_RGB8A1::Decode_ETC1(void) - { - - const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0; - - for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++) - { - ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2; - unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2; - - unsigned int uiPixel = pauiPixelOrder[uiPixelOrder]; - - float fDelta; - if (m_boolOpaque) - fDelta = Block4x4Encoding_ETC1::s_aafCwTable[uiCW][m_auiSelectors[uiPixel]]; - else - fDelta = s_aafCwOpaqueUnsetTable[uiCW][m_auiSelectors[uiPixel]]; - - if (m_boolOpaque == false && m_auiSelectors[uiPixel] == TRANSPARENT_SELECTOR) - { - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); - m_afDecodedAlphas[uiPixel] = 0.0f; - } - else - { - m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // for T mode, set the decoded colors and decoded alpha based on the encoding state - // - void Block4x4Encoding_RGB8A1::DecodePixels_T(void) - { - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - switch (m_auiSelectors[uiPixel]) - { - case 0: - m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1; - m_afDecodedAlphas[uiPixel] = 1.0f; - break; - - case 1: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - break; - - case 2: - if (m_boolOpaque == false) - { - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); - m_afDecodedAlphas[uiPixel] = 0.0f; - } - else - { - m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2; - m_afDecodedAlphas[uiPixel] = 1.0f; - } - break; - - case 3: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - break; - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // for H mode, set the decoded colors and decoded alpha based on the encoding state - // - void Block4x4Encoding_RGB8A1::DecodePixels_H(void) - { - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - switch (m_auiSelectors[uiPixel]) - { - case 0: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - break; - - case 1: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - break; - - case 2: - if (m_boolOpaque == false) - { - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); - m_afDecodedAlphas[uiPixel] = 0.0f; - } - else - { - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - } - break; - - case 3: - m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB(); - m_afDecodedAlphas[uiPixel] = 1.0f; - break; - } - - } - - } - - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - // RGB8A1 can't use individual mode - // RGB8A1 with transparent pixels can't use planar mode - // - void Block4x4Encoding_RGB8A1::PerformIteration(float a_fEffort) - { - assert(!m_boolOpaque); - assert(!m_boolTransparent); - assert(!m_boolDone); - - switch (m_uiEncodingIterations) - { - case 0: - PerformFirstIteration(); - break; - - case 1: - TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); - break; - - case 2: - TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); - if (a_fEffort <= 39.5f) - { - m_boolDone = true; - } - break; - - case 3: - Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH(); - TryT(1); - TryH(1); - if (a_fEffort <= 49.5f) - { - m_boolDone = true; - } - break; - - case 4: - TryDegenerates1(); - if (a_fEffort <= 59.5f) - { - m_boolDone = true; - } - break; - - case 5: - TryDegenerates2(); - if (a_fEffort <= 69.5f) - { - m_boolDone = true; - } - break; - - case 6: - TryDegenerates3(); - if (a_fEffort <= 79.5f) - { - m_boolDone = true; - } - break; - - case 7: - TryDegenerates4(); - m_boolDone = true; - break; - - default: - assert(0); - break; - } - - m_uiEncodingIterations++; - - SetDoneIfPerfect(); - - } - - // ---------------------------------------------------------------------------------------------------- - // find best initial encoding to ensure block has a valid encoding - // - void Block4x4Encoding_RGB8A1::PerformFirstIteration(void) - { - Block4x4Encoding_ETC1::CalculateMostLikelyFlip(); - - m_fError = FLT_MAX; - - TryDifferential(m_boolMostLikelyFlip, 0, 0, 0); - SetDoneIfPerfect(); - if (m_boolDone) - { - return; - } - TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0); - SetDoneIfPerfect(); - - } - - // ---------------------------------------------------------------------------------------------------- - // mostly copied from ETC1 - // differences: - // Block4x4Encoding_RGB8A1 encodingTry = *this; - // - void Block4x4Encoding_RGB8A1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, - int a_iGrayOffset1, int a_iGrayOffset2) - { - - ColorFloatRGBA frgbaColor1; - ColorFloatRGBA frgbaColor2; - - const unsigned int *pauiPixelMapping1; - const unsigned int *pauiPixelMapping2; - - if (a_boolFlip) - { - frgbaColor1 = m_frgbaSourceAverageTop; - frgbaColor2 = m_frgbaSourceAverageBottom; - - pauiPixelMapping1 = s_auiTopPixelMapping; - pauiPixelMapping2 = s_auiBottomPixelMapping; - } - else - { - frgbaColor1 = m_frgbaSourceAverageLeft; - frgbaColor2 = m_frgbaSourceAverageRight; - - pauiPixelMapping1 = s_auiLeftPixelMapping; - pauiPixelMapping2 = s_auiRightPixelMapping; - } - - DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, - a_uiRadius, a_iGrayOffset1, a_iGrayOffset2); - - Block4x4Encoding_RGB8A1 encodingTry = *this; - encodingTry.m_boolFlip = a_boolFlip; - - encodingTry.TryDifferentialHalf(&trys.m_half1); - encodingTry.TryDifferentialHalf(&trys.m_half2); - - // find best halves that are within differential range - DifferentialTrys::Try *ptryBest1 = nullptr; - DifferentialTrys::Try *ptryBest2 = nullptr; - encodingTry.m_fError = FLT_MAX; - - // see if the best of each half are in differential range - int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed; - int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen; - int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue; - if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3) - { - ptryBest1 = trys.m_half1.m_ptryBest; - ptryBest2 = trys.m_half2.m_ptryBest; - encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError; - } - else - { - // else, find the next best halves that are in differential range - for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0]; - ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys]; - ptry1++) - { - for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0]; - ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys]; - ptry2++) - { - iDRed = ptry2->m_iRed - ptry1->m_iRed; - bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4; - iDGreen = ptry2->m_iGreen - ptry1->m_iGreen; - bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4; - iDBlue = ptry2->m_iBlue - ptry1->m_iBlue; - bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4; - - if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta) - { - float fError = ptry1->m_fError + ptry2->m_fError; - - if (fError < encodingTry.m_fError) - { - encodingTry.m_fError = fError; - - ptryBest1 = ptry1; - ptryBest2 = ptry2; - } - } - - } - } - assert(encodingTry.m_fError < FLT_MAX); - assert(ptryBest1 != nullptr); - assert(ptryBest2 != nullptr); - } - - if (encodingTry.m_fError < m_fError) - { - m_mode = MODE_ETC1; - m_boolDiff = true; - m_boolFlip = encodingTry.m_boolFlip; - m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue); - m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue); - m_uiCW1 = ptryBest1->m_uiCW; - m_uiCW2 = ptryBest2->m_uiCW; - - m_fError = 0.0f; - for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++) - { - unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder]; - unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder]; - - unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder]; - unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder]; - - m_auiSelectors[uiPixel1] = uiSelector1; - m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder]; - - if (uiSelector1 == TRANSPARENT_SELECTOR) - { - m_afrgbaDecodedColors[uiPixel1] = ColorFloatRGBA(); - m_afDecodedAlphas[uiPixel1] = 0.0f; - } - else - { - float fDeltaRGB1 = s_aafCwOpaqueUnsetTable[m_uiCW1][uiSelector1]; - m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB(); - m_afDecodedAlphas[uiPixel1] = 1.0f; - } - - if (uiSelector2 == TRANSPARENT_SELECTOR) - { - m_afrgbaDecodedColors[uiPixel2] = ColorFloatRGBA(); - m_afDecodedAlphas[uiPixel2] = 0.0f; - } - else - { - float fDeltaRGB2 = s_aafCwOpaqueUnsetTable[m_uiCW2][uiSelector2]; - m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB(); - m_afDecodedAlphas[uiPixel2] = 1.0f; - } - - float fDeltaA1 = m_afDecodedAlphas[uiPixel1] - m_pafrgbaSource[uiPixel1].fA; - m_fError += fDeltaA1 * fDeltaA1; - float fDeltaA2 = m_afDecodedAlphas[uiPixel2] - m_pafrgbaSource[uiPixel2].fA; - m_fError += fDeltaA2 * fDeltaA2; - } - - m_fError1 = ptryBest1->m_fError; - m_fError2 = ptryBest2->m_fError; - m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors; - m_fError = m_fError1 + m_fError2; - - // sanity check - { - int iRed1 = m_frgbaColor1.IntRed(31.0f); - int iGreen1 = m_frgbaColor1.IntGreen(31.0f); - int iBlue1 = m_frgbaColor1.IntBlue(31.0f); - - int iRed2 = m_frgbaColor2.IntRed(31.0f); - int iGreen2 = m_frgbaColor2.IntGreen(31.0f); - int iBlue2 = m_frgbaColor2.IntBlue(31.0f); - - iDRed = iRed2 - iRed1; - iDGreen = iGreen2 - iGreen1; - iDBlue = iBlue2 - iBlue1; - - assert(iDRed >= -4 && iDRed < 4); - assert(iDGreen >= -4 && iDGreen < 4); - assert(iDBlue >= -4 && iDBlue < 4); - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // mostly copied from ETC1 - // differences: - // uses s_aafCwOpaqueUnsetTable - // color for selector set to 0,0,0,0 - // - void Block4x4Encoding_RGB8A1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf) - { - - a_phalf->m_ptryBest = nullptr; - float fBestTryError = FLT_MAX; - - a_phalf->m_uiTrys = 0; - for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius; - iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius; - iRed++) - { - assert(iRed >= 0 && iRed <= 31); - - for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius; - iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius; - iGreen++) - { - assert(iGreen >= 0 && iGreen <= 31); - - for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius; - iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius; - iBlue++) - { - assert(iBlue >= 0 && iBlue <= 31); - - DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys]; - assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]); - - ptry->m_iRed = iRed; - ptry->m_iGreen = iGreen; - ptry->m_iBlue = iBlue; - ptry->m_fError = FLT_MAX; - ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue); - - // try each CW - for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++) - { - unsigned int auiPixelSelectors[PIXELS / 2]; - ColorFloatRGBA afrgbaDecodedColors[PIXELS / 2]; - float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - - // pre-compute decoded pixels for each selector - ColorFloatRGBA afrgbaSelectors[SELECTORS]; - assert(SELECTORS == 4); - afrgbaSelectors[0] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][0]).ClampRGB(); - afrgbaSelectors[1] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][1]).ClampRGB(); - afrgbaSelectors[2] = ColorFloatRGBA(); - afrgbaSelectors[3] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][3]).ClampRGB(); - - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]]; - ColorFloatRGBA frgbaDecodedPixel; - - for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++) - { - if (pfrgbaSourcePixel->fA < 0.5f) - { - uiSelector = TRANSPARENT_SELECTOR; - } - else if (uiSelector == TRANSPARENT_SELECTOR) - { - continue; - } - - frgbaDecodedPixel = afrgbaSelectors[uiSelector]; - - float fPixelError; - - fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]], - *pfrgbaSourcePixel); - - if (fPixelError < afPixelErrors[uiPixel]) - { - auiPixelSelectors[uiPixel] = uiSelector; - afrgbaDecodedColors[uiPixel] = frgbaDecodedPixel; - afPixelErrors[uiPixel] = fPixelError; - } - - if (uiSelector == TRANSPARENT_SELECTOR) - { - break; - } - } - } - - // add up all pixel errors - float fCWError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - fCWError += afPixelErrors[uiPixel]; - } - - // if best CW so far - if (fCWError < ptry->m_fError) - { - ptry->m_uiCW = uiCW; - for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++) - { - ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel]; - } - ptry->m_fError = fCWError; - } - - } - - if (ptry->m_fError < fBestTryError) - { - a_phalf->m_ptryBest = ptry; - fBestTryError = ptry->m_fError; - } - - assert(ptry->m_fError < FLT_MAX); - - a_phalf->m_uiTrys++; - } - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try encoding in T mode - // save this encoding if it improves the error - // - // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently - // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower - // - void Block4x4Encoding_RGB8A1::TryT(unsigned int a_uiRadius) - { - Block4x4Encoding_RGB8A1 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_T; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - encodingTry.m_fError = FLT_MAX; - } - - int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); - int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); - int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); - - int iMinRed1 = iColor1Red - (int)a_uiRadius; - if (iMinRed1 < 0) - { - iMinRed1 = 0; - } - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { - iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; - if (iMinGreen1 < 0) - { - iMinGreen1 = 0; - } - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { - iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; - if (iMinBlue1 < 0) - { - iMinBlue1 = 0; - } - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { - iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); - int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); - int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); - - int iMinRed2 = iColor2Red - (int)a_uiRadius; - if (iMinRed2 < 0) - { - iMinRed2 = 0; - } - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { - iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; - if (iMinGreen2 < 0) - { - iMinGreen2 = 0; - } - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { - iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; - if (iMinBlue2 < 0) - { - iMinBlue2 = 0; - } - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { - iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) - { - encodingTry.m_uiCW1 = uiDistance; - - // twiddle m_frgbaOriginalColor2_TAndH - // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector - // - for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) - { - for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) - { - for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) - { - for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) - { - if (uiBaseColorSwaps == 0) - { - encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; - encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); - } - else - { - encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); - encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH; - } - - encodingTry.TryT_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - } - - // twiddle m_frgbaOriginalColor1_TAndH - for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) - { - for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) - { - for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) - { - for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++) - { - if (uiBaseColorSwaps == 0) - { - encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); - encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; - } - else - { - encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH; - encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); - } - - encodingTry.TryT_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // find best selector combination for TryT - // called on an encodingTry - // - void Block4x4Encoding_RGB8A1::TryT_BestSelectorCombination(void) - { - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - - unsigned int auiBestPixelSelectors[PIXELS]; - float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; - ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; - - assert(SELECTORS == 4); - afrgbaDecodedPixel[0] = m_frgbaColor1; - afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB(); - afrgbaDecodedPixel[2] = ColorFloatRGBA(); - afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); - - // try each selector - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiMinSelector = 0; - unsigned int uiMaxSelector = SELECTORS - 1; - - if (m_pafrgbaSource[uiPixel].fA < 0.5f) - { - uiMinSelector = 2; - uiMaxSelector = 2; - } - - for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++) - { - float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], - m_pafrgbaSource[uiPixel]); - - if (fPixelError < afBestPixelErrors[uiPixel]) - { - afBestPixelErrors[uiPixel] = fPixelError; - auiBestPixelSelectors[uiPixel] = uiSelector; - afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; - } - } - } - - - // add up all of the pixel errors - float fBlockError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - fBlockError += afBestPixelErrors[uiPixel]; - } - - if (fBlockError < m_fError) - { - m_fError = fBlockError; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try encoding in H mode - // save this encoding if it improves the error - // - // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently - // TWIDDLE_RADIUS of 2 is WAY too slow - // - void Block4x4Encoding_RGB8A1::TryH(unsigned int a_uiRadius) - { - Block4x4Encoding_RGB8A1 encodingTry = *this; - - // init "try" - { - encodingTry.m_mode = MODE_H; - encodingTry.m_boolDiff = true; - encodingTry.m_boolFlip = false; - encodingTry.m_fError = FLT_MAX; - } - - int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f); - int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f); - int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f); - - int iMinRed1 = iColor1Red - (int)a_uiRadius; - if (iMinRed1 < 0) - { - iMinRed1 = 0; - } - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { - iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; - if (iMinGreen1 < 0) - { - iMinGreen1 = 0; - } - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { - iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; - if (iMinBlue1 < 0) - { - iMinBlue1 = 0; - } - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { - iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); - int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f); - int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f); - - int iMinRed2 = iColor2Red - (int)a_uiRadius; - if (iMinRed2 < 0) - { - iMinRed2 = 0; - } - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { - iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; - if (iMinGreen2 < 0) - { - iMinGreen2 = 0; - } - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { - iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; - if (iMinBlue2 < 0) - { - iMinBlue2 = 0; - } - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { - iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) - { - encodingTry.m_uiCW1 = uiDistance; - - // twiddle m_frgbaOriginalColor1_TAndH - for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++) - { - for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++) - { - for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++) - { - encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1); - encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH; - - // if color1 == color2, H encoding issues can pop up, so abort - if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue) - { - continue; - } - - encodingTry.TryH_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - - // twiddle m_frgbaOriginalColor2_TAndH - for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++) - { - for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++) - { - for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++) - { - encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH; - encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2); - - // if color1 == color2, H encoding issues can pop up, so abort - if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue) - { - continue; - } - - encodingTry.TryH_BestSelectorCombination(); - - if (encodingTry.m_fError < m_fError) - { - m_mode = encodingTry.m_mode; - m_boolDiff = encodingTry.m_boolDiff; - m_boolFlip = encodingTry.m_boolFlip; - - m_frgbaColor1 = encodingTry.m_frgbaColor1; - m_frgbaColor2 = encodingTry.m_frgbaColor2; - m_uiCW1 = encodingTry.m_uiCW1; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel]; - } - - m_fError = encodingTry.m_fError; - } - } - } - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // find best selector combination for TryH - // called on an encodingTry - // - void Block4x4Encoding_RGB8A1::TryH_BestSelectorCombination(void) - { - - // abort if colors and CW will pose an encoding problem - { - unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(255.0f); - unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(255.0f); - unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(255.0f); - unsigned int uiColorValue1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1; - - unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(255.0f); - unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(255.0f); - unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(255.0f); - unsigned int uiColorValue2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2; - - unsigned int uiCWLsb = m_uiCW1 & 1; - - if ((uiColorValue1 >= (uiColorValue2 & uiCWLsb)) == 0 || - (uiColorValue1 < (uiColorValue2 & uiCWLsb)) == 1) - { - return; - } - } - - float fDistance = s_afTHDistanceTable[m_uiCW1]; - - unsigned int auiBestPixelSelectors[PIXELS]; - float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS]; - ColorFloatRGBA afrgbaDecodedPixel[SELECTORS]; - - assert(SELECTORS == 4); - afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB(); - afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB(); - afrgbaDecodedPixel[2] = ColorFloatRGBA();; - afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB(); - - - // try each selector - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiMinSelector = 0; - unsigned int uiMaxSelector = SELECTORS - 1; - - if (m_pafrgbaSource[uiPixel].fA < 0.5f) - { - uiMinSelector = 2; - uiMaxSelector = 2; - } - - for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++) - { - float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel], - m_pafrgbaSource[uiPixel]); - - if (fPixelError < afBestPixelErrors[uiPixel]) - { - afBestPixelErrors[uiPixel] = fPixelError; - auiBestPixelSelectors[uiPixel] = uiSelector; - afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector]; - } - } - } - - - // add up all of the pixel errors - float fBlockError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - fBlockError += afBestPixelErrors[uiPixel]; - } - - if (fBlockError < m_fError) - { - m_fError = fBlockError; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel]; - m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel]; - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 1 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_RGB8A1::TryDegenerates1(void) - { - - TryDifferential(m_boolMostLikelyFlip, 1, -2, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 2, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 0, 2); - TryDifferential(m_boolMostLikelyFlip, 1, 0, -2); - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 2 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_RGB8A1::TryDegenerates2(void) - { - - TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0); - TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0); - TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2); - TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2); - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 3 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_RGB8A1::TryDegenerates3(void) - { - - TryDifferential(m_boolMostLikelyFlip, 1, -2, -2); - TryDifferential(m_boolMostLikelyFlip, 1, -2, 2); - TryDifferential(m_boolMostLikelyFlip, 1, 2, -2); - TryDifferential(m_boolMostLikelyFlip, 1, 2, 2); - - } - - // ---------------------------------------------------------------------------------------------------- - // try version 4 of the degenerate search - // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings - // each subsequent version of the degenerate search uses more basecolor movement and is less likely to - // be successfull - // - void Block4x4Encoding_RGB8A1::TryDegenerates4(void) - { - - TryDifferential(m_boolMostLikelyFlip, 1, -4, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 4, 0); - TryDifferential(m_boolMostLikelyFlip, 1, 0, 4); - TryDifferential(m_boolMostLikelyFlip, 1, 0, -4); - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_RGB8A1::SetEncodingBits(void) - { - switch (m_mode) - { - case MODE_ETC1: - SetEncodingBits_ETC1(); - break; - - case MODE_T: - SetEncodingBits_T(); - break; - - case MODE_H: - SetEncodingBits_H(); - break; - - case MODE_PLANAR: - Block4x4Encoding_RGB8::SetEncodingBits_Planar(); - break; - - default: - assert(false); - } - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state if ETC1 mode - // - void Block4x4Encoding_RGB8A1::SetEncodingBits_ETC1(void) - { - - // there is no individual mode in RGB8A1 - assert(m_boolDiff); - - int iRed1 = m_frgbaColor1.IntRed(31.0f); - int iGreen1 = m_frgbaColor1.IntGreen(31.0f); - int iBlue1 = m_frgbaColor1.IntBlue(31.0f); - - int iRed2 = m_frgbaColor2.IntRed(31.0f); - int iGreen2 = m_frgbaColor2.IntGreen(31.0f); - int iBlue2 = m_frgbaColor2.IntBlue(31.0f); - - int iDRed2 = iRed2 - iRed1; - int iDGreen2 = iGreen2 - iGreen1; - int iDBlue2 = iBlue2 - iBlue1; - - assert(iDRed2 >= -4 && iDRed2 < 4); - assert(iDGreen2 >= -4 && iDGreen2 < 4); - assert(iDBlue2 >= -4 && iDBlue2 < 4); - - m_pencodingbitsRGB8->differential.red1 = iRed1; - m_pencodingbitsRGB8->differential.green1 = iGreen1; - m_pencodingbitsRGB8->differential.blue1 = iBlue1; - - m_pencodingbitsRGB8->differential.dred2 = iDRed2; - m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2; - m_pencodingbitsRGB8->differential.dblue2 = iDBlue2; - - m_pencodingbitsRGB8->individual.cw1 = m_uiCW1; - m_pencodingbitsRGB8->individual.cw2 = m_uiCW2; - - SetEncodingBits_Selectors(); - - // in RGB8A1 encoding bits, opaque replaces differential - m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels; - - m_pencodingbitsRGB8->individual.flip = m_boolFlip; - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state if T mode - // - void Block4x4Encoding_RGB8A1::SetEncodingBits_T(void) - { - static const bool SANITY_CHECK = true; - - assert(m_mode == MODE_T); - assert(m_boolDiff == true); - - unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); - unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); - unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); - - unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); - unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); - unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); - - m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2; - m_pencodingbitsRGB8->t.red1b = uiRed1; - m_pencodingbitsRGB8->t.green1 = uiGreen1; - m_pencodingbitsRGB8->t.blue1 = uiBlue1; - - m_pencodingbitsRGB8->t.red2 = uiRed2; - m_pencodingbitsRGB8->t.green2 = uiGreen2; - m_pencodingbitsRGB8->t.blue2 = uiBlue2; - - m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1; - m_pencodingbitsRGB8->t.db = m_uiCW1; - - // in RGB8A1 encoding bits, opaque replaces differential - m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels; - - Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); - - // create an invalid R differential to trigger T mode - m_pencodingbitsRGB8->t.detect1 = 0; - m_pencodingbitsRGB8->t.detect2 = 0; - int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - if (iRed2 >= 4) - { - m_pencodingbitsRGB8->t.detect1 = 7; - m_pencodingbitsRGB8->t.detect2 = 0; - } - else - { - m_pencodingbitsRGB8->t.detect1 = 0; - m_pencodingbitsRGB8->t.detect2 = 1; - } - - if (SANITY_CHECK) - { - iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - - // make sure red overflows - assert(iRed2 < 0 || iRed2 > 31); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state if H mode - // - // colors and selectors may need to swap in order to generate lsb of distance index - // - void Block4x4Encoding_RGB8A1::SetEncodingBits_H(void) - { - static const bool SANITY_CHECK = true; - - assert(m_mode == MODE_H); - assert(m_boolDiff == true); - - unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f); - unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f); - unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f); - - unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f); - unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f); - unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f); - - unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1; - unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2; - - bool boolOddDistance = m_uiCW1 & 1; - bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance; - - if (boolSwapColors) - { - m_pencodingbitsRGB8->h.red1 = uiRed2; - m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1; - m_pencodingbitsRGB8->h.green1b = uiGreen2; - m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3; - m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1; - m_pencodingbitsRGB8->h.blue1c = uiBlue2; - - m_pencodingbitsRGB8->h.red2 = uiRed1; - m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1; - m_pencodingbitsRGB8->h.green2b = uiGreen1; - m_pencodingbitsRGB8->h.blue2 = uiBlue1; - - m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; - m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; - } - else - { - m_pencodingbitsRGB8->h.red1 = uiRed1; - m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1; - m_pencodingbitsRGB8->h.green1b = uiGreen1; - m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3; - m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1; - m_pencodingbitsRGB8->h.blue1c = uiBlue1; - - m_pencodingbitsRGB8->h.red2 = uiRed2; - m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1; - m_pencodingbitsRGB8->h.green2b = uiGreen2; - m_pencodingbitsRGB8->h.blue2 = uiBlue2; - - m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2; - m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1; - } - - // in RGB8A1 encoding bits, opaque replaces differential - m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels; - - Block4x4Encoding_ETC1::SetEncodingBits_Selectors(); - - if (boolSwapColors) - { - m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF; - } - - // create an invalid R differential to trigger T mode - m_pencodingbitsRGB8->h.detect1 = 0; - m_pencodingbitsRGB8->h.detect2 = 0; - m_pencodingbitsRGB8->h.detect3 = 0; - int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; - if (iRed2 < 0 || iRed2 > 31) - { - m_pencodingbitsRGB8->h.detect1 = 1; - } - if (iGreen2 >= 4) - { - m_pencodingbitsRGB8->h.detect2 = 7; - m_pencodingbitsRGB8->h.detect3 = 0; - } - else - { - m_pencodingbitsRGB8->h.detect2 = 0; - m_pencodingbitsRGB8->h.detect3 = 1; - } - - if (SANITY_CHECK) - { - iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2; - iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2; - - // make sure red doesn't overflow and green does - assert(iRed2 >= 0 && iRed2 <= 31); - assert(iGreen2 < 0 || iGreen2 > 31); - } - - } - - // #################################################################################################### - // Block4x4Encoding_RGB8A1_Opaque - // #################################################################################################### - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_RGB8A1_Opaque::PerformIteration(float a_fEffort) - { - assert(!m_boolPunchThroughPixels); - assert(!m_boolTransparent); - assert(!m_boolDone); - - switch (m_uiEncodingIterations) - { - case 0: - PerformFirstIteration(); - break; - - case 1: - Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0); - break; - - case 2: - Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0); - break; - - case 3: - Block4x4Encoding_RGB8::TryPlanar(1); - break; - - case 4: - Block4x4Encoding_RGB8::TryTAndH(1); - if (a_fEffort <= 49.5f) - { - m_boolDone = true; - } - break; - - case 5: - Block4x4Encoding_ETC1::TryDegenerates1(); - if (a_fEffort <= 59.5f) - { - m_boolDone = true; - } - break; - - case 6: - Block4x4Encoding_ETC1::TryDegenerates2(); - if (a_fEffort <= 69.5f) - { - m_boolDone = true; - } - break; - - case 7: - Block4x4Encoding_ETC1::TryDegenerates3(); - if (a_fEffort <= 79.5f) - { - m_boolDone = true; - } - break; - - case 8: - Block4x4Encoding_ETC1::TryDegenerates4(); - m_boolDone = true; - break; - - default: - assert(0); - break; - } - - m_uiEncodingIterations++; - SetDoneIfPerfect(); - } - - // ---------------------------------------------------------------------------------------------------- - // find best initial encoding to ensure block has a valid encoding - // - void Block4x4Encoding_RGB8A1_Opaque::PerformFirstIteration(void) - { - - // set decoded alphas - // calculate alpha error - m_fError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afDecodedAlphas[uiPixel] = 1.0f; - - float fDeltaA = 1.0f - m_pafrgbaSource[uiPixel].fA; - m_fError += fDeltaA * fDeltaA; - } - - CalculateMostLikelyFlip(); - - m_fError = FLT_MAX; - - Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 0, 0, 0); - SetDoneIfPerfect(); - if (m_boolDone) - { - return; - } - Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0); - SetDoneIfPerfect(); - if (m_boolDone) - { - return; - } - Block4x4Encoding_RGB8::TryPlanar(0); - SetDoneIfPerfect(); - if (m_boolDone) - { - return; - } - Block4x4Encoding_RGB8::TryTAndH(0); - SetDoneIfPerfect(); - } - - // #################################################################################################### - // Block4x4Encoding_RGB8A1_Transparent - // #################################################################################################### - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_RGB8A1_Transparent::PerformIteration(float ) - { - assert(!m_boolOpaque); - assert(m_boolTransparent); - assert(!m_boolDone); - assert(m_uiEncodingIterations == 0); - - m_mode = MODE_ETC1; - m_boolDiff = true; - m_boolFlip = false; - - m_uiCW1 = 0; - m_uiCW2 = 0; - - m_frgbaColor1 = ColorFloatRGBA(); - m_frgbaColor2 = ColorFloatRGBA(); - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiSelectors[uiPixel] = TRANSPARENT_SELECTOR; - - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); - m_afDecodedAlphas[uiPixel] = 0.0f; - } - - CalcBlockError(); - - m_boolDone = true; - m_uiEncodingIterations++; - - } - - // ---------------------------------------------------------------------------------------------------- - // -} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h deleted file mode 100644 index ff26e462f8..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcBlock4x4Encoding_RGB8.h" -#include "EtcErrorMetric.h" -#include "EtcBlock4x4EncodingBits.h" - -namespace Etc -{ - - // ################################################################################ - // Block4x4Encoding_RGB8A1 - // RGB8A1 if not completely opaque or transparent - // ################################################################################ - - class Block4x4Encoding_RGB8A1 : public Block4x4Encoding_RGB8 - { - public: - - static const unsigned int TRANSPARENT_SELECTOR = 2; - - Block4x4Encoding_RGB8A1(void); - virtual ~Block4x4Encoding_RGB8A1(void); - - virtual void InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, - ErrorMetric a_errormetric); - - virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric); - - virtual void PerformIteration(float a_fEffort); - - virtual void SetEncodingBits(void); - - void InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric); - - void InitFromEncodingBits_T(void); - void InitFromEncodingBits_H(void); - - void PerformFirstIteration(void); - - void Decode_ETC1(void); - void DecodePixels_T(void); - void DecodePixels_H(void); - void SetEncodingBits_ETC1(void); - void SetEncodingBits_T(void); - void SetEncodingBits_H(void); - - protected: - - bool m_boolOpaque; // all source pixels have alpha >= 0.5 - bool m_boolTransparent; // all source pixels have alpha < 0.5 - bool m_boolPunchThroughPixels; // some source pixels have alpha < 0.5 - - static float s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS]; - - private: - - void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius, - int a_iGrayOffset1, int a_iGrayOffset2); - void TryDifferentialHalf(DifferentialTrys::Half *a_phalf); - - void TryT(unsigned int a_uiRadius); - void TryT_BestSelectorCombination(void); - void TryH(unsigned int a_uiRadius); - void TryH_BestSelectorCombination(void); - - void TryDegenerates1(void); - void TryDegenerates2(void); - void TryDegenerates3(void); - void TryDegenerates4(void); - - }; - - // ################################################################################ - // Block4x4Encoding_RGB8A1_Opaque - // RGB8A1 if all pixels have alpha==1 - // ################################################################################ - - class Block4x4Encoding_RGB8A1_Opaque : public Block4x4Encoding_RGB8A1 - { - public: - - virtual void PerformIteration(float a_fEffort); - - void PerformFirstIteration(void); - - private: - - }; - - // ################################################################################ - // Block4x4Encoding_RGB8A1_Transparent - // RGB8A1 if all pixels have alpha==0 - // ################################################################################ - - class Block4x4Encoding_RGB8A1_Transparent : public Block4x4Encoding_RGB8A1 - { - public: - - virtual void PerformIteration(float a_fEffort); - - private: - - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp deleted file mode 100644 index 600c7ab405..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcBlock4x4Encoding_RGBA8.cpp contains: - Block4x4Encoding_RGBA8 - Block4x4Encoding_RGBA8_Opaque - Block4x4Encoding_RGBA8_Transparent - -These encoders are used when targetting file format RGBA8. - -Block4x4Encoding_RGBA8_Opaque is used when all pixels in the 4x4 block are opaque -Block4x4Encoding_RGBA8_Transparent is used when all pixels in the 4x4 block are transparent -Block4x4Encoding_RGBA8 is used when there is a mixture of alphas in the 4x4 block - -*/ - -#include "EtcConfig.h" -#include "EtcBlock4x4Encoding_RGBA8.h" - -#include "EtcBlock4x4EncodingBits.h" -#include "EtcBlock4x4.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <float.h> -#include <limits> - -namespace Etc -{ - - // #################################################################################################### - // Block4x4Encoding_RGBA8 - // #################################################################################################### - - float Block4x4Encoding_RGBA8::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS] - { - { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f }, - { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f }, - { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f }, - { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f }, - - { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f }, - { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f }, - { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, - { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f }, - - { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, - { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, - { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f }, - { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, - - { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f }, - { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f }, - { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f }, - { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f } - }; - - // ---------------------------------------------------------------------------------------------------- - // - Block4x4Encoding_RGBA8::Block4x4Encoding_RGBA8(void) - { - - m_pencodingbitsA8 = nullptr; - - } - Block4x4Encoding_RGBA8::~Block4x4Encoding_RGBA8(void) {} - // ---------------------------------------------------------------------------------------------------- - // initialization prior to encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits - // - void Block4x4Encoding_RGBA8::InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) - { - Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric); - - m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits; - m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8)); - - } - - // ---------------------------------------------------------------------------------------------------- - // initialization from the encoding bits of a previous encoding - // a_pblockParent points to the block associated with this encoding - // a_errormetric is used to choose the best encoding - // a_pafrgbaSource points to a 4x4 block subset of the source image - // a_paucEncodingBits points to the final encoding bits of a previous encoding - // - void Block4x4Encoding_RGBA8::InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric) - { - - m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits; - m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8)); - - // init RGB portion - Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent, - (unsigned char *) m_pencodingbitsRGB8, - a_pafrgbaSource, - a_errormetric); - - // init A8 portion - // has to be done after InitFromEncodingBits() - { - m_fBase = m_pencodingbitsA8->data.base / 255.0f; - m_fMultiplier = (float)m_pencodingbitsA8->data.multiplier; - m_uiModifierTableIndex = m_pencodingbitsA8->data.table; - - unsigned long long int ulliSelectorBits = 0; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors0 << 40; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors1 << 32; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors2 << 24; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors3 << 16; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors4 << 8; - ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors5; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiShift = 45 - (3 * uiPixel); - m_auiAlphaSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (ALPHA_SELECTORS - 1); - } - - // decode the alphas - // calc alpha error - m_fError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afDecodedAlphas[uiPixel] = DecodePixelAlpha(m_fBase, m_fMultiplier, - m_uiModifierTableIndex, - m_auiAlphaSelectors[uiPixel]); - - float fDeltaAlpha = m_afDecodedAlphas[uiPixel] - m_pafrgbaSource[uiPixel].fA; - m_fError += fDeltaAlpha * fDeltaAlpha; - } - } - - // redo error calc to include alpha - CalcBlockError(); - - } - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - // similar to Block4x4Encoding_RGB8_Base::Encode_RGB8(), but with alpha added - // - void Block4x4Encoding_RGBA8::PerformIteration(float a_fEffort) - { - assert(!m_boolDone); - - if (m_uiEncodingIterations == 0) - { - if (a_fEffort < 24.9f) - { - CalculateA8(0.0f); - } - else if (a_fEffort < 49.9f) - { - CalculateA8(1.0f); - } - else - { - CalculateA8(2.0f); - } - } - - Block4x4Encoding_RGB8::PerformIteration(a_fEffort); - - } - - // ---------------------------------------------------------------------------------------------------- - // find the best combination of base alpga, multiplier and selectors - // - // a_fRadius limits the range of base alpha to try - // - void Block4x4Encoding_RGBA8::CalculateA8(float a_fRadius) - { - - // find min/max alpha - float fMinAlpha = 1.0f; - float fMaxAlpha = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - float fAlpha = m_pafrgbaSource[uiPixel].fA; - - // ignore border pixels - if (isnan(fAlpha)) - { - continue; - } - - if (fAlpha < fMinAlpha) - { - fMinAlpha = fAlpha; - } - if (fAlpha > fMaxAlpha) - { - fMaxAlpha = fAlpha; - } - } - assert(fMinAlpha <= fMaxAlpha); - - float fAlphaRange = fMaxAlpha - fMinAlpha; - - // try each modifier table entry - m_fError = FLT_MAX; // artificially high value - for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++) - { - static const unsigned int MIN_VALUE_SELECTOR = 3; - static const unsigned int MAX_VALUE_SELECTOR = 7; - - float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR]; - - float fTableEntryRange = s_aafModifierTable[uiTableEntry][MAX_VALUE_SELECTOR] - - s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR]; - - float fCenterRatio = fTableEntryCenter / fTableEntryRange; - - float fCenter = fMinAlpha + fCenterRatio*fAlphaRange; - fCenter = roundf(255.0f * fCenter) / 255.0f; - - float fMinBase = fCenter - (a_fRadius / 255.0f); - if (fMinBase < 0.0f) - { - fMinBase = 0.0f; - } - - float fMaxBase = fCenter + (a_fRadius / 255.0f); - if (fMaxBase > 1.0f) - { - fMaxBase = 1.0f; - } - - for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f)) - { - - float fRangeMultiplier = roundf(fAlphaRange / fTableEntryRange); - - float fMinMultiplier = fRangeMultiplier - a_fRadius; - if (fMinMultiplier < 1.0f) - { - fMinMultiplier = 1.0f; - } - else if (fMinMultiplier > 15.0f) - { - fMinMultiplier = 15.0f; - } - - float fMaxMultiplier = fRangeMultiplier + a_fRadius; - if (fMaxMultiplier < 1.0f) - { - fMaxMultiplier = 1.0f; - } - else if (fMaxMultiplier > 15.0f) - { - fMaxMultiplier = 15.0f; - } - - for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f) - { - // find best selector for each pixel - unsigned int auiBestSelectors[PIXELS]; - float afBestAlphaError[PIXELS]; - float afBestDecodedAlphas[PIXELS]; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - float fBestPixelAlphaError = FLT_MAX; - for (unsigned int uiSelector = 0; uiSelector < ALPHA_SELECTORS; uiSelector++) - { - float fDecodedAlpha = DecodePixelAlpha(fBase, fMultiplier, uiTableEntry, uiSelector); - - // border pixels (NAN) should have zero error - float fPixelDeltaAlpha = isnan(m_pafrgbaSource[uiPixel].fA) ? - 0.0f : - fDecodedAlpha - m_pafrgbaSource[uiPixel].fA; - - float fPixelAlphaError = fPixelDeltaAlpha * fPixelDeltaAlpha; - - if (fPixelAlphaError < fBestPixelAlphaError) - { - fBestPixelAlphaError = fPixelAlphaError; - auiBestSelectors[uiPixel] = uiSelector; - afBestAlphaError[uiPixel] = fBestPixelAlphaError; - afBestDecodedAlphas[uiPixel] = fDecodedAlpha; - } - } - } - - float fBlockError = 0.0f; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - fBlockError += afBestAlphaError[uiPixel]; - } - - if (fBlockError < m_fError) - { - m_fError = fBlockError; - - m_fBase = fBase; - m_fMultiplier = fMultiplier; - m_uiModifierTableIndex = uiTableEntry; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_auiAlphaSelectors[uiPixel] = auiBestSelectors[uiPixel]; - m_afDecodedAlphas[uiPixel] = afBestDecodedAlphas[uiPixel]; - } - } - } - } - - } - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_RGBA8::SetEncodingBits(void) - { - - // set the RGB8 portion - Block4x4Encoding_RGB8::SetEncodingBits(); - - // set the A8 portion - { - m_pencodingbitsA8->data.base = (unsigned char)roundf(255.0f * m_fBase); - m_pencodingbitsA8->data.table = m_uiModifierTableIndex; - m_pencodingbitsA8->data.multiplier = (unsigned char)roundf(m_fMultiplier); - - unsigned long long int ulliSelectorBits = 0; - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - unsigned int uiShift = 45 - (3 * uiPixel); - ulliSelectorBits |= ((unsigned long long int)m_auiAlphaSelectors[uiPixel]) << uiShift; - } - - m_pencodingbitsA8->data.selectors0 = ulliSelectorBits >> 40; - m_pencodingbitsA8->data.selectors1 = ulliSelectorBits >> 32; - m_pencodingbitsA8->data.selectors2 = ulliSelectorBits >> 24; - m_pencodingbitsA8->data.selectors3 = ulliSelectorBits >> 16; - m_pencodingbitsA8->data.selectors4 = ulliSelectorBits >> 8; - m_pencodingbitsA8->data.selectors5 = ulliSelectorBits; - } - - } - - // #################################################################################################### - // Block4x4Encoding_RGBA8_Opaque - // #################################################################################################### - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_RGBA8_Opaque::PerformIteration(float a_fEffort) - { - assert(!m_boolDone); - - if (m_uiEncodingIterations == 0) - { - m_fError = 0.0f; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afDecodedAlphas[uiPixel] = 1.0f; - } - } - - Block4x4Encoding_RGB8::PerformIteration(a_fEffort); - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_RGBA8_Opaque::SetEncodingBits(void) - { - - // set the RGB8 portion - Block4x4Encoding_RGB8::SetEncodingBits(); - - // set the A8 portion - m_pencodingbitsA8->data.base = 255; - m_pencodingbitsA8->data.table = 15; - m_pencodingbitsA8->data.multiplier = 15; - m_pencodingbitsA8->data.selectors0 = 0xFF; - m_pencodingbitsA8->data.selectors1 = 0xFF; - m_pencodingbitsA8->data.selectors2 = 0xFF; - m_pencodingbitsA8->data.selectors3 = 0xFF; - m_pencodingbitsA8->data.selectors4 = 0xFF; - m_pencodingbitsA8->data.selectors5 = 0xFF; - - } - - // #################################################################################################### - // Block4x4Encoding_RGBA8_Transparent - // #################################################################################################### - - // ---------------------------------------------------------------------------------------------------- - // perform a single encoding iteration - // replace the encoding if a better encoding was found - // subsequent iterations generally take longer for each iteration - // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort - // - void Block4x4Encoding_RGBA8_Transparent::PerformIteration(float ) - { - assert(!m_boolDone); - assert(m_uiEncodingIterations == 0); - - m_mode = MODE_ETC1; - m_boolDiff = true; - m_boolFlip = false; - - for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++) - { - m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(); - m_afDecodedAlphas[uiPixel] = 0.0f; - } - - m_fError = 0.0f; - - m_boolDone = true; - m_uiEncodingIterations++; - - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits based on encoding state - // - void Block4x4Encoding_RGBA8_Transparent::SetEncodingBits(void) - { - - Block4x4Encoding_RGB8::SetEncodingBits(); - - // set the A8 portion - m_pencodingbitsA8->data.base = 0; - m_pencodingbitsA8->data.table = 0; - m_pencodingbitsA8->data.multiplier = 1; - m_pencodingbitsA8->data.selectors0 = 0; - m_pencodingbitsA8->data.selectors1 = 0; - m_pencodingbitsA8->data.selectors2 = 0; - m_pencodingbitsA8->data.selectors3 = 0; - m_pencodingbitsA8->data.selectors4 = 0; - m_pencodingbitsA8->data.selectors5 = 0; - - } - - // ---------------------------------------------------------------------------------------------------- - // -} diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h deleted file mode 100644 index 5765d36b90..0000000000 --- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcBlock4x4Encoding_RGB8.h" - -namespace Etc -{ - class Block4x4EncodingBits_A8; - - // ################################################################################ - // Block4x4Encoding_RGBA8 - // RGBA8 if not completely opaque or transparent - // ################################################################################ - - class Block4x4Encoding_RGBA8 : public Block4x4Encoding_RGB8 - { - public: - - Block4x4Encoding_RGBA8(void); - virtual ~Block4x4Encoding_RGBA8(void); - - virtual void InitFromSource(Block4x4 *a_pblockParent, - ColorFloatRGBA *a_pafrgbaSource, - unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric); - - virtual void InitFromEncodingBits(Block4x4 *a_pblockParent, - unsigned char *a_paucEncodingBits, - ColorFloatRGBA *a_pafrgbaSource, - ErrorMetric a_errormetric); - - virtual void PerformIteration(float a_fEffort); - - virtual void SetEncodingBits(void); - - protected: - - static const unsigned int MODIFIER_TABLE_ENTRYS = 16; - static const unsigned int ALPHA_SELECTOR_BITS = 3; - static const unsigned int ALPHA_SELECTORS = 1 << ALPHA_SELECTOR_BITS; - - static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS]; - - void CalculateA8(float a_fRadius); - - Block4x4EncodingBits_A8 *m_pencodingbitsA8; // A8 portion of Block4x4EncodingBits_RGBA8 - - float m_fBase; - float m_fMultiplier; - unsigned int m_uiModifierTableIndex; - unsigned int m_auiAlphaSelectors[PIXELS]; - - private: - - inline float DecodePixelAlpha(float a_fBase, float a_fMultiplier, - unsigned int a_uiTableIndex, unsigned int a_uiSelector) - { - float fPixelAlpha = a_fBase + - a_fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]; - if (fPixelAlpha < 0.0f) - { - fPixelAlpha = 0.0f; - } - else if (fPixelAlpha > 1.0f) - { - fPixelAlpha = 1.0f; - } - - return fPixelAlpha; - } - - }; - - // ################################################################################ - // Block4x4Encoding_RGBA8_Opaque - // RGBA8 if all pixels have alpha==1 - // ################################################################################ - - class Block4x4Encoding_RGBA8_Opaque : public Block4x4Encoding_RGBA8 - { - public: - - virtual void PerformIteration(float a_fEffort); - - virtual void SetEncodingBits(void); - - }; - - // ################################################################################ - // Block4x4Encoding_RGBA8_Transparent - // RGBA8 if all pixels have alpha==0 - // ################################################################################ - - class Block4x4Encoding_RGBA8_Transparent : public Block4x4Encoding_RGBA8 - { - public: - - virtual void PerformIteration(float a_fEffort); - - virtual void SetEncodingBits(void); - - }; - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcColor.h b/thirdparty/etc2comp/EtcColor.h deleted file mode 100644 index 7ceae05b65..0000000000 --- a/thirdparty/etc2comp/EtcColor.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <math.h> - -namespace Etc -{ - - inline float LogToLinear(float a_fLog) - { - static const float ALPHA = 0.055f; - static const float ONE_PLUS_ALPHA = 1.0f + ALPHA; - - if (a_fLog <= 0.04045f) - { - return a_fLog / 12.92f; - } - else - { - return powf((a_fLog + ALPHA) / ONE_PLUS_ALPHA, 2.4f); - } - } - - inline float LinearToLog(float &a_fLinear) - { - static const float ALPHA = 0.055f; - static const float ONE_PLUS_ALPHA = 1.0f + ALPHA; - - if (a_fLinear <= 0.0031308f) - { - return 12.92f * a_fLinear; - } - else - { - return ONE_PLUS_ALPHA * powf(a_fLinear, (1.0f/2.4f)) - ALPHA; - } - } - - class ColorR8G8B8A8 - { - public: - - unsigned char ucR; - unsigned char ucG; - unsigned char ucB; - unsigned char ucA; - - }; -} diff --git a/thirdparty/etc2comp/EtcColorFloatRGBA.h b/thirdparty/etc2comp/EtcColorFloatRGBA.h deleted file mode 100644 index f2ca2c1f71..0000000000 --- a/thirdparty/etc2comp/EtcColorFloatRGBA.h +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcConfig.h" -#include "EtcColor.h" - -#include <math.h> - -namespace Etc -{ - - class ColorFloatRGBA - { - public: - - ColorFloatRGBA(void) - { - fR = fG = fB = fA = 0.0f; - } - - ColorFloatRGBA(float a_fR, float a_fG, float a_fB, float a_fA) - { - fR = a_fR; - fG = a_fG; - fB = a_fB; - fA = a_fA; - } - - inline ColorFloatRGBA operator+(ColorFloatRGBA& a_rfrgba) - { - ColorFloatRGBA frgba; - frgba.fR = fR + a_rfrgba.fR; - frgba.fG = fG + a_rfrgba.fG; - frgba.fB = fB + a_rfrgba.fB; - frgba.fA = fA + a_rfrgba.fA; - return frgba; - } - - inline ColorFloatRGBA operator+(float a_f) - { - ColorFloatRGBA frgba; - frgba.fR = fR + a_f; - frgba.fG = fG + a_f; - frgba.fB = fB + a_f; - frgba.fA = fA; - return frgba; - } - - inline ColorFloatRGBA operator-(float a_f) - { - ColorFloatRGBA frgba; - frgba.fR = fR - a_f; - frgba.fG = fG - a_f; - frgba.fB = fB - a_f; - frgba.fA = fA; - return frgba; - } - - inline ColorFloatRGBA operator-(ColorFloatRGBA& a_rfrgba) - { - ColorFloatRGBA frgba; - frgba.fR = fR - a_rfrgba.fR; - frgba.fG = fG - a_rfrgba.fG; - frgba.fB = fB - a_rfrgba.fB; - frgba.fA = fA - a_rfrgba.fA; - return frgba; - } - - inline ColorFloatRGBA operator*(float a_f) - { - ColorFloatRGBA frgba; - frgba.fR = fR * a_f; - frgba.fG = fG * a_f; - frgba.fB = fB * a_f; - frgba.fA = fA; - - return frgba; - } - - inline ColorFloatRGBA ScaleRGB(float a_f) - { - ColorFloatRGBA frgba; - frgba.fR = a_f * fR; - frgba.fG = a_f * fG; - frgba.fB = a_f * fB; - frgba.fA = fA; - - return frgba; - } - - inline ColorFloatRGBA RoundRGB(void) - { - ColorFloatRGBA frgba; - frgba.fR = roundf(fR); - frgba.fG = roundf(fG); - frgba.fB = roundf(fB); - - return frgba; - } - - inline ColorFloatRGBA ToLinear() - { - ColorFloatRGBA frgbaLinear; - frgbaLinear.fR = LogToLinear(fR); - frgbaLinear.fG = LogToLinear(fG); - frgbaLinear.fB = LogToLinear(fB); - frgbaLinear.fA = fA; - - return frgbaLinear; - } - - inline ColorFloatRGBA ToLog(void) - { - ColorFloatRGBA frgbaLog; - frgbaLog.fR = LinearToLog(fR); - frgbaLog.fG = LinearToLog(fG); - frgbaLog.fB = LinearToLog(fB); - frgbaLog.fA = fA; - - return frgbaLog; - } - - inline static ColorFloatRGBA ConvertFromRGBA8(unsigned char a_ucR, - unsigned char a_ucG, unsigned char a_ucB, unsigned char a_ucA) - { - ColorFloatRGBA frgba; - - frgba.fR = (float)a_ucR / 255.0f; - frgba.fG = (float)a_ucG / 255.0f; - frgba.fB = (float)a_ucB / 255.0f; - frgba.fA = (float)a_ucA / 255.0f; - - return frgba; - } - - inline static ColorFloatRGBA ConvertFromRGB4(unsigned char a_ucR4, - unsigned char a_ucG4, - unsigned char a_ucB4) - { - ColorFloatRGBA frgba; - - unsigned char ucR8 = (unsigned char)((a_ucR4 << 4) + a_ucR4); - unsigned char ucG8 = (unsigned char)((a_ucG4 << 4) + a_ucG4); - unsigned char ucB8 = (unsigned char)((a_ucB4 << 4) + a_ucB4); - - frgba.fR = (float)ucR8 / 255.0f; - frgba.fG = (float)ucG8 / 255.0f; - frgba.fB = (float)ucB8 / 255.0f; - frgba.fA = 1.0f; - - return frgba; - } - - inline static ColorFloatRGBA ConvertFromRGB5(unsigned char a_ucR5, - unsigned char a_ucG5, - unsigned char a_ucB5) - { - ColorFloatRGBA frgba; - - unsigned char ucR8 = (unsigned char)((a_ucR5 << 3) + (a_ucR5 >> 2)); - unsigned char ucG8 = (unsigned char)((a_ucG5 << 3) + (a_ucG5 >> 2)); - unsigned char ucB8 = (unsigned char)((a_ucB5 << 3) + (a_ucB5 >> 2)); - - frgba.fR = (float)ucR8 / 255.0f; - frgba.fG = (float)ucG8 / 255.0f; - frgba.fB = (float)ucB8 / 255.0f; - frgba.fA = 1.0f; - - return frgba; - } - - inline static ColorFloatRGBA ConvertFromR6G7B6(unsigned char a_ucR6, - unsigned char a_ucG7, - unsigned char a_ucB6) - { - ColorFloatRGBA frgba; - - unsigned char ucR8 = (unsigned char)((a_ucR6 << 2) + (a_ucR6 >> 4)); - unsigned char ucG8 = (unsigned char)((a_ucG7 << 1) + (a_ucG7 >> 6)); - unsigned char ucB8 = (unsigned char)((a_ucB6 << 2) + (a_ucB6 >> 4)); - - frgba.fR = (float)ucR8 / 255.0f; - frgba.fG = (float)ucG8 / 255.0f; - frgba.fB = (float)ucB8 / 255.0f; - frgba.fA = 1.0f; - - return frgba; - } - - // quantize to 4 bits, expand to 8 bits - inline ColorFloatRGBA QuantizeR4G4B4(void) const - { - ColorFloatRGBA frgba = *this; - - // quantize to 4 bits - frgba = frgba.ClampRGB().ScaleRGB(15.0f).RoundRGB(); - unsigned int uiR4 = (unsigned int)frgba.fR; - unsigned int uiG4 = (unsigned int)frgba.fG; - unsigned int uiB4 = (unsigned int)frgba.fB; - - // expand to 8 bits - frgba.fR = (float) ((uiR4 << 4) + uiR4); - frgba.fG = (float) ((uiG4 << 4) + uiG4); - frgba.fB = (float) ((uiB4 << 4) + uiB4); - - frgba = frgba.ScaleRGB(1.0f/255.0f); - - return frgba; - } - - // quantize to 5 bits, expand to 8 bits - inline ColorFloatRGBA QuantizeR5G5B5(void) const - { - ColorFloatRGBA frgba = *this; - - // quantize to 5 bits - frgba = frgba.ClampRGB().ScaleRGB(31.0f).RoundRGB(); - unsigned int uiR5 = (unsigned int)frgba.fR; - unsigned int uiG5 = (unsigned int)frgba.fG; - unsigned int uiB5 = (unsigned int)frgba.fB; - - // expand to 8 bits - frgba.fR = (float)((uiR5 << 3) + (uiR5 >> 2)); - frgba.fG = (float)((uiG5 << 3) + (uiG5 >> 2)); - frgba.fB = (float)((uiB5 << 3) + (uiB5 >> 2)); - - frgba = frgba.ScaleRGB(1.0f / 255.0f); - - return frgba; - } - - // quantize to 6/7/6 bits, expand to 8 bits - inline ColorFloatRGBA QuantizeR6G7B6(void) const - { - ColorFloatRGBA frgba = *this; - - // quantize to 6/7/6 bits - ColorFloatRGBA frgba6 = frgba.ClampRGB().ScaleRGB(63.0f).RoundRGB(); - ColorFloatRGBA frgba7 = frgba.ClampRGB().ScaleRGB(127.0f).RoundRGB(); - unsigned int uiR6 = (unsigned int)frgba6.fR; - unsigned int uiG7 = (unsigned int)frgba7.fG; - unsigned int uiB6 = (unsigned int)frgba6.fB; - - // expand to 8 bits - frgba.fR = (float)((uiR6 << 2) + (uiR6 >> 4)); - frgba.fG = (float)((uiG7 << 1) + (uiG7 >> 6)); - frgba.fB = (float)((uiB6 << 2) + (uiB6 >> 4)); - - frgba = frgba.ScaleRGB(1.0f / 255.0f); - - return frgba; - } - - inline ColorFloatRGBA ClampRGB(void) - { - ColorFloatRGBA frgba = *this; - if (frgba.fR < 0.0f) { frgba.fR = 0.0f; } - if (frgba.fR > 1.0f) { frgba.fR = 1.0f; } - if (frgba.fG < 0.0f) { frgba.fG = 0.0f; } - if (frgba.fG > 1.0f) { frgba.fG = 1.0f; } - if (frgba.fB < 0.0f) { frgba.fB = 0.0f; } - if (frgba.fB > 1.0f) { frgba.fB = 1.0f; } - - return frgba; - } - - inline ColorFloatRGBA ClampRGBA(void) - { - ColorFloatRGBA frgba = *this; - if (frgba.fR < 0.0f) { frgba.fR = 0.0f; } - if (frgba.fR > 1.0f) { frgba.fR = 1.0f; } - if (frgba.fG < 0.0f) { frgba.fG = 0.0f; } - if (frgba.fG > 1.0f) { frgba.fG = 1.0f; } - if (frgba.fB < 0.0f) { frgba.fB = 0.0f; } - if (frgba.fB > 1.0f) { frgba.fB = 1.0f; } - if (frgba.fA < 0.0f) { frgba.fA = 0.0f; } - if (frgba.fA > 1.0f) { frgba.fA = 1.0f; } - - return frgba; - } - - inline int IntRed(float a_fScale) - { - return (int)roundf(fR * a_fScale); - } - - inline int IntGreen(float a_fScale) - { - return (int)roundf(fG * a_fScale); - } - - inline int IntBlue(float a_fScale) - { - return (int)roundf(fB * a_fScale); - } - - inline int IntAlpha(float a_fScale) - { - return (int)roundf(fA * a_fScale); - } - - float fR, fG, fB, fA; - }; - -} - diff --git a/thirdparty/etc2comp/EtcConfig.h b/thirdparty/etc2comp/EtcConfig.h deleted file mode 100644 index 3bfe1d99a8..0000000000 --- a/thirdparty/etc2comp/EtcConfig.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#ifdef _WIN32 -#define ETC_WINDOWS (1) -#else -#define ETC_WINDOWS (0) -#endif - -#if __APPLE__ -#define ETC_OSX (1) -#else -#define ETC_OSX (0) -#endif - -#if __unix__ -#define ETC_UNIX (1) -#else -#define ETC_UNIX (0) -#endif - - -// short names for common types -#include <stdint.h> -typedef int8_t i8; -typedef int16_t i16; -typedef int32_t i32; -typedef int64_t i64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef float f32; -typedef double f64; - -// Keep asserts enabled in release builds during development -#undef NDEBUG - -// 0=disable. stb_image can be used if you need to compress -//other image formats like jpg -#define USE_STB_IMAGE_LOAD 0 - -#if ETC_WINDOWS -#include <sdkddkver.h> -#define _CRT_SECURE_NO_WARNINGS (1) -#include <tchar.h> -#endif - -#include <stdio.h> - diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.cpp b/thirdparty/etc2comp/EtcDifferentialTrys.cpp deleted file mode 100644 index ef4cd103d9..0000000000 --- a/thirdparty/etc2comp/EtcDifferentialTrys.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcDifferentialTrys.cpp - -Gathers the results of the various encoding trys for both halves of a 4x4 block for Differential mode - -*/ - -#include "EtcConfig.h" -#include "EtcDifferentialTrys.h" - -#include <assert.h> - -namespace Etc -{ - - // ---------------------------------------------------------------------------------------------------- - // construct a list of trys (encoding attempts) - // - // a_frgbaColor1 is the basecolor for the first half - // a_frgbaColor2 is the basecolor for the second half - // a_pauiPixelMapping1 is the pixel order for the first half - // a_pauiPixelMapping2 is the pixel order for the second half - // a_uiRadius is the amount to vary the base colors - // - DifferentialTrys::DifferentialTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2, - const unsigned int *a_pauiPixelMapping1, - const unsigned int *a_pauiPixelMapping2, - unsigned int a_uiRadius, - int a_iGrayOffset1, int a_iGrayOffset2) - { - assert(a_uiRadius <= MAX_RADIUS); - - m_boolSeverelyBentColors = false; - - ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR5G5B5(); - ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR5G5B5(); - - // quantize base colors - // ensure that trys with a_uiRadius don't overflow - int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(31.0f)+a_iGrayOffset1, a_uiRadius); - int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(31.0f) + a_iGrayOffset1, a_uiRadius); - int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(31.0f) + a_iGrayOffset1, a_uiRadius); - int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(31.0f) + a_iGrayOffset2, a_uiRadius); - int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(31.0f) + a_iGrayOffset2, a_uiRadius); - int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(31.0f) + a_iGrayOffset2, a_uiRadius); - - int iDeltaRed = iRed2 - iRed1; - int iDeltaGreen = iGreen2 - iGreen1; - int iDeltaBlue = iBlue2 - iBlue1; - - // make sure components are within range - { - if (iDeltaRed > 3) - { - if (iDeltaRed > 7) - { - m_boolSeverelyBentColors = true; - } - - iRed1 += (iDeltaRed - 3) / 2; - iRed2 = iRed1 + 3; - iDeltaRed = 3; - } - else if (iDeltaRed < -4) - { - if (iDeltaRed < -8) - { - m_boolSeverelyBentColors = true; - } - - iRed1 += (iDeltaRed + 4) / 2; - iRed2 = iRed1 - 4; - iDeltaRed = -4; - } - assert(iRed1 >= (signed)(0 + a_uiRadius) && iRed1 <= (signed)(31 - a_uiRadius)); - assert(iRed2 >= (signed)(0 + a_uiRadius) && iRed2 <= (signed)(31 - a_uiRadius)); - assert(iDeltaRed >= -4 && iDeltaRed <= 3); - - if (iDeltaGreen > 3) - { - if (iDeltaGreen > 7) - { - m_boolSeverelyBentColors = true; - } - - iGreen1 += (iDeltaGreen - 3) / 2; - iGreen2 = iGreen1 + 3; - iDeltaGreen = 3; - } - else if (iDeltaGreen < -4) - { - if (iDeltaGreen < -8) - { - m_boolSeverelyBentColors = true; - } - - iGreen1 += (iDeltaGreen + 4) / 2; - iGreen2 = iGreen1 - 4; - iDeltaGreen = -4; - } - assert(iGreen1 >= (signed)(0 + a_uiRadius) && iGreen1 <= (signed)(31 - a_uiRadius)); - assert(iGreen2 >= (signed)(0 + a_uiRadius) && iGreen2 <= (signed)(31 - a_uiRadius)); - assert(iDeltaGreen >= -4 && iDeltaGreen <= 3); - - if (iDeltaBlue > 3) - { - if (iDeltaBlue > 7) - { - m_boolSeverelyBentColors = true; - } - - iBlue1 += (iDeltaBlue - 3) / 2; - iBlue2 = iBlue1 + 3; - iDeltaBlue = 3; - } - else if (iDeltaBlue < -4) - { - if (iDeltaBlue < -8) - { - m_boolSeverelyBentColors = true; - } - - iBlue1 += (iDeltaBlue + 4) / 2; - iBlue2 = iBlue1 - 4; - iDeltaBlue = -4; - } - assert(iBlue1 >= (signed)(0+a_uiRadius) && iBlue1 <= (signed)(31 - a_uiRadius)); - assert(iBlue2 >= (signed)(0 + a_uiRadius) && iBlue2 <= (signed)(31 - a_uiRadius)); - assert(iDeltaBlue >= -4 && iDeltaBlue <= 3); - } - - m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius); - m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius); - - } - - // ---------------------------------------------------------------------------------------------------- - // - void DifferentialTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue, - const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius) - { - - m_iRed = a_iRed; - m_iGreen = a_iGreen; - m_iBlue = a_iBlue; - - m_pauiPixelMapping = a_pauiPixelMapping; - m_uiRadius = a_uiRadius; - - m_uiTrys = 0; - - } - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.h b/thirdparty/etc2comp/EtcDifferentialTrys.h deleted file mode 100644 index 71860908ff..0000000000 --- a/thirdparty/etc2comp/EtcDifferentialTrys.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcColorFloatRGBA.h" - -namespace Etc -{ - - class DifferentialTrys - { - public: - - static const unsigned int MAX_RADIUS = 2; - - DifferentialTrys(ColorFloatRGBA a_frgbaColor1, - ColorFloatRGBA a_frgbaColor2, - const unsigned int *a_pauiPixelMapping1, - const unsigned int *a_pauiPixelMapping2, - unsigned int a_uiRadius, - int a_iGrayOffset1, int a_iGrayOffset2); - - inline static int MoveAwayFromEdge(int a_i, int a_iDistance) - { - if (a_i < (0+ a_iDistance)) - { - return (0 + a_iDistance); - } - else if (a_i > (31- a_iDistance)) - { - return (31 - a_iDistance); - } - - return a_i; - } - - class Try - { - public : - static const unsigned int SELECTORS = 8; // per half - - int m_iRed; - int m_iGreen; - int m_iBlue; - unsigned int m_uiCW; - unsigned int m_auiSelectors[SELECTORS]; - float m_fError; - }; - - class Half - { - public: - - static const unsigned int MAX_TRYS = 125; - - void Init(int a_iRed, int a_iGreen, int a_iBlue, - const unsigned int *a_pauiPixelMapping, - unsigned int a_uiRadius); - - // center of trys - int m_iRed; - int m_iGreen; - int m_iBlue; - - const unsigned int *m_pauiPixelMapping; - unsigned int m_uiRadius; - - unsigned int m_uiTrys; - Try m_atry[MAX_TRYS]; - - Try *m_ptryBest; - }; - - Half m_half1; - Half m_half2; - - bool m_boolSeverelyBentColors; - }; - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcErrorMetric.h b/thirdparty/etc2comp/EtcErrorMetric.h deleted file mode 100644 index df4dcab4fb..0000000000 --- a/thirdparty/etc2comp/EtcErrorMetric.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -namespace Etc -{ - - enum ErrorMetric - { - RGBA, - RGBX, - REC709, - NUMERIC, - NORMALXYZ, - // - ERROR_METRICS, - // - BT709 = REC709 - }; - - inline const char *ErrorMetricToString(ErrorMetric errorMetric) - { - switch (errorMetric) - { - case RGBA: - return "RGBA"; - case RGBX: - return "RGBX"; - case REC709: - return "REC709"; - case NUMERIC: - return "NUMERIC"; - case NORMALXYZ: - return "NORMALXYZ"; - case ERROR_METRICS: - default: - return "UNKNOWN"; - } - } -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcFile.cpp b/thirdparty/etc2comp/EtcFile.cpp deleted file mode 100644 index 831a3aac45..0000000000 --- a/thirdparty/etc2comp/EtcFile.cpp +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef _WIN32 -#define _CRT_SECURE_NO_WARNINGS (1) -#endif - -#include "EtcConfig.h" - - -#include "EtcFile.h" - -#include "EtcFileHeader.h" -#include "EtcColor.h" -#include "Etc.h" -#include "EtcBlock4x4EncodingBits.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <stdlib.h> - -using namespace Etc; - -// ---------------------------------------------------------------------------------------------------- -// -File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, - unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes, - unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, - unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight) -{ - if (a_pstrFilename == nullptr) - { - m_pstrFilename = const_cast<char *>(""); - } - else - { - m_pstrFilename = new char[strlen(a_pstrFilename) + 1]; - strcpy(m_pstrFilename, a_pstrFilename); - } - - m_fileformat = a_fileformat; - if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION) - { - // ***** TODO: add this later ***** - m_fileformat = Format::KTX; - } - - m_imageformat = a_imageformat; - - m_uiNumMipmaps = 1; - m_pMipmapImages = new RawImage[m_uiNumMipmaps]; - m_pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(a_paucEncodingBits, [](unsigned char *p) { delete[] p; } ); - m_pMipmapImages[0].uiEncodingBitsBytes = a_uiEncodingBitsBytes; - m_pMipmapImages[0].uiExtendedWidth = a_uiExtendedWidth; - m_pMipmapImages[0].uiExtendedHeight = a_uiExtendedHeight; - - m_uiSourceWidth = a_uiSourceWidth; - m_uiSourceHeight = a_uiSourceHeight; - - switch (m_fileformat) - { - case Format::PKM: - m_pheader = new FileHeader_Pkm(this); - break; - - case Format::KTX: - m_pheader = new FileHeader_Ktx(this); - break; - - default: - assert(0); - break; - } - -} - -// ---------------------------------------------------------------------------------------------------- -// -File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, - unsigned int a_uiNumMipmaps, RawImage *a_pMipmapImages, - unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight) -{ - if (a_pstrFilename == nullptr) - { - m_pstrFilename = const_cast<char *>(""); - } - else - { - m_pstrFilename = new char[strlen(a_pstrFilename) + 1]; - strcpy(m_pstrFilename, a_pstrFilename); - } - - m_fileformat = a_fileformat; - if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION) - { - // ***** TODO: add this later ***** - m_fileformat = Format::KTX; - } - - m_imageformat = a_imageformat; - - m_uiNumMipmaps = a_uiNumMipmaps; - m_pMipmapImages = new RawImage[m_uiNumMipmaps]; - - for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++) - { - m_pMipmapImages[mip] = a_pMipmapImages[mip]; - } - - m_uiSourceWidth = a_uiSourceWidth; - m_uiSourceHeight = a_uiSourceHeight; - - switch (m_fileformat) - { - case Format::PKM: - m_pheader = new FileHeader_Pkm(this); - break; - - case Format::KTX: - m_pheader = new FileHeader_Ktx(this); - break; - - default: - assert(0); - break; - } - -} - -// ---------------------------------------------------------------------------------------------------- -// -File::File(const char *a_pstrFilename, Format a_fileformat) -{ - if (a_pstrFilename == nullptr) - { - return; - } - else - { - m_pstrFilename = new char[strlen(a_pstrFilename) + 1]; - strcpy(m_pstrFilename, a_pstrFilename); - } - - m_fileformat = a_fileformat; - if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION) - { - // ***** TODO: add this later ***** - m_fileformat = Format::KTX; - } - - FILE *pfile = fopen(m_pstrFilename, "rb"); - if (pfile == nullptr) - { - printf("ERROR: Couldn't open %s", m_pstrFilename); - exit(1); - } - fseek(pfile, 0, SEEK_END); - unsigned int fileSize = ftell(pfile); - fseek(pfile, 0, SEEK_SET); - size_t szResult; - - m_pheader = new FileHeader_Ktx(this); - szResult = fread( ((FileHeader_Ktx*)m_pheader)->GetData(), 1, sizeof(FileHeader_Ktx::Data), pfile); - assert(szResult > 0); - - m_uiNumMipmaps = 1; - m_pMipmapImages = new RawImage[m_uiNumMipmaps]; - - if (((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData > 0) - fseek(pfile, ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData, SEEK_CUR); - szResult = fread(&m_pMipmapImages->uiEncodingBitsBytes, 1, sizeof(unsigned int), pfile); - assert(szResult > 0); - - m_pMipmapImages->paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[m_pMipmapImages->uiEncodingBitsBytes], [](unsigned char *p) { delete[] p; } ); - assert(ftell(pfile) + m_pMipmapImages->uiEncodingBitsBytes <= fileSize); - szResult = fread(m_pMipmapImages->paucEncodingBits.get(), 1, m_pMipmapImages->uiEncodingBitsBytes, pfile); - assert(szResult == m_pMipmapImages->uiEncodingBitsBytes); - - uint32_t uiInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlInternalFormat; - uint32_t uiBaseInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlBaseInternalFormat; - - if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC1_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC1_RGB8) - { - m_imageformat = Image::Format::ETC1; - } - else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8) - { - m_imageformat = Image::Format::RGB8; - } - else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8A1 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8A1) - { - m_imageformat = Image::Format::RGB8A1; - } - else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGBA8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGBA8) - { - m_imageformat = Image::Format::RGBA8; - } - else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11) - { - m_imageformat = Image::Format::R11; - } - else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11) - { - m_imageformat = Image::Format::SIGNED_R11; - } - else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11) - { - m_imageformat = Image::Format::RG11; - } - else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11) - { - m_imageformat = Image::Format::SIGNED_RG11; - } - else - { - m_imageformat = Image::Format::UNKNOWN; - } - - m_uiSourceWidth = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelWidth; - m_uiSourceHeight = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelHeight; - m_pMipmapImages->uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth); - m_pMipmapImages->uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight); - - unsigned int uiBlocks = m_pMipmapImages->uiExtendedWidth * m_pMipmapImages->uiExtendedHeight / 16; - Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat); - unsigned int expectedbytes = uiBlocks * Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat); - assert(expectedbytes == m_pMipmapImages->uiEncodingBitsBytes); - - fclose(pfile); -} - -File::~File() -{ - if (m_pMipmapImages != nullptr) - { - delete [] m_pMipmapImages; - } - - if(m_pstrFilename != nullptr) - { - delete[] m_pstrFilename; - m_pstrFilename = nullptr; - } - if (m_pheader != nullptr) - { - delete m_pheader; - m_pheader = nullptr; - } -} - -void File::UseSingleBlock(int a_iPixelX, int a_iPixelY) -{ - if (a_iPixelX <= -1 || a_iPixelY <= -1) - return; - if (a_iPixelX >(int) m_uiSourceWidth) - { - //if we are using a ktx thats the size of a single block or less - //then make sure we use the 4x4 image as the single block - if (m_uiSourceWidth <= 4) - { - a_iPixelX = 0; - } - else - { - printf("blockAtHV: H coordinate out of range, capped to image width\n"); - a_iPixelX = m_uiSourceWidth - 1; - } - } - if (a_iPixelY >(int) m_uiSourceHeight) - { - //if we are using a ktx thats the size of a single block or less - //then make sure we use the 4x4 image as the single block - if (m_uiSourceHeight <= 4) - { - a_iPixelY= 0; - } - else - { - printf("blockAtHV: V coordinate out of range, capped to image height\n"); - a_iPixelY = m_uiSourceHeight - 1; - } - } - - unsigned int origWidth = m_uiSourceWidth; - unsigned int origHeight = m_uiSourceHeight; - - m_uiSourceWidth = 4; - m_uiSourceHeight = 4; - - Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat); - unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat); - - int numMipmaps = 1; - RawImage* pMipmapImages = new RawImage[numMipmaps]; - pMipmapImages[0].uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth); - pMipmapImages[0].uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight); - pMipmapImages[0].uiEncodingBitsBytes = 0; - pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[uiEncodingBitsBytesPerBlock], [](unsigned char *p) { delete[] p; }); - - //block position in pixels - // remove the bottom 2 bits to get the block coordinates - unsigned int iBlockPosX = (a_iPixelX & 0xFFFFFFFC); - unsigned int iBlockPosY = (a_iPixelY & 0xFFFFFFFC); - - int numXBlocks = (origWidth / 4); - int numYBlocks = (origHeight / 4); - - - // block location - //int iBlockX = (a_iPixelX % 4) == 0 ? a_iPixelX / 4.0f : (a_iPixelX / 4) + 1; - //int iBlockY = (a_iPixelY % 4) == 0 ? a_iPixelY / 4.0f : (a_iPixelY / 4) + 1; - //m_paucEncodingBits += ((iBlockY * numXBlocks) + iBlockX) * uiEncodingBitsBytesPerBlock; - - - unsigned int num = numXBlocks*numYBlocks; - unsigned int uiH = 0, uiV = 0; - unsigned char* pEncodingBits = m_pMipmapImages[0].paucEncodingBits.get(); - for (unsigned int uiBlock = 0; uiBlock < num; uiBlock++) - { - if (uiH == iBlockPosX && uiV == iBlockPosY) - { - memcpy(pMipmapImages[0].paucEncodingBits.get(),pEncodingBits, uiEncodingBitsBytesPerBlock); - break; - } - pEncodingBits += uiEncodingBitsBytesPerBlock; - uiH += 4; - - if (uiH >= origWidth) - { - uiH = 0; - uiV += 4; - } - } - - delete [] m_pMipmapImages; - m_pMipmapImages = pMipmapImages; -} -// ---------------------------------------------------------------------------------------------------- -// -void File::Write() -{ - - FILE *pfile = fopen(m_pstrFilename, "wb"); - if (pfile == nullptr) - { - printf("Error: couldn't open Etc file (%s)\n", m_pstrFilename); - exit(1); - } - - m_pheader->Write(pfile); - - for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++) - { - if(m_fileformat == Format::KTX) - { - // Write u32 image size - uint32_t u32ImageSize = m_pMipmapImages[mip].uiEncodingBitsBytes; - uint32_t szBytesWritten = fwrite(&u32ImageSize, 1, sizeof(u32ImageSize), pfile); - assert(szBytesWritten == sizeof(u32ImageSize)); - } - - unsigned int iResult = (int)fwrite(m_pMipmapImages[mip].paucEncodingBits.get(), 1, m_pMipmapImages[mip].uiEncodingBitsBytes, pfile); - if (iResult != m_pMipmapImages[mip].uiEncodingBitsBytes) - { - printf("Error: couldn't write Etc file (%s)\n", m_pstrFilename); - exit(1); - } - } - - fclose(pfile); - -} - -// ---------------------------------------------------------------------------------------------------- -// - diff --git a/thirdparty/etc2comp/EtcFile.h b/thirdparty/etc2comp/EtcFile.h deleted file mode 100644 index 69bf3b2d3a..0000000000 --- a/thirdparty/etc2comp/EtcFile.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcColorFloatRGBA.h" -#include "EtcImage.h" -#include "Etc.h" - -namespace Etc -{ - class FileHeader; - class SourceImage; - - class File - { - public: - - enum class Format - { - INFER_FROM_FILE_EXTENSION, - PKM, - KTX, - }; - - File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, - unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes, - unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, - unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight); - - File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat, - unsigned int a_uiNumMipmaps, RawImage *pMipmapImages, - unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight ); - - File(const char *a_pstrFilename, Format a_fileformat); - ~File(); - const char *GetFilename(void) { return m_pstrFilename; } - - void Read(const char *a_pstrFilename); - void Write(void); - - inline unsigned int GetSourceWidth(void) - { - return m_uiSourceWidth; - } - - inline unsigned int GetSourceHeight(void) - { - return m_uiSourceHeight; - } - - inline unsigned int GetExtendedWidth(unsigned int mipmapIndex = 0) - { - if (mipmapIndex < m_uiNumMipmaps) - { - return m_pMipmapImages[mipmapIndex].uiExtendedWidth; - } - else - { - return 0; - } - } - - inline unsigned int GetExtendedHeight(unsigned int mipmapIndex = 0) - { - if (mipmapIndex < m_uiNumMipmaps) - { - return m_pMipmapImages[mipmapIndex].uiExtendedHeight; - } - else - { - return 0; - } - } - - inline Image::Format GetImageFormat() - { - return m_imageformat; - } - - inline unsigned int GetEncodingBitsBytes(unsigned int mipmapIndex = 0) - { - if (mipmapIndex < m_uiNumMipmaps) - { - return m_pMipmapImages[mipmapIndex].uiEncodingBitsBytes; - } - else - { - return 0; - } - } - - inline unsigned char* GetEncodingBits(unsigned int mipmapIndex = 0) - { - if( mipmapIndex < m_uiNumMipmaps) - { - return m_pMipmapImages[mipmapIndex].paucEncodingBits.get(); - } - else - { - return nullptr; - } - } - - inline unsigned int GetNumMipmaps() - { - return m_uiNumMipmaps; - } - - void UseSingleBlock(int a_iPixelX = -1, int a_iPixelY = -1); - private: - - char *m_pstrFilename; // includes directory path and file extension - Format m_fileformat; - Image::Format m_imageformat; - FileHeader *m_pheader; - unsigned int m_uiNumMipmaps; - RawImage* m_pMipmapImages; - unsigned int m_uiSourceWidth; - unsigned int m_uiSourceHeight; - }; - -} diff --git a/thirdparty/etc2comp/EtcFileHeader.cpp b/thirdparty/etc2comp/EtcFileHeader.cpp deleted file mode 100644 index f02fcab011..0000000000 --- a/thirdparty/etc2comp/EtcFileHeader.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "EtcFileHeader.h" - -#include "EtcBlock4x4EncodingBits.h" - -#include <assert.h> - -namespace Etc -{ - - // ---------------------------------------------------------------------------------------------------- - // - FileHeader_Pkm::FileHeader_Pkm(File *a_pfile) - { - m_pfile = a_pfile; - - static const char s_acMagicNumberData[4] = { 'P', 'K', 'M', ' ' }; - static const char s_acVersionData[2] = { '1', '0' }; - - for (unsigned int ui = 0; ui < sizeof(s_acMagicNumberData); ui++) - { - m_data.m_acMagicNumber[ui] = s_acMagicNumberData[ui]; - } - - for (unsigned int ui = 0; ui < sizeof(s_acVersionData); ui++) - { - m_data.m_acVersion[ui] = s_acVersionData[ui]; - } - - m_data.m_ucDataType_msb = 0; // ETC1_RGB_NO_MIPMAPS - m_data.m_ucDataType_lsb = 0; - - m_data.m_ucOriginalWidth_msb = (unsigned char)(m_pfile->GetSourceWidth() >> 8); - m_data.m_ucOriginalWidth_lsb = m_pfile->GetSourceWidth() & 0xFF; - m_data.m_ucOriginalHeight_msb = (unsigned char)(m_pfile->GetSourceHeight() >> 8); - m_data.m_ucOriginalHeight_lsb = m_pfile->GetSourceHeight() & 0xFF; - - m_data.m_ucExtendedWidth_msb = (unsigned char)(m_pfile->GetExtendedWidth() >> 8); - m_data.m_ucExtendedWidth_lsb = m_pfile->GetExtendedWidth() & 0xFF; - m_data.m_ucExtendedHeight_msb = (unsigned char)(m_pfile->GetExtendedHeight() >> 8); - m_data.m_ucExtendedHeight_lsb = m_pfile->GetExtendedHeight() & 0xFF; - - } - - // ---------------------------------------------------------------------------------------------------- - // - void FileHeader_Pkm::Write(FILE *a_pfile) - { - - fwrite(&m_data, sizeof(Data), 1, a_pfile); - - } - - // ---------------------------------------------------------------------------------------------------- - // - FileHeader_Ktx::FileHeader_Ktx(File *a_pfile) - { - m_pfile = a_pfile; - - static const uint8_t s_au8Itentfier[12] = - { - 0xAB, 0x4B, 0x54, 0x58, // first four bytes of Byte[12] identifier - 0x20, 0x31, 0x31, 0xBB, // next four bytes of Byte[12] identifier - 0x0D, 0x0A, 0x1A, 0x0A // final four bytes of Byte[12] identifier - }; - - for (unsigned int ui = 0; ui < sizeof(s_au8Itentfier); ui++) - { - m_data.m_au8Identifier[ui] = s_au8Itentfier[ui]; - } - - m_data.m_u32Endianness = 0x04030201; - m_data.m_u32GlType = 0; - m_data.m_u32GlTypeSize = 1; - m_data.m_u32GlFormat = 0; - - switch (m_pfile->GetImageFormat()) - { - case Image::Format::RGB8: - case Image::Format::SRGB8: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8; - break; - - case Image::Format::RGBA8: - case Image::Format::SRGBA8: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGBA8; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGBA8; - break; - - case Image::Format::RGB8A1: - case Image::Format::SRGB8A1: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8A1; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8A1; - break; - - case Image::Format::R11: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_R11; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11; - break; - - case Image::Format::SIGNED_R11: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_R11; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11; - break; - - case Image::Format::RG11: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RG11; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11; - break; - - case Image::Format::SIGNED_RG11: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_RG11; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11; - break; - - default: - m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC1_RGB8; - m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC1_RGB8; - break; - } - - m_data.m_u32PixelWidth = 0; - m_data.m_u32PixelHeight = 0; - m_data.m_u32PixelDepth = 0; - m_data.m_u32NumberOfArrayElements = 0; - m_data.m_u32NumberOfFaces = 0; - m_data.m_u32BytesOfKeyValueData = 0; - - m_pkeyvaluepair = nullptr; - - m_u32Images = 0; - m_u32KeyValuePairs = 0; - - m_data.m_u32PixelWidth = m_pfile->GetSourceWidth(); - m_data.m_u32PixelHeight = m_pfile->GetSourceHeight(); - m_data.m_u32PixelDepth = 0; - m_data.m_u32NumberOfArrayElements = 0; - m_data.m_u32NumberOfFaces = 1; - m_data.m_u32NumberOfMipmapLevels = m_pfile->GetNumMipmaps(); - - } - - // ---------------------------------------------------------------------------------------------------- - // - void FileHeader_Ktx::Write(FILE *a_pfile) - { - size_t szBytesWritten; - - // Write header - szBytesWritten = fwrite(&m_data, 1, sizeof(Data), a_pfile); - assert(szBytesWritten == sizeof(Data)); - - // Write KeyAndValuePairs - if (m_u32KeyValuePairs) - { - fwrite(m_pkeyvaluepair, m_pkeyvaluepair->u32KeyAndValueByteSize, 1, a_pfile); - } - } - - // ---------------------------------------------------------------------------------------------------- - // - FileHeader_Ktx::Data *FileHeader_Ktx::GetData() - { - return &m_data; - } - - // ---------------------------------------------------------------------------------------------------- - // -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcFileHeader.h b/thirdparty/etc2comp/EtcFileHeader.h deleted file mode 100644 index 55a9cb5d9d..0000000000 --- a/thirdparty/etc2comp/EtcFileHeader.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcFile.h" -#include <stdio.h> -#include <inttypes.h> - -namespace Etc -{ - - class Image; - - class FileHeader - { - public: - - virtual void Write(FILE *a_pfile) = 0; - File GetFile(); - virtual ~FileHeader(void) {} - protected: - - File *m_pfile; - }; - - // ---------------------------------------------------------------------------------------------------- - // - class FileHeader_Pkm : public FileHeader - { - public: - - FileHeader_Pkm(File *a_pfile); - - virtual void Write(FILE *a_pfile); - virtual ~FileHeader_Pkm(void) {} - private: - - typedef struct - { - char m_acMagicNumber[4]; - char m_acVersion[2]; - unsigned char m_ucDataType_msb; // e.g. ETC1_RGB_NO_MIPMAPS - unsigned char m_ucDataType_lsb; - unsigned char m_ucExtendedWidth_msb; // padded to 4x4 blocks - unsigned char m_ucExtendedWidth_lsb; - unsigned char m_ucExtendedHeight_msb; // padded to 4x4 blocks - unsigned char m_ucExtendedHeight_lsb; - unsigned char m_ucOriginalWidth_msb; - unsigned char m_ucOriginalWidth_lsb; - unsigned char m_ucOriginalHeight_msb; - unsigned char m_ucOriginalHeight_lsb; - } Data; - - Data m_data; - }; - - // ---------------------------------------------------------------------------------------------------- - // - class FileHeader_Ktx : public FileHeader - { - public: - - typedef struct - { - uint32_t u32KeyAndValueByteSize; - } KeyValuePair; - - typedef struct - { - uint8_t m_au8Identifier[12]; - uint32_t m_u32Endianness; - uint32_t m_u32GlType; - uint32_t m_u32GlTypeSize; - uint32_t m_u32GlFormat; - uint32_t m_u32GlInternalFormat; - uint32_t m_u32GlBaseInternalFormat; - uint32_t m_u32PixelWidth; - uint32_t m_u32PixelHeight; - uint32_t m_u32PixelDepth; - uint32_t m_u32NumberOfArrayElements; - uint32_t m_u32NumberOfFaces; - uint32_t m_u32NumberOfMipmapLevels; - uint32_t m_u32BytesOfKeyValueData; - } Data; - - enum class InternalFormat - { - ETC1_RGB8 = 0x8D64, - ETC1_ALPHA8 = ETC1_RGB8, - // - ETC2_R11 = 0x9270, - ETC2_SIGNED_R11 = 0x9271, - ETC2_RG11 = 0x9272, - ETC2_SIGNED_RG11 = 0x9273, - ETC2_RGB8 = 0x9274, - ETC2_SRGB8 = 0x9275, - ETC2_RGB8A1 = 0x9276, - ETC2_SRGB8_PUNCHTHROUGH_ALPHA1 = 0x9277, - ETC2_RGBA8 = 0x9278 - }; - - enum class BaseInternalFormat - { - ETC2_R11 = 0x1903, - ETC2_RG11 = 0x8227, - ETC1_RGB8 = 0x1907, - ETC1_ALPHA8 = ETC1_RGB8, - // - ETC2_RGB8 = 0x1907, - ETC2_RGB8A1 = 0x1908, - ETC2_RGBA8 = 0x1908, - }; - - FileHeader_Ktx(File *a_pfile); - - virtual void Write(FILE *a_pfile); - virtual ~FileHeader_Ktx(void) {} - - void AddKeyAndValue(KeyValuePair *a_pkeyvaluepair); - - Data* GetData(); - - private: - - Data m_data; - KeyValuePair *m_pkeyvaluepair; - - uint32_t m_u32Images; - uint32_t m_u32KeyValuePairs; - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcFilter.cpp b/thirdparty/etc2comp/EtcFilter.cpp deleted file mode 100644 index 1ec8acdf3f..0000000000 --- a/thirdparty/etc2comp/EtcFilter.cpp +++ /dev/null @@ -1,404 +0,0 @@ -#include <stdlib.h> -#include <math.h> -#include "EtcFilter.h" - - -namespace Etc -{ - -static const double PiConst = 3.14159265358979323846; - -inline double sinc(double x) -{ - if ( x == 0.0 ) - { - return 1.0; - } - - return sin(PiConst * x) / (PiConst * x); -} - -//inline float sincf( float x ) -//{ -// x *= F_PI; -// if (x < 0.01f && x > -0.01f) -// { -// return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f); -// } -// -// return sinf(x)/x; -//} -// -//double bessel0(double x) -//{ -// const double EPSILON_RATIO = 1E-16; -// double xh, sum, pow, ds; -// int k; -// -// xh = 0.5 * x; -// sum = 1.0; -// pow = 1.0; -// k = 0; -// ds = 1.0; -// while (ds > sum * EPSILON_RATIO) -// { -// ++k; -// pow = pow * (xh / k); -// ds = pow * pow; -// sum = sum + ds; -// } -// -// return sum; -//} - -//**-------------------------------------------------------------------------- -//** Name: kaiser(double alpha, double half_width, double x) -//** Returns: -//** Description: Alpha controls shape of filter. We are using 4. -//**-------------------------------------------------------------------------- -//inline double kaiser(double alpha, double half_width, double x) -//{ -// double ratio = (x / half_width); -// return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha); -//} -// -//float Filter_Lanczos4Sinc(float x) -//{ -// if (x <= -4.0f || x >= 4.0f) // half-width of 4 -// { -// return 0.0; -// } -// -// return sinc(0.875f * x) * sinc(0.25f * x); -//} -// -//double Filter_Kaiser4( double t ) -//{ -// return kaiser( 4.0, 3.0, t); -//} -// -//double Filter_KaiserOptimal( double t ) -//{ -// return kaiser( 8.93, 3.0f, t); -//} - -double FilterLanczos3( double t ) -{ - if ( t <= -3.0 || t >= 3.0 ) - { - return 0.0; - } - - return sinc( t ) * sinc( t / 3.0 ); -} - -double FilterBox( double t ) -{ - return ( t > -0.5 && t < 0.5) ? 1.0 : 0.0; -} - -double FilterLinear( double t ) -{ - if (t < 0.0) t = -t; - - return (t < 1.0) ? (1.0 - t) : 0.0; -} - - -//**-------------------------------------------------------------------------- -//** Name: CalcContributions( int srcSize, -//** int destSize, -//** double filterSize, -//** bool wrap, -//** double (*FilterProc)(double), -//** FilterWeights contrib[] ) -//** Returns: void -//** Description: -//**-------------------------------------------------------------------------- -void CalcContributions( int srcSize, int destSize, double filterSize, bool wrap, double (*FilterProc)(double), FilterWeights contrib[] ) -{ - double scale; - double filterScale; - double center; - double totalWeight; - double weight; - int iRight; - int iLeft; - int iDest; - - scale = (double)destSize / srcSize; - if ( scale < 1.0 ) - { - filterSize = filterSize / scale; - filterScale = scale; - } - else - { - filterScale = 1.0; - } - - if ( filterSize > (double)MaxFilterSize ) - { - filterSize = (double)MaxFilterSize; - } - - for ( iDest = 0; iDest < destSize; ++iDest ) - { - center = (double)iDest / scale; - - iLeft = (int)ceil(center - filterSize); - iRight = (int)floor(center + filterSize); - - if ( !wrap ) - { - if ( iLeft < 0 ) - { - iLeft = 0; - } - - if ( iRight >= srcSize ) - { - iRight = srcSize - 1; - } - } - - int numWeights = iRight - iLeft + 1; - - contrib[iDest].first = iLeft; - contrib[iDest].numWeights = numWeights; - - totalWeight = 0; - double t = ((double)iLeft - center) * filterScale; - for (int i = 0; i < numWeights; i++) - { - weight = (*FilterProc)(t) * filterScale; - totalWeight += weight; - contrib[iDest].weight[i] = weight; - t += filterScale; - } - - //**-------------------------------------------------------- - //** Normalize weights by dividing by the sum of the weights - //**-------------------------------------------------------- - if ( totalWeight > 0.0 ) - { - for ( int i = 0; i < numWeights; i++) - { - contrib[iDest].weight[i] /= totalWeight; - } - } - } -} - -//**------------------------------------------------------------------------- -//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage, -//** int srcWidth, int srcHeight, -//** RGBCOLOR *pDestImage, -//** int destWidth, int destHeight, -//** double (*FilterProc)(double) ) -//** Returns: 0 on failure and 1 on success -//** Description: Filters a 2d image with a two pass filter by averaging the -//** weighted contributions of the pixels within the filter region. The -//** contributions are determined by a weighting function parameter. -//**------------------------------------------------------------------------- -int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, - RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) ) -{ - FilterWeights *contrib; - RGBCOLOR *pPixel; - RGBCOLOR *pSrcPixel; - RGBCOLOR *pTempImage; - int iRow; - int iCol; - int iSrcCol; - int iSrcRow; - int iWeight; - double dRed; - double dGreen; - double dBlue; - double dAlpha; - double filterSize = 3.0; - - int maxDim = (srcWidth>srcHeight)?srcWidth:srcHeight; - contrib = (FilterWeights*)malloc(maxDim * sizeof(FilterWeights)); - - //**------------------------------------------------------------------------ - //** Need to create a temporary image to stuff the horizontally scaled image - //**------------------------------------------------------------------------ - pTempImage = (RGBCOLOR *)malloc( destWidth * srcHeight * sizeof(RGBCOLOR) ); - if ( pTempImage == NULL ) - { - // -- GODOT start -- - free( contrib ); - // -- GODOT end -- - return 0; - } - - //**------------------------------------------------------- - //** Horizontally filter the image into the temporary image - //**------------------------------------------------------- - bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X); - CalcContributions( srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib ); - for ( iRow = 0; iRow < srcHeight; iRow++ ) - { - for ( iCol = 0; iCol < destWidth; iCol++ ) - { - dRed = 0; - dGreen = 0; - dBlue = 0; - dAlpha = 0; - - for ( iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++ ) - { - iSrcCol = iWeight + contrib[iCol].first; - if (bWrapHorizontal) - { - iSrcCol = (iSrcCol < 0) ? (srcWidth + iSrcCol) : (iSrcCol >= srcWidth) ? (iSrcCol - srcWidth) : iSrcCol; - } - pSrcPixel = pSrcImage + (iRow * srcWidth) + iSrcCol; - dRed += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[0]; - dGreen += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[1]; - dBlue += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[2]; - dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[3]; - } - - pPixel = pTempImage + (iRow * destWidth) + iCol; - pPixel->rgba[0] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dRed))); - pPixel->rgba[1] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dGreen))); - pPixel->rgba[2] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dBlue))); - pPixel->rgba[3] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dAlpha))); - } - } - - //**------------------------------------------------------- - //** Vertically filter the image into the destination image - //**------------------------------------------------------- - bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y); - CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib); - for ( iCol = 0; iCol < destWidth; iCol++ ) - { - for ( iRow = 0; iRow < destHeight; iRow++ ) - { - dRed = 0; - dGreen = 0; - dBlue = 0; - dAlpha = 0; - - for ( iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++ ) - { - iSrcRow = iWeight + contrib[iRow].first; - if (bWrapVertical) - { - iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow; - } - pSrcPixel = pTempImage + (iSrcRow * destWidth) + iCol; - dRed += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[0]; - dGreen += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[1]; - dBlue += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[2]; - dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[3]; - } - - pPixel = pDestImage + (iRow * destWidth) + iCol; - pPixel->rgba[0] = (unsigned char)(std::max( 0.0, std::min( 255.0, dRed))); - pPixel->rgba[1] = (unsigned char)(std::max( 0.0, std::min( 255.0, dGreen))); - pPixel->rgba[2] = (unsigned char)(std::max( 0.0, std::min( 255.0, dBlue))); - pPixel->rgba[3] = (unsigned char)(std::max( 0.0, std::min( 255.0, dAlpha))); - } - } - - free( pTempImage ); - free( contrib ); - - return 1; -} - -//**------------------------------------------------------------------------- -//** Name: FilterResample(RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, -//** RGBCOLOR *pDstImage, int dstWidth, int dstHeight) -//** Returns: 1 -//** Description: This function runs a 2d box filter over the srouce image -//** to produce the destination image. -//**------------------------------------------------------------------------- -void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, - RGBCOLOR *pDstImage, int dstWidth, int dstHeight ) -{ - int iRow; - int iCol; - int iSampleRow; - int iSampleCol; - int iFirstSampleRow; - int iFirstSampleCol; - int iLastSampleRow; - int iLastSampleCol; - int red; - int green; - int blue; - int alpha; - int samples; - float xScale; - float yScale; - - RGBCOLOR *pSrcPixel; - RGBCOLOR *pDstPixel; - - xScale = (float)srcWidth / dstWidth; - yScale = (float)srcHeight / dstHeight; - - for ( iRow = 0; iRow < dstHeight; iRow++ ) - { - for ( iCol = 0; iCol < dstWidth; iCol++ ) - { - iFirstSampleRow = (int)(iRow * yScale); - iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1); - if ( iLastSampleRow >= srcHeight ) - { - iLastSampleRow = srcHeight - 1; - } - - iFirstSampleCol = (int)(iCol * xScale); - iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1); - if ( iLastSampleCol >= srcWidth ) - { - iLastSampleCol = srcWidth - 1; - } - - samples = 0; - red = 0; - green = 0; - blue = 0; - alpha = 0; - for ( iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++ ) - { - for ( iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++ ) - { - pSrcPixel = pSrcImage + iSampleRow * srcWidth + iSampleCol; - red += pSrcPixel->rgba[0]; - green += pSrcPixel->rgba[1]; - blue += pSrcPixel->rgba[2]; - alpha += pSrcPixel->rgba[3]; - - samples++; - } - } - - pDstPixel = pDstImage + iRow * dstWidth + iCol; - if ( samples > 0 ) - { - pDstPixel->rgba[0] = static_cast<uint8_t>(red / samples); - pDstPixel->rgba[1] = static_cast<uint8_t>(green / samples); - pDstPixel->rgba[2] = static_cast<uint8_t>(blue / samples); - pDstPixel->rgba[3] = static_cast<uint8_t>(alpha / samples); - } - else - { - pDstPixel->rgba[0] = static_cast<uint8_t>(red); - pDstPixel->rgba[1] = static_cast<uint8_t>(green); - pDstPixel->rgba[2] = static_cast<uint8_t>(blue); - pDstPixel->rgba[3] = static_cast<uint8_t>(alpha); - } - } - } -} - - -}
\ No newline at end of file diff --git a/thirdparty/etc2comp/EtcFilter.h b/thirdparty/etc2comp/EtcFilter.h deleted file mode 100644 index fcf125c6df..0000000000 --- a/thirdparty/etc2comp/EtcFilter.h +++ /dev/null @@ -1,244 +0,0 @@ -#pragma once -#include <stdint.h> -#include <algorithm> - -namespace Etc -{ - -enum FilterEnums -{ - MaxFilterSize = 32 -}; - -enum WrapFlags -{ - FILTER_WRAP_NONE = 0, - FILTER_WRAP_X = 0x1, - FILTER_WRAP_Y = 0x2 -}; - -typedef struct tagFilterWeights -{ - int first; - int numWeights; - double weight[MaxFilterSize * 2 + 1]; -} FilterWeights; - -typedef struct tagRGBCOLOR -{ - union - { - uint32_t ulColor; - uint8_t rgba[4]; - }; -} RGBCOLOR; - - -double FilterBox( double t ); -double FilterLinear( double t ); -double FilterLanczos3( double t ); - -int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, - RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) ); -void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight, - RGBCOLOR *pDstImage, int dstWidth, int dstHeight ); - - -void CalcContributions(int srcSize, int destSize, double filterSize, bool wrap, double(*FilterProc)(double), FilterWeights contrib[]); - -template <typename T> -void FilterResample(T *pSrcImage, int srcWidth, int srcHeight, T *pDstImage, int dstWidth, int dstHeight) -{ - float xScale; - float yScale; - - T *pSrcPixel; - T *pDstPixel; - - xScale = (float)srcWidth / dstWidth; - yScale = (float)srcHeight / dstHeight; - - for (int iRow = 0; iRow < dstHeight; iRow++) - { - for (int iCol = 0; iCol < dstWidth; iCol++) - { - int samples; - int iFirstSampleRow; - int iFirstSampleCol; - int iLastSampleRow; - int iLastSampleCol; - float red; - float green; - float blue; - float alpha; - - iFirstSampleRow = (int)(iRow * yScale); - iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1); - if (iLastSampleRow >= srcHeight) - { - iLastSampleRow = srcHeight - 1; - } - - iFirstSampleCol = (int)(iCol * xScale); - iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1); - if (iLastSampleCol >= srcWidth) - { - iLastSampleCol = srcWidth - 1; - } - - samples = 0; - red = 0.f; - green = 0.f; - blue = 0.f; - alpha = 0.f; - for (int iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++) - { - for (int iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++) - { - pSrcPixel = pSrcImage + (iSampleRow * srcWidth + iSampleCol) * 4; - red += static_cast<float>(pSrcPixel[0]); - green += static_cast<float>(pSrcPixel[1]); - blue += static_cast<float>(pSrcPixel[2]); - alpha += static_cast<float>(pSrcPixel[3]); - - samples++; - } - } - - pDstPixel = pDstImage + (iRow * dstWidth + iCol) * 4; - if (samples > 0) - { - pDstPixel[0] = static_cast<T>(red / samples); - pDstPixel[1] = static_cast<T>(green / samples); - pDstPixel[2] = static_cast<T>(blue / samples); - pDstPixel[3] = static_cast<T>(alpha / samples); - } - else - { - pDstPixel[0] = static_cast<T>(red); - pDstPixel[1] = static_cast<T>(green); - pDstPixel[2] = static_cast<T>(blue); - pDstPixel[3] = static_cast<T>(alpha); - } - } - } - -} - -//**------------------------------------------------------------------------- -//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage, -//** int srcWidth, int srcHeight, -//** RGBCOLOR *pDestImage, -//** int destWidth, int destHeight, -//** double (*FilterProc)(double) ) -//** Returns: 0 on failure and 1 on success -//** Description: Filters a 2d image with a two pass filter by averaging the -//** weighted contributions of the pixels within the filter region. The -//** contributions are determined by a weighting function parameter. -//**------------------------------------------------------------------------- -template <typename T> -int FilterTwoPass(T *pSrcImage, int srcWidth, int srcHeight, - T *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double(*FilterProc)(double)) -{ - const int numComponents = 4; - FilterWeights *contrib; - T *pPixel; - T *pTempImage; - double dRed; - double dGreen; - double dBlue; - double dAlpha; - double filterSize = 3.0; - - int maxDim = (srcWidth>srcHeight) ? srcWidth : srcHeight; - contrib = new FilterWeights[maxDim]; - - //**------------------------------------------------------------------------ - //** Need to create a temporary image to stuff the horizontally scaled image - //**------------------------------------------------------------------------ - pTempImage = new T[destWidth * srcHeight * numComponents]; - if (pTempImage == NULL) - { - return 0; - } - - //**------------------------------------------------------- - //** Horizontally filter the image into the temporary image - //**------------------------------------------------------- - bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X); - CalcContributions(srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib); - for (int iRow = 0; iRow < srcHeight; iRow++) - { - for (int iCol = 0; iCol < destWidth; iCol++) - { - dRed = 0; - dGreen = 0; - dBlue = 0; - dAlpha = 0; - - for (int iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++) - { - int iSrcCol = iWeight + contrib[iCol].first; - if(bWrapHorizontal) - { - iSrcCol = (iSrcCol < 0)?(srcWidth+iSrcCol):(iSrcCol >= srcWidth)?(iSrcCol-srcWidth):iSrcCol; - } - T* pSrcPixel = pSrcImage + ((iRow * srcWidth) + iSrcCol)*numComponents; - dRed += contrib[iCol].weight[iWeight] * pSrcPixel[0]; - dGreen += contrib[iCol].weight[iWeight] * pSrcPixel[1]; - dBlue += contrib[iCol].weight[iWeight] * pSrcPixel[2]; - dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel[3]; - } - - pPixel = pTempImage + ((iRow * destWidth) + iCol)*numComponents; - pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed))); - pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen))); - pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue))); - pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha))); - } - } - - //**------------------------------------------------------- - //** Vertically filter the image into the destination image - //**------------------------------------------------------- - bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y); - CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib); - for (int iCol = 0; iCol < destWidth; iCol++) - { - for (int iRow = 0; iRow < destHeight; iRow++) - { - dRed = 0; - dGreen = 0; - dBlue = 0; - dAlpha = 0; - - for (int iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++) - { - int iSrcRow = iWeight + contrib[iRow].first; - if (bWrapVertical) - { - iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow; - } - T* pSrcPixel = pTempImage + ((iSrcRow * destWidth) + iCol)*numComponents; - dRed += contrib[iRow].weight[iWeight] * pSrcPixel[0]; - dGreen += contrib[iRow].weight[iWeight] * pSrcPixel[1]; - dBlue += contrib[iRow].weight[iWeight] * pSrcPixel[2]; - dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel[3]; - } - - pPixel = pDestImage + ((iRow * destWidth) + iCol)*numComponents; - pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed))); - pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen))); - pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue))); - pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha))); - } - } - - delete[] pTempImage; - delete[] contrib; - - return 1; -} - - -}
\ No newline at end of file diff --git a/thirdparty/etc2comp/EtcImage.cpp b/thirdparty/etc2comp/EtcImage.cpp deleted file mode 100644 index 7a1058844d..0000000000 --- a/thirdparty/etc2comp/EtcImage.cpp +++ /dev/null @@ -1,685 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcImage.cpp - -Image is an array of 4x4 blocks that represent the encoding of the source image - -*/ - -#include "EtcConfig.h" - -#include <stdlib.h> - -#include "EtcImage.h" - -#include "Etc.h" -#include "EtcBlock4x4.h" -#include "EtcBlock4x4EncodingBits.h" -#include "EtcSortedBlockList.h" - -#if ETC_WINDOWS -#include <windows.h> -#endif -#include <ctime> -#include <chrono> -#include <future> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -// fix conflict with Block4x4::AlphaMix -#ifdef OPAQUE -#undef OPAQUE -#endif -#ifdef TRANSPARENT -#undef TRANSPARENT -#endif - -namespace Etc -{ - - // ---------------------------------------------------------------------------------------------------- - // - Image::Image(void) - { - m_encodingStatus = EncodingStatus::SUCCESS; - m_warningsToCapture = EncodingStatus::SUCCESS; - m_pafrgbaSource = nullptr; - - m_pablock = nullptr; - - m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; - m_uiEncodingBitsBytes = 0; - m_paucEncodingBits = nullptr; - - m_format = Format::UNKNOWN; - m_iNumOpaquePixels = 0; - m_iNumTranslucentPixels = 0; - m_iNumTransparentPixels = 0; - } - - // ---------------------------------------------------------------------------------------------------- - // constructor using source image - // used to set state before Encode() is called - // - Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth, - unsigned int a_uiSourceHeight, - ErrorMetric a_errormetric) - { - m_encodingStatus = EncodingStatus::SUCCESS; - m_warningsToCapture = EncodingStatus::SUCCESS; - m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA; - m_uiSourceWidth = a_uiSourceWidth; - m_uiSourceHeight = a_uiSourceHeight; - - m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth); - m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight); - - m_uiBlockColumns = m_uiExtendedWidth >> 2; - m_uiBlockRows = m_uiExtendedHeight >> 2; - - m_pablock = new Block4x4[GetNumberOfBlocks()]; - assert(m_pablock); - - m_format = Format::UNKNOWN; - - m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; - m_uiEncodingBitsBytes = 0; - m_paucEncodingBits = nullptr; - - m_errormetric = a_errormetric; - m_fEffort = 0.0f; - - m_iEncodeTime_ms = -1; - - m_iNumOpaquePixels = 0; - m_iNumTranslucentPixels = 0; - m_iNumTransparentPixels = 0; - m_bVerboseOutput = false; - - } - - // ---------------------------------------------------------------------------------------------------- - // constructor using encoding bits - // recreates encoding state using a previously encoded image - // - Image::Image(Format a_format, - unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, - unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes, - Image *a_pimageSource, ErrorMetric a_errormetric) - { - m_encodingStatus = EncodingStatus::SUCCESS; - m_pafrgbaSource = nullptr; - m_uiSourceWidth = a_uiSourceWidth; - m_uiSourceHeight = a_uiSourceHeight; - - m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth); - m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight); - - m_uiBlockColumns = m_uiExtendedWidth >> 2; - m_uiBlockRows = m_uiExtendedHeight >> 2; - - unsigned int uiBlocks = GetNumberOfBlocks(); - - m_pablock = new Block4x4[uiBlocks]; - assert(m_pablock); - - m_format = a_format; - - m_iNumOpaquePixels = 0; - m_iNumTranslucentPixels = 0; - m_iNumTransparentPixels = 0; - - m_encodingbitsformat = DetermineEncodingBitsFormat(m_format); - if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN) - { - AddToEncodingStatus(ERROR_UNKNOWN_FORMAT); - return; - } - m_uiEncodingBitsBytes = a_uiEncodingBitsBytes; - m_paucEncodingBits = a_paucEncidingBits; - - m_errormetric = a_errormetric; - m_fEffort = 0.0f; - m_bVerboseOutput = false; - m_iEncodeTime_ms = -1; - - unsigned char *paucEncodingBits = m_paucEncodingBits; - unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); - - unsigned int uiH = 0; - unsigned int uiV = 0; - for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++) - { - m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits, - a_pimageSource, a_errormetric); - paucEncodingBits += uiEncodingBitsBytesPerBlock; - uiH += 4; - if (uiH >= m_uiSourceWidth) - { - uiH = 0; - uiV += 4; - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // - Image::~Image(void) - { - if (m_pablock != nullptr) - { - delete[] m_pablock; - m_pablock = nullptr; - } - - /*if (m_paucEncodingBits != nullptr) - { - delete[] m_paucEncodingBits; - m_paucEncodingBits = nullptr; - }*/ - } - - // ---------------------------------------------------------------------------------------------------- - // encode an image - // create a set of encoding bits that conforms to a_format - // find best fit using a_errormetric - // explore a range of possible encodings based on a_fEffort (range = [0:100]) - // speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs) - // - Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs) - { - - auto start = std::chrono::steady_clock::now(); - - m_encodingStatus = EncodingStatus::SUCCESS; - - m_format = a_format; - m_errormetric = a_errormetric; - m_fEffort = a_fEffort; - - if (m_errormetric < 0 || m_errormetric > ERROR_METRICS) - { - AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC); - return m_encodingStatus; - } - - if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL) - { - AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE); - m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL; - } - else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL) - { - AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE); - m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL; - } - if (a_uiJobs < 1) - { - a_uiJobs = 1; - AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE); - } - else if (a_uiJobs > a_uiMaxJobs) - { - a_uiJobs = a_uiMaxJobs; - AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE); - } - - m_encodingbitsformat = DetermineEncodingBitsFormat(m_format); - - if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN) - { - AddToEncodingStatus(ERROR_UNKNOWN_FORMAT); - return m_encodingStatus; - } - - assert(m_paucEncodingBits == nullptr); - m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); - m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes]; - - InitBlocksAndBlockSorter(); - - - std::future<void> *handle = new std::future<void>[a_uiMaxJobs]; - - unsigned int uiNumThreadsNeeded = 0; - unsigned int uiUnfinishedBlocks = GetNumberOfBlocks(); - - uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs; - - for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) - { - handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded); - } - - RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded); - - for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) - { - handle[i].get(); - } - - // perform effort-based encoding - if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL) - { - unsigned int uiFinishedBlocks = 0; - unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks())); - - if (m_bVerboseOutput) - { - printf("effortblocks = %d\n", uiTotalEffortBlocks); - } - unsigned int uiPass = 0; - while (1) - { - if (m_bVerboseOutput) - { - uiPass++; - printf("pass %u\n", uiPass); - } - m_psortedblocklist->Sort(); - uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks(); - uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks; - if (m_bVerboseOutput) - { - printf(" %u unfinished blocks\n", uiUnfinishedBlocks); - // m_psortedblocklist->Print(); - } - - - - //stop enocding when we did enough to satify the effort percentage - if (uiFinishedBlocks >= uiTotalEffortBlocks) - { - if (m_bVerboseOutput) - { - printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks); - } - break; - } - - unsigned int uiIteratedBlocks = 0; - unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks); - uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs; - - if (uiNumThreadsNeeded <= 1) - { - //since we already how many blocks each thread will process - //cap the thread limit to do the proper amount of work, and not more - uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1); - } - else - { - //we have a lot of work to do, so lets multi thread it - std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1]; - - for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) - { - handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded); - } - uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded); - - for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) - { - uiIteratedBlocks += handleToBlockEncoders[i].get(); - } - - delete[] handleToBlockEncoders; - } - - if (m_bVerboseOutput) - { - printf(" %u iterated blocks\n", uiIteratedBlocks); - } - } - } - - // generate Etc2-compatible bit-format 4x4 blocks - for (int i = 0; i < (int)a_uiJobs - 1; i++) - { - handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs); - } - SetEncodingBits(a_uiJobs - 1, a_uiJobs); - - for (int i = 0; i < (int)a_uiJobs - 1; i++) - { - handle[i].get(); - } - - auto end = std::chrono::steady_clock::now(); - std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); - m_iEncodeTime_ms = (int)elapsed.count(); - - delete[] handle; - delete m_psortedblocklist; - return m_encodingStatus; - } - - // ---------------------------------------------------------------------------------------------------- - // iterate the encoding thru the blocks with the worst error - // stop when a_uiMaxBlocks blocks have been iterated - // split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride - // - unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks, - unsigned int a_uiMultithreadingOffset, - unsigned int a_uiMultithreadingStride) - { - assert(a_uiMultithreadingStride > 0); - unsigned int uiIteratedBlocks = a_uiMultithreadingOffset; - - SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock(); - for (plink = plink->Advance(a_uiMultithreadingOffset); - plink != nullptr; - plink = plink->Advance(a_uiMultithreadingStride) ) - { - if (uiIteratedBlocks >= a_uiMaxBlocks) - { - break; - } - - plink->GetBlock()->PerformEncodingIteration(m_fEffort); - - uiIteratedBlocks += a_uiMultithreadingStride; - } - - return uiIteratedBlocks; - } - - // ---------------------------------------------------------------------------------------------------- - // determine which warnings to check for during Encode() based on encoding format - // - void Image::FindEncodingWarningTypesForCurFormat() - { - TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS); - TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1); - switch (m_format) - { - case Image::Format::ETC1: - case Image::Format::RGB8: - case Image::Format::SRGB8: - TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); - TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); - break; - - case Image::Format::RGB8A1: - case Image::Format::SRGB8A1: - TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); - TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS); - break; - case Image::Format::RGBA8: - case Image::Format::SRGBA8: - TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS); - break; - - case Image::Format::R11: - case Image::Format::SIGNED_R11: - TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); - TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); - TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO); - TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); - break; - - case Image::Format::RG11: - case Image::Format::SIGNED_RG11: - TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); - TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); - TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); - break; - case Image::Format::FORMATS: - case Image::Format::UNKNOWN: - default: - assert(0); - break; - } - } - - // ---------------------------------------------------------------------------------------------------- - // examine source pixels to check for warnings - // - void Image::FindAndSetEncodingWarnings() - { - int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4); - if (m_iNumOpaquePixels == numPixels) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS); - } - if (m_iNumOpaquePixels < numPixels) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS); - } - if (m_iNumTranslucentPixels > 0) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS); - } - if (m_iNumTransparentPixels == numPixels) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS); - } - if (m_numColorValues.fB > 0.0f) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); - } - if (m_numColorValues.fG > 0.0f) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO); - } - - if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1); - } - if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f) - { - AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1); - } - } - - // ---------------------------------------------------------------------------------------------------- - // return a string name for a given image format - // - const char * Image::EncodingFormatToString(Image::Format a_format) - { - switch (a_format) - { - case Image::Format::ETC1: - return "ETC1"; - case Image::Format::RGB8: - return "RGB8"; - case Image::Format::SRGB8: - return "SRGB8"; - - case Image::Format::RGB8A1: - return "RGB8A1"; - case Image::Format::SRGB8A1: - return "SRGB8A1"; - case Image::Format::RGBA8: - return "RGBA8"; - case Image::Format::SRGBA8: - return "SRGBA8"; - - case Image::Format::R11: - return "R11"; - case Image::Format::SIGNED_R11: - return "SIGNED_R11"; - - case Image::Format::RG11: - return "RG11"; - case Image::Format::SIGNED_RG11: - return "SIGNED_RG11"; - case Image::Format::FORMATS: - case Image::Format::UNKNOWN: - default: - return "UNKNOWN"; - } - } - - // ---------------------------------------------------------------------------------------------------- - // return a string name for the image's format - // - const char * Image::EncodingFormatToString(void) - { - return EncodingFormatToString(m_format); - } - - // ---------------------------------------------------------------------------------------------------- - // init image blocks prior to encoding - // init block sorter for subsequent sortings - // check for encoding warnings - // - void Image::InitBlocksAndBlockSorter(void) - { - - FindEncodingWarningTypesForCurFormat(); - - // init each block - Block4x4 *pblock = m_pablock; - unsigned char *paucEncodingBits = m_paucEncodingBits; - for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++) - { - unsigned int uiBlockV = uiBlockRow * 4; - - for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++) - { - unsigned int uiBlockH = uiBlockColumn * 4; - - pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric); - - paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); - - pblock++; - } - } - - FindAndSetEncodingWarnings(); - - // init block sorter - { - m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100); - - for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++) - { - pblock = &m_pablock[uiBlock]; - m_psortedblocklist->AddBlock(pblock); - } - } - - } - - // ---------------------------------------------------------------------------------------------------- - // run the first pass of the encoder - // the encoder generally finds a reasonable, fast encoding - // this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding - // - void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride) - { - assert(a_uiMultithreadingStride > 0); - - for (unsigned int uiBlock = a_uiMultithreadingOffset; - uiBlock < GetNumberOfBlocks(); - uiBlock += a_uiMultithreadingStride) - { - Block4x4 *pblock = &m_pablock[uiBlock]; - pblock->PerformEncodingIteration(m_fEffort); - } - } - - // ---------------------------------------------------------------------------------------------------- - // set the encoding bits (for the output file) based on the best encoding for each block - // - void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset, - unsigned int a_uiMultithreadingStride) - { - assert(a_uiMultithreadingStride > 0); - - for (unsigned int uiBlock = a_uiMultithreadingOffset; - uiBlock < GetNumberOfBlocks(); - uiBlock += a_uiMultithreadingStride) - { - Block4x4 *pblock = &m_pablock[uiBlock]; - pblock->SetEncodingBitsFromEncoding(); - } - - } - - // ---------------------------------------------------------------------------------------------------- - // return the image error - // image error is the sum of all block errors - // - float Image::GetError(void) - { - float fError = 0.0f; - - for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++) - { - Block4x4 *pblock = &m_pablock[uiBlock]; - fError += pblock->GetError(); - } - - return fError; - } - - // ---------------------------------------------------------------------------------------------------- - // determine the encoding bits format based on the encoding format - // the encoding bits format is a family of bit encodings that are shared across various encoding formats - // - Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format) - { - Block4x4EncodingBits::Format encodingbitsformat; - - // determine encoding bits format from image format - switch (a_format) - { - case Format::ETC1: - case Format::RGB8: - case Format::SRGB8: - encodingbitsformat = Block4x4EncodingBits::Format::RGB8; - break; - - case Format::RGBA8: - case Format::SRGBA8: - encodingbitsformat = Block4x4EncodingBits::Format::RGBA8; - break; - - case Format::R11: - case Format::SIGNED_R11: - encodingbitsformat = Block4x4EncodingBits::Format::R11; - break; - - case Format::RG11: - case Format::SIGNED_RG11: - encodingbitsformat = Block4x4EncodingBits::Format::RG11; - break; - - case Format::RGB8A1: - case Format::SRGB8A1: - encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1; - break; - - default: - encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; - break; - } - - return encodingbitsformat; - } - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcImage.h b/thirdparty/etc2comp/EtcImage.h deleted file mode 100644 index bd807ac32e..0000000000 --- a/thirdparty/etc2comp/EtcImage.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -//#include "Etc.h" -#include "EtcColorFloatRGBA.h" -#include "EtcBlock4x4EncodingBits.h" -#include "EtcErrorMetric.h" - - -namespace Etc -{ - class Block4x4; - class EncoderSpec; - class SortedBlockList; - - class Image - { - public: - - //the differnt warning and errors that can come up during encoding - enum EncodingStatus - { - SUCCESS = 0, - // - WARNING_THRESHOLD = 1 << 0, - // - WARNING_EFFORT_OUT_OF_RANGE = 1 << 1, - WARNING_JOBS_OUT_OF_RANGE = 1 << 2, - WARNING_SOME_NON_OPAQUE_PIXELS = 1 << 3,//just for opaque formats, etc1, rgb8, r11, rg11 - WARNING_ALL_OPAQUE_PIXELS = 1 << 4, - WARNING_ALL_TRANSPARENT_PIXELS = 1 << 5, - WARNING_SOME_TRANSLUCENT_PIXELS = 1 << 6,//just for rgb8A1 - WARNING_SOME_RGBA_NOT_0_TO_1 = 1 << 7, - WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO = 1 << 8, - WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO = 1 << 9, - // - ERROR_THRESHOLD = 1 << 16, - // - ERROR_UNKNOWN_FORMAT = 1 << 17, - ERROR_UNKNOWN_ERROR_METRIC = 1 << 18, - ERROR_ZERO_WIDTH_OR_HEIGHT = 1 << 19, - // - }; - - enum class Format - { - UNKNOWN, - // - ETC1, - // - // ETC2 formats - RGB8, - SRGB8, - RGBA8, - SRGBA8, - R11, - SIGNED_R11, - RG11, - SIGNED_RG11, - RGB8A1, - SRGB8A1, - // - FORMATS, - // - DEFAULT = SRGB8 - }; - - // constructor using source image - Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth, - unsigned int a_uiSourceHeight, - ErrorMetric a_errormetric); - - // constructor using encoding bits - Image(Format a_format, - unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, - unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes, - Image *a_pimageSource, - ErrorMetric a_errormetric); - - ~Image(void); - - EncodingStatus Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, - unsigned int a_uiJobs, unsigned int a_uiMaxJobs); - - inline void AddToEncodingStatus(EncodingStatus a_encStatus) - { - m_encodingStatus = (EncodingStatus)((unsigned int)m_encodingStatus | (unsigned int)a_encStatus); - } - - inline unsigned int GetSourceWidth(void) - { - return m_uiSourceWidth; - } - - inline unsigned int GetSourceHeight(void) - { - return m_uiSourceHeight; - } - - inline unsigned int GetExtendedWidth(void) - { - return m_uiExtendedWidth; - } - - inline unsigned int GetExtendedHeight(void) - { - return m_uiExtendedHeight; - } - - inline unsigned int GetNumberOfBlocks() - { - return m_uiBlockColumns * m_uiBlockRows; - } - - inline Block4x4 * GetBlocks() - { - return m_pablock; - } - - inline unsigned char * GetEncodingBits(void) - { - return m_paucEncodingBits; - } - - inline unsigned int GetEncodingBitsBytes(void) - { - return m_uiEncodingBitsBytes; - } - - inline int GetEncodingTimeMs(void) - { - return m_iEncodeTime_ms; - } - - float GetError(void); - - inline ColorFloatRGBA * GetSourcePixel(unsigned int a_uiH, unsigned int a_uiV) - { - if (a_uiH >= m_uiSourceWidth || a_uiV >= m_uiSourceHeight) - { - return nullptr; - } - - return &m_pafrgbaSource[a_uiV*m_uiSourceWidth + a_uiH]; - } - - inline Format GetFormat(void) - { - return m_format; - } - - static Block4x4EncodingBits::Format DetermineEncodingBitsFormat(Format a_format); - - inline static unsigned short CalcExtendedDimension(unsigned short a_ushOriginalDimension) - { - return (unsigned short)((a_ushOriginalDimension + 3) & ~3); - } - - inline ErrorMetric GetErrorMetric(void) - { - return m_errormetric; - } - - static const char * EncodingFormatToString(Image::Format a_format); - const char * EncodingFormatToString(void); - //used to get basic information about the image data - int m_iNumOpaquePixels; - int m_iNumTranslucentPixels; - int m_iNumTransparentPixels; - - ColorFloatRGBA m_numColorValues; - ColorFloatRGBA m_numOutOfRangeValues; - - bool m_bVerboseOutput; - private: - //add a warning or error to check for while encoding - inline void TrackEncodingWarning(EncodingStatus a_encStatus) - { - m_warningsToCapture = (EncodingStatus)((unsigned int)m_warningsToCapture | (unsigned int)a_encStatus); - } - - //report the warning if it is something we care about for this encoding - inline void AddToEncodingStatusIfSignfigant(EncodingStatus a_encStatus) - { - if ((EncodingStatus)((unsigned int)m_warningsToCapture & (unsigned int)a_encStatus) == a_encStatus) - { - AddToEncodingStatus(a_encStatus); - } - } - - Image(void); - void FindEncodingWarningTypesForCurFormat(); - void FindAndSetEncodingWarnings(); - - void InitBlocksAndBlockSorter(void); - - void RunFirstPass(unsigned int a_uiMultithreadingOffset, - unsigned int a_uiMultithreadingStride); - - void SetEncodingBits(unsigned int a_uiMultithreadingOffset, - unsigned int a_uiMultithreadingStride); - - unsigned int IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks, - unsigned int a_uiMultithreadingOffset, - unsigned int a_uiMultithreadingStride); - - // inputs - ColorFloatRGBA *m_pafrgbaSource; - unsigned int m_uiSourceWidth; - unsigned int m_uiSourceHeight; - unsigned int m_uiExtendedWidth; - unsigned int m_uiExtendedHeight; - unsigned int m_uiBlockColumns; - unsigned int m_uiBlockRows; - // intermediate data - Block4x4 *m_pablock; - // encoding - Format m_format; - Block4x4EncodingBits::Format m_encodingbitsformat; - unsigned int m_uiEncodingBitsBytes; // for entire image - unsigned char *m_paucEncodingBits; - ErrorMetric m_errormetric; - float m_fEffort; - // stats - int m_iEncodeTime_ms; - - SortedBlockList *m_psortedblocklist; - //this will hold any warning or errors that happen during encoding - EncodingStatus m_encodingStatus; - //these will be the warnings we are tracking - EncodingStatus m_warningsToCapture; - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcIndividualTrys.cpp b/thirdparty/etc2comp/EtcIndividualTrys.cpp deleted file mode 100644 index 56ff4c65ec..0000000000 --- a/thirdparty/etc2comp/EtcIndividualTrys.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcIndividualTrys.cpp - -Gathers the results of the various encoding trys for both halves of a 4x4 block for Individual mode - -*/ - -#include "EtcConfig.h" -#include "EtcIndividualTrys.h" - -#include <assert.h> - -namespace Etc -{ - - // ---------------------------------------------------------------------------------------------------- - // construct a list of trys (encoding attempts) - // - // a_frgbaColor1 is the basecolor for the first half - // a_frgbaColor2 is the basecolor for the second half - // a_pauiPixelMapping1 is the pixel order for the first half - // a_pauiPixelMapping2 is the pixel order for the second half - // a_uiRadius is the amount to vary the base colors - // - IndividualTrys::IndividualTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2, - const unsigned int *a_pauiPixelMapping1, - const unsigned int *a_pauiPixelMapping2, - unsigned int a_uiRadius) - { - assert(a_uiRadius <= MAX_RADIUS); - - ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR4G4B4(); - ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR4G4B4(); - - // quantize base colors - // ensure that trys with a_uiRadius don't overflow - int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(15.0f), a_uiRadius); - int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(15.0f), a_uiRadius); - int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(15.0f), a_uiRadius); - int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(15.0f), a_uiRadius); - int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(15.0f), a_uiRadius); - int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(15.0f), a_uiRadius); - - m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius); - m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius); - - } - - // ---------------------------------------------------------------------------------------------------- - // - void IndividualTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue, - const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius) - { - - m_iRed = a_iRed; - m_iGreen = a_iGreen; - m_iBlue = a_iBlue; - - m_pauiPixelMapping = a_pauiPixelMapping; - m_uiRadius = a_uiRadius; - - m_uiTrys = 0; - - } - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcIndividualTrys.h b/thirdparty/etc2comp/EtcIndividualTrys.h deleted file mode 100644 index 5fb12fbcf4..0000000000 --- a/thirdparty/etc2comp/EtcIndividualTrys.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "EtcColorFloatRGBA.h" - -namespace Etc -{ - - class IndividualTrys - { - public: - - static const unsigned int MAX_RADIUS = 1; - - IndividualTrys(ColorFloatRGBA a_frgbaColor1, - ColorFloatRGBA a_frgbaColor2, - const unsigned int *a_pauiPixelMapping1, - const unsigned int *a_pauiPixelMapping2, - unsigned int a_uiRadius); - - inline static int MoveAwayFromEdge(int a_i, int a_iDistance) - { - if (a_i < (0+ a_iDistance)) - { - return (0 + a_iDistance); - } - else if (a_i > (15- a_iDistance)) - { - return (15 - a_iDistance); - } - - return a_i; - } - - class Try - { - public : - static const unsigned int SELECTORS = 8; // per half - - int m_iRed; - int m_iGreen; - int m_iBlue; - unsigned int m_uiCW; - unsigned int m_auiSelectors[SELECTORS]; - float m_fError; - }; - - class Half - { - public: - - static const unsigned int MAX_TRYS = 27; - - void Init(int a_iRed, int a_iGreen, int a_iBlue, - const unsigned int *a_pauiPixelMapping, - unsigned int a_uiRadius); - - // center of trys - int m_iRed; - int m_iGreen; - int m_iBlue; - - const unsigned int *m_pauiPixelMapping; - unsigned int m_uiRadius; - - unsigned int m_uiTrys; - Try m_atry[MAX_TRYS]; - - Try *m_ptryBest; - }; - - Half m_half1; - Half m_half2; - - }; - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcMath.cpp b/thirdparty/etc2comp/EtcMath.cpp deleted file mode 100644 index 096d5f7ab9..0000000000 --- a/thirdparty/etc2comp/EtcMath.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "EtcConfig.h" -#include "EtcMath.h" - -namespace Etc -{ - - // ---------------------------------------------------------------------------------------------------- - // calculate the line that best fits the set of XY points contained in a_afX[] and a_afY[] - // use a_fSlope and a_fOffset to define that line - // - bool Regression(float a_afX[], float a_afY[], unsigned int a_Points, - float *a_fSlope, float *a_fOffset) - { - float fPoints = (float)a_Points; - - float fSumX = 0.0f; - float fSumY = 0.0f; - float fSumXY = 0.0f; - float fSumX2 = 0.0f; - - for (unsigned int uiPoint = 0; uiPoint < a_Points; uiPoint++) - { - fSumX += a_afX[uiPoint]; - fSumY += a_afY[uiPoint]; - fSumXY += a_afX[uiPoint] * a_afY[uiPoint]; - fSumX2 += a_afX[uiPoint] * a_afX[uiPoint]; - } - - float fDivisor = fPoints*fSumX2 - fSumX*fSumX; - - // if vertical line - if (fDivisor == 0.0f) - { - *a_fSlope = 0.0f; - *a_fOffset = 0.0f; - return true; - } - - *a_fSlope = (fPoints*fSumXY - fSumX*fSumY) / fDivisor; - *a_fOffset = (fSumY - (*a_fSlope)*fSumX) / fPoints; - - return false; - } - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcMath.h b/thirdparty/etc2comp/EtcMath.h deleted file mode 100644 index c58c9a91bc..0000000000 --- a/thirdparty/etc2comp/EtcMath.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <math.h> - -namespace Etc -{ - - // ---------------------------------------------------------------------------------------------------- - // return true if vertical line - bool Regression(float a_afX[], float a_afY[], unsigned int a_Points, - float *a_fSlope, float *a_fOffset); - - inline float ConvertMSEToPSNR(float a_fMSE) - { - if (a_fMSE == 0.0f) - { - return INFINITY; - } - - return 10.0f * log10f(1.0f / a_fMSE); - } - - -} diff --git a/thirdparty/etc2comp/EtcSortedBlockList.cpp b/thirdparty/etc2comp/EtcSortedBlockList.cpp deleted file mode 100644 index bfa6b7b3fa..0000000000 --- a/thirdparty/etc2comp/EtcSortedBlockList.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -EtcSortedBlockList.cpp - -SortedBlockList is a list of 4x4 blocks that can be used by the "effort" system to prioritize -the encoding of the 4x4 blocks. - -The sorting is done with buckets, where each bucket is an indication of how much error each 4x4 block has - -*/ - -#include "EtcConfig.h" -#include "EtcSortedBlockList.h" - -#include "EtcBlock4x4.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> - -namespace Etc -{ - - // ---------------------------------------------------------------------------------------------------- - // construct an empty list - // - // allocate enough memory to add all of the image's 4x4 blocks later - // allocate enough buckets to sort the blocks - // - SortedBlockList::SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets) - { - m_uiImageBlocks = a_uiImageBlocks; - m_iBuckets = (int)a_uiBuckets; - - m_uiAddedBlocks = 0; - m_uiSortedBlocks = 0; - m_palinkPool = new Link[m_uiImageBlocks]; - m_pabucket = new Bucket[m_iBuckets]; - m_fMaxError = 0.0f; - - InitBuckets(); - - } - - // ---------------------------------------------------------------------------------------------------- - // - SortedBlockList::~SortedBlockList(void) - { - delete[] m_palinkPool; - delete[] m_pabucket; - } - - // ---------------------------------------------------------------------------------------------------- - // add a 4x4 block to the list - // the 4x4 block will be sorted later - // - void SortedBlockList::AddBlock(Block4x4 *a_pblock) - { - assert(m_uiAddedBlocks < m_uiImageBlocks); - Link *plink = &m_palinkPool[m_uiAddedBlocks++]; - plink->Init(a_pblock); - } - - // ---------------------------------------------------------------------------------------------------- - // sort all of the 4x4 blocks that have been added to the list - // - // first, determine the maximum error, then assign an error range to each bucket - // next, determine which bucket each 4x4 block belongs to based on the 4x4 block's error - // add the 4x4 block to the appropriate bucket - // lastly, walk thru the buckets and add each bucket to a sorted linked list - // - // the resultant sorting is an approximate sorting from most to least error - // - void SortedBlockList::Sort(void) - { - assert(m_uiAddedBlocks == m_uiImageBlocks); - InitBuckets(); - - // find max block error - m_fMaxError = -1.0f; - - for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++) - { - Link *plinkBlock = &m_palinkPool[uiLink]; - - float fBlockError = plinkBlock->GetBlock()->GetError(); - if (fBlockError > m_fMaxError) - { - m_fMaxError = fBlockError; - } - } - // prevent divide by zero or divide by negative - if (m_fMaxError <= 0.0f) - { - m_fMaxError = 1.0f; - } - //used for debugging - //int numDone = 0; - // put all of the blocks with unfinished encodings into the appropriate bucket - m_uiSortedBlocks = 0; - for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++) - { - Link *plinkBlock = &m_palinkPool[uiLink]; - - // if the encoding is done, don't add it to the list - if (plinkBlock->GetBlock()->GetEncoding()->IsDone()) - { - //numDone++; - continue; - } - - // calculate the appropriate sort bucket - float fBlockError = plinkBlock->GetBlock()->GetError(); - int iBucket = (int) floorf(m_iBuckets * fBlockError / m_fMaxError); - // clamp to bucket index - iBucket = iBucket < 0 ? 0 : iBucket >= m_iBuckets ? m_iBuckets - 1 : iBucket; - - // add block to bucket - { - Bucket *pbucket = &m_pabucket[iBucket]; - if (pbucket->plinkLast) - { - pbucket->plinkLast->SetNext(plinkBlock); - pbucket->plinkLast = plinkBlock; - } - else - { - pbucket->plinkFirst = pbucket->plinkLast = plinkBlock; - } - plinkBlock->SetNext(nullptr); - } - - m_uiSortedBlocks++; - - if (0) - { - printf("%u: e=%.3f\n", uiLink, fBlockError); - Print(); - printf("\n\n\n"); - } - } - //printf("num blocks already done: %d\n",numDone); - //link the blocks together across buckets - m_plinkFirst = nullptr; - m_plinkLast = nullptr; - for (int iBucket = m_iBuckets - 1; iBucket >= 0; iBucket--) - { - Bucket *pbucket = &m_pabucket[iBucket]; - - if (pbucket->plinkFirst) - { - if (m_plinkFirst == nullptr) - { - m_plinkFirst = pbucket->plinkFirst; - } - else - { - assert(pbucket->plinkLast->GetNext() == nullptr); - m_plinkLast->SetNext(pbucket->plinkFirst); - } - - m_plinkLast = pbucket->plinkLast; - } - } - - - } - - // ---------------------------------------------------------------------------------------------------- - // clear all of the buckets. normally done in preparation for a sort - // - void SortedBlockList::InitBuckets(void) - { - for (int iBucket = 0; iBucket < m_iBuckets; iBucket++) - { - Bucket *pbucket = &m_pabucket[iBucket]; - - pbucket->plinkFirst = 0; - pbucket->plinkLast = 0; - } - } - - // ---------------------------------------------------------------------------------------------------- - // print out the list of sorted 4x4 blocks - // normally used for debugging - // - void SortedBlockList::Print(void) - { - for (int iBucket = m_iBuckets-1; iBucket >= 0; iBucket--) - { - Bucket *pbucket = &m_pabucket[iBucket]; - - unsigned int uiBlocks = 0; - for (Link *plink = pbucket->plinkFirst; plink != nullptr; plink = plink->GetNext() ) - { - uiBlocks++; - - if (plink == pbucket->plinkLast) - { - break; - } - } - - float fBucketError = m_fMaxError * iBucket / m_iBuckets; - float fBucketRMS = sqrtf(fBucketError / (4.0f*16.0f) ); - printf("%3d: e=%.3f rms=%.6f %u\n", iBucket, fBucketError, fBucketRMS, uiBlocks); - } - } - - // ---------------------------------------------------------------------------------------------------- - // - -} // namespace Etc diff --git a/thirdparty/etc2comp/EtcSortedBlockList.h b/thirdparty/etc2comp/EtcSortedBlockList.h deleted file mode 100644 index 960e8adc34..0000000000 --- a/thirdparty/etc2comp/EtcSortedBlockList.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2015 The Etc2Comp Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -namespace Etc -{ - class Block4x4; - - class SortedBlockList - { - public: - - class Link - { - public: - - inline void Init(Block4x4 *a_pblock) - { - m_pblock = a_pblock; - m_plinkNext = nullptr; - } - - inline Block4x4 * GetBlock(void) - { - return m_pblock; - } - - inline void SetNext(Link *a_plinkNext) - { - m_plinkNext = a_plinkNext; - } - - inline Link * GetNext(void) - { - return m_plinkNext; - } - - inline Link * Advance(unsigned int a_uiSteps = 1) - { - Link *plink = this; - - for (unsigned int uiStep = 0; uiStep < a_uiSteps; uiStep++) - { - if (plink == nullptr) - { - break; - } - - plink = plink->m_plinkNext; - } - - return plink; - } - - private: - - Block4x4 *m_pblock; - Link *m_plinkNext; - }; - - SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets); - ~SortedBlockList(void); - - void AddBlock(Block4x4 *a_pblock); - - void Sort(void); - - inline Link * GetLinkToFirstBlock(void) - { - return m_plinkFirst; - } - - inline unsigned int GetNumberOfAddedBlocks(void) - { - return m_uiAddedBlocks; - } - - inline unsigned int GetNumberOfSortedBlocks(void) - { - return m_uiSortedBlocks; - } - - void Print(void); - - private: - - void InitBuckets(void); - - class Bucket - { - public: - Link *plinkFirst; - Link *plinkLast; - }; - - unsigned int m_uiImageBlocks; - int m_iBuckets; - - unsigned int m_uiAddedBlocks; - unsigned int m_uiSortedBlocks; - Link *m_palinkPool; - Bucket *m_pabucket; - float m_fMaxError; - - Link *m_plinkFirst; - Link *m_plinkLast; - - }; - -} // namespace Etc diff --git a/thirdparty/etc2comp/LICENSE b/thirdparty/etc2comp/LICENSE deleted file mode 100644 index d645695673..0000000000 --- a/thirdparty/etc2comp/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/thirdparty/etc2comp/README.md b/thirdparty/etc2comp/README.md deleted file mode 100644 index 2f4363d042..0000000000 --- a/thirdparty/etc2comp/README.md +++ /dev/null @@ -1,197 +0,0 @@ -# Etc2Comp - Texture to ETC2 compressor - -Etc2Comp is a command line tool that converts textures (e.g. bitmaps) -into the [ETC2](https://en.wikipedia.org/wiki/Ericsson_Texture_Compression) -format. The tool is built with a focus on encoding performance -to reduce the amount of time required to compile asset heavy applications as -well as reduce overall application size. - -This repo provides source code that can be compiled into a binary. The -binary can then be used to convert textures to the ETC2 format. - -Important: This is not an official Google product. It is an experimental -library published as-is. Please see the CONTRIBUTORS.md file for information -about questions or issues. - -## Setup -This project uses [CMake](https://cmake.org/) to generate platform-specific -build files: - - Linux: make files - - OS X: Xcode workspace files - - Microsoft Windows: Visual Studio solution files - - Note: CMake supports other formats, but this doc only provides steps for - one of each platform for brevity. - -Refer to each platform's setup section to setup your environment and build -an Etc2Comp binary. Then skip to the usage section of this page for examples -of how to use the library. - -### Setup for OS X - build tested on this config: - OS X 10.9.5 i7 16GB RAM - Xcode 5.1.1 - cmake 3.2.3 - -Start by downloading and installing the following components if they are not -already installed on your development machine. - - *Xcode* version 5.1.1, or greater - - [CMake](https://cmake.org/download/) version 3.2.3, or greater - -To build the Etc2Comp binary: - 1. Open a *Terminal* window and navigate to the project directory. - 1. Run `mkdir build_xcode` - 1. Run `cd build_xcode` - 1. Run `cmake -G Xcode ../` - 1. Open *Xcode* and import the `build_xcode/EtcTest.xcodeproj` file. - 1. Open the Product menu and choose Build For -> Running. - 1. Once the build succeeds the binary located at `build_xcode/EtcTool/Debug/EtcTool` -can be executed. - -Optional -Xcode EtcTool ‘Run’ preferences -note: if the build_xcode/EtcTest.xcodeproj is manually deleted then some Xcode preferences -will need to be set by hand after cmake is run (these prefs are retained across -cmake updates if the .xcodeproj is not deleted/removed) - -1. Set the active scheme to ‘EtcTool’ -1. Edit the scheme -1. Select option ‘Run EtcTool’, then tab ‘Arguments’. -Add this launch argument: ‘-argfile ../../EtcTool/args.txt’ -1. Select tab ‘Options’ and set a custom working directory to: ‘$(SRCROOT)/Build_Xcode/EtcTool’ - -### SetUp for Windows - -1. Open a *Terminal* window and navigate to the project directory. -1. Run `mkdir build_vs` -1. Run `cd build_vs` -1. Run CMAKE, noting what build version you need, and pointing to the parent directory as the source root; - For VS 2013 : `cmake -G "Visual Studio 12 2013 Win64" ../` - For VS 2015 : `cmake -G "Visual Studio 14 2015 Win64" ../` - NOTE: To see what supported Visual Studio outputs there are, run `cmake -G` -1. open the 'EtcTest' solution -1. make the 'EtcTool' project the start up project -1. (optional) in the project properties, under 'Debugging ->command arguments' -add the argfile textfile thats included in the EtcTool directory. -example: -argfile C:\etc2\EtcTool\Args.txt - -### Setup For Linux -The Linux build was tested on this config: - Ubuntu desktop 14.04 - gcc/g++ 4.8 - cmake 2.8.12.2 - -1. Verify linux has cmake and C++-11 capable g++ installed -1. Open shell -1. Run `mkdir build_linux` -1. Run `cd build_linux` -1. Run `cmake ../` -1. Run `make` -1. navigate to the newly created EtcTool directory `cd EtcTool` -1. run the executable: `./EtcTool -argfile ../../EtcTool/args.txt` - -Skip to the <a href="#usage">Usage</a> section for more information about using the -tool. - -## Usage - -### Command Line Usage -EtcTool can be run from the command line with the following usage: - etctool.exe source_image [options ...] -output encoded_image - -The encoder will use an array of RGBA floats read from the source_image to create -an ETC1 or ETC2 encoded image in encoded_image. The RGBA floats should be in the -range [0:1]. - -Options: - - -analyze <analysis_folder> - -argfile <arg_file> additional command line arguments read from a file - -blockAtHV <H V> encodes a single block that contains the - pixel specified by the H V coordinates - -compare <comparison_image> compares source_image to comparison_image - -effort <amount> number between 0 and 100 to specify the encoding quality - (100 is the highest quality) - -errormetric <error_metric> specify the error metric, the options are - rgba, rgbx, rec709, numeric and normalxyz - -format <etc_format> ETC1, RGB8, SRGB8, RGBA8, SRGB8, RGB8A1, - SRGB8A1 or R11 - -help prints this message - -jobs or -j <thread_count> specifies the number of threads (default=1) - -normalizexyz normalize RGB to have a length of 1 - -verbose or -v shows status information during the encoding - process - -mipmaps or -m <mip_count> sets the maximum number of mipaps to generate (default=1) - -mipwrap or -w <x|y|xy> sets the mipmap filter wrap mode (default=clamp) - -* -analyze will run an analysis of the encoding and place it in folder -"analysis_folder" (e.g. ../analysis/kodim05). within the analysis_folder, a folder -will be created with a name of the current date/time (e.g. 20151204_153306). this -date/time folder is used to compare encodings of the same texture over time. -within the date/time folder is a text file with several encoding stats and a 2x png -image showing the encoding mode for each 4x4 block. - -* -argfile allows additional command line arguments to be placed in a text file - -* -blockAtHV selects the 4x4 pixel subset of the source image at position (H,V). -This is mainly used for debugging - -* -compare compares the source image to the created encoded image. The encoding -will dictate what error analysis is used in the comparison. - -* -effort uses an "amount" between 0 and 100 to determine how much additional effort -to apply during the encoding. - -* -errormetric selects the fitting algorithm used by the encoder. "rgba" calculates -RMS error using RGB components that are weighted by A. "rgbx" calculates RMS error -using RGBA components, where A is treated as an additional data channel, instead of -as alpha. "rec709" is similar to "rgba", except the RGB components are also weighted -according to Rec709. "numeric" calculates RMS error using unweighted RGBA components. -"normalize" calculates error based on dot product and vector length for RGB and RMS -error for A. - -* -help prints out the usage message - -* -jobs enables multi-threading to speed up image encoding - -* -normalizexyz normalizes the source RGB to have a length of 1. - -* -verbose shows information on the current encoding process. It will then display the -PSNR and time time it took to encode the image. - -* -mipmaps takes an argument that specifies how many mipmaps to generate from the -source image. The mipmaps are generated with a lanczos3 filter using edge clamping. -If the mipmaps option is not specified no mipmaps are created. - -* -mipwrap takes an argument that specifies the mipmap filter wrap mode. The options -are "x", "y" and "xy" which specify wrapping in x only, y only or x and y respectively. -The default options are clamping in both x and y. - -Note: Path names can use slashes or backslashes. The tool will convert the -slashes to the appropriate polarity for the current platform. - - -## API - -The library supports two different APIs - a C-like API that is not heavily -class-based and a class-based API. - -main() in EtcTool.cpp contains an example of both APIs. - -The Encode() method now returns an EncodingStatus that contains bit flags for -reporting various warnings and flags encountered when encoding. - - -## Copyright -Copyright 2015 Etc2Comp Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch b/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch deleted file mode 100644 index ea9b5640b6..0000000000 --- a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch +++ /dev/null @@ -1,224 +0,0 @@ -diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp -index 5656556db9..5c7ebed788 100644 ---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp -+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp -@@ -508,7 +508,7 @@ namespace Etc - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { -- iMinRed1 = 15; -+ iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; -@@ -519,7 +519,7 @@ namespace Etc - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { -- iMinGreen1 = 15; -+ iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; -@@ -530,7 +530,7 @@ namespace Etc - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { -- iMinBlue1 = 15; -+ iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); -@@ -545,7 +545,7 @@ namespace Etc - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { -- iMinRed2 = 15; -+ iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; -@@ -556,7 +556,7 @@ namespace Etc - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { -- iMinGreen2 = 15; -+ iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; -@@ -567,7 +567,7 @@ namespace Etc - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { -- iMinBlue2 = 15; -+ iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) -@@ -761,7 +761,7 @@ namespace Etc - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { -- iMinRed1 = 15; -+ iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; -@@ -772,7 +772,7 @@ namespace Etc - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { -- iMinGreen1 = 15; -+ iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; -@@ -783,7 +783,7 @@ namespace Etc - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { -- iMinBlue1 = 15; -+ iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); -@@ -798,7 +798,7 @@ namespace Etc - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { -- iMinRed2 = 15; -+ iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; -@@ -809,7 +809,7 @@ namespace Etc - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { -- iMinGreen2 = 15; -+ iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; -@@ -820,7 +820,7 @@ namespace Etc - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { -- iMinBlue2 = 15; -+ iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) -diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp -index ba2b42fb05..b94b64e68c 100644 ---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp -+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp -@@ -847,7 +847,7 @@ namespace Etc - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { -- iMinRed1 = 15; -+ iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; -@@ -858,7 +858,7 @@ namespace Etc - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { -- iMinGreen1 = 15; -+ iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; -@@ -869,7 +869,7 @@ namespace Etc - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { -- iMinBlue1 = 15; -+ iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); -@@ -884,7 +884,7 @@ namespace Etc - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { -- iMinRed2 = 15; -+ iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; -@@ -895,7 +895,7 @@ namespace Etc - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { -- iMinGreen2 = 15; -+ iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; -@@ -906,7 +906,7 @@ namespace Etc - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { -- iMinBlue2 = 15; -+ iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) -@@ -1108,7 +1108,7 @@ namespace Etc - int iMaxRed1 = iColor1Red + (int)a_uiRadius; - if (iMaxRed1 > 15) - { -- iMinRed1 = 15; -+ iMaxRed1 = 15; - } - - int iMinGreen1 = iColor1Green - (int)a_uiRadius; -@@ -1119,7 +1119,7 @@ namespace Etc - int iMaxGreen1 = iColor1Green + (int)a_uiRadius; - if (iMaxGreen1 > 15) - { -- iMinGreen1 = 15; -+ iMaxGreen1 = 15; - } - - int iMinBlue1 = iColor1Blue - (int)a_uiRadius; -@@ -1130,7 +1130,7 @@ namespace Etc - int iMaxBlue1 = iColor1Blue + (int)a_uiRadius; - if (iMaxBlue1 > 15) - { -- iMinBlue1 = 15; -+ iMaxBlue1 = 15; - } - - int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f); -@@ -1145,7 +1145,7 @@ namespace Etc - int iMaxRed2 = iColor2Red + (int)a_uiRadius; - if (iMaxRed2 > 15) - { -- iMinRed2 = 15; -+ iMaxRed2 = 15; - } - - int iMinGreen2 = iColor2Green - (int)a_uiRadius; -@@ -1156,7 +1156,7 @@ namespace Etc - int iMaxGreen2 = iColor2Green + (int)a_uiRadius; - if (iMaxGreen2 > 15) - { -- iMinGreen2 = 15; -+ iMaxGreen2 = 15; - } - - int iMinBlue2 = iColor2Blue - (int)a_uiRadius; -@@ -1167,7 +1167,7 @@ namespace Etc - int iMaxBlue2 = iColor2Blue + (int)a_uiRadius; - if (iMaxBlue2 > 15) - { -- iMinBlue2 = 15; -+ iMaxBlue2 = 15; - } - - for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++) diff --git a/thirdparty/etcpak/AUTHORS.txt b/thirdparty/etcpak/AUTHORS.txt new file mode 100644 index 0000000000..e7bae62c85 --- /dev/null +++ b/thirdparty/etcpak/AUTHORS.txt @@ -0,0 +1,3 @@ +Bartosz Taudul <wolf@nereid.pl> +Daniel Jungmann <el.3d.source@gmail.com> +Florian Penzkofer <fp@nullptr.de> diff --git a/thirdparty/etcpak/Dither.cpp b/thirdparty/etcpak/Dither.cpp new file mode 100644 index 0000000000..355686f26b --- /dev/null +++ b/thirdparty/etcpak/Dither.cpp @@ -0,0 +1,120 @@ +#include <algorithm> +#include <string.h> + +#include "Dither.hpp" +#include "Math.hpp" +#ifdef __SSE4_1__ +# ifdef _MSC_VER +# include <intrin.h> +# include <Windows.h> +# else +# include <x86intrin.h> +# endif +#endif + +#ifdef __AVX2__ +void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 ) +{ + static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 }; + static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 }; + static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 }; + static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 }; + + const __m256i BayerAdd0 = _mm256_setr_epi8( + a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0, + a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0 + ); + const __m256i BayerAdd1 = _mm256_setr_epi8( + a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0, + a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0 + ); + const __m256i BayerSub0 = _mm256_setr_epi8( + s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0, + s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0 + ); + const __m256i BayerSub1 = _mm256_setr_epi8( + s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0, + s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0 + ); + + __m256i l0 = _mm256_inserti128_si256( _mm256_castsi128_si256( px0 ), px1, 1 ); + __m256i l1 = _mm256_inserti128_si256( _mm256_castsi128_si256( px2 ), px3, 1 ); + + __m256i a0 = _mm256_adds_epu8( l0, BayerAdd0 ); + __m256i a1 = _mm256_adds_epu8( l1, BayerAdd1 ); + __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 ); + __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 ); + + _mm256_storeu_si256( (__m256i*)(data ), s0 ); + _mm256_storeu_si256( (__m256i*)(data+32), s1 ); + +} +#endif + +void Dither( uint8_t* data ) +{ +#ifdef __AVX2__ + static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 }; + static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 }; + static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 }; + static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 }; + + const __m256i BayerAdd0 = _mm256_setr_epi8( + a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0, + a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0 + ); + const __m256i BayerAdd1 = _mm256_setr_epi8( + a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0, + a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0 + ); + const __m256i BayerSub0 = _mm256_setr_epi8( + s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0, + s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0 + ); + const __m256i BayerSub1 = _mm256_setr_epi8( + s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0, + s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0 + ); + + __m256i px0 = _mm256_loadu_si256( (__m256i*)(data ) ); + __m256i px1 = _mm256_loadu_si256( (__m256i*)(data+32) ); + + __m256i a0 = _mm256_adds_epu8( px0, BayerAdd0 ); + __m256i a1 = _mm256_adds_epu8( px1, BayerAdd1 ); + __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 ); + __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 ); + + _mm256_storeu_si256( (__m256i*)(data ), s0 ); + _mm256_storeu_si256( (__m256i*)(data+32), s1 ); +#else + static constexpr int8_t Bayer31[16] = { + ( 0-8)*2/3, ( 8-8)*2/3, ( 2-8)*2/3, (10-8)*2/3, + (12-8)*2/3, ( 4-8)*2/3, (14-8)*2/3, ( 6-8)*2/3, + ( 3-8)*2/3, (11-8)*2/3, ( 1-8)*2/3, ( 9-8)*2/3, + (15-8)*2/3, ( 7-8)*2/3, (13-8)*2/3, ( 5-8)*2/3 + }; + static constexpr int8_t Bayer63[16] = { + ( 0-8)*2/6, ( 8-8)*2/6, ( 2-8)*2/6, (10-8)*2/6, + (12-8)*2/6, ( 4-8)*2/6, (14-8)*2/6, ( 6-8)*2/6, + ( 3-8)*2/6, (11-8)*2/6, ( 1-8)*2/6, ( 9-8)*2/6, + (15-8)*2/6, ( 7-8)*2/6, (13-8)*2/6, ( 5-8)*2/6 + }; + + for( int i=0; i<16; i++ ) + { + uint32_t col; + memcpy( &col, data, 4 ); + uint8_t r = col & 0xFF; + uint8_t g = ( col >> 8 ) & 0xFF; + uint8_t b = ( col >> 16 ) & 0xFF; + + r = clampu8( r + Bayer31[i] ); + g = clampu8( g + Bayer63[i] ); + b = clampu8( b + Bayer31[i] ); + + col = r | ( g << 8 ) | ( b << 16 ); + memcpy( data, &col, 4 ); + data += 4; + } +#endif +} diff --git a/thirdparty/etcpak/Dither.hpp b/thirdparty/etcpak/Dither.hpp new file mode 100644 index 0000000000..e43ce5676d --- /dev/null +++ b/thirdparty/etcpak/Dither.hpp @@ -0,0 +1,21 @@ +#ifndef __DITHER_HPP__ +#define __DITHER_HPP__ + +#include <stddef.h> +#include <stdint.h> + +#ifdef __AVX2__ +# ifdef _MSC_VER +# include <intrin.h> +# else +# include <x86intrin.h> +# endif +#endif + +void Dither( uint8_t* data ); + +#ifdef __AVX2__ +void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 ); +#endif + +#endif diff --git a/thirdparty/etcpak/ForceInline.hpp b/thirdparty/etcpak/ForceInline.hpp new file mode 100644 index 0000000000..b6f012841b --- /dev/null +++ b/thirdparty/etcpak/ForceInline.hpp @@ -0,0 +1,20 @@ +#ifndef __FORCEINLINE_HPP__ +#define __FORCEINLINE_HPP__ + +#if defined(__GNUC__) +# define etcpak_force_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define etcpak_force_inline __forceinline +#else +# define etcpak_force_inline inline +#endif + +#if defined(__GNUC__) +# define etcpak_no_inline __attribute__((noinline)) +#elif defined(_MSC_VER) +# define etcpak_no_inline __declspec(noinline) +#else +# define etcpak_no_inline +#endif + +#endif diff --git a/thirdparty/etcpak/LICENSE.txt b/thirdparty/etcpak/LICENSE.txt new file mode 100644 index 0000000000..59e85d6ea5 --- /dev/null +++ b/thirdparty/etcpak/LICENSE.txt @@ -0,0 +1,26 @@ +etcpak, an extremely fast ETC compression utility (https://github.com/wolfpld/etcpak) + +Copyright (c) 2013-2021, Bartosz Taudul <wolf@nereid.pl> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the <organization> nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/etcpak/Math.hpp b/thirdparty/etcpak/Math.hpp new file mode 100644 index 0000000000..994e1ac4ea --- /dev/null +++ b/thirdparty/etcpak/Math.hpp @@ -0,0 +1,92 @@ +#ifndef __DARKRL__MATH_HPP__ +#define __DARKRL__MATH_HPP__ + +#include <algorithm> +#include <cmath> +#include <stdint.h> + +#include "ForceInline.hpp" + +template<typename T> +static etcpak_force_inline T AlignPOT( T val ) +{ + if( val == 0 ) return 1; + val--; + for( unsigned int i=1; i<sizeof( T ) * 8; i <<= 1 ) + { + val |= val >> i; + } + return val + 1; +} + +static etcpak_force_inline int CountSetBits( uint32_t val ) +{ + val -= ( val >> 1 ) & 0x55555555; + val = ( ( val >> 2 ) & 0x33333333 ) + ( val & 0x33333333 ); + val = ( ( val >> 4 ) + val ) & 0x0f0f0f0f; + val += val >> 8; + val += val >> 16; + return val & 0x0000003f; +} + +static etcpak_force_inline int CountLeadingZeros( uint32_t val ) +{ + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + return 32 - CountSetBits( val ); +} + +static etcpak_force_inline float sRGB2linear( float v ) +{ + const float a = 0.055f; + if( v <= 0.04045f ) + { + return v / 12.92f; + } + else + { + return pow( ( v + a ) / ( 1 + a ), 2.4f ); + } +} + +static etcpak_force_inline float linear2sRGB( float v ) +{ + const float a = 0.055f; + if( v <= 0.0031308f ) + { + return 12.92f * v; + } + else + { + return ( 1 + a ) * pow( v, 1/2.4f ) - a; + } +} + +template<class T> +static etcpak_force_inline T SmoothStep( T x ) +{ + return x*x*(3-2*x); +} + +static etcpak_force_inline uint8_t clampu8( int32_t val ) +{ + if( ( val & ~0xFF ) == 0 ) return val; + return ( ( ~val ) >> 31 ) & 0xFF; +} + +template<class T> +static etcpak_force_inline T sq( T val ) +{ + return val * val; +} + +static etcpak_force_inline int mul8bit( int a, int b ) +{ + int t = a*b + 128; + return ( t + ( t >> 8 ) ) >> 8; +} + +#endif diff --git a/thirdparty/etcpak/ProcessCommon.hpp b/thirdparty/etcpak/ProcessCommon.hpp new file mode 100644 index 0000000000..657d68888f --- /dev/null +++ b/thirdparty/etcpak/ProcessCommon.hpp @@ -0,0 +1,50 @@ +#ifndef __PROCESSCOMMON_HPP__ +#define __PROCESSCOMMON_HPP__ + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> + +template<class T> +static size_t GetLeastError( const T* err, size_t num ) +{ + size_t idx = 0; + for( size_t i=1; i<num; i++ ) + { + if( err[i] < err[idx] ) + { + idx = i; + } + } + return idx; +} + +static uint64_t FixByteOrder( uint64_t d ) +{ + return ( ( d & 0x00000000FFFFFFFF ) ) | + ( ( d & 0xFF00000000000000 ) >> 24 ) | + ( ( d & 0x000000FF00000000 ) << 24 ) | + ( ( d & 0x00FF000000000000 ) >> 8 ) | + ( ( d & 0x0000FF0000000000 ) << 8 ); +} + +template<class T, class S> +static uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id ) +{ + size_t tidx[2]; + tidx[0] = GetLeastError( terr[0], 8 ); + tidx[1] = GetLeastError( terr[1], 8 ); + + d |= tidx[0] << 26; + d |= tidx[1] << 29; + for( int i=0; i<16; i++ ) + { + uint64_t t = tsel[i][tidx[id[i]%2]]; + d |= ( t & 0x1 ) << ( i + 32 ); + d |= ( t & 0x2 ) << ( i + 47 ); + } + + return d; +} + +#endif diff --git a/thirdparty/etcpak/ProcessDxtc.cpp b/thirdparty/etcpak/ProcessDxtc.cpp new file mode 100644 index 0000000000..508d55fd75 --- /dev/null +++ b/thirdparty/etcpak/ProcessDxtc.cpp @@ -0,0 +1,956 @@ +#include "Dither.hpp" +#include "ForceInline.hpp" +#include "ProcessDxtc.hpp" + +#include <assert.h> +#include <stdint.h> +#include <string.h> + +#ifdef __ARM_NEON +# include <arm_neon.h> +#endif + +#if defined __AVX__ && !defined __SSE4_1__ +# define __SSE4_1__ +#endif + +#if defined __SSE4_1__ || defined __AVX2__ +# ifdef _MSC_VER +# include <intrin.h> +# else +# include <x86intrin.h> +# ifndef _mm256_cvtsi256_si32 +# define _mm256_cvtsi256_si32( v ) ( _mm_cvtsi128_si32( _mm256_castsi256_si128( v ) ) ) +# endif +# endif +#endif + + +static etcpak_force_inline uint16_t to565( uint8_t r, uint8_t g, uint8_t b ) +{ + return ( ( r & 0xF8 ) << 8 ) | ( ( g & 0xFC ) << 3 ) | ( b >> 3 ); +} + +static etcpak_force_inline uint16_t to565( uint32_t c ) +{ + return + ( ( c & 0xF80000 ) >> 19 ) | + ( ( c & 0x00FC00 ) >> 5 ) | + ( ( c & 0x0000F8 ) << 8 ); +} + +static const uint8_t DxtcIndexTable[256] = { + 85, 87, 86, 84, 93, 95, 94, 92, 89, 91, 90, 88, 81, 83, 82, 80, + 117, 119, 118, 116, 125, 127, 126, 124, 121, 123, 122, 120, 113, 115, 114, 112, + 101, 103, 102, 100, 109, 111, 110, 108, 105, 107, 106, 104, 97, 99, 98, 96, + 69, 71, 70, 68, 77, 79, 78, 76, 73, 75, 74, 72, 65, 67, 66, 64, + 213, 215, 214, 212, 221, 223, 222, 220, 217, 219, 218, 216, 209, 211, 210, 208, + 245, 247, 246, 244, 253, 255, 254, 252, 249, 251, 250, 248, 241, 243, 242, 240, + 229, 231, 230, 228, 237, 239, 238, 236, 233, 235, 234, 232, 225, 227, 226, 224, + 197, 199, 198, 196, 205, 207, 206, 204, 201, 203, 202, 200, 193, 195, 194, 192, + 149, 151, 150, 148, 157, 159, 158, 156, 153, 155, 154, 152, 145, 147, 146, 144, + 181, 183, 182, 180, 189, 191, 190, 188, 185, 187, 186, 184, 177, 179, 178, 176, + 165, 167, 166, 164, 173, 175, 174, 172, 169, 171, 170, 168, 161, 163, 162, 160, + 133, 135, 134, 132, 141, 143, 142, 140, 137, 139, 138, 136, 129, 131, 130, 128, + 21, 23, 22, 20, 29, 31, 30, 28, 25, 27, 26, 24, 17, 19, 18, 16, + 53, 55, 54, 52, 61, 63, 62, 60, 57, 59, 58, 56, 49, 51, 50, 48, + 37, 39, 38, 36, 45, 47, 46, 44, 41, 43, 42, 40, 33, 35, 34, 32, + 5, 7, 6, 4, 13, 15, 14, 12, 9, 11, 10, 8, 1, 3, 2, 0 +}; + +static const uint8_t AlphaIndexTable_SSE[64] = { + 9, 15, 14, 13, 12, 11, 10, 8, 57, 63, 62, 61, 60, 59, 58, 56, + 49, 55, 54, 53, 52, 51, 50, 48, 41, 47, 46, 45, 44, 43, 42, 40, + 33, 39, 38, 37, 36, 35, 34, 32, 25, 31, 30, 29, 28, 27, 26, 24, + 17, 23, 22, 21, 20, 19, 18, 16, 1, 7, 6, 5, 4, 3, 2, 0, +}; + +static const uint16_t DivTable[255*3+1] = { + 0xffff, 0xffff, 0xffff, 0xffff, 0xcccc, 0xaaaa, 0x9249, 0x8000, 0x71c7, 0x6666, 0x5d17, 0x5555, 0x4ec4, 0x4924, 0x4444, 0x4000, + 0x3c3c, 0x38e3, 0x35e5, 0x3333, 0x30c3, 0x2e8b, 0x2c85, 0x2aaa, 0x28f5, 0x2762, 0x25ed, 0x2492, 0x234f, 0x2222, 0x2108, 0x2000, + 0x1f07, 0x1e1e, 0x1d41, 0x1c71, 0x1bac, 0x1af2, 0x1a41, 0x1999, 0x18f9, 0x1861, 0x17d0, 0x1745, 0x16c1, 0x1642, 0x15c9, 0x1555, + 0x14e5, 0x147a, 0x1414, 0x13b1, 0x1352, 0x12f6, 0x129e, 0x1249, 0x11f7, 0x11a7, 0x115b, 0x1111, 0x10c9, 0x1084, 0x1041, 0x1000, + 0x0fc0, 0x0f83, 0x0f48, 0x0f0f, 0x0ed7, 0x0ea0, 0x0e6c, 0x0e38, 0x0e07, 0x0dd6, 0x0da7, 0x0d79, 0x0d4c, 0x0d20, 0x0cf6, 0x0ccc, + 0x0ca4, 0x0c7c, 0x0c56, 0x0c30, 0x0c0c, 0x0be8, 0x0bc5, 0x0ba2, 0x0b81, 0x0b60, 0x0b40, 0x0b21, 0x0b02, 0x0ae4, 0x0ac7, 0x0aaa, + 0x0a8e, 0x0a72, 0x0a57, 0x0a3d, 0x0a23, 0x0a0a, 0x09f1, 0x09d8, 0x09c0, 0x09a9, 0x0991, 0x097b, 0x0964, 0x094f, 0x0939, 0x0924, + 0x090f, 0x08fb, 0x08e7, 0x08d3, 0x08c0, 0x08ad, 0x089a, 0x0888, 0x0876, 0x0864, 0x0853, 0x0842, 0x0831, 0x0820, 0x0810, 0x0800, + 0x07f0, 0x07e0, 0x07d1, 0x07c1, 0x07b3, 0x07a4, 0x0795, 0x0787, 0x0779, 0x076b, 0x075d, 0x0750, 0x0743, 0x0736, 0x0729, 0x071c, + 0x070f, 0x0703, 0x06f7, 0x06eb, 0x06df, 0x06d3, 0x06c8, 0x06bc, 0x06b1, 0x06a6, 0x069b, 0x0690, 0x0685, 0x067b, 0x0670, 0x0666, + 0x065c, 0x0652, 0x0648, 0x063e, 0x0634, 0x062b, 0x0621, 0x0618, 0x060f, 0x0606, 0x05fd, 0x05f4, 0x05eb, 0x05e2, 0x05d9, 0x05d1, + 0x05c9, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0581, 0x0579, 0x0572, 0x056b, 0x0563, 0x055c, 0x0555, + 0x054e, 0x0547, 0x0540, 0x0539, 0x0532, 0x052b, 0x0525, 0x051e, 0x0518, 0x0511, 0x050b, 0x0505, 0x04fe, 0x04f8, 0x04f2, 0x04ec, + 0x04e6, 0x04e0, 0x04da, 0x04d4, 0x04ce, 0x04c8, 0x04c3, 0x04bd, 0x04b8, 0x04b2, 0x04ad, 0x04a7, 0x04a2, 0x049c, 0x0497, 0x0492, + 0x048d, 0x0487, 0x0482, 0x047d, 0x0478, 0x0473, 0x046e, 0x0469, 0x0465, 0x0460, 0x045b, 0x0456, 0x0452, 0x044d, 0x0448, 0x0444, + 0x043f, 0x043b, 0x0436, 0x0432, 0x042d, 0x0429, 0x0425, 0x0421, 0x041c, 0x0418, 0x0414, 0x0410, 0x040c, 0x0408, 0x0404, 0x0400, + 0x03fc, 0x03f8, 0x03f4, 0x03f0, 0x03ec, 0x03e8, 0x03e4, 0x03e0, 0x03dd, 0x03d9, 0x03d5, 0x03d2, 0x03ce, 0x03ca, 0x03c7, 0x03c3, + 0x03c0, 0x03bc, 0x03b9, 0x03b5, 0x03b2, 0x03ae, 0x03ab, 0x03a8, 0x03a4, 0x03a1, 0x039e, 0x039b, 0x0397, 0x0394, 0x0391, 0x038e, + 0x038b, 0x0387, 0x0384, 0x0381, 0x037e, 0x037b, 0x0378, 0x0375, 0x0372, 0x036f, 0x036c, 0x0369, 0x0366, 0x0364, 0x0361, 0x035e, + 0x035b, 0x0358, 0x0355, 0x0353, 0x0350, 0x034d, 0x034a, 0x0348, 0x0345, 0x0342, 0x0340, 0x033d, 0x033a, 0x0338, 0x0335, 0x0333, + 0x0330, 0x032e, 0x032b, 0x0329, 0x0326, 0x0324, 0x0321, 0x031f, 0x031c, 0x031a, 0x0317, 0x0315, 0x0313, 0x0310, 0x030e, 0x030c, + 0x0309, 0x0307, 0x0305, 0x0303, 0x0300, 0x02fe, 0x02fc, 0x02fa, 0x02f7, 0x02f5, 0x02f3, 0x02f1, 0x02ef, 0x02ec, 0x02ea, 0x02e8, + 0x02e6, 0x02e4, 0x02e2, 0x02e0, 0x02de, 0x02dc, 0x02da, 0x02d8, 0x02d6, 0x02d4, 0x02d2, 0x02d0, 0x02ce, 0x02cc, 0x02ca, 0x02c8, + 0x02c6, 0x02c4, 0x02c2, 0x02c0, 0x02be, 0x02bc, 0x02bb, 0x02b9, 0x02b7, 0x02b5, 0x02b3, 0x02b1, 0x02b0, 0x02ae, 0x02ac, 0x02aa, + 0x02a8, 0x02a7, 0x02a5, 0x02a3, 0x02a1, 0x02a0, 0x029e, 0x029c, 0x029b, 0x0299, 0x0297, 0x0295, 0x0294, 0x0292, 0x0291, 0x028f, + 0x028d, 0x028c, 0x028a, 0x0288, 0x0287, 0x0285, 0x0284, 0x0282, 0x0280, 0x027f, 0x027d, 0x027c, 0x027a, 0x0279, 0x0277, 0x0276, + 0x0274, 0x0273, 0x0271, 0x0270, 0x026e, 0x026d, 0x026b, 0x026a, 0x0268, 0x0267, 0x0265, 0x0264, 0x0263, 0x0261, 0x0260, 0x025e, + 0x025d, 0x025c, 0x025a, 0x0259, 0x0257, 0x0256, 0x0255, 0x0253, 0x0252, 0x0251, 0x024f, 0x024e, 0x024d, 0x024b, 0x024a, 0x0249, + 0x0247, 0x0246, 0x0245, 0x0243, 0x0242, 0x0241, 0x0240, 0x023e, 0x023d, 0x023c, 0x023b, 0x0239, 0x0238, 0x0237, 0x0236, 0x0234, + 0x0233, 0x0232, 0x0231, 0x0230, 0x022e, 0x022d, 0x022c, 0x022b, 0x022a, 0x0229, 0x0227, 0x0226, 0x0225, 0x0224, 0x0223, 0x0222, + 0x0220, 0x021f, 0x021e, 0x021d, 0x021c, 0x021b, 0x021a, 0x0219, 0x0218, 0x0216, 0x0215, 0x0214, 0x0213, 0x0212, 0x0211, 0x0210, + 0x020f, 0x020e, 0x020d, 0x020c, 0x020b, 0x020a, 0x0209, 0x0208, 0x0207, 0x0206, 0x0205, 0x0204, 0x0203, 0x0202, 0x0201, 0x0200, + 0x01ff, 0x01fe, 0x01fd, 0x01fc, 0x01fb, 0x01fa, 0x01f9, 0x01f8, 0x01f7, 0x01f6, 0x01f5, 0x01f4, 0x01f3, 0x01f2, 0x01f1, 0x01f0, + 0x01ef, 0x01ee, 0x01ed, 0x01ec, 0x01eb, 0x01ea, 0x01e9, 0x01e9, 0x01e8, 0x01e7, 0x01e6, 0x01e5, 0x01e4, 0x01e3, 0x01e2, 0x01e1, + 0x01e0, 0x01e0, 0x01df, 0x01de, 0x01dd, 0x01dc, 0x01db, 0x01da, 0x01da, 0x01d9, 0x01d8, 0x01d7, 0x01d6, 0x01d5, 0x01d4, 0x01d4, + 0x01d3, 0x01d2, 0x01d1, 0x01d0, 0x01cf, 0x01cf, 0x01ce, 0x01cd, 0x01cc, 0x01cb, 0x01cb, 0x01ca, 0x01c9, 0x01c8, 0x01c7, 0x01c7, + 0x01c6, 0x01c5, 0x01c4, 0x01c3, 0x01c3, 0x01c2, 0x01c1, 0x01c0, 0x01c0, 0x01bf, 0x01be, 0x01bd, 0x01bd, 0x01bc, 0x01bb, 0x01ba, + 0x01ba, 0x01b9, 0x01b8, 0x01b7, 0x01b7, 0x01b6, 0x01b5, 0x01b4, 0x01b4, 0x01b3, 0x01b2, 0x01b2, 0x01b1, 0x01b0, 0x01af, 0x01af, + 0x01ae, 0x01ad, 0x01ad, 0x01ac, 0x01ab, 0x01aa, 0x01aa, 0x01a9, 0x01a8, 0x01a8, 0x01a7, 0x01a6, 0x01a6, 0x01a5, 0x01a4, 0x01a4, + 0x01a3, 0x01a2, 0x01a2, 0x01a1, 0x01a0, 0x01a0, 0x019f, 0x019e, 0x019e, 0x019d, 0x019c, 0x019c, 0x019b, 0x019a, 0x019a, 0x0199, + 0x0198, 0x0198, 0x0197, 0x0197, 0x0196, 0x0195, 0x0195, 0x0194, 0x0193, 0x0193, 0x0192, 0x0192, 0x0191, 0x0190, 0x0190, 0x018f, + 0x018f, 0x018e, 0x018d, 0x018d, 0x018c, 0x018b, 0x018b, 0x018a, 0x018a, 0x0189, 0x0189, 0x0188, 0x0187, 0x0187, 0x0186, 0x0186, + 0x0185, 0x0184, 0x0184, 0x0183, 0x0183, 0x0182, 0x0182, 0x0181, 0x0180, 0x0180, 0x017f, 0x017f, 0x017e, 0x017e, 0x017d, 0x017d, + 0x017c, 0x017b, 0x017b, 0x017a, 0x017a, 0x0179, 0x0179, 0x0178, 0x0178, 0x0177, 0x0177, 0x0176, 0x0175, 0x0175, 0x0174, 0x0174, + 0x0173, 0x0173, 0x0172, 0x0172, 0x0171, 0x0171, 0x0170, 0x0170, 0x016f, 0x016f, 0x016e, 0x016e, 0x016d, 0x016d, 0x016c, 0x016c, + 0x016b, 0x016b, 0x016a, 0x016a, 0x0169, 0x0169, 0x0168, 0x0168, 0x0167, 0x0167, 0x0166, 0x0166, 0x0165, 0x0165, 0x0164, 0x0164, + 0x0163, 0x0163, 0x0162, 0x0162, 0x0161, 0x0161, 0x0160, 0x0160, 0x015f, 0x015f, 0x015e, 0x015e, 0x015d, 0x015d, 0x015d, 0x015c, + 0x015c, 0x015b, 0x015b, 0x015a, 0x015a, 0x0159, 0x0159, 0x0158, 0x0158, 0x0158, 0x0157, 0x0157, 0x0156, 0x0156 +}; +static const uint16_t DivTableNEON[255*3+1] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x1c71, 0x1af2, 0x1999, 0x1861, 0x1745, 0x1642, 0x1555, 0x147a, 0x13b1, 0x12f6, 0x1249, 0x11a7, 0x1111, 0x1084, 0x1000, + 0x0f83, 0x0f0f, 0x0ea0, 0x0e38, 0x0dd6, 0x0d79, 0x0d20, 0x0ccc, 0x0c7c, 0x0c30, 0x0be8, 0x0ba2, 0x0b60, 0x0b21, 0x0ae4, 0x0aaa, + 0x0a72, 0x0a3d, 0x0a0a, 0x09d8, 0x09a9, 0x097b, 0x094f, 0x0924, 0x08fb, 0x08d3, 0x08ad, 0x0888, 0x0864, 0x0842, 0x0820, 0x0800, + 0x07e0, 0x07c1, 0x07a4, 0x0787, 0x076b, 0x0750, 0x0736, 0x071c, 0x0703, 0x06eb, 0x06d3, 0x06bc, 0x06a6, 0x0690, 0x067b, 0x0666, + 0x0652, 0x063e, 0x062b, 0x0618, 0x0606, 0x05f4, 0x05e2, 0x05d1, 0x05c0, 0x05b0, 0x05a0, 0x0590, 0x0581, 0x0572, 0x0563, 0x0555, + 0x0547, 0x0539, 0x052b, 0x051e, 0x0511, 0x0505, 0x04f8, 0x04ec, 0x04e0, 0x04d4, 0x04c8, 0x04bd, 0x04b2, 0x04a7, 0x049c, 0x0492, + 0x0487, 0x047d, 0x0473, 0x0469, 0x0460, 0x0456, 0x044d, 0x0444, 0x043b, 0x0432, 0x0429, 0x0421, 0x0418, 0x0410, 0x0408, 0x0400, + 0x03f8, 0x03f0, 0x03e8, 0x03e0, 0x03d9, 0x03d2, 0x03ca, 0x03c3, 0x03bc, 0x03b5, 0x03ae, 0x03a8, 0x03a1, 0x039b, 0x0394, 0x038e, + 0x0387, 0x0381, 0x037b, 0x0375, 0x036f, 0x0369, 0x0364, 0x035e, 0x0358, 0x0353, 0x034d, 0x0348, 0x0342, 0x033d, 0x0338, 0x0333, + 0x032e, 0x0329, 0x0324, 0x031f, 0x031a, 0x0315, 0x0310, 0x030c, 0x0307, 0x0303, 0x02fe, 0x02fa, 0x02f5, 0x02f1, 0x02ec, 0x02e8, + 0x02e4, 0x02e0, 0x02dc, 0x02d8, 0x02d4, 0x02d0, 0x02cc, 0x02c8, 0x02c4, 0x02c0, 0x02bc, 0x02b9, 0x02b5, 0x02b1, 0x02ae, 0x02aa, + 0x02a7, 0x02a3, 0x02a0, 0x029c, 0x0299, 0x0295, 0x0292, 0x028f, 0x028c, 0x0288, 0x0285, 0x0282, 0x027f, 0x027c, 0x0279, 0x0276, + 0x0273, 0x0270, 0x026d, 0x026a, 0x0267, 0x0264, 0x0261, 0x025e, 0x025c, 0x0259, 0x0256, 0x0253, 0x0251, 0x024e, 0x024b, 0x0249, + 0x0246, 0x0243, 0x0241, 0x023e, 0x023c, 0x0239, 0x0237, 0x0234, 0x0232, 0x0230, 0x022d, 0x022b, 0x0229, 0x0226, 0x0224, 0x0222, + 0x021f, 0x021d, 0x021b, 0x0219, 0x0216, 0x0214, 0x0212, 0x0210, 0x020e, 0x020c, 0x020a, 0x0208, 0x0206, 0x0204, 0x0202, 0x0200, + 0x01fe, 0x01fc, 0x01fa, 0x01f8, 0x01f6, 0x01f4, 0x01f2, 0x01f0, 0x01ee, 0x01ec, 0x01ea, 0x01e9, 0x01e7, 0x01e5, 0x01e3, 0x01e1, + 0x01e0, 0x01de, 0x01dc, 0x01da, 0x01d9, 0x01d7, 0x01d5, 0x01d4, 0x01d2, 0x01d0, 0x01cf, 0x01cd, 0x01cb, 0x01ca, 0x01c8, 0x01c7, + 0x01c5, 0x01c3, 0x01c2, 0x01c0, 0x01bf, 0x01bd, 0x01bc, 0x01ba, 0x01b9, 0x01b7, 0x01b6, 0x01b4, 0x01b3, 0x01b2, 0x01b0, 0x01af, + 0x01ad, 0x01ac, 0x01aa, 0x01a9, 0x01a8, 0x01a6, 0x01a5, 0x01a4, 0x01a2, 0x01a1, 0x01a0, 0x019e, 0x019d, 0x019c, 0x019a, 0x0199, + 0x0198, 0x0197, 0x0195, 0x0194, 0x0193, 0x0192, 0x0190, 0x018f, 0x018e, 0x018d, 0x018b, 0x018a, 0x0189, 0x0188, 0x0187, 0x0186, + 0x0184, 0x0183, 0x0182, 0x0181, 0x0180, 0x017f, 0x017e, 0x017d, 0x017b, 0x017a, 0x0179, 0x0178, 0x0177, 0x0176, 0x0175, 0x0174, + 0x0173, 0x0172, 0x0171, 0x0170, 0x016f, 0x016e, 0x016d, 0x016c, 0x016b, 0x016a, 0x0169, 0x0168, 0x0167, 0x0166, 0x0165, 0x0164, + 0x0163, 0x0162, 0x0161, 0x0160, 0x015f, 0x015e, 0x015d, 0x015c, 0x015b, 0x015a, 0x0159, 0x0158, 0x0158, 0x0157, 0x0156, 0x0155, + 0x0154, 0x0153, 0x0152, 0x0151, 0x0150, 0x0150, 0x014f, 0x014e, 0x014d, 0x014c, 0x014b, 0x014a, 0x014a, 0x0149, 0x0148, 0x0147, + 0x0146, 0x0146, 0x0145, 0x0144, 0x0143, 0x0142, 0x0142, 0x0141, 0x0140, 0x013f, 0x013e, 0x013e, 0x013d, 0x013c, 0x013b, 0x013b, + 0x013a, 0x0139, 0x0138, 0x0138, 0x0137, 0x0136, 0x0135, 0x0135, 0x0134, 0x0133, 0x0132, 0x0132, 0x0131, 0x0130, 0x0130, 0x012f, + 0x012e, 0x012e, 0x012d, 0x012c, 0x012b, 0x012b, 0x012a, 0x0129, 0x0129, 0x0128, 0x0127, 0x0127, 0x0126, 0x0125, 0x0125, 0x0124, + 0x0123, 0x0123, 0x0122, 0x0121, 0x0121, 0x0120, 0x0120, 0x011f, 0x011e, 0x011e, 0x011d, 0x011c, 0x011c, 0x011b, 0x011b, 0x011a, + 0x0119, 0x0119, 0x0118, 0x0118, 0x0117, 0x0116, 0x0116, 0x0115, 0x0115, 0x0114, 0x0113, 0x0113, 0x0112, 0x0112, 0x0111, 0x0111, + 0x0110, 0x010f, 0x010f, 0x010e, 0x010e, 0x010d, 0x010d, 0x010c, 0x010c, 0x010b, 0x010a, 0x010a, 0x0109, 0x0109, 0x0108, 0x0108, + 0x0107, 0x0107, 0x0106, 0x0106, 0x0105, 0x0105, 0x0104, 0x0104, 0x0103, 0x0103, 0x0102, 0x0102, 0x0101, 0x0101, 0x0100, 0x0100, + 0x00ff, 0x00ff, 0x00fe, 0x00fe, 0x00fd, 0x00fd, 0x00fc, 0x00fc, 0x00fb, 0x00fb, 0x00fa, 0x00fa, 0x00f9, 0x00f9, 0x00f8, 0x00f8, + 0x00f7, 0x00f7, 0x00f6, 0x00f6, 0x00f5, 0x00f5, 0x00f4, 0x00f4, 0x00f4, 0x00f3, 0x00f3, 0x00f2, 0x00f2, 0x00f1, 0x00f1, 0x00f0, + 0x00f0, 0x00f0, 0x00ef, 0x00ef, 0x00ee, 0x00ee, 0x00ed, 0x00ed, 0x00ed, 0x00ec, 0x00ec, 0x00eb, 0x00eb, 0x00ea, 0x00ea, 0x00ea, + 0x00e9, 0x00e9, 0x00e8, 0x00e8, 0x00e7, 0x00e7, 0x00e7, 0x00e6, 0x00e6, 0x00e5, 0x00e5, 0x00e5, 0x00e4, 0x00e4, 0x00e3, 0x00e3, + 0x00e3, 0x00e2, 0x00e2, 0x00e1, 0x00e1, 0x00e1, 0x00e0, 0x00e0, 0x00e0, 0x00df, 0x00df, 0x00de, 0x00de, 0x00de, 0x00dd, 0x00dd, + 0x00dd, 0x00dc, 0x00dc, 0x00db, 0x00db, 0x00db, 0x00da, 0x00da, 0x00da, 0x00d9, 0x00d9, 0x00d9, 0x00d8, 0x00d8, 0x00d7, 0x00d7, + 0x00d7, 0x00d6, 0x00d6, 0x00d6, 0x00d5, 0x00d5, 0x00d5, 0x00d4, 0x00d4, 0x00d4, 0x00d3, 0x00d3, 0x00d3, 0x00d2, 0x00d2, 0x00d2, + 0x00d1, 0x00d1, 0x00d1, 0x00d0, 0x00d0, 0x00d0, 0x00cf, 0x00cf, 0x00cf, 0x00ce, 0x00ce, 0x00ce, 0x00cd, 0x00cd, 0x00cd, 0x00cc, + 0x00cc, 0x00cc, 0x00cb, 0x00cb, 0x00cb, 0x00ca, 0x00ca, 0x00ca, 0x00c9, 0x00c9, 0x00c9, 0x00c9, 0x00c8, 0x00c8, 0x00c8, 0x00c7, + 0x00c7, 0x00c7, 0x00c6, 0x00c6, 0x00c6, 0x00c5, 0x00c5, 0x00c5, 0x00c5, 0x00c4, 0x00c4, 0x00c4, 0x00c3, 0x00c3, 0x00c3, 0x00c3, + 0x00c2, 0x00c2, 0x00c2, 0x00c1, 0x00c1, 0x00c1, 0x00c1, 0x00c0, 0x00c0, 0x00c0, 0x00bf, 0x00bf, 0x00bf, 0x00bf, 0x00be, 0x00be, + 0x00be, 0x00bd, 0x00bd, 0x00bd, 0x00bd, 0x00bc, 0x00bc, 0x00bc, 0x00bc, 0x00bb, 0x00bb, 0x00bb, 0x00ba, 0x00ba, 0x00ba, 0x00ba, + 0x00b9, 0x00b9, 0x00b9, 0x00b9, 0x00b8, 0x00b8, 0x00b8, 0x00b8, 0x00b7, 0x00b7, 0x00b7, 0x00b7, 0x00b6, 0x00b6, 0x00b6, 0x00b6, + 0x00b5, 0x00b5, 0x00b5, 0x00b5, 0x00b4, 0x00b4, 0x00b4, 0x00b4, 0x00b3, 0x00b3, 0x00b3, 0x00b3, 0x00b2, 0x00b2, 0x00b2, 0x00b2, + 0x00b1, 0x00b1, 0x00b1, 0x00b1, 0x00b0, 0x00b0, 0x00b0, 0x00b0, 0x00af, 0x00af, 0x00af, 0x00af, 0x00ae, 0x00ae, 0x00ae, 0x00ae, + 0x00ae, 0x00ad, 0x00ad, 0x00ad, 0x00ad, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ab, 0x00ab, 0x00ab, 0x00ab, +}; + +static const uint16_t DivTableAlpha[256] = { + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xe38e, 0xcccc, 0xba2e, 0xaaaa, 0x9d89, 0x9249, 0x8888, 0x8000, + 0x7878, 0x71c7, 0x6bca, 0x6666, 0x6186, 0x5d17, 0x590b, 0x5555, 0x51eb, 0x4ec4, 0x4bda, 0x4924, 0x469e, 0x4444, 0x4210, 0x4000, + 0x3e0f, 0x3c3c, 0x3a83, 0x38e3, 0x3759, 0x35e5, 0x3483, 0x3333, 0x31f3, 0x30c3, 0x2fa0, 0x2e8b, 0x2d82, 0x2c85, 0x2b93, 0x2aaa, + 0x29cb, 0x28f5, 0x2828, 0x2762, 0x26a4, 0x25ed, 0x253c, 0x2492, 0x23ee, 0x234f, 0x22b6, 0x2222, 0x2192, 0x2108, 0x2082, 0x2000, + 0x1f81, 0x1f07, 0x1e91, 0x1e1e, 0x1dae, 0x1d41, 0x1cd8, 0x1c71, 0x1c0e, 0x1bac, 0x1b4e, 0x1af2, 0x1a98, 0x1a41, 0x19ec, 0x1999, + 0x1948, 0x18f9, 0x18ac, 0x1861, 0x1818, 0x17d0, 0x178a, 0x1745, 0x1702, 0x16c1, 0x1681, 0x1642, 0x1605, 0x15c9, 0x158e, 0x1555, + 0x151d, 0x14e5, 0x14af, 0x147a, 0x1446, 0x1414, 0x13e2, 0x13b1, 0x1381, 0x1352, 0x1323, 0x12f6, 0x12c9, 0x129e, 0x1273, 0x1249, + 0x121f, 0x11f7, 0x11cf, 0x11a7, 0x1181, 0x115b, 0x1135, 0x1111, 0x10ec, 0x10c9, 0x10a6, 0x1084, 0x1062, 0x1041, 0x1020, 0x1000, + 0x0fe0, 0x0fc0, 0x0fa2, 0x0f83, 0x0f66, 0x0f48, 0x0f2b, 0x0f0f, 0x0ef2, 0x0ed7, 0x0ebb, 0x0ea0, 0x0e86, 0x0e6c, 0x0e52, 0x0e38, + 0x0e1f, 0x0e07, 0x0dee, 0x0dd6, 0x0dbe, 0x0da7, 0x0d90, 0x0d79, 0x0d62, 0x0d4c, 0x0d36, 0x0d20, 0x0d0b, 0x0cf6, 0x0ce1, 0x0ccc, + 0x0cb8, 0x0ca4, 0x0c90, 0x0c7c, 0x0c69, 0x0c56, 0x0c43, 0x0c30, 0x0c1e, 0x0c0c, 0x0bfa, 0x0be8, 0x0bd6, 0x0bc5, 0x0bb3, 0x0ba2, + 0x0b92, 0x0b81, 0x0b70, 0x0b60, 0x0b50, 0x0b40, 0x0b30, 0x0b21, 0x0b11, 0x0b02, 0x0af3, 0x0ae4, 0x0ad6, 0x0ac7, 0x0ab8, 0x0aaa, + 0x0a9c, 0x0a8e, 0x0a80, 0x0a72, 0x0a65, 0x0a57, 0x0a4a, 0x0a3d, 0x0a30, 0x0a23, 0x0a16, 0x0a0a, 0x09fd, 0x09f1, 0x09e4, 0x09d8, + 0x09cc, 0x09c0, 0x09b4, 0x09a9, 0x099d, 0x0991, 0x0986, 0x097b, 0x0970, 0x0964, 0x095a, 0x094f, 0x0944, 0x0939, 0x092f, 0x0924, + 0x091a, 0x090f, 0x0905, 0x08fb, 0x08f1, 0x08e7, 0x08dd, 0x08d3, 0x08ca, 0x08c0, 0x08b7, 0x08ad, 0x08a4, 0x089a, 0x0891, 0x0888, + 0x087f, 0x0876, 0x086d, 0x0864, 0x085b, 0x0853, 0x084a, 0x0842, 0x0839, 0x0831, 0x0828, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800, +}; + +static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src ) +{ +#ifdef __SSE4_1__ + __m128i px0 = _mm_loadu_si128(((__m128i*)src) + 0); + __m128i px1 = _mm_loadu_si128(((__m128i*)src) + 1); + __m128i px2 = _mm_loadu_si128(((__m128i*)src) + 2); + __m128i px3 = _mm_loadu_si128(((__m128i*)src) + 3); + + __m128i smask = _mm_set1_epi32( 0xF8FCF8 ); + __m128i sd0 = _mm_and_si128( px0, smask ); + __m128i sd1 = _mm_and_si128( px1, smask ); + __m128i sd2 = _mm_and_si128( px2, smask ); + __m128i sd3 = _mm_and_si128( px3, smask ); + + __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0)); + + __m128i sc0 = _mm_cmpeq_epi8(sd0, sc); + __m128i sc1 = _mm_cmpeq_epi8(sd1, sc); + __m128i sc2 = _mm_cmpeq_epi8(sd2, sc); + __m128i sc3 = _mm_cmpeq_epi8(sd3, sc); + + __m128i sm0 = _mm_and_si128(sc0, sc1); + __m128i sm1 = _mm_and_si128(sc2, sc3); + __m128i sm = _mm_and_si128(sm0, sm1); + + if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) ) + { + uint32_t c; + memcpy( &c, src, 4 ); + return uint64_t( to565( c ) ) << 16; + } + + __m128i min0 = _mm_min_epu8( px0, px1 ); + __m128i min1 = _mm_min_epu8( px2, px3 ); + __m128i min2 = _mm_min_epu8( min0, min1 ); + + __m128i max0 = _mm_max_epu8( px0, px1 ); + __m128i max1 = _mm_max_epu8( px2, px3 ); + __m128i max2 = _mm_max_epu8( max0, max1 ); + + __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m128i min4 = _mm_min_epu8( min2, min3 ); + __m128i max4 = _mm_max_epu8( max2, max3 ); + + __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i rmin = _mm_min_epu8( min4, min5 ); + __m128i rmax = _mm_max_epu8( max4, max5 ); + + __m128i range1 = _mm_subs_epu8( rmax, rmin ); + __m128i range2 = _mm_sad_epu8( rmax, rmin ); + + uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1; + __m128i range = _mm_set1_epi16( DivTable[vrange] ); + + __m128i inset1 = _mm_srli_epi16( range1, 4 ); + __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) ); + __m128i min = _mm_adds_epu8( rmin, inset ); + __m128i max = _mm_subs_epu8( rmax, inset ); + + __m128i c0 = _mm_subs_epu8( px0, rmin ); + __m128i c1 = _mm_subs_epu8( px1, rmin ); + __m128i c2 = _mm_subs_epu8( px2, rmin ); + __m128i c3 = _mm_subs_epu8( px3, rmin ); + + __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) ); + __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) ); + __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) ); + __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) ); + + __m128i s0 = _mm_hadd_epi16( is0, is1 ); + __m128i s1 = _mm_hadd_epi16( is2, is3 ); + + __m128i m0 = _mm_mulhi_epu16( s0, range ); + __m128i m1 = _mm_mulhi_epu16( s1, range ); + + __m128i p0 = _mm_packus_epi16( m0, m1 ); + + __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) ); + __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 ); + __m128i p3 = _mm_or_si128( p1, p2 ); + __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) ); + + uint32_t vmin = _mm_cvtsi128_si32( min ); + uint32_t vmax = _mm_cvtsi128_si32( max ); + uint32_t vp = _mm_cvtsi128_si32( p ); + + return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) ); +#elif defined __ARM_NEON +# ifdef __aarch64__ + uint8x16x4_t px = vld4q_u8( src ); + + uint8x16_t lr = px.val[0]; + uint8x16_t lg = px.val[1]; + uint8x16_t lb = px.val[2]; + + uint8_t rmaxr = vmaxvq_u8( lr ); + uint8_t rmaxg = vmaxvq_u8( lg ); + uint8_t rmaxb = vmaxvq_u8( lb ); + + uint8_t rminr = vminvq_u8( lr ); + uint8_t rming = vminvq_u8( lg ); + uint8_t rminb = vminvq_u8( lb ); + + int rr = rmaxr - rminr; + int rg = rmaxg - rming; + int rb = rmaxb - rminb; + + int vrange1 = rr + rg + rb; + uint16_t vrange2 = DivTableNEON[vrange1]; + + uint8_t insetr = rr >> 4; + uint8_t insetg = rg >> 4; + uint8_t insetb = rb >> 4; + + uint8_t minr = rminr + insetr; + uint8_t ming = rming + insetg; + uint8_t minb = rminb + insetb; + + uint8_t maxr = rmaxr - insetr; + uint8_t maxg = rmaxg - insetg; + uint8_t maxb = rmaxb - insetb; + + uint8x16_t cr = vsubq_u8( lr, vdupq_n_u8( rminr ) ); + uint8x16_t cg = vsubq_u8( lg, vdupq_n_u8( rming ) ); + uint8x16_t cb = vsubq_u8( lb, vdupq_n_u8( rminb ) ); + + uint16x8_t is0l = vaddl_u8( vget_low_u8( cr ), vget_low_u8( cg ) ); + uint16x8_t is0h = vaddl_u8( vget_high_u8( cr ), vget_high_u8( cg ) ); + uint16x8_t is1l = vaddw_u8( is0l, vget_low_u8( cb ) ); + uint16x8_t is1h = vaddw_u8( is0h, vget_high_u8( cb ) ); + + int16x8_t range = vdupq_n_s16( vrange2 ); + uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1l ), range ) ); + uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1h ), range ) ); + + uint8x8_t p00 = vmovn_u16( m0 ); + uint8x8_t p01 = vmovn_u16( m1 ); + uint8x16_t p0 = vcombine_u8( p00, p01 ); + + uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) ); + uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) ); + uint32x4_t p3 = vaddq_u32( p1, p2 ); + + uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) ); + uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) ); + + uint32_t vp; + vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 ); + + return uint64_t( ( uint64_t( to565( minr, ming, minb ) ) << 16 ) | to565( maxr, maxg, maxb ) | ( uint64_t( vp ) << 32 ) ); +# else + uint32x4_t px0 = vld1q_u32( (uint32_t*)src ); + uint32x4_t px1 = vld1q_u32( (uint32_t*)src + 4 ); + uint32x4_t px2 = vld1q_u32( (uint32_t*)src + 8 ); + uint32x4_t px3 = vld1q_u32( (uint32_t*)src + 12 ); + + uint32x4_t smask = vdupq_n_u32( 0xF8FCF8 ); + uint32x4_t sd0 = vandq_u32( smask, px0 ); + uint32x4_t sd1 = vandq_u32( smask, px1 ); + uint32x4_t sd2 = vandq_u32( smask, px2 ); + uint32x4_t sd3 = vandq_u32( smask, px3 ); + + uint32x4_t sc = vdupq_n_u32( sd0[0] ); + + uint32x4_t sc0 = vceqq_u32( sd0, sc ); + uint32x4_t sc1 = vceqq_u32( sd1, sc ); + uint32x4_t sc2 = vceqq_u32( sd2, sc ); + uint32x4_t sc3 = vceqq_u32( sd3, sc ); + + uint32x4_t sm0 = vandq_u32( sc0, sc1 ); + uint32x4_t sm1 = vandq_u32( sc2, sc3 ); + int64x2_t sm = vreinterpretq_s64_u32( vandq_u32( sm0, sm1 ) ); + + if( sm[0] == -1 && sm[1] == -1 ) + { + return uint64_t( to565( src[0], src[1], src[2] ) ) << 16; + } + + uint32x4_t mask = vdupq_n_u32( 0xFFFFFF ); + uint8x16_t l0 = vreinterpretq_u8_u32( vandq_u32( mask, px0 ) ); + uint8x16_t l1 = vreinterpretq_u8_u32( vandq_u32( mask, px1 ) ); + uint8x16_t l2 = vreinterpretq_u8_u32( vandq_u32( mask, px2 ) ); + uint8x16_t l3 = vreinterpretq_u8_u32( vandq_u32( mask, px3 ) ); + + uint8x16_t min0 = vminq_u8( l0, l1 ); + uint8x16_t min1 = vminq_u8( l2, l3 ); + uint8x16_t min2 = vminq_u8( min0, min1 ); + + uint8x16_t max0 = vmaxq_u8( l0, l1 ); + uint8x16_t max1 = vmaxq_u8( l2, l3 ); + uint8x16_t max2 = vmaxq_u8( max0, max1 ); + + uint8x16_t min3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( min2 ) ) ); + uint8x16_t max3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( max2 ) ) ); + + uint8x16_t min4 = vminq_u8( min2, min3 ); + uint8x16_t max4 = vmaxq_u8( max2, max3 ); + + uint8x16_t min5 = vcombine_u8( vget_high_u8( min4 ), vget_low_u8( min4 ) ); + uint8x16_t max5 = vcombine_u8( vget_high_u8( max4 ), vget_low_u8( max4 ) ); + + uint8x16_t rmin = vminq_u8( min4, min5 ); + uint8x16_t rmax = vmaxq_u8( max4, max5 ); + + uint8x16_t range1 = vsubq_u8( rmax, rmin ); + uint8x8_t range2 = vget_low_u8( range1 ); + uint8x8x2_t range3 = vzip_u8( range2, vdup_n_u8( 0 ) ); + uint16x4_t range4 = vreinterpret_u16_u8( range3.val[0] ); + + uint16_t vrange1; + uint16x4_t range5 = vpadd_u16( range4, range4 ); + uint16x4_t range6 = vpadd_u16( range5, range5 ); + vst1_lane_u16( &vrange1, range6, 0 ); + + uint32_t vrange2 = ( 2 << 16 ) / uint32_t( vrange1 + 1 ); + uint16x8_t range = vdupq_n_u16( vrange2 ); + + uint8x16_t inset = vshrq_n_u8( range1, 4 ); + uint8x16_t min = vaddq_u8( rmin, inset ); + uint8x16_t max = vsubq_u8( rmax, inset ); + + uint8x16_t c0 = vsubq_u8( l0, rmin ); + uint8x16_t c1 = vsubq_u8( l1, rmin ); + uint8x16_t c2 = vsubq_u8( l2, rmin ); + uint8x16_t c3 = vsubq_u8( l3, rmin ); + + uint16x8_t is0 = vpaddlq_u8( c0 ); + uint16x8_t is1 = vpaddlq_u8( c1 ); + uint16x8_t is2 = vpaddlq_u8( c2 ); + uint16x8_t is3 = vpaddlq_u8( c3 ); + + uint16x4_t is4 = vpadd_u16( vget_low_u16( is0 ), vget_high_u16( is0 ) ); + uint16x4_t is5 = vpadd_u16( vget_low_u16( is1 ), vget_high_u16( is1 ) ); + uint16x4_t is6 = vpadd_u16( vget_low_u16( is2 ), vget_high_u16( is2 ) ); + uint16x4_t is7 = vpadd_u16( vget_low_u16( is3 ), vget_high_u16( is3 ) ); + + uint16x8_t s0 = vcombine_u16( is4, is5 ); + uint16x8_t s1 = vcombine_u16( is6, is7 ); + + uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s0 ), vreinterpretq_s16_u16( range ) ) ); + uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s1 ), vreinterpretq_s16_u16( range ) ) ); + + uint8x8_t p00 = vmovn_u16( m0 ); + uint8x8_t p01 = vmovn_u16( m1 ); + uint8x16_t p0 = vcombine_u8( p00, p01 ); + + uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) ); + uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) ); + uint32x4_t p3 = vaddq_u32( p1, p2 ); + + uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) ); + uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) ); + + uint32_t vmin, vmax, vp; + vst1q_lane_u32( &vmin, vreinterpretq_u32_u8( min ), 0 ); + vst1q_lane_u32( &vmax, vreinterpretq_u32_u8( max ), 0 ); + vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 ); + + return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) ); +# endif +#else + uint32_t ref; + memcpy( &ref, src, 4 ); + uint32_t refMask = ref & 0xF8FCF8; + auto stmp = src + 4; + for( int i=1; i<16; i++ ) + { + uint32_t px; + memcpy( &px, stmp, 4 ); + if( ( px & 0xF8FCF8 ) != refMask ) break; + stmp += 4; + } + if( stmp == src + 64 ) + { + return uint64_t( to565( ref ) ) << 16; + } + + uint8_t min[3] = { src[0], src[1], src[2] }; + uint8_t max[3] = { src[0], src[1], src[2] }; + auto tmp = src + 4; + for( int i=1; i<16; i++ ) + { + for( int j=0; j<3; j++ ) + { + if( tmp[j] < min[j] ) min[j] = tmp[j]; + else if( tmp[j] > max[j] ) max[j] = tmp[j]; + } + tmp += 4; + } + + const uint32_t range = DivTable[max[0] - min[0] + max[1] - min[1] + max[2] - min[2]]; + const uint32_t rmin = min[0] + min[1] + min[2]; + for( int i=0; i<3; i++ ) + { + const uint8_t inset = ( max[i] - min[i] ) >> 4; + min[i] += inset; + max[i] -= inset; + } + + uint32_t data = 0; + for( int i=0; i<16; i++ ) + { + const uint32_t c = src[0] + src[1] + src[2] - rmin; + const uint8_t idx = ( c * range ) >> 16; + data |= idx << (i*2); + src += 4; + } + + return uint64_t( ( uint64_t( to565( min[0], min[1], min[2] ) ) << 16 ) | to565( max[0], max[1], max[2] ) | ( uint64_t( data ) << 32 ) ); +#endif +} + +#ifdef __AVX2__ +static etcpak_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst ) +{ + __m256i px0 = _mm256_loadu_si256(((__m256i*)src) + 0); + __m256i px1 = _mm256_loadu_si256(((__m256i*)src) + 1); + __m256i px2 = _mm256_loadu_si256(((__m256i*)src) + 2); + __m256i px3 = _mm256_loadu_si256(((__m256i*)src) + 3); + + __m256i smask = _mm256_set1_epi32( 0xF8FCF8 ); + __m256i sd0 = _mm256_and_si256( px0, smask ); + __m256i sd1 = _mm256_and_si256( px1, smask ); + __m256i sd2 = _mm256_and_si256( px2, smask ); + __m256i sd3 = _mm256_and_si256( px3, smask ); + + __m256i sc = _mm256_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0)); + + __m256i sc0 = _mm256_cmpeq_epi8(sd0, sc); + __m256i sc1 = _mm256_cmpeq_epi8(sd1, sc); + __m256i sc2 = _mm256_cmpeq_epi8(sd2, sc); + __m256i sc3 = _mm256_cmpeq_epi8(sd3, sc); + + __m256i sm0 = _mm256_and_si256(sc0, sc1); + __m256i sm1 = _mm256_and_si256(sc2, sc3); + __m256i sm = _mm256_and_si256(sm0, sm1); + + const int64_t solid0 = 1 - _mm_testc_si128( _mm256_castsi256_si128( sm ), _mm_set1_epi32( -1 ) ); + const int64_t solid1 = 1 - _mm_testc_si128( _mm256_extracti128_si256( sm, 1 ), _mm_set1_epi32( -1 ) ); + + if( solid0 + solid1 == 0 ) + { + const auto c0 = uint64_t( to565( src[0], src[1], src[2] ) ); + const auto c1 = uint64_t( to565( src[16], src[17], src[18] ) ); + memcpy( dst, &c0, 8 ); + memcpy( dst+8, &c1, 8 ); + dst += 16; + return; + } + + __m256i min0 = _mm256_min_epu8( px0, px1 ); + __m256i min1 = _mm256_min_epu8( px2, px3 ); + __m256i min2 = _mm256_min_epu8( min0, min1 ); + + __m256i max0 = _mm256_max_epu8( px0, px1 ); + __m256i max1 = _mm256_max_epu8( px2, px3 ); + __m256i max2 = _mm256_max_epu8( max0, max1 ); + + __m256i min3 = _mm256_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m256i max3 = _mm256_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m256i min4 = _mm256_min_epu8( min2, min3 ); + __m256i max4 = _mm256_max_epu8( max2, max3 ); + + __m256i min5 = _mm256_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m256i max5 = _mm256_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m256i rmin = _mm256_min_epu8( min4, min5 ); + __m256i rmax = _mm256_max_epu8( max4, max5 ); + + __m256i range1 = _mm256_subs_epu8( rmax, rmin ); + __m256i range2 = _mm256_sad_epu8( rmax, rmin ); + + uint16_t vrange0 = DivTable[_mm256_cvtsi256_si32( range2 ) >> 1]; + uint16_t vrange1 = DivTable[_mm256_extract_epi16( range2, 8 ) >> 1]; + __m256i range00 = _mm256_set1_epi16( vrange0 ); + __m256i range = _mm256_inserti128_si256( range00, _mm_set1_epi16( vrange1 ), 1 ); + + __m256i inset1 = _mm256_srli_epi16( range1, 4 ); + __m256i inset = _mm256_and_si256( inset1, _mm256_set1_epi8( 0xF ) ); + __m256i min = _mm256_adds_epu8( rmin, inset ); + __m256i max = _mm256_subs_epu8( rmax, inset ); + + __m256i c0 = _mm256_subs_epu8( px0, rmin ); + __m256i c1 = _mm256_subs_epu8( px1, rmin ); + __m256i c2 = _mm256_subs_epu8( px2, rmin ); + __m256i c3 = _mm256_subs_epu8( px3, rmin ); + + __m256i is0 = _mm256_maddubs_epi16( c0, _mm256_set1_epi8( 1 ) ); + __m256i is1 = _mm256_maddubs_epi16( c1, _mm256_set1_epi8( 1 ) ); + __m256i is2 = _mm256_maddubs_epi16( c2, _mm256_set1_epi8( 1 ) ); + __m256i is3 = _mm256_maddubs_epi16( c3, _mm256_set1_epi8( 1 ) ); + + __m256i s0 = _mm256_hadd_epi16( is0, is1 ); + __m256i s1 = _mm256_hadd_epi16( is2, is3 ); + + __m256i m0 = _mm256_mulhi_epu16( s0, range ); + __m256i m1 = _mm256_mulhi_epu16( s1, range ); + + __m256i p0 = _mm256_packus_epi16( m0, m1 ); + + __m256i p1 = _mm256_or_si256( _mm256_srai_epi32( p0, 6 ), _mm256_srai_epi32( p0, 12 ) ); + __m256i p2 = _mm256_or_si256( _mm256_srai_epi32( p0, 18 ), p0 ); + __m256i p3 = _mm256_or_si256( p1, p2 ); + __m256i p =_mm256_shuffle_epi8( p3, _mm256_set1_epi32( 0x0C080400 ) ); + + __m256i mm0 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), min ); + __m256i mm1 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), max ); + __m256i mm2 = _mm256_unpacklo_epi64( mm1, mm0 ); + __m256i mmr = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 11 ), 11 ); + __m256i mmg = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 26 ), 5 ); + __m256i mmb = _mm256_srli_epi64( _mm256_slli_epi64( mm2, 16 ), 59 ); + __m256i mm3 = _mm256_or_si256( mmr, mmg ); + __m256i mm4 = _mm256_or_si256( mm3, mmb ); + __m256i mm5 = _mm256_shuffle_epi8( mm4, _mm256_set1_epi32( 0x09080100 ) ); + + __m256i d0 = _mm256_unpacklo_epi32( mm5, p ); + __m256i d1 = _mm256_permute4x64_epi64( d0, _MM_SHUFFLE( 3, 2, 2, 0 ) ); + __m128i d2 = _mm256_castsi256_si128( d1 ); + + __m128i mask = _mm_set_epi64x( 0xFFFF0000 | -solid1, 0xFFFF0000 | -solid0 ); + __m128i d3 = _mm_and_si128( d2, mask ); + _mm_storeu_si128( (__m128i*)dst, d3 ); + + for( int j=4; j<8; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]]; + for( int j=12; j<16; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]]; + + dst += 16; +} +#endif + +static const uint8_t AlphaIndexTable[8] = { 1, 7, 6, 5, 4, 3, 2, 0 }; + +static etcpak_force_inline uint64_t ProcessAlpha( const uint8_t* src ) +{ + uint8_t solid8 = *src; + uint16_t solid16 = uint16_t( solid8 ) | ( uint16_t( solid8 ) << 8 ); + uint32_t solid32 = uint32_t( solid16 ) | ( uint32_t( solid16 ) << 16 ); + uint64_t solid64 = uint64_t( solid32 ) | ( uint64_t( solid32 ) << 32 ); + if( memcmp( src, &solid64, 8 ) == 0 && memcmp( src+8, &solid64, 8 ) == 0 ) + { + return solid8; + } + + uint8_t min = src[0]; + uint8_t max = min; + for( int i=1; i<16; i++ ) + { + const auto v = src[i]; + if( v > max ) max = v; + else if( v < min ) min = v; + } + + uint32_t range = ( 8 << 13 ) / ( 1 + max - min ); + uint64_t data = 0; + for( int i=0; i<16; i++ ) + { + uint8_t a = src[i] - min; + uint64_t idx = AlphaIndexTable[( a * range ) >> 13]; + data |= idx << (i*3); + } + + return max | ( min << 8 ) | ( data << 16 ); +} + +#ifdef __SSE4_1__ +static etcpak_force_inline uint64_t ProcessRGB_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 ) +{ + __m128i smask = _mm_set1_epi32( 0xF8FCF8 ); + __m128i sd0 = _mm_and_si128( px0, smask ); + __m128i sd1 = _mm_and_si128( px1, smask ); + __m128i sd2 = _mm_and_si128( px2, smask ); + __m128i sd3 = _mm_and_si128( px3, smask ); + + __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0)); + + __m128i sc0 = _mm_cmpeq_epi8(sd0, sc); + __m128i sc1 = _mm_cmpeq_epi8(sd1, sc); + __m128i sc2 = _mm_cmpeq_epi8(sd2, sc); + __m128i sc3 = _mm_cmpeq_epi8(sd3, sc); + + __m128i sm0 = _mm_and_si128(sc0, sc1); + __m128i sm1 = _mm_and_si128(sc2, sc3); + __m128i sm = _mm_and_si128(sm0, sm1); + + if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) ) + { + return uint64_t( to565( _mm_cvtsi128_si32( px0 ) ) ) << 16; + } + + px0 = _mm_and_si128( px0, _mm_set1_epi32( 0xFFFFFF ) ); + px1 = _mm_and_si128( px1, _mm_set1_epi32( 0xFFFFFF ) ); + px2 = _mm_and_si128( px2, _mm_set1_epi32( 0xFFFFFF ) ); + px3 = _mm_and_si128( px3, _mm_set1_epi32( 0xFFFFFF ) ); + + __m128i min0 = _mm_min_epu8( px0, px1 ); + __m128i min1 = _mm_min_epu8( px2, px3 ); + __m128i min2 = _mm_min_epu8( min0, min1 ); + + __m128i max0 = _mm_max_epu8( px0, px1 ); + __m128i max1 = _mm_max_epu8( px2, px3 ); + __m128i max2 = _mm_max_epu8( max0, max1 ); + + __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m128i min4 = _mm_min_epu8( min2, min3 ); + __m128i max4 = _mm_max_epu8( max2, max3 ); + + __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i rmin = _mm_min_epu8( min4, min5 ); + __m128i rmax = _mm_max_epu8( max4, max5 ); + + __m128i range1 = _mm_subs_epu8( rmax, rmin ); + __m128i range2 = _mm_sad_epu8( rmax, rmin ); + + uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1; + __m128i range = _mm_set1_epi16( DivTable[vrange] ); + + __m128i inset1 = _mm_srli_epi16( range1, 4 ); + __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) ); + __m128i min = _mm_adds_epu8( rmin, inset ); + __m128i max = _mm_subs_epu8( rmax, inset ); + + __m128i c0 = _mm_subs_epu8( px0, rmin ); + __m128i c1 = _mm_subs_epu8( px1, rmin ); + __m128i c2 = _mm_subs_epu8( px2, rmin ); + __m128i c3 = _mm_subs_epu8( px3, rmin ); + + __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) ); + __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) ); + __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) ); + __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) ); + + __m128i s0 = _mm_hadd_epi16( is0, is1 ); + __m128i s1 = _mm_hadd_epi16( is2, is3 ); + + __m128i m0 = _mm_mulhi_epu16( s0, range ); + __m128i m1 = _mm_mulhi_epu16( s1, range ); + + __m128i p0 = _mm_packus_epi16( m0, m1 ); + + __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) ); + __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 ); + __m128i p3 = _mm_or_si128( p1, p2 ); + __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) ); + + uint32_t vmin = _mm_cvtsi128_si32( min ); + uint32_t vmax = _mm_cvtsi128_si32( max ); + uint32_t vp = _mm_cvtsi128_si32( p ); + + return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) ); +} + +static etcpak_force_inline uint64_t ProcessAlpha_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 ) +{ + __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 ); + + __m128i m0 = _mm_shuffle_epi8( px0, mask ); + __m128i m1 = _mm_shuffle_epi8( px1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) ); + __m128i m2 = _mm_shuffle_epi8( px2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) ); + __m128i m3 = _mm_shuffle_epi8( px3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) ); + __m128i m4 = _mm_or_si128( m0, m1 ); + __m128i m5 = _mm_or_si128( m2, m3 ); + __m128i a = _mm_or_si128( m4, m5 ); + + __m128i solidCmp = _mm_shuffle_epi8( a, _mm_setzero_si128() ); + __m128i cmpRes = _mm_cmpeq_epi8( a, solidCmp ); + if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) ) + { + return _mm_cvtsi128_si32( a ) & 0xFF; + } + + __m128i a1 = _mm_shuffle_epi32( a, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m128i max1 = _mm_max_epu8( a, a1 ); + __m128i min1 = _mm_min_epu8( a, a1 ); + __m128i amax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i amin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i max2 = _mm_max_epu8( max1, amax2 ); + __m128i min2 = _mm_min_epu8( min1, amin2 ); + __m128i amax3 = _mm_alignr_epi8( max2, max2, 2 ); + __m128i amin3 = _mm_alignr_epi8( min2, min2, 2 ); + __m128i max3 = _mm_max_epu8( max2, amax3 ); + __m128i min3 = _mm_min_epu8( min2, amin3 ); + __m128i amax4 = _mm_alignr_epi8( max3, max3, 1 ); + __m128i amin4 = _mm_alignr_epi8( min3, min3, 1 ); + __m128i max = _mm_max_epu8( max3, amax4 ); + __m128i min = _mm_min_epu8( min3, amin4 ); + __m128i minmax = _mm_unpacklo_epi8( max, min ); + + __m128i r = _mm_sub_epi8( max, min ); + int range = _mm_cvtsi128_si32( r ) & 0xFF; + __m128i rv = _mm_set1_epi16( DivTableAlpha[range] ); + + __m128i v = _mm_sub_epi8( a, min ); + + __m128i lo16 = _mm_unpacklo_epi8( v, _mm_setzero_si128() ); + __m128i hi16 = _mm_unpackhi_epi8( v, _mm_setzero_si128() ); + + __m128i lomul = _mm_mulhi_epu16( lo16, rv ); + __m128i himul = _mm_mulhi_epu16( hi16, rv ); + + __m128i p0 = _mm_packus_epi16( lomul, himul ); + __m128i p1 = _mm_or_si128( _mm_and_si128( p0, _mm_set1_epi16( 0x3F ) ), _mm_srai_epi16( _mm_and_si128( p0, _mm_set1_epi16( 0x3F00 ) ), 5 ) ); + __m128i p2 = _mm_packus_epi16( p1, p1 ); + + uint64_t pi = _mm_cvtsi128_si64( p2 ); + uint64_t data = 0; + for( int i=0; i<8; i++ ) + { + uint64_t idx = AlphaIndexTable_SSE[(pi>>(i*8)) & 0x3F]; + data |= idx << (i*6); + } + return (uint64_t)(uint16_t)_mm_cvtsi128_si32( minmax ) | ( data << 16 ); +} +#endif + +void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ +#ifdef __AVX2__ + if( width%8 == 0 ) + { + blocks /= 2; + uint32_t buf[8*4]; + int i = 0; + char* dst8 = (char*)dst; + + do + { + auto tmp = (char*)buf; + memcpy( tmp, src + width * 0, 8*4 ); + memcpy( tmp + 8*4, src + width * 1, 8*4 ); + memcpy( tmp + 16*4, src + width * 2, 8*4 ); + memcpy( tmp + 24*4, src + width * 3, 8*4 ); + src += 8; + if( ++i == width/8 ) + { + src += width * 3; + i = 0; + } + + ProcessRGB_AVX( (uint8_t*)buf, dst8 ); + } + while( --blocks ); + } + else +#endif + { + uint32_t buf[4*4]; + int i = 0; + + auto ptr = dst; + do + { + auto tmp = (char*)buf; + memcpy( tmp, src + width * 0, 4*4 ); + memcpy( tmp + 4*4, src + width * 1, 4*4 ); + memcpy( tmp + 8*4, src + width * 2, 4*4 ); + memcpy( tmp + 12*4, src + width * 3, 4*4 ); + src += 4; + if( ++i == width/4 ) + { + src += width * 3; + i = 0; + } + + const auto c = ProcessRGB( (uint8_t*)buf ); + uint8_t fix[8]; + memcpy( fix, &c, 8 ); + for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]]; + memcpy( ptr, fix, sizeof( uint64_t ) ); + ptr++; + } + while( --blocks ); + } +} + +void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + uint32_t buf[4*4]; + int i = 0; + + auto ptr = dst; + do + { + auto tmp = (char*)buf; + memcpy( tmp, src + width * 0, 4*4 ); + memcpy( tmp + 4*4, src + width * 1, 4*4 ); + memcpy( tmp + 8*4, src + width * 2, 4*4 ); + memcpy( tmp + 12*4, src + width * 3, 4*4 ); + src += 4; + if( ++i == width/4 ) + { + src += width * 3; + i = 0; + } + + Dither( (uint8_t*)buf ); + + const auto c = ProcessRGB( (uint8_t*)buf ); + uint8_t fix[8]; + memcpy( fix, &c, 8 ); + for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]]; + memcpy( ptr, fix, sizeof( uint64_t ) ); + ptr++; + } + while( --blocks ); +} + +void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + int i = 0; + auto ptr = dst; + do + { +#ifdef __SSE4_1__ + __m128i px0 = _mm_loadu_si128( (__m128i*)( src + width * 0 ) ); + __m128i px1 = _mm_loadu_si128( (__m128i*)( src + width * 1 ) ); + __m128i px2 = _mm_loadu_si128( (__m128i*)( src + width * 2 ) ); + __m128i px3 = _mm_loadu_si128( (__m128i*)( src + width * 3 ) ); + + src += 4; + if( ++i == width/4 ) + { + src += width * 3; + i = 0; + } + + *ptr++ = ProcessAlpha_SSE( px0, px1, px2, px3 ); + + const auto c = ProcessRGB_SSE( px0, px1, px2, px3 ); + uint8_t fix[8]; + memcpy( fix, &c, 8 ); + for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]]; + memcpy( ptr, fix, sizeof( uint64_t ) ); + ptr++; +#else + uint32_t rgba[4*4]; + uint8_t alpha[4*4]; + + auto tmp = (char*)rgba; + memcpy( tmp, src + width * 0, 4*4 ); + memcpy( tmp + 4*4, src + width * 1, 4*4 ); + memcpy( tmp + 8*4, src + width * 2, 4*4 ); + memcpy( tmp + 12*4, src + width * 3, 4*4 ); + src += 4; + if( ++i == width/4 ) + { + src += width * 3; + i = 0; + } + + for( int i=0; i<16; i++ ) + { + alpha[i] = rgba[i] >> 24; + rgba[i] &= 0xFFFFFF; + } + *ptr++ = ProcessAlpha( alpha ); + + const auto c = ProcessRGB( (uint8_t*)rgba ); + uint8_t fix[8]; + memcpy( fix, &c, 8 ); + for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]]; + memcpy( ptr, fix, sizeof( uint64_t ) ); + ptr++; +#endif + } + while( --blocks ); +} diff --git a/thirdparty/etcpak/ProcessDxtc.hpp b/thirdparty/etcpak/ProcessDxtc.hpp new file mode 100644 index 0000000000..8e0b12e4bd --- /dev/null +++ b/thirdparty/etcpak/ProcessDxtc.hpp @@ -0,0 +1,11 @@ +#ifndef __PROCESSDXT1_HPP__ +#define __PROCESSDXT1_HPP__ + +#include <stddef.h> +#include <stdint.h> + +void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); +void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); +void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); + +#endif diff --git a/thirdparty/etcpak/ProcessRGB.cpp b/thirdparty/etcpak/ProcessRGB.cpp new file mode 100644 index 0000000000..7f4524d105 --- /dev/null +++ b/thirdparty/etcpak/ProcessRGB.cpp @@ -0,0 +1,3100 @@ +#include <array> +#include <string.h> +#include <limits> + +#ifdef __ARM_NEON +# include <arm_neon.h> +#endif + +#include "Dither.hpp" +#include "ForceInline.hpp" +#include "Math.hpp" +#include "ProcessCommon.hpp" +#include "ProcessRGB.hpp" +#include "Tables.hpp" +#include "Vector.hpp" +#if defined __SSE4_1__ || defined __AVX2__ || defined _MSC_VER +# ifdef _MSC_VER +# include <intrin.h> +# include <Windows.h> +# define _bswap(x) _byteswap_ulong(x) +# define _bswap64(x) _byteswap_uint64(x) +# else +# include <x86intrin.h> +# endif +#endif + +#ifndef _bswap +# define _bswap(x) __builtin_bswap32(x) +# define _bswap64(x) __builtin_bswap64(x) +#endif + +namespace +{ + +#if defined _MSC_VER && !defined __clang__ +static etcpak_force_inline unsigned long _bit_scan_forward( unsigned long mask ) +{ + unsigned long ret; + _BitScanForward( &ret, mask ); + return ret; +} +#endif + +typedef std::array<uint16_t, 4> v4i; + +#ifdef __AVX2__ +static etcpak_force_inline __m256i Sum4_AVX2( const uint8_t* data) noexcept +{ + __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0); + __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1); + __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2); + __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3); + + __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF)); + __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF)); + __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF)); + __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF)); + + __m256i t0 = _mm256_cvtepu8_epi16(dm0); + __m256i t1 = _mm256_cvtepu8_epi16(dm1); + __m256i t2 = _mm256_cvtepu8_epi16(dm2); + __m256i t3 = _mm256_cvtepu8_epi16(dm3); + + __m256i sum0 = _mm256_add_epi16(t0, t1); + __m256i sum1 = _mm256_add_epi16(t2, t3); + + __m256i s0 = _mm256_permute2x128_si256(sum0, sum1, (0) | (3 << 4)); // 0, 0, 3, 3 + __m256i s1 = _mm256_permute2x128_si256(sum0, sum1, (1) | (2 << 4)); // 1, 1, 2, 2 + + __m256i s2 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(1, 3, 0, 2)); + __m256i s3 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(0, 2, 1, 3)); + __m256i s4 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(3, 1, 0, 2)); + __m256i s5 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(2, 0, 1, 3)); + + __m256i sum5 = _mm256_add_epi16(s2, s3); // 3, 0, 3, 0 + __m256i sum6 = _mm256_add_epi16(s4, s5); // 2, 1, 1, 2 + return _mm256_add_epi16(sum5, sum6); // 3+2, 0+1, 3+1, 3+2 +} + +static etcpak_force_inline __m256i Average_AVX2( const __m256i data) noexcept +{ + __m256i a = _mm256_add_epi16(data, _mm256_set1_epi16(4)); + + return _mm256_srli_epi16(a, 3); +} + +static etcpak_force_inline __m128i CalcErrorBlock_AVX2( const __m256i data, const v4i a[8]) noexcept +{ + // + __m256i a0 = _mm256_load_si256((__m256i*)a[0].data()); + __m256i a1 = _mm256_load_si256((__m256i*)a[4].data()); + + // err = 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) ); + __m256i a4 = _mm256_madd_epi16(a0, a0); + __m256i a5 = _mm256_madd_epi16(a1, a1); + + __m256i a6 = _mm256_hadd_epi32(a4, a5); + __m256i a7 = _mm256_slli_epi32(a6, 3); + + __m256i a8 = _mm256_add_epi32(a7, _mm256_set1_epi32(0x3FFFFFFF)); // Big value to prevent negative values, but small enough to prevent overflow + + // average is not swapped + // err -= block[0] * 2 * average[0]; + // err -= block[1] * 2 * average[1]; + // err -= block[2] * 2 * average[2]; + __m256i a2 = _mm256_slli_epi16(a0, 1); + __m256i a3 = _mm256_slli_epi16(a1, 1); + __m256i b0 = _mm256_madd_epi16(a2, data); + __m256i b1 = _mm256_madd_epi16(a3, data); + + __m256i b2 = _mm256_hadd_epi32(b0, b1); + __m256i b3 = _mm256_sub_epi32(a8, b2); + __m256i b4 = _mm256_hadd_epi32(b3, b3); + + __m256i b5 = _mm256_permutevar8x32_epi32(b4, _mm256_set_epi32(0, 0, 0, 0, 5, 1, 4, 0)); + + return _mm256_castsi256_si128(b5); +} + +static etcpak_force_inline void ProcessAverages_AVX2(const __m256i d, v4i a[8] ) noexcept +{ + __m256i t = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(31)), _mm256_set1_epi16(128)); + + __m256i c = _mm256_srli_epi16(_mm256_add_epi16(t, _mm256_srli_epi16(t, 8)), 8); + + __m256i c1 = _mm256_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2)); + __m256i diff = _mm256_sub_epi16(c, c1); + diff = _mm256_max_epi16(diff, _mm256_set1_epi16(-4)); + diff = _mm256_min_epi16(diff, _mm256_set1_epi16(3)); + + __m256i co = _mm256_add_epi16(c1, diff); + + c = _mm256_blend_epi16(co, c, 0xF0); + + __m256i a0 = _mm256_or_si256(_mm256_slli_epi16(c, 3), _mm256_srli_epi16(c, 2)); + + _mm256_store_si256((__m256i*)a[4].data(), a0); + + __m256i t0 = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(15)), _mm256_set1_epi16(128)); + __m256i t1 = _mm256_srli_epi16(_mm256_add_epi16(t0, _mm256_srli_epi16(t0, 8)), 8); + + __m256i t2 = _mm256_or_si256(t1, _mm256_slli_epi16(t1, 4)); + + _mm256_store_si256((__m256i*)a[0].data(), t2); +} + +static etcpak_force_inline uint64_t EncodeAverages_AVX2( const v4i a[8], size_t idx ) noexcept +{ + uint64_t d = ( idx << 24 ); + size_t base = idx << 1; + + __m128i a0 = _mm_load_si128((const __m128i*)a[base].data()); + + __m128i r0, r1; + + if( ( idx & 0x2 ) == 0 ) + { + r0 = _mm_srli_epi16(a0, 4); + + __m128i a1 = _mm_unpackhi_epi64(r0, r0); + r1 = _mm_slli_epi16(a1, 4); + } + else + { + __m128i a1 = _mm_and_si128(a0, _mm_set1_epi16(-8)); + + r0 = _mm_unpackhi_epi64(a1, a1); + __m128i a2 = _mm_sub_epi16(a1, r0); + __m128i a3 = _mm_srai_epi16(a2, 3); + r1 = _mm_and_si128(a3, _mm_set1_epi16(0x07)); + } + + __m128i r2 = _mm_or_si128(r0, r1); + // do missing swap for average values + __m128i r3 = _mm_shufflelo_epi16(r2, _MM_SHUFFLE(3, 0, 1, 2)); + __m128i r4 = _mm_packus_epi16(r3, _mm_setzero_si128()); + d |= _mm_cvtsi128_si32(r4); + + return d; +} + +static etcpak_force_inline uint64_t CheckSolid_AVX2( const uint8_t* src ) noexcept +{ + __m256i d0 = _mm256_loadu_si256(((__m256i*)src) + 0); + __m256i d1 = _mm256_loadu_si256(((__m256i*)src) + 1); + + __m256i c = _mm256_broadcastd_epi32(_mm256_castsi256_si128(d0)); + + __m256i c0 = _mm256_cmpeq_epi8(d0, c); + __m256i c1 = _mm256_cmpeq_epi8(d1, c); + + __m256i m = _mm256_and_si256(c0, c1); + + if (!_mm256_testc_si256(m, _mm256_set1_epi32(-1))) + { + return 0; + } + + return 0x02000000 | + ( (unsigned int)( src[0] & 0xF8 ) << 16 ) | + ( (unsigned int)( src[1] & 0xF8 ) << 8 ) | + ( (unsigned int)( src[2] & 0xF8 ) ); +} + +static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const uint8_t* src) noexcept +{ + __m256i sum4 = Sum4_AVX2( src ); + + ProcessAverages_AVX2(Average_AVX2( sum4 ), a ); + + return CalcErrorBlock_AVX2( sum4, a); +} + +static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const __m256i sum4) noexcept +{ + ProcessAverages_AVX2(Average_AVX2( sum4 ), a ); + + return CalcErrorBlock_AVX2( sum4, a); +} + +static etcpak_force_inline void FindBestFit_4x2_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept +{ + __m256i sel0 = _mm256_setzero_si256(); + __m256i sel1 = _mm256_setzero_si256(); + + for (unsigned int j = 0; j < 2; ++j) + { + unsigned int bid = offset + 1 - j; + + __m256i squareErrorSum = _mm256_setzero_si256(); + + __m128i a0 = _mm_loadl_epi64((const __m128i*)a[bid].data()); + __m256i a1 = _mm256_broadcastq_epi64(a0); + + // Processing one full row each iteration + for (size_t i = 0; i < 8; i += 4) + { + __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4)); + + __m256i rgb16 = _mm256_cvtepu8_epi16(rgb); + __m256i d = _mm256_sub_epi16(a1, rgb16); + + // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16 + // This produces slightly different results, but is significant faster + __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14)); + __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0); + __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1); + __m128i pixel3 = _mm256_castsi256_si128(pixel2); + + __m128i pix0 = _mm_broadcastw_epi16(pixel3); + __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16)); + __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1); + + // Processing first two pixels of the row + { + __m256i pix = _mm256_abs_epi16(pixel); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries. + __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0]))); + __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1]))); + + __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1)); + __m256i minError = _mm256_min_epi16(error0, error1); + + // Exploiting symmetry of the selector table and use the sign bit + // This produces slightly different results, but is significant faster + __m256i minIndex1 = _mm256_srli_epi16(pixel, 15); + + // Interleaving values so madd instruction can be used + __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0)); + __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2)); + + __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi); + // Squaring the minimum error to produce correct values when adding + __m256i squareError = _mm256_madd_epi16(minError2, minError2); + + squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError); + + // Packing selector bits + __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8)); + __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8)); + + sel0 = _mm256_or_si256(sel0, minIndexLo2); + sel1 = _mm256_or_si256(sel1, minIndexHi2); + } + + pixel3 = _mm256_extracti128_si256(pixel2, 1); + pix0 = _mm_broadcastw_epi16(pixel3); + pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16)); + pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1); + + // Processing second two pixels of the row + { + __m256i pix = _mm256_abs_epi16(pixel); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries. + __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0]))); + __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1]))); + + __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1)); + __m256i minError = _mm256_min_epi16(error0, error1); + + // Exploiting symmetry of the selector table and use the sign bit + __m256i minIndex1 = _mm256_srli_epi16(pixel, 15); + + // Interleaving values so madd instruction can be used + __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0)); + __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2)); + + __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi); + // Squaring the minimum error to produce correct values when adding + __m256i squareError = _mm256_madd_epi16(minError2, minError2); + + squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError); + + // Packing selector bits + __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8)); + __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8)); + __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2); + __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2); + + sel0 = _mm256_or_si256(sel0, minIndexLo3); + sel1 = _mm256_or_si256(sel1, minIndexHi3); + } + } + + data += 8 * 4; + + _mm256_store_si256((__m256i*)terr[1 - j], squareErrorSum); + } + + // Interleave selector bits + __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1); + __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1); + + __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4)); + __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4)); + + __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1); + + __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2); + + _mm256_store_si256((__m256i*)tsel, sel); +} + +static etcpak_force_inline void FindBestFit_2x4_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept +{ + __m256i sel0 = _mm256_setzero_si256(); + __m256i sel1 = _mm256_setzero_si256(); + + __m256i squareErrorSum0 = _mm256_setzero_si256(); + __m256i squareErrorSum1 = _mm256_setzero_si256(); + + __m128i a0 = _mm_loadl_epi64((const __m128i*)a[offset + 1].data()); + __m128i a1 = _mm_loadl_epi64((const __m128i*)a[offset + 0].data()); + + __m128i a2 = _mm_broadcastq_epi64(a0); + __m128i a3 = _mm_broadcastq_epi64(a1); + __m256i a4 = _mm256_insertf128_si256(_mm256_castsi128_si256(a2), a3, 1); + + // Processing one full row each iteration + for (size_t i = 0; i < 16; i += 4) + { + __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4)); + + __m256i rgb16 = _mm256_cvtepu8_epi16(rgb); + __m256i d = _mm256_sub_epi16(a4, rgb16); + + // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16 + // This produces slightly different results, but is significant faster + __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14)); + __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0); + __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1); + __m128i pixel3 = _mm256_castsi256_si128(pixel2); + + __m128i pix0 = _mm_broadcastw_epi16(pixel3); + __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16)); + __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1); + + // Processing first two pixels of the row + { + __m256i pix = _mm256_abs_epi16(pixel); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries. + __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0]))); + __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1]))); + + __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1)); + __m256i minError = _mm256_min_epi16(error0, error1); + + // Exploiting symmetry of the selector table and use the sign bit + __m256i minIndex1 = _mm256_srli_epi16(pixel, 15); + + // Interleaving values so madd instruction can be used + __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0)); + __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2)); + + __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi); + // Squaring the minimum error to produce correct values when adding + __m256i squareError = _mm256_madd_epi16(minError2, minError2); + + squareErrorSum0 = _mm256_add_epi32(squareErrorSum0, squareError); + + // Packing selector bits + __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i)); + __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i)); + + sel0 = _mm256_or_si256(sel0, minIndexLo2); + sel1 = _mm256_or_si256(sel1, minIndexHi2); + } + + pixel3 = _mm256_extracti128_si256(pixel2, 1); + pix0 = _mm_broadcastw_epi16(pixel3); + pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16)); + pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1); + + // Processing second two pixels of the row + { + __m256i pix = _mm256_abs_epi16(pixel); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries. + __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0]))); + __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1]))); + + __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1)); + __m256i minError = _mm256_min_epi16(error0, error1); + + // Exploiting symmetry of the selector table and use the sign bit + __m256i minIndex1 = _mm256_srli_epi16(pixel, 15); + + // Interleaving values so madd instruction can be used + __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0)); + __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2)); + + __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi); + // Squaring the minimum error to produce correct values when adding + __m256i squareError = _mm256_madd_epi16(minError2, minError2); + + squareErrorSum1 = _mm256_add_epi32(squareErrorSum1, squareError); + + // Packing selector bits + __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i)); + __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i)); + __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2); + __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2); + + sel0 = _mm256_or_si256(sel0, minIndexLo3); + sel1 = _mm256_or_si256(sel1, minIndexHi3); + } + } + + _mm256_store_si256((__m256i*)terr[1], squareErrorSum0); + _mm256_store_si256((__m256i*)terr[0], squareErrorSum1); + + // Interleave selector bits + __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1); + __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1); + + __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4)); + __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4)); + + __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1); + + __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2); + + _mm256_store_si256((__m256i*)tsel, sel); +} + +static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate) noexcept +{ + size_t tidx[2]; + + // Get index of minimum error (terr[0] and terr[1]) + __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]); + __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]); + + __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4)); + __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4)); + + __m256i errMin0 = _mm256_min_epu32(errLo, errHi); + + __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1)); + __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1); + + __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2); + + __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4)); + __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4)); + + __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0); + __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1); + + uint32_t mask0 = _mm256_movemask_epi8(errMask0); + uint32_t mask1 = _mm256_movemask_epi8(errMask1); + + tidx[0] = _bit_scan_forward(mask0) >> 2; + tidx[1] = _bit_scan_forward(mask1) >> 2; + + d |= tidx[0] << 26; + d |= tidx[1] << 29; + + unsigned int t0 = tsel[tidx[0]]; + unsigned int t1 = tsel[tidx[1]]; + + if (!rotate) + { + t0 &= 0xFF00FF00; + t1 &= 0x00FF00FF; + } + else + { + t0 &= 0xCCCCCCCC; + t1 &= 0x33333333; + } + + // Flip selectors from sign bit + unsigned int t2 = (t0 | t1) ^ 0xFFFF0000; + + return d | static_cast<uint64_t>(_bswap(t2)) << 32; +} + +static etcpak_force_inline __m128i r6g7b6_AVX2(__m128 cof, __m128 chf, __m128 cvf) noexcept +{ + __m128i co = _mm_cvttps_epi32(cof); + __m128i ch = _mm_cvttps_epi32(chf); + __m128i cv = _mm_cvttps_epi32(cvf); + + __m128i coh = _mm_packus_epi32(co, ch); + __m128i cv0 = _mm_packus_epi32(cv, _mm_setzero_si128()); + + __m256i cohv0 = _mm256_inserti128_si256(_mm256_castsi128_si256(coh), cv0, 1); + __m256i cohv1 = _mm256_min_epu16(cohv0, _mm256_set1_epi16(1023)); + + __m256i cohv2 = _mm256_sub_epi16(cohv1, _mm256_set1_epi16(15)); + __m256i cohv3 = _mm256_srai_epi16(cohv2, 1); + + __m256i cohvrb0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(11)); + __m256i cohvrb1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(4)); + __m256i cohvg0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(9)); + __m256i cohvg1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(6)); + + __m256i cohvrb2 = _mm256_srai_epi16(cohvrb0, 7); + __m256i cohvrb3 = _mm256_srai_epi16(cohvrb1, 7); + __m256i cohvg2 = _mm256_srai_epi16(cohvg0, 8); + __m256i cohvg3 = _mm256_srai_epi16(cohvg1, 8); + + __m256i cohvrb4 = _mm256_sub_epi16(cohvrb0, cohvrb2); + __m256i cohvrb5 = _mm256_sub_epi16(cohvrb4, cohvrb3); + __m256i cohvg4 = _mm256_sub_epi16(cohvg0, cohvg2); + __m256i cohvg5 = _mm256_sub_epi16(cohvg4, cohvg3); + + __m256i cohvrb6 = _mm256_srai_epi16(cohvrb5, 3); + __m256i cohvg6 = _mm256_srai_epi16(cohvg5, 2); + + __m256i cohv4 = _mm256_blend_epi16(cohvg6, cohvrb6, 0x55); + + __m128i cohv5 = _mm_packus_epi16(_mm256_castsi256_si128(cohv4), _mm256_extracti128_si256(cohv4, 1)); + return _mm_shuffle_epi8(cohv5, _mm_setr_epi8(6, 5, 4, -1, 2, 1, 0, -1, 10, 9, 8, -1, -1, -1, -1, -1)); +} + +struct Plane +{ + uint64_t plane; + uint64_t error; + __m256i sum4; +}; + +static etcpak_force_inline Plane Planar_AVX2(const uint8_t* src) +{ + __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0); + __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1); + __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2); + __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3); + + __m128i rgb0 = _mm_shuffle_epi8(d0, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1)); + __m128i rgb1 = _mm_shuffle_epi8(d1, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1)); + __m128i rgb2 = _mm_shuffle_epi8(d2, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1)); + __m128i rgb3 = _mm_shuffle_epi8(d3, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1)); + + __m128i rg0 = _mm_unpacklo_epi32(rgb0, rgb1); + __m128i rg1 = _mm_unpacklo_epi32(rgb2, rgb3); + __m128i b0 = _mm_unpackhi_epi32(rgb0, rgb1); + __m128i b1 = _mm_unpackhi_epi32(rgb2, rgb3); + + // swap channels + __m128i b8 = _mm_unpacklo_epi64(rg0, rg1); + __m128i g8 = _mm_unpackhi_epi64(rg0, rg1); + __m128i r8 = _mm_unpacklo_epi64(b0, b1); + + __m128i t0 = _mm_sad_epu8(r8, _mm_setzero_si128()); + __m128i t1 = _mm_sad_epu8(g8, _mm_setzero_si128()); + __m128i t2 = _mm_sad_epu8(b8, _mm_setzero_si128()); + + __m128i r8s = _mm_shuffle_epi8(r8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0)); + __m128i g8s = _mm_shuffle_epi8(g8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0)); + __m128i b8s = _mm_shuffle_epi8(b8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0)); + + __m128i s0 = _mm_sad_epu8(r8s, _mm_setzero_si128()); + __m128i s1 = _mm_sad_epu8(g8s, _mm_setzero_si128()); + __m128i s2 = _mm_sad_epu8(b8s, _mm_setzero_si128()); + + __m256i sr0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t0), s0, 1); + __m256i sg0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t1), s1, 1); + __m256i sb0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t2), s2, 1); + + __m256i sr1 = _mm256_slli_epi64(sr0, 32); + __m256i sg1 = _mm256_slli_epi64(sg0, 16); + + __m256i srb = _mm256_or_si256(sr1, sb0); + __m256i srgb = _mm256_or_si256(srb, sg1); + + __m128i t3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(t0), _mm_castsi128_ps(t1), _MM_SHUFFLE(2, 0, 2, 0))); + __m128i t4 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3, 1, 2, 0)); + __m128i t5 = _mm_hadd_epi32(t3, t4); + __m128i t6 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(1, 1, 1, 1)); + __m128i t7 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(2, 2, 2, 2)); + + __m256i sr = _mm256_broadcastw_epi16(t5); + __m256i sg = _mm256_broadcastw_epi16(t6); + __m256i sb = _mm256_broadcastw_epi16(t7); + + __m256i r08 = _mm256_cvtepu8_epi16(r8); + __m256i g08 = _mm256_cvtepu8_epi16(g8); + __m256i b08 = _mm256_cvtepu8_epi16(b8); + + __m256i r16 = _mm256_slli_epi16(r08, 4); + __m256i g16 = _mm256_slli_epi16(g08, 4); + __m256i b16 = _mm256_slli_epi16(b08, 4); + + __m256i difR0 = _mm256_sub_epi16(r16, sr); + __m256i difG0 = _mm256_sub_epi16(g16, sg); + __m256i difB0 = _mm256_sub_epi16(b16, sb); + + __m256i difRyz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255)); + __m256i difGyz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255)); + __m256i difByz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255)); + + __m256i difRxz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255)); + __m256i difGxz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255)); + __m256i difBxz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255)); + + __m256i difRGyz = _mm256_hadd_epi32(difRyz, difGyz); + __m256i difByzxz = _mm256_hadd_epi32(difByz, difBxz); + + __m256i difRGxz = _mm256_hadd_epi32(difRxz, difGxz); + + __m128i sumRGyz = _mm_add_epi32(_mm256_castsi256_si128(difRGyz), _mm256_extracti128_si256(difRGyz, 1)); + __m128i sumByzxz = _mm_add_epi32(_mm256_castsi256_si128(difByzxz), _mm256_extracti128_si256(difByzxz, 1)); + __m128i sumRGxz = _mm_add_epi32(_mm256_castsi256_si128(difRGxz), _mm256_extracti128_si256(difRGxz, 1)); + + __m128i sumRGByz = _mm_hadd_epi32(sumRGyz, sumByzxz); + __m128i sumRGByzxz = _mm_hadd_epi32(sumRGxz, sumByzxz); + + __m128i sumRGBxz = _mm_shuffle_epi32(sumRGByzxz, _MM_SHUFFLE(2, 3, 1, 0)); + + __m128 sumRGByzf = _mm_cvtepi32_ps(sumRGByz); + __m128 sumRGBxzf = _mm_cvtepi32_ps(sumRGBxz); + + const float value = (255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f; + + __m128 scale = _mm_set1_ps(-4.0f / value); + + __m128 af = _mm_mul_ps(sumRGBxzf, scale); + __m128 bf = _mm_mul_ps(sumRGByzf, scale); + + __m128 df = _mm_mul_ps(_mm_cvtepi32_ps(t5), _mm_set1_ps(4.0f / 16.0f)); + + // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y; + __m128 cof0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df)); + __m128 chf0 = _mm_fnmadd_ps(af, _mm_set1_ps( 425.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df)); + __m128 cvf0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps( 425.0f), df)); + + // convert to r6g7b6 + __m128i cohv = r6g7b6_AVX2(cof0, chf0, cvf0); + + uint64_t rgbho = _mm_extract_epi64(cohv, 0); + uint32_t rgbv0 = _mm_extract_epi32(cohv, 2); + + // Error calculation + auto ro0 = (rgbho >> 48) & 0x3F; + auto go0 = (rgbho >> 40) & 0x7F; + auto bo0 = (rgbho >> 32) & 0x3F; + auto ro1 = (ro0 >> 4) | (ro0 << 2); + auto go1 = (go0 >> 6) | (go0 << 1); + auto bo1 = (bo0 >> 4) | (bo0 << 2); + auto ro2 = (ro1 << 2) + 2; + auto go2 = (go1 << 2) + 2; + auto bo2 = (bo1 << 2) + 2; + + __m256i ro3 = _mm256_set1_epi16(ro2); + __m256i go3 = _mm256_set1_epi16(go2); + __m256i bo3 = _mm256_set1_epi16(bo2); + + auto rh0 = (rgbho >> 16) & 0x3F; + auto gh0 = (rgbho >> 8) & 0x7F; + auto bh0 = (rgbho >> 0) & 0x3F; + auto rh1 = (rh0 >> 4) | (rh0 << 2); + auto gh1 = (gh0 >> 6) | (gh0 << 1); + auto bh1 = (bh0 >> 4) | (bh0 << 2); + + auto rh2 = rh1 - ro1; + auto gh2 = gh1 - go1; + auto bh2 = bh1 - bo1; + + __m256i rh3 = _mm256_set1_epi16(rh2); + __m256i gh3 = _mm256_set1_epi16(gh2); + __m256i bh3 = _mm256_set1_epi16(bh2); + + auto rv0 = (rgbv0 >> 16) & 0x3F; + auto gv0 = (rgbv0 >> 8) & 0x7F; + auto bv0 = (rgbv0 >> 0) & 0x3F; + auto rv1 = (rv0 >> 4) | (rv0 << 2); + auto gv1 = (gv0 >> 6) | (gv0 << 1); + auto bv1 = (bv0 >> 4) | (bv0 << 2); + + auto rv2 = rv1 - ro1; + auto gv2 = gv1 - go1; + auto bv2 = bv1 - bo1; + + __m256i rv3 = _mm256_set1_epi16(rv2); + __m256i gv3 = _mm256_set1_epi16(gv2); + __m256i bv3 = _mm256_set1_epi16(bv2); + + __m256i x = _mm256_set_epi16(3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0); + + __m256i rh4 = _mm256_mullo_epi16(rh3, x); + __m256i gh4 = _mm256_mullo_epi16(gh3, x); + __m256i bh4 = _mm256_mullo_epi16(bh3, x); + + __m256i y = _mm256_set_epi16(3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0); + + __m256i rv4 = _mm256_mullo_epi16(rv3, y); + __m256i gv4 = _mm256_mullo_epi16(gv3, y); + __m256i bv4 = _mm256_mullo_epi16(bv3, y); + + __m256i rxy = _mm256_add_epi16(rh4, rv4); + __m256i gxy = _mm256_add_epi16(gh4, gv4); + __m256i bxy = _mm256_add_epi16(bh4, bv4); + + __m256i rp0 = _mm256_add_epi16(rxy, ro3); + __m256i gp0 = _mm256_add_epi16(gxy, go3); + __m256i bp0 = _mm256_add_epi16(bxy, bo3); + + __m256i rp1 = _mm256_srai_epi16(rp0, 2); + __m256i gp1 = _mm256_srai_epi16(gp0, 2); + __m256i bp1 = _mm256_srai_epi16(bp0, 2); + + __m256i rp2 = _mm256_max_epi16(_mm256_min_epi16(rp1, _mm256_set1_epi16(255)), _mm256_setzero_si256()); + __m256i gp2 = _mm256_max_epi16(_mm256_min_epi16(gp1, _mm256_set1_epi16(255)), _mm256_setzero_si256()); + __m256i bp2 = _mm256_max_epi16(_mm256_min_epi16(bp1, _mm256_set1_epi16(255)), _mm256_setzero_si256()); + + __m256i rdif = _mm256_sub_epi16(r08, rp2); + __m256i gdif = _mm256_sub_epi16(g08, gp2); + __m256i bdif = _mm256_sub_epi16(b08, bp2); + + __m256i rerr = _mm256_mullo_epi16(rdif, _mm256_set1_epi16(38)); + __m256i gerr = _mm256_mullo_epi16(gdif, _mm256_set1_epi16(76)); + __m256i berr = _mm256_mullo_epi16(bdif, _mm256_set1_epi16(14)); + + __m256i sum0 = _mm256_add_epi16(rerr, gerr); + __m256i sum1 = _mm256_add_epi16(sum0, berr); + + __m256i sum2 = _mm256_madd_epi16(sum1, sum1); + + __m128i sum3 = _mm_add_epi32(_mm256_castsi256_si128(sum2), _mm256_extracti128_si256(sum2, 1)); + + uint32_t err0 = _mm_extract_epi32(sum3, 0); + uint32_t err1 = _mm_extract_epi32(sum3, 1); + uint32_t err2 = _mm_extract_epi32(sum3, 2); + uint32_t err3 = _mm_extract_epi32(sum3, 3); + + uint64_t error = err0 + err1 + err2 + err3; + /**/ + + uint32_t rgbv = ( rgbv0 & 0x3F ) | ( ( rgbv0 >> 2 ) & 0x1FC0 ) | ( ( rgbv0 >> 3 ) & 0x7E000 ); + uint64_t rgbho0_ = ( rgbho & 0x3F0000003F ) | ( ( rgbho >> 2 ) & 0x1FC000001FC0 ) | ( ( rgbho >> 3 ) & 0x7E0000007E000 ); + uint64_t rgbho0 = ( rgbho0_ & 0x7FFFF ) | ( ( rgbho0_ >> 13 ) & 0x3FFFF80000 ); + + uint32_t hi = rgbv | ((rgbho0 & 0x1FFF) << 19); + rgbho0 >>= 13; + uint32_t lo = ( rgbho0 & 0x1 ) | ( ( rgbho0 & 0x1FE ) << 1 ) | ( ( rgbho0 & 0x600 ) << 2 ) | ( ( rgbho0 & 0x3F800 ) << 5 ) | ( ( rgbho0 & 0x1FC0000 ) << 6 ); + + uint32_t idx = ( ( rgbho >> 33 ) & 0xF ) | ( ( rgbho >> 41 ) & 0x10 ) | ( ( rgbho >> 48 ) & 0x20 ); + lo |= g_flags[idx]; + uint64_t result = static_cast<uint32_t>(_bswap(lo)); + result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32; + + Plane plane; + + plane.plane = result; + plane.error = error; + plane.sum4 = _mm256_permute4x64_epi64(srgb, _MM_SHUFFLE(2, 3, 0, 1)); + + return plane; +} + +static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate, const uint64_t value, const uint32_t error) noexcept +{ + size_t tidx[2]; + + // Get index of minimum error (terr[0] and terr[1]) + __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]); + __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]); + + __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4)); + __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4)); + + __m256i errMin0 = _mm256_min_epu32(errLo, errHi); + + __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1)); + __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1); + + __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2); + + __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4)); + __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4)); + + __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0); + __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1); + + uint32_t mask0 = _mm256_movemask_epi8(errMask0); + uint32_t mask1 = _mm256_movemask_epi8(errMask1); + + tidx[0] = _bit_scan_forward(mask0) >> 2; + tidx[1] = _bit_scan_forward(mask1) >> 2; + + if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error) + { + return value; + } + + d |= tidx[0] << 26; + d |= tidx[1] << 29; + + unsigned int t0 = tsel[tidx[0]]; + unsigned int t1 = tsel[tidx[1]]; + + if (!rotate) + { + t0 &= 0xFF00FF00; + t1 &= 0x00FF00FF; + } + else + { + t0 &= 0xCCCCCCCC; + t1 &= 0x33333333; + } + + // Flip selectors from sign bit + unsigned int t2 = (t0 | t1) ^ 0xFFFF0000; + + return d | static_cast<uint64_t>(_bswap(t2)) << 32; +} + +#endif + +static etcpak_force_inline void Average( const uint8_t* data, v4i* a ) +{ +#ifdef __SSE4_1__ + __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0); + __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1); + __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2); + __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3); + + __m128i d0l = _mm_unpacklo_epi8(d0, _mm_setzero_si128()); + __m128i d0h = _mm_unpackhi_epi8(d0, _mm_setzero_si128()); + __m128i d1l = _mm_unpacklo_epi8(d1, _mm_setzero_si128()); + __m128i d1h = _mm_unpackhi_epi8(d1, _mm_setzero_si128()); + __m128i d2l = _mm_unpacklo_epi8(d2, _mm_setzero_si128()); + __m128i d2h = _mm_unpackhi_epi8(d2, _mm_setzero_si128()); + __m128i d3l = _mm_unpacklo_epi8(d3, _mm_setzero_si128()); + __m128i d3h = _mm_unpackhi_epi8(d3, _mm_setzero_si128()); + + __m128i sum0 = _mm_add_epi16(d0l, d1l); + __m128i sum1 = _mm_add_epi16(d0h, d1h); + __m128i sum2 = _mm_add_epi16(d2l, d3l); + __m128i sum3 = _mm_add_epi16(d2h, d3h); + + __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128()); + __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128()); + __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128()); + __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128()); + __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128()); + __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128()); + __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128()); + __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128()); + + __m128i b0 = _mm_add_epi32(sum0l, sum0h); + __m128i b1 = _mm_add_epi32(sum1l, sum1h); + __m128i b2 = _mm_add_epi32(sum2l, sum2h); + __m128i b3 = _mm_add_epi32(sum3l, sum3h); + + __m128i a0 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b2, b3), _mm_set1_epi32(4)), 3); + __m128i a1 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b1), _mm_set1_epi32(4)), 3); + __m128i a2 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b1, b3), _mm_set1_epi32(4)), 3); + __m128i a3 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b2), _mm_set1_epi32(4)), 3); + + _mm_storeu_si128((__m128i*)&a[0], _mm_packus_epi32(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a1, _MM_SHUFFLE(3, 0, 1, 2)))); + _mm_storeu_si128((__m128i*)&a[2], _mm_packus_epi32(_mm_shuffle_epi32(a2, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a3, _MM_SHUFFLE(3, 0, 1, 2)))); +#elif defined __ARM_NEON + uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t()); + uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t()); + uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t()); + uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t()); + + uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) }; + uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) }; + uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) }; + uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) }; + + uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ) ) ), uint16x8_t()); + uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ) ) ), uint16x8_t()); + uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ) ) ), uint16x8_t()); + uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ) ) ), uint16x8_t()); + + uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) }; + uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) }; + uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) }; + uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) }; + + uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]); + uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]); + uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]); + uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]); + + uint32x4_t a0 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b2, b3), vdupq_n_u32(4)), 3); + uint32x4_t a1 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b1), vdupq_n_u32(4)), 3); + uint32x4_t a2 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b1, b3), vdupq_n_u32(4)), 3); + uint32x4_t a3 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b2), vdupq_n_u32(4)), 3); + + uint16x8_t o0 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a0 )), vqmovun_s32(vreinterpretq_s32_u32( a1 ))); + uint16x8_t o1 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a2 )), vqmovun_s32(vreinterpretq_s32_u32( a3 ))); + + a[0] = v4i{o0[2], o0[1], o0[0], 0}; + a[1] = v4i{o0[6], o0[5], o0[4], 0}; + a[2] = v4i{o1[2], o1[1], o1[0], 0}; + a[3] = v4i{o1[6], o1[5], o1[4], 0}; +#else + uint32_t r[4]; + uint32_t g[4]; + uint32_t b[4]; + + memset(r, 0, sizeof(r)); + memset(g, 0, sizeof(g)); + memset(b, 0, sizeof(b)); + + for( int j=0; j<4; j++ ) + { + for( int i=0; i<4; i++ ) + { + int index = (j & 2) + (i >> 1); + b[index] += *data++; + g[index] += *data++; + r[index] += *data++; + data++; + } + } + + a[0] = v4i{ uint16_t( (r[2] + r[3] + 4) / 8 ), uint16_t( (g[2] + g[3] + 4) / 8 ), uint16_t( (b[2] + b[3] + 4) / 8 ), 0}; + a[1] = v4i{ uint16_t( (r[0] + r[1] + 4) / 8 ), uint16_t( (g[0] + g[1] + 4) / 8 ), uint16_t( (b[0] + b[1] + 4) / 8 ), 0}; + a[2] = v4i{ uint16_t( (r[1] + r[3] + 4) / 8 ), uint16_t( (g[1] + g[3] + 4) / 8 ), uint16_t( (b[1] + b[3] + 4) / 8 ), 0}; + a[3] = v4i{ uint16_t( (r[0] + r[2] + 4) / 8 ), uint16_t( (g[0] + g[2] + 4) / 8 ), uint16_t( (b[0] + b[2] + 4) / 8 ), 0}; +#endif +} + +static etcpak_force_inline void CalcErrorBlock( const uint8_t* data, unsigned int err[4][4] ) +{ +#ifdef __SSE4_1__ + __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0); + __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1); + __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2); + __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3); + + __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF)); + __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF)); + __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF)); + __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF)); + + __m128i d0l = _mm_unpacklo_epi8(dm0, _mm_setzero_si128()); + __m128i d0h = _mm_unpackhi_epi8(dm0, _mm_setzero_si128()); + __m128i d1l = _mm_unpacklo_epi8(dm1, _mm_setzero_si128()); + __m128i d1h = _mm_unpackhi_epi8(dm1, _mm_setzero_si128()); + __m128i d2l = _mm_unpacklo_epi8(dm2, _mm_setzero_si128()); + __m128i d2h = _mm_unpackhi_epi8(dm2, _mm_setzero_si128()); + __m128i d3l = _mm_unpacklo_epi8(dm3, _mm_setzero_si128()); + __m128i d3h = _mm_unpackhi_epi8(dm3, _mm_setzero_si128()); + + __m128i sum0 = _mm_add_epi16(d0l, d1l); + __m128i sum1 = _mm_add_epi16(d0h, d1h); + __m128i sum2 = _mm_add_epi16(d2l, d3l); + __m128i sum3 = _mm_add_epi16(d2h, d3h); + + __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128()); + __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128()); + __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128()); + __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128()); + __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128()); + __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128()); + __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128()); + __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128()); + + __m128i b0 = _mm_add_epi32(sum0l, sum0h); + __m128i b1 = _mm_add_epi32(sum1l, sum1h); + __m128i b2 = _mm_add_epi32(sum2l, sum2h); + __m128i b3 = _mm_add_epi32(sum3l, sum3h); + + __m128i a0 = _mm_add_epi32(b2, b3); + __m128i a1 = _mm_add_epi32(b0, b1); + __m128i a2 = _mm_add_epi32(b1, b3); + __m128i a3 = _mm_add_epi32(b0, b2); + + _mm_storeu_si128((__m128i*)&err[0], a0); + _mm_storeu_si128((__m128i*)&err[1], a1); + _mm_storeu_si128((__m128i*)&err[2], a2); + _mm_storeu_si128((__m128i*)&err[3], a3); +#elif defined __ARM_NEON + uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t()); + uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t()); + uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t()); + uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t()); + + uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) }; + uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) }; + uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) }; + uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) }; + + uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ))), uint16x8_t()); + uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ))), uint16x8_t()); + uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ))), uint16x8_t()); + uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ))), uint16x8_t()); + + uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) }; + uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) }; + uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) }; + uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) }; + + uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]); + uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]); + uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]); + uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]); + + uint32x4_t a0 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b2, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) ); + uint32x4_t a1 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b1) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) ); + uint32x4_t a2 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b1, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) ); + uint32x4_t a3 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b2) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) ); + + vst1q_u32(err[0], a0); + vst1q_u32(err[1], a1); + vst1q_u32(err[2], a2); + vst1q_u32(err[3], a3); +#else + unsigned int terr[4][4]; + + memset(terr, 0, 16 * sizeof(unsigned int)); + + for( int j=0; j<4; j++ ) + { + for( int i=0; i<4; i++ ) + { + int index = (j & 2) + (i >> 1); + unsigned int d = *data++; + terr[index][0] += d; + d = *data++; + terr[index][1] += d; + d = *data++; + terr[index][2] += d; + data++; + } + } + + for( int i=0; i<3; i++ ) + { + err[0][i] = terr[2][i] + terr[3][i]; + err[1][i] = terr[0][i] + terr[1][i]; + err[2][i] = terr[1][i] + terr[3][i]; + err[3][i] = terr[0][i] + terr[2][i]; + } + for( int i=0; i<4; i++ ) + { + err[i][3] = 0; + } +#endif +} + +static etcpak_force_inline unsigned int CalcError( const unsigned int block[4], const v4i& average ) +{ + unsigned int err = 0x3FFFFFFF; // Big value to prevent negative values, but small enough to prevent overflow + err -= block[0] * 2 * average[2]; + err -= block[1] * 2 * average[1]; + err -= block[2] * 2 * average[0]; + err += 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) ); + return err; +} + +static etcpak_force_inline void ProcessAverages( v4i* a ) +{ +#ifdef __SSE4_1__ + for( int i=0; i<2; i++ ) + { + __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data()); + + __m128i t = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(31)), _mm_set1_epi16(128)); + + __m128i c = _mm_srli_epi16(_mm_add_epi16(t, _mm_srli_epi16(t, 8)), 8); + + __m128i c1 = _mm_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2)); + __m128i diff = _mm_sub_epi16(c, c1); + diff = _mm_max_epi16(diff, _mm_set1_epi16(-4)); + diff = _mm_min_epi16(diff, _mm_set1_epi16(3)); + + __m128i co = _mm_add_epi16(c1, diff); + + c = _mm_blend_epi16(co, c, 0xF0); + + __m128i a0 = _mm_or_si128(_mm_slli_epi16(c, 3), _mm_srli_epi16(c, 2)); + + _mm_storeu_si128((__m128i*)a[4+i*2].data(), a0); + } + + for( int i=0; i<2; i++ ) + { + __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data()); + + __m128i t0 = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(15)), _mm_set1_epi16(128)); + __m128i t1 = _mm_srli_epi16(_mm_add_epi16(t0, _mm_srli_epi16(t0, 8)), 8); + + __m128i t2 = _mm_or_si128(t1, _mm_slli_epi16(t1, 4)); + + _mm_storeu_si128((__m128i*)a[i*2].data(), t2); + } +#elif defined __ARM_NEON + for( int i=0; i<2; i++ ) + { + int16x8_t d = vld1q_s16((int16_t*)&a[i*2]); + int16x8_t t = vaddq_s16(vmulq_s16(d, vdupq_n_s16(31)), vdupq_n_s16(128)); + int16x8_t c = vshrq_n_s16(vaddq_s16(t, vshrq_n_s16(t, 8)), 8); + + int16x8_t c1 = vcombine_s16(vget_high_s16(c), vget_high_s16(c)); + int16x8_t diff = vsubq_s16(c, c1); + diff = vmaxq_s16(diff, vdupq_n_s16(-4)); + diff = vminq_s16(diff, vdupq_n_s16(3)); + + int16x8_t co = vaddq_s16(c1, diff); + + c = vcombine_s16(vget_low_s16(co), vget_high_s16(c)); + + int16x8_t a0 = vorrq_s16(vshlq_n_s16(c, 3), vshrq_n_s16(c, 2)); + + vst1q_s16((int16_t*)&a[4+i*2], a0); + } + + for( int i=0; i<2; i++ ) + { + int16x8_t d = vld1q_s16((int16_t*)&a[i*2]); + + int16x8_t t0 = vaddq_s16(vmulq_s16(d, vdupq_n_s16(15)), vdupq_n_s16(128)); + int16x8_t t1 = vshrq_n_s16(vaddq_s16(t0, vshrq_n_s16(t0, 8)), 8); + + int16x8_t t2 = vorrq_s16(t1, vshlq_n_s16(t1, 4)); + + vst1q_s16((int16_t*)&a[i*2], t2); + } +#else + for( int i=0; i<2; i++ ) + { + for( int j=0; j<3; j++ ) + { + int32_t c1 = mul8bit( a[i*2+1][j], 31 ); + int32_t c2 = mul8bit( a[i*2][j], 31 ); + + int32_t diff = c2 - c1; + if( diff > 3 ) diff = 3; + else if( diff < -4 ) diff = -4; + + int32_t co = c1 + diff; + + a[5+i*2][j] = ( c1 << 3 ) | ( c1 >> 2 ); + a[4+i*2][j] = ( co << 3 ) | ( co >> 2 ); + } + } + + for( int i=0; i<4; i++ ) + { + a[i][0] = g_avg2[mul8bit( a[i][0], 15 )]; + a[i][1] = g_avg2[mul8bit( a[i][1], 15 )]; + a[i][2] = g_avg2[mul8bit( a[i][2], 15 )]; + } +#endif +} + +static etcpak_force_inline void EncodeAverages( uint64_t& _d, const v4i* a, size_t idx ) +{ + auto d = _d; + d |= ( idx << 24 ); + size_t base = idx << 1; + + if( ( idx & 0x2 ) == 0 ) + { + for( int i=0; i<3; i++ ) + { + d |= uint64_t( a[base+0][i] >> 4 ) << ( i*8 ); + d |= uint64_t( a[base+1][i] >> 4 ) << ( i*8 + 4 ); + } + } + else + { + for( int i=0; i<3; i++ ) + { + d |= uint64_t( a[base+1][i] & 0xF8 ) << ( i*8 ); + int32_t c = ( ( a[base+0][i] & 0xF8 ) - ( a[base+1][i] & 0xF8 ) ) >> 3; + c &= ~0xFFFFFFF8; + d |= ((uint64_t)c) << ( i*8 ); + } + } + _d = d; +} + +static etcpak_force_inline uint64_t CheckSolid( const uint8_t* src ) +{ +#ifdef __SSE4_1__ + __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0); + __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1); + __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2); + __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3); + + __m128i c = _mm_shuffle_epi32(d0, _MM_SHUFFLE(0, 0, 0, 0)); + + __m128i c0 = _mm_cmpeq_epi8(d0, c); + __m128i c1 = _mm_cmpeq_epi8(d1, c); + __m128i c2 = _mm_cmpeq_epi8(d2, c); + __m128i c3 = _mm_cmpeq_epi8(d3, c); + + __m128i m0 = _mm_and_si128(c0, c1); + __m128i m1 = _mm_and_si128(c2, c3); + __m128i m = _mm_and_si128(m0, m1); + + if (!_mm_testc_si128(m, _mm_set1_epi32(-1))) + { + return 0; + } +#elif defined __ARM_NEON + int32x4_t d0 = vld1q_s32((int32_t*)src + 0); + int32x4_t d1 = vld1q_s32((int32_t*)src + 4); + int32x4_t d2 = vld1q_s32((int32_t*)src + 8); + int32x4_t d3 = vld1q_s32((int32_t*)src + 12); + + int32x4_t c = vdupq_n_s32(d0[0]); + + int32x4_t c0 = vreinterpretq_s32_u32(vceqq_s32(d0, c)); + int32x4_t c1 = vreinterpretq_s32_u32(vceqq_s32(d1, c)); + int32x4_t c2 = vreinterpretq_s32_u32(vceqq_s32(d2, c)); + int32x4_t c3 = vreinterpretq_s32_u32(vceqq_s32(d3, c)); + + int32x4_t m0 = vandq_s32(c0, c1); + int32x4_t m1 = vandq_s32(c2, c3); + int64x2_t m = vreinterpretq_s64_s32(vandq_s32(m0, m1)); + + if (m[0] != -1 || m[1] != -1) + { + return 0; + } +#else + const uint8_t* ptr = src + 4; + for( int i=1; i<16; i++ ) + { + if( memcmp( src, ptr, 4 ) != 0 ) + { + return 0; + } + ptr += 4; + } +#endif + return 0x02000000 | + ( (unsigned int)( src[0] & 0xF8 ) << 16 ) | + ( (unsigned int)( src[1] & 0xF8 ) << 8 ) | + ( (unsigned int)( src[2] & 0xF8 ) ); +} + +static etcpak_force_inline void PrepareAverages( v4i a[8], const uint8_t* src, unsigned int err[4] ) +{ + Average( src, a ); + ProcessAverages( a ); + + unsigned int errblock[4][4]; + CalcErrorBlock( src, errblock ); + + for( int i=0; i<4; i++ ) + { + err[i/2] += CalcError( errblock[i], a[i] ); + err[2+i/2] += CalcError( errblock[i], a[i+4] ); + } +} + +static etcpak_force_inline void FindBestFit( uint64_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data ) +{ + for( size_t i=0; i<16; i++ ) + { + uint16_t* sel = tsel[i]; + unsigned int bid = id[i]; + uint64_t* ter = terr[bid%2]; + + uint8_t b = *data++; + uint8_t g = *data++; + uint8_t r = *data++; + data++; + + int dr = a[bid][0] - r; + int dg = a[bid][1] - g; + int db = a[bid][2] - b; + +#ifdef __SSE4_1__ + // Reference implementation + + __m128i pix = _mm_set1_epi32(dr * 77 + dg * 151 + db * 28); + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + __m128i error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[0])); + __m128i error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[1])); + __m128i error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[0])); + __m128i error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[1])); + + __m128i index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1)); + __m128i minError0 = _mm_min_epi32(error0, error1); + + __m128i index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2)); + __m128i minError1 = _mm_min_epi32(error2, error3); + + __m128i minIndex0 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0)); + __m128i minError = _mm_min_epi32(minError0, minError1); + + // Squaring the minimum error to produce correct values when adding + __m128i minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0)); + __m128i squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow); + squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0)); + _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow); + __m128i minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2)); + __m128i squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh); + squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1)); + _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[2])); + error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[3])); + error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[2])); + error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[3])); + + index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1)); + minError0 = _mm_min_epi32(error0, error1); + + index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2)); + minError1 = _mm_min_epi32(error2, error3); + + __m128i minIndex1 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0)); + minError = _mm_min_epi32(minError0, minError1); + + // Squaring the minimum error to produce correct values when adding + minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0)); + squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow); + squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 2)); + _mm_storeu_si128(((__m128i*)ter) + 2, squareErrorLow); + minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2)); + squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh); + squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 3)); + _mm_storeu_si128(((__m128i*)ter) + 3, squareErrorHigh); + __m128i minIndex = _mm_packs_epi32(minIndex0, minIndex1); + _mm_storeu_si128((__m128i*)sel, minIndex); +#elif defined __ARM_NEON + int32x4_t pix = vdupq_n_s32(dr * 77 + dg * 151 + db * 28); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + uint32x4_t error0 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[0]))); + uint32x4_t error1 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[1]))); + uint32x4_t error2 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[0]))); + uint32x4_t error3 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[1]))); + + uint32x4_t index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1)); + uint32x4_t minError0 = vminq_u32(error0, error1); + + uint32x4_t index1 = vreinterpretq_u32_s32(vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2)))); + uint32x4_t minError1 = vminq_u32(error2, error3); + + uint32x4_t blendMask = vcltq_u32(minError1, minError0); + uint32x4_t minIndex0 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask)); + uint32x4_t minError = vminq_u32(minError0, minError1); + + // Squaring the minimum error to produce correct values when adding + uint32x4_t squareErrorLow = vmulq_u32(minError, minError); + uint32x4_t squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError))), 1); + uint32x4x2_t squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh); + uint64x2x2_t squareError = { vreinterpretq_u64_u32(squareErrorZip.val[0]), vreinterpretq_u64_u32(squareErrorZip.val[1]) }; + squareError.val[0] = vaddq_u64(squareError.val[0], vld1q_u64(ter + 0)); + squareError.val[1] = vaddq_u64(squareError.val[1], vld1q_u64(ter + 2)); + vst1q_u64(ter + 0, squareError.val[0]); + vst1q_u64(ter + 2, squareError.val[1]); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + error0 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[2]))); + error1 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[3]))); + error2 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[2]))); + error3 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[3]))); + + index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1)); + minError0 = vminq_u32(error0, error1); + + index1 = vreinterpretq_u32_s32( vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2))) ); + minError1 = vminq_u32(error2, error3); + + blendMask = vcltq_u32(minError1, minError0); + uint32x4_t minIndex1 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask)); + minError = vminq_u32(minError0, minError1); + + // Squaring the minimum error to produce correct values when adding + squareErrorLow = vmulq_u32(minError, minError); + squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32( vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError)) ), 1 ); + squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh); + squareError.val[0] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[0] ), vld1q_u64(ter + 4)); + squareError.val[1] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[1] ), vld1q_u64(ter + 6)); + vst1q_u64(ter + 4, squareError.val[0]); + vst1q_u64(ter + 6, squareError.val[1]); + + uint16x8_t minIndex = vcombine_u16(vqmovn_u32(minIndex0), vqmovn_u32(minIndex1)); + vst1q_u16(sel, minIndex); +#else + int pix = dr * 77 + dg * 151 + db * 28; + + for( int t=0; t<8; t++ ) + { + const int64_t* tab = g_table256[t]; + unsigned int idx = 0; + uint64_t err = sq( tab[0] + pix ); + for( int j=1; j<4; j++ ) + { + uint64_t local = sq( tab[j] + pix ); + if( local < err ) + { + err = local; + idx = j; + } + } + *sel++ = idx; + *ter++ += err; + } +#endif + } +} + +#if defined __SSE4_1__ || defined __ARM_NEON +// Non-reference implementation, but faster. Produces same results as the AVX2 version +static etcpak_force_inline void FindBestFit( uint32_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data ) +{ + for( size_t i=0; i<16; i++ ) + { + uint16_t* sel = tsel[i]; + unsigned int bid = id[i]; + uint32_t* ter = terr[bid%2]; + + uint8_t b = *data++; + uint8_t g = *data++; + uint8_t r = *data++; + data++; + + int dr = a[bid][0] - r; + int dg = a[bid][1] - g; + int db = a[bid][2] - b; + +#ifdef __SSE4_1__ + // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16 + // This produces slightly different results, but is significant faster + __m128i pixel = _mm_set1_epi16(dr * 38 + dg * 76 + db * 14); + __m128i pix = _mm_abs_epi16(pixel); + + // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same. + // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries. + __m128i error0 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[0])); + __m128i error1 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[1])); + + __m128i index = _mm_and_si128(_mm_cmplt_epi16(error1, error0), _mm_set1_epi16(1)); + __m128i minError = _mm_min_epi16(error0, error1); + + // Exploiting symmetry of the selector table and use the sign bit + // This produces slightly different results, but is needed to produce same results as AVX2 implementation + __m128i indexBit = _mm_andnot_si128(_mm_srli_epi16(pixel, 15), _mm_set1_epi8(-1)); + __m128i minIndex = _mm_or_si128(index, _mm_add_epi16(indexBit, indexBit)); + + // Squaring the minimum error to produce correct values when adding + __m128i squareErrorLo = _mm_mullo_epi16(minError, minError); + __m128i squareErrorHi = _mm_mulhi_epi16(minError, minError); + + __m128i squareErrorLow = _mm_unpacklo_epi16(squareErrorLo, squareErrorHi); + __m128i squareErrorHigh = _mm_unpackhi_epi16(squareErrorLo, squareErrorHi); + + squareErrorLow = _mm_add_epi32(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0)); + _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow); + squareErrorHigh = _mm_add_epi32(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1)); + _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh); + + _mm_storeu_si128((__m128i*)sel, minIndex); +#elif defined __ARM_NEON + int16x8_t pixel = vdupq_n_s16( dr * 38 + dg * 76 + db * 14 ); + int16x8_t pix = vabsq_s16( pixel ); + + int16x8_t error0 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[0] ) ); + int16x8_t error1 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[1] ) ); + + int16x8_t index = vandq_s16( vreinterpretq_s16_u16( vcltq_s16( error1, error0 ) ), vdupq_n_s16( 1 ) ); + int16x8_t minError = vminq_s16( error0, error1 ); + + int16x8_t indexBit = vandq_s16( vmvnq_s16( vshrq_n_s16( pixel, 15 ) ), vdupq_n_s16( -1 ) ); + int16x8_t minIndex = vorrq_s16( index, vaddq_s16( indexBit, indexBit ) ); + + int16x4_t minErrorLow = vget_low_s16( minError ); + int16x4_t minErrorHigh = vget_high_s16( minError ); + + int32x4_t squareErrorLow = vmull_s16( minErrorLow, minErrorLow ); + int32x4_t squareErrorHigh = vmull_s16( minErrorHigh, minErrorHigh ); + + int32x4_t squareErrorSumLow = vaddq_s32( squareErrorLow, vld1q_s32( (int32_t*)ter ) ); + int32x4_t squareErrorSumHigh = vaddq_s32( squareErrorHigh, vld1q_s32( (int32_t*)ter + 4 ) ); + + vst1q_s32( (int32_t*)ter, squareErrorSumLow ); + vst1q_s32( (int32_t*)ter + 4, squareErrorSumHigh ); + + vst1q_s16( (int16_t*)sel, minIndex ); +#endif + } +} +#endif + +static etcpak_force_inline uint8_t convert6(float f) +{ + int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1; + return (i + 11 - ((i + 11) >> 7) - ((i + 4) >> 7)) >> 3; +} + +static etcpak_force_inline uint8_t convert7(float f) +{ + int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1; + return (i + 9 - ((i + 9) >> 8) - ((i + 6) >> 8)) >> 2; +} + +static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar(const uint8_t* src) +{ + int32_t r = 0; + int32_t g = 0; + int32_t b = 0; + + for (int i = 0; i < 16; ++i) + { + b += src[i * 4 + 0]; + g += src[i * 4 + 1]; + r += src[i * 4 + 2]; + } + + int32_t difRyz = 0; + int32_t difGyz = 0; + int32_t difByz = 0; + int32_t difRxz = 0; + int32_t difGxz = 0; + int32_t difBxz = 0; + + const int32_t scaling[] = { -255, -85, 85, 255 }; + + for (int i = 0; i < 16; ++i) + { + int32_t difB = (static_cast<int>(src[i * 4 + 0]) << 4) - b; + int32_t difG = (static_cast<int>(src[i * 4 + 1]) << 4) - g; + int32_t difR = (static_cast<int>(src[i * 4 + 2]) << 4) - r; + + difRyz += difR * scaling[i % 4]; + difGyz += difG * scaling[i % 4]; + difByz += difB * scaling[i % 4]; + + difRxz += difR * scaling[i / 4]; + difGxz += difG * scaling[i / 4]; + difBxz += difB * scaling[i / 4]; + } + + const float scale = -4.0f / ((255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f); + + float aR = difRxz * scale; + float aG = difGxz * scale; + float aB = difBxz * scale; + + float bR = difRyz * scale; + float bG = difGyz * scale; + float bB = difByz * scale; + + float dR = r * (4.0f / 16.0f); + float dG = g * (4.0f / 16.0f); + float dB = b * (4.0f / 16.0f); + + // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y; + float cofR = std::fma(aR, 255.0f, std::fma(bR, 255.0f, dR)); + float cofG = std::fma(aG, 255.0f, std::fma(bG, 255.0f, dG)); + float cofB = std::fma(aB, 255.0f, std::fma(bB, 255.0f, dB)); + float chfR = std::fma(aR, -425.0f, std::fma(bR, 255.0f, dR)); + float chfG = std::fma(aG, -425.0f, std::fma(bG, 255.0f, dG)); + float chfB = std::fma(aB, -425.0f, std::fma(bB, 255.0f, dB)); + float cvfR = std::fma(aR, 255.0f, std::fma(bR, -425.0f, dR)); + float cvfG = std::fma(aG, 255.0f, std::fma(bG, -425.0f, dG)); + float cvfB = std::fma(aB, 255.0f, std::fma(bB, -425.0f, dB)); + + // convert to r6g7b6 + int32_t coR = convert6(cofR); + int32_t coG = convert7(cofG); + int32_t coB = convert6(cofB); + int32_t chR = convert6(chfR); + int32_t chG = convert7(chfG); + int32_t chB = convert6(chfB); + int32_t cvR = convert6(cvfR); + int32_t cvG = convert7(cvfG); + int32_t cvB = convert6(cvfB); + + // Error calculation + auto ro0 = coR; + auto go0 = coG; + auto bo0 = coB; + auto ro1 = (ro0 >> 4) | (ro0 << 2); + auto go1 = (go0 >> 6) | (go0 << 1); + auto bo1 = (bo0 >> 4) | (bo0 << 2); + auto ro2 = (ro1 << 2) + 2; + auto go2 = (go1 << 2) + 2; + auto bo2 = (bo1 << 2) + 2; + + auto rh0 = chR; + auto gh0 = chG; + auto bh0 = chB; + auto rh1 = (rh0 >> 4) | (rh0 << 2); + auto gh1 = (gh0 >> 6) | (gh0 << 1); + auto bh1 = (bh0 >> 4) | (bh0 << 2); + + auto rh2 = rh1 - ro1; + auto gh2 = gh1 - go1; + auto bh2 = bh1 - bo1; + + auto rv0 = cvR; + auto gv0 = cvG; + auto bv0 = cvB; + auto rv1 = (rv0 >> 4) | (rv0 << 2); + auto gv1 = (gv0 >> 6) | (gv0 << 1); + auto bv1 = (bv0 >> 4) | (bv0 << 2); + + auto rv2 = rv1 - ro1; + auto gv2 = gv1 - go1; + auto bv2 = bv1 - bo1; + + uint64_t error = 0; + + for (int i = 0; i < 16; ++i) + { + int32_t cR = clampu8((rh2 * (i / 4) + rv2 * (i % 4) + ro2) >> 2); + int32_t cG = clampu8((gh2 * (i / 4) + gv2 * (i % 4) + go2) >> 2); + int32_t cB = clampu8((bh2 * (i / 4) + bv2 * (i % 4) + bo2) >> 2); + + int32_t difB = static_cast<int>(src[i * 4 + 0]) - cB; + int32_t difG = static_cast<int>(src[i * 4 + 1]) - cG; + int32_t difR = static_cast<int>(src[i * 4 + 2]) - cR; + + int32_t dif = difR * 38 + difG * 76 + difB * 14; + + error += dif * dif; + } + + /**/ + uint32_t rgbv = cvB | (cvG << 6) | (cvR << 13); + uint32_t rgbh = chB | (chG << 6) | (chR << 13); + uint32_t hi = rgbv | ((rgbh & 0x1FFF) << 19); + uint32_t lo = (chR & 0x1) | 0x2 | ((chR << 1) & 0x7C); + lo |= ((coB & 0x07) << 7) | ((coB & 0x18) << 8) | ((coB & 0x20) << 11); + lo |= ((coG & 0x3F) << 17) | ((coG & 0x40) << 18); + lo |= coR << 25; + + const auto idx = (coR & 0x20) | ((coG & 0x20) >> 1) | ((coB & 0x1E) >> 1); + + lo |= g_flags[idx]; + + uint64_t result = static_cast<uint32_t>(_bswap(lo)); + result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32; + + return std::make_pair(result, error); +} + +#ifdef __ARM_NEON + +static etcpak_force_inline int32x2_t Planar_NEON_DifXZ( int16x8_t dif_lo, int16x8_t dif_hi ) +{ + int32x4_t dif0 = vmull_n_s16( vget_low_s16( dif_lo ), -255 ); + int32x4_t dif1 = vmull_n_s16( vget_high_s16( dif_lo ), -85 ); + int32x4_t dif2 = vmull_n_s16( vget_low_s16( dif_hi ), 85 ); + int32x4_t dif3 = vmull_n_s16( vget_high_s16( dif_hi ), 255 ); + int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) ); + +#ifndef __aarch64__ + int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) ); + return vpadd_s32( dif5, dif5 ); +#else + return vdup_n_s32( vaddvq_s32( dif4 ) ); +#endif +} + +static etcpak_force_inline int32x2_t Planar_NEON_DifYZ( int16x8_t dif_lo, int16x8_t dif_hi ) +{ + int16x4_t scaling = { -255, -85, 85, 255 }; + int32x4_t dif0 = vmull_s16( vget_low_s16( dif_lo ), scaling ); + int32x4_t dif1 = vmull_s16( vget_high_s16( dif_lo ), scaling ); + int32x4_t dif2 = vmull_s16( vget_low_s16( dif_hi ), scaling ); + int32x4_t dif3 = vmull_s16( vget_high_s16( dif_hi ), scaling ); + int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) ); + +#ifndef __aarch64__ + int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) ); + return vpadd_s32( dif5, dif5 ); +#else + return vdup_n_s32( vaddvq_s32( dif4 ) ); +#endif +} + +static etcpak_force_inline int16x8_t Planar_NEON_SumWide( uint8x16_t src ) +{ + uint16x8_t accu8 = vpaddlq_u8( src ); +#ifndef __aarch64__ + uint16x4_t accu4 = vpadd_u16( vget_low_u16( accu8 ), vget_high_u16( accu8 ) ); + uint16x4_t accu2 = vpadd_u16( accu4, accu4 ); + uint16x4_t accu1 = vpadd_u16( accu2, accu2 ); + return vreinterpretq_s16_u16( vcombine_u16( accu1, accu1 ) ); +#else + return vdupq_n_s16( vaddvq_u16( accu8 ) ); +#endif +} + +static etcpak_force_inline int16x8_t convert6_NEON( int32x4_t lo, int32x4_t hi ) +{ + uint16x8_t x = vcombine_u16( vqmovun_s32( lo ), vqmovun_s32( hi ) ); + int16x8_t i = vreinterpretq_s16_u16( vshrq_n_u16( vqshlq_n_u16( x, 6 ), 6) ); // clamp 0-1023 + i = vhsubq_s16( i, vdupq_n_s16( 15 ) ); + + int16x8_t ip11 = vaddq_s16( i, vdupq_n_s16( 11 ) ); + int16x8_t ip4 = vaddq_s16( i, vdupq_n_s16( 4 ) ); + + return vshrq_n_s16( vsubq_s16( vsubq_s16( ip11, vshrq_n_s16( ip11, 7 ) ), vshrq_n_s16( ip4, 7) ), 3 ); +} + +static etcpak_force_inline int16x4_t convert7_NEON( int32x4_t x ) +{ + int16x4_t i = vreinterpret_s16_u16( vshr_n_u16( vqshl_n_u16( vqmovun_s32( x ), 6 ), 6 ) ); // clamp 0-1023 + i = vhsub_s16( i, vdup_n_s16( 15 ) ); + + int16x4_t p9 = vadd_s16( i, vdup_n_s16( 9 ) ); + int16x4_t p6 = vadd_s16( i, vdup_n_s16( 6 ) ); + return vshr_n_s16( vsub_s16( vsub_s16( p9, vshr_n_s16( p9, 8 ) ), vshr_n_s16( p6, 8 ) ), 2 ); +} + +static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint8_t* src ) +{ + uint8x16x4_t srcBlock = vld4q_u8( src ); + + int16x8_t bSumWide = Planar_NEON_SumWide( srcBlock.val[0] ); + int16x8_t gSumWide = Planar_NEON_SumWide( srcBlock.val[1] ); + int16x8_t rSumWide = Planar_NEON_SumWide( srcBlock.val[2] ); + + int16x8_t dif_R_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[2] ), 4) ), rSumWide ); + int16x8_t dif_R_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[2] ), 4) ), rSumWide ); + + int16x8_t dif_G_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[1] ), 4 ) ), gSumWide ); + int16x8_t dif_G_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[1] ), 4 ) ), gSumWide ); + + int16x8_t dif_B_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[0] ), 4) ), bSumWide ); + int16x8_t dif_B_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[0] ), 4) ), bSumWide ); + + int32x2x2_t dif_xz_z = vzip_s32( vzip_s32( Planar_NEON_DifXZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifXZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifXZ( dif_G_lo, dif_G_hi ) ); + int32x4_t dif_xz = vcombine_s32( dif_xz_z.val[0], dif_xz_z.val[1] ); + int32x2x2_t dif_yz_z = vzip_s32( vzip_s32( Planar_NEON_DifYZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifYZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifYZ( dif_G_lo, dif_G_hi ) ); + int32x4_t dif_yz = vcombine_s32( dif_yz_z.val[0], dif_yz_z.val[1] ); + + const float fscale = -4.0f / ( (255 * 255 * 8.0f + 85 * 85 * 8.0f ) * 16.0f ); + float32x4_t fa = vmulq_n_f32( vcvtq_f32_s32( dif_xz ), fscale ); + float32x4_t fb = vmulq_n_f32( vcvtq_f32_s32( dif_yz ), fscale ); + int16x4_t bgrgSum = vzip_s16( vzip_s16( vget_low_s16( bSumWide ), vget_low_s16( rSumWide ) ).val[0], vget_low_s16( gSumWide ) ).val[0]; + float32x4_t fd = vmulq_n_f32( vcvtq_f32_s32( vmovl_s16( bgrgSum ) ), 4.0f / 16.0f); + + float32x4_t cof = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, 255.0f ); + float32x4_t chf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, -425.0f ); + float32x4_t cvf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, -425.0f ), fa, 255.0f ); + + int32x4_t coi = vcvtq_s32_f32( cof ); + int32x4_t chi = vcvtq_s32_f32( chf ); + int32x4_t cvi = vcvtq_s32_f32( cvf ); + + int32x4x2_t tr_hv = vtrnq_s32( chi, cvi ); + int32x4x2_t tr_o = vtrnq_s32( coi, coi ); + + int16x8_t c_hvoo_br_6 = convert6_NEON( tr_hv.val[0], tr_o.val[0] ); + int16x4_t c_hvox_g_7 = convert7_NEON( vcombine_s32( vget_low_s32( tr_hv.val[1] ), vget_low_s32( tr_o.val[1] ) ) ); + int16x8_t c_hvoo_br_8 = vorrq_s16( vshrq_n_s16( c_hvoo_br_6, 4 ), vshlq_n_s16( c_hvoo_br_6, 2 ) ); + int16x4_t c_hvox_g_8 = vorr_s16( vshr_n_s16( c_hvox_g_7, 6 ), vshl_n_s16( c_hvox_g_7, 1 ) ); + + int16x4_t rec_gxbr_o = vext_s16( c_hvox_g_8, vget_high_s16( c_hvoo_br_8 ), 3 ); + + rec_gxbr_o = vadd_s16( vshl_n_s16( rec_gxbr_o, 2 ), vdup_n_s16( 2 ) ); + int16x8_t rec_ro_wide = vdupq_lane_s16( rec_gxbr_o, 3 ); + int16x8_t rec_go_wide = vdupq_lane_s16( rec_gxbr_o, 0 ); + int16x8_t rec_bo_wide = vdupq_lane_s16( rec_gxbr_o, 1 ); + + int16x4_t br_hv2 = vsub_s16( vget_low_s16( c_hvoo_br_8 ), vget_high_s16( c_hvoo_br_8 ) ); + int16x4_t gg_hv2 = vsub_s16( c_hvox_g_8, vdup_lane_s16( c_hvox_g_8, 2 ) ); + + int16x8_t scaleh_lo = { 0, 0, 0, 0, 1, 1, 1, 1 }; + int16x8_t scaleh_hi = { 2, 2, 2, 2, 3, 3, 3, 3 }; + int16x8_t scalev = { 0, 1, 2, 3, 0, 1, 2, 3 }; + + int16x8_t rec_r_1 = vmlaq_lane_s16( rec_ro_wide, scalev, br_hv2, 3 ); + int16x8_t rec_r_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_lo, br_hv2, 2 ), 2 ) ) ); + int16x8_t rec_r_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_hi, br_hv2, 2 ), 2 ) ) ); + + int16x8_t rec_b_1 = vmlaq_lane_s16( rec_bo_wide, scalev, br_hv2, 1 ); + int16x8_t rec_b_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_lo, br_hv2, 0 ), 2 ) ) ); + int16x8_t rec_b_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_hi, br_hv2, 0 ), 2 ) ) ); + + int16x8_t rec_g_1 = vmlaq_lane_s16( rec_go_wide, scalev, gg_hv2, 1 ); + int16x8_t rec_g_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_lo, gg_hv2, 0 ), 2 ) ) ); + int16x8_t rec_g_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_hi, gg_hv2, 0 ), 2 ) ) ); + + int16x8_t dif_r_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[2] ) ) ), rec_r_lo ); + int16x8_t dif_r_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[2] ) ) ), rec_r_hi ); + + int16x8_t dif_g_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[1] ) ) ), rec_g_lo ); + int16x8_t dif_g_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[1] ) ) ), rec_g_hi ); + + int16x8_t dif_b_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[0] ) ) ), rec_b_lo ); + int16x8_t dif_b_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[0] ) ) ), rec_b_hi ); + + int16x8_t dif_lo = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_lo, 38 ), dif_g_lo, 76 ), dif_b_lo, 14 ); + int16x8_t dif_hi = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_hi, 38 ), dif_g_hi, 76 ), dif_b_hi, 14 ); + + int16x4_t tmpDif = vget_low_s16( dif_lo ); + int32x4_t difsq_0 = vmull_s16( tmpDif, tmpDif ); + tmpDif = vget_high_s16( dif_lo ); + int32x4_t difsq_1 = vmull_s16( tmpDif, tmpDif ); + tmpDif = vget_low_s16( dif_hi ); + int32x4_t difsq_2 = vmull_s16( tmpDif, tmpDif ); + tmpDif = vget_high_s16( dif_hi ); + int32x4_t difsq_3 = vmull_s16( tmpDif, tmpDif ); + + uint32x4_t difsq_5 = vaddq_u32( vreinterpretq_u32_s32( difsq_0 ), vreinterpretq_u32_s32( difsq_1 ) ); + uint32x4_t difsq_6 = vaddq_u32( vreinterpretq_u32_s32( difsq_2 ), vreinterpretq_u32_s32( difsq_3) ); + + uint64x2_t difsq_7 = vaddl_u32( vget_low_u32( difsq_5 ), vget_high_u32( difsq_5 ) ); + uint64x2_t difsq_8 = vaddl_u32( vget_low_u32( difsq_6 ), vget_high_u32( difsq_6 ) ); + + uint64x2_t difsq_9 = vaddq_u64( difsq_7, difsq_8 ); + +#ifdef __aarch64__ + uint64_t error = vaddvq_u64( difsq_9 ); +#else + uint64_t error = vgetq_lane_u64( difsq_9, 0 ) + vgetq_lane_u64( difsq_9, 1 ); +#endif + + int32_t coR = c_hvoo_br_6[6]; + int32_t coG = c_hvox_g_7[2]; + int32_t coB = c_hvoo_br_6[4]; + + int32_t chR = c_hvoo_br_6[2]; + int32_t chG = c_hvox_g_7[0]; + int32_t chB = c_hvoo_br_6[0]; + + int32_t cvR = c_hvoo_br_6[3]; + int32_t cvG = c_hvox_g_7[1]; + int32_t cvB = c_hvoo_br_6[1]; + + uint32_t rgbv = cvB | ( cvG << 6 ) | ( cvR << 13 ); + uint32_t rgbh = chB | ( chG << 6 ) | ( chR << 13 ); + uint32_t hi = rgbv | ( ( rgbh & 0x1FFF ) << 19 ); + uint32_t lo = ( chR & 0x1 ) | 0x2 | ( ( chR << 1 ) & 0x7C ); + lo |= ( ( coB & 0x07 ) << 7 ) | ( ( coB & 0x18 ) << 8 ) | ( ( coB & 0x20 ) << 11 ); + lo |= ( ( coG & 0x3F) << 17) | ( (coG & 0x40 ) << 18 ); + lo |= coR << 25; + + const auto idx = ( coR & 0x20 ) | ( ( coG & 0x20 ) >> 1 ) | ( ( coB & 0x1E ) >> 1 ); + + lo |= g_flags[idx]; + + uint64_t result = static_cast<uint32_t>( _bswap(lo) ); + result |= static_cast<uint64_t>( static_cast<uint32_t>( _bswap( hi ) ) ) << 32; + + return std::make_pair( result, error ); +} + +#endif + +template<class T, class S> +static etcpak_force_inline uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id, const uint64_t value, const uint64_t error) +{ + size_t tidx[2]; + tidx[0] = GetLeastError( terr[0], 8 ); + tidx[1] = GetLeastError( terr[1], 8 ); + + if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error) + { + return value; + } + + d |= tidx[0] << 26; + d |= tidx[1] << 29; + for( int i=0; i<16; i++ ) + { + uint64_t t = tsel[i][tidx[id[i]%2]]; + d |= ( t & 0x1 ) << ( i + 32 ); + d |= ( t & 0x2 ) << ( i + 47 ); + } + + return FixByteOrder(d); +} + +} + +static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src ) +{ +#ifdef __AVX2__ + uint64_t d = CheckSolid_AVX2( src ); + if( d != 0 ) return d; + + alignas(32) v4i a[8]; + + __m128i err0 = PrepareAverages_AVX2( a, src ); + + // Get index of minimum error (err0) + __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1)); + __m128i errMin0 = _mm_min_epu32(err0, err1); + + __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2)); + __m128i errMin2 = _mm_min_epu32(errMin1, errMin0); + + __m128i errMask = _mm_cmpeq_epi32(errMin2, err0); + + uint32_t mask = _mm_movemask_epi8(errMask); + + uint32_t idx = _bit_scan_forward(mask) >> 2; + + d |= EncodeAverages_AVX2( a, idx ); + + alignas(32) uint32_t terr[2][8] = {}; + alignas(32) uint32_t tsel[8]; + + if ((idx == 0) || (idx == 2)) + { + FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src ); + } + else + { + FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src ); + } + + return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1 ); +#else + uint64_t d = CheckSolid( src ); + if( d != 0 ) return d; + + v4i a[8]; + unsigned int err[4] = {}; + PrepareAverages( a, src, err ); + size_t idx = GetLeastError( err, 4 ); + EncodeAverages( d, a, idx ); + +#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION + uint32_t terr[2][8] = {}; +#else + uint64_t terr[2][8] = {}; +#endif + uint16_t tsel[16][8]; + auto id = g_id[idx]; + FindBestFit( terr, tsel, a, id, src ); + + return FixByteOrder( EncodeSelectors( d, terr, tsel, id ) ); +#endif +} + +static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src ) +{ +#ifdef __AVX2__ + uint64_t d = CheckSolid_AVX2( src ); + if( d != 0 ) return d; + + auto plane = Planar_AVX2( src ); + + alignas(32) v4i a[8]; + + __m128i err0 = PrepareAverages_AVX2( a, plane.sum4 ); + + // Get index of minimum error (err0) + __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1)); + __m128i errMin0 = _mm_min_epu32(err0, err1); + + __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2)); + __m128i errMin2 = _mm_min_epu32(errMin1, errMin0); + + __m128i errMask = _mm_cmpeq_epi32(errMin2, err0); + + uint32_t mask = _mm_movemask_epi8(errMask); + + size_t idx = _bit_scan_forward(mask) >> 2; + + d = EncodeAverages_AVX2( a, idx ); + + alignas(32) uint32_t terr[2][8] = {}; + alignas(32) uint32_t tsel[8]; + + if ((idx == 0) || (idx == 2)) + { + FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src ); + } + else + { + FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src ); + } + + return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1, plane.plane, plane.error ); +#else + uint64_t d = CheckSolid( src ); + if (d != 0) return d; + +#ifdef __ARM_NEON + auto result = Planar_NEON( src ); +#else + auto result = Planar( src ); +#endif + + v4i a[8]; + unsigned int err[4] = {}; + PrepareAverages( a, src, err ); + size_t idx = GetLeastError( err, 4 ); + EncodeAverages( d, a, idx ); + +#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION + uint32_t terr[2][8] = {}; +#else + uint64_t terr[2][8] = {}; +#endif + uint16_t tsel[16][8]; + auto id = g_id[idx]; + FindBestFit( terr, tsel, a, id, src ); + + return EncodeSelectors( d, terr, tsel, id, result.first, result.second ); +#endif +} + +#ifdef __SSE4_1__ +template<int K> +static etcpak_force_inline __m128i Widen( const __m128i src ) +{ + static_assert( K >= 0 && K <= 7, "Index out of range" ); + + __m128i tmp; + switch( K ) + { + case 0: + tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) ); + case 1: + tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) ); + case 2: + tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) ); + case 3: + tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) ); + case 4: + tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) ); + case 5: + tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) ); + case 6: + tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) ); + case 7: + tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) ); + return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) ); + } +} + +static etcpak_force_inline int GetMulSel( int sel ) +{ + switch( sel ) + { + case 0: + return 0; + case 1: + case 2: + case 3: + return 1; + case 4: + return 2; + case 5: + case 6: + case 7: + return 3; + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + return 4; + case 14: + case 15: + return 5; + } +} + +#endif + +#ifdef __ARM_NEON + +static constexpr etcpak_force_inline int GetMulSel(int sel) +{ + return ( sel < 1 ) ? 0 : ( sel < 4 ) ? 1 : ( sel < 5 ) ? 2 : ( sel < 8 ) ? 3 : ( sel < 14 ) ? 4 : 5; +} + +static constexpr int ClampConstant( int x, int min, int max ) +{ + return x < min ? min : x > max ? max : x; +} + +template <int Index> +etcpak_force_inline static uint16x8_t ErrorProbe_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock ) +{ + uint8x8_t srcValWide; +#ifndef __aarch64__ + if( Index < 8 ) + srcValWide = vdup_lane_u8( vget_low_u8( alphaBlock ), ClampConstant( Index, 0, 8 ) ); + else + srcValWide = vdup_lane_u8( vget_high_u8( alphaBlock ), ClampConstant( Index - 8, 0, 8 ) ); +#else + srcValWide = vdup_laneq_u8( alphaBlock, Index ); +#endif + + uint8x8_t deltaVal = vabd_u8( srcValWide, recVal ); + return vmull_u8( deltaVal, deltaVal ); +} + +etcpak_force_inline static uint16_t MinError_EAC_NEON( uint16x8_t errProbe ) +{ +#ifndef __aarch64__ + uint16x4_t tmpErr = vpmin_u16( vget_low_u16( errProbe ), vget_high_u16( errProbe ) ); + tmpErr = vpmin_u16( tmpErr, tmpErr ); + return vpmin_u16( tmpErr, tmpErr )[0]; +#else + return vminvq_u16( errProbe ); +#endif +} + +template <int Index> +etcpak_force_inline static uint64_t MinErrorIndex_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock ) +{ + uint16x8_t errProbe = ErrorProbe_EAC_NEON<Index>( recVal, alphaBlock ); + uint16x8_t minErrMask = vceqq_u16( errProbe, vdupq_n_u16( MinError_EAC_NEON( errProbe ) ) ); + uint64_t idx = __builtin_ctzll( vget_lane_u64( vreinterpret_u64_u8( vqmovn_u16( minErrMask ) ), 0 ) ); + idx >>= 3; + idx <<= 45 - Index * 3; + + return idx; +} + +template <int Index> +etcpak_force_inline static int16x8_t WidenMultiplier_EAC_NEON( int16x8_t multipliers ) +{ + constexpr int Lane = GetMulSel( Index ); +#ifndef __aarch64__ + if( Lane < 4 ) + return vdupq_lane_s16( vget_low_s16( multipliers ), ClampConstant( Lane, 0, 4 ) ); + else + return vdupq_lane_s16( vget_high_s16( multipliers ), ClampConstant( Lane - 4, 0, 4 ) ); +#else + return vdupq_laneq_s16( multipliers, Lane ); +#endif +} + +#endif + +static etcpak_force_inline uint64_t ProcessAlpha_ETC2( const uint8_t* src ) +{ +#if defined __SSE4_1__ + // Check solid + __m128i s = _mm_loadu_si128( (__m128i*)src ); + __m128i solidCmp = _mm_set1_epi8( src[0] ); + __m128i cmpRes = _mm_cmpeq_epi8( s, solidCmp ); + if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) ) + { + return src[0]; + } + + // Calculate min, max + __m128i s1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 2, 3, 0, 1 ) ); + __m128i max1 = _mm_max_epu8( s, s1 ); + __m128i min1 = _mm_min_epu8( s, s1 ); + __m128i smax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i smin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) ); + __m128i max2 = _mm_max_epu8( max1, smax2 ); + __m128i min2 = _mm_min_epu8( min1, smin2 ); + __m128i smax3 = _mm_alignr_epi8( max2, max2, 2 ); + __m128i smin3 = _mm_alignr_epi8( min2, min2, 2 ); + __m128i max3 = _mm_max_epu8( max2, smax3 ); + __m128i min3 = _mm_min_epu8( min2, smin3 ); + __m128i smax4 = _mm_alignr_epi8( max3, max3, 1 ); + __m128i smin4 = _mm_alignr_epi8( min3, min3, 1 ); + __m128i max = _mm_max_epu8( max3, smax4 ); + __m128i min = _mm_min_epu8( min3, smin4 ); + __m128i max16 = _mm_unpacklo_epi8( max, _mm_setzero_si128() ); + __m128i min16 = _mm_unpacklo_epi8( min, _mm_setzero_si128() ); + + // src range, mid + __m128i srcRange = _mm_sub_epi16( max16, min16 ); + __m128i srcRangeHalf = _mm_srli_epi16( srcRange, 1 ); + __m128i srcMid = _mm_add_epi16( min16, srcRangeHalf ); + + // multiplier + __m128i mul1 = _mm_mulhi_epi16( srcRange, g_alphaRange_SIMD ); + __m128i mul = _mm_add_epi16( mul1, _mm_set1_epi16( 1 ) ); + + // wide source + __m128i s16_1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 3, 2, 3, 2 ) ); + __m128i s16[2] = { _mm_unpacklo_epi8( s, _mm_setzero_si128() ), _mm_unpacklo_epi8( s16_1, _mm_setzero_si128() ) }; + + __m128i sr[16] = { + Widen<0>( s16[0] ), + Widen<1>( s16[0] ), + Widen<2>( s16[0] ), + Widen<3>( s16[0] ), + Widen<4>( s16[0] ), + Widen<5>( s16[0] ), + Widen<6>( s16[0] ), + Widen<7>( s16[0] ), + Widen<0>( s16[1] ), + Widen<1>( s16[1] ), + Widen<2>( s16[1] ), + Widen<3>( s16[1] ), + Widen<4>( s16[1] ), + Widen<5>( s16[1] ), + Widen<6>( s16[1] ), + Widen<7>( s16[1] ) + }; + +#ifdef __AVX2__ + __m256i srcRangeWide = _mm256_broadcastsi128_si256( srcRange ); + __m256i srcMidWide = _mm256_broadcastsi128_si256( srcMid ); + + __m256i mulWide1 = _mm256_mulhi_epi16( srcRangeWide, g_alphaRange_AVX ); + __m256i mulWide = _mm256_add_epi16( mulWide1, _mm256_set1_epi16( 1 ) ); + + __m256i modMul[8] = { + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ) ), _mm256_setzero_si256() ), + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ) ), _mm256_setzero_si256() ), + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ) ), _mm256_setzero_si256() ), + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ) ), _mm256_setzero_si256() ), + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ) ), _mm256_setzero_si256() ), + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ) ), _mm256_setzero_si256() ), + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ) ), _mm256_setzero_si256() ), + _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ) ), _mm256_setzero_si256() ), + }; + + // find selector + __m256i mulErr = _mm256_setzero_si256(); + for( int j=0; j<16; j++ ) + { + __m256i s16Wide = _mm256_broadcastsi128_si256( sr[j] ); + __m256i err1, err2; + + err1 = _mm256_sub_epi16( s16Wide, modMul[0] ); + __m256i localErr = _mm256_mullo_epi16( err1, err1 ); + + err1 = _mm256_sub_epi16( s16Wide, modMul[1] ); + err2 = _mm256_mullo_epi16( err1, err1 ); + localErr = _mm256_min_epu16( localErr, err2 ); + + err1 = _mm256_sub_epi16( s16Wide, modMul[2] ); + err2 = _mm256_mullo_epi16( err1, err1 ); + localErr = _mm256_min_epu16( localErr, err2 ); + + err1 = _mm256_sub_epi16( s16Wide, modMul[3] ); + err2 = _mm256_mullo_epi16( err1, err1 ); + localErr = _mm256_min_epu16( localErr, err2 ); + + err1 = _mm256_sub_epi16( s16Wide, modMul[4] ); + err2 = _mm256_mullo_epi16( err1, err1 ); + localErr = _mm256_min_epu16( localErr, err2 ); + + err1 = _mm256_sub_epi16( s16Wide, modMul[5] ); + err2 = _mm256_mullo_epi16( err1, err1 ); + localErr = _mm256_min_epu16( localErr, err2 ); + + err1 = _mm256_sub_epi16( s16Wide, modMul[6] ); + err2 = _mm256_mullo_epi16( err1, err1 ); + localErr = _mm256_min_epu16( localErr, err2 ); + + err1 = _mm256_sub_epi16( s16Wide, modMul[7] ); + err2 = _mm256_mullo_epi16( err1, err1 ); + localErr = _mm256_min_epu16( localErr, err2 ); + + // note that this can overflow, but since we're looking for the smallest error, it shouldn't matter + mulErr = _mm256_adds_epu16( mulErr, localErr ); + } + uint64_t minPos1 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_castsi256_si128( mulErr ) ) ); + uint64_t minPos2 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_extracti128_si256( mulErr, 1 ) ) ); + int sel = ( ( minPos1 & 0xFFFF ) < ( minPos2 & 0xFFFF ) ) ? ( minPos1 >> 16 ) : ( 8 + ( minPos2 >> 16 ) ); + + __m128i recVal16; + switch( sel ) + { + case 0: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() ); + break; + case 1: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() ); + break; + case 2: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() ); + break; + case 3: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() ); + break; + case 4: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() ); + break; + case 5: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() ); + break; + case 6: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() ); + break; + case 7: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() ); + break; + case 8: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() ); + break; + case 9: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() ); + break; + case 10: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() ); + break; + case 11: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() ); + break; + case 12: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() ); + break; + case 13: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() ); + break; + case 14: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() ); + break; + case 15: + recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() ); + break; + default: + assert( false ); + break; + } +#else + // wide multiplier + __m128i rangeMul[16] = { + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() ), + _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() ) + }; + + // find selector + int err = std::numeric_limits<int>::max(); + int sel; + for( int r=0; r<16; r++ ) + { + __m128i err1, err2, minerr; + __m128i recVal16 = rangeMul[r]; + int rangeErr; + + err1 = _mm_sub_epi16( sr[0], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr = _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[1], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[2], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[3], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[4], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[5], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[6], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[7], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[8], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[9], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[10], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[11], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[12], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[13], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[14], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + err1 = _mm_sub_epi16( sr[15], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF; + + if( rangeErr < err ) + { + err = rangeErr; + sel = r; + if( err == 0 ) break; + } + } + + __m128i recVal16 = rangeMul[sel]; +#endif + + // find indices + __m128i err1, err2, minerr; + uint64_t idx = 0, tmp; + + err1 = _mm_sub_epi16( sr[0], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 15*3; + + err1 = _mm_sub_epi16( sr[1], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 14*3; + + err1 = _mm_sub_epi16( sr[2], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 13*3; + + err1 = _mm_sub_epi16( sr[3], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 12*3; + + err1 = _mm_sub_epi16( sr[4], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 11*3; + + err1 = _mm_sub_epi16( sr[5], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 10*3; + + err1 = _mm_sub_epi16( sr[6], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 9*3; + + err1 = _mm_sub_epi16( sr[7], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 8*3; + + err1 = _mm_sub_epi16( sr[8], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 7*3; + + err1 = _mm_sub_epi16( sr[9], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 6*3; + + err1 = _mm_sub_epi16( sr[10], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 5*3; + + err1 = _mm_sub_epi16( sr[11], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 4*3; + + err1 = _mm_sub_epi16( sr[12], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 3*3; + + err1 = _mm_sub_epi16( sr[13], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 2*3; + + err1 = _mm_sub_epi16( sr[14], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 1*3; + + err1 = _mm_sub_epi16( sr[15], recVal16 ); + err2 = _mm_mullo_epi16( err1, err1 ); + minerr = _mm_minpos_epu16( err2 ); + tmp = _mm_cvtsi128_si64( minerr ); + idx |= ( tmp >> 16 ) << 0*3; + + uint16_t rm[8]; + _mm_storeu_si128( (__m128i*)rm, mul ); + uint16_t sm = _mm_cvtsi128_si64( srcMid ); + + uint64_t d = ( uint64_t( sm ) << 56 ) | + ( uint64_t( rm[GetMulSel( sel )] ) << 52 ) | + ( uint64_t( sel ) << 48 ) | + idx; + + return _bswap64( d ); +#elif defined __ARM_NEON + + int16x8_t srcMidWide, multipliers; + int srcMid; + uint8x16_t srcAlphaBlock = vld1q_u8( src ); + { + uint8_t ref = src[0]; + uint8x16_t a0 = vdupq_n_u8( ref ); + uint8x16_t r = vceqq_u8( srcAlphaBlock, a0 ); + int64x2_t m = vreinterpretq_s64_u8( r ); + if( m[0] == -1 && m[1] == -1 ) + return ref; + + // srcRange +#ifdef __aarch64__ + uint8_t min = vminvq_u8( srcAlphaBlock ); + uint8_t max = vmaxvq_u8( srcAlphaBlock ); + uint8_t srcRange = max - min; + multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_n_s16( g_alphaRange_NEON, srcRange ), 1 ), vdupq_n_s16( 1 ) ); + srcMid = min + srcRange / 2; + srcMidWide = vdupq_n_s16( srcMid ); +#else + uint8x8_t vmin = vpmin_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) ); + vmin = vpmin_u8( vmin, vmin ); + vmin = vpmin_u8( vmin, vmin ); + vmin = vpmin_u8( vmin, vmin ); + uint8x8_t vmax = vpmax_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) ); + vmax = vpmax_u8( vmax, vmax ); + vmax = vpmax_u8( vmax, vmax ); + vmax = vpmax_u8( vmax, vmax ); + + int16x8_t srcRangeWide = vreinterpretq_s16_u16( vsubl_u8( vmax, vmin ) ); + multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_s16( g_alphaRange_NEON, srcRangeWide ), 1 ), vdupq_n_s16( 1 ) ); + srcMidWide = vsraq_n_s16( vreinterpretq_s16_u16(vmovl_u8(vmin)), srcRangeWide, 1); + srcMid = vgetq_lane_s16( srcMidWide, 0 ); +#endif + } + + // calculate reconstructed values +#define EAC_APPLY_16X( m ) m( 0 ) m( 1 ) m( 2 ) m( 3 ) m( 4 ) m( 5 ) m( 6 ) m( 7 ) m( 8 ) m( 9 ) m( 10 ) m( 11 ) m( 12 ) m( 13 ) m( 14 ) m( 15 ) + +#define EAC_RECONSTRUCT_VALUE( n ) vqmovun_s16( vmlaq_s16( srcMidWide, g_alpha_NEON[n], WidenMultiplier_EAC_NEON<n>( multipliers ) ) ), + uint8x8_t recVals[16] = { EAC_APPLY_16X( EAC_RECONSTRUCT_VALUE ) }; + + // find selector + int err = std::numeric_limits<int>::max(); + int sel = 0; + for( int r = 0; r < 16; r++ ) + { + uint8x8_t recVal = recVals[r]; + + int rangeErr = 0; +#define EAC_ACCUMULATE_ERROR( n ) rangeErr += MinError_EAC_NEON( ErrorProbe_EAC_NEON<n>( recVal, srcAlphaBlock ) ); + EAC_APPLY_16X( EAC_ACCUMULATE_ERROR ) + + if( rangeErr < err ) + { + err = rangeErr; + sel = r; + if ( err == 0 ) break; + } + } + + // combine results + uint64_t d = ( uint64_t( srcMid ) << 56 ) | + ( uint64_t( multipliers[GetMulSel( sel )] ) << 52 ) | + ( uint64_t( sel ) << 48); + + // generate indices + uint8x8_t recVal = recVals[sel]; +#define EAC_INSERT_INDEX(n) d |= MinErrorIndex_EAC_NEON<n>( recVal, srcAlphaBlock ); + EAC_APPLY_16X( EAC_INSERT_INDEX ) + + return _bswap64( d ); + +#undef EAC_APPLY_16X +#undef EAC_INSERT_INDEX +#undef EAC_ACCUMULATE_ERROR +#undef EAC_RECONSTRUCT_VALUE + +#else + { + bool solid = true; + const uint8_t* ptr = src + 1; + const uint8_t ref = *src; + for( int i=1; i<16; i++ ) + { + if( ref != *ptr++ ) + { + solid = false; + break; + } + } + if( solid ) + { + return ref; + } + } + + uint8_t min = src[0]; + uint8_t max = src[0]; + for( int i=1; i<16; i++ ) + { + if( min > src[i] ) min = src[i]; + else if( max < src[i] ) max = src[i]; + } + int srcRange = max - min; + int srcMid = min + srcRange / 2; + + uint8_t buf[16][16]; + int err = std::numeric_limits<int>::max(); + int sel; + int selmul; + for( int r=0; r<16; r++ ) + { + int mul = ( ( srcRange * g_alphaRange[r] ) >> 16 ) + 1; + + int rangeErr = 0; + for( int i=0; i<16; i++ ) + { + const auto srcVal = src[i]; + + int idx = 0; + const auto modVal = g_alpha[r][0] * mul; + const auto recVal = clampu8( srcMid + modVal ); + int localErr = sq( srcVal - recVal ); + + if( localErr != 0 ) + { + for( int j=1; j<8; j++ ) + { + const auto modVal = g_alpha[r][j] * mul; + const auto recVal = clampu8( srcMid + modVal ); + const auto errProbe = sq( srcVal - recVal ); + if( errProbe < localErr ) + { + localErr = errProbe; + idx = j; + } + } + } + + buf[r][i] = idx; + rangeErr += localErr; + } + + if( rangeErr < err ) + { + err = rangeErr; + sel = r; + selmul = mul; + if( err == 0 ) break; + } + } + + uint64_t d = ( uint64_t( srcMid ) << 56 ) | + ( uint64_t( selmul ) << 52 ) | + ( uint64_t( sel ) << 48 ); + + int offset = 45; + auto ptr = buf[sel]; + for( int i=0; i<16; i++ ) + { + d |= uint64_t( *ptr++ ) << offset; + offset -= 3; + } + + return _bswap64( d ); +#endif +} + + +void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + int w = 0; + uint32_t buf[4*4]; + do + { +#ifdef __SSE4_1__ + __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) ); + __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) ); + __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) ); + __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) ); + + _MM_TRANSPOSE4_PS( px0, px1, px2, px3 ); + + __m128i c0 = _mm_castps_si128( px0 ); + __m128i c1 = _mm_castps_si128( px1 ); + __m128i c2 = _mm_castps_si128( px2 ); + __m128i c3 = _mm_castps_si128( px3 ); + + __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f ); + __m128i p0 = _mm_shuffle_epi8( c0, mask ); + __m128i p1 = _mm_shuffle_epi8( c1, mask ); + __m128i p2 = _mm_shuffle_epi8( c2, mask ); + __m128i p3 = _mm_shuffle_epi8( c3, mask ); + + _mm_store_si128( (__m128i*)(buf + 0), p0 ); + _mm_store_si128( (__m128i*)(buf + 4), p1 ); + _mm_store_si128( (__m128i*)(buf + 8), p2 ); + _mm_store_si128( (__m128i*)(buf + 12), p3 ); + + src += 4; +#else + auto ptr = buf; + for( int x=0; x<4; x++ ) + { + unsigned int a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src += width; + a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src += width; + a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src += width; + a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src -= width * 3 - 1; + } +#endif + if( ++w == width/4 ) + { + src += width * 3; + w = 0; + } + *dst++ = ProcessRGB( (uint8_t*)buf ); + } + while( --blocks ); +} + +void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + int w = 0; + uint32_t buf[4*4]; + do + { +#ifdef __SSE4_1__ + __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) ); + __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) ); + __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) ); + __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) ); + + _MM_TRANSPOSE4_PS( px0, px1, px2, px3 ); + + __m128i c0 = _mm_castps_si128( px0 ); + __m128i c1 = _mm_castps_si128( px1 ); + __m128i c2 = _mm_castps_si128( px2 ); + __m128i c3 = _mm_castps_si128( px3 ); + + __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f ); + __m128i p0 = _mm_shuffle_epi8( c0, mask ); + __m128i p1 = _mm_shuffle_epi8( c1, mask ); + __m128i p2 = _mm_shuffle_epi8( c2, mask ); + __m128i p3 = _mm_shuffle_epi8( c3, mask ); + + _mm_store_si128( (__m128i*)(buf + 0), p0 ); + _mm_store_si128( (__m128i*)(buf + 4), p1 ); + _mm_store_si128( (__m128i*)(buf + 8), p2 ); + _mm_store_si128( (__m128i*)(buf + 12), p3 ); + + src += 4; +#else + auto ptr = buf; + for( int x=0; x<4; x++ ) + { + unsigned int a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src += width; + a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src += width; + a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src += width; + a = *src >> 24; + *ptr++ = a | ( a << 8 ) | ( a << 16 ); + src -= width * 3 - 1; + } +#endif + if( ++w == width/4 ) + { + src += width * 3; + w = 0; + } + *dst++ = ProcessRGB_ETC2( (uint8_t*)buf ); + } + while( --blocks ); +} + +#include <chrono> +#include <thread> + +void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + int w = 0; + uint32_t buf[4*4]; + do + { +#ifdef __SSE4_1__ + __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) ); + __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) ); + __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) ); + __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) ); + + _MM_TRANSPOSE4_PS( px0, px1, px2, px3 ); + + _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) ); + _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) ); + _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) ); + _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) ); + + src += 4; +#else + auto ptr = buf; + for( int x=0; x<4; x++ ) + { + *ptr++ = *src; + src += width; + *ptr++ = *src; + src += width; + *ptr++ = *src; + src += width; + *ptr++ = *src; + src -= width * 3 - 1; + } +#endif + if( ++w == width/4 ) + { + src += width * 3; + w = 0; + } + *dst++ = ProcessRGB( (uint8_t*)buf ); + } + while( --blocks ); +} + +void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + int w = 0; + uint32_t buf[4*4]; + do + { +#ifdef __SSE4_1__ + __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) ); + __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) ); + __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) ); + __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) ); + + _MM_TRANSPOSE4_PS( px0, px1, px2, px3 ); + +# ifdef __AVX2__ + DitherAvx2( (uint8_t*)buf, _mm_castps_si128( px0 ), _mm_castps_si128( px1 ), _mm_castps_si128( px2 ), _mm_castps_si128( px3 ) ); +# else + _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) ); + _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) ); + _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) ); + _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) ); + + Dither( (uint8_t*)buf ); +# endif + + src += 4; +#else + auto ptr = buf; + for( int x=0; x<4; x++ ) + { + *ptr++ = *src; + src += width; + *ptr++ = *src; + src += width; + *ptr++ = *src; + src += width; + *ptr++ = *src; + src -= width * 3 - 1; + } +#endif + if( ++w == width/4 ) + { + src += width * 3; + w = 0; + } + *dst++ = ProcessRGB( (uint8_t*)buf ); + } + while( --blocks ); +} + +void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + int w = 0; + uint32_t buf[4*4]; + do + { +#ifdef __SSE4_1__ + __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) ); + __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) ); + __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) ); + __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) ); + + _MM_TRANSPOSE4_PS( px0, px1, px2, px3 ); + + _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) ); + _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) ); + _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) ); + _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) ); + + src += 4; +#else + auto ptr = buf; + for( int x=0; x<4; x++ ) + { + *ptr++ = *src; + src += width; + *ptr++ = *src; + src += width; + *ptr++ = *src; + src += width; + *ptr++ = *src; + src -= width * 3 - 1; + } +#endif + if( ++w == width/4 ) + { + src += width * 3; + w = 0; + } + *dst++ = ProcessRGB_ETC2( (uint8_t*)buf ); + } + while( --blocks ); +} + +void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ) +{ + int w = 0; + uint32_t rgba[4*4]; + uint8_t alpha[4*4]; + do + { +#ifdef __SSE4_1__ + __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) ); + __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) ); + __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) ); + __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) ); + + _MM_TRANSPOSE4_PS( px0, px1, px2, px3 ); + + __m128i c0 = _mm_castps_si128( px0 ); + __m128i c1 = _mm_castps_si128( px1 ); + __m128i c2 = _mm_castps_si128( px2 ); + __m128i c3 = _mm_castps_si128( px3 ); + + _mm_store_si128( (__m128i*)(rgba + 0), c0 ); + _mm_store_si128( (__m128i*)(rgba + 4), c1 ); + _mm_store_si128( (__m128i*)(rgba + 8), c2 ); + _mm_store_si128( (__m128i*)(rgba + 12), c3 ); + + __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 ); + + __m128i a0 = _mm_shuffle_epi8( c0, mask ); + __m128i a1 = _mm_shuffle_epi8( c1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) ); + __m128i a2 = _mm_shuffle_epi8( c2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) ); + __m128i a3 = _mm_shuffle_epi8( c3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) ); + + __m128i s0 = _mm_or_si128( a0, a1 ); + __m128i s1 = _mm_or_si128( a2, a3 ); + __m128i s2 = _mm_or_si128( s0, s1 ); + + _mm_store_si128( (__m128i*)alpha, s2 ); + + src += 4; +#else + auto ptr = rgba; + auto ptr8 = alpha; + for( int x=0; x<4; x++ ) + { + auto v = *src; + *ptr++ = v; + *ptr8++ = v >> 24; + src += width; + v = *src; + *ptr++ = v; + *ptr8++ = v >> 24; + src += width; + v = *src; + *ptr++ = v; + *ptr8++ = v >> 24; + src += width; + v = *src; + *ptr++ = v; + *ptr8++ = v >> 24; + src -= width * 3 - 1; + } +#endif + if( ++w == width/4 ) + { + src += width * 3; + w = 0; + } + *dst++ = ProcessAlpha_ETC2( alpha ); + *dst++ = ProcessRGB_ETC2( (uint8_t*)rgba ); + } + while( --blocks ); +} diff --git a/thirdparty/etcpak/ProcessRGB.hpp b/thirdparty/etcpak/ProcessRGB.hpp new file mode 100644 index 0000000000..c5555a5bb1 --- /dev/null +++ b/thirdparty/etcpak/ProcessRGB.hpp @@ -0,0 +1,13 @@ +#ifndef __PROCESSRGB_HPP__ +#define __PROCESSRGB_HPP__ + +#include <stdint.h> + +void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); +void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); +void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); +void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); +void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); +void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width ); + +#endif diff --git a/thirdparty/etcpak/Tables.cpp b/thirdparty/etcpak/Tables.cpp new file mode 100644 index 0000000000..5c7fd9cf61 --- /dev/null +++ b/thirdparty/etcpak/Tables.cpp @@ -0,0 +1,221 @@ +#include "Tables.hpp" + +const int32_t g_table[8][4] = { + { 2, 8, -2, -8 }, + { 5, 17, -5, -17 }, + { 9, 29, -9, -29 }, + { 13, 42, -13, -42 }, + { 18, 60, -18, -60 }, + { 24, 80, -24, -80 }, + { 33, 106, -33, -106 }, + { 47, 183, -47, -183 } +}; + +const int64_t g_table256[8][4] = { + { 2*256, 8*256, -2*256, -8*256 }, + { 5*256, 17*256, -5*256, -17*256 }, + { 9*256, 29*256, -9*256, -29*256 }, + { 13*256, 42*256, -13*256, -42*256 }, + { 18*256, 60*256, -18*256, -60*256 }, + { 24*256, 80*256, -24*256, -80*256 }, + { 33*256, 106*256, -33*256, -106*256 }, + { 47*256, 183*256, -47*256, -183*256 } +}; + +const uint32_t g_id[4][16] = { + { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2 }, + { 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4 }, + { 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6 } +}; + +const uint32_t g_avg2[16] = { + 0x00, + 0x11, + 0x22, + 0x33, + 0x44, + 0x55, + 0x66, + 0x77, + 0x88, + 0x99, + 0xAA, + 0xBB, + 0xCC, + 0xDD, + 0xEE, + 0xFF +}; + +const uint32_t g_flags[64] = { + 0x80800402, 0x80800402, 0x80800402, 0x80800402, + 0x80800402, 0x80800402, 0x80800402, 0x8080E002, + 0x80800402, 0x80800402, 0x8080E002, 0x8080E002, + 0x80800402, 0x8080E002, 0x8080E002, 0x8080E002, + 0x80000402, 0x80000402, 0x80000402, 0x80000402, + 0x80000402, 0x80000402, 0x80000402, 0x8000E002, + 0x80000402, 0x80000402, 0x8000E002, 0x8000E002, + 0x80000402, 0x8000E002, 0x8000E002, 0x8000E002, + 0x00800402, 0x00800402, 0x00800402, 0x00800402, + 0x00800402, 0x00800402, 0x00800402, 0x0080E002, + 0x00800402, 0x00800402, 0x0080E002, 0x0080E002, + 0x00800402, 0x0080E002, 0x0080E002, 0x0080E002, + 0x00000402, 0x00000402, 0x00000402, 0x00000402, + 0x00000402, 0x00000402, 0x00000402, 0x0000E002, + 0x00000402, 0x00000402, 0x0000E002, 0x0000E002, + 0x00000402, 0x0000E002, 0x0000E002, 0x0000E002 +}; + +const int32_t g_alpha[16][8] = { + { -3, -6, -9, -15, 2, 5, 8, 14 }, + { -3, -7, -10, -13, 2, 6, 9, 12 }, + { -2, -5, -8, -13, 1, 4, 7, 12 }, + { -2, -4, -6, -13, 1, 3, 5, 12 }, + { -3, -6, -8, -12, 2, 5, 7, 11 }, + { -3, -7, -9, -11, 2, 6, 8, 10 }, + { -4, -7, -8, -11, 3, 6, 7, 10 }, + { -3, -5, -8, -11, 2, 4, 7, 10 }, + { -2, -6, -8, -10, 1, 5, 7, 9 }, + { -2, -5, -8, -10, 1, 4, 7, 9 }, + { -2, -4, -8, -10, 1, 3, 7, 9 }, + { -2, -5, -7, -10, 1, 4, 6, 9 }, + { -3, -4, -7, -10, 2, 3, 6, 9 }, + { -1, -2, -3, -10, 0, 1, 2, 9 }, + { -4, -6, -8, -9, 3, 5, 7, 8 }, + { -3, -5, -7, -9, 2, 4, 6, 8 } +}; + +const int32_t g_alphaRange[16] = { + 0x100FF / ( 1 + g_alpha[0][7] - g_alpha[0][3] ), + 0x100FF / ( 1 + g_alpha[1][7] - g_alpha[1][3] ), + 0x100FF / ( 1 + g_alpha[2][7] - g_alpha[2][3] ), + 0x100FF / ( 1 + g_alpha[3][7] - g_alpha[3][3] ), + 0x100FF / ( 1 + g_alpha[4][7] - g_alpha[4][3] ), + 0x100FF / ( 1 + g_alpha[5][7] - g_alpha[5][3] ), + 0x100FF / ( 1 + g_alpha[6][7] - g_alpha[6][3] ), + 0x100FF / ( 1 + g_alpha[7][7] - g_alpha[7][3] ), + 0x100FF / ( 1 + g_alpha[8][7] - g_alpha[8][3] ), + 0x100FF / ( 1 + g_alpha[9][7] - g_alpha[9][3] ), + 0x100FF / ( 1 + g_alpha[10][7] - g_alpha[10][3] ), + 0x100FF / ( 1 + g_alpha[11][7] - g_alpha[11][3] ), + 0x100FF / ( 1 + g_alpha[12][7] - g_alpha[12][3] ), + 0x100FF / ( 1 + g_alpha[13][7] - g_alpha[13][3] ), + 0x100FF / ( 1 + g_alpha[14][7] - g_alpha[14][3] ), + 0x100FF / ( 1 + g_alpha[15][7] - g_alpha[15][3] ), +}; + +#ifdef __SSE4_1__ +const __m128i g_table_SIMD[2] = +{ + _mm_setr_epi16( 2, 5, 9, 13, 18, 24, 33, 47), + _mm_setr_epi16( 8, 17, 29, 42, 60, 80, 106, 183) +}; +const __m128i g_table128_SIMD[2] = +{ + _mm_setr_epi16( 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128), + _mm_setr_epi16( 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128) +}; +const __m128i g_table256_SIMD[4] = +{ + _mm_setr_epi32( 2*256, 5*256, 9*256, 13*256), + _mm_setr_epi32( 8*256, 17*256, 29*256, 42*256), + _mm_setr_epi32( 18*256, 24*256, 33*256, 47*256), + _mm_setr_epi32( 60*256, 80*256, 106*256, 183*256) +}; + +const __m128i g_alpha_SIMD[16] = { + _mm_setr_epi16( g_alpha[ 0][0], g_alpha[ 0][1], g_alpha[ 0][2], g_alpha[ 0][3], g_alpha[ 0][4], g_alpha[ 0][5], g_alpha[ 0][6], g_alpha[ 0][7] ), + _mm_setr_epi16( g_alpha[ 1][0], g_alpha[ 1][1], g_alpha[ 1][2], g_alpha[ 1][3], g_alpha[ 1][4], g_alpha[ 1][5], g_alpha[ 1][6], g_alpha[ 1][7] ), + _mm_setr_epi16( g_alpha[ 2][0], g_alpha[ 2][1], g_alpha[ 2][2], g_alpha[ 2][3], g_alpha[ 2][4], g_alpha[ 2][5], g_alpha[ 2][6], g_alpha[ 2][7] ), + _mm_setr_epi16( g_alpha[ 3][0], g_alpha[ 3][1], g_alpha[ 3][2], g_alpha[ 3][3], g_alpha[ 3][4], g_alpha[ 3][5], g_alpha[ 3][6], g_alpha[ 3][7] ), + _mm_setr_epi16( g_alpha[ 4][0], g_alpha[ 4][1], g_alpha[ 4][2], g_alpha[ 4][3], g_alpha[ 4][4], g_alpha[ 4][5], g_alpha[ 4][6], g_alpha[ 4][7] ), + _mm_setr_epi16( g_alpha[ 5][0], g_alpha[ 5][1], g_alpha[ 5][2], g_alpha[ 5][3], g_alpha[ 5][4], g_alpha[ 5][5], g_alpha[ 5][6], g_alpha[ 5][7] ), + _mm_setr_epi16( g_alpha[ 6][0], g_alpha[ 6][1], g_alpha[ 6][2], g_alpha[ 6][3], g_alpha[ 6][4], g_alpha[ 6][5], g_alpha[ 6][6], g_alpha[ 6][7] ), + _mm_setr_epi16( g_alpha[ 7][0], g_alpha[ 7][1], g_alpha[ 7][2], g_alpha[ 7][3], g_alpha[ 7][4], g_alpha[ 7][5], g_alpha[ 7][6], g_alpha[ 7][7] ), + _mm_setr_epi16( g_alpha[ 8][0], g_alpha[ 8][1], g_alpha[ 8][2], g_alpha[ 8][3], g_alpha[ 8][4], g_alpha[ 8][5], g_alpha[ 8][6], g_alpha[ 8][7] ), + _mm_setr_epi16( g_alpha[ 9][0], g_alpha[ 9][1], g_alpha[ 9][2], g_alpha[ 9][3], g_alpha[ 9][4], g_alpha[ 9][5], g_alpha[ 9][6], g_alpha[ 9][7] ), + _mm_setr_epi16( g_alpha[10][0], g_alpha[10][1], g_alpha[10][2], g_alpha[10][3], g_alpha[10][4], g_alpha[10][5], g_alpha[10][6], g_alpha[10][7] ), + _mm_setr_epi16( g_alpha[11][0], g_alpha[11][1], g_alpha[11][2], g_alpha[11][3], g_alpha[11][4], g_alpha[11][5], g_alpha[11][6], g_alpha[11][7] ), + _mm_setr_epi16( g_alpha[12][0], g_alpha[12][1], g_alpha[12][2], g_alpha[12][3], g_alpha[12][4], g_alpha[12][5], g_alpha[12][6], g_alpha[12][7] ), + _mm_setr_epi16( g_alpha[13][0], g_alpha[13][1], g_alpha[13][2], g_alpha[13][3], g_alpha[13][4], g_alpha[13][5], g_alpha[13][6], g_alpha[13][7] ), + _mm_setr_epi16( g_alpha[14][0], g_alpha[14][1], g_alpha[14][2], g_alpha[14][3], g_alpha[14][4], g_alpha[14][5], g_alpha[14][6], g_alpha[14][7] ), + _mm_setr_epi16( g_alpha[15][0], g_alpha[15][1], g_alpha[15][2], g_alpha[15][3], g_alpha[15][4], g_alpha[15][5], g_alpha[15][6], g_alpha[15][7] ), +}; + +const __m128i g_alphaRange_SIMD = _mm_setr_epi16( + g_alphaRange[0], + g_alphaRange[1], + g_alphaRange[4], + g_alphaRange[5], + g_alphaRange[8], + g_alphaRange[14], + 0, + 0 ); +#endif + +#ifdef __AVX2__ +const __m256i g_alpha_AVX[8] = { + _mm256_setr_epi16( g_alpha[ 0][0], g_alpha[ 1][0], g_alpha[ 2][0], g_alpha[ 3][0], g_alpha[ 4][0], g_alpha[ 5][0], g_alpha[ 6][0], g_alpha[ 7][0], g_alpha[ 8][0], g_alpha[ 9][0], g_alpha[10][0], g_alpha[11][0], g_alpha[12][0], g_alpha[13][0], g_alpha[14][0], g_alpha[15][0] ), + _mm256_setr_epi16( g_alpha[ 0][1], g_alpha[ 1][1], g_alpha[ 2][1], g_alpha[ 3][1], g_alpha[ 4][1], g_alpha[ 5][1], g_alpha[ 6][1], g_alpha[ 7][1], g_alpha[ 8][1], g_alpha[ 9][1], g_alpha[10][1], g_alpha[11][1], g_alpha[12][1], g_alpha[13][1], g_alpha[14][1], g_alpha[15][1] ), + _mm256_setr_epi16( g_alpha[ 0][2], g_alpha[ 1][2], g_alpha[ 2][2], g_alpha[ 3][2], g_alpha[ 4][2], g_alpha[ 5][2], g_alpha[ 6][2], g_alpha[ 7][2], g_alpha[ 8][2], g_alpha[ 9][2], g_alpha[10][2], g_alpha[11][2], g_alpha[12][2], g_alpha[13][2], g_alpha[14][2], g_alpha[15][2] ), + _mm256_setr_epi16( g_alpha[ 0][3], g_alpha[ 1][3], g_alpha[ 2][3], g_alpha[ 3][3], g_alpha[ 4][3], g_alpha[ 5][3], g_alpha[ 6][3], g_alpha[ 7][3], g_alpha[ 8][3], g_alpha[ 9][3], g_alpha[10][3], g_alpha[11][3], g_alpha[12][3], g_alpha[13][3], g_alpha[14][3], g_alpha[15][3] ), + _mm256_setr_epi16( g_alpha[ 0][4], g_alpha[ 1][4], g_alpha[ 2][4], g_alpha[ 3][4], g_alpha[ 4][4], g_alpha[ 5][4], g_alpha[ 6][4], g_alpha[ 7][4], g_alpha[ 8][4], g_alpha[ 9][4], g_alpha[10][4], g_alpha[11][4], g_alpha[12][4], g_alpha[13][4], g_alpha[14][4], g_alpha[15][4] ), + _mm256_setr_epi16( g_alpha[ 0][5], g_alpha[ 1][5], g_alpha[ 2][5], g_alpha[ 3][5], g_alpha[ 4][5], g_alpha[ 5][5], g_alpha[ 6][5], g_alpha[ 7][5], g_alpha[ 8][5], g_alpha[ 9][5], g_alpha[10][5], g_alpha[11][5], g_alpha[12][5], g_alpha[13][5], g_alpha[14][5], g_alpha[15][5] ), + _mm256_setr_epi16( g_alpha[ 0][6], g_alpha[ 1][6], g_alpha[ 2][6], g_alpha[ 3][6], g_alpha[ 4][6], g_alpha[ 5][6], g_alpha[ 6][6], g_alpha[ 7][6], g_alpha[ 8][6], g_alpha[ 9][6], g_alpha[10][6], g_alpha[11][6], g_alpha[12][6], g_alpha[13][6], g_alpha[14][6], g_alpha[15][6] ), + _mm256_setr_epi16( g_alpha[ 0][7], g_alpha[ 1][7], g_alpha[ 2][7], g_alpha[ 3][7], g_alpha[ 4][7], g_alpha[ 5][7], g_alpha[ 6][7], g_alpha[ 7][7], g_alpha[ 8][7], g_alpha[ 9][7], g_alpha[10][7], g_alpha[11][7], g_alpha[12][7], g_alpha[13][7], g_alpha[14][7], g_alpha[15][7] ), +}; + +const __m256i g_alphaRange_AVX = _mm256_setr_epi16( + g_alphaRange[ 0], g_alphaRange[ 1], g_alphaRange[ 2], g_alphaRange[ 3], g_alphaRange[ 4], g_alphaRange[ 5], g_alphaRange[ 6], g_alphaRange[ 7], + g_alphaRange[ 8], g_alphaRange[ 9], g_alphaRange[10], g_alphaRange[11], g_alphaRange[12], g_alphaRange[13], g_alphaRange[14], g_alphaRange[15] +); +#endif + +#ifdef __ARM_NEON +const int16x8_t g_table128_NEON[2] = +{ + { 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128 }, + { 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128 } +}; + +const int32x4_t g_table256_NEON[4] = +{ + { 2*256, 5*256, 9*256, 13*256 }, + { 8*256, 17*256, 29*256, 42*256 }, + { 18*256, 24*256, 33*256, 47*256 }, + { 60*256, 80*256, 106*256, 183*256 } +}; + +const int16x8_t g_alpha_NEON[16] = +{ + { -3, -6, -9, -15, 2, 5, 8, 14 }, + { -3, -7, -10, -13, 2, 6, 9, 12 }, + { -2, -5, -8, -13, 1, 4, 7, 12 }, + { -2, -4, -6, -13, 1, 3, 5, 12 }, + { -3, -6, -8, -12, 2, 5, 7, 11 }, + { -3, -7, -9, -11, 2, 6, 8, 10 }, + { -4, -7, -8, -11, 3, 6, 7, 10 }, + { -3, -5, -8, -11, 2, 4, 7, 10 }, + { -2, -6, -8, -10, 1, 5, 7, 9 }, + { -2, -5, -8, -10, 1, 4, 7, 9 }, + { -2, -4, -8, -10, 1, 3, 7, 9 }, + { -2, -5, -7, -10, 1, 4, 6, 9 }, + { -3, -4, -7, -10, 2, 3, 6, 9 }, + { -1, -2, -3, -10, 0, 1, 2, 9 }, + { -4, -6, -8, -9, 3, 5, 7, 8 }, + { -3, -5, -7, -9, 2, 4, 6, 8 } +}; + +const int16x8_t g_alphaRange_NEON = +{ + (int16_t)g_alphaRange[0], + (int16_t)g_alphaRange[1], + (int16_t)g_alphaRange[4], + (int16_t)g_alphaRange[5], + (int16_t)g_alphaRange[8], + (int16_t)g_alphaRange[14], + 0, + 0 +}; +#endif diff --git a/thirdparty/etcpak/Tables.hpp b/thirdparty/etcpak/Tables.hpp new file mode 100644 index 0000000000..69d7e8aa07 --- /dev/null +++ b/thirdparty/etcpak/Tables.hpp @@ -0,0 +1,49 @@ +#ifndef __TABLES_HPP__ +#define __TABLES_HPP__ + +#include <stdint.h> + +#ifdef __AVX2__ +# include <immintrin.h> +#endif +#ifdef __SSE4_1__ +# include <smmintrin.h> +#endif +#ifdef __ARM_NEON +# include <arm_neon.h> +#endif + +extern const int32_t g_table[8][4]; +extern const int64_t g_table256[8][4]; + +extern const uint32_t g_id[4][16]; + +extern const uint32_t g_avg2[16]; + +extern const uint32_t g_flags[64]; + +extern const int32_t g_alpha[16][8]; +extern const int32_t g_alphaRange[16]; + +#ifdef __SSE4_1__ +extern const __m128i g_table_SIMD[2]; +extern const __m128i g_table128_SIMD[2]; +extern const __m128i g_table256_SIMD[4]; + +extern const __m128i g_alpha_SIMD[16]; +extern const __m128i g_alphaRange_SIMD; +#endif + +#ifdef __AVX2__ +extern const __m256i g_alpha_AVX[8]; +extern const __m256i g_alphaRange_AVX; +#endif + +#ifdef __ARM_NEON +extern const int16x8_t g_table128_NEON[2]; +extern const int32x4_t g_table256_NEON[4]; +extern const int16x8_t g_alpha_NEON[16]; +extern const int16x8_t g_alphaRange_NEON; +#endif + +#endif diff --git a/thirdparty/etcpak/Vector.hpp b/thirdparty/etcpak/Vector.hpp new file mode 100644 index 0000000000..3370a88aea --- /dev/null +++ b/thirdparty/etcpak/Vector.hpp @@ -0,0 +1,222 @@ +#ifndef __DARKRL__VECTOR_HPP__ +#define __DARKRL__VECTOR_HPP__ + +#include <assert.h> +#include <algorithm> +#include <math.h> +#include <stdint.h> + +#include "Math.hpp" + +template<class T> +struct Vector2 +{ + Vector2() : x( 0 ), y( 0 ) {} + Vector2( T v ) : x( v ), y( v ) {} + Vector2( T _x, T _y ) : x( _x ), y( _y ) {} + + bool operator==( const Vector2<T>& rhs ) const { return x == rhs.x && y == rhs.y; } + bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); } + + Vector2<T>& operator+=( const Vector2<T>& rhs ) + { + x += rhs.x; + y += rhs.y; + return *this; + } + Vector2<T>& operator-=( const Vector2<T>& rhs ) + { + x -= rhs.x; + y -= rhs.y; + return *this; + } + Vector2<T>& operator*=( const Vector2<T>& rhs ) + { + x *= rhs.x; + y *= rhs.y; + return *this; + } + + T x, y; +}; + +template<class T> +Vector2<T> operator+( const Vector2<T>& lhs, const Vector2<T>& rhs ) +{ + return Vector2<T>( lhs.x + rhs.x, lhs.y + rhs.y ); +} + +template<class T> +Vector2<T> operator-( const Vector2<T>& lhs, const Vector2<T>& rhs ) +{ + return Vector2<T>( lhs.x - rhs.x, lhs.y - rhs.y ); +} + +template<class T> +Vector2<T> operator*( const Vector2<T>& lhs, const float& rhs ) +{ + return Vector2<T>( lhs.x * rhs, lhs.y * rhs ); +} + +template<class T> +Vector2<T> operator/( const Vector2<T>& lhs, const T& rhs ) +{ + return Vector2<T>( lhs.x / rhs, lhs.y / rhs ); +} + + +typedef Vector2<int32_t> v2i; +typedef Vector2<float> v2f; + + +template<class T> +struct Vector3 +{ + Vector3() : x( 0 ), y( 0 ), z( 0 ) {} + Vector3( T v ) : x( v ), y( v ), z( v ) {} + Vector3( T _x, T _y, T _z ) : x( _x ), y( _y ), z( _z ) {} + template<class Y> + Vector3( const Vector3<Y>& v ) : x( T( v.x ) ), y( T( v.y ) ), z( T( v.z ) ) {} + + T Luminance() const { return T( x * 0.3f + y * 0.59f + z * 0.11f ); } + void Clamp() + { + x = std::min( T(1), std::max( T(0), x ) ); + y = std::min( T(1), std::max( T(0), y ) ); + z = std::min( T(1), std::max( T(0), z ) ); + } + + bool operator==( const Vector3<T>& rhs ) const { return x == rhs.x && y == rhs.y && z == rhs.z; } + bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); } + + T& operator[]( unsigned int idx ) { assert( idx < 3 ); return ((T*)this)[idx]; } + const T& operator[]( unsigned int idx ) const { assert( idx < 3 ); return ((T*)this)[idx]; } + + Vector3<T> operator+=( const Vector3<T>& rhs ) + { + x += rhs.x; + y += rhs.y; + z += rhs.z; + return *this; + } + + Vector3<T> operator*=( const Vector3<T>& rhs ) + { + x *= rhs.x; + y *= rhs.y; + z *= rhs.z; + return *this; + } + + Vector3<T> operator*=( const float& rhs ) + { + x *= rhs; + y *= rhs; + z *= rhs; + return *this; + } + + T x, y, z; + T padding; +}; + +template<class T> +Vector3<T> operator+( const Vector3<T>& lhs, const Vector3<T>& rhs ) +{ + return Vector3<T>( lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z ); +} + +template<class T> +Vector3<T> operator-( const Vector3<T>& lhs, const Vector3<T>& rhs ) +{ + return Vector3<T>( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z ); +} + +template<class T> +Vector3<T> operator*( const Vector3<T>& lhs, const Vector3<T>& rhs ) +{ + return Vector3<T>( lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z ); +} + +template<class T> +Vector3<T> operator*( const Vector3<T>& lhs, const float& rhs ) +{ + return Vector3<T>( T( lhs.x * rhs ), T( lhs.y * rhs ), T( lhs.z * rhs ) ); +} + +template<class T> +Vector3<T> operator/( const Vector3<T>& lhs, const T& rhs ) +{ + return Vector3<T>( lhs.x / rhs, lhs.y / rhs, lhs.z / rhs ); +} + +template<class T> +bool operator<( const Vector3<T>& lhs, const Vector3<T>& rhs ) +{ + return lhs.Luminance() < rhs.Luminance(); +} + +typedef Vector3<int32_t> v3i; +typedef Vector3<float> v3f; +typedef Vector3<uint8_t> v3b; + + +static inline v3b v3f_to_v3b( const v3f& v ) +{ + return v3b( uint8_t( std::min( 1.f, v.x ) * 255 ), uint8_t( std::min( 1.f, v.y ) * 255 ), uint8_t( std::min( 1.f, v.z ) * 255 ) ); +} + +template<class T> +Vector3<T> Mix( const Vector3<T>& v1, const Vector3<T>& v2, float amount ) +{ + return v1 + ( v2 - v1 ) * amount; +} + +template<> +inline v3b Mix( const v3b& v1, const v3b& v2, float amount ) +{ + return v3b( v3f( v1 ) + ( v3f( v2 ) - v3f( v1 ) ) * amount ); +} + +template<class T> +Vector3<T> Desaturate( const Vector3<T>& v ) +{ + T l = v.Luminance(); + return Vector3<T>( l, l, l ); +} + +template<class T> +Vector3<T> Desaturate( const Vector3<T>& v, float mul ) +{ + T l = T( v.Luminance() * mul ); + return Vector3<T>( l, l, l ); +} + +template<class T> +Vector3<T> pow( const Vector3<T>& base, float exponent ) +{ + return Vector3<T>( + pow( base.x, exponent ), + pow( base.y, exponent ), + pow( base.z, exponent ) ); +} + +template<class T> +Vector3<T> sRGB2linear( const Vector3<T>& v ) +{ + return Vector3<T>( + sRGB2linear( v.x ), + sRGB2linear( v.y ), + sRGB2linear( v.z ) ); +} + +template<class T> +Vector3<T> linear2sRGB( const Vector3<T>& v ) +{ + return Vector3<T>( + linear2sRGB( v.x ), + linear2sRGB( v.y ), + linear2sRGB( v.z ) ); +} + +#endif diff --git a/thirdparty/icu4c/APIChangeReport.md b/thirdparty/icu4c/APIChangeReport.md deleted file mode 100644 index 5385904fd1..0000000000 --- a/thirdparty/icu4c/APIChangeReport.md +++ /dev/null @@ -1,396 +0,0 @@ - - -<!-- - Copyright © 2019 and later: Unicode, Inc. and others. - License & terms of use: http://www.unicode.org/copyright.html ---> - -# ICU4C API Comparison: ICU 67 with ICU 68 - -> _Note_ Markdown format of this document is new for ICU 65. - -- [Removed from ICU 67](#removed) -- [Deprecated or Obsoleted in ICU 68](#deprecated) -- [Changed in ICU 68](#changed) -- [Promoted to stable in ICU 68](#promoted) -- [Added in ICU 68](#added) -- [Other existing drafts in ICU 68](#other) -- [Signature Simplifications](#simplifications) - -## Removed - -Removed from ICU 67 - -| File | API | ICU 67 | ICU 68 | -|---|---|---|---| -| fmtable.h | const UFormattable* icu::Formattable::toUFormattable() | StableICU 52 | (missing) -| measunit.h | LocalArray<MeasureUnit> icu::MeasureUnit::splitToSingleUnits(int32_t&, UErrorCode&) const | InternalICU 67 | (missing) -| measunit.h | int32_t icu::MeasureUnit::getIndex() const | Internal | (missing) -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::resolveUnitPerUnit(const MeasureUnit&, const MeasureUnit&, bool*) | Internal | (missing) -| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::getIndexCount() | Internal | (missing) -| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::internalGetIndexForTypeAndSubtype(const char*, const char*) | Internal | (missing) -| nounit.h | UClassID icu::NoUnit::getDynamicClassID() const | DraftICU 60 | (missing) -| nounit.h | icu::NoUnit::NoUnit(const NoUnit&) | DraftICU 60 | (missing) -| nounit.h | icu::NoUnit::~NoUnit() | DraftICU 60 | (missing) -| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::base() | DraftICU 60 | (missing) -| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::percent() | DraftICU 60 | (missing) -| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::permille() | DraftICU 60 | (missing) -| nounit.h | <tt>static</tt> UClassID icu::NoUnit::getStaticClassID() | DraftICU 60 | (missing) -| nounit.h | void* icu::NoUnit::clone() const | DraftICU 60 | (missing) -| uniset.h | const USet* icu::UnicodeSet::toUSet() | StableICU 4.2 | (missing) - -## Deprecated - -Deprecated or Obsoleted in ICU 68 - -| File | API | ICU 67 | ICU 68 | -|---|---|---|---| -| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&) const | DraftICU 63 | DeprecatedICU 68 -| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&) const | DraftICU 63 | DeprecatedICU 68 -| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68 -| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68 - -## Changed - -Changed in ICU 68 (old, new) - - - -| File | API | ICU 67 | ICU 68 | -|---|---|---|---| -| bytestrie.h | BytesTrie& icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65 -| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65 -| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&, UListFormatterType, UListFormatterWidth, UErrorCode&) | Draft→StableICU 67 -| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::operator=(Builder&&) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65 -| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | LocaleMatcher& icu::LocaleMatcher::operator=(LocaleMatcher&&) | Draft→StableICU 65 -| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | Result& icu::LocaleMatcher::Result::operator=(Result&&) | Draft→StableICU 65 -| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&&) | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&&) | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Result::Result(Result&&) | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65 -| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65 -| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65 -| locid.h | UBool icu::Locale::ConvertingIterator< Iter, Conv >::hasNext() const override | Draft→StableICU 65 -| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65 -| locid.h | UBool icu::Locale::RangeIterator< Iter >::hasNext() const override | Draft→StableICU 65 -| locid.h | const Locale& icu::Locale::ConvertingIterator< Iter, Conv >::next() override | Draft→StableICU 65 -| locid.h | const Locale& icu::Locale::Iterator::next() | Draft→StableICU 65 -| locid.h | const Locale& icu::Locale::RangeIterator< Iter >::next() override | Draft→StableICU 65 -| locid.h | icu::Locale::ConvertingIterator< Iter, Conv >::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65 -| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65 -| locid.h | icu::Locale::RangeIterator< Iter >::RangeIterator(Iter, Iter) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&) | Draft→StableICU 65 -| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&) const | Draft→StableICU 65 -| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&) const | DraftICU 63 | DeprecatedICU 68 -| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&) const | DraftICU 63 | DeprecatedICU 68 -| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65 -| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65 -| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65 -| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65 -| ucharstrie.h | UCharsTrie& icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65 -| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65 -| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67 -| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65 -| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65 -| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65 -| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65 -| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68 -| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65 - -## Promoted - -Promoted to stable in ICU 68 - -| File | API | ICU 67 | ICU 68 | -|---|---|---|---| -| bytestrie.h | BytesTrie& icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65 -| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65 -| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52 -| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&, UListFormatterType, UListFormatterWidth, UErrorCode&) | Draft→StableICU 67 -| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::operator=(Builder&&) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65 -| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | LocaleMatcher& icu::LocaleMatcher::operator=(LocaleMatcher&&) | Draft→StableICU 65 -| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | Result& icu::LocaleMatcher::Result::operator=(Result&&) | Draft→StableICU 65 -| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&) const | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65 -| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&&) | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&&) | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Result::Result(Result&&) | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65 -| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65 -| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65 -| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65 -| locid.h | UBool icu::Locale::ConvertingIterator< Iter, Conv >::hasNext() const override | Draft→StableICU 65 -| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65 -| locid.h | UBool icu::Locale::RangeIterator< Iter >::hasNext() const override | Draft→StableICU 65 -| locid.h | const Locale& icu::Locale::ConvertingIterator< Iter, Conv >::next() override | Draft→StableICU 65 -| locid.h | const Locale& icu::Locale::Iterator::next() | Draft→StableICU 65 -| locid.h | const Locale& icu::Locale::RangeIterator< Iter >::next() override | Draft→StableICU 65 -| locid.h | icu::Locale::ConvertingIterator< Iter, Conv >::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65 -| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65 -| locid.h | icu::Locale::RangeIterator< Iter >::RangeIterator(Iter, Iter) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&) | Draft→StableICU 65 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&) | Draft→StableICU 65 -| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&) const | Draft→StableICU 65 -| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65 -| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65 -| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65 -| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65 -| ucharstrie.h | UCharsTrie& icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65 -| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65 -| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67 -| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67 -| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65 -| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65 -| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65 -| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65 -| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65 -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65 - -## Added - -Added in ICU 68 - -| File | API | ICU 67 | ICU 68 | -|---|---|---|---| -| dtitvfmt.h | UDisplayContext icu::DateIntervalFormat::getContext(UDisplayContextType, UErrorCode&) const | (missing) | DraftICU 68 -| dtitvfmt.h | void icu::DateIntervalFormat::setContext(UDisplayContext, UErrorCode&) | (missing) | DraftICU 68 -| dtptngen.h | <tt>static</tt> DateTimePatternGenerator* icu::DateTimePatternGenerator::createInstanceNoStdPat(const Locale&, UErrorCode&) | (missing) | Internal -| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setMaxDistance(const Locale&, const Locale&) | (missing) | DraftICU 68 -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setNoDefaultLocale() | (missing) | DraftICU 68 -| localematcher.h | UBool icu::LocaleMatcher::isMatch(const Locale&, const Locale&, UErrorCode&) const | (missing) | DraftICU 68 -| measunit.h | int32_t icu::MeasureUnit::getOffset() const | (missing) | Internal -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getCandela() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoon() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoonImperial() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDot() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDram() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDrop() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEarthRadius() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getGrain() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getJigger() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getLumen() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPinch() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getQuartImperial() | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createCandela(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoon(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoonImperial(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDot(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDram(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDrop(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEarthRadius(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createGrain(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createJigger(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createLumen(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPinch(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createQuartImperial(UErrorCode&) | (missing) | DraftICU 68 -| measunit.h | std::pair< LocalArray< MeasureUnit >, int32_t > icu::MeasureUnit::splitToSingleUnits(UErrorCode&) const | (missing) | DraftICU 68 -| numberformatter.h | Derived icu::number::NumberFormatterSettings< Derived >::usage(StringPiece) const& | (missing) | DraftICU 68 -| numberformatter.h | Derived icu::number::NumberFormatterSettings< Derived >::usage(StringPiece)&& | (missing) | DraftICU 68 -| numberformatter.h | MeasureUnit icu::number::FormattedNumber::getOutputUnit(UErrorCode&) const | (missing) | DraftICU 68 -| numberformatter.h | Usage& icu::number::impl::Usage::operator=(Usage&&) | (missing) | Internal -| numberformatter.h | Usage& icu::number::impl::Usage::operator=(const Usage&) | (missing) | Internal -| numberformatter.h | bool icu::number::impl::Usage::isSet() const | (missing) | Internal -| numberformatter.h | icu::number::impl::Usage::Usage(Usage&&) | (missing) | Internal -| numberformatter.h | icu::number::impl::Usage::Usage(const Usage&) | (missing) | Internal -| numberformatter.h | icu::number::impl::Usage::~Usage() | (missing) | Internal -| numberformatter.h | int16_t icu::number::impl::Usage::length() const | (missing) | Internal -| numberformatter.h | void icu::number::impl::Usage::set(StringPiece) | (missing) | Internal -| numberrangeformatter.h | std::pair< StringClass, StringClass > icu::number::FormattedNumberRange::getDecimalNumbers(UErrorCode&) const | (missing) | DraftICU 68 -| plurrule.h | UnicodeString icu::PluralRules::select(const number::FormattedNumberRange&, UErrorCode&) const | (missing) | DraftICU 68 -| plurrule.h | UnicodeString icu::PluralRules::select(const number::impl::UFormattedNumberRangeData*, UErrorCode&) const | (missing) | Internal -| plurrule.h | int32_t icu::PluralRules::getSamples(const UnicodeString&, FixedDecimal*, int32_t, UErrorCode&) | (missing) | Internal -| timezone.h | <tt>static</tt> TimeZone* icu::TimeZone::forLocaleOrDefault(const Locale&) | (missing) | Internal -| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_FORMAL_SYMBOL_NAME | (missing) | DraftICU 68 -| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_VARIANT_SYMBOL_NAME | (missing) | DraftICU 68 -| udateintervalformat.h | UDisplayContext udtitvfmt_getContext(const UDateIntervalFormat*, UDisplayContextType, UErrorCode*) | (missing) | DraftICU 68 -| udateintervalformat.h | void udtitvfmt_setContext(UDateIntervalFormat*, UDisplayContext, UErrorCode*) | (missing) | DraftICU 68 -| umachine.h | <tt>#define</tt> U_DEFINE_FALSE_AND_TRUE | (missing) | InternalICU 68 -| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2 -| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_AUTO | (missing) | DraftICU 68 -| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_MIN2 | (missing) | DraftICU 68 -| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_FORMAL | (missing) | DraftICU 68 -| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_VARIANT | (missing) | DraftICU 68 -| unumberformatter.h | int32_t unumf_resultToDecimalNumber(const UFormattedNumber*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | UFormattedNumberRange* unumrf_openResult(UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | UNumberRangeFormatter* unumrf_openForSkeletonWithCollapseAndIdentityFallback(const UChar*, int32_t, UNumberRangeCollapse, UNumberRangeIdentityFallback, const char*, UParseError*, UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | UNumberRangeIdentityResult unumrf_resultGetIdentityResult(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | const UFormattedValue* unumrf_resultAsValue(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | int32_t unumrf_resultGetFirstDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | int32_t unumrf_resultGetSecondDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | void unumrf_close(UNumberRangeFormatter*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | void unumrf_closeResult(UFormattedNumberRange*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | void unumrf_formatDecimalRange(const UNumberRangeFormatter*, const char*, int32_t, const char*, int32_t, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68 -| unumberrangeformatter.h | void unumrf_formatDoubleRange(const UNumberRangeFormatter*, double, double, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68 -| upluralrules.h | int32_t uplrules_selectForRange(const UPluralRules*, const struct UFormattedNumberRange*, UChar*, int32_t, UErrorCode*) | (missing) | DraftICU 68 - -## Other - -Other existing drafts in ICU 68 - -| File | API | ICU 67 | ICU 68 | -|---|---|---|---| -| bytestream.h | void icu::ByteSink::AppendU8(const char*, int32_t) | DraftICU 67 | -| bytestream.h | void icu::ByteSink::AppendU8(const char8_t*, int32_t) | DraftICU 67 | -| dtptngen.h | UDateFormatHourCycle icu::DateTimePatternGenerator::getDefaultHourCycle(UErrorCode&) const | DraftICU 67 | -| localematcher.h | Builder& icu::LocaleMatcher::Builder::setDirection(ULocMatchDirection) | DraftICU 67 | -| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_ONLY_TWO_WAY | DraftICU 67 | -| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_WITH_ONE_WAY | DraftICU 67 | -| locid.h | void icu::Locale::canonicalize(UErrorCode&) | DraftICU 67 | -| measfmt.h | void icu::MeasureFormat::parseObject(const UnicodeString&, Formattable&, ParsePosition&) const | DraftICU 53 | -| measunit.h | MeasureUnit icu::MeasureUnit::product(const MeasureUnit&, UErrorCode&) const | DraftICU 67 | -| measunit.h | MeasureUnit icu::MeasureUnit::reciprocal(UErrorCode&) const | DraftICU 67 | -| measunit.h | MeasureUnit icu::MeasureUnit::withDimensionality(int32_t, UErrorCode&) const | DraftICU 67 | -| measunit.h | MeasureUnit icu::MeasureUnit::withSIPrefix(UMeasureSIPrefix, UErrorCode&) const | DraftICU 67 | -| measunit.h | MeasureUnit& icu::MeasureUnit::operator=(MeasureUnit&&) noexcept | DraftICU 67 | -| measunit.h | UMeasureSIPrefix icu::MeasureUnit::getSIPrefix(UErrorCode&) const | DraftICU 67 | -| measunit.h | UMeasureUnitComplexity icu::MeasureUnit::getComplexity(UErrorCode&) const | DraftICU 67 | -| measunit.h | const char* icu::MeasureUnit::getIdentifier() const | DraftICU 67 | -| measunit.h | icu::MeasureUnit::MeasureUnit(MeasureUnit&&) noexcept | DraftICU 67 | -| measunit.h | int32_t icu::MeasureUnit::getDimensionality(UErrorCode&) const | DraftICU 67 | -| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::forIdentifier(StringPiece, UErrorCode&) | DraftICU 67 | -| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*) | DraftICU 67 | -| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*, int32_t) | DraftICU 67 | -| stringpiece.h | icu::StringPiece::StringPiece(const std::u8string&) | DraftICU 67 | -| stringpiece.h | icu::StringPiece::StringPiece(std::nullptr_t) | DraftICU 67 | -| stringpiece.h | int32_t icu::StringPiece::compare(StringPiece) | DraftICU 67 | -| stringpiece.h | int32_t icu::StringPiece::find(StringPiece, int32_t) | DraftICU 67 | -| stringpiece.h | void icu::StringPiece::set(const char8_t*) | DraftICU 67 | -| stringpiece.h | void icu::StringPiece::set(const char8_t*, int32_t) | DraftICU 67 | -| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_11 | DraftICU 67 | -| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_12 | DraftICU 67 | -| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_23 | DraftICU 67 | -| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_24 | DraftICU 67 | -| udateintervalformat.h | void udtitvfmt_formatCalendarToResult(const UDateIntervalFormat*, UCalendar*, UCalendar*, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 | -| udateintervalformat.h | void udtitvfmt_formatToResult(const UDateIntervalFormat*, UDate, UDate, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 | -| udatpg.h | UDateFormatHourCycle udatpg_getDefaultHourCycle(const UDateTimePatternGenerator*, UErrorCode*) | DraftICU 67 | -| uregex.h | <tt>enum</tt> URegexpFlag::UREGEX_CANON_EQ | DraftICU 2.4 | -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_BREAK_ENGINE | DraftICU 67 | -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_CHARACTER | DraftICU 67 | -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_LINE | DraftICU 67 | -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_SENTENCE | DraftICU 67 | -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_TITLE | DraftICU 67 | -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_WORD | DraftICU 67 | -| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_START | DraftICU 67 | - -## Simplifications - -This section shows cases where the signature was "simplified" for the sake of comparison. The simplified form is in bold, followed by - all possible variations in "original" form. - - -## Colophon - -Contents generated by StableAPI tool on Fri Oct 23 11:32:42 PDT 2020 - -Copyright © 2019 and later: Unicode, Inc. and others. -License & terms of use: http://www.unicode.org/copyright.html -
\ No newline at end of file diff --git a/thirdparty/icu4c/common/bytestriebuilder.cpp b/thirdparty/icu4c/common/bytestriebuilder.cpp index ec1ab7d8f5..28256f272a 100644 --- a/thirdparty/icu4c/common/bytestriebuilder.cpp +++ b/thirdparty/icu4c/common/bytestriebuilder.cpp @@ -474,31 +474,39 @@ BytesTrieBuilder::writeDeltaTo(int32_t jumpTarget) { U_ASSERT(i>=0); if(i<=BytesTrie::kMaxOneByteDelta) { return write(i); + } else { + char intBytes[5]; + return write(intBytes, internalEncodeDelta(i, intBytes)); } - char intBytes[5]; - int32_t length; +} + +int32_t +BytesTrieBuilder::internalEncodeDelta(int32_t i, char intBytes[]) { + U_ASSERT(i>=0); + if(i<=BytesTrie::kMaxOneByteDelta) { + intBytes[0]=(char)i; + return 1; + } + int32_t length=1; if(i<=BytesTrie::kMaxTwoByteDelta) { intBytes[0]=(char)(BytesTrie::kMinTwoByteDeltaLead+(i>>8)); - length=1; } else { if(i<=BytesTrie::kMaxThreeByteDelta) { intBytes[0]=(char)(BytesTrie::kMinThreeByteDeltaLead+(i>>16)); - length=2; } else { if(i<=0xffffff) { intBytes[0]=(char)BytesTrie::kFourByteDeltaLead; - length=3; } else { intBytes[0]=(char)BytesTrie::kFiveByteDeltaLead; intBytes[1]=(char)(i>>24); - length=4; + length=2; } - intBytes[1]=(char)(i>>16); + intBytes[length++]=(char)(i>>16); } - intBytes[1]=(char)(i>>8); + intBytes[length++]=(char)(i>>8); } intBytes[length++]=(char)i; - return write(intBytes, length); + return length; } U_NAMESPACE_END diff --git a/thirdparty/icu4c/common/charstr.cpp b/thirdparty/icu4c/common/charstr.cpp index 318a185b3f..c35622882c 100644 --- a/thirdparty/icu4c/common/charstr.cpp +++ b/thirdparty/icu4c/common/charstr.cpp @@ -14,6 +14,8 @@ * created by: Markus W. Scherer */ +#include <cstdlib> + #include "unicode/utypes.h" #include "unicode/putil.h" #include "charstr.h" @@ -141,6 +143,38 @@ CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &error return *this; } +CharString &CharString::appendNumber(int32_t number, UErrorCode &status) { + if (number < 0) { + this->append('-', status); + if (U_FAILURE(status)) { + return *this; + } + } + + if (number == 0) { + this->append('0', status); + return *this; + } + + int32_t numLen = 0; + while (number != 0) { + int32_t residue = number % 10; + number /= 10; + this->append(std::abs(residue) + '0', status); + numLen++; + if (U_FAILURE(status)) { + return *this; + } + } + + int32_t start = this->length() - numLen, end = this->length() - 1; + while(start < end) { + std::swap(this->data()[start++], this->data()[end--]); + } + + return *this; +} + char *CharString::getAppendBuffer(int32_t minCapacity, int32_t desiredCapacityHint, int32_t &resultCapacity, diff --git a/thirdparty/icu4c/common/charstr.h b/thirdparty/icu4c/common/charstr.h index 6619faac61..175acd1c0a 100644 --- a/thirdparty/icu4c/common/charstr.h +++ b/thirdparty/icu4c/common/charstr.h @@ -127,6 +127,9 @@ public: return append(s.data(), s.length(), errorCode); } CharString &append(const char *s, int32_t sLength, UErrorCode &status); + + CharString &appendNumber(int32_t number, UErrorCode &status); + /** * Returns a writable buffer for appending and writes the buffer's capacity to * resultCapacity. Guarantees resultCapacity>=minCapacity if U_SUCCESS(). diff --git a/thirdparty/icu4c/common/cmemory.h b/thirdparty/icu4c/common/cmemory.h index a9d9424b4e..f03b7dcce6 100644 --- a/thirdparty/icu4c/common/cmemory.h +++ b/thirdparty/icu4c/common/cmemory.h @@ -31,14 +31,63 @@ #include <stddef.h> #include <string.h> #include "unicode/localpointer.h" +#include "uassert.h" #if U_DEBUG && defined(UPRV_MALLOC_COUNT) #include <stdio.h> #endif - -#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size) -#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size) +// uprv_memcpy and uprv_memmove +#if defined(__clang__) +#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ + /* Suppress warnings about addresses that will never be NULL */ \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Waddress\"") \ + U_ASSERT(dst != NULL); \ + U_ASSERT(src != NULL); \ + _Pragma("clang diagnostic pop") \ + U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \ +} UPRV_BLOCK_MACRO_END +#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ + /* Suppress warnings about addresses that will never be NULL */ \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Waddress\"") \ + U_ASSERT(dst != NULL); \ + U_ASSERT(src != NULL); \ + _Pragma("clang diagnostic pop") \ + U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \ +} UPRV_BLOCK_MACRO_END +#elif defined(__GNUC__) +#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ + /* Suppress warnings about addresses that will never be NULL */ \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Waddress\"") \ + U_ASSERT(dst != NULL); \ + U_ASSERT(src != NULL); \ + _Pragma("GCC diagnostic pop") \ + U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \ +} UPRV_BLOCK_MACRO_END +#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ + /* Suppress warnings about addresses that will never be NULL */ \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Waddress\"") \ + U_ASSERT(dst != NULL); \ + U_ASSERT(src != NULL); \ + _Pragma("GCC diagnostic pop") \ + U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \ +} UPRV_BLOCK_MACRO_END +#else +#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ + U_ASSERT(dst != NULL); \ + U_ASSERT(src != NULL); \ + U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \ +} UPRV_BLOCK_MACRO_END +#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \ + U_ASSERT(dst != NULL); \ + U_ASSERT(src != NULL); \ + U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \ +} UPRV_BLOCK_MACRO_END +#endif /** * \def UPRV_LENGTHOF diff --git a/thirdparty/icu4c/common/dictbe.cpp b/thirdparty/icu4c/common/dictbe.cpp index b42cdf03fa..44285755f3 100644 --- a/thirdparty/icu4c/common/dictbe.cpp +++ b/thirdparty/icu4c/common/dictbe.cpp @@ -265,13 +265,9 @@ ThaiBreakEngine::divideUpDictionaryRange( UText *text, goto foundBest; } do { - int32_t wordsMatched = 1; if (words[(wordsFound + 1) % THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) { - if (wordsMatched < 2) { - // Followed by another dictionary word; mark first word as a good candidate - words[wordsFound%THAI_LOOKAHEAD].markCurrent(); - wordsMatched = 2; - } + // Followed by another dictionary word; mark first word as a good candidate + words[wordsFound%THAI_LOOKAHEAD].markCurrent(); // If we're already at the end of the range, we're done if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) { @@ -503,13 +499,9 @@ LaoBreakEngine::divideUpDictionaryRange( UText *text, goto foundBest; } do { - int32_t wordsMatched = 1; if (words[(wordsFound + 1) % LAO_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) { - if (wordsMatched < 2) { - // Followed by another dictionary word; mark first word as a good candidate - words[wordsFound%LAO_LOOKAHEAD].markCurrent(); - wordsMatched = 2; - } + // Followed by another dictionary word; mark first word as a good candidate + words[wordsFound%LAO_LOOKAHEAD].markCurrent(); // If we're already at the end of the range, we're done if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) { @@ -699,13 +691,9 @@ BurmeseBreakEngine::divideUpDictionaryRange( UText *text, goto foundBest; } do { - int32_t wordsMatched = 1; if (words[(wordsFound + 1) % BURMESE_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) { - if (wordsMatched < 2) { - // Followed by another dictionary word; mark first word as a good candidate - words[wordsFound%BURMESE_LOOKAHEAD].markCurrent(); - wordsMatched = 2; - } + // Followed by another dictionary word; mark first word as a good candidate + words[wordsFound%BURMESE_LOOKAHEAD].markCurrent(); // If we're already at the end of the range, we're done if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) { @@ -908,13 +896,9 @@ KhmerBreakEngine::divideUpDictionaryRange( UText *text, goto foundBest; } do { - int32_t wordsMatched = 1; if (words[(wordsFound + 1) % KHMER_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) { - if (wordsMatched < 2) { - // Followed by another dictionary word; mark first word as a good candidate - words[wordsFound % KHMER_LOOKAHEAD].markCurrent(); - wordsMatched = 2; - } + // Followed by another dictionary word; mark first word as a good candidate + words[wordsFound % KHMER_LOOKAHEAD].markCurrent(); // If we're already at the end of the range, we're done if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) { diff --git a/thirdparty/icu4c/common/edits.cpp b/thirdparty/icu4c/common/edits.cpp index 95f0c19a72..92ca36fb5d 100644 --- a/thirdparty/icu4c/common/edits.cpp +++ b/thirdparty/icu4c/common/edits.cpp @@ -86,6 +86,7 @@ Edits &Edits::moveArray(Edits &src) U_NOEXCEPT { } Edits &Edits::operator=(const Edits &other) { + if (this == &other) { return *this; } // self-assignment: no-op length = other.length; delta = other.delta; numChanges = other.numChanges; diff --git a/thirdparty/icu4c/common/filteredbrk.cpp b/thirdparty/icu4c/common/filteredbrk.cpp index c07128cbce..25080f9d33 100644 --- a/thirdparty/icu4c/common/filteredbrk.cpp +++ b/thirdparty/icu4c/common/filteredbrk.cpp @@ -20,6 +20,7 @@ #include "ubrkimpl.h" // U_ICUDATA_BRKITR #include "uvector.h" #include "cmemory.h" +#include "umutex.h" U_NAMESPACE_BEGIN @@ -139,13 +140,30 @@ class SimpleFilteredSentenceBreakData : public UMemory { public: SimpleFilteredSentenceBreakData(UCharsTrie *forwards, UCharsTrie *backwards ) : fForwardsPartialTrie(forwards), fBackwardsTrie(backwards), refcount(1) { } - SimpleFilteredSentenceBreakData *incr() { refcount++; return this; } - SimpleFilteredSentenceBreakData *decr() { if((--refcount) <= 0) delete this; return 0; } - virtual ~SimpleFilteredSentenceBreakData(); + SimpleFilteredSentenceBreakData *incr() { + umtx_atomic_inc(&refcount); + return this; + } + SimpleFilteredSentenceBreakData *decr() { + if(umtx_atomic_dec(&refcount) <= 0) { + delete this; + } + return 0; + } + virtual ~SimpleFilteredSentenceBreakData(); + + bool hasForwardsPartialTrie() const { return fForwardsPartialTrie.isValid(); } + bool hasBackwardsTrie() const { return fBackwardsTrie.isValid(); } - LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M." - LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs. - int32_t refcount; + const UCharsTrie &getForwardsPartialTrie() const { return *fForwardsPartialTrie; } + const UCharsTrie &getBackwardsTrie() const { return *fBackwardsTrie; } + +private: + // These tries own their data arrays. + // They are shared and must therefore not be modified. + LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M." + LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs. + u_atomic_int32_t refcount; }; SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData() {} @@ -244,7 +262,13 @@ SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(BreakIt fData(new SimpleFilteredSentenceBreakData(forwards, backwards)), fDelegate(adopt) { - // all set.. + if (fData == nullptr) { + delete forwards; + delete backwards; + if (U_SUCCESS(status)) { + status = U_MEMORY_ALLOCATION_ERROR; + } + } } SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator() { @@ -261,59 +285,62 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) { int32_t bestValue = -1; // loops while 'n' points to an exception. utext_setNativeIndex(fText.getAlias(), n); // from n.. - fData->fBackwardsTrie->reset(); - UChar32 uch; //if(debug2) u_printf(" n@ %d\n", n); // Assume a space is following the '.' (so we handle the case: "Mr. /Brown") - if((uch=utext_previous32(fText.getAlias()))==(UChar32)0x0020) { // TODO: skip a class of chars here?? + if(utext_previous32(fText.getAlias())==u' ') { // TODO: skip a class of chars here?? // TODO only do this the 1st time? //if(debug2) u_printf("skipping prev: |%C| \n", (UChar)uch); } else { //if(debug2) u_printf("not skipping prev: |%C| \n", (UChar)uch); - uch = utext_next32(fText.getAlias()); + utext_next32(fText.getAlias()); //if(debug2) u_printf(" -> : |%C| \n", (UChar)uch); } - UStringTrieResult r = USTRINGTRIE_INTERMEDIATE_VALUE; - - while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL && // more to consume backwards and.. - USTRINGTRIE_HAS_NEXT(r=fData->fBackwardsTrie->nextForCodePoint(uch))) {// more in the trie - if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far - bestPosn = utext_getNativeIndex(fText.getAlias()); - bestValue = fData->fBackwardsTrie->getValue(); - } - //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias())); + { + // Do not modify the shared trie! + UCharsTrie iter(fData->getBackwardsTrie()); + UChar32 uch; + while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL) { // more to consume backwards + UStringTrieResult r = iter.nextForCodePoint(uch); + if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far + bestPosn = utext_getNativeIndex(fText.getAlias()); + bestValue = iter.getValue(); + } + if(!USTRINGTRIE_HAS_NEXT(r)) { + break; + } + //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias())); + } } - if(USTRINGTRIE_MATCHES(r)) { // exact match? - //if(debug2) u_printf("rev<?/%C/?end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue); - bestValue = fData->fBackwardsTrie->getValue(); - bestPosn = utext_getNativeIndex(fText.getAlias()); - //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue); - } + //if(bestValue >= 0) { + //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue); + //} if(bestPosn>=0) { //if(debug2) u_printf("rev< /%C/ end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue); //if(USTRINGTRIE_MATCHES(r)) { // matched - so, now what? - //int32_t bestValue = fBackwardsTrie->getValue(); + //int32_t bestValue = iter.getValue(); ////if(debug2) u_printf("rev< /%C/ matched, skip..%d bestValue=%d\n", (UChar)uch, r, bestValue); if(bestValue == kMATCH) { // exact match! //if(debug2) u_printf(" exact backward match\n"); return kExceptionHere; // See if the next is another exception. } else if(bestValue == kPARTIAL - && fData->fForwardsPartialTrie.isValid()) { // make sure there's a forward trie + && fData->hasForwardsPartialTrie()) { // make sure there's a forward trie //if(debug2) u_printf(" partial backward match\n"); // We matched the "Ph." in "Ph.D." - now we need to run everything through the forwards trie // to see if it matches something going forward. - fData->fForwardsPartialTrie->reset(); UStringTrieResult rfwd = USTRINGTRIE_INTERMEDIATE_VALUE; utext_setNativeIndex(fText.getAlias(), bestPosn); // hope that's close .. //if(debug2) u_printf("Retrying at %d\n", bestPosn); + // Do not modify the shared trie! + UCharsTrie iter(fData->getForwardsPartialTrie()); + UChar32 uch; while((uch=utext_next32(fText.getAlias()))!=U_SENTINEL && - USTRINGTRIE_HAS_NEXT(rfwd=fData->fForwardsPartialTrie->nextForCodePoint(uch))) { + USTRINGTRIE_HAS_NEXT(rfwd=iter.nextForCodePoint(uch))) { //if(debug2) u_printf("fwd> /%C/ cont?%d @%d\n", (UChar)uch, rfwd, utext_getNativeIndex(fText.getAlias())); } if(USTRINGTRIE_MATCHES(rfwd)) { @@ -339,7 +366,7 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) { int32_t SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) { if(n == UBRK_DONE || // at end or - fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions + !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions return n; } // OK, do we need to break here? @@ -369,7 +396,7 @@ SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) { int32_t SimpleFilteredSentenceBreakIterator::internalPrev(int32_t n) { if(n == 0 || n == UBRK_DONE || // at end or - fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions + !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions return n; } // OK, do we need to break here? @@ -420,7 +447,7 @@ SimpleFilteredSentenceBreakIterator::previous(void) { UBool SimpleFilteredSentenceBreakIterator::isBoundary(int32_t offset) { if (!fDelegate->isBoundary(offset)) return false; // no break to suppress - if (fData->fBackwardsTrie.isNull()) return true; // no data = no suppressions + if (!fData->hasBackwardsTrie()) return true; // no data = no suppressions UErrorCode status = U_ZERO_ERROR; resetState(status); diff --git a/thirdparty/icu4c/common/hash.h b/thirdparty/icu4c/common/hash.h index f02cb7087a..b927ddb3c3 100644 --- a/thirdparty/icu4c/common/hash.h +++ b/thirdparty/icu4c/common/hash.h @@ -85,16 +85,22 @@ public: inline int32_t puti(const UnicodeString& key, int32_t value, UErrorCode& status); + inline int32_t putiAllowZero(const UnicodeString& key, int32_t value, UErrorCode& status); + inline void* get(const UnicodeString& key) const; inline int32_t geti(const UnicodeString& key) const; + inline int32_t getiAndFound(const UnicodeString& key, UBool &found) const; + inline void* remove(const UnicodeString& key); inline int32_t removei(const UnicodeString& key); inline void removeAll(void); + inline UBool containsKey(const UnicodeString& key) const; + inline const UHashElement* find(const UnicodeString& key) const; /** @@ -203,6 +209,11 @@ inline int32_t Hashtable::puti(const UnicodeString& key, int32_t value, UErrorCo return uhash_puti(hash, new UnicodeString(key), value, &status); } +inline int32_t Hashtable::putiAllowZero(const UnicodeString& key, int32_t value, + UErrorCode& status) { + return uhash_putiAllowZero(hash, new UnicodeString(key), value, &status); +} + inline void* Hashtable::get(const UnicodeString& key) const { return uhash_get(hash, &key); } @@ -211,6 +222,10 @@ inline int32_t Hashtable::geti(const UnicodeString& key) const { return uhash_geti(hash, &key); } +inline int32_t Hashtable::getiAndFound(const UnicodeString& key, UBool &found) const { + return uhash_getiAndFound(hash, &key, &found); +} + inline void* Hashtable::remove(const UnicodeString& key) { return uhash_remove(hash, &key); } @@ -219,6 +234,10 @@ inline int32_t Hashtable::removei(const UnicodeString& key) { return uhash_removei(hash, &key); } +inline UBool Hashtable::containsKey(const UnicodeString& key) const { + return uhash_containsKey(hash, &key); +} + inline const UHashElement* Hashtable::find(const UnicodeString& key) const { return uhash_find(hash, &key); } diff --git a/thirdparty/icu4c/common/localematcher.cpp b/thirdparty/icu4c/common/localematcher.cpp index 5795cbf87e..132aee290e 100644 --- a/thirdparty/icu4c/common/localematcher.cpp +++ b/thirdparty/icu4c/common/localematcher.cpp @@ -345,9 +345,8 @@ UBool compareLSRs(const UHashTok t1, const UHashTok t2) { int32_t LocaleMatcher::putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength, UErrorCode &errorCode) { if (U_FAILURE(errorCode)) { return suppLength; } - int32_t index = uhash_geti(supportedLsrToIndex, &lsr); - if (index == 0) { - uhash_puti(supportedLsrToIndex, const_cast<LSR *>(&lsr), i + 1, &errorCode); + if (!uhash_containsKey(supportedLsrToIndex, &lsr)) { + uhash_putiAllowZero(supportedLsrToIndex, const_cast<LSR *>(&lsr), i, &errorCode); if (U_SUCCESS(errorCode)) { supportedLSRs[suppLength] = &lsr; supportedIndexes[suppLength++] = i; @@ -685,12 +684,11 @@ int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remai int32_t bestSupportedLsrIndex = -1; for (int32_t bestShiftedDistance = LocaleDistance::shiftDistance(thresholdDistance);;) { // Quick check for exact maximized LSR. - // Returns suppIndex+1 where 0 means not found. if (supportedLsrToIndex != nullptr) { desiredLSR.setHashCode(); - int32_t index = uhash_geti(supportedLsrToIndex, &desiredLSR); - if (index != 0) { - int32_t suppIndex = index - 1; + UBool found = false; + int32_t suppIndex = uhash_getiAndFound(supportedLsrToIndex, &desiredLSR, &found); + if (found) { if (remainingIter != nullptr) { remainingIter->rememberCurrent(desiredIndex, errorCode); } diff --git a/thirdparty/icu4c/common/localeprioritylist.cpp b/thirdparty/icu4c/common/localeprioritylist.cpp index 8916b121be..4455eedb75 100644 --- a/thirdparty/icu4c/common/localeprioritylist.cpp +++ b/thirdparty/icu4c/common/localeprioritylist.cpp @@ -187,17 +187,18 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e if (U_FAILURE(errorCode)) { return false; } } LocalPointer<Locale> clone; - int32_t index = uhash_geti(map, &locale); - if (index != 0) { + UBool found = false; + int32_t index = uhash_getiAndFound(map, &locale, &found); + if (found) { // Duplicate: Remove the old item and append it anew. - LocaleAndWeight &lw = list->array[index - 1]; + LocaleAndWeight &lw = list->array[index]; clone.adoptInstead(lw.locale); lw.locale = nullptr; lw.weight = 0; ++numRemoved; } if (weight <= 0) { // do not add q=0 - if (index != 0) { + if (found) { // Not strictly necessary but cleaner. uhash_removei(map, &locale); } @@ -217,7 +218,7 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e return false; } } - uhash_puti(map, clone.getAlias(), listLength + 1, &errorCode); + uhash_putiAllowZero(map, clone.getAlias(), listLength, &errorCode); if (U_FAILURE(errorCode)) { return false; } LocaleAndWeight &lw = list->array[listLength]; lw.locale = clone.orphan(); diff --git a/thirdparty/icu4c/common/locdispnames.cpp b/thirdparty/icu4c/common/locdispnames.cpp index 47c0667417..96af3f9aa8 100644 --- a/thirdparty/icu4c/common/locdispnames.cpp +++ b/thirdparty/icu4c/common/locdispnames.cpp @@ -698,7 +698,7 @@ uloc_getDisplayName(const char *locale, } /* end switch */ if (len>0) { - /* we addeed a component, so add separator and write it if there's room. */ + /* we added a component, so add separator and write it if there's room. */ if(len+sepLen<=cap) { const UChar * plimit = p + len; for (; p < plimit; p++) { diff --git a/thirdparty/icu4c/common/locid.cpp b/thirdparty/icu4c/common/locid.cpp index 874e4a7055..0d506293a9 100644 --- a/thirdparty/icu4c/common/locid.cpp +++ b/thirdparty/icu4c/common/locid.cpp @@ -254,7 +254,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale) Locale::~Locale() { - if (baseName != fullName) { + if ((baseName != fullName) && (baseName != fullNameBuffer)) { uprv_free(baseName); } baseName = NULL; @@ -466,7 +466,7 @@ Locale& Locale::operator=(const Locale& other) { } Locale& Locale::operator=(Locale&& other) U_NOEXCEPT { - if (baseName != fullName) uprv_free(baseName); + if ((baseName != fullName) && (baseName != fullNameBuffer)) uprv_free(baseName); if (fullName != fullNameBuffer) uprv_free(fullName); if (other.fullName == other.fullNameBuffer) { @@ -524,7 +524,7 @@ static const char* const KNOWN_CANONICALIZED[] = { "km", "km_KH", "kn", "kn_IN", "ko", "ko_KR", "ky", "ky_KG", "lo", "lo_LA", "lt", "lt_LT", "lv", "lv_LV", "mk", "mk_MK", "ml", "ml_IN", "mn", "mn_MN", "mr", "mr_IN", "ms", "ms_MY", "my", "my_MM", "nb", "nb_NO", "ne", "ne_NP", - "nl", "nl_NL", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF", + "nl", "nl_NL", "no", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF", "pt", "pt_BR", "pt_PT", "ro", "ro_RO", "ru", "ru_RU", "sd", "sd_IN", "si", "si_LK", "sk", "sk_SK", "sl", "sl_SI", "so", "so_SO", "sq", "sq_AL", "sr", "sr_Cyrl_RS", "sr_Latn", "sr_RS", "sv", "sv_SE", "sw", "sw_TZ", "ta", @@ -627,6 +627,17 @@ private: LocalMemory<const char*>& types, LocalMemory<int32_t>& replacementIndexes, int32_t &length, UErrorCode &status); + + // Read the subdivisionAlias data from alias to + // strings+types+replacementIndexes + // Allocate length items for types, to store the type field. + // Allocate length items for replacementIndexes, + // to store the index in the strings for the replacement variant. + void readSubdivisionAlias(UResourceBundle* alias, + UniqueCharStrings* strings, + LocalMemory<const char*>& types, + LocalMemory<int32_t>& replacementIndexes, + int32_t &length, UErrorCode &status); }; /** @@ -647,6 +658,7 @@ public: const CharStringMap& scriptMap() const { return script; } const CharStringMap& territoryMap() const { return territory; } const CharStringMap& variantMap() const { return variant; } + const CharStringMap& subdivisionMap() const { return subdivision; } static void U_CALLCONV loadData(UErrorCode &status); static UBool U_CALLCONV cleanup(); @@ -658,11 +670,13 @@ private: CharStringMap scriptMap, CharStringMap territoryMap, CharStringMap variantMap, + CharStringMap subdivisionMap, CharString* strings) : language(std::move(languageMap)), script(std::move(scriptMap)), territory(std::move(territoryMap)), variant(std::move(variantMap)), + subdivision(std::move(subdivisionMap)), strings(strings) { } @@ -676,6 +690,7 @@ private: CharStringMap script; CharStringMap territory; CharStringMap variant; + CharStringMap subdivision; CharString* strings; friend class AliasDataBuilder; @@ -867,6 +882,34 @@ AliasDataBuilder::readVariantAlias( } /** + * Read the subdivisionAlias data from alias to strings+types+replacementIndexes. + * Allocate length items for types, to store the type field. Allocate length + * items for replacementIndexes, to store the index in the strings for the + * replacement regions. + */ +void +AliasDataBuilder::readSubdivisionAlias( + UResourceBundle* alias, + UniqueCharStrings* strings, + LocalMemory<const char*>& types, + LocalMemory<int32_t>& replacementIndexes, + int32_t &length, + UErrorCode &status) +{ + return readAlias( + alias, strings, types, replacementIndexes, length, +#if U_DEBUG + [](const char* type) { + U_ASSERT(uprv_strlen(type) >= 3 && uprv_strlen(type) <= 8); + }, +#else + [](const char*) {}, +#endif + [](const UnicodeString&) { }, + status); +} + +/** * Initializes the alias data from the ICU resource bundles. The alias data * contains alias of language, country, script and variants. * @@ -905,12 +948,14 @@ AliasDataBuilder::build(UErrorCode &status) { ures_getByKey(metadataAlias.getAlias(), "territory", nullptr, &status)); LocalUResourceBundlePointer variantAlias( ures_getByKey(metadataAlias.getAlias(), "variant", nullptr, &status)); + LocalUResourceBundlePointer subdivisionAlias( + ures_getByKey(metadataAlias.getAlias(), "subdivision", nullptr, &status)); if (U_FAILURE(status)) { return nullptr; } int32_t languagesLength = 0, scriptLength = 0, territoryLength = 0, - variantLength = 0; + variantLength = 0, subdivisionLength = 0; // Read the languageAlias into languageTypes, languageReplacementIndexes // and strings @@ -955,6 +1000,16 @@ AliasDataBuilder::build(UErrorCode &status) { variantReplacementIndexes, variantLength, status); + // Read the subdivisionAlias into subdivisionTypes, subdivisionReplacementIndexes + // and strings + LocalMemory<const char*> subdivisionTypes; + LocalMemory<int32_t> subdivisionReplacementIndexes; + readSubdivisionAlias(subdivisionAlias.getAlias(), + &strings, + subdivisionTypes, + subdivisionReplacementIndexes, + subdivisionLength, status); + if (U_FAILURE(status)) { return nullptr; } @@ -994,6 +1049,14 @@ AliasDataBuilder::build(UErrorCode &status) { status); } + // Build the subdivisionMap from subdivisionTypes & subdivisionReplacementIndexes. + CharStringMap subdivisionMap(2, status); + for (int32_t i = 0; U_SUCCESS(status) && i < subdivisionLength; i++) { + subdivisionMap.put(subdivisionTypes[i], + strings.get(subdivisionReplacementIndexes[i]), + status); + } + if (U_FAILURE(status)) { return nullptr; } @@ -1004,6 +1067,7 @@ AliasDataBuilder::build(UErrorCode &status) { std::move(scriptMap), std::move(territoryMap), std::move(variantMap), + std::move(subdivisionMap), strings.orphanCharStrings()); if (data == nullptr) { @@ -1105,6 +1169,14 @@ private: // Replace by using variantAlias. bool replaceVariant(UErrorCode& status); + + // Replace by using subdivisionAlias. + bool replaceSubdivision(StringPiece subdivision, + CharString& output, UErrorCode& status); + + // Replace transformed extensions. + bool replaceTransformedExtensions( + CharString& transformedExtensions, CharString& output, UErrorCode& status); }; CharString& @@ -1294,7 +1366,6 @@ AliasReplacer::replaceLanguage( } } if (replacedExtensions != nullptr) { - // TODO(ICU-21292) // DO NOTHING // UTS35 does not specifiy what should we do if we have extensions in the // replacement. Currently we know only the following 4 "BCP47 LegacyRules" have @@ -1435,6 +1506,106 @@ AliasReplacer::replaceVariant(UErrorCode& status) return false; } +bool +AliasReplacer::replaceSubdivision( + StringPiece subdivision, CharString& output, UErrorCode& status) +{ + if (U_FAILURE(status)) { + return false; + } + const char *replacement = data->subdivisionMap().get(subdivision.data()); + if (replacement != nullptr) { + const char* firstSpace = uprv_strchr(replacement, ' '); + // Found replacement data for this subdivision. + size_t len = (firstSpace != nullptr) ? + (firstSpace - replacement) : uprv_strlen(replacement); + if (2 <= len && len <= 8) { + output.append(replacement, (int32_t)len, status); + if (2 == len) { + // Add 'zzzz' based on changes to UTS #35 for CLDR-14312. + output.append("zzzz", 4, status); + } + } + return true; + } + return false; +} + +bool +AliasReplacer::replaceTransformedExtensions( + CharString& transformedExtensions, CharString& output, UErrorCode& status) +{ + // The content of the transformedExtensions will be modified in this + // function to NULL-terminating (tkey-tvalue) pairs. + if (U_FAILURE(status)) { + return false; + } + int32_t len = transformedExtensions.length(); + const char* str = transformedExtensions.data(); + const char* tkey = ultag_getTKeyStart(str); + int32_t tlangLen = (tkey == str) ? 0 : + ((tkey == nullptr) ? len : static_cast<int32_t>((tkey - str - 1))); + CharStringByteSink sink(&output); + if (tlangLen > 0) { + Locale tlang = LocaleBuilder() + .setLanguageTag(StringPiece(str, tlangLen)) + .build(status); + tlang.canonicalize(status); + tlang.toLanguageTag(sink, status); + if (U_FAILURE(status)) { + return false; + } + T_CString_toLowerCase(output.data()); + } + if (tkey != nullptr) { + // We need to sort the tfields by tkey + UVector tfields(status); + if (U_FAILURE(status)) { + return false; + } + do { + const char* tvalue = uprv_strchr(tkey, '-'); + if (tvalue == nullptr) { + status = U_ILLEGAL_ARGUMENT_ERROR; + } + const char* nextTKey = ultag_getTKeyStart(tvalue); + if (nextTKey != nullptr) { + *((char*)(nextTKey-1)) = '\0'; // NULL terminate tvalue + } + tfields.insertElementAt((void*)tkey, tfields.size(), status); + if (U_FAILURE(status)) { + return false; + } + tkey = nextTKey; + } while (tkey != nullptr); + tfields.sort([](UElement e1, UElement e2) -> int8_t { + // uprv_strcmp return int and in some platform, such as arm64-v8a, + // it may return positive values > 127 which cause the casted value + // of int8_t negative. + int res = uprv_strcmp( + (const char*)e1.pointer, (const char*)e2.pointer); + return (res == 0) ? 0 : ((res > 0) ? 1 : -1); + }, status); + for (int32_t i = 0; i < tfields.size(); i++) { + if (output.length() > 0) { + output.append('-', status); + } + const char* tfield = (const char*) tfields.elementAt(i); + const char* tvalue = uprv_strchr(tfield, '-'); + // Split the "tkey-tvalue" pair string so that we can canonicalize the tvalue. + U_ASSERT(tvalue != nullptr); + *((char*)tvalue++) = '\0'; // NULL terminate tkey + output.append(tfield, status).append('-', status); + const char* bcpTValue = ulocimp_toBcpType(tfield, tvalue, nullptr, nullptr); + output.append((bcpTValue == nullptr) ? tvalue : bcpTValue, status); + } + } + if (U_FAILURE(status)) { + return false; + } + return true; +} + CharString& AliasReplacer::outputToString( CharString& out, UErrorCode status) @@ -1453,8 +1624,12 @@ AliasReplacer::outputToString( out.append(SEP_CHAR, status); } variants.sort([](UElement e1, UElement e2) -> int8_t { - return uprv_strcmp( + // uprv_strcmp return int and in some platform, such as arm64-v8a, + // it may return positive values > 127 which cause the casted value + // of int8_t negative. + int res = uprv_strcmp( (const char*)e1.pointer, (const char*)e2.pointer); + return (res == 0) ? 0 : ((res > 0) ? 1 : -1); }, status); int32_t variantsStart = out.length(); for (int32_t i = 0; i < variants.size(); i++) { @@ -1497,7 +1672,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status region = nullptr; } const char* variantsStr = locale.getVariant(); - const char* extensionsStr = locale_getKeywordsStart(locale.getName()); CharString variantsBuff(variantsStr, -1, status); if (!variantsBuff.isEmpty()) { if (U_FAILURE(status)) { return false; } @@ -1516,8 +1690,12 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status // Sort the variants variants.sort([](UElement e1, UElement e2) -> int8_t { - return uprv_strcmp( + // uprv_strcmp return int and in some platform, such as arm64-v8a, + // it may return positive values > 127 which cause the casted value + // of int8_t negative. + int res = uprv_strcmp( (const char*)e1.pointer, (const char*)e2.pointer); + return (res == 0) ? 0 : ((res > 0) ? 1 : -1); }, status); // A changed count to assert when loop too many times. @@ -1561,11 +1739,52 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status if (U_FAILURE(status)) { return false; } // Nothing changed and we know the order of the vaiants are not change // because we have no variant or only one. - if (changed == 0 && variants.size() <= 1) { + const char* extensionsStr = locale_getKeywordsStart(locale.getName()); + if (changed == 0 && variants.size() <= 1 && extensionsStr == nullptr) { return false; } outputToString(out, status); + if (U_FAILURE(status)) { + return false; + } if (extensionsStr != nullptr) { + changed = 0; + Locale temp(locale); + LocalPointer<icu::StringEnumeration> iter(locale.createKeywords(status)); + if (U_SUCCESS(status) && !iter.isNull()) { + const char* key; + while ((key = iter->next(nullptr, status)) != nullptr) { + if (uprv_strcmp("sd", key) == 0 || uprv_strcmp("rg", key) == 0 || + uprv_strcmp("t", key) == 0) { + CharString value; + CharStringByteSink valueSink(&value); + locale.getKeywordValue(key, valueSink, status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + CharString replacement; + if (uprv_strlen(key) == 2) { + if (replaceSubdivision(value.toStringPiece(), replacement, status)) { + changed++; + temp.setKeywordValue(key, replacement.data(), status); + } + } else { + U_ASSERT(uprv_strcmp(key, "t") == 0); + if (replaceTransformedExtensions(value, replacement, status)) { + changed++; + temp.setKeywordValue(key, replacement.data(), status); + } + } + if (U_FAILURE(status)) { + return false; + } + } + } + } + if (changed != 0) { + extensionsStr = locale_getKeywordsStart(temp.getName()); + } out.append(extensionsStr, status); } if (U_FAILURE(status)) { @@ -1573,8 +1792,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status } // If the tag is not changed, return. if (uprv_strcmp(out.data(), locale.getName()) == 0) { - U_ASSERT(changed == 0); - U_ASSERT(variants.size() > 1); out.clear(); return false; } @@ -1636,7 +1853,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize) { fIsBogus = FALSE; /* Free our current storage */ - if (baseName != fullName) { + if ((baseName != fullName) && (baseName != fullNameBuffer)) { uprv_free(baseName); } baseName = NULL; @@ -1672,6 +1889,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize) uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err); if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) { + U_ASSERT(baseName == nullptr); /*Go to heap for the fullName if necessary*/ fullName = (char *)uprv_malloc(sizeof(char)*(length + 1)); if(fullName == 0) { @@ -1825,7 +2043,7 @@ Locale::hashCode() const void Locale::setToBogus() { /* Free our current storage */ - if(baseName != fullName) { + if((baseName != fullName) && (baseName != fullNameBuffer)) { uprv_free(baseName); } baseName = NULL; diff --git a/thirdparty/icu4c/common/loclikelysubtags.cpp b/thirdparty/icu4c/common/loclikelysubtags.cpp index a031bfa587..aa592e6ea8 100644 --- a/thirdparty/icu4c/common/loclikelysubtags.cpp +++ b/thirdparty/icu4c/common/loclikelysubtags.cpp @@ -320,7 +320,8 @@ XLikelySubtags::~XLikelySubtags() { LSR XLikelySubtags::makeMaximizedLsrFrom(const Locale &locale, UErrorCode &errorCode) const { const char *name = locale.getName(); if (uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=") - // Private use language tag x-subtag-subtag... + // Private use language tag x-subtag-subtag... which CLDR changes to + // und-x-subtag-subtag... return LSR(name, "", "", LSR::EXPLICIT_LSR); } return makeMaximizedLsr(locale.getLanguage(), locale.getScript(), locale.getCountry(), diff --git a/thirdparty/icu4c/common/norm2allmodes.h b/thirdparty/icu4c/common/norm2allmodes.h index e8bd52c6ae..584835da57 100644 --- a/thirdparty/icu4c/common/norm2allmodes.h +++ b/thirdparty/icu4c/common/norm2allmodes.h @@ -38,7 +38,7 @@ public: virtual UnicodeString & normalize(const UnicodeString &src, UnicodeString &dest, - UErrorCode &errorCode) const { + UErrorCode &errorCode) const U_OVERRIDE { if(U_FAILURE(errorCode)) { dest.setToBogus(); return dest; @@ -64,13 +64,13 @@ public: virtual UnicodeString & normalizeSecondAndAppend(UnicodeString &first, const UnicodeString &second, - UErrorCode &errorCode) const { + UErrorCode &errorCode) const U_OVERRIDE { return normalizeSecondAndAppend(first, second, true, errorCode); } virtual UnicodeString & append(UnicodeString &first, const UnicodeString &second, - UErrorCode &errorCode) const { + UErrorCode &errorCode) const U_OVERRIDE { return normalizeSecondAndAppend(first, second, false, errorCode); } UnicodeString & @@ -107,7 +107,7 @@ public: UnicodeString &safeMiddle, ReorderingBuffer &buffer, UErrorCode &errorCode) const = 0; virtual UBool - getDecomposition(UChar32 c, UnicodeString &decomposition) const { + getDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE { UChar buffer[4]; int32_t length; const UChar *d=impl.getDecomposition(c, buffer, length); @@ -122,7 +122,7 @@ public: return true; } virtual UBool - getRawDecomposition(UChar32 c, UnicodeString &decomposition) const { + getRawDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE { UChar buffer[30]; int32_t length; const UChar *d=impl.getRawDecomposition(c, buffer, length); @@ -137,18 +137,18 @@ public: return true; } virtual UChar32 - composePair(UChar32 a, UChar32 b) const { + composePair(UChar32 a, UChar32 b) const U_OVERRIDE { return impl.composePair(a, b); } virtual uint8_t - getCombiningClass(UChar32 c) const { + getCombiningClass(UChar32 c) const U_OVERRIDE { return impl.getCC(impl.getNorm16(c)); } // quick checks virtual UBool - isNormalized(const UnicodeString &s, UErrorCode &errorCode) const { + isNormalized(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE { if(U_FAILURE(errorCode)) { return false; } @@ -161,11 +161,11 @@ public: return sLimit==spanQuickCheckYes(sArray, sLimit, errorCode); } virtual UNormalizationCheckResult - quickCheck(const UnicodeString &s, UErrorCode &errorCode) const { + quickCheck(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE { return Normalizer2WithImpl::isNormalized(s, errorCode) ? UNORM_YES : UNORM_NO; } virtual int32_t - spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const { + spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE { if(U_FAILURE(errorCode)) { return 0; } @@ -194,27 +194,57 @@ public: private: virtual void normalize(const UChar *src, const UChar *limit, - ReorderingBuffer &buffer, UErrorCode &errorCode) const { + ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE { impl.decompose(src, limit, &buffer, errorCode); } using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function. virtual void normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize, UnicodeString &safeMiddle, - ReorderingBuffer &buffer, UErrorCode &errorCode) const { + ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE { impl.decomposeAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode); } + + void + normalizeUTF8(uint32_t options, StringPiece src, ByteSink &sink, + Edits *edits, UErrorCode &errorCode) const U_OVERRIDE { + if (U_FAILURE(errorCode)) { + return; + } + if (edits != nullptr && (options & U_EDITS_NO_RESET) == 0) { + edits->reset(); + } + const uint8_t *s = reinterpret_cast<const uint8_t *>(src.data()); + impl.decomposeUTF8(options, s, s + src.length(), &sink, edits, errorCode); + sink.Flush(); + } + virtual UBool + isNormalizedUTF8(StringPiece sp, UErrorCode &errorCode) const U_OVERRIDE { + if(U_FAILURE(errorCode)) { + return false; + } + const uint8_t *s = reinterpret_cast<const uint8_t *>(sp.data()); + const uint8_t *sLimit = s + sp.length(); + return sLimit == impl.decomposeUTF8(0, s, sLimit, nullptr, nullptr, errorCode); + } + virtual const UChar * - spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const { + spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE { return impl.decompose(src, limit, NULL, errorCode); } using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function. - virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const { + virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const U_OVERRIDE { return impl.isDecompYes(impl.getNorm16(c)) ? UNORM_YES : UNORM_NO; } - virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasDecompBoundaryBefore(c); } - virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasDecompBoundaryAfter(c); } - virtual UBool isInert(UChar32 c) const { return impl.isDecompInert(c); } + virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE { + return impl.hasDecompBoundaryBefore(c); + } + virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE { + return impl.hasDecompBoundaryAfter(c); + } + virtual UBool isInert(UChar32 c) const U_OVERRIDE { + return impl.isDecompInert(c); + } }; class ComposeNormalizer2 : public Normalizer2WithImpl { @@ -321,24 +351,30 @@ public: private: virtual void normalize(const UChar *src, const UChar *limit, - ReorderingBuffer &buffer, UErrorCode &errorCode) const { + ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE { impl.makeFCD(src, limit, &buffer, errorCode); } using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function. virtual void normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize, UnicodeString &safeMiddle, - ReorderingBuffer &buffer, UErrorCode &errorCode) const { + ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE { impl.makeFCDAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode); } virtual const UChar * - spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const { + spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE { return impl.makeFCD(src, limit, NULL, errorCode); } using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function. - virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasFCDBoundaryBefore(c); } - virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasFCDBoundaryAfter(c); } - virtual UBool isInert(UChar32 c) const { return impl.isFCDInert(c); } + virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE { + return impl.hasFCDBoundaryBefore(c); + } + virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE { + return impl.hasFCDBoundaryAfter(c); + } + virtual UBool isInert(UChar32 c) const U_OVERRIDE { + return impl.isFCDInert(c); + } }; struct Norm2AllModes : public UMemory { diff --git a/thirdparty/icu4c/common/normalizer2impl.cpp b/thirdparty/icu4c/common/normalizer2impl.cpp index cbf6b4d980..c0ad5c69f3 100644 --- a/thirdparty/icu4c/common/normalizer2impl.cpp +++ b/thirdparty/icu4c/common/normalizer2impl.cpp @@ -731,9 +731,131 @@ UBool Normalizer2Impl::decompose(UChar32 c, uint16_t norm16, return buffer.append((const UChar *)mapping+1, length, TRUE, leadCC, trailCC, errorCode); } +// Dual functionality: +// sink != nullptr: normalize +// sink == nullptr: isNormalized/spanQuickCheckYes +const uint8_t * +Normalizer2Impl::decomposeUTF8(uint32_t options, + const uint8_t *src, const uint8_t *limit, + ByteSink *sink, Edits *edits, UErrorCode &errorCode) const { + U_ASSERT(limit != nullptr); + UnicodeString s16; + uint8_t minNoLead = leadByteForCP(minDecompNoCP); + + const uint8_t *prevBoundary = src; + // only for quick check + uint8_t prevCC = 0; + + for (;;) { + // Fast path: Scan over a sequence of characters below the minimum "no" code point, + // or with (decompYes && ccc==0) properties. + const uint8_t *fastStart = src; + const uint8_t *prevSrc; + uint16_t norm16 = 0; + + for (;;) { + if (src == limit) { + if (prevBoundary != limit && sink != nullptr) { + ByteSinkUtil::appendUnchanged(prevBoundary, limit, + *sink, options, edits, errorCode); + } + return src; + } + if (*src < minNoLead) { + ++src; + } else { + prevSrc = src; + UCPTRIE_FAST_U8_NEXT(normTrie, UCPTRIE_16, src, limit, norm16); + if (!isMostDecompYesAndZeroCC(norm16)) { + break; + } + } + } + // isMostDecompYesAndZeroCC(norm16) is false, that is, norm16>=minYesNo, + // and the current character at [prevSrc..src[ is not a common case with cc=0 + // (MIN_NORMAL_MAYBE_YES or JAMO_VT). + // It could still be a maybeYes with cc=0. + if (prevSrc != fastStart) { + // The fast path looped over yes/0 characters before the current one. + if (sink != nullptr && + !ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc, + *sink, options, edits, errorCode)) { + break; + } + prevBoundary = prevSrc; + prevCC = 0; + } + + // Medium-fast path: Quick check. + if (isMaybeOrNonZeroCC(norm16)) { + // Does not decompose. + uint8_t cc = getCCFromYesOrMaybe(norm16); + if (prevCC <= cc || cc == 0) { + prevCC = cc; + if (cc <= 1) { + if (sink != nullptr && + !ByteSinkUtil::appendUnchanged(prevBoundary, src, + *sink, options, edits, errorCode)) { + break; + } + prevBoundary = src; + } + continue; + } + } + if (sink == nullptr) { + return prevBoundary; // quick check: "no" or cc out of order + } + + // Slow path + // Decompose up to and including the current character. + if (prevBoundary != prevSrc && norm16HasDecompBoundaryBefore(norm16)) { + if (!ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc, + *sink, options, edits, errorCode)) { + break; + } + prevBoundary = prevSrc; + } + ReorderingBuffer buffer(*this, s16, errorCode); + if (U_FAILURE(errorCode)) { + break; + } + decomposeShort(prevBoundary, src, STOP_AT_LIMIT, FALSE /* onlyContiguous */, + buffer, errorCode); + // Decompose until the next boundary. + if (buffer.getLastCC() > 1) { + src = decomposeShort(src, limit, STOP_AT_DECOMP_BOUNDARY, FALSE /* onlyContiguous */, + buffer, errorCode); + } + if (U_FAILURE(errorCode)) { + break; + } + if ((src - prevSrc) > INT32_MAX) { // guard before buffer.equals() + errorCode = U_INDEX_OUTOFBOUNDS_ERROR; + break; + } + // We already know there was a change if the original character decomposed; + // otherwise compare. + if (isMaybeOrNonZeroCC(norm16) && buffer.equals(prevBoundary, src)) { + if (!ByteSinkUtil::appendUnchanged(prevBoundary, src, + *sink, options, edits, errorCode)) { + break; + } + } else { + if (!ByteSinkUtil::appendChange(prevBoundary, src, buffer.getStart(), buffer.length(), + *sink, edits, errorCode)) { + break; + } + } + prevBoundary = src; + prevCC = 0; + } + return src; +} + const uint8_t * Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit, - UBool stopAtCompBoundary, UBool onlyContiguous, + StopAt stopAt, UBool onlyContiguous, ReorderingBuffer &buffer, UErrorCode &errorCode) const { if (U_FAILURE(errorCode)) { return nullptr; @@ -746,21 +868,28 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit, UChar32 c = U_SENTINEL; if (norm16 >= limitNoNo) { if (isMaybeOrNonZeroCC(norm16)) { - // No boundaries around this character. + // No comp boundaries around this character. + uint8_t cc = getCCFromYesOrMaybe(norm16); + if (cc == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) { + return prevSrc; + } c = codePointFromValidUTF8(prevSrc, src); - if (!buffer.append(c, getCCFromYesOrMaybe(norm16), errorCode)) { + if (!buffer.append(c, cc, errorCode)) { return nullptr; } + if (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1) { + return src; + } continue; } // Maps to an isCompYesAndZeroCC. - if (stopAtCompBoundary) { + if (stopAt != STOP_AT_LIMIT) { return prevSrc; } c = codePointFromValidUTF8(prevSrc, src); c = mapAlgorithmic(c, norm16); norm16 = getRawNorm16(c); - } else if (stopAtCompBoundary && norm16 < minNoNoCompNoMaybeCC) { + } else if (stopAt != STOP_AT_LIMIT && norm16 < minNoNoCompNoMaybeCC) { return prevSrc; } // norm16!=INERT guarantees that [prevSrc, src[ is valid UTF-8. @@ -768,7 +897,8 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit, // its norm16==INERT is normalization-inert, // so it gets copied unchanged in the fast path, // and we stop the slow path where invalid UTF-8 begins. - U_ASSERT(norm16 != INERT); + // c >= 0 is the result of an algorithmic mapping. + U_ASSERT(c >= 0 || norm16 != INERT); if (norm16 < minYesNo) { if (c < 0) { c = codePointFromValidUTF8(prevSrc, src); @@ -798,11 +928,15 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit, } else { leadCC = 0; } + if (leadCC == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) { + return prevSrc; + } if (!buffer.append((const char16_t *)mapping+1, length, TRUE, leadCC, trailCC, errorCode)) { return nullptr; } } - if (stopAtCompBoundary && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + if ((stopAt == STOP_AT_COMP_BOUNDARY && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) || + (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1)) { return src; } } @@ -1954,10 +2088,10 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous, break; } // We know there is not a boundary here. - decomposeShort(prevSrc, src, FALSE /* !stopAtCompBoundary */, onlyContiguous, + decomposeShort(prevSrc, src, STOP_AT_LIMIT, onlyContiguous, buffer, errorCode); // Decompose until the next boundary. - src = decomposeShort(src, limit, TRUE /* stopAtCompBoundary */, onlyContiguous, + src = decomposeShort(src, limit, STOP_AT_COMP_BOUNDARY, onlyContiguous, buffer, errorCode); if (U_FAILURE(errorCode)) { break; diff --git a/thirdparty/icu4c/common/normalizer2impl.h b/thirdparty/icu4c/common/normalizer2impl.h index 4218a30a34..bdb6767a92 100644 --- a/thirdparty/icu4c/common/normalizer2impl.h +++ b/thirdparty/icu4c/common/normalizer2impl.h @@ -491,6 +491,12 @@ public: UnicodeString &safeMiddle, ReorderingBuffer &buffer, UErrorCode &errorCode) const; + + /** sink==nullptr: isNormalized()/spanQuickCheckYes() */ + const uint8_t *decomposeUTF8(uint32_t options, + const uint8_t *src, const uint8_t *limit, + ByteSink *sink, Edits *edits, UErrorCode &errorCode) const; + UBool compose(const UChar *src, const UChar *limit, UBool onlyContiguous, UBool doCompose, @@ -649,6 +655,9 @@ private: UChar32 minNeedDataCP, ReorderingBuffer *buffer, UErrorCode &errorCode) const; + + enum StopAt { STOP_AT_LIMIT, STOP_AT_DECOMP_BOUNDARY, STOP_AT_COMP_BOUNDARY }; + const UChar *decomposeShort(const UChar *src, const UChar *limit, UBool stopAtCompBoundary, UBool onlyContiguous, ReorderingBuffer &buffer, UErrorCode &errorCode) const; @@ -656,7 +665,7 @@ private: ReorderingBuffer &buffer, UErrorCode &errorCode) const; const uint8_t *decomposeShort(const uint8_t *src, const uint8_t *limit, - UBool stopAtCompBoundary, UBool onlyContiguous, + StopAt stopAt, UBool onlyContiguous, ReorderingBuffer &buffer, UErrorCode &errorCode) const; static int32_t combine(const uint16_t *list, UChar32 trail); diff --git a/thirdparty/icu4c/common/pluralmap.h b/thirdparty/icu4c/common/pluralmap.h index d898ac4671..2a14a07af1 100644 --- a/thirdparty/icu4c/common/pluralmap.h +++ b/thirdparty/icu4c/common/pluralmap.h @@ -24,7 +24,7 @@ class U_COMMON_API PluralMapBase : public UMemory { public: /** * The names of all the plural categories. NONE is not an actual plural - * category, but rather represents the absense of a plural category. + * category, but rather represents the absence of a plural category. */ enum Category { NONE = -1, diff --git a/thirdparty/icu4c/common/putil.cpp b/thirdparty/icu4c/common/putil.cpp index 3ed6a05d22..ffcbbcce59 100644 --- a/thirdparty/icu4c/common/putil.cpp +++ b/thirdparty/icu4c/common/putil.cpp @@ -1139,7 +1139,7 @@ uprv_tzname(int n) #endif if (tzid != NULL && isValidOlsonID(tzid) #if U_PLATFORM == U_PF_SOLARIS - /* When TZ equals localtime on Solaris, check the /etc/localtime file. */ + /* Don't misinterpret TZ "localtime" on Solaris as a time zone name. */ && uprv_strcmp(tzid, TZ_ENV_CHECK) != 0 #endif ) { @@ -1361,7 +1361,7 @@ uprv_pathIsAbsolute(const char *path) /* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR (needed for some Darwin ICU build environments) */ -#if U_PLATFORM_IS_DARWIN_BASED && TARGET_OS_SIMULATOR +#if U_PLATFORM_IS_DARWIN_BASED && defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR # if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR) # define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT" # endif diff --git a/thirdparty/icu4c/common/putilimp.h b/thirdparty/icu4c/common/putilimp.h index a325c6c359..5b95a68418 100644 --- a/thirdparty/icu4c/common/putilimp.h +++ b/thirdparty/icu4c/common/putilimp.h @@ -527,7 +527,7 @@ U_CAPI void * U_EXPORT2 uprv_maximumPtr(void *base); * on the destination pointer and capacity cannot overflow. * * The pinned capacity must fulfill the following conditions (for positive capacities): - * - dest + capacity is a valid pointer according to the machine arcitecture (AS/400, 64-bit, etc.) + * - dest + capacity is a valid pointer according to the machine architecture (AS/400, 64-bit, etc.) * - (dest + capacity) >= dest * - The size (in bytes) of T[capacity] does not exceed 0x7fffffff * diff --git a/thirdparty/icu4c/common/rbbi.cpp b/thirdparty/icu4c/common/rbbi.cpp index 9b7e70c3cf..b821ca4463 100644 --- a/thirdparty/icu4c/common/rbbi.cpp +++ b/thirdparty/icu4c/common/rbbi.cpp @@ -812,7 +812,7 @@ int32_t RuleBasedBreakIterator::handleNext() { } #endif - // handleNext alway sets the break tag value. + // handleNext always sets the break tag value. // Set the default for it. fRuleStatusIndex = 0; diff --git a/thirdparty/icu4c/common/rbbi_cache.cpp b/thirdparty/icu4c/common/rbbi_cache.cpp index 63ff3001c7..44f19d8697 100644 --- a/thirdparty/icu4c/common/rbbi_cache.cpp +++ b/thirdparty/icu4c/common/rbbi_cache.cpp @@ -258,7 +258,7 @@ void RuleBasedBreakIterator::BreakCache::preceding(int32_t startPos, UErrorCode previous(status); } else { // seek() leaves the BreakCache positioned at the preceding boundary - // if the requested position is between two bounaries. + // if the requested position is between two boundaries. // current() pushes the BreakCache position out to the BreakIterator itself. U_ASSERT(startPos > fTextIdx); current(); diff --git a/thirdparty/icu4c/common/rbbiscan.cpp b/thirdparty/icu4c/common/rbbiscan.cpp index 9c406af671..45911b1cfe 100644 --- a/thirdparty/icu4c/common/rbbiscan.cpp +++ b/thirdparty/icu4c/common/rbbiscan.cpp @@ -284,7 +284,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action) case doEndAssign: { - // We have reached the end of an assignement statement. + // We have reached the end of an assignment statement. // Current scan char is the ';' that terminates the assignment. // Terminate expression, leaves expression parse tree rooted in TOS node. @@ -856,6 +856,10 @@ UChar32 RBBIRuleScanner::nextCharLL() { return (UChar32)-1; } ch = fRB->fRules.char32At(fNextIndex); + if (U_IS_SURROGATE(ch)) { + error(U_ILLEGAL_CHAR_FOUND); + return U_SENTINEL; + } fNextIndex = fRB->fRules.moveIndex32(fNextIndex, 1); if (ch == chCR || diff --git a/thirdparty/icu4c/common/rbbitblb.cpp b/thirdparty/icu4c/common/rbbitblb.cpp index 70e260fc08..dd76337bc6 100644 --- a/thirdparty/icu4c/common/rbbitblb.cpp +++ b/thirdparty/icu4c/common/rbbitblb.cpp @@ -151,7 +151,7 @@ void RBBITableBuilder::buildForwardTable() { // // calculate the functions nullable, firstpos, lastpos and followpos on // nodes in the parse tree. - // See the alogrithm description in Aho. + // See the algorithm description in Aho. // Understanding how this works by looking at the code alone will be // nearly impossible. // diff --git a/thirdparty/icu4c/common/resource.h b/thirdparty/icu4c/common/resource.h index 3795694412..48f5b9fa6e 100644 --- a/thirdparty/icu4c/common/resource.h +++ b/thirdparty/icu4c/common/resource.h @@ -274,8 +274,10 @@ public: * * @param key The key string of the enumeration-start resource. * Empty if the enumeration starts at the top level of the bundle. - * @param value Call getArray() or getTable() as appropriate. - * Then reuse for output values from Array and Table getters. + * @param value Call getArray() or getTable() as appropriate. Then reuse for + * output values from Array and Table getters. Note: ResourceTable and + * ResourceArray instances must outlive the ResourceValue instance for + * ResourceTracer to be happy. * @param noFallback true if the bundle has no parent; * that is, its top-level table has the nofallback attribute, * or it is the root bundle of a locale tree. diff --git a/thirdparty/icu4c/common/restrace.cpp b/thirdparty/icu4c/common/restrace.cpp index 5c6498850e..1f83372d68 100644 --- a/thirdparty/icu4c/common/restrace.cpp +++ b/thirdparty/icu4c/common/restrace.cpp @@ -54,6 +54,9 @@ void ResourceTracer::traceOpen() const { CharString& ResourceTracer::getFilePath(CharString& output, UErrorCode& status) const { if (fResB) { + // Note: if you get a segfault around here, check that ResourceTable and + // ResourceArray instances outlive ResourceValue instances referring to + // their contents: output.append(fResB->fData->fPath, status); output.append('/', status); output.append(fResB->fData->fName, status); diff --git a/thirdparty/icu4c/common/servnotf.h b/thirdparty/icu4c/common/servnotf.h index 305570c1e6..73ce38c772 100644 --- a/thirdparty/icu4c/common/servnotf.h +++ b/thirdparty/icu4c/common/servnotf.h @@ -82,7 +82,7 @@ public: /** * Add a listener to be notified when notifyChanged is called. * The listener must not be null. AcceptsListener must return - * true for the listener. Attempts to concurrently + * true for the listener. Attempts to concurrently * register the identical listener more than once will be * silently ignored. */ @@ -90,7 +90,7 @@ public: /** * Stop notifying this listener. The listener must - * not be null. Attemps to remove a listener that is + * not be null. Attempts to remove a listener that is * not registered will be silently ignored. */ virtual void removeListener(const EventListener* l, UErrorCode& status); diff --git a/thirdparty/icu4c/common/ubrk.cpp b/thirdparty/icu4c/common/ubrk.cpp index f8bdf5a6b6..bb5bdd1b50 100644 --- a/thirdparty/icu4c/common/ubrk.cpp +++ b/thirdparty/icu4c/common/ubrk.cpp @@ -174,6 +174,18 @@ ubrk_safeClone( return (UBreakIterator *)newBI; } +U_CAPI UBreakIterator * U_EXPORT2 +ubrk_clone(const UBreakIterator *bi, UErrorCode *status) { + if (U_FAILURE(*status)) { + return nullptr; + } + BreakIterator *newBI = ((BreakIterator *)bi)->clone(); + if (newBI == nullptr) { + *status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return (UBreakIterator *)newBI; +} U_CAPI void U_EXPORT2 diff --git a/thirdparty/icu4c/common/ucase.cpp b/thirdparty/icu4c/common/ucase.cpp index 2b142f5bc2..4f4c274d60 100644 --- a/thirdparty/icu4c/common/ucase.cpp +++ b/thirdparty/icu4c/common/ucase.cpp @@ -681,7 +681,7 @@ ucase_isCaseSensitive(UChar32 c) { * - In [CoreProps], C has one of the properties Uppercase, or Lowercase * - Given D = NFD(C), then it is not the case that: * D = UCD_lower(D) = UCD_upper(D) = UCD_title(D) - * (This third criterium does not add any characters to the list + * (This third criterion does not add any characters to the list * for Unicode 3.2. Ignored.) * * D2. A character C is defined to be case-ignorable diff --git a/thirdparty/icu4c/common/uchar.cpp b/thirdparty/icu4c/common/uchar.cpp index eb14e4c75d..61e9c3d900 100644 --- a/thirdparty/icu4c/common/uchar.cpp +++ b/thirdparty/icu4c/common/uchar.cpp @@ -194,7 +194,7 @@ u_isISOControl(UChar32 c) { /* Some control characters that are used as space. */ #define IS_THAT_CONTROL_SPACE(c) \ - (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==NL)) + (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==0x85)) /* Java has decided that U+0085 New Line is not whitespace any more. */ #define IS_THAT_ASCII_CONTROL_SPACE(c) \ @@ -677,14 +677,14 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) { sa->add(sa->set, CR+1); /* range TAB..CR */ sa->add(sa->set, 0x1c); sa->add(sa->set, 0x1f+1); - USET_ADD_CP_AND_NEXT(sa, NL); + USET_ADD_CP_AND_NEXT(sa, 0x85); // NEXT LINE (NEL) /* add for u_isIDIgnorable() what was not added above */ - sa->add(sa->set, DEL); /* range DEL..NBSP-1, NBSP added below */ + sa->add(sa->set, 0x7f); /* range DEL..NBSP-1, NBSP added below */ sa->add(sa->set, HAIRSP); sa->add(sa->set, RLM+1); - sa->add(sa->set, INHSWAP); - sa->add(sa->set, NOMDIG+1); + sa->add(sa->set, 0x206a); // INHIBIT SYMMETRIC SWAPPING + sa->add(sa->set, 0x206f+1); // NOMINAL DIGIT SHAPES USET_ADD_CP_AND_NEXT(sa, ZWNBSP); /* add no-break spaces for u_isWhitespace() what was not added above */ @@ -693,23 +693,25 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) { USET_ADD_CP_AND_NEXT(sa, NNBSP); /* add for u_digit() */ - sa->add(sa->set, U_a); - sa->add(sa->set, U_z+1); - sa->add(sa->set, U_A); - sa->add(sa->set, U_Z+1); - sa->add(sa->set, U_FW_a); - sa->add(sa->set, U_FW_z+1); - sa->add(sa->set, U_FW_A); - sa->add(sa->set, U_FW_Z+1); + sa->add(sa->set, u'a'); + sa->add(sa->set, u'z'+1); + sa->add(sa->set, u'A'); + sa->add(sa->set, u'Z'+1); + // fullwidth + sa->add(sa->set, u'a'); + sa->add(sa->set, u'z'+1); + sa->add(sa->set, u'A'); + sa->add(sa->set, u'Z'+1); /* add for u_isxdigit() */ - sa->add(sa->set, U_f+1); - sa->add(sa->set, U_F+1); - sa->add(sa->set, U_FW_f+1); - sa->add(sa->set, U_FW_F+1); + sa->add(sa->set, u'f'+1); + sa->add(sa->set, u'F'+1); + // fullwidth + sa->add(sa->set, u'f'+1); + sa->add(sa->set, u'F'+1); /* add for UCHAR_DEFAULT_IGNORABLE_CODE_POINT what was not added above */ - sa->add(sa->set, WJ); /* range WJ..NOMDIG */ + sa->add(sa->set, 0x2060); /* range 2060..206f */ sa->add(sa->set, 0xfff0); sa->add(sa->set, 0xfffb+1); sa->add(sa->set, 0xe0000); diff --git a/thirdparty/icu4c/common/ucnv2022.cpp b/thirdparty/icu4c/common/ucnv2022.cpp index 169ad4c526..1726440b94 100644 --- a/thirdparty/icu4c/common/ucnv2022.cpp +++ b/thirdparty/icu4c/common/ucnv2022.cpp @@ -820,7 +820,7 @@ getKey_2022(char c,int32_t* key,int32_t* offset){ return INVALID_2022; } -/*runs through a state machine to determine the escape sequence - codepage correspondance +/*runs through a state machine to determine the escape sequence - codepage correspondence */ static void changeState_2022(UConverter* _this, @@ -1424,7 +1424,7 @@ toUnicodeCallback(UConverter *cnv, * KSC5601 : alias to ibm-949 mapping table * GB2312 : alias to ibm-1386 mapping table * ISO-8859-1 : Algorithmic implemented as LATIN1 case -* ISO-8859-7 : alisas to ibm-9409 mapping table +* ISO-8859-7 : alias to ibm-9409 mapping table */ /* preference order of JP charsets */ @@ -2324,7 +2324,7 @@ endloop: /*************************************************************** * Rules for ISO-2022-KR encoding * i) The KSC5601 designator sequence should appear only once in a file, -* at the begining of a line before any KSC5601 characters. This usually +* at the beginning of a line before any KSC5601 characters. This usually * means that it appears by itself on the first line of the file * ii) There are only 2 shifting sequences SO to shift into double byte mode * and SI to shift into single byte mode diff --git a/thirdparty/icu4c/common/ucnv_bld.cpp b/thirdparty/icu4c/common/ucnv_bld.cpp index 0e198892f1..d08eec7369 100644 --- a/thirdparty/icu4c/common/ucnv_bld.cpp +++ b/thirdparty/icu4c/common/ucnv_bld.cpp @@ -427,7 +427,7 @@ getAlgorithmicTypeFromName(const char *realName) #define UCNV_CACHE_LOAD_FACTOR 2 /* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */ -/* Will always be called with the cnvCacheMutex alrady being held */ +/* Will always be called with the cnvCacheMutex already being held */ /* by the calling function. */ /* Stores the shared data in the SHARED_DATA_HASHTABLE * @param data The shared data diff --git a/thirdparty/icu4c/common/ucnv_err.cpp b/thirdparty/icu4c/common/ucnv_err.cpp index 6b738face5..e1f2b934aa 100644 --- a/thirdparty/icu4c/common/ucnv_err.cpp +++ b/thirdparty/icu4c/common/ucnv_err.cpp @@ -321,7 +321,7 @@ UCNV_FROM_U_CALLBACK_ESCAPE ( case UCNV_PRV_ESCAPE_CSS2: valueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT; /* adding \ */ valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 0); - /* Always add space character, becase the next character might be whitespace, + /* Always add space character, because the next character might be whitespace, which would erroneously be considered the termination of the escape sequence. */ valueString[valueStringLength++] = (UChar) UNICODE_SPACE_CODEPOINT; break; diff --git a/thirdparty/icu4c/common/ucnv_lmb.cpp b/thirdparty/icu4c/common/ucnv_lmb.cpp index 168392837b..41317d1cc0 100644 --- a/thirdparty/icu4c/common/ucnv_lmb.cpp +++ b/thirdparty/icu4c/common/ucnv_lmb.cpp @@ -81,7 +81,7 @@ [G] D1 [D2] That is, a sometimes-optional 'group' byte, followed by 1 and sometimes 2 - data bytes. The maximum size of a LMBCS chjaracter is 3 bytes: + data bytes. The maximum size of a LMBCS character is 3 bytes: */ #define ULMBCS_CHARSIZE_MAX 3 /* @@ -164,7 +164,7 @@ beginning of internal 'system' range names: */ /* Then we needed a place to put all the other ansi control characters that must be moved to different values because LMBCS reserves those values for other purposes. To represent the control characters, we start -with a first byte of 0xF & add the control chaarcter value as the +with a first byte of 0xF & add the control character value as the second byte */ #define ULMBCS_GRP_CTRL 0x0F diff --git a/thirdparty/icu4c/common/ucnv_u7.cpp b/thirdparty/icu4c/common/ucnv_u7.cpp index 87ba8cf37e..de9f3f42ec 100644 --- a/thirdparty/icu4c/common/ucnv_u7.cpp +++ b/thirdparty/icu4c/common/ucnv_u7.cpp @@ -814,7 +814,7 @@ const UConverterSharedData _UTF7Data= * the use of "~" in some servers as a home directory indicator. * * 5) UTF-7 permits multiple alternate forms to represent the same - * string; in particular, printable US-ASCII chararacters can be + * string; in particular, printable US-ASCII characters can be * represented in encoded form. * * In modified UTF-7, printable US-ASCII characters except for "&" diff --git a/thirdparty/icu4c/common/ucnvisci.cpp b/thirdparty/icu4c/common/ucnvisci.cpp index 44a7c05a3c..ffb8c7ac3e 100644 --- a/thirdparty/icu4c/common/ucnvisci.cpp +++ b/thirdparty/icu4c/common/ucnvisci.cpp @@ -992,7 +992,7 @@ UConverter_fromUnicode_ISCII_OFFSETS_LOGIC( if (converterData->currentDeltaFromUnicode == PNJ_DELTA) { if (sourceChar == PNJ_TIPPI) { - /* Make sure Tippi is converterd to Bindi. */ + /* Make sure Tippi is converted to Bindi. */ sourceChar = PNJ_BINDI; } else if (sourceChar == PNJ_ADHAK) { /* This is for consonant cluster handling. */ @@ -1147,7 +1147,7 @@ static const uint16_t lookupTable[][2]={ /* is the code point valid in current script? */ \ if(sourceChar> ASCII_END && \ (validityTable[(targetUniChar & 0x7F)] & data->currentMaskToUnicode)==0){ \ - /* Vocallic RR is assigne in ISCII Telugu and Unicode */ \ + /* Vocallic RR is assigned in ISCII Telugu and Unicode */ \ if(data->currentDeltaToUnicode!=(TELUGU_DELTA) || \ targetUniChar!=VOCALLIC_RR){ \ targetUniChar=missingCharMarker; \ @@ -1272,7 +1272,7 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo goto CALLBACK; } else if (*contextCharToUnicode==ISCII_INV) { if (sourceChar==ISCII_HALANT) { - targetUniChar = 0x0020; /* replace with space accoding to Indic FAQ */ + targetUniChar = 0x0020; /* replace with space according to Indic FAQ */ } else { targetUniChar = ZWJ; } diff --git a/thirdparty/icu4c/common/ucurr.cpp b/thirdparty/icu4c/common/ucurr.cpp index 0e14cddcff..20bbd51488 100644 --- a/thirdparty/icu4c/common/ucurr.cpp +++ b/thirdparty/icu4c/common/ucurr.cpp @@ -844,7 +844,7 @@ typedef struct { #endif -// Comparason function used in quick sort. +// Comparison function used in quick sort. static int U_CALLCONV currencyNameComparator(const void* a, const void* b) { const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a; const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b; @@ -1530,7 +1530,7 @@ uprv_parseCurrency(const char* locale, int32_t max = 0; int32_t matchIndex = -1; - // case in-sensitive comparision against currency names + // case in-sensitive comparison against currency names searchCurrencyName(currencyNames, total_currency_name_count, upperText, textLen, partialMatchLen, &max, &matchIndex); diff --git a/thirdparty/icu4c/common/uhash.cpp b/thirdparty/icu4c/common/uhash.cpp index 86311ceb0b..67c7c36354 100644 --- a/thirdparty/icu4c/common/uhash.cpp +++ b/thirdparty/icu4c/common/uhash.cpp @@ -133,8 +133,10 @@ static const float RESIZE_POLICY_RATIO_TABLE[6] = { * or a pointer. If a hint bit is zero, then the associated * token is assumed to be an integer. */ +#define HINT_BOTH_INTEGERS (0) #define HINT_KEY_POINTER (1) #define HINT_VALUE_POINTER (2) +#define HINT_ALLOW_ZERO (4) /******************************************************************** * PRIVATE Implementation @@ -479,8 +481,9 @@ _uhash_put(UHashtable *hash, goto err; } U_ASSERT(hash != NULL); - /* Cannot always check pointer here or iSeries sees NULL every time. */ - if ((hint & HINT_VALUE_POINTER) && value.pointer == NULL) { + if ((hint & HINT_VALUE_POINTER) ? + value.pointer == NULL : + value.integer == 0 && (hint & HINT_ALLOW_ZERO) == 0) { /* Disallow storage of NULL values, since NULL is returned by * get() to indicate an absent key. Storing NULL == removing. */ @@ -687,6 +690,28 @@ uhash_igeti(const UHashtable *hash, return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer; } +U_CAPI int32_t U_EXPORT2 +uhash_getiAndFound(const UHashtable *hash, + const void *key, + UBool *found) { + UHashTok keyholder; + keyholder.pointer = (void *)key; + const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); + *found = !IS_EMPTY_OR_DELETED(e->hashcode); + return e->value.integer; +} + +U_CAPI int32_t U_EXPORT2 +uhash_igetiAndFound(const UHashtable *hash, + int32_t key, + UBool *found) { + UHashTok keyholder; + keyholder.integer = key; + const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); + *found = !IS_EMPTY_OR_DELETED(e->hashcode); + return e->value.integer; +} + U_CAPI void* U_EXPORT2 uhash_put(UHashtable *hash, void* key, @@ -736,7 +761,34 @@ uhash_iputi(UHashtable *hash, keyholder.integer = key; valueholder.integer = value; return _uhash_put(hash, keyholder, valueholder, - 0, /* neither is a ptr */ + HINT_BOTH_INTEGERS, + status).integer; +} + +U_CAPI int32_t U_EXPORT2 +uhash_putiAllowZero(UHashtable *hash, + void *key, + int32_t value, + UErrorCode *status) { + UHashTok keyholder, valueholder; + keyholder.pointer = key; + valueholder.integer = value; + return _uhash_put(hash, keyholder, valueholder, + HINT_KEY_POINTER | HINT_ALLOW_ZERO, + status).integer; +} + + +U_CAPI int32_t U_EXPORT2 +uhash_iputiAllowZero(UHashtable *hash, + int32_t key, + int32_t value, + UErrorCode *status) { + UHashTok keyholder, valueholder; + keyholder.integer = key; + valueholder.integer = value; + return _uhash_put(hash, keyholder, valueholder, + HINT_BOTH_INTEGERS | HINT_ALLOW_ZERO, status).integer; } @@ -785,6 +837,29 @@ uhash_removeAll(UHashtable *hash) { U_ASSERT(hash->count == 0); } +U_CAPI UBool U_EXPORT2 +uhash_containsKey(const UHashtable *hash, const void *key) { + UHashTok keyholder; + keyholder.pointer = (void *)key; + const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); + return !IS_EMPTY_OR_DELETED(e->hashcode); +} + +/** + * Returns true if the UHashtable contains an item with this integer key. + * + * @param hash The target UHashtable. + * @param key An integer key stored in a hashtable + * @return true if the key is found. + */ +U_CAPI UBool U_EXPORT2 +uhash_icontainsKey(const UHashtable *hash, int32_t key) { + UHashTok keyholder; + keyholder.integer = key; + const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); + return !IS_EMPTY_OR_DELETED(e->hashcode); +} + U_CAPI const UHashElement* U_EXPORT2 uhash_find(const UHashtable *hash, const void* key) { UHashTok keyholder; diff --git a/thirdparty/icu4c/common/uhash.h b/thirdparty/icu4c/common/uhash.h index b59d2711bb..af75999860 100644 --- a/thirdparty/icu4c/common/uhash.h +++ b/thirdparty/icu4c/common/uhash.h @@ -23,7 +23,7 @@ /** * UHashtable stores key-value pairs and does moderately fast lookup * based on keys. It provides a good tradeoff between access time and - * storage space. As elements are added to it, it grows to accomodate + * storage space. As elements are added to it, it grows to accommodate * them. By default, the table never shrinks, even if all elements * are removed from it. * @@ -54,6 +54,13 @@ * uhash_remove() on that key. This keeps uhash_get(), uhash_count(), * and uhash_nextElement() consistent with one another. * + * Keys and values can be integers. + * Functions that work with an integer key have an "i" prefix. + * Functions that work with an integer value have an "i" suffix. + * As with putting a NULL value pointer, putting a zero value integer removes the item. + * Except, there are pairs of functions that allow setting zero values + * and fetching (value, found) pairs. + * * To see everything in a hashtable, use uhash_nextElement() to * iterate through its contents. Each call to this function returns a * UHashElement pointer. A hash element contains a key, value, and @@ -406,6 +413,44 @@ uhash_iputi(UHashtable *hash, UErrorCode *status); /** + * Put a (key=pointer, value=integer) item in a UHashtable. If the + * keyDeleter is non-NULL, then the hashtable owns 'key' after this + * call. valueDeleter must be NULL. + * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero. + * + * @param hash The target UHashtable. + * @param key The key to store. + * @param value The integer value to store. + * @param status A pointer to an UErrorCode to receive any errors. + * @return The previous value, or 0 if none. + * @see uhash_getiAndFound + */ +U_CAPI int32_t U_EXPORT2 +uhash_putiAllowZero(UHashtable *hash, + void *key, + int32_t value, + UErrorCode *status); + +/** + * Put a (key=integer, value=integer) item in a UHashtable. If the + * keyDeleter is non-NULL, then the hashtable owns 'key' after this + * call. valueDeleter must be NULL. + * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero. + * + * @param hash The target UHashtable. + * @param key The key to store. + * @param value The integer value to store. + * @param status A pointer to an UErrorCode to receive any errors. + * @return The previous value, or 0 if none. + * @see uhash_igetiAndFound + */ +U_CAPI int32_t U_EXPORT2 +uhash_iputiAllowZero(UHashtable *hash, + int32_t key, + int32_t value, + UErrorCode *status); + +/** * Retrieve a pointer value from a UHashtable using a pointer key, * as previously stored by uhash_put(). * @param hash The target UHashtable. @@ -449,6 +494,34 @@ uhash_igeti(const UHashtable *hash, int32_t key); /** + * Retrieves an integer value from a UHashtable using a pointer key, + * as previously stored by uhash_putiAllowZero() or uhash_puti(). + * + * @param hash The target UHashtable. + * @param key A pointer key stored in a hashtable + * @param found A pointer to a boolean which will be set for whether the key was found. + * @return The requested item, or 0 if not found. + */ +U_CAPI int32_t U_EXPORT2 +uhash_getiAndFound(const UHashtable *hash, + const void *key, + UBool *found); + +/** + * Retrieves an integer value from a UHashtable using an integer key, + * as previously stored by uhash_iputiAllowZero() or uhash_iputi(). + * + * @param hash The target UHashtable. + * @param key An integer key stored in a hashtable + * @param found A pointer to a boolean which will be set for whether the key was found. + * @return The requested item, or 0 if not found. + */ +U_CAPI int32_t U_EXPORT2 +uhash_igetiAndFound(const UHashtable *hash, + int32_t key, + UBool *found); + +/** * Remove an item from a UHashtable stored by uhash_put(). * @param hash The target UHashtable. * @param key A key stored in a hashtable @@ -496,6 +569,26 @@ U_CAPI void U_EXPORT2 uhash_removeAll(UHashtable *hash); /** + * Returns true if the UHashtable contains an item with this pointer key. + * + * @param hash The target UHashtable. + * @param key A pointer key stored in a hashtable + * @return true if the key is found. + */ +U_CAPI UBool U_EXPORT2 +uhash_containsKey(const UHashtable *hash, const void *key); + +/** + * Returns true if the UHashtable contains an item with this integer key. + * + * @param hash The target UHashtable. + * @param key An integer key stored in a hashtable + * @return true if the key is found. + */ +U_CAPI UBool U_EXPORT2 +uhash_icontainsKey(const UHashtable *hash, int32_t key); + +/** * Locate an element of a UHashtable. The caller must not modify the * returned object. The primary use of this function is to obtain the * stored key when it may not be identical to the search key. For diff --git a/thirdparty/icu4c/common/uloc.cpp b/thirdparty/icu4c/common/uloc.cpp index ebfbb50650..d96e79b8fd 100644 --- a/thirdparty/icu4c/common/uloc.cpp +++ b/thirdparty/icu4c/common/uloc.cpp @@ -143,7 +143,7 @@ static const char * const LANGUAGES[] = { "mad", "maf", "mag", "mai", "mak", "man", "mas", "mde", "mdf", "mdh", "mdr", "men", "mer", "mfe", "mg", "mga", "mgh", "mgo", "mh", "mi", "mic", "min", "mis", "mk", - "ml", "mn", "mnc", "mni", "mo", + "ml", "mn", "mnc", "mni", "moh", "mos", "mr", "mrj", "ms", "mt", "mua", "mul", "mus", "mwl", "mwr", "mwv", "my", "mye", "myv", "mzn", @@ -166,9 +166,9 @@ static const char * const LANGUAGES[] = { "sl", "sli", "sly", "sm", "sma", "smj", "smn", "sms", "sn", "snk", "so", "sog", "sq", "sr", "srn", "srr", "ss", "ssy", "st", "stq", "su", "suk", "sus", "sux", - "sv", "sw", "swb", "swc", "syc", "syr", "szl", + "sv", "sw", "swb", "syc", "syr", "szl", "ta", "tcy", "te", "tem", "teo", "ter", "tet", "tg", - "th", "ti", "tig", "tiv", "tk", "tkl", "tkr", "tl", + "th", "ti", "tig", "tiv", "tk", "tkl", "tkr", "tlh", "tli", "tly", "tmh", "tn", "to", "tog", "tpi", "tr", "tru", "trv", "ts", "tsd", "tsi", "tt", "ttt", "tum", "tvl", "tw", "twq", "ty", "tyv", "tzm", @@ -181,7 +181,7 @@ static const char * const LANGUAGES[] = { "za", "zap", "zbl", "zea", "zen", "zgh", "zh", "zu", "zun", "zxx", "zza", NULL, - "in", "iw", "ji", "jw", "sh", /* obsolete language codes */ + "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", /* obsolete language codes */ NULL }; @@ -260,7 +260,7 @@ static const char * const LANGUAGES_3[] = { "mad", "maf", "mag", "mai", "mak", "man", "mas", "mde", "mdf", "mdh", "mdr", "men", "mer", "mfe", "mlg", "mga", "mgh", "mgo", "mah", "mri", "mic", "min", "mis", "mkd", - "mal", "mon", "mnc", "mni", "mol", + "mal", "mon", "mnc", "mni", "moh", "mos", "mar", "mrj", "msa", "mlt", "mua", "mul", "mus", "mwl", "mwr", "mwv", "mya", "mye", "myv", "mzn", @@ -283,9 +283,9 @@ static const char * const LANGUAGES_3[] = { "slv", "sli", "sly", "smo", "sma", "smj", "smn", "sms", "sna", "snk", "som", "sog", "sqi", "srp", "srn", "srr", "ssw", "ssy", "sot", "stq", "sun", "suk", "sus", "sux", - "swe", "swa", "swb", "swc", "syc", "syr", "szl", + "swe", "swa", "swb", "syc", "syr", "szl", "tam", "tcy", "tel", "tem", "teo", "ter", "tet", "tgk", - "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", "tgl", + "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", "tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tpi", "tur", "tru", "trv", "tso", "tsd", "tsi", "tat", "ttt", "tum", "tvl", "twi", "twq", "tah", "tyv", "tzm", @@ -298,8 +298,8 @@ static const char * const LANGUAGES_3[] = { "zha", "zap", "zbl", "zea", "zen", "zgh", "zho", "zul", "zun", "zxx", "zza", NULL, -/* "in", "iw", "ji", "jw", "sh", */ - "ind", "heb", "yid", "jaw", "srp", +/* "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", */ + "ind", "heb", "yid", "jaw", "mol", "srp", "swc", "tgl", NULL }; @@ -334,13 +334,13 @@ static const char * const COUNTRIES[] = { "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", - "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", - "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", + "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK", + "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", - "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", + "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", @@ -357,7 +357,7 @@ static const char * const COUNTRIES[] = { "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", - "WS", "YE", "YT", "ZA", "ZM", "ZW", + "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW", NULL, "AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR", /* obsolete country codes */ NULL @@ -397,10 +397,10 @@ static const char * const COUNTRIES_3[] = { "BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG", /* "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", */ "CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CRI", -/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", */ - "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DJI", "DNK", -/* "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", */ - "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI", +/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK", */ + "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DGA", "DJI", "DNK", +/* "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER", */ + "DMA", "DOM", "DZA", "XEA", "ECU", "EST", "EGY", "ESH", "ERI", /* "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", */ "ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA", /* "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", */ @@ -409,8 +409,8 @@ static const char * const COUNTRIES_3[] = { "GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM", /* "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", */ "GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN", -/* "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */ - "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL", +/* "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */ + "XIC", "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL", /* "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", */ "ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR", /* "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", */ @@ -443,8 +443,8 @@ static const char * const COUNTRIES_3[] = { "TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB", /* "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", */ "VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF", -/* "WS", "YE", "YT", "ZA", "ZM", "ZW", */ - "WSM", "YEM", "MYT", "ZAF", "ZMB", "ZWE", +/* "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW", */ + "WSM", "XXK", "YEM", "MYT", "ZAF", "ZMB", "ZWE", NULL, /* "AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR" */ "ANT", "BUR", "SCG", "FXX", "ROM", "SUN", "TMP", "YMD", "YUG", "ZAR", diff --git a/thirdparty/icu4c/common/uloc_keytype.cpp b/thirdparty/icu4c/common/uloc_keytype.cpp index 019da058cf..c289ebe76f 100644 --- a/thirdparty/icu4c/common/uloc_keytype.cpp +++ b/thirdparty/icu4c/common/uloc_keytype.cpp @@ -271,7 +271,7 @@ initFromResourceBundle(UErrorCode& sts) { if (U_FAILURE(sts)) { break; } - // check if this is an alias of canoncal legacy type + // check if this is an alias of canonical legacy type if (uprv_compareInvWithUChar(NULL, legacyTypeId, -1, to, toLen) == 0) { const char* from = ures_getKey(typeAliasDataEntry.getAlias()); if (isTZ) { diff --git a/thirdparty/icu4c/common/uloc_tag.cpp b/thirdparty/icu4c/common/uloc_tag.cpp index 7f7fd9119e..1235081bf3 100644 --- a/thirdparty/icu4c/common/uloc_tag.cpp +++ b/thirdparty/icu4c/common/uloc_tag.cpp @@ -129,7 +129,6 @@ static const char* const LEGACY[] = { // Legacy tags with no preferred value in the IANA // registry. Kept for now for the backward compatibility // because ICU has mapped them this way. - "cel-gaulish", "xtg-x-cel-gaulish", "i-default", "en-x-i-default", "i-enochian", "und-x-i-enochian", "i-mingo", "see-x-i-mingo", @@ -647,6 +646,22 @@ _isTKey(const char* s, int32_t len) return FALSE; } +U_CAPI const char * U_EXPORT2 +ultag_getTKeyStart(const char *localeID) { + const char *result = localeID; + const char *sep; + while((sep = uprv_strchr(result, SEP)) != nullptr) { + if (_isTKey(result, static_cast<int32_t>(sep - result))) { + return result; + } + result = ++sep; + } + if (_isTKey(result, -1)) { + return result; + } + return nullptr; +} + static UBool _isTValue(const char* s, int32_t len) { @@ -671,9 +686,13 @@ _isTransformedExtensionSubtag(int32_t& state, const char* s, int32_t len) const int32_t kGotTKey = -1; // Got tkey, wait for tvalue. ERROR if stop here. const int32_t kGotTValue = 6; // Got tvalue, wait for tkey, tvalue or end + + if (len < 0) { + len = (int32_t)uprv_strlen(s); + } switch (state) { case kStart: - if (ultag_isLanguageSubtag(s, len)) { + if (ultag_isLanguageSubtag(s, len) && len != 4) { state = kGotLanguage; return TRUE; } @@ -1775,11 +1794,6 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status) return; } - /* Determine if variants already exists */ - if (ultag_getVariantsSize(langtag)) { - posixVariant = TRUE; - } - n = ultag_getExtensionsSize(langtag); /* resolve locale keywords and reordering keys */ @@ -1787,6 +1801,11 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status) key = ultag_getExtensionKey(langtag, i); type = ultag_getExtensionValue(langtag, i); if (*key == LDMLEXT) { + /* Determine if variants already exists */ + if (ultag_getVariantsSize(langtag)) { + posixVariant = TRUE; + } + _appendLDMLExtensionAsKeywords(type, &kwdFirst, extPool, kwdBuf, &posixVariant, status); if (U_FAILURE(*status)) { break; @@ -2028,7 +2047,10 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } - uprv_memcpy(tagBuf, tag, tagLen); + + if (tagLen > 0) { + uprv_memcpy(tagBuf, tag, tagLen); + } *(tagBuf + tagLen) = 0; /* create a ULanguageTag */ @@ -2692,8 +2714,7 @@ ulocimp_toLanguageTag(const char* localeID, if (U_SUCCESS(tmpStatus)) { if (ultag_isPrivateuseValueSubtags(buf.data(), buf.length())) { /* return private use only tag */ - static const char PREFIX[] = { PRIVATEUSE, SEP }; - sink.Append(PREFIX, sizeof(PREFIX)); + sink.Append("und-x-", 6); sink.Append(buf.data(), buf.length()); done = TRUE; } else if (strict) { diff --git a/thirdparty/icu4c/common/ulocimp.h b/thirdparty/icu4c/common/ulocimp.h index 5691fe9a77..1f796aa213 100644 --- a/thirdparty/icu4c/common/ulocimp.h +++ b/thirdparty/icu4c/common/ulocimp.h @@ -286,6 +286,9 @@ ultag_isUnicodeLocaleType(const char* s, int32_t len); U_CFUNC UBool ultag_isVariantSubtags(const char* s, int32_t len); +U_CAPI const char * U_EXPORT2 +ultag_getTKeyStart(const char *localeID); + U_CFUNC const char* ulocimp_toBcpKey(const char* key); diff --git a/thirdparty/icu4c/common/unicode/bytestream.h b/thirdparty/icu4c/common/unicode/bytestream.h index 044f7a77e7..9735ee0bf8 100644 --- a/thirdparty/icu4c/common/unicode/bytestream.h +++ b/thirdparty/icu4c/common/unicode/bytestream.h @@ -71,7 +71,6 @@ public: */ virtual void Append(const char* bytes, int32_t n) = 0; -#ifndef U_HIDE_DRAFT_API /** * Appends n bytes to this. Same as Append(). * Call AppendU8() with u8"string literals" which are const char * in C++11 @@ -81,7 +80,7 @@ public: * * @param bytes the pointer to the bytes * @param n the number of bytes; must be non-negative - * @draft ICU 67 + * @stable ICU 67 */ inline void AppendU8(const char* bytes, int32_t n) { Append(bytes, n); @@ -97,13 +96,12 @@ public: * * @param bytes the pointer to the bytes * @param n the number of bytes; must be non-negative - * @draft ICU 67 + * @stable ICU 67 */ inline void AppendU8(const char8_t* bytes, int32_t n) { Append(reinterpret_cast<const char*>(bytes), n); } #endif -#endif // U_HIDE_DRAFT_API /** * Returns a writable buffer for appending and writes the buffer's capacity to diff --git a/thirdparty/icu4c/common/unicode/bytestrie.h b/thirdparty/icu4c/common/unicode/bytestrie.h index 85f802df42..271a81d1b4 100644 --- a/thirdparty/icu4c/common/unicode/bytestrie.h +++ b/thirdparty/icu4c/common/unicode/bytestrie.h @@ -30,6 +30,8 @@ #include "unicode/uobject.h" #include "unicode/ustringtrie.h" +class BytesTrieTest; + U_NAMESPACE_BEGIN class ByteSink; @@ -378,6 +380,7 @@ public: private: friend class BytesTrieBuilder; + friend class ::BytesTrieTest; /** * Constructs a BytesTrie reader instance. diff --git a/thirdparty/icu4c/common/unicode/bytestriebuilder.h b/thirdparty/icu4c/common/unicode/bytestriebuilder.h index cae16e48b4..3cff89e443 100644 --- a/thirdparty/icu4c/common/unicode/bytestriebuilder.h +++ b/thirdparty/icu4c/common/unicode/bytestriebuilder.h @@ -30,6 +30,8 @@ #include "unicode/stringpiece.h" #include "unicode/stringtriebuilder.h" +class BytesTrieTest; + U_NAMESPACE_BEGIN class BytesTrieElement; @@ -125,6 +127,8 @@ public: BytesTrieBuilder &clear(); private: + friend class ::BytesTrieTest; + BytesTrieBuilder(const BytesTrieBuilder &other); // no copy constructor BytesTrieBuilder &operator=(const BytesTrieBuilder &other); // no assignment operator @@ -168,6 +172,7 @@ private: virtual int32_t writeValueAndFinal(int32_t i, UBool isFinal); virtual int32_t writeValueAndType(UBool hasValue, int32_t value, int32_t node); virtual int32_t writeDeltaTo(int32_t jumpTarget); + static int32_t internalEncodeDelta(int32_t i, char intBytes[]); CharString *strings; // Pointer not object so we need not #include internal charstr.h. BytesTrieElement *elements; diff --git a/thirdparty/icu4c/common/unicode/docmain.h b/thirdparty/icu4c/common/unicode/docmain.h index edcb5d4e83..e82678c95f 100644 --- a/thirdparty/icu4c/common/unicode/docmain.h +++ b/thirdparty/icu4c/common/unicode/docmain.h @@ -15,7 +15,7 @@ * \file * \brief (Non API- contains Doxygen definitions) * - * This file contains documentation for Doxygen and doesnot have + * This file contains documentation for Doxygen and does not have * any significance with respect to C or C++ API */ @@ -74,7 +74,7 @@ * </tr> * <tr> * <td>Strings and Character Iteration</td> - * <td>ustring.h, utf8.h, utf16.h, UText, UCharIterator</td> + * <td>ustring.h, utf8.h, utf16.h, icu::StringPiece, UText, UCharIterator, icu::ByteSink</td> * <td>icu::UnicodeString, icu::CharacterIterator, icu::Appendable, icu::StringPiece,icu::ByteSink</td> * </tr> * <tr> @@ -128,9 +128,9 @@ * <td>icu::Normalizer2</td> * </tr> * <tr> - * <td>Calendars</td> + * <td>Calendars and Time Zones</td> * <td>ucal.h</td> - * <td>icu::Calendar</td> + * <td>icu::Calendar, icu::TimeZone</td> * </tr> * <tr> * <td>Date and Time Formatting</td> diff --git a/thirdparty/icu4c/common/unicode/icuplug.h b/thirdparty/icu4c/common/unicode/icuplug.h index 52f810da57..205af360d4 100644 --- a/thirdparty/icu4c/common/unicode/icuplug.h +++ b/thirdparty/icu4c/common/unicode/icuplug.h @@ -117,14 +117,13 @@ /* === Basic types === */ #ifndef U_HIDE_INTERNAL_API +struct UPlugData; /** * @{ - * Opaque structure passed to/from a plugin. - * use the APIs to access it. + * Typedef for opaque structure passed to/from a plugin. + * Use the APIs to access it. * @internal ICU 4.4 Technology Preview */ - -struct UPlugData; typedef struct UPlugData UPlugData; /** @} */ diff --git a/thirdparty/icu4c/common/unicode/localematcher.h b/thirdparty/icu4c/common/unicode/localematcher.h index 63a68b0b7f..0cd068ef32 100644 --- a/thirdparty/icu4c/common/unicode/localematcher.h +++ b/thirdparty/icu4c/common/unicode/localematcher.h @@ -91,8 +91,6 @@ enum ULocMatchDemotion { typedef enum ULocMatchDemotion ULocMatchDemotion; #endif -#ifndef U_FORCE_HIDE_DRAFT_API - /** * Builder option for whether to include or ignore one-way (fallback) match data. * The LocaleMatcher uses CLDR languageMatch data which includes fallback (oneway=true) entries. @@ -108,20 +106,20 @@ typedef enum ULocMatchDemotion ULocMatchDemotion; * but not if it is merely a fallback. * * @see LocaleMatcher::Builder#setDirection(ULocMatchDirection) - * @draft ICU 67 + * @stable ICU 67 */ enum ULocMatchDirection { /** * Locale matching includes one-way matches such as Breton→French. (default) * - * @draft ICU 67 + * @stable ICU 67 */ ULOCMATCH_DIRECTION_WITH_ONE_WAY, /** * Locale matching limited to two-way matches including e.g. Danish↔Norwegian * but ignoring one-way matches. * - * @draft ICU 67 + * @stable ICU 67 */ ULOCMATCH_DIRECTION_ONLY_TWO_WAY }; @@ -129,8 +127,6 @@ enum ULocMatchDirection { typedef enum ULocMatchDirection ULocMatchDirection; #endif -#endif // U_FORCE_HIDE_DRAFT_API - struct UHashtable; U_NAMESPACE_BEGIN @@ -463,14 +459,13 @@ public: */ Builder &setDemotionPerDesiredLocale(ULocMatchDemotion demotion); -#ifndef U_HIDE_DRAFT_API /** * Option for whether to include or ignore one-way (fallback) match data. * By default, they are included. * * @param direction the match direction to set. * @return this Builder object - * @draft ICU 67 + * @stable ICU 67 */ Builder &setDirection(ULocMatchDirection direction) { if (U_SUCCESS(errorCode_)) { @@ -478,7 +473,6 @@ public: } return *this; } -#endif // U_HIDE_DRAFT_API #ifndef U_HIDE_DRAFT_API /** @@ -704,7 +698,7 @@ private: LSR *lsrs; int32_t supportedLocalesLength; // These are in preference order: 1. Default locale 2. paradigm locales 3. others. - UHashtable *supportedLsrToIndex; // Map<LSR, Integer> stores index+1 because 0 is "not found" + UHashtable *supportedLsrToIndex; // Map<LSR, Integer> // Array versions of the supportedLsrToIndex keys and values. // The distance lookup loops over the supportedLSRs and returns the index of the best match. const LSR **supportedLSRs; diff --git a/thirdparty/icu4c/common/unicode/locid.h b/thirdparty/icu4c/common/unicode/locid.h index ba858d702a..81f4685d65 100644 --- a/thirdparty/icu4c/common/unicode/locid.h +++ b/thirdparty/icu4c/common/unicode/locid.h @@ -571,15 +571,13 @@ public: */ void minimizeSubtags(UErrorCode& status); -#ifndef U_HIDE_DRAFT_API /** * Canonicalize the locale ID of this object according to CLDR. * @param status the status code - * @draft ICU 67 + * @stable ICU 67 * @see createCanonical */ void canonicalize(UErrorCode& status); -#endif // U_HIDE_DRAFT_API /** * Gets the list of keywords for the specified locale. diff --git a/thirdparty/icu4c/common/unicode/normalizer2.h b/thirdparty/icu4c/common/unicode/normalizer2.h index 5eb1d95caf..2d355250c2 100644 --- a/thirdparty/icu4c/common/unicode/normalizer2.h +++ b/thirdparty/icu4c/common/unicode/normalizer2.h @@ -225,10 +225,8 @@ public: * Normalizes a UTF-8 string and optionally records how source substrings * relate to changed and unchanged result substrings. * - * Currently implemented completely only for "compose" modes, - * such as for NFC, NFKC, and NFKC_Casefold - * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS). - * Otherwise currently converts to & from UTF-16 and does not support edits. + * Implemented completely for all built-in modes except for FCD. + * The base class implementation converts to & from UTF-16 and does not support edits. * * @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET. * @param src Source UTF-8 string. @@ -381,11 +379,9 @@ public: * resolves to "yes" or "no" to provide a definitive result, * at the cost of doing more work in those cases. * - * This works for all normalization modes, - * but it is currently optimized for UTF-8 only for "compose" modes, - * such as for NFC, NFKC, and NFKC_Casefold - * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS). - * For other modes it currently converts to UTF-16 and calls isNormalized(). + * This works for all normalization modes. + * It is optimized for UTF-8 for all built-in modes except for FCD. + * The base class implementation converts to UTF-16 and calls isNormalized(). * * @param s UTF-8 input string * @param errorCode Standard ICU error code. Its input value must @@ -543,10 +539,8 @@ public: * Normalizes a UTF-8 string and optionally records how source substrings * relate to changed and unchanged result substrings. * - * Currently implemented completely only for "compose" modes, - * such as for NFC, NFKC, and NFKC_Casefold - * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS). - * Otherwise currently converts to & from UTF-16 and does not support edits. + * Implemented completely for most built-in modes except for FCD. + * The base class implementation converts to & from UTF-16 and does not support edits. * * @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET. * @param src Source UTF-8 string. @@ -676,11 +670,9 @@ public: * resolves to "yes" or "no" to provide a definitive result, * at the cost of doing more work in those cases. * - * This works for all normalization modes, - * but it is currently optimized for UTF-8 only for "compose" modes, - * such as for NFC, NFKC, and NFKC_Casefold - * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS). - * For other modes it currently converts to UTF-16 and calls isNormalized(). + * This works for all normalization modes. + * It is optimized for UTF-8 for all built-in modes except for FCD. + * The base class implementation converts to UTF-16 and calls isNormalized(). * * @param s UTF-8 input string * @param errorCode Standard ICU error code. Its input value must diff --git a/thirdparty/icu4c/common/unicode/platform.h b/thirdparty/icu4c/common/unicode/platform.h index 2bb2f8b318..cb3a833fef 100644 --- a/thirdparty/icu4c/common/unicode/platform.h +++ b/thirdparty/icu4c/common/unicode/platform.h @@ -880,6 +880,6 @@ namespace std { #else # define U_CALLCONV_FPTR #endif -/* @} */ +/** @} */ #endif // _PLATFORM_H diff --git a/thirdparty/icu4c/common/unicode/stringpiece.h b/thirdparty/icu4c/common/unicode/stringpiece.h index 7d7d871e1f..8c96789e73 100644 --- a/thirdparty/icu4c/common/unicode/stringpiece.h +++ b/thirdparty/icu4c/common/unicode/stringpiece.h @@ -75,12 +75,11 @@ class U_COMMON_API StringPiece : public UMemory { * @stable ICU 4.2 */ StringPiece(const char* str); -#ifndef U_HIDE_DRAFT_API #if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN) /** * Constructs from a NUL-terminated const char8_t * pointer. * @param str a NUL-terminated const char8_t * pointer - * @draft ICU 67 + * @stable ICU 67 */ StringPiece(const char8_t* str) : StringPiece(reinterpret_cast<const char*>(str)) {} #endif @@ -88,10 +87,9 @@ class U_COMMON_API StringPiece : public UMemory { * Constructs an empty StringPiece. * Needed for type disambiguation from multiple other overloads. * @param p nullptr - * @draft ICU 67 + * @stable ICU 67 */ StringPiece(std::nullptr_t p) : ptr_(p), length_(0) {} -#endif // U_HIDE_DRAFT_API /** * Constructs from a std::string. @@ -99,17 +97,15 @@ class U_COMMON_API StringPiece : public UMemory { */ StringPiece(const std::string& str) : ptr_(str.data()), length_(static_cast<int32_t>(str.size())) { } -#ifndef U_HIDE_DRAFT_API #if defined(__cpp_lib_char8_t) || defined(U_IN_DOXYGEN) /** * Constructs from a std::u8string. - * @draft ICU 67 + * @stable ICU 67 */ StringPiece(const std::u8string& str) : ptr_(reinterpret_cast<const char*>(str.data())), length_(static_cast<int32_t>(str.size())) { } #endif -#endif // U_HIDE_DRAFT_API /** * Constructs from some other implementation of a string piece class, from any @@ -152,18 +148,16 @@ class U_COMMON_API StringPiece : public UMemory { * @stable ICU 4.2 */ StringPiece(const char* offset, int32_t len) : ptr_(offset), length_(len) { } -#ifndef U_HIDE_DRAFT_API #if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN) /** * Constructs from a const char8_t * pointer and a specified length. * @param str a const char8_t * pointer (need not be terminated) * @param len the length of the string; must be non-negative - * @draft ICU 67 + * @stable ICU 67 */ StringPiece(const char8_t* str, int32_t len) : StringPiece(reinterpret_cast<const char*>(str), len) {} #endif -#endif // U_HIDE_DRAFT_API /** * Substring of another StringPiece. @@ -233,13 +227,12 @@ class U_COMMON_API StringPiece : public UMemory { */ void set(const char* str); -#ifndef U_HIDE_DRAFT_API #if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN) /** * Resets the stringpiece to refer to new data. * @param xdata pointer the new string data. Need not be NUL-terminated. * @param len the length of the new data - * @draft ICU 67 + * @stable ICU 67 */ inline void set(const char8_t* xdata, int32_t len) { set(reinterpret_cast<const char*>(xdata), len); @@ -248,13 +241,12 @@ class U_COMMON_API StringPiece : public UMemory { /** * Resets the stringpiece to refer to new data. * @param str a pointer to a NUL-terminated string. - * @draft ICU 67 + * @stable ICU 67 */ inline void set(const char8_t* str) { set(reinterpret_cast<const char*>(str)); } #endif -#endif // U_HIDE_DRAFT_API /** * Removes the first n string units. @@ -286,13 +278,12 @@ class U_COMMON_API StringPiece : public UMemory { } } -#ifndef U_HIDE_DRAFT_API /** * Searches the StringPiece for the given search string (needle); * @param needle The string for which to search. * @param offset Where to start searching within this string (haystack). * @return The offset of needle in haystack, or -1 if not found. - * @draft ICU 67 + * @stable ICU 67 */ int32_t find(StringPiece needle, int32_t offset); @@ -301,10 +292,9 @@ class U_COMMON_API StringPiece : public UMemory { * similar to std::string::compare(). * @param other The string to compare to. * @return below zero if this < other; above zero if this > other; 0 if this == other. - * @draft ICU 67 + * @stable ICU 67 */ int32_t compare(StringPiece other); -#endif // U_HIDE_DRAFT_API /** * Maximum integer, used as a default value for substring methods. diff --git a/thirdparty/icu4c/common/unicode/ubrk.h b/thirdparty/icu4c/common/unicode/ubrk.h index 37189a8598..1249b0b160 100644 --- a/thirdparty/icu4c/common/unicode/ubrk.h +++ b/thirdparty/icu4c/common/unicode/ubrk.h @@ -296,6 +296,8 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength, const UChar * text, int32_t textLength, UErrorCode * status); +#ifndef U_HIDE_DEPRECATED_API + /** * Thread safe cloning operation * @param bi iterator to be cloned @@ -312,7 +314,7 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength, * @param status to indicate whether the operation went on smoothly or there were errors * An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any allocations were necessary. * @return pointer to the new clone - * @stable ICU 2.0 + * @deprecated ICU 69 Use ubrk_clone() instead. */ U_CAPI UBreakIterator * U_EXPORT2 ubrk_safeClone( @@ -321,6 +323,23 @@ ubrk_safeClone( int32_t *pBufferSize, UErrorCode *status); +#endif /* U_HIDE_DEPRECATED_API */ + +#ifndef U_HIDE_DRAFT_API + +/** + * Thread safe cloning operation. + * @param bi iterator to be cloned + * @param status to indicate whether the operation went on smoothly or there were errors + * @return pointer to the new clone + * @draft ICU 69 + */ +U_CAPI UBreakIterator * U_EXPORT2 +ubrk_clone(const UBreakIterator *bi, + UErrorCode *status); + +#endif // U_HIDE_DRAFT_API + #ifndef U_HIDE_DEPRECATED_API /** diff --git a/thirdparty/icu4c/common/unicode/ucnv.h b/thirdparty/icu4c/common/unicode/ucnv.h index 58f271cfb5..5d784990f2 100644 --- a/thirdparty/icu4c/common/unicode/ucnv.h +++ b/thirdparty/icu4c/common/unicode/ucnv.h @@ -1699,10 +1699,10 @@ ucnv_countAvailable(void); /** * Gets the canonical converter name of the specified converter from a list of - * all available converters contaied in the alias file. All converters + * all available converters contained in the alias file. All converters * in this list can be opened. * - * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvaiable()]</TT>) + * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvailable()]</TT>) * @return a pointer a string (library owned), or <TT>NULL</TT> if the index is out of bounds. * @see ucnv_countAvailable * @stable ICU 2.0 diff --git a/thirdparty/icu4c/common/unicode/ucnvsel.h b/thirdparty/icu4c/common/unicode/ucnvsel.h index 5e0a71cf35..3d7d3327f7 100644 --- a/thirdparty/icu4c/common/unicode/ucnvsel.h +++ b/thirdparty/icu4c/common/unicode/ucnvsel.h @@ -45,11 +45,11 @@ * from the serialized form. */ +struct UConverterSelector; /** * @{ - * The selector data structure + * Typedef for selector data structure. */ -struct UConverterSelector; typedef struct UConverterSelector UConverterSelector; /** @} */ diff --git a/thirdparty/icu4c/common/unicode/unifilt.h b/thirdparty/icu4c/common/unicode/unifilt.h index 420e1a1905..7870b55939 100644 --- a/thirdparty/icu4c/common/unicode/unifilt.h +++ b/thirdparty/icu4c/common/unicode/unifilt.h @@ -40,8 +40,8 @@ U_NAMESPACE_BEGIN * * <code>UnicodeFilter</code> defines a protocol for selecting a * subset of the full range (U+0000 to U+10FFFF) of Unicode characters. - * Currently, filters are used in conjunction with classes like {@link - * Transliterator} to only process selected characters through a + * Currently, filters are used in conjunction with classes like + * {@link Transliterator} to only process selected characters through a * transformation. * * <p>Note: UnicodeFilter currently stubs out two pure virtual methods diff --git a/thirdparty/icu4c/common/unicode/uniset.h b/thirdparty/icu4c/common/unicode/uniset.h index 50b6360f3a..8403c4026c 100644 --- a/thirdparty/icu4c/common/unicode/uniset.h +++ b/thirdparty/icu4c/common/unicode/uniset.h @@ -178,8 +178,6 @@ class RuleCharacterIterator; * Unicode property * </table> * - * <p><b>Warning</b>: you cannot add an empty string ("") to a UnicodeSet.</p> - * * <p><b>Formal syntax</b></p> * * \htmlonly<blockquote>\endhtmlonly @@ -601,7 +599,7 @@ public: /** * Make this object represent the range `start - end`. - * If `end > start` then this object is set to an empty range. + * If `start > end` then this object is set to an empty range. * A frozen set will not be modified. * * @param start first character in the set, inclusive @@ -1077,7 +1075,7 @@ public: /** * Adds the specified range to this set if it is not already * present. If this set already contains the specified range, - * the call leaves this set unchanged. If <code>end > start</code> + * the call leaves this set unchanged. If <code>start > end</code> * then an empty range is added, leaving the set unchanged. * This is equivalent to a boolean logic OR, or a set UNION. * A frozen set will not be modified. @@ -1095,6 +1093,9 @@ public: * present. If this set already contains the specified character, * the call leaves this set unchanged. * A frozen set will not be modified. + * + * @param c the character (code point) + * @return this object, for chaining * @stable ICU 2.0 */ UnicodeSet& add(UChar32 c); @@ -1104,8 +1105,8 @@ public: * present. If this set already contains the multicharacter, * the call leaves this set unchanged. * Thus "ch" => {"ch"} - * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b> * A frozen set will not be modified. + * * @param s the source string * @return this object, for chaining * @stable ICU 2.4 @@ -1124,8 +1125,8 @@ public: public: /** - * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"} - * If this set already any particular character, it has no effect on that character. + * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"} + * If this set already contains any particular character, it has no effect on that character. * A frozen set will not be modified. * @param s the source string * @return this object, for chaining @@ -1135,7 +1136,6 @@ public: /** * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"} - * If this set already any particular character, it has no effect on that character. * A frozen set will not be modified. * @param s the source string * @return this object, for chaining @@ -1145,7 +1145,6 @@ public: /** * Complement EACH of the characters in this string. Note: "ch" == {"c", "h"} - * If this set already any particular character, it has no effect on that character. * A frozen set will not be modified. * @param s the source string * @return this object, for chaining @@ -1155,7 +1154,6 @@ public: /** * Remove EACH of the characters in this string. Note: "ch" == {"c", "h"} - * If this set already any particular character, it has no effect on that character. * A frozen set will not be modified. * @param s the source string * @return this object, for chaining @@ -1165,7 +1163,7 @@ public: /** * Makes a set from a multicharacter string. Thus "ch" => {"ch"} - * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b> + * * @param s the source string * @return a newly created set containing the given string. * The caller owns the return object and is responsible for deleting it. @@ -1185,15 +1183,13 @@ public: /** * Retain only the elements in this set that are contained in the - * specified range. If <code>end > start</code> then an empty range is + * specified range. If <code>start > end</code> then an empty range is * retained, leaving the set empty. This is equivalent to * a boolean logic AND, or a set INTERSECTION. * A frozen set will not be modified. * - * @param start first character, inclusive, of range to be retained - * to this set. - * @param end last character, inclusive, of range to be retained - * to this set. + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range * @stable ICU 2.0 */ virtual UnicodeSet& retain(UChar32 start, UChar32 end); @@ -1202,14 +1198,31 @@ public: /** * Retain the specified character from this set if it is present. * A frozen set will not be modified. + * + * @param c the character (code point) + * @return this object, for chaining * @stable ICU 2.0 */ UnicodeSet& retain(UChar32 c); +#ifndef U_HIDE_DRAFT_API + /** + * Retains only the specified string from this set if it is present. + * Upon return this set will be empty if it did not contain s, or + * will only contain s if it did contain s. + * A frozen set will not be modified. + * + * @param s the source string + * @return this object, for chaining + * @draft ICU 69 + */ + UnicodeSet& retain(const UnicodeString &s); +#endif // U_HIDE_DRAFT_API + /** * Removes the specified range from this set if it is present. * The set will not contain the specified range once the call - * returns. If <code>end > start</code> then an empty range is + * returns. If <code>start > end</code> then an empty range is * removed, leaving the set unchanged. * A frozen set will not be modified. * @@ -1226,6 +1239,9 @@ public: * The set will not contain the specified range once the call * returns. * A frozen set will not be modified. + * + * @param c the character (code point) + * @return this object, for chaining * @stable ICU 2.0 */ UnicodeSet& remove(UChar32 c); @@ -1253,15 +1269,13 @@ public: /** * Complements the specified range in this set. Any character in * the range will be removed if it is in this set, or will be - * added if it is not in this set. If <code>end > start</code> + * added if it is not in this set. If <code>start > end</code> * then an empty range is complemented, leaving the set unchanged. * This is equivalent to a boolean logic XOR. * A frozen set will not be modified. * - * @param start first character, inclusive, of range to be removed - * from this set. - * @param end last character, inclusive, of range to be removed - * from this set. + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range * @stable ICU 2.0 */ virtual UnicodeSet& complement(UChar32 start, UChar32 end); @@ -1271,16 +1285,18 @@ public: * will be removed if it is in this set, or will be added if it is * not in this set. * A frozen set will not be modified. + * + * @param c the character (code point) + * @return this object, for chaining * @stable ICU 2.0 */ UnicodeSet& complement(UChar32 c); /** * Complement the specified string in this set. - * The set will not contain the specified string once the call - * returns. - * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b> + * The string will be removed if it is in this set, or will be added if it is not in this set. * A frozen set will not be modified. + * * @param s the string to complement * @return this object, for chaining * @stable ICU 2.4 diff --git a/thirdparty/icu4c/common/unicode/unistr.h b/thirdparty/icu4c/common/unicode/unistr.h index 456389f265..85bd964951 100644 --- a/thirdparty/icu4c/common/unicode/unistr.h +++ b/thirdparty/icu4c/common/unicode/unistr.h @@ -44,9 +44,10 @@ struct UConverter; // unicode/ucnv.h #ifndef USTRING_H /** * \ingroup ustring_ustrlen + * @param s Pointer to sequence of UChars. + * @return Length of sequence. */ -U_CAPI int32_t U_EXPORT2 -u_strlen(const UChar *s); +U_CAPI int32_t U_EXPORT2 u_strlen(const UChar *s); #endif U_NAMESPACE_BEGIN @@ -2766,7 +2767,6 @@ public: * @param options Options bit set, usually 0. See U_TITLECASE_NO_LOWERCASE, * U_TITLECASE_NO_BREAK_ADJUSTMENT, U_TITLECASE_ADJUST_TO_CASED, * U_TITLECASE_WHOLE_STRING, U_TITLECASE_SENTENCES. - * @param options Options bit set, see ucasemap_open(). * @return A reference to this. * @stable ICU 3.8 */ @@ -3614,7 +3614,7 @@ private: // turn a bogus string into an empty one void unBogus(); - // implements assigment operator, copy constructor, and fastCopyFrom() + // implements assignment operator, copy constructor, and fastCopyFrom() UnicodeString ©From(const UnicodeString &src, UBool fastCopy=false); // Copies just the fields without memory management. diff --git a/thirdparty/icu4c/common/unicode/urename.h b/thirdparty/icu4c/common/unicode/urename.h index fe59fdd893..737f4b308e 100644 --- a/thirdparty/icu4c/common/unicode/urename.h +++ b/thirdparty/icu4c/common/unicode/urename.h @@ -482,6 +482,7 @@ #define ubiditransform_open U_ICU_ENTRY_POINT_RENAME(ubiditransform_open) #define ubiditransform_transform U_ICU_ENTRY_POINT_RENAME(ubiditransform_transform) #define ublock_getCode U_ICU_ENTRY_POINT_RENAME(ublock_getCode) +#define ubrk_clone U_ICU_ENTRY_POINT_RENAME(ubrk_clone) #define ubrk_close U_ICU_ENTRY_POINT_RENAME(ubrk_close) #define ubrk_countAvailable U_ICU_ENTRY_POINT_RENAME(ubrk_countAvailable) #define ubrk_current U_ICU_ENTRY_POINT_RENAME(ubrk_current) @@ -534,6 +535,7 @@ #define ucal_getTimeZoneDisplayName U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneDisplayName) #define ucal_getTimeZoneID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneID) #define ucal_getTimeZoneIDForWindowsID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneIDForWindowsID) +#define ucal_getTimeZoneOffsetFromLocal U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneOffsetFromLocal) #define ucal_getTimeZoneTransitionDate U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneTransitionDate) #define ucal_getType U_ICU_ENTRY_POINT_RENAME(ucal_getType) #define ucal_getWeekendTransition U_ICU_ENTRY_POINT_RENAME(ucal_getWeekendTransition) @@ -962,6 +964,7 @@ #define uhash_compareScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_compareScriptSet) #define uhash_compareUChars U_ICU_ENTRY_POINT_RENAME(uhash_compareUChars) #define uhash_compareUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_compareUnicodeString) +#define uhash_containsKey U_ICU_ENTRY_POINT_RENAME(uhash_containsKey) #define uhash_count U_ICU_ENTRY_POINT_RENAME(uhash_count) #define uhash_deleteHashtable U_ICU_ENTRY_POINT_RENAME(uhash_deleteHashtable) #define uhash_deleteScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_deleteScriptSet) @@ -970,6 +973,7 @@ #define uhash_find U_ICU_ENTRY_POINT_RENAME(uhash_find) #define uhash_get U_ICU_ENTRY_POINT_RENAME(uhash_get) #define uhash_geti U_ICU_ENTRY_POINT_RENAME(uhash_geti) +#define uhash_getiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_getiAndFound) #define uhash_hashCaselessUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashCaselessUnicodeString) #define uhash_hashChars U_ICU_ENTRY_POINT_RENAME(uhash_hashChars) #define uhash_hashIChars U_ICU_ENTRY_POINT_RENAME(uhash_hashIChars) @@ -977,12 +981,15 @@ #define uhash_hashScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_hashScriptSet) #define uhash_hashUChars U_ICU_ENTRY_POINT_RENAME(uhash_hashUChars) #define uhash_hashUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashUnicodeString) +#define uhash_icontainsKey U_ICU_ENTRY_POINT_RENAME(uhash_icontainsKey) #define uhash_iget U_ICU_ENTRY_POINT_RENAME(uhash_iget) #define uhash_igeti U_ICU_ENTRY_POINT_RENAME(uhash_igeti) +#define uhash_igetiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_igetiAndFound) #define uhash_init U_ICU_ENTRY_POINT_RENAME(uhash_init) #define uhash_initSize U_ICU_ENTRY_POINT_RENAME(uhash_initSize) #define uhash_iput U_ICU_ENTRY_POINT_RENAME(uhash_iput) #define uhash_iputi U_ICU_ENTRY_POINT_RENAME(uhash_iputi) +#define uhash_iputiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_iputiAllowZero) #define uhash_iremove U_ICU_ENTRY_POINT_RENAME(uhash_iremove) #define uhash_iremovei U_ICU_ENTRY_POINT_RENAME(uhash_iremovei) #define uhash_nextElement U_ICU_ENTRY_POINT_RENAME(uhash_nextElement) @@ -990,6 +997,7 @@ #define uhash_openSize U_ICU_ENTRY_POINT_RENAME(uhash_openSize) #define uhash_put U_ICU_ENTRY_POINT_RENAME(uhash_put) #define uhash_puti U_ICU_ENTRY_POINT_RENAME(uhash_puti) +#define uhash_putiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_putiAllowZero) #define uhash_remove U_ICU_ENTRY_POINT_RENAME(uhash_remove) #define uhash_removeAll U_ICU_ENTRY_POINT_RENAME(uhash_removeAll) #define uhash_removeElement U_ICU_ENTRY_POINT_RENAME(uhash_removeElement) @@ -1150,6 +1158,8 @@ #define ultag_isUnicodeLocaleKey U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleKey) #define ultag_isUnicodeLocaleType U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleType) #define ultag_isVariantSubtags U_ICU_ENTRY_POINT_RENAME(ultag_isVariantSubtags) +#define umeas_getPrefixBase U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixBase) +#define umeas_getPrefixPower U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixPower) #define umsg_applyPattern U_ICU_ENTRY_POINT_RENAME(umsg_applyPattern) #define umsg_autoQuoteApostrophe U_ICU_ENTRY_POINT_RENAME(umsg_autoQuoteApostrophe) #define umsg_clone U_ICU_ENTRY_POINT_RENAME(umsg_clone) @@ -1672,6 +1682,9 @@ #define uset_compact U_ICU_ENTRY_POINT_RENAME(uset_compact) #define uset_complement U_ICU_ENTRY_POINT_RENAME(uset_complement) #define uset_complementAll U_ICU_ENTRY_POINT_RENAME(uset_complementAll) +#define uset_complementAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_complementAllCodePoints) +#define uset_complementRange U_ICU_ENTRY_POINT_RENAME(uset_complementRange) +#define uset_complementString U_ICU_ENTRY_POINT_RENAME(uset_complementString) #define uset_contains U_ICU_ENTRY_POINT_RENAME(uset_contains) #define uset_containsAll U_ICU_ENTRY_POINT_RENAME(uset_containsAll) #define uset_containsAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_containsAllCodePoints) @@ -1695,12 +1708,15 @@ #define uset_openPatternOptions U_ICU_ENTRY_POINT_RENAME(uset_openPatternOptions) #define uset_remove U_ICU_ENTRY_POINT_RENAME(uset_remove) #define uset_removeAll U_ICU_ENTRY_POINT_RENAME(uset_removeAll) +#define uset_removeAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_removeAllCodePoints) #define uset_removeAllStrings U_ICU_ENTRY_POINT_RENAME(uset_removeAllStrings) #define uset_removeRange U_ICU_ENTRY_POINT_RENAME(uset_removeRange) #define uset_removeString U_ICU_ENTRY_POINT_RENAME(uset_removeString) #define uset_resemblesPattern U_ICU_ENTRY_POINT_RENAME(uset_resemblesPattern) #define uset_retain U_ICU_ENTRY_POINT_RENAME(uset_retain) #define uset_retainAll U_ICU_ENTRY_POINT_RENAME(uset_retainAll) +#define uset_retainAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_retainAllCodePoints) +#define uset_retainString U_ICU_ENTRY_POINT_RENAME(uset_retainString) #define uset_serialize U_ICU_ENTRY_POINT_RENAME(uset_serialize) #define uset_serializedContains U_ICU_ENTRY_POINT_RENAME(uset_serializedContains) #define uset_set U_ICU_ENTRY_POINT_RENAME(uset_set) diff --git a/thirdparty/icu4c/common/unicode/uset.h b/thirdparty/icu4c/common/unicode/uset.h index 502ea8dc14..1d0daf9d09 100644 --- a/thirdparty/icu4c/common/unicode/uset.h +++ b/thirdparty/icu4c/common/unicode/uset.h @@ -582,8 +582,8 @@ U_CAPI void U_EXPORT2 uset_addString(USet* set, const UChar* str, int32_t strLen); /** - * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"} - * If this set already any particular character, it has no effect on that character. + * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"} + * If this set already contains any particular character, it has no effect on that character. * A frozen set will not be modified. * @param set the object to which to add the character * @param str the source string @@ -628,6 +628,20 @@ uset_removeRange(USet* set, UChar32 start, UChar32 end); U_CAPI void U_EXPORT2 uset_removeString(USet* set, const UChar* str, int32_t strLen); +#ifndef U_HIDE_DRAFT_API +/** + * Removes EACH of the characters in this string. Note: "ch" == {"c", "h"} + * A frozen set will not be modified. + * + * @param set the object to be modified + * @param str the string + * @param length the length of the string, or -1 if NUL-terminated + * @draft ICU 69 + */ +U_CAPI void U_EXPORT2 +uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length); +#endif // U_HIDE_DRAFT_API + /** * Removes from this set all of its elements that are contained in the * specified set. This operation effectively modifies this @@ -650,15 +664,41 @@ uset_removeAll(USet* set, const USet* removeSet); * A frozen set will not be modified. * * @param set the object for which to retain only the specified range - * @param start first character, inclusive, of range to be retained - * to this set. - * @param end last character, inclusive, of range to be retained - * to this set. + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range * @stable ICU 3.2 */ U_CAPI void U_EXPORT2 uset_retain(USet* set, UChar32 start, UChar32 end); +#ifndef U_HIDE_DRAFT_API +/** + * Retains only the specified string from this set if it is present. + * Upon return this set will be empty if it did not contain s, or + * will only contain s if it did contain s. + * A frozen set will not be modified. + * + * @param set the object to be modified + * @param str the string + * @param length the length of the string, or -1 if NUL-terminated + * @draft ICU 69 + */ +U_CAPI void U_EXPORT2 +uset_retainString(USet *set, const UChar *str, int32_t length); + +/** + * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"} + * A frozen set will not be modified. + * + * @param set the object to be modified + * @param str the string + * @param length the length of the string, or -1 if NUL-terminated + * @draft ICU 69 + */ +U_CAPI void U_EXPORT2 +uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length); +#endif // U_HIDE_DRAFT_API + /** * Retains only the elements in this set that are contained in the * specified set. In other words, removes from this set all of @@ -696,6 +736,49 @@ uset_compact(USet* set); U_CAPI void U_EXPORT2 uset_complement(USet* set); +#ifndef U_HIDE_DRAFT_API +/** + * Complements the specified range in this set. Any character in + * the range will be removed if it is in this set, or will be + * added if it is not in this set. If <code>start > end</code> + * then an empty range is complemented, leaving the set unchanged. + * This is equivalent to a boolean logic XOR. + * A frozen set will not be modified. + * + * @param set the object to be modified + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range + * @draft ICU 69 + */ +U_CAPI void U_EXPORT2 +uset_complementRange(USet *set, UChar32 start, UChar32 end); + +/** + * Complements the specified string in this set. + * The string will be removed if it is in this set, or will be added if it is not in this set. + * A frozen set will not be modified. + * + * @param set the object to be modified + * @param str the string + * @param length the length of the string, or -1 if NUL-terminated + * @draft ICU 69 + */ +U_CAPI void U_EXPORT2 +uset_complementString(USet *set, const UChar *str, int32_t length); + +/** + * Complements EACH of the characters in this string. Note: "ch" == {"c", "h"} + * A frozen set will not be modified. + * + * @param set the object to be modified + * @param str the string + * @param length the length of the string, or -1 if NUL-terminated + * @draft ICU 69 + */ +U_CAPI void U_EXPORT2 +uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length); +#endif // U_HIDE_DRAFT_API + /** * Complements in this set all elements contained in the specified * set. Any character in the other set will be removed if it is diff --git a/thirdparty/icu4c/common/unicode/ushape.h b/thirdparty/icu4c/common/unicode/ushape.h index fed4869abd..14371edc8f 100644 --- a/thirdparty/icu4c/common/unicode/ushape.h +++ b/thirdparty/icu4c/common/unicode/ushape.h @@ -323,7 +323,7 @@ u_shapeArabic(const UChar *source, int32_t sourceLength, #define U_SHAPE_PRESERVE_PRESENTATION 0x8000 /** Presentation form option: * Replace Arabic Presentation Forms-A and Arabic Presentationo Forms-B with - * their unshaped correspondants in range 0+06xx, before shaping. + * their unshaped correspondents in range 0+06xx, before shaping. * @stable ICU 3.6 */ #define U_SHAPE_PRESERVE_PRESENTATION_NOOP 0 diff --git a/thirdparty/icu4c/common/unicode/utrace.h b/thirdparty/icu4c/common/unicode/utrace.h index 28c313c582..677486f473 100644 --- a/thirdparty/icu4c/common/unicode/utrace.h +++ b/thirdparty/icu4c/common/unicode/utrace.h @@ -173,24 +173,23 @@ typedef enum UTraceFunctionNumber { UTRACE_RES_DATA_LIMIT, #endif // U_HIDE_INTERNAL_API -#ifndef U_HIDE_DRAFT_API /** * The lowest break iterator location. - * @draft ICU 67 + * @stable ICU 67 */ UTRACE_UBRK_START=0x4000, /** * Indicates that a character instance of break iterator was created. * - * @draft ICU 67 + * @stable ICU 67 */ UTRACE_UBRK_CREATE_CHARACTER = UTRACE_UBRK_START, /** * Indicates that a word instance of break iterator was created. * - * @draft ICU 67 + * @stable ICU 67 */ UTRACE_UBRK_CREATE_WORD, @@ -200,21 +199,21 @@ typedef enum UTraceFunctionNumber { * Provides one C-style string to UTraceData: the lb value ("", * "loose", "strict", or "normal"). * - * @draft ICU 67 + * @stable ICU 67 */ UTRACE_UBRK_CREATE_LINE, /** * Indicates that a sentence instance of break iterator was created. * - * @draft ICU 67 + * @stable ICU 67 */ UTRACE_UBRK_CREATE_SENTENCE, /** * Indicates that a title instance of break iterator was created. * - * @draft ICU 67 + * @stable ICU 67 */ UTRACE_UBRK_CREATE_TITLE, @@ -224,12 +223,10 @@ typedef enum UTraceFunctionNumber { * Provides one C-style string to UTraceData: the script code of what * the break engine cover ("Hani", "Khmr", "Laoo", "Mymr", or "Thai"). * - * @draft ICU 67 + * @stable ICU 67 */ UTRACE_UBRK_CREATE_BREAK_ENGINE, -#endif // U_HIDE_DRAFT_API - #ifndef U_HIDE_INTERNAL_API /** * One more than the highest normal break iterator trace location. diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h index a46481a3fe..b09d4943c1 100644 --- a/thirdparty/icu4c/common/unicode/uvernum.h +++ b/thirdparty/icu4c/common/unicode/uvernum.h @@ -60,13 +60,13 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.4 */ -#define U_ICU_VERSION_MAJOR_NUM 68 +#define U_ICU_VERSION_MAJOR_NUM 69 /** The current ICU minor version as an integer. * This value will change in the subsequent releases of ICU * @stable ICU 2.6 */ -#define U_ICU_VERSION_MINOR_NUM 2 +#define U_ICU_VERSION_MINOR_NUM 1 /** The current ICU patchlevel version as an integer. * This value will change in the subsequent releases of ICU @@ -86,7 +86,7 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.6 */ -#define U_ICU_VERSION_SUFFIX _68 +#define U_ICU_VERSION_SUFFIX _69 /** * \def U_DEF2_ICU_ENTRY_POINT_RENAME @@ -139,7 +139,7 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.4 */ -#define U_ICU_VERSION "68.2" +#define U_ICU_VERSION "69.1" /** * The current ICU library major version number as a string, for library name suffixes. @@ -152,13 +152,13 @@ * * @stable ICU 2.6 */ -#define U_ICU_VERSION_SHORT "68" +#define U_ICU_VERSION_SHORT "69" #ifndef U_HIDE_INTERNAL_API /** Data version in ICU4C. * @internal ICU 4.4 Internal Use Only **/ -#define U_ICU_DATA_VERSION "68.2" +#define U_ICU_DATA_VERSION "69.1" #endif /* U_HIDE_INTERNAL_API */ /*=========================================================================== diff --git a/thirdparty/icu4c/common/uniset.cpp b/thirdparty/icu4c/common/uniset.cpp index b73d612f24..461e5a7197 100644 --- a/thirdparty/icu4c/common/uniset.cpp +++ b/thirdparty/icu4c/common/uniset.cpp @@ -30,24 +30,6 @@ #include "bmpset.h" #include "unisetspan.h" -// Define UChar constants using hex for EBCDIC compatibility -// Used #define to reduce private static exports and memory access time. -#define SET_OPEN ((UChar)0x005B) /*[*/ -#define SET_CLOSE ((UChar)0x005D) /*]*/ -#define HYPHEN ((UChar)0x002D) /*-*/ -#define COMPLEMENT ((UChar)0x005E) /*^*/ -#define COLON ((UChar)0x003A) /*:*/ -#define BACKSLASH ((UChar)0x005C) /*\*/ -#define INTERSECTION ((UChar)0x0026) /*&*/ -#define UPPER_U ((UChar)0x0055) /*U*/ -#define LOWER_U ((UChar)0x0075) /*u*/ -#define OPEN_BRACE ((UChar)123) /*{*/ -#define CLOSE_BRACE ((UChar)125) /*}*/ -#define UPPER_P ((UChar)0x0050) /*P*/ -#define LOWER_P ((UChar)0x0070) /*p*/ -#define UPPER_N ((UChar)78) /*N*/ -#define EQUALS ((UChar)0x003D) /*=*/ - // HIGH_VALUE > all valid values. 110000 for codepoints #define UNICODESET_HIGH 0x0110000 @@ -444,7 +426,6 @@ UBool UnicodeSet::contains(UChar32 start, UChar32 end) const { * @return <tt>true</tt> if this set contains the specified string */ UBool UnicodeSet::contains(const UnicodeString& s) const { - if (s.length() == 0) return FALSE; int32_t cp = getSingleCP(s); if (cp < 0) { return stringsContains(s); @@ -559,11 +540,9 @@ UBool UnicodeSet::matchesIndexValue(uint8_t v) const { if (hasStrings()) { for (i=0; i<strings->size(); ++i) { const UnicodeString& s = *(const UnicodeString*)strings->elementAt(i); - //if (s.length() == 0) { - // // Empty strings match everything - // return TRUE; - //} - // assert(s.length() != 0); // We enforce this elsewhere + if (s.isEmpty()) { + continue; // skip the empty string + } UChar32 c = s.char32At(0); if ((c & 0xFF) == v) { return TRUE; @@ -582,9 +561,6 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text, int32_t limit, UBool incremental) { if (offset == limit) { - // Strings, if any, have length != 0, so we don't worry - // about them here. If we ever allow zero-length strings - // we much check for them here. if (contains(U_ETHER)) { return incremental ? U_PARTIAL_MATCH : U_MATCH; } else { @@ -614,11 +590,9 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text, for (i=0; i<strings->size(); ++i) { const UnicodeString& trial = *(const UnicodeString*)strings->elementAt(i); - - //if (trial.length() == 0) { - // return U_MATCH; // null-string always matches - //} - // assert(trial.length() != 0); // We ensure this elsewhere + if (trial.isEmpty()) { + continue; // skip the empty string + } UChar c = trial.charAt(forward ? 0 : trial.length() - 1); @@ -971,12 +945,12 @@ UnicodeSet& UnicodeSet::add(UChar32 c) { * present. If this set already contains the multicharacter, * the call leaves this set unchanged. * Thus "ch" => {"ch"} - * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b> + * * @param s the source string * @return the modified set, for chaining */ UnicodeSet& UnicodeSet::add(const UnicodeString& s) { - if (s.length() == 0 || isFrozen() || isBogus()) return *this; + if (isFrozen() || isBogus()) return *this; int32_t cp = getSingleCP(s); if (cp < 0) { if (!stringsContains(s)) { @@ -991,8 +965,7 @@ UnicodeSet& UnicodeSet::add(const UnicodeString& s) { /** * Adds the given string, in order, to 'strings'. The given string - * must have been checked by the caller to not be empty and to not - * already be in 'strings'. + * must have been checked by the caller to not already be in 'strings'. */ void UnicodeSet::_add(const UnicodeString& s) { if (isFrozen() || isBogus()) { @@ -1021,16 +994,13 @@ void UnicodeSet::_add(const UnicodeString& s) { * @param string to test */ int32_t UnicodeSet::getSingleCP(const UnicodeString& s) { - //if (s.length() < 1) { - // throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet"); - //} - if (s.length() > 2) return -1; - if (s.length() == 1) return s.charAt(0); - - // at this point, len = 2 - UChar32 cp = s.char32At(0); - if (cp > 0xFFFF) { // is surrogate pair - return cp; + int32_t sLength = s.length(); + if (sLength == 1) return s.charAt(0); + if (sLength == 2) { + UChar32 cp = s.char32At(0); + if (cp > 0xFFFF) { // is surrogate pair + return cp; + } } return -1; } @@ -1150,6 +1120,26 @@ UnicodeSet& UnicodeSet::retain(UChar32 c) { return retain(c, c); } +UnicodeSet& UnicodeSet::retain(const UnicodeString &s) { + if (isFrozen() || isBogus()) { return *this; } + UChar32 cp = getSingleCP(s); + if (cp < 0) { + bool isIn = stringsContains(s); + // Check for getRangeCount() first to avoid somewhat-expensive size() + // when there are single code points. + if (isIn && getRangeCount() == 0 && size() == 1) { + return *this; + } + clear(); + if (isIn) { + _add(s); + } + } else { + retain(cp, cp); + } + return *this; +} + /** * Removes the specified range from this set if it is present. * The set will not contain the specified range once the call @@ -1186,7 +1176,7 @@ UnicodeSet& UnicodeSet::remove(UChar32 c) { * @return the modified set, for chaining */ UnicodeSet& UnicodeSet::remove(const UnicodeString& s) { - if (s.length() == 0 || isFrozen() || isBogus()) return *this; + if (isFrozen() || isBogus()) return *this; int32_t cp = getSingleCP(s); if (cp < 0) { if (strings != nullptr && strings->removeElement((void*) &s)) { @@ -1252,12 +1242,12 @@ UnicodeSet& UnicodeSet::complement(void) { * Complement the specified string in this set. * The set will not contain the specified string once the call * returns. - * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b> + * * @param s the string to complement * @return this object, for chaining */ UnicodeSet& UnicodeSet::complement(const UnicodeString& s) { - if (s.length() == 0 || isFrozen() || isBogus()) return *this; + if (isFrozen() || isBogus()) return *this; int32_t cp = getSingleCP(s); if (cp < 0) { if (stringsContains(s)) { @@ -2001,22 +1991,22 @@ escapeUnprintable) { } // Okay to let ':' pass through switch (c) { - case SET_OPEN: - case SET_CLOSE: - case HYPHEN: - case COMPLEMENT: - case INTERSECTION: - case BACKSLASH: - case OPEN_BRACE: - case CLOSE_BRACE: - case COLON: + case u'[': + case u']': + case u'-': + case u'^': + case u'&': + case u'\\': + case u'{': + case u'}': + case u':': case SymbolTable::SYMBOL_REF: - buf.append(BACKSLASH); + buf.append(u'\\'); break; default: // Escape whitespace if (PatternProps::isWhiteSpace(c)) { - buf.append(BACKSLASH); + buf.append(u'\\'); } break; } @@ -2049,7 +2039,7 @@ UnicodeString& UnicodeSet::_toPattern(UnicodeString& result, backslashCount = 0; } else { result.append(c); - if (c == BACKSLASH) { + if (c == u'\\') { ++backslashCount; } else { backslashCount = 0; @@ -2082,13 +2072,13 @@ UnicodeString& UnicodeSet::toPattern(UnicodeString& result, UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result, UBool escapeUnprintable) const { - result.append(SET_OPEN); + result.append(u'['); // // Check against the predefined categories. We implicitly build // // up ALL category sets the first time toPattern() is called. // for (int8_t cat=0; cat<Unicode::GENERAL_TYPES_COUNT; ++cat) { // if (*this == getCategorySet(cat)) { -// result.append(COLON); +// result.append(u':'); // result.append(CATEGORY_NAMES, cat*2, 2); // return result.append(CATEGORY_CLOSE); // } @@ -2104,7 +2094,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result, getRangeEnd(count-1) == MAX_VALUE) { // Emit the inverse - result.append(COMPLEMENT); + result.append(u'^'); for (int32_t i = 1; i < count; ++i) { UChar32 start = getRangeEnd(i-1)+1; @@ -2112,7 +2102,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result, _appendToPat(result, start, escapeUnprintable); if (start != end) { if ((start+1) != end) { - result.append(HYPHEN); + result.append(u'-'); } _appendToPat(result, end, escapeUnprintable); } @@ -2127,7 +2117,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result, _appendToPat(result, start, escapeUnprintable); if (start != end) { if ((start+1) != end) { - result.append(HYPHEN); + result.append(u'-'); } _appendToPat(result, end, escapeUnprintable); } @@ -2136,14 +2126,14 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result, if (strings != nullptr) { for (int32_t i = 0; i<strings->size(); ++i) { - result.append(OPEN_BRACE); + result.append(u'{'); _appendToPat(result, *(const UnicodeString*) strings->elementAt(i), escapeUnprintable); - result.append(CLOSE_BRACE); + result.append(u'}'); } } - return result.append(SET_CLOSE); + return result.append(u']'); } /** diff --git a/thirdparty/icu4c/common/uniset_props.cpp b/thirdparty/icu4c/common/uniset_props.cpp index 37277fcb75..8fde5abcdd 100644 --- a/thirdparty/icu4c/common/uniset_props.cpp +++ b/thirdparty/icu4c/common/uniset_props.cpp @@ -47,31 +47,6 @@ U_NAMESPACE_USE -// Define UChar constants using hex for EBCDIC compatibility -// Used #define to reduce private static exports and memory access time. -#define SET_OPEN ((UChar)0x005B) /*[*/ -#define SET_CLOSE ((UChar)0x005D) /*]*/ -#define HYPHEN ((UChar)0x002D) /*-*/ -#define COMPLEMENT ((UChar)0x005E) /*^*/ -#define COLON ((UChar)0x003A) /*:*/ -#define BACKSLASH ((UChar)0x005C) /*\*/ -#define INTERSECTION ((UChar)0x0026) /*&*/ -#define UPPER_U ((UChar)0x0055) /*U*/ -#define LOWER_U ((UChar)0x0075) /*u*/ -#define OPEN_BRACE ((UChar)123) /*{*/ -#define CLOSE_BRACE ((UChar)125) /*}*/ -#define UPPER_P ((UChar)0x0050) /*P*/ -#define LOWER_P ((UChar)0x0070) /*p*/ -#define UPPER_N ((UChar)78) /*N*/ -#define EQUALS ((UChar)0x003D) /*=*/ - -//static const UChar POSIX_OPEN[] = { SET_OPEN,COLON,0 }; // "[:" -static const UChar POSIX_CLOSE[] = { COLON,SET_CLOSE,0 }; // ":]" -//static const UChar PERL_OPEN[] = { BACKSLASH,LOWER_P,0 }; // "\\p" -//static const UChar PERL_CLOSE[] = { CLOSE_BRACE,0 }; // "}" -//static const UChar NAME_OPEN[] = { BACKSLASH,UPPER_N,0 }; // "\\N" -static const UChar HYPHEN_RIGHT_BRACE[] = {HYPHEN,SET_CLOSE,0}; /*-]*/ - // Special property set IDs static const char ANY[] = "ANY"; // [\u0000-\U0010FFFF] static const char ASCII[] = "ASCII"; // [\u0000-\u007F] @@ -81,12 +56,6 @@ static const char ASSIGNED[] = "Assigned"; // [:^Cn:] #define NAME_PROP "na" #define NAME_PROP_LENGTH 2 -/** - * Delimiter string used in patterns to close a category reference: - * ":]". Example: "[:Lu:]". - */ -//static const UChar CATEGORY_CLOSE[] = {COLON, SET_CLOSE, 0x0000}; /* ":]" */ - // Cached sets ------------------------------------------------------------- *** U_CDECL_BEGIN @@ -140,27 +109,27 @@ uniset_getUnicode32Instance(UErrorCode &errorCode) { static inline UBool isPerlOpen(const UnicodeString &pattern, int32_t pos) { UChar c; - return pattern.charAt(pos)==BACKSLASH && ((c=pattern.charAt(pos+1))==LOWER_P || c==UPPER_P); + return pattern.charAt(pos)==u'\\' && ((c=pattern.charAt(pos+1))==u'p' || c==u'P'); } /*static inline UBool isPerlClose(const UnicodeString &pattern, int32_t pos) { - return pattern.charAt(pos)==CLOSE_BRACE; + return pattern.charAt(pos)==u'}'; }*/ static inline UBool isNameOpen(const UnicodeString &pattern, int32_t pos) { - return pattern.charAt(pos)==BACKSLASH && pattern.charAt(pos+1)==UPPER_N; + return pattern.charAt(pos)==u'\\' && pattern.charAt(pos+1)==u'N'; } static inline UBool isPOSIXOpen(const UnicodeString &pattern, int32_t pos) { - return pattern.charAt(pos)==SET_OPEN && pattern.charAt(pos+1)==COLON; + return pattern.charAt(pos)==u'[' && pattern.charAt(pos+1)==u':'; } /*static inline UBool isPOSIXClose(const UnicodeString &pattern, int32_t pos) { - return pattern.charAt(pos)==COLON && pattern.charAt(pos+1)==SET_CLOSE; + return pattern.charAt(pos)==u':' && pattern.charAt(pos+1)==u']'; }*/ // TODO memory debugging provided inside uniset.cpp @@ -326,9 +295,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, while (mode != 2 && !chars.atEnd()) { U_ASSERT((lastItem == 0 && op == 0) || - (lastItem == 1 && (op == 0 || op == HYPHEN /*'-'*/)) || - (lastItem == 2 && (op == 0 || op == HYPHEN /*'-'*/ || - op == INTERSECTION /*'&'*/))); + (lastItem == 1 && (op == 0 || op == u'-')) || + (lastItem == 2 && (op == 0 || op == u'-' || op == u'&'))); UChar32 c = 0; UBool literal = FALSE; @@ -356,27 +324,27 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, c = chars.next(opts, literal, ec); if (U_FAILURE(ec)) return; - if (c == 0x5B /*'['*/ && !literal) { + if (c == u'[' && !literal) { if (mode == 1) { chars.setPos(backup); // backup setMode = 1; } else { // Handle opening '[' delimiter mode = 1; - patLocal.append((UChar) 0x5B /*'['*/); + patLocal.append(u'['); chars.getPos(backup); // prepare to backup c = chars.next(opts, literal, ec); if (U_FAILURE(ec)) return; - if (c == 0x5E /*'^'*/ && !literal) { + if (c == u'^' && !literal) { invert = TRUE; - patLocal.append((UChar) 0x5E /*'^'*/); + patLocal.append(u'^'); chars.getPos(backup); // prepare to backup c = chars.next(opts, literal, ec); if (U_FAILURE(ec)) return; } // Fall through to handle special leading '-'; // otherwise restart loop for nested [], \p{}, etc. - if (c == HYPHEN /*'-'*/) { + if (c == u'-') { literal = TRUE; // Fall through to handle literal '-' below } else { @@ -418,7 +386,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, op = 0; } - if (op == HYPHEN /*'-'*/ || op == INTERSECTION /*'&'*/) { + if (op == u'-' || op == u'&') { patLocal.append(op); } @@ -454,10 +422,10 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, } switch (op) { - case HYPHEN: /*'-'*/ + case u'-': removeAll(*nested); break; - case INTERSECTION: /*'&'*/ + case u'&': retainAll(*nested); break; case 0: @@ -483,24 +451,24 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, if (!literal) { switch (c) { - case 0x5D /*']'*/: + case u']': if (lastItem == 1) { add(lastChar, lastChar); _appendToPat(patLocal, lastChar, FALSE); } // Treat final trailing '-' as a literal - if (op == HYPHEN /*'-'*/) { + if (op == u'-') { add(op, op); patLocal.append(op); - } else if (op == INTERSECTION /*'&'*/) { + } else if (op == u'&') { // syntaxError(chars, "Trailing '&'"); ec = U_MALFORMED_SET; return; } - patLocal.append((UChar) 0x5D /*']'*/); + patLocal.append(u']'); mode = 2; continue; - case HYPHEN /*'-'*/: + case u'-': if (op == 0) { if (lastItem != 0) { op = (UChar) c; @@ -510,8 +478,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, add(c, c); c = chars.next(opts, literal, ec); if (U_FAILURE(ec)) return; - if (c == 0x5D /*']'*/ && !literal) { - patLocal.append(HYPHEN_RIGHT_BRACE, 2); + if (c == u']' && !literal) { + patLocal.append(u"-]", 2); mode = 2; continue; } @@ -520,7 +488,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, // syntaxError(chars, "'-' not after char or set"); ec = U_MALFORMED_SET; return; - case INTERSECTION /*'&'*/: + case u'&': if (lastItem == 2 && op == 0) { op = (UChar) c; continue; @@ -528,11 +496,11 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, // syntaxError(chars, "'&' not after set"); ec = U_MALFORMED_SET; return; - case 0x5E /*'^'*/: + case u'^': // syntaxError(chars, "'^' not after '['"); ec = U_MALFORMED_SET; return; - case 0x7B /*'{'*/: + case u'{': if (op != 0) { // syntaxError(chars, "Missing operand after operator"); ec = U_MALFORMED_SET; @@ -549,13 +517,13 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, while (!chars.atEnd()) { c = chars.next(opts, literal, ec); if (U_FAILURE(ec)) return; - if (c == 0x7D /*'}'*/ && !literal) { + if (c == u'}' && !literal) { ok = TRUE; break; } buf.append(c); } - if (buf.length() < 1 || !ok) { + if (!ok) { // syntaxError(chars, "Invalid multicharacter string"); ec = U_MALFORMED_SET; return; @@ -565,9 +533,9 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, // we don't need to drop through to the further // processing add(buf); - patLocal.append((UChar) 0x7B /*'{'*/); + patLocal.append(u'{'); _appendToPat(patLocal, buf, FALSE); - patLocal.append((UChar) 0x7D /*'}'*/); + patLocal.append(u'}'); continue; case SymbolTable::SYMBOL_REF: // symbols nosymbols @@ -580,7 +548,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, chars.getPos(backup); c = chars.next(opts, literal, ec); if (U_FAILURE(ec)) return; - UBool anchor = (c == 0x5D /*']'*/ && !literal); + UBool anchor = (c == u']' && !literal); if (symbols == 0 && !anchor) { c = SymbolTable::SYMBOL_REF; chars.setPos(backup); @@ -594,7 +562,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, add(U_ETHER); usePat = TRUE; patLocal.append((UChar) SymbolTable::SYMBOL_REF); - patLocal.append((UChar) 0x5D /*']'*/); + patLocal.append(u']'); mode = 2; continue; } @@ -617,7 +585,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars, lastChar = c; break; case 1: - if (op == HYPHEN /*'-'*/) { + if (op == u'-') { if (lastChar >= c) { // Don't allow redundant (a-a) or empty (b-a) ranges; // these are most likely typos. @@ -1036,11 +1004,11 @@ UBool UnicodeSet::resemblesPropertyPattern(RuleCharacterIterator& chars, RuleCharacterIterator::Pos pos; chars.getPos(pos); UChar32 c = chars.next(iterOpts, literal, ec); - if (c == 0x5B /*'['*/ || c == 0x5C /*'\\'*/) { + if (c == u'[' || c == u'\\') { UChar32 d = chars.next(iterOpts & ~RuleCharacterIterator::SKIP_WHITESPACE, literal, ec); - result = (c == 0x5B /*'['*/) ? (d == 0x3A /*':'*/) : - (d == 0x4E /*'N'*/ || d == 0x70 /*'p'*/ || d == 0x50 /*'P'*/); + result = (c == u'[') ? (d == u':') : + (d == u'N' || d == u'p' || d == u'P'); } chars.setPos(pos); return result && U_SUCCESS(ec); @@ -1071,17 +1039,17 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern, posix = TRUE; pos += 2; pos = ICU_Utility::skipWhitespace(pattern, pos); - if (pos < pattern.length() && pattern.charAt(pos) == COMPLEMENT) { + if (pos < pattern.length() && pattern.charAt(pos) == u'^') { ++pos; invert = TRUE; } } else if (isPerlOpen(pattern, pos) || isNameOpen(pattern, pos)) { UChar c = pattern.charAt(pos+1); - invert = (c == UPPER_P); - isName = (c == UPPER_N); + invert = (c == u'P'); + isName = (c == u'N'); pos += 2; pos = ICU_Utility::skipWhitespace(pattern, pos); - if (pos == pattern.length() || pattern.charAt(pos++) != OPEN_BRACE) { + if (pos == pattern.length() || pattern.charAt(pos++) != u'{') { // Syntax error; "\p" or "\P" not followed by "{" FAIL(ec); } @@ -1093,9 +1061,9 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern, // Look for the matching close delimiter, either :] or } int32_t close; if (posix) { - close = pattern.indexOf(POSIX_CLOSE, 2, pos); + close = pattern.indexOf(u":]", 2, pos); } else { - close = pattern.indexOf(CLOSE_BRACE, pos); + close = pattern.indexOf(u'}', pos); } if (close < 0) { // Syntax error; close delimiter missing @@ -1105,7 +1073,7 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern, // Look for an '=' sign. If this is present, we will parse a // medium \p{gc=Cf} or long \p{GeneralCategory=Format} // pattern. - int32_t equals = pattern.indexOf(EQUALS, pos); + int32_t equals = pattern.indexOf(u'=', pos); UnicodeString propName, valueName; if (equals >= 0 && equals < close && !isName) { // Equals seen; parse medium/long pattern diff --git a/thirdparty/icu4c/common/unisetspan.cpp b/thirdparty/icu4c/common/unisetspan.cpp index 68e44d91ee..fe0d74f5b2 100644 --- a/thirdparty/icu4c/common/unisetspan.cpp +++ b/thirdparty/icu4c/common/unisetspan.cpp @@ -231,6 +231,9 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set, const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i); const UChar *s16=string.getBuffer(); int32_t length16=string.length(); + if (length16==0) { + continue; // skip the empty string + } UBool thisRelevant; spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED); if(spanLength<length16) { // Relevant string. @@ -312,7 +315,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set, const UChar *s16=string.getBuffer(); int32_t length16=string.length(); spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED); - if(spanLength<length16) { // Relevant string. + if(spanLength<length16 && length16>0) { // Relevant string. if(which&UTF16) { if(which&CONTAINED) { if(which&FWD) { @@ -362,7 +365,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set, addToSpanNotSet(c); } } - } else { // Irrelevant string. + } else { // Irrelevant string. (Also the empty string.) if(which&UTF8) { if(which&CONTAINED) { // Only necessary for LONGEST_MATCH. uint8_t *s8=utf8+utf8Count; @@ -653,11 +656,12 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi for(i=0; i<stringsLength; ++i) { int32_t overlap=spanLengths[i]; if(overlap==ALL_CP_CONTAINED) { - continue; // Irrelevant string. + continue; // Irrelevant string. (Also the empty string.) } const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i); const UChar *s16=string.getBuffer(); int32_t length16=string.length(); + U_ASSERT(length>0); // Try to match this string at pos-overlap..pos. if(overlap>=LONG_SPAN) { @@ -697,6 +701,9 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i); const UChar *s16=string.getBuffer(); int32_t length16=string.length(); + if (length16==0) { + continue; // skip the empty string + } // Try to match this string at pos-overlap..pos. if(overlap>=LONG_SPAN) { @@ -817,11 +824,12 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC for(i=0; i<stringsLength; ++i) { int32_t overlap=spanBackLengths[i]; if(overlap==ALL_CP_CONTAINED) { - continue; // Irrelevant string. + continue; // Irrelevant string. (Also the empty string.) } const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i); const UChar *s16=string.getBuffer(); int32_t length16=string.length(); + U_ASSERT(length>0); // Try to match this string at pos-(length16-overlap)..pos-length16. if(overlap>=LONG_SPAN) { @@ -863,6 +871,9 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i); const UChar *s16=string.getBuffer(); int32_t length16=string.length(); + if (length16==0) { + continue; // skip the empty string + } // Try to match this string at pos-(length16-overlap)..pos-length16. if(overlap>=LONG_SPAN) { @@ -1358,11 +1369,12 @@ int32_t UnicodeSetStringSpan::spanNot(const UChar *s, int32_t length) const { // Try to match the strings at pos. for(i=0; i<stringsLength; ++i) { if(spanLengths[i]==ALL_CP_CONTAINED) { - continue; // Irrelevant string. + continue; // Irrelevant string. (Also the empty string.) } const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i); const UChar *s16=string.getBuffer(); int32_t length16=string.length(); + U_ASSERT(length>0); if(length16<=rest && matches16CPB(s, pos, length, s16, length16)) { return pos; // There is a set element at pos. } @@ -1401,11 +1413,12 @@ int32_t UnicodeSetStringSpan::spanNotBack(const UChar *s, int32_t length) const // it is easier and we only need to know whether the string is irrelevant // which is the same in either array. if(spanLengths[i]==ALL_CP_CONTAINED) { - continue; // Irrelevant string. + continue; // Irrelevant string. (Also the empty string.) } const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i); const UChar *s16=string.getBuffer(); int32_t length16=string.length(); + U_ASSERT(length>0); if(length16<=pos && matches16CPB(s, pos-length16, length, s16, length16)) { return pos; // There is a set element at pos. } diff --git a/thirdparty/icu4c/common/uprops.h b/thirdparty/icu4c/common/uprops.h index 8bf929919f..09830bdeb9 100644 --- a/thirdparty/icu4c/common/uprops.h +++ b/thirdparty/icu4c/common/uprops.h @@ -310,55 +310,12 @@ u_isgraphPOSIX(UChar32 c); U_CFUNC UBool u_isprintPOSIX(UChar32 c); -/** Turn a bit index into a bit flag. @internal */ -#define FLAG(n) ((uint32_t)1<<(n)) - -/** Flags for general categories in the order of UCharCategory. @internal */ -#define _Cn FLAG(U_GENERAL_OTHER_TYPES) -#define _Lu FLAG(U_UPPERCASE_LETTER) -#define _Ll FLAG(U_LOWERCASE_LETTER) -#define _Lt FLAG(U_TITLECASE_LETTER) -#define _Lm FLAG(U_MODIFIER_LETTER) -/* #define _Lo FLAG(U_OTHER_LETTER) -- conflicts with MS Visual Studio 9.0 xiosbase */ -#define _Mn FLAG(U_NON_SPACING_MARK) -#define _Me FLAG(U_ENCLOSING_MARK) -#define _Mc FLAG(U_COMBINING_SPACING_MARK) -#define _Nd FLAG(U_DECIMAL_DIGIT_NUMBER) -#define _Nl FLAG(U_LETTER_NUMBER) -#define _No FLAG(U_OTHER_NUMBER) -#define _Zs FLAG(U_SPACE_SEPARATOR) -#define _Zl FLAG(U_LINE_SEPARATOR) -#define _Zp FLAG(U_PARAGRAPH_SEPARATOR) -#define _Cc FLAG(U_CONTROL_CHAR) -#define _Cf FLAG(U_FORMAT_CHAR) -#define _Co FLAG(U_PRIVATE_USE_CHAR) -#define _Cs FLAG(U_SURROGATE) -#define _Pd FLAG(U_DASH_PUNCTUATION) -#define _Ps FLAG(U_START_PUNCTUATION) -/* #define _Pe FLAG(U_END_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 xlocnum */ -/* #define _Pc FLAG(U_CONNECTOR_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */ -#define _Po FLAG(U_OTHER_PUNCTUATION) -#define _Sm FLAG(U_MATH_SYMBOL) -#define _Sc FLAG(U_CURRENCY_SYMBOL) -#define _Sk FLAG(U_MODIFIER_SYMBOL) -#define _So FLAG(U_OTHER_SYMBOL) -#define _Pi FLAG(U_INITIAL_PUNCTUATION) -/* #define _Pf FLAG(U_FINAL_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */ - /** Some code points. @internal */ enum { TAB =0x0009, LF =0x000a, FF =0x000c, CR =0x000d, - U_A =0x0041, - U_F =0x0046, - U_Z =0x005a, - U_a =0x0061, - U_f =0x0066, - U_z =0x007a, - DEL =0x007f, - NL =0x0085, NBSP =0x00a0, CGJ =0x034f, FIGURESP=0x2007, @@ -367,15 +324,6 @@ enum { ZWJ =0x200d, RLM =0x200f, NNBSP =0x202f, - WJ =0x2060, - INHSWAP =0x206a, - NOMDIG =0x206f, - U_FW_A =0xff21, - U_FW_F =0xff26, - U_FW_Z =0xff3a, - U_FW_a =0xff41, - U_FW_f =0xff46, - U_FW_z =0xff5a, ZWNBSP =0xfeff }; diff --git a/thirdparty/icu4c/common/uresbund.cpp b/thirdparty/icu4c/common/uresbund.cpp index 2ece87897d..5ea4187100 100644 --- a/thirdparty/icu4c/common/uresbund.cpp +++ b/thirdparty/icu4c/common/uresbund.cpp @@ -92,6 +92,15 @@ static UBool chopLocale(char *name) { } /** + * Called to check whether a name without '_' needs to be checked for a parent. + * Some code had assumed that locale IDs with '_' could not have a non-root parent. + * We may want a better way of doing this. + */ +static UBool mayHaveParent(char *name) { + return (name[0] != 0 && uprv_strstr("nb nn",name) != nullptr); +} + +/** * Internal function */ static void entryIncrease(UResourceDataEntry *entry) { @@ -529,8 +538,8 @@ loadParentsExceptRoot(UResourceDataEntry *&t1, char name[], int32_t nameCapacity, UBool usingUSRData, char usrDataPath[], UErrorCode *status) { if (U_FAILURE(*status)) { return FALSE; } - UBool hasChopped = TRUE; - while (hasChopped && t1->fParent == NULL && !t1->fData.noFallback && + UBool checkParent = TRUE; + while (checkParent && t1->fParent == NULL && !t1->fData.noFallback && res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) { Resource parentRes = res_getResource(&t1->fData, "%%Parent"); if (parentRes != RES_BOGUS) { // An explicit parent was found. @@ -573,7 +582,7 @@ loadParentsExceptRoot(UResourceDataEntry *&t1, } } t1 = t2; - hasChopped = chopLocale(name); + checkParent = chopLocale(name) || mayHaveParent(name); } return TRUE; } @@ -692,7 +701,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, } } } - if (hasChopped && !isRoot) { + if ((hasChopped || mayHaveParent(name)) && !isRoot) { if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) { goto finish; } @@ -716,7 +725,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, hasRealData = TRUE; isDefault = TRUE; // TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path? - if (hasChopped && !isRoot) { + if ((hasChopped || mayHaveParent(name)) && !isRoot) { if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) { goto finish; } @@ -1908,6 +1917,8 @@ ures_getByKeyWithFallback(const UResourceBundle *resB, } else { break; } + } else if (res == RES_BOGUS) { + break; } } while(*myPath); /* Continue until the whole path is consumed */ } @@ -3019,7 +3030,7 @@ ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status) U_CAPI UBool U_EXPORT2 ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){ if(res1==NULL || res2==NULL){ - return res1==res2; /* pointer comparision */ + return res1==res2; /* pointer comparison */ } if(res1->fKey==NULL|| res2->fKey==NULL){ return (res1->fKey==res2->fKey); diff --git a/thirdparty/icu4c/common/uresdata.cpp b/thirdparty/icu4c/common/uresdata.cpp index ae731e4544..9af081be40 100644 --- a/thirdparty/icu4c/common/uresdata.cpp +++ b/thirdparty/icu4c/common/uresdata.cpp @@ -960,14 +960,6 @@ res_findResource(const ResourceData *pResData, Resource r, char** path, const ch if(URES_IS_TABLE(type)) { *key = pathP; t2 = res_getTableItemByKey(pResData, t1, &indexR, key); - if(t2 == RES_BOGUS) { - /* if we fail to get the resource by key, maybe we got an index */ - indexR = uprv_strtol(pathP, &closeIndex, 10); - if(indexR >= 0 && *closeIndex == 0 && (*pathP != '0' || closeIndex - pathP == 1)) { - /* if we indeed have an index, try to get the item by index */ - t2 = res_getTableItemByIndex(pResData, t1, indexR, key); - } // else t2 is already RES_BOGUS - } } else if(URES_IS_ARRAY(type)) { indexR = uprv_strtol(pathP, &closeIndex, 10); if(indexR >= 0 && *closeIndex == 0) { diff --git a/thirdparty/icu4c/common/uresimp.h b/thirdparty/icu4c/common/uresimp.h index 69d82566fe..f038dedace 100644 --- a/thirdparty/icu4c/common/uresimp.h +++ b/thirdparty/icu4c/common/uresimp.h @@ -270,11 +270,13 @@ ures_getByKeyWithFallback(const UResourceBundle *resB, * function can perform fallback on the sub-resources of the table. * @param resB a resource * @param inKey a key associated with the requested resource + * @param len if not NULL, used to return the length of the string * @param status: fills in the outgoing error code * could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found * could be a non-failing error * e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT> - * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it + * @return returns a pointer to a zero-terminated UChar array which lives in a + * memory mapped/DLL file. */ U_CAPI const UChar* U_EXPORT2 ures_getStringByKeyWithFallback(const UResourceBundle *resB, diff --git a/thirdparty/icu4c/common/uset.cpp b/thirdparty/icu4c/common/uset.cpp index eae7981d52..a7e3046dbf 100644 --- a/thirdparty/icu4c/common/uset.cpp +++ b/thirdparty/icu4c/common/uset.cpp @@ -117,6 +117,12 @@ uset_removeString(USet* set, const UChar* str, int32_t strLen) { } U_CAPI void U_EXPORT2 +uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length) { + UnicodeString s(length==-1, str, length); + ((UnicodeSet*) set)->UnicodeSet::removeAll(s); +} + +U_CAPI void U_EXPORT2 uset_removeAll(USet* set, const USet* remove) { ((UnicodeSet*) set)->UnicodeSet::removeAll(*(const UnicodeSet*)remove); } @@ -127,6 +133,18 @@ uset_retain(USet* set, UChar32 start, UChar32 end) { } U_CAPI void U_EXPORT2 +uset_retainString(USet *set, const UChar *str, int32_t length) { + UnicodeString s(length==-1, str, length); + ((UnicodeSet*) set)->UnicodeSet::retain(s); +} + +U_CAPI void U_EXPORT2 +uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length) { + UnicodeString s(length==-1, str, length); + ((UnicodeSet*) set)->UnicodeSet::retainAll(s); +} + +U_CAPI void U_EXPORT2 uset_retainAll(USet* set, const USet* retain) { ((UnicodeSet*) set)->UnicodeSet::retainAll(*(const UnicodeSet*)retain); } @@ -142,6 +160,23 @@ uset_complement(USet* set) { } U_CAPI void U_EXPORT2 +uset_complementRange(USet *set, UChar32 start, UChar32 end) { + ((UnicodeSet*) set)->UnicodeSet::complement(start, end); +} + +U_CAPI void U_EXPORT2 +uset_complementString(USet *set, const UChar *str, int32_t length) { + UnicodeString s(length==-1, str, length); + ((UnicodeSet*) set)->UnicodeSet::complement(s); +} + +U_CAPI void U_EXPORT2 +uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length) { + UnicodeString s(length==-1, str, length); + ((UnicodeSet*) set)->UnicodeSet::complementAll(s); +} + +U_CAPI void U_EXPORT2 uset_complementAll(USet* set, const USet* complement) { ((UnicodeSet*) set)->UnicodeSet::complementAll(*(const UnicodeSet*)complement); } diff --git a/thirdparty/icu4c/common/usprep.cpp b/thirdparty/icu4c/common/usprep.cpp index 8351a77370..874ffc63a8 100644 --- a/thirdparty/icu4c/common/usprep.cpp +++ b/thirdparty/icu4c/common/usprep.cpp @@ -575,7 +575,7 @@ usprep_map( const UStringPrepProfile* profile, } }else if(type==USPREP_DELETE){ - // just consume the codepoint and contine + // just consume the codepoint and continue continue; } //copy the code point into destination diff --git a/thirdparty/icu4c/common/ustr_wcs.cpp b/thirdparty/icu4c/common/ustr_wcs.cpp index e9f278e969..89d0762480 100644 --- a/thirdparty/icu4c/common/ustr_wcs.cpp +++ b/thirdparty/icu4c/common/ustr_wcs.cpp @@ -364,7 +364,7 @@ _strFromWCS( UChar *dest, } /* we have found a null so convert the - * chunk from begining of non-null char to null + * chunk from beginning of non-null char to null */ retVal = uprv_wcstombs(pCSrc,pSrc,remaining); @@ -387,7 +387,7 @@ _strFromWCS( UChar *dest, * null terminate it and convert wchar_ts to chars */ if(nulLen >= _STACK_BUFFER_CAPACITY){ - /* Should rarely occcur */ + /* Should rarely occur */ /* allocate new buffer buffer */ pWStack =(wchar_t*) uprv_malloc(sizeof(wchar_t) * (nulLen + 1)); if(pWStack==NULL){ diff --git a/thirdparty/icu4c/common/utext.cpp b/thirdparty/icu4c/common/utext.cpp index 763b6684fb..d79f8141bb 100644 --- a/thirdparty/icu4c/common/utext.cpp +++ b/thirdparty/icu4c/common/utext.cpp @@ -382,7 +382,7 @@ utext_previous32From(UText *ut, int64_t index) { // UChar32 cPrev; // The character preceding cCurr, which is what we will return. - // Address the chunk containg the position preceding the incoming index + // Address the chunk containing the position preceding the incoming index // A tricky edge case: // We try to test the requested native index against the chunkNativeStart to determine // whether the character preceding the one at the index is in the current chunk. @@ -894,7 +894,7 @@ struct UTF8Buf { // one for a supplementary starting in the last normal position, // and one for an entry for the buffer limit position. uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to - // correspoding offset in filled part of buf. + // corresponding offset in filled part of buf. int32_t align; }; @@ -1545,7 +1545,7 @@ utf8TextMapOffsetToNative(const UText *ut) { } // -// Map a native index to the corrsponding chunk offset +// Map a native index to the corresponding chunk offset // static int32_t U_CALLCONV utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) { diff --git a/thirdparty/icu4c/common/util.h b/thirdparty/icu4c/common/util.h index 9c3b76d9ed..b5fac383a2 100644 --- a/thirdparty/icu4c/common/util.h +++ b/thirdparty/icu4c/common/util.h @@ -13,10 +13,10 @@ #ifndef ICU_UTIL_H #define ICU_UTIL_H -#include "unicode/utypes.h" -#include "unicode/uobject.h" +#include "charstr.h" #include "unicode/unistr.h" - +#include "unicode/uobject.h" +#include "unicode/utypes.h" //-------------------------------------------------------------------- // class ICU_Utility // i18n utility functions, scoped into the class ICU_Utility. diff --git a/thirdparty/icu4c/common/utracimp.h b/thirdparty/icu4c/common/utracimp.h index f32fe1db39..945540d25a 100644 --- a/thirdparty/icu4c/common/utracimp.h +++ b/thirdparty/icu4c/common/utracimp.h @@ -193,7 +193,7 @@ UPRV_BLOCK_MACRO_BEGIN { \ * Trace statement for each exit point of a function that has a UTRACE_ENTRY() * statement, and that returns a value. * - * @param val The function's return value, int32_t or comatible type. + * @param val The function's return value, int32_t or compatible type. * * @internal */ diff --git a/thirdparty/icu4c/common/uvector.cpp b/thirdparty/icu4c/common/uvector.cpp index cf19edf646..9c7e74c6d5 100644 --- a/thirdparty/icu4c/common/uvector.cpp +++ b/thirdparty/icu4c/common/uvector.cpp @@ -312,7 +312,7 @@ int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const { } else { for (i=startIndex; i<count; ++i) { /* Pointers are not always the same size as ints so to perform - * a valid comparision we need to know whether we are being + * a valid comparison we need to know whether we are being * provided an int or a pointer. */ if (hint & HINT_KEY_POINTER) { if (key.pointer == elements[i].pointer) { @@ -518,7 +518,7 @@ sortiComparator(const void * /*context */, const void *left, const void *right) } /** - * Sort the vector, assuming it constains ints. + * Sort the vector, assuming it contains ints. * (A more general sort would take a comparison function, but it's * not clear whether UVector's UElementComparator or * UComparator from uprv_sortAray would be more appropriate.) diff --git a/thirdparty/icu4c/common/wintz.cpp b/thirdparty/icu4c/common/wintz.cpp index 580cedadb6..ebf31650c2 100644 --- a/thirdparty/icu4c/common/wintz.cpp +++ b/thirdparty/icu4c/common/wintz.cpp @@ -124,10 +124,26 @@ uprv_detectWindowsTimeZone() // No way to support when DST is turned off and the offset in minutes is not a multiple of 60. if (utcOffsetMins % 60 == 0) { char gmtOffsetTz[11] = {}; // "Etc/GMT+dd" is 11-char long with a terminal null. - // Note '-' before 'utcOffsetMin'. The timezone ID's sign convention - // is that a timezone ahead of UTC is Etc/GMT-<offset> and a timezone - // behind UTC is Etc/GMT+<offset>. - int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", -utcOffsetMins / 60); + // Important note on the sign convention for zones: + // + // From https://en.wikipedia.org/wiki/Tz_database#Area + // "In order to conform with the POSIX style, those zone names beginning with "Etc/GMT" have their sign reversed + // from the standard ISO 8601 convention. In the "Etc" area, zones west of GMT have a positive sign and those + // east have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours ahead of GMT)." + // + // Regarding the POSIX style, from https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + // "The offset specifies the time value you must add to the local time to get a Coordinated Universal Time value." + // + // However, the Bias value in DYNAMIC_TIME_ZONE_INFORMATION *already* follows the POSIX convention. + // + // From https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information + // "The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and + // local time. All translations between UTC and local time are based on the following formula: + // UTC = local time + bias" + // + // For example, a time zone that is 3 hours ahead of UTC (UTC+03:00) would have a Bias value of -180, and the + // corresponding time zone ID would be "Etc/GMT-3". (So there is no need to negate utcOffsetMins below.) + int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", utcOffsetMins / 60); if (ret > 0 && ret < UPRV_LENGTHOF(gmtOffsetTz)) { return uprv_strdup(gmtOffsetTz); } diff --git a/thirdparty/icu4c/icudt68l.dat b/thirdparty/icu4c/icudt69l.dat Binary files differindex 9ecea5d548..3101a49695 100644 --- a/thirdparty/icu4c/icudt68l.dat +++ b/thirdparty/icu4c/icudt69l.dat diff --git a/thirdparty/meshoptimizer/LICENSE.md b/thirdparty/meshoptimizer/LICENSE.md index 4fcd766d22..3c52415f62 100644 --- a/thirdparty/meshoptimizer/LICENSE.md +++ b/thirdparty/meshoptimizer/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016-2020 Arseny Kapoulkine +Copyright (c) 2016-2021 Arseny Kapoulkine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/meshoptimizer/clusterizer.cpp b/thirdparty/meshoptimizer/clusterizer.cpp index f7d88c5136..f8aad7b49c 100644 --- a/thirdparty/meshoptimizer/clusterizer.cpp +++ b/thirdparty/meshoptimizer/clusterizer.cpp @@ -2,6 +2,7 @@ #include "meshoptimizer.h" #include <assert.h> +#include <float.h> #include <math.h> #include <string.h> @@ -12,6 +13,68 @@ namespace meshopt { +// This must be <= 255 since index 0xff is used internally to indice a vertex that doesn't belong to a meshlet +const size_t kMeshletMaxVertices = 255; + +// A reasonable limit is around 2*max_vertices or less +const size_t kMeshletMaxTriangles = 512; + +struct TriangleAdjacency2 +{ + unsigned int* counts; + unsigned int* offsets; + unsigned int* data; +}; + +static void buildTriangleAdjacency(TriangleAdjacency2& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator) +{ + size_t face_count = index_count / 3; + + // allocate arrays + adjacency.counts = allocator.allocate<unsigned int>(vertex_count); + adjacency.offsets = allocator.allocate<unsigned int>(vertex_count); + adjacency.data = allocator.allocate<unsigned int>(index_count); + + // fill triangle counts + memset(adjacency.counts, 0, vertex_count * sizeof(unsigned int)); + + for (size_t i = 0; i < index_count; ++i) + { + assert(indices[i] < vertex_count); + + adjacency.counts[indices[i]]++; + } + + // fill offset table + unsigned int offset = 0; + + for (size_t i = 0; i < vertex_count; ++i) + { + adjacency.offsets[i] = offset; + offset += adjacency.counts[i]; + } + + assert(offset == index_count); + + // fill triangle data + for (size_t i = 0; i < face_count; ++i) + { + unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2]; + + adjacency.data[adjacency.offsets[a]++] = unsigned(i); + adjacency.data[adjacency.offsets[b]++] = unsigned(i); + adjacency.data[adjacency.offsets[c]++] = unsigned(i); + } + + // fix offsets that have been disturbed by the previous pass + for (size_t i = 0; i < vertex_count; ++i) + { + assert(adjacency.offsets[i] >= adjacency.counts[i]); + + adjacency.offsets[i] -= adjacency.counts[i]; + } +} + static void computeBoundingSphere(float result[4], const float points[][3], size_t count) { assert(count > 0); @@ -82,13 +145,310 @@ static void computeBoundingSphere(float result[4], const float points[][3], size result[3] = radius; } +struct Cone +{ + float px, py, pz; + float nx, ny, nz; +}; + +static float getMeshletScore(float distance2, float spread, float cone_weight, float expected_radius) +{ + float cone = 1.f - spread * cone_weight; + float cone_clamped = cone < 1e-3f ? 1e-3f : cone; + + return (1 + sqrtf(distance2) / expected_radius * (1 - cone_weight)) * cone_clamped; +} + +static Cone getMeshletCone(const Cone& acc, unsigned int triangle_count) +{ + Cone result = acc; + + float center_scale = triangle_count == 0 ? 0.f : 1.f / float(triangle_count); + + result.px *= center_scale; + result.py *= center_scale; + result.pz *= center_scale; + + float axis_length = result.nx * result.nx + result.ny * result.ny + result.nz * result.nz; + float axis_scale = axis_length == 0.f ? 0.f : 1.f / sqrtf(axis_length); + + result.nx *= axis_scale; + result.ny *= axis_scale; + result.nz *= axis_scale; + + return result; +} + +static float computeTriangleCones(Cone* triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + (void)vertex_count; + + size_t vertex_stride_float = vertex_positions_stride / sizeof(float); + size_t face_count = index_count / 3; + + float mesh_area = 0; + + for (size_t i = 0; i < face_count; ++i) + { + unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + const float* p0 = vertex_positions + vertex_stride_float * a; + const float* p1 = vertex_positions + vertex_stride_float * b; + const float* p2 = vertex_positions + vertex_stride_float * c; + + float p10[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]}; + float p20[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]}; + + float normalx = p10[1] * p20[2] - p10[2] * p20[1]; + float normaly = p10[2] * p20[0] - p10[0] * p20[2]; + float normalz = p10[0] * p20[1] - p10[1] * p20[0]; + + float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz); + float invarea = (area == 0.f) ? 0.f : 1.f / area; + + triangles[i].px = (p0[0] + p1[0] + p2[0]) / 3.f; + triangles[i].py = (p0[1] + p1[1] + p2[1]) / 3.f; + triangles[i].pz = (p0[2] + p1[2] + p2[2]) / 3.f; + + triangles[i].nx = normalx * invarea; + triangles[i].ny = normaly * invarea; + triangles[i].nz = normalz * invarea; + + mesh_area += area; + } + + return mesh_area; +} + +static void finishMeshlet(meshopt_Meshlet& meshlet, unsigned char* meshlet_triangles) +{ + size_t offset = meshlet.triangle_offset + meshlet.triangle_count * 3; + + // fill 4b padding with 0 + while (offset & 3) + meshlet_triangles[offset++] = 0; +} + +static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int b, unsigned int c, unsigned char* used, meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t meshlet_offset, size_t max_vertices, size_t max_triangles) +{ + unsigned char& av = used[a]; + unsigned char& bv = used[b]; + unsigned char& cv = used[c]; + + bool result = false; + + unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff); + + if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles) + { + meshlets[meshlet_offset] = meshlet; + + for (size_t j = 0; j < meshlet.vertex_count; ++j) + used[meshlet_vertices[meshlet.vertex_offset + j]] = 0xff; + + finishMeshlet(meshlet, meshlet_triangles); + + meshlet.vertex_offset += meshlet.vertex_count; + meshlet.triangle_offset += (meshlet.triangle_count * 3 + 3) & ~3; // 4b padding + meshlet.vertex_count = 0; + meshlet.triangle_count = 0; + + result = true; + } + + if (av == 0xff) + { + av = (unsigned char)meshlet.vertex_count; + meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = a; + } + + if (bv == 0xff) + { + bv = (unsigned char)meshlet.vertex_count; + meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = b; + } + + if (cv == 0xff) + { + cv = (unsigned char)meshlet.vertex_count; + meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = c; + } + + meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 0] = av; + meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 1] = bv; + meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 2] = cv; + meshlet.triangle_count++; + + return result; +} + +struct KDNode +{ + union + { + float split; + unsigned int index; + }; + + // leaves: axis = 3, children = number of extra points after this one (0 if 'index' is the only point) + // branches: axis != 3, left subtree = skip 1, right subtree = skip 1+children + unsigned int axis : 2; + unsigned int children : 30; +}; + +static size_t kdtreePartition(unsigned int* indices, size_t count, const float* points, size_t stride, unsigned int axis, float pivot) +{ + size_t m = 0; + + // invariant: elements in range [0, m) are < pivot, elements in range [m, i) are >= pivot + for (size_t i = 0; i < count; ++i) + { + float v = points[indices[i] * stride + axis]; + + // swap(m, i) unconditionally + unsigned int t = indices[m]; + indices[m] = indices[i]; + indices[i] = t; + + // when v >= pivot, we swap i with m without advancing it, preserving invariants + m += v < pivot; + } + + return m; +} + +static size_t kdtreeBuildLeaf(size_t offset, KDNode* nodes, size_t node_count, unsigned int* indices, size_t count) +{ + assert(offset + count <= node_count); + (void)node_count; + + KDNode& result = nodes[offset]; + + result.index = indices[0]; + result.axis = 3; + result.children = unsigned(count - 1); + + // all remaining points are stored in nodes immediately following the leaf + for (size_t i = 1; i < count; ++i) + { + KDNode& tail = nodes[offset + i]; + + tail.index = indices[i]; + tail.axis = 3; + tail.children = ~0u >> 2; // bogus value to prevent misuse + } + + return offset + count; +} + +static size_t kdtreeBuild(size_t offset, KDNode* nodes, size_t node_count, const float* points, size_t stride, unsigned int* indices, size_t count, size_t leaf_size) +{ + assert(count > 0); + assert(offset < node_count); + + if (count <= leaf_size) + return kdtreeBuildLeaf(offset, nodes, node_count, indices, count); + + float mean[3] = {}; + float vars[3] = {}; + float runc = 1, runs = 1; + + // gather statistics on the points in the subtree using Welford's algorithm + for (size_t i = 0; i < count; ++i, runc += 1.f, runs = 1.f / runc) + { + const float* point = points + indices[i] * stride; + + for (int k = 0; k < 3; ++k) + { + float delta = point[k] - mean[k]; + mean[k] += delta * runs; + vars[k] += delta * (point[k] - mean[k]); + } + } + + // split axis is one where the variance is largest + unsigned int axis = vars[0] >= vars[1] && vars[0] >= vars[2] ? 0 : vars[1] >= vars[2] ? 1 + : 2; + + float split = mean[axis]; + size_t middle = kdtreePartition(indices, count, points, stride, axis, split); + + // when the partition is degenerate simply consolidate the points into a single node + if (middle <= leaf_size / 2 || middle >= count - leaf_size / 2) + return kdtreeBuildLeaf(offset, nodes, node_count, indices, count); + + KDNode& result = nodes[offset]; + + result.split = split; + result.axis = axis; + + // left subtree is right after our node + size_t next_offset = kdtreeBuild(offset + 1, nodes, node_count, points, stride, indices, middle, leaf_size); + + // distance to the right subtree is represented explicitly + result.children = unsigned(next_offset - offset - 1); + + return kdtreeBuild(next_offset, nodes, node_count, points, stride, indices + middle, count - middle, leaf_size); +} + +static void kdtreeNearest(KDNode* nodes, unsigned int root, const float* points, size_t stride, const unsigned char* emitted_flags, const float* position, unsigned int& result, float& limit) +{ + const KDNode& node = nodes[root]; + + if (node.axis == 3) + { + // leaf + for (unsigned int i = 0; i <= node.children; ++i) + { + unsigned int index = nodes[root + i].index; + + if (emitted_flags[index]) + continue; + + const float* point = points + index * stride; + + float distance2 = + (point[0] - position[0]) * (point[0] - position[0]) + + (point[1] - position[1]) * (point[1] - position[1]) + + (point[2] - position[2]) * (point[2] - position[2]); + float distance = sqrtf(distance2); + + if (distance < limit) + { + result = index; + limit = distance; + } + } + } + else + { + // branch; we order recursion to process the node that search position is in first + float delta = position[node.axis] - node.split; + unsigned int first = (delta <= 0) ? 0 : node.children; + unsigned int second = first ^ node.children; + + kdtreeNearest(nodes, root + 1 + first, points, stride, emitted_flags, position, result, limit); + + // only process the other node if it can have a match based on closest distance so far + if (fabsf(delta) <= limit) + kdtreeNearest(nodes, root + 1 + second, points, stride, emitted_flags, position, result, limit); + } +} + } // namespace meshopt size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles) { + using namespace meshopt; + assert(index_count % 3 == 0); - assert(max_vertices >= 3); - assert(max_triangles >= 1); + assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices); + assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles); + assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned + + (void)kMeshletMaxVertices; + (void)kMeshletMaxTriangles; // meshlet construction is limited by max vertices and max triangles per meshlet // the worst case is that the input is an unindexed stream since this equally stresses both limits @@ -100,77 +460,226 @@ size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_ return meshlet_limit_vertices > meshlet_limit_triangles ? meshlet_limit_vertices : meshlet_limit_triangles; } -size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles) +size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight) { + using namespace meshopt; + assert(index_count % 3 == 0); - assert(max_vertices >= 3); - assert(max_triangles >= 1); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices); + assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles); + assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned meshopt_Allocator allocator; - meshopt_Meshlet meshlet; - memset(&meshlet, 0, sizeof(meshlet)); + TriangleAdjacency2 adjacency = {}; + buildTriangleAdjacency(adjacency, indices, index_count, vertex_count, allocator); + + unsigned int* live_triangles = allocator.allocate<unsigned int>(vertex_count); + memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int)); + + size_t face_count = index_count / 3; + + unsigned char* emitted_flags = allocator.allocate<unsigned char>(face_count); + memset(emitted_flags, 0, face_count); + + // for each triangle, precompute centroid & normal to use for scoring + Cone* triangles = allocator.allocate<Cone>(face_count); + float mesh_area = computeTriangleCones(triangles, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride); + + // assuming each meshlet is a square patch, expected radius is sqrt(expected area) + float triangle_area_avg = face_count == 0 ? 0.f : mesh_area / float(face_count) * 0.5f; + float meshlet_expected_radius = sqrtf(triangle_area_avg * max_triangles) * 0.5f; + + // build a kd-tree for nearest neighbor lookup + unsigned int* kdindices = allocator.allocate<unsigned int>(face_count); + for (size_t i = 0; i < face_count; ++i) + kdindices[i] = unsigned(i); - assert(max_vertices <= sizeof(meshlet.vertices) / sizeof(meshlet.vertices[0])); - assert(max_triangles <= sizeof(meshlet.indices) / 3); + KDNode* nodes = allocator.allocate<KDNode>(face_count * 2); + kdtreeBuild(0, nodes, face_count * 2, &triangles[0].px, sizeof(Cone) / sizeof(float), kdindices, face_count, /* leaf_size= */ 8); // index of the vertex in the meshlet, 0xff if the vertex isn't used unsigned char* used = allocator.allocate<unsigned char>(vertex_count); memset(used, -1, vertex_count); - size_t offset = 0; + meshopt_Meshlet meshlet = {}; + size_t meshlet_offset = 0; - for (size_t i = 0; i < index_count; i += 3) - { - unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2]; - assert(a < vertex_count && b < vertex_count && c < vertex_count); + Cone meshlet_cone_acc = {}; - unsigned char& av = used[a]; - unsigned char& bv = used[b]; - unsigned char& cv = used[c]; + for (;;) + { + unsigned int best_triangle = ~0u; + unsigned int best_extra = 5; + float best_score = FLT_MAX; - unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff); + Cone meshlet_cone = getMeshletCone(meshlet_cone_acc, meshlet.triangle_count); - if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles) + for (size_t i = 0; i < meshlet.vertex_count; ++i) { - destination[offset++] = meshlet; + unsigned int index = meshlet_vertices[meshlet.vertex_offset + i]; + + unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index]; + size_t neighbours_size = adjacency.counts[index]; + + for (size_t j = 0; j < neighbours_size; ++j) + { + unsigned int triangle = neighbours[j]; + assert(!emitted_flags[triangle]); + + unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + unsigned int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff); + + // triangles that don't add new vertices to meshlets are max. priority + if (extra != 0) + { + // artificially increase the priority of dangling triangles as they're expensive to add to new meshlets + if (live_triangles[a] == 1 || live_triangles[b] == 1 || live_triangles[c] == 1) + extra = 0; + + extra++; + } + + // since topology-based priority is always more important than the score, we can skip scoring in some cases + if (extra > best_extra) + continue; + + const Cone& tri_cone = triangles[triangle]; + + float distance2 = + (tri_cone.px - meshlet_cone.px) * (tri_cone.px - meshlet_cone.px) + + (tri_cone.py - meshlet_cone.py) * (tri_cone.py - meshlet_cone.py) + + (tri_cone.pz - meshlet_cone.pz) * (tri_cone.pz - meshlet_cone.pz); - for (size_t j = 0; j < meshlet.vertex_count; ++j) - used[meshlet.vertices[j]] = 0xff; + float spread = tri_cone.nx * meshlet_cone.nx + tri_cone.ny * meshlet_cone.ny + tri_cone.nz * meshlet_cone.nz; - memset(&meshlet, 0, sizeof(meshlet)); + float score = getMeshletScore(distance2, spread, cone_weight, meshlet_expected_radius); + + // note that topology-based priority is always more important than the score + // this helps maintain reasonable effectiveness of meshlet data and reduces scoring cost + if (extra < best_extra || score < best_score) + { + best_triangle = triangle; + best_extra = extra; + best_score = score; + } + } } - if (av == 0xff) + if (best_triangle == ~0u) { - av = meshlet.vertex_count; - meshlet.vertices[meshlet.vertex_count++] = a; + float position[3] = {meshlet_cone.px, meshlet_cone.py, meshlet_cone.pz}; + unsigned int index = ~0u; + float limit = FLT_MAX; + + kdtreeNearest(nodes, 0, &triangles[0].px, sizeof(Cone) / sizeof(float), emitted_flags, position, index, limit); + + best_triangle = index; } - if (bv == 0xff) + if (best_triangle == ~0u) + break; + + unsigned int a = indices[best_triangle * 3 + 0], b = indices[best_triangle * 3 + 1], c = indices[best_triangle * 3 + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + // add meshlet to the output; when the current meshlet is full we reset the accumulated bounds + if (appendMeshlet(meshlet, a, b, c, used, meshlets, meshlet_vertices, meshlet_triangles, meshlet_offset, max_vertices, max_triangles)) { - bv = meshlet.vertex_count; - meshlet.vertices[meshlet.vertex_count++] = b; + meshlet_offset++; + memset(&meshlet_cone_acc, 0, sizeof(meshlet_cone_acc)); } - if (cv == 0xff) + live_triangles[a]--; + live_triangles[b]--; + live_triangles[c]--; + + // remove emitted triangle from adjacency data + // this makes sure that we spend less time traversing these lists on subsequent iterations + for (size_t k = 0; k < 3; ++k) { - cv = meshlet.vertex_count; - meshlet.vertices[meshlet.vertex_count++] = c; + unsigned int index = indices[best_triangle * 3 + k]; + + unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index]; + size_t neighbours_size = adjacency.counts[index]; + + for (size_t i = 0; i < neighbours_size; ++i) + { + unsigned int tri = neighbours[i]; + + if (tri == best_triangle) + { + neighbours[i] = neighbours[neighbours_size - 1]; + adjacency.counts[index]--; + break; + } + } } - meshlet.indices[meshlet.triangle_count][0] = av; - meshlet.indices[meshlet.triangle_count][1] = bv; - meshlet.indices[meshlet.triangle_count][2] = cv; - meshlet.triangle_count++; + // update aggregated meshlet cone data for scoring subsequent triangles + meshlet_cone_acc.px += triangles[best_triangle].px; + meshlet_cone_acc.py += triangles[best_triangle].py; + meshlet_cone_acc.pz += triangles[best_triangle].pz; + meshlet_cone_acc.nx += triangles[best_triangle].nx; + meshlet_cone_acc.ny += triangles[best_triangle].ny; + meshlet_cone_acc.nz += triangles[best_triangle].nz; + + emitted_flags[best_triangle] = 1; + } + + if (meshlet.triangle_count) + { + finishMeshlet(meshlet, meshlet_triangles); + + meshlets[meshlet_offset++] = meshlet; + } + + assert(meshlet_offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles)); + return meshlet_offset; +} + +size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + + assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices); + assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles); + assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned + + meshopt_Allocator allocator; + + // index of the vertex in the meshlet, 0xff if the vertex isn't used + unsigned char* used = allocator.allocate<unsigned char>(vertex_count); + memset(used, -1, vertex_count); + + meshopt_Meshlet meshlet = {}; + size_t meshlet_offset = 0; + + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + // appends triangle to the meshlet and writes previous meshlet to the output if full + meshlet_offset += appendMeshlet(meshlet, a, b, c, used, meshlets, meshlet_vertices, meshlet_triangles, meshlet_offset, max_vertices, max_triangles); } if (meshlet.triangle_count) - destination[offset++] = meshlet; + { + finishMeshlet(meshlet, meshlet_triangles); - assert(offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles)); + meshlets[meshlet_offset++] = meshlet; + } - return offset; + assert(meshlet_offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles)); + return meshlet_offset; } meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) @@ -178,18 +687,17 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t using namespace meshopt; assert(index_count % 3 == 0); + assert(index_count / 3 <= kMeshletMaxTriangles); assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); assert(vertex_positions_stride % sizeof(float) == 0); - assert(index_count / 3 <= 256); - (void)vertex_count; size_t vertex_stride_float = vertex_positions_stride / sizeof(float); // compute triangle normals and gather triangle corners - float normals[256][3]; - float corners[256][3][3]; + float normals[kMeshletMaxTriangles][3]; + float corners[kMeshletMaxTriangles][3][3]; size_t triangles = 0; for (size_t i = 0; i < index_count; i += 3) @@ -327,25 +835,23 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t return bounds; } -meshopt_Bounds meshopt_computeMeshletBounds(const meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) { + using namespace meshopt; + + assert(triangle_count <= kMeshletMaxTriangles); assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); assert(vertex_positions_stride % sizeof(float) == 0); - unsigned int indices[sizeof(meshlet->indices) / sizeof(meshlet->indices[0][0])]; + unsigned int indices[kMeshletMaxTriangles * 3]; - for (size_t i = 0; i < meshlet->triangle_count; ++i) + for (size_t i = 0; i < triangle_count * 3; ++i) { - unsigned int a = meshlet->vertices[meshlet->indices[i][0]]; - unsigned int b = meshlet->vertices[meshlet->indices[i][1]]; - unsigned int c = meshlet->vertices[meshlet->indices[i][2]]; - - assert(a < vertex_count && b < vertex_count && c < vertex_count); + unsigned int index = meshlet_vertices[meshlet_triangles[i]]; + assert(index < vertex_count); - indices[i * 3 + 0] = a; - indices[i * 3 + 1] = b; - indices[i * 3 + 2] = c; + indices[i] = index; } - return meshopt_computeClusterBounds(indices, meshlet->triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride); + return meshopt_computeClusterBounds(indices, triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride); } diff --git a/thirdparty/meshoptimizer/indexgenerator.cpp b/thirdparty/meshoptimizer/indexgenerator.cpp index aa4a30efa4..f60db0dc4f 100644 --- a/thirdparty/meshoptimizer/indexgenerator.cpp +++ b/thirdparty/meshoptimizer/indexgenerator.cpp @@ -4,6 +4,8 @@ #include <assert.h> #include <string.h> +// This work is based on: +// John McDonald, Mark Kilgard. Crack-Free Point-Normal Triangles using Adjacent Edge Normals. 2010 namespace meshopt { @@ -83,10 +85,49 @@ struct VertexStreamHasher } }; +struct EdgeHasher +{ + const unsigned int* remap; + + size_t hash(unsigned long long edge) const + { + unsigned int e0 = unsigned(edge >> 32); + unsigned int e1 = unsigned(edge); + + unsigned int h1 = remap[e0]; + unsigned int h2 = remap[e1]; + + const unsigned int m = 0x5bd1e995; + + // MurmurHash64B finalizer + h1 ^= h2 >> 18; + h1 *= m; + h2 ^= h1 >> 22; + h2 *= m; + h1 ^= h2 >> 17; + h1 *= m; + h2 ^= h1 >> 19; + h2 *= m; + + return h2; + } + + bool equal(unsigned long long lhs, unsigned long long rhs) const + { + unsigned int l0 = unsigned(lhs >> 32); + unsigned int l1 = unsigned(lhs); + + unsigned int r0 = unsigned(rhs >> 32); + unsigned int r1 = unsigned(rhs); + + return remap[l0] == remap[r0] && remap[l1] == remap[r1]; + } +}; + static size_t hashBuckets(size_t count) { size_t buckets = 1; - while (buckets < count) + while (buckets < count + count / 4) buckets *= 2; return buckets; @@ -119,6 +160,26 @@ static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, c return 0; } +static void buildPositionRemap(unsigned int* remap, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator) +{ + VertexHasher vertex_hasher = {reinterpret_cast<const unsigned char*>(vertex_positions), 3 * sizeof(float), vertex_positions_stride}; + + size_t vertex_table_size = hashBuckets(vertex_count); + unsigned int* vertex_table = allocator.allocate<unsigned int>(vertex_table_size); + memset(vertex_table, -1, vertex_table_size * sizeof(unsigned int)); + + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned int index = unsigned(i); + unsigned int* entry = hashLookup(vertex_table, vertex_table_size, vertex_hasher, index, ~0u); + + if (*entry == ~0u) + *entry = index; + + remap[index] = *entry; + } +} + } // namespace meshopt size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) @@ -345,3 +406,146 @@ void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const uns destination[i] = remap[index]; } } + +void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + meshopt_Allocator allocator; + + static const int next[4] = {1, 2, 0, 1}; + + // build position remap: for each vertex, which other (canonical) vertex does it map to? + unsigned int* remap = allocator.allocate<unsigned int>(vertex_count); + buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator); + + // build edge set; this stores all triangle edges but we can look these up by any other wedge + EdgeHasher edge_hasher = {remap}; + + size_t edge_table_size = hashBuckets(index_count); + unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size); + unsigned int* edge_vertex_table = allocator.allocate<unsigned int>(edge_table_size); + + memset(edge_table, -1, edge_table_size * sizeof(unsigned long long)); + memset(edge_vertex_table, -1, edge_table_size * sizeof(unsigned int)); + + for (size_t i = 0; i < index_count; i += 3) + { + for (int e = 0; e < 3; ++e) + { + unsigned int i0 = indices[i + e]; + unsigned int i1 = indices[i + next[e]]; + unsigned int i2 = indices[i + next[e + 1]]; + assert(i0 < vertex_count && i1 < vertex_count && i2 < vertex_count); + + unsigned long long edge = ((unsigned long long)i0 << 32) | i1; + unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull); + + if (*entry == ~0ull) + { + *entry = edge; + + // store vertex opposite to the edge + edge_vertex_table[entry - edge_table] = i2; + } + } + } + + // build resulting index buffer: 6 indices for each input triangle + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int patch[6]; + + for (int e = 0; e < 3; ++e) + { + unsigned int i0 = indices[i + e]; + unsigned int i1 = indices[i + next[e]]; + assert(i0 < vertex_count && i1 < vertex_count); + + // note: this refers to the opposite edge! + unsigned long long edge = ((unsigned long long)i1 << 32) | i0; + unsigned long long* oppe = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull); + + patch[e * 2 + 0] = i0; + patch[e * 2 + 1] = (*oppe == ~0ull) ? i0 : edge_vertex_table[oppe - edge_table]; + } + + memcpy(destination + i * 2, patch, sizeof(patch)); + } +} + +void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + meshopt_Allocator allocator; + + static const int next[3] = {1, 2, 0}; + + // build position remap: for each vertex, which other (canonical) vertex does it map to? + unsigned int* remap = allocator.allocate<unsigned int>(vertex_count); + buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator); + + // build edge set; this stores all triangle edges but we can look these up by any other wedge + EdgeHasher edge_hasher = {remap}; + + size_t edge_table_size = hashBuckets(index_count); + unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size); + memset(edge_table, -1, edge_table_size * sizeof(unsigned long long)); + + for (size_t i = 0; i < index_count; i += 3) + { + for (int e = 0; e < 3; ++e) + { + unsigned int i0 = indices[i + e]; + unsigned int i1 = indices[i + next[e]]; + assert(i0 < vertex_count && i1 < vertex_count); + + unsigned long long edge = ((unsigned long long)i0 << 32) | i1; + unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull); + + if (*entry == ~0ull) + *entry = edge; + } + } + + // build resulting index buffer: 12 indices for each input triangle + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int patch[12]; + + for (int e = 0; e < 3; ++e) + { + unsigned int i0 = indices[i + e]; + unsigned int i1 = indices[i + next[e]]; + assert(i0 < vertex_count && i1 < vertex_count); + + // note: this refers to the opposite edge! + unsigned long long edge = ((unsigned long long)i1 << 32) | i0; + unsigned long long oppe = *hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull); + + // use the same edge if opposite edge doesn't exist (border) + oppe = (oppe == ~0ull) ? edge : oppe; + + // triangle index (0, 1, 2) + patch[e] = i0; + + // opposite edge (3, 4; 5, 6; 7, 8) + patch[3 + e * 2 + 0] = unsigned(oppe); + patch[3 + e * 2 + 1] = unsigned(oppe >> 32); + + // dominant vertex (9, 10, 11) + patch[9 + e] = remap[i0]; + } + + memcpy(destination + i * 4, patch, sizeof(patch)); + } +} diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h index 1714000384..fe8d349731 100644 --- a/thirdparty/meshoptimizer/meshoptimizer.h +++ b/thirdparty/meshoptimizer/meshoptimizer.h @@ -1,7 +1,7 @@ /** - * meshoptimizer - version 0.15 + * meshoptimizer - version 0.16 * - * Copyright (C) 2016-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://github.com/zeux/meshoptimizer * * This library is distributed under the MIT License. See notice at the end of this file. @@ -12,7 +12,7 @@ #include <stddef.h> /* Version macro; major * 1000 + minor * 10 + patch */ -#define MESHOPTIMIZER_VERSION 150 /* 0.15 */ +#define MESHOPTIMIZER_VERSION 160 /* 0.16 */ /* If no API is defined, assume default */ #ifndef MESHOPTIMIZER_API @@ -98,6 +98,35 @@ MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destinati MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count); /** + * Generate index buffer that can be used as a geometry shader input with triangle adjacency topology + * Each triangle is converted into a 6-vertex patch with the following layout: + * - 0, 2, 4: original triangle vertices + * - 1, 3, 5: vertices adjacent to edges 02, 24 and 40 + * The resulting patch can be rendered with geometry shaders using e.g. VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY. + * This can be used to implement algorithms like silhouette detection/expansion and other forms of GS-driven rendering. + * + * destination must contain enough space for the resulting index buffer (index_count*2 elements) + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + +/** + * Generate index buffer that can be used for PN-AEN tessellation with crack-free displacement + * Each triangle is converted into a 12-vertex patch with the following layout: + * - 0, 1, 2: original triangle vertices + * - 3, 4: opposing edge for edge 0, 1 + * - 5, 6: opposing edge for edge 1, 2 + * - 7, 8: opposing edge for edge 2, 0 + * - 9, 10, 11: dominant vertices for corners 0, 1, 2 + * The resulting patch can be rendered with hardware tessellation using PN-AEN and displacement mapping. + * See "Tessellation on Any Budget" (John McDonald, GDC 2011) for implementation details. + * + * destination must contain enough space for the resulting index buffer (index_count*4 elements) + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + +/** * Vertex transform cache optimizer * Reorders indices to reduce the number of GPU vertex shader invocations * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually. @@ -373,22 +402,31 @@ MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetc struct meshopt_Meshlet { - unsigned int vertices[64]; - unsigned char indices[126][3]; - unsigned char triangle_count; - unsigned char vertex_count; + /* offsets within meshlet_vertices and meshlet_triangles arrays with meshlet data */ + unsigned int vertex_offset; + unsigned int triangle_offset; + + /* number of vertices and triangles used in the meshlet; data is stored in consecutive range defined by offset and count */ + unsigned int vertex_count; + unsigned int triangle_count; }; /** * Experimental: Meshlet builder * Splits the mesh into a set of meshlets where each meshlet has a micro index buffer indexing into meshlet vertices that refer to the original vertex buffer * The resulting data can be used to render meshes using NVidia programmable mesh shading pipeline, or in other cluster-based renderers. - * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first. + * When using buildMeshlets, vertex positions need to be provided to minimize the size of the resulting clusters. + * When using buildMeshletsScan, for maximum efficiency the index buffer being converted has to be optimized for vertex cache first. * - * destination must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound - * max_vertices and max_triangles can't exceed limits statically declared in meshopt_Meshlet (max_vertices <= 64, max_triangles <= 126) + * meshlets must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound + * meshlet_vertices must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices + * meshlet_triangles must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3 + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + * max_vertices and max_triangles must not exceed implementation limits (max_vertices <= 255 - not 256!, max_triangles <= 512) + * cone_weight should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency */ -MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsScan(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles); struct meshopt_Bounds @@ -426,10 +464,10 @@ struct meshopt_Bounds * to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable. * * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer - * index_count should be less than or equal to 256*3 (the function assumes clusters of limited size) + * index_count/3 should be less than or equal to 512 (the function assumes clusters of limited size) */ MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); -MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const struct meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); /** * Experimental: Spatial sorter @@ -513,6 +551,10 @@ inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, template <typename T> inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count); template <typename T> +inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +template <typename T> +inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +template <typename T> inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count); template <typename T> inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count); @@ -547,7 +589,9 @@ inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size template <typename T> inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size); template <typename T> -inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); +inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight); +template <typename T> +inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); template <typename T> inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); template <typename T> @@ -762,6 +806,24 @@ inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indi } template <typename T> +inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count * 2); + + meshopt_generateAdjacencyIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); +} + +template <typename T> +inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count * 4); + + meshopt_generateTessellationIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); +} + +template <typename T> inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count) { meshopt_IndexAdapter<T> in(0, indices, index_count); @@ -908,11 +970,19 @@ inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices } template <typename T> -inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles) +inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_buildMeshlets(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, max_vertices, max_triangles, cone_weight); +} + +template <typename T> +inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles) { meshopt_IndexAdapter<T> in(0, indices, index_count); - return meshopt_buildMeshlets(destination, in.data, index_count, vertex_count, max_vertices, max_triangles); + return meshopt_buildMeshletsScan(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_count, max_vertices, max_triangles); } template <typename T> @@ -934,7 +1004,7 @@ inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_ #endif /** - * Copyright (c) 2016-2020 Arseny Kapoulkine + * Copyright (c) 2016-2021 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp index 942db14461..b2cb589462 100644 --- a/thirdparty/meshoptimizer/simplifier.cpp +++ b/thirdparty/meshoptimizer/simplifier.cpp @@ -131,7 +131,7 @@ struct PositionHasher static size_t hashBuckets2(size_t count) { size_t buckets = 1; - while (buckets < count) + while (buckets < count + count / 4) buckets *= 2; return buckets; diff --git a/thirdparty/meshoptimizer/vertexcodec.cpp b/thirdparty/meshoptimizer/vertexcodec.cpp index 2cbfaac367..5f3ec204ab 100644 --- a/thirdparty/meshoptimizer/vertexcodec.cpp +++ b/thirdparty/meshoptimizer/vertexcodec.cpp @@ -710,18 +710,12 @@ static v128_t decodeShuffleMask(unsigned char mask0, unsigned char mask1) SIMD_TARGET static void wasmMoveMask(v128_t mask, unsigned char& mask0, unsigned char& mask1) { - v128_t mask_0 = wasm_v32x4_shuffle(mask, mask, 0, 2, 1, 3); - - uint64_t mask_1a = wasm_i64x2_extract_lane(mask_0, 0) & 0x0804020108040201ull; - uint64_t mask_1b = wasm_i64x2_extract_lane(mask_0, 1) & 0x8040201080402010ull; + // magic constant found using z3 SMT assuming mask has 8 groups of 0xff or 0x00 + const uint64_t magic = 0x000103070f1f3f80ull; // TODO: This can use v8x16_bitmask in the future - uint64_t mask_2 = mask_1a | mask_1b; - uint64_t mask_4 = mask_2 | (mask_2 >> 16); - uint64_t mask_8 = mask_4 | (mask_4 >> 8); - - mask0 = uint8_t(mask_8); - mask1 = uint8_t(mask_8 >> 32); + mask0 = uint8_t((wasm_i64x2_extract_lane(mask, 0) * magic) >> 56); + mask1 = uint8_t((wasm_i64x2_extract_lane(mask, 1) * magic) >> 56); } SIMD_TARGET |