/*
		graphic effect lib.
		  Fazzy Legato

		h. Toda 1994 2 6
*/

#include <stdio.h>
#include <stdlib.h>
#include <egb.h>
#include "g_eff.h"

#define NOERR 0		/* no error */

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 (*read2)() ;
static int (*write)() ;
static int (*mask)() ;

static int md ;
static int fSen ;

g_fuzzyLegato( BASICPARA *para, int mode, int fuzzySen )
{
	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 ;
	read2 = para->read2 ;
	write = para->write ;
	mask = para->mask ;

	md = mode ;
	fSen = fuzzySen ;

	switch( md )
	{
	case 0:
	case 1:
		smooth() ;
		break ;
	case 2:
		smooth_a() ;
		break ;
	case 3:
		smooth_a() ;
		smooth() ;
		break ;
	default:
		smooth() ;
		break ;
	}

	return NOERR ;
}


/* RGB data 処理 */

static smooth()
{
	unsigned char a[4], b[4], c[4], d[4] ;
	int cmp, start, mid, fine, mode, s, x, y ;
	int k0, k1, k2 ;
	int smid ;

	s = ( 256*(cMax+1) - fSen*(cMax+1) ) / 256 ;		/* sharp rate */
	smid = cMax * 96 / 256 ;

	for( y=y1+1 ; y<=y2-1 ; y++ )	/* 原画の転送 */
	{
		for( x=x1+1 ; x<=x2-1 ; x++ )
		{
			if( (mSen == 0) || (mask( x, y ) < mSen) )
			{
				read1( x, y, a ) ;
				read2( x, y, b ) ;
				a[3] = b[3] ;
				if( aSen )
				{
					if( b[3] )
					{
						write( x, y, a ) ;
					}
				}
				else
				{
					write( x, y, a ) ;
				}
			}
		}
	}

	for( y=y1+1 ; y<=y2-1 ; y++ )
	{
		mode = 0;
		for( x=x1+1 ; x<=x2-1 ; x++ )
		{
			read1( x,   y,   a ) ;
			read1( x,   y+1, b ) ;
			read1( x+1, y,   c ) ;
			read1( x+1, y-1, d ) ;
			cmp = cmpdata( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = x;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata( a, d, s ) == 0) )
			{
				mode = 0;
				fine = x;
				smooth1( start, mid, fine, y );
				x = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki( x, y );
			  if( cmpdata(a,c,s) )
			  {
			    if( (k1 <= k0) && (k1 < 0) )
			    {
			      k2 = katamuki( x+1, y );
			      if( (k1 <= k2) || (cmpdata(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = x;
			      }
			    }
			  }
			  k0 = k1;

			  if( x == x2-1 )		/* 最後の例外処理 1994 2 8 に追加 */
			  {
			  	mode = 2 ;
			  	mid = x ;
			  }

			}
//			if( (mode == 2) && (cmpdata( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata( c, d, s ) == 0) || (x == x2-1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = x;
				smooth1( start, mid, fine, y );
				x = mid;
			}
		}
	}

	for( y=y1+1 ; y<=y2-1 ; y++ )
	{
		mode = 0;
		for( x=x2-1 ; x>=x1+1 ; x-- )
		{
			read1( x,   y,   a ) ;
			read1( x,   y+1, b ) ;
			read1( x-1, y,   c ) ;
			read1( x-1, y-1, d ) ;
			cmp = cmpdata( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = x;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata( a, d, s ) == 0) )
			{
				mode = 0;
				fine = x;
				smooth2( start, mid, fine, y );
				x = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki( x, y );
			  if( cmpdata(a,c,s) )
			  {
			    if( (k1 >= k0) && (k1 > 0) )
			    {
			      k2 = katamuki( x-1, y );
			      if( (k1 >= k2) || (cmpdata(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = x;
			      }
			    }
			  }
			  k0 = k1;

			  if( x == x1+1 )		/* 最後の例外処理 */
			  {
			  	mode = 2 ;
			  	mid = x ;
			  }

			}
//			if( (mode == 2) && (cmpdata( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata( c, d, s ) == 0) || (x == x1+1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = x;
				smooth2( start, mid, fine, y );
				x = mid;
			}
		}
	}

	for( x=x1+1 ; x<=x2-1 ; x++ )
	{
		mode = 0;
		for( y=y1+1 ; y<=y2-1 ; y++ )
		{
			read1( x,   y,   a ) ;
			read1( x+1, y,   b ) ;
			read1( x,   y+1, c ) ;
			read1( x-1, y+1, d ) ;
			cmp = cmpdata( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = y;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata( a, d, s ) == 0) )
			{
				mode = 0;
				fine = y;
				smooth3( start, mid, fine, x );
				y = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki( x, y );
			  if( cmpdata(a,c,s) )
			  {
			    if( (k1 <= k0) && (k1 < 0) )
			    {
			      k2 = katamuki( x, y+1 );
			      if( (k1 <= k2) || (cmpdata(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = y;
			      }
			    }
			  }
			  k0 = k1;

			  if( y == y2-1 )		/* 最後の例外処理 */
			  {
			  	mode = 2 ;
			  	mid = y ;
			  }

			}
//			if( (mode == 2) && (cmpdata( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata( c, d, s ) == 0) || (y == y2-1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = y;
				smooth3( start, mid, fine, x );
				y = mid;
			}
		}
	}

	for( x=x2-1 ; x>=x1+1 ; x-- )
	{
		mode = 0;
		for( y=y1+1 ; y<=y2-1 ; y++ )
		{
			read1( x,   y,   a ) ;
			read1( x-1, y,   b ) ;
			read1( x,   y+1, c ) ;
			read1( x+1, y+1, d ) ;
			cmp = cmpdata( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = y;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata( a, d, s ) == 0) )
			{
				mode = 0;
				fine = y;
				smooth4( start, mid, fine, x );
				y = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki( x, y );
			  if( cmpdata(a,c,s) )
			  {
			    if( (k1 >= k0) && (k1 > 0) )
			    {
			      k2 = katamuki( x, y+1 );
			      if( (k1 >= k2) || (cmpdata(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = y;
			      }
			    }
			  }
			  k0 = k1;

			  if( y == y2-1 )		/* 最後の例外処理 */
			  {
			  	mode = 2 ;
			  	mid = y ;
			  }

			}
//			if( (mode == 2) && (cmpdata( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata( c, d, s ) == 0) || (y == y2-1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = y;
				smooth4( start, mid, fine, x );
				y = mid;
			}
		}
	}
	return NOERR;
}

static katamuki( x, y )		/* return=(katamuki + or 0 or -) s=rate */
int x, y;
{
	unsigned char p[3][3][4];
	int ck;

	ck = 0;

	if( (x <= 0) || (y <= 0) )
		return 0 ;

	read1( x-1, y-1, p[0][0] ) ;
	read1( x,   y-1, p[0][1] ) ;
	read1( x+1, y-1, p[0][2] ) ;
	read1( x-1, y,   p[1][0] ) ;
	read1( x,   y,   p[1][1] ) ;
	read1( x+1, y,   p[1][2] ) ;
	read1( x-1, y+1, p[2][0] ) ;
	read1( x,   y+1, p[2][1] ) ;
	read1( x+1, y+1, p[2][2] ) ;
	ck = ck - kata_s( p[0][0], p[1][1] );
	ck = ck - kata_s( p[0][1], p[1][2] );
	ck = ck - kata_s( p[1][0], p[2][1] );
	ck = ck - kata_s( p[1][1], p[2][2] );

	ck = ck + kata_s( p[0][1], p[1][0] );
	ck = ck + kata_s( p[0][2], p[1][1] );
	ck = ck + kata_s( p[1][1], p[2][0] );
	ck = ck + kata_s( p[1][2], p[2][1] );

	return ck;
}

static kata_s( a, b )		/* total abs(sub) */
unsigned char *a, *b;
{
	int subd, add;

	subd = (int)b[0] - (int)a[0] ;
	if( subd < 0 )subd = -subd ;
	add = subd ;
	subd = (int)b[1] - (int)a[1] ;
	if( subd < 0 )subd = -subd ;
	add = add + subd ;
	subd = (int)b[2] - (int)a[2] ;
	if( subd < 0 )subd = -subd ;
	add = add + subd ;
	return add;
}

static cmpdata( a, b, rate )
unsigned char *a, *b;
int rate;
{
	int subd;

	subd = (int)b[0] - (int)a[0] ;
	if( subd < 0 )subd = -subd ;
	if( subd > rate )return 1;
	subd = (int)b[1] - (int)a[1] ;
	if( subd < 0 )subd = -subd ;
	if( subd > rate )return 1;
	subd = (int)b[2] - (int)a[2] ;
	if( subd < 0 )subd = -subd ;
	if( subd > rate )return 1;
	return 0 ;
}

static smooth1( st, md, fn, y )
int st, md, fn, y;
{
	int x1, x2, x3;
	int i, n, rate;
	unsigned char a[4], b[4], c[4], d[4] ;

	x1 = ( st + md ) >> 1;
	x2 = md;
	x3 = ( md + fn + 1 ) >> 1;
	if( x1 == x2 )goto smoo1;
	rate = 128/(x2-x1+1);
	n = 1;
	for( i=x1 ; i<=x2-1 ; i++ ){
		read1( i, y+1, a ) ;
		read2( i, y,   b ) ;
		mix( a, b, n*rate, c ) ;
		if( aSen )
		{
//			read1( i, y, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( i, y ) < mSen) )
		{
			write( i, y, c ) ;
		}
		n++;
	}
	if( x2 == x3 )goto smoo2;
smoo1:
	if( x2 == x3 )return 0;
	rate = 128/(x3-x2+1);
	n = 1;
	for( i=x2+1 ; i<=x3 ; i++ ){
		read1( i, y-1, a ) ;
		read2( i, y,   b ) ;
		mix( a, b, (128 - n*rate), c ) ;
		if( aSen )
		{
//			read1( i, y, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( i, y ) < mSen) )
		{
			write( i, y, c ) ;
		}
		n++;
	}
smoo2:
	read2( x2+1, y, a ) ;
	read2( x2-1, y, b ) ;
	mix( a, b, 128, c ) ;
	read2( x2,   y, b ) ;
	if( aSen )
	{
//		read1( x2, y, d ) ;
//		mix( c, b, d[3]*mx/aMax, c ) ;
		mix( c, b, b[3]*mx/aMax, c ) ;
	}
	else
	{
		mix( c, b, mx, c ) ;
	}
	c[3] = b[3] ;
	if( (mSen == 0) || (mask( x2, y ) < mSen) )
	{
		write( x2, y, c ) ;
	}
	return 0;
}

static smooth2( st, md, fn, y )
int st, md, fn, y;
{
	int x1, x2, x3;
	int i, n, rate ;
	unsigned char a[4], b[4], c[4], d[4] ;

	x1 = ( st + md + 1 ) >> 1;
	x2 = md;
	x3 = ( md + fn ) >> 1;
	if( x1 == x2 )goto smoo1;
	rate = 128/(x1-x2+1);
	n = 1;
	for( i=x1 ; i>=x2+1 ; i-- ){
		read1( i, y+1, a ) ;
		read2( i, y,   b ) ;
		mix( a, b, n*rate, c ) ;
		if( aSen )
		{
//			read1( i, y, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( i, y ) < mSen) )
		{
			write( i, y, c ) ;
		}
		n++;
	}
	if( x2 == x3 )goto smoo2;
smoo1:
	if( x2 == x3 )return 0;
	rate = 128/(x2-x3+1);
	n = 1;
	for( i=x2-1 ; i>=x3 ; i-- ){
		read1( i, y-1, a ) ;
		read2( i, y,   b ) ;
		mix( a, b, (128 - n*rate), c ) ;
		if( aSen )
		{
//			read1( i, y, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( i, y ) < mSen) )
		{
			write( i, y, c ) ;
		}
		n++;
	}
smoo2:
	read2( x2+1, y, a ) ;
	read2( x2-1, y, b ) ;
	mix( a, b, 128, c ) ;
	read2( x2,   y, b ) ;
	if( aSen )
	{
//		read1( x2, y, d ) ;
//		mix( c, b, d[3]*mx/aMax, c ) ;
		mix( c, b, b[3]*mx/aMax, c ) ;
	}
	else
	{
		mix( c, b, mx, c ) ;
	}
	c[3] = b[3] ;
	if( (mSen == 0) || (mask( x2, y ) < mSen) )
	{
		write( x2, y, c ) ;
	}
	return 0;
}

static smooth3( st, md, fn, x )
int st, md, fn, x;
{
	int y1, y2, y3;
	int i, n, rate;
	unsigned char a[4], b[4], c[4], d[4] ;

	y1 = ( st + md ) >> 1;
	y2 = md;
	y3 = ( md + fn ) >> 1;
	if( y1 == y2 )goto smoo1;
	rate = 128/(y2-y1+1);
	n = 1;
	for( i=y1 ; i<=y2-1 ; i++ ){
		read1( x+1, i, a ) ;
		read2( x,   i, b ) ;
		mix( a, b, n*rate, c ) ;
		if( aSen )
		{
//			read1( x, i, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( x, i ) < mSen) )
		{
			write( x, i, c ) ;
		}
		n++;
	}
	if( y2 == y3 )goto smoo2;
smoo1:
	if( y2 == y3 )return 0;
	rate = 128/(y3-y2+1);
	n = 1;
	for( i=y2+1 ; i<=y3 ; i++ ){
		read1( x-1, i, a ) ;
		read2( x,   i, b ) ;
		mix( a, b, (128 - n*rate), c ) ;
		if( aSen )
		{
//			read1( x, i, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( x, i ) < mSen) )
		{
			write( x, i, c ) ;
		}
		n++;
	}
smoo2:
	read2( x, y2+1, a ) ;
	read2( x, y2-1, b ) ;
	mix( a, b, 128, c ) ;
	read2( x, y2,   b ) ;
	if( aSen )
	{
//		read1( x, y2, d ) ;
//		mix( c, b, d[3]*mx/aMax, c ) ;
		mix( c, b, b[3]*mx/aMax, c ) ;
	}
	else
	{
		mix( c, b, mx, c ) ;
	}
	c[3] = b[3] ;
	if( (mSen == 0) || (mask( x, y2 ) < mSen) )
	{
		write( x, y2, c ) ;
	}
	return 0;
}

static smooth4( st, md, fn, x )
int st, md, fn, x;
{
	int y1, y2, y3;
	int i, n, rate;
	unsigned char a[4], b[4], c[4], d[4] ;

	y1 = ( st + md ) >> 1;
	y2 = md;
	y3 = ( md + fn ) >> 1;
	if( y1 == y2 )goto smoo1;
	rate = 128/(y2-y1+1);
	n = 1;
	for( i=y1 ; i<=y2-1 ; i++ ){
		read1( x-1, i, a ) ;
		read2( x,   i, b ) ;
		mix( a, b, n*rate, c ) ;
		if( aSen )
		{
//			read1( x, i, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( x, i ) < mSen) )
		{
			write( x, i, c ) ;
		}
		n++;
	}
	if( y2 == y3 )goto smoo2;
smoo1:
	if( y2 == y3 )return 0;
	rate = 128/(y3-y2+1);
	n = 1;
	for( i=y2+1 ; i<=y3 ; i++ ){
		read1( x+1, i, a ) ;
		read2( x,   i, b ) ;
		mix( a, b, (128 - n*rate), c ) ;
		if( aSen )
		{
//			read1( x, i, d ) ;
//			mix( c, b, d[3]*mx/aMax, c ) ;
			mix( c, b, b[3]*mx/aMax, c ) ;
		}
		else
		{
			mix( c, b, mx, c ) ;
		}
		c[3] = b[3] ;
		if( (mSen == 0) || (mask( x, i ) < mSen) )
		{
			write( x, i, c ) ;
		}
		n++;
	}
smoo2:
	read2( x, y2+1, a ) ;
	read2( x, y2-1, b ) ;
	mix( a, b, 128, c ) ;
	read2( x, y2,   b ) ;
	if( aSen )
	{
//		read1( x, y2, d ) ;
//		mix( c, b, d[3]*mx/aMax, c ) ;
		mix( c, b, b[3]*mx/aMax, c ) ;
	}
	else
	{
		mix( c, b, mx, c ) ;
	}
	c[3] = b[3] ;
	if( (mSen == 0) || (mask( x, y2 ) < mSen) )
	{
		write( x, y2, c ) ;
	}
	return 0;
}

static mix( a, b, rate, c )	/* rate ( 0-256 ) */
int rate ;
unsigned char *a, *b, *c ;
{
	if( rate < 0 )
		rate = 0 ;
	if( rate > 256 )
		rate = 256 ;

	c[0] = ( a[0] * rate + b[0] * (256-rate) + 0x80 ) >> 8 ;
	c[1] = ( a[1] * rate + b[1] * (256-rate) + 0x80 ) >> 8 ;
	c[2] = ( a[2] * rate + b[2] * (256-rate) + 0x80 ) >> 8 ;

	return NOERR ;
}


/* alpha data 処理 */

static smooth_a()
{
	unsigned char a[4], b[4], c[4], d[4] ;
	int cmp, start, mid, fine, mode, s, x, y ;
	int k0, k1, k2 ;
	int smid ;

	s = ( 256*(aMax+1) - fSen*(aMax+1) ) / 256 ;		/* sharp rate */
	smid = aMax * 96 / 256 ;

	for( y=y1+1 ; y<=y2-1 ; y++ )	/* 原画の転送 */
	{
		for( x=x1+1 ; x<=x2-1 ; x++ )
		{
			read1( x, y, a ) ;
			read2( x, y, b ) ;
			a[0] = b[0] ;
			a[1] = b[1] ;
			a[2] = b[2] ;
			write( x, y, a ) ;
		}
	}

	for( y=y1+1 ; y<=y2-1 ; y++ )
	{
		mode = 0;
		for( x=x1+1 ; x<=x2-1 ; x++ )
		{
			read1( x,   y,   a ) ;
			read1( x,   y+1, b ) ;
			read1( x+1, y,   c ) ;
			read1( x+1, y-1, d ) ;
			cmp = cmpdata_a( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = x;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata_a( a, d, s ) == 0) )
			{
				mode = 0;
				fine = x;
				smooth1_a( start, mid, fine, y );
				x = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki_a( x, y );
			  if( cmpdata_a(a,c,s) )
			  {
			    if( (k1 <= k0) && (k1 < 0) )
			    {
			      k2 = katamuki_a( x+1, y );
			      if( (k1 <= k2) || (cmpdata_a(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = x;
			      }
			    }
			  }
			  k0 = k1;

			  if( x == x2-1 )		/* 最後の例外処理 1994 2 8 に追加 */
			  {
			  	mode = 2 ;
			  	mid = x ;
			  }

			}
//			if( (mode == 2) && (cmpdata_a( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata_a( c, d, s ) == 0) || (x == x2-1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = x;
				smooth1_a( start, mid, fine, y );
				x = mid;
			}
		}
	}

	for( y=y1+1 ; y<=y2-1 ; y++ )
	{
		mode = 0;
		for( x=x2-1 ; x>=x1+1 ; x-- )
		{
			read1( x,   y,   a ) ;
			read1( x,   y+1, b ) ;
			read1( x-1, y,   c ) ;
			read1( x-1, y-1, d ) ;
			cmp = cmpdata_a( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = x;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata_a( a, d, s ) == 0) )
			{
				mode = 0;
				fine = x;
				smooth2_a( start, mid, fine, y );
				x = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki_a( x, y );
			  if( cmpdata_a(a,c,s) )
			  {
			    if( (k1 >= k0) && (k1 > 0) )
			    {
			      k2 = katamuki_a( x-1, y );
			      if( (k1 >= k2) || (cmpdata_a(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = x;
			      }
			    }
			  }
			  k0 = k1;

			  if( x == x1+1 )		/* 最後の例外処理 */
			  {
			  	mode = 2 ;
			  	mid = x ;
			  }

			}
//			if( (mode == 2) && (cmpdata_a( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata_a( c, d, s ) == 0) || (x == x1+1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = x;
				smooth2_a( start, mid, fine, y );
				x = mid;
			}
		}
	}

	for( x=x1+1 ; x<=x2-1 ; x++ )
	{
		mode = 0;
		for( y=y1+1 ; y<=y2-1 ; y++ )
		{
			read1( x,   y,   a ) ;
			read1( x+1, y,   b ) ;
			read1( x,   y+1, c ) ;
			read1( x-1, y+1, d ) ;
			cmp = cmpdata_a( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = y;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata_a( a, d, s ) == 0) )
			{
				mode = 0;
				fine = y;
				smooth3_a( start, mid, fine, x );
				y = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki_a( x, y );
			  if( cmpdata_a(a,c,s) )
			  {
			    if( (k1 <= k0) && (k1 < 0) )
			    {
			      k2 = katamuki_a( x, y+1 );
			      if( (k1 <= k2) || (cmpdata_a(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = y;
			      }
			    }
			  }
			  k0 = k1;

			  if( y == y2-1 )		/* 最後の例外処理 */
			  {
			  	mode = 2 ;
			  	mid = y ;
			  }

			}
//			if( (mode == 2) && (cmpdata_a( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata_a( c, d, s ) == 0) || (y == y2-1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = y;
				smooth3_a( start, mid, fine, x );
				y = mid;
			}
		}
	}

	for( x=x2-1 ; x>=x1+1 ; x-- )
	{
		mode = 0;
		for( y=y1+1 ; y<=y2-1 ; y++ )
		{
			read1( x,   y,   a ) ;
			read1( x-1, y,   b ) ;
			read1( x,   y+1, c ) ;
			read1( x+1, y+1, d ) ;
			cmp = cmpdata_a( a, b, s );
			if( (mode == 0) && cmp )
			{
				mode = 1;
				start = y;
				k0 = 0;
			}
			if( (mode == 1) && (cmp == 0) )
				mode = 0;
			if( (mode == 2) && (cmpdata_a( a, d, s ) == 0) )
			{
				mode = 0;
				fine = y;
				smooth4_a( start, mid, fine, x );
				y = mid;
			}
			if( mode == 1 )
			{
			  k1 = katamuki_a( x, y );
			  if( cmpdata_a(a,c,s) )
			  {
			    if( (k1 >= k0) && (k1 > 0) )
			    {
			      k2 = katamuki_a( x, y+1 );
			      if( (k1 >= k2) || (cmpdata_a(b,c,smid) == 0) )
			      {
					mode = 2;
					mid = y;
			      }
			    }
			  }
			  k0 = k1;

			  if( y == y2-1 )		/* 最後の例外処理 */
			  {
			  	mode = 2 ;
			  	mid = y ;
			  }

			}
//			if( (mode == 2) && (cmpdata_a( c, d, s ) == 0) )
			if( (mode == 2) && ( (cmpdata_a( c, d, s ) == 0) || (y == y2-1) ) )
			{								  /* 最後の例外処理↑ */
				mode = 0;
				fine = y;
				smooth4_a( start, mid, fine, x );
				y = mid;
			}
		}
	}
	return NOERR;
}

static katamuki_a( x, y )		/* return=(katamuki + or 0 or -) s=rate */
int x, y;
{
	unsigned char p[3][3][4];
	int ck;

	ck = 0;

	if( (x <= 0) || (y <= 0) )
		return 0 ;

	read1( x-1, y-1, p[0][0] ) ;
	read1( x,   y-1, p[0][1] ) ;
	read1( x+1, y-1, p[0][2] ) ;
	read1( x-1, y,   p[1][0] ) ;
	read1( x,   y,   p[1][1] ) ;
	read1( x+1, y,   p[1][2] ) ;
	read1( x-1, y+1, p[2][0] ) ;
	read1( x,   y+1, p[2][1] ) ;
	read1( x+1, y+1, p[2][2] ) ;
	ck = ck - kata_s_a( p[0][0], p[1][1] );
	ck = ck - kata_s_a( p[0][1], p[1][2] );
	ck = ck - kata_s_a( p[1][0], p[2][1] );
	ck = ck - kata_s_a( p[1][1], p[2][2] );

	ck = ck + kata_s_a( p[0][1], p[1][0] );
	ck = ck + kata_s_a( p[0][2], p[1][1] );
	ck = ck + kata_s_a( p[1][1], p[2][0] );
	ck = ck + kata_s_a( p[1][2], p[2][1] );

	return ck;
}

static kata_s_a( a, b )		/* total abs(sub) */
unsigned char *a, *b;
{
	int subd;

	subd = (int)b[3] - (int)a[3] ;
	if( subd < 0 )subd = -subd ;
	return subd;
}

static cmpdata_a( a, b, rate )
unsigned char *a, *b;
int rate;
{
	int subd;

	subd = (int)b[3] - (int)a[3] ;
	if( subd < 0 )subd = -subd ;
	if( subd > rate )return 1;
	return 0 ;
}

static smooth1_a( st, md, fn, y )
int st, md, fn, y;
{
	int x1, x2, x3;
	int i, n, rate;
	unsigned char a[4], b[4], c[4] ;

	x1 = ( st + md ) >> 1;
	x2 = md;
	x3 = ( md + fn + 1 ) >> 1;
	if( x1 == x2 )goto smoo1;
	rate = 128/(x2-x1+1);
	n = 1;
	for( i=x1 ; i<=x2-1 ; i++ ){
		read1( i, y+1, a ) ;
		read2( i, y,   b ) ;
		mix_a( a, b, n*rate, c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( i, y, b ) ;
		n++;
	}
	if( x2 == x3 )goto smoo2;
smoo1:
	if( x2 == x3 )return 0;
	rate = 128/(x3-x2+1);
	n = 1;
	for( i=x2+1 ; i<=x3 ; i++ ){
		read1( i, y-1, a ) ;
		read2( i, y,   b ) ;
		mix_a( a, b, (128 - n*rate), c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( i, y, b ) ;
		n++;
	}
smoo2:
	read2( x2+1, y, a ) ;
	read2( x2-1, y, b ) ;
	mix_a( a, b, 128, c ) ;
	read2( x2,   y, b ) ;
	mix_a( c, b, mx, c ) ;
	b[3] = c[3] ;
	write( x2, y, b ) ;
	return 0;
}

static smooth2_a( st, md, fn, y )
int st, md, fn, y;
{
	int x1, x2, x3;
	int i, n, rate ;
	unsigned char a[4], b[4], c[4] ;

	x1 = ( st + md + 1 ) >> 1;
	x2 = md;
	x3 = ( md + fn ) >> 1;
	if( x1 == x2 )goto smoo1;
	rate = 128/(x1-x2+1);
	n = 1;
	for( i=x1 ; i>=x2+1 ; i-- ){
		read1( i, y+1, a ) ;
		read2( i, y,   b ) ;
		mix_a( a, b, n*rate, c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( i, y, b ) ;
		n++;
	}
	if( x2 == x3 )goto smoo2;
smoo1:
	if( x2 == x3 )return 0;
	rate = 128/(x2-x3+1);
	n = 1;
	for( i=x2-1 ; i>=x3 ; i-- ){
		read1( i, y-1, a ) ;
		read2( i, y,   b ) ;
		mix_a( a, b, (128 - n*rate), c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( i, y, b ) ;
		n++;
	}
smoo2:
	read2( x2+1, y, a ) ;
	read2( x2-1, y, b ) ;
	mix_a( a, b, 128, c ) ;
	read2( x2,   y, b ) ;
	mix_a( c, b, mx, c ) ;
	b[3] = c[3] ;
	write( x2, y, b ) ;
	return 0;
}

static smooth3_a( st, md, fn, x )
int st, md, fn, x;
{
	int y1, y2, y3;
	int i, n, rate;
	unsigned char a[4], b[4], c[4] ;

	y1 = ( st + md ) >> 1;
	y2 = md;
	y3 = ( md + fn ) >> 1;
	if( y1 == y2 )goto smoo1;
	rate = 128/(y2-y1+1);
	n = 1;
	for( i=y1 ; i<=y2-1 ; i++ ){
		read1( x+1, i, a ) ;
		read2( x,   i, b ) ;
		mix_a( a, b, n*rate, c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( x, i, b ) ;
		n++;
	}
	if( y2 == y3 )goto smoo2;
smoo1:
	if( y2 == y3 )return 0;
	rate = 128/(y3-y2+1);
	n = 1;
	for( i=y2+1 ; i<=y3 ; i++ ){
		read1( x-1, i, a ) ;
		read2( x,   i, b ) ;
		mix_a( a, b, (128 - n*rate), c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( x, i, b ) ;
		n++;
	}
smoo2:
	read2( x, y2+1, a ) ;
	read2( x, y2-1, b ) ;
	mix_a( a, b, 128, c ) ;
	read2( x, y2,   b ) ;
	mix_a( c, b, mx, c ) ;
	b[3] = c[3] ;
	write( x, y2, b ) ;
	return 0;
}

static smooth4_a( st, md, fn, x )
int st, md, fn, x;
{
	int y1, y2, y3;
	int i, n, rate;
	unsigned char a[4], b[4], c[4] ;

	y1 = ( st + md ) >> 1;
	y2 = md;
	y3 = ( md + fn ) >> 1;
	if( y1 == y2 )goto smoo1;
	rate = 128/(y2-y1+1);
	n = 1;
	for( i=y1 ; i<=y2-1 ; i++ ){
		read1( x-1, i, a ) ;
		read2( x,   i, b ) ;
		mix_a( a, b, n*rate, c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( x, i, b ) ;
		n++;
	}
	if( y2 == y3 )goto smoo2;
smoo1:
	if( y2 == y3 )return 0;
	rate = 128/(y3-y2+1);
	n = 1;
	for( i=y2+1 ; i<=y3 ; i++ ){
		read1( x+1, i, a ) ;
		read2( x,   i, b ) ;
		mix_a( a, b, (128 - n*rate), c ) ;
		mix_a( c, b, mx, c ) ;
		b[3] = c[3] ;
		write( x, i, b ) ;
		n++;
	}
smoo2:
	read2( x, y2+1, a ) ;
	read2( x, y2-1, b ) ;
	mix_a( a, b, 128, c ) ;
	read2( x, y2,   b ) ;
	mix_a( c, b, mx, c ) ;
	b[3] = c[3] ;
	write( x, y2, b ) ;
	return 0;
}

static mix_a( a, b, rate, c )	/* rate ( 0-256 ) */
int rate ;
unsigned char *a, *b, *c ;
{
	if( rate < 0 )
		rate = 0 ;
	if( rate > 256 )
		rate = 256 ;

	c[3] = ( a[3] * rate + b[3] * (256-rate) + 0x80 ) >> 8 ;

	return NOERR ;
}
