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 <math.h>
20#include "agg_basics.h"
21
22namespace agg
23{
24    template<class LoResT=int8u,
25             class HiResT=int8u,
26             unsigned GammaShift=8,
27             unsigned HiResShift=8> class gamma_lut
28    {
29    public:
30        typedef gamma_lut<LoResT, HiResT, GammaShift, HiResShift> self_type;
31
32        enum gamma_scale_e
33        {
34            gamma_shift = GammaShift,
35            gamma_size  = 1 << gamma_shift,
36            gamma_mask  = gamma_size - 1
37        };
38
39        enum hi_res_scale_e
40        {
41            hi_res_shift = HiResShift,
42            hi_res_size  = 1 << hi_res_shift,
43            hi_res_mask  = hi_res_size - 1
44        };
45
46        ~gamma_lut()
47        {
48            pod_allocator<LoResT>::deallocate(m_inv_gamma, hi_res_size);
49            pod_allocator<HiResT>::deallocate(m_dir_gamma, gamma_size);
50        }
51
52        gamma_lut() :
53            m_gamma(1.0),
54            m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
55            m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
56        {
57            unsigned i;
58            for(i = 0; i < gamma_size; i++)
59            {
60                m_dir_gamma[i] = HiResT(i << (hi_res_shift - gamma_shift));
61            }
62
63            for(i = 0; i < hi_res_size; i++)
64            {
65                m_inv_gamma[i] = LoResT(i >> (hi_res_shift - gamma_shift));
66            }
67        }
68
69        gamma_lut(double g) :
70            m_gamma(1.0),
71            m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
72            m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
73        {
74            gamma(g);
75        }
76
77        void gamma(double g)
78        {
79            m_gamma = g;
80
81            unsigned i;
82            for(i = 0; i < gamma_size; i++)
83            {
84                m_dir_gamma[i] = (HiResT)
85                    uround(pow(i / double(gamma_mask), m_gamma) * double(hi_res_mask));
86            }
87
88            double inv_g = 1.0 / g;
89            for(i = 0; i < hi_res_size; i++)
90            {
91                m_inv_gamma[i] = (LoResT)
92                    uround(pow(i / double(hi_res_mask), inv_g) * double(gamma_mask));
93            }
94        }
95
96        double gamma() const
97        {
98            return m_gamma;
99        }
100
101        HiResT dir(LoResT v) const
102        {
103            return m_dir_gamma[unsigned(v)];
104        }
105
106        LoResT inv(HiResT v) const
107        {
108            return m_inv_gamma[unsigned(v)];
109        }
110
111    private:
112        gamma_lut(const self_type&);
113        const self_type& operator = (const self_type&);
114
115        double m_gamma;
116        HiResT* m_dir_gamma;
117        LoResT* m_inv_gamma;
118    };
119}
120
121#endif
122