/*
 *	app.c
 *
 *	Nuklear GUIデモ
 *
 *	* Sun Nov 20 19:00:00 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 */
#include "app.h"

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

#ifdef USE_SOUND
const void* sound_table[SOUND_COUNT];
#endif /*USE_SOUND*/

#ifdef USE_TEXTURE
TEXTURE texture_table[TEXTURE_COUNT];
#endif /*USE_TEXTURE*/

#ifdef USE_SPRITE
#define SPRITE_ SPRITE_INIT2
const SPRITE sprite_table[SPRITE_COUNT] = {
#include "sprite.h"
};
#undef SPRITE_
#endif /*USE_SPRITE*/

/****************************************************************************
 *	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 >= SOUND_COUNT) { DIE(); }
	sound_play(iCh, sound_table[iData], iLoop);
}
#endif/*USE_SOUND_MANAGER*/

#ifdef  USE_SOUND_MIXER
static const uint8_t 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ﾐｷｻｰﾁｬﾈﾙ1:演出BGM再生中	減音対象論理ﾁｬﾈﾙ:ｽﾃｰｼﾞBGM
//        |+---- TAPﾐｷｻｰﾁｬﾈﾙ2:ｴﾗｰ音再生中	減音対象論理ﾁｬﾈﾙ:ｴﾗｰ音以外
//        +----- TAPﾐｷｻｰﾁｬﾈﾙ0:ﾄｰﾀﾙﾚﾍﾞﾙ		減音対象論理ﾁｬﾈﾙ:全て
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) {
#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*/
	//フレーズシーケンスをプログラムで処理する場合。
	return (iPhr==SND_BGM_1G)||(iPhr==SND_BGM_ST)?iPhr:-1;
#endif/*USE_REG*/
}
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

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);
#ifdef V_SCREEN
	pceLCDSetBuffer(_def_vbuff);
#else /*V_SCREEN*/
	pceLCDSetBuffer(vbuff);
#endif /*V_SCREEN*/
//不要	pceLCDDispStart();	//{{2014/12/31削除:cstart.cのpceAppInit00()でpceLCDDispStart()を呼び出し、液晶画面の表示を開始するようにしました。}}
#ifdef USE_REPEAT
	pad_set_repeat(REPEAT_PAD, REPEAT_DELAY, REPEAT_INTERVAL);
#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 USE_UFE
	/* USBファイルシステムエミュレーションを開始します。 */
	ufe_setup(9/*PC側ファイルサーバ接続待ち時間(調整可)*/);
#endif /*USE_UFE*/

#ifdef USE_RESOURCE
	/* pexファイル添付リソースを取得します。 */
	resource = resource_address(PRESCAN_STRINGIFY(PROJECT) ".pex");
#endif /*USE_RESOURCE*/

#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 LDIRECT_INTERVAL
	/* 高速切替・16階調表示を初期化します。 */
	ldirect_init(LDIRECT_INTERVAL);
#endif /*LDIRECT_INTERVAL*/

#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);

#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
	{
#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_
	}
#endif /*USE_SOUND*/

	/* Sound Managerを初期化します。 */
#ifdef  USE_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*/

	/* TAPﾐｷｻｰを初期化します｡ */
#ifdef  USE_SOUND_MIXER
	{
		pTapMxr=TapMxr_New(TapMxrCh_Max+1);
		timer_start(100,TapMxr_TimerProc,(void*)100);	//TAPﾐｷｻｰ用ﾀｲﾏ割込処理を開始する｡
	}
#endif/*USE_SOUND_MIXER*/

	/* TAPｼｰｹﾝｻを初期化します｡ */
#ifdef  USE_SOUND_SEQUENCER
	{
		static struct {
			ST_TapSeqInfo stTapSeqInfo;
			const uint8_t* TBL_TapSet[(TapLogCh_Max+1)];
		} stTapSeqInfo = {{
			SOUND_COUNT,			//nPhr
			TapDevCh_Max+1,			//nDevCh
			TapLogCh_Max+1,			//nLogCh
			TapSeqCh_Max+1,			//nSeqCh
			1000/FPS,			//iCont
			31/*調整可*/,			//nEvt
			~(1<<TapEvt_Ctrl)/*変更可*/,	//iEvtMsk
			TapSeq_fnPlay,
			TapSeq_fnStop,
			TapSeq_fnLoop,
			TapSeq_fnEnd,
			TapSeq_fnNext,
			TapSeq_fnCtrl,
			TapSeq_fnGetPhrTime,
			TapSeq_fnGetPhrNext,
		},{
			(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},	//ｴﾗｰ音
		}};
		pTapSeq=TapSeq_New(&stTapSeqInfo.stTapSeqInfo);
		timer_start(10,TapSeq_TimerProc,(void*)10);	//ｻｳﾝﾄﾞｼｰｹﾝｻ用ﾀｲﾏ割込処理を開始する｡
	}
#endif/*USE_SOUND_SEQUENCER*/

	/* LEDシーケンサを初期化します。 */
#ifdef  USE_LED
	pLedSeq = LedSeq_New(LedCh_Max + 1, LedSeqCh_Max + 1);
#endif//USE_LED

	/* イベントタイマを初期化します。 */
#ifdef  USE_EVENT_TIMER
	{
		static ST_EvtTmrFunc stEvtTmrFunc = { EvtTmr_onEvent };
		pEvtTmr = EvtTmr_New(EvtTmrNo_Max+1);	//ｲﾍﾞﾝﾄﾀｲﾏを初期化する｡
		EvtTmr_AddFunc(pEvtTmr, &stEvtTmrFunc);	//ｲﾍﾞﾝﾄ処理関数を登録する｡
	}
#endif/*USE_EVENT_TIMER*/

	/* 汎用カウンタ管理を初期化します。 */
#ifdef  USE_COUNTER_MANAGER
	pCntMgr = CntMgr_New(CntCh_Max+1);
#endif/*USE_COUNTER_MANAGER*/

	/* 存続カウンタを初期化します。 */
#ifdef  USE_DURATION_COUNTER
	pDurCnt = DurCnt_New();
#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
	{
#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()に対しては無意味です。*/);
	}
#endif /*USE_TEXTURE*/

#ifdef USE_SPRITE
	/* 簡易スプライトドライバを初期化します。 */
	sprite_init(&render, sprite_table, SPRITE_COUNT, texture_table, TEXTURE_COUNT);
#endif /*USE_SPRITE*/

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

#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))
	/* 列挙定義キーを取得します。 */
	pEnmKey = REG_open_key(TBL_RegTbl, RegKey_EnmDef);
#endif//(defined(USE_ENM)&&defined(USE_REG))

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

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

#ifdef  USE_ACT
	/* アクターオブジェクトを初期化します。 */
	aoApp = ActObj_New(NULL/*pParent*/, NULL/*pFsmKey*/, 0/*iFsmMap*/, NULL/*pPrpKey*/, 0/*iPrpTbl*/, NULL/*fnAct*/, 0/*nDirSeqCh*/, 0/*nDataBytes*/);
#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());
/*}}アプリケーション特有の初期化*/
}

/****************************************************************************
 *	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 LDIRECT_INTERVAL
	/* 高速切替・16階調表示を解除します。 */
	ldirect_free();
#endif /*LDIRECT_INTERVAL*/

#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 USE_UFE
	/* USBファイルシステムエミュレーションを終了します。 */
	ufe_stop();
#endif /*USE_UFE*/

#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を退避する。 */
    #ifdef  V_SCREEN
	static unsigned char tmpbuf[sizeof vbuff];	//ログバッファと縦画面を併用する場合は、仮想VRAMを退避する一時的なバッファとして_def_vbuffを使えない。rotate_screen()が_def_vbuffを破壊するからである。tmpbuf[]の分メモリ使用量が増えることに注意せよ。
	memcpy(tmpbuf, vbuff, sizeof vbuff);
    #else //V_SCREEN
	memcpy(_def_vbuff, vbuff, sizeof vbuff);	//ログバッファと縦画面を併用しない場合は、仮想VRAMを退避する一時的なバッファとして_def_vbuffを使う。
    #endif//V_SCREEN
	/* ログバッファ描画。 */
	LogBuf_Draw(pLogBuf, 0, 0);
#endif/*USE_LOG_BUFFER*/

#ifdef V_SCREEN
	rotate_screen();
#endif /*V_SCREEN*/

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

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

#ifdef  USE_EVENT_TIMER
	/* イベントタイマ処理。 */
	EvtTmr_Exec(pEvtTmr);
#endif/*USE_EVENT_TIMER*/

#ifdef  USE_COUNTER_MANAGER
	/* 汎用カウンタ管理処理。 */
	CntMgr_Exec(pCntMgr);
#endif/*USE_COUNTER_MANAGER*/

#ifdef  USE_DURATION_COUNTER
	/* 存続カウンタ処理。 */
	DurCnt_Exec(pDurCnt);
#endif/*USE_DURATION_COUNTER*/

#ifdef  USE_LED
	/* LEDシーケンサ処理。 */
	{
		unsigned char Buffer[LedCh_Max + 1];
		memset(Buffer, 1/*消灯*/, sizeof Buffer);
		LedSeq_Exec(pLedSeq, Buffer);
		//{{TODO:ここでBuffer[]を画面に描画してください｡}}
	}
#endif//USE_LED

#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/*警告抑制*/;
		/*}}2006/12/15:サウンドポーズ対応*/
		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*/

#ifdef USE_IDLE
			/* アイドル処理+システム処理。 */
			idle_yield();
#else /*USE_IDLE*/
			/* システム処理。 */
			yield();
#endif /*USE_IDLE*/

			/* パッド状態更新。 */
			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*/

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

#ifdef USE_PAUSE
			/* PAUSE処理。 */
			if(joy & TRG_START) {
				pause = !pause;	/* PAUSE状態切り替え */
				if(pause) {	/* PAUSE IN */
					/*{{2006/12/15:サウンドポーズ対応*/
					ENTER_CS;
					sound_pause = fINT_EDMA.EHDM1;
					if(sound_pause) {
						fINT_EDMA.EHDM1 = 0;
					}
					LEAVE_CS;
					/*}}2006/12/15:サウンドポーズ対応*/
					/* 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 */
					/*{{2006/12/15:サウンドポーズ対応*/
					ENTER_CS;
					if(sound_pause) {
						fINT_EDMA.EHDM1 = 1;
					}
					LEAVE_CS;
					/*}}2006/12/15:サウンドポーズ対応*/
					/* 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); /* イメージ退避用バッファ開放 */
				}
			}
			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*/

#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
 ****************************************************************************/

int overview(struct nk_context* ctx);

int app_main(int argc, char* argv[]) {
	for(;;) {
		schedule();
		//背景を市松模様で塗り潰す。
		{
			int* p = (int*)vbuff;
			int x, y, c;
			for(y = 0; y < DISP_Y; y++) {
				c = (1<<0)|(0<<8)|(1<<16)|(0<<24);
				if(y & 1) { c <<= 8; }
				for(x = 0; x < (DISP_X / 4); x++) {
					*p++ = c;
				}
			}
		}
		//NuklearのGUIを実行する。
		overview(ctx);
	}
	return 0;
}

#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
