
#include "PajaTypes.h"
#include "ImageResampleC.h"
#include <windows.h>
#include <stdio.h>
#include <vector>
#include <math.h>

using namespace PajaTypes;
using namespace PajaSystem;




static
void
TRACE( const char* szFormat, ...  )
{
	char	szMsg[256];
	va_list	rList;
	va_start( rList, szFormat );
	_vsnprintf( szMsg, 255, szFormat, rList );
	va_end( rList );
	OutputDebugString( szMsg );
}




bool
ImageResampleC::resample_nearest( uint32 ui32Bpp,
							uint8* pSrcData, uint32 ui32SrcWidth, uint32 ui32SrcHeight,
							uint8* pDstData, uint32 ui32DstWidth, uint32 ui32DstHeight )
{
	int32	i32Y = 0;
	int32	i32X = 0;
	int32	i32DeltaX = (((int32)ui32SrcWidth - 1) << 16) / ((int32)ui32DstWidth - 1);
	int32	i32DeltaY = (((int32)ui32SrcHeight - 1) << 16) / ((int32)ui32DstHeight - 1);

	if( ui32Bpp == 8 ) {

		uint8* pDst = pDstData;
		i32Y = 0;

		for( uint32 y = 0; y < ui32DstHeight; y++ ) {
			i32X = 0;
			uint8* pSrc = pSrcData + (i32Y >> 16) * (int32)ui32SrcWidth;
			for( uint32 x = 0; x < ui32DstWidth; x++ ) {
				*pDst++ = pSrc[i32X >> 16];
				i32X += i32DeltaX;
			}
			i32Y += i32DeltaY;
		}

	}
	else if( ui32Bpp == 24 ) {

		uint8* pDst = pDstData;
		i32Y = 0;

		for( uint32 y = 0; y < ui32DstHeight; y++ ) {
			i32X = 0;
			uint8* pSrc = pSrcData + ((i32Y >> 16) * ((int32)ui32SrcWidth * 3));
			for( uint32 x = 0; x < ui32DstWidth; x++ ) {
				uint8* pPix = &pSrc[(i32X >> 16) * 3];
				*pDst++ = pPix[0];
				*pDst++ = pPix[1];
				*pDst++ = pPix[2];
				i32X += i32DeltaX;
			}
			i32Y += i32DeltaY;
		}

	}
	else if( ui32Bpp == 32 ) {

		uint32* pDst = (uint32*)pDstData;
		i32Y = 0;

		for( uint32 y = 0; y < ui32DstHeight; y++ ) {
			i32X = 0;
			uint32* pSrc = ((uint32*)pSrcData) + ((i32Y >> 16) * (int32)ui32SrcWidth);
			for( uint32 x = 0; x < ui32DstWidth; x++ ) {
				*pDst++ = pSrc[i32X >> 16];
				i32X += i32DeltaX;
			}
			i32Y += i32DeltaY;
		}

	}

	return true;
}





bool
ImageResampleC::resample_bilinear( uint32 ui32Bpp,
							uint8* pSrcData, uint32 ui32SrcWidth, uint32 ui32SrcHeight,
							uint8* pDstData, uint32 ui32DstWidth, uint32 ui32DstHeight )
{

	if( ui32Bpp == 8 ) {

		uint8* pDst = pDstData;
		int32	i32Y = 0;
		int32	i32X = 0;
		int32	i32DeltaX = (((int32)ui32SrcWidth - 1) << 16) / ((int32)ui32DstWidth - 1);
		int32	i32DeltaY = (((int32)ui32SrcHeight - 1) << 16) / ((int32)ui32DstHeight - 1);

		for( uint32 y = 0; y < ui32DstHeight; y++ ) {
			i32X = 0;

			int32	i32IdxY = (i32Y >> 16);
			int32	i32IdxYNext = i32IdxY + 1;
			if( i32IdxYNext >= (int32)ui32SrcHeight )
				i32IdxYNext = (int32)ui32SrcHeight - 1;

			uint8* pSrc = pSrcData + (i32IdxY * (int32)ui32SrcWidth);
			uint8* pSrcNext = pSrc + (int32)ui32SrcWidth;

			int32	i32YFrac = i32Y & 0xffff;

			for( uint32 x = 0; x < ui32DstWidth; x++ ) {

				int32	i32IdxX = (i32X >> 16);
				int32	i32IdxXNext = i32IdxX + 1;
				if( i32IdxXNext >= (int32)ui32SrcWidth )
					i32IdxXNext = (int32)ui32SrcWidth - 1;

				int32	i32XFrac = i32X & 0xffff;

				uint8* pPix0 = &pSrc[i32IdxX];
				uint8* pPix1 = &pSrc[i32IdxXNext];
				uint8* pPix2 = &pSrcNext[i32IdxX];
				uint8* pPix3 = &pSrcNext[i32IdxXNext];

				int32	i32Tmp1, i32Tmp2;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;

				i32X += i32DeltaX;
			}
			i32Y += i32DeltaY;
		}

	}
	else if( ui32Bpp == 24 ) {

		uint8* pDst = pDstData;
		int32	i32Y = 0;
		int32	i32X = 0;
		int32	i32DeltaX = (((int32)ui32SrcWidth - 1) << 16) / ((int32)ui32DstWidth - 1);
		int32	i32DeltaY = (((int32)ui32SrcHeight - 1) << 16) / ((int32)ui32DstHeight - 1);

		int32	i32SrcWidth3 = (int32)(ui32SrcWidth - 1) * 3;

		for( uint32 y = 0; y < ui32DstHeight; y++ ) {
			i32X = 0;

			int32	i32IdxY = (i32Y >> 16);
			int32	i32IdxYNext = i32IdxY + 1;
			if( i32IdxYNext >= (int32)ui32SrcHeight )
				i32IdxYNext = (int32)ui32SrcHeight - 1;

			uint8* pSrc = pSrcData + (i32IdxY * ((int32)ui32SrcWidth * 3));
			uint8* pSrcNext = pSrc + (int32)ui32SrcWidth * 3;

			int32	i32YFrac = i32Y & 0xffff;

			for( uint32 x = 0; x < ui32DstWidth; x++ ) {

				int32	i32IdxX = (i32X >> 16) * 3;
				int32	i32IdxXNext = i32IdxX + 3;
				if( i32IdxXNext > i32SrcWidth3 )
					i32IdxXNext = i32SrcWidth3;

				int32	i32XFrac = i32X & 0xffff;

				uint8* pPix0 = &pSrc[i32IdxX];
				uint8* pPix1 = &pSrc[i32IdxXNext];
				uint8* pPix2 = &pSrcNext[i32IdxX];
				uint8* pPix3 = &pSrcNext[i32IdxXNext];

				int32	i32Tmp1, i32Tmp2;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;
				pPix0++; pPix1++; pPix2++; pPix3++;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;
				pPix0++; pPix1++; pPix2++; pPix3++;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;

				i32X += i32DeltaX;
			}
			i32Y += i32DeltaY;
		}

	}
	else if( ui32Bpp == 32 ) {

		uint8* pDst = pDstData;
		int32	i32Y = 0;
		int32	i32X = 0;
		int32	i32DeltaX = (((int32)ui32SrcWidth - 1) << 16) / ((int32)ui32DstWidth - 1);
		int32	i32DeltaY = (((int32)ui32SrcHeight - 1) << 16) / ((int32)ui32DstHeight - 1);
		int32	i32SrcWidth4 = (int32)(ui32SrcWidth - 1) * 4;

		for( uint32 y = 0; y < ui32DstHeight; y++ ) {
			i32X = 0;

			int32	i32IdxY = (i32Y >> 16);
			int32	i32IdxYNext = i32IdxY + 1;
			if( i32IdxYNext >= (int32)ui32SrcHeight )
				i32IdxYNext = (int32)ui32SrcHeight - 1;

			uint8* pSrc = pSrcData + (i32IdxY * ((int32)ui32SrcWidth * 4));
			uint8* pSrcNext = pSrc + (int32)ui32SrcWidth * 4;

			int32	i32YFrac = i32Y & 0xffff;

			for( uint32 x = 0; x < ui32DstWidth; x++ ) {

				int32	i32IdxX = (i32X >> 16) * 4;
				int32	i32IdxXNext = i32IdxX + 4;
				if( i32IdxXNext > i32SrcWidth4 )
					i32IdxXNext = i32SrcWidth4;

				int32	i32XFrac = i32X & 0xffff;

				uint8* pPix0 = &pSrc[i32IdxX];
				uint8* pPix1 = &pSrc[i32IdxXNext];
				uint8* pPix2 = &pSrcNext[i32IdxX];
				uint8* pPix3 = &pSrcNext[i32IdxXNext];

				int32	i32Tmp1, i32Tmp2;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;
				pPix0++; pPix1++; pPix2++; pPix3++;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;
				pPix0++; pPix1++; pPix2++; pPix3++;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;
				pPix0++; pPix1++; pPix2++; pPix3++;

				i32Tmp1 = ((*pPix1 * i32XFrac) + (*pPix0) * (0xffff - i32XFrac)) >> 16;
				i32Tmp2 = ((*pPix3 * i32XFrac) + (*pPix2) * (0xffff - i32XFrac)) >> 16;
				*pDst++ = (i32Tmp2 * i32YFrac + i32Tmp1 * (0xffff - i32YFrac)) >> 16;

				i32X += i32DeltaX;
			}
			i32Y += i32DeltaY;
		}

	}

	return true;
}
