#include "app.h"
#ifdef  USE_DXLIB
/****************************************************************************
 *	
 ****************************************************************************/
#if     (!defined(_DEBUG) && !defined(USE_PDCURSES))
#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")	//リリースビルドならばDOS窓を出さない。ただしCursesを使う場合はリリースビルドであってもDOS窓を出す。DOS窓を出さずにCursesを使おうとするとinitscr()がエラーを検出してプロセスを終了するからです。
#endif//(!defined(_DEBUG) && !defined(USE_PDCURSES))
/****************************************************************************
 *	
 ****************************************************************************/
static int		timer_id;
static jmp_buf		env_exit;
static int		iFullScrMode;						//0=ウインドウ表示,1=メイン画面をメインモニタでフルスクリーン表示,2=メイン画面をサブモニタでフルスクリーン表示
static int		bFullScrMouseDisp;					//0=フルスクリーン時にマウスカーソルを表示しない,1=フルスクリーン時もマウスカーソルを表示する
static int		windowSizeX, windowSizeY;				//ウインドウのクライアントサイズ
static int		desktopSizeX, desktopSizeY, colorBitDepth;		//メインモニタのデスクトップ解像度
static int		subDeskSizeX, subDeskSizeY;				//　サブモニタのデスクトップ解像度						シングルモニタ環境ならば、これらの値は0のままとする。
static int		fullscrSizeX, fullscrSizeY, fullscrPosX, fullscrPosY;	//メイン画面のメインモニタでのフルスクリーンサイズ,及び,フルスクリーン原点
static int		subFullSizeX, subFullSizeY, subFullPosX, subFullPosY;	//メイン画面の　サブモニタでのフルスクリーンサイズ,及び,フルスクリーン原点	シングルモニタ環境ならば、これらの値は0のままとする。
static RECT		rcSubMon;						//サブモニタの矩形								シングルスクリーンアプリケーションでもデュアルスクリーンシングルスクリーンアプリケーションでも、常にサブモニタの矩形を取得しておく。実際にマルチモニタ環境であるかどうかは、GetSubMonitorRect()の戻り値を保持しておかなくても、「if(rcSubMon.left||rcSubMon.top)」で判断出来る。
static int		grScr;							//仮想画面
#ifdef  DUALSCREEN
static HWND		hSubWnd;						//デュアルスクリーン用ウインドウ
static int		subWndSizeX, subWndSizeY;				//デュアルスクリーン用ウインドウのクライアントサイズ
static int		ful2scrSizeX, ful2scrSizeY, ful2scrPosX, ful2scrPosY;	//サブ画面のメインモニタのフルスクリーンサイズ,及び,フルスクリーン原点
static int		subFul2SizeX, subFul2SizeY, subFul2PosX, subFul2PosY;	//サブ画面の　サブモニタのフルスクリーンサイズ,及び,フルスクリーン原点		シングルモニタ環境ならば、これらの値は0のままとする。
static int		grSubScr;						//サブ画面の仮想画面
static int		bSubKeepWindowMode;					//0=フルスクリーンモードならばサブ画面もフルスクリーン表示する(一般的な動作),1=フルスクリーンモードでもサブ画面はウインドウモードを維持する(特殊な動作)
#define SUBWND_STYLE	(WS_POPUP|WS_CAPTION)					//┬左記のウインドウスタイルはDxLibのDxWindow.cppのWStyle_WindowModeTable[5],WExStyle_WindowModeTable[5]からWS_SYSMENUを抜きWS_EX_TOOLWINDOWを追加した値です。デュアルスクリーン用ウインドウのスタイルをメインウインドウのスタイルに合わせました。WS_EX_TOOLWINDOWを追加した理由はデュアルスクリーン用ウインドウはタスクバーに表示しないようにするためです。
#define SUBWND_STYLE_EX	(WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE)			//┘
#endif//DUALSCREEN
#define WINDOW_REDUCE	//このシンボルを定義すると、ウインドウを自動的に縮小します。
/*--------------------------------------------------------------------------*/
#define SHOW_FPS	//このシンボルを定義すると、FPS表示が有効になります。
#ifdef  SHOW_FPS
static int		bShowFps;						//FPS表示のOn/Off
static double		dActualExecFps;						//計算処理の実効FPS
static double		dActualDrawFps;						//描画処理の実効FPS
static void ExecFps() {
	static int TBL_FrameTime[FPS];	//時刻の取得履歴。一秒間分のフレーム(=FPS回)の描画実行に掛かった時間の平均で計測する事にした。
	static int iFrameTime;		//次に格納するTBL_FrameTime[]のインデクス
	//計算処理の実効FPSを計測する。
	int newFrameTime = GetTickCount();		//現在時刻を取得する。
	int oldFrameTime = TBL_FrameTime[iFrameTime];	//FPS回前の時刻を取り出しておく。
	int elapsedTime = newFrameTime - oldFrameTime;	//FPS回分の描画実行にかかった時間を求める。
	TBL_FrameTime[iFrameTime] = newFrameTime;	//現在時刻を格納する。
	if(++iFrameTime >= FPS) { iFrameTime = 0; }	//次に格納するTBL_FrameTime[]のインデクスを進める。
	if(elapsedTime) { dActualExecFps = (double)(FPS * 1000) / (double)elapsedTime; }	//計測したFPS値を更新する。
	//[F11]でFPS表示のOn/Offを行う。(MAMEのキーアサインに倣った)
	if(keyTrig[KEY_INPUT_F11]) { bShowFps = !bShowFps; }
}
static void DrawFps() {
	static int TBL_FrameTime[FPS];	//時刻の取得履歴。一秒間分のフレーム(=FPS回)の描画実行に掛かった時間の平均で計測する事にした。
	static int iFrameTime;		//次に格納するTBL_FrameTime[]のインデクス
	//描画処理の実効FPSを計測する。
	int newFrameTime = GetTickCount();		//現在時刻を取得する。
	int oldFrameTime = TBL_FrameTime[iFrameTime];	//FPS回前の時刻を取り出しておく。
	int elapsedTime = newFrameTime - oldFrameTime;	//FPS回分の描画実行にかかった時間を求める。
	TBL_FrameTime[iFrameTime] = newFrameTime;	//現在時刻を格納する。
	if(++iFrameTime >= FPS) { iFrameTime = 0; }	//次に格納するTBL_FrameTime[]のインデクスを進める。
	if(elapsedTime) { dActualDrawFps = (double)(FPS * 1000) / (double)elapsedTime; }	//計測したFPS値を更新する。
	//FPSを表示する。(コールバックキューを介さないので画面更新の直前で行う必要が有ります)
	if(bShowFps) {
		draw_strf_framed(DISP_X, 0, 4, 8, 1.0, 0.0, (dActualExecFps < (FPS * 0.9/*調整可*/)) ? D3DRGB(1.0, 0.0, 0.0) : -1, "Exec %6.2f", dActualExecFps);
		draw_strf_framed(DISP_X, 8, 4, 8, 1.0, 0.0, (dActualDrawFps < (FPS * 0.9/*調整可*/)) ? D3DRGB(1.0, 0.0, 0.0) : -1, "Draw %6.2f", dActualDrawFps);
	}
}
#endif//SHOW_FPS
/*--------------------------------------------------------------------------*/
#define BACKGROUND_PRELOAD	//このシンボルを定義すると、アプリケーション実行開始後しばらくの間、バックグラウンドで静止画とフレーズのプリロードを行います。それらを初回に使用する時の引っ掛かりが低減されます。ただし、アプリケーション実行開始後しばらくの間の負荷が増えるので、それが問題となる場合はこのシンボルを定義しないで下さい。
#ifdef  BACKGROUND_PRELOAD
static void BackgroundPreload(void* arg) {
	{
		static int iTexNo = TexNo_Max;	//最後のテクスチャから…
		while(iTexNo) {			//最初のテクスチャ(1)まで…
			const char* pName = EnmDef_GetName(pEnmKey, RegKey_TexNo, iTexNo);	//列挙定義名を取得する。
			if(strcasestr(pName, "SPRSHT")) {	//スプライトシートならば静止画と見なして、プリロードを行う。
				draw_grp(DISP_X, DISP_Y, iTexNo);	//ダミー描画を実行して、即、読み込みを行う。本当はここでDxLibの非同期読み込みを開始すべきだが、2016/11/02現在はまだDxLibの非同期読み込みを利用する仕組みを作っていないので…
				syslog(LOG_DEBUG, "BackgroundPreload: draw_grp(%s) done", pName);	//システムログを出力する。
				iTexNo--;	//次回のために、テクスチャ番号を変更する。(最後は0になって終わり)
				return;	//ここまで
			}
			iTexNo--;	//静止画でなければ、テクスチャ番号を変更して、次のテクスチャの処理を行う。(何もせずに1フレーム分の時間を消費してしまう事を避けるために。)
		}
	}
	{
		static int iPhrNo = PhrNo_Max;	//最後のフレーズから…
		while(iPhrNo) {			//最初のフレーズ(1)まで…
			if(prep_phr(iPhrNo)) {	//フレーズの準備を開始する,又は,準備状態を取得する。戻り値が「0以外」ならば準備が完了していないので、今回の処理はここまでとする。
				return;	//ここまで
			}
			(*pTapSeq->pInfo->fnGetPhrTime)(pTapSeq, iPhrNo);	//総時間(ミリ秒)をキャッシュするために、明示的にDxlibHelper.cppのTapSeq_fnGetPhrTime()を呼び出す。
			const char* pName = EnmDef_GetName(pEnmKey, RegKey_PhrNo, iPhrNo);	//列挙定義名を取得する。
			syslog(LOG_DEBUG, "BackgroundPreload: prep_phr(%s) done", pName);	//システムログを出力する。
			iPhrNo--;	//次回のために、フレーズ番号を変更する。(最後は0になって終わり)
			//ここでreturnしても構わないのだが、ループを継続して、次のフレーズの準備開始までおこなう事にした。
		}
	}
}
#endif//BACKGROUND_PRELOAD
/****************************************************************************
 *	
 ****************************************************************************/
#ifdef  __CLIP_LEDS_H__
static void LedSeq_TimeProc(void* arg);
#endif//__CLIP_LEDS_H__
#ifdef  USE_SOFDEC
static void Sofdec_fnGetNextMovie(const char* sCurrentMoviePath, char sNextMoviePath[/*_MAX_PATH*/]);
#endif//USE_SOFDEC
#ifdef  USE_ADX
static void Sofdec_fnGetNextSound(const char* sCurrentSoundPath, char sNextSoundPath[/*_MAX_PATH*/]);
#endif//USE_ADX
/****************************************************************************
 *	
 ****************************************************************************/
#ifdef  DUALSCREEN
//デュアルスクリーン用ウインドウプロシージャ
static LRESULT CALLBACK DsWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch(uMsg) {
	case WM_DESTROY:
		//デュアルスクリーン用ウインドウが閉じられた場合も、メインウインドウが閉じられた場合と同様に、プログラムを終了する。
		PostQuitMessage(0);
		break;
	case WM_ACTIVATE:
		//デュアルスクリーン用ウインドウがアクティブになったら、すぐにメインウインドウをアクティブにする。
		// - この処理を行うと、副作用としてデュアルスクリーン用ウインドウの枠をドラッグ出来なくなり、ウインドウサイズを変更出来なくなる。
		//   2016/03/27現在はウインドウサイズを固定としているので問題無いが、もし今後ウインドサイズを可変とする場合はこの処理を削除せよ。
		if(LOWORD(wParam)/*fActive*/) {
			HWND hMainWindow = GetMainWindowHandle();
			if(hMainWindow) { SetActiveWindow(hMainWindow); }
		}
		break;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
#endif//DUALSCREEN
#ifdef  USE_NUKLEAR
//Nuklear用ウインドウプロシージャ
static LRESULT CALLBACK NkWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch(uMsg) {
	case WM_MOUSEMOVE:
	case WM_MOUSEWHEEL:
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
		{
			int x = (short)LOWORD(lParam), y = (short)HIWORD(lParam);
			//マウスの座標を論理画面の座標に変換する。
			switch(iFullScrMode) {
			default:DIE();
			case 0:	//ウインドウ表示
				x = x * DISP_X / windowSizeX;
				y = y * DISP_Y / windowSizeY;
				break;
			case 1:	//メイン画面をメインモニタでフルスクリーン表示
				x = (x - fullscrPosX) * DISP_X / fullscrSizeX;
				y = (y - fullscrPosY) * DISP_Y / fullscrSizeY;
				break;
			case 2:	//メイン画面をサブモニタでフルスクリーン表示
				x = (x - subFullPosX) * DISP_X / subFullSizeX;
				y = (y - subFullPosY) * DISP_Y / subFullSizeY;
				break;
			}
			lParam = MAKELONG(x, y);
		}
		break;
	}
	//Nuklearがこのメッセージを処理したら…
	if(nk_dxlib_handle_event(ctx, hWnd, uMsg, wParam, lParam)) {
	  #if 1
		//マウスカーソルがNuklearのウインドウの上に有れば…
		if(nk_window_is_any_hovered(ctx)) {
	  #else	//↑↓どちらかを選択して下さい。どちらが適切かはアプリケーション次第ですが↑の方が安全だと思います。
		//マウスカーソルがNuklearのウインドウの上に有るか、又は、Nuklearのエディットボックスが編集中ならば…
		if(nk_item_is_any_active(ctx)) {
	  #endif
			//DxLibにはこのメッセージを処理させない。
			if(SetUseHookWinProcReturnValue(TRUE)) { DIE(); }
			return 1;	//これがWindowsへの戻り値となる。
		}
	}
	return 0;	//この戻り値は関係無い。
}
#endif//USE_NUKLEAR
#ifdef  __CLIP_LCDS_H__
//液晶シーケンサ用のアプリケーション定義の描画関数
static void LcdSeqCh_fnDraw(int iLcdSeqCh, const ST_LcdSeqCh* pLcdSeqCh) {
	CbkQue_draw_spr(pCbkQue,
		pLcdSeqCh->Pri,
		pLcdSeqCh->PosX,
		pLcdSeqCh->PosY,
		pLcdSeqCh->SprNo,
		pLcdSeqCh->Color,
		pLcdSeqCh->Mode);
}
#endif//__CLIP_LCDS_H__
#ifdef  USE_SSBPLIB
static void* ssbpLib_GetAddress(const char* pName) {
	syslog(LOG_DEBUG, "ssbpLib_GetAddress: '%s'", pName);
	if(!strcmp(pName, "vsyslog"          )) { return vsyslog;           }
	if(!strcmp(pName, "vdie"             )) { return vdie;              }
	if(!strcmp(pName, "DeleteGraph"      )) { return DeleteGraph;       }
	if(!strcmp(pName, "LoadGraph"        )) { return LoadGraph;         }
	if(!strcmp(pName, "GetGraphSize"     )) { return GetGraphSize;      }
	if(!strcmp(pName, "DrawPolygon3DBase")) { return DrawPolygon3DBase; }
	if(!strcmp(pName, "SetDrawBlendMode" )) { return SetDrawBlendMode;  }
	if(!strcmp(pName, "SetDrawBright"    )) { return SetDrawBright;     }
	DIE();
}
#endif//USE_SSBPLIB
void cpp_init(int argc, char* argv[]) {
	//サブモニタの矩形を取得する。
	// - シングルスクリーンアプリケーションでもデュアルスクリーンシングルスクリーンアプリケーションでも、常にサブモニタの矩形を取得しておく。
	//   実際にマルチモニタ環境であるかどうかは、GetSubMonitorRect()の戻り値を保持しておかなくても、「if(rcSubMon.left||rcSubMon.top)」で判断出来る。
	if(GetSubMonitorRect(&rcSubMon)) {							//マルチモニタ環境ならば…
		subDeskSizeX = rcSubMon.right - rcSubMon.left;					//┬サブモニタのデスクトップ解像度を求める。
		subDeskSizeY = rcSubMon.bottom - rcSubMon.top;					//┘
	}
	//DxLibを初期化する。
	{
		char sCaption[MAX_PATH];
		snprintf(sCaption, sizeof sCaption, "%s version %s", program_invocation_short_name, __TIMESTAMP__);
#ifndef _DEBUG
		if(SetOutApplicationLogValidFlag(FALSE)) { DIE(); }				//リリースビルドならばログを出力しない。
#endif//_DEBUG
		if(SetMainWindowText(sCaption)) { DIE(); }					//ウインドウのタイトルを実行ファイル名+日付にする。
		if(SetWindowIconID(IDI_MAIN)) { DIE(); }					//メインウインドウで使用するアイコンのIDをセットする。
	//{{□参照資料「ＤＸライブラリ質問掲示板 - ウィンドウモード切り換えについて」(http://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=3366)
		if(ChangeWindowMode(TRUE)) { DIE(); }						//ウインドウモードにする。実行中にフルスクリーン表示に切り替えた場合もウインドウを使って表示する。
		if(GetDefaultState(&desktopSizeX, &desktopSizeY, &colorBitDepth)) { DIE(); }	//メインモニタのデスクトップ解像度を取得する。
#ifndef DUALSCREEN
		windowSizeX = DISP_X;								//┐
		windowSizeY = DISP_Y;								//│
#ifdef  WINDOW_REDUCE										//│
		while((windowSizeX > desktopSizeX) /*||						//│
		      (windowSizeY > desktopSizeY)*/) {						//│ウインドウのクライアントサイズを決定する。シングルモニタ環境ならば、デスクトップに収まるサイズまで縮小する。
			if((windowSizeX >>= 1) <= 0) { DIE(); }					//│
			if((windowSizeY >>= 1) <= 0) { DIE(); }					//│
		}										//┘
		while((windowSizeX * windowSizeY * 3) > (desktopSizeX * desktopSizeY)) {	//┐//{{必須ではない。
			if((windowSizeX >>= 1) <= 0) { DIE(); }					//│メイン画面のクライアントサイズの面積がデスクトップの面積の３(調整可)倍以下になるまで、ウインドウサイズを縮小する事にしました。
			if((windowSizeY >>= 1) <= 0) { DIE(); }					//│ウインドウサイズがデスクトップサイズよりも僅かに小さいだけで、ほとんどフルスクリーンと変わらないような状況を回避するためです。
		}										//┘//}}必須ではない。
#endif//WINDOW_REDUCE
#else //DUALSCREEN
		windowSizeX = DISP_X;								//┐
		windowSizeY = DISP_Y;								//│
		subWndSizeX = SUB_DISP_X;							//│
		subWndSizeY = SUB_DISP_Y;							//│
#ifdef  WINDOW_REDUCE										//│
		while((windowSizeX + subWndSizeX > desktopSizeX) /*||				//│
		      (windowSizeY + subWndSizeY > desktopSizeY)*/) {				//│ウインドウのクライアントサイズを決定する。マルチモニタ環境ならば、二つ並べてデスクトップに収まるサイズまで縮小する。
			if((windowSizeX >>= 1) <= 0) { DIE(); }					//│
			if((windowSizeY >>= 1) <= 0) { DIE(); }					//│
			if((subWndSizeX >>= 1) <= 0) { DIE(); }					//│
			if((subWndSizeY >>= 1) <= 0) { DIE(); }					//│
		}										//┘
		while((windowSizeX * windowSizeY * 3) > (desktopSizeX * desktopSizeY)) {	//┐//{{必須ではない。
			if((windowSizeX >>= 1) <= 0) { DIE(); }					//│
			if((windowSizeY >>= 1) <= 0) { DIE(); }					//│メイン画面のクライアントサイズの面積がデスクトップの面積の３(調整可)倍以下になるまで、ウインドウサイズを縮小する事にしました。
			if((subWndSizeX >>= 1) <= 0) { DIE(); }					//│ウインドウサイズがデスクトップサイズよりも僅かに小さいだけで、ほとんどフルスクリーンと変わらないような状況を回避するためです。
			if((subWndSizeY >>= 1) <= 0) { DIE(); }					//│
		}										//┘//}}必須ではない。
		if(subWndSizeX > windowSizeX) {							//┐//{{必須ではない。
			subWndSizeY = windowSizeX * subWndSizeY / subWndSizeX;			//│
			subWndSizeX = windowSizeX;						//│
		}										//│サブ画面のウインドウサイズは、縦横とも、メイン画面のウインドウサイズ以下とする事にした。
		if(subWndSizeY > windowSizeY) {							//│もし超えていた場合は、サブ画面のウインドウサイズが、縦横とも、メイン画面のウインドウサイズに収まるように、小さくする事にした。
			subWndSizeX = windowSizeY * subWndSizeX / subWndSizeY;			//│
			subWndSizeY = windowSizeY;						//│
		}										//┘//}}必須ではない。
#endif//WINDOW_REDUCE
#endif//DUALSCREEN
		//メイン画面のフルスクリーンサイズ,及び,フルスクリーン原点を求める。
		fullscrSizeX = desktopSizeX;							//┐
		fullscrSizeY = fullscrSizeX * DISP_Y / DISP_X;					//│
		if(fullscrSizeY > desktopSizeY) {						//├メインモニタのフルスクリーンサイズを求める。
			fullscrSizeY = desktopSizeY;						//│まず横一杯に合わせて縦サイズを計算し、もしオーバーしたら、縦一杯に合わせて横サイズを計算する。
			fullscrSizeX = fullscrSizeY * DISP_X / DISP_Y;				//│
		}										//┘
		fullscrPosX = (desktopSizeX - fullscrSizeX) / 2;				//┬メインモニタのフルスクリーン原点を求める。
		fullscrPosY = (desktopSizeY - fullscrSizeY) / 2;				//┘
		if(rcSubMon.left || rcSubMon.top) {						//マルチモニタ環境ならば…
			subFullSizeX = subDeskSizeX;						//┐
			subFullSizeY = subFullSizeX * DISP_Y / DISP_X;				//│
			if(subFullSizeY > subDeskSizeY) {					//├サブモニタのフルスクリーンサイズを求める。
				subFullSizeY = subDeskSizeY;					//│まず横一杯に合わせて縦サイズを計算し、もしオーバーしたら、縦一杯に合わせて横サイズを計算する。
				subFullSizeX = subFullSizeY * DISP_X / DISP_Y;			//│
			}									//┘
			subFullPosX = (subDeskSizeX - subFullSizeX) / 2;			//┬サブモニタのフルスクリーン原点を求める。
			subFullPosY = (subDeskSizeY - subFullSizeY) / 2;			//┘
		}
#ifdef  DUALSCREEN
		//サブ画面のフルスクリーンサイズ,及び,フルスクリーン原点を求める。
		ful2scrSizeX = desktopSizeX;							//┐
		ful2scrSizeY = ful2scrSizeX * SUB_DISP_Y / SUB_DISP_X;				//│
		if(ful2scrSizeY > desktopSizeY) {						//├メインモニタのフルスクリーンサイズを求める。
			ful2scrSizeY = desktopSizeY;						//│まず横一杯に合わせて縦サイズを計算し、もしオーバーしたら、縦一杯に合わせて横サイズを計算する。
			ful2scrSizeX = ful2scrSizeY * SUB_DISP_X / SUB_DISP_Y;			//│
		}										//┘
		ful2scrPosX = (desktopSizeX - ful2scrSizeX) / 2;				//┬メインモニタのフルスクリーン原点を求める。
		ful2scrPosY = (desktopSizeY - ful2scrSizeY) / 2;				//┘
		if(rcSubMon.left || rcSubMon.top) {						//マルチモニタ環境ならば…
			subFul2SizeX = subDeskSizeX;						//┐
			subFul2SizeY = subFul2SizeX * SUB_DISP_Y / SUB_DISP_X;			//│
			if(subFul2SizeY > subDeskSizeY) {					//├サブモニタのフルスクリーンサイズを求める。
				subFul2SizeY = subDeskSizeY;					//│まず横一杯に合わせて縦サイズを計算し、もしオーバーしたら、縦一杯に合わせて横サイズを計算する。
				subFul2SizeX = subFul2SizeY * SUB_DISP_X / SUB_DISP_Y;		//│
			}									//┘
			subFul2PosX = (subDeskSizeX - subFul2SizeX) / 2;			//┬サブモニタのフルスクリーン原点を求める。
			subFul2PosY = (subDeskSizeY - subFul2SizeY) / 2;			//┘
		}
#endif//DUALSCREEN
		if(SetGraphMode(max(desktopSizeX, subDeskSizeX),				//┬画面サイズを縦横個別にメインモニタとサブモニタの最大サイズに設定する。	←┬一見不要に見えるが必要です。SetWindowSize()によるウインドウサイズ変更は、(DxLib_Init()の前でも後でも)画面サイズを超えられないようです。要するに、デフォルトの画面サイズである640×480よりも大きいウインドウサイズへの変更を行いたい場合は、SetGraphMode()を使って画面サイズも大きくしておく必要が有るようです。しかし何となく根本的な制限ではなくて、DxLibがウインドウのリサイズの明示的に制限しているだけのような気もします。
				max(desktopSizeY, subDeskSizeY),				//│										　└'SetWindowSizeChangeEnableFlag(FALSE,FALSE)'を行わなければウインドウのリサイズは制限されないようなのですが、意図しない拡大が行われてしまいます。いろいろパラメータを組み合わせてみたのですが解決できなかったので、SetGraphMode()を呼び出して解決する事にしました。無駄に大きなバックバッファが生成されてメモリを消費する問題が有りますが、それ以外の支障は無いはずです。今後より良い方法が見つかったら変更するかも知れません。
				colorBitDepth)) { DIE(); }					//┘
		if(SetWindowSizeChangeEnableFlag(FALSE, FALSE)) { DIE(); }			//ウインドウのサイズが変化しても拡大しない設定にする。	
		if(SetWindowInitPosition(0, 0)) { DIE(); }					//ウインドウの初期位置を設定する。
		if(SetWindowSize(windowSizeX, windowSizeY)) { DIE(); }				//ウインドウの初期サイズを設定する。
	//}}□参照資料「ＤＸライブラリ質問掲示板 - ウィンドウモード切り換えについて」(http://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=3366)
		if(SetWindowStyleMode(5/*最小化無し*/)) { DIE(); }				//ゲームプログラムでは、ウインドウが最小化しない方が良いと思うので、最小化ボタンを無くす事にした。
		if(SetWindowUserCloseEnableFlag(FALSE)) { DIE(); }				//[×]ボタンが押された時に自動的にウインドウを削除せずGetWindowUserCloseFlag()で検出する。
		if(SetWaitVSyncFlag(FALSE)) { DIE(); }						//ScreenFlip()実行時にVSYNC待ちをしない。		⇒{{2016/03/27削除:フルスクリーン表示でもScreenFlip()を使わないように変更したので不要になりました。}}		DUALSCREEN時は必須です。DUALSCREEN時以外は任意です。	⇒{{2016/07/31再度有効化:再度有効化しました。このフラグはScreenFlip()だけでなくフロントバッファに対するDrawExtendGraph()等にも影響が有るようだからです(厳密には未検証)。テストのためにschedule()内の同期処理を削除して、この行をコメントアウトするとDrawExtendGraph()によるウインドウ表示でも60fpsに制限されるが、この行を有効にすると(負荷が低ければ)100fpsぐらいまで上がりました。(GeForce GT 735M)}}
		if(SetAlwaysRunFlag(TRUE)) { DIE(); }						//ウインドウが非アクティブでも実行する。DxLib_Init()より先に実行しておく必要がある。そうしないと起動直後に非アクティブだった場合に実行が開始しないので注意せよ。	DUALSCREEN時は必須です。DUALSCREEN時以外は任意です。
	/*任意*/if(SetFontCacheTextureColorBitDepth(16)) { DIE(); }				//フォントのキャッシュとして使用するテクスチャのカラービット深度を設定する(16又は32のみ指定可能。デフォルトは32)	//{{2016/08/12追加:16でも32でも見た目に違いが判らないと思ったので、メモリ節約のために16としました。}}
	#ifdef  USE_DIRECT3D_VERSION
		if(SetUseDirect3DVersion(USE_DIRECT3D_VERSION)) { DIE(); }			//使用するDirect3Dのバージョンを設定する。DxLib_Init呼び出しの前でのみ使用可能。
	#endif//USE_DIRECT3D_VERSION
		if(DxLib_Init()) { DIE(); }							//DxLibを開始する。
#ifdef  DUALSCREEN
		WNDCLASS wc;									//デュアルスクリーン用ウインドウを作成する。
		memset(&wc, 0, sizeof wc);
		wc.style         = CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc   = DsWndProc;
		wc.hInstance     = GetModuleHandle(NULL);
		wc.hCursor       = LoadCursor(NULL, IDC_ARROW) ;
		wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
		wc.lpszClassName = program_invocation_short_name;
		if(!RegisterClass(&wc)) { DIE(); }
	    //{{2016/12/12変更:デュアルスクリーン用ウインドウを、メインウインドウの子ウインドウにしました。変更前は、メインウインドウが最前面でもデュアルスクリーン用ウインドウが別のウインドウに隠れる事が有りましたが、変更後は、メインウインドウが最前面ならばデュアルスクリーン用ウインドウも最前面になるようになりました。
	    //	hSubWnd = CreateWindowEx(SUBWND_STYLE_EX, wc.lpszClassName, sCaption, SUBWND_STYLE, 0, 0, subWndSizeX, subWndSizeY, NULL, NULL, wc.hInstance, NULL);
	    //↓2016/12/12変更:デュアルスクリーン用ウインドウを、メインウインドウの子ウインドウにしました。変更前は、メインウインドウが最前面でもデュアルスクリーン用ウインドウが別のウインドウに隠れる事が有りましたが、変更後は、メインウインドウが最前面ならばデュアルスクリーン用ウインドウも最前面になるようになりました。
		hSubWnd = CreateWindowEx(SUBWND_STYLE_EX, wc.lpszClassName, sCaption, SUBWND_STYLE, 0, 0, subWndSizeX, subWndSizeY, GetMainWindowHandle(), NULL, wc.hInstance, NULL);
	    //}}2016/12/12変更:デュアルスクリーン用ウインドウを、メインウインドウの子ウインドウにしました。変更前は、メインウインドウが最前面でもデュアルスクリーン用ウインドウが別のウインドウに隠れる事が有りましたが、変更後は、メインウインドウが最前面ならばデュアルスクリーン用ウインドウも最前面になるようになりました。
		if(!hSubWnd) { DIE(); }
		RECT rcWindow, rcClient;							//デュアルスクリーン用ウインドウの位置とサイズを調整する。
		if(!GetWindowRect(hSubWnd, &rcWindow)) { DIE(); }
		if(!GetClientRect(hSubWnd, &rcClient)) { DIE(); }
		rcWindow.right  += subWndSizeX - (rcClient.right - rcClient.left);
		rcWindow.bottom += subWndSizeY - (rcClient.bottom - rcClient.top);
	    //{{2016/08/08変更:メイン画面とサブ画面のサイズを個別に設定できるように変更した事に伴い、デュアルスクリーン用ウインドウの位置を設定する処理も変更しました。
	    //	if(rcSubMon.left || rcSubMon.top) {
	    //	  //{{2016/03/27修正:こうしないとメインモニタとサブモニタの拡大率設定が違う場合(例えばメインが200%でサブが150%とか)に、Windowsの自動拡大が勝手に働いてメインウインドウがサブウインドウの拡大率に引きずられて全画面にならない。プロファイルでdpiAware=trueを指定していても回避出来ない。どうやらWindows10は一つのアプリケーションが拡大率設定の異なる複数のモニタにまたがった時の動作が良くないようだ。このように修正しても手でサブスクリーンをサブモニタへ移動してから全画面表示してしまうと同じ結果になるのだが、何も対策しないよりはマシだろう。	⇒{{2016/09/28コメント追記:本日test.manifestをdpiAware=True/PMに変更したので、Windows 8.1以降では左記の対策は不要になった。しかしWindows 8以前ではdpiAware=trueと見なされるので、左記の対策は残しておく事にした。もしかしたらWindows 8以前ではメインモニタとサブモニタの拡大率設定を個別に設定出来なくて考慮不要かも知れない(未確認)のだが、少なくとも害はないだろう。
	    //	  //	if(!OffsetRect(&rcWindow, rcSubMon.left - rcWindow.left, rcSubMon.top - rcWindow.top)) { DIE(); }	//マルチモニタ環境ならば、サブモニタに配置する。
	    //	  //↓2016/03/27修正:こうしないとメインモニタとサブモニタの拡大率設定が違う場合(例えばメインが200%でサブが150%とか)に、Windowsの自動拡大が勝手に働いてメインウインドウがサブウインドウの拡大率に引きずられて全画面にならない。プロファイルでdpiAware=trueを指定していても回避出来ない。どうやらWindows10は一つのアプリケーションが拡大率設定の異なる複数のモニタにまたがった時の動作が良くないようだ。このように修正しても手でサブスクリーンをサブモニタへ移動してから全画面表示してしまうと同じ結果になるのだが、何も対策しないよりはマシだろう。	⇒{{2016/09/28コメント追記:本日test.manifestをdpiAware=True/PMに変更したので、Windows 8.1以降では左記の対策は不要になった。しかしWindows 8以前ではdpiAware=trueと見なされるので、左記の対策は残しておく事にした。もしかしたらWindows 8以前ではメインモニタとサブモニタの拡大率設定を個別に設定出来なくて考慮不要かも知れない(未確認)のだが、少なくとも害はないだろう。
	    //		if(!OffsetRect(&rcWindow, rcWindow.right - rcWindow.left, 0)) { DIE(); }				//マルチモニタ環境でも、メインウインドウの右(と予測される位置)に配置する。
	    //	  //}}2016/03/27修正:こうしないとメインモニタとサブモニタの拡大率設定が違う場合(例えばメインが200%でサブが150%とか)に、Windowsの自動拡大が勝手に働いてメインウインドウがサブウインドウの拡大率に引きずられて全画面にならない。プロファイルでdpiAware=trueを指定していても回避出来ない。どうやらWindows10は一つのアプリケーションが拡大率設定の異なる複数のモニタにまたがった時の動作が良くないようだ。このように修正しても手でサブスクリーンをサブモニタへ移動してから全画面表示してしまうと同じ結果になるのだが、何も対策しないよりはマシだろう。	⇒{{2016/09/28コメント追記:本日test.manifestをdpiAware=True/PMに変更したので、Windows 8.1以降では左記の対策は不要になった。しかしWindows 8以前ではdpiAware=trueと見なされるので、左記の対策は残しておく事にした。もしかしたらWindows 8以前ではメインモニタとサブモニタの拡大率設定を個別に設定出来なくて考慮不要かも知れない(未確認)のだが、少なくとも害はないだろう。
	    //	} else {
	    //		if(!OffsetRect(&rcWindow, rcWindow.right - rcWindow.left, 0)) { DIE(); }				//シングルモニタ環境ならば、メインウインドウの右(と予測される位置)に配置する。
	    //	}
	    //↓2016/08/08変更:メイン画面とサブ画面のサイズを個別に設定できるように変更した事に伴い、デュアルスクリーン用ウインドウの位置を設定する処理も変更しました。
		RECT rcMainWnd;
		if(!GetWindowRect(GetMainWindowHandle(), &rcMainWnd)) { DIE(); }
		if(!OffsetRect(&rcWindow, rcMainWnd.right - rcMainWnd.left, 0)) { DIE(); }	//シングルモニタ環境でもマルチモニタ環境でも、メインウインドウの右に配置する。
	    //}}2016/08/08変更:メイン画面とサブ画面のサイズを個別に設定できるように変更した事に伴い、デュアルスクリーン用ウインドウの位置を設定する処理も変更しました。
		if(!MoveWindow(hSubWnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, FALSE)) { DIE(); }
		ShowWindow(hSubWnd, SW_SHOWNA/*アクティブ化不要*/);
		UpdateWindow(hSubWnd);
#endif//DUALSCREEN
		if((grScr = MakeScreen(DISP_X, DISP_Y, FALSE)) == -1) { DIE(); }		//仮想画面を作成する。
#ifdef  DUALSCREEN
		if((grSubScr = MakeScreen(SUB_DISP_X, SUB_DISP_Y, FALSE)) == -1) { DIE(); }	//サブ画面の仮想画面を作成する。
#endif//DUALSCREEN
		if(SetDrawScreen(grScr)) { DIE(); }						//描画対象を仮想画面にする。
		if(SetDrawMode(DX_DRAWMODE_BILINEAR)) { DIE(); }				//バイリニア法で描画する。デフォルトのネアレストネイバー法で描画する場合は、この行をコメントアウトせよ。
#ifdef  _DEBUG
		if(SetBackgroundColor(0, 255, 0)) { DIE(); }					//デバッグ版では、描画のし忘れを見落とさないように背景色を緑色にする。
#endif//_DEBUG
	///	if(ChangeFont("MS Mincho")) { DIE(); }						//┐
	///	if(ChangeFontType(DX_FONTTYPE_ANTIALIASING_EDGE)) { DIE(); }			//│
	///	if(ChangeFontType(DX_FONTTYPE_EDGE)) { DIE(); }					//├DrawString()用の設定を行う。埋め込みテクスチャフォントを使う場合は設定不要です。
	///	if(SetFontSize(16)) { DIE(); }							//│
	///	if(SetFontThickness(0)) { DIE(); }						//┘
		if(SetUseDXArchiveFlag(TRUE)) { DIE(); }					//┐
#ifdef  _DEBUG											//│
		if(SetDXArchivePriority(1/*フォルダを優先*/)) { DIE(); }			//├アーカイブを使う場合はこの行を有効にして下さい。
#endif//_DEBUG											//│
	///	if(SetDXArchiveKeyString(program_invocation_short_name)) { DIE(); }		//┘
	///	if(SetTransColor(0, 255, 0)) { DIE(); }						//┬グラフィックを読み込む時に透過色機能を使用しない。透過色機能を使用する場合はこの行を変更して下さい。
		if(SetUseTransColor(FALSE)) { DIE(); }						//┘
		if(SetCreateSoundDataType(DX_SOUNDDATATYPE_FILE)) { DIE(); }			//音声データの再生形式を設定する。データの用途に応じてLoadSoundMem()を呼び出す直前で変更しても構わない。
	}
#ifdef  __CLIP_CBKQ_H__
	//コールバックキューを初期化する。
	pCbkQue = DynamicCbkQue_New(16384/*調整可*/);		//16384でCbkQue_draw_grp()x500回分ぐらいです。CbkQue_draw_strf()等を使うともっと消費します。動的コールバックキューなので小さな値でも(0でも)構いません。
#ifdef  DUALSCREEN
	pSubCbkQue = DynamicCbkQue_New(16384/*調整可*/);	//16384でCbkQue_draw_grp()x500回分ぐらいです。CbkQue_draw_strf()等を使うともっと消費します。動的コールバックキューなので小さな値でも(0でも)構いません。
#endif//DUALSCREEN
#endif//__CLIP_CBKQ_H__
#ifdef  RegKey_TexDef
	//テクスチャ描画を初期化する。
	stTexInf.pTexDef = REG_open_key(TBL_RegTbl, RegKey_TexDef);
#endif//RegKey_TexDef
#ifdef  RegKey_SprDef
	//スプライト描画を初期化する。
	stSprInf.pSprDef = REG_open_key(TBL_RegTbl, RegKey_SprDef);
#endif//RegKey_SprDef
#ifdef  RegKey_PhrDef
	//フレーズ再生を初期化する。
	stPhrInf.pPhrDef = REG_open_key(TBL_RegTbl, RegKey_PhrDef);
#endif//RegKey_PhrDef
#ifdef  USE_SOFDEC
	//Sofdecを初期化する。
	static const ST_SofdecHelperInfo stSofdecHelperInfo = {
		//--- SofdecHelper ---
		SOFDEC_NUM_MOVIES,	//同時再生するムービーの数			0可
		Sofdec_fnGetNextMovie,	//ムービーのシームレス連続再生用コールバック	NULL可
		0/*MovieKey*/,		//暗号化されたムービーデータの復号キー		0を指定すると、ムービーデータは暗号化されていないものと見なして、ムービーデータのデクリプタを作成しない。	//{{2017/04/03追加:暗号化されたデータの再生に対応しました。}}
    #ifdef  USE_ADX
		//--- AdxHelper ---
		ADX_NUM_SOUNDS,		//同時再生するサウンドの数			0可
		Sofdec_fnGetNextSound,	//サウンドのシームレス連続再生用コールバック	NULL可
		0/*SoundKey*/,		//暗号化された音声データの復号キー		0を指定すると、音声データは暗号化されていないものと見なして、音声データのデクリプタを作成しない。		//{{2017/04/03追加:暗号化されたデータの再生に対応しました。}}
    #endif//USE_ADX
	};
	SofdecHelper_Init(&stSofdecHelperInfo);
#endif//USE_SOFDEC
#ifdef  USE_SSBPLIB
	//ssbpLibを初期化する。
	ssbpLib_Init(ssbpLib_GetAddress);
	resman = ssbpLib_ResourceManager_getInstance();
#endif//USE_SSBPLIB
	//フォントハンドルを作成する。
	if((fontSmall  = CreateFontToHandle("ＭＳ 明朝", 12, 0, DX_FONTTYPE_EDGE                 )) == -1) { DIE(); }	//┐
	if((fontMedium = CreateFontToHandle("ＭＳ 明朝", 24, 0, DX_FONTTYPE_ANTIALIASING_EDGE    )) == -1) { DIE(); }	//│
	if((fontLarge  = CreateFontToHandle("ＭＳ 明朝", 48, 0, DX_FONTTYPE_ANTIALIASING_EDGE_8X8)) == -1) { DIE(); }	//│
	{char* buf = TrueType_AddFontFile("grp/ttf/Apple ][.ttf");							//│
	int FontCacheCharNum = GetFontCacheCharNum();									//├変更可	//フォントキャッシュでキャッシュできる文字数を退避する。
	if(SetFontCacheCharNum(128/*調整可*/)) { DIE(); }								//│		//フォントキャッシュでキャッシュできる文字数を設定する。フォントキャッシュの容量を節約するためにこうしました。DxLibのデフォルトでは2024文字(DxLibMakeTest/DxFont.h参照)ですが、英語フォントならばもっと少なくて済むからです。
	if((fontCustom = CreateFontToHandle(        buf, 32, 0, DX_FONTTYPE_ANTIALIASING_8X8     )) == -1) { DIE(); }	//│		//カスタムフォント用のフォントハンドルを作成する。
	if(SetFontCacheCharNum(FontCacheCharNum)) { DIE(); }	//忘れないで!!						//│		//フォントキャッシュでキャッシュできる文字数を復帰する。
	free(buf);}													//┘
	//スプライトフォントを作成する。
	if(!(pSprFntNum = REG_open_key_l(TBL_RegTbl, RegKey_SprFnt, RegKey_Num, -1))) { DIE(); };	//┬変更可
	if(!(pSprFntMda = REG_open_key_l(TBL_RegTbl, RegKey_SprFnt, RegKey_Mda, -1))) { DIE(); };	//┘
#ifdef  __CLIP_DURC_H__
	//存続カウンタを初期化する。
	pDurCnt = DurCnt_New();
#endif//__CLIP_DURC_H__
	//タイマを初期化する。
	TimMgr_Init(&stTimMgr, FPS);
	//サウンドを初期化する。
#ifdef  USE_ADX
	init_snd(&stTimMgr, 1/*=_use_adx*/);
#else //USE_ADX
	init_snd(&stTimMgr, 0/*=_use_adx*/);
#endif//USE_ADX
#ifdef  __CLIP_CNTM_H__
	//汎用カウンタ管理を初期化する。
	{
		pCntMgr = CntMgr_New(CntCh_Max+1);
		//汎用カウンタ管理を開始する。
		{
			static ST_TimMgrFunc stTimMgrFunc = { (void (*)(void*))CntMgr_Exec, pCntMgr, 1 };
			TimMgr_AddFunc(&stTimMgr, TimMgrCh_1f, &stTimMgrFunc);
		}
	}
#endif//__CLIP_CNTM_H__
#ifdef  __CLIP_DLYQ_H__
	//遅延コールバックキューを初期化する。
	{
		pDlyQue = DlyQue_New();
		//遅延コールバックキューを開始する。
		{
			static ST_TimMgrFunc stTimMgrFunc = { (void (*)(void*))DlyQue_Exec, pDlyQue, 1 };
			TimMgr_AddFunc(&stTimMgr, TimMgrCh_1f, &stTimMgrFunc);
		}
	}
#endif//__CLIP_DLYQ_H__
#ifdef  __CLIP_LCDS_H__
	//液晶シーケンサを初期化する。
	{
		static const struct {
			ST_LcdSeqInfo	stLcdSeqInfo;
			ST_LcdSeqChInfo	TBL_LcdSeqChInfo[(LcdSeqCh_Max+1)];
		} stLcdSeqInfo = {{
			LcdSeqCh_fnDraw,
			SprNo_Max,
			LcdSeqCh_Max+1,
		},{
//{{アプリケーション特有の設定
			{DX_BLENDMODE_ALPHA,100,DISP_X*1/3,DISP_Y*1/3,-1},	//BgdAlp
			{DX_BLENDMODE_ADD  ,200,DISP_X*2/3,DISP_Y*1/3,-1},	//BgdAdd
			{DX_BLENDMODE_ALPHA,300,DISP_X*1/3,DISP_Y*2/3,-1},	//FgdAlp
			{DX_BLENDMODE_ADD  ,400,DISP_X*2/3,DISP_Y*2/3,-1},	//FgdAdd
//}}アプリケーション特有の設定
		}};
		pLcdSeq = LcdSeq_New(&stLcdSeqInfo.stLcdSeqInfo);
	}
#endif//__CLIP_LCDS_H__
#ifdef  __CLIP_DIRS_H__
	//演出シーケンサを初期化する。
	{
		pDirSeq = DirSeq_New(fnAct, DirSeqCh_Max+1);
		//演出シーケンサを開始する。
		{
			static ST_TimMgrFunc stTimMgrFunc = { (void (*)(void*))DirSeq_Exec, pDirSeq, 1 };
			TimMgr_AddFunc(&stTimMgr, TimMgrCh_1f, &stTimMgrFunc);
		}
	}
#endif//__CLIP_DIRS_H__
#ifdef  __CLIP_EVTM_H__
	//イベントタイマを初期化する。
	{
		pEvtTmr = EvtTmr_New(EvtTmrNo_Max+1);
		//イベント処理関数を登録する。
		{
			static ST_EvtTmrFunc stEvtTmrFunc = { onEvent };
			EvtTmr_AddFunc(pEvtTmr, &stEvtTmrFunc);
		}
		//イベントタイマを開始する。
		{
			static ST_TimMgrFunc stTimMgrFunc = { (void (*)(void*))EvtTmr_Exec, pEvtTmr, 1 };
			TimMgr_AddFunc(&stTimMgr, TimMgrCh_1f, &stTimMgrFunc);
		}
	}
#endif//__CLIP_EVTM_H__
#ifdef  __CLIP_LEDS_H__
	//LEDシーケンサを初期化する。
	{
		pLedSeq = LedSeq_New(LedCh_Max + 1, LedSeqCh_Max + 1);
		//LEDシーケンサを開始する。
		{
			static ST_TimMgrFunc stTimMgrFunc = { (void (*)(void*))LedSeq_TimeProc, NULL, 1 };
			TimMgr_AddFunc(&stTimMgr, TimMgrCh_1f, &stTimMgrFunc);
		}
	}
#endif//__CLIP_LEDS_H__
#ifdef  USE_NUKLEAR
	//Nuklearを初期化する。
	{
		ctx = nk_dxlib_new();
		if(SetHookWinProc(NkWndProc)) { DIE(); }
	    #ifdef  SprNo_NK_CUSTOM_CURSOR_DATA
		nk_dxlib_load_cursor(ctx, SprNo_NK_CUSTOM_CURSOR_DATA);
	    #endif//SprNo_NK_CUSTOM_CURSOR_DATA
	    //{{任意:nk_dxlib_new()が設定したデフォルトフォントのままで使用する場合はこの範囲は不要です。
		{
			static struct nk_user_font font;
			nk_dxlib_init_font(&font, fontSmall);
			nk_style_set_font(ctx, &font);
		}
	    //}}任意:nk_dxlib_new()が設定したデフォルトフォントのままで使用する場合はこの範囲は不要です。
	}
#endif//USE_NUKLEAR
#ifdef  BACKGROUND_PRELOAD
	//バックグラウンドプリロードを開始する。
	{
		static ST_TimMgrFunc stTimMgrFunc = { BackgroundPreload, NULL, 1 };
		TimMgr_AddFunc(&stTimMgr, TimMgrCh_1f, &stTimMgrFunc);
	}
#endif//BACKGROUND_PRELOAD
//{{アプリケーション特有の処理
	{
		//※TODO:
	}
//}}アプリケーション特有の処理
	//タイマを開始する。
	timer_id = timer_start(1, (void (*)(void*))TimMgr_Intr, &stTimMgr);
}
/*--------------------------------------------------------------------------*/
void cpp_exit() {
	//タイマを停止する。
	timer_stop(timer_id);
#ifdef  USE_SSBPLIB
	//ssbpLibを終了する。
	ssbpLib_ResourceManager_delete(resman);
#endif//USE_SSBPLIB
#ifdef  USE_SOFDEC
	//Sofdecを終了する。
	SofdecHelper_Exit();
#endif//USE_SOFDEC
	//DxLibを終了する。
	if(DxLib_End()) { DIE(); }
}
/****************************************************************************
 *	グラフィック
 ****************************************************************************/
#ifdef  RegKey_TexDef
static void fnPreLoadGraph(int iGrp) {
//{{アプリケーション特有の処理
    //	switch(iGrp) {
    //	case TexNo_〜:
    //		SetMovieRightImageAlphaFlag(1);
    //		break;
    //	default:
    //		SetMovieRightImageAlphaFlag(0);
    //		break;
    //	}
//}}アプリケーション特有の処理
}
#endif//RegKey_TexDef
ST_TexInf stTexInf
#ifdef  RegKey_TexDef
={
	RegKey_Path,		//name_Path
    #ifdef  RegKey_loop
	RegKey_loop,		//name_loop
    #else //RegKey_loop
	0,			//name_loop		ダミー
    #endif//RegKey_loop
    #ifdef  RegKey_scale
	RegKey_scale,		//name_scale
    #else //RegKey_scale
	0,			//name_scale		ダミー
    #endif//RegKey_scale
	fnPreLoadGraph,		//fnPreLoadGraph	NULL可
}
#endif//RegKey_TexDef
;
ST_SprInf stSprInf
#ifdef  RegKey_SprDef
={
	RegKey_TexNo,		//name_TexNo
	RegKey_x,		//name_x
	RegKey_y,		//name_y
	RegKey_w,		//name_w
	RegKey_h,		//name_h
	RegKey_cx,		//name_cx
	RegKey_cy,		//name_cy
	RegKey_Param,		//name_Param
}
#endif//RegKey_SprDef
;
/*--------------------------------------------------------------------------*/
#ifdef  USE_SOFDEC
static void Sofdec_fnGetNextMovie(const char* sCurrentMoviePath, char sNextMoviePath[/*_MAX_PATH*/]) {
//{{アプリケーション特有の処理
	//※TODO:
//}}アプリケーション特有の処理
}
#endif//USE_SOFDEC
/*--------------------------------------------------------------------------*/
#ifdef  USE_AFTERFX
static void AfxBin_Draw_fnDraw(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, const char* _footage, int sequence, double opacity, int blendingMode, void* user_data) {
	static ST_AfxBin_Draw_GetFootage_Param param={	/* ＳＴＡＴＩＣです！ */
		RegKey_SprNo,	//テクスチャを使って描画する場合はRegKey_TexNoに変えて下さい。
	};
	if(!param.pEnmKey) { if(!pEnmKey) { DIE(); } param.pEnmKey = pEnmKey; }	//初回に当関数が呼び出された時にpEnmKeyフィールドを格納する。グローバル変数pEnmKeyに'pEnmKey=REG_open_key(TBL_RegTbl,RegKey_EnmDef)'が格納済みと想定します。
	//素材のベースIDを取得する。
	int footage = AfxBin_Draw_GetFootage(_footage, &param);	//ユーティリティ関数を利用する。又はアプリケーションが他の方法で検索しても構いません。
	//スプライト情報を取得する。
	ST_SprDef stSprDef;
	get_sprDef(footage + sequence, &stSprDef);
	//自由変形スプライトを描画する。
	ST_CbkQue* pCbkQue = (ST_CbkQue*)((void**)user_data)[0];
	int        pri     =   (intptr_t)((void**)user_data)[1];
	CbkQue_draw_spr3(pCbkQue,
		pri,
		x1, y1,	//topLeft
		x2, y2,	//topRight
		x3, y3,	//bottomRight	//┬TriangleFanの並び
		x4, y4,	//bottomLeft	//┘
		footage + sequence,
		D3DRGBA(1.0,1.0,1.0,opacity),
		blendingMode ? DX_BLENDMODE_ADD : DX_BLENDMODE_ALPHA);
}
static const ST_AfxBin* AfxBin_Draw_fnFilter(int layerDepth, const char* layerPath[], const ST_AfxBin* pAfxBin, void* user_data) {
	//※TODO:
	return pAfxBin;
}
static void fnGetAnchorPoint(int iAfxSeqNo, int* anchorPoint_x, int* anchorPoint_y) {
//{{アプリケーション特有の処理
	static ght_hash_table_t* ht;
	if(!ht) { ght_set_rehash((ht = ght_create(0)), 1); }
	int* anchorPoint/*[2]*/ = (int*)ght_get(ht, sizeof iAfxSeqNo, &iAfxSeqNo);
	if(!anchorPoint) {
		static yaml_document_t* d;
		if(!d) {
//{{2016/09/24変更:アンカーポイントを定義したYamlファイルが、DXアーカイブ内に有っても読み込めるようにしました。
//			SEH_try {
//				const char* pName = "grp/yml/AnchorPoint.yml";	//※TODO:
//				syslog(LOG_DEBUG, "fnGetAnchorPoint: yaml_document_load '%s'", pName);
//				d = yaml_document_load(pName);
//			} SEH_catch(YamlException) {
//				syslog(LOG_WARNING, "fnGetAnchorPoint: yaml_document_load failed.");
//				d = yaml_document_new();
//			} SEH_end
//↓2016/09/24変更:アンカーポイントを定義したYamlファイルが、DXアーカイブ内に有っても読み込めるようにしました。
			const char* pName = "grp/yml/AnchorPoint.yml";	//※TODO:
			syslog(LOG_DEBUG, "fnGetAnchorPoint: FullyLoadText '%s'", pName);
			char* s = FullyLoadText(pName);
			if(s) {
				d = yaml_document_parse(s);
				free(s);
			} else {
				syslog(LOG_WARNING, "fnGetAnchorPoint: FullyLoadText failed.");
				d = yaml_document_new();
			}
//}}2016/09/24変更:アンカーポイントを定義したYamlファイルが、DXアーカイブ内に有っても読み込めるようにしました。
		}
		anchorPoint = (int*)malloc(sizeof(int) * 2);
		if(!anchorPoint) { DIE(); }
		SEH_try {
			const char* pName = EnmDef_GetName(pEnmKey, RegKey_AfxSeq, iAfxSeqNo);
			syslog(LOG_DEBUG, "fnGetAnchorPoint: yaml_path_get_number_f '%s'", pName);
			anchorPoint[0] = yaml_path_get_number_f(d, NULL, "%s.x", pName);
			anchorPoint[1] = yaml_path_get_number_f(d, NULL, "%s.y", pName);
		} SEH_catch(YamlException) {
			syslog(LOG_WARNING, "fnGetAnchorPoint: yaml_path_get_number_f failed.");
			anchorPoint[0] = 0;
			anchorPoint[1] = 0;
		} SEH_end
		if(ght_insert(ht, anchorPoint, sizeof iAfxSeqNo, &iAfxSeqNo)) { DIE(); }
	}
	*anchorPoint_x = anchorPoint[0];
	*anchorPoint_y = anchorPoint[1];
//}}アプリケーション特有の処理
}
void CbkQue_draw_afx(ST_CbkQue* pCbkQue, int pri, int iAfxSeqNo, int iFrame, int bLoop, int position_x/* = 0*/, int position_y/* = 0*/, double scale_x /*= 1.0*/, double scale_y /*= 1.0*/, double rotation /*= 0.0*/, double opacity /*= 1.0*/, int blendingMode /*= 0*/) {
	void* user_data[2] = { pCbkQue, (void*)(intptr_t)pri };
	ST_AfxMat tmp = AfxMat_1;
	int anchorPoint_x, anchorPoint_y;
	fnGetAnchorPoint(iAfxSeqNo, &anchorPoint_x, &anchorPoint_y);
	if(position_x || position_y)			{ AfxMat_Position(&tmp, position_x, position_y); }
	if(rotation)					{ AfxMat_Rotation(&tmp, rotation); }
	if((scale_x != 1.0) || (scale_y != 1.0))	{ AfxMat_Scale(&tmp, scale_x, scale_y); }
	if(anchorPoint_x || anchorPoint_y)		{ AfxMat_AnchorPoint(&tmp, anchorPoint_x, anchorPoint_y); }
	AfxBin_DrawNo(TBL_AfxSeqNo, iAfxSeqNo, iFrame, bLoop, &tmp, opacity, blendingMode, AfxBin_Draw_fnDraw, AfxBin_Draw_fnFilter, user_data);
}
#endif//USE_AFTERFX
/****************************************************************************
 *	サウンド
 ****************************************************************************/
#ifdef  RegKey_PhrDef
static void fnPreLoadSoundMem(int iPhr) {
//{{アプリケーション特有の処理
    //	switch(iPhr) {
    //	case PhrNo_〜:
    //		SetCreateSoundDataType(DX_SOUNDDATATYPE_MEMNOPRESS);
    //		//SetCreateSoundDataType(DX_SOUNDDATATYPE_MEMNOPRESS_PLUS);
    //		//SetCreateSoundDataType(DX_SOUNDDATATYPE_MEMPRESS);
    //		break;
    //	default:
    //		SetCreateSoundDataType(DX_SOUNDDATATYPE_FILE);
    //		break;
    //	}
//}}アプリケーション特有の処理
}
#endif//RegKey_PhrDef
ST_PhrInf stPhrInf
#ifdef  RegKey_PhrDef
={
	RegKey_Path,		//name_Path
    #ifdef  RegKey_Next
	RegKey_Next,		//name_Next
    #else //RegKey_Next
	0,			//name_Next		ダミー
    #endif//RegKey_Next
	fnPreLoadSoundMem,	//fnPreLoadSoundMem	NULL可
}
#endif//RegKey_PhrDef
;
/*--------------------------------------------------------------------------*/
//{{アプリケーション特有の設定
static const uint8_t TBL_TapSet_Bgm []={TapDevCh_Bgm ,-1};
static const uint8_t TBL_TapSet_Sfx1[]={TapDevCh_Sfx1,-1};
static const uint8_t TBL_TapSet_Sfx2[]={TapDevCh_Sfx2,-1};
static const uint8_t TBL_TapSet_Err []={TapDevCh_Err ,-1};
static const uint8_t* const TBL_TapSet[]={
	TBL_TapSet_Bgm ,
	TBL_TapSet_Sfx1,
	TBL_TapSet_Sfx2,
	TBL_TapSet_Err ,
};
static_assert(((sizeof TBL_TapSet)/(sizeof TBL_TapSet[0])) == (TapLogCh_Max+1), "TBL_TapSet[]の要素数が不正です。");
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static const uint8_t TBL_BaseCh[]={
	TapLogCh_Bgm,	//Bgm
	TapLogCh_Sfx1,	//Sfx
	TapLogCh_Err,	//Err
};
static_assert(((sizeof TBL_BaseCh)/(sizeof TBL_BaseCh[0])) == (TapSeqCh_Max+1), "TBL_BaseCh[]の要素数が不正です。");
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static const int TBL_MxrChMask_Bgm []={1<<TapMxrCh_Tvo|1<<TapMxrCh_Mut};
static const int TBL_MxrChMask_Sfx1[]={1<<TapMxrCh_Tvo|1<<TapMxrCh_Mut};
static const int TBL_MxrChMask_Sfx2[]={1<<TapMxrCh_Tvo|1<<TapMxrCh_Mut};
static const int TBL_MxrChMask_Err []={1<<TapMxrCh_Tvo};
static const int* const TBL_MxrChMask[]={
	TBL_MxrChMask_Bgm ,
	TBL_MxrChMask_Sfx1,
	TBL_MxrChMask_Sfx2,
	TBL_MxrChMask_Err ,
};
static_assert((TapMxrCh_Max+1) <= 32, "ミキサーチャネル数が32を超える場合は'TBL_MxrChMask_〜[][2]'等とする変更が必要です。");
static_assert(((sizeof TBL_MxrChMask)/(sizeof TBL_MxrChMask[0])) == (TapLogCh_Max+1), "TBL_MxrChMask[]の要素数が不正です。");
//}}アプリケーション特有の設定
ST_SndInf stSndInf={
	//TAPシーケンサの設定
	(PhrNo_Max+1),		//nPhr			フレーズ数
	(TapDevCh_Max+1),	//nDevCh		デバイスチャネル数
	(TapLogCh_Max+1),	//nLogCh		論理チャネル数
	(TapSeqCh_Max+1),	//nSeqCh		シーケンサチャネル数
	(1000/FPS),		//iCont			ループフレーズ引き継ぎ時間[ms]
	500,			//iPrep			再生準備時間[ms]	//{{2017/04/02追加:再生準備通知を追加しました。}}
	31,			//nEvt			イベント記録数
	~(1<<TapEvt_Ctrl),	//iEvtMsk		イベントマスク
	TBL_TapSet,		//pTBL_TapSet		TAPセットテーブルへのポインタ
	TBL_BaseCh,		//pTBL_BaseCh		ベース論理チャネル番号テーブルへのポインタ
	//TAPミキサーの設定
	(TapMxrCh_Max+1),	//nMxrCh		ミキサチャネル数
	TBL_MxrChMask,		//TBL_MxrChMask		ミキサーチャネルマスク
};
/*--------------------------------------------------------------------------*/
#ifdef  USE_ADX
static void Sofdec_fnGetNextSound(const char* sCurrentSoundPath, char sNextSoundPath[/*_MAX_PATH*/]) {
//{{アプリケーション特有の処理
	//※TODO:
//}}アプリケーション特有の処理
}
#endif//USE_ADX
/****************************************************************************
 *	LED
 ****************************************************************************/
#ifdef  __CLIP_LEDS_H__
static int LedSeq_Exec_fnFilter(ST_LedSeq* pLedSeq, int iLedSeqCh, int iLedCh, int Dimmer) {
//{{アプリケーション特有の処理
	//※TODO:
//}}アプリケーション特有の処理
	return Dimmer;
}
static void LedSeq_TimeProc(void* arg) {
	//展開バッファを1(消灯)でクリアする。
	memset(LedSeq_Buffer, 1/*消灯*/, sizeof LedSeq_Buffer);	//忘れないで!!
	//LEDシーケンサの周期処理を実行する。
	LedSeq_Exec(pLedSeq, LedSeq_Buffer, LedSeq_Exec_fnFilter);
}
#endif//__CLIP_LEDS_H__
/****************************************************************************
 *	
 ****************************************************************************/
void schedule() {
#ifdef  __CLIP_RRS_H__
	//UIジョブからの呼び出しでなければ…
	if(RRS_i_job(pRRS) != (RRS_n_job(pRRS) - 1)) {	//最後のジョブがUIジョブである。
		//計算ジョブであると判断して、計算ジョブの周期処理を行う。
		// - ジョブを三個以上作成した場合は、必ずしも、UIジョブでなければ計算ジョブであるとは限らない。
		//   UIジョブと計算ジョブ以外からは、schedule()を呼び出さないように注意しろ。
		RRS_yield(pRRS);
//{{アプリケーション特有の処理
		//※TODO:
//}}アプリケーション特有の処理
		return;	//ここまで
	}
#endif//__CLIP_RRS_H__
	int bFrameSkip = 0;	//今回のフレームでフレームスキップを行うか。
#ifdef  SHOW_FPS
	//計算処理の実効FPSを算出,及び,FPS表示のOn/Offを行う。
	ExecFps();
#endif//SHOW_FPS
	{
	    //{{フレームスキップ処理
		static int f0, fs;	//前回のフレームカウンタ、フレームスキップの残り回数
		       int f1, df;	//今回のフレームカウンタ、今回の経過フレーム数
		//フレームスキップの残り回数が有れば、○%でフレームスキップを行う。
	    //	if(fs && !(now & 3)/*25%*/) { bFrameSkip = 1; }	//┐
		if(fs &&  (now & 1)/*50%*/) { bFrameSkip = 1; }	//├どれか一つを選択して下さい。
	    //	if(fs &&  (now & 3)/*75%*/) { bFrameSkip = 1; }	//┘
	    //}}フレームスキップ処理
#ifdef  USE_NUKLEAR
		//Nuklearの描画処理を実行する。
		// - nk_dxlib_render()の中で、コンテキストがクリアされる。
		//   「nk_dxlib_render()→nk_input_begin()→ProcessMessage()→nk_input_end()→アプリケーション処理」という処理順序にするために、ここでnk_dxlib_render()を呼び出す必要が有る事に注意せよ。
		//   実際には「nk_input_begin()→ProcessMessage()→nk_input_end()→nk_dxlib_render()→アプリケーション処理」という処理順序でも動作するようだが、Nuklearのdemoのサンプルソースに合わせてこの処理順序にしておく方が安全だろう。
		// - nk_dxlib_render()の中で行った描画処理はコールバックキューに積まれて、実際の描画処理はこの後で(フレームスキップが発生しなければ)描画される。
		nk_dxlib_render(ctx, pCbkQue, SHRT_MAX/*調整可*/);
		//Nuklearのイベント処理を開始する。
		nk_input_begin(ctx);
#endif//USE_NUKLEAR
		for(;;) {
#ifdef  USE_ACTIVETCL
			//Tcl/Tkのイベント処理を行う。
			while(Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT)) { /** no job **/ }
			if(!Tk_GetNumMainWindows()) { longjmp(env_exit, 1); }
#endif//USE_ACTIVETCL
#ifdef  DUALSCREEN
			//デュアルスクリーン用ウインドウのメッセージを処理する。
			{
				MSG msg;
				while(PeekMessage(&msg, hSubWnd, 0, 0, PM_REMOVE)) {
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
			}
#endif//DUALSCREEN
			//何らかの要因でウインドウが削除されたか,又は,[×]ボタンが押されたら終了する。
			if(ProcessMessage() || GetWindowUserCloseFlag()) { longjmp(env_exit, 1); }
			//タイマの周期処理を実行する。
			TimMgr_Exec(&stTimMgr);
#ifdef  __CLIP_TAPS_H__
			//TAPシーケンサのイベント処理を行う。
			{
				ST_TapEvt* pTapEvt;
				while((pTapEvt = TapSeq_EvtGet(pTapSeq))) { onTapEvt(pTapEvt); }
			}
#endif//__CLIP_TAPS_H__
#ifdef  USE_SOFDEC
			//Sofdecの周期処理を実行する。
			SofdecHelper_Exec();
#endif//USE_SOFDEC
#ifdef  __CLIP_RRS_H__
			//Round Robin Scheduler (RRS)を実行する。
			// - この処理タイミングは、UIジョブ以外のジョブはUIジョブよりも早く実行されて良い、と想定しています。
			//   もしUIジョブと歩調を合わせる場合は、下記のRRS_yield()の呼び出し処理をschedule()の先頭へ移動して下さい。
			//   そうすれば、schedule()一回につき、RRS_yield()も一回だけ実行されるようになります。
			RRS_yield(pRRS);
#endif//__CLIP_RRS_H__
	    //{{フレームスキップ処理
			//今回のフレームカウンタを取得する。
			f1 = TimMgr_GetCnt(&stTimMgr, TimMgrCh_1f);
			//今回の経過フレーム数を求める。
			df = f1 - f0;
			//1フレーム以上経過したか,又は,今回のフレームでフレームスキップを行うならば、ループを抜ける。
			if(df || bFrameSkip) { break; }
	    //}}フレームスキップ処理
			//ここでタイムスライスを放棄する方が全体の性能が良くなるかどうかはアプリケーション次第です。
	      /*任意*/	Sleep(0);
		}
#ifdef  USE_NUKLEAR
		//Nuklearのイベント処理を終了する。
		nk_input_end(ctx);
#endif//USE_NUKLEAR
	    //{{フレームスキップ処理
		//フレームスキップを消化したならば…
		if((unsigned)df < 1) {
			//フレームスキップの残り回数を減らす。
			UVAR_DEC(fs);
		//時間オーバーが発生したならば…
		} else if((unsigned)df > 1) {
			//フレームスキップの残り回数を増やす。
			// - 実際にフレームスキップを行うのは次回以降のフレームです。
			UVAR_ADD(fs, df - 1);
			fs = min((unsigned)fs, (unsigned)SEC(0.5)/*調整可*/);	//リミッタ
		}
		//次回のために、フレームカウンタを記憶する。
		f0 = f1;
	    //}}フレームスキップ処理
	}
#ifdef  __CLIP_DURC_H__
	//存続カウンタの周期処理を実行する。
	DurCnt_Exec(pDurCnt);
#endif//__CLIP_DURC_H__
#ifdef  __CLIP_LCDS_H__
	//液晶シーケンサの描画処理を実行する。
	LcdSeq_Draw(pLcdSeq);
#endif//__CLIP_LCDS_H__
	//今回のフレームでフレームスキップを行うならば…
	if(bFrameSkip) {
#ifdef  __CLIP_CBKQ_H__
		//描画処理,及び,ムービーグラフィックの自動停止処理を行わずに、コールバックキューを空の状態に戻す。
		CbkQue_Clear(pCbkQue);		//コールバックキューを空の状態に戻す。アプリケーションによっては、一度登録したコールバックキューを何度も使い回す場合は、この行を削除して下さい。
#ifdef  DUALSCREEN
		CbkQue_Clear(pSubCbkQue);	//コールバックキューを空の状態に戻す。アプリケーションによっては、一度登録したコールバックキューを何度も使い回す場合は、この行を削除して下さい。
#endif//DUALSCREEN
#endif//__CLIP_CBKQ_H__
	//今回のフレームでフレームスキップを行わないならば…
	} else {
#ifndef DUALSCREEN	//--------------------------------------------------------------------------------------//
#ifdef  __CLIP_CBKQ_H__
		//コールバックキューを実行する。
		if(SetDrawScreen(grScr)) { DIE(); }							//描画対象を仮想画面にする。
		CbkQue_Invoke(pCbkQue);		//登録されているノードを全て呼び出す。アプリケーションによっては、他の処理を挟んでCbkQue_InvokePri()を複数回分けて呼び出すように変更して下さい。
		CbkQue_Clear(pCbkQue);		//コールバックキューを空の状態に戻す。アプリケーションによっては、一度登録したコールバックキューを何度も使い回す場合は、この行を削除して下さい。
#endif//__CLIP_CBKQ_H__
#ifdef  SHOW_FPS
		//描画処理の実効FPSを算出,及び,FPSの描画を行う。
		DrawFps();
#endif//SHOW_FPS
		//画面を更新する。
		if(SetDrawScreen(DX_SCREEN_FRONT)) { DIE(); }						//描画対象をフロントバッファにする。
		switch(iFullScrMode) {
		default:DIE();
		case 0:	//ウインドウ表示
			if(DrawExtendGraph(								//仮想画面の内容をフロントバッファに反映する。
				0,
				0,
				windowSizeX,
				windowSizeY,
				grScr, FALSE)) { DIE(); }
			break;
		case 1:	//メイン画面をメインモニタでフルスクリーン表示
			if(DrawExtendGraph(								//仮想画面の内容をフロントバッファに反映する。
				fullscrPosX,
				fullscrPosY,
				fullscrPosX + fullscrSizeX,
				fullscrPosY + fullscrSizeY,
				grScr, FALSE)) { DIE(); }
			break;
		case 2:	//メイン画面をサブモニタでフルスクリーン表示
			if(DrawExtendGraph(								//仮想画面の内容をフロントバッファに反映する。
				subFullPosX,
				subFullPosY,
				subFullPosX + subFullSizeX,
				subFullPosY + subFullSizeY,
				grScr, FALSE)) { DIE(); }
			break;
		}
		//仮想画面をクリアする。
		if(SetDrawScreen(grScr)) { DIE(); }							//描画対象を仮想画面にする。
		if(ClearDrawScreen()) { DIE(); }							//仮想画面をクリアする。
		//今回のフレームでplay_grp()が呼ばれなかったムービーグラフィックを、自動的に停止する。
		auto_stop_grp();
#else //DUALSCREEN	//--------------------------------------------------------------------------------------//
#ifdef  __CLIP_CBKQ_H__
		//コールバックキューを実行する。
		if(SetDrawScreen(grScr)) { DIE(); }							//描画対象を仮想画面にする。
		CbkQue_Invoke(pCbkQue);		//登録されているノードを全て呼び出す。アプリケーションによっては、他の処理を挟んでCbkQue_InvokePri()を複数回分けて呼び出すように変更して下さい。
		CbkQue_Clear(pCbkQue);		//コールバックキューを空の状態に戻す。アプリケーションによっては、一度登録したコールバックキューを何度も使い回す場合は、この行を削除して下さい。
#endif//__CLIP_CBKQ_H__
#ifdef  SHOW_FPS
		//描画処理の実効FPSを算出,及び,FPSの描画を行う。
		DrawFps();
#endif//SHOW_FPS
		//画面を更新する。
		if(!iFullScrMode) {	//ウインドウ表示
			if(SetDrawScreen(DX_SCREEN_FRONT)) { DIE(); }					//描画対象をフロントバッファにする。
			if(DrawExtendGraph(								//仮想画面の内容をフロントバッファに反映する。
				0,
				0,
				windowSizeX,
				windowSizeY,
				grScr, FALSE)) { DIE(); }

		} else {		//フルスクリーン表示
			if(SetDrawScreen(DX_SCREEN_BACK)) { DIE(); }					//描画対象をバックバッファにする。	シングルスクリーンアプリケーションの場合は直接フロントバッファへ転送するが、デュアルスクリーンアプリケーションの場合はバックバッファへ転送してフリップする事にした。理由は下記の'暫定対策'のコメントを参照せよ。
			switch(iFullScrMode) {
			default:DIE();
			case 1:	//メイン画面をメインモニタでフルスクリーン表示
				if(DrawExtendGraph(							//仮想画面の内容をバックバッファに反映する。
					fullscrPosX,
					fullscrPosY,
					fullscrPosX + fullscrSizeX,
					fullscrPosY + fullscrSizeY,
					grScr, FALSE)) { DIE(); }
				break;
			case 2:	//メイン画面をサブモニタでフルスクリーン表示
				if(DrawExtendGraph(							//仮想画面の内容をフロントバッファに反映する。
					subFullPosX,
					subFullPosY,
					subFullPosX + subFullSizeX,
					subFullPosY + subFullSizeY,
					grScr, FALSE)) { DIE(); }
				break;
			}
			if(ScreenFlip()) { DIE(); }							//バックバッファをフロントバッファに反映する。
		    //{{暫定対策
			{
				int Red, Green, Blue;							//┐
				if(GetBackgroundColor(&Red, &Green, &Blue)) { DIE(); }			//│
				if(SetBackgroundColor(0, 0, 0)) { DIE(); }				//├シングルスクリーンアプリケーションの場合はフルスクリーンに切り替える瞬間だけで良いのだが、デュアルスクリーンアプリケーションの場合はメイン画面とサブ画面の転送サイズが異なる場合にゴミが見えてしまうので、毎回クリアせざるを得ない。実際にはフロントバッファをクリア,即,転送でもチラツキは見えないようだが、念のためにバックバッファに転送してフリップする事にした。やや性能が落ちると思うがこちらの方が安全だろう。
				if(ClearDrawScreen()) { DIE(); }					//│
				if(SetBackgroundColor(Red, Green, Blue)) { DIE(); }			//┘
			}
		    //}}暫定対策
		}
		//仮想画面をクリアする。
		if(SetDrawScreen(grScr)) { DIE(); }							//描画対象を仮想画面にする。
		if(ClearDrawScreen()) { DIE(); }							//仮想画面をクリアする。
#ifdef  __CLIP_CBKQ_H__
		//デュアルスクリーン用のコールバックキューを実行する。
		if(SetDrawScreen(grSubScr)) { DIE(); }							//描画対象をサブ画面の仮想画面にする。
		CbkQue_Invoke(pSubCbkQue);	//登録されているノードを全て呼び出す。アプリケーションによっては、他の処理を挟んでCbkQue_InvokePri()を複数回分けて呼び出すように変更して下さい。
		CbkQue_Clear(pSubCbkQue);	//コールバックキューを空の状態に戻す。アプリケーションによっては、一度登録したコールバックキューを何度も使い回す場合は、この行を削除して下さい。
#endif//__CLIP_CBKQ_H__
		//デュアルスクリーンの画面を更新する。
		if(SetScreenFlipTargetWindow(hSubWnd)) { DIE(); }					//ScreenFlip()やフロントバッファへのDrawExtendGraph()等で画像を転送する先のウインドウをデュアルスクリーン用ウインドウに切り替える。
		if(!iFullScrMode) {	//ウインドウ表示
			if(SetDrawScreen(DX_SCREEN_FRONT)) { DIE(); }					//描画対象をフロントバッファにする。
			if(DrawExtendGraph(								//サブ画面の仮想画面の内容をフロントバッファに反映する。
				0,
				0,
				subWndSizeX,
				subWndSizeY,
				grSubScr, FALSE)) { DIE(); }
		} else {		//フルスクリーン表示
			//マルチモニタ環境ならば…
			if(rcSubMon.left || rcSubMon.top) {
				if(SetDrawScreen(DX_SCREEN_BACK)) { DIE(); }				//描画対象をバックバッファにする。	シングルスクリーンアプリケーションの場合は直接フロントバッファへ転送するが、デュアルスクリーンアプリケーションの場合はバックバッファへ転送してフリップする事にした。理由は下記の'暫定対策'のコメントを参照せよ。
				//通常のフルスクリーンモードならば…
				if(!bSubKeepWindowMode) {
					switch(iFullScrMode) {
					default:DIE();
					case 1:	//サブ画面をサブモニタでフルスクリーン表示
						if(DrawExtendGraph(					//サブ画面の仮想画面の内容をバックバッファに反映する。
							subFul2PosX,
							subFul2PosY,
							subFul2PosX + subFul2SizeX,
							subFul2PosY + subFul2SizeY,
							grSubScr, FALSE)) { DIE(); }
						break;
					case 2:	//サブ画面をメインモニタでフルスクリーン表示
						if(DrawExtendGraph(					//サブ画面の仮想画面の内容をバックバッファに反映する。
							ful2scrPosX,
							ful2scrPosY,
							ful2scrPosX + ful2scrSizeX,
							ful2scrPosY + ful2scrSizeY,
							grSubScr, FALSE)) { DIE(); }
						break;
					}
				//特殊なフルスクリーンモードならば…
				} else {
					if(DrawExtendGraph(						//サブ画面の仮想画面の内容をバックバッファに反映する。
						0,
						0,
						subWndSizeX,
						subWndSizeY,
						grSubScr, FALSE)) { DIE(); }
				}
				if(ScreenFlip()) { DIE(); }						//バックバッファをフロントバッファに反映する。
			    //{{暫定対策
				{
					int Red, Green, Blue;						//┐
					if(GetBackgroundColor(&Red, &Green, &Blue)) { DIE(); }		//│
					if(SetBackgroundColor(0, 0, 0)) { DIE(); }			//├シングルスクリーンアプリケーションの場合はフルスクリーンに切り替える瞬間だけで良いのだが、デュアルスクリーンアプリケーションの場合はメイン画面とサブ画面の転送サイズが異なる場合にゴミが見えてしまうので、毎回クリアせざるを得ない。実際にはフロントバッファをクリア,即,転送でもチラツキは見えないようだが、念のためにバックバッファに転送してフリップする事にした。やや性能が落ちると思うがこちらの方が安全だろう。
					if(ClearDrawScreen()) { DIE(); }				//│
					if(SetBackgroundColor(Red, Green, Blue)) { DIE(); }		//┘
				}
			    //}}暫定対策
			//シングルモニタ環境ならば…
			} else {
				/** no job **/
			}
		}
		//サブ画面の仮想画面をクリアする。
		if(SetDrawScreen(grSubScr)) { DIE(); }							//描画対象をサブ画面の仮想画面にする。
		if(ClearDrawScreen()) { DIE(); }							//サブ画面の仮想画面をクリアする。
		//デュアルスクリーンの画面を更新を終了する。
		if(SetScreenFlipTargetWindow(NULL)) { DIE(); }						//ScreenFlip()やフロントバッファへのDrawExtendGraph()等で画像を転送する先のウインドウをメインウインドウに戻す。
		if(SetDrawScreen(grScr)) { DIE(); }							//描画対象を仮想画面にする。	必須ではないが、アプリケーションがコールバックキューを介さずに直接描画した場合に、描画対象はメイン画面の仮想画面となっている方が都合が良いと思うので、描画対象をメイン画面の仮想画面に戻しておく事にした。
		//今回のフレームでplay_grp()が呼ばれなかったムービーグラフィックを、自動的に停止する。
		auto_stop_grp();
#endif//DUALSCREEN	//--------------------------------------------------------------------------------------//
	}
	{
		//キーの状態を更新する。
		memcpy(keyTrig, keyStat, 256);
		if(GetWindowActiveFlag()) {
			if(GetHitKeyStateAll(keyStat)) { DIE(); }		//ウインドウがアクティブならば、キーの状態を取得する。
		} else {
			memset(keyStat, 0, 256);				//ウインドウが非アクティブならば、キーが押されていないものと見なす。
		}
		for(int i = 0; i < 256; i++) {
			keyTrig[i] = (keyTrig[i] ^ keyStat[i]) & keyStat[i];	//トリガを検出する。
		}
		//[Esc]キーが押されたら終了する。
		if(keyTrig[KEY_INPUT_ESCAPE]) { longjmp(env_exit, 1); }
	}
	{
		int Button;
		//マウスカーソルの位置を取得する。
		// - マウスのクリック履歴が有れば、上書きされる。
		if(GetMousePoint(&mousePosX, &mousePosY)) { DIE(); }
		//マウスのボタンの状態を得る。
		mouseStat = GetMouseInput();
		//マウスのクリック履歴を取得する。
		// - ボタンのフラグはOrし、位置は最終にクリックした位置を格納する。
		mouseTrig = 0;
		while(!GetMouseInputLog(&Button, &mousePosX, &mousePosY, TRUE)) { mouseTrig |= Button; }
		//マウスボタンのオートリピート処理を行う。
		{
			static int cnt[8/*調整可*/];
			int i;
			for(i = 0; i <= ARRAY_SIZE(cnt); i++) {
				if(mouseTrig & (1<<i)) {
					cnt[i] = SEC(0.5)/*調整可*/;
				} else if(mouseStat & (1<<i)) {
					if(cnt[i] && !--cnt[i]) {
						mouseTrig |= (1<<i);
						cnt[i] = SEC(0.1)/*調整可*/;
					}
				}
			}
		}
		//マウスの座標を論理画面の座標に変換する。
		switch(iFullScrMode) {
		default:DIE();
		case 0:	//ウインドウ表示
			mousePosX = mousePosX * DISP_X / windowSizeX;
			mousePosY = mousePosY * DISP_Y / windowSizeY;
			break;
		case 1:	//メイン画面をメインモニタでフルスクリーン表示
			mousePosX = (mousePosX - fullscrPosX) * DISP_X / fullscrSizeX;
			mousePosY = (mousePosY - fullscrPosY) * DISP_Y / fullscrSizeY;
			break;
		case 2:	//メイン画面をサブモニタでフルスクリーン表示
			mousePosX = (mousePosX - subFullPosX) * DISP_X / subFullSizeX;
			mousePosY = (mousePosY - subFullPosY) * DISP_Y / subFullSizeY;
			break;
		}
	}
	{
		//[F12]でフルスクリーン時にマウスカーソルを表示するかを切り替えする。
		if(keyTrig[KEY_INPUT_F12]) {
			bFullScrMouseDisp = !bFullScrMouseDisp;
			if(iFullScrMode) {									//フルスクリーン表示中ならば…
				if(SetMouseDispFlag(bFullScrMouseDisp)) { DIE(); }				//マウスカーソルを表示するかを切り替える。
			}
		}
		//左Altキー,又は,右Altキーを押しながら、Returnキーが押されたら…
		if((keyStat[KEY_INPUT_LALT] || keyStat[KEY_INPUT_RALT]) && keyTrig[KEY_INPUT_RETURN]) {
#ifndef DUALSCREEN	//--------------------------------------------------------------------------------------//
			static int windowPosX, windowPosY;
			//ウインドウ表示⇔フルスクリーン表示を切り替える。
			//フルスクリーン表示になったら…
			if((iFullScrMode = !iFullScrMode)) {	//0=ウインドウ表示,1=メイン画面をメインモニタでフルスクリーン表示
				if(GetWindowPosition(&windowPosX, &windowPosY)) { DIE(); }			//現在のウインドウの位置を取得しておく。
				if(SetWindowStyleMode(4/*何も無し*/)) { DIE(); }				//ウインドウスタイルを'4=何も無し'に変更する。
				POINT pt = { windowPosX, windowPosY };						//現在のウインドウの位置が、サブモニタ内でなければ…	シングルモニタ環境でも同じ処理で安全です。シングルモニタ環境ならばrcSubMon={0,0,0,0}なので、この判定は常にTrueになるからです。
				if(!PtInRect(&rcSubMon, pt)) {
					if(SetWindowSize(desktopSizeX, desktopSizeY)) { DIE(); }		//ウインドウのサイズをメインモニタのデスクトップと同じにする。
					if(SetWindowPosition(0, 0)) { DIE(); }					//ウインドウの位置を画面左上に変更する。
				} else {									//現在のウインドウの位置が、サブモニタ内ならば…
					if(SetWindowSize(subDeskSizeX, subDeskSizeY)) { DIE(); }		//ウインドウのサイズをサブモニタのデスクトップと同じにする。
					if(SetWindowPosition(rcSubMon.left, rcSubMon.top)) { DIE(); }		//ウインドウの位置をサブモニタの原点に設定する。
					iFullScrMode++;		//2=メイン画面をサブモニタでフルスクリーン表示
				}
			    //{{暫定対策
				{
					int Red, Green, Blue, DrawScreen = GetDrawScreen();			//┐
					if(SetDrawScreen(DX_SCREEN_FRONT)) { DIE(); }				//│
					if(GetBackgroundColor(&Red, &Green, &Blue)) { DIE(); }			//│
					if(SetBackgroundColor(0, 0, 0)) { DIE(); }				//├フルスクリーン時に余白の生じる画面サイズの場合、ウインドウ時のフロントバッファに最後に表示した内容が、フルスクリーン時に左上にゴミとして見えてしまう問題が生じた。暫定対策として、フルスクリーンに切り替える瞬間にフロントバッファを消去する事にした。
					if(ClearDrawScreen()) { DIE(); }					//│
					if(SetBackgroundColor(Red, Green, Blue)) { DIE(); }			//│
					if(SetDrawScreen(DrawScreen)) { DIE(); }				//┘
				}
			    //}}暫定対策
				if(!bFullScrMouseDisp) { if(SetMouseDispFlag(FALSE)) { DIE(); } }		//マウスカーソルを消す。	SetWindowStyleMode()にはマウスカーソルの表示設定を初期化する副作用が有るので、SetWindowStyleMode()よりも後でSetMouseDispFlag()を呼び出す必要が有る。
			//ウインドウ表示になったら…
			} else {
				if(SetWindowStyleMode(5/*最小化無し*/)) { DIE(); }				//ウインドウスタイルを起動時と同じ設定に戻す。
				if(SetWindowSize(windowSizeX, windowSizeY)) { DIE(); }				//ウインドウのサイズを起動時と同じ設定に戻す。
				if(SetWindowPosition(windowPosX, windowPosY)) { DIE(); }			//ウインドウの位置をフルスクリーン表示に切り替える前の位置に戻す。
				if(!bFullScrMouseDisp) { if(SetMouseDispFlag(TRUE)) { DIE(); } }		//マウスカーソルを表示する。	SetWindowStyleMode()にはマウスカーソルの表示設定を初期化する副作用が有るので、SetWindowStyleMode()よりも後でSetMouseDispFlag()を呼び出す必要が有る。
			}
#else //DUALSCREEN	//--------------------------------------------------------------------------------------//
			static int windowPosX, windowPosY;
			static WINDOWPLACEMENT windowPlacement;
			//ウインドウ表示⇔フルスクリーン表示を切り替える。
			//フルスクリーン表示になったら…
			if((iFullScrMode = !iFullScrMode)) {	//0=ウインドウ表示,1=メイン画面をメインモニタでフルスクリーン表示
				bSubKeepWindowMode = bFullScrMouseDisp = !!keyStat[KEY_INPUT_RALT];		//左ALT+Returnならば通常のフルスクリーンモード、右ALT+Returnならば特殊なフルスクリーンモードとする。特殊なフルスクリーンモードならばマウスカーソルを消さない。
				if(GetWindowPosition(&windowPosX, &windowPosY)) { DIE(); }			//現在のウインドウの位置を取得しておく。
				if(SetWindowStyleMode(4/*何も無し*/)) { DIE(); }				//ウインドウスタイルを'4=何も無し'に変更する。
				POINT pt = { windowPosX, windowPosY };						//現在のウインドウの位置が、サブモニタ内でなければ…	シングルモニタ環境でも同じ処理で安全です。シングルモニタ環境ならばrcSubMon={0,0,0,0}なので、この判定は常にTrueになるからです。
				if(!PtInRect(&rcSubMon, pt)) {
					if(SetWindowSize(desktopSizeX, desktopSizeY)) { DIE(); }		//ウインドウのサイズをメインモニタのデスクトップと同じにする。
					if(SetWindowPosition(0, 0)) { DIE(); }					//ウインドウの位置を画面左上に変更する。
					//マルチモニタ環境ならば…
					if(rcSubMon.left || rcSubMon.top) {
						GetWindowPlacement(hSubWnd, &windowPlacement);			//ウインドウ表示の位置を記憶する。
						//通常のフルスクリーンモードならば…
						if(!bSubKeepWindowMode) {
							SetWindowLong(hSubWnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);	//┬ウインドウスタイルをフルスクリーン表示用に変更する。
							SetWindowLong(hSubWnd, GWL_STYLE, WS_POPUP);		//┘
							MoveWindow(hSubWnd, rcSubMon.left, rcSubMon.top, subDeskSizeX, subDeskSizeY, FALSE);
							ShowWindow(hSubWnd, SW_SHOW);	//□参照資料「ウインドウスタイルの動的変更」(http://katze.hatenablog.jp/entry/2013/10/05/150832)
						//特殊なフルスクリーンモードならば…
						} else {
							MoveWindow(hSubWnd,
								rcSubMon.left,
								rcSubMon.top,
								windowPlacement.rcNormalPosition.right - windowPlacement.rcNormalPosition.left,
								windowPlacement.rcNormalPosition.bottom - windowPlacement.rcNormalPosition.top,
								FALSE);
						}
					//シングルモニタ環境ならば…
					} else {
						ShowWindow(hSubWnd, SW_HIDE);					//デュアルスクリーン用ウインドウを表示しない。
					}
				} else {									//現在のウインドウの位置が、サブモニタ内ならば…
					if(SetWindowSize(subDeskSizeX, subDeskSizeY)) { DIE(); }		//ウインドウのサイズをサブモニタのデスクトップと同じにする。
					if(SetWindowPosition(rcSubMon.left, rcSubMon.top)) { DIE(); }		//ウインドウの位置をサブモニタの原点に設定する。
					iFullScrMode++;		//2=メイン画面をサブモニタでフルスクリーン表示
					//マルチモニタ環境ならば…
					if(rcSubMon.left || rcSubMon.top) {
						GetWindowPlacement(hSubWnd, &windowPlacement);			//ウインドウ表示の位置を記憶する。
						//通常のフルスクリーンモードならば…
						if(!bSubKeepWindowMode) {
							SetWindowLong(hSubWnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);	//┬ウインドウスタイルをフルスクリーン表示用に変更する。
							SetWindowLong(hSubWnd, GWL_STYLE, WS_POPUP);		//┘
							MoveWindow(hSubWnd, 0, 0, desktopSizeX, desktopSizeY, FALSE);
							ShowWindow(hSubWnd, SW_SHOW);	//□参照資料「ウインドウスタイルの動的変更」(http://katze.hatenablog.jp/entry/2013/10/05/150832)
						//特殊なフルスクリーンモードならば…
						} else {
							MoveWindow(hSubWnd,
								0,
								0,
								windowPlacement.rcNormalPosition.right - windowPlacement.rcNormalPosition.left,
								windowPlacement.rcNormalPosition.bottom - windowPlacement.rcNormalPosition.top,
								FALSE);
						}
					//シングルモニタ環境ならば…
					} else {
						ShowWindow(hSubWnd, SW_HIDE);					//デュアルスクリーン用ウインドウを表示しない。
					}
				}
				if(!bFullScrMouseDisp) { if(SetMouseDispFlag(FALSE)) { DIE(); } }		//マウスカーソルを消す。	SetWindowStyleMode()にはマウスカーソルの表示設定を初期化する副作用が有るので、SetWindowStyleMode()よりも後でSetMouseDispFlag()を呼び出す必要が有る。
			//ウインドウ表示になったら…
			} else {
				bSubKeepWindowMode = bFullScrMouseDisp = 0;					//ウインドウモードではbSubKeepWindowMode,bFullScrMouseDispは参照しないが、デバッグし易さのために0にしておく事にした。
				if(SetWindowStyleMode(5/*最小化無し*/)) { DIE(); }				//ウインドウスタイルを起動時と同じ設定に戻す。
				if(SetWindowSize(windowSizeX, windowSizeY)) { DIE(); }				//ウインドウのサイズを起動時と同じ設定に戻す。
				if(SetWindowPosition(windowPosX, windowPosY)) { DIE(); }			//ウインドウの位置をフルスクリーン表示に切り替える前の位置に戻す。
				//マルチモニタ環境ならば…
				if(rcSubMon.left || rcSubMon.top) {
					SetWindowLong(hSubWnd, GWL_EXSTYLE, SUBWND_STYLE_EX);			//┬ウインドウスタイルを起動時と同じ設定に戻す。
					SetWindowLong(hSubWnd, GWL_STYLE, SUBWND_STYLE);			//┘
					SetWindowPlacement(hSubWnd, &windowPlacement);				//ウインドウ表示の位置を復元する。
					ShowWindow(hSubWnd, SW_SHOW);	//□参照資料「ウインドウスタイルの動的変更」(http://katze.hatenablog.jp/entry/2013/10/05/150832)
				//シングルモニタ環境ならば…
				} else {
					ShowWindow(hSubWnd, SW_SHOW);						//デュアルスクリーン用ウインドウを表示する。
				}
				if(!bFullScrMouseDisp) { if(SetMouseDispFlag(TRUE)) { DIE(); } }		//マウスカーソルを表示する。	SetWindowStyleMode()にはマウスカーソルの表示設定を初期化する副作用が有るので、SetWindowStyleMode()よりも後でSetMouseDispFlag()を呼び出す必要が有る。
			}
#endif//DUALSCREEN	//--------------------------------------------------------------------------------------//
		}
	}
	//グローバルカウンタを進める。
	now++;
#if     (defined(_DEBUG) && defined(__CLIP_PRP_H__) && defined(USE_PDCURSES))
	//フルスクリーン表示でなければ、特定のキーが押されたらプロパティエディタを実行する。
	// - プロパティテーブルを複数作成した場合は、押されたキーによってどのプロパティテーブルのプロパティエディタを実行するかを変更しろ。
	if(!iFullScrMode && CheckHitKey(KEY_INPUT_TAB/*[Tab]*/)) {
		//プロパティエディタを開始するために押されたキーが離されるまで待つ。
		for(;;) {
			if(ProcessMessage() || GetWindowUserCloseFlag()) { longjmp(env_exit, 1); }	//何らかの要因でウインドウが削除されたか,又は,[×]ボタンが押されたら終了する。
			if(!CheckHitKey(KEY_INPUT_TAB/*[Tab]*/)) { break; }
		}
		//コマンドプロンプトをアクティブにする。
		char sConsoleTitle[MAX_PATH];
		if(GetConsoleTitle(sConsoleTitle, sizeof sConsoleTitle)) {
			HWND hConsoleWindow = FindWindow(NULL, sConsoleTitle);
			if(hConsoleWindow) { SetForegroundWindow(hConsoleWindow); }
		}
		//プロパティエディタを実行する。
		PrpEdt_run(phApp->pPrpKey, phApp->iTbl, phApp + 1, 0, fnVarFmt, stdscr, PRPEDT_PATH_W, PRPEDT_VAL_W, '\t'/*[Tab]*/);
		//メインウインドウをアクティブにする。
		SetForegroundWindow(GetMainWindowHandle());
		//プロパティエディタを終了するために押されたキーが離されるまで待つ。
		for(;;) {
			if(ProcessMessage() || GetWindowUserCloseFlag()) { longjmp(env_exit, 1); }	//何らかの要因でウインドウが削除されたか,又は,[×]ボタンが押されたら終了する。
			if(!CheckHitKey(KEY_INPUT_TAB/*[Tab]*/)) { break; }
		}
	}
#endif//(defined(_DEBUG) && defined(__CLIP_PRP_H__) && defined(USE_PDCURSES))
//{{アプリケーション特有の周期処理
	{
		RND32(seed);		//┐
		mrand48();		//├使用しない乱数の処理は削除しても構いません。
		WELL_next(&well);	//┘
		if(ResetTransformTo2D()) { DIE(); }
		if(SetDrawAreaFull()) { DIE(); }
	    //{{この範囲の処理順序はアプリケーション毎に調整して下さい。
		//コルーチンを実行する。
		ActObj_CallCoroutineToTree(aoApp);
		//演出シーケンサを実行する。
		ActObj_ExecDirSeqToTree(aoApp);
	    #ifdef  FsmTrans_Exec
		//周期処理を実行する。
		ActObj_ApplyTransToTree(aoApp,
			FsmTrans_Exec|Fsm_Trans_noreq,
			NULL);
	    #endif//FsmTrans_Exec
	    #ifdef  FsmTrans_Draw
		//描画処理を実行する。
		ActObj_ApplyTransToTree(aoApp,
			FsmTrans_Draw|Fsm_Trans_noreq,
			NULL);
	    #endif//FsmTrans_Draw
	    #ifdef  FsmTrans_Free
		//Term状態で待機しているオブジェクトを自分で開放させる。
		ActObj_ApplyTransToTree(aoApp,
			FsmTrans_Free|Fsm_Trans_noreq,
			NULL);
	    #endif//FsmTrans_Free
	    //}}この範囲の処理順序はアプリケーション毎に調整して下さい。
	}
//}}アプリケーション特有の周期処理
}
/*--------------------------------------------------------------------------*/
void delay(double sec) {
	if(sec <= 0.0) { return; }		//secに0以下の秒数が指定されたら、何もせずに帰る。
	int i = SEC(sec);
	do { schedule(); } while(--i > 0);	//secに0超過1f未満の秒数が指定されても、1fは待つ。
}
/****************************************************************************
 *	UIジョブ
 ****************************************************************************/
int cpp_main(int argc, char* argv[]) {
	if(RRS_i_job(pRRS) != (RRS_n_job(pRRS) - 1)) { DIE(); }	//最後のジョブがUIジョブである事を確認する。
	if(!setjmp(env_exit)) {
		for(;;) {
			schedule();
		}
	}
	return EXIT_SUCCESS;
}
/****************************************************************************
 *	TAPシーケンサ
 ****************************************************************************/
#ifdef  __CLIP_TAPS_H__
void onTapEvt(ST_TapEvt* pTapEvt) {
//{{アプリケーション特有の処理
	//※TODO:
	switch(pTapEvt->iEvt) {
	default:DIE();
	case TapEvt_Play:
	case TapEvt_Loop:
	case TapEvt_Next:
		syslog(LOG_DEBUG, "onTapEvt: iEvt=%d iLogCh=%d iPhr=%d", pTapEvt->iEvt, pTapEvt->iLogCh, pTapEvt->iPhr);
		break;
	case TapEvt_Stop:
	case TapEvt_End:
		syslog(LOG_DEBUG, "onTapEvt: iEvt=%d iLogCh=%d iPhr=%d", pTapEvt->iEvt, pTapEvt->iLogCh, pTapEvt->iPhr);
		break;
	//case TapEvt_Ctrl:
	}
//}}アプリケーション特有の処理
}
#endif//__CLIP_TAPS_H__
/****************************************************************************
 *	演出シーケンサ
 ****************************************************************************/
#ifdef  __CLIP_DIRS_H__
void fnAct(struct _ST_DirSeq* pDirSeq, int iCh, int ActNo, int bOverFlow) {
//{{アプリケーション特有の処理
	//※下記は実装の一例です。アプリケーションによって全く異なる処理に変更して構いません。
	static unsigned short arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9;
	int ActHi = (ActNo >> 16);								//ActNo[23:16]
	int ActLo = (unsigned short)ActNo;							//ActNo[15: 0]
	switch(ActHi) {
	//変数
	case ActHi_set_arg1: arg1 = ActLo; return; //ここまで
	case ActHi_set_arg2: arg2 = ActLo; return; //ここまで
	case ActHi_set_arg3: arg3 = ActLo; return; //ここまで
	case ActHi_set_arg4: arg4 = ActLo; return; //ここまで
	case ActHi_set_arg5: arg5 = ActLo; return; //ここまで
	case ActHi_set_arg6: arg6 = ActLo; return; //ここまで
	case ActHi_set_arg7: arg7 = ActLo; return; //ここまで
	case ActHi_set_arg8: arg8 = ActLo; return; //ここまで
	case ActHi_set_arg9: arg9 = ActLo; return; //ここまで
	//スプライト準備
	case ActHi_prep_spr:
		if((ActLo < 1) || (ActLo > SprNo_Max)) { DIE(); }				//スプライト番号が範囲内である事を確認する。
		prep_spr(ActLo);								//スプライトを準備する。
		return;	//ここまで
	//フレーズ準備
	case ActHi_prep_phr:
		if((ActLo < 1) || (ActLo > PhrNo_Max)) { DIE(); }				//フレーズ番号が範囲内である事を確認する。
		prep_phr(ActLo);								//フレーズを準備する。
		return;	//ここまで
	//ここに追加出来ます。
	}
	//液晶シーケンサ
	if((ActHi >= ActHi_LcdSeqCh_Play) && (ActHi <= ActHi_LcdSeqCh_Play_Max)) {
		if((unsigned)ActLo > SprNo_Max) { DIE(); }					//スプライト番号が範囲内,又は,0である事を確認する。
		int iLcdSeqCh = ActHi - ActHi_LcdSeqCh_Play;					//液晶シーケンサチャネル番号を求める。
		if((unsigned)iLcdSeqCh > LcdSeqCh_Max) { DIE(); }				//液晶シーケンサチャネル番号が範囲内である事を確認する。
		LcdSeqCh_Play(pLcdSeq, iLcdSeqCh, ActLo/*0可*/);				//スプライトの再生を開始,又は,停止する。
		return;	//ここまで
	}
	//LEDシーケンサ(LEDシーケンス再生)
	if((ActHi >= ActHi_LedSeqCh_Play) && (ActHi <= ActHi_LedSeqCh_Play_Max)) {
		if((unsigned)ActLo > LedSeqNo_Max) { DIE(); }					//LEDシーケンス番号が範囲内,又は,0である事を確認する。
		int iLedSeqCh = ActHi - ActHi_LedSeqCh_Play;					//LEDシーケンサチャネル番号を求める。
		if((unsigned)iLedSeqCh > LedSeqCh_Max) { DIE(); }				//LEDシーケンサチャネル番号が範囲内である事を確認する。
		if(ActLo) {
			LedSeqCh_PlayNo(pLedSeq, iLedSeqCh, TBL_LedSeqNo, ActLo);		//LEDシーケンスの再生を開始する。
		} else {
			LedSeqCh_Stop(pLedSeq, iLedSeqCh);					//LEDシーケンスの再生を停止する。
		}
		return;	//ここまで
	}
	//TAPシーケンサ(フレーズ再生)
	if((ActHi >= ActHi_TapLogCh_Play) && (ActHi <= ActHi_TapLogCh_Play_Max)) {
		if((unsigned)ActLo > PhrNo_Max) { DIE(); }					//フレーズ番号が範囲内,又は,0である事を確認する。
		int iTapLogCh = ActHi - ActHi_TapLogCh_Play;					//TAP論理チャネル番号を求める。
		if((unsigned)iTapLogCh > TapLogCh_Max) { DIE(); }				//TAP論理チャネル番号が範囲内である事を確認する。
		if(ActLo) {
			TapLogCh_Play(pTapSeq, iTapLogCh, ActLo, 1, 0, 0);			//フレーズの再生を開始する。
		} else {
			TapLogCh_Stop(pTapSeq, iTapLogCh);					//フレーズの再生を停止する。
		}
		return;	//ここまで
	}
	//TAPシーケンサ(TAPシーケンス再生)
	if((ActHi >= ActHi_TapSeqCh_Play) && (ActHi <= ActHi_TapSeqCh_Play_Max)) {
		if((unsigned)ActLo > PhrNo_Max) { DIE(); }					//TAPシーケンス番号が範囲内,又は,0である事を確認する。
		int iTapSeqCh = ActHi - ActHi_TapSeqCh_Play;					//TAPシーケンサチャネル番号を求める。
		if((unsigned)iTapSeqCh > TapSeqCh_Max) { DIE(); }				//TAPシーケンサチャネル番号が範囲内である事を確認する。
		if(ActLo) {
			TapSeqCh_PlayNo(pTapSeq, iTapSeqCh, TBL_TapSeqNo, ActLo);		//TAPシーケンスの再生を開始する。
		} else {
			TapSeqCh_Stop(pTapSeq, iTapSeqCh);					//TAPシーケンスの再生を停止する。
		}
		return;	//ここまで
	}
	//TAPミキサー
	if((ActHi >= ActHi_TapMxrCh_SetAtt) && (ActHi <= ActHi_TapMxrCh_SetAtt_Max)) {
		if((unsigned)ActLo > UINT8_MAX) { DIE(); }					//目標減衰量が範囲内である事を確認する。
		int iTapMxrCh = ActHi - ActHi_TapMxrCh_SetAtt;					//TAPミキサーチャネル番号を求める。
		if((unsigned)iTapMxrCh > TapMxrCh_Max) { DIE(); }				//TAPミキサーチャネル番号が範囲内である事を確認する。
		TapMxrCh_SetAtt(pTapMxr, iTapMxrCh, ActLo, arg1/*iRate*/, arg2/*iScale*/);	//TAPミキサーチャネルの減衰量変化を開始する。
		return;	//ここまで
	}
	//ここに追加出来ます。
	//演出番号が0〜65535ならば、dDirSeqC.exeが演出名に対して自動的に割り当てた演出番号と見なして、この後で個別処理を行う。
	const char* actStr = REG_get_string_l(TBL_RegTbl, RegKey_DirAct, ActNo, -1);
	if(actStr) {
		//演出文字列の処理
		//ここに追加出来ます。
		syslog(LOG_DEBUG, "fnAct: iCh=%d ActNo=%d bOverFlow=%d actStr='%s'", iCh, ActNo, bOverFlow, actStr);
		return;	//ここまで
	} else {
		//演出名の処理
		//ここに追加出来ます。
		syslog(LOG_DEBUG, "fnAct: iCh=%d ActNo=%d bOverFlow=%d", iCh, ActNo, bOverFlow);
		return;	//ここまで
	}
//}}アプリケーション特有の処理
}
#endif//__CLIP_DIRS_H__
/****************************************************************************
 *	イベントタイマ
 ****************************************************************************/
#ifdef  __CLIP_EVTM_H__
void onEvent(int iEvtTmrCh, int iEvent) {
	syslog(LOG_DEBUG, "onEvent: iEvtTmrCh=%d iEvent=%d", iEvtTmrCh, iEvent);
}
#endif//__CLIP_EVTM_H__
#endif//USE_DXLIB
