//
//	clipsprf.cs
//
//	スプライトフォント
//
//	CLiP - Common Library for P/ECE
//	Copyright (C) 2017 Naoyuki Sawa
//
//	* Sun Mar 19 22:19:43 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//	* Mon Mar 20 22:44:17 JST 2017 Naoyuki Sawa
//	- SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//	  スプライトフォントの文字コードは、シフトJISでレジストリテーブルに格納されているからです。
//	  実際の所、スプライトフォントに含める2バイト文字はせいぜい全角空白ぐらいだと思うので、全角空白が上手く処理出来れば動作確認出来ると思います。
//	- SprFnt_PrintXF_subr()にて、演算誤差で位置がぶれる問題を修正しました。
//	  詳細は、clipsprf.cの同日のコメントを参照して下さい。
//	* Tue Apr 04 23:33:32 JST 2017 Naoyuki Sawa
//	- スプライトフォント描画に回転機能を追加しました。
//	* Wed Apr 19 22:11:14 JST 2017 Naoyuki Sawa
//	- SprFnt_GetSize()をローカル関数⇒グローバル関数に変更しました。
//
using System;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	定数
		//*****************************************************************************
		public const int SprFnt_SprNo	= 0;	//0(blank),又は,スプライト番号(1～0xFFFF)
		public const int SprFnt_NextX	= 1;	//列ストライド。この文字を描いた後、この値の分、右へ進みます。
		public const int SprFnt_NextY	= 2;	//行ストライド。一行に描いた文字の、この値の内、最大の値の分、改行時に下へ進みます。
		public const int SprFnt_DrawX	= 3;	//描画オフセットX。スプライト原点Xを、この位置に描画します。
		public const int SprFnt_DrawY	= 4;	//描画オフセットY。スプライト原点Yを、この位置に描画します。
		//*****************************************************************************
		//	構造体
		//*****************************************************************************
		//文字の描画設定
		private struct ST_SprFnt_Info {
			public int	SprNo;		//0(blank),又は,スプライト番号(1～0xFFFF)						┐
			public int	NextX;		//列ストライド。この文字を描いた後、この値の分、右へ進みます。				│
			public int	NextY;		//行ストライド。一行に描いた文字の、この値の内、最大の値の分、改行時に下へ進みます。	├詳細は、/clip/tool/dSprFntC/winapp.hの、ST_SprFntHdr,及び,ST_SprFntRowのコメントを参照して下さい。
			public int	DrawX;		//描画オフセットX。スプライト原点Xを、この位置に描画します。				│
			public int	DrawY;		//描画オフセットY。スプライト原点Yを、この位置に描画します。				┘
		}
		//*****************************************************************************
		//	ローカル関数
		//*****************************************************************************
		//文字の描画設定の値を取得する。
		private static int SprFnt_GetInfo_subr(VoidPtr pSprFnt, VoidPtr pChrKey, int iValueName/*SprFnt_NextX or SprFnt_NextY or SprFnt_DrawX or SprFnt_DrawY*/) {
			int iValue = REG_get_value(pChrKey, iValueName);	//この文字のキーから、値を取得する。
			if(iValue == -1) {					//この文字のキーから、値を取得出来なければ…
				iValue = REG_get_value(pSprFnt, iValueName);	//スプライトフォントのキーから、デフォルト値を取得する。
				if(iValue == -1) { iValue = 0; }		//デフォルト値も無ければ、0とする。
			}
			return iValue << 8 >> 8;				//取得した値のbit23を符号拡張して元の値に戻す。
		}
		//-----------------------------------------------------------------------------
		//文字の描画設定を取得する。
		private static void SprFnt_GetInfo(VoidPtr pSprFnt, int c, out ST_SprFnt_Info pInfo) {
			//この文字のキーを取得する。
			VoidPtr pChrKey = REG_open_key(pSprFnt, c);
			//この文字のキーが無ければ…
			if(!pChrKey) {
				//フォールバック用のキーを取得する。
				pChrKey = REG_open_key(pSprFnt, 0/*fallback*/);
				if(!pChrKey) { throw new ApplicationException(); }	//この文字のキーもフォールバック用のキーも取得出来なければエラー停止する。ここでエラー停止した場合は恐らく呼び出し側のバグでこのスプライトフォントに登録されていない文字を含む文字列を描画しようとしており,かつ,このスプライトフォントにフォールバック用の描画設定も設定されていない事が原因です。
			}
			//この文字の(又はフォールバック用の)描画設定を取得する。
			pInfo.SprNo = REG_get_value(pChrKey, SprFnt_SprNo);			//この文字のキーから、0(blank),又は,スプライト番号(1～0xFFFF)を取得する。
			if(pInfo.SprNo == -1) { throw new ApplicationException(); }		//この文字のキーから、0(blank),又は,スプライト番号(1～0xFFFF)が取得出来なければエラー停止する。dSprFntC.exeはどの文字のキーにも少なくともSprNoの値を出力しているはずである。
			pInfo.NextX = SprFnt_GetInfo_subr(pSprFnt, pChrKey, SprFnt_NextX);	//列ストライド,又は,デフォルト値,又は,0を取得する。
			pInfo.NextY = SprFnt_GetInfo_subr(pSprFnt, pChrKey, SprFnt_NextY);	//行ストライド,又は,デフォルト値,又は,0を取得する。
			pInfo.DrawX = SprFnt_GetInfo_subr(pSprFnt, pChrKey, SprFnt_DrawX);	//描画オフセットX,又は,デフォルト値,又は,0を取得する。
			pInfo.DrawY = SprFnt_GetInfo_subr(pSprFnt, pChrKey, SprFnt_DrawY);	//描画オフセットY,又は,デフォルト値,又は,0を取得する。
		}
		//-----------------------------------------------------------------------------
//{{2017/04/19移動:SprFnt_GetSize()をローカル関数⇒グローバル関数に変更しました。
//		//文字列のサイズを取得する。
//		private static void SprFnt_GetSize(VoidPtr pSprFnt, string s, out int p_size_x, out int p_size_y) {
//			//アルゴリズムは概ねclippce.cのrender_string()と同じです。
//			int x = 0, y = 0, size_x = 0, size_y = 0;
//			int h = 0;
////{{2017/03/20変更:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
////			foreach(int c in s) {
////↓2017/03/20変更:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//			foreach(int _c in s) {	//【NOTE】「foreach(int c in s) { c = UnicodeToShiftJisChr(c); ～」とすると「CS1656 'c'は'foreach繰り返し変数'であるため、これに割り当てることはできません。」というエラーになるので、一時変数'_c'を経由するようにしました。
//				int c = UnicodeToShiftJisChr(_c);
////}}2017/03/20変更:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//				if(c == '\n') {
//					x = 0;
//					y += h;
//					h = 0;
//				} else {
//					ST_SprFnt_Info stInfo;
//					//この文字の描画設定を取得する。
//					SprFnt_GetInfo(pSprFnt, c, out stInfo);
//					//列ストライドの分、次の描画位置を右へ進める。
//					x += stInfo.NextX;
//					//現在の行に描いた文字の、行ストライドの最大値を更新する。
//					if(stInfo.NextY > h) { h = stInfo.NextY; }
//					//サイズを更新する。
//					if(x > size_x) { size_x = x; }
//					if((y + h) > size_y) { size_y = (y + h); }
//				}
//			}
//			p_size_x = size_x;
//			p_size_y = size_y;
//		}
//}}2017/04/19移動:SprFnt_GetSize()をローカル関数⇒グローバル関数に変更しました。
		//-----------------------------------------------------------------------------
		//SprFnt_Print()の描画処理の本体です。
//{{2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
//		private static void SprFnt_Print_subr(VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,int/*color*/,int/*iSprNo*/> fn, object user_data, double x, double y, double scale_x, double scale_y, int color, string s) {
//			double x0 = x;
//			int h = 0;
////{{2017/03/20変更:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
////			foreach(int c in s) {
////↓2017/03/20変更:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//			foreach(int _c in s) {	//【NOTE】「foreach(int c in s) { c = UnicodeToShiftJisChr(c); ～」とすると「CS1656 'c'は'foreach繰り返し変数'であるため、これに割り当てることはできません。」というエラーになるので、一時変数'_c'を経由するようにしました。
//				int c = UnicodeToShiftJisChr(_c);
////}}2017/03/20変更:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//				if(c == '\n') {
//					x = x0;
//					y += h * scale_y;
//					h = 0;
//				} else {
//					ST_SprFnt_Info stInfo;
//					//この文字の描画設定を取得する。
//					SprFnt_GetInfo(pSprFnt, c, out stInfo);
//					//この文字のスプライトがblankでなければ…
//					if(stInfo.SprNo != 0/*blank*/) {
//						//スプライトを描画する。
//						fn.Invoke(user_data, (int)(x + (stInfo.DrawX * scale_x)), (int)(y + (stInfo.DrawY * scale_y)), scale_x, scale_y, color, stInfo.SprNo);
//					}
//					//列ストライドの分、次の描画位置を右へ進める。
//					x += stInfo.NextX * scale_x;
//					//現在の行に描いた文字の、行ストライドの最大値を更新する。
//					if(stInfo.NextY > h) { h = stInfo.NextY; }	//scale_yを掛ける処理は改行時に行うのでここでは行わない。
//				}
//			}
//		}
//↓2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		private static void SprFnt_Print_subr(VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,double/*rot*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x0, int y0, double scale_x, double scale_y, double rot, double cx, double cy, int color, string s) {
			int h = 0, x = 0, y = 0;
			//変換行列を作成する。
			double dCos = Math.Cos(rot), dSin = Math.Sin(rot);
			double a00 = dCos * scale_x, a01 = -dSin * scale_y, a02 = x0 - (a00 * cx) - (a01 * cy);
			double a10 = dSin * scale_x, a11 =  dCos * scale_y, a12 = y0 - (a10 * cx) - (a11 * cy);
			foreach(int _c in s) {	//【NOTE】「foreach(int c in s) { c = UnicodeToShiftJisChr(c); ～」とすると「CS1656 'c'は'foreach繰り返し変数'であるため、これに割り当てることはできません。」というエラーになるので、一時変数'_c'を経由するようにしました。
				int c = UnicodeToShiftJisChr(_c);
				if(c == '\n') {
					x = 0;
					y += h;
					h = 0;
				} else {
					ST_SprFnt_Info stInfo;
					//この文字の描画設定を取得する。
					SprFnt_GetInfo(pSprFnt, c, out stInfo);
					//この文字のスプライトがblankでなければ…
					if(stInfo.SprNo != 0/*blank*/) {
						//スプライトを描画する。
						double dx = x + stInfo.DrawX, dy = y + stInfo.DrawY;
						double ex = (dx * a00) + (dy * a01) + a02;
						double ey = (dx * a10) + (dy * a11) + a12;
						fn.Invoke(user_data, (int)ex, (int)ey, scale_x, scale_y, rot, color, stInfo.SprNo);
					}
					//列ストライドの分、次の描画位置を右へ進める。
					x += stInfo.NextX;
					//現在の行に描いた文字の、行ストライドの最大値を更新する。
					if(stInfo.NextY > h) { h = stInfo.NextY; }	//scale_yを掛ける処理は改行時に行うのでここでは行わない。
				}
			}
		}
//}}2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		//-----------------------------------------------------------------------------
		//SprFnt_PrintXF()の描画処理の本体です。
//{{2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
//		private static void SprFnt_PrintXF_subr(VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,int/*color*/,int/*iSprNo*/> fn, object user_data, double x1, double y1, double x2, double y2, double scale_x, double scale_y, int color, StringPtr s1, StringPtr s2, double transition/*0.0～1.0*/) {
//			double x10 = x1, x20 = x2, t1 = (1.0 - transition), t2 = transition;
//			int color1 = RGBA_MAKE(RGBA_GETRED(color), RGBA_GETGREEN(color), RGBA_GETBLUE(color), (int)(RGBA_GETALPHA(color) * t1));
//			int color2 = RGBA_MAKE(RGBA_GETRED(color), RGBA_GETGREEN(color), RGBA_GETBLUE(color), (int)(RGBA_GETALPHA(color) * t2));
//			int c1, c2, h1 = 0, h2 = 0;
//			for(;;) {
//				ST_SprFnt_Info stInfo1 = default(ST_SprFnt_Info)/*エラー抑制*/, stInfo2 = default(ST_SprFnt_Info)/*エラー抑制*/;
//				//文字列1について…
//				for(;;) {
//					//文字1を取得する。
//					if((c1 = s1[0]) == '\0') { break; }	//文字列1が終端ならばループを抜ける。
//					s1++;
////{{2017/03/20追加:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//					c1 = UnicodeToShiftJisChr(c1);
////}}2017/03/20追加:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//					//文字1が改行文字でなければ…
//					if(c1 != '\n') {
//						//文字1の描画設定を取得する。
//						SprFnt_GetInfo(pSprFnt, c1, out stInfo1);
//						break;	//ループを抜ける。
//					}
//					//文字1が改行文字ならば…
//					x1 = x10;
//					y1 += h1 * scale_y;
//					h1 = 0;
//				}
//				//文字列2について…
//				for(;;) {
//					//文字2を取得する。
//					if((c2 = s2[0]) == '\0') { break; }	//文字列2が終端ならばループを抜ける。
//					s2++;
////{{2017/03/20追加:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//					c2 = UnicodeToShiftJisChr(c2);
////}}2017/03/20追加:SprFnt_GetSize(),SprFnt_Print_subr(),SprFnt_PrintXF_subr()において、文字コードをUnicode⇒ShiftJisに変換するのを忘れていたのを修正しました。
//					//文字2が改行文字でなければ…
//					if(c2 != '\n') {
//						//文字2の描画設定を取得する。
//						SprFnt_GetInfo(pSprFnt, c2, out stInfo2);
//						break;	//ループを抜ける。
//					}
//					//文字2が改行文字ならば…
//					x2 = x20;
//					y2 += h2 * scale_y;
//					h2 = 0;
//				}
//				//文字列1も文字列2も終端ならば、終了する。
//				if((c1 == '\0') && (c2 == '\0')) { break; }	//ここまで
//				//文字列1が終端でなく,かつ,文字1のスプライトがblankでなければ…
//				if((c1 != '\0') && (stInfo1.SprNo != 0/*blank*/)) {
//					//文字列2が終端でなく,かつ,文字2のスプライトがblankでなければ…
//					if((c2 != '\0') && (stInfo2.SprNo != 0/*blank*/)) {
////{{2017/03/20変更:SprFnt_PrintXF_subr()において、補間処理の演算誤差で位置がぶれる問題を修正しました。
////						double x = (x1 * t1) + (x2 * t2);
////						double y = (y1 * t1) + (y2 * t2);
////↓2017/03/20変更:SprFnt_PrintXF_subr()において、補間処理の演算誤差で位置がぶれる問題を修正しました。
//						double x = (x1 == x2) ? x1 : ((x1 * t1) + (x2 * t2));
//						double y = (y1 == y2) ? y1 : ((y1 * t1) + (y2 * t2));
////}}2017/03/20変更:SprFnt_PrintXF_subr()において、補間処理の演算誤差で位置がぶれる問題を修正しました。
//						//文字1と文字2のスプライト番号が同じならば…
//						if(stInfo1.SprNo == stInfo2.SprNo) {
//							//文字1(文字2でも同じ)を、補間した位置に描く。
//							fn.Invoke(user_data, (int)(x  + (stInfo1.DrawX * scale_x)), (int)(y  + (stInfo1.DrawY * scale_y)), scale_x, scale_y, color , stInfo1.SprNo);
//						//文字1と文字2のスプライト番号が同じでなければ…
//						} else {
//							//文字1と文字2を、補間した位置に、クロスフェードして描く。
//							fn.Invoke(user_data, (int)(x  + (stInfo1.DrawX * scale_x)), (int)(y  + (stInfo1.DrawY * scale_y)), scale_x, scale_y, color1, stInfo1.SprNo);
//							fn.Invoke(user_data, (int)(x  + (stInfo2.DrawX * scale_x)), (int)(y  + (stInfo2.DrawY * scale_y)), scale_x, scale_y, color2, stInfo2.SprNo);
//						}
//					//文字列2が終端か,又は,文字2のスプライトがblankならば…
//					} else {
//							//文字1を、文字1の位置に、フェードアウトして描く。
//							fn.Invoke(user_data, (int)(x1 + (stInfo1.DrawX * scale_x)), (int)(y1 + (stInfo1.DrawY * scale_y)), scale_x, scale_y, color1, stInfo1.SprNo);
//					}
//				//文字列1が終端か,又は,文字1のスプライトがblankならば…
//				} else {
//					//文字列2が終端でなく,かつ,文字2のスプライトがblankでなければ…
//					if((c2 != '\0') && (stInfo2.SprNo != 0/*blank*/)) {
//							//文字2を、文字2の位置に、フェードインして描く。
//							fn.Invoke(user_data, (int)(x2 + (stInfo2.DrawX * scale_x)), (int)(y2 + (stInfo2.DrawY * scale_y)), scale_x, scale_y, color2, stInfo2.SprNo);
//					//文字列2が終端か,又は,文字2のスプライトがblankならば…
//					} else {
//							/** no job **/
//					}
//				}
//				//文字列1が終端でなければ…
//				if(c1 != '\0') {
//					//列ストライドの分、次の描画位置を右へ進める。
//					x1 += stInfo1.NextX * scale_x;
//					//現在の行に描いた文字の、行ストライドの最大値を更新する。
//					if(stInfo1.NextY > h1) { h1 = stInfo1.NextY; }	//scale_yを掛ける処理は改行時に行うのでここでは行わない。
//				}
//				//文字列2が終端でなければ…
//				if(c2 != '\0') {
//					//列ストライドの分、次の描画位置を右へ進める。
//					x2 += stInfo2.NextX * scale_x;
//					//現在の行に描いた文字の、行ストライドの最大値を更新する。
//					if(stInfo2.NextY > h2) { h2 = stInfo2.NextY; }	//scale_yを掛ける処理は改行時に行うのでここでは行わない。
//				}
//			}
//		}
//↓2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		private static void SprFnt_PrintXF_subr(VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,double/*rot*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x0, int y0, double scale_x, double scale_y, double rot, double cx1, double cy1, double cx2, double cy2, int color, StringPtr s1, StringPtr s2, double transition/*0.0～1.0*/) {
			double t1 = (1.0 - transition), t2 = transition;
			int color1 = RGBA_MAKE(RGBA_GETRED(color), RGBA_GETGREEN(color), RGBA_GETBLUE(color), (int)(RGBA_GETALPHA(color) * t1));
			int color2 = RGBA_MAKE(RGBA_GETRED(color), RGBA_GETGREEN(color), RGBA_GETBLUE(color), (int)(RGBA_GETALPHA(color) * t2));
			int c1, c2, h1 = 0, x1 = 0, y1 = 0, h2 = 0, x2 = 0, y2 = 0;
			//変換行列を作成する。
			double dCos = Math.Cos(rot), dSin = Math.Sin(rot);
			double cx = (cx1 == cx2) ? cx1 : ((cx1 * t1) + (cx2 * t2));
			double cy = (cy1 == cy2) ? cy1 : ((cy1 * t1) + (cy2 * t2));
			double a00 = dCos * scale_x, a01 = -dSin * scale_y, a02 = x0 - (a00 * cx) - (a01 * cy);
			double a10 = dSin * scale_x, a11 =  dCos * scale_y, a12 = y0 - (a10 * cx) - (a11 * cy);
			for(;;) {
				ST_SprFnt_Info stInfo1 = default(ST_SprFnt_Info)/*エラー抑制*/, stInfo2 = default(ST_SprFnt_Info)/*エラー抑制*/;
				double dx, dy, ex, ey;
				//文字列1について…
				for(;;) {
					//文字1を取得する。
					if((c1 = s1[0]) == '\0') { break; }	//文字列1が終端ならばループを抜ける。
					s1++;
					c1 = UnicodeToShiftJisChr(c1);
					//文字1が改行文字でなければ…
					if(c1 != '\n') {
						//文字1の描画設定を取得する。
						SprFnt_GetInfo(pSprFnt, c1, out stInfo1);
						break;	//ループを抜ける。
					}
					//文字1が改行文字ならば…
					x1 = 0;
					y1 += h1;
					h1 = 0;
				}
				//文字列2について…
				for(;;) {
					//文字2を取得する。
					if((c2 = s2[0]) == '\0') { break; }	//文字列2が終端ならばループを抜ける。
					s2++;
					c2 = UnicodeToShiftJisChr(c2);
					//文字2が改行文字でなければ…
					if(c2 != '\n') {
						//文字2の描画設定を取得する。
						SprFnt_GetInfo(pSprFnt, c2, out stInfo2);
						break;	//ループを抜ける。
					}
					//文字2が改行文字ならば…
					x2 = 0;
					y2 += h2;
					h2 = 0;
				}
				//文字列1も文字列2も終端ならば、終了する。
				if((c1 == '\0') && (c2 == '\0')) { break; }	//ここまで
				//文字列1が終端でなく,かつ,文字1のスプライトがblankでなければ…
				if((c1 != '\0') && (stInfo1.SprNo != 0/*blank*/)) {
					//文字列2が終端でなく,かつ,文字2のスプライトがblankでなければ…
					if((c2 != '\0') && (stInfo2.SprNo != 0/*blank*/)) {
						double x = (x1 == x2) ? x1 : ((x1 * t1) + (x2 * t2));
						double y = (y1 == y2) ? y1 : ((y1 * t1) + (y2 * t2));
						//文字1と文字2のスプライト番号が同じならば…
						if(stInfo1.SprNo == stInfo2.SprNo) {
							//文字1(文字2でも同じ)を、補間した位置に描く。
							dx = x  + stInfo1.DrawX; dy = y  + stInfo1.DrawY;
							ex = (dx * a00) + (dy * a01) + a02;
							ey = (dx * a10) + (dy * a11) + a12;
							fn.Invoke(user_data, (int)ex, (int)ey, scale_x, scale_y, rot, color , stInfo1.SprNo);
						//文字1と文字2のスプライト番号が同じでなければ…
						} else {
							//文字1と文字2を、補間した位置に、クロスフェードして描く。
							dx = x  + stInfo1.DrawX; dy = y  + stInfo1.DrawY;
							ex = (dx * a00) + (dy * a01) + a02;
							ey = (dx * a10) + (dy * a11) + a12;
							fn.Invoke(user_data, (int)ex, (int)ey, scale_x, scale_y, rot, color1, stInfo1.SprNo);
							dx = x  + stInfo2.DrawX; dy = y  + stInfo2.DrawY;
							ex = (dx * a00) + (dy * a01) + a02;
							ey = (dx * a10) + (dy * a11) + a12;
							fn.Invoke(user_data, (int)ex, (int)ey, scale_x, scale_y, rot, color2, stInfo2.SprNo);
						}
					//文字列2が終端か,又は,文字2のスプライトがblankならば…
					} else {
							//文字1を、文字1の位置に、フェードアウトして描く。
							dx = x1 + stInfo1.DrawX; dy = y1 + stInfo1.DrawY;
							ex = (dx * a00) + (dy * a01) + a02;
							ey = (dx * a10) + (dy * a11) + a12;
							fn.Invoke(user_data, (int)ex, (int)ey, scale_x, scale_y, rot, color1, stInfo1.SprNo);
					}
				//文字列1が終端か,又は,文字1のスプライトがblankならば…
				} else {
					//文字列2が終端でなく,かつ,文字2のスプライトがblankでなければ…
					if((c2 != '\0') && (stInfo2.SprNo != 0/*blank*/)) {
							//文字2を、文字2の位置に、フェードインして描く。
							dx = x2 + stInfo2.DrawX; dy = y2 + stInfo2.DrawY;
							ex = (dx * a00) + (dy * a01) + a02;
							ey = (dx * a10) + (dy * a11) + a12;
							fn.Invoke(user_data, (int)ex, (int)ey, scale_x, scale_y, rot, color2, stInfo2.SprNo);
					//文字列2が終端か,又は,文字2のスプライトがblankならば…
					} else {
							/** no job **/
					}
				}
				//文字列1が終端でなければ…
				if(c1 != '\0') {
					//列ストライドの分、次の描画位置を右へ進める。
					x1 += stInfo1.NextX;
					//現在の行に描いた文字の、行ストライドの最大値を更新する。
					if(stInfo1.NextY > h1) { h1 = stInfo1.NextY; }	//scale_yを掛ける処理は改行時に行うのでここでは行わない。
				}
				//文字列2が終端でなければ…
				if(c2 != '\0') {
					//列ストライドの分、次の描画位置を右へ進める。
					x2 += stInfo2.NextX;
					//現在の行に描いた文字の、行ストライドの最大値を更新する。
					if(stInfo2.NextY > h2) { h2 = stInfo2.NextY; }	//scale_yを掛ける処理は改行時に行うのでここでは行わない。
				}
			}
		}
//}}2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		//*****************************************************************************
		//	グローバル関数
		//*****************************************************************************
		//【NOTE】
		// * Sun Mar 19 22:19:43 JST 2017 Naoyuki Sawa
		// - Unityで使用する場合は、素材のピクセルとUnityの座標のスケーリングが異なる事,及び,UnityのY軸は上下逆である事を考慮して下さい。
		//   具体的には、当モジュールの関数を呼び出す前に、アプリケーション側で:
		//   │x *=  pixelsPerUnit
		//   │y *= -pixelsPerUnit
		//   としてから当モジュールの関数を呼び出し、当モジュールの関数から呼び出されたコールバック関数の中で:
		//   │x /=  pixelsPerUnit
		//   │y /= -pixelsPerUnit
		//   としてから描画を実行すると、上手く行くと思います。(※未検証)
		//-----------------------------------------------------------------------------
		//スプライトフォントを使用して、文字列を描画する。
//{{2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
//		public static void SprFnt_Print(  VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x, int y, double scale_x, double scale_y, double ax, double ay, int color, string s) {
//			int size_x, size_y;
//			SprFnt_GetSize(pSprFnt, s, out size_x, out size_y);
//			x -= (int)(size_x * scale_x * ax);
//			y -= (int)(size_y * scale_y * ay);
//			SprFnt_Print_subr(pSprFnt, fn, user_data, x, y, scale_x, scale_y, color, s);
//		}
//↓2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		public static void SprFnt_Print(  VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,double/*rot*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x, int y, double scale_x, double scale_y, double rot, double ax, double ay, int color, string s) {
			int size_x, size_y;
			double cx, cy;
			//文字列のサイズを求める。
			SprFnt_GetSize(pSprFnt, s, out size_x, out size_y);
			//文字列のピボットを求める。
			cx = size_x * ax;
			cy = size_y * ay;
			//文字列を描画する。
			SprFnt_Print_subr(pSprFnt, fn, user_data, x, y, scale_x, scale_y, rot, cx, cy, color, s);
		}
//}}2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		//-----------------------------------------------------------------------------
		//スプライトフォントを使用して、書式付き文字列を描画する。
//{{2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
//		public static void SprFnt_PrintF( VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x, int y, double scale_x, double scale_y, double ax, double ay, int color, string fmt, params object[] ap) {
//			SprFnt_Print(pSprFnt, fn, user_data, x, y, scale_x, scale_y, ax, ay, color, string.Format(fmt, ap));
//		}
//↓2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		public static void SprFnt_PrintF( VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,double/*rot*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x, int y, double scale_x, double scale_y, double rot, double ax, double ay, int color, string fmt, params object[] ap) {
			SprFnt_Print(pSprFnt, fn, user_data, x, y, scale_x, scale_y, rot, ax, ay, color, string.Format(fmt, ap));
		}
//}}2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		//-----------------------------------------------------------------------------
		//文字列s1とs2を、混合率(1.0-transition):transitionで、各文字の位置を補間しながら、クロスフェードして描く。
//{{2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
//		public static void SprFnt_PrintXF(VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x, int y, double scale_x, double scale_y, double ax, double ay, int color, string s1, string s2, double transition/*0.0～1.0*/) {
//			int size_x, size_y, x1, y1, x2, y2;
//			//文字列1の描画位置を求める。
//			SprFnt_GetSize(pSprFnt, s1, out size_x, out size_y);
//			x1 = x - (int)(size_x * scale_x * ax);
//			y1 = y - (int)(size_y * scale_y * ay);
//			//文字列2の描画位置を求める。
//			SprFnt_GetSize(pSprFnt, s2, out size_x, out size_y);
//			x2 = x - (int)(size_x * scale_x * ax);
//			y2 = y - (int)(size_y * scale_y * ay);
//			//文字列1と文字列2をクロスフェードして描く。
//			SprFnt_PrintXF_subr(pSprFnt, fn, user_data, x1, y1, x2, y2, scale_x, scale_y, color, s1, s2, transition);
//		}
//↓2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		public static void SprFnt_PrintXF(VoidPtr pSprFnt, Action<object/*user_data*/,int/*x*/,int/*y*/,double/*scale_x*/,double/*scale_y*/,double/*rot*/,int/*color*/,int/*iSprNo*/> fn, object user_data, int x, int y, double scale_x, double scale_y, double rot, double ax, double ay, int color, string s1, string s2, double transition/*0.0～1.0*/) {
			int size_x1, size_y1, size_x2, size_y2;
			double cx1, cy1, cx2, cy2;
			//文字列1のサイズを求める。
			SprFnt_GetSize(pSprFnt, s1, out size_x1, out size_y1);
			//文字列2のサイズを求める。
			SprFnt_GetSize(pSprFnt, s2, out size_x2, out size_y2);
			//片方のサイズが空ならば、もう一方のサイズに合わせる。(両方とも空ならば空のままで構いません。)
			// - 片方の文字列が空文字列だった場合に、もう片方の文字列だけをフェードインして描くためです。
			if((size_x1 | size_y1) == 0) { size_x1 = size_x2; size_y1 = size_y2; }
			if((size_x2 | size_y2) == 0) { size_x2 = size_x1; size_y2 = size_y1; }
			//文字列1のピボットを求める。
			cx1 = size_x1 * ax;
			cy1 = size_y1 * ay;
			//文字列2のピボットを求める。
			cx2 = size_x2 * ax;
			cy2 = size_y2 * ay;
			//文字列1と文字列2をクロスフェードして描く。
			SprFnt_PrintXF_subr(pSprFnt, fn, user_data, x, y, scale_x, scale_y, rot, cx1, cy1, cx2, cy2, color, s1, s2, transition);
		}
//}}2017/04/04変更:スプライトフォント描画に回転機能を追加しました。
		//-----------------------------------------------------------------------------
//{{2017/04/19移動:SprFnt_GetSize()をローカル関数⇒グローバル関数に変更しました。
		//文字列のサイズを取得する。
		public static void SprFnt_GetSize(VoidPtr pSprFnt, string s, out int p_size_x, out int p_size_y) {
			//アルゴリズムは概ねclippce.cのrender_string()と同じです。
			int x = 0, y = 0, size_x = 0, size_y = 0;
			int h = 0;
			foreach(int _c in s) {	//【NOTE】「foreach(int c in s) { c = UnicodeToShiftJisChr(c); ～」とすると「CS1656 'c'は'foreach繰り返し変数'であるため、これに割り当てることはできません。」というエラーになるので、一時変数'_c'を経由するようにしました。
				int c = UnicodeToShiftJisChr(_c);
				if(c == '\n') {
					x = 0;
					y += h;
					h = 0;
				} else {
					ST_SprFnt_Info stInfo;
					//この文字の描画設定を取得する。
					SprFnt_GetInfo(pSprFnt, c, out stInfo);
					//列ストライドの分、次の描画位置を右へ進める。
					x += stInfo.NextX;
					//現在の行に描いた文字の、行ストライドの最大値を更新する。
					if(stInfo.NextY > h) { h = stInfo.NextY; }
					//サイズを更新する。
					if(x > size_x) { size_x = x; }
					if((y + h) > size_y) { size_y = (y + h); }
				}
			}
			p_size_x = size_x;
			p_size_y = size_y;
		}
//}}2017/04/19移動:SprFnt_GetSize()をローカル関数⇒グローバル関数に変更しました。
	}
}
