/*---------------------------------------------------------------------------* Project: NintendoWare File: font_ResFont.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 14747 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include namespace nw { namespace font { namespace { /*!--------------------------------------------------------------------------* @brief オフセットで格納されているポインタを解決します。 @param[in,out] ptr 解決するポインタ。 @param[in] base オフセットの基準となるアドレス。 *---------------------------------------------------------------------------*/ template inline void ResolveOffset(T*& ptr, void* base) { ptr = reinterpret_cast( reinterpret_cast(base) + reinterpret_cast(ptr) ); } } // namespace /* ------------------------------------------------------------------------ コンストラクタ/デストラクタ ------------------------------------------------------------------------ */ ResFont::ResFont() { } ResFont::~ResFont() { if (!IsManaging(NULL)) { RemoveResource(); } } /* ------------------------------------------------------------------------ 構築 ------------------------------------------------------------------------ */ u32 ResFont::GetDrawBufferSize(const void* bfnt) { NN_POINTER_ASSERT(bfnt); NN_ALIGN_ASSERT(bfnt, GlyphDataAlignment); const FontTextureGlyph* pGlyph = NULL; const ut::BinaryFileHeader* fileHeader = reinterpret_cast(bfnt); //---- オフセット解決済みのフォントか? if (fileHeader->signature == BINFILE_SIG_FONT_RESOLEVED) { } else { //---- 正しいファイルヘッダを持っているか // サポートしてるバージョンかチェック if (! IsValidBinaryFile(fileHeader, BINFILE_SIG_FONT, FONT_FILE_VERSION, 2)) { // サポートしていない形式 NN_LOG("Invalid font resource."); return 0; } } // FontInfomation を探す const ut::BinaryBlockHeader* blockHeader = reinterpret_cast( reinterpret_cast(fileHeader) + fileHeader->headerSize ); int nBlocks = 0; while (nBlocks < fileHeader->dataBlocks) { NN_POINTER_ASSERT( blockHeader ); if (blockHeader->kind == BINBLOCK_SIG_TGLP) { pGlyph = reinterpret_cast( reinterpret_cast(blockHeader) + sizeof(*blockHeader) ); break; } blockHeader = reinterpret_cast( reinterpret_cast(blockHeader) + blockHeader->size ); nBlocks++; } if (pGlyph == NULL) { return 0; } return sizeof(internal::TextureObject) * pGlyph->sheetNum; } void* ResFont::SetDrawBuffer(void* buffer) { void *const prevBuffer = GetTextureObjectsBufferPtr(); if (prevBuffer == buffer) { return buffer; } if (NULL != prevBuffer) { DeleteTextureNames(); } SetTextureObjectsBufferPtr(buffer); if (NULL != buffer) { GenTextureNames(); } return prevBuffer; } bool ResFont::SetResource(void* bfnt) { NN_POINTER_ASSERT(bfnt); NN_ALIGN_ASSERT(bfnt, GlyphDataAlignment); FontInformation* pFontInfo = NULL; ut::BinaryFileHeader* fileHeader = reinterpret_cast(bfnt); //---- 既にリソースがセットされていないか if (! IsManaging(NULL)) { NN_LOG("Font resource already atached."); return false; } //---- オフセット解決済みのフォントか? if (fileHeader->signature == BINFILE_SIG_FONT_RESOLEVED) { // FontInfomation を探す ut::BinaryBlockHeader* blockHeader; int nBlocks = 0; blockHeader = reinterpret_cast( reinterpret_cast(fileHeader) + fileHeader->headerSize ); while (nBlocks < fileHeader->dataBlocks) { NN_POINTER_ASSERT( blockHeader ); if (blockHeader->kind == BINBLOCK_SIG_FINF) { pFontInfo = reinterpret_cast( reinterpret_cast(blockHeader) + sizeof(*blockHeader) ); break; } blockHeader = reinterpret_cast( reinterpret_cast(blockHeader) + blockHeader->size ); nBlocks++; } } else { //---- 正しいファイルヘッダを持っているか // サポートしてるバージョンかチェック if (! IsValidBinaryFile(fileHeader, BINFILE_SIG_FONT, FONT_FILE_VERSION, 2)) { // サポートしていない形式 NN_LOG("Invalid font resource."); return false; } // 再構築する pFontInfo = Rebuild(fileHeader); } if (pFontInfo == NULL) { return false; } SetResourceBuffer(bfnt, pFontInfo); return true; } void* ResFont::RemoveResource() { if (IsManaging(NULL)) { NN_LOG("ResFont::RemoveResource(): Res font is not loaded.\n"); return 0; } return RemoveResourceBuffer(); } FontInformation* ResFont::Rebuild(ut::BinaryFileHeader* fileHeader) { NN_POINTER_ASSERT(fileHeader); NN_ALIGN_ASSERT(fileHeader, GlyphDataAlignment); ut::BinaryBlockHeader* blockHeader; FontInformation* info = NULL; int nBlocks = 0; blockHeader = reinterpret_cast( reinterpret_cast(fileHeader) + fileHeader->headerSize ); while (nBlocks < fileHeader->dataBlocks) { NN_POINTER_ASSERT(blockHeader); switch (blockHeader->kind) { //-------------------------------------------------- // INFO ブロック case BINBLOCK_SIG_FINF: // INFOブロックは1つでなければならない NN_ASSERT(info == NULL); { info = reinterpret_cast( reinterpret_cast(blockHeader) + sizeof(*blockHeader) ); NN_ASSERT(info->fontType == FONT_TYPE_TEXTURE); NN_ASSERT(info->alterCharIndex != GLYPH_INDEX_NOT_FOUND); // pGlyph は必須 NN_NULL_ASSERT(info->pGlyph); ResolveOffset(info->pGlyph, fileHeader); NN_POINTER_ASSERT(info->pGlyph); // pWidth と pMap はなくても良い if (info->pWidth != NULL) { ResolveOffset(info->pWidth, fileHeader); NN_POINTER_ASSERT(info->pWidth); } if (info->pMap != NULL) { ResolveOffset(info->pMap, fileHeader); NN_POINTER_ASSERT(info->pMap); } } break; //-------------------------------------------------- // TGLP ブロック case BINBLOCK_SIG_TGLP: // TGLP ブロックも1つでなければならないが複数存在しても致命的ではない { FontTextureGlyph* glyph = reinterpret_cast( reinterpret_cast(blockHeader) + sizeof(*blockHeader) ); NN_NULL_ASSERT(glyph->sheetImage); ResolveOffset(glyph->sheetImage, fileHeader); NN_POINTER_ASSERT(glyph->sheetImage); //---- 32x32 の I4 が最小、1024x1024 の RGBA8 が最大 NW_FONT_MIN_ASSERT ( glyph->cellWidth, 1 ); NW_FONT_MIN_ASSERT ( glyph->cellHeight, 1 ); NW_FONT_MINMAX_ASSERT ( glyph->sheetSize, 32 * 32 / 2, 1024 * 1024 * 4 ); NW_FONT_MIN_ASSERT ( glyph->sheetNum, 1 ); NW_FONT_MIN_ASSERT ( glyph->sheetRow, 1 ); NW_FONT_MIN_ASSERT ( glyph->sheetLine, 1 ); NW_FONT_MINMAX_ASSERT ( glyph->sheetWidth, 32, 1024 ); NW_FONT_MINMAX_ASSERT ( glyph->sheetHeight, 32, 1024 ); } break; //-------------------------------------------------- // CWDHブロック case BINBLOCK_SIG_CWDH: { FontWidth* width = reinterpret_cast( reinterpret_cast(blockHeader) + sizeof(*blockHeader) ); NN_ASSERT( width->indexBegin <= width->indexEnd ); if (width->pNext != NULL) { ResolveOffset(width->pNext, fileHeader); NN_POINTER_ASSERT( width->pNext ); } } break; //-------------------------------------------------- // CMAPブロック case BINBLOCK_SIG_CMAP: { FontCodeMap* map = reinterpret_cast( reinterpret_cast(blockHeader) + sizeof(*blockHeader) ); NN_ASSERT( map->ccodeBegin <= map->ccodeEnd ); NN_ASSERT( (map->mappingMethod == FONT_MAPMETHOD_DIRECT) || (map->mappingMethod == FONT_MAPMETHOD_TABLE) || (map->mappingMethod == FONT_MAPMETHOD_SCAN) ); if (map->pNext != NULL) { ResolveOffset(map->pNext, fileHeader); NN_POINTER_ASSERT(map->pNext); } } break; //-------------------------------------------------- // GLGR ブロック case BINBLOCK_SIG_GLGR: { // ResFont では GLGR ブロックは参照しないので何もする必要はない } break; //-------------------------------------------------- // unknown default: NN_ASSERTMSG(false, "The font has unknown block('%c%c%c%c').", (blockHeader->kind >> 24) & 0xFF, (blockHeader->kind >> 16) & 0xFF, (blockHeader->kind >> 8) & 0xFF, (blockHeader->kind >> 0) & 0xFF ); return NULL; } blockHeader = reinterpret_cast( reinterpret_cast(blockHeader) + blockHeader->size ); nBlocks++; } //---- シグネチャを変更してオフセット解決済みにマークする fileHeader->signature = BINFILE_SIG_FONT_RESOLEVED; return info; } } // namespace font } // namespace nw