/********************************************************************/ /* font.c */ /* DebugForIPL2 */ /* */ /* Copyright (C) 2003-2004 NINTENDO Co.,Ltd. */ /********************************************************************/ /* フォント処理 $Log: font.c,v $ Revision 1.1 2004/08/31 06:20:24 Yosiokat Initial revision // **** old logs **** Revision 1.19 2004/08/25 02:21:40 Yosiokat ・1.14のコメントは間違いのため、再コミット。 ・small fix. Revision 1.18 2004/08/25 02:15:51 Yosiokat タグred_ipl2_2004_08_24_pp2_isdbg_fixの削除。 Revision 1.17 2004/08/20 11:35:29 Yosiokat small fix. Revision 1.16 2004/08/18 07:17:29 Yosiokat 上下LCDをターゲットにして、別個に初期化できるよう変更。 Revision 1.15 2004/08/17 07:52:03 Yosiokat ・SetTargetScreenSJISを追加して、上下LCDのどちらにも文字表示が可能になるよう変更。 Revision 1.14 2004/08/16 10:03:08 Yosiokat GetStrEntryで範囲外のhandleが与えられた際にNULLを返すよう変更。 Revision 1.13 2004/08/13 07:32:58 Yosiokat small fix. Revision 1.12 2004/08/13 04:33:18 Yosiokat small fix. Revision 1.11 2004/08/10 07:02:10 yosiokat small fix. Revision 1.10 2004/08/07 05:44:44 Yosiokat ・SJIS文字列表示関数を引数でハンドルを指定しない仕様に変更する。 ・上記変更に対応して、クリア関数も仕様変更。 Revision 1.9 2004/07/29 04:58:42 Yosiokat 構造体のパディングを明示的に追加。 Revision 1.8 2004/07/13 00:31:48 Yosiokat ・サブLCD側のVRAMを対象にするよう変更。 Revision 1.7 2004/06/15 13:09:10 Yosiokat ・MY_PrintfをOS_Printfに。 Revision 1.6 2004/06/06 06:28:24 Yosiokat OS_PrintfをOS_Printfに。 Revision 1.5 2004/06/06 02:39:31 Yosiokat SJISコード判定用の定数定義をfont.hに移動。 Revision 1.4 2004/05/31 11:53:23 yosiokat __DEBUGを__PRINTに変更。 Revision 1.3 2004/05/26 05:07:34 Yosiokat DrawStringSJISで空文字列を指定した際に異常動作するバグを修正。 Revision 1.2 2004/05/26 01:16:57 Yosiokat 文字制御をSJISベースに変更中。 Revision 1.1 2004/05/25 08:59:22 Yosiokat 文字列をSJISで制御するように変更。 */ #include #include "font.h" #include "data.h" // define data---------------------------------- #define SEARCH_ENTRY_MAX_NUM 128 // 処理が重くなるのを防ぐための、エントリのサーチ回数上限 #define NITRO_CHAR_SIZE 0x20 // NITRO標準キャラクタサイズ(4bitカラー) #define CHAR_CODE_OFFSET (SJIS_CHAR_VRAM_OFFSET / NITRO_CHAR_SIZE) // キャラナンバーをスクリーンに転送する際のオフセット(BG_CHAR_VRAM+0x4000から始めているので、オフセットは0x200) #define DRAW_CHAR_NUM_LIMIT (SJIS_CHAR_VRAM_SIZE / NITRO_CHAR_SIZE) // 1つの文字列で表示できるキャラクタ数の限界 #define HANDLE_INDEX 0x40000000 // フォント構成データ typedef struct FontComponent { u16 need_tate_dot; // 文字を表示するのに必要なキャラ単位のドット数 u16 tate_dot; // 文字キャラの縦ドット数 u16 yoko_dot; // 文字キャラの横ドット数 u16 org_char_size; // 文字キャラのbyteサイズ u32 org_row_size; // 文字キャラ u32 start_adr; // キャラクタバイナリのスタートアドレス u32 end_adr; // キャラクタバイナリのエンドアドレス }FontComponent; // VRAMキャラデータのメモリブロック動的確保リスト typedef struct CharAllocListTag CharAllocList; struct CharAllocListTag { CharAllocList *next; // 次のメモリブロック確保構造体へのポインタ u16 memTop; // キャラ割り当てテーブルcharAllocTblの占有ブロックの先頭ポイント u16 memNum; // 確保したメモリブロックの数 }CharAllocListTag; // SJIS文字列表示のためのVRAMエントリデータ typedef struct StrEntry { const FontComponent *font; // 表示するフォントの構成要素 u32 dataAddr; // データ元のアドレス(IDとして使用) u32 *charMemp; // 動的に確保したVRAMメモリブロックへのポインタ u16 charNum; // トータルのキャラ数 u16 drawPos; // 表示位置(BGスクリーンバッファの先頭からの2byteオフセット) }StrEntry; // フォントの文字間隔詰め展開用データ typedef struct FontPropotion { u16 *leftp; // 現在の左側フォントデータへのポインタ u16 *rightp; // 現在の右側フォントデータへのポインタ u16 h_offset; // 16x16ドット単位のキャラクタデータ内の現在の横オフセット u8 pad[2]; u32 buff16x16[2][16/2]; }FontPropotion; // インクリメント/インクリメントなしフラグ(SetScrDataで使用) typedef enum IncFlag { NO_INC, // インクリメントなし INC_1 // 1インクリメント }IncFlag; // extern data---------------------------- extern void _binary_f12han_dat(void); extern void _binary_f12han_dat_end(void); // function's prototype declaration------------- static void SetScrData(u16 code_top, StrEntry *sEntryp, IncFlag inc_flag); static u16 MeasureStringCharWidth(const u8 *str); static void SpreadStringCloser(u8 *str, StrEntry *sEntryp, u16 v_offset); static void SetFirstFont(u8 **strpp, u16 v_offset, FontPropotion *fontProp); static u8 * CloseFontChar(u8 **strpp, u16 v_offset, FontPropotion *fontProp); static u32 CalcCharCodeAddress(u8 **strpp, const FontComponent **font); static void SpreadFontZen(u16 bit0_color, u16 bit1_color, u8 *fromAdr, u32 *toAdr); static void InitStrEntryTable( StrEntry **sEntrypp ); static StrEntry *GetStrEntry( u16 handle ); static StrEntry **GetStrEntryAddress( u16 handle ); static int InsertStrEntry(u16 *handle, u16 charNum); static int InsertStrEntry2(u16 handle, u16 charNum); static u16 DeleteStrEntry( u16 handle); static BOOL GetEmptyStrEntry(u32 dataAddr, u16 *handlep); static u16 SearchStrEntry(u32 dataAddr); static u8 * HexToDecimalString(const void *hexp, u8 *strp, u16 figure, u16 size); static u8 * HexToString(const void *hexp, u8 *strp, u16 figure); static void InitAllocSystemSJIS( TargetScreen target ); static void *AllocMemoryFromVram( int size ); static void FreeMemoryToVram( void *p ); static u16 DrawStringSJIS_Core(u16 x, u16 y, u16 color, const void *strp, int handleIndex); static int CalcHandleIndex(u32 dataAddr, int index); // global variables----------------------------- // static variables----------------------------- static int font_init = 0; static TargetScreen targetScreen = BOTTOM_SCREEN; static const FontComponent *nowFontHan; static StrEntry *entryTblS[ STR_ENTRY_MAX_NUM ]; static StrEntry *entryTblM[ STR_ENTRY_MAX_NUM ]; static StrEntry **entryTblp; static u16 *bgBakp; // const data----------------------------------- const u16 tbl_ASCII_to_SJIS[0x100]; const FontComponent fontTypeTableHan[] = { { 16, 12, 6, 12, 14*0xbc, (u32)&_binary_f12han_dat, (u32)&_binary_f12han_dat_end}, }; // functions description------------------------ //---------------------------------------------- // API関数 //---------------------------------------------- // フォントAPIの初期化 void InitFont( TargetScreen target) { if( font_init & (0x01 << target ) ) { // ターゲットが初期すみならリターン return; } InitAllocSystemSJIS( target ); // ターゲットのVRAMアリーナ初期化 if( target == TOP_SCREEN ) { // ターゲットのエントリを初期化 InitStrEntryTable( &entryTblM[0] ); }else { InitStrEntryTable( &entryTblS[0] ); } if( font_init == 0 ) { // まだ何も初期化されていないなら、スクリーンを初期設定に。 SetTargetScreenSJIS( target ); } SetFont( (FontType)0 ); font_init |= 0x01 << target; } // 表示フォントの切り替え void SetFont(FontType font) { if(font >= FONT_TYPE_MAX) { font = (FontType)0; } nowFontHan = &fontTypeTableHan[font]; } // 表示ターゲットスクリーンの切り替え void SetTargetScreenSJIS( TargetScreen target ) { targetScreen = target; if( target == TOP_SCREEN ) { entryTblp = &entryTblM[0]; bgBakp = bgBakM; }else { entryTblp = &entryTblS[0]; bgBakp = bgBakS; } } // 指定されたSJIS文字列を表示する。(ハンドル指定なしでハンドル算出加算値付き) static u16 DrawStringSJIS_Core(u16 x, u16 y, u16 color, const void *strp, int handleIndex) { StrEntry *sEntryp; int newEntry; u16 handle; u16 charNum; u16 code; u16 v_offset = 1; // ※v_offsetは引数にすることもできる。 InitFont( targetScreen ); // 空文字列チェック if(*(u8 *)strp == 0x00) { return 0; } // 文字列表示に必要なキャラクタ数の測定 charNum = MeasureStringCharWidth((const u8 *)strp); if(charNum > DRAW_CHAR_NUM_LIMIT) { // 必要キャラクタ数が512以内ならメモリ確保。 OS_Printf("SJIS-draw: str length max over.\n"); return DSJIS_ERR_STR_LENGTH_TOO_LONG; } // ハンドル取得 if( !GetEmptyStrEntry( (u32)handleIndex, &handle ) ) { OS_Printf("SJIS-draw: error StrEntry get failed.\n"); return DSJIS_ERR_ENTRY_GET_FAILED; } // 文字列エントリの登録 newEntry = InsertStrEntry2( handle, charNum ); if(newEntry < 0) { OS_Printf("SJIS-draw: error StrEntry alloc failed.\n"); return DSJIS_ERR_ENTRY_ALLOC_FAILED; } sEntryp = GetStrEntry(handle); // エントリへのポインタを格納 sEntryp->dataAddr = (u32)handleIndex; // VRAMキャラメモリの動的確保 if(newEntry > 0) { sEntryp->charMemp = AllocMemoryFromVram( charNum * NITRO_CHAR_SIZE * 2 ); // ※縦も2キャラ分必要なので、NITRO_CHAR_SIZE*2 // OS_Printf("alloc charMemp = %x\n",sEntryp->charMemp); if( sEntryp->charMemp == NULL ) { // メモリ確保に失敗したら、エントリのメモリを解放してリターン OS_Printf("VRAM char memory alloc failed.\n"); OS_Free(sEntryp); return DSJIS_ERR_CHAR_ALLOC_FAILED; } } // 文字列エントリの登録 sEntryp->font = nowFontHan; // 現在のフォントタイプを格納 sEntryp->drawPos = (u16)(x + y * 0x20); // 表示場所を格納。 sEntryp->charNum = charNum; // 縦配置位置指定v_offsetの矯正 if(v_offset) { if(((nowFontHan->tate_dot & 0x07)== 0)) { // 縦8dot or 16dotの場合はv_offsetは0 v_offset = 0; }else { if( (16 - nowFontHan->tate_dot) < v_offset ) { // それ以外の時は、縦16dotに収まる範囲に矯正 v_offset = (u16)(16 - nowFontHan->tate_dot); } } } // 対象文字列のフォントデータをビット展開&キャラデータ詰めをおこなって、確保したVRAMキャラメモリに転送 SpreadStringCloser((u8 *)strp, sEntryp, v_offset); // スクリーンデータに今回の文字列のキャラナンバーを書き込み code = (u16)( (((u32)sEntryp->charMemp - (u32)G2_GetBG1CharPtr()) / NITRO_CHAR_SIZE) | color ); SetScrData(code, sEntryp, INC_1); return handle; } // ハンドルインデックスの算出 static int CalcHandleIndex(u32 dataAddr, int index) { if(index) { index += HANDLE_INDEX + (int)dataAddr; // インデックスを加算した場合は、他のデータのアドレスと被らないよう、NITROメモリマップ外になるようオフセットを加算。 }else { index = (int)dataAddr; } return index; } // 指定されたSJIS文字列を表示する。(ハンドル指定なし) u16 DrawStringSJIS(u16 x, u16 y, u16 color, const void *strp) { return DrawStringSJIS_Core( x, y, color, strp, (int)strp); // index = strp でCoreをコール } // 指定された値を16進数で表示する。(ハンドル指定なし版) u16 DrawHexSJIS(u16 x, u16 y, u16 color, const void *hexp, u16 figure) { u8 buff[16]; u8 *strp = HexToString(hexp, buff, figure); return DrawStringSJIS_Core(x, y, color, strp, (int)hexp); } // 指定された値を10進数で表示する。(ハンドル指定なし版) u16 DrawDecimalSJIS(u16 x, u16 y, u16 color, const void *hexp, u16 figure, u16 size) { u8 buff[16]; u8 *strp = HexToDecimalString(hexp, buff, figure, size); return DrawStringSJIS_Core(x, y, color, strp, (int)hexp); } // 指定されたSJIS文字列を表示する。(ハンドル指定なしでハンドル算出加算値付き) u16 DrawStringSJISEx(u16 x, u16 y, u16 color, const void *strp, int index) { index = CalcHandleIndex( (u32)strp, index); return DrawStringSJIS_Core( x, y, color, strp, index); // index を加算してCoreをコール } // 指定された値を16進数で表示する。(ハンドル指定なし版) u16 DrawHexSJISEx(u16 x, u16 y, u16 color, const void *hexp, u16 figure, int index) { u8 buff[16]; u8 *strp = HexToString(hexp, buff, figure); index = CalcHandleIndex( (u32)hexp, index); return DrawStringSJIS_Core(x, y, color, strp, index); } // 指定された値を10進数で表示する。(ハンドル指定なし版) u16 DrawDecimalSJISEx(u16 x, u16 y, u16 color, const void *hexp, u16 figure, u16 size, int index) { u8 buff[16]; u8 *strp = HexToDecimalString(hexp, buff, figure, size); index = CalcHandleIndex( (u32)hexp, index); return DrawStringSJIS_Core(x, y, color, strp, index); } // 指定コードから始まるスクリーンデータのセット static void SetScrData(u16 code_top, StrEntry *sEntryp, IncFlag inc_flag) { u16 i; u16 lastPos; u16 pos_l; u16 *buffp_l; u16 *buffp_h; lastPos = 0x800 >> 1; // バッファ最終位置 == BGスクリーンサイズ(0x800) pos_l = (u16)(sEntryp->drawPos + 0x0020); // 下8dotキャラクタ表示位置 buffp_h = bgBakp + sEntryp->drawPos; buffp_l = buffp_h + 0x0020; for(i = 0; i < sEntryp->charNum; i++) { *buffp_h++ = code_top; code_top += inc_flag; if(nowFontHan->need_tate_dot == 16) { // 必要縦ドットが16の場合(8ドット文字以外全部)、もう1キャラセット *buffp_l++ = code_top; } code_top += inc_flag; pos_l++; if(pos_l == lastPos) { break; } } } // 指定されたハンドルのSJIS文字列をクリアする。 void ClearStringSJIS_handle(u16 handle) { StrEntry *sEntryp; InitFont( targetScreen ); sEntryp = GetStrEntry(handle); if(sEntryp == NULL) { return; } // スクリーンデータのクリア SetScrData(0x0000, sEntryp, NO_INC); // キャラクタデータのクリア // MI_CpuClearFast(sEntryp->charMemp, sEntryp->charNum * NITRO_CHAR_SIZE * 2); // 動的に確保したVRAMキャラデータのクリア FreeMemoryToVram( sEntryp->charMemp ); // このエントリが確保していたキャラクタメモリの解放。 (void)DeleteStrEntry(handle); } // 指定されたデータアドレスで表示しているSJIS文字列をクリアする。 void ClearStringSJIS(void *datap) { u16 handle = SearchStrEntry( (u32)datap ); if( handle > STR_ENTRY_MAX_NUM ) { return; } ClearStringSJIS_handle(handle); } // 指定されたデータアドレスで表示しているSJIS文字列をクリアする。Ex系で描画したものを消す場合。 void ClearStringSJISEx(void *datap, int handleIndex) { u16 handle; handleIndex = CalcHandleIndex( (u32)datap, handleIndex); handle = SearchStrEntry( (u32)handleIndex ); if( handle > STR_ENTRY_MAX_NUM ) { return; } ClearStringSJIS_handle(handle); } // 現在登録されている全てのSJIS文字列をクリアする(動的メモリも全て解放) void ClearAllStringSJIS(void) { u16 handle; InitFont( targetScreen ); for(handle = 0; handle < STR_ENTRY_MAX_NUM; handle++) { if( GetStrEntry( handle ) != NULL) { ClearStringSJIS_handle(handle); } } } // 指定されたハンドルで表示されている文字列のカラーを変更。 u16 ChangeColorSJIS(u16 handle, u16 new_color) { int i; u16 *buffp_l; u16 *buffp_h; StrEntry *sEntryp = GetStrEntry( handle ); // エントリへのポインタを格納 if((handle > STR_ENTRY_MAX_NUM) || (sEntryp == NULL)) { return 0; } buffp_h = bgBakp + sEntryp->drawPos; buffp_l = buffp_h + 0x20; for(i = 0; i < sEntryp->charNum; i++) { *buffp_h = (u16)((*buffp_h & 0x0fff) | new_color); *buffp_l = (u16)((*buffp_l & 0x0fff) | new_color); buffp_h++; buffp_l++; } return 1; } //---------------------------------------------- // 文字列エントリテーブルの処理 //---------------------------------------------- // エントリテーブルの初期化 static void InitStrEntryTable( StrEntry **sEntrypp ) { u16 i; for(i = 0; i < STR_ENTRY_MAX_NUM; i++) { *sEntrypp++ = NULL; } } // 指定されたハンドルのStrEntryポインタを返す static StrEntry * GetStrEntry( u16 handle ) { if ( handle >= STR_ENTRY_MAX_NUM ) { return NULL; }else { // return entryTblS[ handle ]; return entryTblp[ handle ]; } } // 指定されたハンドルのStrEntryポインタへのポインタを返す static StrEntry ** GetStrEntryAddress( u16 handle ) { if ( handle >= STR_ENTRY_MAX_NUM ) { return NULL; }else { // return &entryTblS[ handle ]; return &entryTblp[ handle ]; } } // StrEntryの登録 static int InsertStrEntry(u16 *handle, u16 charNum) { StrEntry **sEntrypp = GetStrEntryAddress( *handle ); if(*handle >= STR_ENTRY_MAX_NUM) { return -1; }else if(*handle > 0) { if( *sEntrypp != NULL) { // 指定ハンドルに既にエントリがある場合は、確保メモリ量を新規メモリ量と比べて、 if( charNum > (*sEntrypp)->charNum ) { // 再確保が必要な場合は、メモリ解放→再確保を行う。 // OS_Printf("SJIS: same entry free to charMemory.\n"); // OS_Printf("free charMemp = %x\n",(*sEntrypp)->charMemp); SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア FreeMemoryToVram( (*sEntrypp)->charMemp ); // このエントリが確保していたキャラクタメモリの解放。 return 1; }else { if( charNum < (*sEntrypp)->charNum ) { SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア } return 0; // このエントリでは、キャラクタメモリを継続して使用 } } } // *handle == 0 // 指定ハンドルが0の時は新しいハンドルを確保 *handle = 0; sEntrypp = GetStrEntryAddress( *handle ); for( ; *handle < STR_ENTRY_MAX_NUM; (*handle)++ ) { if( *sEntrypp++ == NULL) { // NULLエントリを探す break; } } if(*handle == STR_ENTRY_MAX_NUM) { return -1; // NULLエントリが見つからなかったら、エラー終了。 } // StrEntryのメモリ確保 *sEntrypp = (StrEntry *)OS_Alloc( sizeof(StrEntry) ); if( *sEntrypp == NULL) { OS_Printf("StrEntry allocate failed.\n"); return -1; }else { return 1; } } // エントリ挿入処理2 static int InsertStrEntry2(u16 handle, u16 charNum) { StrEntry **sEntrypp = GetStrEntryAddress( handle ); if( *sEntrypp != NULL) { // 指定ハンドルに既にエントリがある場合は、確保メモリ量を新規メモリ量と比べて、 if( charNum > (*sEntrypp)->charNum ) { // 再確保が必要な場合は、メモリ解放→再確保を行う。 // OS_Printf("SJIS: same entry free to charMemory.\n"); // OS_Printf("free charMemp = %x\n",(*sEntrypp)->charMemp); SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア FreeMemoryToVram( (*sEntrypp)->charMemp ); // このエントリが確保していたキャラクタメモリの解放。 return 1; }else { if( charNum < (*sEntrypp)->charNum ) { SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア } return 0; // このエントリでは、キャラクタメモリを継続して使用 } } // StrEntryのメモリを新規確保 *sEntrypp = (StrEntry *)OS_Alloc( sizeof(StrEntry) ); if( *sEntrypp == NULL) { OS_Printf("StrEntry allocate failed.\n"); return -1; }else { return 1; } } // 指定されたハンドルのStrEntry要素をエントリテーブルから削除 static u16 DeleteStrEntry(u16 handle) { StrEntry **sEntrypp = GetStrEntryAddress( handle ); if( *sEntrypp == NULL) { return NULL; } OS_Free( *sEntrypp ); *sEntrypp = NULL; return handle; } // 空きエントリを探す(あんま効率よくない) static BOOL GetEmptyStrEntry(u32 dataAddr, u16 *handlep) { int i = SEARCH_ENTRY_MAX_NUM; // 処理が重くなるのを防ぐため、サーチ回数に制限を加える。 u16 handle = (u16)( (dataAddr >> 2) & (STR_ENTRY_MAX_NUM - 1) ); while(i--) { StrEntry *sEntryp = GetStrEntry( handle ); if( sEntryp == NULL ) { *handlep = handle; return TRUE; // 新規ハンドル位置確保 }else { if( sEntryp->dataAddr == dataAddr ) { *handlep = handle; return TRUE; // 既存ハンドル位置発見 } handle = (u16)( (handle + 1) & (STR_ENTRY_MAX_NUM - 1) ); } } return FALSE; } // 指定データのハンドルを探す(あんま効率よくない) static u16 SearchStrEntry(u32 dataAddr) { int i = SEARCH_ENTRY_MAX_NUM; // 処理が重くなるのを防ぐため、サーチ回数に制限を加える。 u16 handle = (u16)( (dataAddr >> 2) & (STR_ENTRY_MAX_NUM - 1) ); while(i--) { StrEntry *sEntryp = GetStrEntry( handle ); if(sEntryp != NULL) { if( sEntryp->dataAddr == dataAddr ) { return handle; // 既存ハンドル位置発見 } } handle = (u16)( (handle + 1) & (STR_ENTRY_MAX_NUM - 1) ); } return 0xffff; } //---------------------------------------------- // キャラクタVRAMの動的確保処理 //---------------------------------------------- // 文字列表示に必要なキャラクタ数の測定 static u16 MeasureStringCharWidth(const u8 *str) { u16 totalWidth = 0; // 文字列のトータルの横ドットサイズ u16 charNum = 0; // 文字列表示に必要なキャラクタ数 // 文字列のトータルの横ドットサイズを算出 while(*str) { // 各文字は SJIS か ASCII か? if( ((*str >= SJIS_HIGHER_CODE1_MIN) && (*str <= SJIS_HIGHER_CODE1_MAX)) || ((*str >= SJIS_HIGHER_CODE2_MIN) && (*str <= SJIS_HIGHER_CODE2_MAX)) ) { str += 2; // SJIS文字 totalWidth += nowFontHan->yoko_dot; }else { str++; // ASCII文字 totalWidth += nowFontHan->yoko_dot; } } // トータル横ドット数から、文字列の表示に必要なキャラクタ数を算出 charNum = (u16)(totalWidth >> 3); if(totalWidth & 0x0007) { charNum = (u16)(charNum + 1); } return charNum; } //---------------------------------------------- // フォントデータ→NITROキャラデータへの変換関数群 //---------------------------------------------- // 指定された文字列を指定メモリブロックに展開しながら転送(使用フォントによって文字詰めも行う) static void SpreadStringCloser(u8 *strp, StrEntry *sEntryp, u16 v_offset) { u32 charBuff[(NITRO_CHAR_SIZE * 4) / 4]; // 16x16キャラ2文字で4キャラ分のバッファ。(2文字展開して、文字詰めを行うため) u8 *charMemp; u8 *fromAdr; u16 i; u16 charNum; FontPropotion fontPro; // Spread target string char data to WRAM pool charNum = sEntryp->charNum; charMemp = (u8 *)sEntryp->charMemp; fontPro.h_offset = 0; fontPro.leftp = (u16 *)0x0; fontPro.rightp = (u16 *)0x0; while(1) { // 隣接する2つの1bitフォントデータを16x16ドットキャラクタ配列にロード if(fontPro.h_offset == 0) { SetFirstFont(&strp, v_offset, &fontPro); // 表示文字列を16x16ドット単位に区切った時に先頭にくるキャラクタをロード } fromAdr = CloseFontChar(&strp, v_offset, &fontPro); // 上記キャラクタに隣接するキャラクタをロード // ロードした1bitフォントデータを4bitNITROキャラデータに展開 SpreadFontZen(3, 1, fromAdr, (u32 *)charBuff); // キャラクタデータを4bitに展開。 // 展開したキャラデータをVRAMにコピー fromAdr = (u8 *)charBuff; for(i = 0; i < 2; i++) { // 生成した16x16ドット(4キャラ)分のデータを転送 MI_CpuCopyFast(fromAdr, charMemp, (NITRO_CHAR_SIZE * 2)); fromAdr += NITRO_CHAR_SIZE * 2; charMemp+= NITRO_CHAR_SIZE * 2; if(--charNum == 0) { return; } } } } // 最初のフォントデータをバッファにセット static void SetFirstFont(u8 **strpp, u16 v_offset, FontPropotion *fontProp) { u8 tate; u8 *fontAdr; u16 *firstp; const FontComponent *fontComp; if(**strpp == 0x00) { return; } fontAdr = (u8 *)CalcCharCodeAddress(strpp, &fontComp); // 今回の文字のコードから、フォントデータ格納アドレスを算出。 MI_CpuClearFast(fontProp->buff16x16[0], 64); // 16x16ドット単位の一時展開バッファのクリア firstp = (u16 *)fontProp->buff16x16[0] + v_offset; for(tate = 0; tate < fontComp->tate_dot - 1; tate++) { *firstp = (u16)(*fontAdr++ << 8); if(fontComp->yoko_dot > 8) { *firstp |= *fontAdr++; } firstp++; } fontProp->h_offset = fontComp->yoko_dot; fontProp->leftp = (u16 *)fontProp->buff16x16[0]; fontProp->rightp = (u16 *)fontProp->buff16x16[1]; } // 隣接するフォントデータをバッファにセット static u8 * CloseFontChar(u8 **strpp, u16 v_offset, FontPropotion *fontProp) { u8 tate; u8 *fontAdr; u16 *temp; u16 *leftp_tmp; u16 *rightp_tmp; const FontComponent *fontComp; while(fontProp->h_offset < 16) { if(**strpp == 0x00) { break; } fontAdr = (u8 *)CalcCharCodeAddress(strpp, &fontComp); // 今回の文字のコードから、フォントデータ格納アドレスを算出。 leftp_tmp = fontProp->leftp + v_offset; // フォントデータを横ドット詰めしながらロード rightp_tmp = fontProp->rightp + v_offset; for(tate=0; tate < fontComp->tate_dot - 1; tate++) { *rightp_tmp = (u16)(*fontAdr++ << 8); if(fontComp->yoko_dot > 8) { *rightp_tmp |= *fontAdr++; } *leftp_tmp |= *rightp_tmp >> fontProp->h_offset; *rightp_tmp <<= 16 - fontProp->h_offset; leftp_tmp++; rightp_tmp++; } fontProp->h_offset += fontComp->yoko_dot; } fontProp->h_offset -= 16; temp = fontProp->leftp; fontProp->leftp = fontProp->rightp; fontProp->rightp = temp; return (u8 *)temp; } // 文字コードに対応したフォントデータ格納アドレスを算出する。 static u32 CalcCharCodeAddress(u8 **strpp, const FontComponent **font) { u8 higher_code; u8 lower_code; u16 sjis_code; u32 adr; // 対象文字が SJIS or ASCII かを判定 higher_code = *(*strpp)++; if( ((higher_code >= SJIS_HIGHER_CODE1_MIN) && (higher_code <= SJIS_HIGHER_CODE1_MAX)) ||((higher_code >= SJIS_HIGHER_CODE2_MIN) && (higher_code <= SJIS_HIGHER_CODE2_MAX)) ) { // SJISか? lower_code = *(*strpp)++; *font = nowFontHan; }else { // ASCII sjis_code = tbl_ASCII_to_SJIS[higher_code]; higher_code = (u8)(sjis_code >> 8); lower_code = (u8)(sjis_code & 0x00ff); *font = nowFontHan; } // 文字コードからフォントデータアドレスを算出 if(higher_code <= SJIS_HIGHER_CODE1_MIN + 3) { higher_code -= 0x81; }else if(higher_code <= SJIS_HIGHER_CODE1_MIN + 6) { higher_code -= 0x83; }else if(higher_code <= SJIS_HIGHER_CODE1_MAX) { higher_code -= 0x84; }else if(higher_code >= SJIS_HIGHER_CODE2_MIN) { higher_code -= 0xc4; } if(lower_code < 0x80) { lower_code -= 0x40; }else { lower_code -= 0x41; } adr = (*font)->start_adr +((*font)->org_row_size) * higher_code +((*font)->org_char_size+2) * lower_code + 2; return adr; } // 指定バッファの1bitフォントデータを4bitNITROキャラデータに展開。 static void SpreadFontZen(u16 bit0_color, u16 bit1_color, u8 *fromAdr, u32 *toAdr) { int i; u8 tate; u8 yoko; u8 rd_data; u32 wr_data; u32 b0c; u32 b1c; u32 *toAdr_left; u32 *toAdr_right; toAdr_left = toAdr; toAdr_right = toAdr + 16; // toAdr + (16 * 4byte) for(tate = 0; tate < nowFontHan->need_tate_dot; tate++) { // キャラクタの縦ドット数だけ展開 // 左右それぞれの8dotキャラを展開 for(yoko = 0; yoko < 2; yoko++) { wr_data = 0x00000000; // ライトデータ初期化 if(tate < nowFontHan->tate_dot) { rd_data = *fromAdr++; // 左右8dotキャラの読み出し b0c = (u32)bit0_color; // bit0 のカラー b1c = (u32)bit1_color; // bit1 のカラー for(i = 0; i < 8; i++) { // 8dot分の各1bitの判定 if(rd_data & 0x80) { wr_data |= b1c; // "1"をカラー1へ }else { wr_data |= b0c; // "0"をカラー0へ } rd_data <<= 1; b0c <<= 4; b1c <<= 4; } } if(yoko==0) { *toAdr_right++ = wr_data; // 32bit書きこみ }else { *toAdr_left++ = wr_data; } } } } //---------------------------------------------- // MALLOCシステムの初期化 //---------------------------------------------- // VRAM上にヒープを作成。(アリーナにVRAMはないので、WRAM_MAIN, WRAM_SUBのアリーナで代用) static void InitAllocSystemSJIS( TargetScreen target ) { void* tempLo; OSHeapHandle hh; // VRAM上にヒープを作成 if( target == TOP_SCREEN ) { // メインLCD OS_SetArenaLo( OS_ARENA_WRAM_MAIN, (void *)VRAM_M_ARENA_LO ); OS_SetArenaHi( OS_ARENA_WRAM_MAIN, (void *)VRAM_M_ARENA_HI ); tempLo = OS_InitAlloc( OS_ARENA_WRAM_MAIN, OS_GetWramMainArenaLo(), OS_GetWramMainArenaHi(), 1 ); OS_SetArenaLo( OS_ARENA_WRAM_MAIN, tempLo ); hh = OS_CreateHeap( OS_ARENA_WRAM_MAIN, OS_GetWramMainArenaLo(), OS_GetWramMainArenaHi() ); if(hh < 0) OS_Panic( "ARM9-MAIN LCD: Fail to create heap...\n" ); OS_Printf( " arena lo = %x\n", OS_GetWramMainArenaLo() ); OS_Printf( "WRAM arena hi = %x\n", OS_GetWramMainArenaHi() ); hh = OS_SetCurrentHeap( OS_ARENA_WRAM_MAIN, hh ); }else { // BOTTOM_SCREEN // サブLCD OS_SetArenaLo( OS_ARENA_WRAM_SUB, (void *)VRAM_S_ARENA_LO ); OS_SetArenaHi( OS_ARENA_WRAM_SUB, (void *)VRAM_S_ARENA_HI ); tempLo = OS_InitAlloc( OS_ARENA_WRAM_SUB, OS_GetWramSubArenaLo(), OS_GetWramSubArenaHi(), 1 ); OS_SetArenaLo( OS_ARENA_WRAM_SUB, tempLo ); hh = OS_CreateHeap( OS_ARENA_WRAM_SUB, OS_GetWramSubArenaLo(), OS_GetWramSubArenaHi() ); if(hh < 0) OS_Panic( "ARM9-SUB LCD: Fail to create heap...\n" ); OS_Printf( "WRAM arena lo = %x\n", OS_GetWramSubArenaLo() ); OS_Printf( "WRAM arena hi = %x\n", OS_GetWramSubArenaHi() ); hh = OS_SetCurrentHeap( OS_ARENA_WRAM_SUB, hh ); } } // VRAMへのキャラメモリ確保 static void *AllocMemoryFromVram( int size ) { if ( targetScreen == TOP_SCREEN ) { return OS_AllocFromWramMain( size ); // ※縦も2キャラ分必要なので、NITRO_CHAR_SIZE*2 }else { return OS_AllocFromWramSub ( size ); // ※縦も2キャラ分必要なので、NITRO_CHAR_SIZE*2 } } // VRAMへのキャラメモリ解放 static void FreeMemoryToVram( void *p ) { if ( targetScreen == TOP_SCREEN ) { OS_FreeToWramMain( p ); }else { OS_FreeToWramSub( p ); } } //---------------------------------------------- // 16進データを文字列に変換 //---------------------------------------------- // メインメモリからでも大丈夫な形式での1byteのデータ読み出し。 __inline static u16 ReadByteHWBus(const void *srcp) { if((int)srcp & 0x00000001) return (u16)(*(u16 *)((int)srcp ^ 0x00000001) >> 8); else return (u16)(*(u16 *)(srcp) & 0x00ff); } // 16進データを10進文字列に変換 static u8 *HexToDecimalString(const void *hexp, u8 *strp, u16 figure, u16 size) { u16 i; u32 target = 0; for(i = 0; i < size; i++) { target |= ReadByteHWBus( ((u8 *)hexp)++ ) << (8 * i); } strp += figure; *strp-- = 0x00; for(i = 0; i < figure; i++) { CP_SetDiv32_32(target, 10); *strp-- = (u8 )(CP_GetDivRemainder32() + 0x30); target = (u32) CP_GetDivResult32(); } return (strp + 1); } // 16進データを16進文字列に変換 static u8 *HexToString(const void *hexp, u8 *strp, u16 figure) { u16 i; u8 hex; strp += figure; *strp-- = 0x00; for(i = 0; i < figure; i++){ hex = (u8)ReadByteHWBus(hexp); if(i & 0x01){ hex = (u8)( (hex >> 4) & 0x0f); ((u8 *)hexp)++; }else{ hex = (u8)( hex & 0x0f); } if(hex < 0x000a) hex += 0x30; else hex += 0x41 - 0x0a; *strp-- = hex; } return (strp + 1); } //---------------------------------------------- // ASCII -> SJIS 変換テーブル //---------------------------------------------- const u16 tbl_ASCII_to_SJIS[0x100] = { // 00 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, // 10 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, // 20 0x8140,0x8149,0x8168,0x81f2,0x8190,0x8193,0x8195,0x8166, 0x8169,0x816a,0x8196,0x817b,0x8143,0x817c,0x8144,0x815e, // 30 0x824f,0x8250,0x8251,0x8252,0x8253,0x8254,0x8255,0x8256, 0x8257,0x8258,0x8146,0x8147,0x8183,0x8181,0x8184,0x8148, // 40 0x8197,0x8260,0x8261,0x8262,0x8263,0x8264,0x8265,0x8266, 0x8267,0x8268,0x8269,0x826a,0x826b,0x826c,0x826d,0x826e, // 50 0x826f,0x8270,0x8271,0x8272,0x8273,0x8274,0x8275,0x8276, 0x8277,0x8278,0x8279,0x816d,0x818f,0x816e,0x814f,0x8151, // 60 0x8165,0x8281,0x8282,0x8283,0x8284,0x8285,0x8286,0x8287, 0x8288,0x8289,0x828a,0x828b,0x828c,0x828d,0x828e,0x828f, // 70 0x8290,0x8291,0x8292,0x8293,0x8294,0x8295,0x8296,0x8297, 0x8298,0x8299,0x829a,0x816f,0x8162,0x8170,0x8160,0x81fc, // 80 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, // 90 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, // a0 0x81fc,0x8142,0x8175,0x8176,0x8141,0x8145,0x8192,0x8340, 0x8342,0x8344,0x8346,0x8348,0x8383,0x8385,0x8387,0x8362, // b0 0x815b,0x8341,0x8343,0x8345,0x8347,0x8349,0x834a,0x834c, 0x834e,0x8350,0x8352,0x8354,0x8356,0x8358,0x835a,0x835c, // c0 0x835e,0x8360,0x8363,0x8365,0x8367,0x8369,0x836a,0x836b, 0x836c,0x836d,0x836e,0x8371,0x8374,0x8377,0x837a,0x837d, // d0 0x837e,0x837f,0x838a,0x8382,0x8384,0x8386,0x8388,0x8389, 0x838a,0x838b,0x838c,0x838d,0x838f,0x8393,0x814a,0x814b, // e0 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, // f0 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, };