/*
 ******************************************************************************
 *              
 *    ユーティリティー
 *    $Id: utility.c,v 1.1 2003/05/30 21:25:28 tong Exp $ 
 ******************************************************************************
 */
#define  UTILp
#include "utility.h"

#if !PRODUCT
/*
 ******************************************************************************
 *    指定のファイルポイントを取り込む
 *    (ハング情報として表示される)
 ******************************************************************************
 */
typedef struct here_point {
        char   *file;
        int    line;
} HEREPT;
HEREPT herePoint = {0};
void __here(char *file, int line)
{
    herePoint.file = file;
    herePoint.line = line;
}
/*
 ******************************************************************************
 *    領域の侵食チェック処理
 ******************************************************************************
 */
/* 領域チェック処理の初期化 */
void initial_check_area(t_chkar *area, size_t size, t_chkar magic)
{
    fillArea_s(area, size, magic);
}
/* 領域のチェック */
void check_area(t_chkar *area, size_t size, t_chkar magic)
{
    int      i;
    t_chkar  *areaP = area;

    for(i=0; i<(int)(size / sizeof(t_chkar)); i++) {
	if(*areaP != magic) {
#if DEBUG
	    PRINTF(__ERROR
		   "check_area():領域にメモリー侵食があったぜ!!"
		   "(address=%x)\n", areaP);
	    PRINTF("チェック領域 %xh〜%xh\n", area, (char *)area + size);
	    DUMPMEMORY((char *)areaP - 32, 64);
#endif
	    __STOP;
	}
	areaP++;
    }
}
#endif
#if DEBUG
/*
 ******************************************************************************
 *    処理タイム計測のための領域
 *    (マーキングしたポイントからの処理タイムを計測表示する。
 *     MARKING_TIME()     : マーキングポイントの指定
 *     PRINT_NANOTIME(s)  : マーキングポイントからの処理時間をナノで表示)
 *     PRINT_MICROTIME(s) : マーキングポイントからの処理時間をマイクロで表示)
 ******************************************************************************
 */
OSTime  tm;
/*
 ******************************************************************************
 *     アクセスポイントのマーキングを行う
 *     (任意の場所にマーキングを行い, そこを１フレーム中に通過した回数を
 *    表示するためのマーキングを行う処理)
 ******************************************************************************
*/
// アクセスポイントの情報領域
ACCINF  __accessInfo;
// アクセスポイント情報の登録個所へのポインターを返す
static ACPTIF *find_accPoint(ACCINF *accessInfo, char *file, int line)
{
    int  i, n = 0;
    char *f = file;

    while(*f++)
	n++;
    // アクセスポイント情報を検索する
    for(i=0; i<accessInfo->accPointCnt; i++)
	if(accessInfo->accPoint[i].line == line) {
	    if(cmpmem(accessInfo->accPoint[i].file, file, n))
		return &accessInfo->accPoint[i];
	}
    return NULL;
}
// アクセスポイント情報の登録を行う
void marking_accessPoint(char *name, char *file, int line)
{
    ACCINF  *accessInfo = getP_accessInfo();
    ACPTIF  *accPoint = find_accPoint(accessInfo, file, line);

    if(!accPoint)
	// アクセスポイントの登録
	if((accessInfo->accPointCnt + 1) < MAX_ACCESSPOINT) {
	    accPoint = &accessInfo->accPoint[accessInfo->accPointCnt++];
	    accPoint->file = file;
	    accPoint->line = line;
	    accPoint->name = name;
	}
    accPoint->accessCnt++;
}
/*
 ******************************************************************************
 *     マーキングしたアクセスポイントのアクセス情報を表示する
 *     (任意の場所にマーキングを行い, そこを１フレーム中に通過した回数を
 *    表示する。表示後はリセットされる)
 ******************************************************************************
*/
void print_accessInfo(void)
{
    ACCINF  *accessInfo = getP_accessInfo();
    int  i;

    if(!accessInfo->accPointCnt)
	return;
    PRINTF("\n ====== アクセス情報の表示 ======\n");
    for(i=0; i<accessInfo->accPointCnt; i++)
	PRINTF("%s --> %d 回/フレーム\n",
	       accessInfo->accPoint[i].name,
	       accessInfo->accPoint[i].accessCnt);
	       
    clearArea_i(accessInfo, sizeof(ACCINF));
}
/*
 ******************************************************************************
 *
 *     
 *
 ******************************************************************************
*/
/*
 ******************************************************************************
 *     指定ポインターの内容をダンプする。
 ******************************************************************************
 */
void dumpMem(void *mem, size_t size)
{
    size_t  i, j, l = size / 16U;
    char    *p = (char *)mem;

    for(i=0; i<l; i++) {
	PRINTF("%08x : ", p);
	for(j=0; j<16; j++)
	    PRINTF("%02x ",*p++);
	PRINTF("\n");
    }
}
#endif
/*
 ******************************************************************************
 *      id を インクリメント/デクリメント する
 *      (id が先頭に戻るか, リミットになれば TRUE を返す)
 ******************************************************************************
 */
// id のインクリメント(short型対応)
int increment_id_s(short *id, short max, int mode)
{
    if(++(*id) >= max) {
	if(mode == (short)LOOP_ID)
	    *id = 0;
	else
	    *id = (short)(max - 1);
	return TRUE;
    }
    return FALSE;
}
// id のデクリメント(short型対応)
int decrement_id_s(short *id, short max, int mode)
{
    if(--(*id) < 0) {
	if(mode == (short)LOOP_ID)
	    *id =(short)(max - 1);
	else
	    *id = 0;
	return TRUE;
    }
    return FALSE;
}
/*
 ******************************************************************************
 *     昇順の挿入ソート
 *     (unsigned shot 型の n 個のデータを昇順にソートする)
 ******************************************************************************
 */
void insSort_us(unshort *data, int n)
{
    int      i, j;
    unshort  w_data;

    for(i=1; i<n; i++) {
	w_data = data[i];
	for(j = i - 1; (j >= 0) && (data[j] > w_data); j--)
	    data[j + 1] = data[j];
	data[j + 1] = w_data;
    }
}
#if USE_BINSEARCH_US
/*
 ******************************************************************************
 *     二分探索で検索する
 *     (unsigned shot 型の n 個のデータを二分探索で検索する。
 *      見つかればインデックスを返し, 見つからなければ (-1) を返す)
 ******************************************************************************
 */
int binSearch_us(unshort *data, int n, unshort s)
{
    int  left  = 0;
    int  right = n - 1;
    int  mid;

    while(left < right) {
	mid = (right + left) >> 1;
	if(*(data + mid) < s)
	    left = mid + 1;
	else
	    right = mid;
    }
    if(*(data + left) == s)
	return left;
    return -1;
}
#endif
/*
 ******************************************************************************
 *     "無"処理
 ******************************************************************************
 */
int noProc(void) { return FALSE; }
/*
 ******************************************************************************
 *     カウントダウン処理
 *     (与えられた数値でカウントダウンを行い, 0になれば TRUE を返す。)
 ******************************************************************************
 */
int countdown(int *count, int n)
{
    if(!*count) {
	*count = n;
	return FALSE;
    }
    return (--(*count) <= 0);
}
/*
 ******************************************************************************
 *      指定バイト数のメモリー内容の比較を行う
 *      (位置すれば TRUE を返す)
 ******************************************************************************
 */
int cmpmem(void *m1, void *m2, int n)
{
    char *c_m1 = (char *)m1;
    char *c_m2 = (char *)m2;
    
    while(n--)
	if(*c_m1++ != *c_m2++)
	    return FALSE;
    return TRUE;
}
/*
 ******************************************************************************
 *      浮動小数の階乗
 ******************************************************************************
 */
float raisetof(float f, int n)
{
    int  i;
    
#if DEBUG
    if(!n) {
	PRINTF("raiseto() : 0乗はできない!!\n");
	return f;
    }
#endif
    for(i=1; i<n; i++)
	f *= f;
    return f;
}
/*
 ******************************************************************************
 *      浮動小数を固定小数に変換する
 *      (固定小数の小数点以下の有効桁は FIX_VALID_DIGIT で表される。)
 ******************************************************************************
 */
t_fix flt_to_fix(float f)
{
    return (t_fix)(f * FIX_BASE);
}
/*
 ******************************************************************************
 *      固定小数による浮動小数の加算
 ******************************************************************************
 */
float addxf(float f1, float f2)
{
    return  (float)(flt_to_fix(f1) + flt_to_fix(f2)) / FIX_BASE;
}
/*
 ******************************************************************************
 *      乱数の生成
 ******************************************************************************
 */
static unsigned long int iseed = 1;
/* 整数乱数の生成の初期化 */
void initial_random_i(unsigned long int v)
{
    iseed = v;
}
/* 整数乱数の生成処理(0 - 32767) */
int random_i(void)
{
    iseed = iseed * 1103515245 + 12345;
    return ((int)(iseed >> 16) & 0x7fff);
//    return (int)(iseed / 0x10000) % 0x8000;
}

static unsigned long fseed = 1;
/* 小数乱数の生成の初期化 */
void initial_random_d(unsigned long v)
{
    fseed = v;
}
/* 小数乱数の生成処理 */
double random_d(void)
{
    fseed = fseed * 1566083941UL + 1;
    return (double)((double)1.0F
		    / ((double)ULONG_MAX + (double)1.0F)) * (double)fseed;
}
/*
 ******************************************************************************
 *      ２つの浮動小数点のコピー
 ******************************************************************************
 */
void cpy2_f(float *d, float *s)
{
    *d++ = *s++;
    *d   = *s;
}
/*
 ******************************************************************************
 *      ３つの浮動小数点のコピー
 ******************************************************************************
 */
void cpy3_f(float *d, float *s)
{
    *d++ = *s++;
    *d++ = *s++;
    *d   = *s;
}
#if !PRODUCT
/*
 ******************************************************************************
 *      コピーメモリーのポインターチェックを行う
 *      (エラーの場合は FALSE を返す)
 ******************************************************************************
 */
#define chk_cpymem_i(d,s,sz)                  chk_cpymem(d,s,sz,sizeof(int))
#define chk_cpymem_s(d,s,sz)                  chk_cpymem(d,s,sz,sizeof(short))
#define chk_cpymem_c(d,s,sz)                  chk_cpymem(d,s,sz,sizeof(char))
static int chk_cpymem(void *d_mem, void *s_mem, size_t size, size_t typeSize) 
{
    if(!d_mem) {
#if DEBUG
	PRINTF(__ERROR
	       "コピー先のメモリーが NULL である!!\n");
#endif
	return FALSE;
    }
    if(!s_mem) {
#if DEBUG
	PRINTF(__ERROR
	       "コピー元のメモリーが NULL である!!\n");
#endif
	return FALSE;
    }
    if((size < typeSize) 
        || ((size / typeSize * typeSize) != size)) {
#if DEBUG
	PRINTF(__ERROR
	       "コピーサイズがおかしい!!(%s:%d)\n");
	PRINTF("size = %d (%xh)\n", size, size);
#endif
        return FALSE;
    }
    if(!is_codesegment(s_mem)) {
#if DEBUG
	PRINTF(__ERROR
	       "コピー元がコードセグメントでない!!(%x)\n", s_mem);
#endif
	return FALSE;
    }
    return TRUE;
}
#endif
#if UNUSE
/*
 ******************************************************************************
 *      (int)型の領域のコピーを行う
 ******************************************************************************
 */
#if DEBUG
void dbg_cpymem_i(void *d_mem, void *s_mem, size_t size, char *file, int line)
#else
void cpymem_i(void *d_mem, void *s_mem, size_t size)
#endif
{
    size_t i;
    unint  *dmem = (unint *)d_mem;
    unint  *smem = (unint *)s_mem;

#if !PRODUCT
    if(!chk_cpymem_i(d_mem, s_mem, size)) {
#if DEBUG
	PRINTF(__ERROR
	       "cpymem_i():パラメータがおかしい!!(%s:%d)\n", file, line);
	__HERE(file, line);
#endif
	__STOP;
    }
#endif
    size /= sizeof(int);
    for(i=0; i<size; i++)
	*dmem++ = *smem++;
}
#endif
/*
 ******************************************************************************
 *      (short)型の領域のコピーを行う
 ******************************************************************************
 */
#if DEBUG
void dbg_cpymem_s(void *d_mem, void *s_mem, size_t size, char *file, int line)
#else
void cpymem_s(void *d_mem, void *s_mem, size_t size)
#endif
{
    size_t  i;
    unshort *dmem = (unshort *)d_mem;
    unshort *smem = (unshort *)s_mem;

    if(!chk_cpymem_s(d_mem, s_mem, size)) {
#if DEBUG
	PRINTF(__ERROR
	       "cpymem_s():パラメータがおかしい!!(%s:%d)\n", file, line);
	__HERE(file, line);
#endif
	__STOP;
    }
    size /= sizeof(unshort);
    for(i=0; i<size; i++)
	*dmem++ = *smem++;
}
/*
 ******************************************************************************
 *      (char)型の領域のコピーを行う
 ******************************************************************************
 */
#if DEBUG
void dbg_cpymem_c(void *d_mem, void *s_mem, size_t size, char *file, int line)
#else
void cpymem_c(void *d_mem, void *s_mem, size_t size)
#endif
{
    size_t i;
    unchar *dmem = (unchar *)d_mem;
    unchar *smem = (unchar *)s_mem;

#if !PRODUCT
    if(!chk_cpymem_c(d_mem, s_mem, size)) {
#if DEBUG
	PRINTF(__ERROR
	       "cpymem_s():パラメータがおかしい!!\n");
	__HERE(file, line);
#endif
	__STOP;
    }
#endif
    for(i=0; i<size; i++)
	*dmem++ = *smem++;
}
#if !PRODUCT
/*
 ******************************************************************************
 *      フィルメモリーのポインターチェックを行う
 *      (エラーの場合は FALSE を返す)
 ******************************************************************************
 */
#define chk_fillArea_i(a,s)              chk_fillArea(a,s,sizeof(int))
#define chk_fillArea_s(a,s)              chk_fillArea(a,s,sizeof(short))
#define chk_fillArea_c(a,s)              chk_fillArea(a,s,sizeof(char))
static int chk_fillArea(void *area, size_t size, size_t typeSize)
{
    if(size < typeSize) {
#if DEBUG
	PRINTF(__ERROR
	       "chk_fillArea():サイズが小さすぎる。サイズが間違ってるよ？\n"); 
	PRINTF("size = %d (%xh)\n", size, size);
#endif
        return FALSE;
    }
    if((size / typeSize * typeSize) != size) {
#if DEBUG
	PRINTF(__ERROR
	       "chk_fillArea():指定領域を埋めるサイズがおかしい!!\n");
	PRINTF("size = %d (%xh)\n", size, size);
#endif
        return FALSE;
    }
    if(!area) {
#if DEBUG
	PRINTF(__ERROR
	       "chk_fillArea():指定領域が NULL である!!\n");
#endif
	return FALSE;
    }
    if(!is_codesegment(area)) {
#if DEBUG
	PRINTF(__ERROR
	       "chk_fillArea():指定領域がコードセグメントでない!!\n");
#endif
	return FALSE;
    }
    return TRUE;
}
#endif
#if UNUSE
/*
 ******************************************************************************
 *      指定領域を(int)型の指定コードで埋める
 ******************************************************************************
 */
void fillArea_i(void *area, size_t size, int d)
{
    size_t  i;
    unint   *d_area = (unint *)area;

#if !PRODUCT
    if(!chk_fillArea_i(area, size)) {
#if DEBUG
	PRINTF(__ERROR
	       "fillArea_i():パラメータがおかしい!!\n");
	__HERE(file, line);
#endif
	__STOP;
	return;
    }
#endif
    size /= sizeof(int);
    for(i=0; i<size; i++)
	*d_area++ = (unint)d;
}
#endif
/*
 ******************************************************************************
 *      指定領域を(short)型の指定コードで埋める
 ******************************************************************************
 */
#if !DEBUG
void fillArea_s(void *area, size_t size, short d)
#else
void dbg_fillArea_s(void *area, size_t size, short d, char *file, int line)
#endif
{
    size_t  i;
    unshort *d_area = (unshort *)area;

#if !PRODUCT
    if(!chk_fillArea_s(area, size)) {
#if DEBUG
	PRINTF(__ERROR
	       "fillArea_s():パラメータがおかしい!!\n");
	__HERE(file, line);
#endif
	__STOP;
	return;
    }
#endif
    size /= sizeof(unshort);
    for(i=0; i<size; i++)
	*d_area++ = (unshort)d;
}
/*
 ******************************************************************************
 *      指定領域を(char)型の指定コードで埋める
 ******************************************************************************
 */
#if !DEBUG
void fillArea_c(void *area, size_t size, char d)
#else
void dbg_fillArea_c(void *area, size_t size, char d, char *file, int line)
#endif
{
    size_t  i;
    unchar  *d_area = (unchar *)area;

#if !PRODUCT
    if(!chk_fillArea_c(area, size)) {
#if DEBUG
	PRINTF(__ERROR
	       "fillArea_c():パラメータがおかしい!!\n");
	__HERE(file, line);
#endif
	__STOP;
	return;
    }
#endif
    for(i=0; i<size; i++)
	*d_area++ = d;
}
/*
 ******************************************************************************
 *    四捨五入
 *    例) 0.1F --> 0 , 0.5F --> 1 , -0.1F --> 0 , -0.5F --> -1
 ******************************************************************************
*/
int roundf(float f)
{
    if(f > 0.0F)
	return (int)(f + 0.5F);
    if(f < 0.0F)
	return (int)(f - 0.5F);
    return 0;
}
/*
 ******************************************************************************
 *    切り上げ
 *    例) 0.1F --> 1, 0.5F --> 1, -0.1F --> -1,  -0.5F --> -1
 ******************************************************************************
*/
int riasef(float f)
{
    if(f > 0.0F)
	return (int)(f + 0.999999F);
    if(f < 0.0F)
	return (int)(f - 0.999999F);
    return 0;
}
/*
 ******************************************************************************
 *    絶対値を求める
 ******************************************************************************
*/
int abs(int v)
{
    return v < 0 ? -v : v;
}
float absf(float v)
{
    return v < 0.0F ? -v : v;
}
/*
 ******************************************************************************
 *    楕円の計算
 ******************************************************************************
*/
void ellipse(float *x, float *y,
	     float ox, float oy, float rh, float rv, float deg)
{
#if 0
    float  theta = radian(deg); 

    *x = rh * cosf(theta) + ox;
    *y = rv * sinf(theta) + oy;
#endif
    float  theta = deg; 

    *x = rh * cosf_table(theta) + ox;
    *y = rv * sinf_table(theta) + oy;
}
/*
 ******************************************************************************
 *	角度調整(-180.0F < angl <= 180.0F)
 ******************************************************************************
 */
float	anglAdjustIn180(float angl)
{
    while (angl < 180.0F)	angl += 360.0F;
    while (angl >= 180.0F)	angl -= 360.0F;
    return angl;
}
/*
 ******************************************************************************
 *    円の計算
 ******************************************************************************
*/
void circle(float *x, float *y, float ox, float oy, float r, float deg)
{
#if 0
    float  theta = radian(deg); 

    *x = r * cosf(theta) + ox;
    *y = r * sinf(theta) + oy;
#endif
    float  theta = deg; 

    *x = r * cosf_table(theta) + ox;
    *y = r * sinf_table(theta) + oy;
}
/*
 ******************************************************************************
 *    重力落下計算(左上が原点の場合)
 ******************************************************************************
*/
float calc_speedG(float speedf, float accel, float maxSpeedf)
{
    return((speedf + accel) < maxSpeedf ? speedf + accel : maxSpeedf);
}
#if 0
/*
 ******************************************************************************
 *   円による重なり範囲チェック
 ******************************************************************************
*/
int check_CircleArea(float x1, float y1, float r1,
		     float x2, float y2, float r2)
{
    return(chkRangeOfTwoPointf(x1,y1, x2,y2, r1+r2));
}
#endif
/*
 ******************************************************************************
 *
 *   矩形による重なり範囲チェック
 *
 ******************************************************************************
*/
/*
 ******************************************************************************
 *   ２次元での指定点が矩形内に含まれるかチェックする
 ******************************************************************************
 */
int chk_pointInRectangArea2D(int x1, int y1,  int x2, int y2,  int h, int w)
{
    return ((w - abs(x1 - x2)) >= 0) && ((h - abs(y1 - y2)) >= 0);
}
/*
 ******************************************************************************
 *   ２次元での指定点が矩形内に含まれるかチェックする(深さを返す)
 ******************************************************************************
 */
int chk_pointInRectangArea2D_d(int x1, int y1, int x2, int y2, int h, int w,
			       int *dx, int *dy)
{
    *dx = w - abs(x1 - x2);
    *dy = h - abs(y1 - y2);
    return (*dx >= 0) && (*dy >= 0);
}
/*
 ******************************************************************************
 *   ２次元での重なりチェック(深さを返さない)
 ******************************************************************************
 */
int chk_rectangArea2D(int  x1, int  y1, unsigned  h1, unsigned  w1,
		      int  x2, int  y2, unsigned  h2, unsigned  w2)
{
    return((((int)(w1 + w2) - abs(x1 - x2)) >= 0)
	   && (((int)(h1 + h2) - abs(y1 - y2)) >= 0));
}
/*
 ******************************************************************************
 *   ２次元での重なりチェック(深さを返す)
 ******************************************************************************
 */
int chk_rectangArea2D_d(int  x1, int  y1, unsigned  h1, unsigned  w1,
			int  x2, int  y2, unsigned  h2, unsigned  w2,
			int *dx, int *dy)
{
    *dx = (int)(w1 + w2) - abs(x1 - x2);
    *dy = (int)(h1 + h2) - abs(y1 - y2);
    return((*dx >= 0) && (*dy >= 0));
}
/*
 ******************************************************************************
 *   ３次元での重なりチェック
 ******************************************************************************
 */
int chk_rectangArea3D(float x1, float y1, float z1,
		      float h1, float w1, float d1,
		      float x2, float y2, float z2,
		      float h2, float w2, float d2,
		      float *dx, float *dy, float *dz)
{
    *dx = (w1 + w2) - absf(x1 - x2);
    *dy = (h1 + h2) - absf(y1 - y2);
    *dz = (d1 + d2) - absf(z1 - z2);
    return((int)((*dx >= 0.0F) && (*dy >= 0.0F) && (*dz >= 0.0F)));
}
/*
 ******************************************************************************
 *   重なり場所を知らせる
 ******************************************************************************
*/
/*
     ２次元での重なり場所
 */
unsigned char get_crossSide2D(int x_t, int y_t, int x_s, int y_s)
{
    unsigned char side = NOT_CROSS_SIDE;

    if(x_s < x_t)
	side |= CROSS_RIGHT;
    if(x_s > x_t)
	side |= CROSS_LEFT;
    if(y_s < y_t)
	side |= CROSS_DOWN;
    if(y_s > y_t)
	side |= CROSS_UP;
    if(x_s == x_t && y_s == y_t)	
	side = CROSS_RIGHT | CROSS_LEFT | CROSS_UP | CROSS_DOWN;
    return side;
}
/*
     ３次元での重なり場所
 */
unsigned char get_crossSide3D(float x_t, float y_t, float z_t,
			      float x_s, float y_s, float z_s)
{
    unsigned char side = NOT_CROSS_SIDE;

    if(x_s < x_t)
	side |= CROSS_RIGHT;
    if(x_s > x_t)
	side |= CROSS_LEFT;
    if(y_s < y_t)
	side |= CROSS_DOWN;
    if(y_s > y_t)
	side |= CROSS_UP;
    if(z_s < z_t)
	side |= CROSS_FORWARD;
    if(z_s > z_t)
	side |= CROSS_BACK;

    if((x_s == x_t) && (y_s == y_t) && (z_s == z_t))	
	side = CROSS_RIGHT | CROSS_LEFT
	       | CROSS_UP | CROSS_DOWN
	       | CROSS_FORWARD | CROSS_BACK;
    return side;
}

/*
 ******************************************************************************
 *
 *      マトリックス処理
 *
 ******************************************************************************
 */
/*
 ******************************************************************************
 *      回転, 位置の行列を求める
 ******************************************************************************
 */
void setmatrix_r_t(MATRIX *matrix, float xAngle,  float yAngle,  float zAngle,
		                   float xOffset, float yOffset, float zOffset)
{
    setmatrix_r(matrix, xAngle, yAngle, zAngle);
    setmatrix_t(matrix, xOffset, yOffset, zOffset);
}
/*
 ******************************************************************************
 *      反転, 位置, スケールの行列を求める
 ******************************************************************************
 */
void setmatrix_t_s(MATRIX *matrix, float wx,     float wy,     float wz,
		                   unsigned h,   unsigned v,
		                   float xScale, float yScale)
{
    setmatrix_t(matrix, wx, wy, wz);
    setmatrix_2f(matrix, h, v);
    setmatrix_2s(matrix, xScale, yScale);
}
/*
 ******************************************************************************
 *      回転, 位置, 反転, スケールの行列を求める
 ******************************************************************************
 */
void setmatrix_r_s_t(MATRIX *matrix,
		            float wx,     float wy,     float wz,
		            unsigned h,   unsigned v,
		            float xAngle, float yAngle, float zAngle, 
		            float xScale, float yScale)
{
    setmatrix_t(matrix, wx, wy, wz);
    setmatrix_2f(matrix, h, v);
    setmatrix_r(matrix, xAngle, yAngle, zAngle);
    setmatrix_2s(matrix, xScale, yScale);
}
/*
 ******************************************************************************
 *      回転, 位置, 反転, スケール, ローカル位置の行列を求める
 ******************************************************************************
 */
void setmatrix(MATRIX *matrix, float wx,     float wy,     float wz,
	                       float lx,     float ly,     float lz,
	                       unsigned h,   unsigned v,
	                       float xAngle, float yAngle, float zAngle, 
	                       float xScale, float yScale)
{
    setmatrix_t(matrix, wx, wy, wz);
    setmatrix_2f(matrix, h, v);
    setmatrix_r(matrix, xAngle, yAngle, zAngle);
    setmatrix_2s(matrix, xScale, yScale);
    Localposition(matrix, lx, ly, lz);
}
/*
 ******************************************************************************
 *	マトリックス操作関数
 *      (index1 = XX, index2 = YYならz軸回転の行列乗算
 *       index1 = YY, index2 = ZZならx軸回転の行列乗算
 *       index1 = ZZ, index2 = XXならy軸回転の行列乗算)
 ******************************************************************************
 */
void setmatrixf_r_tbl(MATRIXF *matrixf, float angle, int index1, int index2)
{
    if (angle != 0.0F) {
	int   i;
	float *m1 = (matrixf->mf)[index1];
	float *m2 = (matrixf->mf)[index2];
	float sina = sinf_table(angle);
	float cosa = cosf_table(angle);

	for (i = 0; i < 4; ++i) {
	    float m1x = *m1;
	    float m2x = *m2;

	    *m1++ = m1x * cosa + m2x * sina;	// i行1列要素
	    *m2++ = m2x * cosa - m1x * sina;	// i行2列要素
	}
    }
}

/* 単位行列４×４行列の左上３×３を代入。 */
static void loadIdentity4x4_3x3(float m[4][4])
{
    m[0][0] = 1.0F;
    m[1][0] = 0.0F;
    m[2][0] = 0.0F;
    m[0][1] = 0.0F;
    m[1][1] = 1.0F;
    m[2][1] = 0.0F;
    m[0][2] = 0.0F;
    m[1][2] = 0.0F;
    m[2][2] = 1.0F;
}
/* 移動行列４×４行列の第１行４列,第２行４列,第２行４列を代入。 */
static void loadMtxElementf4x4_L4_C1C2C3(float m[4][4],
					 float xOffset,
					 float yOffset,
					 float zOffset)
{
    m[3][0] = xOffset;
    m[3][1] = yOffset;
    m[3][2] = zOffset;
}

/* 単位行列４×４行列の第４行を代入。 */
static void loadMtxElementf4x4_C4(float m[4][4])
{
    m[0][3] = 0.0F;
    m[1][3] = 0.0F;
    m[2][3] = 0.0F;
    m[3][3] = 1.0F;
}

/* 移動行列の代入。 */
void loadmatrixf(MATRIXF *matrixf, float xOffset, float yOffset, float zOffset)
{
    float (*m)[4] = (matrixf->mf);

    loadIdentity4x4_3x3(m);
    loadMtxElementf4x4_L4_C1C2C3(m, xOffset, yOffset, zOffset);
    loadMtxElementf4x4_C4(m);
}
/*
 ******************************************************************************
 *
 *      曲線関数
 *
 ******************************************************************************
 */
/*
 ******************************************************************************
 *	Ｂスプライン関数（２次）
 ******************************************************************************
 */
/*----------------------------------------------------------------------*/
/*	Bsplineの領域の初期化						*/
/*	b  : Bspline構造体のポインタ					*/
/*	pn : 間の点の数（始点も含む。終点は含まない。）			*/
/*	(Bspline *)Malloc( sizeof( Bspline ) * pn )			*/
/*----------------------------------------------------------------------*/
void Initial_Bspline( Bspline *b, int pn )
{
    register int	i;
    float		a, t, tt;

    tt = 1.0f / ( float )pn;
    t = 0.0f;
    for ( i = 0; i < pn; i ++ ) {
	a = 1.0f - t;
	BSPLINE_B1(b) = ( a * a ) * 0.5f;
	BSPLINE_B2(b) = a * t + 0.5f;
	BSPLINE_B3(b) = ( t * t ) * 0.5f;
	b ++;
	t += tt;
    }
}

/*----------------------------------------------------------------------*/
/*	曲線座標の算出							*/
/*	b   : n 番目の B 値						*/
/*	p0  : 座標０							*/
/*	p1  : 座標１							*/
/*	p2  : 座標２							*/
/*	ans : 解答							*/
/*----------------------------------------------------------------------*/
void BsplineCalc( Bspline *b, short *p0, short *p1, short *p2,
			 short *ans )
{
    register int	i;
    float		a;

    for ( i = 0; i < XYZ; i ++ ) {
	a = ( float )( *p0 ) * BSPLINE_B1(b)
	    + ( float )( *p1 ) * BSPLINE_B2(b)
	    + ( float )( *p2 ) * BSPLINE_B3(b);
	if ( a < 0.0f ) {
	    ( *ans ) = ( short )( a - 0.5f );
	} else {
	    ( *ans ) = ( short )( a + 0.5f );
	}
	p0 ++;
	p1 ++;
	p2 ++;
	ans ++;
    }
}

/*
 *  Bspline の 係数を求める
 */
void get_bspline3_index(float T,float *B)
{
    float T3;
    float T2;
    float R2;
    float R3;
    float R6;
    
    if(T>1.0f) T=1.0f;
    if(T<0.0f) T=0.0f;
    R2 = 0.5F;
    R3 = 1.0F / 3.0F;
    R6 = R2 * R3;
    
    T3 = T*T*T;
    T2 = T*T;
    
    B[0]= (1.0f-T)*(1.0f-T)*(1.0f-T) * R6;
    B[1]=  T3 * R2 - T2 + 2.0f * R3;
    B[2]= (-T3 + T2 + T) * R2 + R6;
    B[3]=  T3 * R6;

#if 0
     if(T>1.0f) T=1.0f;
    if(T<0.0f) T=0.0f;

    B[0]= (1.0f-T)*(1.0f-T)*(1.0f-T)/6.0f;
    B[1]=  T*T*T / 2.0f - T*T + 2.0f / 3.0f;
    B[2]= -T*T*T / 2.0f + T*T / 2.0f + T / 2.0f + 1.0f / 6.0f;
    B[3]=  T*T*T / 6.0f;
#endif
}

/*
 ******************************************************************************
 *  	Bsplineで角度を求める。
 * 		(-180.0F度から179.0F度の値を入力,
 *		 Bsplineで補間してfloat型の値を入れる。)
 ******************************************************************************
 */
static void check_Bspline_angleOnly(float *before_data, float *after_data)
{
    if(absf(*before_data - *after_data) > 180.0F) {
	if(*before_data > 0.0F) {
	    *after_data = *after_data + (2.0F * 180.0F);
	}
	else {
	    *after_data = *after_data - (2.0F * 180.0F);
	}
    }
}

void get_Bspline_angleOnly(float *B,
			   float *out_angle_p,
			   float angle0,
			   float angle1,
			   float angle2,
			   float angle3)
{
    check_Bspline_angleOnly(&angle0, &angle1);
    check_Bspline_angleOnly(&angle1, &angle2);
    check_Bspline_angleOnly(&angle2, &angle3);

    *out_angle_p = B[0]*angle0+B[1]*angle1+B[2]*angle2+B[3]*angle3;
}

/*----------------------------------------------------------------------*/
/*	Bspline（３次）							*/
/*----------------------------------------------------------------------*/
void get_Bspline_point( float *B,	/* 係数 */
			float *spos0,	/* １点目 */
			float *spos1,	/* ２点目 */
			float *spos2,	/* ３点目 */
			float *spos3,	/* ４点目 */
			float *dpos )	/* 結果 */
{
    register int	i;

    for ( i = 0; i < XY; i ++ ) {
	( *dpos ) = ( *spos0 ) * B[ 0 ] + ( *spos1 ) * B[ 1 ]
	    + ( *spos2 ) * B[ 2 ] + ( *spos3 ) * B[ 3 ];
	spos0 ++;
	spos1 ++;
	spos2 ++;
	spos3 ++;
	dpos ++;
    }
}

void get_Bspline_point3D( float *B,	/* 係数 */
			float *spos0,	/* １点目 */
			float *spos1,	/* ２点目 */
			float *spos2,	/* ３点目 */
			float *spos3,	/* ４点目 */
			float *dpos)	/* 結果 */

{
    register int	i;

    for ( i = 0; i < XYZ; i ++ ) {
	( *dpos ) = ( *spos0 ) * B[ 0 ] + ( *spos1 ) * B[ 1 ]
	    + ( *spos2 ) * B[ 2 ] + ( *spos3 ) * B[ 3 ];
	spos0 ++;
	spos1 ++;
	spos2 ++;
	spos3 ++;
	dpos ++;
    }
}


/************************************************************************/
/*	ベジェ曲線関数							*/
/************************************************************************/
/*----------------------------------------------------------------------*/
/*	ベジェ曲線の領域の初期化					*/
/*	b  : ベジェ曲線構造体のポインタ					*/
/*	n : 間の点の数（始点も含む。終点は含まない。）			*/
/*	(Bezye *)Malloc( sizeof( Bezye ) * n )			*/
/*----------------------------------------------------------------------*/
void Initial_BezyeKyokusen( Bezye *b, int n )
{
    register int	i;
    float		a, t, tt;

    tt = 1.0f / ( float )n;
    t = 0.0f;
    for ( i = 0; i < n; i ++ ) {
	a = 1.0f - t;
	BEZYE_B1(b) = a * a * a;
	BEZYE_B2(b) = 3.0f * t * ( a * a );
	BEZYE_B3(b) = 3.0f * ( t * t ) * a;
	BEZYE_B4(b) = t * t * t;
	t += tt;
	b ++;
    }
}

/*----------------------------------------------------------------------*/
/*	曲線座標の算出							*/
/*	b   : n 番目の B 値						*/
/*	p0  : 座標０							*/
/*	p1  : 座標１							*/
/*	p2  : 座標２							*/
/*	p3  : 座標３							*/
/*	ans : 解答							*/
/*----------------------------------------------------------------------*/
void Bezye_Calc( Bezye *b, short *p0, short *p1, short *p2,
		 short *p3, short *ans )
{
    register int	i;
    float		a;

    for ( i = 0; i < XYZ; i ++ ) {
	a = ( float )( *p0 ) * BEZYE_B1(b)
	    + ( float )( *p1 ) * BEZYE_B2(b)
	    + ( float )( *p2 ) * BEZYE_B3(b)
	    + ( float )( *p3 ) * BEZYE_B4(b);
	if ( a < 0.0f ) {
	    ( *ans ) = ( short )( a - 0.5f );
	} else {
	    ( *ans ) = ( short )( a + 0.5f );
	}
	p0 ++;
	p1 ++;
	p2 ++;
	p3 ++;
	ans ++;
    }
}
/*
 ******************************************************************************
 *
 *      三角関数
 *
 ******************************************************************************
 */
/*
 ******************************************************************************
 *   テーブルを使った三角関数 
 ******************************************************************************
*/
#define to_short_angle(a) ((unshort)(int)((a) * (32767.0F / 180.0F)))
#define from_short_sin(s) ((float)(s) *  (1.0F / 32767.0F))

float sinf_table(float angle)
{
    unshort sang;
    short ss;
    float r;

#if DEBUG
    if(angle > (360.0F * 10.0F) ||
       angle < (-360.0F * 10.0F)){
	PRINTF(__ERROR"sinf_table() angleの値が適切でありません angle = %f\n",
	       angle);
    }
#endif
    /* 上限調整 */
    while(angle <= 0.0F) angle += 360.0F;
    while(angle > 360.0F) angle -= 360.0F;
#if DEBUG
    {
	unint iang = (unint)(int)((angle) * (32767.0F / 180.0F));
	if(iang > USHRT_MAX)
	    PRINTF(__ERROR"utility.c: sinf_table() オーバーフロー \n");
    }
#endif
    /* short型 データに変換 */
    sang = to_short_angle(angle);
    ss = sins(sang);
    r = from_short_sin(ss);
    return (r);
}

float cosf_table(float angle)
{
    unshort cang;
    short cs;
    float r;
    
#if DEBUG
    if(angle > (360.0F * 10.0F) ||
       angle < (-360.0F * 10.0F)){
	PRINTF(__ERROR"cosf_table() angleの値が適切でありません angle = %f\n",
	       angle);
    }
#endif
    /* 上限調整 */
    while(angle <= 0.0F) angle += 360.0F;
    while(angle > 360.0F) angle -= 360.0F;
#if DEBUG
    {
	unint iang = (unint)(int)((angle) * (32767.0F / 180.0F));
	if(iang > USHRT_MAX)
	    PRINTF(__ERROR"utility.c: sinf_table() オーバーフロー \n");
    }
#endif
    /* short型 データに変換 */
    cang = to_short_angle(angle);
    cs = coss(cang);
    r = from_short_sin(cs);
    return (r);
}
/*
 ******************************************************************************
 *   テーブルを使った三角関数 
 ******************************************************************************
*/
static unshort atntable[] =
{
    0x0000, 0x000a, 0x0014, 0x001f, 0x0029, 0x0033, 0x003d, 0x0047,
    0x0051, 0x005c, 0x0066, 0x0070, 0x007a, 0x0084, 0x008f, 0x0099,
    0x00a3, 0x00ad, 0x00b7, 0x00c2, 0x00cc, 0x00d6, 0x00e0, 0x00ea,
    0x00f4, 0x00ff, 0x0109, 0x0113, 0x011d, 0x0127, 0x0131, 0x013c,
    0x0146, 0x0150, 0x015a, 0x0164, 0x016f, 0x0179, 0x0183, 0x018d,
    0x0197, 0x01a1, 0x01ac, 0x01b6, 0x01c0, 0x01ca, 0x01d4, 0x01de,
    0x01e9, 0x01f3, 0x01fd, 0x0207, 0x0211, 0x021b, 0x0226, 0x0230,
    0x023a, 0x0244, 0x024e, 0x0258, 0x0262, 0x026d, 0x0277, 0x0281,
    0x028b, 0x0295, 0x029f, 0x02a9, 0x02b4, 0x02be, 0x02c8, 0x02d2,
    0x02dc, 0x02e6, 0x02f0, 0x02fb, 0x0305, 0x030f, 0x0319, 0x0323,
    0x032d, 0x0337, 0x0341, 0x034c, 0x0356, 0x0360, 0x036a, 0x0374,
    0x037e, 0x0388, 0x0392, 0x039c, 0x03a7, 0x03b1, 0x03bb, 0x03c5,
    0x03cf, 0x03d9, 0x03e3, 0x03ed, 0x03f7, 0x0401, 0x040c, 0x0416,
    0x0420, 0x042a, 0x0434, 0x043e, 0x0448, 0x0452, 0x045c, 0x0466,
    0x0470, 0x047a, 0x0484, 0x048e, 0x0499, 0x04a3, 0x04ad, 0x04b7,
    0x04c1, 0x04cb, 0x04d5, 0x04df, 0x04e9, 0x04f3, 0x04fd, 0x0507,
    0x0511, 0x051b, 0x0525, 0x052f, 0x0539, 0x0543, 0x054d, 0x0557,
    0x0561, 0x056b, 0x0575, 0x057f, 0x0589, 0x0593, 0x059d, 0x05a7,
    0x05b1, 0x05bb, 0x05c5, 0x05cf, 0x05d9, 0x05e3, 0x05ed, 0x05f7,
    0x0601, 0x060b, 0x0615, 0x061f, 0x0629, 0x0633, 0x063d, 0x0647,
    0x0651, 0x065b, 0x0665, 0x066e, 0x0678, 0x0682, 0x068c, 0x0696,
    0x06a0, 0x06aa, 0x06b4, 0x06be, 0x06c8, 0x06d2, 0x06dc, 0x06e5,
    0x06ef, 0x06f9, 0x0703, 0x070d, 0x0717, 0x0721, 0x072b, 0x0735,
    0x073e, 0x0748, 0x0752, 0x075c, 0x0766, 0x0770, 0x077a, 0x0783,
    0x078d, 0x0797, 0x07a1, 0x07ab, 0x07b5, 0x07be, 0x07c8, 0x07d2,
    0x07dc, 0x07e6, 0x07ef, 0x07f9, 0x0803, 0x080d, 0x0817, 0x0820,
    0x082a, 0x0834, 0x083e, 0x0848, 0x0851, 0x085b, 0x0865, 0x086f,
    0x0878, 0x0882, 0x088c, 0x0896, 0x089f, 0x08a9, 0x08b3, 0x08bd,
    0x08c6, 0x08d0, 0x08da, 0x08e3, 0x08ed, 0x08f7, 0x0901, 0x090a,
    0x0914, 0x091e, 0x0927, 0x0931, 0x093b, 0x0944, 0x094e, 0x0958,
    0x0961, 0x096b, 0x0975, 0x097e, 0x0988, 0x0992, 0x099b, 0x09a5,
    0x09ae, 0x09b8, 0x09c2, 0x09cb, 0x09d5, 0x09de, 0x09e8, 0x09f2,
    0x09fb, 0x0a05, 0x0a0e, 0x0a18, 0x0a22, 0x0a2b, 0x0a35, 0x0a3e,
    0x0a48, 0x0a51, 0x0a5b, 0x0a64, 0x0a6e, 0x0a77, 0x0a81, 0x0a8b,
    0x0a94, 0x0a9e, 0x0aa7, 0x0ab1, 0x0aba, 0x0ac4, 0x0acd, 0x0ad7,
    0x0ae0, 0x0ae9, 0x0af3, 0x0afc, 0x0b06, 0x0b0f, 0x0b19, 0x0b22,
    0x0b2c, 0x0b35, 0x0b3f, 0x0b48, 0x0b51, 0x0b5b, 0x0b64, 0x0b6e,
    0x0b77, 0x0b80, 0x0b8a, 0x0b93, 0x0b9d, 0x0ba6, 0x0baf, 0x0bb9,
    0x0bc2, 0x0bcb, 0x0bd5, 0x0bde, 0x0be7, 0x0bf1, 0x0bfa, 0x0c03,
    0x0c0d, 0x0c16, 0x0c1f, 0x0c29, 0x0c32, 0x0c3b, 0x0c45, 0x0c4e,
    0x0c57, 0x0c60, 0x0c6a, 0x0c73, 0x0c7c, 0x0c86, 0x0c8f, 0x0c98,
    0x0ca1, 0x0cab, 0x0cb4, 0x0cbd, 0x0cc6, 0x0ccf, 0x0cd9, 0x0ce2,
    0x0ceb, 0x0cf4, 0x0cfd, 0x0d07, 0x0d10, 0x0d19, 0x0d22, 0x0d2b,
    0x0d34, 0x0d3e, 0x0d47, 0x0d50, 0x0d59, 0x0d62, 0x0d6b, 0x0d74,
    0x0d7d, 0x0d87, 0x0d90, 0x0d99, 0x0da2, 0x0dab, 0x0db4, 0x0dbd,
    0x0dc6, 0x0dcf, 0x0dd8, 0x0de1, 0x0dea, 0x0df3, 0x0dfc, 0x0e05,
    0x0e0f, 0x0e18, 0x0e21, 0x0e2a, 0x0e33, 0x0e3c, 0x0e45, 0x0e4e,
    0x0e56, 0x0e5f, 0x0e68, 0x0e71, 0x0e7a, 0x0e83, 0x0e8c, 0x0e95,
    0x0e9e, 0x0ea7, 0x0eb0, 0x0eb9, 0x0ec2, 0x0ecb, 0x0ed4, 0x0edc,
    0x0ee5, 0x0eee, 0x0ef7, 0x0f00, 0x0f09, 0x0f12, 0x0f1b, 0x0f23,
    0x0f2c, 0x0f35, 0x0f3e, 0x0f47, 0x0f50, 0x0f58, 0x0f61, 0x0f6a,
    0x0f73, 0x0f7c, 0x0f84, 0x0f8d, 0x0f96, 0x0f9f, 0x0fa7, 0x0fb0,
    0x0fb9, 0x0fc2, 0x0fca, 0x0fd3, 0x0fdc, 0x0fe5, 0x0fed, 0x0ff6,
    0x0fff, 0x1007, 0x1010, 0x1019, 0x1021, 0x102a, 0x1033, 0x103b,
    0x1044, 0x104d, 0x1055, 0x105e, 0x1067, 0x106f, 0x1078, 0x1080,
    0x1089, 0x1092, 0x109a, 0x10a3, 0x10ab, 0x10b4, 0x10bc, 0x10c5,
    0x10ce, 0x10d6, 0x10df, 0x10e7, 0x10f0, 0x10f8, 0x1101, 0x1109,
    0x1112, 0x111a, 0x1123, 0x112b, 0x1134, 0x113c, 0x1145, 0x114d,
    0x1156, 0x115e, 0x1166, 0x116f, 0x1177, 0x1180, 0x1188, 0x1191,
    0x1199, 0x11a1, 0x11aa, 0x11b2, 0x11bb, 0x11c3, 0x11cb, 0x11d4,
    0x11dc, 0x11e4, 0x11ed, 0x11f5, 0x11fd, 0x1206, 0x120e, 0x1216,
    0x121f, 0x1227, 0x122f, 0x1237, 0x1240, 0x1248, 0x1250, 0x1259,
    0x1261, 0x1269, 0x1271, 0x127a, 0x1282, 0x128a, 0x1292, 0x129a,
    0x12a3, 0x12ab, 0x12b3, 0x12bb, 0x12c3, 0x12cc, 0x12d4, 0x12dc,
    0x12e4, 0x12ec, 0x12f4, 0x12fc, 0x1305, 0x130d, 0x1315, 0x131d,
    0x1325, 0x132d, 0x1335, 0x133d, 0x1345, 0x134d, 0x1355, 0x135e,
    0x1366, 0x136e, 0x1376, 0x137e, 0x1386, 0x138e, 0x1396, 0x139e,
    0x13a6, 0x13ae, 0x13b6, 0x13be, 0x13c6, 0x13ce, 0x13d6, 0x13de,
    0x13e6, 0x13ed, 0x13f5, 0x13fd, 0x1405, 0x140d, 0x1415, 0x141d,
    0x1425, 0x142d, 0x1435, 0x143d, 0x1444, 0x144c, 0x1454, 0x145c,
    0x1464, 0x146c, 0x1473, 0x147b, 0x1483, 0x148b, 0x1493, 0x149b,
    0x14a2, 0x14aa, 0x14b2, 0x14ba, 0x14c1, 0x14c9, 0x14d1, 0x14d9,
    0x14e0, 0x14e8, 0x14f0, 0x14f8, 0x14ff, 0x1507, 0x150f, 0x1516,
    0x151e, 0x1526, 0x152d, 0x1535, 0x153d, 0x1544, 0x154c, 0x1554,
    0x155b, 0x1563, 0x156b, 0x1572, 0x157a, 0x1581, 0x1589, 0x1591,
    0x1598, 0x15a0, 0x15a7, 0x15af, 0x15b7, 0x15be, 0x15c6, 0x15cd,
    0x15d5, 0x15dc, 0x15e4, 0x15eb, 0x15f3, 0x15fa, 0x1602, 0x1609,
    0x1611, 0x1618, 0x1620, 0x1627, 0x162f, 0x1636, 0x163e, 0x1645,
    0x164c, 0x1654, 0x165b, 0x1663, 0x166a, 0x1671, 0x1679, 0x1680,
    0x1688, 0x168f, 0x1696, 0x169e, 0x16a5, 0x16ac, 0x16b4, 0x16bb,
    0x16c2, 0x16ca, 0x16d1, 0x16d8, 0x16e0, 0x16e7, 0x16ee, 0x16f6,
    0x16fd, 0x1704, 0x170b, 0x1713, 0x171a, 0x1721, 0x1728, 0x1730,
    0x1737, 0x173e, 0x1745, 0x174c, 0x1754, 0x175b, 0x1762, 0x1769,
    0x1770, 0x1778, 0x177f, 0x1786, 0x178d, 0x1794, 0x179b, 0x17a2,
    0x17aa, 0x17b1, 0x17b8, 0x17bf, 0x17c6, 0x17cd, 0x17d4, 0x17db,
    0x17e2, 0x17e9, 0x17f0, 0x17f7, 0x17fe, 0x1806, 0x180d, 0x1814,
    0x181b, 0x1822, 0x1829, 0x1830, 0x1837, 0x183e, 0x1845, 0x184c,
    0x1853, 0x185a, 0x1860, 0x1867, 0x186e, 0x1875, 0x187c, 0x1883,
    0x188a, 0x1891, 0x1898, 0x189f, 0x18a6, 0x18ad, 0x18b3, 0x18ba,
    0x18c1, 0x18c8, 0x18cf, 0x18d6, 0x18dd, 0x18e3, 0x18ea, 0x18f1,
    0x18f8, 0x18ff, 0x1906, 0x190c, 0x1913, 0x191a, 0x1921, 0x1928,
    0x192e, 0x1935, 0x193c, 0x1943, 0x1949, 0x1950, 0x1957, 0x195d,
    0x1964, 0x196b, 0x1972, 0x1978, 0x197f, 0x1986, 0x198c, 0x1993,
    0x199a, 0x19a0, 0x19a7, 0x19ae, 0x19b4, 0x19bb, 0x19c2, 0x19c8,
    0x19cf, 0x19d5, 0x19dc, 0x19e3, 0x19e9, 0x19f0, 0x19f6, 0x19fd,
    0x1a04, 0x1a0a, 0x1a11, 0x1a17, 0x1a1e, 0x1a24, 0x1a2b, 0x1a31,
    0x1a38, 0x1a3e, 0x1a45, 0x1a4b, 0x1a52, 0x1a58, 0x1a5f, 0x1a65,
    0x1a6c, 0x1a72, 0x1a79, 0x1a7f, 0x1a86, 0x1a8c, 0x1a93, 0x1a99,
    0x1a9f, 0x1aa6, 0x1aac, 0x1ab3, 0x1ab9, 0x1ac0, 0x1ac6, 0x1acc,
    0x1ad3, 0x1ad9, 0x1adf, 0x1ae6, 0x1aec, 0x1af2, 0x1af9, 0x1aff,
    0x1b05, 0x1b0c, 0x1b12, 0x1b18, 0x1b1f, 0x1b25, 0x1b2b, 0x1b32,
    0x1b38, 0x1b3e, 0x1b44, 0x1b4b, 0x1b51, 0x1b57, 0x1b5d, 0x1b64,
    0x1b6a, 0x1b70, 0x1b76, 0x1b7d, 0x1b83, 0x1b89, 0x1b8f, 0x1b95,
    0x1b9c, 0x1ba2, 0x1ba8, 0x1bae, 0x1bb4, 0x1bba, 0x1bc1, 0x1bc7,
    0x1bcd, 0x1bd3, 0x1bd9, 0x1bdf, 0x1be5, 0x1beb, 0x1bf2, 0x1bf8,
    0x1bfe, 0x1c04, 0x1c0a, 0x1c10, 0x1c16, 0x1c1c, 0x1c22, 0x1c28,
    0x1c2e, 0x1c34, 0x1c3a, 0x1c40, 0x1c46, 0x1c4c, 0x1c52, 0x1c58,
    0x1c5e, 0x1c64, 0x1c6a, 0x1c70, 0x1c76, 0x1c7c, 0x1c82, 0x1c88,
    0x1c8e, 0x1c94, 0x1c9a, 0x1ca0, 0x1ca6, 0x1cac, 0x1cb2, 0x1cb8,
    0x1cbe, 0x1cc3, 0x1cc9, 0x1ccf, 0x1cd5, 0x1cdb, 0x1ce1, 0x1ce7,
    0x1ced, 0x1cf3, 0x1cf8, 0x1cfe, 0x1d04, 0x1d0a, 0x1d10, 0x1d16,
    0x1d1b, 0x1d21, 0x1d27, 0x1d2d, 0x1d33, 0x1d38, 0x1d3e, 0x1d44,
    0x1d4a, 0x1d4f, 0x1d55, 0x1d5b, 0x1d61, 0x1d66, 0x1d6c, 0x1d72,
    0x1d78, 0x1d7d, 0x1d83, 0x1d89, 0x1d8e, 0x1d94, 0x1d9a, 0x1da0,
    0x1da5, 0x1dab, 0x1db1, 0x1db6, 0x1dbc, 0x1dc2, 0x1dc7, 0x1dcd,
    0x1dd3, 0x1dd8, 0x1dde, 0x1de3, 0x1de9, 0x1def, 0x1df4, 0x1dfa,
    0x1dff, 0x1e05, 0x1e0b, 0x1e10, 0x1e16, 0x1e1b, 0x1e21, 0x1e26,
    0x1e2c, 0x1e32, 0x1e37, 0x1e3d, 0x1e42, 0x1e48, 0x1e4d, 0x1e53,
    0x1e58, 0x1e5e, 0x1e63, 0x1e69, 0x1e6e, 0x1e74, 0x1e79, 0x1e7f,
    0x1e84, 0x1e8a, 0x1e8f, 0x1e94, 0x1e9a, 0x1e9f, 0x1ea5, 0x1eaa,
    0x1eb0, 0x1eb5, 0x1eba, 0x1ec0, 0x1ec5, 0x1ecb, 0x1ed0, 0x1ed5,
    0x1edb, 0x1ee0, 0x1ee6, 0x1eeb, 0x1ef0, 0x1ef6, 0x1efb, 0x1f00,
    0x1f06, 0x1f0b, 0x1f10, 0x1f16, 0x1f1b, 0x1f20, 0x1f26, 0x1f2b,
    0x1f30, 0x1f36, 0x1f3b, 0x1f40, 0x1f45, 0x1f4b, 0x1f50, 0x1f55,
    0x1f5a, 0x1f60, 0x1f65, 0x1f6a, 0x1f6f, 0x1f75, 0x1f7a, 0x1f7f,
    0x1f84, 0x1f8a, 0x1f8f, 0x1f94, 0x1f99, 0x1f9e, 0x1fa4, 0x1fa9,
    0x1fae, 0x1fb3, 0x1fb8, 0x1fbd, 0x1fc3, 0x1fc8, 0x1fcd, 0x1fd2,
    0x1fd7, 0x1fdc, 0x1fe1, 0x1fe6, 0x1fec, 0x1ff1, 0x1ff6, 0x1ffb,
    0x2000,
};

static unshort
U_GetAtanTable(float a, float b)
{
	unshort angle;
	int num;
	
	if (b == 0.0f)
	    angle = atntable[0];
	else {
	    if((num = (int)(a/b * 1024.0f + 0.5f)) > 1024)
		angle = atntable[0];
	    else
		angle = atntable[num];
	}
	return(angle);
}

/*
 *  (y / x) の actan 
 */
short atans_table(float x,float y)
{
    unshort angle;
    
    if (y >= 0.0F) {
	if (x >= 0.0F) {
	    if (x >= y)
		angle = (unshort)(0x0000 + U_GetAtanTable(y, x));
	    else
		angle = (unshort)(0x4000 - U_GetAtanTable(x, y));
	}
	else {
	    x = -x;
	    if (x < y)
		angle = (unshort)(0x4000+U_GetAtanTable(x, y));
	    else
		angle = (unshort)(0x8000-U_GetAtanTable(y, x));
	}
    }
    else {
	y = -y;
	
	if (x < 0.0F) {
	    x = -x;
	    
	    if (x >= y)
		angle = (unshort)(0x8000 + U_GetAtanTable(y, x));
	    else
		angle = (unshort)(0xc000 - U_GetAtanTable(x, y));
	}
	else {
	    if (x < y) {
		angle = (unshort)(0xc000 + U_GetAtanTable(x, y));
	    } else {
		angle = (unshort)(0x0000 - U_GetAtanTable(y, x));
	    }
	}
    }
    return((short)angle);
}

float atanf_table(float x,float y)
{
    short ang;
    float l;
    float h;
    
    ang = atans_table(x,y);
    l = (float)((unshort)(ang) & 0x00FF) * (1.0F / 256.0F);
    h = (float)(short)((short)ang >> 8);

    return ((h + l) * (90.0F / 64.0F));
}

/************************************************************************/
/*     角度の演算（０〜３６０゜の間で）					*/
/************************************************************************/
void calc_angle( float *angle, float o_angle, float haba )
{
    float		a = o_angle - ( *angle );

    if ( is_zeroMSmallf(a) ) {
	if ( a < ( -HALF_ANGLE ) ) {
	    ( *angle ) += haba;
	    if ( ( *angle ) >= MAX_ANGLE ) ( *angle ) -= MAX_ANGLE;
	} else {
	    ( *angle ) -= haba;
	    if ( ( *angle ) < o_angle ) ( *angle ) = o_angle;
	}
    } else {
	if ( a < HALF_ANGLE ) {
	    ( *angle ) += haba;
	    if ( ( *angle ) > o_angle ) ( *angle ) = o_angle;
	} else {
	    ( *angle ) -= haba;
	    if ( ( *angle ) < MIN_ANGLE ) ( *angle ) += MAX_ANGLE;
	}
    }
}

