/*
		  YUV変換→YをFFT→μνデータ表示→フィルタ→逆FFT
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <egb.h>
#include <math.h>
#include "tetujin.h"
#include "g_eff.h"
#include "fft.h"
#include "fftspt.h"

#define NOERR 0		/* no error */

static fftFlg = 0 ;	/* g_fft2実行後:1, g_fft2_inv実行後:2,
						   g_fft2_clr実行後:0 */

// ワーク & バッファ
static char *buffer ;
static double *aReal, *aImag ;
static double *bReal, *bImag ;
static char *work ;
static char *cb, *cr ;
static int *a_mul ;

static int exp2 = 0, length ;

static int mx ;
static int aSen ;
static int mSen ;
static int cMax ;
static int aMax ;
static int x1 ;
static int y1 ;
static int x2 ;
static int y2 ;
static int (*read1)() ;
static int (*write)() ;
static int (*mask)() ;

g_fft2_readFlg()
{
	return fftFlg ;
}

g_fft2( BASICPARA *para, int ex )
{
	mx = para->mix ;
	aSen = para->alphaSen ;
	mSen = para->maskSen ;
	cMax = para->colorMax ;
	aMax = para->alphaMax ;
	x1 = para->lupx ;
	y1 = para->lupy ;
//	x2 = para->rdwx ;
//	y2 = para->rdwy ;
	read1 = para->read1 ;
	write = para->write ;
	mask = para->mask ;

	int i, j, size ;

	length = 1 << ex ;
	exp2 = ex ;

	if( fftFlg )
		TL_free( buffer ) ;
	fftFlg = 0 ;

	size = length*length*sizeof( double )* 4 + sizeof( double )*length*3
	     + length*length * 2 + length*length*sizeof( int ) ;

	if( (buffer = (char *)TL_malloc( size )) == NULL )
		return OUT_OF_MEMORY ;

	aReal = (double *)buffer ;
	aImag = aReal + length*length ;
	bReal = aImag + length*length ;
	bImag = bReal + length*length ;
	work  = (char *)(bImag + length*length) ;
	cb = work + sizeof( double )*length*3 ;
	cr = cb + length*length ;
	a_mul = (int *)( cr + length*length) ;

	fftFlg = 1 ;

	for( i=0 ; i<length ; i++ )
	{
		for( j=0 ; j<length ; j++ )
		{
			char a[4] ;
			int y0, u0, v0 ;

			read1( x1+j, y1+i, a ) ;

			rgbToYuv( a[0], a[1], a[2], &y0, &u0, &v0, cMax ) ;

			aReal[ j + i*length ] = (double)y0 ;
			aImag[ j + i*length ] = 0 ;

			cb[ j + i*length ] = u0 ;
			cr[ j + i*length ] = v0 ;
			a_mul[ j + i*length ] = 0x10000 ;
		}
	}

	fft_2( work, aReal, aImag, ex, 1 ) ;

	fdsp() ;

	return NOERR ;
}

g_fft2_mul( BASICPARA *para, int rate )
{
	mx = para->mix ;
	aSen = para->alphaSen ;
	mSen = para->maskSen ;
	cMax = para->colorMax ;
	aMax = para->alphaMax ;
//	x1 = para->lupx ;
//	y1 = para->lupy ;
//	x2 = para->rdwx ;
//	y2 = para->rdwy ;
	read1 = para->read1 ;
	write = para->write ;
	mask = para->mask ;

	int i, j, ex ;

	if( fftFlg == 0 )return NOERR ;

	ex = exp2 ;
	if( ex == 0 )return NOERR ;

	for( i=0 ; i<length ; i++ )
	{
		for( j=0 ; j<length ; j++ )
		{
			int i2, j2 ;
			char a[4] ;

			read1( x1+j, y1+i, a ) ;

			if( a[3] )
			{
				a_mul[ j + i*length ] = 0x10000 * rate / 256 ;
				i2 = length - i ;
				j2 = length - j ;
				if( ( i2<length ) && ( j2<length ) )
					a_mul[ j2 + i2*length ] = a_mul[ j + i*length ] ;
			}
		}
	}
	fdsp() ;
	fftFlg = 1 ;

	return NOERR ;
}

g_fft2_fix( BASICPARA *para )
{
	mx = para->mix ;
	aSen = para->alphaSen ;
	mSen = para->maskSen ;
	cMax = para->colorMax ;
	aMax = para->alphaMax ;
//	x1 = para->lupx ;
//	y1 = para->lupy ;
//	x2 = para->rdwx ;
//	y2 = para->rdwy ;
	read1 = para->read1 ;
	write = para->write ;
	mask = para->mask ;

	int i, j, ex ;

	if( fftFlg == 0 )return NOERR ;

	ex = exp2 ;
	if( ex == 0 )return NOERR ;

	for( i=0 ; i<length ; i++ )
	{
		for( j=0 ; j<length ; j++ )
		{
			aReal[ j + i*length ]
			= aReal[ j + i*length ] * a_mul[ j + i*length ] / 0x10000 ;

			aImag[ j + i*length ]
			= aImag[ j + i*length ] * a_mul[ j + i*length ] / 0x10000 ;

			a_mul[ j + i*length ] = 0x10000 ;
		}
	}
	fdsp() ;
	fftFlg = 1 ;

	return NOERR ;
}

g_fft2_can( BASICPARA *para )
{
	mx = para->mix ;
	aSen = para->alphaSen ;
	mSen = para->maskSen ;
	cMax = para->colorMax ;
	aMax = para->alphaMax ;
//	x1 = para->lupx ;
//	y1 = para->lupy ;
//	x2 = para->rdwx ;
//	y2 = para->rdwy ;
	read1 = para->read1 ;
	write = para->write ;
	mask = para->mask ;

	int i, j, ex ;

	if( fftFlg == 0 )return NOERR ;

	ex = exp2 ;
	if( ex == 0 )return NOERR ;

	for( i=0 ; i<length ; i++ )
	{
		for( j=0 ; j<length ; j++ )
		{
			a_mul[ j + i*length ] = 0x10000 ;
		}
	}
	fdsp() ;
	fftFlg = 1 ;

	return NOERR ;
}

g_fft2_inv( BASICPARA *para )
{
	mx = para->mix ;
	aSen = para->alphaSen ;
	mSen = para->maskSen ;
	cMax = para->colorMax ;
	aMax = para->alphaMax ;
//	x1 = para->lupx ;
//	y1 = para->lupy ;
//	x2 = para->rdwx ;
//	y2 = para->rdwy ;
	read1 = para->read1 ;
	write = para->write ;
	mask = para->mask ;

	int i, j, ex ;

	if( fftFlg != 1 )return NOERR ;

	ex = exp2 ;
	if( ex == 0 )return NOERR ;

	for( i=0 ; i<length ; i++ )
	{
		for( j=0 ; j<length ; j++ )
		{
			bReal[ j + i*length ]
			= aReal[ j + i*length ] * a_mul[ j + i*length ] / 0x10000 ;

			bImag[ j + i*length ]
			= aImag[ j + i*length ] * a_mul[ j + i*length ] / 0x10000 ;
		}
	}

	fft_2( work, bReal, bImag, ex, -1 ) ;

	for( i=0 ; i<length ; i++ )
	{
		for( j=0 ; j<length ; j++ )
		{
			char a[4] ;
			int y0, r0, g0, b0 ;

			y0 = bReal[ j + i*length ] ;
			yuvToRgb( y0, cb[ j + i*length ], cr[ j + i*length ],
											&r0, &g0, &b0, cMax ) ;
			a[0] = r0 ;
			a[1] = g0 ;
			a[2] = b0 ;
			a[3] = 0 ;

			write( x1+j, y1+i, a ) ;
		}
	}

	fftFlg = 2 ;

	return NOERR ;
}

g_fft2_dsp( BASICPARA *para )
{
	mx = para->mix ;
	aSen = para->alphaSen ;
	mSen = para->maskSen ;
	cMax = para->colorMax ;
	aMax = para->alphaMax ;
//	x1 = para->lupx ;
//	y1 = para->lupy ;
//	x2 = para->rdwx ;
//	y2 = para->rdwy ;
	read1 = para->read1 ;
	write = para->write ;
	mask = para->mask ;

	if( fftFlg != 2 )return NOERR ;

	fdsp() ;
	fftFlg = 1 ;

	return NOERR ;
}

g_fft2_clr()
{
	if( fftFlg )
		TL_free( buffer ) ;
	fftFlg = 0 ;

	return NOERR ;
}

static int fdsp()
{
	int i, j ;

	for( i=0 ; i<length ; i++ )
	{
		for( j=0 ; j<length ; j++ )
		{
			char a[4] ;
			double abs ;

			abs = aReal[ j + i*length ]*aReal[ j + i*length ]
			     + aImag[ j + i*length ]*aImag[ j + i*length ] ;
			abs = sqrt( abs ) * a_mul[ j + i*length ] / 0x10000 ;
			abs = log( abs ) * 255 / log( 255.0 ) ;
			if( abs > 255 )abs = 255 ;
			if( abs < 0 )abs = 0 ;
			a[0] = abs ;
			a[1] = abs ;
			a[2] = abs ;
			write( x1+j, y1+i, a ) ;
		}
	}

	return NOERR ;
}

static rgbToYuv( int r0, int g0, int b0, int *y0, int *u0, int *v0, int max )
{
	int y, cb, cr ;

	y  =  19595*r0 + 38470*g0 + 7471*b0 ;
	cb = -11049*r0 - 21699*g0 + 32748*b0 ;
	cr =  32755*r0 -27427*g0 -5328*b0 ;

	*y0 = ( ((y/max)*219) >> 16 ) + 16 ;
	*u0 = ( ((cb/max)*224) >> 16 ) + 128 ;
	*v0 = ( ((cr/max)*224) >> 16 ) + 128 ;

	if( *y0 < 0 )*y0 = 0 ;
	if( *y0 > 255 )*y0 = 255 ;
	if( *u0 < 0 )*u0 = 0 ;
	if( *u0 > 255 )*u0 = 255 ;
	if( *v0 < 0 )*v0 = 0 ;
	if( *v0 > 255 )*v0 = 255 ;

	return NOERR ;
}

static yuvToRgb( int y0, int u0, int v0, int *r0, int *g0, int *b0, int max )
{
	y0 = (( y0 - 16 ) * max )/219 ;
	u0 = (( u0 -128 ) * max )/224 ;
	v0 = (( v0 -128 ) * max )/224 ;

	*r0 = ( 65536*y0 + 4*u0 + 91920*v0 ) >> 16 ;
	*g0 = ( 65536*y0 - 22569*u0 - 46819*v0 ) >> 16 ;
	*b0 = ( 65536*y0 + 116198*u0 - 9*v0 ) >> 16 ;

	if( *r0 < 0 )*r0 = 0 ;
	if( *r0 > max )*r0 = max ;
	if( *g0 < 0 )*g0 = 0 ;
	if( *g0 > max )*g0 = max ;
	if( *b0 < 0 )*b0 = 0 ;
	if( *b0 > max )*b0 = max ;

	return NOERR ;
}

