//-----------------------------------------------------------------------------
//    ____ _               
//   | ___| |   ___  _  _  
//   | ___| |  / __)\ \/ / 
//   | |  | |_| ___) |  |
//   |_|  \___|\___)/_/\_\ Image Library  
//					
//	  2006, Intel Corporation, licensed under Apache 2.0 
//
// file :		FlexFilter.h
// author :		Scott Ettinger - scott.m.ettinger@intel.com
// description: FlexImage filter functions
//				
// modified : 
//-----------------------------------------------------------------------------

#ifndef FLEXFILTER_H
#define FLEXFILTER_H

#if defined(HAVE_CONFIG_H)
# include "config.h"
#endif

#include "FlexImage.h"

//1 channel filters are implemented separately from multi-channel for speed

//1D filter Row wise 1 channel any type data or kernel valid pixels only
template<class T, class T2>
bool FlexFilterRowV(FlexImage<T,1> &src, FlexImage<T,1> &dst, T2 *kernel, int kernelSize, bool allocate = true);

//1D filter Column wise 1 channel any type data or kernel valid pixels only
template<class T, class T2>
bool FlexFilterColumnV(FlexImage<T,1> &src, FlexImage<T,1> &dst, T2 *kernel, int kernelSize, bool allocate = true);

//2D Filter any type data or kernel valid pixels only
template<class T, class T2>
bool FlexFilter2DV(FlexImage<T,1> &src, FlexImage<T,1> &dst, T2 *kernel, int kWidth, int kHeight, bool allocate = true);

//Zero a 1 pixel border of the image
template<class T> 
inline void ZeroBorder(FlexImage<T,1> &im);

//----------------------------- Implementation --------------------------------

//1D filter Row wise 1 channel any type data or kernel valid pixels only
template<class T, class T2>
bool FlexFilterRowV(FlexImage<T,1> &src, FlexImage<T,1> &dst, T2 *kernel, int kernelSize, bool allocate)
{
	if(kernelSize % 2 == 0)									//enforce odd length kernels
		return false;
	if(allocate)
		dst.Reallocate(src.Size());
	dst.Set((T)0);
	int n = kernelSize / 2;
	for(int y = 0; y < src.Height(); y++)
	{	T *psrc = &src(n, y), *pdst = &dst(n, y);
		for(int x = n; x < src.Width() - n; x++)
		{	int k = 0;
			T2 acc = 0;
			for(int i = -n; i <= n; i++) 
				acc += (T2)(psrc[i] * kernel[k++]);
			*pdst = (T)acc;
			pdst++;
			psrc++;
		}
	}
	return true;
}

//1D filter Column wise 1 channel any type data or kernel valid pixels only
template<class T, class T2>
bool FlexFilterColumnV(FlexImage<T,1> &src, FlexImage<T,1> &dst, T2 *kernel, int kernelSize, bool allocate)
{
	if(kernelSize % 2 == 0)									//enforce odd length kernels
		return false;
	if(allocate)
		dst.Reallocate(src.Size());
	dst.Set((T)0);
	int n = kernelSize / 2;
	int sb = src.StepBytes();
	for(int y = n; y < src.Height() - n; y++)
	{	T *psrc = &src(0, y), *pdst = &dst(0, y);
		for(int x = 0; x < src.Width(); x++)
		{	int k = 0;
			T2 acc = 0;
			for(int i = -n; i <= n; i++) 
				acc += (T2)(*(T *)((char *)psrc + sb * i) * kernel[k++]);
			*pdst = (T)acc;
			pdst++;
			psrc++;
		}
	}
	return true;
}

//2D Filter any type data or kernel valid pixels only
template<class T, class T2>
bool FlexFilter2DV(FlexImage<T,1> &src, FlexImage<T,1> &dst, T2 *kernel, int kWidth, int kHeight, bool allocate)
{
	if(kWidth % 2 == 0 || kHeight % 2 == 0)
		return false;
	if(allocate)
		dst.Reallocate(src.Size());
	dst.Set((T)0);
	int nw = kWidth / 2, nh = kHeight / 2;
	int sb = src.StepBytes();
	for(int y = nh; y < src.Height() - nh; y++)
	{	T *psrc = &src(nw, y - nh), *pdst = &dst(nw, y);
		for(int x = nw; x < src.Width() - nw; x++)
		{	int k = 0;
			T *p = psrc++;
			for(int j = -nh; j <= nh; j++)
			{	for(int i = -nw; i <= nw; i++) 
					*pdst += p[i] * kernel[k++];
				p = (T *)((char *)p + sb);
			}	
			pdst++;
		}
	}
	return true;
}

//Zero a 1 pixel border of the image
template<class T> 
inline void ZeroBorder(FlexImage<T,1> &im)
{
	T *p1 = &im(0,0), *p2 = &im(0,im.Height() - 1);
	for(int i = 0; i < im.Width(); i++)
	{	*(p1++) = 0;
		*(p2++) = 0;
	}
	p1 = &im(0,0);	p2 = &im(im.Width() - 1, 0);
	for(int i = 0; i < im.Height(); i++)
	{	*p1 = 0; *p2 = 0;
		p1 = (T *)((Im8u *)p1 + im.StepBytes());
		p2 = (T *)((Im8u *)p2 + im.StepBytes());
	}
}

#endif

