/*---------------------------------------------------------------------------* Project: Horizon File: gr_Utility.h Copyright (C)2010 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 29329 $ *---------------------------------------------------------------------------*/ #ifndef NN_GR_UTILITY_H_ #define NN_GR_UTILITY_H_ #include #include #include #include #include namespace nn { namespace gr { namespace CTR { //------------------------------------------------------------------------------ /*! @brief 3x4行列をwHzyxの順に逆転してコピーします。(ヘッダーあり) @param[in] dst 結果を書き込む先のポインタです。 @param[in] src 34行列です。 @param[in] header ヘッダです。 */ void CopyMtx34WithHeader( f32* dst, const nn::math::MTX34* src, bit32 header ); /*! @brief 4x4行列をwHzyxの順に逆転してコピーします。(ヘッダーあり) @param[in] dst 結果を書き込む先のポインタです。 @param[in] src 44行列です。 @param[in] header ヘッダです。 */ void CopyMtx44WithHeader( f32* dst, const nn::math::MTX44* src, bit32 header ); //------------------------------------------------------------------------------------ /*! @brief 34行列を頂点シェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] mtx34 34行列です。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandVS( bit32* command, u8 location, const nn::math::MTX34& mtx34 ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_FLOAT_ADDR ); CopyMtx34WithHeader( (f32*)command, &mtx34, PICA_CMD_HEADER_VS_F32( 3 ) ); return command + 14; } //------------------------------------------------------------------------------------ /*! @brief 44行列を頂点シェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] mtx44 44行列です。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandVS( bit32* command, u8 location, const nn::math::MTX44& mtx44 ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_FLOAT_ADDR ); CopyMtx44WithHeader( (f32*)command, &mtx44, PICA_CMD_HEADER_VS_F32( 4 ) ); return command + 18; } //------------------------------------------------------------------------------------ /*! @brief ベクトルを頂点シェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] vec4 4次元のベクトルです。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandVS( bit32* command, u8 location, const nn::math::VEC4& vec4 ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FLOAT_ADDR, 5 ); *command++ = nn::math::F32AsU32( vec4.w ); *command++ = nn::math::F32AsU32( vec4.z ); *command++ = nn::math::F32AsU32( vec4.y ); *command++ = nn::math::F32AsU32( vec4.x ); return command; } //------------------------------------------------------------------------------------ /*! @brief ベクトルの配列を頂点シェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] vec4 4次元のベクトルの配列です。 @param[in] num 配列のサイズです。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandVS( bit32* command, u8 location, const nn::math::VEC4 vec4[], const int num ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_FLOAT_ADDR ); *command++ = nn::math::F32AsU32( vec4[0].w ); *command++ = PICA_CMD_HEADER_VS_F32( num ); *command++ = nn::math::F32AsU32( vec4[0].z ); *command++ = nn::math::F32AsU32( vec4[0].y ); *command++ = nn::math::F32AsU32( vec4[0].x ); for ( int i = 1; i < num; ++i ) { *command++ = nn::math::F32AsU32( vec4[i].w ); *command++ = nn::math::F32AsU32( vec4[i].z ); *command++ = nn::math::F32AsU32( vec4[i].y ); *command++ = nn::math::F32AsU32( vec4[i].x ); } *command++ = 0; // padding return command; } //------------------------------------------------------------------------------------ /*! @brief 整数を頂点シェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] x x 座標の値です。 @param[in] y y 座標の値です。 @param[in] z z 座標の値です。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandVS( bit32* command, u8 location, u8 x, u8 y, u8 z ) { *command++ = PICA_CMD_DATA_VS_INT( x, y, z ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_INT0 + location ); return command; } //------------------------------------------------------------------------------------ /*! @brief 34行列をジオメトリシェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] mtx34 34行列です。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandGS( bit32* command, u8 location, const nn::math::MTX34& mtx34 ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_FLOAT_ADDR ); CopyMtx34WithHeader( (f32*)command, &mtx34, PICA_CMD_HEADER_GS_F32( 3 ) ); return command + 14; } //------------------------------------------------------------------------------------ /*! @brief 44行列をジオメトリシェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] mtx44 44行列です。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandGS( bit32* command, u8 location, const nn::math::MTX44& mtx44 ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_FLOAT_ADDR ); CopyMtx44WithHeader( (f32*)command, &mtx44, PICA_CMD_HEADER_GS_F32( 4 ) ); return command + 18; } //------------------------------------------------------------------------------------ /*! @brief ベクトルをジオメトリシェーダのユニフォームにセットするコマンドを生成します. @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] vec4 4次元のベクトルです。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandGS( bit32* command, u8 location, const nn::math::VEC4& vec4 ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_BURSTSEQ( PICA_REG_GS_FLOAT_ADDR, 5 ); *command++ = nn::math::F32AsU32( vec4.w ); // a *command++ = nn::math::F32AsU32( vec4.z ); // b *command++ = nn::math::F32AsU32( vec4.y ); // g *command++ = nn::math::F32AsU32( vec4.x ); // r return command; } //------------------------------------------------------------------------------------ /*! @brief ベクトルの配列をジオメトリシェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] vec4 4次元のベクトルの配列です。 @param[in] num 配列のサイズです。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandGS( bit32* command, u8 location, const nn::math::VEC4 vec4[], const int num ) { *command++ = 0x80000000 | location; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_FLOAT_ADDR ); *command++ = nn::math::F32AsU32( vec4[0].w ); *command++ = PICA_CMD_HEADER_GS_F32( num ); *command++ = nn::math::F32AsU32( vec4[0].z ); *command++ = nn::math::F32AsU32( vec4[0].y ); *command++ = nn::math::F32AsU32( vec4[0].x ); for ( int i = 1; i < num; ++i ) { *command++ = nn::math::F32AsU32( vec4[i].w ); *command++ = nn::math::F32AsU32( vec4[i].z ); *command++ = nn::math::F32AsU32( vec4[i].y ); *command++ = nn::math::F32AsU32( vec4[i].x ); } *command++ = 0; // padding return command; } //------------------------------------------------------------------------------------ /*! @brief 整数をジオメトリシェーダのユニフォームにセットするコマンドを生成します。 @param[in] command 描画コマンドの書き込み先の先頭アドレスです。 @param[in] location レジスタの場所です。 @param[in] x x 座標の値です。 @param[in] y y 座標の値です。 @param[in] z z 座標の値です。 @return 書き込まれた描画コマンドの終端の次のアドレスを返します。 */ inline bit32* MakeUniformCommandGS( bit32* command, u8 location, u8 x, u8 y, u8 z ) { *command++ = PICA_CMD_DATA_GS_INT( x, y, z ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_INT0 + location ); return command; } //------------------------------------------------------------------------------------ /*! @brief float32 を u8 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です。 */ inline u8 FloatToUnsignedByte( f32 val ) { return ( u8 )( 0.5f + ( val < 0.f ? 0.f : ( 1.f < val ? 1.f : val ) ) * ( 0xff ) ); } //------------------------------------------------------------------------------------ /*! @brief float32 を クランプせずに u8 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u8 FloatToUnsignedByteNoClamp( f32 val ) { return ( u8 )( 0.5f + val * 0xff ); } //------------------------------------------------------------------------------------ /*! @brief float32 から float16 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u16 Float32ToFloat16( f32 val ) { static const int bias_ = 128 - (1 << (5 - 1)); u32 uval_ = *(u32*)&val; int e_ = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0; if (e_ >= 0) { return ( u16 )( ((uval_ & 0x7fffff) >> (23 - 10)) | (e_ << 10) | ((uval_ >> 31) << (10 + 5)) ); } return ( u16 )((uval_ >> 31) << (10 + 5)); } //------------------------------------------------------------------------------------ /*! @brief float32 から float24 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToFloat24( f32 val ) { static const int bias_ = 128 - (1 << (7 - 1)); u32 uval_ = *(unsigned*)&val; s32 e_ = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0; return e_ >= 0 ? ((uval_ & 0x7fffff) >> (23 - 16)) | (e_ << 16) | ((uval_ >> 31) << (16 + 7)) : ((uval_ >> 31) << (16 + 7)); } //------------------------------------------------------------------------------------ /*! @brief float32 から float20 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToFloat20( f32 val ) { static const int bias_ = 128 - (1 << (7 - 1)); u32 uval_ = *(unsigned*)&val; s32 e_ = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0; return e_ >= 0 ? ((uval_ & 0x7fffff) >> (23 - 12)) | (e_ << 12) | ((uval_ >> 31) << (12 + 7)) : ((uval_ >> 31) << (12 + 7)); } //------------------------------------------------------------------------------------ /*! @brief float32 から float31 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToFloat31( f32 val ) { unsigned uval_, m_; int e_; float f_ = val; static const int bias_ = 128 - (1 << (7 - 1)); uval_ = *(unsigned*)&f_; e_ = (uval_ & 0x7fffffff) ? (((uval_ >> 23) & 0xff) - bias_) : 0; m_ = (uval_ & 0x7fffff) >> (23 - 23); return e_ >= 0 ? m_ | (e_ << 23) | ((uval_ >> 31) << (23 + 7)) : ((uval_ >> 31) << (23 + 7)); } //------------------------------------------------------------------------------------ /*! @brief float32 から 符号なし fixed24 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToUnsignedFix24( f32 val ) { unsigned v_ = *(unsigned*)&val; if (val <= 0 || (v_ & 0x7f800000) == 0x7f800000) { return 0; } else { val *= 1 << (24 - 0); if ( val >= (1 << 24) ) { return (1 << 24) - 1; } else { return (unsigned)(val); } } } //------------------------------------------------------------------------------------ /*! @brief float32 から 符号なし fixed16 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToUnsignedFix16( f32 val ) { unsigned v_ = *(unsigned*)&val; if (val <= 0 || (v_ & 0x7f800000) == 0x7f800000) { return 0; } else { val *= 1 << (16 - 0); if ( val >= (1 << 16) ) { return (1 << 16) - 1; } else { return (unsigned)( val ); } } } //------------------------------------------------------------------------------------ /*! @brief float32 から 符号あり fixed16 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u16 Float32ToFix16( f32 val ) { unsigned v_ = *(unsigned*) &val; if ( (val == 0.f) || ( (v_ & 0x7f800000) == 0x7f800000 ) ) { return 0; } else { val += 0.5f * (1 << 4); val *= 1 << (16 - 4); if (val < 0) { val = 0; } else if (val >= (1 << 16)) { val = (1 << 16) - 1; } if (val >= (1 << (16 - 1))) { return (unsigned)(val - (1 << (16 - 1))); } else { return (unsigned)(val + (1 << (16 - 1))); } } } //------------------------------------------------------------------------------------ /*! @brief float32 から 符号なし fixed12 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToUnsignedFix12( f32 val ) { unsigned v_ = *(unsigned*)&val; if( val <= 0 || (v_ & 0x7f800000) == 0x7f800000 ) { return 0; } else { unsigned uval_; val *= 1 << (12 - 0); if (val >= (1 << 12)) { uval_ = (1 << 12) - 1; } else { uval_ = (unsigned)(val); } return uval_; } } //------------------------------------------------------------------------------------ /*! @brief float32 から 符号あり fixed12 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToFix12( f32 val ) { unsigned v_ = *(unsigned*)&val; if( val == 0.f || (v_ & 0x7f800000) == 0x7f800000 ) return 0; int ret; val *= (1 << (12 - 1)); if( val < 0 ) { ret = 1 << (12 - 1); val = -val; } else ret = 0; if( val >= (1 << (12 - 1)) ) val = (1 << (12 - 1)) - 1; ret |= (unsigned)(val); return ret; } /*! @brief float32 から fixed12 ( fraction 11) に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToFix12Fraction11( f32 val ) { unsigned v_ = *(unsigned*)&val; if (val == 0.f || (v_ & 0x7f800000) == 0x7f800000) { return 0; } else { val += 0.5f * (1 << 1); val *= 1 << (12 - 1); if (val < 0) { val = 0; } else if (val >= (1 << 12)) { val = (1 << 12) - 1; } if (val >= (1 << (12 - 1))) { return (unsigned)(val - (1 << (12 - 1))); } else { return (unsigned)(val + (1 << (12 - 1))); } } } //------------------------------------------------------------------------------------ /*! @brief float32 から fixed13 ( fraction 8) に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToFix13Fraction8( f32 val ) { unsigned v_ = *(unsigned*)&val; if ( ( val == 0.0f ) || ( (v_ & 0x7f800000) == 0x7f800000 ) ) { return 0; } val += 0.5f * (1 << 5); val *= 1 << (13 - 5); if (val < 0) { val = 0; } else if (val >= (1 << 13)) { val = (1 << 13) - 1; } return (val >= (1 << (13 - 1))) ? (unsigned)(val - (1 << (13 - 1))) : (unsigned)(val + (1 << (13 - 1))); } //------------------------------------------------------------------------------------ /*! @brief float32 から fixed11 ( fraction 8) に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToFix13Fraction11( f32 val ) { unsigned v_ = *(unsigned*)&val; if( val == 0.f || (v_ & 0x7f800000) == 0x7f800000 ) return 0; val += 0.5f * (1 << 2); val *= 1 << (13 - 2); if (val < 0) val = 0; else if (val >= (1 << 13)) val = (1 << 13) - 1; return (val >= (1 << (13 - 1))) ? (unsigned)(val - (1 << (13 - 1))) : (unsigned)(val + (1 << (13 - 1))); } //------------------------------------------------------------------------------------ /*! @brief float32 から 符号無し fixed11 に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u32 Float32ToUnsignedFix11( f32 val ) { unsigned v_ = *(unsigned*)&val; if( val <= 0 || (v_ & 0x7f800000) == 0x7f800000 ) return 0; unsigned uval_; val *= 1 << (11 - 0); if (val >= (1 << 11)) uval_ = (1 << 11) - 1; else uval_ = (unsigned)(val); return uval_; } //------------------------------------------------------------------------------------ /*! @brief float32 から fixed8 ( 7bits fraction ) に変換します。 @param[in] val 変換前の値です。 @return 変換後の値です */ inline u8 Float32ToFix8Fraction7( f32 val ) { unsigned v_ = *(unsigned*)&val; if (val == 0.f || (v_ & 0x7f800000) == 0x7f800000) { return 0; } else { val += 0.5f * (1 << 1); val *= 1 << (8 - 1); if (val < 0) { val = 0; } else if (val >= (1 << 8)) { val = (1 << 8) - 1; } if (val >= (1 << (8 - 1))) { return (unsigned)(val - (1 << (8 - 1))); } else { return (unsigned)(val + (1 << (8 - 1))); } } } //------------------------------------------------------------------------------------ /*! @brief 頂点配列の型から、バイトサイズを求めます。 @param[in] type 頂点配列の型です。 @return バイトサイズです。 */ inline u32 PicaDataVertexAttrTypeToByteSize( const PicaDataVertexAttrType type ) { switch ( type ) { case PICA_DATA_SIZE_1_BYTE : return 1 * sizeof( s8 ); case PICA_DATA_SIZE_1_UNSIGNED_BYTE : return 1 * sizeof( u8 ); case PICA_DATA_SIZE_1_SHORT : return 1 * sizeof( s16 ); case PICA_DATA_SIZE_1_FLOAT : return 1 * sizeof( f32 ); case PICA_DATA_SIZE_2_BYTE : return 2 * sizeof( s8 ); case PICA_DATA_SIZE_2_UNSIGNED_BYTE : return 2 * sizeof( u8 ); case PICA_DATA_SIZE_2_SHORT : return 2 * sizeof( s16 ); case PICA_DATA_SIZE_2_FLOAT : return 2 * sizeof( f32 ); case PICA_DATA_SIZE_3_BYTE : return 3 * sizeof( s8 ); case PICA_DATA_SIZE_3_UNSIGNED_BYTE : return 3 * sizeof( u8 ); case PICA_DATA_SIZE_3_SHORT : return 3 * sizeof( s16 ); case PICA_DATA_SIZE_3_FLOAT : return 3 * sizeof( f32 ); case PICA_DATA_SIZE_4_BYTE : return 4 * sizeof( s8 ); case PICA_DATA_SIZE_4_UNSIGNED_BYTE : return 4 * sizeof( u8 ); case PICA_DATA_SIZE_4_SHORT : return 4 * sizeof( s16 ); case PICA_DATA_SIZE_4_FLOAT : return 4 * sizeof( f32 ); } return 0; } } // namespace CTR } // namespace gr } // namespace nn #endif // NN_GR_UTILITY_H_