/*
 *	app.c
 *
 *	クラックスもどき
 *
 *	* Sun Jul 29 23:59:59 JST 2018 Naoyuki Sawa
 *	- 1st リリース。
 */
#include "app.h"

/****************************************************************************
 *	
 ****************************************************************************/

//{{2017/08/26削除:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
//#ifdef USE_SOUND
//const void* sound_table[SOUND_COUNT];
//#endif /*USE_SOUND*/
//}}2017/08/26追加:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。

//{{2017/08/26削除:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
//#ifdef USE_MUSIC
///*const*/ void* music_table[MUSIC_COUNT];
//#endif /*USE_MUSIC*/
//}}2017/08/26追加:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。

//{{2017/08/26削除:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
//#ifdef USE_TEXTURE
//TEXTURE texture_table[TEXTURE_COUNT];
//#endif /*USE_TEXTURE*/
//}}2017/08/26追加:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。

//{{2017/08/26削除:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
//#ifdef USE_SPRITE
//#define SPRITE_ SPRITE_INIT2
//const SPRITE sprite_table[SPRITE_COUNT] = {
//#include "sprite.h"
//};
//#undef SPRITE_
//#endif /*USE_SPRITE*/
//}}2017/08/26追加:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。

/****************************************************************************
 *	main()を呼び出す前に初期化関数を実行する仕組み
 *	main()が終了した後に終了時関数を実行する仕組み
 ****************************************************************************/
//初期化関数,終了時関数を登録する場合は、このブロックを有効にして下さい。
// - 詳細は、/clip/clippce.cの「main()を呼び出す前に初期化関数を実行する仕組み」「main()が終了した後に終了時関数を実行する仕組み」を参照して下さい。
#if 0
static void InitFunc() { //初期化関数
	//※TODO:
}
static void* const TBL_InitTbl[]={(void*)FOURCC_pCRT,(void*)FOURCC_dXIU,InitFunc,NULL};
static void ExitFunc() { //終了時関数
	//※TODO:
}
static void* const TBL_ExitTbl[]={(void*)FOURCC_pCRT,(void*)FOURCC_dXTU,ExitFunc,NULL};
#endif

/****************************************************************************
 *	不要な描画関数を置き換えてメモリを節約する
 ****************************************************************************/
//3D描画関数を使用する場合に、不要な描画関数を置き換えてメモリを節約する場合は、以下のブロックを有効にした上で、実際に使用する描画関数の行だけをコメントアウトして下さい。
// - 以下の例は、Ｚ比較なし・2bitmaskテクスチャのスキャンライン描画関数だけを実際に使用すると想定して、それ以外の描画関数をダミー関数に置き換えてメモリ節約した例です。
//   sprite_draw2()の拡縮回転のためだけに3D描画関数を使用して、本当の3D描画を行わない場合は、以下の例がそのまま使用出来ます。(スプライト画像は全て2bitmask形式だと仮定)
// - それ以外の場合は、アプリケーションが実際に使用する描画関数によって、適切な描画関数の行をコメントアウトして使用して下さい。
//   尚、この対策は必須ではなく、メモリを節約する必要が無ければ、以下のブロックを無効にしたままで(又は削除して)問題ありません。
// - 実際のアプリケーションで使用した例としては、2009年5月9日に公開した「輪郭描画デモ」(http://piece-me.org/archive/edge-20090509-src.zip)の/edge/main.cを参照して下さい。
// * Sun May 13 23:59:59 JST 2018 Naoyuki Sawa
// - USE_SPRITE2の定義を追加しました。
//   3D描画関数を使用する{USE_3D,USE_RENDF,USE_MESH,USE_SPRITE2}が定義されている場合は、以下のブロックを自動的に有効にする事にしました。
//   どの関数を使用しているかの選択は、これまで通り手作業で行って下さい。
#ifdef  USE_SPRITE2
	void draw_scanline_wz_color(    const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds11.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・テクスチャなし）
	void draw_scanline_wz_1bit(     const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds12.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・1bitテクスチャ）
	void draw_scanline_wz_1bitmask( const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds13.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・1bitmaskテクスチャ）
	void draw_scanline_wz_2bit(     const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds14.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・2bitテクスチャ）
	void draw_scanline_wz_2bitmask( const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds15.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・2bitmaskテクスチャ）
	void draw_scanline_woz_color(   const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds21.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・テクスチャなし）
	void draw_scanline_woz_1bit(    const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds22.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・1bitテクスチャ）
	void draw_scanline_woz_1bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds23.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・1bitmaskテクスチャ）
	void draw_scanline_woz_2bit(    const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds24.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・2bitテクスチャ）
//使用	void draw_scanline_woz_2bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds25.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・2bitmaskテクスチャ）
#elif   (defined(USE_3D)||defined(USE_RENDF)||defined(USE_MESH))
	void draw_scanline_wz_color(    const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds11.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・テクスチャなし）
	void draw_scanline_wz_1bit(     const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds12.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・1bitテクスチャ）
	void draw_scanline_wz_1bitmask( const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds13.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・1bitmaskテクスチャ）
//使用	void draw_scanline_wz_2bit(     const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds14.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・2bitテクスチャ）
	void draw_scanline_wz_2bitmask( const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds15.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較あり・2bitmaskテクスチャ）
	void draw_scanline_woz_color(   const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds21.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・テクスチャなし）
	void draw_scanline_woz_1bit(    const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds22.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・1bitテクスチャ）
	void draw_scanline_woz_1bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds23.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・1bitmaskテクスチャ）
	void draw_scanline_woz_2bit(    const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds24.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・2bitテクスチャ）
	void draw_scanline_woz_2bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param) { DIE(); } //framds25.c 高速RAM転送候補：スキャンライン描画関数（Ｚ比較なし・2bitmaskテクスチャ）
#endif

/****************************************************************************
 *	main
 ****************************************************************************/

int main() {
#ifdef  USE_ARGS
	static char cmdline[128] = PRESCAN_STRINGIFY(PROJECT);	//「r.exe」にコマンドライン引数を指定した場合、ここが書き換えられます。
	char** const argv = strsplit(cmdline, " ", 0);
	int    const argc = strv_length(argv);
#else //USE_ARGS
	char** const argv = (char*[]){ PRESCAN_STRINGIFY(PROJECT), NULL };
	int    const argc = 1;
#endif//USE_ARGS
	/* 呼び出し元プログラムの起動に使用された名前を設定します。 */
	program_invocation_short_name = basename((program_invocation_name = argv[0]));
	/* 捕捉されなかった例外を捕えるための、例外フレームを初期化します。 */
	SEH_init();
	/* アプリケーションを初期化します。 */
	app_init(argc, argv);
	/* メインループを実行します。 */
	return app_main(argc, argv);
}

/****************************************************************************
 *	app_init
 ****************************************************************************/

#ifdef  USE_SOUND_MANAGER
static void sound_play_stub(int iCh, int iData, int iLoop) {
	if((unsigned)iData > PhrNo_Max) { DIE(); }
	sound_play(iCh, sound_table[iData], iLoop);
}
#endif/*USE_SOUND_MANAGER*/

#ifdef  USE_SOUND_MIXER
//【注意】
//│配列TBL_TapMxrChMask[]は必ずint配列として定義して下さい。
//│ミキサーチャネルが少なくてビット数が足りたとしても、配列TBL_TapMxrChMask[]をuint8_t配列やuint16_t配列として定義してはいけません。
//│この下のset_att()にて配列TBL_TapMxrChMask[]の要素へのポインタをTapMxr_GetAtt()の引数aMxrChMaskとして引き渡しており、TapMxr_GetAtt()は引数aMxrChMaskがint境界に整列している事を前提としてアクセスしているからです。
//│もし配列TBL_TapMxrChMask[]をuint8_t配列やuint16_t配列として定義してしまうと、この下のset_att()から呼び出したTapMxr_GetAtt()の中でアドレスエラーが発生します。
static const int TBL_TapMxrChMask[(TapLogCh_Max+1)]={
BIN8(00000111),	//論理ﾁｬﾈﾙ0に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	ｽﾃｰｼﾞBGM
BIN8(00000110),	//論理ﾁｬﾈﾙ1に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出BGM
BIN8(00000110),	//論理ﾁｬﾈﾙ2に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出SE
BIN8(00000110),	//論理ﾁｬﾈﾙ3に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出SE
BIN8(00000110),	//論理ﾁｬﾈﾙ4に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出SE
BIN8(00000110),	//論理ﾁｬﾈﾙ5に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	UI
BIN8(00000110),	//論理ﾁｬﾈﾙ6に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	UI
BIN8(00000100)};//論理ﾁｬﾈﾙ7に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	ｴﾗｰ音
//        ||+--- TAPﾐｷｻｰﾁｬﾈﾙ0:演出BGM再生中	減音対象論理ﾁｬﾈﾙ:ｽﾃｰｼﾞBGM
//        |+---- TAPﾐｷｻｰﾁｬﾈﾙ1:ｴﾗｰ音再生中	減音対象論理ﾁｬﾈﾙ:ｴﾗｰ音以外
//        +----- TAPﾐｷｻｰﾁｬﾈﾙ2:ﾄｰﾀﾙﾚﾍﾞﾙ		減音対象論理ﾁｬﾈﾙ:全て
static void set_att(int iLogCh, ST_TapLogCh* pLogCh) {	//この論理ﾁｬﾈﾙの減衰量と､この論理ﾁｬﾈﾙに適用するﾐｷｻｰﾁｬﾈﾙの合計減衰量を､この論理ﾁｬﾈﾙが制御しているﾃﾞﾊﾞｲｽﾁｬﾈﾙに適用する｡	(pLogCh->iDevCh==UINT8_MAX)の時に呼び出してはいけない｡
	int iAtt=pLogCh->iAtt;					//この論理ﾁｬﾈﾙの減衰量				//2次ﾎﾞﾘｭｰﾑ相当
	iAtt+=TapMxr_GetAtt(pTapMxr,&TBL_TapMxrChMask[iLogCh]);	//この論理ﾁｬﾈﾙに適用するﾐｷｻｰﾁｬﾈﾙの合計減衰量	//1次ﾎﾞﾘｭｰﾑ相当
	sound_att(pLogCh->iDevCh,iAtt);				//この論理ﾁｬﾈﾙが制御しているﾃﾞﾊﾞｲｽﾁｬﾈﾙに､上記2点の合計減衰量を適用する｡
}
static void TapMxr_TimerProc(void* iTime) {	//TAPﾐｷｻｰ用ﾀｲﾏ割込処理
	int iDevCh,iLogCh;
	if(TapSeq_GetLogCh(pTapSeq,TapLogCh_Bg2)->iPhr!=UINT16_MAX){TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Stg,64, 0,  0);}	//論理ﾁｬﾈﾙ1で演出BGMが再生中ならば､ｽﾃｰｼﾞBGMを即消音する｡		┐
	else                                                       {TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Stg, 0,64,500);}	//論理ﾁｬﾈﾙ1で演出BGMが停止中ならば､ｽﾃｰｼﾞBGMを0.5秒で復帰する｡		├{{TODO:ｱﾌﾟﾘｹｰｼｮﾝ調整}}
	if(TapSeq_GetLogCh(pTapSeq,TapLogCh_Err)->iPhr!=UINT16_MAX){TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Err,64, 0,  0);}	//論理ﾁｬﾈﾙ7でｴﾗｰ音が再生中ならば､ｽﾃｰｼﾞBGM,演出BGM,SEを即消音する｡	│
	else                                                       {TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Err, 0, 0,  0);}	//論理ﾁｬﾈﾙ7でｴﾗｰ音が停止中ならば､ｽﾃｰｼﾞBGM,演出BGM,SEを即復帰する｡	┘
	TapMxr_Exec(pTapMxr,(int)iTime);	//TAPﾐｷｻｰを実行する｡
	for(iDevCh=0;iDevCh<pTapSeq->pInfo->nDevCh;iDevCh++){	//ﾃﾞﾊﾞｲｽﾁｬﾈﾙの減衰量を設定する｡
		iLogCh=TapSeq_GetDevCh(pTapSeq,iDevCh)->iLogCh;
		if(iLogCh!=UINT8_MAX){		//このﾃﾞﾊﾞｲｽﾁｬﾈﾙを制御している論理ﾁｬﾈﾙが有れば…
			ST_TapLogCh* pLogCh=TapSeq_GetLogCh(pTapSeq,iLogCh);
			set_att(iLogCh,pLogCh);	//この論理ﾁｬﾈﾙの減衰量と､この論理ﾁｬﾈﾙに適用するﾐｷｻｰﾁｬﾈﾙの合計減衰量を､ﾃﾞﾊﾞｲｽﾁｬﾈﾙに適用する｡
		}
	}
}
#endif/*USE_SOUND_MIXER*/

#ifdef  USE_SOUND_SEQUENCER
static void TapSeq_fnPlay(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	set_att(iLogCh,pLogCh);
	sound_play(pLogCh->iDevCh,sound_table[pLogCh->iPhr],pLogCh->iLoop?pLogCh->iLoop:-1);
}
static void TapSeq_fnStop(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	sound_stop(pLogCh->iDevCh);
}
static void TapSeq_fnLoop(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	/** no job **/
}
static void TapSeq_fnEnd(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	/** no job **/
}
static void TapSeq_fnNext(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	set_att(iLogCh,pLogCh);
	sound_play(pLogCh->iDevCh,sound_table[pLogCh->iPhr],pLogCh->iLoop?pLogCh->iLoop:-1);
}
static void TapSeq_fnCtrl(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	set_att(iLogCh,pLogCh);
}
static int TapSeq_fnGetPhrTime(ST_TapSeq* pTapSeq, int iPhr) {
	return ppd_playback_time(sound_table[iPhr]);
}
static int TapSeq_fnGetPhrNext(ST_TapSeq* pTapSeq, int iPhr) {
//{{2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
//#ifdef  USE_REG
//    #ifdef  RegKey_Next
//	//フレーズシーケンスをレジストリから取得する場合。
//	iPhr++;			//sound.hは0ベース,フレーズシーケンスは1ベースなので、一時的に1ベースに変換する。詳細は、/clip/tool/dPhrDefC/winapp.c を参照せよ。
//	iPhr = REG_get_value_l(TBL_RegTbl,RegKey_PhrDef,iPhr,RegKey_Next,-1)<<8>>8;	//通常フレーズ(-1),中間フレーズ(<>iPhr),ループフレーズ(=iPhr),完全フレーズ(-2)
//	if(iPhr>=0){iPhr--;}	//通常フレーズ(-1),又は,完全フレーズ(-2)以外ならば、sound.hの値(=0ベース)に戻す。
//	return iPhr;
//    #else //RegKey_Next
//	//フレーズシーケンスをレジストリから取得するが、全て通常フレーズである場合は'RegKey_Next'が定義されない。
//	return -1;
//    #endif//RegKey_Next
//#else /*USE_REG*/
//    #if     (defined(SND_BGM_1G)&&defined(SND_BGM_ST))
//	//フレーズシーケンスをプログラムで処理する場合。
//	return (iPhr==SND_BGM_1G)||(iPhr==SND_BGM_ST)?iPhr:-1;
//    #else //(defined(SND_BGM_1G)&&defined(SND_BGM_ST))
//	//フレーズシーケンスをプログラムで処理するが、全て通常フレーズである場合は常に-1を返す。
//	return -1;
//    #endif//(defined(SND_BGM_1G)&&defined(SND_BGM_ST))
//#endif/*USE_REG*/
//↓2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
    #ifdef  RegKey_Next
	return REG_get_value_l(TBL_RegTbl,RegKey_PhrDef,iPhr,RegKey_Next,-1)<<8>>8;	//通常フレーズ(-1),中間フレーズ(<>iPhr),ループフレーズ(=iPhr),完全フレーズ(-2)
    #else //RegKey_Next
	return -1;	//フレーズシーケンスをレジストリから取得するが、全て通常フレーズである場合は'RegKey_Next'が定義されない。
    #endif//RegKey_Next
//}}2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
}
static void TapSeq_TimerProc(void* iTime) {
	TapSeq_Exec(pTapSeq,(int)iTime);
}
#endif/*USE_SOUND_SEQUENCER*/

#ifdef  USE_EVENT_TIMER
static void EvtTmr_onEvent(int iEvtTmrCh, int iEvent) { //ｲﾍﾞﾝﾄﾀｲﾏ用ｲﾍﾞﾝﾄ処理関数
	TRACE("%d:%d:%d\n", now/FPS, iEvtTmrCh, iEvent);
}
#endif/*USE_EVENT_TIMER*/

#ifdef  USE_LOG_BUFFER
static int LogBuf_fnDraw(int x, int y, const char* Str) { //ｱﾌﾟﾘｹｰｼｮﾝ定義の文字列描画関数
	render_reduced_string(&render, x, y, Str, 3);
	return 10;
}
#endif/*USE_LOG_BUFFER*/

#ifdef  USE_NVLOG
void nvlog_(const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	nvlog_vprintf(nvlog, fmt, ap);
	va_end(ap);
	pceFileWriteSct(&faNvLog, nvlog, 0, NVLOG_SIZE);
}
#endif//USE_NVLOG

#ifdef  USE_TCL
//srand seed
static int Tcl_SrandCmd(Tcl_Interp* iPtr) {
	if((iPtr->argc < 1) || (iPtr->argc > 2)) { DIE(); }
	srand((iPtr->argc == 2) ? atoi(iPtr->argv[1]) : time(NULL));
	return TCL_OK;
}
//rand
static int Tcl_RandCmd(Tcl_Interp* iPtr) {
	if(iPtr->argc != 1) { DIE(); }
	iPtr->result = strdup_printf("%d", rand());
	return TCL_OK;
}
//log string
static int Tcl_LogCmd(Tcl_Interp* iPtr) {
	if(iPtr->argc != 2) { DIE(); }
#ifdef  USE_LOG_BUFFER
	LogBuf_Print(pLogBuf, iPtr->argv[1]);
	update();
#else //USE_LOG_BUFFER
	TRACE("%s\n", iPtr->argv[1]);
#endif//USE_LOG_BUFFER
	return TCL_OK;
}
//schedule
static int Tcl_ScheduleCmd(Tcl_Interp* iPtr) {
	if(iPtr->argc != 1) { DIE(); }
	schedule();
	return TCL_OK;
}
#endif//USE_TCL

//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
#ifdef  USE_LED
static void LedSeq_TimeProc(ST_LedSeq* pLedSeq) {
	unsigned char Buffer[LedCh_Max + 1];
	memset(Buffer, 1/*消灯*/, sizeof Buffer);
	LedSeq_Exec(pLedSeq, Buffer, NULL);
	//{{TODO:ここでBuffer[]を画面に描画してください｡}}
}
#endif//USE_LED
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

#ifdef  USE_SNR
int fnSnrSeq(struct _ST_SnrSeq* pSnrSeq, int iCh, int iSnrFnc, struct blob_reader* pArgs) {
	if((iSnrFnc <= 0) || iSnrFnc >= (intptr_t)TBL_SnrFnc[0]) { DIE(); }
	return (*TBL_SnrFnc[iSnrFnc])(pSnrSeq, iCh, iSnrFnc, pArgs);
}
#endif//USE_SNR

void app_init(int argc, char* argv[]) {
#ifdef  USE_USBSUSPEND_PROBLEMWORKAROUND
	//「USBがサスペンドした時にP/ECEがハングアップする事が有る問題」を回避する処理を設定します。
	Intel915G_WindowsXp_UsbSuspend_ProblemWorkaround_init();
#endif//USE_USBSUSPEND_PROBLEMWORKAROUND

	/* 一般的な初期化。 */
	pceAppSetProcPeriod(1000 / FPS);
#if     (defined(V_SCREEN)||defined(ASYNC_CAPTURE))
	pceLCDSetBuffer(_def_vbuff);
#else //(defined(V_SCREEN)||defined(ASYNC_CAPTURE))
	pceLCDSetBuffer(vbuff);
#endif//(defined(V_SCREEN)||defined(ASYNC_CAPTURE))
//不要	pceLCDDispStart();	//{{2014/12/31削除:cstart.cのpceAppInit00()でpceLCDDispStart()を呼び出し、液晶画面の表示を開始するようにしました。}}

#ifdef USE_REPEAT
	/* オートリピートを設定します。 */
    #ifdef  V_SCREEN
	pad_set_repeat(((REPEAT_PAD) & ~(PAD_LF|PAD_RI|PAD_UP|PAD_DN))	//縦画面用設定変換(schedule()にて行っている縦画面用入力変換の逆の変換です。)
	             | ((REPEAT_PAD) & PAD_LF ? PAD_DN : 0)
	             | ((REPEAT_PAD) & PAD_RI ? PAD_UP : 0)
	             | ((REPEAT_PAD) & PAD_UP ? PAD_LF : 0)
	             | ((REPEAT_PAD) & PAD_DN ? PAD_RI : 0), REPEAT_DELAY, REPEAT_INTERVAL);
    #else //V_SCREEN
	pad_set_repeat(REPEAT_PAD, REPEAT_DELAY, REPEAT_INTERVAL);
    #endif//V_SCREEN
#endif /*USE_REPEAT*/

	/* 描画環境初期化。 */
	surface.w = DISP_X;
	surface.h = DISP_Y;
	surface.vbuff = vbuff;
#ifdef USE_3D
	surface.zbuff = zbuff;
	render_init_3d(&render, &surface, 0, 0, 0, 0, FRONT, BACK, FOVY);
#else /*USE_3D*/
	render_init_2d(&render, &surface, 0, 0, 0, 0);
#endif /*USE_3D*/
#ifdef USE_RENDF
	surface.zbuff = zbuff;
	rendf_init(&rendf, &surface, 0, 0, 0, 0, FRONT, BACK, FOVY);
#endif /*USE_RENDF*/

#if defined(TRACE_ON) && (TRACE_ON)
	/* 標準エラー出力を開きます。 */
	stderr_open(9/*標準エラー出力モニタ接続待ち時間(調整可)*/);
#endif /*TRACE_ON*/

#ifdef UFEORDER
	/* USBファイルシステムエミュレーションを開始します。 */
	ufe_setup(9/*PC側ファイルサーバ接続待ち時間(調整可)*/);
	/* PFFSとUFEの優先順位を指定します。 */
	ufe_order(UFEORDER);
#endif /*UFEORDER*/

//{{2017/08/25変更:常にリソースを使用するように変更しました。
//#ifdef USE_RESOURCE
//    #if   (USE_RESOURCE == 1)
//	/* pexファイル添付リソースを取得します。 */
//	resource = resource_address(PRESCAN_STRINGIFY(PROJECT) ".pex");
//    #elif (USE_RESOURCE == 2)
//	/* srfファイルリンクリソースを取得します。 */
//	{ extern const int __START_resource_code[];	//詳細は、/clip/test.pce/Makefileの、'Tue Aug 01 23:04:57 JST 2017 Naoyuki Sawa'のコメントを参照して下さい。
//	  resource =       __START_resource_code; }
//    #else
//	#error 'USE_RESOURCE'の定義が不正です。
//    #endif
//#endif /*USE_RESOURCE*/
//↓2017/08/25変更:常にリソースを使用するように変更しました。
#ifdef  USE_PEXRES
	/* pexファイル添付リソースを取得します。 */
	resource = resource_address(PRESCAN_STRINGIFY(PROJECT) ".pex");
#else //USE_PEXRES
	/* srfファイルリンクリソースを取得します。 */
	{ extern const int __START_resource_code[];	//詳細は、/clip/test.pce/Makefileの、'Tue Aug 01 23:04:57 JST 2017 Naoyuki Sawa'のコメントを参照して下さい。
	  resource =       __START_resource_code; }
#endif//USE_PEXRES
	//リソースからデータアドレスを取得します。
	{ static const struct { const char* fname; const void** paddr; } tbl[] = {
#ifdef  USE_LOT
	  { "LotTbl.bin", (const void**)&TBL_LotTblNo },	//抽選テーブル
#endif//USE_LOT
#ifdef  USE_SNR
	  { "SnrSeq.bin", (const void**)&TBL_SnrTblNo },	//シナリオシーケンサ
#endif//USE_SNR
#ifdef  USE_LED
	  { "LedDef.bin", (const void**)&TBL_LedSeqNo },	//LEDシーケンサ
#endif//USE_LED
#ifdef  USE_ANM
	  { "AnmSeq.bin", (const void**)&TBL_AnmSeqNo },	//アニメーションシーケンサ
#endif//USE_ANM
#ifdef  USE_NCS
	  { "NcsSeq.bin", (const void**)&TBL_NcsSeqNo },	//NCS補間シーケンサ
#endif//USE_NCS
#ifdef  USE_REG
	  { "RegTbl.bin", (const void**)&TBL_RegTbl },		//レジストリテーブル
#endif//USE_REG
#ifdef  USE_SOUND_SEQUENCER
	  { "TapDef.bin", (const void**)&TBL_TapSeqNo },	//サウンドシーケンサ
#endif//USE_SOUND_SEQUENCER
#ifdef  USE_EVENT_TIMER
	  { "EvtTmr.bin", (const void**)&TBL_EvtTmrNo },	//イベントタイマ
#endif//USE_EVENT_TIMER
	  //{{TODO:リソースに含めるデータが増えたらここに追加して下さい。}}
	  {0/*終端*/}}, *ptr = tbl;
	  while(ptr->fname) { *ptr->paddr = fpk_address(resource, ptr->fname, NULL); ptr++; } }
//}}2017/08/25変更:常にリソースを使用するように変更しました。

#ifdef TURBO
	/* クロック・メモリウェイトを切替えます。 */
	turbo(TURBO);
#endif /*TURBO*/

#ifdef USE_DBG
	/* DBGユニットを設定します。 */
	dbg_init();
#endif /*USE_DBG*/

#ifdef GC_LEVEL
	/* ガーベージコレクターを初期化します。 */
	gc_init(GC_LEVEL);
#endif /*GC_LEVEL*/

#ifdef BITMAP_GC_UNIT
	/* Bitmap GCを初期化します。 */
	BitmapGC_Init(BITMAP_GC_UNIT);
#endif /*BITMAP_GC_UNIT*/

#ifdef  USE_PCL
	/* コルーチンを初期化します。 */
	co_thread_init();
#endif//USE_PCL

#ifdef LDIRECT_INTERVAL
	/* 高速切替・16階調表示を初期化します。 */
	ldirect_init(LDIRECT_INTERVAL);
#endif /*LDIRECT_INTERVAL*/

#ifdef USE_VQTC
	/* VQ圧縮テクスチャ描画を初期化します。 */
	VqTc_InitDrawing();
#endif /*USE_VQTC*/

#ifdef USE_MUSIC
	/* 音楽ライブラリを初期化します。 */
	InitMusic();
#if defined(USE_2BIT_ADPCM) || defined(USE_TRUESPEECH)
	/* - 2-bit ADPCM Decoder,又は,DSP Group TrueSpeech Decoderと、音楽ライブラリを併用する場合は、音楽ライブラリ側の使用チャネルをずらすことにしました。
	 *   この対策を行わないと、両方がチャネル0を使用しようとして、ハングアップしてしまいます。
	 * - 2-bit ADPCM Decoder,又は,DSP Group TrueSpeech Decoderに限らず、stream_play()を利用する機能と、音楽ライブラリと併用する場合は、同様の対策が必要です。
	 * //{{2015/01/15コメント削除:muslib.c版のInitMusic()は「music_wch = 0;」を行わないようにしたので、どのタイミングでmusic_wchを変更しても構いません。
	 * //- music_wchを変更する処理は、InitMusic()よりも後で行う必要があります。
	 * //  InitMusic()が、「music_wch = 0;」を行っているからです。InitMusic()よりも先に変更すると、0に戻ってしまいます。
	 * //- 尚、music_loudness()の機能もmusic_wchを参照していますが、
	 * //  随時、値を取得しているので、music_loudness()を呼び出した後にmusic_wchを変更しても、問題はありません。
	 * //}}2015/01/15コメント削除:muslib.c版のInitMusic()は「music_wch = 0;」を行わないようにしたので、どのタイミングでmusic_wchを変更しても構いません。 */
	music_wch = 3; /* チャネル0=2-bit ADPCM Decoder,又は,DSP Group TrueSpeech Decoder、チャネル1-2=アプリケーション使用、チャネル3=音楽ライブラリとする */
#endif /*defined(USE_2BIT_ADPCM) || defined(USE_TRUESPEECH)*/
#endif /*USE_MUSIC*/

	/* クリーンアップ関数を登録。 */
	atexit(app_exit);

//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	//タイマ管理を初期化します。
	TimMgr_Init(&stTimMgr, FPS);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

#ifdef USE_2BIT_ADPCM
	/* 2-bit ADPCM Decoderを起動します。 */
	adpcm_init(SOUND_MAXCH);
#endif /*USE_2BIT_ADPCM*/

#ifdef USE_TRUESPEECH
	/* DSP Group TrueSpeech Decoderを起動します。 */
	TrueSpeech_Init(SOUND_MAXCH);
#endif /*USE_TRUESPEECH*/

#ifdef USE_SOUND
	/* サウンドを初期化します。 */
//{{2017/08/25変更:常にリソースを使用するように変更しました。
//	{
//#define SOUND_(name) { extern const unsigned char name[]; sound_table[SND_##name] = name; }
//#define SOUND_RESOURCE_(name,fname) { sound_table[SND_##name] = fpk_address(resource, fname, NULL); }
//#include "sound.h"
//#undef SOUND_
//#undef SOUND_RESOURCE_
//	}
//↓2017/08/25変更:常にリソースを使用するように変更しました。
//	{ static const char* const tbl[] = {
//#define SOUND_RESOURCE_(name,fname) fname,
//#include "sound.h"
//#undef  SOUND_RESOURCE_
//	  };
//	  int i;
//	  for(i = 0; i < SOUND_COUNT; i++) { sound_table[i] = fpk_address(resource, tbl[i], NULL); } }
//↓2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
	{
		const void* pPhrDef = REG_open_key(TBL_RegTbl, RegKey_PhrDef);
		int iPhrNo;
		for(iPhrNo = 1; iPhrNo <= PhrNo_Max; iPhrNo++) {
			const void* pPhrKey = REG_open_key(pPhrDef, iPhrNo);
			const char* path = REG_get_string(pPhrKey, RegKey_Path);
			if(!path) { DIE(); }
			sound_table[iPhrNo] = fpk_address(resource, path, NULL);
		}
	}
//}}2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
#endif /*USE_SOUND*/

#ifdef USE_MUSIC
	/* 音楽を初期化します。 */
//{{2017/08/25変更:常にリソースを使用するように変更しました。
//	{
//#define MUSIC_(name) { extern /*const*/ unsigned char name[]; music_table[MUS_##name] = name; }
//#define MUSIC_RESOURCE_(name,fname) { music_table[MUS_##name] = (void*)fpk_address(resource, fname, NULL); }
//#include "music.h"
//#undef MUSIC_
//#undef MUSIC_RESOURCE_
//	}
//↓2017/08/25変更:常にリソースを使用するように変更しました。
//	{ static const char* const tbl[] = {
//#define MUSIC_RESOURCE_(name,fname) fname,
//#include "music.h"
//#undef  MUSIC_RESOURCE_
//	  };
//	  int i;
//	  for(i = 0; i < MUSIC_COUNT; i++) { music_table[i] = (void*)fpk_address(resource, tbl[i], NULL); } }
//↓2017/08/26削除:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
	{
		const void* pMusDef = REG_open_key(TBL_RegTbl, RegKey_MusDef);
		int iMusNo;
		for(iMusNo = 1; iMusNo <= MusNo_Max; iMusNo++) {
			const void* pMusKey = REG_open_key(pMusDef, iMusNo);
			const char* path = REG_get_string(pMusKey, RegKey_Path);
			if(!path) { DIE(); }
			music_table[iMusNo] = (void*)fpk_address(resource, path, NULL);
		}
	}
//}}2017/08/26削除:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
#endif /*USE_MUSIC*/

#ifdef  USE_SOUND_MANAGER
	/* Sound Managerを初期化します。 */
	{
		static const ST_SndMgrInfo stSndMgrInfo = { sound_play_stub, sound_stop, sound_stat, sound_att };
		pSndMgrBgm = SndMgr_Init(&stSndMgrInfo, SOUND_MANAGER_BGM_MINCH, SOUND_MANAGER_BGM_MAXCH); /* BGM Sound Manager */
		pSndMgrSe1 = SndMgr_Init(&stSndMgrInfo, SOUND_MANAGER_SE1_MINCH, SOUND_MANAGER_SE1_MAXCH); /* SE1 Sound Manager */
		pSndMgrSe2 = SndMgr_Init(&stSndMgrInfo, SOUND_MANAGER_SE2_MINCH, SOUND_MANAGER_SE2_MAXCH); /* SE2 Sound Manager */
	}
#endif/*USE_SOUND_MANAGER*/

#ifdef  USE_SOUND_MIXER
	/* TAPﾐｷｻｰを初期化します｡ */
	pTapMxr=TapMxr_New(TapMxrCh_Max+1);
//{{2017/08/28変更:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
//	timer_start(100,TapMxr_TimerProc,(void*)100);	//TAPﾐｷｻｰ用ﾀｲﾏ割込処理を開始する｡
//↓2017/08/28変更:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1ms, (void (*)(void*))TapMxr_TimerProc, (void*)100, 100);
//}}2017/08/28変更:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
#endif/*USE_SOUND_MIXER*/

#ifdef  USE_SOUND_SEQUENCER
	/* TAPｼｰｹﾝｻを初期化します｡ */
	{
		static const uint8_t* const TBL_TapSet[]={
			(uint8_t[]){TapDevCh_Bg1,-1},			//ｽﾃｰｼﾞBGM
			(uint8_t[]){TapDevCh_Bg2,-1},			//演出BGM
			(uint8_t[]){TapDevCh_Se1,TapDevCh_Se2,-1},	//演出SE
			(uint8_t[]){TapDevCh_Se1,TapDevCh_Se2,-1},	//演出SE
			(uint8_t[]){TapDevCh_Se1,TapDevCh_Se2,-1},	//演出SE
			(uint8_t[]){TapDevCh_Ui1,TapDevCh_Ui2,-1},	//UI
			(uint8_t[]){TapDevCh_Ui1,TapDevCh_Ui2,-1},	//UI
			(uint8_t[]){TapDevCh_Ui1,TapDevCh_Ui2,-1},	//ｴﾗｰ音
		};
		static const uint8_t TBL_BaseCh[]={
			0,	//ｽﾃｰｼﾞ	┐
			0,	//演出	│2017/02/09現在のsnd/TapDef.txtでは、シーケンサデータの中で論理チャネル番号を直接指定しているので、TBL_BaseCh[]によるオフセットは0としてあります。
			0,	//UI	│もし今後、シーケンサデータの中で論理チャネル番号を相対指定するように変更した場合は、TBL_BaseCh[]によるオフセットも適切に変更して下さい。
			0,	//ｴﾗｰ	┘
		};
		static const ST_TapSeqInfo stTapSeqInfo={
			PhrNo_Max+1,			//nPhr
			TapDevCh_Max+1,			//nDevCh
			TapLogCh_Max+1,			//nLogCh
			TapSeqCh_Max+1,			//nSeqCh
			1000/FPS,			//iCont
			0,				//iPrep
			31/*調整可*/,			//nEvt
			~(1<<TapEvt_Ctrl)/*変更可*/,	//iEvtMsk
			TapSeq_fnPlay,
			TapSeq_fnStop,
			TapSeq_fnLoop,
			TapSeq_fnEnd,
			TapSeq_fnNext,
			TapSeq_fnCtrl,
			NULL,				//fnPrep
			TapSeq_fnGetPhrTime,
			TapSeq_fnGetPhrNext,
			TBL_TapSet,
			TBL_BaseCh,
		};
		if(ARRAY_SIZE(TBL_TapSet) != (TapLogCh_Max+1)) { DIE(); }
		if(ARRAY_SIZE(TBL_BaseCh) != (TapSeqCh_Max+1)) { DIE(); }
		pTapSeq=TapSeq_New(&stTapSeqInfo);
//{{2017/08/28変更:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
//		timer_start(10,TapSeq_TimerProc,(void*)10);	//ｻｳﾝﾄﾞｼｰｹﾝｻ用ﾀｲﾏ割込処理を開始する｡
//↓2017/08/28変更:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
		TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1ms, (void (*)(void*))TapSeq_TimerProc, (void*)10, 10);
//}}2017/08/28変更:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	}
#endif/*USE_SOUND_SEQUENCER*/

#ifdef  USE_LED
	/* LEDシーケンサを初期化します。 */
	pLedSeq = LedSeq_New(LedCh_Max + 1, LedSeqCh_Max + 1);
//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1exec, (void (*)(void*))LedSeq_TimeProc, pLedSeq, 1);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
#endif//USE_LED

#ifdef  USE_SNR
	//シナリオシーケンサを初期化します。
	pSnrSeq = SnrSeq_New(fnSnrSeq, SnrSeqCh_Max+1, (SnrSeqCh_Max+1)*2/*調整可*/);	//1チャネル当たり平均して2個のコンテキストを同時実行すると想定して仮調整しました。
	TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1exec, (void (*)(void*))SnrSeq_Exec, pSnrSeq, 1);
#endif//USE_SNR

#ifdef  USE_EVENT_TIMER
	/* イベントタイマを初期化します。 */
	{
		static ST_EvtTmrFunc stEvtTmrFunc = { EvtTmr_onEvent };
		pEvtTmr = EvtTmr_New(EvtTmrNo_Max+1);	//ｲﾍﾞﾝﾄﾀｲﾏを初期化する｡
		EvtTmr_AddFunc(pEvtTmr, &stEvtTmrFunc);	//ｲﾍﾞﾝﾄ処理関数を登録する｡
	}
//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1exec, (void (*)(void*))EvtTmr_Exec, pEvtTmr, 1);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
#endif/*USE_EVENT_TIMER*/

#ifdef  USE_COUNTER_MANAGER
	/* 汎用カウンタ管理を初期化します。 */
	pCntMgr = CntMgr_New(CntCh_Max+1);
//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1exec, (void (*)(void*))CntMgr_Exec, pCntMgr, 1);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
#endif/*USE_COUNTER_MANAGER*/

#ifdef  USE_DURATION_COUNTER
	/* 存続カウンタを初期化します。 */
	pDurCnt = DurCnt_New();
//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1exec, (void (*)(void*))DurCnt_Exec, pDurCnt, 1);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
#endif/*USE_DURATION_COUNTER*/

#ifdef  USE_LOG_BUFFER
	/* ログバッファを初期化します。 */
	pLogBuf = LogBuf_Init((DISP_Y+9)/10, LogBuf_fnDraw);
#endif/*USE_LOG_BUFFER*/

#ifdef  USE_NVLOG
	//不揮発性ログバッファを初期化します。
	{
		time_t t;
		pceFileCreate("nvlog.bin", NVLOG_SIZE);
		pceFileOpen(&faNvLog, "nvlog.bin", FOMD_WR);
		pceFileReadSct(&faNvLog, nvlog, 0, NVLOG_SIZE);	//前回のログに追加する事にした。毎回空の状態から開始したい場合はこの行を削除せよ。
		time(&t);
		NVLOG("Start at %s", strstrip(ctime(&t)));
	}
#endif//USE_NVLOG

#ifdef  USE_TCL
	//Tclインタプリタを高速化するために、定期的にガーベージコレクションを行う。
#if     defined(GC_LEVEL)
/*必須*/timer_start(500/*調整可*/, gc_run, NULL);//cliptcl.cのコメント参照。通常のGCでTclインタプリタを使用する場合は、この行を実行しないと極端に遅くなる。
#elif   defined(BITMAP_GC_UNIT)
//任意	timer_start(500/*調整可*/, gc_run, NULL);//cliptcl.cのコメント参照。Bitmap GCを使用する場合は極端に遅くはないが、この行を実行する方が高速ではある。
#else //defined(GC_LEVEL)||defined(BITMAP_GC_UNIT)
	#error Tclインタプリタはガーベージコレクターの併用が必須です。
#endif//defined(GC_LEVEL)||defined(BITMAP_GC_UNIT)
	//Tclインタプリタを作成する。
	iPtr = Tcl_CreateInterp();
	//汎用的なアプリケーション定義のコマンドを登録する。
	Tcl_CreateCommand(iPtr, "srand",    Tcl_SrandCmd,    NULL);
	Tcl_CreateCommand(iPtr, "rand",     Tcl_RandCmd,     NULL);
	Tcl_CreateCommand(iPtr, "log",      Tcl_LogCmd,      NULL);
	Tcl_CreateCommand(iPtr, "schedule", Tcl_ScheduleCmd, NULL);
#endif//USE_TCL

#ifdef USE_TEXTURE
	/* テクスチャを初期化します。 */
//{{2017/08/25変更:常にリソースを使用するように変更しました。
//	{
//#define TEXTURE_(name) extern const unsigned char name[];
//#define TEXTURE_RESOURCE_(name,fname) const void* const name = fpk_address(resource, fname, NULL);
//#include "texture.h"
//#undef TEXTURE_
//#undef TEXTURE_RESOURCE_
//		texture_table_init(texture_table, TEXTURE_COUNT,
//#define TEXTURE_(name) name,
//#define TEXTURE_RESOURCE_(name,fname) name,
//#include "texture.h"
//#undef TEXTURE_
//#undef TEXTURE_RESOURCE_
//		NULL/*最後の','を吸収するためのダミー。texture_table_init()に対しては無意味です。*/);
//	}
//↓2017/08/25変更:常にリソースを使用するように変更しました。
//	{ static const char* const tbl[] = {
//#define TEXTURE_RESOURCE_(name,fname) fname,
//#include "texture.h"
//#undef  TEXTURE_RESOURCE_
//	  };
//	  int i;
//	  for(i = 0; i < TEXTURE_COUNT; i++) { texture_init(&texture_table[i], fpk_address(resource, tbl[i], NULL)); } }
//↓2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
	{
		const void* pTexDef = REG_open_key(TBL_RegTbl, RegKey_TexDef);
		int iTexNo;
		for(iTexNo = 1; iTexNo <= TexNo_Max; iTexNo++) {
			const void* pTexKey = REG_open_key(pTexDef, iTexNo);
			const char* path = REG_get_string(pTexKey, RegKey_Path);
			if(!path) { DIE(); }
			texture_init(&texture_table[iTexNo], fpk_address(resource, path, NULL));
		}
	}
//}}2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
#endif /*USE_TEXTURE*/

#ifdef USE_SPRITE
	/* 簡易スプライトドライバを初期化します。 */
//{{2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
//	sprite_init(&render, sprite_table, SPRITE_COUNT, texture_table, TEXTURE_COUNT);
//↓2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
//{{2018/05/27追加:SPRDEF_REDUCEシンボルを追加しました。
#ifdef  SPRDEF_REDUCE
	{
		const void* pSprDef = REG_get_blob(TBL_RegTbl, RegKey_SprDef);
		if(REG_get_blob_size(pSprDef) != (sizeof(SPRITE) * (SprNo_Max+1))) { DIE(); }
		sprite_init(&render, pSprDef, SprNo_Max+1, texture_table, TexNo_Max+1);
	}
#else //SPRDEF_REDUCE
//}}2018/05/27追加:SPRDEF_REDUCEシンボルを追加しました。
	{
		static SPRITE sprite_table[(SprNo_Max+1)];
		const void* pSprDef = REG_open_key(TBL_RegTbl, RegKey_SprDef);
		int iSprNo;
		for(iSprNo = 1; iSprNo <= SprNo_Max; iSprNo++) {
			const void* pSprKey = REG_open_key(pSprDef, iSprNo);
			SPRITE* pSpr = &sprite_table[iSprNo];
			int getValue(int valueName) {	//GCC拡張機能
				int valueData = REG_get_value(pSprKey, valueName);
				if(valueData == -1) { DIE(); }
				return valueData;
			}
			pSpr->texno = getValue(RegKey_TexNo);
			pSpr->x     = getValue(RegKey_x);
			pSpr->y     = getValue(RegKey_y);
			pSpr->w     = getValue(RegKey_w);
			pSpr->h     = getValue(RegKey_h);
			pSpr->cx    = getValue(RegKey_cx);
			pSpr->cy    = getValue(RegKey_cy);
			pSpr->param = getValue(RegKey_Param);
		}
		sprite_init(&render, sprite_table, SprNo_Max+1, texture_table, TexNo_Max+1);
	}
//{{2018/05/27追加:SPRDEF_REDUCEシンボルを追加しました。
#endif//SPRDEF_REDUCE
//}}2018/05/27追加:SPRDEF_REDUCEシンボルを追加しました。
//}}2017/08/26変更:各種定義ヘッダをP/ECE専用の形式から汎用形式への切り替えを行いました。
#endif /*USE_SPRITE*/

//{{2018/05/11追加:メッシュ定義の生成規則を追加しました。
#ifdef  USE_MESH
	{
		const void* pMesDef = REG_open_key(TBL_RegTbl, RegKey_MesDef);
		int iMeshNo;
		for(iMeshNo = 1; iMeshNo <= MeshNo_Max; iMeshNo++) {
			mesh_table[iMeshNo] = REG_get_blob(pMesDef, iMeshNo);
			if(!mesh_table[iMeshNo]) { DIE(); }
			{
				const char* pTextureName = REG_get_string(pMesDef, iMeshNo);
				if(pTextureName) {
					const void* pEnmKey = REG_open_key(TBL_RegTbl, RegKey_EnmDef);	//2018/05/11現在の処理順序では、列挙定義キーを取得する処理がここよりも後にあり、グローバル変数pEnmKeyがまだ初期化されていないので、ここではローカル変数pEnmKeyに取得する事にした。今後もし処理順序を入れ替える事にしたら、この行は不要になるので削除して構わない。
					int iTexNo = EnmDef_GetVal(pEnmKey, RegKey_TexNo, pTextureName);
					if((iTexNo < 1) || (iTexNo > TexNo_Max)) { DIE(); }
					mesh_texture_table[iMeshNo] = &texture_table[iTexNo];
				}
			}
		}
	}
#endif//USE_MESH
//}}2018/05/11追加:メッシュ定義の生成規則を追加しました。

#ifdef  USE_CBKQUE
	/* コールバックキューを初期化します。 */
	pCbkQue = DynamicCbkQue_New(2048/*調整可*/);	//2048でCbkQue_sprite_draw()x100回分ぐらいです。CbkQue_render_printf()等を使うともっと消費します。動的コールバックキューなので小さな値でも(0でも)構いません。
#endif//USE_CBKQUE

#ifdef  USE_DLYQUE
	/* 遅延コールバックキューを初期化します。 */
	pDlyQue = DlyQue_New();
//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	TimMgr_AddFunc_New(&stTimMgr, TimMgrCh_1exec, (void (*)(void*))DlyQue_Exec, pDlyQue, 1);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
#endif//USE_DLYQUE

#ifdef USE_TCPIP
	/* TCP/IPプロトコルスイートを開始します。 */
	tcpip_start(0/*Ethernetドライバ送信バッファサイズ(調整可)*/);
#endif /*USE_TCPIP*/

#ifdef USE_VIDREC
	/* 画面出力を初期化します。 */
	yield(); /* runで実行した場合の実行確認に応答するため、USB機能の切り替えを僅かに遅らせる */
#ifdef LDIRECT_INTERVAL
	cdcacm_start(0, sizeof vbuff / 2, NULL, NULL);
#else /*LDIRECT_INTERVAL*/
	cdcacm_start(0, sizeof vbuff / 4, NULL, NULL);
#endif /*LDIRECT_INTERVAL*/
#endif /*USE_VIDREC*/

#ifdef  USE_TASK
	/* タスクスケジューラを初期化します。
	 * - アイドルスレッドと併用する場合は、idle_proc()の中で初期化してください。
	 *   アイドルスレッドと併用する方法は、task_yield()の[note]を参照してください。 */
	task_init(INT_MIN);//{{TODO:ｼｽﾃﾑｱｲﾄﾞﾙﾀｽｸの実行優先度はｱﾌﾟﾘｹｰｼｮﾝ調整}}
#endif/*USE_TASK*/

#if     (defined(USE_ENM)&&defined(USE_REG))
	/* 列挙定義キーを取得します。 */
	if(!(pEnmKey = REG_open_key(TBL_RegTbl, RegKey_EnmDef))) { DIE(); }
#endif//(defined(USE_ENM)&&defined(USE_REG))

#ifdef  USE_PRP
	/* プロパティテーブルキーを取得します。 */
	if(!(pPrpKey = REG_open_key(TBL_RegTbl, RegKey_PrpTbl))) { DIE(); }
    #ifdef  PrpTbl_App
	/* プロパティヘッダを初期化します。 */
	PrpHdr_init(phApp, pPrpKey, PrpTbl_App);	//ﾃﾝﾌﾟﾚｰﾄとして1個だけ定義しました｡必要に応じて定義を追加して下さい｡
    #endif//PrpTbl_App
#endif//USE_PRP

#ifdef  USE_FSM
	/* 有限状態機械マップキーを取得します。 */
	if(!(pFsmKey = REG_open_key(TBL_RegTbl, RegKey_FsmMap))) { DIE(); }
    #ifdef  FsmMap_App
	/* 有限状態機械を初期化します。 */
	FsmObj_Init(&foApp, TBL_FsmFunc, pFsmKey, FsmMap_App, NULL);	//ﾃﾝﾌﾟﾚｰﾄとして1個だけ定義しました｡必要に応じて定義を追加して下さい｡
    #endif//FsmMap_App
#endif//USE_FSM

#ifdef  USE_ACT
    #ifndef USE_PCL
	#error USE_ACTはUSE_PCLにも依存しています。ActObj_New()のST_ActObj_New_Param引数にcoFuncを指定しなくてもダミーのコルーチンが作成されるので、アプリケーション開始時にco_thread_init()が呼ばれていないと正常に動作しません。
    #endif//USE_PCL
	/* アクターオブジェクトを初期化します。 */
	aoRoot = ActObj_New(NULL);			//ﾙｰﾄﾉｰﾄﾞとして1個だけ定義しました｡必要に応じて定義を追加して下さい｡
#endif//USE_ACT

#ifdef  USE_RRS
	/* Round Robin Scheduler (RRS)を初期化します。 */
	RRS_new_l(&pRRS, 0/*stacksize*/,	//{{TODO:変更可}}
		//{{TODO:ここにジョブ関数を列挙して下さい。}}
		NULL/*終端*/);
#endif//USE_RRS

#ifdef  USE_MSGHSK
	//メッセージハンドシェイクを初期化する。
	MsgHsk_Init(&stMsgHsk, pRRS);
#endif//USE_MSGHSK

#ifdef  USE_NUKLEAR
	//Nuklearコンテキストを作成する。
	ctx = nk_piece_new();
#endif//USE_NUKLEAR

/*{{アプリケーション特有の初期化*/
	srand(pceTimerGetCount());
/*}}アプリケーション特有の初期化*/

//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	//タイマ管理を開始します。
	TimMgr_timerId = timer_start(1, (void (*)(void*))TimMgr_Intr, &stTimMgr);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
}

/****************************************************************************
 *	app_exit
 ****************************************************************************/

void app_exit() {
/*{{アプリケーション特有のクリーンアップ*/
	/** no job **/
/*}}アプリケーション特有のクリーンアップ*/

#ifdef USE_VIDREC
	/* 画面出力を終了します。 */
	cdcacm_stop();
#endif /*USE_VIDREC*/

#ifdef USE_TCPIP
	/* TCP/IPプロトコルスイートを終了します。 */
	tcpip_stop();
#endif /*USE_TCPIP*/

#ifdef USE_VQTC
	/* VQ圧縮テクスチャ描画を解除します。 */
	VqTc_ExitDrawing();
#endif /*USE_VQTC*/

#ifdef LDIRECT_INTERVAL
	/* 高速切替・16階調表示を解除します。 */
	ldirect_free();
#endif /*LDIRECT_INTERVAL*/

#ifdef  USE_PCL
	/* コルーチンを終了します。 */
	co_thread_cleanup();
#endif//USE_PCL

#ifdef BITMAP_GC_UNIT
	/* Bitmap GCを解除します。 */
	BitmapGC_Free();
#endif /*BITMAP_GC_UNIT*/

#ifdef GC_LEVEL
	/* ガーベージコレクターを解除します。 */
	gc_free();
#endif /*GC_LEVEL*/

#ifdef USE_DBG
	/* DBGユニットの設定を解除します。 */
	dbg_free();
#endif /*USE_DBG*/

#ifdef UFEORDER
	/* USBファイルシステムエミュレーションを終了します。 */
	ufe_stop();
#endif /*UFEORDER*/

#ifdef  USE_USBSUSPEND_PROBLEMWORKAROUND
	//「USBがサスペンドした時にP/ECEがハングアップする事が有る問題」を回避する処理を解除します。
	Intel915G_WindowsXp_UsbSuspend_ProblemWorkaround_free();
#endif//USE_USBSUSPEND_PROBLEMWORKAROUND
}

/****************************************************************************
 *	update
 ****************************************************************************/

/* * Mon Mar 10 13:29:56 JST 2008 Naoyuki Sawa
 * - update()から、画面更新処理を分離し、高速化しました。
 */
#ifdef V_SCREEN
/* vbuff(縦画面)→_def_vbuff(横画面)変換 */
//static void rotate_screen() {
//	unsigned char *src = &vbuff[88 - 1];	/* 転送先の横画面は左上から走査開始します */
//	unsigned char *dst = &_def_vbuff[0];	/* 転送元の縦画面は右上から走査開始します */
//	int x = 88;
//	do {
//		int y = 128;
//		do {
//			*dst++ = *src;		/* 横画面を右方向に走査します */
//			src += 88;		/* 縦画面を下方向に走査します */
//		} while(--y);
//						/* 横画面は既に次の行へ移動しています */
//		src -= 88 * 128 + 1;		/* 縦画面を左の列の一番上へ移動します */
//	} while(--x);
//}
//↓高速化 (C版 = 9.2ms/1call → ASM版 = 3.2ms/1call)
/*static*/ void rotate_screen();
asm("
	.code
	.align	1
rotate_screen:
	xld.w	%r12, 0x0e00			; %r12 := FRAM4_START
	xld.w	%r13, rotate_screen_DOX		; %r13 := DOY
	xld.w	%r14, rotate_screen_END		; %r14 := END
	xcall.d	memcpy				; %r10 := FRAM4_START = memcpy(FRAM4_START, DOX, END - DOX)
	sub	%r14, %r13			; %r14 := END - DOY			*delay*
	xld.w	%r4, vbuff+87			; %r4  := src = &vbuff[88 - 1]
	xld.w	%r5, _def_vbuff			; %r5  := dst = &_def_vbuff[0]
	xld.w	%r6, 88				; %r6  := 88
	xld.w	%r7, 128			; %r7  := 128
	xld.w	%r11, 11265			; %r11 := 88 * 128 + 1
	ld.w	%r12, %r6			; %r12 := x = 88
	jp	%r10				; goto FRAM4_START			(jp.dは不可!!)
;//{{ここからFRAM4領域へ転送
rotate_screen_DOX:				; do {
	ld.w	%r13, %r7			;   %r13 := y = 128
rotate_screen_DOY:				;   do {
	ld.ub	%r9, [%r4]			;     %r9  := c = *src
	sub	%r13, 1				;     %r13 := --y			*anti-interlock*
	ld.b	[%r5]+, %r9			;     %r5  := *dst++ = c
	jrne.d	rotate_screen_DOY		;   } while(--y)
	add	%r4, %r6			;     %r4  := src += 88			*delay*
	sub	%r12, 1				;   %r12 := --x
	jrne.d	rotate_screen_DOX		; } while(--x)
	sub	%r4, %r11			;   %r4  := src -= 88 * 128 + 1		*delay*
	ret
rotate_screen_END:
;//}}ここまでFRAM4領域へ転送
");
#endif /*V_SCREEN*/

/* * Mon Nov 06 17:37:17 JST 2006 Naoyuki Sawa
 * - schedule()から、画面更新処理だけを分離しました。
 *   フレーム待ち無し画面更新だけを行う場合は、この関数を呼び出してください。
 * * Thu Dec 21 21:17:56 JST 2014 Naoyuki Sawa
 * - ログバッファ描画を、これまではschedule()で行っていましたが、update()で行うように変更しました。
 *   それに加えて、ログバッファ描画前後で、仮想VRAMを保存するようにしました。
 *   この変更によって、アプリケーションは、ログバッファ描画の影響を無視して、オーバーレイと見なせるようになりました。
 *   以下のような処理が可能となります。
 *   □例1
 *   │void app_main(){
 *   │  surface_clear(&surface,0);
 *   │  render_ellipse(&render,0,0,DISP_X,DISP_Y,3);//円を描画する｡
 *   │  for(;;){
 *   │    schedule();//円を破壊せずにﾛｸﾞﾊﾞｯﾌｧ描画のみをｽｸﾛｰﾙできる｡
 *   │    LogBuf_Printf(pLogBuf,"%d",now);
 *   │} }
 *   □例2
 *   │void test(){
 *   │  //〜何か処理〜
 *   │  LogBuf_Printf(pLogBuf,"some message");
 *   │  update();//ﾛｸﾞﾊﾞｯﾌｧ描画のみを更新する｡
 *   │  //〜何か処理〜
 *   │} }
 * - 今回の変更に伴い、ログバッファ描画が、録画と、PCからの画面キャプチャに含まれなくなったことに、注意してください。
 *   録画はschedule()の中のvidrec()で，キャプチャはschedule()の中のyield()内で行われる処理です。
 *   vidrec()やyield()が呼ばれる時点では、仮想VRAMは復元されており、ログバッファ描画は残っていないからです。
 *   ログバッファ描画は、主にテストのための表示ですので、録画やキャプチャに含まれていなくても問題が無いと思いますが、
 *   もし必要である場合は、当関数の最後の、仮想VRAMを復元する処理を削除すれば、変更前と同様に含まれるようにできます。
 */
void update() {
#ifdef  USE_LOG_BUFFER
	/* ログバッファ描画前に仮想VRAMを退避する。 */
    #if     (defined(V_SCREEN)||defined(ASYNC_CAPTURE))
	static unsigned char tmpbuf[sizeof vbuff];	//ログバッファと縦画面を併用する場合は、仮想VRAMを退避する一時的なバッファとして_def_vbuffを使えない。rotate_screen()が_def_vbuffを破壊するからである。tmpbuf[]の分メモリ使用量が増えることに注意せよ。
	memcpy(tmpbuf, vbuff, sizeof vbuff);
    #else //(defined(V_SCREEN)||defined(ASYNC_CAPTURE))
	memcpy(_def_vbuff, vbuff, sizeof vbuff);	//ログバッファと縦画面を併用しない場合は、仮想VRAMを退避する一時的なバッファとして_def_vbuffを使う。
    #endif//(defined(V_SCREEN)||defined(ASYNC_CAPTURE))
	/* ログバッファ描画。 */
	LogBuf_Draw(pLogBuf, 0, 0);
#endif/*USE_LOG_BUFFER*/

#if     (defined(V_SCREEN)||defined(ASYNC_CAPTURE))
    #ifdef  V_SCREEN
	//vbuff(縦画面)→_def_vbuff(横画面)変換
	rotate_screen();
    #else //V_SCREEN
	//vbuff(横画面)→_def_vbuff(横画面)コピー
	memcpy(_def_vbuff, vbuff, sizeof vbuff);
    #endif//V_SCREEN
#endif//(defined(V_SCREEN)||defined(ASYNC_CAPTURE))

	/* 画面転送 */
	pceLCDTrans();

#ifdef  USE_LOG_BUFFER
	/* ログバッファ描画前に退避した仮想VRAMを復元する。 */
    #ifdef  (defined(V_SCREEN)||defined(ASYNC_CAPTURE))
	memcpy(vbuff, tmpbuf, sizeof vbuff);		//ログバッファと縦画面を併用する場合
    #else //(defined(V_SCREEN)||defined(ASYNC_CAPTURE))
	memcpy(vbuff, _def_vbuff, sizeof vbuff);	//ログバッファと縦画面を併用しない場合
    #endif//(defined(V_SCREEN)||defined(ASYNC_CAPTURE))
#endif/*USE_LOG_BUFFER*/
}

/****************************************************************************
 *	vidrec
 ****************************************************************************/

#ifdef USE_VIDREC
static void vidrec() {
#ifdef LDIRECT_INTERVAL
	static const unsigned char hdr[4] = { DISP_X,DISP_Y,4/*[bpp]*/,FPS };
#else /*LDIRECT_INTERVAL*/
	static const unsigned char hdr[4] = { DISP_X,DISP_Y,2/*[bpp]*/,FPS };
#endif /*LDIRECT_INTERVAL*/
	static int active;
	//
	unsigned char buf[128/*調整可*/]; /* (sizeof vbuff)/Nのサイズとすること */
	const unsigned char* src;
	unsigned char* dst;

	if(cdcacm_recv(buf, 1) > 0) {
		switch(buf[0]) {
		case 0:
			active = 0; /* 画面出力停止 */
			break;
		case 1:
			active = 1; /* 画面出力開始 */
			src = hdr;
			do {
				if(pcePadGetDirect() & PAD_SELECT) {
					exit(0); /* 送信待ちに割り込んで強制終了 */
				}
				src += cdcacm_send(src, &hdr[sizeof hdr] - src);
			} while(src < &hdr[sizeof hdr]);
			break;
		}
	}
	if(active) {
		src = vbuff;
		do {
			dst = buf;
			do {
#ifdef LDIRECT_INTERVAL
				*dst++ = src[0]|(src[1]<<4); 
				src += 2;
#else /*LDIRECT_INTERVAL*/
				*dst++ = src[0]|(src[1]<<2)|(src[2]<<4)|(src[3]<<6);
				src += 4;
#endif /*LDIRECT_INTERVAL*/
			} while(dst < &buf[sizeof buf]);
			dst = buf;
			do {
				if(pcePadGetDirect() & PAD_SELECT) {
					exit(0); /* 送信待ちに割り込んで強制終了 */
				}
				dst += cdcacm_send(dst, &buf[sizeof buf] - dst);
			} while(dst < &buf[sizeof buf]);
		} while(src < &vbuff[sizeof vbuff]);
	}
}
#endif /*USE_VIDREC*/

/****************************************************************************
 *	schedule
 ****************************************************************************/

/* * Fri Dec 15 00:49:15 JST 2006 Naoyuki Sawa
 * - schedule()関数に、サウンドポーズ対応コードを追加しました。
 *   少し試した限りでは上手く動作しているようですが、スリープからの復帰時に問題が起きないか未確認です。
 * - もし、ポーズ状態のまま、すなわち、サウンドポーズ状態のままでアプリケーションを終了してしまった場合にも、
 *   CLiPライブラリ内のpceAppExit()でpceWaveStop(1)を呼び出しており、サウンド状態がリセットされるので、大丈夫です。
 */

void schedule() {
#ifdef  USE_RRS
	/* Round Robin Scheduler (RRS)処理。 */
	RRS_yield(pRRS);
#endif//USE_RRS

//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
	//タイマ管理の周期処理を実行します。
	TimMgr_Exec(&stTimMgr);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

//{{2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
//#ifdef  USE_EVENT_TIMER
//	/* イベントタイマ処理。 */
//	EvtTmr_Exec(pEvtTmr);
//#endif/*USE_EVENT_TIMER*/
//}}2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

//{{2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
//#ifdef  USE_COUNTER_MANAGER
//	/* 汎用カウンタ管理処理。 */
//	CntMgr_Exec(pCntMgr);
//#endif/*USE_COUNTER_MANAGER*/
//}}2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

//{{2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
//#ifdef  USE_DURATION_COUNTER
//	/* 存続カウンタ処理。 */
//	DurCnt_Exec(pDurCnt);
//#endif/*USE_DURATION_COUNTER*/
//}}2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

//{{2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
//#ifdef  USE_LED
//	/* LEDシーケンサ処理。 */
//	{
//		unsigned char Buffer[LedCh_Max + 1];
//		memset(Buffer, 1/*消灯*/, sizeof Buffer);
//		LedSeq_Exec(pLedSeq, Buffer, NULL);
//		//{{TODO:ここでBuffer[]を画面に描画してください｡}}
//	}
//#endif//USE_LED
//}}2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

//{{2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
//#ifdef  USE_DLYQUE
//	/* 遅延コールバックキュー処理。 */
//	DlyQue_Exec(pDlyQue);
//#endif//USE_DLYQUE
//}}2017/08/28削除:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。

#ifdef  USE_ACT
	//アクターオブジェクトの一般的な処理を実行する。
    #ifdef  FsmTrans_Exec
	ActObj_ApplyTransToTree(aoRoot, FsmTrans_Exec|Fsm_Trans_noreq, NULL);	//周期処理を実行する。
    #endif//FsmTrans_Exec
    #ifdef  FsmTrans_Draw
	ActObj_ApplyTransToTree(aoRoot, FsmTrans_Draw|Fsm_Trans_noreq, NULL);	//描画処理を実行する。
    #endif//FsmTrans_Draw
    #ifdef  FsmTrans_Free
	ActObj_ApplyTransToTree(aoRoot, FsmTrans_Free|Fsm_Trans_noreq, NULL);	//Term状態で待機しているオブジェクトを自分で開放させる。
    #endif//FsmTrans_Free
#endif//USE_ACT

#ifdef  USE_CBKQUE
	/* コールバックキュー処理。 */
	CbkQue_Invoke(pCbkQue);	//登録されているノードを全て呼び出す。アプリケーションによっては、他の処理を挟んでCbkQue_InvokePri()を複数回分けて呼び出すように変更して下さい。
	CbkQue_Clear(pCbkQue);	//コールバックキューを空の状態に戻す。アプリケーションによっては、一度登録したコールバックキューを何度も使い回す場合は、この行を削除して下さい。
#endif//USE_CBKQUE

#ifdef  USE_NUKLEAR
	//Nuklearの描画処理。
	// - GUIの表示優先度は、直接描画やコールバックキュー描画よりも上，PAUSEメッセージよりも下が適切だと思うので、ここでNuklearの描画処理を行う事にした。
	nk_piece_render(ctx, &render);
#endif//USE_NUKLEAR

#ifdef USE_PAUSE
	{
		/* PAUSEメッセージ領域のイメージ退避用バッファは、324バイト必要です。
		 * スタック上に取るのは危険ですし、staticに取るのもメモリの無駄です。
		 * そこで、PAUSE時にのみヒープから確保することにします。
		 */
		//unsigned char save[PAUSE_H][PAUSE_W];
		unsigned char (*save)[PAUSE_W] = NULL/*警告抑制*/;
		int pause = 0;
		/*{{2006/12/15:サウンドポーズ対応*/
		//int sound_pause = 0/*警告抑制*/;
		/*↓2018/02/28変更:サウンドポーズのコードを効率化*/
		int save_EHDM1 = 0/*警告抑制*/;
		/*}}2018/02/28変更:サウンドポーズのコードを効率化*/
		int x, y;
		for(;;) {
#endif /*USE_PAUSE*/

			/* 画面更新。 */
			update();

#ifdef USE_VIDREC
			/* 画面出力。 */
			vidrec();
#endif /*USE_VIDREC*/

#ifdef  USE_SOUND_MANAGER
			/* Sound Manager処理。 */
			SndMgr_Exec(pSndMgrBgm); /* BGM Sound Manager */
			SndMgr_Exec(pSndMgrSe1); /* SE1 Sound Manager */
			SndMgr_Exec(pSndMgrSe2); /* SE2 Sound Manager */
#endif/*USE_SOUND_MANAGER*/

			/* システム処理。 */
			yield();

			/* パッド状態更新。 */
			joy = pad_get();
#ifdef V_SCREEN
			joy = (joy & ~(PAD_LF | PAD_RI | PAD_UP | PAD_DN | /* 縦画面用入力変換 */
				       TRG_LF | TRG_RI | TRG_UP | TRG_DN))
				| (joy & PAD_LF ? PAD_UP : 0)
				| (joy & PAD_RI ? PAD_DN : 0)
				| (joy & PAD_UP ? PAD_RI : 0)
				| (joy & PAD_DN ? PAD_LF : 0)
				| (joy & TRG_LF ? TRG_UP : 0)
				| (joy & TRG_RI ? TRG_DN : 0)
				| (joy & TRG_UP ? TRG_RI : 0)
				| (joy & TRG_DN ? TRG_LF : 0);
#endif /*V_SCREEN*/

			/*{{2018/02/28削除:SELECTボタンによる例外投入を対応*/
			///* SELECTボタンが押されたら終了する。 */ /* アプリケーションによって不要ならば、この2行を削除してください。 */
			//if(joy & TRG_SELECT) exit(EXIT_SUCCESS); /* アプリケーションによって不要ならば、この2行を削除してください。 */
			/*}}2018/02/28削除:SELECTボタンによる例外投入を対応*/

#ifdef USE_PAUSE
			/*{{2018/02/28追加:SELECTボタンによる例外投入を対応*/
#ifdef  USE_SELECT
			//ポーズ中にSELECTボタンが押されたら、まずポーズを解除するために、STARTボタンが押された事にする。
			// - この場所で即、例外を投入したり実行を終了してはいけません。
			//   もしポーズ中だった場合、タイマ管理やサウンド再生の中断や、イメージ退避用バッファを確保しているからです。
			//   それらを元に戻さずに例外を捕捉して実行を継続すると、内部状態が不正になったりリソースリークが発生します。
			if(joy & TRG_SELECT) { if(pause) { joy |= TRG_START; } }
#endif//USE_SELECT
			/*}}2018/02/28追加:SELECTボタンによる例外投入を対応*/

			/* PAUSE処理。 */
			if(joy & TRG_START) {
				pause = !pause;	/* PAUSE状態切り替え */
				if(pause) {	/* PAUSE IN */
//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
					//タイマ管理を停止します。
					timer_stop(TimMgr_timerId);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
					/*{{2006/12/15:サウンドポーズ対応*/
					//ENTER_CS;
					//sound_pause = fINT_EDMA.EHDM1;
					//if(sound_pause) {
					//	fINT_EDMA.EHDM1 = 0;
					//}
					//LEAVE_CS;
					/*↓2018/02/28変更:サウンドポーズのコードを効率化*/
					ENTER_CS;
					save_EHDM1 = fINT_EDMA.EHDM1;		//ポーズ前のサウンド再生状態を記憶する。サウンド再生中ならばsave_EHDM1=1,サウンド再生中でなければsave_EHDM1=0となる。
					             fINT_EDMA.EHDM1 = 0;	//ポーズ中は確実にサウンド再生中断する。ポーズ前に既にfINT_EDMA.EHDM1=0だった場合は無駄処理となるが動作上は問題無い。
					LEAVE_CS;
					/*}}2018/02/28変更:サウンドポーズのコードを効率化*/
					/* PAUSEメッセージ表示部分のイメージを退避。 */
					save = (unsigned char (*)[PAUSE_W])malloc(PAUSE_W * PAUSE_H); /* イメージ退避用バッファ確保 */
					if(save == NULL) DIE();
					for(y = 0; y < PAUSE_H; y++) {
						for(x = 0; x < PAUSE_W; x++) {
							save[y][x] = vbuff[DISP_X * (PAUSE_Y + y) + (PAUSE_X + x)];
						}
					}
				} else {	/* PAUSE OUT */
					/* PAUSEメッセージ表示部分のイメージを復帰。 */
					for(y = 0; y < PAUSE_H; y++) {
						for(x = 0; x < PAUSE_W; x++) {
							vbuff[DISP_X * (PAUSE_Y + y) + (PAUSE_X + x)] = save[y][x];
						}
					}
					free(save); /* イメージ退避用バッファ開放 */
					/*{{2006/12/15:サウンドポーズ対応*/
					//ENTER_CS;
					//if(sound_pause) {
					//	fINT_EDMA.EHDM1 = 1;
					//}
					//LEAVE_CS;
					/*↓2018/02/28変更:サウンドポーズのコードを効率化*/
					ENTER_CS;
					fINT_EDMA.EHDM1 = save_EHDM1;		//ポーズ前のサウンド再生状態を復元する。ポーズ前に元々fINT_EDMA.EHDM1=0だった場合は無駄処理となるが動作上は問題無い。
					LEAVE_CS;
					/*}}2018/02/28変更:サウンドポーズのコードを効率化*/
//{{2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
					//タイマ管理を再開します。
					TimMgr_timerId = timer_start(1, (void (*)(void*))TimMgr_Intr, &stTimMgr);
//}}2017/08/28追加:タイマ管理を用いて周期処理の呼び出しを一元管理するように変更しました。
				}
			}
			if(!pause) break;
			/* PAUSEメッセージ点滅表示。 */
			if(pceTimerGetCount() % 1000 < 750) {
				render_string_framed(&render, PAUSE_X, PAUSE_Y, PAUSE_STR, PAUSE_FONT, PAUSE_COLOR);
			} else {
				for(y = 0; y < PAUSE_H; y++) {
					for(x = 0; x < PAUSE_W; x++) {
						vbuff[DISP_X * (PAUSE_Y + y) + (PAUSE_X + x)] = save[y][x];
					}
				}
			}
		}
	}
#endif /*USE_PAUSE*/

	/*{{2018/02/28追加:SELECTボタンによる例外投入を対応*/
#ifdef  USE_SELECT
	//SELECTボタンが押されたら…
	if(joy & TRG_SELECT) {
#ifdef  USE_SELECT_EXCEPTION
		//例外を投入する。
		SEH_throw(SelectException);
#else //USE_SELECT_EXCEPTION
		//実行を終了する。
		exit(EXIT_SUCCESS);
#endif//USE_SELECT_EXCEPTION
	}
#endif//USE_SELECT
	/*}}2018/02/28追加:SELECTボタンによる例外投入を対応*/

#ifdef  USE_NUKLEAR
	//Nuklearのイベント処理。
	nk_input_begin(ctx);
	nk_piece_handle_event(ctx, joy);
	nk_input_end(ctx);
#endif//USE_NUKLEAR

	now++;	/* グローバルタイマ更新 */

/*{{アプリケーション特有の周期処理*/
    //	surface_clear(&surface, 0/*変更可*/);	//暗黙のサーフェイスクリアを行う。この処理はdemo_main()の処理と衝突するので、demo_main()と同時に使用する事は出来ない。従って、simplify.sedにてdemo_main()を削除した後に、この処理を有効化するようにした。アプリケーションによっては、暗黙のサーフェイスクリアが不要な場合は、この行を削除して下さい。
/*}}アプリケーション特有の周期処理*/
}

/****************************************************************************
 *	delay
 ****************************************************************************/

void delay(int frame) {
	while(frame > 0) {
		schedule();
		frame--;
	}
}

/****************************************************************************
 *	app_main
 ****************************************************************************/

#if 0
int app_main(int argc, char* argv[]) {
//{{隠しコマンド。Bを押しながら起動すると電池表示を消す。デバッグ時に電池表示を消しやすいようにするためです。
	delay(1);
	if(joy & PAD_B) {
		pceWaveSetMasterAtt(0);
		pcePowerSetReport(PWR_RPTOFF);
	}
//}}隠しコマンド。Bを押しながら起動すると電池表示を消す。デバッグ時に電池表示を消しやすいようにするためです。
	for(;;) {
		schedule();
	}
	return 0;
}
#endif
