1 /*
2 ===============================================================================
3 
4   FILE:  field_rgb14.cpp
5 
6   CONTENTS:
7 
8 
9   PROGRAMMERS:
10 
11     martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
12     uday.karan@gmail.com - Hobu, Inc.
13 
14   COPYRIGHT:
15 
16     (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
17     (c) 2014, Uday Verma, Hobu, Inc.
18 
19     This is free software; you can redistribute and/or modify it under the
20     terms of the GNU Lesser General Licence as published by the Free Software
21     Foundation. See the COPYING file for more information.
22 
23     This software is distributed WITHOUT ANY WARRANTY and without even the
24     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 
26   CHANGE HISTORY:
27 
28 ===============================================================================
29 */
30 
31 #include "../las.hpp"
32 
33 namespace lazperf
34 {
35 namespace detail
36 {
37 
38 namespace
39 {
40 
color_diff_bits_1_4(const las::rgb14 & color,const las::rgb14 & last)41 unsigned int color_diff_bits_1_4(const las::rgb14& color, const las::rgb14& last)
42 {
43     const las::rgb14& a = last;
44     const las::rgb14& b = color;
45 
46     auto flag_diff = [](unsigned short c1, unsigned short c2, int mask) -> bool
47     {
48         return ((c1 ^ c2) & mask);
49     };
50 
51     unsigned int r =
52         (flag_diff(a.r, b.r, 0x00FF) << 0) |
53         (flag_diff(a.r, b.r, 0xFF00) << 1) |
54         (flag_diff(a.g, b.g, 0x00FF) << 2) |
55         (flag_diff(a.g, b.g, 0xFF00) << 3) |
56         (flag_diff(a.b, b.b, 0x00FF) << 4) |
57         (flag_diff(a.b, b.b, 0xFF00) << 5) |
58         ((flag_diff(b.r, b.g, 0x00FF) |
59           flag_diff(b.r, b.b, 0x00FF) |
60           flag_diff(b.r, b.g, 0xFF00) |
61           flag_diff(b.r, b.b, 0xFF00)) << 6);
62     return r;
63 }
64 
65 } // unnamed namespace
66 
67 
writeSizes()68 void Rgb14Compressor::writeSizes()
69 {
70     rgb_enc_.done();
71     stream_ << rgb_enc_.num_encoded();
72 }
73 
writeData()74 void Rgb14Compressor::writeData()
75 {
76     LAZDEBUG(std::cerr << "RGB       : " <<
77         utils::sum(rgb_enc_.encoded_bytes(), rgb_enc_.num_encoded()) << "\n");
78 
79     if (rgb_enc_.num_encoded())
80         stream_.putBytes(rgb_enc_.encoded_bytes(), rgb_enc_.num_encoded());
81 }
82 
compress(const char * buf,int & sc)83 const char *Rgb14Compressor::compress(const char *buf, int& sc)
84 {
85     const las::rgb14 color(buf);
86 
87     // don't have the first data yet, just push it to our
88     // have last stuff and move on
89     if (last_channel_ == -1)
90     {
91         ChannelCtx& c = chan_ctxs_[sc];
92         stream_.putBytes((const unsigned char*)&color, sizeof(las::rgb));
93         c.last_ = color;
94         c.have_last_ = true;
95         last_channel_ = sc;
96         return buf + sizeof(las::rgb);
97     }
98 
99     ChannelCtx& c = chan_ctxs_[sc];
100     las::rgb14 *pLastColor = &chan_ctxs_[last_channel_].last_;
101     if (!c.have_last_)
102     {
103         c.have_last_ = true;
104         c.last_ = *pLastColor;
105         pLastColor = &c.last_;
106     }
107     // This mess is because of the broken-ness of the handling for last in v3, where
108     // 'last_point' only gets updated on the first context switch in the LASzip code.
109     las::rgb& lastColor = *pLastColor;
110 
111     // compress color
112     int diff_l = 0;
113     int diff_h = 0;
114 
115     unsigned int sym = detail::color_diff_bits_1_4(color, lastColor);
116     if (sym)
117         rgb_enc_.makeValid();
118     rgb_enc_.encodeSymbol(c.used_model_, sym);
119 
120     // high and low R
121     if (sym & (1 << 0))
122     {
123         diff_l = (color.r & 0xFF) - (lastColor.r & 0xFF);
124         rgb_enc_.encodeSymbol(c.diff_model_[0], uint8_t(diff_l));
125     }
126     if (sym & (1 << 1))
127     {
128         diff_h = static_cast<int>(color.r >> 8) - (lastColor.r >> 8);
129         rgb_enc_.encodeSymbol(c.diff_model_[1], uint8_t(diff_h));
130     }
131 
132     // Only encode green and blue if they are different from red.
133     if (sym & (1 << 6))
134     {
135         if (sym & (1 << 2))
136         {
137             int corr = static_cast<int>(color.g & 0xFF) -
138                 utils::clamp<uint8_t>(diff_l + (lastColor.g & 0xFF));
139             rgb_enc_.encodeSymbol(c.diff_model_[2], uint8_t(corr));
140         }
141 
142         if (sym & (1 << 4))
143         {
144             diff_l = (diff_l + (color.g & 0xFF) - (lastColor.g & 0xFF)) / 2;
145             int corr = static_cast<int>(color.b & 0xFF) -
146                 utils::clamp<uint8_t>(diff_l + (lastColor.b & 0xFF));
147             rgb_enc_.encodeSymbol(c.diff_model_[4], uint8_t(corr));
148         }
149 
150         if (sym & (1 << 3))
151         {
152             int corr = static_cast<int>(color.g >> 8) -
153                 utils::clamp<uint8_t>(diff_h + (lastColor.g >> 8));
154             rgb_enc_.encodeSymbol(c.diff_model_[3], uint8_t(corr));
155         }
156 
157         if (sym & (1 << 5))
158         {
159             diff_h = (diff_h + ((color.g >> 8)) - (lastColor.g >> 8)) / 2;
160             int corr = static_cast<int>(color.b >> 8) -
161                 utils::clamp<uint8_t>(diff_h + (lastColor.b >> 8));
162             rgb_enc_.encodeSymbol(c.diff_model_[5], uint8_t(corr));
163         }
164     }
165 
166     lastColor = color;
167     last_channel_ = sc;
168     return buf + sizeof(las::rgb14);
169 }
170 
171 // DECOMPRESSOR
172 
dumpSums()173 void Rgb14Decompressor::dumpSums()
174 {
175     std::cout << "RGB      : " << sumRgb.value() << "\n";
176 }
177 
readSizes()178 void Rgb14Decompressor::readSizes()
179 {
180     stream_ >> rgb_cnt_;
181 }
182 
readData()183 void Rgb14Decompressor::readData()
184 {
185     rgb_dec_.initStream(stream_, rgb_cnt_);
186 }
187 
decompress(char * buf,int & sc)188 char *Rgb14Decompressor::decompress(char *buf, int& sc)
189 {
190     if (last_channel_ == -1)
191     {
192         ChannelCtx& c = chan_ctxs_[sc];
193         stream_.getBytes((unsigned char*)buf, sizeof(las::rgb));
194         c.last_.unpack(buf);
195         c.have_last_ = true;
196         last_channel_ = sc;
197         return buf + sizeof(las::rgb14);
198     }
199     if (rgb_cnt_ == 0)
200     {
201         las::rgb14 *color = reinterpret_cast<las::rgb14 *>(buf);
202         *color = chan_ctxs_[last_channel_].last_;
203         return buf + sizeof(las::rgb14);
204     }
205 
206     ChannelCtx& c = chan_ctxs_[sc];
207     las::rgb14 *pLastColor = &chan_ctxs_[last_channel_].last_;
208     if (sc != last_channel_)
209     {
210         last_channel_ = sc;
211         if (!c.have_last_)
212         {
213             c.have_last_ = true;
214             c.last_ = *pLastColor;
215             pLastColor = &chan_ctxs_[last_channel_].last_;
216         }
217     }
218     las::rgb14& lastColor = *pLastColor;
219 
220     uint32_t sym = rgb_dec_.decodeSymbol(c.used_model_);
221 
222     las::rgb14 color;
223 
224     if (sym & (1 << 0))
225     {
226         uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[0]);
227         color.r = static_cast<unsigned short>(uint8_t(corr + (lastColor.r & 0xFF)));
228     }
229     else
230         color.r = lastColor.r & 0xFF;
231 
232     if (sym & (1 << 1))
233     {
234         uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[1]);
235         color.r |= (static_cast<unsigned short>(uint8_t(corr + (lastColor.r >> 8))) << 8);
236     }
237     else
238         color.r |= lastColor.r & 0xFF00;
239 
240     if (sym & (1 << 6))
241     {
242         int diff = (color.r & 0xFF) - (lastColor.r & 0xFF);
243 
244         if (sym & (1 << 2))
245         {
246             uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[2]);
247             color.g = static_cast<unsigned short>(uint8_t(corr +
248                 utils::clamp<uint8_t>(diff + (lastColor.g & 0xFF))));
249         }
250         else
251             color.g = lastColor.g & 0xFF;
252 
253         if (sym & (1 << 4))
254         {
255             uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[4]);
256             diff = (diff + ((color.g & 0xFF) - (lastColor.g & 0xFF))) / 2;
257             color.b = static_cast<unsigned short>(uint8_t(corr +
258                 utils::clamp<uint8_t>(diff + (lastColor.b & 0xFF))));
259         }
260         else
261             color.b = lastColor.b & 0xFF;
262 
263         diff = (color.r >> 8) - (lastColor.r >> 8);
264         if (sym & (1 << 3))
265         {
266             uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[3]);
267             color.g |= (static_cast<unsigned short>(uint8_t(corr +
268                 utils::clamp<uint8_t>(diff + (lastColor.g >> 8))))) << 8;
269         }
270         else
271             color.g |= lastColor.g & 0xFF00;
272 
273         if (sym & (1 << 5))
274         {
275             uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[5]);
276             diff = (diff + (color.g >> 8) - (lastColor.g >> 8)) / 2;
277             color.b |= (static_cast<unsigned short>(uint8_t(corr +
278                             utils::clamp<uint8_t>(diff + (lastColor.b >> 8))))) << 8;
279         }
280         else
281             color.b |= (lastColor.b & 0xFF00);
282     }
283     else
284     {
285         color.g = color.r;
286         color.b = color.r;
287     }
288 
289     LAZDEBUG(sumRgb.add(color));
290     lastColor = color;
291     color.pack(buf);
292     return buf + sizeof(las::rgb14);
293 }
294 
295 } // namespace detail
296 } // namespace lazperf
297