Anti-Grain Geometry Tutorial
agg_gamma_lut.h
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 
16 #ifndef AGG_GAMMA_LUT_INCLUDED
17 #define AGG_GAMMA_LUT_INCLUDED
18 
19 #include <cmath>
20 #include "agg_basics.h"
21 #include "agg_gamma_functions.h"
22 
23 namespace agg
24 {
25  template<class LoResT=int8u,
26  class HiResT=int8u,
27  unsigned GammaShift=8,
28  unsigned HiResShift=8> class gamma_lut
29  {
30  public:
32 
33  enum gamma_scale_e
34  {
35  gamma_shift = GammaShift,
36  gamma_size = 1 << gamma_shift,
37  gamma_mask = gamma_size - 1
38  };
39 
40  enum hi_res_scale_e
41  {
42  hi_res_shift = HiResShift,
43  hi_res_size = 1 << hi_res_shift,
44  hi_res_mask = hi_res_size - 1
45  };
46 
47  ~gamma_lut()
48  {
49  pod_allocator<LoResT>::deallocate(m_inv_gamma, hi_res_size);
50  pod_allocator<HiResT>::deallocate(m_dir_gamma, gamma_size);
51  }
52 
53  gamma_lut() :
54  m_gamma(1.0),
55  m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
56  m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
57  {
58  unsigned i;
59  for(i = 0; i < gamma_size; i++)
60  {
61  m_dir_gamma[i] = HiResT(i << (hi_res_shift - gamma_shift));
62  }
63 
64  for(i = 0; i < hi_res_size; i++)
65  {
66  m_inv_gamma[i] = LoResT(i >> (hi_res_shift - gamma_shift));
67  }
68  }
69 
70  gamma_lut(double g) :
71  m_gamma(1.0),
72  m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
73  m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
74  {
75  gamma(g);
76  }
77 
78  void gamma(double g)
79  {
80  m_gamma = g;
81 
82  unsigned i;
83  for(i = 0; i < gamma_size; i++)
84  {
85  m_dir_gamma[i] = (HiResT)
86  uround(std::pow(i / double(gamma_mask), m_gamma) * double(hi_res_mask));
87  }
88 
89  double inv_g = 1.0 / g;
90  for(i = 0; i < hi_res_size; i++)
91  {
92  m_inv_gamma[i] = (LoResT)
93  uround(std::pow(i / double(hi_res_mask), inv_g) * double(gamma_mask));
94  }
95  }
96 
97  double gamma() const
98  {
99  return m_gamma;
100  }
101 
102  HiResT dir(LoResT v) const
103  {
104  return m_dir_gamma[unsigned(v)];
105  }
106 
107  LoResT inv(HiResT v) const
108  {
109  return m_inv_gamma[unsigned(v)];
110  }
111 
112  private:
113  gamma_lut(const self_type&);
114  const self_type& operator = (const self_type&);
115 
116  double m_gamma;
117  HiResT* m_dir_gamma;
118  LoResT* m_inv_gamma;
119  };
120 
121  //
122  // sRGB support classes
123  //
124 
125  // Optimized sRGB lookup table. The direct conversion (sRGB to linear)
126  // is a straightforward lookup. The inverse conversion (linear to sRGB)
127  // is implemented using binary search.
128  template<class LinearType>
130  {
131  public:
132  LinearType dir(int8u v) const
133  {
134  return m_dir_table[v];
135  }
136 
137  int8u inv(LinearType v) const
138  {
139  // Unrolled binary search.
140  int8u x = 0;
141  if (v > m_inv_table[128]) x = 128;
142  if (v > m_inv_table[x + 64]) x += 64;
143  if (v > m_inv_table[x + 32]) x += 32;
144  if (v > m_inv_table[x + 16]) x += 16;
145  if (v > m_inv_table[x + 8]) x += 8;
146  if (v > m_inv_table[x + 4]) x += 4;
147  if (v > m_inv_table[x + 2]) x += 2;
148  if (v > m_inv_table[x + 1]) x += 1;
149  return x;
150  }
151 
152  protected:
153  LinearType m_dir_table[256];
154  LinearType m_inv_table[256];
155 
156  // Only derived classes may instantiate.
157  sRGB_lut_base()
158  {
159  }
160  };
161 
162 
163  // sRGB_lut - implements sRGB conversion for the various types.
164  // Base template is undefined, specializations are provided below.
165  template<class LinearType>
166  class sRGB_lut;
167 
168  template<>
169  class sRGB_lut<float> : public sRGB_lut_base<float>
170  {
171  public:
172  sRGB_lut()
173  {
174  // Generate lookup tables.
175  m_dir_table[0] = 0;
176  m_inv_table[0] = 0;
177  for (unsigned i = 1; i <= 255; ++i)
178  {
179  // Floating-point RGB is in range [0,1].
180  m_dir_table[i] = float(sRGB_to_linear(i / 255.0));
181  m_inv_table[i] = float(sRGB_to_linear((i - 0.5) / 255.0));
182  }
183  }
184  };
185 
186  template<>
187  class sRGB_lut<int16u> : public sRGB_lut_base<int16u>
188  {
189  public:
190  sRGB_lut()
191  {
192  // Generate lookup tables.
193  m_dir_table[0] = 0;
194  m_inv_table[0] = 0;
195  for (int i = 1; i <= 255; ++i)
196  {
197  // 16-bit RGB is in range [0,65535].
198  m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0));
199  m_inv_table[i] = uround(65535.0 * sRGB_to_linear((i - 0.5) / 255.0));
200  }
201  }
202  };
203 
204  template<>
205  class sRGB_lut<int8u> : public sRGB_lut_base<int8u>
206  {
207  public:
208  sRGB_lut()
209  {
210  // Generate lookup tables.
211  m_dir_table[0] = 0;
212  m_inv_table[0] = 0;
213  for (int i = 1; i <= 255; ++i)
214  {
215  // 8-bit RGB is handled with simple bidirectional lookup tables.
216  m_dir_table[i] = uround(255.0 * sRGB_to_linear(i / 255.0));
217  m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 255.0));
218  }
219  }
220 
221  int8u inv(int8u v) const
222  {
223  // In this case, the inverse transform is a simple lookup.
224  return m_inv_table[v];
225  }
226  };
227 
228  // Common base class for sRGB_conv objects. Defines an internal
229  // sRGB_lut object so that users don't have to.
230  template<class T>
232  {
233  public:
234  static T rgb_from_sRGB(int8u x)
235  {
236  return lut.dir(x);
237  }
238 
239  static int8u rgb_to_sRGB(T x)
240  {
241  return lut.inv(x);
242  }
243 
244  private:
245  static sRGB_lut<T> lut;
246  };
247 
248  // Definition of sRGB_conv_base::lut. Due to the fact that this a template,
249  // we don't need to place the definition in a cpp file. Hurrah.
250  template<class T>
252 
253  // Wrapper for sRGB-linear conversion.
254  // Base template is undefined, specializations are provided below.
255  template<class T>
256  class sRGB_conv;
257 
258  template<>
259  class sRGB_conv<float> : public sRGB_conv_base<float>
260  {
261  public:
262  static float alpha_from_sRGB(int8u x)
263  {
264  static const double y = 1 / 255.0;
265  return float(x * y);
266  }
267 
268  static int8u alpha_to_sRGB(float x)
269  {
270  if (x < 0) return 0;
271  if (x > 1) return 255;
272  return int8u(0.5 + x * 255);
273  }
274  };
275 
276  template<>
277  class sRGB_conv<int16u> : public sRGB_conv_base<int16u>
278  {
279  public:
280  static int16u alpha_from_sRGB(int8u x)
281  {
282  return (x << 8) | x;
283  }
284 
285  static int8u alpha_to_sRGB(int16u x)
286  {
287  return x >> 8;
288  }
289  };
290 
291  template<>
292  class sRGB_conv<int8u> : public sRGB_conv_base<int8u>
293  {
294  public:
295  static int8u alpha_from_sRGB(int8u x)
296  {
297  return x;
298  }
299 
300  static int8u alpha_to_sRGB(int8u x)
301  {
302  return x;
303  }
304  };
305 }
306 
307 #endif
Definition: agg_arc.cpp:24