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