mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
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
725 lines
28 KiB
C++
725 lines
28 KiB
C++
// 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 ) );
|
||
// パレット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;
|
||
}
|
||
}
|
||
}
|
||
}
|