/*---------------------------------------------------------------------------* Project: NintendoWare File: font_ResFontBase.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: 23461 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #if defined(NW_PLATFORM_CTR) #include #endif #include #include namespace nw { namespace font { namespace { enum { CMD_TEX_NEAREST = 0, CMD_TEX_LINEAR = 1 }; #define NW_FONT_COMMAND_TEX_WRAP_FILTER( magFilter, minFilter ) \ ( (magFilter) << 1 | (minFilter) << 2 | ( 0/*isETC1*/ ? 2 : 0 ) << 4 \ | 0/*wrapT*/ << 8 | 0/*wrapS*/ << 12 \ | 0/*minFilter2*/ << 24 ) } // namespace /* ------------------------------------------------------------------------ コンストラクタ/デストラクタ ------------------------------------------------------------------------ */ ResFontBase::ResFontBase() : m_pResource(NULL), m_pFontInfo(NULL), m_pTexObjs(NULL), m_LastCharCode(0), m_LastGlyphIndex(GLYPH_INDEX_NOT_FOUND) { EnableLinearFilter(true, true); // m_Filter } ResFontBase::~ResFontBase() { } /* ------------------------------------------------------------------------ 構築/破棄 ------------------------------------------------------------------------ */ void ResFontBase::SetResourceBuffer( void* pUserBuffer, FontInformation* pFontInfo ) { NN_POINTER_ASSERT(pUserBuffer); NN_POINTER_ASSERT(pFontInfo); NN_ASSERT(m_pResource == NULL); NN_ASSERT(m_pFontInfo == NULL); m_pResource = pUserBuffer; m_pFontInfo = pFontInfo; } void* ResFontBase::RemoveResourceBuffer() { // テクスチャ名の削除 // m_pResourceが指す内容に依存するので // m_pResourceをクリアする前に行う。 if (NULL != m_pTexObjs) { DeleteTextureNames(); m_pTexObjs = 0; } void* pUserData = m_pResource; m_pResource = NULL; m_pFontInfo = NULL; return pUserData; } /* ------------------------------------------------------------------------ フォント全体情報アクセサ ------------------------------------------------------------------------ */ int ResFontBase::GetWidth() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->width; } int ResFontBase::GetHeight() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->height; } int ResFontBase::GetAscent() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->ascent; } int ResFontBase::GetDescent() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->height - m_pFontInfo->ascent; } int ResFontBase::GetBaselinePos() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->pGlyph->baselinePos; } int ResFontBase::GetCellHeight() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->pGlyph->cellHeight; } int ResFontBase::GetCellWidth() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->pGlyph->cellWidth; } int ResFontBase::GetMaxCharWidth() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->pGlyph->maxCharWidth; } Font::Type ResFontBase::GetType() const { return TYPE_RESOURCE; } TexFmt ResFontBase::GetTextureFormat() const { NN_POINTER_ASSERT(m_pFontInfo); return static_cast(m_pFontInfo->pGlyph->sheetFormat); } int ResFontBase::GetLineFeed() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->linefeed; } const CharWidths ResFontBase::GetDefaultCharWidths() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->defaultWidth; } void ResFontBase::SetDefaultCharWidths( const CharWidths& widths ) { NN_POINTER_ASSERT(m_pFontInfo); NN_POINTER_ASSERT( &widths ); m_pFontInfo->defaultWidth = widths; } bool ResFontBase::SetAlternateChar( CharCode c ) { NN_POINTER_ASSERT(m_pFontInfo); GlyphIndex index = FindGlyphIndex(c); if (index != GLYPH_INDEX_NOT_FOUND) { m_pFontInfo->alterCharIndex = index; return true; } return false; } void ResFontBase::SetLineFeed( int linefeed ) { NN_POINTER_ASSERT(m_pFontInfo); NW_FONT_MINMAX_ASSERT(linefeed, SCHAR_MIN, SCHAR_MAX); m_pFontInfo->linefeed = static_cast(linefeed); } /* ------------------------------------------------------------------------ 文字単体情報アクセサ ------------------------------------------------------------------------ */ int ResFontBase::GetCharWidth( CharCode c ) const { return GetCharWidths(c).charWidth; } const CharWidths ResFontBase::GetCharWidths( CharCode c ) const { GlyphIndex index = GetGlyphIndex(c); return GetCharWidthsFromIndex(index); } void ResFontBase::GetGlyph( Glyph* glyph, CharCode c ) const { GlyphIndex index = GetGlyphIndex(c); GetGlyphFromIndex(glyph, index); } bool ResFontBase::HasGlyph( CharCode c ) const { return ( GLYPH_INDEX_NOT_FOUND != FindGlyphIndex(c) ); } /* ------------------------------------------------------------------------ 文字ストリーム ------------------------------------------------------------------------ */ CharacterCode ResFontBase::GetCharacterCode() const { NN_POINTER_ASSERT(m_pFontInfo); return static_cast(m_pFontInfo->characterCode); } /* ------------------------------------------------------------------------ グリフインデックス ------------------------------------------------------------------------ */ ResFontBase::GlyphIndex ResFontBase::GetGlyphIndex( CharCode c ) const { NN_POINTER_ASSERT(m_pFontInfo); GlyphIndex index = FindGlyphIndex(c); return (index != GLYPH_INDEX_NOT_FOUND) ? index: m_pFontInfo->alterCharIndex; } ResFontBase::GlyphIndex ResFontBase::FindGlyphIndex( CharCode c ) const { NN_POINTER_ASSERT(m_pFontInfo); if (c == m_LastCharCode) { return m_LastGlyphIndex; } m_LastCharCode = c; const FontCodeMap* pMap = m_pFontInfo->pMap; while (pMap != NULL) { if (pMap->ccodeBegin <= c && c <= pMap->ccodeEnd) { m_LastGlyphIndex = FindGlyphIndex(pMap, c); return m_LastGlyphIndex; } pMap = pMap->pNext; } m_LastGlyphIndex = GLYPH_INDEX_NOT_FOUND; return m_LastGlyphIndex; } ResFontBase::GlyphIndex ResFontBase::FindGlyphIndex( const FontCodeMap* pMap, CharCode c ) const { NN_POINTER_ASSERT(pMap); u16 index = GLYPH_INDEX_NOT_FOUND; switch (pMap->mappingMethod) { //----------------------------------------------------------- // インデックス = 文字コード - オフセット case FONT_MAPMETHOD_DIRECT: { u16 offset = pMap->GetMapInfo()[0]; index = static_cast(c - pMap->ccodeBegin + offset); } break; //----------------------------------------------------------- // インデックス = table[文字コード - 文字コードオフセット] case FONT_MAPMETHOD_TABLE: { const int table_index = c - pMap->ccodeBegin; index = pMap->GetMapInfo()[table_index]; } break; //----------------------------------------------------------- // インデックス = 二分探索(文字コード) case FONT_MAPMETHOD_SCAN: { const CMapInfoScan* const scanInfo = reinterpret_cast(pMap->GetMapInfo()); const CMapScanEntry* first = &(scanInfo->GetEntries()[0]); const CMapScanEntry* last = &(scanInfo->GetEntries()[scanInfo->num - 1]); while( first <= last ) { const CMapScanEntry* mid = first + (last - first) / 2; if( mid->ccode < c ) { first = mid + 1; } else if( c < mid->ccode ) { last = mid - 1; } else { index = mid->index; break; } } } break; //----------------------------------------------------------- // unknown default: NN_ASSERTMSG(false, "unknwon MAPMETHOD"); } return index; } const CharWidths& ResFontBase::GetCharWidthsFromIndex( GlyphIndex index ) const { NN_POINTER_ASSERT(m_pFontInfo); const FontWidth* pWidth; pWidth = m_pFontInfo->pWidth; while (pWidth != NULL) { if (pWidth->indexBegin <= index && index <= pWidth->indexEnd) { return GetCharWidthsFromIndex( pWidth, index ); } pWidth = pWidth->pNext; } return m_pFontInfo->defaultWidth; } const CharWidths& ResFontBase::GetCharWidthsFromIndex( const FontWidth* pWidth, GlyphIndex index ) const { NN_POINTER_ASSERT(pWidth); return pWidth->GetWidthTable()[index - pWidth->indexBegin]; } void ResFontBase::GetGlyphFromIndex( Glyph* glyph, GlyphIndex index ) const { NN_POINTER_ASSERT(m_pFontInfo); const FontTextureGlyph& tg = *m_pFontInfo->pGlyph; const u32 cellsInASheet = internal::GetCellsInASheet(tg); const u32 sheetNo = index / cellsInASheet; const u32 offsetBytes = sheetNo * tg.sheetSize; const void* pSheet = tg.sheetImage + offsetBytes; glyph->pTexture = pSheet; glyph->widths = GetCharWidthsFromIndex(index); glyph->pTextureObject = NULL != m_pTexObjs ? GetTextureObject(sheetNo) : 0; SetGlyphMember(glyph, index, tg); } void ResFontBase::SetGlyphMember( Glyph* glyph, GlyphIndex index, const FontTextureGlyph& tg ) { const u32 cellNo = index % internal::GetCellsInASheet(tg); const u32 cellUnitX = cellNo % tg.sheetRow; const u32 cellUnitY = cellNo / tg.sheetRow; const u32 cellPixelX = cellUnitX * (tg.cellWidth + 1); const u32 cellPixelY = cellUnitY * (tg.cellHeight + 1); glyph->height = tg.cellHeight; glyph->texFormat = static_cast(tg.sheetFormat); glyph->texWidth = tg.sheetWidth; glyph->texHeight = tg.sheetHeight; glyph->cellX = static_cast(cellPixelX + 1); glyph->cellY = static_cast(cellPixelY + 1); } /* ------------------------------------------------------------------------ テクスチャフィルタ ------------------------------------------------------------------------ */ void ResFontBase::EnableLinearFilter( bool atSmall, bool atLarge ) { // 同じレジスタに以下に設定される項目がありますが、フォントではサポートしていないため、 // 常に固定値です。 // ・テクスチャをラップして使用することはありません。 // ・テクスチャをミップマップで使用することはありません。 // ・テクスチャフォーマットとして ETC1(アルファ無し)はサポートしていません。 // ・テクスチャユニット0がシャドウテクスチャが設定されることはありません。 const int magFilter = atLarge ? CMD_TEX_LINEAR: CMD_TEX_NEAREST; const int minFilter = atSmall ? CMD_TEX_LINEAR: CMD_TEX_NEAREST; m_WrapFilter = NW_FONT_COMMAND_TEX_WRAP_FILTER( magFilter, minFilter); if (! IsManaging(NULL)) { // 一度管理しているテクスチャオブジェクトを破棄し、テクスチャオブジェクト名を再確保する。 DeleteTextureNames(); GenTextureNames(); } } bool ResFontBase::IsLinearFilterEnableAtSmall() const { return 0 != (m_WrapFilter & (1 << 2)); } bool ResFontBase::IsLinearFilterEnableAtLarge() const { return 0 != (m_WrapFilter & (1 << 1)); } u32 ResFontBase::GetTextureWrapFilterValue() const { return m_WrapFilter; } int ResFontBase::GetActiveSheetNum() const { NN_POINTER_ASSERT(m_pFontInfo); return m_pFontInfo->pGlyph->sheetNum; } void ResFontBase::GenTextureNames() { internal::TextureObject* texObjs = GetTextureObjectsBufferPtr(); NN_POINTER_ASSERT(texObjs); const FontTextureGlyph& tg = *m_pFontInfo->pGlyph; const int sheetNum = GetActiveSheetNum(); u32 offsetBytes = 0; for (int i = 0; i < sheetNum; ++i) { const GLuint texName = 0; const void *const pImage = tg.sheetImage + offsetBytes; const TexFmt format = static_cast(tg.sheetFormat); texObjs[i].Set(texName, this, pImage, format, tg.sheetWidth, tg.sheetHeight); offsetBytes += tg.sheetSize; } #if defined(NW_PLATFORM_CTR) nngxUpdateBuffer(tg.sheetImage, tg.sheetSize * sheetNum); #endif } void ResFontBase::DeleteTextureNames() { internal::TextureObject* texObjs = GetTextureObjectsBufferPtr(); NN_POINTER_ASSERT(texObjs); const int sheetNum = GetActiveSheetNum(); for (int i = 0; i < sheetNum; ++i) { const GLuint texName = texObjs[i].GetName(); if (texName != 0) { glDeleteTextures(1, &texName); texObjs[i].SetName(0); // テクスチャ名を未割り当て状態にしておく } #if defined(NW_DEBUG) texObjs[i].Reset(); #endif } } } // namespace font } // namespace nw