/*
 *	clipflt.h
 *
 *	高速単精度浮動小数点演算ライブラリ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Sat Jun 21 22:52:08 JST 2008 Naoyuki Sawa
 *	- 作成開始。
 *	* Thu Jun 26 01:31:00 JST 2008 Naoyuki Sawa
 *	- C99の単精度版の標準関数についてのコメントを追記しました。
 *	* Sun Jun 29 15:18:06 JST 2008 Naoyuki Sawa
 *	- 単精度浮動小数点の基本演算サブルーチンが、%r4,%r5,%r6,%r7の値を変更しないことを、仕様としました。
 *	* Sun Jul 20 13:26:33 JST 2008 Naoyuki Sawa
 *	- 浮動小数点ベクトル、浮動小数点行列の構造体と、関数を追加しました。
 *	  keep/01_浮動小数版演算描画コード保存/clipmath.cモジュールを参考にしました。
 *	  浮動小数点演算が遅すぎて固定小数点演算へ移行したわけですが、再び浮動小数点演算に戻ったわけです。
 *	- 処理内容は、keep/01_浮動小数版演算描画コード保存/clipmath.c、および、clipfix.cとほぼ同じなので、あまりコメントを書いていません。
 *	  keep/01_浮動小数版演算描画コード保存/clipmath.c、および、clipfix.cのコメントを参考にして下さい。
 *	  また、clipfix.cに実装したけれど、ほとんど使用しなかった機能については、本モジュールでは未実装としてあります。(mat3f_rotxyx()など)
 *	- 高速RAMへの配置は、特に使用頻度が高いと予想する、vec3f_xform()とmat3f_xform()だけを、framflt3.cに分離しました。
 *	* 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、および、それらの関数群をを追加しました。
 *	* Fri Sep 05 12:45:54 JST 2008 Naoyuki Sawa
 *	- vec2f_dist()、vec2f_dist2()を作成し、アセンブラ化も行ないました。
 *	  これまでは、アプリケーションごとに個別に行なっていた処理ですが、使用頻度が高いので、関数化することにしました。
 *	* Fri Sep 05 12:47:13 JST 2008 Naoyuki Sawa
 *	- vec2f_distance_l_p()、vec2f_intersection_l()、vec2f_is_intersected_ls()を作成し、アセンブラ化も行ないました。
 *	- 「deq notes(http://www.deqnotes.net/)」さんのサイトの、
 *	  「平面幾何におけるベクトル演算(http://www.deqnotes.net/acmicpc/2d_geometry/)」のページを参考にさせていただきました。
 *	- アセンブラ版でレジスタの使い回しが効率的になるよう、少し式の変換を行ないましたが、アルゴリズムは上記記事と同じです。
 *	  関数名も、上記記事のソースコードの関数名に由来しています。
 *	* Mon Sep 22 00:17:58 JST 2008 Naoyuki Sawa
 *	- vec3f_dist()、vec3f_dist2()を作成し、アセンブラ化も行ないました。
 *	* Wed Sep 24 01:46:03 JST 2008 Naoyuki Sawa
 *	- rndf()、rndf_range()を作成し、アセンブラ化も行ないました。
 *	* Fri Sep 26 21:35:54 JST 2008 Naoyuki Sawa
 *	- dief()を作成し、アセンブラ化も行ないました。
 *	* Sat Oct 25 20:29:48 JST 2008 Naoyuki Sawa
 *	- mat2f_invno()を作成しました。
 *	* Sat Nov 08 15:28:16 JST 2008 Naoyuki Sawa
 *	- mat3f_inv()、mat2f_inv()を作成しました。
 *	* Thu Apr 02 13:37:51 JST 2009 Naoyuki Sawa
 *	- xtof()とftox()を追加しました。
 *	- xtof(),ftox()は、fst(),fld()と同じ働きですが、以下の二点が異なります。
 *	  - fst(),fld()はマクロ定義されており、コンパイル時の変換も可能で、定数テーブルの初期化に利用できます。
 *	    xtof(),ftox()は関数で実装されており、常に実行時処理となり、定数テーブルの初期化に利用できません。
 *	  - xtof(),ftox()は、固定小数点のバイアスが2^10であることを利用して、効率的な実装としました。
 *	    fst(),fld()は、実行時処理に展開された場合は、上述の特性は考慮されず、非効率的な処理となります。
 *	- xtof()とftox()は、%r4,%r5,%r6,%r7の値を破壊しません。
 *	  xtof()とftox()は独自に定義した関数であり、単精度浮動小数点の基本演算サブルーチンではありませんが、
 *	  framflt1.sモジュールで実装した基本演算サブルーチンと同様のレジスタ規約を前提として、利用可能です。
 *	- xtof()とftox()の追加に伴い、vec3f_conv(),vec3x_conv(),mat3f_conv(),mat3x_conv()が、xtof(),ftox()を利用するように変更しました。
 *	* Wed Sep 09 18:21:50 JST 2009 Naoyuki Sawa
 *	- vec2f_is_point_in_alternate_concaves()を追加しました。
 *	* Sat Sep 12 04:32:03 JST 2009 Naoyuki Sawa
 *	- vec2f_is_point_in_alternate_concaves()の仕様を変更しました。
 *	  [旧] 多角形がドーナツ状に重なっている場合、外側の多角形の辺上の点は"内"、内側の多角形の辺上の点は"外"と見なします。
 *	  [新] 多角形がドーナツ状に重なっている場合、外側の多角形の辺上の点も、内側の多角形の辺上の点も、"内"と見なします。
 *	* Sun Sep 20 17:20:17 JST 2009 Naoyuki Sawa
 *	- solve_simultaneous_equations()を追加しました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* 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のコメントを参照して下さい。
 *	* Tue Mar 08 21:09:23 JST 2016 Naoyuki Sawa
 *	- solve_simultaneous_equations()をマルチスレッド化しました。
 *	  詳細は、clipflt1.c 内の、「マルチスレッド版solve_simultaneous_equations()の検証結果」を参照して下さい。
 *	* Sun May 29 21:54:56 JST 2016 Naoyuki Sawa
 *	- Visual C++ .NETならば、コンパイラが持っている単精度版の数学関数を使うようにしました。
 *	  詳細は、以下の通りです。
 *	- VC++2015で当ライブラリをコンパイルしてみた所、VC++2015はC99に対応しているので、コンパイラが単精度版の数学関数を持っており、当モジュールで定義している単精度版の数学関数と衝突して、コンパイルエラーになりました。
 *	  VC++6.0の場合は、C++の場合のみインライン版の単精度版の数学関数が定義されるという特殊な構造だったので、コンパイラ側の関数を無効化して常に当モジュールの単精度版の数学関数を使用するようにして対処していたのですが、
 *	  VC++2015の場合は、CでもC++でもインライン版の単精度版の数学関数が定義されるので(c:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\math.h)、常にコンパイラの単精度版の数学関数を使用する事にしました。
 *	- 上記の対策のために、Visual C++ .NETならば、clipflt.hの一部と、framflt2.cの全部を、条件コンパイルで無効化するようにしました。
 *	  framflt2.cは全部を無効化する代わりにVC++2015のlibclipプロジェクトから外しても良かったのですが、VC++6.0とVC++2015とでlibclipプロジェクトに含めるファイルを同じにしておきたかったので、前者の方法を取る事にしました。
 *	  VC++6.0とVC++2015とでlibclipプロジェクトに含めるファイルを同じにしておきたい理由は、VC++6.0のlibclipプロジェクトを単純に変換して、VC++2015のlibclipプロジェクトを生成したいからです。
 */
#ifndef __CLIP_FLT_H__
#define __CLIP_FLT_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

/*****************************************************************************
 *	定数・マクロ
 *****************************************************************************/

typedef union _FLT_INT {
	struct {
		unsigned m : 23;	/* mantissa */
		unsigned e :  8;	/* exponent */
		unsigned s :  1;	/* sign */
	} i;
	float f;
} FLT_INT;

/*****************************************************************************
 *	EPSON版浮動小数点演算ライブラリ(fp.lib)の同名ルーチン置き換え
 *****************************************************************************/

//┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫重　要┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
//┃* Sun Jun 29 15:18:06 JST 2008 Naoyuki Sawa                                                                                         ┃
//┃- 本モジュール内で定義されている、単精度浮動小数点の基本演算サブルーチンは、すべて、%r4,%r5,%r6,%r7の値を変更しません。             ┃
//┃  S1C33 ABI仕様に従って値を維持する%r0,%r1,%r2,%r3に加えて、%r4,%r5,%r6,%r7の値も維持します。                                       ┃
//┃  呼び出し側プログラムは、%r0,%r1,%r2,%r3,%r4,%r5,%r6,%r7の値が変更されないことを前提に、レジスタ使用を最適化できます。             ┃
//┃- 基本演算サブルーチンによっては、現在の実装では%r14や%r15の値も維持しているものが有りますが、今後の実装変更において保証されません。┃
//┃  呼び出し側プログラムは、%r0,%r1,%r2,%r3,%r4,%r5,%r6,%r7以外の値が変更されないことを前提として、作成しないでください。             ┃
//┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

float __addsf3(float x, float y);	/* float + float ->     float */
float __subsf3(float x, float y);	/* float - float ->     float */
float __mulsf3(float x, float y);	/* float * float ->     float */
float __divsf3(float x, float y);	/* float / float ->     float */
float __negsf2(float x, float y);	/*       - float ->     float */
int __fixsfsi(float x);			/*         float ->       int */
unsigned __fixunssfsi(float x);		/*         float ->  unsigned */
float __floatsisf(int x);		/*           int ->     float */
float __truncdfsf2(double x);		/*        double ->     float */
double __extendsfdf2(float x);		/*         float ->    double */
void __fcmps(float x, float y);		/* float - float -> condition */

/*****************************************************************************
 *	ANSIライブラリ数学関数(math.lib)と類似の機能の単精度版
 *****************************************************************************/

//{{2016/05/29追加:Visual C++ .NETならば、コンパイラが持っている単精度版の数学関数を使うようにしました。
#if     !(defined(_MSC_VER) && (_MSC_VER > 1200))	//Visual C++ .NETならば、この範囲のコードを使用しません。↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//}}2016/05/29追加:Visual C++ .NETならば、コンパイラが持っている単精度版の数学関数を使うようにしました。

/* * Thu Jun 26 01:31:00 JST 2008 Naoyuki Sawa
 * - C99には、単精度版の標準関数が定められているそうです。(sqrtf()など)
 *   以下の関数は、C99の単精度版の標準関数とほぼ同じ仕様だと思いますが、
 *   C99の関数仕様を良く知らないので、安全のため別の名前にしておきます。
 *   今後、C99の単精度版の標準関数の仕様に一致することが確認できた際に、
 *   sqrtfをfloat_sqrtに#defineする、などの方法で対応しようと思います。
 * * Sat Jul 12 22:49:09 JST 2008 Naoyuki Sawa
 * - C99の関数名に変更しました。(float_sqrt→sqrtfなど)
 *   #defineで対応しようかとも思っていましたが、やっぱり完全に書き換えることにしました。
 *   #defineでは、アセンブラルーチンから使うときに、元の名前でしか呼び出せないからです。
 * - 全置換で変換したので、当日以前のコードやコメントも、全部C99の関数名になっています。
 *   もう、float_*()形式の名前はどこにも残っていないので、忘れてしまって結構です。
 */
float sqrtf(float x);
float modff(float x, float* intptr);
float fmodf(float x, float y);
float cosf(float x);
float sinf(float x);
float tanf(float x);
float acosf(float x);
float asinf(float x);
float atanf(float x);
float atan2f(float y, float x);
float expf(float x);
float ldexpf(float x, int exp);
float frexpf(float x, int* expptr);
float logf(float x);
float floorf(float x);
float ceilf(float x);
float fabsf(float x);

/* * Thu Feb 25 21:08:23 JST 2016 Naoyuki Sawa
 * - VC++6.0で単精度版の数学関数の定義が衝突する事がある問題を回避しました。
 * - このブロックは、VC++6.0で、*.cppソースからインクルードされた場合のみ、有効になります。
 *   このブロックを追加した理由は、以下の通りです。
 * [問題点の内容]
 * - libclipを使ったアプリケーションの、*.cppソース内で、floorf()関数を使った時、floorf()関数の定義が、その*.cppソースと、framflt2.cの定義とで、衝突しているという、リンクエラーが生じました。
 *   その*.cppソースでは、floorf()関数を呼び出しているだけで、定義しているわけではないのに、なぜそのようなエラーが生じるのか不思議に思い、調査したところ、以下の事が判りました。
 * - VC++6.0は、C++に対してのみ、単精度版の数学関数を、インライン関数として定義しているようです。(\Program Files (x86)\Microsoft Visual Studio\VC98\Include\MATH.H 参照)
 *   VC++6.0では、C++のインライン関数がインライン展開させずに実体化された時、グローバルのリンケージを持つようです。(←推測です)
 *   そして、C++同士での実体化したインライン関数の衝突は、リンカの機能としてエラーになりませんが(←推測です)、C++で実体化したインライン関数と、Cで定義した同名関数の衝突はエラーになるようです。(←推測です)
 *   今回の場合、前者が「libclipを使ったアプリケーションの*.cppソース内でfloorf()関数を使った時に実体化したfloorf()」、後者が「framflt2.cで定義されたfloorf()」に相当します。
 * - 衝突を回避するために、framflt2.cでの単精度版の数学関数の定義を抑制してしまうと、今度は逆に、*.cソースから単精度版の数学関数が利用出来ないという問題が生じます。
 *   従って、単純に、framflt2.cでの単精度版の数学関数の定義を抑制するという方法も使えません。
 * - 根本的な問題点は、VC++6.0が、C++に対してだけ単精度版の数学関数を提供していて、Cに対して単精度版の数学関数を提供していない事です。
 *   もしVC++6.0がC++とCの両方に対して提供しているならばframflt2.cでの単精度版の数学関数を抑制すれば良いし、もしVC++6.0がどちらにも提供しなければframflt2.cで提供すれば良いのですが、
 *   VC++6.0がC++だけに提供してCに提供していないので、そのような単純な解決策が取れません。
 * [解決した方法]
 * - そこで、VC++6.0がC++だけに対して提供している単精度版の数学関数のインライン関数を無効化して、問題を回避する事にしました。
 *   まず、framflt2.cにて、framflt2.cが提供している単精度版の数学関数を呼び出す、別名の関数(fn_floorf等)を定義しました。
 *   次に、当ヘッダファイルがC++からインクルードされた場合、単精度版の数学関数を、上記の別名の関数にマクロで置き換えました。
 *   これによって、VC++6.0がC++だけに対して提供している単精度版の数学関数のインライン関数が使用される事は無くなり、定義の衝突も回避出来ます。
 * [注意点]
 * - もし、当ヘッダファイルをインクルードせずに、直接<math.h>をインクルードするようなC++ソースが存在し、その中で単精度版の数学関数を使用すると、前述の問題が発生する可能性が有ります。
 *   たとえば、オープンソースのライブラリをコンパイルして組み込む時などに、この状況が発生し得ます。(単精度版の数学関数が使用される事は少ないと思うので、実際に発生する事は少ないと思いますが…)
 *   もし今後、どうしても回避できない状況が発生した場合は、\Program Files (x86)\Microsoft Visual Studio\VC98\Include\MATH.Hをlibclipフォルダ等にコピーして、単精度版の数学関数をコメントアウトし、
 *   インクルードパスの優先度でlibclipフォルダ等を先にして回避するような方法を取らざるを得なくなるかも知れません。
 *   現時点ではそこまでの問題にはなっておらず、なるべくVC++6.0のヘッダファイルに対する変更は行いたくないので、上述の対策に留める事にしました。
 * [最後に]
 * - ここで述べた点は、VC++6.0でCとC++のモジュールを併用する場合だけの注意点です。
 *   今回行った対策は、P/ECEプロジェクトには影響無く、これまでと変わっていません。
 */
#ifdef  _MSC_VER
#ifdef  __cplusplus
#define sqrtf    fn_sqrtf
extern "C" float fn_sqrtf(float x);
#define modff    fn_modff
extern "C" float fn_modff(float x, float* intptr);
#define fmodf    fn_fmodf
extern "C" float fn_fmodf(float x, float y);
#define cosf     fn_cosf
extern "C" float fn_cosf(float x);
#define sinf     fn_sinf
extern "C" float fn_sinf(float x);
#define tanf     fn_tanf
extern "C" float fn_tanf(float x);
#define acosf    fn_acosf
extern "C" float fn_acosf(float x);
#define asinf    fn_asinf
extern "C" float fn_asinf(float x);
#define atanf    fn_atanf
extern "C" float fn_atanf(float x);
#define atan2f   fn_atan2f
extern "C" float fn_atan2f(float y, float x);
#define expf     fn_expf
extern "C" float fn_expf(float x);
#define ldexpf   fn_ldexpf
extern "C" float fn_ldexpf(float x, int exp);
#define frexpf   fn_frexpf
extern "C" float fn_frexpf(float x, int* expptr);
#define logf     fn_logf
extern "C" float fn_logf(float x);
#define floorf   fn_floorf
extern "C" float fn_floorf(float x);
#define ceilf    fn_ceilf
extern "C" float fn_ceilf(float x);
#define fabsf    fn_fabsf
extern "C" float fn_fabsf(float x);
#endif//__cplusplus
#endif//_MSC_VER

//{{2016/05/29追加:Visual C++ .NETならば、コンパイラが持っている単精度版の数学関数を使うようにしました。
#endif//!(defined(_MSC_VER) && (_MSC_VER > 1200))	//Visual C++ .NETならば、この範囲のコードを使用しません。↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
//}}2016/05/29追加:Visual C++ .NETならば、コンパイラが持っている単精度版の数学関数を使うようにしました。

/****************************************************************************
 *	デバッグ表示
 ****************************************************************************/

#ifdef  PIECE
  void dief(const char* fmt, ...) __attribute__((noreturn));
#else //PIECE
  #define dief die	//{{2016/02/25追加:P/ECE以外では、dief()はdie()と同じにマクロ定義しました。P/ECEではdie()がpceFontPrintf()を使っているために、それとは別に汎用版のdief()を用意したのですが、P/ECE以外ではdie()自体が汎用版となっており、同じで問題無いからです。}}
#endif//PIECE

/****************************************************************************
 *	浮動小数点乱数
 ****************************************************************************/

float rndf(int* seed); /* 0.0f以上、1.0f未満の乱数 */
#define RNDF(s) (rndf(&(s)))
float rndf_range(int* seed, float a, float b); /* a以上、b未満の乱数 */
#define RNDF_RANGE(s, a, b) (rndf_range(&(s), (a), (b)))

/****************************************************************************
 *	固定小数点{値,ベクトル,行列}⇔浮動小数点{値,ベクトル,行列}
 ****************************************************************************/

typedef struct _vec3f vec3f;
typedef struct _mat3f mat3f;

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

typedef vector vec3x;	/* clipfix.h */
typedef matrix mat3x;	/* clipfix.h */

float xtof(fixed x);	/* %r4,%r5,%r6,%r7の値を破壊しません */
fixed ftox(float f);	/* %r4,%r5,%r6,%r7の値を破壊しません */

void vec3f_conv(vec3f* vec1, const vec3x* vec2);
void vec3x_conv(vec3x* vec1, const vec3f* vec2);

void mat3f_conv(mat3f* mat1, const mat3x* mat2);
void mat3x_conv(mat3x* mat1, const mat3f* mat2);

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

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

/*typedef*/ struct _vec3f {
	float x, y, z;
} /*vec3f*/;

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

extern const vec3f vec3f_0;
extern const vec3f vec3f_1;
extern const vec3f vec3f_x;
extern const vec3f vec3f_y;
extern const vec3f vec3f_z;

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

void vec3f_xform(const mat3f* mat, vec3f* vec);	/* 左から行列を掛けて、右のベクトルを変換します。 */

void vec3f_add(vec3f* vec1, const vec3f* vec2);
void vec3f_sub(vec3f* vec1, const vec3f* vec2);
void vec3f_mul(vec3f* vec1, const vec3f* vec2);
void vec3f_div(vec3f* vec1, const vec3f* vec2);

void vec3f_neg(vec3f* vec);
void vec3f_normal(vec3f* vec);

float vec3f_mag(const vec3f* vec);
float vec3f_mag2(const vec3f* vec);
float vec3f_dot(const vec3f* vec1, const vec3f* vec2);
vec3f vec3f_cross(const vec3f* vec1, const vec3f* vec2);

float vec3f_dist(const vec3f* vec1, const vec3f* vec2);		/* 二点間の距離を求める */
float vec3f_dist2(const vec3f* vec1, const vec3f* vec2);	/* 二点間の距離の二乗を求める */

//void vec3f_reflect(vec3f* vec, const vec3f* normal);
//※2008/07/20: 実装するときは、vreflect()とは光源ベクトルの指定の方向を逆にする予定です。
//  vreflect()は逆向きの光源ベクトルで指定していますが、順向きの方が自然だと思うからです。

/* 点pを通り法線ベクトルnである平面と、点aを通りベクトルvである直線の交点計算 */
vec3f vec3f_intersection_p_l(const vec3f* p, const vec3f* n, const vec3f* a, const vec3f* v);

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

/*typedef*/ struct _mat3f {
	/*     +----------------- 姿勢ベクトルのx成分 */
	/*     |    +------------ 姿勢ベクトルのy成分 */
	/*     |    |    +------- 姿勢ベクトルのz成分 */
	/*     |    |    |    +-- 平行移動成分        */
	float a00, a01, a02, a03;
	float a10, a11, a12, a13;
	float a20, a21, a22, a23;
} /*mat3f*/;

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

extern const mat3f mat3f_0;
extern const mat3f mat3f_1;

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

void mat3f_xform(mat3f* mat1, const mat3f* mat2);	/* 右から行列を掛けて、左の行列を変換します。 */

void mat3f_xlate(mat3f* mat, float x, float y, float z);
void mat3f_scale(mat3f* mat, float x, float y, float z);
void mat3f_rot(mat3f* mat, const vec3f* axis, float ang);
void mat3f_rotx(mat3f* mat, float ang);
void mat3f_roty(mat3f* mat, float ang);
void mat3f_rotz(mat3f* mat, float ang);
//void mat3f_rotxyx(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotxzx(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotyxy(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotyzy(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotzxz(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotzyz(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotxyz(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotxzy(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotyxz(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotyzx(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotzxy(mat3f* mat, float ang1, float ang2, float ang3);
//void mat3f_rotzyx(mat3f* mat, float ang1, float ang2, float ang3);
//float mat3f_rotget(const mat3f* mat, vec3f* axis);

//void mat3f_xpose(mat3f* mat);
void mat3f_invno(mat3f* mat);
void mat3f_inv(mat3f* mat);	/* 逆行列を求めます。正規直交行列でなくても構いません。 */

void mat3f_orient(mat3f* mat, const vec3f* forward, const vec3f* up);
void mat3f_lookat(mat3f* mat, const vec3f* eye, const vec3f* center, float ang);

void mat3f_frustum(mat3f* mat, float width, float height, float front);
void mat3f_perspect(mat3f* mat, float fovy, float aspect, float front);

//void mat3f_viewport(mat3f* mat, int left, int top, int width, int height);
void mat3f_viewportz(mat3f* mat, int left, int top, int width, int height);

//void mat3f_shadow(mat3f* mat, const vec3f* light, const vec3f* ground, const vec3f* normal);

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

typedef struct _vec2f vec2f;
typedef struct _mat2f mat2f;

/*typedef*/ struct _vec2f {
	float x, y;
} /*vec2f*/;

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

extern const vec2f vec2f_0;
extern const vec2f vec2f_1;
extern const vec2f vec2f_x;
extern const vec2f vec2f_y;

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

void vec2f_xform(const mat2f* mat, vec2f* vec);	/* 左から行列を掛けて、右のベクトルを変換します。 */

void vec2f_add(vec2f* vec1, const vec2f* vec2);
void vec2f_sub(vec2f* vec1, const vec2f* vec2);
void vec2f_mul(vec2f* vec1, const vec2f* vec2);
void vec2f_div(vec2f* vec1, const vec2f* vec2);

void vec2f_neg(vec2f* vec);
void vec2f_normal(vec2f* vec);

float vec2f_mag(const vec2f* vec);
float vec2f_mag2(const vec2f* vec);
float vec2f_dot(const vec2f* vec1, const vec2f* vec2);
float vec2f_cross(const vec2f* vec1, const vec2f* vec2);

float vec2f_dist(const vec2f* vec1, const vec2f* vec2);		/* 二点間の距離を求める */
float vec2f_dist2(const vec2f* vec1, const vec2f* vec2);	/* 二点間の距離の二乗を求める */

float vec2f_distance_l_p(const vec2f* a, const vec2f* b, const vec2f* c);				/* 点a,bを通る直線と点cとの距離 */
vec2f vec2f_intersection_l_p(const vec2f* a, const vec2f* b, const vec2f* c);				/* a,bを通る直線と、点cから直線へ下ろした垂線との交点計算 */
vec2f vec2f_intersection_l(const vec2f* a1, const vec2f* a2, const vec2f* b1, const vec2f* b2);		/* a1,a2を通る直線とb1,b2を通る直線の交点計算 */
int vec2f_is_intersected_ls(const vec2f* a1, const vec2f* a2, const vec2f* b1, const vec2f* b2);	/* a1,a2を端点とする線分とb1,b2を端点とする線分の交差判定 */

/* 点pと、v[nv]を頂点とする凸多角形の内外判定 */
int vec2f_is_point_in_convex(const vec2f* p, const vec2f* v/*[nv]*/, int nv);
/* 点pと、v[nv]を頂点とする凹多角形の内外判定 */
int vec2f_is_point_in_concave(const vec2f* p, const vec2f* v/*[nv]*/, int nv);

/* a[na]を頂点とする凹多角形と、b[nb]を頂点とする凹多角形の交差判定 */
int vec2f_is_intersected_p(const vec2f* a/*[na]*/, int na, const vec2f* b/*[nb]*/, int nb);

/* 点pと、交互モードで描かれた複数の閉じた多角形の、内外判定を行ないます。
 * [in]
 *	p		調査する点。
 *	v		各多角形の頂点の座標が入った配列へのポインタ。
 *	nv		各多角形の頂点の数が入った配列へのポインタ。
 *	n		多角形の数。
 * [out]
 *	戻り値		内ならば、0以外の値を返します。
 *			外ならば、0を返します。
 * [note]
 *	* 多角形がドーナツ状に重なっている場合、外側の多角形の辺上の点も、内側の多角形の辺上の点も、"内"と見なします。
 *	  たとえば、二つの多角形が左の図のように重なっている場合、"内"と見なされるピクセルは、右の図のようになります。
 *
 *		■━━━━━━━■		■■■■■■■■■
 *		┃　　　　　　　┃		■■■■■■■■■
 *		┃　■━━━■　┃		■■■■■■■■■
 *		┃　┃　　　┃　┃		■■■　　　■■■
 *		┃　┃　　　┃　┃	⇒	■■■　　　■■■
 *		┃　┃　　　┃　┃		■■■　　　■■■
 *		┃　■━━━■　┃		■■■■■■■■■
 *		┃　　　　　　　┃		■■■■■■■■■
 *		■━━━━━━━■		■■■■■■■■■
 *
 *	* 本関数の引数v,nv,nの仕様は、Win32 APIのPolyPolygon()やCreatePolyPolygonRgn()の、引数仕様と互換です。
 *	- 本関数は、Win32 APIで、以下のような処理を行った場合と同様の結果となります。
 *
 *		hRgn = CreatePolyPolygonRgn(v, nv, n, ALTERNATE);
 *		retval = PtInRegion(hRgn, p->x, p->y);
 */
int vec2f_is_point_in_alternate_concaves(const vec2f* p, const vec2f* v/*[sum(nv[0...n-1])]*/, const int* nv/*[n]*/, int n);

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

/*typedef*/ struct _mat2f {
	/*     +------------ 姿勢ベクトルのx成分 */
	/*     |    +------- 姿勢ベクトルのy成分 */
	/*     |    |    +-- 平行移動成分        */
	float a00, a01, a02;
	float a10, a11, a12;
} /*mat2f*/;

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

extern const mat2f mat2f_0;
extern const mat2f mat2f_1;

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

void mat2f_xform(mat2f* mat1, const mat2f* mat2);	/* 右から行列を掛けて、左の行列を変換します。 */

void mat2f_xlate(mat2f* mat, float x, float y);
void mat2f_scale(mat2f* mat, float x, float y);
void mat2f_rot(mat2f* mat, float ang);

void mat2f_invno(mat2f* mat);
void mat2f_inv(mat2f* mat);	/* 逆行列を求めます。正規直交行列でなくても構いません。 */

/****************************************************************************
 *	連立方程式
 ****************************************************************************/

/* 連立方程式の解を求めます。
 * [in]
 *	A,b		連立方程式。
 * [out]
 *	x		連立方程式の解。
 * [note]
 *	* 本関数の使い方を、例を挙げて説明します。
 *	  以下の例は、「Excelを用いた連立方程式の計算(http://homepage1.nifty.com/gfk/renritu-excel.htm)」を引用させいいただきました。
 *
 *		下記の3元連立1次方程式を考えよう。(変数は x1, x2, x3)
 *
 *			5 x1 + 3 x2 +   x3 = 3
 *			4 x1 + 5 x2 + 2 x3 = 4
 *			  x1 + 3 x2 + 6 x3 = 6
 *
 *			    ┌ 5, 3, 1 ┐
 *			A = │ 4, 5, 2 │
 *			    └ 1, 3, 6 ┘
 *
 *			    ┌ x1 ┐
 *			x = │ x2 │
 *			    └ x3 ┘
 *
 *			    ┌ 3 ┐
 *			b = │ 4 │
 *			    └ 6 ┘
 *
 *		とおき、マトリックス(行列)で表記すると、極めて簡単に
 *
 *			A × x = b … (1)
 *
 *		となる。
 *
 *		連立方程式は(1)のマトリックス式で表記できた。
 *
 *			A × x = b … (1)
 *
 *		両辺に逆マトリックス A-1 をかける。
 *
 *			A-1 × ( A × x ) = A-1 × b
 *			( A-1 × A ) × x = A-1 × b
 *
 *			A-1 × A = E より
 *
 *			E × x = A-1 × b
 *			x = A-1 × b … (2)
 *
 *		これで解 x が計算できる。
 *
 *	- 以上の例を、本関数を使って解くには、以下のように呼び出してください。
 *
 *		float A[9] = { 5, 3, 1,
 *		               4, 5, 2,
 *		               1, 3, 6 };
 *		float b[3] = { 3, 4, 6 };
 *		float x[3];
 *
 *		solve_simultaneous_equations(A, b, x, 3);
 */
void solve_simultaneous_equations(const float* A/*[n][n]*/, const float* b/*[n]*/, float* x/*[n]*/, int n);

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

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif /*__CLIP_FLT_H__*/
