/*	
 *	framfont.c
 *
 *	高速RAMに転送するモジュール
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Tue Nov 19 12:30:00 JST 2002 Naoyuki Sawa
 *	- 旧clipdobj.cとclipmod.cから、コピー・修正して新規作成しました。
 *	* Sun Dec 8 05:43:00 JST 2002 Naoyuki Sawa
 *	- mod_mix()のループ音バグを修正。
 *	- テンポエフェクト対応。
 *	* Fri Jan 31 21:57:00 JST 2003 Naoyuki Sawa
 *	- new_LCDDrawObject()のPIXEL(p,m)マクロのmask判定部分を改良。
 *	 「(mask >> (m) & 1)」→「(mask & (1 << (m)))」に変更しました。
 *	  約3%高速化(全画面転送時)、コードサイズは20バイト少なくなりました。
 *	  この改良は「ryukの薫製工房」さん(http://www.interq.or.jp/earth/ryuk/)によるものです。
 *	- new_LCDDrawObject()のクリッピング時画面外判定処理を改良。
 *	  これまで、反転なし/ありそれぞれの処理の中で行っていたものを、共通化してまとめました。
 *	  コードサイズが4バイト少なくなりました。
 *	- 以上の変更を行った結果、現時点のコードサイズは0xfe0(4064)バイトです。
 *	* Sat Feb 1 14:08:00 JST 2003 Naoyuki Sawa
 *	- new_LCDDrawObject()にて、残りライン数の取得「y = obj.dh」を共通化、容量節約しました。
 *	- MODドライバを可変チャネル数に対応しました。
 *	* Tue Apr 1 19:00:00 JST 2003 Naoyuki Sawa
 *	- clipfram.cを分割し、このファイルを新設しました。
 *	* Wed Sep 19 16:48:08 JST 2007 Naoyuki Sawa
 *	- 高速化しました。
 *	  これまで使っていた上のコードは、実装を簡単にするために、要クリッピング時にrender_point()を利用していました。
 *	  しかし、render_point()を呼ばない方が高速で、また、レジスタ保存が少ない分コードも減らせることがわかりました。
 *	  そこで、render_point()を呼ばない方法で再実装し、高速化とコードサイズの削減を行いました。
 *	  クリッピング不要時は10%程度高速化、要クリッピング時は3倍近い高速化の効果が得られました。
 *	- ASM版を実装したので、これまで本モジュールに対して適用していた、sedによるmlt.w→mlt.h変換が不要になりました。
 *	  従って、Makefileのframfont.o生成規則を修正しました。
 *	* Tue May 26 21:15:26 JST 2015 Naoyuki Sawa
 *	- clippce.cモジュールに4x5ピクセルフォントを追加した事に伴い、render_font()関数にて無効なフォントタイプの検査を変更しました。
 *	  詳細は、clippce.cモジュールの同日(2015/05/26)のコメントを参照してください。
 *	* Tue Nov 22 23:55:39 JST 2016 Naoyuki Sawa
 *	- render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
 *	  変更した理由は、以下の通りです。
 *	- これまでは、完全に画面外のケースも、一部が画面外のケースと同じ扱いとして、1ピクセルづつ判定していました。
 *	  そうしていた理由は、完全に画面外の文字描画が指定されるケースは少ないと思っていたからです。
 *	  以前は実際にそうだったのですが、2016/07/15にclippce.cに「null_render」を追加した事で、必ずしもそうとは限らなくなりました。
 *	  文字列の描画サイズを取得するためにヌルレンダラーへのダミー描画を行う場合、全ての文字が完全に画面外への描画となるからです。
 *	  そこで、完全に画面外の場合も高速化する利点が有ると考えて、今回の変更を行う事にしました。
 *	- 文字列の描画サイズを取得するためにヌルレンダラーへのダミー描画を頻繁に行う例としては、nuklear/nuklear_piece.cのnk_piecefont_get_text_width()が挙げられます。
 *	  実際に、Nuklearでテキストの折り返し表示を行うと、P/ECEでは非常に遅くなり、上記の関数の処理が遅かったことが主な原因でした。
 *	  今回の高速化によって、上記の処理が早くなる事を期待したのですが、試したところ、残念ながら体感ではあまり違いがわかりませんでした。
 *	  とはいえ、いくらか高速化されている事は確かなので、今回の変更を採用しておく事にしました。
 *	  簡単にテストしたところ、ヌルレンダラーへのダミー描画だけを行うケース(=理想的なケース)では、約30%程度高速化の効果が得られました。
 *	- デメリットとしては、画面内,及び,一部が画面内のテキスト描画を行う場合は、今回追加した高速化のための判定処理は、速度低下とコードサイズの増大にしかなりません。
 *	  画面内,及び,一部が画面内のテキスト描画の方が多い事を考えると、今回の高速化はデメリットの方が大きい可能性もあるのですが、致命的というほどではないはずなので、今回の変更を採用しておく事にしました。
 *	- 今回の変更にあわせて、これまでは当モジュール内のアセンブラコードの、タブやコメントの書き方が、昔の書き方をしていたので、最近の書き方にあわせて整形しました。
 *	  そのため、大幅に変わっているように見えますが、内容は変えていません。
 *	  今回変えたのは、あくまでも、前述の高速化のためのコードを追加した点のみです。
 *	* Wed Nov 23 10:01:18 JST 2016 Naoyuki Sawa
 *	- render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
 *	  前回(2016/11/22)の変更によって、framfont.oのコードサイズが、352バイト⇒384バイトに、32バイト増加していたのですが、
 *	  今回(2016/11/23)の変更によって、framfont.oのコードサイズが、384バイト⇒368バイトに、16バイト減少しました。
 *	  結果として、前回(2016/11/22)の変更を行う前と、今回(2016/11/23)の変更を行った後では、16バイト増加に抑えられました。
 *	* Sat Feb 04 23:11:25 JST 2017 Naoyuki Sawa
 *	- clippce.cモジュールに4x4ピクセルフォントを追加した事に伴い、render_font()関数にて無効なフォントタイプの検査を変更しました。
 *	  詳細は、clippce.cモジュールの同日(2017/02/04)のコメントを参照してください。
 */
#include "clip.h"

/****************************************************************************
 *	ユーティリティ：フォント
 ****************************************************************************/

#if 0 /* 2007/09/19まで安定して動作していたコードなので、コメントアウトして保存しておくことにします。 */
///* シンプルライブラリのput_1char()内部関数(\usr\PIECE\lib\src\simple\symbol.c)を参考にしました。
// * また、pceFontPut()関数(\usr\PIECE\sysdev\pcekn\font.c)に倣って、ビューポート内/外による場合分けを行いました。
// * フォント描画領域が完全にビューポート内なら、クリッピングを省略し、二倍程度高速に描画できます。
// */
//unsigned short
//render_font(RENDER* render, int x, int y, unsigned short code, int type, int color)
//{
//	SURFACE* surface;
//	unsigned char* vptr;
//	const unsigned char* p;
//	int ofs, w, h, x_min, y_min, x_max, y_max, c;
//
//	/* フォントサイズを求めます。 */
//	type &= 0x7f; /* bit7(改行指示)は無視 */
//	if(type < 0 || 2 < type) /*DIE()*/return 0; /* 無効なフォントタイプ、容量削減のためDIE()しません */
//	w = render_font_size[type][0];
//	h = render_font_size[type][1];
//
//	 /* 半角空白は頻繁に指定されると思うので、描画を省略して高速化します。
//	  * w,hは戻り値に使うので、w,hを取得する前にスキップしないよう注意！
//	  */
//	if(code == ' ') goto SKIP;
//
//	/* フォントアドレスを求めます。 */
//	pceFontSetType(type);
//	p = pceFontGetAdrs(code);
//
//	/* 半角フォント描画… */
//	if((int)p & (1 << 31)) {
//		p = (unsigned char*)((int)p & ~(1 << 31)); /* 半角ビットを下ろす */
//		/* 描画範囲を求めます。 */
//		x_min = x;
//		y_min = y;
//		x_max = x + w;
//		y_max = y + h;
//		/* 完全にビューポート内なら、クリッピング不要です。 */
//		if(render->left <= x_min && x_max <= render->right &&
//		   render->top  <= y_min && y_max <= render->bottom) {
//			surface = render->surface;
//			ofs = surface->w * y + x;
//			vptr = surface->vbuff + ofs;
//			for(y = y_min; y < y_max; y++) {
//				c = *p++;
//				for(x = x_min; x < x_max; x++) {
//					if(c & 0x80) *vptr = color;
//					vptr++;
//					c <<= 1;
//				}
//				vptr += surface->w - w; /* 次の行へ */
//			}
//		/* ビューポートをはみ出していたら、要クリッピング。 */
//		} else {
//			for(y = y_min; y < y_max; y++) {
//				c = *p++;
//				for(x = x_min; x < x_max; x++) {
//					if(c & 0x80) render_point(render, x, y, color);
//					c <<= 1;
//				}
//			}
//		}
//	/* 全角フォント描画… */
//	} else {
//		w *= 2; /* 全角なので二文字分の幅。戻り値に使うのでwを変更する必要あり */
//		/* 描画範囲を求めます。 */
//		x_min = x;
//		y_min = y;
//		x_max = x + w;
//		y_max = y + h;
//		/* 完全にビューポート内なら、クリッピング不要です。 */
//		if(render->left <= x_min && x_max <= render->right &&
//		   render->top  <= y_min && y_max <= render->bottom) {
//			surface = render->surface;
//			ofs = surface->w * y + x;
//			vptr = surface->vbuff + ofs;
//			for(y = y_min; y < y_max; y += 2) { /* 2ラインづつ描く */
//				c = p[0] << 16 | p[1] << 8 | p[2]; /* 3バイトで2ライン分 */
//				p += 3;
//				for(x = x_min; x < x_max; x++) {
//					if(c & 0x800000) *(vptr + 0         ) = color;
//					if(c &    0x800) *(vptr + surface->w) = color;
//					vptr++;
//					c <<= 1;
//				}
//				vptr += surface->w * 2 - w; /* 二行下へ */
//			}
//		/* ビューポートをはみ出していたら、要クリッピング。 */
//		} else {
//			for(y = y_min; y < y_max; y += 2) { /* 2ラインづつ描く */
//				c = p[0] << 16 | p[1] << 8 | p[2]; /* 3バイトで2ライン分 */
//				p += 3;
//				for(x = x_min; x < x_max; x++) {
//					if(c & 0x800000) render_point(render, x, y + 0, color);
//					if(c &    0x800) render_point(render, x, y + 1, color);
//					c <<= 1;
//				}
//			}
//		}
//	}
//SKIP:
//	return h << 8 | w;
//}
#endif
//↓* Wed Sep 19 16:48:08 JST 2007 Naoyuki Sawa
//↓- 高速化しました。
//↓  これまで使っていた上のコードは、実装を簡単にするために、要クリッピング時にrender_point()を利用していました。
//↓  しかし、render_point()を呼ばない方が高速で、また、レジスタ保存が少ない分コードも減らせることがわかりました。
//↓  そこで、render_point()を呼ばない方法で再実装し、高速化とコードサイズの削減を行いました。
//↓  クリッピング不要時は10%程度高速化、要クリッピング時は3倍近い高速化の効果が得られました。
#if 0 /* 2007/09/19作成のC言語版です。 */
unsigned short
render_font(RENDER* render, int x, int y, unsigned short code, int type, int color)
{
	int w;
	int h;
	int xlim;
	int ylim;
	int xmax;
	int ymax;
	int vadd;
	int c;
	SURFACE* surface;
	unsigned char* vptr;
	const unsigned char* p;

	/* フォントサイズを求めます。 */
	type &= 0x7F; /* bit7(改行指示)は無視。bit31-8も無視する仕様(pceFontSetType()に準拠) */
    //{{2015/05/26変更:4x5ピクセルフォントを追加しました。
    //	if(type > 2) /*DIE()*/return 0; /* 無効なフォントタイプ、容量削減のためDIE()しません */
    //↓2015/05/26変更:4x5ピクセルフォントを追加しました。
    //	if(type > 3) /*DIE()*/return 0; /* 無効なフォントタイプ、容量削減のためDIE()しません */
    //↓2017/02/04変更:4x4ピクセルフォントを追加しました。
	if(type > 4) /*DIE()*/return 0; /* 無効なフォントタイプ、容量削減のためDIE()しません */
    //}}2017/02/04変更:4x4ピクセルフォントを追加しました。
	w = render_font_size[type][0];
	h = render_font_size[type][1];

	 /* 半角空白は頻繁に指定されると思うので、描画を省略して高速化します。
	  * w,hは戻り値に使うので、w,hを取得する前にスキップしないよう注意！
	  */
	if(code != ' ') {
		/* フォントアドレスを求めます。 */
		pceFontSetType(type);
		p = pceFontGetAdrs(code);

		/* 描画開始アドレスを求めます。
		 * 画面外の場合もそのまま計算しておき、描画時に1ピクセルづつ判定します。	⇒{{2016/11/22コメント追記:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。}}
		 */
		surface = render->surface;
		vptr = surface->vbuff + surface->w * y + x;
		vadd = surface->w - w; /* 半角左へ戻って1行下へ */

		/* ループカウンタ範囲を求めます。 */
		x -= render->left;
		y -= render->top;
		xlim = render->right - render->left;
		ylim = render->bottom - render->top;
		xmax = x + w;
		ymax = y + h;

		/* 半角フォント描画… */
		if((int)p & (1<<31)) {
			p = (unsigned char*)((int)p & ~(1<<31)); /* 半角ビットを下ろす */

			/* 完全にビューポート内なら、クリッピング不要です。 */
			if((0 <= x) && (xmax <= xlim) &&
			   (0 <= y) && (ymax <= ylim)) {
				do {
					c = *p++;
					do {
						if(c & (1<<7)) {
							*vptr = color;
						}
						c <<= 1;
						vptr++;
					} while(++x < xmax);
					x -= w;
					vptr += vadd; /* 半角左へ戻って1行下へ */
				} while(++y < ymax);
			/* ビューポートをはみ出していたら、要クリッピング。 */
			} else {
//{{2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
				/* 完全にビューポート外ならば、描画処理を行わない。 */
				if((xmax <= 0) || (xlim <= x) ||
				   (ymax <= 0) || (ylim <= y)) { goto L_RET; }
				/* 完全にビューポート内でなければ、描画処理を行う。 */
//}}2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
				do {
					c = *p++;
					do {
						if(c & (1<<7)) {
							if(((unsigned)x < (unsigned)xlim)) {		/* ((0 <= x) && (x < xlim)) */
								if((unsigned)y < (unsigned)ylim) {	/* ((0 <= y) && (y < ylim)) */
									*vptr = color;
								}
							}
						}
						c <<= 1;
						vptr++;
					} while(++x < xmax);
					x -= w;
					vptr += vadd; /* 半角左へ戻って1行下へ */
				} while(++y < ymax);
			}
		/* 全角フォント描画… */
		} else {
			/* 全角なので二文字分の幅とします。 */
			xmax += w; /* xmax =              x + 半角w * 2 */
			w    *= 2; /* w    =                  半角w * 2 */
			vadd *= 2; /* vadd = surface->w * 2 - 半角w * 2 (全角左へ戻って2行下へ) */

			/* 完全にビューポート内なら、クリッピング不要です。 */
			if((0 <= x) && (xmax <= xlim) &&
			   (0 <= y) && (ymax <= ylim)) {
				do {
					c =          *p++;
					c = (c<<8) | *p++;
					c = (c<<8) | *p++;
					do {
						if(c & (1<<23)) {
							*(vptr + 0         ) = color;
						}
						if(c & (1<<11)) {
							*(vptr + surface->w) = color;
						}
						c <<= 1;
						vptr++;
					} while(++x < xmax);
					x -= w;
					vptr += vadd; /* 全角左へ戻って2行下へ */
				} while((y += 2) < ymax); /* 2ラインづつ描く */
			/* ビューポートをはみ出していたら、要クリッピング。 */
			} else {
//{{2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
				/* 完全にビューポート外ならば、描画処理を行わない。 */
				if((xmax <= 0) || (xlim <= x) ||
				   (ymax <= 0) || (ylim <= y)) { goto L_RET; }
				/* 完全にビューポート内でなければ、描画処理を行う。 */
//}}2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
				do {
					c =          *p++;
					c = (c<<8) | *p++;
					c = (c<<8) | *p++;
					do {
						if(((unsigned)x < (unsigned)xlim)) {			/* ((0 <= x) && (x < xlim)) */
							if(c & (1<<23)) {
								if((unsigned)y < (unsigned)ylim) {	/* ((0 <= y) && (y < ylim)) */
									*(vptr + 0         ) = color;
								}
							}
							if(c & (1<<11)) {
								y++; /* 忘れないで!! */
								if((unsigned)y < (unsigned)ylim) {	/* ((0 <= y) && (y < ylim)) */
									*(vptr + surface->w) = color;
								}
								y--; /* 忘れないで!! */
							}
						}
						c <<= 1;
						vptr++;
					} while(++x < xmax);
					x -= w;
					vptr += vadd; /* 全角左へ戻って2行下へ */
				} while((y += 2) < ymax); /* 2ラインづつ描く */
			}
		}
	}
//{{2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
L_RET:
//}}2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
	return (h<<8) | w;
}
#else /* 2007/09/19作成のASM版です。C言語版とほぼ同じアルゴリズムですが、一部ASM版特有の高速化を行いました。 */
asm("
		.code
		.align		1
		.global		render_font
render_font:
		pushn		%r3
		ld.w		%r0, %r12					;//%r0  := render
		ld.w		%r1, %r13					;//%r1  := x
		ld.w		%r2, %r14					;//%r2  := y
		ld.uh		%r3, %r15					;//%r3  := code
		;//%r0      := render
		;//%r1      := x
		;//%r2      := y
		;//%r3      := code
		;//[%sp+ 0] := %r0
		;//[%sp+ 4] := %r1
		;//[%sp+ 8] := %r2
		;//[%sp+12] := %r3
		;//[%sp+16] := retp
		;//[%sp+20] := type
		;//[%sp+24] := color
		xld.ub		%r12, [%sp+20]					;//%r12 := type     (00000000 00000000 00000000 ?ttttttt)
		add		%r12, %r12					;//%r12 := type * 2 (00000000 00000000 0000000? ttttttt0)
		ld.ub		%r12, %r12					;//%r12 := type * 2 (00000000 00000000 00000000 ttttttt0)
;//{{2015/05/26変更:4x5ピクセルフォントを追加しました。
;//		cmp		%r12, 4						;//if((type * 2) > (2 * 2)) { goto render_font_ERR }
;//↓2015/05/26変更:4x5ピクセルフォントを追加しました。
;//		cmp		%r12, 6						;//if((type * 2) > (3 * 2)) { goto render_font_ERR }
;//↓2017/02/04変更:4x4ピクセルフォントを追加しました。
		cmp		%r12, 8						;//if((type * 2) > (4 * 2)) { goto render_font_ERR }
;//}}2017/02/04変更:4x4ピクセルフォントを追加しました。
		xjrgt		render_font_ERR
		ext		render_font_size@ah
		ext		render_font_size@al
		ld.uh		%r10, [%r12]					;//%r10 := (h<<8)|w (00000000 00000000 hhhhhhhh wwwwwwww)
		;//%r0      := render
		;//%r1      := x
		;//%r2      := y
		;//%r3      := code
		;//%r10     := (h<<8)|w
		;//%r12     := type*2
		;//[%sp+ 0] := %r0
		;//[%sp+ 4] := %r1
		;//[%sp+ 8] := %r2
		;//[%sp+12] := %r3
		;//[%sp+16] := retp
		;//[%sp+24] := color
		xcmp		%r3, 0x20					;//if(code == ' ') { goto render_font_SPC }					'cmp %r3,0x20'では不可!!
		xjreq		render_font_SPC
		xld.h		[%sp+20], %r10					;//[%sp+20] := w, [%sp+21] := h							スタック渡しされた引数のメモリは破壊しても安全なので、そのメモリを別のローカル変数を格納する用途にも使える。
		;//%r0      := render
		;//%r1      := x
		;//%r2      := y
		;//%r3      := code
		;//%r10     := (h<<8)|w
		;//%r12     := type*2
		;//[%sp+ 0] := %r0
		;//[%sp+ 4] := %r1
		;//[%sp+ 8] := %r2
		;//[%sp+12] := %r3
		;//[%sp+16] := retp
		;//[%sp+20] := w
		;//[%sp+21] := h
		;//[%sp+24] := color
		xcall.d		pceFontSetType					;//pceFontSetType(type)
		srl		%r12, 1						;//%r12 :=        type              (00000000 00000000 00000000 0ttttttt)	*delay*
		xcall.d		pceFontGetAdrs					;//%r10 := p = pceFontGetAdrs(code) (?ppppppp pppppppp pppppppp pppppppp)
		ld.w		%r12, %r3					;//%r12 :=                    code						*delay*
		;//%r0      := render
		;//%r1      := x
		;//%r2      := y
		;//%r10     := p
		;//[%sp+ 0] := %r0
		;//[%sp+ 4] := %r1
		;//[%sp+ 8] := %r2
		;//[%sp+12] := %r3
		;//[%sp+16] := retp
		;//[%sp+20] := w
		;//[%sp+21] := h
		;//[%sp+24] := color
		ld.w		%r3, [%r0]+					;//%r3  := surface
		ld.h		%r4, [%r0]+					;//%r4  := render->left
		ld.h		%r5, [%r0]+					;//%r5  := render->top
		ld.h		%r6, [%r0]+					;//%r6  := render->right
		ld.h		%r7, [%r0]					;//%r7  := render->bottom
		;//%r1      := x
		;//%r2      := y
		;//%r3      := surface
		;//%r4      := render->left
		;//%r5      := render->top
		;//%r6      := render->right
		;//%r7      := render->bottom
		;//%r10     := p
		;//[%sp+ 0] := %r0
		;//[%sp+ 4] := %r1
		;//[%sp+ 8] := %r2
		;//[%sp+12] := %r3
		;//[%sp+16] := retp
		;//[%sp+20] := w
		;//[%sp+21] := h
		;//[%sp+24] := color
		xld.w		%r0, [%r3+4]					;//%r0  := surface->vbuff
		xld.h		%r3, [%r3+0]					;//%r3  := surface->w
		mlt.h		%r3, %r2					;//%r0  := vptr = surface->vbuff + surface->w * y + x
		ld.w		%r9, %alr
		add		%r0, %r9
		add		%r0, %r1
		;//%r0      := vptr
		;//%r1      := x
		;//%r2      := y
		;//%r3      := surface->w
		;//%r4      := render->left
		;//%r5      := render->top
		;//%r6      := render->right
		;//%r7      := render->bottom
		;//%r10     := p
		;//[%sp+ 0] := %r0
		;//[%sp+ 4] := %r1
		;//[%sp+ 8] := %r2
		;//[%sp+12] := %r3
		;//[%sp+16] := retp
		;//[%sp+20] := w
		;//[%sp+21] := h
		;//[%sp+24] := color
		sub		%r1, %r4					;//%r1  := x -= render->left
		sub		%r2, %r5					;//%r2  := y -= render->top
		sub		%r6, %r4					;//%r6  := xlim = render->right - render->left
		sub		%r7, %r5					;//%r7  := ylim = render->bottom - render->top
		xld.ub		%r11, [%sp+20]					;//%r11 := w
		xld.ub		%r12, [%sp+21]					;//%r12 := h
		ld.w		%r4, %r11					;//%r4  := w
		ld.w		%r5, %r3					;//%r5  := vadd = surface->w - w
		sub		%r5, %r4
		add		%r11, %r1					;//%r11 := xmax = x + w
		add		%r12, %r2					;//%r12 := ymax = y + h
		xld.ub		%r13, [%sp+24]					;//%r13 := color
		;//%r0      := vptr
		;//%r1      := x
		;//%r2      := y
		;//%r3      := surface->w
		;//%r4      := w
		;//%r5      := vadd
		;//%r6      := xlim
		;//%r7      := ylim
		;//%r10     := p
		;//%r11     := xmax
		;//%r12     := ymax
		;//%r13     := color
		;//[%sp+ 0] := %r0
		;//[%sp+ 4] := %r1
		;//[%sp+ 8] := %r2
		;//[%sp+12] := %r3
		;//[%sp+16] := retp
		;//[%sp+20] := w
		;//[%sp+21] := h
		add		%r10, %r10					;//%psr(C) := ?, %r10 := p * 2 (pppppppp pppppppp pppppppp ppppppp0)
		xjruge.d	render_font_ZEN					;//if(?) { goto render_font_ZEN }
		srl		%r10, 1						;//              %r10 := p     (0ppppppp pppppppp pppppppp pppppppp)		*delay*
		;//半角 --------------------------------------------------------;//
;//{{2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
;//		cmp		%r1, 0						;//if(x    <    0) { goto render_font_HAN_OUT }
;//		xjrlt		render_font_HAN_OUT
;//		cmp		%r6, %r11					;//if(xlim < xmax) { goto render_font_HAN_OUT }
;//		xjrlt		render_font_HAN_OUT
;//		cmp		%r2, 0						;//if(y    <    0) { goto render_font_HAN_OUT }
;//		xjrlt		render_font_HAN_OUT
;//		cmp		%r7, %r12					;//if(ylim < ymax) { goto render_font_HAN_OUT }
;//		xjrlt		render_font_HAN_OUT
;//↓2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
		xcall		render_font_TEST1				;//完全にビューポート内でなければ…
		xjrlt		render_font_HAN_OUT				;//半角(クリッピング有り)へ分岐する。
;//}}2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
		;//半角(クリッピング無し) --------------------------------------;//
render_font_HAN_IN_REPY:							;//do {
		ld.ub		%r14, [%r10]+					;//                   c = *p++
		swap		%r14, %r14					;//                   c = abcdefgh 00000000 00000000 00000000
render_font_HAN_IN_REPX:							;//  do {
		add		%r14, %r14					;//      %psr(C) = a, c = bcdefgh0 00000000 00000000 00000000
		jruge.d		3						;//      if(a)
		 add		%r1, 1						;//      <---------------+							*delay*
		 ld.b		[%r0], %r13					;//      | *vptr = color |
;//		add		%r1, 1						;//      ----------------+
		cmp		%r1, %r11					;//
		xjrlt.d		render_font_HAN_IN_REPX				;//  } while(++x < xmax)
		add		%r0, 1						;//    vptr++									*delay*
		sub		%r1, %r4					;//  x -= w
		add		%r2, 1						;//
		cmp		%r2, %r12					;//
		xjrlt.d		render_font_HAN_IN_REPY				;//} while(++y < ymax)
		add		%r0, %r5					;//  vptr += vadd								*delay*
		xjp		render_font_RET
		;//半角(クリッピング有り) --------------------------------------;//
render_font_HAN_OUT:								;//
;//{{2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
;//;//{{2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
;//		cmp		%r11, 0						;//if(xmax <= 0) { goto render_font_RET }
;//		xjrle		render_font_RET
;//		cmp		%r6, %r1					;//if(xlim <= x) { goto render_font_RET }
;//		xjrle		render_font_RET
;//		cmp		%r12, 0						;//if(ymax <= 0) { goto render_font_RET }
;//		xjrle		render_font_RET
;//		cmp		%r7, %r2					;//if(ylim <= y) { goto render_font_RET }
;//		xjrle		render_font_RET
;//;//}}2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
;//↓2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
		xcall		render_font_TEST2				;//完全にビューポート外ならば…
		xjrle		render_font_RET					;//描画処理を行わない。
;//}}2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
render_font_HAN_OUT_REPY:							;//do {
		ld.ub		%r14, [%r10]+					;//                   c = *p++
		swap		%r14, %r14					;//                   c = abcdefgh 00000000 00000000 00000000
render_font_HAN_OUT_REPX:							;//  do {
		add		%r14, %r14					;//      %psr(C) = a, c = bcdefgh0 00000000 00000000 00000000
		jruge		6						;//      if(a)
		 cmp		%r1, %r6					;//      | 
		 jruge		4						;//      | if((unsigned)x < (unsigned)xlim)
		  cmp		%r2, %r7					;//      | | 
		  jruge		2						;//      | | if((unsigned)y < (unsigned)ylim)
		   ld.b		[%r0], %r13					;//      | | | *vptr = color
		add		%r1, 1						;//
		cmp		%r1, %r11					;//
		xjrlt.d		render_font_HAN_OUT_REPX			;//  } while(++x < xmax)
		add		%r0, 1						;//    vptr++									*delay*
		sub		%r1, %r4					;//  x -= w
		add		%r2, 1						;//
		cmp		%r2, %r12					;//
		xjrlt.d		render_font_HAN_OUT_REPY			;//} while(++y < ymax)
		add		%r0, %r5					;//  vptr += vadd								*delay*
		xjp		render_font_RET
		;//全角 --------------------------------------------------------;//
render_font_ZEN:
		add		%r11, %r4					;//xmax += w
		add		%r4, %r4					;//w    *= 2
		add		%r5, %r5					;//vadd *= 2
		xld.b		[%sp+20], %r4					;//[%sp+20] = w * 2
;//{{2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
;//		cmp		%r1, 0						;//if(x    <    0) { goto render_font_ZEN_OUT }
;//		xjrlt		render_font_ZEN_OUT
;//		cmp		%r6, %r11					;//if(xlim < xmax) { goto render_font_ZEN_OUT }
;//		xjrlt		render_font_ZEN_OUT
;//		cmp		%r2, 0						;//if(y    <    0) { goto render_font_ZEN_OUT }
;//		xjrlt		render_font_ZEN_OUT
;//		cmp		%r7, %r12					;//if(ylim < ymax) { goto render_font_ZEN_OUT }
;//		xjrlt		render_font_ZEN_OUT
;//↓2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
		xcall		render_font_TEST1				;//完全にビューポート内でなければ…
		xjrlt		render_font_ZEN_OUT				;//全角(クリッピング有り)へ分岐する。
;//}}2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
		;//全角(クリッピング無し) --------------------------------------;//
render_font_ZEN_IN_REPY:							;//do {
		ld.ub		%r14, [%r10]+					;//  c =          *p++ (00000000 00000000 00000000 abcdefgh)
		ld.ub		%r9, [%r10]+					;//
		sll		%r14, 8						;//
		or		%r14, %r9					;//  c = (c<<8) | *p++ (00000000 00000000 abcdefgh ij00klmn)
		ld.ub		%r9, [%r10]+					;//
		sll		%r14, 8						;//
		or		%r14, %r9					;//  c = (c<<8) | *p++ (00000000 abcdefgh ij00klmn opqrst00)
;//{{高速化
;//render_font_ZEN_IN_REPX:							;//  do {
;//		xand		%r9, %r14, 0x800000				;//
;//		jreq		2						;//    if(c & (1<<23))
;//		 ld.b		[%r0], %r13					;//    | *(vptr + 0         ) = color
;//		xand		%r9, %r14, 0x800				;//
;//		jreq		4						;//    if(c & (1<<11))
;//		 add		%r0, %r3					;//    |
;//		 ld.b		[%r0], %r13					;//    | *(vptr + surface->w) = color
;//		 sub		%r0, %r3					;//    |
;//		add		%r14, %r14					;//    c <<= 1
;//		add		%r1, 1						;//
;//↓高速化
		sll		%r14, 8						;//  %r14 := c1 (abcdefgh ij00klmn opqrst00 00000000)
		ld.w		%r15, %r14					;//  %r15 := c2 (klmnopqr st000000 00000000 00000000)
		xsll		%r15, 12					;//										'sll %r15,12'では不可!!
render_font_ZEN_IN_REPX:							;//  do {
		add		%r14, %r14					;//    %psr(C) := a, c1 = bcdefghi j00klmno pqrst000 00000000
		jruge.d		3						;//    if(a)
		 add		%r15, %r15					;//    | %psr(C) := k, c2 = lmnopqrs t0000000 00000000 00000000			*delay*
		 ld.b		[%r0], %r13					;//    | *(vptr + 0         ) = color
		jruge.d		5						;//    if(k)
		 add		%r1, 1						;//    |									*delay*
		 add		%r0, %r3					;//    |
		 ld.b		[%r0], %r13					;//    | *(vptr + surface->w) = color
		 sub		%r0, %r3					;//    |
;//}}高速化
		cmp		%r1, %r11					;//
		xjrlt.d		render_font_ZEN_IN_REPX				;//  } while(++x < xmax)
		add		%r0, 1						;//    vptr++									*delay*
		sub		%r1, %r4					;//  x -= w
		add		%r2, 2						;//
		cmp		%r2, %r12					;//
		xjrlt.d		render_font_ZEN_IN_REPY				;//} while((y += 2) < ymax)
		add		%r0, %r5					;//  vptr += vadd								*delay*
		xjp		render_font_RET
		;//全角(クリッピング有り) --------------------------------------;//
render_font_ZEN_OUT:								;//
;//{{2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
;//;//{{2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
;//		cmp		%r11, 0						;//if(xmax <= 0) { goto render_font_RET }
;//		xjrle		render_font_RET
;//		cmp		%r6, %r1					;//if(xlim <= x) { goto render_font_RET }
;//		xjrle		render_font_RET
;//		cmp		%r12, 0						;//if(ymax <= 0) { goto render_font_RET }
;//		xjrle		render_font_RET
;//		cmp		%r7, %r2					;//if(ylim <= y) { goto render_font_RET }
;//		xjrle		render_font_RET
;//;//}}2016/11/22追加:render_font()を、完全に画面外ならば描画処理を行わないようにして、完全に画面外のケースを高速化しました。
;//↓2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
		xcall		render_font_TEST2				;//完全にビューポート外ならば…
		xjrle		render_font_RET					;//描画処理を行わない。
;//}}2016/11/23変更:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
render_font_ZEN_OUT_REPY:							;//do {
		ld.ub		%r14, [%r10]+					;//  c =          *p++ (00000000 00000000 00000000 abcdefgh)
		ld.ub		%r9, [%r10]+					;//
		sll		%r14, 8						;//
		or		%r14, %r9					;//  c = (c<<8) | *p++ (00000000 00000000 abcdefgh ij00klmn)
		ld.ub		%r9, [%r10]+					;//
		sll		%r14, 8						;//
		or		%r14, %r9					;//  c = (c<<8) | *p++ (00000000 abcdefgh ij00klmn opqrst00)
render_font_ZEN_OUT_REPX:							;//  do {
		cmp		%r1, %r6					;//
		xjruge.d	render_font_ZEN_OUT_SKIP			;//    if((unsigned)x < (unsigned)xlim) {
		add		%r1, 1						;//    <------------------------------------+					*delay*
		xand		%r9, %r14, 0x800000				;//                                         |
		jreq		4						;//      if(c & (1<<23))                    |
		 cmp		%r2, %r7					;//      |                                  |
		 jruge		2						;//      | if((unsigned)y < (unsigned)ylim) |
		  ld.b		[%r0], %r13					;//      | | *(vptr + 0         ) = color   |
		xand		%r9, %r14, 0x800				;//                                         |
		jreq		8						;//      if(c & (1<<11))                    |
		 add		%r2, 1						;//      | y++                              |
		 cmp		%r2, %r7					;//      |                                  |
		 jruge.d	5						;//      | if((unsigned)y < (unsigned)ylim) |
		  sub		%r2, 1						;//      | y--                              |					*delay*
		  add		%r0, %r3					;//      | |                                |
		  ld.b		[%r0], %r13					;//      | | *(vptr + surface->w) = color   |
		  sub		%r0, %r3					;//      | |                                |
render_font_ZEN_OUT_SKIP:							;//    }                                    |
		add		%r14, %r14					;//    c <<= 1                              |
;//		add		%r1, 1						;//    -------------------------------------+
		cmp		%r1, %r11					;//
		xjrlt.d		render_font_ZEN_OUT_REPX			;//  } while(++x < xmax)
		add		%r0, 1						;//    vptr++									*delay*
		sub		%r1, %r4					;//  x -= w
		add		%r2, 2						;//
		cmp		%r2, %r12					;//
		xjrlt.d		render_font_ZEN_OUT_REPY			;//} while((y += 2) < ymax)
		add		%r0, %r5					;//  vptr += vadd								*delay*
		;//-------------------------------------------------------------;//
render_font_RET:
		xld.uh		%r10, [%sp+20]					;//%r10 = (h<<8)|w
render_font_SPC:
		popn		%r3
		ret
render_font_ERR:
		xjp.d		render_font_SPC
		ld.w		%r10, 0						;//										*delay*
;//{{2016/11/23追加:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
render_font_TEST1:
		;//%r1      := x
		;//%r2      := y
		;//%r6      := xlim
		;//%r7      := ylim
		;//%r11     := xmax
		;//%r12     := ymax
		cmp		%r1, 0						;//if((x    <    0) ||
		jrlt		6
		cmp		%r6, %r11					;//   (xlim < xmax) ||
		jrlt		4
		cmp		%r2, 0						;//   (y    <    0) ||
		jrlt		2
		cmp		%r7, %r12					;//   (ylim < ymax)) { %psr := 'lt' }	完全にビューポート内ではない。
		ret								;//else              { %psr := 'ge' }	完全にビューポート内である。
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;//
render_font_TEST2:
		;//%r1      := x
		;//%r2      := y
		;//%r6      := xlim
		;//%r7      := ylim
		;//%r11     := xmax
		;//%r12     := ymax
		cmp		%r11, 0						;//if((xmax <=   0) ||
		jrle		6
		cmp		%r6, %r1					;//   (xlim <=   x) ||
		jrle		4
		cmp		%r12, 0						;//   (ymax <=   0) ||
		jrle		2
		cmp		%r7, %r2					;//   (ylim <=   y)) { %psr := 'le' }	完全にビューポート外である。
		ret								;//else              { %psr := 'gt' }	完全にビューポート外ではない。
;//}}2016/11/23追加:render_font()の、ビューポート内外の判定処理を、半角と全角とで処理を共通化して、コードサイズを削減しました。
");
#endif
