/*
 *	clipint.c
 *
 *	整数演算ライブラリ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Sat Sep 12 20:19:17 JST 2009 Naoyuki Sawa
 *	- 新規作成。
 *	- clipflt.hモジュール互換仕様の整数版です。
 *	  今回はrender_vec2i_alternate_concaves()だけが必要だったので、そのための最小限の関数以外はほとんど未実装です。
 *	* Sun Sep 13 15:47:06 JST 2009 Naoyuki Sawa
 *	- vec2i_is_point_in_concave()をアセンブラ化し、高速化しました。
 *	* Tue Oct 04 23:23:40 JST 2016 Naoyuki Sawa
 *	- これまで長い間、当モジュールで実装済みだった関数はvec2i_is_point_in_concave,vec2i_is_point_in_alternate_concaves,render_vec2i_alternate_concavesだけで、
 *	  それ以外の関数は未実装のままだったのですが、今回、DxlibHelper.cppの「太いポリラインの描画」のために整数ベクトル演算が必要になって、それ以外の関数も実装を行いました。
 *	  詳細は、以下の通りです。
 *	- sqrtiを追加しました。(sqrt,sqrtf,sqrtlの命名規則に倣っただけで、標準Cライブラリで定義されている関数ではありません。)
 *	- vec2i_0,vec2i_1,vec2i_x,vec2i_yが未実装だったのを、実装しました。
 *	- vec2i_add,vec2i_sub,vec2i_mul,vec2i_divが未実装だったのを、実装しました。
 *	- vec2i_neg,vec2i_normalが未実装だったのを、実装しました。
 *	- vec2i_mag,vec2i_mag2,vec2i_dot,vec2i_crossが未実装だったのを、実装しました。
 *	- vec2i_dist,vec2i_dist2が未実装だったのを、実装しました。
 *	- vec2i_distance_l_p,vec2i_intersection_l_p,vec2i_intersection_l,vec2i_is_intersected_lsが未実装だったのを、実装しました。
 *	- vec2i_is_point_in_convex,vec2i_is_intersected_pが未実装だったのを、実装しました。
 *	- 今回の実装は、ほとんど、clipflt1.cのソースをコピーして〜fを〜iに変えた事以外は、型の違いによる修正を少し行っただけです。
 *	  ただし、本当にそれで正しく動作しているか、まだ検証が不十分です。
 *	  今後、実際にアプリケーションで使用しながら、検証を行う予定です。
 *	  尚、vec2i_is_point_in_concave,vec2i_is_point_in_alternate_concaves,render_vec2i_alternate_concavesだけは既に実装済みだった関数で、2009年当時の実装時にある程度検証済みです。
 *	- vec2f_〜は浮動小数演算なのでゼロ除算例外は発生しませんでしたが、vec2i_〜では整数演算なのでゼロ除算例外が発生する事に注意して下さい。
 *	  具体的には、vec2i_div(),vec2i_normal(),vec2i_distance_l_p(),vec2i_intersection_l()、及び、それらを内部で呼び出している処理で、ゼロ除算例外が発生する可能性が有ります。
 *	  ゼロ除算が発生しないように、呼び出し側で、引数を検査して下さい。
 *	  ちなみに、VC++6.0やP/ECEでは、浮動小数演算のゼロ除算例外は発生しませんが、「Borland C++ 5.5.1 for Win32」では、浮動小数演算でもゼロ除算例外が発生するようです。
 *	* Thu Oct 06 21:47:33 JST 2016 Naoyuki Sawa
 *	- sqrtu()を追加し、既存のsqrti()と追加したsqrtu()の実装を共通化しました。
 *	  詳細は、以下の通りです。
 *	- これまでは、開平法の解説が判り易い、「プログラムモグモグ」(http://itchyny.hatenablog.com/)さんの「2010-12-22 平方根なんてビット演算ですればいいじゃない」(http://itchyny.hatenablog.com/entry/20101222/1293028538)のソースを利用させて頂いていました。
 *	  今回、簡潔でP/ECEに適した開平法の実装である、「Ｐ／ｗａｒｅ」(http://park17.wakwak.com/~hitode/)さんの「平方根(2003-05-21)」「平方根その２(2003-05-22)」(http://park17.wakwak.com/~hitode/piece/index.html#isqrt)を見付けたので、そちらに変更しました。
 *	  C言語版は、「平方根(2003-05-21)」の「isqr()」をそのまま利用させて頂きました。
 *	  アセンブラ版は、「平方根その２(2003-05-22)」の「isqr:」(筆算方式)をベースに、少しだけ改善させて頂きました。
 *	  本当は、P/ECEでは、「平方根その２(2003-05-22)」の「isqr2:」(掛け算方式)の方が早くて小さいのですが、今回は開平法の勉強と言う事で、敢えて「isqr:」(筆算方式)の方を使う事にしました。
 *	* Fri Oct 07 21:38:15 JST 2016 Naoyuki Sawa
 *	- vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
 *	  浮動小数点版のvec2f_is_intersected_ls()では、オーバーフローは発生し辛いので、上記の問題は無かったのですが、整数版のvec2i_is_intersected_ls()では、簡単にオーバーフローが発生するので、この問題が顕著でした。
 *	  例えば、これまで、DxlibHelper.cppのdraw_spr_thick_polyline()に対して、縦横500ピクセル以上の距離が有る線分を指定した場合に、draw_spr_thick_polyline()から呼び出されたvec2i_is_intersected_ls()にて上記の問題が発生し、太いポリラインの接合部分の交差判定が間違って、線分が途切れたような不正な描画結果になっていました。
 *	  <例>これまで不正な描画結果になっていたコードの例
 *	  │const int xy[][2]={{100,100},{600,100},{600,600},{1100,600}};
 *	  │const double uv[][2][2]={{{0,0},{0,1}},{{0.3,0},{0.3,1}},{{0.7,0},{0.7,1}},{{1,0},{1,1}}};
 *	  │draw_spr_thick_polyline(xy,uv,4,50,SprNo_OPEN);
 *	  上記の問題の対策として、今回、vec2i_is_intersected_ls()の中で、外積と外積の乗算を用いて0,及び,同符号の判定を行うのをやめて、明示的に0,及び,同符号の判定を行うように変更しました。
 *	  今回の対策によって、前述の例のコードでも、正しく描画出来るようになりました。
 *	* Sun Oct 09 21:21:44 JST 2016 Naoyuki Sawa
 *	- render_vec2i_thick_polyline()を追加しました。
 *	  関数宣言は、cliprend.hに有ります。
 *	* Sun Oct 23 10:04:30 JST 2016 Naoyuki Sawa
 *	- vec2i_split_polygon_into_triangles()を追加しました。
 *	* Mon Oct 24 21:50:37 JST 2016 Naoyuki Sawa
 *	- vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。
 *	  変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
 *	  変更した理由は、以下の通りです。
 *	- vec2i_split_polygon_into_triangles()は、以下のような原因で、分割失敗する可能性が有ります。
 *	  ・指定された多角形の中に、交差している辺が有る。(=正しい多角形ではない)
 *	  ・演算誤差のために、誤って、三角形の内部に残りの頂点が有ると見なしてしまい、分割出来ないと判断してしまう。
 *	  これまでは、前者,後者共に、分割処理中に一回でも上記のケースが生じたら、全体を分割失敗と見なしていたのが問題でした。
 *	  少しでも分割出来ない部分が有ると、その多角形全体が描かれず、見た目にちらつきが生じるからです。
 *	- そこで、見た目のちらつきを緩和するための対策として、一か所でも失敗したら全体を描かないのではなく、分割出来た所までは描くように変更しました。
 *	  そのために、vec2i_split_polygon_into_triangles()の戻り値の意味を変更し、分割出来た所までの三角形の数を返す事にしました。
 *	  呼び出し側では、戻り値の数ぶんの所まで、tri_p[]を描画すれば良いです。
 *	  もし、分割が完全に成功したか、一部でも失敗したかを、呼び出し側で判断する必要が有る場合は、戻り値が(n-2)に等しいかを判定すれば良いです。
 *	- 実験した所、誤差による分割失敗が起き易い頂点の多い多角形(100角形等)でも、実際に分割失敗するのは、最後の98個目の三角形の切り取り時でした。
 *	  要するに、最後に残った3頂点が、演算誤差で逆回りの形で残ってしまい、切り取りに失敗するようです。
 *	  この場合、既に97個の三角形が切り取れているわけで、それを描くだけで見た目上はほぼ十分です。
 *	  従って、今回の対策は有効であると思います。
 *	* Mon Oct 24 21:50:37 JST 2016 Naoyuki Sawa
 *	- render_vec2i_render_polygon(),render_vec2i_render_polygon_fill()を追加しました。
 *	  関数宣言は、cliprend.hに有ります。
 */
#include "clip.h"
/****************************************************************************
 *	汎用
 ****************************************************************************/
//{{2016/10/06変更:sqrtu()を追加し、既存のsqrti()と追加したsqrtu()の実装を共通化しました。
//int sqrti(int x) {
//	if(x < 0) { DIE(); }
//	{
//		//二進数の開平法を使って平方根を求める。
//		// - 「プログラムモグモグ」(http://itchyny.hatenablog.com/)さんの
//		//   「2010-12-22 平方根なんてビット演算ですればいいじゃない」(http://itchyny.hatenablog.com/entry/20101222/1293028538)の記事を参考にさせて頂きました。
//		int a = 0, y = 0, i = 0, t = x;
//		while(t >>= 1) { i++; }
//		for(i += (i & 1); i >= 0; i -= 2) {
//			int c = ((y << 1) | 1) <= (x >> i);
//			    a =  (a << 1) | c;
//			    y =  (y << 1) | c;
//			    x -= (c * y) << i;	//この行の処理は「if(c) { x -= y << i; }」と等価です。
//			    y += c;
//		}
//		return a;
//	}
//}
//↓2016/10/06変更:sqrtu()を追加し、既存のsqrti()と追加したsqrtu()の実装を共通化しました。
// * Thu Oct 06 21:47:33 JST 2016 Naoyuki Sawa
// - sqrtu()を追加し、既存のsqrti()と追加したsqrtu()の実装を共通化しました。
//   詳細は、以下の通りです。
// - これまでは、開平法の解説が判り易い、「プログラムモグモグ」(http://itchyny.hatenablog.com/)さんの「2010-12-22 平方根なんてビット演算ですればいいじゃない」(http://itchyny.hatenablog.com/entry/20101222/1293028538)のソースを利用させて頂いていました。
//   今回、簡潔でP/ECEに適した開平法の実装である、「Ｐ／ｗａｒｅ」(http://park17.wakwak.com/~hitode/)さんの「平方根(2003-05-21)」「平方根その２(2003-05-22)」(http://park17.wakwak.com/~hitode/piece/index.html#isqrt)を見付けたので、そちらに変更しました。
//   C言語版は、「平方根(2003-05-21)」の「isqr()」をそのまま利用させて頂きました。
//   アセンブラ版は、「平方根その２(2003-05-22)」の「isqr:」(筆算方式)をベースに、少しだけ改善させて頂きました。
//   本当は、P/ECEでは、「平方根その２(2003-05-22)」の「isqr2:」(掛け算方式)の方が早くて小さいのですが、今回は開平法の勉強と言う事で、敢えて「isqr:」(筆算方式)の方を使う事にしました。
#ifndef PIECE
int sqrti(int s/*0〜INT_MAX*/) {
	if(s < 0) { DIE(); }
	return sqrtu(s);
}
unsigned sqrtu(unsigned s/*0〜UINT_MAX*/) {
	unsigned t = 0x40000000, h = 0, a = 0;
	do{
		unsigned b = h + t;
		a <<= 1;
		h >>= 1;
		if(s >= b) {	//アセンブラ版では、「s >= b」ではなく、「(s+1) > b」で比較を行っています。
			s -= b;
			a++;
			h += t;
		}
	} while(t >>= 2);
	return a;
}
#else //PIECE
int sqrti(int s/*0〜INT_MAX*/);
unsigned sqrtu(unsigned s/*0〜UINT_MAX*/);
asm("
		.code
		.align		1
		.global		sqrti
		.global		sqrtu
sqrti:
		;//%r12 := s
		cmp		%r12, 0				;//if(s < 0) { DIE() }
		jrlt		sqrti_DIE			;//return sqrtu(s)
		;//---------------------------------------------;//
		;//%r12 := s
sqrtu:
		ld.w		%r13, 1				;//%r13 := t = 0x40000000
		rr		%r13, 2				;//
		ld.w		%r10, 0				;//%r10 := a = 0
		ld.w		%r11, %r10			;//%r11 := h = 0
		add		%r12, 1				;//%r12 := (s+1)				【ここがポイント】本来は'<='である比較を、'<'の比較にに変えるために、あらかじめ比較対象の右辺に'+1'しています。こうする事で、比較結果のキャリーフラグをそのまま、変数aにシフトイン出来ます。
		sbc		%r12, %r10			;//if((s+1) == 0) { %r12 := UINT_MAX }		ただし、s=UINT_MAXだった場合に、(s+1)=0になってしまう問題が有ります。そこで、s=UINT_MAXの場合は、(s+1)=UINT_MAXに補正します。√UINT_MAXも√(UINT_MAX-1)も65535なので、正しい結果となります。
		ld.w		%r14, %r11			;//%r14 := b = h		────┐
sqrtu_LOOP:							;//do {					│
		add		%r14, %r13			;//  %r14 := b += t		←───┤
		srl		%r11, 1				;//  %r11 := h >>= 1			│
		cmp		%r14, %r12			;//  %psr(C) := b < (s+1)		│
		jruge.d		sqrtu_SKIP			;//  if(b < (s+1)) {			│
		adc		%r10, %r10			;//  %r10 := (a << 1) | %psr(C)		│	*delay*
		sub		%r12, %r14			;//    %r12 := (s+1) -= b		│
		add		%r11, %r13			;//    %r11 := h += t			│
sqrtu_SKIP:							;//  }					│
		srl		%r13, 2				;//  %r13 := t >>= 2			│
		jrne.d		sqrtu_LOOP			;//} while(t)				│
		ld.w		%r14, %r11			;//  %r14 := b = h		────┘	*delay*
		ret						;//return a
");
static void __attribute__((noreturn,unused))/*asmブロックから参照*/ sqrti_DIE() { DIE(); }
#endif//PIECE
//}}2016/10/06変更:sqrtu()を追加し、既存のsqrti()と追加したsqrtu()の実装を共通化しました。
/****************************************************************************
 *	整数ベクトル(2D)
 ****************************************************************************/
//{{2016/10/04削除:vec2i_sub(),vec2i_cross()を関数として実装したので、マクロ定義は削除しました。
//#define vec2i_sub(vec1, vec2)	\
//	(vec1)->x -= (vec2)->x;	\
//	(vec1)->y -= (vec2)->y;
//#define vec2i_cross(vec1, vec2)	\
//	(((vec1)->x * (vec2)->y) - ((vec1)->y * (vec2)->x))
//}}2016/10/04削除:vec2i_sub(),vec2i_cross()を関数として実装したので、マクロ定義は削除しました。
/*--------------------------------------------------------------------------*/
const vec2i vec2i_0 = { 0, 0 };
const vec2i vec2i_1 = { 1, 1 };
const vec2i vec2i_x = { 1, 0 };
const vec2i vec2i_y = { 0, 1 };
/*--------------------------------------------------------------------------*/
void vec2i_add(vec2i* vec1, const vec2i* vec2) {
	vec1->x += vec2->x;
	vec1->y += vec2->y;
}
void vec2i_sub(vec2i* vec1, const vec2i* vec2) {
	vec1->x -= vec2->x;
	vec1->y -= vec2->y;
}
void vec2i_mul(vec2i* vec1, const vec2i* vec2) {
	vec1->x *= vec2->x;
	vec1->y *= vec2->y;
}
void vec2i_div(vec2i* vec1, const vec2i* vec2) {
	vec1->x /= vec2->x;
	vec1->y /= vec2->y;
}
/*--------------------------------------------------------------------------*/
void vec2i_neg(vec2i* vec) {
	vec->x = -vec->x;
	vec->y = -vec->y;
}
void vec2i_normal(vec2i* vec) {
	int mag = vec2i_mag(vec);
	vec->x /= mag;
	vec->y /= mag;
}
/*--------------------------------------------------------------------------*/
int vec2i_mag(const vec2i* vec) {
	return sqrti(vec2i_mag2(vec));
}
int vec2i_mag2(const vec2i* vec) {
	return vec2i_dot(vec, vec);
}
int vec2i_dot(const vec2i* vec1, const vec2i* vec2) {
	return (vec1->x * vec2->x) + (vec1->y * vec2->y);
}
int vec2i_cross(const vec2i* vec1, const vec2i* vec2) {
	return (vec1->x * vec2->y) - (vec1->y * vec2->x);
}
/*--------------------------------------------------------------------------*/
/* 二点間の距離を求める */
int vec2i_dist(const vec2i* vec1, const vec2i* vec2) {
	return sqrti(vec2i_dist2(vec1, vec2));
}
/* 二点間の距離の二乗を求める */
int vec2i_dist2(const vec2i* vec1, const vec2i* vec2) {
	vec2i tmp = *vec1;
	vec2i_sub(&tmp, vec2);
	return vec2i_mag2(&tmp);
}
/*--------------------------------------------------------------------------*/
/* 点a,bを通る直線と点cとの距離 */
int vec2i_distance_l_p(const vec2i* a, const vec2i* b, const vec2i* c) {
	vec2i v1;
	vec2i v2;
	v1 = v2 = *a;
	vec2i_sub(&v1, b);	/* a-b */
	vec2i_sub(&v2, c);	/* a-c */
	return abs(vec2i_cross(&v1, &v2) / vec2i_mag(&v1));
}
/* a,bを通る直線と、点cから直線へ下ろした垂線との交点計算 */
vec2i vec2i_intersection_l_p(const vec2i* a, const vec2i* b, const vec2i* c) {
	vec2i d;
	d.x = (a->y - b->y) + c->x;
	d.y = (b->x - a->x) + c->y;
	return vec2i_intersection_l(a, b, c, &d);
}
/* a1,a2を通る直線とb1,b2を通る直線の交点計算 */
vec2i vec2i_intersection_l(const vec2i* a1, const vec2i* a2, const vec2i* b1, const vec2i* b2) {
	vec2i a;
	vec2i b;
	vec2i c;
	int a_b, a_c;
	a = *a2; vec2i_sub(&a, a1);	/* a2-a1 */
	b = *a1; vec2i_sub(&b, b2);	/* a1-b2 */
	c = *b1; vec2i_sub(&c, b2);	/* b1-b2 */
	a_b = vec2i_cross(&a, &b);		//┐
	a_c = vec2i_cross(&a, &c);		//│vec2f_intersection_l()では浮動小数演算なので除算⇒乗算の順に行っていたが、
	a.x = ((c.x * a_b) / a_c) + b2->x;	//│vec2i_intersection_l()は整数演算なので乗算⇒除算の順で行うように変更した。
	a.y = ((c.y * a_b) / a_c) + b2->y;	//┘
	return a;
}
/* a1,a2を端点とする線分とb1,b2を端点とする線分の交差判定 */
int vec2i_is_intersected_ls(const vec2i* a1, const vec2i* a2, const vec2i* b1, const vec2i* b2) {
	vec2i v1;
	vec2i v2;
	vec2i v3;
//{{2016/10/07追加:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
	int c12, c13;
//}}2016/10/07追加:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
	/* 点b1と点b2が、直線a1→a2に対して異なる側にあるか? */
	v1 = v2 = v3 = *a1;
	vec2i_sub(&v1, a2);	/* a1-a2 */
	vec2i_sub(&v2, b1);	/* a1-b1 */
	vec2i_sub(&v3, b2);	/* a1-b2 */
//{{2016/10/07変更:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
//	if((vec2i_cross(&v1, &v2) * vec2i_cross(&v1, &v3)) >= 0) {
//↓2016/10/07変更:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
	c12 = vec2i_cross(&v1, &v2);			//(v1×v2)
	c13 = vec2i_cross(&v1, &v3);			//(v1×v3)
	if(!c12 || !c13 || ((c12 ^ c13) >= 0)) {	//(v1×v2)が0,又は,(v1×v3)が0,又は,(v1×v2)と(v1×v3)が同符号ならば…
//}}2016/10/07変更:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
		return 0; /* 同じ側 */
	}
	/* 点a1と点a2が、直線b1→b2に対して異なる側にあるか? */
	v1 = v2 = v3 = *b1;
	vec2i_sub(&v1, b2);	/* b1-b2 */
	vec2i_sub(&v2, a1);	/* b1-a1 */
	vec2i_sub(&v3, a2);	/* b1-a2 */
//{{2016/10/07変更:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
//	if((vec2i_cross(&v1, &v2) * vec2i_cross(&v1, &v3)) >= 0) {
//↓2016/10/07変更:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
	c12 = vec2i_cross(&v1, &v2);			//(v1×v2)
	c13 = vec2i_cross(&v1, &v3);			//(v1×v3)
	if(!c12 || !c13 || ((c12 ^ c13) >= 0)) {	//(v1×v2)が0,又は,(v1×v3)が0,又は,(v1×v2)と(v1×v3)が同符号ならば…
//}}2016/10/07変更:vec2i_is_intersected_ls()に対して、大きなベクトルが指定された場合に、外積と外積の乗算がオーバーフローして、間違った結果を返す事が有った問題を修正しました。
		return 0; /* 同じ側 */
	}
	return 1; /* 交差している */
}
/*--------------------------------------------------------------------------*/
/* 点pと、v[nv]を頂点とする凸多角形の内外判定 */
int vec2i_is_point_in_convex(const vec2i* p, const vec2i* v/*[nv]*/, int nv) {
	vec2i a = v[nv - 1];			/* 最初の始点 */
	vec2i b;
	vec2i c;
	int f = 0;				/* 左右の記録 */
	int g;
	do {
		b = a; vec2i_sub(&b, p);	/* 調べる点(p)から、辺の始点(a)へのベクトル */
		c = a; vec2i_sub(&c, v);	/* 辺の終点(v)から、辺の始点(a)へのベクトル */
		g = vec2i_cross(&b, &c);	/* 調べる点が、辺の直線の左右(+/-)どちらにあるかを求める */
		if(g) {				/* 調べる点が辺の直線上(0)ならば、この辺は判断に含めない */
			if(f) {			/* 直線上でない最初の辺ならば、左右の記録のみ */
				if((f ^ g) < 0) {	/* 左右が混在していたら、点は凸多角形の外 */
					return 0;
				}
			}
			f = g;			/* 左右を記録する(初回のみでも良いが、毎回記録する方が処理が簡単) */
		}
		a = *v++;			/* 今回の終点を、次回の始点とする */
	} while(--nv);
	return 1;				/* 左右が混在していなければ、点は凸多角形の内 */
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* 点pと、v[nv]を頂点とする凹多角形の内外判定 */
#ifndef PIECE
int vec2i_is_point_in_concave(const vec2i* p, const vec2i* v/*[nv]*/, int nv) {
	int i;
	int j;
	int n;
	const vec2i* vi;
	const vec2i* vj;
	int xmin;
	int xmax;
	int ymin;
	int ymax;
	int prev;
	int f;
	vec2i v0;
	vec2i v1;
	/* いちばん上の頂点を検索しながら、同時に境界ボックスを求め、おおまかな当り判定を行います。 */
	i = j = nv;
	vi = vj = v;
	xmin = xmax = vj->x;
	ymin = ymax = vj->y;
	vj++;
	j--;
	do {
		if((vj->x < xmin)) {
			xmin = vj->x;
		} else if(vj->x > xmax) {
			xmax = vj->x;
		}
		if((vj->y < ymin)) {
			ymin = vj->y;
			i = j;
			vi = vj;
		} else if(vj->y > ymax) {
			ymax = vj->y;
		}
		vj++;
	} while(--j);
	if((p->x < xmin) || (p->x > xmax) ||
	   (p->y < ymin) || (p->y > ymax)) {
		return 0;
	}
	/* 点を始点とする半直線と、多角形の辺の交差回数が、奇数ならば内側、偶数ならば外側です。 */
	prev = 0;
	n = 0;
	j = nv;
	do {
		v0 = *vi;
		v1 = *vi;
		vi++;
		if(!--i) {
			vi = v;
		}
		vec2i_sub(&v0, p);
		vec2i_sub(&v1, vi);
		f = vec2i_cross(&v0, &v1);
		if(!f) {					/* 点pが辺の直線上にある場合の特別処理 */
			if(v0.x) {				/* 点pが辺の始点上でなく、 */
				if(v0.x < 0) {			/* 点pが辺の始点よりも右で、 */
					if(v0.x < v1.x) {	/* 点pが辺の終点よりも右なら、 */
						goto NOT_ON_LS;	/* 点pは辺の線分上ではないので処理継続 */
					}
				} else /*if(v0.x > 0)*/ {	/* 点pが辺の始点よりも左で、 */
					if(v0.x > v1.x) {	/* 点pが辺の終点よりも左なら、 */
						goto NOT_ON_LS;	/* 点pは辺の線分上ではないので処理継続 */
					}
				}
			}
			if(v0.y) {				/* 点pが辺の始点上でなく、 */
				if(v0.y < 0) {			/* 点pが辺の始点よりも下で、 */
					if(v0.y < v1.y) {	/* 点pが辺の終点よりも下なら、 */
						goto NOT_ON_LS;	/* 点pは辺の線分上ではないので処理継続 */
					}
				} else /*if(v0.y > 0)*/ {	/* 点pが辺の始点よりも上で、 */
					if(v0.y > v1.y) {	/* 点pが辺の終点よりも上なら、 */
						goto NOT_ON_LS;	/* 点pは辺の線分上ではないので処理継続 */
					}
				}
			}
			return -1;				/* 点pは辺の線分上である */
NOT_ON_LS:		;					/* 点pは辺の線分上ではないので処理継続 */
		}
		if(v1.y) {
			if(v1.y < 0) {
				if((f < 0) && (v1.y <= v0.y)) {
					if(prev < 0) {
						if(v0.y < 0) {
							n ^= 1;
						}
					} else {
						if(v0.y <= 0) {
							n ^= 1;
						}
					}
				}
			} else /*if(v1.y > 0)*/ {
				if((f > 0) && (v1.y >= v0.y)) {
					if(prev > 0) {
						if(v0.y > 0) {
							n ^= 1;
						}
					} else {
						if(v0.y >= 0) {
							n ^= 1;
						}
					}
				}
			}
			prev = v1.y;
		}
	} while(--j);
	return n; /* 0 or 1 */
}
#else //PIECE
asm("
		.code
		.align		1
		.global		vec2i_is_point_in_concave
vec2i_is_point_in_concave:
		pushn		%r3
		;// %r12 := p
		;// %r13 := v
		;// %r14 := nv
		;//-----------------------------------------------------;
		ld.w		%r2, %r14				;// %r2  := j = nv
		ld.w		%r3, %r13				;// %r3  := vj = v
		ld.w		%r4, [%r3]+				;// %r4  := xmin = vj->x
		ld.w		%r5, [%r3]+				;// %r5  := ymin = vj->y, %r3  := vj++
		ld.w		%r6, %r4				;// %r6  := xmax = vj->x
		ld.w		%r7, %r5				;// %r7  := ymax = vj->y
		sub		%r2, 1					;// %r2  := j--
		ld.w		%r0, %r2				;// %r0  :=  i - 1 =  j ( iは1つ減った値を保持しておき、確定後に戻す。高速化)
		ld.w		%r1, %r3				;// %r1  := vi + 1 = vj (viは1つ進んだ値を保持しておき、確定後に戻す。高速化)
		;// %r0  :=  i - 1
		;// %r1  := vi + 1
		;// %r2  := j
		;// %r3  := vj
		;// %r4  := xmin
		;// %r5  := ymin
		;// %r6  := xmax
		;// %r7  := ymax
		;// %r12 := p
		;// %r13 := v
		;// %r14 := nv
vec2i_is_point_in_concave_LOOP1:					;// do {
		ld.w		%r10, [%r3]+				;//   %r10  := vj->x
		ld.w		%r11, [%r3]+				;//   %r11  := vj->y, %r3  := vj++
		;//
		cmp		%r10, %r4				;//   if(vj->x < xmin)
		jrge.d		3
		cmp		%r10, %r6				;//   <-------------------------+	*delay*
		 ld.w		%r4, %r10				;//     %r4  := xmin = vj->x	|
		;//							;//				|
;//		cmp		%r10, %r6				;//   if(vj->x > xmax) ---------+
		jrle.d		3
		cmp		%r11, %r5				;//   <-------------------------+	*delay*
		 ld.w		%r6, %r10				;//     %r6  := xmax = vj->x	|
		;//							;//				|
;//		cmp		%r11, %r5				;//   if(vj->y < ymin) ---------+
		jrge.d		3
		cmp		%r11, %r7				;//   <-------------------------+	*delay*
		 ld.w		%r5, %r11				;//     %r5  := ymin = vj->y	|
		;//							;//				|
;//		cmp		%r11, %r7				;//   if(vj->y > ymax) ---------+
		jrle.d		5
		sub		%r2, 1					;//   <-------------------------+	*delay*
		 ld.w		%r7, %r11				;//     %r7  := ymax = vj->y	|
		 ld.w		%r0, %r2				;//     %r0  :=  i - 1 =  j	|
		 ld.w		%r1, %r3				;//     %r1  := vi + 1 = vj	|
		;//							;//				|
;//		sub		%r2, 1					;//   %r2  := j-- --------------+
		jrne		vec2i_is_point_in_concave_LOOP1		;// } while(j)
		;//
		ld.w		%r2, [%r12]+				;// %r2  := p->x
		ld.w		%r3, [%r12]				;// %r3  := p->y
		;//
		cmp		%r2, %r4				;// if(p->x < xmin)
		jrlt		vec2i_is_point_in_concave_RET0		;//   return 0
		;//
		cmp		%r2, %r6				;// if(p->x > xmax)
		jrgt		vec2i_is_point_in_concave_RET0		;//   return 0
		;//
		cmp		%r3, %r5				;// if(p->y < ymin)
		jrlt		vec2i_is_point_in_concave_RET0		;//   return 0
		;//
		cmp		%r3, %r7				;// if(p->y > ymax)
		jrgt		vec2i_is_point_in_concave_RET0		;//   return 0
		;//
		add		%r0, 1					;// %r0  :=  i ( iは1つ減った値を保持している。 iが確定したので、ここで戻す)
		sub		%r1, 8					;// %r1  := vi (viは1つ進んだ値を保持している。viが確定したので、ここで戻す)
		;// %r0  := i
		;// %r1  := vi
		;// %r2  := p->x
		;// %r3  := p->y
		;// %r13 := v
		;// %r14 := nv
		;//-----------------------------------------------------;
		ld.w		%r10, 0					;// %r10 := n = 0
		ld.w		%r11, 0					;// %r11 := prev = 0
		;// %r0  := i
		;// %r1  := vi
		;// %r2  := p->x
		;// %r3  := p->y
		;// %r10 := n
		;// %r11 := prev
		;// %r13 := v
		;// %r14 := j = nv
vec2i_is_point_in_concave_LOOP2:					;// do {
		ld.w		%r4, [%r1]+				;//   %r4  := v0.x = vi->x
		ld.w		%r5, [%r1]+				;//   %r5  := v0.y = vi->y, %r1  := vi++
		ld.w		%r6, %r4				;//   %r6  := v1.x = vi->x
		ld.w		%r7, %r5				;//   %r7  := v1.y = vi->y
		;// %r0  := i
		;// %r1  := vi
		;// %r2  := p->x
		;// %r3  := p->y
		;// %r4  := v0.x
		;// %r5  := v0.y
		;// %r6  := v1.x
		;// %r7  := v1.y
		;// %r10 := n
		;// %r11 := prev
		;// %r13 := v
		;// %r14 := j
		sub		%r0, 1					;//   %r0  := i--
		jrne.d		3					;//   if(!i)
		sub		%r4, %r2				;//   <-------------------------+	*delay*
		 ld.w		%r1, %r13				;//     %r1  := vi = v		|
		;//							;//				|
;//		sub		%r4, %r2				;//   %r4  := v0.x -= p->x -----+
		sub		%r5, %r3				;//   %r5  := v0.y -= p->y
		;//
		xld.w		%r12, [%r1+0]				;//   %r12 :=         vi->x
		xld.w		%r15, [%r1+4]				;//   %r15 :=         vi->y
		sub		%r6, %r12				;//   %r6  := v1.x -= vi->x
		sub		%r7, %r15				;//   %r7  := v1.y -= vi->y
		;//
		mlt.w		%r4, %r7				;//   %alr :=     v0.x * v1.y
		ld.w		%r12, %alr				;//   %r12 :=     v0.x * v1.y
		mlt.w		%r5, %r6				;//   %alr :=                   v0.y * v1.x
		ld.w		%r15, %alr				;//   %r13 :=                   v0.y * v1.x
		sub		%r12, %r15				;//   %r12 := f = v0.x * v1.y - v0.y * v1.x
		jrne		vec2i_is_point_in_concave_NOT_ON_LS	;//   if(!f)
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		cmp		%r4, 0					;//     if(v0.x) {
		jreq		vec2i_is_point_in_concave_X_ON_LS
		jrgt		vec2i_is_point_in_concave_V0X_GT_0	;//       if(v0.x < 0)
		cmp		%r4, %r6				;//         if(v0.x < v1.x)
		jrlt		vec2i_is_point_in_concave_NOT_ON_LS	;//           goto NOT_ON_LS
		jp		vec2i_is_point_in_concave_X_ON_LS
vec2i_is_point_in_concave_V0X_GT_0:					;//       else
		cmp		%r4, %r6				;//         if(v0.x > v1.x)
		jrgt		vec2i_is_point_in_concave_NOT_ON_LS	;//           goto NOT_ON_LS
vec2i_is_point_in_concave_X_ON_LS:					;//     }
		cmp		%r5, 0					;//     if(v0.y) {
		jreq		vec2i_is_point_in_concave_RET_1
		jrgt		vec2i_is_point_in_concave_V0Y_GT_0	;//       if(v0.y < 0)
		cmp		%r5, %r7				;//         if(v0.y < v1.y)
		jrlt		vec2i_is_point_in_concave_NOT_ON_LS	;//           goto NOT_ON_LS
		jp		vec2i_is_point_in_concave_RET_1
vec2i_is_point_in_concave_V0Y_GT_0:					;//       else
		cmp		%r5, %r7				;//         if(v0.y > v1.y)
		jrgt		vec2i_is_point_in_concave_NOT_ON_LS	;//           goto NOT_ON_LS
		jp		vec2i_is_point_in_concave_RET_1
vec2i_is_point_in_concave_NOT_ON_LS:					;//     }
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		cmp		%r7, 0					;//   if(v1.y)
		jreq		vec2i_is_point_in_concave_NEXT
		jrgt.d		vec2i_is_point_in_concave_V1Y_GT_0	;//     if(v1.y < 0)
		cmp		%r12, 0					;//     %psr := f - 0				*delay*
;//vec2i_is_point_in_concave_V1Y_LT_0:
		jrge		vec2i_is_point_in_concave_PREV_V1Y	;//       if(f < 0)
		cmp		%r7, %r5				;//         if(v1.y <= v0.y)
		jrgt		vec2i_is_point_in_concave_PREV_V1Y
		cmp		%r11, 0					;//           if(prev < 0) {
		jrge.d		4
		 cmp		%r5, 0					;//           %psr := v0.y - 0			*delay*
		 jrge		vec2i_is_point_in_concave_PREV_V1Y	;//             if(v0.y < 0)
		 jp		vec2i_is_point_in_concave_N_TOGGLE	;//               n ^= 1
		;//							;//           } else {
		jrgt		vec2i_is_point_in_concave_PREV_V1Y	;//             if(v0.y <= 0)
		jp		vec2i_is_point_in_concave_N_TOGGLE	;//               n ^= 1
		;//							;//           }
vec2i_is_point_in_concave_V1Y_GT_0:					;//     } else {
		jrle		vec2i_is_point_in_concave_PREV_V1Y	;//       if(f > 0)
		cmp		%r7, %r5				;//         if(v1.y >= v0.y)
		jrlt		vec2i_is_point_in_concave_PREV_V1Y
		cmp		%r11, 0					;//           if(prev < 0) {
		jrle.d		4
		 cmp		%r5, 0					;//           %psr := v0.y - 0			*delay*
		 jrle		vec2i_is_point_in_concave_PREV_V1Y	;//             if(v0.y > 0)
		 jp		vec2i_is_point_in_concave_N_TOGGLE	;//               n ^= 1
		;//							;//           } else {
		jrlt		vec2i_is_point_in_concave_PREV_V1Y	;//             if(v0.y >= 0)
;//		jp		vec2i_is_point_in_concave_N_TOGGLE	;//               n ^= 1
		;//							;//           }
vec2i_is_point_in_concave_N_TOGGLE:					;//     }
		xor		%r10, 1					;//   %r10 := n ^= 1
vec2i_is_point_in_concave_PREV_V1Y:
		ld.w		%r11, %r7				;//   %r3  := prev = v1.y
		;// %r0  := i
		;// %r1  := vi
		;// %r2  := p->x
		;// %r3  := p->y
		;// %r10 := n
		;// %r11 := prev
		;// %r13 := v
		;// %r14 := j
vec2i_is_point_in_concave_NEXT:
		sub		%r14, 1					;//   %r14 := j--
		jrne		vec2i_is_point_in_concave_LOOP2		;// } while(j)
		;//-----------------------------------------------------;
vec2i_is_point_in_concave_RET:
		popn		%r3
		ret
vec2i_is_point_in_concave_RET0:
		jp.d		vec2i_is_point_in_concave_RET
		ld.w		%r10, 0					;// %r10 := n = 0	*delay*
vec2i_is_point_in_concave_RET_1:
		jp.d		vec2i_is_point_in_concave_RET
		ld.w		%r10, -1				;// %r10 := n = -1	*delay*
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* a[na]を頂点とする凹多角形と、b[nb]を頂点とする凹多角形の交差判定 */
int vec2i_is_intersected_p(const vec2i* a/*[na]*/, int na, const vec2i* b/*[nb]*/, int nb) {
	int ia;
	int ib;
	const vec2i* a1;
	const vec2i* a2;
	const vec2i* b1;
	const vec2i* b2;
	int axmin;
	int axmax;
	int aymin;
	int aymax;
	int bxmin;
	int bxmax;
	int bymin;
	int bymax;
	/* 境界ボックスを求め、おおまかな当り判定を行います。 */
	a1 = a;
	ia = na;
	axmin = axmax = a1->x;
	aymin = aymax = a1->y;
	a1++;
	ia--;
	do {
		if(a1->x < axmin) { axmin = a1->x; } else if(a1->x > axmax) { axmax = a1->x; }
		if(a1->y < aymin) { aymin = a1->y; } else if(a1->y > aymax) { aymax = a1->y; }
		a1++;
	} while(--ia);
	/* 上のループを完了すると、「a1 = &a[na];」になっています。後で利用します。 */
	b1 = b;
	ib = nb;
	bxmin = bxmax = b1->x;
	bymin = bymax = b1->y;
	b1++;
	ib--;
	do {
		if(b1->x < bxmin) { bxmin = b1->x; } else if(b1->x > bxmax) { bxmax = b1->x; }
		if(b1->y < bymin) { bymin = b1->y; } else if(b1->y > bymax) { bymax = b1->y; }
		b1++;
	} while(--ib);
	/* 上のループを完了すると、「b1 = &b[nb];」になっています。後で利用します。 */
	if((axmin > bxmax) || (axmax < bxmin) || (aymin > bymax) || (aymax < bymin)) {
		return 0;
	}
	/* 線分同士の総当り交差判定を行い、凹多角形同士が交差しているか判断します。 */
	a1--; /* a1 = &a[na - 1]; */
	b1--; /* b1 = &b[nb - 1]; */
	a2 = a;
	ia = na;
	do {
		b2 = b;
		ib = nb;
		do {
			if(vec2i_is_intersected_ls(a1, a2, b1, b2)) {
				return 1; /* 交差している */
			}
			b1 = b2;
			b2++;
		} while(--ib);
		/* 上のループを完了すると、都合良く「b1 = &b[nb - 1];」に戻っています。 */
		a1 = a2;
		a2++;
	} while(--ia);
	/* 一方の凹多角形に、もう一方の凹多角形が、完全に含まれているか判断します。 */
	if(vec2i_is_point_in_concave(a, b, nb)) {
		return 1; /* 凹多角形aが、凹多角形bを含んでいる */
	}
	if(vec2i_is_point_in_concave(b, a, na)) {
		return 1; /* 凹多角形bが、凹多角形aを含んでいる */
	}
	return 0;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* 点pと、交互モードで描かれた複数の閉じた多角形の内外判定 */
int vec2i_is_point_in_alternate_concaves(const vec2i* p, const vec2i* v/*[sum(nv[0...n-1])]*/, const int* nv/*[n]*/, int n) {
	int c = 0;
	do {
		int f = vec2i_is_point_in_concave(p, v, *nv);
		if(f) {
			/* どれかの多角形の辺上ならば、即座に"内"と見なす */
			if(f == -1) {
				return f;
			}
			/* 多角形の内部ならば、回数の偶数奇数をトグルする */
			c ^= 1;
		}
		v += *nv++;
	} while(--n);
	return c;
}
/*--------------------------------------------------------------------------*/
/* n角形を、(n-2)個の三角形に分割する。 */
//□参照資料
//│「ねぎらぼ」(http://negi-magnet.hatenablog.com/)さんの
//│「DXライブラリで多角形を描く (with C++サンプル)」(http://negi-magnet.hatenablog.com/entry/2013/10/10/201716)の記事を参考にさせて頂きました。
//ただし、上記の記事では、分割を開始する頂点を検索するために原点から一番遠い頂点を検索していますが、当実装では、その方法は取らない事にしました。
//原点から一番遠い頂点を検索する目的は、鋭角な三角形を見付けるためですが、一番遠い頂点を検索するよりも、多角形と同じ向きの三角形を検索する方が、判り易いと思ったからです。
int vec2i_split_polygon_into_triangles(const vec2i p[/*n*/], int n/*0不可*/, vec2i tri_p[/*(n-2)*/][3]) {	//引数p[n]で指定されたn角形を、(n-2)個の三角形に分割して、tri_p[(n-2)][3]に格納する。
	int i, j, n_tri = 0;
	vec2i* buf;
#ifdef  PIECE
//□P/ECEの場合
	//P/ECEではalloca()の負荷が大きいので、なるべくalloca()を使わないような方法にしました。
	//具体的には、以下の通りです。
	// - 固定サイズのバッファを用意しておき、頂点数が固定サイズ以下ならば、それを使います。
	// - 頂点数が固定サイズよりも多い場合は、仕方が無いのでalloca()を使います。
	//   本当は、P/ECEの場合はalloca()を使うよりもmalloc()を使う方が高速なのですが、実装の簡単のために、この場合はalloca()を使う事にしました。
	//   元々、頂点数が固定サイズを超える程多ければ、当関数自体の処理時間が長くなるので、全体に占めるalloca()処理時間は相対的に小さくなります。
	// - 当関数が、一時バッファとして_def_vbuff[]を利用するのは、望ましくない事に注意して下さい。(従って、今回の実装でもそうはしませんでした。)
	//   当関数を呼び出すrender_vec2i_render_polygon_fill()が一時バッファとして_def_vbuff[]を利用しており、もし当関数が一時バッファとして_def_vbuff[]を利用すると衝突してしまうからです。
	//   原則として、一時バッファとして_def_vbuff[]を利用するのは、(render_vec2i_render_polygon_fill()のような)高水準の関数のみとすべきです。
	//   当関数のような、他の関数のサブルーチンとして利用される可能性の高い低水準の関数では、一時バッファとして_def_vbuff[]を利用すべきではありません。
	vec2i _buf[16/*調整可*/];	//固定サイズのバッファ
	buf = (n <= ARRAY_SIZE(_buf)) ? _buf : alloca(sizeof(vec2i) * n);
#else //PIECE
//□Win32,及び,その他全般の場合
	//Win32,及び,その他全般の場合は、alloc()を使って可変サイズのバッファを確保する。
	buf = alloca(sizeof(vec2i) * n);
#endif//PIECE
	//頂点数が3未満の多角形に対して、当関数を呼び出してはいけない。
	if(n < 3) { DIE(); }
	//渡された多角形の、表裏判定を行う。
	{
#if 0	//──────────────────────────────────────────────────────────────────────────────────────────────
		//隣り合う辺の外積の合計を求める。
		int sum = 0;	//(int)型で充分だろう。仮に外積一つが最大で(2000x2000)としても、頂点数が高々500程度ならば、合計は0x77359400でオーバーフローしない。実際にはもっと小さいだろうから、余裕が有るはず。しかし万一オーバーフローしたら、(int64_t)型に変更せよ。
		for(i = 0; i < n; i++) {
			vec2i p0 = p[(i + 0)    ];
			vec2i p1 = p[(i + 1) % n];
			vec2i p2 = p[(i + 2) % n];
			vec2i_sub(&p2, &p1);	//=v12	┬後者はp1を破壊するので、この処理順序で行う必要が有る。
			vec2i_sub(&p1, &p0);	//=v01	┘
			sum += vec2i_cross(&p1, &p2);
		}
#else	//これ↑は間違っていました。正しくはこう↓でした。□参照資料「イメージングソリューション」さんの「n点からなる多角形の面積を求める」の記事(http://imagingsolution.net/math/calc_n_point_area/)
		//原点から隣り合う各頂点へのベクトル(要するに各頂点の座標)同士の外積の合計を求める。
		int sum = 0;	//(int)型で充分だろう。仮に外積一つが最大で(2000x2000)としても、頂点数が高々500程度ならば、合計は0x77359400でオーバーフローしない。実際にはもっと小さいだろうから、余裕が有るはず。しかし万一オーバーフローしたら、(int64_t)型に変更せよ。
		for(i = 0; i < n; i++) {
			sum += vec2i_cross(&p[i], &p[(i + 1) % n]);
		}
#endif	//──────────────────────────────────────────────────────────────────────────────────────────────
		//表裏判定が出来なければ(おそらく全ての頂点が一直線上に有る)、分割失敗を返す。
//{{2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
//		if(!sum) { return 0; }		//分割失敗
//↓2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
		if(!sum) { return n_tri; }	//分割失敗(n_tri<(n-2))
//}}2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
		//渡された多角形を、バッファにコピーする。
		for(i = 0; i < n; i++) {
			buf[i] = p[(sum > 0) ? (          i)	//渡された多角形が右回り(表)ならば、そのままコピーする。
			                     : ((n - 1) - i)];	//渡された多角形が左回り(裏)ならば、反転してコピーする。
		}
	}
	//頂点が3個以上である間…
	while(n >= 3) {
		//どの三角形を切り取るかを、検索する。
		// - 以下の処理では、buf[0〜2]を切り取る三角形と仮定して、判定を行う。
		for(i = 0; i < n; i++) {
			//三角形の、表裏判定を行う。
			vec2i v01 = { buf[1].x - buf[0].x, buf[1].y - buf[0].y };
			vec2i v12 = { buf[2].x - buf[1].x, buf[2].y - buf[1].y };
			//三角形が右回り(表),又は,一直線上ならば…
			// - 個々の三角形は一直線上でも切り取り可能と判断する事にした。
			//   そうしないと、多角形の一部の辺が一直線上に有った場合に、分割できなくなってしまう。
			if(vec2i_cross(&v01, &v12) >= 0) {
				//この後の処理で、点buf[j]が三角形の内部に有るかを調べる時に使う、変化しないベクトルを求めておく。
				vec2i v01 = { buf[1].x - buf[0].x, buf[1].y - buf[0].y };	//buf[0]->buf[1]
				vec2i v12 = { buf[2].x - buf[1].x, buf[2].y - buf[1].y };	//buf[1]->buf[2]
				vec2i v20 = { buf[0].x - buf[2].x, buf[0].y - buf[2].y };	//buf[2]->buf[0]
//{{この範囲は高速化のためだけの処理です。削除しても動作します。
				//三角形のバウンディングボックスを求める。
				int xmin = buf[0].x, xmax = buf[0].x;
				int ymin = buf[0].y, ymax = buf[0].y;
				xmin = min(xmin, buf[1].x); xmax = max(xmax, buf[1].x);
				ymin = min(ymin, buf[1].y); ymax = max(ymax, buf[1].y);
				xmin = min(xmin, buf[2].x); xmax = max(xmax, buf[2].x);
				ymin = min(ymin, buf[2].y); ymax = max(ymax, buf[2].y);
//}}この範囲は高速化のためだけの処理です。削除しても動作します。
				//残りのbuf[3〜(n-1)]が一つでも三角形の内部に有るかを調べる。
				for(j = 3; j < n; j++) {
//{{この範囲は高速化のためだけの処理です。削除しても動作します。
					//高速化のために、まず、大まかな判定を行う。
					// - 点buf[j]が三角形のバウンディングボックスの内部でなければ、明らかに点buf[j]が三角形の内部ではないので、この下の処理を行う必要は無い。
					if((buf[j].x <= xmin) || (buf[j].x >= xmax) ||
					   (buf[j].y <= ymin) || (buf[j].y >= ymax)) { continue; }
//}}この範囲は高速化のためだけの処理です。削除しても動作します。
					//点buf[j]が、三角形の内部に有るかを調べる。
					{
						vec2i vp0 = { buf[0].x - buf[j].x, buf[0].y - buf[j].y };	//buf[j]->buf[0]
						vec2i vp1 = { buf[1].x - buf[j].x, buf[1].y - buf[j].y };	//buf[j]->buf[1]
						vec2i vp2 = { buf[2].x - buf[j].x, buf[2].y - buf[j].y };	//buf[j]->buf[2]
						if((vec2i_cross(&vp0, &v01) > 0) &&		//buf[j]->buf[0]->buf[1]が右回り,かつ,						┐点buf[j]が三角形の辺上に有る場合(=外積が0の場合)は、点buf[j]が三角形buf[0〜2]の外部にあるのと同じと見なして、0を返す事にした。
						   (vec2i_cross(&vp1, &v12) > 0) &&		//buf[j]->buf[1]->buf[2]が右回り,かつ,						│呼び出し側(split_polygon_into_triangles())の観点で言うと、三角形以外の頂点が三角形の辺上に有っても、切り取り可能と判断します。
						   (vec2i_cross(&vp2, &v20) > 0)) { break; }	//buf[j]->buf[2]->buf[0]が右回りならば、点buf[j]が三角形buf[0〜2]の内部に有る。	┘上記のケースを切り取り可能と判断しても問題になる事は無いと思うので、少しでも分割失敗になる可能性を減らすために、そうしました。
					}
				}
				//残りのbuf[3〜(n-1)]が、一つも三角形の内部に無ければ、この三角形を切り取れる。
				if(j == n) { break; }	//このループを抜ける。
			}
			//頂点配列をローテートして、次の試行を行う。
			memrotate(buf, sizeof(vec2i), sizeof(vec2i) * n);
		}
		//切り取れる三角形が見つかったら…
		if(i < n) {
			//切り取る三角形の、頂点座標を格納する。
			memcpy(tri_p[n_tri], buf, sizeof(vec2i) * 3);	//tri_p[n_tri][0]=buf[0],tri_p[n_tri][1]=buf[1],tri_p[n_tri][2]=buf[2]
			n_tri++;
			//三角形の頂点(buf[0],buf[1],buf[2])の内、残りの図形から共有されていない頂点(つまりbuf[1])を削除する。
			memmove(&buf[1], &buf[2], sizeof(vec2i) * (n - 2));
			n--;
		//切り取れる三角形が見つからなかったら…
		} else {
			//以下のような原因で、分割失敗する可能性が有ります。
			//・指定された多角形の中に、交差している辺が有る。(=正しい多角形ではない)
			//・演算誤差のために、誤って、三角形の内部に残りの頂点が有ると見なしてしまい、分割出来ないと判断してしまう。
			//前者は分割失敗して正しいのですが、後者が問題です。
			//実際には、少ない頂点数の多角形で発生する事は少なく、50角形や100角形で時々発生する程度なので、許容する事にしました。
			//呼び出し側で、分割失敗した場合に描画を行わないようにしていると、複雑な多角形が時々描画されないような挙動になると思います。
			//もしそのような挙動が問題となった場合は、三角形の内部に残りの頂点が有るかの判断に許容範囲を設ける等の対策を検討して下さい。	//{{2016/10/24コメント追記:vec2i_split_polygon_into_triangles()の戻り値の意味を変更する事によって対策を行いました。詳細は下記のコメントを参照して下さい。}}
//{{2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
//			return 0;	//分割失敗
//↓2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
			// * Mon Oct 24 21:50:37 JST 2016 Naoyuki Sawa
			// - vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。
			//   変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
			//   変更した理由は、以下の通りです。
			// - vec2i_split_polygon_into_triangles()は、以下のような原因で、分割失敗する可能性が有ります。
			//   ・指定された多角形の中に、交差している辺が有る。(=正しい多角形ではない)
			//   ・演算誤差のために、誤って、三角形の内部に残りの頂点が有ると見なしてしまい、分割出来ないと判断してしまう。
			//   これまでは、前者,後者共に、分割処理中に一回でも上記のケースが生じたら、全体を分割失敗と見なしていたのが問題でした。
			//   少しでも分割出来ない部分が有ると、その多角形全体が描かれず、見た目にちらつきが生じるからです。
			// - そこで、見た目のちらつきを緩和するための対策として、一か所でも失敗したら全体を描かないのではなく、分割出来た所までは描くように変更しました。
			//   そのために、vec2i_split_polygon_into_triangles()の戻り値の意味を変更し、分割出来た所までの三角形の数を返す事にしました。
			//   呼び出し側では、戻り値の数ぶんの所まで、tri_p[]を描画すれば良いです。
			//   もし、分割が完全に成功したか、一部でも失敗したかを、呼び出し側で判断する必要が有る場合は、戻り値が(n-2)に等しいかを判定すれば良いです。
			// - 実験した所、誤差による分割失敗が起き易い頂点の多い多角形(100角形等)でも、実際に分割失敗するのは、最後の98個目の三角形の切り取り時でした。
			//   要するに、最後に残った3頂点が、演算誤差で逆回りの形で残ってしまい、切り取りに失敗するようです。
			//   この場合、既に97個の三角形が切り取れているわけで、それを描くだけで見た目上はほぼ十分です。
			//   従って、今回の対策は有効であると思います。
			return n_tri;	//分割失敗(n_tri<(n-2))
//}}2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
		}
	}
//{{2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
//	return 1;	//分割成功
//↓2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
	return n_tri;	//分割成功(n_tri==(n-2))
//}}2016/10/24変更:vec2i_split_polygon_into_triangles()の戻り値の意味を変更しました。変更前は「分割成功(1)/分割失敗(0)」でしたが、変更後は「分割した三角形の数(0〜(n-2)」としました。
}
/****************************************************************************
 *	P/ECE用描画関数
 ****************************************************************************/
#ifdef  PIECE
//複数の多角形を、交互モードで塗り潰します。
// - 詳細は、cliprend.hの関数説明を参照して下さい。
void render_vec2i_alternate_concaves(RENDER* render, const vec2i* v/*[sum(nv[0...n-1])]*/, const int* nv/*[n]*/, int n, int c) { /* ←cliprend.h */
	int i;
	int j;
	int xmin;
	int xmax;
	int ymin;
	int ymax;
	const vec2i* pv;
	vec2i p;
	/* 境界矩形を求める */
	pv = v;
	xmin = xmax = pv->x; /* 少なくとも一つは座標が有ると仮定 */
	ymin = ymax = pv->y; /* 少なくとも一つは座標が有ると仮定 */
	for(i = 0; i < n; i++) {
		for(j = 0; j < nv[i]; j++) {
			if(pv->x < xmin) xmin = pv->x;
			if(pv->x > xmax) xmax = pv->x;
			if(pv->y < ymin) ymin = pv->y;
			if(pv->y > ymax) ymax = pv->y;
			pv++;
		}
	}
	/* 境界矩形をクリッピングする */
	if(xmin < render->left      ) xmin = render->left      ;
	if(xmax > render->right  - 1) xmax = render->right  - 1;
	if(ymin < render->top       ) ymin = render->top       ;
	if(ymax > render->bottom - 1) ymax = render->bottom - 1;
	/* 境界矩形内のピクセルを描く */
	for(p.y = ymin; p.y <= ymax; p.y++) {
		for(p.x = xmin; p.x <= xmax; p.x++) {
			if(vec2i_is_point_in_alternate_concaves(&p, v, nv, n)) {
				render_point(render, p.x, p.y, c);
			}
		}
	}
}
/*--------------------------------------------------------------------------*/
//太いポリラインを描画する。
// - 詳細は、cliprend.hの関数説明を参照して下さい。
// - DxlibHelper.cppの、draw_grp_or_spr_thick_polyline(),及び,calc_thick_polyline_edge_p()を元にして作成しました。
//   ただし、draw_grp_or_spr_thick_polyline()と当関数(render_vec2i_thick_polyline())とでは、以下の点が異なっているため、少しアルゴリズムを変更しました。
//   ・draw_grp_or_spr_thick_polyline()はトライアングルストリップとして描画しますが、当関数は凹多角形として描画するので、頂点の格納順序を変更しました。
//   ・draw_grp_or_spr_thick_polyline()はテクスチャを使って描画しますが、当関数は単純な塗り潰しを行うだけなので、テクスチャ座標の計算処理を省きました。
void render_vec2i_thick_polyline(RENDER* render, const vec2i* v/*[n]*/, int n, int w, int c) { /* ←cliprend.h */
	int i, out_n, out_l, out_r;
	vec2i *out_p/*[out_n]*/, (*edge_p)[2/*左側,右側*/][2/*始点,終点*/];
	out_n = ((n - 1) * 4);								//1線分あたり最大4頂点に展開するので、最大((n-1)*4)頂点となります。
#if 0
//□一時バッファをalloca()を使って割り当てる場合
	out_p = alloca(sizeof(vec2i) * out_n);
	edge_p = alloca(sizeof(vec2i[2/*左側,右側*/][2/*始点,終点*/]) * (n - 1));	//線分の数は、指定された頂点よりも一つ少ないので、(n-1)となります。
#else
//□一時バッファとして_def_vbuff[]を利用する場合
	out_p = (vec2i*)_def_vbuff;
	edge_p = (vec2i (*)[2/*左側,右側*/][2/*始点,終点*/])(out_p + out_n);
#endif
	//各線分の左側と右側の線分の、始点と終点の座標を生成する。
	for(i = 0; i < (n - 1); i++) {
		vec2i p1 = v[i + 0];	//始点
		vec2i p2 = v[i + 1];	//終点
		//始点から終点へのベクトルを求める。
		vec2i v12 = {
			p2.x - p1.x,
			p2.y - p1.y,
		};
		//v12の長さを求める。
		int m12 = vec2i_mag(&v12);
		//v12の長さが0でなければ…
		if(m12) {
			//v12に垂直なベクトルを求める。
			vec2i w12 = {
				-v12.y,
				 v12.x,
			};
			//始点から、w12のマイナス方向に、距離(w/2)の位置の点を求める。
			vec2i p11 = {
				p1.x - ((w12.x * w) / (m12 * 2)),
				p1.y - ((w12.y * w) / (m12 * 2)),
			};
			//始点から、w12のプラス方向に、距離(w/2)の位置の点を求める。
			// - 前の処理での除算の切り捨て分を吸収するために、始点基準ではなく、p11基準で計算する。
			//   そうしないと、幅がwよりも小さくなってしまう事が生じる。
			vec2i p21 = {
				p11.x + (w12.x * w) / m12,
				p11.y + (w12.y * w) / m12,
			};
			//終点から、w12のマイナス方向に、距離(w/2)の位置の点を求める。
			// - 素直に計算しても構わないのだが、(p11+v12)で計算する方が簡単である。
			vec2i p12 = {
				p11.x + v12.x,
				p11.y + v12.y,
			};
			//終点から、w12のプラス方向に、距離(w/2)の位置の点を求める。
			// - 素直に計算しても構わないのだが、(p12+v12)で計算する方が簡単である。
			vec2i p22 = {
				p21.x + v12.x,
				p21.y + v12.y,
			};
			//結果を格納する。
			edge_p[i][0][0] = p11;	//始点から、w12のマイナス方向に、距離(w/2)の位置の点を格納する。
			edge_p[i][0][1] = p12;	//終点から、w12のマイナス方向に、距離(w/2)の位置の点を格納する。
			edge_p[i][1][0] = p21;	//始点から、w12のプラス方向に、距離(w/2)の位置の点を格納する。
			edge_p[i][1][1] = p22;	//終点から、w12のプラス方向に、距離(w/2)の位置の点を格納する。
		//v12の長さが0ならば…
		} else {
			//全ての座標に同じ座標を格納する。
			edge_p[i][0][0] = edge_p[i][1][0] = p1;	//┬ここへ来たという事は(p1==p2)のはずなので、全てp1,又は,全てp2にしても構わないのだが、一応、p1が始点,p2が終点という意味なので、このように使い分けて格納する事にした。
			edge_p[i][0][1] = edge_p[i][1][1] = p2;	//┘
		}
	}
	//出力バッファの中央から、左側線分は逆方向へ、右側線分は順方向へ、頂点座標を格納して行く。
	out_l = (out_n / 2);		//┬前の頂点と比較し易いように、インデクスは前の頂点を指すようにする。従って、左側線分の頂点の初期値は(中央+1)、右側線分の頂点の初期値は(中央-1)としておく。
	out_r = (out_n / 2) - 1;	//┘
	//各線分について…
	for(i = 0; i < (n - 1); i++) {	//ここは(n-1)で合っている。この後の判定では(n-2)の箇所が有るので混同しないよう注意しろ。
		vec2i p11 = edge_p[i][0/*左側*/][0/*始点*/];					//左側始点
		vec2i p12 = edge_p[i][0/*左側*/][1/*終点*/];					//左側終点
		vec2i p21 = edge_p[i][1/*右側*/][0/*始点*/];					//右側始点
		vec2i p22 = edge_p[i][1/*右側*/][1/*終点*/];					//右側終点
		//最初の線分ならば…
		if(!i) {
			//左側の線分の始点を格納する。
		//不要	if(memcmp(&out_p[out_l], &p11, sizeof(vec2i))) {			//直前の頂点と同じでなければ…		⇒ここでは直前の頂点が無いので比較不要です。
				out_l--;
				if(out_l < 0) { DIE(); }					//バグ
				out_p[out_l] = p11;						//左側始点
		//不要	}
			//右側の線分の始点を格納する。
		//不要	if(memcmp(&out_p[out_r], &p21, sizeof(vec2i))) {			//直前の頂点と同じでなければ…		⇒ここでは直前の頂点が無いので比較不要です。
				out_r++;
				if(out_r >= out_n) { DIE(); 	}				//バグ
				out_p[out_r] = p21;						//右側始点
		//不要	}
		}
		//最後の線分でなければ…(最初の線分である可能性も有る)
		if(i < (n - 2)) {	//'最後の接点'ではなく'最後の線分'を判定するので、(n-1)ではなく(n-2)とする事に注意しろ。
			//次の線分を取得する。
			vec2i next_p11 = edge_p[i + 1][0/*左側*/][0/*始点*/];			//左側始点
			vec2i next_p12 = edge_p[i + 1][0/*左側*/][1/*終点*/];			//左側終点
			vec2i next_p21 = edge_p[i + 1][1/*右側*/][0/*始点*/];			//右側始点
			vec2i next_p22 = edge_p[i + 1][1/*右側*/][1/*終点*/];			//右側終点
			//左側の線分が交差していたら…
			if(vec2i_is_intersected_ls(&p11, &p12, &next_p11, &next_p12)) {
				//左側の線分の交点を求める。
				vec2i tmp_p1 = vec2i_intersection_l(&p11, &p12, &next_p11, &next_p12);
				//右側の線分が交差していたら…
				if(vec2i_is_intersected_ls(&p21, &p22, &next_p21, &next_p22)) {
					//右側の線分の交点を求める。
					vec2i tmp_p2 = vec2i_intersection_l(&p21, &p22, &next_p21, &next_p22);
					//左側の線分の交点を格納する。
					if(memcmp(&out_p[out_l], &tmp_p1, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_l--;
						if(out_l < 0) { DIE(); }			//バグ
						out_p[out_l] = tmp_p1;				//左側交点
					}
					//右側の線分の交点を格納する。
					if(memcmp(&out_p[out_r], &tmp_p2, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_r++;
						if(out_r >= out_n) { DIE(); }			//バグ
						out_p[out_r] = tmp_p2;				//右側交点
					}
				//右側の線分が交差していなければ…
				} else {
					//左側の線分の交点を格納する。
					if(memcmp(&out_p[out_l], &tmp_p1, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_l--;
						if(out_l < 0) { DIE(); }			//バグ
						out_p[out_l] = tmp_p1;				//左側交点
					}
					//右側の線分の終点を格納する。
					if(memcmp(&out_p[out_r], &p22, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_r++;
						if(out_r >= out_n) { DIE(); }			//バグ
						out_p[out_r] = p22;				//右側終点
					}
					//次の線分の右側の線分の始点を格納する。
					if(memcmp(&out_p[out_r], &next_p21, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_r++;
						if(out_r >= out_n) { DIE(); }			//バグ
						out_p[out_r] = next_p21;			//次の線分の右側始点
					}
				}
			//左側の線分が交差していなければ…
			} else {
				//右側の線分が交差していたら…
				if(vec2i_is_intersected_ls(&p21, &p22, &next_p21, &next_p22)) {
					//右側の線分の交点を求める。
					vec2i tmp_p2 = vec2i_intersection_l(&p21, &p22, &next_p21, &next_p22);
					//左側の線分の終点を格納する。
					if(memcmp(&out_p[out_l], &p12, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_l--;
						if(out_l < 0) { DIE(); }			//バグ
						out_p[out_l] = p12;				//左側終点
					}
					//次の線分の左側の線分の始点を格納する。
					if(memcmp(&out_p[out_l], &next_p11, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_l--;
						if(out_l < 0) { DIE(); }			//バグ
						out_p[out_l] = next_p11;			//次の線分の左側始点
					}
					//右側の線分の交点を格納する。
					if(memcmp(&out_p[out_r], &tmp_p2, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_r++;
						if(out_r >= out_n) { DIE(); }			//バグ
						out_p[out_r] = tmp_p2;				//右側交点
					}
				//右側の線分が交差していなければ…
				} else {
					//左側の線分の終点を格納する。
					if(memcmp(&out_p[out_l], &p12, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_l--;
						if(out_l < 0) { DIE(); }			//バグ
						out_p[out_l] = p12;				//左側終点
					}
					//次の線分の左側の線分の始点を格納する。
					if(memcmp(&out_p[out_l], &next_p11, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_l--;
						if(out_l < 0) { DIE(); }			//バグ
						out_p[out_l] = next_p11;			//次の線分の左側始点
					}
					//右側の線分の終点を格納する。
					if(memcmp(&out_p[out_r], &p22, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_r++;
						if(out_r >= out_n) { DIE(); }			//バグ
						out_p[out_r] = p22;				//右側終点
					}
					//次の線分の右側の線分の始点を格納する。
					if(memcmp(&out_p[out_r], &next_p21, sizeof(vec2i))) {	//直前の頂点と同じでなければ…
						out_r++;
						if(out_r >= out_n) { DIE(); }			//バグ
						out_p[out_r] = next_p21;			//次の線分の右側始点
					}
				}
			}
		//最後の線分ならば…(最初の線分である可能性も有る)
		} else {
			//左側の線分の終点を格納する。
			if(memcmp(&out_p[out_l], &p12, sizeof(vec2i))) {			//直前の頂点と同じでなければ…
				out_l--;
				if(out_l < 0) { DIE(); }					//バグ
				out_p[out_l] = p12;						//左側終点
			}
			//右側の線分の終点を格納する。
			if(memcmp(&out_p[out_r], &p22, sizeof(vec2i))) {			//直前の頂点と同じでなければ…
				out_r++;
				if(out_r >= out_n) { DIE(); }					//バグ
				out_p[out_r] = p22;						//右側終点
			}
		}
	}
	//凹多角形を描画する。
	out_r = (out_r + 1) - out_l;
	if(out_r >= 3) {
		render_vec2i_alternate_concaves(render,
			&out_p[out_l],
			&out_r,
			1,
			c);
	}
}
/*--------------------------------------------------------------------------*/
//多角形を描画する。
void render_vec2i_render_polygon(RENDER* render, const vec2i* v/*[n]*/, int n/*3〜*/, int c) {
	const vec2i* v_prev;
	//(n<3)で当関数を呼び出してはいけません。
	if(n < 3) { DIE(); }
	//最後の頂点を、前の頂点の初期値とする。
	v_prev = &v[n - 1];
	//頂点数をプレデクリメントして0以上である間…
	while(--n >= 0) {
		//前の頂点から、現在の頂点へ、線を描く。
		render_line(render, v_prev->x, v_prev->y, v->x, v->y, c);
		//現在の頂点を前の頂点とし、現在の頂点を次へ進める。
		v_prev = v++;
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//多角形を塗り潰す。
void render_vec2i_render_polygon_fill(RENDER* render, const vec2i* v/*[n]*/, int n/*3〜*/, int c) {
	vec2i (*tri_p)[3];
	VERTEX vertex[3];
	TEXTURE* texture_save;
	int n_tri, i, j;
	//(n<3)で当関数を呼び出してはいけません。
	if(n < 3) { DIE(); }
	//多角形を三角形に分割する。
#if 0
//□一時バッファをalloca()を使って割り当てる場合
	tri_p = alloca(sizeof(vec2i[3]) * (n - 2));
#else
//□一時バッファとして_def_vbuff[]を利用する場合
	tri_p = (vec2i(*)[3])_def_vbuff;
#endif
	n_tri = vec2i_split_polygon_into_triangles(v, n, tri_p);	//切り取れた三角形の数(0〜(n-2))を取得する。
	if(n_tri > (n - 2)) { DIE(); }	//三角形の数が(n-2)を超える事は無いはず。もし超えたらvec2i_split_polygon_into_triangles()のバグです。
	//分割した各三角形を描画する。
	texture_save = render->context->texture;	//設定されているテクスチャ(又はNULL)を退避する。
	render->context->texture = NULL;		//一時的にテクスチャ無しとする。
	for(i = 0; i < n_tri; i++) {
		for(j = 0; j < 3; j++) {
			vertex[j].x = tri_p[i][j].x;
			vertex[j].y = tri_p[i][j].y;
		}
		render_polygon(render, vertex, 3, c);
	}
	render->context->texture = texture_save;	//設定されていたテクスチャ(又はNULL)を復元する。
}
#endif//PIECE
