#if !defined CONVOLUTION_KERNEL_
#define CONVOLUTION_KERNEL_
//-----------------------------------------------------------------------------
///
/// Class:  ConvolutionKernel
///
/// This class can implement a general square convolution kernel,  or can
/// generate one procedurally.
///
/// The procedural Kernel generator implements a 2D gaussian shaped image
/// sharpening (or blurring kernel).  The type of sharpening performed is
/// typically called unsharp masking. The filter weights are detemined by
/// the formula:
///
///                    2    2              2        2
///             -( ( dx + dy ) / (2 * sigma * radius ) )
///           e
///  where:
///           dx = x distance from center of kernel
///           dy = y distance from center of kernel
///
///
/// This creates a circularly symmetric, Gaussian shapped kernel. The filter
/// weights are then normalized so their sum = 1.0 and to produce an output
/// that computes:
///
///              (1+sharpness)*I - sharpness*G
///
/// where I is the original image G is the orignal image with the gausing
/// kernel applied.
///
/// Here are some example kernels with the default sharpness factor, 0.5, for
/// various radii:
///
///                                -0.00002 -0.0006 -0.0020 -0.0006 -0.00002
/// -0.00006 -0.0053 -0.00006      -0.0006  -0.0189 -0.0581 -0.0189 -0.0006
/// -0.0053   1.0215 -0.0053       -0.0020  -0.0581  1.3210 -0.0581 -0.0020
/// -0.00006 -0.0053 -0.00006      -0.0006  -0.0189 -0.0581 -0.0189 -0.0006
///                                -0.00002 -0.0013 -0.0020 -0.0013 -0.00002
///
///      Radius = 1                                 Radius = 2
///
///  The default kernel is:
///
///                          -0.0057 -0.0419 -0.0057
///                          -0.0419  1.1903 -0.0419
///                          -0.0057 -0.0419 -0.0057
///
///
/// The sharpness typically ranges from -1 for maximum blur (makeing a standard
/// gaussian blur), to 0 for no effect, to positive values up to about 10 for
/// various degrees of sharpening. Values greater than 1 create a very
/// pronounced sharpening effect. The radius can be any non-negative value.
/// A radius of zero will perform no filtering, while successively larger
/// values will filter lower and lower frequencies. The actual kernel size is
/// determined by the formula:
///
///              width,height = 1 + 2*(int)radius
///
/// Thus, a radius of 1.5 (the default) will create a 3x3 kernel.
///
/// Typically the parameters you would use for:
///
/// Low Sharpen     -- Sharpness =  5.0,  Radius = 1.5
/// Medium Sharpen  -- Sharpness =  7.5,  Radius = 1.75
/// High Sharpen    -- Sharpness = 10.0,  Radius = 2.0
///
/// For a Sharpen tool, the typical ranges would be 0.0 to 10.0 for Sharpness,
/// and 1.0 to 4.0 for Radius
///
/// Blur values would be as follows:
///
/// Low Blur        -- Sharpness = -1.0, Radius = 3.0
/// Medium Blur     -- Sharpness = -1.0, Radius = 8.0
/// High Blur       -- Sharpness = -1.0, Radius = 32.0
///
/// For a blur tool, the Sharpness value would be fixed at -1.0, and the typical
/// range for the user to select radius would be 1.0 to 32.0. The blur kernels
/// generated by this class are seperable.
///
//-----------------------------------------------------------------------------

namespace mudbox {

class ConvolutionKernel {
    private:
        float      *m_Kernel;        // floating point version.
        short      *m_fixedKernel;   // fixed point version S4.11
        int         m_Size;          // always square

        bool        m_Generated;     // true if the kernel is generated
                                     // by the following parameters.
        float       m_Sharpness;
        float       m_Radius;
        float       m_Sigma;

        void        Generate(void);  // generate the FP kernel from the 3 parms
        void        makeFixed(void); // generate the fixed point kernel from the FP one

    public:
        /// copy constructor
        ConvolutionKernel(const ConvolutionKernel &k);

        /// user specified arbitrary size x size kernel. The ctor copies the kernel
        /// into this class.
        ConvolutionKernel(float *kernel, int size);

        /// construct a procedurally generated kernel (as described above)
        ConvolutionKernel(float sharpness = 0.5f,
                          float radius    = 1.5f,
                          float sigma     = (1.0f/3.0f));

        /// destructor. Releases memory
        ~ConvolutionKernel();

        void  setSharpness(float val);
        void  setRadius(float val);
        void  setSigma(float val);

        /// Copies the supplied kernel into this class.
        void  setKernel(float *f, int Size);

        float getSharpness()     const { return m_Sharpness; }
        float getRadius()        const { return m_Radius;    }
        float getSigma()         const { return m_Sigma;     }

        /// @return true if procedurally generated, false otherwise
        bool  isGenerated(void)  const { return m_Generated; }

        /// @return the size of the kernel (width and height are the same)
        int   getSize (void)     const { return m_Size; }

        /// copies the kernel to the target buffer which must be appropriately sized
        void         getKernel(float *targetBuffer) const;

        /// @return a pointer to the kernel (in 32 bit float format)
        const float *getKernel(void) const      { return m_Kernel; }

        /// @return a pointer to the 16 bit fixed point kernel in S4.11 format
        ///
        /// @note The Fixed kernel is made up of fixed point signed numbers in the
        /// form S4.11. This was chosen because the procedurally generated kernel
        /// will always be expressable in this form as long as the sharpness is in
        /// the range -1 to 10.
        const short *getFixedKernel(void) const { return m_fixedKernel; }

        /// Prints the convolution kernel to the log. (for debugging purposes)
        void         logPrintKernel(void) const;
};

//-----------------------------------------------------------------------------

//-
// ==================================================================
// (C) Copyright 2009 by Autodesk, Inc. All Rights Reserved. By using
// this code,  you  are  agreeing  to the terms and conditions of the
// License  Agreement  included  in  the documentation for this code.
// AUTODESK  MAKES  NO  WARRANTIES,  EXPRESS  OR  IMPLIED,  AS TO THE
// CORRECTNESS OF THIS CODE OR ANY DERIVATIVE WORKS WHICH INCORPORATE
// IT.  AUTODESK PROVIDES THE CODE ON AN 'AS-IS' BASIS AND EXPLICITLY
// DISCLAIMS  ANY  LIABILITY,  INCLUDING CONSEQUENTIAL AND INCIDENTAL
// DAMAGES  FOR ERRORS, OMISSIONS, AND  OTHER  PROBLEMS IN THE  CODE.
//
// Use, duplication,  or disclosure by the U.S. Government is subject
// to  restrictions  set forth  in FAR 52.227-19 (Commercial Computer
// Software Restricted Rights) as well as DFAR 252.227-7013(c)(1)(ii)
// (Rights  in Technical Data and Computer Software),  as applicable.
// ==================================================================
//+
#endif

}; // end of namespace mudbox
