예제 #1
0
파일: drbg.c 프로젝트: emaldona/nss
/*
 * This function expands the internal state of the prng to fulfill any number
 * of bytes we need for this request. We only use this call if we need more
 * than can be supplied by a single call to SHA256_HashBuf.
 *
 * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen
 */
static void
prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
             unsigned int no_of_returned_bytes)
{
    PRUint8 data[VSize(rng)];
    PRUint8 thisHash[SHA256_LENGTH];

    PORT_Memcpy(data, V(rng), VSize(rng));
    while (no_of_returned_bytes) {
        SHA256Context ctx;
        unsigned int len;
        unsigned int carry;

        SHA256_Begin(&ctx);
        SHA256_Update(&ctx, data, sizeof data);
        SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH);
        if (no_of_returned_bytes < SHA256_LENGTH) {
            len = no_of_returned_bytes;
        }
        PORT_Memcpy(returned_bytes, thisHash, len);
        returned_bytes += len;
        no_of_returned_bytes -= len;
        /* The carry parameter is a bool (increment or not).
     * This increments data if no_of_returned_bytes is not zero */
        carry = no_of_returned_bytes;
        PRNG_ADD_CARRY_ONLY(data, (sizeof data) - 1, carry);
    }
    PORT_Memset(data, 0, sizeof data);
    PORT_Memset(thisHash, 0, sizeof thisHash);
}
예제 #2
0
/* 
 * Generates new random bytes and advances the internal prng state.	
 * additional bytes are only used in algorithm testing.
 * 
 * This function is specified in NIST SP 800-90 section 10.1.1.4
 */
static SECStatus
prng_generateNewBytes(RNGContext *rng, 
		PRUint8 *returned_bytes, unsigned int no_of_returned_bytes,
		const PRUint8 *additional_input,
		unsigned int additional_input_len)
{
    PRUint8 H[SHA256_LENGTH]; /* both H and w since they 
			       * aren't used concurrently */
    unsigned int carry;
    int k1, k2;

    if (!rng->isValid) {
	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
	return SECFailure;
    }
    /* This code only triggers during tests, normal
     * prng operation does not use additional_input */
    if (additional_input){
	SHA256Context ctx;
	/* NIST SP 800-90 defines two temporaries in their calculations,
	 * w and H. These temporaries are the same lengths, and used
	 * at different times, so we use the following macro to collapse
	 * them to the same variable, but keeping their unique names for
	 * easy comparison to the spec */
#define w H
	rng->V_type = prngAdditionalDataType;
 	SHA256_Begin(&ctx);
 	SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data);
 	SHA256_Update(&ctx, additional_input, additional_input_len);
	SHA256_End(&ctx, w, NULL, sizeof w);
	PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w)
	PORT_Memset(w, 0, sizeof w);
#undef w 
    }

    if (no_of_returned_bytes == SHA256_LENGTH) {
	/* short_cut to hashbuf and save a copy and a clear */
	SHA256_HashBuf(returned_bytes, V(rng), VSize(rng) );
    } else {
    	prng_Hashgen(rng, returned_bytes, no_of_returned_bytes);
    }
    /* advance our internal state... */
    rng->V_type = prngGenerateByteType;
    SHA256_HashBuf(H, rng->V_Data, sizeof rng->V_Data);
    PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), H, sizeof H)
    PRNG_ADD_BITS(V(rng), VSize(rng), rng->C, sizeof rng->C);
    PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter, 
					sizeof rng->reseed_counter)
    PRNG_ADD_CARRY_ONLY(rng->reseed_counter,(sizeof rng->reseed_counter)-1, 1);

    /* continuous rng check */
    if (memcmp(V(rng), rng->oldV, sizeof rng->oldV) == 0) {
	rng->isValid = PR_FALSE;
	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
	return SECFailure;
    }
    PORT_Memcpy(rng->oldV, V(rng), sizeof rng->oldV);
    return SECSuccess;
}
예제 #3
0
/*
 * Clean up the global RNG context
 */
static void
prng_freeRNGContext(RNGContext *rng)
{
    PRUint8 inputhash[VSize(rng) + (sizeof rng->C)];

    /* destroy context lock */
    SKIP_AFTER_FORK(PZ_DestroyLock(globalrng->lock));

    /* zero global RNG context except for C & V to preserve entropy */
    prng_Hash_df(inputhash, sizeof rng->C, rng->C, sizeof rng->C, NULL, 0); 
    prng_Hash_df(&inputhash[sizeof rng->C], VSize(rng), V(rng), VSize(rng), 
								  NULL, 0); 
    memset(rng, 0, sizeof *rng);
    memcpy(rng->C, inputhash, sizeof rng->C); 
    memcpy(V(rng), &inputhash[sizeof rng->C], VSize(rng)); 

    memset(inputhash, 0, sizeof inputhash);
}
예제 #4
0
// キャラクターに当たっていたら押し出す処理を行う( chk_ch に ch が当たっていたら ch が離れる )
void Chara_Collision( CHARA *ch, VECTOR *ch_MoveVec, CHARA *chk_ch )
{
	VECTOR ChkChToChVec ;
	VECTOR PushVec ;
	VECTOR ChPosition ;
	float Length ;

	// 移動後の ch の座標を算出
	ChPosition = VAdd( ch->Position, *ch_MoveVec ) ;

	// 当たっていなかったら何もしない
	if( HitCheck_Capsule_Capsule(
			ChPosition, VAdd( ChPosition, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), CHARA_HIT_WIDTH, 
			chk_ch->Position, VAdd( chk_ch->Position, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), CHARA_HIT_WIDTH ) == TRUE )
	{
		// 当たっていたら ch が chk から離れる処理をする

		// chk_ch から ch へのベクトルを算出
		ChkChToChVec = VSub( ChPosition, chk_ch->Position ) ;

		// Y軸は見ない
		ChkChToChVec.y = 0.0f ;

		// 二人の距離を算出
		Length = VSize( ChkChToChVec ) ;

		// chk_ch から ch へのベクトルを正規化( ベクトルの長さを 1.0f にする )
		PushVec = VScale( ChkChToChVec, 1.0f / Length ) ;

		// 押し出す距離を算出、もし二人の距離から二人の大きさを引いた値に押し出し力を足して離れてしまう場合は、ぴったりくっつく距離に移動する
		if( Length - CHARA_HIT_WIDTH * 2.0f + CHARA_HIT_PUSH_POWER > 0.0f )
		{
			float TempY ;

			TempY = ChPosition.y ;
			ChPosition = VAdd( chk_ch->Position, VScale( PushVec, CHARA_HIT_WIDTH * 2.0f ) ) ; 

			// Y座標は変化させない
			ChPosition.y = TempY ;
		}
		else
		{
			// 押し出し
			ChPosition = VAdd( ChPosition, VScale( PushVec, CHARA_HIT_PUSH_POWER ) ) ;
		}
	}

	// 当たり判定処理後の移動ベクトルをセット
	*ch_MoveVec = VSub( ChPosition, ch->Position ) ;
}
예제 #5
0
float GetSpeed(FVector projdirection, FVector PawnVelocity)
{
	FVector projvelocity = Scale(Normal(projdirection), 3920.0);
	projvelocity.Z += 0;

	float ForwardPct = FMin(Dot(Normal(PawnVelocity), Normal(projdirection)), 0.5);
	float InheritPct = FMax(0.5, ForwardPct);

	projvelocity.X += InheritPct * PawnVelocity.X;
	projvelocity.Y += InheritPct * PawnVelocity.Y;
	projvelocity.Z += 0.5 * PawnVelocity.Z;

	return VSize(projvelocity);
}
예제 #6
0
/*
 * This function expands the internal state of the prng to fulfill any number
 * of bytes we need for this request. We only use this call if we need more
 * than can be supplied by a single call to SHA256_HashBuf. 
 *
 * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen
 */
static void
prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes, 
	     unsigned int no_of_returned_bytes)
{
    PRUint8 data[VSize(rng)];

    PORT_Memcpy(data, V(rng), VSize(rng));
    while (no_of_returned_bytes) {
	SHA256Context ctx;
	unsigned int len;
	unsigned int carry;
	int k1;

 	SHA256_Begin(&ctx);
 	SHA256_Update(&ctx, data, sizeof data);
	SHA256_End(&ctx, returned_bytes, &len, no_of_returned_bytes);
	returned_bytes += len;
	no_of_returned_bytes -= len;
	/* The carry parameter is a bool (increment or not). 
	 * This increments data if no_of_returned_bytes is not zero */
	PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, no_of_returned_bytes);
    }
    PORT_Memset(data, 0, sizeof data); 
}
예제 #7
0
/*
 * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2
 *
 * NOTE: bytes & len are entropy || nonce || personalization_string. In
 * normal operation, NSS calculates them all together in a single call.
 */
static SECStatus
prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
{
    if (len < PRNG_SEEDLEN) {
	/* if the seedlen is to small, it's probably because we failed to get
	 * enough random data */
	PORT_SetError(SEC_ERROR_NEED_RANDOM);
	return SECFailure;
    }
    prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0);
    rng->V_type = prngCGenerateType;
    prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
    PRNG_RESET_RESEED_COUNT(rng)
    return SECSuccess;
}
예제 #8
0
void Normalize (FVector &v)
{
        float size = VSize(v);
 
        if ( !size )
        {
                v.X = v.Y = v.Z = 0;
        }
        else
        {
                v.X /= size;
                v.Y /= size;
                v.Z /= size;
        }
}
예제 #9
0
파일: drbg.c 프로젝트: emaldona/nss
/*
 * Hash_DRBG Instantiate NIST SP 800-90 10.1.1.2
 *
 * NOTE: bytes & len are entropy || nonce || personalization_string. In
 * normal operation, NSS calculates them all together in a single call.
 */
static SECStatus
prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
{
    if (!rng->isKatTest && len < PRNG_SEEDLEN) {
        /* If the seedlen is too small, it's probably because we failed to get
         * enough random data.
         * This is stricter than NIST SP800-90A requires. Don't enforce it for
         * tests. */
        PORT_SetError(SEC_ERROR_NEED_RANDOM);
        return SECFailure;
    }
    prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0);
    rng->V_type = prngCGenerateType;
    prng_Hash_df(rng->C, sizeof rng->C, rng->V_Data, sizeof rng->V_Data, NULL, 0);
    PRNG_RESET_RESEED_COUNT(rng)
    return SECSuccess;
}
예제 #10
0
/*
 * Update the global random number generator with more seeding
 * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90
 * section 10.1.1.3
 *
 * If entropy is NULL, it is fetched from the noise generator.
 */
static SECStatus
prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len,
	const PRUint8 *additional_input, unsigned int additional_input_len)
{
    PRUint8 noiseData[(sizeof rng->V_Data)+PRNG_SEEDLEN];
    PRUint8 *noise = &noiseData[0];

    /* if entropy wasn't supplied, fetch it. (normal operation case) */
    if (entropy == NULL) {
    	entropy_len = (unsigned int) RNG_SystemRNG(
			&noiseData[sizeof rng->V_Data], PRNG_SEEDLEN);
    } else {
	/* NOTE: this code is only available for testing, not to applications */
	/* if entropy was too big for the stack variable, get it from malloc */
	if (entropy_len > PRNG_SEEDLEN) {
	    noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data));
	    if (noise == NULL) {
		return SECFailure;
	    }
	}
	PORT_Memcpy(&noise[sizeof rng->V_Data],entropy, entropy_len);
    }

    if (entropy_len < 256/PR_BITS_PER_BYTE) {
	/* noise == &noiseData[0] at this point, so nothing to free */
	PORT_SetError(SEC_ERROR_NEED_RANDOM);
	return SECFailure;
    }

    rng->V_type = prngReseedType;
    PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data);
    prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len,
		additional_input, additional_input_len);
    /* clear potential CSP */
    PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len); 
    rng->V_type = prngCGenerateType;
    prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
    PRNG_RESET_RESEED_COUNT(rng)

    if (noise != &noiseData[0]) {
	PORT_Free(noise);
    }
    return SECSuccess;
}
예제 #11
0
//---------------------------------------------------------------------------------------
Image::Image()
    : m_error("")
{
    //Build default img: grey square 24x24 px

    m_bmpSize = VSize(24, 24);
    //TODO: get display reolution from lomse initialization. Here it is assumed 96 ppi
    m_imgSize = USize(24.0 * 2540.0f / 96.0f, 24.0 * 2540.0f / 96.0f);
    m_format = k_pix_format_rgba32;

    //allocate a buffer for the bitmap
    int bmpsize = 24 * 24 * 4;   //24px width, 24px height, 4bytes per pixel (RGBA)
    if ((m_bmap = (unsigned char*)malloc(bmpsize)) == NULL)
    {
        LOMSE_LOG_ERROR("[Image constructor]: not enough memory for image buffer");
        throw runtime_error("[Image constructor]: not enough memory for image buffer");
    }

    unsigned char no_image = 0x77;
    memset(m_bmap, no_image, bmpsize);
}
예제 #12
0
inline VECTOR VAdjustLength(const VECTOR& lhs, float rhs)
{
    return lhs * (rhs / VSize(lhs));
}
예제 #13
0
// キャラクターの移動処理
void Chara_Move( CHARA *ch, VECTOR MoveVector )
{
	int i, j, k ;						// 汎用カウンタ変数
	int MoveFlag ;						// 水平方向に移動したかどうかのフラグ( 0:移動していない  1:移動した )
	int HitFlag ;						// ポリゴンに当たったかどうかを記憶しておくのに使う変数( 0:当たっていない  1:当たった )
	MV1_COLL_RESULT_POLY_DIM HitDim ;			// キャラクターの周囲にあるポリゴンを検出した結果が代入される当たり判定結果構造体
	int KabeNum ;						// 壁ポリゴンと判断されたポリゴンの数
	int YukaNum ;						// 床ポリゴンと判断されたポリゴンの数
	MV1_COLL_RESULT_POLY *Kabe[ CHARA_MAX_HITCOLL ] ;	// 壁ポリゴンと判断されたポリゴンの構造体のアドレスを保存しておくためのポインタ配列
	MV1_COLL_RESULT_POLY *Yuka[ CHARA_MAX_HITCOLL ] ;	// 床ポリゴンと判断されたポリゴンの構造体のアドレスを保存しておくためのポインタ配列
	MV1_COLL_RESULT_POLY *Poly ;				// ポリゴンの構造体にアクセスするために使用するポインタ( 使わなくても済ませられますがプログラムが長くなるので・・・ )
	HITRESULT_LINE LineRes ;				// 線分とポリゴンとの当たり判定の結果を代入する構造体
	VECTOR OldPos ;						// 移動前の座標	
	VECTOR NowPos ;						// 移動後の座標

	// 移動前の座標を保存
	OldPos = ch->Position ;

	// 移動後の座標を算出
	NowPos = VAdd( ch->Position, MoveVector ) ;

	// キャラクターの周囲にあるステージポリゴンを取得する
	// ( 検出する範囲は移動距離も考慮する )
	HitDim = MV1CollCheck_Sphere( stg.ModelHandle, -1, ch->Position, CHARA_ENUM_DEFAULT_SIZE + VSize( MoveVector ) ) ;

	// x軸かy軸方向に 0.01f 以上移動した場合は「移動した」フラグを1にする
	if( fabs( MoveVector.x ) > 0.01f || fabs( MoveVector.z ) > 0.01f )
	{
		MoveFlag = 1 ;
	}
	else
	{
		MoveFlag = 0 ;
	}

	// 検出されたポリゴンが壁ポリゴン( XZ平面に垂直なポリゴン )か床ポリゴン( XZ平面に垂直ではないポリゴン )かを判断する
	{
		// 壁ポリゴンと床ポリゴンの数を初期化する
		KabeNum = 0 ;
		YukaNum = 0 ;

		// 検出されたポリゴンの数だけ繰り返し
		for( i = 0 ; i < HitDim.HitNum ; i ++ )
		{
			// XZ平面に垂直かどうかはポリゴンの法線のY成分が0に限りなく近いかどうかで判断する
			if( HitDim.Dim[ i ].Normal.y < 0.000001f && HitDim.Dim[ i ].Normal.y > -0.000001f )
			{
				// 壁ポリゴンと判断された場合でも、キャラクターのY座標+1.0fより高いポリゴンのみ当たり判定を行う
				if( HitDim.Dim[ i ].Position[ 0 ].y > ch->Position.y + 1.0f ||
					HitDim.Dim[ i ].Position[ 1 ].y > ch->Position.y + 1.0f ||
					HitDim.Dim[ i ].Position[ 2 ].y > ch->Position.y + 1.0f )
				{
					// ポリゴンの数が列挙できる限界数に達していなかったらポリゴンを配列に追加
					if( KabeNum < CHARA_MAX_HITCOLL )
					{
						// ポリゴンの構造体のアドレスを壁ポリゴンポインタ配列に保存する
						Kabe[ KabeNum ] = &HitDim.Dim[ i ] ;

						// 壁ポリゴンの数を加算する
						KabeNum ++ ;
					}
				}
			}
			else
			{
				// ポリゴンの数が列挙できる限界数に達していなかったらポリゴンを配列に追加
				if( YukaNum < CHARA_MAX_HITCOLL )
				{
					// ポリゴンの構造体のアドレスを床ポリゴンポインタ配列に保存する
					Yuka[ YukaNum ] = &HitDim.Dim[ i ] ;

					// 床ポリゴンの数を加算する
					YukaNum ++ ;
				}
			}
		}
	}

	// 壁ポリゴンとの当たり判定処理
	if( KabeNum != 0 )
	{
		// 壁に当たったかどうかのフラグは初期状態では「当たっていない」にしておく
		HitFlag = 0 ;

		// 移動したかどうかで処理を分岐
		if( MoveFlag == 1 )
		{
			// 壁ポリゴンの数だけ繰り返し
			for( i = 0 ; i < KabeNum ; i ++ )
			{
				// i番目の壁ポリゴンのアドレスを壁ポリゴンポインタ配列から取得
				Poly = Kabe[ i ] ;

				// ポリゴンとキャラクターが当たっていなかったら次のカウントへ
				if( HitCheck_Capsule_Triangle( NowPos, VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), CHARA_HIT_WIDTH, Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) == FALSE ) continue ;

				// ここにきたらポリゴンとキャラクターが当たっているということなので、ポリゴンに当たったフラグを立てる
				HitFlag = 1 ;

				// 壁に当たったら壁に遮られない移動成分分だけ移動する
				{
					VECTOR SlideVec ;	// キャラクターをスライドさせるベクトル

					// 進行方向ベクトルと壁ポリゴンの法線ベクトルに垂直なベクトルを算出
					SlideVec = VCross( MoveVector, Poly->Normal ) ;

					// 算出したベクトルと壁ポリゴンの法線ベクトルに垂直なベクトルを算出、これが
					// 元の移動成分から壁方向の移動成分を抜いたベクトル
					SlideVec = VCross( Poly->Normal, SlideVec ) ;

					// それを移動前の座標に足したものを新たな座標とする
					NowPos = VAdd( OldPos, SlideVec ) ;
				}

				// 新たな移動座標で壁ポリゴンと当たっていないかどうかを判定する
				for( j = 0 ; j < KabeNum ; j ++ )
				{
					// j番目の壁ポリゴンのアドレスを壁ポリゴンポインタ配列から取得
					Poly = Kabe[ j ] ;

					// 当たっていたらループから抜ける
					if( HitCheck_Capsule_Triangle( NowPos, VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), CHARA_HIT_WIDTH, Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) == TRUE ) break ;
				}

				// j が KabeNum だった場合はどのポリゴンとも当たらなかったということなので
				// 壁に当たったフラグを倒した上でループから抜ける
				if( j == KabeNum )
				{
					HitFlag = 0 ;
					break ;
				}
			}
		}
		else
		{
			// 移動していない場合の処理
			
			// 壁ポリゴンの数だけ繰り返し
			for( i = 0 ; i < KabeNum ; i ++ )
			{
				// i番目の壁ポリゴンのアドレスを壁ポリゴンポインタ配列から取得
				Poly = Kabe[ i ] ;

				// ポリゴンに当たっていたら当たったフラグを立てた上でループから抜ける
				if( HitCheck_Capsule_Triangle( NowPos, VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), CHARA_HIT_WIDTH, Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) == TRUE )
				{
					HitFlag = 1 ;
					break ;
				}
			}
		}

		// 壁に当たっていたら壁から押し出す処理を行う
		if( HitFlag == 1 )
		{
			// 壁からの押し出し処理を試みる最大数だけ繰り返し
			for( k = 0 ; k < CHARA_HIT_TRYNUM ; k ++ )
			{
				// 壁ポリゴンの数だけ繰り返し
				for( i = 0 ; i < KabeNum ; i ++ )
				{
					// i番目の壁ポリゴンのアドレスを壁ポリゴンポインタ配列から取得
					Poly = Kabe[ i ] ;

					// キャラクターと当たっているかを判定
					if( HitCheck_Capsule_Triangle( NowPos, VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), CHARA_HIT_WIDTH, Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) == FALSE ) continue ;

					// 当たっていたら規定距離分キャラクターを壁の法線方向に移動させる
					NowPos = VAdd( NowPos, VScale( Poly->Normal, CHARA_HIT_SLIDE_LENGTH ) ) ;

					// 移動した上で壁ポリゴンと接触しているかどうかを判定
					for( j = 0 ; j < KabeNum ; j ++ )
					{
						// 当たっていたらループを抜ける
						Poly = Kabe[ j ] ;
						if( HitCheck_Capsule_Triangle( NowPos, VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), CHARA_HIT_WIDTH, Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) == TRUE ) break ;
					}

					// 全てのポリゴンと当たっていなかったらここでループ終了
					if( j == KabeNum ) break ;
				}

				// i が KabeNum ではない場合は全部のポリゴンで押し出しを試みる前に全ての壁ポリゴンと接触しなくなったということなのでループから抜ける
				if( i != KabeNum ) break ;
			}
		}
	}

	// 床ポリゴンとの当たり判定
	if( YukaNum != 0 )
	{
		// ジャンプ中且つ上昇中の場合は処理を分岐
		if( ch->State == 2 && ch->JumpPower > 0.0f )
		{
			float MinY ;

			// 天井に頭をぶつける処理を行う

			// 一番低い天井にぶつける為の判定用変数を初期化
			MinY = 0.0f ;

			// 当たったかどうかのフラグを当たっていないを意味する0にしておく
			HitFlag = 0 ;

			// 床ポリゴンの数だけ繰り返し
			for( i = 0 ; i < YukaNum ; i ++ )
			{
				// i番目の床ポリゴンのアドレスを床ポリゴンポインタ配列から取得
				Poly = Yuka[ i ] ;

				// 足先から頭の高さまでの間でポリゴンと接触しているかどうかを判定
				LineRes = HitCheck_Line_Triangle( NowPos, VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) ;

				// 接触していなかったら何もしない
				if( LineRes.HitFlag == FALSE ) continue ;
				
				// 既にポリゴンに当たっていて、且つ今まで検出した天井ポリゴンより高い場合は何もしない
				if( HitFlag == 1 && MinY < LineRes.Position.y ) continue ;

				// ポリゴンに当たったフラグを立てる
				HitFlag = 1 ;

				// 接触したY座標を保存する
				MinY = LineRes.Position.y ;
			}

			// 接触したポリゴンがあったかどうかで処理を分岐
			if( HitFlag == 1 )
			{
				// 接触した場合はキャラクターのY座標を接触座標を元に更新
				NowPos.y = MinY - CHARA_HIT_HEIGHT ;

				// Y軸方向の速度は反転
				ch->JumpPower = -ch->JumpPower ;
			}
		}
		else
		{
			float MaxY ;

			// 下降中かジャンプ中ではない場合の処理

			// 床ポリゴンに当たったかどうかのフラグを倒しておく
			HitFlag = 0 ;

			// 一番高い床ポリゴンにぶつける為の判定用変数を初期化
			MaxY = 0.0f ;

			// 床ポリゴンの数だけ繰り返し
			for( i = 0 ; i < YukaNum ; i ++ )
			{
				// i番目の床ポリゴンのアドレスを床ポリゴンポインタ配列から取得
				Poly = Yuka[ i ] ;

				// ジャンプ中かどうかで処理を分岐
				if( ch->State == 2 )
				{
					// ジャンプ中の場合は頭の先から足先より少し低い位置の間で当たっているかを判定
					LineRes = HitCheck_Line_Triangle( VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), VAdd( NowPos, VGet( 0.0f, -1.0f, 0.0f ) ), Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) ;
				}
				else
				{
					// 走っている場合は頭の先からそこそこ低い位置の間で当たっているかを判定( 傾斜で落下状態に移行してしまわない為 )
					LineRes = HitCheck_Line_Triangle( VAdd( NowPos, VGet( 0.0f, CHARA_HIT_HEIGHT, 0.0f ) ), VAdd( NowPos, VGet( 0.0f, -40.0f, 0.0f ) ), Poly->Position[ 0 ], Poly->Position[ 1 ], Poly->Position[ 2 ] ) ;
				}

				// 当たっていなかったら何もしない
				if( LineRes.HitFlag == FALSE ) continue ;

				// 既に当たったポリゴンがあり、且つ今まで検出した床ポリゴンより低い場合は何もしない
				if( HitFlag == 1 && MaxY > LineRes.Position.y ) continue ;

				// ポリゴンに当たったフラグを立てる
				HitFlag = 1 ;

				// 接触したY座標を保存する
				MaxY = LineRes.Position.y ;
			}

			// 床ポリゴンに当たったかどうかで処理を分岐
			if( HitFlag == 1 )
			{
				// 当たった場合

				// 接触したポリゴンで一番高いY座標をキャラクターのY座標にする
				NowPos.y = MaxY ;

				// Y軸方向の移動速度は0に
				ch->JumpPower = 0.0f ;

				// もしジャンプ中だった場合は着地状態にする
				if( ch->State == 2 )
				{
					// 移動していたかどうかで着地後の状態と再生するアニメーションを分岐する
					if( MoveFlag )
					{
						// 移動している場合は走り状態に
						Chara_PlayAnim( ch, 1 ) ;
						ch->State = 1 ;
					}
					else
					{
						// 移動していない場合は立ち止り状態に
						Chara_PlayAnim( ch, 4 ) ;
						ch->State = 0 ;
					}

					// 着地時はアニメーションのブレンドは行わない
					ch->AnimBlendRate = 1.0f ;
				}
			}
			else
			{
				// 床コリジョンに当たっていなくて且つジャンプ状態ではなかった場合は
				if( ch->State != 2 )
				{
					// ジャンプ中にする
					ch->State = 2 ;

					// ちょっとだけジャンプする
					ch->JumpPower = CHARA_FALL_UP_POWER ;

					// アニメーションは落下中のものにする
					Chara_PlayAnim( ch, 3 ) ;
				}
			}
		}
	}

	// 新しい座標を保存する
	ch->Position = NowPos ;

	// キャラクターのモデルの座標を更新する
	MV1SetPosition( ch->ModelHandle, ch->Position ) ;

	// 検出したキャラクターの周囲のポリゴン情報を開放する
	MV1CollResultPolyDimTerminate( HitDim ) ;
}