1// basisu_pvrtc1_4.cpp
2// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15#include "basisu_pvrtc1_4.h"
16
17namespace basisu
18{
19#if 0
20 static 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 };
21 static const uint8_t g_pvrtc_4[16] = { 0,16,33,49,66,82,99,115,140,156,173,189,206,222,239,255 };
22 static const uint8_t g_pvrtc_3[8] = { 0,33,74,107,148,181,222,255 };
23 static const uint8_t g_pvrtc_alpha[9] = { 0,34,68,102,136,170,204,238,255 };
24#endif
25
26 static 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 };
27 static 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 };
28#if 0
29 static 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 };
30 static 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 };
31#endif
32
33#if 0
34 static const uint8_t g_pvrtc_5_floor[256] =
35 {
36 0,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,
37 3,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,
38 7,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,
39 11,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,
40 15,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,
41 19,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,
42 23,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,
43 27,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,31
44 };
45
46 static const uint8_t g_pvrtc_5_ceil[256] =
47 {
48 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,
49 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,
50 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,
51 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,
52 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,
53 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,
54 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,
55 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,31,31,31,31
56 };
57
58 static const uint8_t g_pvrtc_4_floor[256] =
59 {
60 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,
61 1,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,
62 3,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,
63 5,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,
64 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,9,9,9,9,
65 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,11,11,11,
66 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,13,13,
67 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,15
68 };
69
70 static const uint8_t g_pvrtc_4_ceil[256] =
71 {
72 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,
73 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,
74 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,
75 6,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,
76 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,
77 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,
78 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,
79 14,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,15
80 };
81
82 static const uint8_t g_pvrtc_3_floor[256] =
83 {
84 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,0,
85 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,
86 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,
87 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,
88 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,
89 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,
90 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,
91 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
92 };
93
94 static const uint8_t g_pvrtc_3_ceil[256] =
95 {
96 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,
97 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,
98 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,
99 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,
100 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,
101 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,
102 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,
103 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,7,7
104 };
105
106 static const uint8_t g_pvrtc_alpha_floor[256] =
107 {
108 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,0,
109 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,
110 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,
111 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,
112 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,
113 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,
114 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,
115 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,8
116 };
117
118 static const uint8_t g_pvrtc_alpha_ceil[256] =
119 {
120 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,
121 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,
122 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,
123 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,
124 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,
125 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,
126 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,
127 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
128 };
129#endif
130
131 uint32_t pvrtc4_swizzle_uv(uint32_t width, uint32_t height, uint32_t x, uint32_t y)
132 {
133 assert((x < width) && (y < height) && basisu::is_pow2(height) && basisu::is_pow2(width));
134
135 uint32_t min_d = width, max_v = y;
136 if (height < width)
137 {
138 min_d = height;
139 max_v = x;
140 }
141
142 // Interleave the XY LSB's
143 uint32_t shift_ofs = 0, swizzled = 0;
144 for (uint32_t s_bit = 1, d_bit = 1; s_bit < min_d; s_bit <<= 1, d_bit <<= 2, ++shift_ofs)
145 {
146 if (y & s_bit) swizzled |= d_bit;
147 if (x & s_bit) swizzled |= (2 * d_bit);
148 }
149
150 max_v >>= shift_ofs;
151
152 // OR in the rest of the bits from the largest dimension
153 swizzled |= (max_v << (2 * shift_ofs));
154
155 return swizzled;
156 }
157
158 color_rgba pvrtc4_block::get_endpoint(uint32_t endpoint_index, bool unpack) const
159 {
160 assert(endpoint_index < 2);
161 const uint32_t packed = m_endpoints >> (endpoint_index * 16);
162
163 uint32_t r, g, b, a;
164 if (packed & 0x8000)
165 {
166 // opaque 554 or 555
167 if (!endpoint_index)
168 {
169 r = (packed >> 10) & 31;
170 g = (packed >> 5) & 31;
171 b = (packed >> 1) & 15;
172
173 if (unpack)
174 {
175 b = (b << 1) | (b >> 3);
176 }
177 }
178 else
179 {
180 r = (packed >> 10) & 31;
181 g = (packed >> 5) & 31;
182 b = packed & 31;
183 }
184
185 a = unpack ? 255 : 7;
186 }
187 else
188 {
189 // translucent 4433 or 4443
190 if (!endpoint_index)
191 {
192 a = (packed >> 12) & 7;
193 r = (packed >> 8) & 15;
194 g = (packed >> 4) & 15;
195 b = (packed >> 1) & 7;
196
197 if (unpack)
198 {
199 a = (a << 1);
200 a = (a << 4) | a;
201
202 r = (r << 1) | (r >> 3);
203 g = (g << 1) | (g >> 3);
204 b = (b << 2) | (b >> 1);
205 }
206 }
207 else
208 {
209 a = (packed >> 12) & 7;
210 r = (packed >> 8) & 15;
211 g = (packed >> 4) & 15;
212 b = packed & 15;
213
214 if (unpack)
215 {
216 a = (a << 1);
217 a = (a << 4) | a;
218
219 r = (r << 1) | (r >> 3);
220 g = (g << 1) | (g >> 3);
221 b = (b << 1) | (b >> 3);
222 }
223 }
224 }
225
226 if (unpack)
227 {
228 r = (r << 3) | (r >> 2);
229 g = (g << 3) | (g >> 2);
230 b = (b << 3) | (b >> 2);
231 }
232
233 assert((r < 256) && (g < 256) && (b < 256) && (a < 256));
234
235 return color_rgba(r, g, b, a);
236 }
237
238 color_rgba pvrtc4_block::get_endpoint_5554(uint32_t endpoint_index) const
239 {
240 assert(endpoint_index < 2);
241 const uint32_t packed = m_endpoints >> (endpoint_index * 16);
242
243 uint32_t r, g, b, a;
244 if (packed & 0x8000)
245 {
246 // opaque 554 or 555
247 if (!endpoint_index)
248 {
249 r = (packed >> 10) & 31;
250 g = (packed >> 5) & 31;
251 b = (packed >> 1) & 15;
252
253 b = (b << 1) | (b >> 3);
254 }
255 else
256 {
257 r = (packed >> 10) & 31;
258 g = (packed >> 5) & 31;
259 b = packed & 31;
260 }
261
262 a = 15;
263 }
264 else
265 {
266 // translucent 4433 or 4443
267 if (!endpoint_index)
268 {
269 a = (packed >> 12) & 7;
270 r = (packed >> 8) & 15;
271 g = (packed >> 4) & 15;
272 b = (packed >> 1) & 7;
273
274 a = a << 1;
275
276 r = (r << 1) | (r >> 3);
277 g = (g << 1) | (g >> 3);
278 b = (b << 2) | (b >> 1);
279 }
280 else
281 {
282 a = (packed >> 12) & 7;
283 r = (packed >> 8) & 15;
284 g = (packed >> 4) & 15;
285 b = packed & 15;
286
287 a = a << 1;
288
289 r = (r << 1) | (r >> 3);
290 g = (g << 1) | (g >> 3);
291 b = (b << 1) | (b >> 3);
292 }
293 }
294
295 assert((r < 32) && (g < 32) && (b < 32) && (a < 16));
296
297 return color_rgba(r, g, b, a);
298 }
299
300 bool pvrtc4_image::get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const
301 {
302 assert((x < m_width) && (y < m_height));
303
304 int block_x0 = (static_cast<int>(x) - 2) >> 2;
305 int block_x1 = block_x0 + 1;
306 int block_y0 = (static_cast<int>(y) - 2) >> 2;
307 int block_y1 = block_y0 + 1;
308
309 block_x0 = posmod(block_x0, m_block_width);
310 block_x1 = posmod(block_x1, m_block_width);
311 block_y0 = posmod(block_y0, m_block_height);
312 block_y1 = posmod(block_y1, m_block_height);
313
314 pColors[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));
315 pColors[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));
316
317 if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
318 {
319 for (uint32_t c = 0; c < 4; c++)
320 {
321 uint32_t m = (pColors[0][c] + pColors[3][c]) / 2;
322 pColors[1][c] = static_cast<uint8_t>(m);
323 pColors[2][c] = static_cast<uint8_t>(m);
324 }
325 pColors[2][3] = 0;
326 return true;
327 }
328
329 for (uint32_t c = 0; c < 4; c++)
330 {
331 pColors[1][c] = static_cast<uint8_t>((pColors[0][c] * 5 + pColors[3][c] * 3) / 8);
332 pColors[2][c] = static_cast<uint8_t>((pColors[0][c] * 3 + pColors[3][c] * 5) / 8);
333 }
334
335 return false;
336 }
337
338 color_rgba pvrtc4_image::get_pixel(uint32_t x, uint32_t y, uint32_t m) const
339 {
340 assert((x < m_width) && (y < m_height));
341
342 int block_x0 = (static_cast<int>(x) - 2) >> 2;
343 int block_x1 = block_x0 + 1;
344 int block_y0 = (static_cast<int>(y) - 2) >> 2;
345 int block_y1 = block_y0 + 1;
346
347 block_x0 = posmod(block_x0, m_block_width);
348 block_x1 = posmod(block_x1, m_block_width);
349 block_y0 = posmod(block_y0, m_block_height);
350 block_y1 = posmod(block_y1, m_block_height);
351
352 if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
353 {
354 if (m == 0)
355 return 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));
356 else if (m == 3)
357 return 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));
358
359 color_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)));
360 color_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)));
361
362 return 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);
363 }
364 else
365 {
366 if (m == 0)
367 return 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));
368 else if (m == 3)
369 return 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));
370
371 color_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)));
372 color_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)));
373
374 if (m == 2)
375 return 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);
376 else
377 return 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);
378 }
379 }
380
381 uint64_t pvrtc4_image::local_endpoint_optimization_opaque(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual)
382 {
383 uint64_t initial_error = evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false);
384 if (!initial_error)
385 return initial_error;
386
387 vec3F c_avg_orig(0);
388
389 for (int y = 0; y < 7; y++)
390 {
391 const uint32_t py = wrap_y(by * 4 + y - 1);
392 for (uint32_t x = 0; x < 7; x++)
393 {
394 const uint32_t px = wrap_x(bx * 4 + x - 1);
395
396 const color_rgba& c = orig_img(px, py);
397
398 c_avg_orig[0] += c[0];
399 c_avg_orig[1] += c[1];
400 c_avg_orig[2] += c[2];
401 }
402 }
403
404 c_avg_orig *= 1.0f / 49.0f;
405
406 vec3F quant_colors[2];
407 quant_colors[0].set(c_avg_orig);
408 quant_colors[0] -= vec3F(.0125f);
409
410 quant_colors[1].set(c_avg_orig);
411 quant_colors[1] += vec3F(.0125f);
412
413 float total_weight[2];
414
415 bool success = true;
416
417 for (uint32_t pass = 0; pass < 4; pass++)
418 {
419 vec3F new_colors[2] = { vec3F(0), vec3F(0) };
420 memset(total_weight, 0, sizeof(total_weight));
421
422 static const float s_weights[7][7] =
423 {
424 { 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f },
425 { 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },
426 { 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },
427 { 2.242640f, 3.242640f, 4.242640f, 5.000000f, 4.242640f, 3.242640f, 2.242640f },
428 { 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },
429 { 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },
430 { 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f }
431 };
432
433 for (int y = 0; y < 7; y++)
434 {
435 const uint32_t py = wrap_y(by * 4 + y - 1);
436 for (uint32_t x = 0; x < 7; x++)
437 {
438 const uint32_t px = wrap_x(bx * 4 + x - 1);
439
440 const color_rgba& orig_c = orig_img(px, py);
441
442 vec3F color(orig_c[0], orig_c[1], orig_c[2]);
443
444 uint32_t c = quant_colors[0].squared_distance(color) > quant_colors[1].squared_distance(color);
445
446 const float weight = s_weights[y][x];
447 new_colors[c] += color * weight;
448
449 total_weight[c] += weight;
450 }
451 }
452
453 if (!total_weight[0] || !total_weight[1])
454 success = false;
455
456 quant_colors[0] = new_colors[0] / (float)total_weight[0];
457 quant_colors[1] = new_colors[1] / (float)total_weight[1];
458 }
459
460 if (!success)
461 {
462 quant_colors[0] = c_avg_orig;
463 quant_colors[1] = c_avg_orig;
464 }
465
466 vec4F colors[2] = { quant_colors[0], quant_colors[1] };
467
468 colors[0] += vec3F(.5f);
469 colors[1] += vec3F(.5f);
470 color_rgba color_0((int)colors[0][0], (int)colors[0][1], (int)colors[0][2], 0);
471 color_rgba color_1((int)colors[1][0], (int)colors[1][1], (int)colors[1][2], 0);
472
473 pvrtc4_block cur_blocks[3][3];
474
475 for (int y = -1; y <= 1; y++)
476 {
477 for (int x = -1; x <= 1; x++)
478 {
479 const uint32_t block_x = wrap_block_x(bx + x);
480 const uint32_t block_y = wrap_block_y(by + y);
481 cur_blocks[x + 1][y + 1] = m_blocks(block_x, block_y);
482 }
483 }
484
485 color_rgba l1(0), h1(0);
486
487 l1[0] = g_pvrtc_5_nearest[color_0[0]];
488 h1[0] = g_pvrtc_5_nearest[color_1[0]];
489
490 l1[1] = g_pvrtc_5_nearest[color_0[1]];
491 h1[1] = g_pvrtc_5_nearest[color_1[1]];
492
493 l1[2] = g_pvrtc_4_nearest[color_0[2]];
494 h1[2] = g_pvrtc_5_nearest[color_0[2]];
495
496 l1[3] = 0;
497 h1[3] = 0;
498
499 m_blocks(bx, by).set_endpoint_raw(0, l1, true);
500 m_blocks(bx, by).set_endpoint_raw(1, h1, true);
501
502 uint64_t e03_err_0 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);
503
504 pvrtc4_block blocks0[3][3];
505 for (int y = -1; y <= 1; y++)
506 {
507 for (int x = -1; x <= 1; x++)
508 {
509 const uint32_t block_x = wrap_block_x(bx + x);
510 const uint32_t block_y = wrap_block_y(by + y);
511 blocks0[x + 1][y + 1] = m_blocks(block_x, block_y);
512 }
513 }
514
515 l1[0] = g_pvrtc_5_nearest[color_1[0]];
516 h1[0] = g_pvrtc_5_nearest[color_0[0]];
517
518 l1[1] = g_pvrtc_5_nearest[color_1[1]];
519 h1[1] = g_pvrtc_5_nearest[color_0[1]];
520
521 l1[2] = g_pvrtc_4_nearest[color_1[2]];
522 h1[2] = g_pvrtc_5_nearest[color_0[2]];
523
524 l1[3] = 0;
525 h1[3] = 0;
526
527 m_blocks(bx, by).set_endpoint_raw(0, l1, true);
528 m_blocks(bx, by).set_endpoint_raw(1, h1, true);
529
530 uint64_t e03_err_1 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);
531
532 if (initial_error < basisu::minimum(e03_err_0, e03_err_1))
533 {
534 for (int y = -1; y <= 1; y++)
535 {
536 for (int x = -1; x <= 1; x++)
537 {
538 const uint32_t block_x = wrap_block_x(bx + x);
539 const uint32_t block_y = wrap_block_y(by + y);
540 m_blocks(block_x, block_y) = cur_blocks[x + 1][y + 1];
541 }
542 }
543 return initial_error;
544 }
545 else if (e03_err_0 < e03_err_1)
546 {
547 for (int y = -1; y <= 1; y++)
548 {
549 for (int x = -1; x <= 1; x++)
550 {
551 const uint32_t block_x = wrap_block_x(bx + x);
552 const uint32_t block_y = wrap_block_y(by + y);
553 m_blocks(block_x, block_y) = blocks0[x + 1][y + 1];
554 }
555 }
556 assert(e03_err_0 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));
557 return e03_err_0;
558 }
559
560 assert(e03_err_1 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));
561 return e03_err_1;
562 }
563
564} // basisu
565