/*
*	Yamana's Otomeza Plug-in Tool
*		レリーフもどき
*	
*	1995.07.13	乙女座プラグイン対応版
*	1995.08.13	３倍速化、パレット無変更モード追加、品質向上
*	1995.08.20	うっすらモード追加
*	
*/
#include	"otome_pi.h"

//#define	DEBUG

const char longname[]  = "EFFECT: レリーフ";
int			cnfg_max = 2;
PI_CNFG		cnfg[] =
			{	/* 1234567890123456 ,min,max,def,set */
				{ "動作モード"		,  0,  2,  0,  0 },
				{ "良 ←  感度     ",  0, 14,  4,  4 },
			};

/* 使わないとき 0 にする */
#define		USE_ENV 	PI_SET_ENV
#define		USE_TYPE	PI_EFFC_ALORSL
#include	"otome_pi.c"


#define	PASTEL_LEVEL	128

/*************** パレット操作部 ****************/

int 	pal[256];

void getPalette(col)
int col;
{
	int 	i,j;
	char	*p = pi_imge->clut ;
	
	p += 4;
#if 0
	for( i=0; i<col ; i++)
		printf("[%2d]=%2d %2x,%2x,%2x\r\n"
					,i,p[i*8],p[i*8+4],p[i*8+5],p[i*8+6] );
#endif
	
	for( i=0 ; i<col ; i++ )
	{
		j = i*8;
		/* 輝度計算 */
		pal[ p[j] & 0xff ] =
			(	  ( p[j+4] & 0xff )* 11		/* B */
				+ ( p[j+5] & 0xff )* 30		/* R */
				+ ( p[j+6] & 0xff )* 59		/* G */
			)>>10 ;
		
		/* 25500〜0 >> 24〜0 までの値が入る. */
	}
	
}

#define	C_GRAY	0x07
#define	C_WHITE	0x0f
#define	C_BLACK	0x00
#define	GRAY32K 	0x3def	/* 各下位 4ビットを 1 とした */
#define	WHITE32K	0x7fff
#define	BLACK32K	0x0000

void setPalette( mode )
int 	mode;
{
	char	*p;
	int 	i,j,col;
	
	static char pal_data[][4]=
		{
			{	C_BLACK,0x00,0x00,0x00	},
			{	C_GRAY ,0x70,0x70,0x70	},
			{	C_WHITE,0xf0,0xf0,0xf0	}
		};
	
	if( mode>1 )	return;
	if( mode>0 )
	{
		col = (PI_PIX == 8 ? 256:16);
		p=pi_imge->clut+8;
		{	/* 黒 */
			*(p  ) = *(p  )/2 ;
			*(p+1) = *(p+1)/2 ;
			*(p+2) = *(p+2)/2 ;
		}
		
		for( p+=8,i=1 ; i<15 ; i++,p+=8 )
		{	
			*(p  ) = (*(p  ) + 0x70 )/2;
			*(p+1) = (*(p+1) + 0x70 )/2;
			*(p+2) = (*(p+2) + 0x70 )/2;
		}
		{	/* 白 */
			*(p  ) = (*(p  ) + 0xff )/2;
			*(p+1) = (*(p+1) + 0xff )/2;
			*(p+2) = (*(p+2) + 0xff )/2;
		}
		for( p+=8 ; i<col ; i++,p+=8 )
		{	
			*(p  ) = (*(p  ) + 0x70 )/2;
			*(p+1) = (*(p+1) + 0x70 )/2;
			*(p+2) = (*(p+2) + 0x70 )/2;
		}
		
	}
	else	/* mode==0 */
	{
		for( i=0, p=pi_imge->clut+4 ; i<3 ;i++ )
		{
			j = 8*(pal_data[i][0]) ;
			
			p[j+4] = pal_data[i][1] ;
			p[j+5] = pal_data[i][2] ;
			p[j+6] = pal_data[i][3] ;
		}
	}
	
}

/***************** レリーフ処理部 *******************/

int 	width,height;
char	*buf[2];

/* こんなのでもそこそこの処理速度で十分それらしく見える */

int palcmp(x)
int x;
{
	return ( pal[ buf[0][x] ]*2 - pal[ buf[1][x+1] ] - pal[ buf[0][x+1] ] );
}

int rgbcmp(x)
int x;
{
	return (buf[0][x]*2 - buf[1][x+1] - buf[0][x+1] );
}

/*********************************/

int getPix16(_x,_y)
int _x,_y;
{
	return ((pi_imge->image[ ((_x)>>1) + (_y)*(pi_imge->size.x>>1) ]
					>>(((_x) & 1)? 4:0) )& 0x0f );
}
int getPix256(_x,_y)
int 	_x,_y;
{
	return (pi_imge->image[ (_x) + (_y)*(pi_imge->size.x) ])& 0xff ;
}
int getPix32k(_x,_y)
int _x,_y;
{
	return WORD( pi_imge->image + ((_x)<<1) + (_y)*(pi_imge->size.x<<1) );
}



void	putPix16(_x,_y,_c)
int 	_x,_y,_c;
{	
	char	*p;
	
	p = &pi_imge->image[ ((_x)>>1) + (_y)*(pi_imge->size.x>>1) ] ;
	
	if( (_x) & 1 )	*p = (*p & 0x0f)|(((_c)& 0x0f)<<4) ;
			else	*p = (*p & 0xf0)| ((_c)& 0x0f) ;
	
}
void	putPix256(_x,_y,_c)
int 	_x,_y,_c;
{
	pi_imge->image[ (_x) + (_y)*(pi_imge->size.x) ] = ((_c)& 0xff);
}

void	putPix32k(_x,_y,_c)
int 	_x,_y,_c;
{
	WORD( pi_imge->image + (((_x)<<1) + (_y)*(pi_imge->size.x<<1)) )
		= (_c) ;
}

/*********************************/


void getBuf(fr,y,n, getFunc)
FRAME	*fr;
int 	y,n;
int 	(*getFunc)();
{
	int 	x;
	
	for(x=0; x<width; x++)
		buf[n][x] = getFunc( (fr->lupx + x),(fr->lupy + y) );
	buf[n][x] = buf[n][x-1];
	
}

void getBuf32K(fr,y,n, getFunc )
FRAME	*fr;
int 	y,n;
int 	(*getFunc)();
{
	int 	x,col;
	
	for(x=0; x<width+1; x++)
	{
		col = getFunc( (fr->lupx + x), (fr->lupy + y) );
		buf[n][x] = 
		(	  (((col)    ) & 0x1f)*11
			+ (((col)>>5 ) & 0x1f)*30
			+ (((col)>>10) & 0x1f)*59
		)>>7 ;
		
		/* 3100-0 >> 24-0 */
	}
}

/*********************************/

void shiftBuf()
{
	char 	*t = buf[0];
	
	buf[0] = buf[1];
	buf[1] = t ;
}

void	nullFunc(fr,sy,col ,putFunc )
FRAME	*fr;
int 	sy,col;
void	(*putFunc)();
{	
}

void	grayLine(fr,sy ,putFunc )
FRAME	*fr;
int 	sy;
void	(*putFunc)();
{
	FRAME	para;
	
	para.lupx = fr->lupx;
	para.rdwx = fr->rdwx;
	para.lupy = para.rdwy = (fr->lupy + sy);
	
	EGB_rectangle( EgbPtr, &para);
}

void Relieve(fr,y,depth, putFunc, cmpFunc )
FRAME	*fr;
int 	y,depth;
void	(*putFunc)();
int 	(*cmpFunc)();
{
	int 	x,col,tmp;
	
	for( x=0; x<width ; x++)
	{
		tmp = cmpFunc( x );
		
			 if( tmp== 0      )	continue;
		else if( tmp<(-depth) )	col = WHITE32K;
		else if( tmp>  depth  )	col = BLACK32K;
		else continue;
		
		putFunc( (fr->lupx + x), (fr->lupy + y), col );
	}
}

/*************/

int mk_Relief( fr, depth, pmode, bufFunc, getFunc, putFunc, cmpFunc )
FRAME	*fr;
int 	depth,pmode;
void 	(*bufFunc)();
int 	(*getFunc)();
void	(*putFunc)();
int 	(*cmpFunc)();
{
	int 	y;
	int 	ch,mx,my;
	void	(*grayFunc)();
	
	if( pmode == 0 )	grayFunc = grayLine;
				else	grayFunc = nullFunc;
	
	bufFunc( fr, 0, 0, getFunc );
	for( y=0 ; y<height-1 ; y++ )
	{
		MOS_rdpos(&ch,&mx,&my);
		if( (ch & 3)==2 ) break;
		
		bufFunc ( fr, y+1, 1    , getFunc );
		grayFunc( fr, y  ,        putFunc );
		Relieve ( fr, y  , depth, putFunc, cmpFunc );
		shiftBuf();
	}
	memcpy( buf[1], buf[0], width+1 );
	grayFunc( fr, y  ,        putFunc );
	Relieve ( fr, y  , depth, putFunc, cmpFunc );
	
	
	return NOERR;
}

/***************************************/

int APL_exec()
{
	int 	depth,pmode;
	char	*mem;
	FRAME	fr;
	
#ifdef DEBUG
	clock_t	t;
	t = clock();
#endif
	
	pmode = cnfg[0].val;
	depth = cnfg[1].val;
	
	fr.lupx = WORD( g_para + 0 );
	fr.lupy = WORD( g_para + 2 );
	fr.rdwx = WORD( g_para + 4 );
	fr.rdwy = WORD( g_para + 6 );
	
	/* よく使う値 */
	width  = ( fr.rdwx - fr.lupx + 1 );
	height = ( fr.rdwy - fr.lupy + 1 );
	
	if( (mem=PI_MALLOC( (width+1)*2  ))==NULL )
		return PI_ERROR_NO_MEMORY;
	buf[0] = mem;
	buf[1] = mem+width+1;
	
	EGB_writePage( EgbPtr, PI_PAGE );
	EGB_viewport ( EgbPtr, &fr );
	EGB_writeMode( EgbPtr, EGB_PSET );
	EGB_paintMode( EgbPtr, 0x02 );
	
	if( pi_imge->pix <= 8 )	/* 16/256モード */
	{
		getPalette( (pi_imge->pix < 8 ? 16:256 ) );
		setPalette( pmode );
		
		EGB_color(EgbPtr, EGB_FORECOL, C_GRAY );
		
		if( pi_imge->pix == 4 )
			mk_Relief( &fr, depth, pmode,
				getBuf, getPix16, putPix16, palcmp );
		else
			mk_Relief( &fr, depth, pmode,
				getBuf, getPix256,putPix256,palcmp );
		
	}
	else	/* 32K色モード */
	{	
		EGB_color(EgbPtr, EGB_FORECOL, GRAY32K );
		if( pmode==1 )
		{
			EGB_pastel	 ( EgbPtr, PASTEL_LEVEL );
			EGB_writeMode( EgbPtr, EGB_PASTEL );
		}
		
		mk_Relief( &fr, depth, (pmode>1 ? 1:0 ),
				getBuf32K, getPix32k, putPix32k, rgbcmp );
	}
	
#ifdef DEBUG
	printf("clock = %d", clock()-t );
#endif
	
	PI_FREE( mem );
	
	return NOERR;
}

/*
	768*512,512*512(32k)
			V1.0	getPix	putPix		grayLineからputPixを呼ぶ
	16色	1131	390		363			545
	256						290
	32k						240
	
	アルゴリズム変更		+10
	
*/
