/*	
 *	cliprend.h
 *
 *	描画ライブラリを定義します。
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2009 Naoyuki Sawa
 *
 *	* Wed Feb 13 06:00:00 JST 2002 Naoyuki Sawa
 *	- 作成開始。
 *	* Wed Jun 28 00:56:31 JST 2006 Naoyuki Sawa
 *	- mesh_load()の宣言を追加しました。
 *	* Wed Jan 10 14:39:19 JST 2007 Naoyuki Sawa
 *	- surface_stretch()を追加しました。
 *	* Mon Mar 12 00:13:49 JST 2007 Naoyuki Sawa
 *	- render_rectangle_dark()→render_rectangle_shadow()に名前変更しました。
 *	* Sun Jul 15 23:00:19 JST 2007 Naoyuki Sawa
 *	- render_rectangle_shadow()のコメントが間違っていたのを修正しました。
 *	  コードには変更ありません。
 *	* Thu Sep 27 16:44:15 JST 2007 Naoyuki Sawa
 *	- RENDER構造体とRENDERCONTEXT構造体の全体をレイアウト固定とするコメントを追記しました。
 *	  コードには変更ありません。
 *	* Wed Oct 17 12:30:13 JST 2007 Naoyuki Sawa
 *	- surface_stretch()をASM化しました。
 *	  使用方法の注意点は、FRAM4領域を使用しているAPI(pceLCDTrans(),pceFileWriteSct()等)と同様です。
 *	  詳細は、ASM版surface_stretch()のコード上のコメントを参照してください。
 *	* Mon Nov 05 15:54:07 JST 2007 Naoyuki Sawa
 *	- soft_focus()を追加しました。
 *	* Fri Dec 28 20:39:14 JST 2007 Naoyuki Sawa
 *	- render_rectangle_clip()を追加しました。
 *	* Tue Jan 01 21:17:37 JST 2008 Naoyuki Sawa
 *	- DSLPARAM構造体の、fore_colorとback_colorの順序を入れ替えました。
 *	* Sun Jan 13 13:34:20 JST 2008 Naoyuki Sawa
 *	- draw_primitive_wz()をframdp1.cへ、draw_primitive_woz()をframdp2.cへ、移動しました。
 *	  draw_primitive_wz()とdraw_primitive_woz()を、今後、アセンブラ化するための準備です。
 *	- この変更に伴い、いくつかの細かな変更を行いました。
 *	  変更箇所は、cliprend.hとclipren3.cを、「2008/01/13」で検索してください。
 *	* Mon Jan 14 23:18:06 JST 2008 Naoyuki Sawa
 *	- draw_primitive_woz()を廃止し、draw_primitive_wz()に統合し、関数名をdraw_primitive()に変更しました。
 *	  詳しくは、framdprm.cのコメントを参照してください。
 *	* Wed Jul 30 22:07:23 JST 2008 Naoyuki Sawa
 *	  CLIPVERTEXの定義を、cliprend.hからclipren3.cへ移動しました。
 *	  clipren3.cの内部でしか使っていなかったので、他のモジュールへの影響は有りません。
 *	  今後、浮動小数点版描画モジュールを作成する予定で、その際、浮動小数点版描画モジュール内では、
 *	  同じCLIPVERTEXという名前で、浮動小数点のクリッピング用頂点構造体を定義する予定です。
 *	  それに備えて、固定小数版のCLIPVERTEXをclipren3.cローカルとしておくために、移動を行いました。
 *	* Sun Aug 10 21:42:25 JST 2008 Naoyuki Sawa
 *	- tool/ExportPieceClipが、<vector>要素を固定小数点でなく浮動小数点で出力するよう変更したことに追従し、
 *	  mesh_load()とwire_load()に、浮動小数点のまま読み込むか、固定小数点に変換するかの選択を追加しました。
 *	* Thu Apr 16 00:14:17 JST 2009 Naoyuki Sawa
 *	- texture_copy()を追加し、同時にASM化しました。。
 *	* Sat Apr 18 14:43:08 JST 2009 Naoyuki Sawa
 *	- texture_copy()の仕様を変更しました。
 *	  これまでは、仮想VRAM全体を、同じサイズのテクスチャ全体へ取り込むことしかできませんでしたが、
 *	  今回の変更により、サーフェイスの一部を、テクスチャ全体へ取り込むことしかできるようになりました。
 *	* Mon Apr 20 00:00:08 JST 2009 Naoyuki Sawa
 *	- texture_copy()の仕様を変更しました。
 *	  これまでは、マスク無しテクスチャへの取り込み専用でしたが、今回より、マスク有りにも対応しました。
 *	  テクスチャのマスク有無を判断して、自動的に処理を変えます。
 *	  詳しい内容は、texture_copy()のコメントを参照してください。
 *	* Wed May 06 20:58:21 JST 2009 Naoyuki Sawa
 *	- render_edge()を追加しました。
 *	* Sat May 09 13:21:42 JST 2009 Naoyuki Sawa
 *	- render_edge()の変更に伴い、引数thresholdのコメントを追記。
 */
#ifndef __CLIP_REND_H__
#define __CLIP_REND_H__

/* REND_NOASMを定義するとCルーチン、定義しなければasmルーチンを使います。 */
#undef REND_NOASM	/* まず確実に未定義にした上で… */
//#define REND_NOASM	/* 必要に応じて定義してください（定義すると遅くなります） */

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

#ifdef PIECE
typedef PBMP_FILEHEADER	TEXTUREHEADER;
typedef PIECE_BMP	TEXTURE;
#else /*PIECE*/
typedef struct _TEXTUREHEADER {		/* PBMP_FILEHEADERにバイナリ互換 */
	unsigned long head;		/* + 0,4 シグネチャ'PBMP'        */
	unsigned long fsize;		/* + 4,4 ファイルサイズ          */
	unsigned char bpp;		/* + 8,1 ビット深度              */
	unsigned char mask;		/* + 9,1 マスク深度              */
	short w;			/* +10,2 幅                      */
	short h;			/* +12,2 高さ                    */
					/* +14,2 パディング              */
	unsigned long buf_size;		/* +16,4 データサイズ            */
					/* =20                           */
} TEXTUREHEADER;
typedef struct _TEXTURE {		/* PIECE_BMPにバイナリ互換 */
	TEXTUREHEADER header;		/* + 0,20 ヘッダ           */
	unsigned char* buf;		/* +20, 4 ビットデータ     */
	unsigned char* mask;		/* +24, 4 マスクデータ     */
					/* =28                     */
} TEXTURE;
#endif /*PIECE*/

/* SURFACE構造体は、PIECE_VRAM構造体の上位バイナリ互換です。
 * PIECE_VRAMへのポインタを要求する関数に、SURFACEへのポインタを渡せます。
 */
typedef struct _SURFACE {		/* 描画先サーフェイス   */
	short w;			/* + 0,2 幅             */
	short h;			/* + 2,2 高さ           */
	unsigned char* vbuff;		/* + 4,4 カラーバッファ */
	/* ↑ここまでPIECE_VRAM互換。↓これ以降は拡張部分です。 */
	unsigned char* zbuff;		/* + 8,4 Ｚバッファ     */
					/* =12                  */
} SURFACE;

typedef struct _VERTEX {		/* ポリゴン頂点          */
	short x;			/* +0,2 水平ピクセル座標 */
	short y;			/* +2,2 垂直ピクセル座標 */
	unsigned char s;		/* +4,1 水平テクセル座標 */
	unsigned char t;		/* +5,1 垂直テクセル座標 */
} VERTEX;				/* =6                    */

typedef struct _TCOORD {		/* テクスチャ座標 */
	unsigned char s;		/* +0,1 水平座標  */
	unsigned char t;		/* +1,1 垂直座標  */
					/* =2             */
} TCOORD;

typedef struct _FACEVERTEX {		/* フェイス頂点                  */
	unsigned char iv;		/* +0,1 頂点座標インデクス       */
	unsigned char ic;		/* +1,1 テクスチャ座標インデクス */
} FACEVERTEX;

typedef struct _FACE {			/* フェイス                      */
	unsigned char nfv;		/* +0,1    頂点の数              */
	unsigned char c;		/* +1,1    カラー                */
	/*FACEVERTEX fv[nfv];*/		/* +2,2nfv フェイス頂点リスト    */
					/* =2+2nfv                       */
} FACE;

typedef struct _MESH {			/* メッシュ                             */
	unsigned char nv;		/* +0,1            頂点座標の数         */
	unsigned char nc;		/* +1,1            テクスチャ座標の数   */
	unsigned char nf;		/* +2,1            フェイスの数         */
	unsigned char reserved;		/* +3,1            (予約)               */
	/*vector v[nv];*/		/* +4,12nv         頂点座標リスト       */
	/*TCOORD c[nc];*/		/* +4+12nv,2nc     テクスチャ座標リスト */
	/*FACE f[nf];*/			/* +4+12nv+2nc,(?) フェイスリスト       */
					/* =4+12nv+2nc+(?)                      */
} MESH;

/*****************************************************************************
 *	内部使用
 *****************************************************************************/

//{{2008/07/30:clipren3.cへ移動
///* クリッピング用頂点 */
//typedef struct _CLIPVERTEX {
//	fixed x, y, z;		/* + 0,12 頂点座標       */
//	fixed s, t;		/* +12, 8 テクスチャ座標 */
//				/* =20                   */
//} CLIPVERTEX;
//}}2008/07/30:clipren3.cへ移動

/* 描画用頂点 */
typedef struct _RENDVERTEX {
	unsigned short x, y;	/* + 0,4 頂点座標               */
	unsigned short z;	/* + 4,2 Ｚ値(8.8bit)           */
	unsigned short s, t;	/* + 6,4 テクスチャ座標(8.8bit) */
				/* =10                          */
} RENDVERTEX;

///* DDA */
//typedef struct _DDA {
//	int n;			/* + 0,4 端数の増加量     */
//	int d;			/* + 4,4 端数             */
//	int u;			/* + 8,4 毎回の変化量     */
//	int v;			/* +12,4 繰上げ時の変化量 */
//				/* =16                    */
//} DDA;
//→2003/12/28: 他のモジュールでも使うことがあるので、clipmisc.hへ移動しました。

/* draw_scanline_*_*()へ引き渡すパラメータの構造体です。
 * draw_scanline_*_*()はアセンブラで高速化するので、確実にオフセット固定とするために、この構造体を用意しました。
 */
typedef struct _DSLPARAM {
	/* サーフェイス */
	unsigned short surface_w;			/*  0, 2: 幅 */
	unsigned short surface_h;			/*  2, 2: 高さ */
	unsigned char* surface_vbuff;			/*  4, 4: カラーバッファ */
	unsigned char* surface_zbuff;			/*  8, 4: Ｚバッファ */
	/* テクスチャ */
	unsigned short texture_w;			/* 12, 2: 幅 */
	unsigned short texture_h;			/* 14, 2: 高さ */
	unsigned char* texture_buf;			/* 16, 4: イメージ */
	unsigned char* texture_mask;			/* 20, 4: マスク */
	/* カラー */
//{{2008/01/01:変更
//	unsigned char back_color;			/* 24, 1: 背景色 */
//	unsigned char fore_color;			/* 25, 1: 前景色 */
//↓ * Tue Jan 01 21:17:37 JST 2008 Naoyuki Sawa
//↓ - DSLPARAM構造体の、fore_colorとback_colorの順序を入れ替えました。
//↓   必須では有りませんが、DRW_CLR()のパラメータ順と一致させて、解り易くするためです。
//↓ - 現時点で、これらのフィールドを参照していたモジュールは、以下のとおりです。
//↓	framds11.c … スキャンライン描画関数（Ｚ比較あり・テクスチャなし）
//↓	framds12.c … スキャンライン描画関数（Ｚ比較あり・1bitテクスチャ）
//↓	framds13.c … スキャンライン描画関数（Ｚ比較あり・1bitmaskテクスチャ）
//↓	framds21.c … スキャンライン描画関数（Ｚ比較なし・テクスチャなし）
//↓	framds22.c … スキャンライン描画関数（Ｚ比較なし・1bitテクスチャ）
//↓	framds23.c … スキャンライン描画関数（Ｚ比較なし・1bitmaskテクスチャ）
//↓   framds11.c、framds21.cは既にアセンブラ化していたので、オフセットを修正しました。
//↓   framds12.c、framds13.c、framds22.c、framds23.cはまだアセンブラ化していないので、
//↓   今回の変更に伴う修正は必要ありませんでした。
	unsigned char fore_color;			/* 24, 1: 前景色 */
	unsigned char back_color;			/* 25, 1: 背景色 */
//}}2008/01/01:変更
} DSLPARAM;

/* スキャンライン描画関数の本体です。アプリケーションから直接利用しないで下さい。 */
typedef void (*DSLPROC)(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);
void draw_primitive(RENDVERTEX vertices[/*n_vertices*/], int n_vertices, DSLPARAM* param, DSLPROC draw_scanline); /* framdprm.c {{2008/01/14:追加}} */ 
/* (Ｚコンペアあり) */
//void draw_primitive_wz(RENDVERTEX vertices[/*n_vertices*/], int n_vertices, DSLPARAM* param, DSLPROC draw_scanline);	/* framdp1.c {{2008/01/13:追加}} */ /* {{2008/01/14:削除}} */
void draw_scanline_wz_color(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds11.c */
void draw_scanline_wz_1bit(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds12.c */
void draw_scanline_wz_1bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds13.c */
void draw_scanline_wz_2bit(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds14.c */
void draw_scanline_wz_2bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds15.c */
/* (Ｚコンペアなし) */
//void draw_primitive_woz(RENDVERTEX vertices[/*n_vertices*/], int n_vertices, DSLPARAM* param, DSLPROC draw_scanline);	/* framdp2.c {{2008/01/13:追加}} */ /* {{2008/01/14:削除}} */
void draw_scanline_woz_color(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds21.c */
void draw_scanline_woz_1bit(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds22.c */
void draw_scanline_woz_1bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds23.c */
void draw_scanline_woz_2bit(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds24.c */
void draw_scanline_woz_2bitmask(const RENDVERTEX* v0, const RENDVERTEX* v1, DSLPARAM* param);	/* framds25.c */

/****************************************************************************
 *	スキャンライン描画関数用マクロ定義
 ****************************************************************************/

/* draw_primitive_*()用 DDAセットアップ */
#define DRAW_PRIMITIVE_SETUP(i) \
	side->cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		side->i.n = (v1->i - v0->i) % side->ny; \
		side->i.d = -side->ny; \
		side->i.u = (v1->i - v0->i) / side->ny; \
		side->i.v = 1; \
	} else { \
		side->i.n = (v0->i - v1->i) % side->ny; \
		side->i.d = -side->ny; \
		side->i.u = -((v0->i - v1->i) / side->ny); \
		side->i.v = -1; \
	}

/* draw_primitive_*()用 DDAステップ実行 */
#define DRAW_PRIMITIVE_STEP(i) \
	side->cur.i += side->i.u; \
	side->i.d += side->i.n * 2; \
	if(side->i.d >= 0) { \
		side->cur.i += side->i.v; \
		side->i.d -= side->ny * 2; \
	}

/* draw_scanline_*_*()用 DDAセットアップ */
#define DRAW_SCANLINE_SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u = (v1->i - v0->i) / nx; \
		i.v = 1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -((v0->i - v1->i) / nx); \
		i.v = -1; \
	}

/* draw_scanline_*_*()用 DDAステップ実行 */
#define DRAW_SCANLINE_STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

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

/* テクスチャ構造体を初期化します。
 * [in]
 *	texture		初期化するテクスチャ構造体。
 *	data		PBMPファイルイメージの先頭アドレス。
 * [out]
 *	戻り値		引数textureの値をそのまま返します。
 * [note]
 *	* TEXTURE構造体はPIECE_BMP構造体と同じ(typedef)なので、
 *	  この関数はPIECE_BMP構造体の初期化にも利用できます。
 */
TEXTURE* texture_init(TEXTURE* texture, const void* data);

/* テクスチャ構造体配列を初期化します。
 * [in]
 *	texture		初期化するテクスチャ構造体配列の先頭アドレス。
 *	texture_count	初期化するテクスチャ構造体配列の要素数。
 *	...		PBMPファイルイメージの先頭アドレスを列挙してください。
 *			列挙数はtexture_countで指定した数と同じでなければいけません。
 * [note]
 *	* 複数のテクスチャを利用するアプリケーションのためのユーティリティ関数です。
 *	  次の例のように使ってください。
 *
 *		extern const unsigned char PAT0[];
 *		extern const unsigned char PAT1[];
 *		TEXTURE texture_table[2];
 *		void init() {
 *			texture_table_init(texture_table, 2, PAT0, PAT1);
 *			// texture_table[0]はPAT0を使って初期化されました。
 *			// texture_table[1]はPAT1を使って初期化されました。
 *		}
 */
void texture_table_init(TEXTURE texture[], int texture_count, ...);

/* サーフェイスをクリアします。
 * [in]
 *	surface		サーフェイス構造体。
 *	color		背景色。
 * [note]
 *	* カラーバッファ(vbuff)がNULLでなければ、背景色でクリアします。
 *	* Ｚバッファ(zbuff)がNULLでなければ、0xFFでクリアします。
 */
void surface_clear(SURFACE* surface, int color);

/* ピクセルカラーを取得します。
 * [in]
 *	surface		サーフェイス構造体。
 *	x,y		ピクセル座標。
 * [out]
 *	戻り値		ピクセルカラー。
 *			サーフェイス外のピクセル座標なら、-1を返します。
 * [note]
 *	* この関数は、render_point()と対を成します。
 */
int surface_point(SURFACE* surface, int x, int y);

/* 転送元サーフェイス全体を、転送先サーフェイス全体へ、補間コピーします。
 * [in]
 *	dst		転送先サーフェイス。
 *	src		転送元サーフェイス。
 * [note]
 *	* 転送先、転送元のサーフェイスサイズは任意です。
 *	  たとえば、水平方向拡大、垂直方向縮小のような場合でも、問題無く処理できます。
 *	* 通常の4色表示でも、高速切替16色表示でも利用できます。
 *	  リニア補間と加重平均のアルゴリズムなので、本関数は階調数を意識していません。
 *	* 拡大・縮小に同じアルゴリズムを使用しています。
 *	  拡大は一般的なリニア補間ですが、縮小は範囲内全ピクセルの加重平均となります。
 *	  特に、縮小の負荷が高いので、注意してください。
 *	* 本関数は、拡大も縮小も低速で、リアルタイムゲームに利用することは難しいです。
 *	  以下に、テスト結果を記録しておきます。
 *	----------------------------------------------------------------------------------------------------------------------------
 *	* テスト環境
 *	  スタック SRAM
 *	  コード SRAM
 *	  TURBO ON 48MHz
 *	  16階調表示 OFF
 *	* テスト結果
 *	   63x 43 -> 128x88 (拡大) 0.16秒
 *	  128x 88 -> 128x88 (等倍) 0.12秒
 *	  255x255 -> 128x88 (縮小) 0.53秒
 *	* 考察
 *	- 本関数は、あまり力を入れて高速化しませんでした。
 *	  もし、多少、高速化できたとしても、リアルタイムゲームで毎フレームストレッチを実行できる速度には、ほど遠いと考えたからです。
 *	- スタックを高速RAMに配置したり、コードを高速RAMに配置すれば、速度が改善できますが、せいぜい二倍程度であり、高速化不足です。
 *	  また、ストレッチを効果的に使うには、16階調表示との併用が必要ですが、その場合、高速切替の負荷で、さらに速度が遅くなります。
 *	- 以上の理由により、高速化をあきらめて、単純な実装を維持することにしました。
 *	  本関数は、静的な画像を描画した任意サイズのサーフェイスを、メインサーフェイスにストレッチするような用途に利用してください。
 *	- ★注意★本関数の実装とは直接関係ありませんが、255×255を超えるサーフェイスの利用には注意してください。
 *	  render_object()はpceLCDDrawObject()を利用しており、pceLCDDrawObject()はRECTPの制限のため、255×255を超えられないからです。
 *	----------------------------------------------------------------------------------------------------------------------------
 *	* Wed Oct 17 12:30:13 JST 2007 Naoyuki Sawa
 *	- surface_stretch()をASM化しました。
 *	  使用方法の注意点は、FRAM4領域を使用しているAPI(pceLCDTrans(),pceFileWriteSct()等)と同様です。
 *	  詳細は、ASM版surface_stretch()のコード上のコメントを参照してください。
 */
void surface_stretch(SURFACE* dst, SURFACE* src);

/* サーフェイス全体に、ソフトフォーカスをかけます。
 * [in]
 *	surface		ソフトフォーカスをかけるサーフェイス。
 *			ソフトフォーカス処理をのための中間バッファとして、_def_vbuffを利用しています。
 *			そのため、11264(=128*88)ピクセル以上のサーフェイスを指定することはできません。
 *			本関数の呼び出しによって、_def_vbuffの内容は破壊されます。
 *	x		水平方向のソフトフォーカスの度合い。
 *	y		垂直方向のソフトフォーカスの度合い。
 *			ソフトフォーカスの度合いは「効果無し:1.0⇔0.0:最大効果」です。
 *			1.0超過、または、0.0未満を指定した場合は、この範囲に切り詰めます。
 * [note]
 *	- surface_stretch()の応用例です。
 *	  サーフェイスを縮小し、再度、拡大することで、ソフトフォーカス効果が得られます。
 *	- ソフトフォーカスの度合いは、水平(x)、垂直(y)、独立に指定できるようにしました。
 *	  片方を1.0(効果無し)に固定したまま、もう一方を1.0⇔0.0に変化させると、面白い効果が得られます。
 *	  通常のソフトフォーカスを行う場合は、両方に同じ値を指定してください。
 *	- 度合いのパラメータ(x,y)をfixedとせず、doubleとした理由は、以下のとおりです。
 *	  ①clipfixやframfixモジュールが、無駄にリンクされるのを防ぐためです。
 *	    2007/11/05現在、clippceやclipren2等の必須モジュールは、clipfixやframfixを利用していません。
 *	    アプリケーションプログラム内で固定小数を使わず、かつ、clipren3等のモジュールも使わなければ、
 *	    clipfixやframfixモジュールをリンクせずに済みます。
 *	    もし、soft_focus()が固定小数を使ってしまうと、soft_focus()は必須モジュールであるclipren2に
 *	    含まれているので、clipfixやframfixモジュールも必ずリンクされてしまい、無駄です。
 *	    このような無駄を避けるために、固定小数の使用を避けました。
 *	    その代わりに、adddf3やmuldf3等の浮動小数モジュールが参照されますが、
 *	    これらは既に必須モジュールであるclipprntから参照されており、今回増加するわけではありません。
 *	  ②soft_focus()の実行時間が充分に長く、浮動小数演算のオーパーヘッドが無視できるからです。
 *	    soft_focus()の実行時間は、パラメータにもよりますが、おおよそ100～200ミリ秒程度と推測します。
 *	    これは、soft_focus()内で浮動小数演算が占める時間や、アプリケーションかsoft_focus()への
 *	    パラメータ計算のために浮動小数演算を要する時間よりも充分に長いです。
 *	    従って、パラメータが浮動小数演算であっても、オーパーヘッドは無視できると考えました。
 *	- <使用例>
 *		int i = UPDOWN_MOTION(now, 30);	// 0,1,2,...,27,28,29,28,27,...,2,1,0,1,2,...
 *		double t = i / 29.0;		// 0.0→1.0→0.0→1.0→...
 *		t = pow(t, 2.0);		// 効果かかり始め(1.0付近)の変化を早めます。(調整可)
 *		soft_focus(&surface, t, t);	// ソフトフォーカスをかけます。
 */
void soft_focus(SURFACE* surface, double x, double y);

/* サーフェイスの描画結果を、テクスチャ画像に取り込みます。
 * [in]
 *	texture		取り込み先のテクスチャ。
 *	surface		取り込み元のサーフェイス。
 *	x		取り込み元の領域の左上X座標。
 *	y		取り込み元の領域の左上Y座標。
 * [note]
 *	* 取り込み先のテクスチャは、あらかじめ以下のフィールドが設定されている必要があります。
 *		texture->header.bpp	1(P/ECE仕様)、2(P/ECE仕様)、または、4(CLiP拡張)
 *		texture->header.mask	0(マスク無し)、または、1(マスク有り)
 *		texture->header.w	8の倍数(P/ECE仕様)
 *		texture->header.h	任意(P/ECE仕様)
 *		texture->buf		[bpp×w×h÷8]バイト以上のバッファ
 *		texture->mask		マスク有りの場合は、[1×w×h÷8]バイト以上のバッファ
 *	  texture->buf(,texture->mask)がRAMに在るならば、プログラムに埋め込んだテクスチャに画像を取り込んで、書き換えることも可能です。
 *	* 以下のフィールドが設定されていても、本関数の動作に影響しません。
 *		texture->header.head	検査しません
 *		texture->header.fsize	検査しません
 *		texture->buf_size	検査しません
 *	* 取り込み元の領域は、引数(x,y)を原点とし、取り込み先テクスチャ全体サイズ(w,h)に相当する矩形です。
 *	  この矩形が、取り込み元サーフェイスをはみ出さないよう、注意してください。
 *	  また、取り込み先テクスチャの一部だけに、画像を取り込むことはできません。
 *	* マスク無しの場合、取り込み元のサーフェイスに、テクスチャのbppで表せない値のピクセルが有ると、取り込んだ画像は不正となります。
 *	  たとえば、テクスチャのbpp=2の場合に、取り込み元のサーフェイスに、値=4以上のピクセルが有ると、取り込んだ画像は不正となります。
 *	* マスク有りの場合、取り込み元のサーフェイスに、テクスチャのbppで表せない値のピクセルが有ると、そのピクセルは透明色となります。
 *	* 以下に、使用例を示します。
 *		#define BPP 2
 *		#define W 64
 *		#define H 64
 *		unsigned char tbuff[BPP * W * H / 8];
 *		unsigned char tmask[  1 * W * H / 8];
 *		TEXTURE tex = { header : { bpp : BPP, mask : 1, W : 64, H : 64 }, buf : tbuff, mask : tmask };
 *		void test() {
 *			// surfaceに描画
 *			surface_clear(&surface, -1); // 背景を透明色として取り込む
 *			render_printf(&render, 56, 36, 0x81, 3, "%02d", now % 100);
 *			// surfaceの中央付近を、texの画像に取り込む
 *			texture_copy(&tex, &surface, 32, 12);
 *			// texに取り込んだ画像を、モデルに貼り付けて、surfaceに再描画
 *			surface_clear(&surface, 0);
 *			render.context->texture = &tex;
 *			render_mesh(&render, &MESH_MODEL);
 *		}
 */
void texture_copy(TEXTURE* texture, SURFACE* surface, int x, int y);

/*****************************************************************************
 *	RENDER
 *****************************************************************************/

#define RENDER_CONTEXT_STACK_SIZE	16			/* コンテキストスタックサイズ */

/* _render_object()のASM版からオフセット固定で直接扱うため、全体をレイアウト固定とします。 (2007/09/27追記) */
typedef struct _RENDERCONTEXT {
	matrix matrix;						/* + 0,48: 変換行列              */
	TEXTURE* texture;					/* +48, 4: テクスチャ(NULL:なし) */
} RENDERCONTEXT;						/* +52 */

/* _render_object()のASM版からオフセット固定で直接扱うため、全体をレイアウト固定とします。 (2007/09/27追記) */
typedef struct _RENDER {
	SURFACE* surface;					/* + 0, 4: 描画サーフェイス                 */
	short left;						/* + 4, 2: ビューポート矩形(グリッド座標系) */
	short top;						/* + 6, 2:                                  */
	short right;						/* + 8, 2:                                  */
	short bottom;						/* +10, 2:                                  */
	/* ↑ここより上↑はrender_line()アセンブラ版から直接扱うため、レイアウト固定です。 (2004/12/20現在) */
	/* ↑render_font()のASM版からも、オフセット固定で参照するようになりました。        (2007/09/19追記) */
	/* ↓ここより下↓を直接扱うアセンブラ版関数はまだ無いので、レイアウト変更可能です。(2004/12/20現在) → _render_object()のASM版から、オフセット固定で参照するようになりました。(2007/09/27追記) */
	fixed front;						/* +12, 4: クリッピング距離(3D描画専用)     */
	fixed back;						/* +16, 4:                                  */
	RENDERCONTEXT* context;					/* +20, 4: コンテキストスタックトップ       */
	/* ↑ここより上↑は_render_object()のASM版から直接扱うため、レイアウト固定です。   (2007/09/27追記) */
	RENDERCONTEXT context_stack[RENDER_CONTEXT_STACK_SIZE];	/* +24, ?: コンテキストスタック             */
} RENDER;

/* フレームを初期化します。
 * [in]
 *	render		レンダラーへのポインタ。
 *	surface		描画サーフェイス。
 *	x,y		ビューポート原点。
 *	width,height	ビューポートサイズ。
 *	front,back	クリッピング距離。
 *	fovy		垂直視野角度。
 * [note]
 *	* width,heightに0を指定すると、サーフェイスの幅、高さと同じと見なします。
 *	  従って、サーフェイス全体をビューポート領域として指定するには、
 *	  x,y,width,heightを0,0,0,0と指定するのが簡単です。
 *	* 3D描画を行わない場合は、front,back,fovyに全て0を指定してください。
 *	  front,back,fovyに全て0を指定した場合、変換行列は初期化されません。
 *	* この関数は、サーフェイスのクリアを行いません。
 *	  カラーバッファおよびＺバッファのクリアは、呼び出し側で行ってください。
 *	* 2003/09/14: 2D用と3D用に初期化関数を分けました。
 *	  2D用として初期化する場合は、もうfront/back/fovyに0を指定する必要はありません。
 */
void render_init_2d(RENDER* render, SURFACE* surface, int x, int y, int width, int height);
void render_init_3d(RENDER* render, SURFACE* surface, int x, int y, int width, int height, fixed front, fixed back, fixed fovy);

/* コンテキストを退避します。
 * [in]
 *	render		レンダラーへのポインタ。
 */
void render_save(RENDER* render);

/* コンテキストを復元します。
 * [in]
 *	render		レンダラーへのポインタ。
 */
void render_restore(RENDER* render);

/* 点を描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x,y		点の座標。
 *	color		カラー。
 * [note]
 *	* この関数は、surface_point()と対を成します。
 */
void render_point(RENDER* render, int x, int y, int color);

/* 同じ色の範囲を塗りつぶします。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x0,y0		塗りつぶし開始点。
 *	color		カラー。
 * [out]
 *	戻り値		塗ったピクセルの数。
 * [note]
 *	* (x0,y0)の色が続く範囲を、colorで塗りつぶします。
 *	  (x0,y0)の色が既にcolorと同じなら、何もしません。
 *	* (x0,y0)がビューポート外なら、何もしません。
 */
int render_paint(RENDER* render, int x0, int y0, int color);

/* 線分を描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x0,y0		始点座標。
 *	x1,y1		終点座標。
 *	color		カラー。
 * [note]
 *	* 多角形を描くために、連続して呼び出されることを想定しています。
 *	  よって、終点ピクセル(x1,y1)は描きません。
 *	* ただし実装の都合上、クリッピングされた側の終点も描かないので、
 *	  画面内から画面外への線分を描こうとすると、画面端に1ピクセルの
 *	  すき間ができてしまいます。要修正。
 *	* Fri Mar  8 07:00:00 JST 2002 Naoyuki Sawa
 *	  修正しました。
 */
void render_line(RENDER* render, int x0, int y0, int x1, int y1, int color);

/* 破線を描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x0,y0		始点座標。
 *	x1,y1		終点座標。
 *	i_pat		破線パターンの開始インデックス。
 *	pat		//破線パターン。(カラー値の配列。値4以上は透明)
 *			//↓* Tue May 16 17:10:00 JST 2006 Naoyuki Sawa
 *			//↓- render_dashes()を16階調モードでも利用できるよう、透明色の定義を変更しました。
 *			//↓  これまでは4以上を透明色として扱っていましたが、今後は16以上を透明色とします。
 *			破線パターン。(カラー値の配列。値16以上は透明)
 *	n_pat		破線パターンの要素数。(1以上)
 * [out]
 *	戻り値		破線パターンの終了インデックス＋１。
 *			連続した線分を描くときは、この戻り値を次のrender_dashes()呼び出しのi_patに渡せば、
 *			破線パターンがうまくつながります。
 * [note]
 *	* n_patに0を指定すると、ゼロ除算エラーが発生します。
 *	* i_pat>=n_patでも構いません。適切な繰り返し位置から開始します。
 */
int render_dashes(RENDER* render, int x0, int y0, int x1, int y1, unsigned i_pat, const unsigned char* pat, unsigned n_pat);

/* 矩形を描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x,y		左上原点座標。
 *	w,h		矩形のサイズ。
 *	color		カラー。
 * [note]
 *	* 座標とサイズはグリッド座標系で指定してください。(Windows GDIと同様です)
 */
void render_rectangle(RENDER* render, int x, int y, int w, int h, int color);

/* 矩形座標の正規化とクリッピングを行います。
 * [in]
 *	(px,py,pw,ph)		変更前の座標値へのポインタ。
 * [out]
 *	戻り値			0 = 完全に画面外。
 *				    描画を行う必要はありません。
 *				    (*px,*py,*pw,*ph)は変更しません。
 *				1 = 少なくとも一部が画面内。
 *				    描画を行う必要があります。
 *				    (*px,*py,*pw,*ph)は変更されます。
 *	(*px,*py,*pw,*ph)	変更後の座標値を格納します。
 *				戻り値が0の場合は、格納しません。
 */
int render_rectangle_clip(RENDER* render, int* px, int* py, int* pw, int* ph);

/* 矩形を塗りつぶします。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x,y		左上原点座標。
 *	w,h		矩形のサイズ。
 *	color		カラー。
 * [note]
 *	* 座標とサイズはグリッド座標系で指定してください。(Windows GDIと同様です)
 */
void render_rectangle_fill(RENDER* render, int x, int y, int w, int h, int color);

/* 矩形領域のピクセル値を増減します。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x,y		左上原点座標。
 *	w,h		矩形のサイズ。
 *	adjust		ピクセル値増加量、または、ピクセル値減少量。
 *			(adjust<0)の場合、ピクセル値を減少します。
 *			(adjust>0)の場合、ピクセル値を増加します。
 *			(adjust=0)の場合、何もしません。
 *	limit		ピクセル値上限、または、ピクセル値下限。
 *			(adjust<0)の場合、(limit=ピクセル値下限)と見なします。
 *			  ピクセル値を減少した結果、limitを下回ったら、limitに補正します。
 *			  通常は、0を指定してください。
 *			  0以外の値を指定することも可能です。
 *			(adjust>0)の場合、(limit=ピクセル値上限)と見なします。
 *			  ピクセル値を増加した結果、limitを上回ったら、limitに補正します。
 *			  通常は、3(4階調表示)、または、15(16階調表示)を指定してください。
 *			  3、または、15以外の値を指定することも可能です。
 *			(adjust=0)の場合、limitは意味を持ちません。
 * [note]
 *	* 座標とサイズはグリッド座標系で指定してください。(Windows GDIと同様です)
 */
void render_rectangle_shadow(RENDER* render, int x, int y, int w, int h, int adjust, int limit);

/* 楕円を描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x,y		楕円に外接する矩形の左上原点座標。
 *	w,h		楕円に外接する矩形のサイズ。
 *	color		カラー。
 * [note]
 *	* 座標とサイズはグリッド座標系で指定してください。(Windows GDIと同様です)
 */
void render_ellipse(RENDER* render, int x, int y, int w, int h, int color);

/* 楕円を塗りつぶします。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x,y		楕円に外接する矩形の左上原点座標。
 *	w,h		楕円に外接する矩形のサイズ。
 *	color		カラー。
 * [note]
 *	* 座標とサイズはグリッド座標系で指定してください。(Windows GDIと同様です)
 */
void render_ellipse_fill(RENDER* render, int x, int y, int w, int h, int color);

/* ポリゴンを描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	vertices	頂点リスト。
 *	n_vertices	頂点の数。
 *	color		カラー。
 */
void render_polygon(RENDER* render, const VERTEX* vertices, int n_vertices, int color);

/* メッシュを描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	mesh		描画されるメッシュ。
 */
void render_mesh(RENDER* render, const MESH* mesh);

/* メッシュファイルをロードします。
 * [in]
 *	filename	メッシュファイル名。
 *	//{{2008/08/10:追加
 *	convert_fixed	0 = <vector>要素を浮動小数点のままで、浮動小数点MESHとする。
 *			1 = <vector>要素を固定小数点に変換し、固定小数点MESHとする。
 *	//}}2008/08/10:追加
 * [out]
 *	戻り値		メッシュ構造体のメモリブロック。
 *			不要になったら、free()を呼び出して解放してください。
 * [note]
 *	* ファイルが見つからなかったり、読み込みエラーが発生した場合は、DIE()によって停止します。
 *	  本関数が失敗時にNULLを返すことは無いので、呼び出し側にて戻り値を検査する必要はありません。
 *	* メッシュファイル形式については、tool/ExportPieceClipを参照してください。
 *	  独自定義のXML形式メッシュ情報を出力する、Metasequoia用の自作プラグインです。
 */
//{{2008/08/10:変更
//MESH* mesh_load(const char* filename); /* → clipobj3.c */
//↓2008/08/10:変更
MESH* mesh_load(const char* filename, int convert_fixed); /* → clipobj3.c */
//}}2008/08/10:変更

/* オブジェクトのエッジを描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	threshold	隣り合ったピクセルの、視点からの深度の差がthreshold(閾値)以上ならば、エッジと判定します。
 *			Zバッファ値ではなく、実座標系での値で指定してください。
 *			たとえば、背面クリップ距離=100.0の場合に、視界の1/20を閾値とするならば、5.0を指定します。
 *			* Sat May 09 13:21:42 JST 2009 Naoyuki Sawa 追記
 *			- thresholdに小さすぎる値が指定された場合にも、視界に応じた最小有効値に切り上げる処理を追加しました。
 *			  したがって、thresholdに0.0を指定すれば、自動的に最小有効値でエッジ検出を行います。
 *			  ただし、斜めの平面に誤ったエッジが発生する可能性は高くなるので、注意してください。
 * [note]
 *	* クリッピング領域外には、エッジを描画しません。
 *	  適切にクリッピング領域を狭めておくことにより、処理時間を短縮することができます。
 *	* 初回、および、render->front,render->back,thresholdのいずれかが変化すると、パラメータの再計算を行います。
 *	  パラメータの再計算には、数100ミリ秒程度の時間がかかるため、以下のような工夫が必要です。
 *	  - ゲーム中に初回の再計算が発生しないよう、ゲーム開始前にダミーの初回呼び出しを行っておく。
 *	  - render->front,render->back,thresholdは、ゲーム中には変化させないようにする。
 * [使用例]
 *		surface_clear(&surface, 0);
 *		...
 *		render_mesh(&render, &MESH1);
 *		render_mesh(&render, &MESH2);
 *		render_mesh(&render, &MESH3);
 *		...
 *		render_edge(&render, fld(5.0));
 */
void render_edge(RENDER* render, fixed threshold);

#endif /*__CLIP_REND_H__*/
