ctr_Repair/trunk/SkipFirstLaunch/idb/src/IDBUT.cpp
N2614 0d5bf9a14e UIG製のコードを追加
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@651 385bec56-5757-e545-9c3a-d8741f4650f1
2012-02-22 02:25:50 +00:00

725 lines
28 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// IDBUT.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "IDBUT.h"
//#include "IDBi.h"
#include <nn/assert.h>
#include <string.h>
#include <wchar.h>
#include <nn/CTR/ctr_ProgramId.h>
// 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を初期化します<BR><BR>
@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 アイコンデータを初期化します。<BR><BR>
icon->dataはNULLに初期化されますので、<BR>
アプリケーションの側で実体を指し示すようにする必要があります。
@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; i<IDB_LANGUAGE_MAX; i++ )
{
IDBUT_InitSoftwareInfo( icon->info );
}
icon->data = NULL;
}
/*!
@brief アイコンデータから適切な言語のインデックスを返します<BR><BR>
本体の設定言語のタイトルが無かった場合、代替の言語を表示しますが、<BR>
リージョンによって優先するべき言語が異なります。<BR>
この関数は、本体リージョンとユーザーの言語から、<BR>
表示するべき言語のインデックスを返します。
@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 別の本体から受信したアイコンデータを使用する際の適切な言語のインデックスを返します<BR><BR>
本体の設定言語のタイトルが無かった場合、代替の言語を表示しますが、<BR>
リージョンによって優先するべき言語が異なります。<BR>
この関数は、受信側本体リージョンとユーザーの言語から、<BR>
表示するべき言語のインデックスを返します。
@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へデータ形式を変換します<BR><BR>
IDBで保存しているIDB_IconDataは48*48と24*24のテクスチャですが、<BR>
実際に表示する時はGPUの制約上、64*64と32*32にパディングする必要があります。<BR>
パディングを行ったフォーマットが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; y<BIG_ICON_BLOCK_HEIGHT; y++ )
{
memcpy(
&dstTex->big[ 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; y<SMALL_ICON_BLOCK_HEIGHT; y++ )
{
memcpy(
&dstTex->little[ 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; bx<BIG_ICON_BLOCK_WIDTH; bx++ )
{
for ( int x=0; x<DATA_BLOCK_WIDTH; x++ )
{
dstTex->big[ bottomBBlockTexIndex[bx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] - nextBlockOffsetY ] =
src->big[ bottomBBlockIndex[bx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] ];
}
}
for ( int sx=0; sx<SMALL_ICON_BLOCK_WIDTH; sx++ )
{
for ( int x=0; x<DATA_BLOCK_WIDTH; x++ )
{
dstTex->little[ bottomSBlockTexIndex[sx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] - nextBlockOffsetY ] =
src->little[ bottomSBlockIndex[sx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] ];
}
}
// 右
for ( int by=0; by<BIG_ICON_BLOCK_HEIGHT; by++ )
{
for ( int y=0; y<DATA_BLOCK_HEIGHT; y++ )
{
dstTex->big[ rightBBlockTexIndex[by] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] - nextBlockOffsetX ] =
src->big[ rightBBlockIndex[by] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] ];
}
}
for ( int sy=0; sy<SMALL_ICON_BLOCK_HEIGHT; sy++ )
{
for ( int y=0; y<DATA_BLOCK_HEIGHT; y++ )
{
dstTex->little[ rightSBlockTexIndex[sy] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] - nextBlockOffsetX ] =
src->little[ rightSBlockIndex[sy] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] ];
}
}
}
/*!
@brief IDB_TextureDataからIDB_IconDataへデータ形式を変換します<BR><BR>
IDBで保存しているIDB_IconDataは48*48と24*24のテクスチャですが、<BR>
実際に表示する時はGPUの制約上、64*64と32*32にパディングする必要があります。<BR>
パディングを行ったフォーマットが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; y<BIG_ICON_BLOCK_HEIGHT; y++ )
{
memcpy(
&dst->big[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; y<SMALL_ICON_BLOCK_HEIGHT; y++ )
{
memcpy(
&dst->little[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のサイズを取得します。<BR><BR>
@return IDB_IconDataのサイズを返します。
*/
s32 IDBUT_GetIDB_IconDataSize(void)
{
return sizeof(IDB_IconData);
}
/*!
@brief CTRのROMアイコンヘッダのnn::CTR::SystemMenuDataから、IDBで使用する形式のデータに変換します<BR><BR>
      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; i<nn::CTR::NN_CTR_BANNER_LANG_NUM_V1; i++ )
{
memset( idbIcon->info[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; i<IDB_LANGUAGE_MAX; i++ )
{
memset( idbIcon->info[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<SConvertBuf*>(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 ) );
// パレットは抜きの色で、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 )
{
// ブロック単位(×)でどの位置か
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;
}
}
}
}