/*===========================================
          DolphMorph（ドルフモーフ）

      モーフィング＆変形アニメ作成ソフト

  モーフィングアルゴリズム: EAST 1994
  インターフェース作成:     松内 良介 1994
===========================================*/
#define	MODULE_MORPHGO
#if 0
	モジュール morphgo.c

	モーフィング／変形アニメの設定ダイアログなどの実現部

		●モジュールの初期化・終了
			int		init_morphgo(void);
			void	end_morphgo(void);

		●モーフィング実行用の通信関数
	static	int		morphgo_setupMorph(void);
	static	int		morphgo_succeed(MORPH_INFO *info);
			int		morphgo_getBackImagePixel(int x,int y);
			int		morphgo_getBackFlag(void);
	static	float	morphInterpolateFunc(int type, float a);

		●モーフィング／変形アニメ生成 (デスクトップメニューからの呼び出し)
			int		morphgo_checkExecMorph(int type)
			void	morphgo_execMorph(int type);

		●計算実行中ダイアログ上の部品呼び出し関数
			int		MorphSucceedStopDBtnFunc(idObj, messId, argc, pev, trigger);
		●設定ダイアログ上の背景画像表示
	static	void	dispBackImage(int idWin);

		●モーフィング／変形アニメ作成の設定ダイアログ上部品の呼び出し関数
			int		MorphSetupBetweenNBoxFunc(idObj)
			int		MorphSetupSpecTIconFunc(idObj)
			int		MorphSetupOkDBtnFunc(void)
			int		MorphSetupCancelDBtnFunc(void)
			int		MorphSetupBackTIconFunc(idObj)
			int		MorphSetupBackWinFunc(idObj, messId)
			int		MorphSetupTransTypeTIconFunc(idObj)
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <egb.h>
#include <wgb.h>
#include <math.h>

#include "morph.h"
#include "desktop.h"
#include "morphgo.h"
#include "domorph.h"
#include "wgbmac.h"
#include "guisub.h"
#include "points.h"
#include "image.h"
#include "imstore.h"
#include "alert.h"

/*--------------------------------------------------------*/
/*                        部品ＩＤ                        */
/*--------------------------------------------------------*/

	int	idMorphSucceedWin = -1 ;
	int	idMorphSucceedTitleMsg = -1 ;
	int	idMorphSucceedMsg = -1 ;
	int	idMorphSucceedStopDBtn = -1 ;
	int	idMorphSetupWin = -1 ;
	int	idMorphSetupBetweenNBox = -1 ;
	int	idMorphSetupSpecTIcon[4] = -1 ;
	int	idMorphSetupBackTIcon[2] = -1 ;
	int	idMorphSetupOkDBtn = -1 ;
	int	idMorphSetupCancelDBtn = -1 ;
	int	idMorphSetupTitleMsg = -1 ;
	int	idMorphBetweenMsg = -1 ;
	int	idMorphSetupTransTypeTIcon[4] = -1 ;

	int	MorphSetupBetweenNBoxFunc();

/*--------------------------------------------------------*/
/*                    モジュール内変数                    */
/*--------------------------------------------------------*/

	#define	BACKWID	64
	#define	BACKHT	48

	static int morphType;	/* DO_MORPH, DO_TRANSFORM */
	static int nMorphSpec;
	static int nBackFlag;	/* 0:なし  1:あり */
	static float morphSpec[] = { 0.02, 0.05, 0.01, 0.007};
	static int bBreak;		/* 中断フラグ */
	static IMAGE *piBackDisp = NULL;	/* 背景画像 */
	static IMAGE *piBack = NULL;
	static int bBack = 0;
	static int nTransType = 0;	// 変形のぐあい

/*--------------------------------------------------------*/
/*                モジュールの初期化／終了                */
/*--------------------------------------------------------*/

	int init_morphgo(void)
	{
		RM_initRadioButton(idMorphSetupSpecTIcon,INTNUM(idMorphSetupSpecTIcon),
						   &nMorphSpec);
		RM_initRadioButton(idMorphSetupBackTIcon,INTNUM(idMorphSetupBackTIcon),
						   &nBackFlag);
		RM_initRadioButton(idMorphSetupTransTypeTIcon,
						   INTNUM(idMorphSetupTransTypeTIcon), &nTransType);
		if ((piBackDisp = image_new(BACKWID/2,BACKHT/2)) == NULL)
			return -1;
		bBack = 0;
		return 0;
	}
	
	void end_morphgo(void)
	{
	}

/*--------------------------------------------------------*/
/*            モーフィング処理のパラメータ入力            */
/*--------------------------------------------------------*/

	static int bExec;
	static int nMorph;

	static int morphgo_setupMorph(void)
	{
		bExec = 0;
		RM_moveCenter(idMorphSetupWin);
		MTL_setFlagObj(idDesktopSelectiveHyper, MS_UNSELECT) ;
		MMI_SendMessage(idMorphSetupWin, MM_ATTACH, 1, idDesktopAlertHyper);
		MMI_SendMessage(idMorphSetupWin, MM_SHOW, 0);
		MMI_ExecSystem();
		MMI_SendMessage(idMorphSetupWin, MM_ERASE, 0);
		MMI_SendMessage(idMorphSetupWin, MM_DETACH, 0);
		MTL_resetFlagObj(idDesktopSelectiveHyper, ~MS_UNSELECT) ;
		int var,min,max,delta,ptClm;
		MMI_SendMessage(idMorphSetupBetweenNBox, MM_GETNUMBOX, 5,
						&var,&min,&max,&delta,&ptClm);
		nMorph = var;
		if (bExec)
			return 0;
		else
			return -1;
	}

/*--------------------------------------------------------*/
/*                モーフィング計算中の表示                */
/*--------------------------------------------------------*/

	static int morphgo_succeed(MORPH_INFO *info)
	{
		static FRAME frAdjUsr = {2,32+12+16,-2,32+12+16+16+8+20+4+12+3};
		FRAME fr,frWin;
		int cx;
		WINCLIP *pwclp;
		MG_mosDisp(2);
		RM_adjustWinUser(idMorphSucceedWin, &frAdjUsr);
		RM_setClipWinUser(idMorphSucceedWin, &pwclp);
		RM_setOriginZero();
		RM_getWinUserFrame(idMorphSucceedWin, &fr);
		RM_getFrame(idMorphSucceedWin, &frWin);
		WGB_BOXFILL(guiEgbPtr, fr.lupx,fr.lupy,fr.rdwx,fr.rdwy,WINBACK,0);
		cx = (frWin.lupx + frWin.rdwx + 1) / 2;
		char msg[200];
		#define	BARLEN	200
		int len;
		if (info->morphType == DO_MORPH)
			len = (BARLEN/4) * info->varType +
				  _min(BARLEN/4,
				  	   ((BARLEN/4) * info->moveLimit) / info->moveMax);
		else
			len = (BARLEN/2) * info->varType +
				  _min(BARLEN/2,
				  	   ((BARLEN/2) * info->moveLimit) / info->moveMax);
		WGB_RBOXFILL(guiEgbPtr,cx-100,frWin.lupy+32+12+16+16+8-20,
					 BARLEN, 20, WHITE,0);
		WGB_RBOXFILL(guiEgbPtr,cx-100,frWin.lupy+32+12+16+16+8-20,
					 len,20, BLACK,0);
		sprintf(msg,"   pass %d  %d / %d   ",
				info->varType+1, info->moveMax, info->moveLimit);
		RM_putstring12(guiEgbPtr,
					   cx-(6/2)*strlen(msg), frWin.lupy+32+12+16+16+8+20+4-20,
					   msg,BLACK,0);
		RM_resetClipWinUser(pwclp);
		RM_recoverOrigin();
		MG_mosDisp(3);

		EVENT *pev;
		MMI_iosense();
		if (MMI_GetEvnt(EVALL, &pev) == NOERR)
			MMI_ExecEvnt(pev);

		return (bBreak ? -1 : 0);
	}

/*--------------------------------------------------------*/
/*              外部のための背景画像アクセス              */
/*--------------------------------------------------------*/

	// ★このへんのモジュール分割はめちゃくちゃ。要再考

	int morphgo_getBackImagePixel(int x,int y)
	{
		if (bBack == 0 || nBackFlag == 0)
			return 0x7fff;
		if (x < 0 || piBack->width <= x || y < 0 || piBack->height <= y)
			return 0x7fff;
		return (int)((unsigned short *)(piBack->image))
				[piBack->width * y + x];
	}

	int morphgo_getBackFlag(void)
	{
		if (bBack == 0 || nBackFlag == 0)
			return 0;
		else
			return 1;
	}

/*--------------------------------------------------------*/
/*               モーフィングの速度変化関数               */
/*--------------------------------------------------------*/

	static float morphInterpolateFunc(int type, float a)
	// a: 0〜1
	// type : 0=直線的  1=だんだん速く  2=だんだん遅く
	//		  3=最初遅く、まんなか速く、最後遅く
	{
		switch (type)
		{
		case 0:
			return a;
		case 1:
			return a*a;
		case 2:
			return sqrt(a);
		case 3:
			if (a <= 0.5)
			 	return a * a * 2.0;
			else
				return 0.5 + sqrt((a - 0.5)/2.0);
		default:
			return a;
		}
	}

/*--------------------------------------------------------*/
/*                   モーフィング実行！                   */
/*--------------------------------------------------------*/

	int	morphgo_checkExecMorph(int type)
	{
		if (points_checkMorphImages() != 0)
			return -1;
		else
			return 0;
	}

	void morphgo_execMorph(int type)
					// type 0=モーフィング  1=変形アニメ
	{
		int moscsr;
		static char alertTitle[30] = "モーフィング／変形アニメ作成";
		LIST *plPOINT,*plLINE;
		int imwid,imht;	// 画像のサイズ
		morphType = (type == 1 ? DO_TRANSFORM : DO_MORPH);
		int err;
		if ((err = points_checkMorphImages()) != 0)
		{
			if (err == POINTS_IMAGE_NO_THERE)
				dispAlertMessage(alertTitle, "操作点設定ウィンドウのＡ,Ｂ側に"
								 "画像が存在しないので、モーフィング"
								 "（変形アニメ作成）できません");
			else if (err == POINTS_IMAGE_MISMATCH_SIZE)
				dispAlertMessage(alertTitle, "操作点設定ウィンドウのＡ,Ｂ側の"
								 "画像の大きさが違うので、モーフィング"
								 "（変形アニメ作成）できません");
			goto END;
		}
		points_getImageSize(&imwid, &imht);
		if (morphType == DO_MORPH)
		{
		  MMI_SendMessage(idMorphSetupTitleMsg, MM_SETMSG, 1, "モーフィング");
		  MMI_SendMessage(idMorphSucceedTitleMsg, MM_SETMSG, 1,
		  				  "モーフィング計算実行中");
		  strcpy(alertTitle, "モーフィング");
		}
		else
		{
		  MMI_SendMessage(idMorphSetupTitleMsg, MM_SETMSG, 1,"変形アニメ作成");
		  MMI_SendMessage(idMorphSucceedTitleMsg, MM_SETMSG, 1,
		  				  "変形アニメ 計算実行中");
		  strcpy(alertTitle, "変形アニメ作成");
		}
		MorphSetupBetweenNBoxFunc(idMorphSetupBetweenNBox);
	  /* 背景画像の登録 */
		IMAGE *pi;
		pi = imstore_getImage(imstore_getMarkNum(0));
		bBack = 0;
		if (pi != NULL)
		{
			if (piBack != NULL)
				image_delete(piBack);
			piBack = NULL;
			if ((piBack = image_copy(pi)) == NULL)
			{
				alert_noMemory(alertTitle);
				goto END;
			}
			image_zoomdown(piBackDisp, piBack);
			bBack = 1;
		}
	  /* 各種パラメータの入力 */
		if (morphgo_setupMorph() != 0)
			goto END;
		plPOINT = list_new(sizeof(MORPH_POINT));
		plLINE  = list_new(sizeof(MORPH_LINE));	// ★ちゃんと作成できた？
		if (points_makeMorphPoints(plPOINT, plLINE) != 0)
			goto AFTER_MORPHTERM;
	  /* モーフィング開始 */
		MG_mosDisp(2);
		MG_PushPtr(MOSICON_WAIT, &moscsr);
		MG_mosDisp(3);
		RM_moveCenter(idMorphSucceedWin);
		MMI_SendMessage(idMorphSucceedWin, MM_ATTACH, 1, idDesktopAlertHyper);
		MMI_SendMessage(idMorphSucceedWin, MM_SHOW, 0);
		morphInitialize(imwid,imht,morphSpec[nMorphSpec],plPOINT,plLINE);
	  /* 中間画像を生成 */
		int i;
		bBreak = 0;
		for (i=1; i<=nMorph; i++)
		{
			IMAGE *pi;
			if ((pi = image_new(imwid,imht)) == NULL)
			{
				alert_noMemory(alertTitle);
				break;
			}
			static char msgbuf[80];
			sprintf(msgbuf, "  %d枚中 %d枚目を計算しています  ",nMorph,i);
			MMI_SendMessage(idMorphSucceedMsg, MM_SETMSG, 1, msgbuf);
			MMI_SendMessage(idMorphSucceedMsg, MM_SHOW, 0);
			float t;
			t = (float)(i-1) / (float)(nMorph-1);
			t = morphInterpolateFunc(nTransType, t);
			if (morphExec(t, morphgo_succeed, 1, morphType) != 0)
			{
				dispAlertMessage(alertTitle,"計算を中断しました");
				break;
			}
			int x,y;
			for (y=0; y<imht; y++)
				for (x=0; x<imwid; x++)
				{
					int r,g,b;
					morphGetColor(x,y,&r,&g,&b);
					((unsigned short*)pi->image)[imwid*y+x] = g*1024+r*32+b;
				}
			if (imstore_storeNewImage(1,pi,-1) < 0)
			{
				alert_noMemory(alertTitle);
				break;
			}
		}
	  /* モーフィング終了 */
	  MORPHTERM:;
		morphTerminate();
		MMI_SendMessage(idMorphSucceedWin, MM_ERASE, 0);
		MMI_SendMessage(idMorphSucceedWin, MM_DETACH, 0);
		MG_mosDisp(2);
		MG_PopPtr(moscsr);
		MG_mosDisp(3);
	  AFTER_MORPHTERM:;
		list_destroy(plPOINT);
		list_destroy(plLINE);
	  END:;
	}

/*--------------------------------------------------------*/
/*             設定ダイアログ上の背景画像表示             */
/*--------------------------------------------------------*/

	static void dispBackImage(int idWin)
	{
		RM_setOriginZero();
		WINCLIP *pClip;
		RM_setClipWinUser(idWin, &pClip);
		FRAME fr;
		RM_getWinUserFrame(idWin,&fr);
		if (!bBack)
		{
			WGB_BOXFILL(guiEgbPtr,fr.lupx,fr.lupy,fr.rdwx,fr.rdwy,
						WINBACK,0);
			WGB_BOXLINE(guiEgbPtr,fr.lupx,fr.lupy,fr.rdwx,fr.rdwy,
						BLACK,0);
			RM_putstring12(guiEgbPtr, (fr.lupx+fr.rdwx)/2 - (12*3)/2,
						   (fr.lupy+fr.rdwy)/2 - 12/2, "未設定", BLACK, 0);
		}
		else
			image_disp(piBackDisp, fr.lupx, fr.lupy, BACKWID,BACKHT);
		RM_resetClipWinUser(pClip);
		RM_recoverOrigin();
	}

/*--------------------------------------------------------*/
/*                   部品の呼び出し関数                   */
/*--------------------------------------------------------*/

									/* idMorphSucceedStopDBtn:MJ_DBUTTONL40 */
	int	MorphSucceedStopDBtnFunc(void)
	{
		bBreak = 1;
		return NOERR ;
	}
									/* idMorphSetupBetweenNBox:MJ_NUMBOXL40 */
	int	MorphSetupBetweenNBoxFunc(int idObj)
	{
		int var,min,max,delta,ptClm;
		MMI_SendMessage(idObj,MM_GETNUMBOX,5, &var,&min,&max,&delta,&ptClm);
		static char msg[40];
		if (morphType == DO_MORPH)
			sprintf(msg, "（%d枚を補間） ", var-2);
		else /* morphType == DO_TRANSFORM */
			sprintf(msg, "（%d枚を生成） ", var-1);
		MMI_SendMessage(idMorphBetweenMsg, MM_SETMSG, 1, msg);
		MMI_SendMessage(idMorphBetweenMsg, MM_SHOW, 0);
		return NOERR ;
	}
						/* idMorphSetupSpecTIcon[0],[1],[2],[3]:MJ_TICONL40 */
	int	MorphSetupSpecTIconFunc(int idObj)
	{
		RM_pushRadioButton(idObj,idMorphSetupWin,
						   idMorphSetupSpecTIcon,INTNUM(idMorphSetupSpecTIcon),
						   &nMorphSpec);
		return NOERR ;
	}
										/* idMorphSetupOkDBtn:MJ_DBUTTONL40 */
	int	MorphSetupOkDBtnFunc(void)
	{
		bExec = 1;
		MMI_SetHaltFlag(TRUE);
		return NOERR ;
	}
									/* idMorphSetupCancelDBtn:MJ_DBUTTONL40 */
	int	MorphSetupCancelDBtnFunc(void)
	{
		bExec = 0;
		MMI_SetHaltFlag(TRUE);
		return NOERR ;
	}
								/* idMorphSetupBackTIcon[0],[1]:MJ_TICONL40 */
	int	MorphSetupBackTIconFunc(int idObj)
	{
		RM_pushRadioButton(idObj,idMorphSetupWin,
						   idMorphSetupBackTIcon,INTNUM(idMorphSetupBackTIcon),
						   &nBackFlag);
		return NOERR ;
	}

											/* idMorphSetupWin:MJ_WINDOWL40 */
	int	MorphSetupBackWinFunc(int idObj, int messId)
	{
		if (messId == MM_SHOW)
		{
			RM_roundFramePosition(idObj, 2,2);
			dispBackImage(idObj);
		}
		else if (messId == MM_MOVE)
		{
			RM_roundFramePosition(idObj, 2,2);
			dispBackImage(idObj);
		}	
		return NOERR ;
	}
				   /* idMorphSetupTransTypeTIcon[0],[1],[2],[3]:MJ_TICONL40 */
	int	MorphSetupTransTypeTIconFunc(int idObj)
	{
		RM_pushRadioButton(idObj,idMorphSetupWin,
						   idMorphSetupTransTypeTIcon,
						   INTNUM(idMorphSetupTransTypeTIcon),
						   &nTransType);
		return NOERR ;
	}

