/*	オプション <AnotherAddress> [x1 y1 x2 y2] <parameter1> <parameter2> */
#include <87.cf>
#include <float.h>
#include <math.h>

#define	MAXRANGE	40
#define	RANGE1		((MAXRANGE*2)+1)
#define	RANGE2		5282
/* #define	RANGE2		(int)((MAXRANGE+1)*(MAXRANGE+1)*_PI+0.5) */
#define	MAXWIDTH	640

short	history[ RANGE1 ][ MAXWIDTH ];
int	filter[3][ RANGE2 ];
short	pattern[ MAXRANGE+1 ];

void	g_flare( ibuf, obuf, value, range )
short int *ibuf, *obuf;
int	value, range;
{
	int	x, y, yy, i, j, s, m, r, p;
	int	c, cmax, c0[3], r1, g1, b1;

	trace("g_flare called");
	r=range*2+1;
	s=_PI*(range+1)*(range+1)+0.5;

	cmax=0;		/* 領域内のマスクの下にあるうちで一番明るい色を選ぶ */
	for ( y=0; y<480; y++ ) {
		for ( x=0; x<640; x++ ) {
			c=ibuf[y*640+x];
			if ( c>cmax ){
				cmax=c;
			}
		}
	}
	if ( cmax==0 ){
		goto QuitFlare;	/* マスクの下が真っ黒の場合 */
	}

	c0[0]=(cmax& 0x1f)*value/10;
	cmax>>=5;
	c0[1]=(cmax& 0x1f)*value/10;
	cmax>>=5;
	c0[2]=(cmax& 0x1f)*value/10;

	for( i=0;; i++ ){	/* 円弧パターンを作る */
		j = sqrt( range*range-i*i )+0.5;
		if( j<i ){
			break;
		}
		pattern[i] = j;
		pattern[j] = i;
	}

	for ( j=0; j<3; j++ ) {		/* 面積-輝度の対応表を作る */
		for ( m=0; m<s; m++ ) {
			if ( m>=s/3 ) {
				i=c0[j];
			} else {
				i=c0[j]-(s-m*3)*(s-m*3)*c0[j]/(s*s);
				if ( i<0 ){
					i=0;
				}
				if ( i>c0[j] ){
					i=c0[j];
				}
			}
			filter[j][m]=i;
		}
	}
	/* 処理速度を稼ぐため、以下の preprocess で
	   過去に調べたマスク面積の履歴を取る */
	/* preprocess */
	for ( y=0; y<=range; y++ ) {
		for ( x=0; x<640; x++ ){
			history[y][x]=0;
		}
		/* preprocess of preprocess */
		for ( x=0; x<=pattern[y]; x++ ) {
			if ( ibuf[x+y*640] ){
				history[y][0]++;
			}
		}
		/* mainprocess of preprocess */
		for ( x=1; x<640; x++ ) {
			history[y][x]=history[y][x-1];
			if ( x<640-pattern[y] && ibuf[x+pattern[y]+y*640] ){
				history[y][x]++;
			}
			if ( x>pattern[y] && ibuf[x-pattern[y]-1+y*640] ){
				history[y][x]--;
			}
		}
	}
	/* mainprocess */
	for ( y=0; y<480; y++ ) {
		/* put flare-pattern */
		for ( x=0; x<640; x++ ) {
			if ( (p=ibuf[x+y*640])!= 0 ){
				continue;
			}
			m=0;
			for (yy=((y>=range)?(y-range):0); 
				 yy<=((y<480-range)?(y+range):479); yy++ ) {
			   m+=history[yy%r][x];
			}

			b1=(p & 0x1f)+filter[0][m];
			if ( b1>31 ){
				b1=31;
			}
			p>>=5;
			r1=(p & 0x1f)+filter[1][m];
			if ( r1>31 ){
				r1=31;
			}
			p>>=5;
			g1=(p & 0x1f)+filter[2][m];
			if ( g1>31 ){
				g1=31;
			}
			obuf[x+y*640]=((((g1<<5)+r1)<<5)+b1 );
		}
		yy=(y+range+1)%r;
		for( x=0; x<640; x++ ){
			history[yy][x] = 0;
		}
		yy = y+1;
		for( x=0; x<=range; x++ ){
			if( yy<480-pattern[x] && ibuf[x+(yy+pattern[x])*640] ){
				history[(yy+pattern[x])%r][0]++;
			}
			if( pattern[x]!=range &&
			   y>=pattern[x] && ibuf[x+(y-pattern[x])*640] ){
			   history[(y-pattern[x])%r][0]--;
			}
		}
		for( yy=0; yy<=range; yy++ ){
			for ( x=1; x<640; x++ ) {
				if( y+1+yy<480 ){
					history[(y+1+yy)%r][x]=history[(y+1+yy)%r][x-1];
				}
				if( y+1>=yy && yy ){
					history[(y+1-yy)%r][x]=history[(y+1-yy)%r][x-1];
				}
				if ( x<640-pattern[yy] ){
					if( y+yy<480 && ibuf[x+pattern[yy]+(y+1+yy)*640] ){
						history[(y+1+yy)%r][x]++;
					}
					if( y+1>=yy && yy && ibuf[x+pattern[yy]+(y+1-yy)*640] ){
						history[(y+1-yy)%r][x]++;
					}
				}
				if ( x>pattern[yy] ){
					if( y+yy<480 && ibuf[x-pattern[yy]-1+(y+1+yy)*640] ){
						history[(y+1+yy)%r][x]--;
					}
					if( y+1>=yy && yy && ibuf[x-pattern[yy]-1+(y+1-yy)*640]){
						history[(y+1-yy)%r][x]--;
					}
				}
			}
		}
	}
QuitFlare:
	trace("g_flare DONE");
	return;
}
