// IDBUT.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "IDBUT.h" //#include "IDBi.h" #include #include #include #include // TWL アイコンの変換のためのバッファ typedef struct { u8 tmpBuf[ TWL_ICON_WIDTH * TWL_ICON_HEIGHT * 3 ]; u8 nativeBuf[ TWL_ICON_WIDTH * TWL_ICON_HEIGHT * 3 ]; }SConvertBuf; enum IDB_TwlAlphaColor { IDB_TWL_ALPHA_COLOR_R = 235, IDB_TWL_ALPHA_COLOR_G = 235, IDB_TWL_ALPHA_COLOR_B = 235 }; // 内部関数 void IDBUT_ConvertTwl555To888( u8* pDst, const u8* pSrc, const u8* pPltt ); void IDBUT_Convert888To565( u16* pDst, const u8* pSrc, int width, int height ); void IDBUT_ConvertLineToNative( u8* pDst, const u8* pSrc, int width, int height ); void IDBUT_GetLegacyIconTexture( u16* pDst, const u8* pImage, const u8* pPltt, u8* workBuffer ); void IDBUT_SetBlock8( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ); void IDBUT_SetBlock4( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ); void IDBUT_SetBlock2( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ); int IDBUT_GetCtrLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ); int IDBUT_GetCtrLanguageIndexReceiverSide( IDB_Icon *icon, nn::cfg::CTR::CfgLanguageCode receiverLanguage ); int IDBUT_GetTwlLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ); ///////////////////////////////////////////////////////////////////////////////// // 関数定義 ///////////////////////////////////////////////////////////////////////////////// /*! @brief SystemMenuDataTitleを初期化します

@param[in/out] info 初期化する構造体 */ void IDBUT_InitSoftwareInfo( nn::CTR::SystemMenuDataTitle *info ) { memset( info->shortName, 0, sizeof(info->shortName) ); memset( info->longName, 0, sizeof(info->longName) ); memset( info->publisher, 0, sizeof(info->publisher) ); } /*! @brief アイコンデータを初期化します。

icon->dataはNULLに初期化されますので、
アプリケーションの側で実体を指し示すようにする必要があります。 @param[in/out] icon 初期化する構造体 */ void IDBUT_InitIcon( IDB_Icon *icon ) { int i; icon->key.programID = nn::CTR::INVALID_PROGRAM_ID; icon->key.remasterVersion = 0; memset( icon->key.padding, 0, sizeof( icon->key.padding ) ); icon->region = nn::CTR::BNR_REGION_JAPAN; memset( icon->rating, 0, sizeof(icon->rating) ); icon->matchMakeGameCode = 0; icon->matchMakeGameCodeBit= 0; icon->format = IDB_ICON_FORMAT_INVALID; for ( i=0; iinfo ); } icon->data = NULL; } /*! @brief アイコンデータから適切な言語のインデックスを返します

本体の設定言語のタイトルが無かった場合、代替の言語を表示しますが、
リージョンによって優先するべき言語が異なります。
この関数は、本体リージョンとユーザーの言語から、
表示するべき言語のインデックスを返します。 @param[in] icon 対象のIDB_Icon @param[in] region 本体リージョン @param[in] language ユーザーの言語 @return 表示するべきインデックスを返します。(nn::cfg::CTR::CfgLanguageCodeと同じ値です) */ int IDBUT_GetLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) { // これが返ることはないはず int ret = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; if( icon->format == IDB_ICON_FORMAT_CTR ) { ret = IDBUT_GetCtrLanguageIndex( icon, region, language ); } else if( icon->format == IDB_ICON_FORMAT_TWL || icon->format == IDB_ICON_FORMAT_NTR ) { ret = IDBUT_GetTwlLanguageIndex( icon, region, language ); } return ret; } /*! @brief 別の本体から受信したアイコンデータを使用する際の適切な言語のインデックスを返します

本体の設定言語のタイトルが無かった場合、代替の言語を表示しますが、
リージョンによって優先するべき言語が異なります。
この関数は、受信側本体リージョンとユーザーの言語から、
表示するべき言語のインデックスを返します。 @param[in] icon 対象のIDB_Icon @param[in] region 受信側本体リージョン @param[in] language 受信側ユーザーの言語 @return 表示するべきインデックスを返します。(nn::cfg::CTR::CfgLanguageCodeと同じ値です) */ int IDBUT_GetLanguageIndexReceiverSide( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) { // これが返ることはないはず int ret = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; if( icon->format == IDB_ICON_FORMAT_CTR ) { ret = IDBUT_GetCtrLanguageIndexReceiverSide( icon, language ); } else if( icon->format == IDB_ICON_FORMAT_TWL || icon->format == IDB_ICON_FORMAT_NTR ) { ret = IDBUT_GetTwlLanguageIndex( icon, region, language ); } return ret; } int IDBUT_GetCtrLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) { switch ( region ) { case nn::cfg::CTR::CFG_REGION_JAPAN: return nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; case nn::cfg::CTR::CFG_REGION_AMERICA: case nn::cfg::CTR::CFG_REGION_EUROPE: // CFG_REGION_AUSTRALIA case nn::cfg::CTR::CFG_REGION_TAIWAN: if ( icon->info[language].longName[0] != L'\0' && icon->info[language].shortName[0] != L'\0' ) return language; return nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; case nn::cfg::CTR::CFG_REGION_CHINA: return nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; case nn::cfg::CTR::CFG_REGION_KOREA: return nn::cfg::CTR::CFG_LANGUAGE_KOREAN; } return nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; // ここに来る事は無いはず } int IDBUT_GetCtrLanguageIndexReceiverSide( IDB_Icon *icon, nn::cfg::CTR::CfgLanguageCode language ) { if ( icon->info[language].longName[0] != L'\0' && icon->info[language].shortName[0] != L'\0' ) return language; return nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; } int IDBUT_GetTwlLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) { // これがそのまま返ることはない int ret = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; if ( icon->info[ language ].longName[ 0 ] != L'\0' ) { ret = language; } else { const int TWL_LANGUAGE_PRIORITY_JUET_NUM = 6; const int TWL_LANGUAGE_PRIORITY_CK_NUM = 8; int languagePriority[ TWL_LANGUAGE_PRIORITY_CK_NUM ]; int priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; memset( languagePriority, 0, sizeof( languagePriority ) ); switch( region ) { case nn::cfg::CTR::CFG_REGION_JAPAN: case nn::cfg::CTR::CFG_REGION_TAIWAN: priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; break; case nn::cfg::CTR::CFG_REGION_AMERICA: priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; break; case nn::cfg::CTR::CFG_REGION_EUROPE: case nn::cfg::CTR::CFG_REGION_AUSTRALIA: priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; break; case nn::cfg::CTR::CFG_REGION_CHINA: priorityMaxNum = TWL_LANGUAGE_PRIORITY_CK_NUM; languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; languagePriority[ 6 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; languagePriority[ 7 ] = nn::cfg::CTR::CFG_LANGUAGE_KOREAN; break; case nn::cfg::CTR::CFG_REGION_KOREA: priorityMaxNum = TWL_LANGUAGE_PRIORITY_CK_NUM; languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_KOREAN; languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; languagePriority[ 6 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; languagePriority[ 7 ] = nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; break; default: break; } // 優先順位順にタイトルが存在する言語を探す for( int i = 0; i < priorityMaxNum; ++i ) { int languageID = languagePriority[ i ]; if( icon->info[ languageID ].longName[ 0 ] != L'\0' ) { ret = languageID; break; } } } return ret; } int IDBUTi_GetLastIndexOfReturn( const wchar_t * const str, size_t len ) { for ( int i = len - 1; i>=0; i-- ) { if ( str[i]==L'\n' ) return i; } return -1; } /*! @brief IDB_IconDataからIDB_TextureDataへデータ形式を変換します

IDBで保存しているIDB_IconDataは48*48と24*24のテクスチャですが、
実際に表示する時はGPUの制約上、64*64と32*32にパディングする必要があります。
パディングを行ったフォーマットがIDB_TextureDataです。 @param[in] srcIcon 変換元のIDB_IconData @param[out] dstTex 変換先のIDB_TextureData */ void IDBUT_GetTextureFromIcon( IDB_TextureData* dstTex, const IDB_IconData* srcIcon ) { const IDB_IconData *src =(IDB_IconData *)srcIcon; for ( int y=0; ybig[ y * DATA_BLOCK_LENGTH * BIG_TEXTURE_BLOCK_WIDTH ], &src->big[ y * DATA_BLOCK_LENGTH * BIG_ICON_BLOCK_WIDTH ], DATA_BLOCK_SIZE * BIG_ICON_BLOCK_WIDTH ); // 鯣芧듣芽闣芣蛤벜뫧릧黣莻鯦몷꜊ memset( &dstTex->big[ y * DATA_BLOCK_LENGTH * BIG_TEXTURE_BLOCK_WIDTH + DATA_BLOCK_LENGTH * BIG_ICON_BLOCK_WIDTH ], 0xff, ((BIG_TEXTURE_WIDTH-BIG_ICON_WIDTH)/DATA_BLOCK_WIDTH)*DATA_BLOCK_SIZE ); } for ( int y=0; ylittle[ y * DATA_BLOCK_LENGTH * SMALL_TEXTURE_BLOCK_WIDTH ], &src->little[ y * DATA_BLOCK_LENGTH * SMALL_ICON_BLOCK_WIDTH ], DATA_BLOCK_SIZE * SMALL_ICON_BLOCK_WIDTH ); // 鯣芧듣芽闣芣蛤벜뫧릧黣莻鯦몷꜊ memset( &dstTex->little[ y * DATA_BLOCK_LENGTH * SMALL_TEXTURE_BLOCK_WIDTH + DATA_BLOCK_LENGTH * SMALL_ICON_BLOCK_WIDTH ], 0xff, ((SMALL_TEXTURE_WIDTH-SMALL_ICON_WIDTH)/DATA_BLOCK_WIDTH)*DATA_BLOCK_SIZE ); } // テクスチャフィルタ対策に一ドット縁取りをする const int rightEdgeIndex[8] = { 21, 23, 29, 31, 53, 55, 61, 63 }; // 8*8のブロックの右端のインデックス const int bottomEdgeIndex[8] = { 42, 43, 46, 47, 58, 59, 62, 63 }; // 8*8のブロックの下端のインデックス const int nextBlockOffsetX = 21; // ブロックを跨いだときの隣のドットのオフセット const int nextBlockOffsetY = 42; // ブロックを跨いだときの隣のドットのオフセット const int rightBBlockIndex[ BIG_ICON_BLOCK_HEIGHT] = { 5, 11, 17, 23, 29, 35 }; // ブロック単位での右端のインデックス(アイコン大) const int bottomBBlockIndex[BIG_ICON_BLOCK_WIDTH] = { 30, 31, 32, 33, 34, 35 }; // ブロック単位での下端のインデックス(アイコン大) const int rightSBlockIndex[ SMALL_ICON_BLOCK_HEIGHT] = { 2, 5, 8 }; // ブロック単位での右端のインデックス(アイコン小) const int bottomSBlockIndex[SMALL_ICON_BLOCK_WIDTH] = { 6, 7, 8 }; // ブロック単位での下端のインデックス(アイコン小) const int rightBBlockTexIndex[ BIG_ICON_BLOCK_HEIGHT] = { 6, 14, 22, 30, 38, 46 }; // ブロック単位での右端の隣のインデックス(テクスチャ大) const int bottomBBlockTexIndex[BIG_ICON_BLOCK_WIDTH] = { 48, 49, 50, 51, 52, 53 }; // ブロック単位での下端の隣のインデックス(テクスチャ大) const int rightSBlockTexIndex[ SMALL_ICON_BLOCK_HEIGHT] = { 3, 7, 11 }; // ブロック単位での右端の隣のインデックス(テクスチャ小) const int bottomSBlockTexIndex[SMALL_ICON_BLOCK_WIDTH] = { 12, 13, 14 }; // ブロック単位での下端の隣のインデックス(テクスチャ小) // 下 for ( int bx=0; bxbig[ bottomBBlockTexIndex[bx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] - nextBlockOffsetY ] = src->big[ bottomBBlockIndex[bx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] ]; } } for ( int sx=0; sxlittle[ bottomSBlockTexIndex[sx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] - nextBlockOffsetY ] = src->little[ bottomSBlockIndex[sx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] ]; } } // 右 for ( int by=0; bybig[ rightBBlockTexIndex[by] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] - nextBlockOffsetX ] = src->big[ rightBBlockIndex[by] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] ]; } } for ( int sy=0; sylittle[ rightSBlockTexIndex[sy] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] - nextBlockOffsetX ] = src->little[ rightSBlockIndex[sy] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] ]; } } } /*! @brief IDB_TextureDataからIDB_IconDataへデータ形式を変換します

IDBで保存しているIDB_IconDataは48*48と24*24のテクスチャですが、
実際に表示する時はGPUの制約上、64*64と32*32にパディングする必要があります。
パディングを行ったフォーマットがIDB_TextureDataです。 @param[in] srcTex 変換元のIDB_TextureData @param[out] dstIcon 変換先のIDB_IconData */ void IDBUT_GetIconFromTexture( IDB_IconData* dstIcon, const IDB_TextureData* srcTex ) { int y; IDB_IconData *dst =(IDB_IconData *)dstIcon; for ( y=0; ybig[y * DATA_BLOCK_LENGTH * BIG_ICON_BLOCK_WIDTH ], &srcTex->big[y * DATA_BLOCK_LENGTH * BIG_TEXTURE_BLOCK_WIDTH ], DATA_BLOCK_SIZE*BIG_ICON_BLOCK_WIDTH ); } for ( y=0; ylittle[y * DATA_BLOCK_LENGTH * SMALL_ICON_BLOCK_WIDTH ], &srcTex->little[y * DATA_BLOCK_LENGTH * SMALL_TEXTURE_BLOCK_WIDTH ], DATA_BLOCK_SIZE*SMALL_ICON_BLOCK_WIDTH ); } } /*! @brief IDB_IconDataのサイズを取得します。

@return IDB_IconDataのサイズを返します。 */ s32 IDBUT_GetIDB_IconDataSize(void) { return sizeof(IDB_IconData); } /*! @brief CTRのROMアイコンヘッダのnn::CTR::SystemMenuDataから、IDBで使用する形式のデータに変換します

      idbIconの中でsysMenuData内のデータを参照しますので、idbIconを使用している間はsysMenuDataを破棄する事はできません @param[out] idbIcon 出力先のIDB_Icon @param[in] key 変換元のIDB_Key @param[in] sysMenuData 変換元のSystemMenuData */ void IDBUT_GetIconFromSystemMenuData( IDB_Icon* idbIcon, const IDB_Key *key, nn::CTR::SystemMenuData* sysMenuData ) { const nn::CTR::SystemMenuDataHeader *header = &sysMenuData->header; if ( key!=NULL ) { memcpy( &idbIcon->key, key, sizeof(idbIcon->key) ); }else{ idbIcon->key.programID = nn::CTR::INVALID_PROGRAM_ID; idbIcon->key.remasterVersion = 0; } memset( idbIcon->key.padding, 0, sizeof( idbIcon->key.padding ) ); idbIcon->region = header->region; memcpy( idbIcon->rating, header->rating, sizeof( idbIcon->rating ) ); idbIcon->matchMakeGameCode = header->matchMakeGameCode; idbIcon->matchMakeGameCodeBit = header->matchMakeGameCodeBit; memcpy( idbIcon->info, header->title, sizeof(idbIcon->info) ); idbIcon->format = IDB_ICON_FORMAT_CTR; idbIcon->data = &sysMenuData->raw; } /*! @brief TWL/NTRのバナーファイルのnn::CTR::LegacyTwlBannerFileから、IDBで使用する形式のデータに変換します。       idbIconの中でlegacyBannerData内のデータを参照しますので、idbIconを使用している間はlegacyBannerDataを破棄する事はできません @param[out] idbIcon 出力先のIDB_Icon @param[in] key 変換元のIDB_Key @param[in] legacyBannerData 変換元のLegacyTwlBannerFile */ void IDBUT_GetIconFromLegacyBannerData( IDB_Icon* idbIcon, const IDB_Key *key, nn::CTR::LegacyTwlBannerFile* legacyBannerData ) { if ( key!=NULL ) { idbIcon->key = *key; }else{ idbIcon->key.programID = nn::CTR::INVALID_PROGRAM_ID; idbIcon->key.remasterVersion = 0; } memset( idbIcon->key.padding, 0, sizeof( idbIcon->key.padding ) ); idbIcon->region = nn::CTR::BNR_REGION_ALL; // TODO : NTRではいいとして、TWLのリージョンは? memset( idbIcon->rating, 0x80, sizeof( idbIcon->rating ) ); // TODO : レーティングは全部? idbIcon->matchMakeGameCode = 0; idbIcon->matchMakeGameCodeBit = 0; if ( legacyBannerData->h.platform == nn::CTR::NN_CTR_BANNER_PLATFORM_NTR ) { // NN_LOG("IDB_ICON_FORMAT_NTR\n"); idbIcon->format = IDB_ICON_FORMAT_NTR; idbIcon->ntrData = (IDB_NTRIconData *)&legacyBannerData->v1.image; // TODO: NTRのバナーデータはバージョン違いがありますが未対応です。 }else{ // NN_LOG("IDB_ICON_FORMAT_TWL\n"); idbIcon->format = IDB_ICON_FORMAT_TWL; idbIcon->twlData = (IDB_TWLIconData *)&legacyBannerData->anime; // TODO: TWLのバナーデータはバージョン違いがありますが未対応です。 } for ( int i=0; iinfo[i].longName, 0, sizeof(idbIcon->info[i].longName) ); memset( idbIcon->info[i].shortName, 0, sizeof(idbIcon->info[i].shortName) ); memset( idbIcon->info[i].publisher, 0, sizeof(idbIcon->info[i].publisher) ); wcsncpy( idbIcon->info[i].longName, (wchar_t *)legacyBannerData->v1.gameName[i], NN_CTR_BANNER_LANG_LENGTH); } int langNum = nn::CTR::NN_CTR_BANNER_LANG_NUM_V1; // 中国語のサポートがあるバージョンか? if( legacyBannerData->h.version >= NN_CTR_BANNER_CHINESE_SUPPORT_VER ) { // 中国語のタイトルを埋め込み for( int i = 0; i < nn::CTR::NN_CTR_BANNER_LANG_NUM_V2; ++i ) { int ofs = langNum + i; memset( idbIcon->info[ofs].longName, 0, sizeof(idbIcon->info[ofs].longName) ); memset( idbIcon->info[ofs].shortName, 0, sizeof(idbIcon->info[ofs].shortName) ); memset( idbIcon->info[ofs].publisher, 0, sizeof(idbIcon->info[ofs].publisher) ); wcsncpy( idbIcon->info[ofs].longName, (wchar_t *)legacyBannerData->v2.gameName[i], NN_CTR_BANNER_LANG_LENGTH); } langNum += nn::CTR::NN_CTR_BANNER_LANG_NUM_V2; if( legacyBannerData->h.version >= NN_CTR_BANNER_KOREAN_SUPPORT_VER ) { // 韓国語のタイトルを埋め込み for( int i = 0; i < nn::CTR::NN_CTR_BANNER_LANG_NUM_V3; ++i ) { int ofs = langNum + i; memset( idbIcon->info[ofs].longName, 0, sizeof(idbIcon->info[ofs].longName) ); memset( idbIcon->info[ofs].shortName, 0, sizeof(idbIcon->info[ofs].shortName) ); memset( idbIcon->info[ofs].publisher, 0, sizeof(idbIcon->info[ofs].publisher) ); wcsncpy( idbIcon->info[ofs].longName, (wchar_t *)legacyBannerData->v3.gameName[i], NN_CTR_BANNER_LANG_LENGTH); } langNum += nn::CTR::NN_CTR_BANNER_LANG_NUM_V3; } } // 残りの言語は全て0埋め for ( int i=langNum; iinfo[i].longName, 0, sizeof(idbIcon->info[i].longName) ); memset( idbIcon->info[i].shortName, 0, sizeof(idbIcon->info[i].shortName) ); memset( idbIcon->info[i].publisher, 0, sizeof(idbIcon->info[i].publisher) ); } } void IDBUT_GetTwlIconTextureByControlInfoNo( u16* dstTwlIconTexture, const nn::CTR::LegacyBannerAnime* bannerAnm, const u8 controlInfoNo, u8* workBuffer ) { u8 cellNo = bannerAnm->control[ controlInfoNo ].normal.cellNo; IDBUT_GetTwlIconTextureByCellNo( dstTwlIconTexture, bannerAnm, cellNo, workBuffer ); } void IDBUT_GetTwlIconTextureByCellNo( u16* dstTwlIconTexture, const nn::CTR::LegacyBannerAnime* bannerAnm, const u8 cellNo, u8* workBuffer ) { u8 plttNo = 0; IDBUT_GetLegacyIconTexture( dstTwlIconTexture, bannerAnm->image[ cellNo ], bannerAnm->pltt[ plttNo ], workBuffer ); } s32 IDBUT_GetWorkBufferSizeForConvertTwlIcon(void) { return 3 * TWL_ICON_WIDTH * TWL_ICON_HEIGHT * 2; } s32 IDBUT_GetTwlIconTextureSize(void) { return sizeof( u16 ) * TWL_ICON_WIDTH * TWL_ICON_HEIGHT; } void IDBUT_GetNtrIconTexture( u16* dstNtrIconTexture, const IDB_NTRIconDataRaw* ntrIconDataRaw, u8* workBuffer ) { IDBUT_GetLegacyIconTexture( dstNtrIconTexture, ntrIconDataRaw->image, ntrIconDataRaw->pltt, workBuffer ); } s32 IDBUT_GetWorkBufferSizeForConvertNtrIcon(void) { return IDBUT_GetWorkBufferSizeForConvertTwlIcon(); } s32 IDBUT_GetNtrIconTextureSize(void) { return IDBUT_GetTwlIconTextureSize(); } void IDBUT_GetLegacyIconTexture( u16* dstIconTexture, const u8* pImage, const u8* pPltt, u8* workBuffer ) { SConvertBuf* convBuf = reinterpret_cast(workBuffer); memset( convBuf->tmpBuf, 0, sizeof(convBuf->tmpBuf) ); memset( convBuf->nativeBuf, 0, sizeof(convBuf->nativeBuf) ); // NTR の bgr555 のバッファを bgr888 へ変換 IDBUT_ConvertTwl555To888( convBuf->tmpBuf, pImage, pPltt ); // bgr888 のバッファをネイティブフォーマットへ変換 IDBUT_ConvertLineToNative( convBuf->nativeBuf, convBuf->tmpBuf, TWL_ICON_WIDTH, TWL_ICON_HEIGHT ); // bgr888 のバッファを bgr565 のバッファへ変換 IDBUT_Convert888To565( dstIconTexture, convBuf->nativeBuf, TWL_ICON_WIDTH, TWL_ICON_HEIGHT ); } void IDBUT_ConvertTwl555To888( u8* pDst, const u8* pSrc, const u8* pPltt ) { // パレットを変換 u8 dstPltt[ NN_CTR_BANNER_PLTT_SIZE / 2 ][ 3 ]; memset( dstPltt, 0, sizeof( dstPltt ) ); // パレット0は抜きの色で、CTR 全体で統一されている dstPltt[ 0 ][ 0 ] = IDB_TWL_ALPHA_COLOR_B; dstPltt[ 0 ][ 1 ] = IDB_TWL_ALPHA_COLOR_G; dstPltt[ 0 ][ 2 ] = IDB_TWL_ALPHA_COLOR_R; for( int i = 1; i < NN_CTR_BANNER_PLTT_SIZE / 2; ++i ) { u16 color = *( (u16*)pPltt + i ); dstPltt[ i ][ 0 ] = (u8)( (u16)( (f64)( ( color >> 10 ) & 0x1f ) / 31.0 * 255.0 ) ); dstPltt[ i ][ 1 ] = (u8)( (u16)( (f64)( ( color >> 5 ) & 0x1f ) / 31.0 * 255.0 ) ); dstPltt[ i ][ 2 ] = (u8)( (u16)( (f64)( ( color >> 0 ) & 0x1f ) / 31.0 * 255.0 ) ); //NN_LOG("[%02x] %04x\n", i, color); } // 画像を変換 for( int i = 0; i < TWL_ICON_WIDTH * TWL_ICON_HEIGHT / 2; ++i ) { // ブロック単位(8×8)でどの位置か int blockX = ( i / 4 ) % 4; int blockY = i / 128; // ブロックの始めの数字 int start = 128 * blockY + 32 * blockX; // ブロックの始めからどの位置かで id を決定する int id = start + ( ( i % 32 ) % 4 ) + 4 * ( ( i / 16 ) % 8 ); int prev = 2 * i * 3; int next = ( 2 * i + 1 ) * 3; u8 plttPrev = ( pSrc[ id ] & 0x0f ); u8 plttNext = ( pSrc[ id ] & 0xf0 ) >> 4; //NN_LOG("[%d] %02x [%d] %02x\n", prev, plttPrev, next, plttNext); for( int j = 0; j < 3; ++ j ) { pDst[ prev + j ] = dstPltt[ plttPrev ][ j ]; pDst[ next + j ] = dstPltt[ plttNext ][ j ]; } } } void IDBUT_Convert888To565( u16* pDst, const u8* pSrc, int width, int height ) { for( int h = 0; h < height; ++h ) { for( int w = 0; w < width; ++w ) { u16 r = pSrc[3 * (h * width + w) + 0] >> 3; u16 g = pSrc[3 * (h * width + w) + 1] >> 2; u16 b = pSrc[3 * (h * width + w) + 2] >> 3; pDst[h * width + w] = ( ( r & 0x1f ) << 0 ) | ( ( g & 0x3f ) << 5 ) | ( ( b & 0x1f ) << 11 ); } } } void IDBUT_ConvertLineToNative( u8* pDst, const u8* pSrc, int width, int height ) { for( int h = 0; h < height; h += DATA_BLOCK_HEIGHT ) { for( int w = 0; w < width; w += DATA_BLOCK_WIDTH ) { IDBUT_SetBlock8( pDst, pSrc, width, height, w, h ); } } } void IDBUT_SetBlock8( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ) { for( int h = 0; h < 8; h += 4 ) { for( int w = 0; w < 8; w += 4 ) { IDBUT_SetBlock4( pDst, pSrc, width, height, posX + w, posY + h ); } } } void IDBUT_SetBlock4( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ) { for( int h = 0; h < 4; h += 2 ) { for( int w = 0; w < 4; w += 2 ) { IDBUT_SetBlock2( pDst, pSrc, width, height, posX + w, posY + h ); } } } void IDBUT_SetBlock2( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ) { NN_UNUSED_VAR( height ); static int dstW = 0; static int dstH = 0; if( posX == 0 && posY == 0) { dstW = 0; dstH = 0; } for( int h = 0; h < 2; ++h ) { for( int w = 0; w < 2; ++w ) { int dstPos = 3 * ( dstH * width + dstW ); int srcPos = 3 * ( ( posY + h ) * width + ( posX + w ) ); pDst[ dstPos + 0 ] = pSrc[ srcPos + 0 ]; pDst[ dstPos + 1 ] = pSrc[ srcPos + 1 ]; pDst[ dstPos + 2 ] = pSrc[ srcPos + 2 ]; ++dstW; if( dstW >= width ) { dstW = 0; ++dstH; } } } }