Path: blob/master/thirdparty/basis_universal/encoder/basisu_pvrtc1_4.cpp
9903 views
// basisu_pvrtc1_4.cpp1// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14#include "basisu_pvrtc1_4.h"1516namespace basisu17{18#if 019static const uint8_t g_pvrtc_5[32] = { 0,8,16,24,33,41,49,57,66,74,82,90,99,107,115,123,132,140,148,156,165,173,181,189,198,206,214,222,231,239,247,255 };20static const uint8_t g_pvrtc_4[16] = { 0,16,33,49,66,82,99,115,140,156,173,189,206,222,239,255 };21static const uint8_t g_pvrtc_3[8] = { 0,33,74,107,148,181,222,255 };22static const uint8_t g_pvrtc_alpha[9] = { 0,34,68,102,136,170,204,238,255 };23#endif2425static const uint8_t g_pvrtc_5_nearest[256] = { 0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31 };26static const uint8_t g_pvrtc_4_nearest[256] = { 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15 };27#if 028static const uint8_t g_pvrtc_3_nearest[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 };29static const uint8_t g_pvrtc_alpha_nearest[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8 };30#endif3132#if 033static const uint8_t g_pvrtc_5_floor[256] =34{350,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,363,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,377,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,3811,11,11,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,3915,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,4019,19,19,19,19,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,4123,23,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,4227,27,27,27,27,27,27,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,3143};4445static const uint8_t g_pvrtc_5_ceil[256] =46{470,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,484,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,498,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,12,12,12,12,12,5012,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,5116,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,5220,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,5324,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,5428,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,3155};5657static const uint8_t g_pvrtc_4_floor[256] =58{590,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,601,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,613,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,625,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,637,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,649,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,6511,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,6613,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,1567};6869static const uint8_t g_pvrtc_4_ceil[256] =70{710,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,722,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,734,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,746,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,758,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,7610,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,7712,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,7814,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,1579};8081static const uint8_t g_pvrtc_3_floor[256] =82{830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,840,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,851,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,862,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,873,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,884,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,895,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,906,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,791};9293static const uint8_t g_pvrtc_3_ceil[256] =94{950,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,961,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,972,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,983,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,994,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,1005,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,1016,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,1027,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7103};104105static const uint8_t g_pvrtc_alpha_floor[256] =106{1070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1080,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1091,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1102,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1113,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1124,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1135,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,1146,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8115};116117static const uint8_t g_pvrtc_alpha_ceil[256] =118{1190,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1201,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1212,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1223,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1234,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1245,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,1256,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1267,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8127};128#endif129130uint32_t pvrtc4_swizzle_uv(uint32_t width, uint32_t height, uint32_t x, uint32_t y)131{132assert((x < width) && (y < height) && basisu::is_pow2(height) && basisu::is_pow2(width));133134uint32_t min_d = width, max_v = y;135if (height < width)136{137min_d = height;138max_v = x;139}140141// Interleave the XY LSB's142uint32_t shift_ofs = 0, swizzled = 0;143for (uint32_t s_bit = 1, d_bit = 1; s_bit < min_d; s_bit <<= 1, d_bit <<= 2, ++shift_ofs)144{145if (y & s_bit) swizzled |= d_bit;146if (x & s_bit) swizzled |= (2 * d_bit);147}148149max_v >>= shift_ofs;150151// OR in the rest of the bits from the largest dimension152swizzled |= (max_v << (2 * shift_ofs));153154return swizzled;155}156157color_rgba pvrtc4_block::get_endpoint(uint32_t endpoint_index, bool unpack) const158{159assert(endpoint_index < 2);160const uint32_t packed = m_endpoints >> (endpoint_index * 16);161162uint32_t r, g, b, a;163if (packed & 0x8000)164{165// opaque 554 or 555166if (!endpoint_index)167{168r = (packed >> 10) & 31;169g = (packed >> 5) & 31;170b = (packed >> 1) & 15;171172if (unpack)173{174b = (b << 1) | (b >> 3);175}176}177else178{179r = (packed >> 10) & 31;180g = (packed >> 5) & 31;181b = packed & 31;182}183184a = unpack ? 255 : 7;185}186else187{188// translucent 4433 or 4443189if (!endpoint_index)190{191a = (packed >> 12) & 7;192r = (packed >> 8) & 15;193g = (packed >> 4) & 15;194b = (packed >> 1) & 7;195196if (unpack)197{198a = (a << 1);199a = (a << 4) | a;200201r = (r << 1) | (r >> 3);202g = (g << 1) | (g >> 3);203b = (b << 2) | (b >> 1);204}205}206else207{208a = (packed >> 12) & 7;209r = (packed >> 8) & 15;210g = (packed >> 4) & 15;211b = packed & 15;212213if (unpack)214{215a = (a << 1);216a = (a << 4) | a;217218r = (r << 1) | (r >> 3);219g = (g << 1) | (g >> 3);220b = (b << 1) | (b >> 3);221}222}223}224225if (unpack)226{227r = (r << 3) | (r >> 2);228g = (g << 3) | (g >> 2);229b = (b << 3) | (b >> 2);230}231232assert((r < 256) && (g < 256) && (b < 256) && (a < 256));233234return color_rgba(r, g, b, a);235}236237color_rgba pvrtc4_block::get_endpoint_5554(uint32_t endpoint_index) const238{239assert(endpoint_index < 2);240const uint32_t packed = m_endpoints >> (endpoint_index * 16);241242uint32_t r, g, b, a;243if (packed & 0x8000)244{245// opaque 554 or 555246if (!endpoint_index)247{248r = (packed >> 10) & 31;249g = (packed >> 5) & 31;250b = (packed >> 1) & 15;251252b = (b << 1) | (b >> 3);253}254else255{256r = (packed >> 10) & 31;257g = (packed >> 5) & 31;258b = packed & 31;259}260261a = 15;262}263else264{265// translucent 4433 or 4443266if (!endpoint_index)267{268a = (packed >> 12) & 7;269r = (packed >> 8) & 15;270g = (packed >> 4) & 15;271b = (packed >> 1) & 7;272273a = a << 1;274275r = (r << 1) | (r >> 3);276g = (g << 1) | (g >> 3);277b = (b << 2) | (b >> 1);278}279else280{281a = (packed >> 12) & 7;282r = (packed >> 8) & 15;283g = (packed >> 4) & 15;284b = packed & 15;285286a = a << 1;287288r = (r << 1) | (r >> 3);289g = (g << 1) | (g >> 3);290b = (b << 1) | (b >> 3);291}292}293294assert((r < 32) && (g < 32) && (b < 32) && (a < 16));295296return color_rgba(r, g, b, a);297}298299bool pvrtc4_image::get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const300{301assert((x < m_width) && (y < m_height));302303int block_x0 = (static_cast<int>(x) - 2) >> 2;304int block_x1 = block_x0 + 1;305int block_y0 = (static_cast<int>(y) - 2) >> 2;306int block_y1 = block_y0 + 1;307308block_x0 = posmod(block_x0, m_block_width);309block_x1 = posmod(block_x1, m_block_width);310block_y0 = posmod(block_y0, m_block_height);311block_y1 = posmod(block_y1, m_block_height);312313pColors[0] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));314pColors[3] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));315316if (get_block_uses_transparent_modulation(x >> 2, y >> 2))317{318for (uint32_t c = 0; c < 4; c++)319{320uint32_t m = (pColors[0][c] + pColors[3][c]) / 2;321pColors[1][c] = static_cast<uint8_t>(m);322pColors[2][c] = static_cast<uint8_t>(m);323}324pColors[2][3] = 0;325return true;326}327328for (uint32_t c = 0; c < 4; c++)329{330pColors[1][c] = static_cast<uint8_t>((pColors[0][c] * 5 + pColors[3][c] * 3) / 8);331pColors[2][c] = static_cast<uint8_t>((pColors[0][c] * 3 + pColors[3][c] * 5) / 8);332}333334return false;335}336337color_rgba pvrtc4_image::get_pixel(uint32_t x, uint32_t y, uint32_t m) const338{339assert((x < m_width) && (y < m_height));340341int block_x0 = (static_cast<int>(x) - 2) >> 2;342int block_x1 = block_x0 + 1;343int block_y0 = (static_cast<int>(y) - 2) >> 2;344int block_y1 = block_y0 + 1;345346block_x0 = posmod(block_x0, m_block_width);347block_x1 = posmod(block_x1, m_block_width);348block_y0 = posmod(block_y0, m_block_height);349block_y1 = posmod(block_y1, m_block_height);350351if (get_block_uses_transparent_modulation(x >> 2, y >> 2))352{353if (m == 0)354return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));355else if (m == 3)356return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));357358color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));359color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));360361return color_rgba((l[0] + h[0]) / 2, (l[1] + h[1]) / 2, (l[2] + h[2]) / 2, (m == 2) ? 0 : (l[3] + h[3]) / 2);362}363else364{365if (m == 0)366return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));367else if (m == 3)368return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));369370color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));371color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));372373if (m == 2)374return color_rgba((l[0] * 3 + h[0] * 5) / 8, (l[1] * 3 + h[1] * 5) / 8, (l[2] * 3 + h[2] * 5) / 8, (l[3] * 3 + h[3] * 5) / 8);375else376return color_rgba((l[0] * 5 + h[0] * 3) / 8, (l[1] * 5 + h[1] * 3) / 8, (l[2] * 5 + h[2] * 3) / 8, (l[3] * 5 + h[3] * 3) / 8);377}378}379380uint64_t pvrtc4_image::local_endpoint_optimization_opaque(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual)381{382uint64_t initial_error = evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false);383if (!initial_error)384return initial_error;385386vec3F c_avg_orig(0);387388for (int y = 0; y < 7; y++)389{390const uint32_t py = wrap_y(by * 4 + y - 1);391for (uint32_t x = 0; x < 7; x++)392{393const uint32_t px = wrap_x(bx * 4 + x - 1);394395const color_rgba& c = orig_img(px, py);396397c_avg_orig[0] += c[0];398c_avg_orig[1] += c[1];399c_avg_orig[2] += c[2];400}401}402403c_avg_orig *= 1.0f / 49.0f;404405vec3F quant_colors[2];406quant_colors[0].set(c_avg_orig);407quant_colors[0] -= vec3F(.0125f);408409quant_colors[1].set(c_avg_orig);410quant_colors[1] += vec3F(.0125f);411412float total_weight[2];413414bool success = true;415416for (uint32_t pass = 0; pass < 4; pass++)417{418vec3F new_colors[2] = { vec3F(0), vec3F(0) };419memset(total_weight, 0, sizeof(total_weight));420421static const float s_weights[7][7] =422{423{ 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f },424{ 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },425{ 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },426{ 2.242640f, 3.242640f, 4.242640f, 5.000000f, 4.242640f, 3.242640f, 2.242640f },427{ 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },428{ 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },429{ 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f }430};431432for (int y = 0; y < 7; y++)433{434const uint32_t py = wrap_y(by * 4 + y - 1);435for (uint32_t x = 0; x < 7; x++)436{437const uint32_t px = wrap_x(bx * 4 + x - 1);438439const color_rgba& orig_c = orig_img(px, py);440441vec3F color(orig_c[0], orig_c[1], orig_c[2]);442443uint32_t c = quant_colors[0].squared_distance(color) > quant_colors[1].squared_distance(color);444445const float weight = s_weights[y][x];446new_colors[c] += color * weight;447448total_weight[c] += weight;449}450}451452if (!total_weight[0] || !total_weight[1])453success = false;454455quant_colors[0] = new_colors[0] / (float)total_weight[0];456quant_colors[1] = new_colors[1] / (float)total_weight[1];457}458459if (!success)460{461quant_colors[0] = c_avg_orig;462quant_colors[1] = c_avg_orig;463}464465vec4F colors[2] = { quant_colors[0], quant_colors[1] };466467colors[0] += vec3F(.5f);468colors[1] += vec3F(.5f);469color_rgba color_0((int)colors[0][0], (int)colors[0][1], (int)colors[0][2], 0);470color_rgba color_1((int)colors[1][0], (int)colors[1][1], (int)colors[1][2], 0);471472pvrtc4_block cur_blocks[3][3];473474for (int y = -1; y <= 1; y++)475{476for (int x = -1; x <= 1; x++)477{478const uint32_t block_x = wrap_block_x(bx + x);479const uint32_t block_y = wrap_block_y(by + y);480cur_blocks[x + 1][y + 1] = m_blocks(block_x, block_y);481}482}483484color_rgba l1(0), h1(0);485486l1[0] = g_pvrtc_5_nearest[color_0[0]];487h1[0] = g_pvrtc_5_nearest[color_1[0]];488489l1[1] = g_pvrtc_5_nearest[color_0[1]];490h1[1] = g_pvrtc_5_nearest[color_1[1]];491492l1[2] = g_pvrtc_4_nearest[color_0[2]];493h1[2] = g_pvrtc_5_nearest[color_0[2]];494495l1[3] = 0;496h1[3] = 0;497498m_blocks(bx, by).set_endpoint_raw(0, l1, true);499m_blocks(bx, by).set_endpoint_raw(1, h1, true);500501uint64_t e03_err_0 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);502503pvrtc4_block blocks0[3][3];504for (int y = -1; y <= 1; y++)505{506for (int x = -1; x <= 1; x++)507{508const uint32_t block_x = wrap_block_x(bx + x);509const uint32_t block_y = wrap_block_y(by + y);510blocks0[x + 1][y + 1] = m_blocks(block_x, block_y);511}512}513514l1[0] = g_pvrtc_5_nearest[color_1[0]];515h1[0] = g_pvrtc_5_nearest[color_0[0]];516517l1[1] = g_pvrtc_5_nearest[color_1[1]];518h1[1] = g_pvrtc_5_nearest[color_0[1]];519520l1[2] = g_pvrtc_4_nearest[color_1[2]];521h1[2] = g_pvrtc_5_nearest[color_0[2]];522523l1[3] = 0;524h1[3] = 0;525526m_blocks(bx, by).set_endpoint_raw(0, l1, true);527m_blocks(bx, by).set_endpoint_raw(1, h1, true);528529uint64_t e03_err_1 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);530531if (initial_error < basisu::minimum(e03_err_0, e03_err_1))532{533for (int y = -1; y <= 1; y++)534{535for (int x = -1; x <= 1; x++)536{537const uint32_t block_x = wrap_block_x(bx + x);538const uint32_t block_y = wrap_block_y(by + y);539m_blocks(block_x, block_y) = cur_blocks[x + 1][y + 1];540}541}542return initial_error;543}544else if (e03_err_0 < e03_err_1)545{546for (int y = -1; y <= 1; y++)547{548for (int x = -1; x <= 1; x++)549{550const uint32_t block_x = wrap_block_x(bx + x);551const uint32_t block_y = wrap_block_y(by + y);552m_blocks(block_x, block_y) = blocks0[x + 1][y + 1];553}554}555assert(e03_err_0 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));556return e03_err_0;557}558559assert(e03_err_1 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));560return e03_err_1;561}562563} // basisu564565566