1 // Copyright 2018 Google LLC
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 at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // 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 and
13 // limitations under the License.
14 
15 #include "src/decoder/weight_infill.h"
16 #include "src/decoder/integer_sequence_codec.h"
17 
18 #include <array>
19 #include <cmath>
20 #include <utility>
21 
22 namespace astc_codec {
23 
24 namespace {
25 
26 // The following functions are based on Section C.2.18 of the ASTC specification
GetScaleFactorD(int block_dim)27 int GetScaleFactorD(int block_dim) {
28   return static_cast<int>((1024.f + static_cast<float>(block_dim >> 1)) /
29                           static_cast<float>(block_dim - 1));
30 }
31 
GetGridSpaceCoordinates(Footprint footprint,int s,int t,int weight_dim_x,int weight_dim_y)32 std::pair<int, int> GetGridSpaceCoordinates(
33     Footprint footprint, int s, int t, int weight_dim_x, int weight_dim_y) {
34   const int ds = GetScaleFactorD(footprint.Width());
35   const int dt = GetScaleFactorD(footprint.Height());
36 
37   const int cs = ds * s;
38   const int ct = dt * t;
39 
40   const int gs = (cs * (weight_dim_x - 1) + 32) >> 6;
41   const int gt = (ct * (weight_dim_y - 1) + 32) >> 6;
42 
43   assert(gt < 1 << 8);
44   assert(gs < 1 << 8);
45 
46   return std::make_pair(gs, gt);
47 }
48 
49 // Returns the weight-grid values that are to be used for bilinearly
50 // interpolating the weight to its final value. If the returned value
51 // is equal to weight_dim_x * weight_dim_y, it may be ignored.
BilerpGridPointsForWeight(const std::pair<int,int> & grid_space_coords,int weight_dim_x)52 std::array<int, 4> BilerpGridPointsForWeight(
53     const std::pair<int, int>& grid_space_coords, int weight_dim_x) {
54   const int js = grid_space_coords.first >> 4;
55   const int jt = grid_space_coords.second >> 4;
56 
57   std::array<int, 4> result;
58   result[0] = js + weight_dim_x * jt;
59   result[1] = js + weight_dim_x * jt + 1;
60   result[2] = js + weight_dim_x * (jt + 1);
61   result[3] = js + weight_dim_x * (jt + 1) + 1;
62 
63   return result;
64 }
65 
BilerpGridPointFactorsForWeight(const std::pair<int,int> & grid_space_coords)66 std::array<int, 4> BilerpGridPointFactorsForWeight(
67     const std::pair<int, int>& grid_space_coords) {
68   const int fs = grid_space_coords.first & 0xF;
69   const int ft = grid_space_coords.second & 0xF;
70 
71   std::array<int, 4> result;
72   result[3] = (fs * ft + 8) >> 4;
73   result[2] = ft - result[3];
74   result[1] = fs - result[3];
75   result[0] = 16 - fs - ft + result[3];
76 
77   assert(result[0] <= 16);
78   assert(result[1] <= 16);
79   assert(result[2] <= 16);
80   assert(result[3] <= 16);
81 
82   return result;
83 }
84 
85 }  // namespace
86 
87 ////////////////////////////////////////////////////////////////////////////////
88 
CountBitsForWeights(int weight_dim_x,int weight_dim_y,int target_weight_range)89 int CountBitsForWeights(int weight_dim_x, int weight_dim_y,
90                         int target_weight_range) {
91   int num_weights = weight_dim_x * weight_dim_y;
92   return IntegerSequenceCodec::
93       GetBitCountForRange(num_weights, target_weight_range);
94 }
95 
InfillWeights(const std::vector<int> & weights,Footprint footprint,int dim_x,int dim_y)96 std::vector<int> InfillWeights(const std::vector<int>& weights,
97                                Footprint footprint, int dim_x, int dim_y) {
98   std::vector<int> result;
99   result.reserve(footprint.NumPixels());
100   for (int t = 0; t < footprint.Height(); ++t) {
101     for (int s = 0; s < footprint.Width(); ++s) {
102       const auto grid_space_coords =
103           GetGridSpaceCoordinates(footprint, s, t, dim_x, dim_y);
104       const auto grid_pts =
105           BilerpGridPointsForWeight(grid_space_coords, dim_x);
106       const auto grid_factors =
107           BilerpGridPointFactorsForWeight(grid_space_coords);
108 
109       int weight = 0;
110       for (int i = 0; i < 4; ++i) {
111         if (grid_pts[i] < dim_x * dim_y) {
112           weight += weights.at(grid_pts[i]) * grid_factors[i];
113         }
114       }
115       result.push_back((weight + 8) >> 4);
116     }
117   }
118 
119   return result;
120 }
121 
122 }  // namespace astc_codec
123