/*			polygon
			1994 5/4
*/

#include <stdio.h>
#include <stdlib.h>
#include <egb.h>
#include <mos.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include "poly.h"

#define ENDSW 2		/* 終了ボタンはマウス右 */
#define CANCELSW 3	/* キャンセルボタンはマウス左右ボタン */

static int sw = 0,cx = 0,cy = 0;	/* MOUSE data */

static int pn = 0;			/* POLYGON point counter */
static int ax1=0,ay1=0,ax2=0,ay2=0;		/* POLYGON area min & max */
static short int poly[POLYMAX+2][2];	/* POLYGON point data */

static char para[256];		/* PARAM */
static char *ework ;
static char *buffer ;
static int xlen ;
static int ylen ;
static int color ;
static int ( *setDisplay )() ;
static int initFlag = 0 ;

/* init */
/* 引数 EGBワーク,ポリゴン作業領域,横,縦,カーソルを表示内に入れるための関数 */
polygon_rectangle_init( char *egbWork, char *buf,
						int x, int y, int c, int ( *f )() )
{
	ework = egbWork ;
	buffer = buf ;
	xlen = x ;
	ylen = y ;
	color = c ;
	setDisplay = f ;

	initFlag = 1 ;
	return NOERR ;
}

/* polygon 1 */
polygon_1st( int *lux, int *luy, int *rdx, int *rdy )
{
	int x0,y0,ydis,d,loop,i,add,dini,numini;
	double num,deg;
	int ret ;

	ax1 = 0; ay1 = 0; ax2 = 0; ay2 = 0;
	*lux = ax1; *luy = ay1;
	*rdx = ax2; *rdy = ay2;

	if( initFlag == 0 )return -1 ;

	MOS_rdpos(&sw,&cx,&cy);	/* この場におよんで押してないのはやる気なし */
	if( sw != 1 )
	{
		return -1 ;
	}

	pn = 0;					/* pn = 0 */
	polygon_rectangle_clear() ;

	poly[0][0] = cx;
	x0 = cx;
	ax1 = cx;
	ax2 = cx;
	d=0;
	poly[0][1] = cy;
	y0 = cy;
	ay1 = cy;
	ay2 = cy;

	mouseInit() ;

plygn0:
	ret = mouse( 1, 1 ) ;
plygn1:
	if( sw == CANCELSW )
	{
		while( sw )
		{				/* マウスボタンリリースまで待つ */
			int x, y ;

			MOS_rdpos(&sw,&x,&y);
		}

		polygon_2nd() ;
		polygon_rectangle_clear() ;
		pn = 0 ;
		return -1 ;
	}
	if( ret )sw = ENDSW ; /* ダブルクリックなら終わる */
	if( (cx == x0) && (cy == y0) && (sw == 1) )goto plygn0;
plygn2:
	if( pn < POLYMAX ){
		poly[pn + 1][0] = cx;
		poly[pn + 1][1] = cy;

		polygonDispLine( pn ) ;

		pn = pn + 1;
	}
	ydis = cy - y0;
	if( ydis == 0 )goto plygn3;
	num = xlen*y0 + x0;
	deg = xlen + ( (double)cx - (double)x0 ) / (double)ydis;
	if( ydis < 0 )deg = -deg;
	loop = ydis;
	if( loop < 0 )loop = -loop;
	if( d * ydis >= 0 ){
		loop = loop - 1;
		num = num + deg;
	}
	for(i=0;i<=loop;i++){
		add = (int)( num + .5 ) ;
		BYTE( buffer + (add >> 3) )
		= BYTE( buffer + (add >> 3) ) ^ ( 0x80 >> (add % 8) ) ;
		num = num + deg ;
	}
	if( d == 0 ){
		dini = ydis ;
		numini = xlen*y0 + x0 ;
	}
	d = 1;
	if( ydis < 0 )d = -1;
plygn3:
	if( ax1 > cx )ax1 = cx;
	if( ax2 < cx )ax2 = cx;
	if( ay1 > cy )ay1 = cy;
	if( ay2 < cy )ay2 = cy;
	x0 = cx;
	y0 = cy;
	if( sw == 1 ){
		for(i=0;i<100;i++);
		goto plygn0;
	}
	if( sw == ENDSW ){

		while( sw )
		{				/* マウスボタンリリースまで待つ */
			int x, y ;

			MOS_rdpos(&sw,&x,&y);
			if( sw == CANCELSW )break ;
		}
		if( sw == CANCELSW )goto plygn1 ;

		sw = 0;
		cx = poly[0][0];
		cy = poly[0][1];
		goto plygn2;
	}
	if( d*dini < 0 ){
		add = numini ;
		BYTE( buffer + (add >> 3) )
		= BYTE( buffer + (add >> 3) ) ^ ( 0x80 >> (add % 8) ) ;
	}
	polygonBufConnect( ay1, ay2 );
	*lux = ax1; *luy = ay1;
	*rdx = ax2; *rdy = ay2;

	return NOERR;
}

/* polygon 2 */
polygon_2nd()
{
	int i ;

	if( initFlag == 0 )return -1 ;

	if( pn == 0 )return -1;

	for( i=0 ; i<pn ; i++ )
	{
		polygonDispLine( i ) ;
		polygonBufOrLine( i ) ;
	}

	return 0;
}

/* rectangle 1 */
rectangle_1st( int *lux, int *luy, int *rdx, int *rdy )
{
	int x,y;

	ax1 = 0; ay1 = 0; ax2 = 0; ay2 = 0;
	*lux = ax1; *luy = ay1;
	*rdx = ax2; *rdy = ay2;

	if( initFlag == 0 )return -1 ;

	MOS_rdpos(&sw,&cx,&cy);	/* この場におよんで押してないのはやる気なし */
	if( sw != 1 )
	{
		return -1 ;
	}

	pn = 0;					/* pn = 0 */
	polygon_rectangle_clear() ;

	ax1 = cx;
	ay1 = cy;

	if( boxMouse() )
		return -1 ;

	ax2 = cx;
	ay2 = cy;

	if( ax1 > ax2 )
	{
		int temp ;

		temp = ax1 ;
		ax1 = ax2 ;
		ax2 = temp ;
	}
	if( ay1 > ay2 )
	{
		int temp ;

		temp = ay1 ;
		ay1 = ay2 ;
		ay2 = temp ;
	}

	for( y=ay1 ; y<=ay2 ; y++ )
	{
		for( x=ax1 ; x<=ax2 ; x++ )
		{
			int add ;

			add = xlen*y + x ;
			BYTE( buffer + (add >> 3) )
			= BYTE( buffer + (add >> 3) ) | ( 0x80 >> (add % 8) ) ;
		}
	}
	*lux = ax1; *luy = ay1;
	*rdx = ax2; *rdy = ay2;

	return NOERR ;
}

/* rectangle 2 */
rectangle_2nd()
{
	EGB_color(ework,0,color);
	EGB_paintMode(ework,0x2);
	EGB_writeMode(ework,4);

	WORD(para + 0) = ax1;
	WORD(para + 2) = ay1;
	WORD(para + 4) = ax2;
	WORD(para + 6) = ay2;
	EGB_rectangle(ework,para);

	EGB_writeMode(ework,0);
	EGB_paintMode(ework,0x222);

	return NOERR ;
}

/* read */
polygon_rectangle_read( int x, int y )
{
	int add ;

	if( (x < 0) || (x >= xlen) )return 0 ;
	if( (y < 0) || (y >= ylen) )return 0 ;

	add = xlen * y + x ;

	if( BYTE( buffer + (add >> 3) ) & ( 0x80 >> (add % 8) ) )
		return 1 ;
	else
		return 0 ;
}

/* polygon buffer clear */
polygon_rectangle_clear()
{
	int i, n ;

	n = (xlen*ylen) >> 3 ;
	for( i=0 ; i<n ; i++ )
		BYTE( buffer + i ) = 0 ;

	return NOERR ;
}

static polygonDispLine( n )
{
	EGB_color(ework,0,color);
	EGB_paintMode(ework,0x222);
	EGB_writeMode(ework,4);

	WORD(para + 0) = 2;
	WORD(para + 2) = poly[n][0];
	WORD(para + 4) = poly[n][1];
	WORD(para + 6) = poly[n+1][0];
	WORD(para + 8) = poly[n+1][1];
	EGB_unConnect(ework,para);

	WORD(para + 0) = 2;
	WORD(para + 2) = poly[n+1][0];
	WORD(para + 4) = poly[n+1][1];
	WORD(para + 6) = poly[n+1][0];
	WORD(para + 8) = poly[n+1][1];
	EGB_unConnect(ework,para);

	EGB_writeMode(ework,0);
	return NOERR ;
}

static polygonBufOrLine( n )
{
	int i, count ;
	int x0, y0, x1, y1, xd, yd ;
	int absxd, absyd ;
	double xadd, yadd ;
	double xdouble, ydouble ;

	x0 = poly[n][0];
	y0 = poly[n][1];
	x1 = poly[n+1][0];
	y1 = poly[n+1][1];

	xd = x1 - x0 ;
	yd = y1 - y0 ;

	if( xd > 0 )
		absxd = xd ;
	else
		absxd = - xd ;

	if( yd > 0 )
		absyd = yd ;
	else
		absyd = - yd ;

	if( (absxd == 0) && (absyd == 0) )
	{
		int add ;

		add = xlen*y0 + x0 ;
		BYTE( buffer + (add >> 3) )
		= BYTE( buffer + (add >> 3) ) | ( 0x80 >> (add % 8) ) ;

		return NOERR ;
	}

	if( absxd >= absyd )
	{
		yadd = (double)yd / (double)xd ;
		if( xd > 0 )
			xadd = 1 ;
		else
		{
			xadd = - 1 ;
			yadd = - yadd ;
		}
		count = absxd ;
	}
	else
	{
		xadd = (double)xd / (double)yd ;
		if( yd > 0 )
			yadd = 1 ;
		else
		{
			yadd = - 1 ;
			xadd = - xadd ;
		}
		count = absyd ;
	}

	xdouble = x0 ;
	ydouble = y0 ;
	for( i=0 ; i<count ; i++ )
	{
		int x, y, add ;

		x = xdouble + .5 ;
		y = ydouble + .5 ;

		add = xlen*y + x ;
		if( add < (xlen * ylen) )
			BYTE( buffer + (add >> 3) )
			= BYTE( buffer + (add >> 3) ) | ( 0x80 >> (add % 8) ) ;

		xdouble += xadd ;
		ydouble += yadd ;
	}

	return NOERR ;
}

static polygonBufConnect( y1, y2 )
{
	int i, n1, n2, k, d, e ;

	n1 = xlen*y1 ;
	n2 = xlen*( y2 + 1 ) ;
	k = 0 ;

	for( i=n1 ; i<n2 ; i++ )
	{
		d = BYTE( buffer + (i >> 3) ) ;
		e = 0x80 >> (i % 8) ;
		if( d & e )
			k ^= 1 ;
		if( k )
			BYTE( buffer + (i >> 3) ) = d | e ;
	}

	return NOERR ;
}

static int swmemory, cxmemory, cymemory ;

/* マウスイニシャライズ */

static int mouseInit()
{
	swmemory = -100000 ;
	cxmemory = -100000 ;
	cymemory = -100000 ;
	return NOERR ;
}

/*
   backmode 0:マウスボタン開放時にreturn 1:マウスボタン押した時にreturn
   dspmode 0:なにも表示しない 1:コネクトラインを表示
   戻り値 0:ダブルクリックでない 1:ダブルクリックである
*/

static int mouse( int backmode, int dspmode )		/* mouse */
{
	int x,y,cx0,cy0,mdsp,dummy;
	int doubleClick, ret ;

	EGB_color(ework,0,color);
	EGB_paintMode(ework,0x222);
	EGB_writeMode(ework,4);

	cx0 = -1; cy0 = -1; mdsp = 1; dummy = -1; doubleClick = 0 ;
	if( mdsp ){
		MOS_rdpos(&sw,&cx0,&cy0);
		setDisplay( cx0, cy0 ) ;
		if( dspmode )mousesub(dspmode,cx,cy,cx0,cy0);
	}	
mouse1:
	MOS_rdpos(&sw,&x,&y);
	setDisplay( x, y ) ;
	if( sw )goto mouse2;
	if( doubleClick == 0 )doubleClick = 1 ;
	if( (cx0 == x) && (cy0  == y) )goto mouse1;
	doubleClick = -1 ;
	if( mdsp == 0 ){
		cx0 = x;
		cy0 = y;
	}
	if( dspmode )mousesub(dspmode,cx,cy,cx0,cy0);
	mdsp = mdsp ^ 1;
	goto mouse1;
mouse2:
	if( mdsp && dspmode )mousesub(dspmode,cx,cy,cx0,cy0);

	if(
		(doubleClick > 0) && (x == cxmemory) && (y == cymemory) &&
		(sw == 1) && (swmemory == 1)
	)
		ret = 1 ;
	else
		ret = 0 ;

	swmemory = sw ;
	if( doubleClick )
	{
		cxmemory = x ;
		cymemory = y ;
	}
	else if( (cx != x) || (cy != y) )
	{
		cxmemory = -100000 ;
		cymemory = -100000 ;
	}

	cx = x;
	cy = y;
	if( backmode )goto mouse3;
	while( dummy ){
		MOS_rdpos(&dummy,&x,&y);
		setDisplay( x, y ) ;
	}

mouse3:
	EGB_writeMode(ework,0);
	return ret ;
}

static mousesub(int dspmode,int cx,int cy,int cx0,int cy0)	/* 特殊カーソル */
{
	switch( dspmode ){
		case 0:
			break;
		case 1:
			WORD(para + 0) = 2;
			WORD(para + 2) = cx;
			WORD(para + 4) = cy;
			WORD(para + 6) = cx0;
			WORD(para + 8) = cy0;
			EGB_unConnect(ework,para);
			break;
		}
	return 0;
}

/* BOX用マウス */

static int boxMouse()
{
	int x,y,cx0,cy0,mdsp;
	int ret ;

	EGB_color(ework,0,color);
	EGB_paintMode(ework,0x2);
	EGB_writeMode(ework,4);

	cx0 = -1; cy0 = -1; mdsp = 1; ret = 0 ;
	if( mdsp ){
		MOS_rdpos(&sw,&cx0,&cy0);
		if( sw > 1 )ret = -1 ;
		boxMousesub(cx,cy,cx0,cy0);
		setDisplay( cx0, cy0 ) ;
	}	
mouse1:
	MOS_rdpos(&sw,&x,&y);
	if( sw == 0 )goto mouse2;
	if( sw > 1 )ret = -1 ;
	if( (cx0 == x) && (cy0  == y) )goto mouse1;
	if( mdsp == 0 ){
		cx0 = x;
		cy0 = y;
	}
	boxMousesub(cx,cy,cx0,cy0);
	setDisplay( cx0, cy0 ) ;
	mdsp = mdsp ^ 1;
	goto mouse1;
mouse2:
	if( ret )
	{
		if( mdsp )boxMousesub(cx,cy,cx0,cy0);
		setDisplay( cx0, cy0 ) ;
	}
	else
	{
		if( mdsp == 0 )boxMousesub(cx,cy,cx0,cy0);
		setDisplay( cx0, cy0 ) ;
	}

	cx = cx0;
	cy = cy0;

mouse3:
	EGB_writeMode(ework,0);
	EGB_paintMode(ework,0x222);
	return ret ;
}

static boxMousesub(int cx,int cy,int cx0,int cy0)	/* BOXカーソル */
{
	WORD(para + 0) = cx;
	WORD(para + 2) = cy;
	WORD(para + 4) = cx0;
	WORD(para + 6) = cy0;
	EGB_rectangle(ework,para);
	return 0;
}

/* fixRectangle lx, lyの大きさの長方形の左上座標のみの指定 */
fixRectangle_1st( int lx, int ly, int *lux, int *luy )
{
	int x,y,mdsp,cx0,cy0;
	int ret ;

	if( initFlag == 0 )return -1 ;

	MOS_rdpos(&sw,&cx,&cy);	/* この場におよんで押してないのはやる気なし */
	if( sw != 1 )
	{
		return -1 ;
	}

	EGB_color(ework,0,color);
	EGB_paintMode(ework,0x2);
	EGB_writeMode(ework,4);

	cx0 = -1; cy0 = -1; mdsp = 1; ret = 0 ;
	if( mdsp ){
		MOS_rdpos(&sw,&cx0,&cy0);
		if( sw > 1 )ret = -1 ;
		boxMousesub( cx0,cy0,cx0+lx-1,cy0+ly-1 );
		setDisplay( cx0, cy0 ) ;
	}	
mouse1:
	MOS_rdpos(&sw,&x,&y);
	if( sw == 0 )goto mouse2;
	if( sw > 1 )ret = -1 ;
	if( (cx0 == x) && (cy0  == y) )goto mouse1;
	if( mdsp == 0 ){
		cx0 = x;
		cy0 = y;
	}
	boxMousesub( cx0,cy0,cx0+lx-1,cy0+ly-1 );
	if( mdsp )	/* 交互にディスプレイ内に入れる */
		setDisplay( cx0, cy0 ) ;
	else
		setDisplay( cx0+lx, cy0+ly ) ;
	mdsp = mdsp ^ 1;
	goto mouse1;
mouse2:
	if( ret )
	{	/* ボックスカーソル消し */
		if( mdsp )boxMousesub( cx0,cy0,cx0+lx-1,cy0+ly-1 );
		setDisplay( cx0, cy0 ) ;
	}
	else
	{	/* ボックスカーソル消し */
		if( mdsp )boxMousesub( cx0,cy0,cx0+lx-1,cy0+ly-1 );
		setDisplay( cx0, cy0 ) ;
	}

	*lux = cx0 ; *luy = cy0 ;

mouse3:
	EGB_writeMode(ework,0);
	EGB_paintMode(ework,0x222);

	return ret ;
}

