/*
 *	clipflt.h
 *
 *	高速単精度浮動小数点演算ライブラリ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2009 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()を利用するように変更しました。
 */
#ifndef __CLIP_FLT_H__
#define __CLIP_FLT_H__

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

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)と類似の機能の単精度版
 *****************************************************************************/

/* * 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);

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

void dief(const char* fmt, ...) __attribute__((noreturn));

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

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;

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);

/****************************************************************************
 *	浮動小数点ベクトル(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);

/****************************************************************************
 *	浮動小数点行列(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);	/* 逆行列を求めます。正規直交行列でなくても構いません。 */

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

#endif /*__CLIP_FLT_H__*/
