/*
 * image_resampling.cpp
 *
 */

#include "image_resampling.h"

#include "gc_color_theme.h"

#include <math.h>

//typedef unsigned char  src_type_t;
//typedef image_resampling_src_type_t src_type_t;


#define N_BITS_VIDEO             8
#define LIVELLO_BIANCO           1.0
#define LIVELLO_NERO             0.0

/*static*/ const float pow_n_bits_video = 256.0f;//pow(2,8);
/*static*/ const float pow_n_bits_video_m1=255.0f;// pow_n_bits_video -1.0f;


static inline unsigned char sample_to_video(uint8_t v)
{
	return v;
}

static inline unsigned char sample_to_video(uint16_t v)
{
	return v>>8;
}

template<typename T_> static void imageResamplingTyped(
		unsigned char* dst, int dx, int dy, int stride,	//output
		int cx, int cy,	float rotation, float zoom,
		T_* src, int sx, int sy, int ss,
		float max	//source image
		)
{
	//    alfa_mon = mcpx_image.contrast/127.0;
	//float alfa_mon=0.25;
    //float alfa = alfa_mon;
    //float pow_max_alfa = powf(max, alfa);
    //float factor_2 = pow_n_bits_video/((LIVELLO_BIANCO - LIVELLO_NERO)* pow_max_alfa);
    //pow_max_alfa = pow_max_alfa * LIVELLO_NERO;
	(void)max;

    //int dstW=DX;
    //int dstH=DY;
    int srcW=sx;
    int srcH=sy;
    int srcDelta=ss;  //srouce stride
    float fDstCX=dx/2; //241+dx_border;
    float fDstCY=dy/2; //483;

    float fSrcCX=cx; //sx/2;
    float fSrcCY=cy; //sy/2;

    float fScale=zoom; //groundMap.scale(); //mfd_scale/DY); //calcScale();
    float fAngle=rotation; //GeoRef::heading()+GeoImage::headingOffset();//map_rotation+GeoImage::headingOffset();

    float duCol = sinf(-fAngle) * (1.0f / fScale);
    float dvCol = cosf(-fAngle) * (1.0f / fScale);
    float duRow = dvCol;
    float dvRow = -duCol;
    float startingu = fSrcCX - (fDstCX * dvCol + fDstCY * duCol);
    float startingv = fSrcCY - (fDstCX * dvRow + fDstCY * duRow);

    float rowu = startingu;
    float rowv = startingv;

    const int srcMaskW=srcW-1;
    const int srcMaskH=srcH-1;

    const int srcClipW=~srcMaskW;
    const int srcClipH=~srcMaskH;

	int r_start=0;
	int r_end=dy;
	int c_start=0;
	int c_end=dx;

	T_* pSrcBase=src;
	//T_* pSrcBase1=&src[srcDelta];

	for(int y=r_start; y<r_end; ++y)
	{
        float u = rowu;
        float v = rowv;

		for(int x=c_start; x<c_end; ++x)
		{
            int ux=u;
            int vy=v;

            //if ((ux<0) || (ux>=srcW) || (vy<0) || (vy>=srcH))
            if ((ux & srcClipW) || (vy & srcClipH))
            {
            	dst[x]=0;
            }
            else
            {

#if 0 /*interpolation*/
    			float delta_x = ux-u;
    			float delta_y = vy-v;

          		float y1 = pSrcBase[vy*srcDelta+ux];
          		float y2 = pSrcBase[vy*srcDelta+ux+1];
                float ym = y1 + (y2 - y1)*delta_x ;

    			y1 = pSrcBase1[(vy)*srcDelta+ux];
          		y2 = pSrcBase1[(vy)*srcDelta+ux+1];
                float yn = y1 + (y2 - y1)*delta_x;

            	float z = ym + (yn - ym)*delta_y;
            	int vi=z;
            	src_type_t ImageEl=vi>255 ? 255 : vi;

#else
				T_ ImageEl=pSrcBase[vy*srcDelta+ux];
#endif

#if 0
				float res = (powf(ImageEl, alfa) - pow_max_alfa)* factor_2;
				if (res>pow_n_bits_video_m1)
				{
					res=pow_n_bits_video_m1;
				}
#endif
				unsigned char res=gc_color_theme::sc_color_index_convert(sample_to_video(ImageEl));
				dst[x]=res;
            }

            u += duRow;
            v += dvRow;
		}
        dst+=stride;
        //s+=pitch;

        rowu += duCol;
        rowv += dvCol;
	}
}

static void imageResampling(
		unsigned char* dst, int dx, int dy, int stride,	//output
		int cx, int cy,	float rotation, float zoom,
		unsigned int bpp, const void* src, int sx, int sy, int ss,
		float max	//source image
		)
{
	if (bpp==2)
	{
		imageResamplingTyped(dst, dx, dy, stride, cx, cy, rotation, zoom, (uint16_t*)src, sx, sy, ss, max);
	}
	else
	{
		imageResamplingTyped(dst, dx, dy, stride, cx, cy, rotation, zoom, (uint8_t*)src, sx, sy, ss, max);
	}
}


void image_resampling(
		unsigned char* dst, int dx, int dy, int stride,

		int cx, int cy,	float rotation, float zoom,

		unsigned int bpp, const image_resampling_src_type_t* src, int sx, int sy, int ss)
{
	imageResampling(dst, dx, dy, stride, cx, cy, rotation, zoom, bpp, src, sx, sy, ss, 0);
}

void image_simple_resampling_16to8(
		unsigned char* dst, int dx, int dy, int stride,  //dest[stride*dy], dx<0stride -> valid pixels
		uint16_t* src, int sx, int sy, int ss)
{
	if ((sx!=dx) || (sy!=dy) || (stride!=ss) || (stride!=dx) || (dx!=dy))
	{
		imageResamplingTyped(dst, dx, dy, stride, sx/2, sy/2, 0, 1, src, sx, sy, ss, 0);
	}
	else
	{
		for(int i=0; i<(dy*dx); ++i)
		{
			dst[i]=src[i]>>8;
		}
	}
}


#if 0

static void imageResampling(
		unsigned char* dst, int dx, int dy, int stride,	//output
		int cx, int cy,	float rotation, float zoom,
		src_type_t* src, int sx, int sy, int ss,
		float max	//source image
		)
{
	//    alfa_mon = mcpx_image.contrast/127.0;
	//float alfa_mon=0.25;
    //float alfa = alfa_mon;
    //float pow_max_alfa = powf(max, alfa);
    //float factor_2 = pow_n_bits_video/((LIVELLO_BIANCO - LIVELLO_NERO)* pow_max_alfa);
    //pow_max_alfa = pow_max_alfa * LIVELLO_NERO;
	(void)max;

    //int dstW=DX;
    //int dstH=DY;
    int srcW=sx;
    int srcH=sy;
    int srcDelta=ss;  //srouce stride
    float fDstCX=dx/2; //241+dx_border;
    float fDstCY=dy/2; //483;

    float fSrcCX=cx; //sx/2;
    float fSrcCY=cy; //sy/2;

    float fScale=zoom; //groundMap.scale(); //mfd_scale/DY); //calcScale();
    float fAngle=rotation; //GeoRef::heading()+GeoImage::headingOffset();//map_rotation+GeoImage::headingOffset();

    float duCol = sinf(-fAngle) * (1.0f / fScale);
    float dvCol = cosf(-fAngle) * (1.0f / fScale);
    float duRow = dvCol;
    float dvRow = -duCol;
    float startingu = fSrcCX - (fDstCX * dvCol + fDstCY * duCol);
    float startingv = fSrcCY - (fDstCX * dvRow + fDstCY * duRow);

    float rowu = startingu;
    float rowv = startingv;

    const int srcMaskW=srcW-1;
    const int srcMaskH=srcH-1;

    const int srcClipW=~srcMaskW;
    const int srcClipH=~srcMaskH;

	int r_start=0;
	int r_end=dy;
	int c_start=0;
	int c_end=dx;

	src_type_t* pSrcBase=src;
	src_type_t* pSrcBase1=&src[srcDelta];

	for(int y=r_start; y<r_end; ++y)
	{
        float u = rowu;
        float v = rowv;

		for(int x=c_start; x<c_end; ++x)
		{
            int ux=u;
            int vy=v;

            //if ((ux<0) || (ux>=srcW) || (vy<0) || (vy>=srcH))
            if ((ux & srcClipW) || (vy & srcClipH))
            {
            	dst[x]=0;
            }
            else
            {

#if 0 /*interpolation*/
    			float delta_x = ux-u;
    			float delta_y = vy-v;

          		float y1 = pSrcBase[vy*srcDelta+ux];
          		float y2 = pSrcBase[vy*srcDelta+ux+1];
                float ym = y1 + (y2 - y1)*delta_x ;

    			y1 = pSrcBase1[(vy)*srcDelta+ux];
          		y2 = pSrcBase1[(vy)*srcDelta+ux+1];
                float yn = y1 + (y2 - y1)*delta_x;

            	float z = ym + (yn - ym)*delta_y;
            	int vi=z;
            	src_type_t ImageEl=vi>255 ? 255 : vi;

#else
				src_type_t ImageEl=pSrcBase[vy*srcDelta+ux];
#endif

#if 0
				float res = (powf(ImageEl, alfa) - pow_max_alfa)* factor_2;
				if (res>pow_n_bits_video_m1)
				{
					res=pow_n_bits_video_m1;
				}
#endif
				unsigned char res=gc_color_theme::sc_color_index_convert(ImageEl>>8);
				dst[x]=res;
            }

            u += duRow;
            v += dvRow;
		}
        dst+=stride;
        //s+=pitch;

        rowu += duCol;
        rowv += dvCol;
	}
}


#endif
