/*
 *	clipcntm.h
 *
 *	汎用カウンタ管理
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2015 Naoyuki Sawa
 *
 *	* Sun Apr 13 21:02:48 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	- Sound Mixer(clipsndx.*)を元にして作成しました。
 *	  Sound Mixer(clipsndx.*)と処理内容が似ていますが、下記の相違のために共通化することは難しく、別機能として分けることにしました。
 *	  ・Sound Mixerは8ビット値であるが、汎用カウンタ管理は8ビットでは足りない。
 *	  ・Sound Mixerは各チャネルのサウンドチャネルマスクが必要だが、汎用カウンタ管理には必要無い。
 *	  ・Sound Mixerは各チャネルの減衰量の合計を求める必要があるが、汎用カウンタ管理には必要無い。
 *	  ・Sound Mixerは割込処理から呼ばれる可能性を考慮して排他制御の必要があるが、汎用カウンタ管理は(その目的から考えて)割込処理から呼ばれることは無く排他制御は必要無い。
 *	* Wed Feb 04 21:22:53 JST 2015 Naoyuki Sawa
 *	- Hewは要素数[0]の配列に対応していないので、要素数[1]として調整しました。
 *	  P/ECE開発環境(GCC)やWindows(VC++6.0)は、要素数[0]の配列に対応しているので、関係有りません。
 */
#ifndef __CLIP_CNTM_H__
#define __CLIP_CNTM_H__

/****************************************************************************
 *	構造体
 ****************************************************************************/

/* 汎用カウンタ管理構造体 */
typedef struct _ST_CntMgrCh {
	uint16_t ValNow;	/* + 0,2 現在値 (0〜USHRT_MAX) */
	uint16_t ValTo;		/* + 2,2 目標値 (0〜USHRT_MAX) */
	uint16_t Rate;		/* + 4,2 変化速度 (CntMgr_Exec()一回毎に(Rate/Scale)の速度で変化) */
	uint16_t Scale;		/* + 6,2 変化速度 (CntMgr_Exec()一回毎に(Rate/Scale)の速度で変化) */
	uint16_t ErrTerm;	/* + 8,2 誤差項 */
} ST_CntMgrCh;			/* =10 */

/* 汎用カウンタ管理構造体 */
typedef struct _ST_CntMgr {
	unsigned short nCntMgrCh;		/* +0,2   汎用カウンタ管理チャネル数 */
#ifndef __RENESAS__
	ST_CntMgrCh pCntMgrCh[0/*nCntMgrCh*/];	/* +2,10N 汎用カウンタ管理チャネル構造体配列 */
#else //__RENESAS__
	ST_CntMgrCh pCntMgrCh[1/*nCntMgrCh*/];	/* +2,10N 汎用カウンタ管理チャネル構造体配列 */		//Hewは要素数[0]の配列に対応していないので、要素数[1]として調整しました。
#endif//__RENESAS__
} ST_CntMgr;					/* =2+10N */

/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/

/* 汎用カウンタ管理を作成します。
 * [in]
 *	nCntMgrCh	汎用カウンタ管理チャネル数
 * [out]
 *	戻り値		汎用カウンタ管理
 * [note]
 *	- 当関数は、malloc()を使用して、汎用カウンタ管理構造体のメモリを動的に確保します。
 *	  動的なメモリ確保を行いたくない場合は、当関数の代りに、CntMgr_InitStatic()を使用してください。
 */
ST_CntMgr* CntMgr_Init(int nCntMgrCh);

/* 静的に確保したメモリを使用して、汎用カウンタ管理を作成します。
 * [in]
 *	pCntMgr		静的に確保したメモリ
 *	nCntMgrCh	汎用カウンタ管理チャネル数
 * [note]
 *	- 当関数を使用して作成した汎用カウンタ管理は、CntMgr_Free()による開放は不要です。
 * [使用例]
 *	│struct {
 *	│  ST_CntMgr   cntMgr;
 *	│  ST_CntMgrCh cntMgrCh[3];
 *	│} stCntMgr;
 *	│CntMgr_InitStatic(&stCntMgr.cntMgr, 3);
 */
void CntMgr_InitStatic(ST_CntMgr* pCntMgr, int nCntMgrCh);

/* 汎用カウンタ管理を開放します。
 * [in]
 *	pCntMgr		汎用カウンタ管理
 *			本関数のみ、pCntMgr引数にNULLを指定可能です。
 *			「CntMgr_Free(NULL)」の呼び出しは安全であり、何も行いません。
 * [note]
 *	- アプリケーション終了直前ならば、明示的に汎用カウンタ管理を開放する必要はありません。
 *	  汎用カウンタ管理はメモリリソースのみ使用し、割り込みフック等は行っていないからです。
 */
#define CntMgr_Free free

/* 汎用カウンタ管理の周期処理を行います。
 * [in]
 *	pCntMgr		汎用カウンタ管理
 * [note]
 *	- 各汎用カウンタ管理チャネルの現在値変化処理を行います。
 *	- アプリケーションが定期的に、当関数を呼び出してください。
 *	  周期時間はアプリケーション定義ですが、画面更新周期(1F)が適切です。
 */
void CntMgr_Exec(ST_CntMgr* pCntMgr);

/* 汎用カウンタ管理チャネルの現在値変化を開始します。
 * [in]
 *	pCntMgr		汎用カウンタ管理
 *	iCntMgrCh	汎用カウンタ管理チャネル番号 (0〜(nCntMgrCh-1))
 *	ValTo		目標値
 *	Rate		変化速度 (CntMgr_Exec()一回毎に(Rate/Scale)の速度で変化)
 *	Scale		変化速度 (CntMgr_Exec()一回毎に(Rate/Scale)の速度で変化)
 * [note]
 *	- Rate,又は,Scaleの片方にでも0を指定すると、即変化します。
 */
void CntMgr_SetVal(ST_CntMgr* pCntMgr, int iCntMgrCh, int ValTo, int Rate, int Scale);

/* 汎用カウンタ管理チャネルの現在値を取得します。
 * [in]
 *	pCntMgr		汎用カウンタ管理
 *	iCntMgrCh	汎用カウンタ管理チャネル番号 (0〜(nCntMgrCh-1))
 * [out]
 *	戻り値		現在値
 * [note]
 *	- 個別の汎用カウンタ管理チャネルの現在値を取得する場合は、CntMgr_GetVal()を使用するのが簡単ですが、
 *	  全ての汎用カウンタ管理チャネルの現在値を取得する場合は、CntMgr_GetValAll()を使用する方が効率が良いです。
 */
int CntMgr_GetVal(ST_CntMgr* pCntMgr, int iCntMgrCh);

/* 全ての汎用カウンタ管理チャネルの現在値を取得します。
 * [in]
 *	pCntMgr		汎用カウンタ管理
 *	ValNow		全ての汎用カウンタ管理チャネルの現在値を格納するための配列
 * [out]
 *	戻り値		ValNowに、全ての汎用カウンタ管理チャネルの減衰量を格納する
 * [note]
 *	- 個別の汎用カウンタ管理チャネルの現在値を取得する場合は、CntMgr_GetVal()を使用するのが簡単ですが、
 *	  全ての汎用カウンタ管理チャネルの現在値を取得する場合は、CntMgr_GetValAll()を使用する方が効率が良いです。
 */
void CntMgr_GetValAll(ST_CntMgr* pCntMgr, uint16_t ValNow[/*nCntMgrCh*/]);

//□使用例
//│enum{//汎用ｶｳﾝﾀ管理ﾁｬﾈﾙ定義
//│CntMgrCh_MdGet,//獲得ﾒﾀﾞﾙ数
//│CntMgrCh_GmLft,//残りｹﾞｰﾑ数
//│CntMgrCh_GmCnt,//消化ｹﾞｰﾑ数
//│CntMgrCh_SIZE};
//│ST_CntMgr* pCntMgr;//汎用ｶｳﾝﾀ管理
//│int TBL_Val[CntMgrCh_SIZE];//内部値
//│void app_main(){//ﾃｽﾄ関数
//│  uint16_t ValNow[CntMgrCh_SIZE];
//│  pCntMgr=CntMgr_Init(CntMgrCh_SIZE);//汎用ｶｳﾝﾀ管理を初期化
//│  CntMgr_SetVal(pCntMgr,CntMgrCh_GmLft,TBL_Val[CntMgrCh_GmLft]=50,0,0);//残りｹﾞｰﾑ数(即反映)
//│  for(;;){
//│    schedule();
//│    surface_clear(&surface,0);
//│    if(joy&TRG_A){//遊技開始想定
//│      CntMgr_SetVal(pCntMgr,CntMgrCh_MdGet,min(max(0,TBL_Val[CntMgrCh_MdGet]-= 3),999),1,2);//獲得ﾒﾀﾞﾙ数(1/2[f]の頻度で変化)
//│      CntMgr_SetVal(pCntMgr,CntMgrCh_GmLft,min(max(0,TBL_Val[CntMgrCh_GmLft]--  ), 99),1,2);//残りｹﾞｰﾑ数(1/2[f]の頻度で変化)
//│      CntMgr_SetVal(pCntMgr,CntMgrCh_GmCnt,min(max(0,TBL_Val[CntMgrCh_GmCnt]++  ), 99),1,2);//消化ｹﾞｰﾑ数(1/2[f]の頻度で変化)
//│    }
//│    if(joy&TRG_B){//小役入賞想定
//│      CntMgr_SetVal(pCntMgr,CntMgrCh_MdGet,min(max(0,TBL_Val[CntMgrCh_MdGet]+=15),999),1,2);//獲得ﾒﾀﾞﾙ数(1/2[f]の頻度で変化)
//│    }
//│    CntMgr_Exec(pCntMgr);//汎用ｶｳﾝﾀ管理の周期処理
//│    CntMgr_GetValAll(pCntMgr,ValNow);//汎用ｶｳﾝﾀ管理の現在値を取得
//│    render_printf(&render,0, 0,0,3,"           内部値 表示値");
//│    render_printf(&render,0,10,0,3,"獲得ﾒﾀﾞﾙ数 %6d %6d",TBL_Val[CntMgrCh_MdGet],ValNow[CntMgrCh_MdGet]);
//│    render_printf(&render,0,20,0,3,"残りｹﾞｰﾑ数 %6d %6d",TBL_Val[CntMgrCh_GmLft],ValNow[CntMgrCh_GmLft]);
//│    render_printf(&render,0,30,0,3,"消化ｹﾞｰﾑ数 %6d %6d",TBL_Val[CntMgrCh_GmCnt],ValNow[CntMgrCh_GmCnt]);
//│  }
//│}

#endif/*__CLIP_CNTM_H__*/
