/*
 *	clipflt2.c
 *
 *	高速単精度浮動小数点演算ライブラリ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Sun Jul 20 13:26:33 JST 2008 Naoyuki Sawa
 *	- 作成開始。
 *	* Sun Jul 20 19:20:18 JST 2008 Naoyuki Sawa
 *	- mat3f_rot()等で、誤って、倍精度版のsin()、cos()を呼び出してしまっていました。
 *	  そのため、mat3f_rot()等を使用すると、大きな性能低下となってしまっていました。
 *	  正しく、単精度版のsinf()、cosf()を呼び出すよう、修正しました。
 *	* Sun Aug 17 22:24:29 JST 2008 Naoyuki Sawa
 *	- vecf→vec3f、matf→mat3f、vecx→vec3x、matx→mat3xに名前変更しました。
 *	  全置換で変換したので、本日以前のコメントなどもすべて名前変更されています。
 *	* Mon Aug 18 00:28:27 JST 2008 Naoyuki Sawa
 *	- vec2f、mat2f、および、それらの関数群をを追加しました。
 *	* Tue Aug 19 23:47:09 JST 2008 Naoyuki Sawa
 *	- vec2f、mat2fの関数群をアセンブラ化し、高速化、省メモリ化しました。
 *	- vec2f_xform,mat2f_xformは、vec3f_xform,mat3f_xformと違って、高速RAM配置候補とはしません。
 *	  vec3f_xform,mat3f_xformは、3D処理のなかでまとまって大量に使用されることが考えられますが、
 *	  vec2f_xform,mat2f_xformは、3D処理ほど速度が重要な場面で使うことは少ないと考えたからです。
 *	* Mon Sep 08 16:31:59 JST 2008 Naoyuki Sawa
 *	- clipflt.cをclipflt1.cとclipflt2.cに分割しました。
 *	- 複雑な関数を使わないプログラムにも、常に全関数がリンクされて実行ファイルが大きくなることを防ぐため、
 *	  使用頻度の高い関数をclipflt1.c、使用頻度の低い関数をclipflt2.cに分けることにしました。
 *	  関数分けの明確な基準は無いので、今後も適宜、関数分けや移動を行なう予定です。
 *	  また、今後も関数が増えたら、必要に応じてclipflt3.c,clipflt4.c,...を追加して行く予定です。
 *	* Mon Sep 08 21:04:20 JST 2008 Naoyuki Sawa
 *	- vec3f_intersection_p_l()を追加し、アセンブラ化も行ないました。
 *	* Wed Sep 10 00:42:21 JST 2008 Naoyuki Sawa
 *	- vec2f_is_point_in_convex()を追加し、アセンブラ化も行ないました。
 *	* Fri Sep 12 01:53:36 JST 2008 Naoyuki Sawa
 *	- アセンブラ版vec2f_is_point_in_convex()のバグを修正しました。
 *	  スタックフレームの確保を忘れて、呼び出し元のスタックフレームを破壊してしまっていました。
 *	* Sat Sep 13 01:33:53 JST 2008 Naoyuki Sawa
 *	- vec2f_is_point_in_concave()を追加し、アセンブラ化も行ないました。
 *	* Sat Sep 13 15:42:08 JST 2008 Naoyuki Sawa
 *	- vec2f_is_point_in_concave()のバグを修正しました。
 *	* Sun Sep 14 00:00:03 JST 2008 Naoyuki Sawa
 *	- vec2f_is_point_in_concave()が、辺の線分上や端点にある点を、凹多角形の外と判断してしまう問題を修正しました。
 *	* Mon Sep 15 00:00:02 JST 2008 Naoyuki Sawa
 *	- vec2f_is_intersected_p()を追加し、アセンブラ化も行ないました。
 *	* Wed Sep 17 06:58:49 JST 2008 Naoyuki Sawa
 *	- vec2f_intersection_l_p()を追加し、アセンブラ化も行ないました。
 *	* Sun Sep 21 20:36:56 JST 2008 Naoyuki Sawa
 *	- vec3f_intersection_p_l()のアセンブラ版に、戻り値を格納する隠し引数の扱いがエリアスセーフでない問題が有ったため、アセンブラ版をとりやめ、C言語版に戻しました。
 *	  vec2f_intersection_l()のアセンブラ版に、戻り値を格納する隠し引数の扱いがエリアスセーフでない問題が有ったため、アセンブラ版を修正しエリアスセーフにしました。
 *	  詳しくは、「keep/★TODO要再確認★戻り値を格納する隠し引数もエリアスセーフ必要-20080920.txt」を参照してください。
 *	* Mon Sep 22 23:10:25 JST 2008 Naoyuki Sawa
 *	- 上記の問題について、vec3f_intersection_p_l()も、アセンブラ版を修正しエリアスセーフにしました。
 *	* Wed Sep 09 18:21:50 JST 2009 Naoyuki Sawa
 *	- vec2f_is_point_in_alternate_concaves()を追加しました。
 *	* Fri Sep 11 02:55:30 JST 2009 Naoyuki Sawa
 *	- render_vec2f_alternate_concaves()を追加しました。
 *	  宣言は、clipflt.hではなく、cliprend.hに含めました。
 *	* Sat Sep 12 04:12:14 JST 2009 Naoyuki Sawa
 *	- vec2f_is_point_in_concave()に、以下の変更を行いました。
 *	- これまでは、nに交差回数を数えていましたが、冗長でした。
 *	  交差回数が奇数か偶数かが判れば充分なので、1ビットでトグルするだけにしました。
 *	- 戻り値の仕様を変更しました。
 *	  [旧] 点pが、凹多角形の内部か、辺の線分上ならば、0以外の値を返す。凹多角形の外部ならば、0を返す。
 *	  [新] 点pが、凹多角形の内部ならば、1を返す。辺の線分上ならば、-1を返す。凹多角形の外部ならば、0を返す。
 *	  凹多角形の内部か、辺の線分上かを、区別できるようになりました。vec2f_is_point_in_alternate_concaves()が、この仕様を利用します。
 *	  その他のプログラムは、戻り値が0か、0以外かでしか判断していないので、この仕様変更は影響を及ぼしません。
 *	* Thu Feb 25 21:08:23 JST 2016 Naoyuki Sawa
 *	- clipflt.hに依存しているモジュールを、libclipに含められるようにするために、clipflt.hをlibclip/extclip.hに含める必要が生じました。
 *	  これまでは、clipflt.hをlibclip/extclip.hに含めると、エラーが出ていたので、エラーが出ないように以下の修正を行いました。
 *	- P/ECE以外では、dief()はdie()と同じにマクロ定義しました。
 *	  P/ECEではdie()がpceFontPrintf()を使っているために、それとは別に汎用版のdief()を用意したのですが、P/ECE以外ではdie()自体が汎用版となっており、同じで問題無いからです。
 *	- clipfix.hが先にインクルードされていなければ、固定小数点に依存する機能を除外するようにしました。
 *	  libclip/extclip.hでclipfix.hをインクルードせずに、clipflt.hだけインクルードした場合のためです。
 *	  もし今後、libclip/extclip.hでclipfix.hをインクルードするように変更したら、このブロックも有効になる予定です。
 *	- cliprend.hが先にインクルードされていなければ、描画に依存する機能を除外するようにしました。
 *	  libclip/extclip.hでcliprend.hをインクルードせずに、clipflt.hだけインクルードした場合のためです。
 *	  もし今後、libclip/extclip.hでcliprend.hをインクルードするように変更したら、このブロックも有効になる予定です。
 *	- P/ECE以外では、単精度版の数学関数は、倍精度版の数学関数を呼び出すようにしました。
 *	  これまでは、当モジュール内の単精度版の数学関数を、C言語版が無く直接アセンブラ版で作成していたので、P/ECE以外に含められませんでした。
 *	  clipflt.hに依存しているモジュールを、libclipに含められるようにするためだけの目的で、動作すれば良いだけなので速度は考慮していません。
 *	- VC++6.0で単精度版の数学関数の定義が衝突する事がある問題を回避しました。
 *	  詳細は、clipflt.hの、「ANSIライブラリ数学関数(math.lib)と類似の機能の単精度版」の宣言部分の、2016/02/25のコメントを参照して下さい。
 */
#include "clip.h"

#ifndef PIECE
#define NOASM	// このシンポルを定義すると、C言語版を使用します。 */
#endif /*PIECE*/

/****************************************************************************
 *	浮動小数点ベクトル(3D)
 ****************************************************************************/

/* 点pを通り法線ベクトルnである平面と、点aを通りベクトルvである直線の交点計算 */
#ifdef NOASM
vec3f vec3f_intersection_p_l(const vec3f* p, const vec3f* n, const vec3f* a, const vec3f* v) {
	vec3f q;
	float t;
	q = *p; vec3f_sub(&q, a);		/* (p-a)           */
	t = vec3f_dot(&q, n) / vec3f_dot(v, n);	/* (p-a)・n / v・n */
  #ifdef  __GNUC__
	q = (vec3f){ t, t, t };
  #else //__GNUC__
	q.x = t;
	q.y = t;
	q.z = t;
  #endif//__GNUC__
	vec3f_mul(&q, v);			/* v * t     */
	vec3f_add(&q, a);			/* v * t + a */
	return q;
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec3f_intersection_p_l
vec3f_intersection_p_l:
		;// %r12     := 戻り値を格納する隠し引数
		;// %r13     := p
		;// %r14     := n
		;// %r15     := a
		;// [%sp+0]  := retp
		;// [%sp+4]  := v
		xsub		%sp, %sp, 24
		;//
		xld.w		[%sp+12], %r12			;// [%sp+12] := 戻り値を格納する隠し引数
		xld.w		[%sp+16], %r14			;// [%sp+16] := n
		xld.w		[%sp+20], %r15			;// [%sp+20] := a
		;//
		ld.w		%r12, %sp			;// %r12     :=        &q
		xcall.d		memcpy				;// %r10     := memcpy(&q, p, sizeof(vec3f)) -+
		ld.w		%r14, 12			;// %r14     :=               sizeof(vec3f)   |			*delay*
		;//						;//                                           |
		xld.w		%r13, [%sp+20]			;// %r13     :=               a               |
		xcall.d		vec3f_sub			;//             vec3f_sub(&q, a)              |
		ld.w		%r12, %r10			;// %r12     :=           &q <----------------+			*delay*
		;//
		ld.w		%r12, %sp			;// %r12     :=               &a
		xld.w		%r13, [%sp+16]			;// %r13     :=                   n
		xcall		vec3f_dot			;// %r10     :=     vec3f_dot(&q, n)
		xld.w		[%sp+0], %r10			;// [%sp+0]  :=     vec3f_dot(&q, n)
		;//
		xld.w		%r12, [%sp+28]			;// %r12     :=                                  v
		xld.w		%r13, [%sp+16]			;// %r13     :=                                     n
		xcall		vec3f_dot			;// %r10     :=                        vec3f_dot(v, n) --+
		;//						;//                                                      |
		xld.w		%r12, [%sp+0]			;// %r12     :=     vec3f_dot(&q, n)                     |
		xcall.d		__divsf3			;// %r10     := f = vec3f_dot(&q, n) / vec3f_dot(v, n)   |
		ld.w		%r13, %r10			;// %r13     :=                        vec3f_dot(v, n) <-+	*delay*
		;//
		xld.w		[%sp+0], %r10			;// [%sp+0]  := q.x = f
		xld.w		[%sp+4], %r10			;// [%sp+4]  := q.y = f
		xld.w		[%sp+8], %r10			;// [%sp+8]  := q.z = f
		ld.w		%r12, %sp			;// %r12     :=           &q
		xld.w		%r13, [%sp+28]			;// %r13     :=               v
		xcall		vec3f_mul			;//             vec3f_mul(&q, v)
		;//
		ld.w		%r12, %sp			;// %r12     :=           &q
		xld.w		%r13, [%sp+20]			;// %r13     :=               a
		xcall		vec3f_add			;//             vec3f_add(&q, a)
		;//
		xld.w		%r12, [%sp+12]			;// %r12     := 戻り値を格納する隠し引数
		ld.w		%r13, %sp			;// %r13     :=                &q
		xcall.d		memcpy				;// %r10     := memcpy(戻り値, &q, sizeof(vec3f))
		ld.w		%r14, 12			;// %r14     :=                    sizeof(vec3f)		*delay*
		;//
		xadd		%sp, %sp, 24
		ret						;// %r10     := 戻り値を格納した隠し引数 (S1C33 ABI仕様により必須)
");
#endif /*NOASM*/

/****************************************************************************
 *	浮動小数点行列(3D)
 ****************************************************************************/

/****************************************************************************
 *	浮動小数点ベクトル(2D)
 ****************************************************************************/

/* 点a,bを通る直線と点cとの距離 */
#ifdef NOASM
float vec2f_distance_l_p(const vec2f* a, const vec2f* b, const vec2f* c) {
	vec2f v1;
	vec2f v2;
	v1 = v2 = *a;
	vec2f_sub(&v1, b);	/* a-b */
	vec2f_sub(&v2, c);	/* a-c */
	return fabsf(vec2f_cross(&v1, &v2) / vec2f_mag(&v1));
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec2f_distance_l_p
vec2f_distance_l_p:
		xsub		%sp, %sp, 20
		;//
		ld.w		%r4, [%r12]+		;// %r4      := a->x
		ld.w		%r5, [%r12]		;// %r5      := a->y
		xld.w		[%sp+0], %r4		;// [%sp+0]  := v1.x = a->x
		xld.w		[%sp+4], %r5		;// [%sp+4]  := v1.y = a->y
		xld.w		[%sp+8], %r4		;// [%sp+8]  := v2.x = a->x
		xld.w		[%sp+12], %r5		;// [%sp+12] := v2.y = a->y
		xld.w		[%sp+16], %r14		;// [%sp+16] := c
		;//
		ld.w		%r12, %sp		;// %r12     :=           &v1
		xcall		vec2f_sub		;//             vec2f_sub(&v1, b)
		;//
		xld.w		%r13, [%sp+16]		;// %r13     :=                c
;//		xadd		%r12, %sp, 8		;// %r12     :=           &v2 ----+
		ld.w		%r12, %sp		;// <-----------------------------+
		xcall.d		vec2f_sub		;//             vec2f_sub(&v2, c) |
		add		%r12, 8			;// <-----------------------------+						*delay*
		;//
		ld.w		%r12, %sp		;// %r12     :=             &v1							*delay*
;//		xadd		%r13, %sp, 8		;// %r12     :=                  &v2 ---+
		ld.w		%r13, %sp		;// <-----------------------------------+
		xcall.d		vec2f_cross		;// %r10     := vec2f_cross(&v1, &v2) --|-+
		add		%r13, 8			;// <-----------------------------------+ |					*delay*
		xld.w		[%sp+16], %r10		;// [%sp+16] := vec2f_cross(&v1, &v2) <---+
		;//
		ld.w		%r12, %sp		;// %r12     :=           &v1
		xcall		vec2f_mag		;//             vec2f_mag(&v1) --------------------------+
		;//					;//                                                      |
		xld.w		%r12, [%sp+16]		;// %r12     := vec2f_cross(&v1, &v2)                    |
		xcall.d		__divsf3		;// %r10     := vec2f_cross(&v1, &v2) / vec2f_mag(&v1) --|-----+
		ld.w		%r13, %r10		;// %r13     :=                         vec2f_mag(&v1) <-+     |		*delay*
		;//					;//                                                            |
		xadd		%sp, %sp, 20		;//                                                            |
		;//					;//                                                            |
		xjp.d		fabsf			;// %r10     := fabsf(vec2f_cross(&v1, &v2) / vec2f_mag(&v1))  |
		ld.w		%r12, %r10		;// %r12     :=       vec2f_cross(&v1, &v2) / vec2f_mag(&v1) <-+		*delay*
");
#endif /*NOASM*/

/*--------------------------------------------------------------------------*/

/* a,bを通る直線と、点cから直線へ下ろした垂線との交点計算 */
#ifdef NOASM
vec2f vec2f_intersection_l_p(const vec2f* a, const vec2f* b, const vec2f* c) {
	vec2f d;
	d.x = (a->y - b->y) + c->x;
	d.y = (b->x - a->x) + c->y;
	return vec2f_intersection_l(a, b, c, &d);
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec2f_intersection_l_p
vec2f_intersection_l_p:
		xsub		%sp, %sp, 36
		;//
		xld.w		[%sp+4], %r12		;// [%sp+4]  := 戻り値を格納する隠し引数
		xld.w		[%sp+8], %r13		;// [%sp+8]  := a
		xld.w		[%sp+12], %r14		;// [%sp+12] := b
		xld.w		[%sp+16], %r15		;// [%sp+16] := c
		;//
		ld.w		%r4, [%r13]+		;// %r4      := a->x
		ld.w		%r5, [%r13]		;// %r5      := a->y
		ld.w		%r6, [%r14]+		;// %r6      := b->x
		ld.w		%r7, [%r14]		;// %r7      := b->y
		xld.w		[%sp+20], %r5		;// [%sp+20] := d.x = a->y
		xld.w		[%sp+24], %r6		;// [%sp+24] := d.y = b->x
		xld.w		[%sp+28], %r7		;// [%sp+28] := b->y
		xld.w		[%sp+32], %r4		;// [%sp+32] := a->x
		;//
		xadd		%r12, %sp, 20		;// %r12     := &d
		xld.w		[%sp+0], %r12		;// [%sp+0]  := &d ---------------------------------+
;//		xadd		%r13, %sp, 28		;// %r13     :=     { b->y, a->x } --+              |
		ld.w		%r13, %sp		;// <--------------------------------+              |
		xcall.d		vec2f_sub		;//   vec2f_sub(&d, { b->y, a->x })  |              |
		add		%r13, 28		;// <--------------------------------+              |	*delay*
		;//					;//                                                 |
		xld.w		%r12, [%sp+0]		;// %r12     := &d                                  |
		xld.w		%r13, [%sp+16]		;// %r13     :=     { c->x, c->y }                  |
		xcall		vec2f_add		;//   vec2f_add(&d, { c->x, c->y })                 |
		;//					;//                                                 |
		xld.w		%r12, [%sp+4]		;// %r12     := 戻り値を格納する隠し引数            |
		xld.w		%r13, [%sp+8]		;// %r13     :=                      a              |
		xld.w		%r14, [%sp+12]		;// %r14     :=                         b           |
		xld.w		%r15, [%sp+16]		;// %r15     :=                            c        |
		xcall		vec2f_intersection_l	;// %r10     := vec2f_intersection_l(a, b, c, &d) <-+
		;//
		xadd		%sp, %sp, 36
		ret					;// %r10     := 戻り値を格納した隠し引数 (S1C33 ABI仕様により必須)
");
#endif /*NOASM*/

/*--------------------------------------------------------------------------*/

/* a1,a2を通る直線とb1,b2を通る直線の交点計算 */
#ifdef NOASM
vec2f vec2f_intersection_l(const vec2f* a1, const vec2f* a2, const vec2f* b1, const vec2f* b2) {
	vec2f a;
	vec2f b;
	vec2f c;
	float f;
	a = *a2; vec2f_sub(&a, a1);	/* a2-a1 */
	b = *a1; vec2f_sub(&b, b2);	/* a1-b2 */
	c = *b1; vec2f_sub(&c, b2);	/* b1-b2 */
	f = vec2f_cross(&a, &b) / vec2f_cross(&a, &c);
  #ifdef  __GNUC__
	a = (vec2f){ f, f };
  #else //__GNUC__
	a.x = f;
	a.y = f;
  #endif//__GNUC__
	vec2f_mul(&a, &c);
	vec2f_add(&a, b2);
	return a;
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec2f_intersection_l
vec2f_intersection_l:
		xsub		%sp, %sp, 32
		;//
		xld.w		[%sp+24], %r12		;// [%sp+24] := 戻り値を格納する隠し引数
		;//
		ld.w		%r4, [%r14]+		;// %r4      := a2->x
		ld.w		%r5, [%r14]		;// %r5      := a2->y
		xld.w		[%sp+0], %r4		;// [%sp+0]  := a.x = a2->x
		xld.w		[%sp+4], %r5		;// [%sp+4]  := a.y = a2->y
		;//
		ld.w		%r4, [%r13]+		;// %r4      := a1->x, %r13 := a1 + 4 --+
		ld.w		%r5, [%r13]		;// %r5      := a1->y			|
		xld.w		[%sp+8], %r4		;// [%sp+8]  := b.x = a1->x		|
		xld.w		[%sp+12], %r5		;// [%sp+12] := b.y = a1->y		|
		;//					;//					|
		ld.w		%r4, [%r15]+		;// %r4      := b1->x			|
		ld.w		%r5, [%r15]		;// %r5      := b1->y			|
		xld.w		[%sp+16], %r4		;// [%sp+16] := c.x = b1->x		|
		xld.w		[%sp+20], %r5		;// [%sp+20] := c.y = b1->y		|
		;//					;//					|
		ld.w		%r12, %sp		;// %r12     :=           &a		|
		xcall.d		vec2f_sub		;//             vec2f_sub(&a, a1)	|
		sub		%r13, 4			;// %r13     :=               a1 <------+				*delay*
		;//
		xld.w		%r13, [%sp+36]		;// %r13     :=               b2
;//		xadd		%r12, %sp, 8		;// %r12     :=           &b -----+
		ld.w		%r12, %sp		;// <-----------------------------+
		xcall.d		vec2f_sub		;//             vec2f_sub(&b, b2) |
		add		%r12, 8			;// <-----------------------------+					*delay*
		;//
		xld.w		%r13, [%sp+36]		;// %r13     :=               b2
;//		xadd		%r12, %sp, 16		;// %r12     :=           &c -----+
		ld.w		%r12, %sp		;// <-----------------------------+
		xcall.d		vec2f_sub		;//             vec2f_sub(&c, b2) |
		add		%r12, 16		;// <-----------------------------+					*delay*
		;//
		ld.w		%r12, %sp		;// %r12     :=             &a
;//		xadd		%r13, %sp, 8		;// %r13     :=                 &b -+
		ld.w		%r13, %sp		;// <-------------------------------+
		xcall.d		vec2f_cross		;// %r10     := vec2f_cross(&a, &b) |
		add		%r13, 8			;// <-------------------------------+					*delay*
		xld.w		[%sp+28], %r10		;// [%sp+28] := vec2f_cross(&a, &b)
		;//
		ld.w		%r12, %sp		;// %r12     :=             &a
;//		xadd		%r13, %sp, 16		;// %r13     :=                 &c -+
		ld.w		%r13, %sp		;// <-------------------------------+
		xcall.d		vec2f_cross		;// %r10     := vec2f_cross(&a, &c) |
		add		%r13, 16		;// <-------------------------------+					*delay*
		;//
		xld.w		%r12, [%sp+28]		;// %r12     :=     vec2f_cross(&a, &b)
		xcall.d		__divsf3		;// %r10     := f = vec2f_cross(&a, &b) / vec2f_cross(&a, &c)
		ld.w		%r13, %r10		;// %r13     :=                           vec2f_cross(&a, &c)		*delay*
		;//
		xld.w		[%sp+0], %r10		;// [%sp+0]  := a.x = f
		xld.w		[%sp+4], %r10		;// [%sp+4]  := a.y = f
		ld.w		%r12, %sp		;// %r12     :=           &a
;//		xadd		%r13, %sp, 16		;// %r13     :=               &c -+
		ld.w		%r13, %sp		;// <-----------------------------+
		xcall.d		vec2f_mul		;//             vec2f_mul(&a, &c) |
		add		%r13, 16		;// <-----------------------------+					*delay*
		;//
		ld.w		%r12, %sp		;// %r12     :=           &a
		xld.w		%r13, [%sp+36]		;// %r13     :=               b2
		xcall		vec2f_add		;//             vec2f_add(&a, b2)
		;//
		xld.w		%r10, [%sp+24]		;// %r10     := 戻り値を格納する隠し引数
		xld.w		%r4, [%sp+0]		;// %r4      := a.x
		xld.w		%r5, [%sp+4]		;// %r5      := a.y
		ld.w		[%r10]+, %r4		;// 戻り値.x := a.x, %r10 := 戻り値を格納する隠し引数 + 4
		ld.w		[%r10], %r5		;// 戻り値.y := a.y
		;//
		xadd		%sp, %sp, 32
		ret.d
		sub		%r10, 4			;// %r10     := 戻り値を格納した隠し引数 (S1C33 ABI仕様により必須)	*delay*
");
#endif /*NOASM*/

/*--------------------------------------------------------------------------*/

/* a1,a2を端点とする線分とb1,b2を端点とする線分の交差判定 */
#ifdef NOASM
int vec2f_is_intersected_ls(const vec2f* a1, const vec2f* a2, const vec2f* b1, const vec2f* b2) {
	vec2f v1;
	vec2f v2;
	vec2f v3;

	/* 点b1と点b2が、直線a1→a2に対して異なる側にあるか? */
	v1 = v2 = v3 = *a1;
	vec2f_sub(&v1, a2);	/* a1-a2 */
	vec2f_sub(&v2, b1);	/* a1-b1 */
	vec2f_sub(&v3, b2);	/* a1-b2 */
	if((vec2f_cross(&v1, &v2) * vec2f_cross(&v1, &v3)) >= 0.0f) {
		return 0; /* 同じ側 */
	}

	/* 点a1と点a2が、直線b1→b2に対して異なる側にあるか? */
	v1 = v2 = v3 = *b1;
	vec2f_sub(&v1, b2);	/* b1-b2 */
	vec2f_sub(&v2, a1);	/* b1-a1 */
	vec2f_sub(&v3, a2);	/* b1-a2 */
	if((vec2f_cross(&v1, &v2) * vec2f_cross(&v1, &v3)) >= 0.0f) {
		return 0; /* 同じ側 */
	}

	return 1; /* 交差している */
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec2f_is_intersected_ls
vec2f_is_intersected_ls:
		pushn		%r3
		;//
		ld.w		%r0, %r12			;// %r0  := a1
		ld.w		%r1, %r13			;// %r1  := a2
		ld.w		%r2, %r14			;// %r2  := b1
;//		ld.w		%r3, %r15			;// %r3  := b2 ---------------------+
		call.d		vec2f_is_intersected_ls_SUB	;// %r10 := sign((v1×v2)*(v1×v3)) |
		ld.w		%r3, %r15			;// <-------------------------------+					*delay*
		jreq		vec2f_is_intersected_ls_RET	;// if(!sign) return sign
		;//
		ld.w		%r12, %r0
		ld.w		%r13, %r1
		ld.w		%r14, %r2
		ld.w		%r15, %r3
		ld.w		%r0, %r14			;// %r0  := b1
		ld.w		%r1, %r15			;// %r1  := b2
		ld.w		%r2, %r12			;// %r2  := a1
;//		ld.w		%r3, %r13			;// %r3  := a2 ---------------------+
		call.d		vec2f_is_intersected_ls_SUB	;// %r10 := sign((v1×v2)*(v1×v3)) |
		ld.w		%r3, %r13			;// <-------------------------------+					*delay*
		;//
vec2f_is_intersected_ls_RET:
		popn		%r3
		ret
		;//---------------------------------------------;//
vec2f_is_intersected_ls_SUB:
		xsub		%sp, %sp, 28
		;//
		ld.w		%r4, [%r0]			;// %r4      := a1->x
		xld.w		%r5, [%r0+4]			;// %r5      := a1->y
		xld.w		[%sp+0], %r4			;// v1.x     := a1->x
		xld.w		[%sp+4], %r5			;// v1.y     := a1->y
		xld.w		[%sp+8], %r4			;// v2.x     := a1->x
		xld.w		[%sp+12], %r5			;// v2.y     := a1->y
		xld.w		[%sp+16], %r4			;// v3.x     := a1->x
		xld.w		[%sp+20], %r5			;// v3.y     := a1->y
		;//
		ld.w		%r12, %sp			;// %r12     :=           &v1
		xcall.d		vec2f_sub			;//             vec2f_sub(&v1, a2)
		ld.w		%r13, %r1			;// %r13     :=                a2					*delay*
		;//
		xadd		%r12, %sp, 8			;// %r12     :=           &v2
		xcall.d		vec2f_sub			;//             vec2f_sub(&v2, b1)
		ld.w		%r13, %r2			;// %r13     :=                b1					*delay*
		;//
		xadd		%r12, %sp, 16			;// %r12     :=           &v3
		xcall.d		vec2f_sub			;//             vec2f_sub(&v3, b2)
		ld.w		%r13, %r3			;// %r13     :=                b2					*delay*
		;//
		ld.w		%r12, %sp			;// %r12     :=             &v1
;//		xadd		%r13, %sp, 8			;// %r13     :=                  &v2 ---+
		ld.w		%r13, %sp			;// <-----------------------------------+
		xcall.d		vec2f_cross			;// %r10     := vec2f_cross(&v1, &v2) --|-+
		add		%r13, 8				;// <-----------------------------------+ |				*delay*
		xld.w		[%sp+24], %r10			;// [%sp+24] := vec2f_cross(&v1, &v2) <---+
		;//
		ld.w		%r12, %sp			;// %r12     :=             &v1
;//		xadd		%r13, %sp, 16			;// %r13     :=                  &v3 ---+
		ld.w		%r13, %sp			;// <-----------------------------------+
		xcall.d		vec2f_cross			;// %r10     := vec2f_cross(&v1, &v3) --|-----------------------+
		add		%r13, 16			;// <-----------------------------------+                       |	*delay*
		;//						;//                                                             |
		xld.w		%r12, [%sp+24]			;// %r12     := vec2f_cross(&v1, &v2)                           |
		xcall.d		__mulsf3			;// %r10     := vec2f_cross(&v1, &v2) * vec2f_cross(&v1, &v3)   |
		ld.w		%r13, %r10			;// %r13     :=                         vec2f_cross(&v1, &v3) <-+	*delay*
		;//
		xadd		%sp, %sp, 28
		;//
		rl		%r10, 1				;// %r10     := eeeeeeee mmmmmmmm mmmmmmmm mmmmmmms
		ret.d
		and		%r10, 1				;// %r10     := 00000000 00000000 00000000 0000000s, %psr(Z) := !s	*delay*
");
#endif /*NOASM*/

/*--------------------------------------------------------------------------*/

/* 点pと、v[nv]を頂点とする凸多角形の内外判定 */
#ifdef NOASM
int vec2f_is_point_in_convex(const vec2f* p, const vec2f* v/*[nv]*/, int nv) {
	vec2f a = v[nv - 1];			/* 最初の始点 */
	vec2f b;
	vec2f c;
	float f = 0.0f;				/* 左右の記録 */
	float g;
	do {
		b = a; vec2f_sub(&b, p);	/* 調べる点(p)から、辺の始点(a)へのベクトル */
		c = a; vec2f_sub(&c, v);	/* 辺の終点(v)から、辺の始点(a)へのベクトル */
		g = vec2f_cross(&b, &c);	/* 調べる点が、辺の直線の左右(+/-)どちらにあるかを求める */
		if(g) {				/* 調べる点が辺の直線上(0)ならば、この辺は判断に含めない */
			if(f) {			/* 直線上でない最初の辺ならば、左右の記録のみ */
				if((*(int*)&f ^ *(int*)&g) < 0) {	/* 左右が混在していたら、点は凸多角形の外 */
					return 0;
				}
			}
			f = g;			/* 左右を記録する(初回のみでも良いが、毎回記録する方が処理が簡単) */
		}
		a = *v++;			/* 今回の終点を、次回の始点とする */
	} while(--nv);
	return 1;				/* 左右が混在していなければ、点は凸多角形の内 */
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec2f_is_point_in_convex
vec2f_is_point_in_convex:
		pushn		%r3
		xsub		%sp, %sp, 16
		;//
		ld.w		%r0, %r12			;// %r0  := p
		ld.w		%r1, %r13			;// %r1  := v
		ld.w		%r2, %r14			;// %r2  := nv
		ld.w		%r3, 0				;// %r3  := f = 0.0f
		;//
		sub		%r14, 1				;// %r14 :=        (nv - 1)
		sla		%r14, 3				;// %r14 :=        (nv - 1) * sizeof(vec2f)
		add		%r13, %r14			;// %r13 :=      &v[nv - 1]
		ld.w		%r4, [%r13]+			;// %r4  := a.x = v[nv - 1].x
		ld.w		%r5, [%r13]			;// %r5  := a.y = v[nv - 1].y
		;//
vec2f_is_point_in_convex_LOOP:
		xld.w		[%sp+0], %r4			;// b.x  := a.x
		xld.w		[%sp+4], %r5			;// b.y  := a.y
		xld.w		[%sp+8], %r4			;// c.x  := a.x
		xld.w		[%sp+12], %r5			;// c.y  := a.y
		;//
		ld.w		%r12, %sp			;// %r12 :=           &b
		xcall.d		vec2f_sub			;//         vec2f_sub(&b, p)
		ld.w		%r13, %r0			;// %r13 ;=               p			*delay*
		;//
		xadd		%r12, %sp, 8			;// %r12 :=           &c
		xcall.d		vec2f_sub			;//         vec2f_sub(&c, v)
		ld.w		%r13, %r1			;// %r13 :=               v			*delay*
		;//
		ld.w		%r12, %sp			;// %r12 :=                 &b
;//		xadd		%r13, %sp, 8			;// %r13 :=                     &c ---+
		ld.w		%r13, %sp			;// <---------------------------------+
		xcall.d		vec2f_cross			;// %r10 := g = vec2f_cross(&b, &c) --|-+
		add		%r13, 8				;// <---------------------------------+ |	*delay*
		;//						;//                                     |
		cmp		%r10, 0				;// if(g) <-----------------------------+
		jreq		vec2f_is_point_in_convex_NEXT
		cmp		%r3, 0				;//   if(f)
		jreq		4
		 xor		%r3, %r10			;//     %r3  := (f ^ g)
		 cmp		%r3, 0				;//     if((f ^ g)[31]) return 0
		 jrlt		vec2f_is_point_in_convex_RET0
		ld.w		%r3, %r10			;//   %r3  := f = g
vec2f_is_point_in_convex_NEXT:
		ld.w		%r4, [%r1]+			;// %r4  := a.x = v->x
		ld.w		%r5, [%r1]+			;// %r5  := a.y = v->y, %r1  := v++
		sub		%r2, 1				;// %r2  := nv--
		jrne		vec2f_is_point_in_convex_LOOP
		;//
		ld.w		%r10, 1				;// return 1
		xadd		%sp, %sp, 16			;// <-+
		popn		%r3				;//   |
		ret						;//   |
vec2f_is_point_in_convex_RET0:					;//   |
		jp.d		-3				;// --+
		ld.w		%r10, 0				;// return 0					*delay*
");
#endif /*NOASM*/

/*--------------------------------------------------------------------------*/

/* 点pと、v[nv]を頂点とする凹多角形の内外判定
 * * Fri Sep 12 23:10:59 JST 2008 Naoyuki Sawa
 * - アルゴリズムは、framht2.cモジュールのht2_pt_pgn()と同じです。
 *   アセンブラ版でレジスタを効率良く使い回せるよう、少し式を入れ替えました。
 * * Sat Sep 13 15:42:08 JST 2008 Naoyuki Sawa
 * - vec2f_is_point_in_concave()のバグを修正しました。
 * - これまでの版では、ある辺の一直線上にある点は、凹多角形外であっても、すべて内と判断してしまうバグがありました。
 *   たとえば、「vec2f v[4] = {{50,10},{50,20},{60,20},{40,30}};」という凹多角形に対して、
 *   (x=50)の垂直線上の点や、(y=20)の水平線上の点を、凹多角形外であっても、すべて内と判断してしまっていました。
 * - バグの原因は、辺のベクトルと、点から辺の一点へのベクトルの外積が0の場合に、即、点が辺の線分上と判断してしまっていたことでした。
 *   本当は、それでは辺と一直線上にあることしか判断できず、辺の線分上であるかどうかの判断が必要なのですが、それを忘れていました。
 * - 正しくは上述のように、外積が0だった場合は、辺の線分上か否かの判断を行うべきなのですが、
 *   現在の実装では、レジスタの使い回しのために、外積を求めた時点で辺の始点の座標が失われており、もし行うと処理が冗長になります。
 *   そこで、外積が0だった場合は、その辺に対して半直線は交差していないと扱うことにしました。
 *   辺の線分上にある点や、辺の点上にある点を、外と判断してしまう可能性があります(未確認)が、とりあえず大きな問題は無いと思います。→2008/09/14:対応しました。
 * - なお、C言語版を見ると判るとおり、「if(v1.y) {」の判断を先に行って、「f = vec2f_cross(&v0, &v1);」の処理をifの中に移せば、
 *   「if(v1.y) {」が不成立の時に、「f = vec2f_cross(&v0, &v1);」の計算を省略し、高速化できる可能性が有ります。
 *   しかし実際には、「if(v1.y) {」が不成立のことは稀なので(辺が水平の場合のみ)、あまり違いは無いと思います。
 *   アセンブラ版のレジスタ使い回しの効率を考えると、このままの処理順の方が都合が良いです。
 * - 今回のバグは、framht2.cモジュールのht2_pt_pgn()のアルゴリズムに由来します。
 *   まだ確認していないのですが、framht2.cモジュールのht2_pt_pgn()にも、同じバグが存在するはずです。(※重要!!未修正です!!)
 *   今度framht2.cモジュールのht2_pt_pgn()を利用するアプリケーションを作成するときに、忘れずにht2_pt_pgn()のバグも修正する予定です。
 * * Sun Sep 14 00:00:03 JST 2008 Naoyuki Sawa
 * - vec2f_is_point_in_concave()が、辺の線分上や端点にある点を、凹多角形の外と判断してしまう問題を修正しました。
 *   これまでの挙動でも、必ずしも誤りというわけではなかったのですが、やはり、辺の線分上や端点も内と見なす方が使い勝手が良いです。
 *   実際にvec2f_is_point_in_convex()はそういう仕様(内と見なす)ですので、どちらも同じ挙動となり、使い勝手が良くなったと思います。
 * * Sat Sep 12 04:12:14 JST 2009 Naoyuki Sawa
 * - これまでは、nに交差回数を数えていましたが、冗長でした。
 *   交差回数が奇数か偶数かが判れば充分なので、1ビットでトグルするだけにしました。
 * - 戻り値の仕様を変更しました。
 *   [旧] 点pが、凹多角形の内部か、辺の線分上ならば、0以外の値を返す。凹多角形の外部ならば、0を返す。
 *   [新] 点pが、凹多角形の内部ならば、1を返す。辺の線分上ならば、-1を返す。凹多角形の外部ならば、0を返す。
 *   凹多角形の内部か、辺の線分上かを、区別できるようになりました。vec2f_is_point_in_alternate_concaves()が、この仕様を利用します。
 *   その他のプログラムは、戻り値が0か、0以外かでしか判断していないので、この仕様変更は影響を及ぼしません。
 */
#ifdef NOASM
int vec2f_is_point_in_concave(const vec2f* p, const vec2f* v/*[nv]*/, int nv) {
	int i;
	int j;
	int n;
	const vec2f* vi;
	const vec2f* vj;
	float xmin;
	float xmax;
	float ymin;
	float ymax;
	float prev;
	float f;
	vec2f v0;
	vec2f 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.0f;
	n = 0;
	j = nv;
	do {
		v0 = *vi;
		v1 = *vi;
		vi++;
		if(!--i) {
			vi = v;
		}
		vec2f_sub(&v0, p);
		vec2f_sub(&v1, vi);
		f = vec2f_cross(&v0, &v1);
		if(!f) {					/* 点pが辺の直線上にある場合の特別処理 */
			if(v0.x) {				/* 点pが辺の始点上でなく、 */
				if(v0.x < 0.0f) {		/* 点pが辺の始点よりも右で、 */
					if(v0.x < v1.x) {	/* 点pが辺の終点よりも右なら、 */
						goto NOT_ON_LS;	/* 点pは辺の線分上ではないので処理継続 */
					}
				} else/*if(v0.x > 0.0f)*/ {	/* 点pが辺の始点よりも左で、 */
					if(v0.x > v1.x) {	/* 点pが辺の終点よりも左なら、 */
						goto NOT_ON_LS;	/* 点pは辺の線分上ではないので処理継続 */
					}
				}
			}
			if(v0.y) {				/* 点pが辺の始点上でなく、 */
				if(v0.y < 0.0f) {		/* 点pが辺の始点よりも下で、 */
					if(v0.y < v1.y) {	/* 点pが辺の終点よりも下なら、 */
						goto NOT_ON_LS;	/* 点pは辺の線分上ではないので処理継続 */
					}
				} else/*if(v0.y > 0.0f)*/ {	/* 点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.0f) {
				if((f < 0.0f) && (v1.y <= v0.y)) {
					if(prev < 0.0f) {
						if(v0.y < 0.0f) {
							n ^= 1;
						}
					} else {
						if(v0.y <= 0.0f) {
							n ^= 1;
						}
					}
				}
			} else /* if(v1.y > 0.0f) */ {
				if((f > 0.0f) && (v1.y >= v0.y)) {
					if(prev > 0.0f) {
						if(v0.y > 0.0f) {
							n ^= 1;
						}
					} else {
						if(v0.y >= 0.0f) {
							n ^= 1;
						}
					}
				}
			}
			prev = v1.y;
		}
	} while(--j);
	return n; /* 0 or 1 */
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec2f_is_point_in_concave
vec2f_is_point_in_concave:
		pushn		%r3
		xsub		%sp, %sp, 32
		;// %r12     := p
		;// %r13     := v
		;// %r14     := nv
		;//-----------------------------------------------------;
		ld.w		%r4, [%r12]+				;// %r4      := p->x
		ld.w		%r5, [%r12]				;// %r5      := p->y
		xld.w		[%sp+16], %r4				;// [%sp+16] := p->x
		xld.w		[%sp+20], %r5				;// [%sp+20] := p->y
		xld.w		[%sp+24], %r13				;// [%sp+24] := v
		xld.w		[%sp+28], %r14				;// [%sp+28] := nv
		;//
		ld.w		%r0, %r14				;// %r0      := i = nv
		ld.w		%r1, %r14				;// %r1      := j = nv
		ld.w		%r2, %r13				;// %r2      := vi = v
		ld.w		%r3, %r13				;// %r3      := vj = v
		ld.w		%r4, [%r3]+				;// %r4      := xmin = vj->x
		ld.w		%r5, %r4				;// %r5      := xmax = vj->x
		ld.w		%r6, [%r3]+				;// %r6      := ymin = vj->y, %r3  := vj++
		ld.w		%r7, %r6				;// %r7      := ymax = vj->y
		sub		%r1, 1					;// %r1      := j--
		;// %r0      := i
		;// %r1      := j
		;// %r2      := vi
		;// %r3      := vj
		;// %r4      := xmin
		;// %r5      := xmax
		;// %r6      := ymin
		;// %r7      := ymax
		;// [%sp+16] := p->x
		;// [%sp+20] := p->y
		;// [%sp+24] := v
		;// [%sp+28] := nv
vec2f_is_point_in_concave_LOOP1:
		ld.w		%r12, [%r3]				;// %r12     := vj->x
		xcall.d		__fcmps					;// %psr     := vj->x - xmin
		ld.w		%r13, %r4				;// %r13     :=         xmin			*delay*
		jrge		2					;// if(vj->x < xmin)
		 ld.w		%r4, [%r3]				;//   %r4      := xmin = vj->x
		;//
		ld.w		%r12, [%r3]				;// %r12     := vj->x
		xcall.d		__fcmps					;// %psr     := vj->x - xmax
		ld.w		%r13, %r5				;// %r13     :=         xmax			*delay*
		jrle		2					;// if(vj->x > xmax)
		 ld.w		%r5, [%r3]				;//   %r5      := xmax = vj->x
		;//
		add		%r3, 4					;// %r3      := &vj->y
		;//
		ld.w		%r12, [%r3]				;// %r12     := vj->y
		xcall.d		__fcmps					;// %psr     := vj->y - ymin
		ld.w		%r13, %r6				;// %r13     :=         ymin			*delay*
		jrge		5					;// if(vj->y < ymin)
		 ld.w		%r6, [%r3]				;//   %r6      := ymin = vj->y
		 ld.w		%r0, %r1				;//   %r0      := i = j
		 ld.w		%r2, %r3				;//   %r2      :=      &vj->y
		 sub		%r2, 4					;//   %r2      := vi = &vj->x
		;//
		ld.w		%r12, [%r3]				;// %r12     := vj->y
		xcall.d		__fcmps					;// %psr     := vj->y - ymax
		ld.w		%r13, %r7				;// %r13     :=         ymax			*delay*
		jrle		2					;// if(vj->y > ymax)
		 ld.w		%r7, [%r3]				;//   %r7      := ymax = vj->y
		;//
		sub		%r1, 1					;// %r1      := j--
		jrne.d		vec2f_is_point_in_concave_LOOP1
		add		%r3, 4					;// %r3      := &(vj + 1)->x			*delay*
		;//
		xld.w		%r12, [%sp+16]				;// %r12     := p->x
		xcall.d		__fcmps					;// %psr     := p->x - xmin
		ld.w		%r13, %r4				;// %r13     :=        xmin			*delay*
		jrlt		vec2f_is_point_in_concave_RET0		;// if(p->x < xmin) return 0
		;//
		xld.w		%r12, [%sp+16]				;// %r12     := p->x
		xcall.d		__fcmps					;// %psr     := p->x - xmax
		ld.w		%r13, %r5				;// %r13     :=        xmax			*delay*
		jrgt		vec2f_is_point_in_concave_RET0		;// if(p->x > xmax) return 0
		;//
		xld.w		%r12, [%sp+20]				;// %r12     := p->y
		xcall.d		__fcmps					;// %psr     := p->y - ymin
		ld.w		%r13, %r6				;// %r13     :=        ymin			*delay*
		jrlt		vec2f_is_point_in_concave_RET0		;// if(p->y < ymin) return 0
		;//
		xld.w		%r12, [%sp+20]				;// %r12     := p->y
		xcall.d		__fcmps					;// %psr     := p->y - ymax
		ld.w		%r13, %r7				;// %r13     :=        ymax			*delay*
		jrgt		vec2f_is_point_in_concave_RET0		;// if(p->y > ymax) return 0
		;// %r0      := i
		;// %r2      := vi
		;// [%sp+16] := p->x
		;// [%sp+20] := p->y
		;// [%sp+24] := v
		;// [%sp+28] := nv
		;//-----------------------------------------------------;
		xld.w		%r1, [%sp+28]				;// %r1      := j = nv
		ld.w		%r3, 0					;// %r3      := prev = 0.0f
		xld.w		[%sp+28], %r3				;// [%sp+28] := n = 0
		;// %r0      := i
		;// %r1      := j
		;// %r2      := vi
		;// %r3      := prev
		;// [%sp+16] := p->x
		;// [%sp+20] := p->y
		;// [%sp+24] := v
		;// [%sp+28] := n
vec2f_is_point_in_concave_LOOP2:
		ld.w		%r4, [%r2]+				;// %r4      := vi->x
		ld.w		%r5, [%r2]+				;// %r5      := vi->y, %r2  := vi++
		xld.w		[%sp+0], %r4				;// [%sp+0]  := v0.x = vi->x
		xld.w		[%sp+4], %r5				;// [%sp+4]  := v0.y = vi->y
		xld.w		[%sp+8], %r4				;// [%sp+8]  := v1.x = vi->x
		xld.w		[%sp+12], %r5				;// [%sp+12] := v1.y = vi->y
		;// %r0      := i
		;// %r1      := j
		;// %r2      := vi
		;// %r3      := prev
		;// [%sp+0]  := v0.x
		;// [%sp+4]  := v0.y
		;// [%sp+8]  := v1.x
		;// [%sp+12] := v1.y
		;// [%sp+16] := p->x
		;// [%sp+20] := p->y
		;// [%sp+24] := v
		;// [%sp+28] := n
		sub		%r0, 1					;// %r0      := i--
		jrne		2					;// if(!i)
		 xld.w		%r2, [%sp+24]				;//   %r2      := vi = v
		;//
		ld.w		%r12, %sp				;// %r12     :=           &v0
;//		xadd		%r13, %sp, 16				;// %r13     :=                p --+
		ld.w		%r13, %sp				;// <------------------------------+
		xcall.d		vec2f_sub				;//             vec2f_sub(&v0, p)  |
		add		%r13, 16				;// <------------------------------+		*delay*
		;//
		xadd		%r12, %sp, 8				;// %r12     :=           &v1
		xcall.d		vec2f_sub				;//             vec2f_sub(&v1, vi)
		ld.w		%r13, %r2				;// %r13     :=                vi		*delay*
		;//
		ld.w		%r12, %sp				;// %r12     :=                 &v0
;//		xadd		%r13, %sp, 8				;// %r13     :=                      &vi --+
		ld.w		%r13, %sp				;// <--------------------------------------+
		xcall.d		vec2f_cross				;// %r10     := f = vec2f_cross(&v0, &v1)  |
		add		%r13, 8					;// <--------------------------------------+	*delay*
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		cmp		%r10, 0					;// %psr     := f - 0.0f
		jrne.d		vec2f_is_point_in_concave_NOT_ON_LS	;// if(!f)
		ld.w		%r4, %psr				;// %r4      := f - 0.0f ------------------+	*delay*
		xld.w		%r12, [%sp+0]				;//   %r12     := v0.x			   |
		xld.w		%r13, [%sp+8]				;//   %r13     := v1.x			   |
		cmp		%r12, 0					;//   if(v0.x)				   |
		jreq		vec2f_is_point_in_concave_X_ON_LS	;//					   |
		jrgt		vec2f_is_point_in_concave_V0X_GT_0	;//     if(v0.x < 0.0f)			   |
		xcall		__fcmps					;//       %psr     := v0.x - v1.x	   |
		jrlt		vec2f_is_point_in_concave_NOT_ON_LS	;//       if(v0.x < v1.x) goto NOT_ON_LS   |
		jp		vec2f_is_point_in_concave_X_ON_LS	;//					   |
vec2f_is_point_in_concave_V0X_GT_0:					;//					   |
		xcall		__fcmps					;//       %psr     := v0.x - v1.x	   |
		jrgt		vec2f_is_point_in_concave_NOT_ON_LS	;//       if(v0.x > v1.x) goto NOT_ON_LS   |
vec2f_is_point_in_concave_X_ON_LS:					;//					   |
		xld.w		%r12, [%sp+4]				;//   %r12     := v0.y			   |
		xld.w		%r13, [%sp+12]				;//   %r13     := v1.y			   |
		cmp		%r12, 0					;//   if(v0.y)				   |
		jreq		vec2f_is_point_in_concave_RET_1		;//					   |
		jrgt		vec2f_is_point_in_concave_V0Y_GT_0	;//     if(v0.y < 0.0f)			   |
		xcall		__fcmps					;//       %psr     := v0.y - v1.y	   |
		jrlt		vec2f_is_point_in_concave_NOT_ON_LS	;//       if(v0.y < v1.y) goto NOT_ON_LS   |
		jp		vec2f_is_point_in_concave_RET_1		;//					   |
vec2f_is_point_in_concave_V0Y_GT_0:					;//					   |
		xcall		__fcmps					;//       %psr     := v0.y - v1.y	   |
		jrgt		vec2f_is_point_in_concave_NOT_ON_LS	;//       if(v0.y > v1.y) goto NOT_ON_LS   |
		jp		vec2f_is_point_in_concave_RET_1		;//   return -1				   |
vec2f_is_point_in_concave_NOT_ON_LS:					;//					   |
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;//					   |
		xld.w		%r12, [%sp+12]				;// %r12     := v1.y -------------------+  |
		xld.w		%r13, [%sp+4]				;// %r13     := v0.y -------------------+  |
		cmp		%r12, 0					;// if(v1.y)				|  |
		jreq		vec2f_is_point_in_concave_NEXT		;//					|  |
		jrgt.d		vec2f_is_point_in_concave_V1Y_GT_0	;//					|  |
		ld.w		%psr, %r4				;//   %psr     := f - 0.0f -------------|--+	*delay*
		;//							;//					|  |
;//vec2f_is_point_in_concave_V1Y_LT_0:					;//   if(v1.y < 0.0f)			|  |
		jrge		vec2f_is_point_in_concave_PREV_V1Y	;//     if((f < 0.0f) <-----------------|--+
		xcall		__fcmps					;//     %psr     := v1.y - v0.y <-------+  |
		jrgt		vec2f_is_point_in_concave_PREV_V1Y	;//     && (v1.y <= v0.y))		|  |
		;//							;//					|  |
		cmp		%r3, 0					;//       %psr     := prev - 0.0f	|  |
		xld.w		%r4, [%sp+4]				;//       %r4      := v0.y		|  |
		jrge.d		4					;//       if(prev < 0.0f)		|  |
		cmp		%r4, 0					;//       %psr     := v0.y - 0.0f	|  |	*delay*
		 jrge		vec2f_is_point_in_concave_PREV_V1Y	;//         if(v0.y < 0.0f)		|  |
		 jp		vec2f_is_point_in_concave_N_TOGGLE	;//           n ^= 1			|  |
		jrgt		vec2f_is_point_in_concave_PREV_V1Y	;//         if(v0.y <= 0.0f)		|  |
		jp		vec2f_is_point_in_concave_N_TOGGLE	;//           n ^= 1			|  |
		;//							;//					|  |
vec2f_is_point_in_concave_V1Y_GT_0:					;//   else /* if(v1.y > 0.0f) */	|  |
		jrle		vec2f_is_point_in_concave_PREV_V1Y	;//     if((f > 0.0f) <-----------------|--+
		xcall		__fcmps					;//     %psr     := v1.y - v0.y <-------+
		jrlt		vec2f_is_point_in_concave_PREV_V1Y	;//     && (v1.y >= v0.y))
		;//
		cmp		%r3, 0					;//       %psr     := prev - 0.0f
		xld.w		%r4, [%sp+4]				;//       %r4      := v0.y
		jrle.d		4					;//       if(prev > 0.0f)
		cmp		%r4, 0					;//       %psr     := v0.y - 0.0f		*delay*
		 jrle		vec2f_is_point_in_concave_PREV_V1Y	;//         if(v0.y > 0.0f)
		 jp		vec2f_is_point_in_concave_N_TOGGLE	;//           n ^= 1
		jrlt		vec2f_is_point_in_concave_PREV_V1Y	;//         if(v0.y >= 0.0f)
;//		jp		vec2f_is_point_in_concave_N_TOGGLE	;//           n ^= 1
		;//
vec2f_is_point_in_concave_N_TOGGLE:
		xld.w		%r4, [%sp+28]				;//           %r4      := n
		xor		%r4, 1					;//           %r4      := n ^= 1
		xld.w		[%sp+28], %r4				;//           [%sp+28] := n
		;//
vec2f_is_point_in_concave_PREV_V1Y:
		xld.w		%r3, [%sp+12]				;//   %r3      := prev = v1.y
		;// %r0      := i
		;// %r1      := j
		;// %r2      := vi
		;// %r3      := prev
		;// [%sp+16] := p->x
		;// [%sp+20] := p->y
		;// [%sp+24] := v
		;// [%sp+28] := n
vec2f_is_point_in_concave_NEXT:
		sub		%r1, 1					;// %r1      := j--
		jrne		vec2f_is_point_in_concave_LOOP2
		;//-----------------------------------------------------;
		xld.w		%r10, [%sp+28]				;// %r10     := n = 0 or 1
vec2f_is_point_in_concave_RET:
		xadd		%sp, %sp, 32
		popn		%r3
		ret
vec2f_is_point_in_concave_RET0:
		jp.d		vec2f_is_point_in_concave_RET
		ld.w		%r10, 0					;// %r10     := n = 0				*delay*
vec2f_is_point_in_concave_RET_1:
		jp.d		vec2f_is_point_in_concave_RET
		ld.w		%r10, -1				;// %r10     := n = -1				*delay*
");
#endif /*NOASM*/

/*--------------------------------------------------------------------------*/

/* a[na]を頂点とする凹多角形と、b[nb]を頂点とする凹多角形の交差判定
 * * Mon Sep 15 00:00:02 JST 2008 Naoyuki Sawa
 * - アルゴリズムは、framht2.cモジュールのht2_pgn_pgn()と同じです。
 *   アセンブラ版でレジスタを効率良く使い回せるよう、処理を少し工夫しました。
 */
#ifdef NOASM
int vec2f_is_intersected_p(const vec2f* a/*[na]*/, int na, const vec2f* b/*[nb]*/, int nb) {
	int ia;
	int ib;
	const vec2f* a1;
	const vec2f* a2;
	const vec2f* b1;
	const vec2f* b2;
	float axmin;
	float axmax;
	float aymin;
	float aymax;
	float bxmin;
	float bxmax;
	float bymin;
	float 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(vec2f_is_intersected_ls(a1, a2, b1, b2)) {
				return 1; /* 交差している */
			}
			b1 = b2;
			b2++;
		} while(--ib);
		/* 上のループを完了すると、都合良く「b1 = &b[nb - 1];」に戻っています。 */
		a1 = a2;
		a2++;
	} while(--ia);

	/* 一方の凹多角形に、もう一方の凹多角形が、完全に含まれているか判断します。 */
	if(vec2f_is_point_in_concave(a, b, nb)) {
		return 1; /* 凹多角形aが、凹多角形bを含んでいる */
	}
	if(vec2f_is_point_in_concave(b, a, na)) {
		return 1; /* 凹多角形bが、凹多角形aを含んでいる */
	}

	return 0;
}
#else /*NOASM*/
asm("
		.code
		.align		1
		.global		vec2f_is_intersected_p
vec2f_is_intersected_p:
		pushn		%r3
		xsub		%sp, %sp, 32
		;//
		xld.w		[%sp+0], %r12				;// [%sp+0]  := a
		xld.w		[%sp+4], %r13				;// [%sp+4]  := na
		xld.w		[%sp+8], %r14				;// [%sp+8]  := b
		xld.w		[%sp+12], %r15				;// [%sp+12] := nb
		;// %r12     := a
		;// %r13     := na
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;//-----------------------------------------------------;
		ld.w		%r0, %r12				;// %r0      := a1 = a
		ld.w		%r1, %r13				;// %r1      := ia = na
		ld.w		%r4, [%r0]+				;// %r4      := axmin = a1->x
		ld.w		%r5, %r4				;// %r5      := axmax = a1->x
		ld.w		%r6, [%r0]+				;// %r6      := aymin = a1->y, %r0  := a1++
		ld.w		%r7, %r6				;// %r7      := aymax = a1->y
		sub		%r1, 1					;// %r1      := ia--
		;// %r0      := a1
		;// %r1      := ia
		;// %r4      := axmin
		;// %r5      := axmax
		;// %r6      := aymin
		;// %r7      := aymax
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
vec2f_is_intersected_p_LOOP1A:
		ld.w		%r12, [%r0]				;// %r12     := a1->x
		xcall.d		__fcmps					;// %psr     := a1->x - axmin
		ld.w		%r13, %r4				;// %r13     :=         axmin			*delay*
		jrge		2					;// if(a1->x < axmin)
		 ld.w		%r4, [%r0]				;//   %r4      := axmin = a1->x
		;//
		ld.w		%r12, [%r0]				;// %r12     := a1->x
		xcall.d		__fcmps					;// %psr     := a1->x - axmax
		ld.w		%r13, %r5				;// %r13     :=         axmax			*delay*
		jrle		2					;// if(a1->x > axmax)
		 ld.w		%r5, [%r0]				;//   %r5      := axmax = a1->x
		;//
		add		%r0, 4					;// %r0      := &a1->y
		;//
		ld.w		%r12, [%r0]				;// %r12     := a1->y
		xcall.d		__fcmps					;// %psr     := a1->y - aymax
		ld.w		%r13, %r6				;// %r13     :=         aymax			*delay*
		jrge		2					;// if(a1->y < aymax)
		 ld.w		%r6, [%r0]				;//   %r6      := aymax = a1->y
		;//
		ld.w		%r12, [%r0]				;// %r12     := a1->y
		xcall.d		__fcmps					;// %psr     := a1->y - aymax
		ld.w		%r13, %r7				;// %r13     :=         aymax			*delay*
		jrle		2					;// if(a1->y > aymax)
		 ld.w		%r7, [%r0]				;//   %r7      := aymax = a1->y
		;//
		sub		%r1, 1					;// %r1      := ia--
		jrne.d		vec2f_is_intersected_p_LOOP1A
		add		%r0, 4					;// %r0      := &(a1 + 1)->x			*delay*
		;// %r0      := a1 = &a[na]
		;// %r4      := axmin
		;// %r5      := axmax
		;// %r6      := aymin
		;// %r7      := aymax
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		xld.w		[%sp+16], %r4				;// [%sp+16] := axmin
		xld.w		[%sp+20], %r5				;// [%sp+20] := axmax
		xld.w		[%sp+24], %r6				;// [%sp+24] := aymin
		xld.w		[%sp+28], %r7				;// [%sp+28] := aymax
		;// %r0      := a1 = &a[na]
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;// [%sp+16] := axmin
		;// [%sp+20] := axmax
		;// [%sp+24] := aymin
		;// [%sp+28] := aymax
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		xld.w		%r2, [%sp+8]				;// %r2      := b1 = b
		xld.w		%r3, [%sp+12]				;// %r3      := ib = nb
		ld.w		%r4, [%r2]+				;// %r4      := bxmin = b1->x
		ld.w		%r5, %r4				;// %r5      := bxmax = b1->x
		ld.w		%r6, [%r2]+				;// %r6      := bymin = b1->y, %r2  := b1++
		ld.w		%r7, %r6				;// %r7      := bymax = b1->y
		sub		%r3, 1					;// %r3      := ib--
		;// %r0      := a1 = &a[na]
		;// %r2      := b1
		;// %r3      := ib
		;// %r4      := bxmin
		;// %r5      := bxmax
		;// %r6      := bymin
		;// %r7      := bymax
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;// [%sp+16] := axmin
		;// [%sp+20] := axmax
		;// [%sp+24] := aymin
		;// [%sp+28] := aymax
vec2f_is_intersected_p_LOOP1B:
		ld.w		%r12, [%r2]				;// %r12     := b1->x
		xcall.d		__fcmps					;// %psr     := b1->x - bxmin
		ld.w		%r13, %r4				;// %r13     :=         bxmin			*delay*
		jrge		2					;// if(b1->x < bxmin)
		 ld.w		%r4, [%r2]				;//   %r4      := bxmin = b1->x
		;//
		ld.w		%r12, [%r2]				;// %r12     := b1->x
		xcall.d		__fcmps					;// %psr     := b1->x - bxmax
		ld.w		%r13, %r5				;// %r13     :=         bxmax			*delay*
		jrle		2					;// if(b1->x > bxmax)
		 ld.w		%r5, [%r2]				;//   %r5      := bxmax = b1->x
		;//
		add		%r2, 4					;// %r2      := &b1->y
		;//
		ld.w		%r12, [%r2]				;// %r12     := b1->y
		xcall.d		__fcmps					;// %psr     := b1->y - bymax
		ld.w		%r13, %r6				;// %r13     :=         bymax			*delay*
		jrge		2					;// if(b1->y < bymax)
		 ld.w		%r6, [%r2]				;//   %r6      := bymax = b1->y
		;//
		ld.w		%r12, [%r2]				;// %r12     := b1->y
		xcall.d		__fcmps					;// %psr     := b1->y - bymax
		ld.w		%r13, %r7				;// %r13     :=         bymax			*delay*
		jrle		2					;// if(b1->y > bymax)
		 ld.w		%r7, [%r2]				;//   %r7      := bymax = b1->y
		;//
		sub		%r3, 1					;// %r3      := ib--
		jrne.d		vec2f_is_intersected_p_LOOP1B
		add		%r2, 4					;// %r2      := &(b1 + 1)->x			*delay*
		;// %r0      := a1 = &a[na]
		;// %r2      := b1 = &b[nb]
		;// %r4      := bxmin
		;// %r5      := bxmax
		;// %r6      := bymin
		;// %r7      := bymax
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;// [%sp+16] := axmin
		;// [%sp+20] := axmax
		;// [%sp+24] := aymin
		;// [%sp+28] := aymax
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		xld.w		%r12, [%sp+16]				;// %r12     := axmin
		xcall.d		__fcmps					;// %psr     := axmin - bxmax
		ld.w		%r13, %r5				;// %r13     :=         bxmax			*delay*
		jrgt		vec2f_is_intersected_p_RET0		;// if(axmin > bxmax) return 0
		;//
		xld.w		%r12, [%sp+20]				;// %r12     := axmax
		xcall.d		__fcmps					;// %psr     := axmax - bxmin
		ld.w		%r13, %r4				;// %r13     :=         bxmin			*delay*
		jrlt		vec2f_is_intersected_p_RET0		;// if(axmax < bxmin) return 0
		;//
		xld.w		%r12, [%sp+24]				;// %r12     := aymin
		xcall.d		__fcmps					;// %psr     := aymin - bymax
		ld.w		%r13, %r7				;// %r13     :=         bymax			*delay*
		jrgt		vec2f_is_intersected_p_RET0		;// if(aymin > bymax) return 0
		;//
		xld.w		%r12, [%sp+28]				;// %r12     := aymax
		xcall.d		__fcmps					;// %psr     := aymax - bymin
		ld.w		%r13, %r6				;// %r13     :=         bymin			*delay*
		jrlt		vec2f_is_intersected_p_RET0		;// if(aymax < bymin) return 0
		;// %r0      := a1 = &a[na]
		;// %r2      := b1 = &b[nb]
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;//-----------------------------------------------------;
		sub		%r0, 8					;// %r0      := a1-- = &a[na - 1]
		xld.w		[%sp+16], %r0				;// [%sp+16] := a1
		sub		%r2, 8					;// %r2      := b1-- = &b[nb - 1]
		xld.w		[%sp+20], %r2				;// [%sp+20] := b1
		;//
		xld.w		%r0, [%sp+0]				;// %r0      := a2 = a
		xld.w		%r1, [%sp+4]				;// %r1      := ia = na
		;// %r0      := a2
		;// %r1      := ia
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;// [%sp+16] := a1
		;// [%sp+20] := b1
vec2f_is_intersected_p_LOOP2A:
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		xld.w		%r2, [%sp+8]				;// %r2      := b2 = b
		xld.w		%r3, [%sp+12]				;// %r3      := ib = nb
		;// %r0      := a2
		;// %r1      := ia
		;// %r2      := b2
		;// %r3      := ib
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;// [%sp+16] := a1
		;// [%sp+20] := b1
vec2f_is_intersected_p_LOOP2B:
		xld.w		%r12, [%sp+16]				;// %r12     :=                         a1
		ld.w		%r13, %r0				;// %r13     :=                             a2
		xld.w		%r14, [%sp+20]				;// %r14     :=                                 b1
		xcall.d		vec2f_is_intersected_ls			;// %r10     := vec2f_is_intersected_ls(a1, a2, b1, b2)
		ld.w		%r15, %r2				;// %r15     :=                                     b2		*delay*
		cmp		%r10, 0					;// if(vec2f_is_intersected_ls(a1, a2, b1, b2))
		jrne		vec2f_is_intersected_p_RET		;//   return 1
		;//
		xld.w		[%sp+20], %r2				;// [%sp+b1] := b1 = b2
		sub		%r3, 1					;// %r3      := ib--
		jrne.d		vec2f_is_intersected_p_LOOP2B
		add		%r2, 8					;// %r2      := b2++						*delay*
		;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;
		xld.w		[%sp+16], %r0				;// [%sp+a1] := a1 = a2
		sub		%r1, 1					;// %r1      := ia--
		jrne.d		vec2f_is_intersected_p_LOOP2A
		add		%r0, 8					;// %r0      := a2++						*delay*
		;// [%sp+0]  := a
		;// [%sp+4]  := na
		;// [%sp+8]  := b
		;// [%sp+12] := nb
		;//-----------------------------------------------------;
		xld.w		%r12, [%sp+0]				;// %r12    :=                           a
		xld.w		%r13, [%sp+8]				;// %r13    :=                              b
		xld.w		%r14, [%sp+12]				;// %r14    :=                                 nb
		xcall		vec2f_is_point_in_concave		;// %r10    := vec2f_is_point_in_concave(a, b, nb)
		cmp		%r10, 0					;// if(vec2f_is_point_in_concave(a, b, nb))
		jrne		vec2f_is_intersected_p_RET		;//   return 1
		;//
		xld.w		%r12, [%sp+8]				;// %r12    :=                           b
		xld.w		%r13, [%sp+0]				;// %r13    :=                              a
		xld.w		%r14, [%sp+4]				;// %r14    :=                                 na
		xcall		vec2f_is_point_in_concave		;// %r10    := vec2f_is_point_in_concave(b, a, na)
vec2f_is_intersected_p_RET:
		xadd		%sp, %sp, 32
		popn		%r3
		ret
vec2f_is_intersected_p_RET0:
		jp.d		vec2f_is_intersected_p_RET
		ld.w		%r10, 0					;// %r10    := 0						*delay*
");
#endif /*NOASM*/

/*--------------------------------------------------------------------------*/

int
vec2f_is_point_in_alternate_concaves(const vec2f* p, const vec2f* v/*[sum(nv[0...n-1])]*/, const int* nv/*[n]*/, int n)
{
	int c = 0;
	do {
		int f = vec2f_is_point_in_concave(p, v, *nv);
		if(f) {
			/* どれかの多角形の辺上ならば、即座に"内"と見なす */
			if(f == -1) {
				return f;
			}
			/* 多角形の内部ならば、回数の偶数奇数をトグルする */
			c ^= 1;
		}
		v += *nv++;
	} while(--n);
	return c;
}

/*--------------------------------------------------------------------------*/

#ifdef  __CLIP_REND_H__	//{{2016/02/25追加:cliprend.hが先にインクルードされていなければ、描画に依存する機能を除外するようにしました。libclip/extclip.hでcliprend.hをインクルードせずに、clipflt.hだけインクルードした場合のためです。もし今後、libclip/extclip.hでcliprend.hをインクルードするように変更したら、このブロックも有効になる予定です。}}

void
render_vec2f_alternate_concaves(RENDER* render, const vec2f* v/*[sum(nv[0...n-1])]*/, const int* nv/*[n]*/, int n, int c) /* ←cliprend.h */
{
	int i;
	int j;
	int x;
	int y;
	int left;
	int right;
	int top;
	int bottom;
	float xmin;
	float xmax;
	float ymin;
	float ymax;
	const vec2f* pv;
	vec2f 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++;
		}
	}

	/* 境界矩形をクリッピングする */
	left   =      floorf(xmin);
	right  = (int)floorf(xmax) + 1;
	top    =      floorf(ymin);
	bottom = (int)floorf(ymax) + 1;
	if(left   < render->left  ) left   = render->left  ;
	if(right  > render->right ) right  = render->right ;
	if(top    < render->top   ) top    = render->top   ;
	if(bottom > render->bottom) bottom = render->bottom;

	/* 境界矩形内のピクセルを描く */
	for(y = top; y < bottom; y++) {
		p.y = y;
		for(x = left; x < right; x++) {
			p.x = x;
			if(vec2f_is_point_in_alternate_concaves(&p, v, nv, n)) {
				render_point(render, x, y, c);
			}
		}
	}
}

#endif//__CLIP_REND_H__	//{{2016/02/25追加:cliprend.hが先にインクルードされていなければ、描画に依存する機能を除外するようにしました。libclip/extclip.hでcliprend.hをインクルードせずに、clipflt.hだけインクルードした場合のためです。もし今後、libclip/extclip.hでcliprend.hをインクルードするように変更したら、このブロックも有効になる予定です。}}

/****************************************************************************
 *	浮動小数点行列(2D)
 ****************************************************************************/

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

