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