1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     font_ResFontBase.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 23461 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nn/assert.h>
19 #if defined(NW_PLATFORM_CTR)
20     #include <nn/gx/CTR/gx_CommandAccess.h>
21 #endif
22 #include <nw/font/font_ResFontBase.h>
23 #include <nw/ut/ut_Inlines.h>
24 
25 
26 namespace nw {
27 namespace font {
28 
29 namespace {
30 
31 enum
32 {
33     CMD_TEX_NEAREST = 0,
34     CMD_TEX_LINEAR  = 1
35 };
36 
37 #define NW_FONT_COMMAND_TEX_WRAP_FILTER( magFilter, minFilter )             \
38       ( (magFilter) << 1 | (minFilter) << 2 | ( 0/*isETC1*/ ? 2 : 0 ) << 4  \
39     | 0/*wrapT*/ << 8 | 0/*wrapS*/ << 12                                    \
40     | 0/*minFilter2*/ << 24 )
41 
42 }   //     namespace
43 
44 
45 /* ------------------------------------------------------------------------
46         コンストラクタ/デストラクタ
47    ------------------------------------------------------------------------ */
48 
ResFontBase()49 ResFontBase::ResFontBase()
50 :   m_pResource(NULL),
51     m_pFontInfo(NULL),
52     m_pTexObjs(NULL),
53     m_LastCharCode(0),
54     m_LastGlyphIndex(GLYPH_INDEX_NOT_FOUND)
55 {
56     EnableLinearFilter(true, true);     // m_Filter
57 }
58 
~ResFontBase()59 ResFontBase::~ResFontBase()
60 {
61 }
62 
63 
64 
65 /* ------------------------------------------------------------------------
66         構築/破棄
67    ------------------------------------------------------------------------ */
68 
69 void
SetResourceBuffer(void * pUserBuffer,FontInformation * pFontInfo)70 ResFontBase::SetResourceBuffer(
71     void*               pUserBuffer,
72     FontInformation*    pFontInfo
73 )
74 {
75     NN_POINTER_ASSERT(pUserBuffer);
76     NN_POINTER_ASSERT(pFontInfo);
77     NN_ASSERT(m_pResource == NULL);
78     NN_ASSERT(m_pFontInfo == NULL);
79 
80     m_pResource = pUserBuffer;
81     m_pFontInfo = pFontInfo;
82 }
83 
84 void*
RemoveResourceBuffer()85 ResFontBase::RemoveResourceBuffer()
86 {
87     // テクスチャ名の削除
88     // m_pResourceが指す内容に依存するので
89     // m_pResourceをクリアする前に行う。
90     if (NULL != m_pTexObjs)
91     {
92         DeleteTextureNames();
93         m_pTexObjs = 0;
94     }
95 
96     void* pUserData = m_pResource;
97 
98     m_pResource = NULL;
99     m_pFontInfo = NULL;
100 
101     return pUserData;
102 }
103 
104 
105 
106 
107 /* ------------------------------------------------------------------------
108         フォント全体情報アクセサ
109    ------------------------------------------------------------------------ */
110 
111 int
GetWidth() const112 ResFontBase::GetWidth() const
113 {
114     NN_POINTER_ASSERT(m_pFontInfo);
115     return m_pFontInfo->width;
116 }
117 
118 int
GetHeight() const119 ResFontBase::GetHeight() const
120 {
121     NN_POINTER_ASSERT(m_pFontInfo);
122     return m_pFontInfo->height;
123 }
124 
125 int
GetAscent() const126 ResFontBase::GetAscent() const
127 {
128     NN_POINTER_ASSERT(m_pFontInfo);
129     return m_pFontInfo->ascent;
130 }
131 
132 int
GetDescent() const133 ResFontBase::GetDescent() const
134 {
135     NN_POINTER_ASSERT(m_pFontInfo);
136     return m_pFontInfo->height - m_pFontInfo->ascent;
137 }
138 
139 int
GetBaselinePos() const140 ResFontBase::GetBaselinePos() const
141 {
142     NN_POINTER_ASSERT(m_pFontInfo);
143     return m_pFontInfo->pGlyph->baselinePos;
144 }
145 
146 int
GetCellHeight() const147 ResFontBase::GetCellHeight() const
148 {
149     NN_POINTER_ASSERT(m_pFontInfo);
150     return m_pFontInfo->pGlyph->cellHeight;
151 }
152 
153 int
GetCellWidth() const154 ResFontBase::GetCellWidth() const
155 {
156     NN_POINTER_ASSERT(m_pFontInfo);
157     return m_pFontInfo->pGlyph->cellWidth;
158 }
159 
160 int
GetMaxCharWidth() const161 ResFontBase::GetMaxCharWidth() const
162 {
163     NN_POINTER_ASSERT(m_pFontInfo);
164     return m_pFontInfo->pGlyph->maxCharWidth;
165 }
166 
167 Font::Type
GetType() const168 ResFontBase::GetType() const
169 {
170     return TYPE_RESOURCE;
171 }
172 
173 TexFmt
GetTextureFormat() const174 ResFontBase::GetTextureFormat() const
175 {
176     NN_POINTER_ASSERT(m_pFontInfo);
177     return static_cast<TexFmt>(m_pFontInfo->pGlyph->sheetFormat);
178 }
179 
180 int
GetLineFeed() const181 ResFontBase::GetLineFeed() const
182 {
183     NN_POINTER_ASSERT(m_pFontInfo);
184     return m_pFontInfo->linefeed;
185 }
186 
187 const CharWidths
GetDefaultCharWidths() const188 ResFontBase::GetDefaultCharWidths() const
189 {
190     NN_POINTER_ASSERT(m_pFontInfo);
191     return m_pFontInfo->defaultWidth;
192 }
193 
194 void
SetDefaultCharWidths(const CharWidths & widths)195 ResFontBase::SetDefaultCharWidths( const CharWidths& widths )
196 {
197     NN_POINTER_ASSERT(m_pFontInfo);
198     NN_POINTER_ASSERT( &widths );
199     m_pFontInfo->defaultWidth = widths;
200 }
201 
202 bool
SetAlternateChar(CharCode c)203 ResFontBase::SetAlternateChar( CharCode c )
204 {
205     NN_POINTER_ASSERT(m_pFontInfo);
206     GlyphIndex index = FindGlyphIndex(c);
207 
208     if (index != GLYPH_INDEX_NOT_FOUND)
209     {
210         m_pFontInfo->alterCharIndex = index;
211         return true;
212     }
213 
214     return false;
215 }
216 
217 void
SetLineFeed(int linefeed)218 ResFontBase::SetLineFeed( int linefeed )
219 {
220     NN_POINTER_ASSERT(m_pFontInfo);
221     NW_FONT_MINMAX_ASSERT(linefeed, SCHAR_MIN, SCHAR_MAX);
222     m_pFontInfo->linefeed = static_cast<s8>(linefeed);
223 }
224 
225 
226 
227 
228 /* ------------------------------------------------------------------------
229         文字単体情報アクセサ
230    ------------------------------------------------------------------------ */
231 
232 int
GetCharWidth(CharCode c) const233 ResFontBase::GetCharWidth( CharCode c ) const
234 {
235     return GetCharWidths(c).charWidth;
236 }
237 
238 const CharWidths
GetCharWidths(CharCode c) const239 ResFontBase::GetCharWidths( CharCode c ) const
240 {
241     GlyphIndex index = GetGlyphIndex(c);
242     return GetCharWidthsFromIndex(index);
243 }
244 
245 void
GetGlyph(Glyph * glyph,CharCode c) const246 ResFontBase::GetGlyph( Glyph* glyph, CharCode c ) const
247 {
248     GlyphIndex index = GetGlyphIndex(c);
249     GetGlyphFromIndex(glyph, index);
250 }
251 
252 bool
HasGlyph(CharCode c) const253 ResFontBase::HasGlyph( CharCode c ) const
254 {
255     return ( GLYPH_INDEX_NOT_FOUND != FindGlyphIndex(c) );
256 }
257 
258 
259 
260 
261 
262 /* ------------------------------------------------------------------------
263         文字ストリーム
264    ------------------------------------------------------------------------ */
265 
266 CharacterCode
GetCharacterCode() const267 ResFontBase::GetCharacterCode() const
268 {
269     NN_POINTER_ASSERT(m_pFontInfo);
270 
271     return static_cast<CharacterCode>(m_pFontInfo->characterCode);
272 }
273 
274 
275 
276 /* ------------------------------------------------------------------------
277         グリフインデックス
278    ------------------------------------------------------------------------ */
279 
280 ResFontBase::GlyphIndex
GetGlyphIndex(CharCode c) const281 ResFontBase::GetGlyphIndex( CharCode c ) const
282 {
283     NN_POINTER_ASSERT(m_pFontInfo);
284     GlyphIndex index = FindGlyphIndex(c);
285     return (index != GLYPH_INDEX_NOT_FOUND) ? index: m_pFontInfo->alterCharIndex;
286 }
287 
288 ResFontBase::GlyphIndex
FindGlyphIndex(CharCode c) const289 ResFontBase::FindGlyphIndex( CharCode c ) const
290 {
291     NN_POINTER_ASSERT(m_pFontInfo);
292 
293     if (c == m_LastCharCode)
294     {
295         return m_LastGlyphIndex;
296     }
297 
298     m_LastCharCode = c;
299 
300     const FontCodeMap* pMap = m_pFontInfo->pMap;
301     while (pMap != NULL)
302     {
303         if (pMap->ccodeBegin <= c && c <= pMap->ccodeEnd)
304         {
305             m_LastGlyphIndex = FindGlyphIndex(pMap, c);
306             return m_LastGlyphIndex;
307         }
308 
309         pMap = pMap->pNext;
310     }
311 
312     m_LastGlyphIndex = GLYPH_INDEX_NOT_FOUND;
313     return m_LastGlyphIndex;
314 }
315 
316 ResFontBase::GlyphIndex
FindGlyphIndex(const FontCodeMap * pMap,CharCode c) const317 ResFontBase::FindGlyphIndex(
318     const FontCodeMap*  pMap,
319     CharCode            c
320 ) const
321 {
322     NN_POINTER_ASSERT(pMap);
323     u16 index = GLYPH_INDEX_NOT_FOUND;
324 
325     switch (pMap->mappingMethod)
326     {
327     //-----------------------------------------------------------
328     // インデックス = 文字コード - オフセット
329     case FONT_MAPMETHOD_DIRECT:
330         {
331             u16 offset = pMap->GetMapInfo()[0];
332             index = static_cast<u16>(c - pMap->ccodeBegin + offset);
333         }
334         break;
335 
336     //-----------------------------------------------------------
337     // インデックス = table[文字コード - 文字コードオフセット]
338     case FONT_MAPMETHOD_TABLE:
339         {
340             const int table_index = c - pMap->ccodeBegin;
341 
342             index = pMap->GetMapInfo()[table_index];
343         }
344         break;
345 
346     //-----------------------------------------------------------
347     // インデックス = 二分探索(文字コード)
348     case FONT_MAPMETHOD_SCAN:
349         {
350             const CMapInfoScan* const scanInfo
351                 = reinterpret_cast<const CMapInfoScan*>(pMap->GetMapInfo());
352             const CMapScanEntry* first  = &(scanInfo->GetEntries()[0]);
353             const CMapScanEntry* last   = &(scanInfo->GetEntries()[scanInfo->num - 1]);
354 
355             while( first <= last )
356             {
357                 const CMapScanEntry* mid = first + (last - first) / 2;
358 
359                 if( mid->ccode < c )
360                 {
361                     first = mid + 1;
362                 }
363                 else if( c < mid->ccode )
364                 {
365                     last = mid - 1;
366                 }
367                 else
368                 {
369                     index = mid->index;
370                     break;
371                 }
372             }
373         }
374         break;
375 
376     //-----------------------------------------------------------
377     // unknown
378     default:
379         NN_ASSERTMSG(false, "unknwon MAPMETHOD");
380     }
381 
382     return index;
383 }
384 
385 const CharWidths&
GetCharWidthsFromIndex(GlyphIndex index) const386 ResFontBase::GetCharWidthsFromIndex( GlyphIndex index ) const
387 {
388     NN_POINTER_ASSERT(m_pFontInfo);
389     const FontWidth* pWidth;
390 
391     pWidth = m_pFontInfo->pWidth;
392 
393     while (pWidth != NULL)
394     {
395         if (pWidth->indexBegin <= index && index <= pWidth->indexEnd)
396         {
397             return GetCharWidthsFromIndex( pWidth, index );
398         }
399 
400         pWidth = pWidth->pNext;
401     }
402 
403     return m_pFontInfo->defaultWidth;
404 }
405 
406 const CharWidths&
GetCharWidthsFromIndex(const FontWidth * pWidth,GlyphIndex index) const407 ResFontBase::GetCharWidthsFromIndex(
408     const FontWidth*    pWidth,
409     GlyphIndex          index
410 ) const
411 {
412     NN_POINTER_ASSERT(pWidth);
413     return pWidth->GetWidthTable()[index - pWidth->indexBegin];
414 }
415 
416 void
GetGlyphFromIndex(Glyph * glyph,GlyphIndex index) const417 ResFontBase::GetGlyphFromIndex(
418     Glyph*      glyph,
419     GlyphIndex  index
420 ) const
421 {
422     NN_POINTER_ASSERT(m_pFontInfo);
423     const FontTextureGlyph& tg = *m_pFontInfo->pGlyph;
424 
425     const u32 cellsInASheet = internal::GetCellsInASheet(tg);
426     const u32 sheetNo       = index       / cellsInASheet;
427     const u32 offsetBytes   = sheetNo * tg.sheetSize;
428     const void* pSheet      = tg.sheetImage + offsetBytes;
429 
430     glyph->pTexture         = pSheet;
431     glyph->widths           = GetCharWidthsFromIndex(index);
432     glyph->pTextureObject   = NULL != m_pTexObjs ? GetTextureObject(sheetNo) : 0;
433     SetGlyphMember(glyph, index, tg);
434 }
435 
436 void
SetGlyphMember(Glyph * glyph,GlyphIndex index,const FontTextureGlyph & tg)437 ResFontBase::SetGlyphMember(
438     Glyph*                  glyph,
439     GlyphIndex              index,
440     const FontTextureGlyph& tg
441 )
442 {
443     const u32 cellNo        = index       % internal::GetCellsInASheet(tg);
444     const u32 cellUnitX     = cellNo      % tg.sheetRow;
445     const u32 cellUnitY     = cellNo      / tg.sheetRow;
446     const u32 cellPixelX    = cellUnitX   * (tg.cellWidth  + 1);
447     const u32 cellPixelY    = cellUnitY   * (tg.cellHeight + 1);
448 
449     glyph->height       = tg.cellHeight;
450     glyph->texFormat    = static_cast<TexFmt>(tg.sheetFormat);
451     glyph->texWidth     = tg.sheetWidth;
452     glyph->texHeight    = tg.sheetHeight;
453     glyph->cellX        = static_cast<u16>(cellPixelX + 1);
454     glyph->cellY        = static_cast<u16>(cellPixelY + 1);
455 }
456 
457 
458 /* ------------------------------------------------------------------------
459         テクスチャフィルタ
460    ------------------------------------------------------------------------ */
461 
462 void
EnableLinearFilter(bool atSmall,bool atLarge)463 ResFontBase::EnableLinearFilter(
464     bool    atSmall,
465     bool    atLarge
466 )
467 {
468     // 同じレジスタに以下に設定される項目がありますが、フォントではサポートしていないため、
469     // 常に固定値です。
470     // ・テクスチャをラップして使用することはありません。
471     // ・テクスチャをミップマップで使用することはありません。
472     // ・テクスチャフォーマットとして ETC1(アルファ無し)はサポートしていません。
473     // ・テクスチャユニット0がシャドウテクスチャが設定されることはありません。
474     const int magFilter = atLarge ? CMD_TEX_LINEAR: CMD_TEX_NEAREST;
475     const int minFilter = atSmall ? CMD_TEX_LINEAR: CMD_TEX_NEAREST;
476     m_WrapFilter =
477         NW_FONT_COMMAND_TEX_WRAP_FILTER(
478             magFilter,
479             minFilter);
480 
481     if (! IsManaging(NULL))
482     {
483         // 一度管理しているテクスチャオブジェクトを破棄し、テクスチャオブジェクト名を再確保する。
484         DeleteTextureNames();
485         GenTextureNames();
486     }
487 }
488 
489 bool
IsLinearFilterEnableAtSmall() const490 ResFontBase::IsLinearFilterEnableAtSmall() const
491 {
492     return 0 != (m_WrapFilter & (1 << 2));
493 }
494 
495 bool
IsLinearFilterEnableAtLarge() const496 ResFontBase::IsLinearFilterEnableAtLarge() const
497 {
498     return 0 != (m_WrapFilter & (1 << 1));
499 }
500 
501 u32
GetTextureWrapFilterValue() const502 ResFontBase::GetTextureWrapFilterValue() const
503 {
504     return m_WrapFilter;
505 }
506 
507 int
GetActiveSheetNum() const508 ResFontBase::GetActiveSheetNum() const
509 {
510     NN_POINTER_ASSERT(m_pFontInfo);
511     return m_pFontInfo->pGlyph->sheetNum;
512 }
513 
514 void
GenTextureNames()515 ResFontBase::GenTextureNames()
516 {
517     internal::TextureObject* texObjs = GetTextureObjectsBufferPtr();
518     NN_POINTER_ASSERT(texObjs);
519 
520     const FontTextureGlyph& tg = *m_pFontInfo->pGlyph;
521     const int sheetNum = GetActiveSheetNum();
522     u32 offsetBytes = 0;
523     for (int i = 0; i < sheetNum; ++i)
524     {
525         const GLuint texName = 0;
526         const void *const pImage = tg.sheetImage + offsetBytes;
527         const TexFmt format = static_cast<TexFmt>(tg.sheetFormat);
528         texObjs[i].Set(texName, this, pImage, format, tg.sheetWidth, tg.sheetHeight);
529 
530         offsetBytes += tg.sheetSize;
531     }
532 
533 #if defined(NW_PLATFORM_CTR)
534     nngxUpdateBuffer(tg.sheetImage, tg.sheetSize * sheetNum);
535 #endif
536 }
537 
538 void
DeleteTextureNames()539 ResFontBase::DeleteTextureNames()
540 {
541     internal::TextureObject* texObjs = GetTextureObjectsBufferPtr();
542     NN_POINTER_ASSERT(texObjs);
543 
544     const int sheetNum = GetActiveSheetNum();
545     for (int i = 0; i < sheetNum; ++i)
546     {
547         const GLuint texName = texObjs[i].GetName();
548         if (texName != 0)
549         {
550             glDeleteTextures(1, &texName);
551             texObjs[i].SetName(0);  // テクスチャ名を未割り当て状態にしておく
552         }
553 
554 #if defined(NW_DEBUG)
555         texObjs[i].Reset();
556 #endif
557     }
558 }
559 
560 }   // namespace font
561 }   // namespace nw
562