/*
		graphic effect lib.
		  YUV変換→階調可変→RGB変換

		h. Toda 1994 5 16
*/

#include <stdio.h>
#include <stdlib.h>
#include <egb.h>
#include "g_eff.h"

#define NOERR 0		/* no error */
#define TOTAL 1024

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_yuvConv( BASICPARA *para, int ydiv, int udiv, int vdiv, int mode )
{
	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 x, y ;

	if( (ydiv == 0) || (udiv == 0) || (vdiv == 0) )
		return 0 ;

	for( y=y1 ; y<=y2 ; y++ )
	{
		for( x=x1 ; x<=x2 ; x++ )
		{
			char a[4], b[4] ;
			int y0, u0, v0, r0, g0, b0 ;

			read1( x, y, a ) ;

			rgbToYuv( a[0], a[1], a[2], &y0, &u0, &v0, cMax ) ;

			if( mode )
			{
				int temp ;

				if( mode == 1 )
				{
					read1( (x/2)*2, y, b ) ;
					rgbToYuv( b[0], b[1], b[2], &temp, &u0, &v0, cMax ) ;
				}
				if( mode == 2 )
				{
					read1( x, (y/2)*2, b ) ;
					rgbToYuv( b[0], b[1], b[2], &temp, &u0, &v0, cMax ) ;
				}
				if( mode == 3 )
				{
					read1( (x/2)*2, (y/2)*2, b ) ;
					rgbToYuv( b[0], b[1], b[2], &temp, &u0, &v0, cMax ) ;
				}
			}

			y0 = y0 * ydiv / 256 ;
			y0 = y0 * 256 / ydiv + (128 / ydiv) ;
			if( y0 > 255 )y0 = 255 ;

			u0 = u0 * udiv / 256 ;
			u0 = u0 * 256 / udiv + (128 / udiv) ;
			if( u0 > 255 )u0 = 255 ;

			v0 = v0 * vdiv / 256 ;
			v0 = v0 * 256 / vdiv + (128 / vdiv) ;
			if( v0 > 255 )v0 = 255 ;

			yuvToRgb( y0, u0, v0, &r0, &g0, &b0, cMax ) ;
			b[0] = r0 ;
			b[1] = g0 ;
			b[2] = b0 ;

			mixWrite( x, y, b, a ) ;
		}
	}

	return NOERR ;
}

static mixWrite( int x, int y, unsigned char *a, unsigned char *b )
{
	unsigned char c[4] ;
	int mix ;

	if( mSen )
	{
		if( mask( x, y ) >= mSen )
			return NOERR ;
	}

	mix = mx ;
	if( aSen )
	{
		mix = mix * b[3] / aMax ;
	}

	c[0] = ( a[0] * mix + b[0] * ( 256 - mix ) + 0x80 ) >> 8 ;
	c[1] = ( a[1] * mix + b[1] * ( 256 - mix ) + 0x80 ) >> 8 ;
	c[2] = ( a[2] * mix + b[2] * ( 256 - mix ) + 0x80 ) >> 8 ;
	c[3] = b[3] ;

	if( mix )
	{
		write( x, y, c ) ;
	}

	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 ;
}

