/*
	ARTemis (Graphic Editor for FM-TOWNS)
	(c) MATSUUCHI Ryosuke 1992,1993

	rotate.c

	｢回転コピー｣コマンド
*/

#include <stdio.h>
#include <math.h>
#include "ge.h"
#include "imageman.h"
#include "dispman.h"
#include "mask.h"

static int input_angle(int ax0, int ay0, int *sin_, int *cos_)
// 返値: 0=正常終了 -1=キャンセル
{
	void drawcsr(int msx,int msy)
	{
		int tx,ty;
		tx = DMimage_getx(msx);
		ty = DMimage_gety(msy);
		MOFF;  EIMline(ax0,ay0,tx,ty,white,DrawXOR);  MON;
	}
	for(;;)
	{
		int prex,prey;
		DMdispcsr(ms.x,ms.y);
		drawcsr((prex=ms.x),(prey=ms.y));
		do
		{
			ms_get(&ms);
		} while (   ms.dx==0 && ms.dy==0 && ms.btn1==OFF && ms.btn2==OFF
				 && key_chk()==0);
		DMerasecsr();
		drawcsr(prex,prey);			// 消去
		scrollForCsr(1,1);
		if (ms.btn1==OFFON)
		{
			int tx,ty;
			tx=DMimage_getx(ms.x)-ax0, ty=DMimage_gety(ms.y)-ay0;
			if (tx == 0 && ty == 0)
				*sin_ = 0, *cos_ = 0x8000;
			else
			{
				float len;
				len = sqrt((float)(tx*tx+ty*ty));
				*sin_ = -(int)(((float)ty * 65536) / len);
				*cos_ = (int)(((float)tx * 65536) / len);
			}
			return 0;
		}
		if (ms.btn2==OFFON)
			return -1;
	}
}


static int input_dest(int bx[],int by[],int sinn,int coss,int ax0,int ay0,
					  int ax1,int ay1,int ax2,int ay2)
{
	sinn = -sinn;
	void drawcsr(int msx,int msy)
	{
		int tx,ty;
		tx = DMimage_getx(msx);
		ty = DMimage_gety(msy);
		MOFF;
		EIMline(tx+bx[0],ty+by[0],tx+bx[1],ty+by[1],white,DrawXOR);
		EIMline(tx+bx[0],ty+by[0],tx+bx[2],ty+by[2],white,DrawXOR);
		EIMline(tx+bx[1],ty+by[1],tx+bx[3],ty+by[3],white,DrawXOR);
		EIMline(tx+bx[2],ty+by[2],tx+bx[3],ty+by[3],white,DrawXOR);
		MON;
	}
	area_drawbound();
	MOFF;
	EIMline(ax1,ay1,ax2,ay2,white,DrawXOR);
	EIMline(ax1,ay2,ax2,ay1,white,DrawXOR);
	MON;
	for(;;)
	{
		int prex,prey;
		DMdispcsr(ms.x,ms.y);
		drawcsr((prex=ms.x),(prey=ms.y));
		do
		{
			ms_get(&ms);
		} while (   ms.dx==0 && ms.dy==0 && ms.btn1==OFF && ms.btn2==OFF
				 && key_chk()==0);
		DMerasecsr();
		drawcsr(prex,prey);			// 消去
		scrollForCsr(1,1);
		if (ms.btn1==OFFON)
		{
			area_drawbound();
			MOFF;
			EIMline(ax1,ay1,ax2,ay2,white,DrawXOR);
			EIMline(ax1,ay2,ax2,ay1,white,DrawXOR);
			MON;
			EIMbackup();
			int tx,ty,bx1,bx2,by1,by2,bx0,by0,x,y;
			tx=DMimage_getx(ms.x), ty=DMimage_gety(ms.y);
			bx1 = _min(tx+bx[0],tx+bx[1],tx+bx[2],tx+bx[3]);
			bx2 = _max(tx+bx[0],tx+bx[1],tx+bx[2],tx+bx[3]);
			by1 = _min(ty+by[0],ty+by[1],ty+by[2],ty+by[3]);
			by2 = _max(ty+by[0],ty+by[1],ty+by[2],ty+by[3]);
			bx0 = (bx1+bx2)/2;
			by0 = (by1+by2)/2;
			bx1 = _max(0,bx1);
			bx2 = _min(EIMgetxsize()-1,bx2);
			by1 = _max(0,by1);
			by2 = _min(EIMgetysize()-1,by2);
			for (y=by1; y<=by2; y++)
				for (x=bx1; x<=bx2; x++)
				{
					int sx,sy;  // fixed-real
					sx = (ax0<<16) +  coss  *(x-bx0) + sinn*(y-by0);
					sy = (ay0<<16) + (-sinn)*(x-bx0) + coss*(y-by0);
					if (area_chkxy2(sx>>16,sy>>16))
						matte_pset(x,y,EIMpoint_back2(sx,sy),blkop);
				}
			return 0;
		}
		if (ms.btn2==OFFON)
		{
			area_drawbound();
			MOFF;
			EIMline(ax1,ay1,ax2,ay2,white,DrawXOR);
			EIMline(ax1,ay2,ax2,ay1,white,DrawXOR);
			MON;
			return -1;
		}
	}
}


static void commandRotate_sub(int meth)
// meth : AREA_BOX / AREA_POLYGON
{
	for (;;)
	{
retry:
		if (area_input(meth) != 0)
			break;
		EIMbackup();
		int ax1,ay1,ax2,ay2,ax0,ay0;
		int sinn,coss;  // fixed-real
		area_getboundxy(&ax1,&ay1,&ax2,&ay2);
		ax0 = (ax1 + ax2) / 2;
		ay0 = (ay1 + ay2) / 2;
angle:
		area_drawbound();
		MOFF;  EIMline(ax0,ay0,ax2,ay0,white,DrawXOR);  MON;
		int r = input_angle(ax0,ay0,&sinn,&coss);
		area_drawbound();
		MOFF;  EIMline(ax0,ay0,ax2,ay0,white,DrawXOR);  MON;
		if (r != 0)
			goto retry;
		int bx[4],by[4];
#define	ROTXY(outn, x,y) \
				(bx[outn]=(( coss*(x))>>16) + ((sinn*(y))>>16), \
				 by[outn]=((-sinn*(x))>>16) + ((coss*(y))>>16))
		ROTXY(0,ax1-ax0,ay1-ay0);
		ROTXY(1,ax2-ax0,ay1-ay0);
		ROTXY(2,ax1-ax0,ay2-ay0);
		ROTXY(3,ax2-ax0,ay2-ay0);
#undef ROTXY
		for (;;)
		{
			if (input_dest(bx,by,sinn,coss,ax0,ay0,ax1,ay1,ax2,ay2) != 0)
				goto angle;
		}
	}
}

void commandRotateBox()
{
	commandRotate_sub(AREA_BOX);
}

void commandRotatePoly()
{
	commandRotate_sub(AREA_POLYGON);
}
