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