1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: font_PackedFont.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: 24754 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <GLES2/gl2.h>
19 #include <GLES2/gl2ext.h>
20 #include <nn/gx.h>
21 #include <nw/font/font_PackedFont.h>
22 #include <nw/ut/ut_Inlines.h>
23 #include <nw/assert.h>
24 #include <nw/math/math_Arithmetic.h>
25
26 #include <cstring>
27 #include <algorithm>
28
29 namespace nw {
30 namespace font {
31
32 namespace
33 {
34
35 #ifdef NW_PLATFORM_CTR
36 /*!--------------------------------------------------------------------------*
37 @brief 蓄積された3Dコマンドを順次実行開始し、
38 それらが終了するまで待機します。
39
40 予約されたコマンドリストオブジェクト0がバインドされている場合は
41 何も行われません。
42 *---------------------------------------------------------------------------*/
43 void
RunCmdlistDone()44 RunCmdlistDone()
45 {
46 // 3Dコマンドを区切り、実行を開始します。
47 nngxSplitDrawCmdlist();
48 nngxRunCmdlist();
49 nngxWaitCmdlistDone();
50 }
51 #endif
52
53 // PODでどのようになるか未定
54 void
GXDrawDone()55 GXDrawDone()
56 {
57 #ifdef NW_PLATFORM_CTR
58 RunCmdlistDone();
59 #endif
60 }
61
62 } // namespace
63
64 /* =======================================================================
65 PackedFont public
66 ======================================================================== */
67
68 /* ------------------------------------------------------------------------
69 コンストラクタ/デストラクタ
70 ------------------------------------------------------------------------ */
71
PackedFont()72 PackedFont::PackedFont()
73 : m_NumCompSheet(0),
74 m_NumSheetCache(0),
75 m_pCacheIndexArray(NULL),
76 m_pCacheUserArray(NULL),
77 m_pCompSheetArray(NULL),
78 m_pSheetCache(NULL)
79 {
80 }
81
~PackedFont()82 PackedFont::~PackedFont()
83 {
84 Destroy();
85 }
86
87
88
89 /* ------------------------------------------------------------------------
90 バッファサイズ計算
91 ------------------------------------------------------------------------ */
92
93 u32
GetRequireBufferSize(const void * bfnt,const char * glyphGroups,int numSheetCache)94 PackedFont::GetRequireBufferSize(
95 const void* bfnt,
96 const char* glyphGroups,
97 int numSheetCache
98 )
99 {
100 NN_POINTER_ASSERT(bfnt);
101 NN_POINTER_ASSERT(glyphGroups);
102
103 //---- 妥当性のチェック
104 if (! IsValidResource(bfnt, 16*1024))
105 {
106 return 0;
107 }
108
109 FontGlyphGroupsAcs gg(bfnt);
110
111 u32 copySize = CalcCopySize (gg, glyphGroups, NULL);
112 u32 cacheSize = CalcCacheSize(gg, numSheetCache);
113
114 return copySize + cacheSize;
115 }
116
117 u32
GetRequireBufferSize(const void * bfnt,const char * glyphGroups,f32 rateSheetCache)118 PackedFont::GetRequireBufferSize(
119 const void* bfnt,
120 const char* glyphGroups,
121 f32 rateSheetCache
122 )
123 {
124 NN_POINTER_ASSERT(bfnt);
125 NN_POINTER_ASSERT(glyphGroups);
126 NW_FONT_FLOAT_ASSERT(rateSheetCache);
127
128 //---- 妥当性のチェック
129 if (! IsValidResource(bfnt, 16*1024))
130 {
131 return 0;
132 }
133
134 FontGlyphGroupsAcs gg(bfnt);
135
136 int numLoadSheet;
137
138 u32 copySize = CalcCopySize (gg, glyphGroups, &numLoadSheet);
139 int numSheetCache = static_cast<int>(numLoadSheet * rateSheetCache);
140 u32 cacheSize = CalcCacheSize(gg, numSheetCache);
141
142 return copySize + cacheSize;
143 }
144
145
146
147 /* ------------------------------------------------------------------------
148 構築/破棄
149 ------------------------------------------------------------------------ */
150
151 void
InitStreamingConstruct(PackedFont::ConstructContext * pContext,void * outBuffer,u32 outBufferSize,const char * glyphGroups)152 PackedFont::InitStreamingConstruct(
153 PackedFont::ConstructContext* pContext,
154 void* outBuffer,
155 u32 outBufferSize,
156 const char* glyphGroups
157 )
158 {
159 NN_POINTER_ASSERT(pContext);
160 NN_POINTER_ASSERT(outBuffer);
161 NN_ALIGN_ASSERT(outBuffer, GlyphDataAlignment);
162 NW_FONT_BUFFERSIZE_ASSERT(outBufferSize);
163 NN_POINTER_ASSERT(glyphGroups);
164
165 pContext->Init( outBuffer, outBufferSize, glyphGroups );
166 pContext->op = ConstructContext::ANALYZE_FILE_HEADER;
167 }
168
169 PackedFont::ConstructResult
StreamingConstruct(PackedFont::ConstructContext * pContext,const void * stream,u32 streamSize)170 PackedFont::StreamingConstruct(
171 PackedFont::ConstructContext* pContext,
172 const void* stream,
173 u32 streamSize
174 )
175 {
176 NN_POINTER_ASSERT(pContext);
177 NN_POINTER_ASSERT(stream);
178 NW_FONT_BUFFERSIZE_ASSERT(streamSize);
179
180 //---- 既に構築済みなら失敗とする
181 if (GetFINF() != NULL)
182 {
183 // ただし CONSTRUCT_FINISH を返した後であるなら
184 // エラーではなく CONSTRUCT_FINISH とする。
185 return pContext->HasMoreBlock() ? CONSTRUCT_ERROR: CONSTRUCT_FINISH;
186 }
187
188 PackedFont::ConstructResult ret = CONSTRUCT_CONTINUE;
189 CachedStreamReader& s = pContext->GetStreamReader();
190 s.Attach(stream, streamSize);
191
192 while (ret == CONSTRUCT_CONTINUE)
193 {
194 switch (pContext->op)
195 {
196 case ConstructContext::DISPATCH: ret = ConstructOpDispatch(pContext, &s); break;
197 case ConstructContext::ANALYZE_FILE_HEADER: ret = ConstructOpAnalyzeFileHeader(pContext, &s); break;
198 case ConstructContext::ANALYZE_GLGR: ret = ConstructOpAnalyzeGLGRPacked(pContext, &s); break;
199 case ConstructContext::ANALYZE_FINF: ret = ConstructOpAnalyzeFINF(pContext, &s); break;
200 case ConstructContext::ANALYZE_CMAP: ret = ConstructOpAnalyzeCMAP(pContext, &s); break;
201 case ConstructContext::ANALYZE_CWDH: ret = ConstructOpAnalyzeCWDH(pContext, &s); break;
202 case ConstructContext::COPY: ret = ConstructOpCopy(pContext, &s); break;
203 case ConstructContext::SKIP: ret = ConstructOpSkip(pContext, &s); break;
204 case ConstructContext::FATAL_ERROR: ret = ConstructOpFatalError(pContext, &s); break;
205 case ConstructContext::ANALYZE_TGLP: ret = ConstructOpAnalyzeTGLP(pContext, &s); break;
206 case ConstructContext::PREPAIR_EXPAND_SHEET:
207 {
208 ret = ConstructOpPrepairCopyPackedSheet(pContext, &s);
209 if (pContext->op == PackedFont::ConstructContext::COPY)
210 {
211 // 圧縮シートデータ先頭へのポインタを収集する
212 m_pCompSheetArray[m_NumCompSheet] = pContext->GetCurrentPtr<u8*>();
213 m_NumCompSheet++;
214 }
215 }
216 break;
217
218 case ConstructContext::PREPAIR_COPY_SHEET:
219 NN_LOG("PackedFont: specified font is not compressed.");
220 pContext->op = ConstructContext::FATAL_ERROR;
221 return CONSTRUCT_ERROR;
222
223 default:
224 NN_ASSERTMSG(false, "NW FONT Internal error\n" "invalid operation(%d)", pContext->op);
225 pContext->op = ConstructContext::FATAL_ERROR;
226 return CONSTRUCT_ERROR;
227 }
228 }
229
230 //---- フォントリソースに対する処理終了時
231 if (ret == CONSTRUCT_FINISH && GetFINF() == NULL)
232 {
233 void* pUserBuffer;
234 FontInformation* pFontInfo;
235 u16* pAdjustArray;
236
237 pContext->Finish(&pUserBuffer, &pFontInfo, &pAdjustArray);
238 SetResourceBuffer(pUserBuffer, pFontInfo, pAdjustArray);
239
240 if (AdjustIndex(GetFINF()->alterCharIndex) == GLYPH_INDEX_NOT_FOUND)
241 {
242 GetFINF()->alterCharIndex = 0;
243 }
244
245 // 全てのシートを未ロードとする
246 for (int i = 0; i < m_NumCompSheet; ++i)
247 {
248 m_pCacheIndexArray[i] = SHEET_INDEX_NOT_LOADED;
249 }
250
251 // 全てのシートを未ロードとする
252 for (int i = 0; i < m_NumSheetCache; ++i)
253 {
254 m_pCacheUserArray[i] = SHEET_INDEX_NOT_LOADED;
255 }
256
257 }
258
259 return ret;
260 }
261
262 bool
Construct(void * pBuffer,u32 bufferSize,const void * bfnt,const char * glyphGroups)263 PackedFont::Construct(
264 void* pBuffer,
265 u32 bufferSize,
266 const void* bfnt,
267 const char* glyphGroups
268 )
269 {
270 NN_POINTER_ASSERT(pBuffer);
271 NN_ALIGN_ASSERT(pBuffer, GlyphDataAlignment);
272 NW_FONT_BUFFERSIZE_ASSERT(bufferSize);
273 NN_POINTER_ASSERT(bfnt);
274 NN_POINTER_ASSERT(glyphGroups);
275
276 PackedFont::ConstructResult ret;
277 PackedFont::ConstructContext context;
278 const u32 fileSize = reinterpret_cast<const ut::BinaryFileHeader*>(bfnt)->fileSize;
279 NW_FONT_BUFFERSIZE_ASSERT(fileSize);
280
281 InitStreamingConstruct(&context, pBuffer, bufferSize, glyphGroups);
282 ret = StreamingConstruct(&context, bfnt, fileSize);
283
284 return ret == CONSTRUCT_FINISH;
285 }
286
287 void*
Destroy()288 PackedFont::Destroy()
289 {
290 if (IsManaging(NULL))
291 {
292 return 0;
293 }
294
295 // テクスチャ名を削除する際に m_NumSheetCache を
296 // 参照するため、m_NumSheetCacheを初期化する前に呼び出す。
297 void *const buffer = RemoveResourceBuffer();
298
299 m_NumSheetCache = 0;
300 m_pCacheIndexArray = NULL;
301 m_pCacheUserArray = NULL;
302 m_pCompSheetArray = NULL;
303 m_pSheetCache = NULL;
304
305 return buffer;
306 }
307
308
309
310 /* ------------------------------------------------------------------------
311 Fontクラスオーバーライド
312 ------------------------------------------------------------------------ */
313
314 void
GetGlyph(Glyph * pGlyph,CharCode c) const315 PackedFont::GetGlyph(
316 Glyph* pGlyph,
317 CharCode c
318 ) const
319 {
320 NN_POINTER_ASSERT(pGlyph);
321 NN_POINTER_ASSERT(GetFINF());
322 GlyphIndex index = GetGlyphIndex(c);
323 u16 adjustedIndex = AdjustIndex(index);
324
325 if (adjustedIndex == GLYPH_INDEX_NOT_FOUND)
326 {
327 index = GetFINF()->alterCharIndex;
328 adjustedIndex = AdjustIndex(index);
329 }
330 NN_ASSERT( adjustedIndex != GLYPH_INDEX_NOT_FOUND );
331
332 int compIndex = CalcSheetIndex(adjustedIndex);
333 int cacheIndex = GetCacheIndex(compIndex);
334
335 if (cacheIndex == SHEET_INDEX_NOT_LOADED)
336 {
337 cacheIndex = LoadSheet(compIndex);
338 pGlyph->isSheetUpdated = true;
339 }
340 m_LRUMan.Use(cacheIndex);
341
342 MakeGlyph(pGlyph, index, cacheIndex);
343 }
344
345
346 int
GetActiveSheetNum() const347 PackedFont::GetActiveSheetNum() const
348 {
349 return m_NumSheetCache;
350 }
351
352
353
354 /* ------------------------------------------------------------------------
355 シート管理
356 ------------------------------------------------------------------------ */
357
358 bool
PreloadSheet(CharCode c)359 PackedFont::PreloadSheet(CharCode c)
360 {
361 NN_POINTER_ASSERT(GetFINF());
362 bool bCacheNow = false;
363
364 int compIndex = GetSheetIndex(c);
365 int cacheIndex = GetCacheIndex(compIndex);
366
367 if (cacheIndex == SHEET_INDEX_NOT_LOADED)
368 {
369 cacheIndex = LoadSheet(compIndex);
370 bCacheNow = true;
371 }
372 NN_ASSERT( cacheIndex != SHEET_INDEX_NOT_LOADED );
373 m_LRUMan.Use(cacheIndex);
374
375 return bCacheNow;
376 }
377
378 bool
LockSheet(CharCode c)379 PackedFont::LockSheet(CharCode c)
380 {
381 NN_POINTER_ASSERT(GetFINF());
382 int compIndex = GetSheetIndex(c);
383 int cacheIndex = GetCacheIndex(compIndex);
384
385 //---- キャッシュされていないならキャッシュする
386 if (cacheIndex == SHEET_INDEX_NOT_LOADED)
387 {
388 if (m_LRUMan.GetNumLocked() >= m_NumSheetCache - 1)
389 {
390 return false;
391 }
392
393 cacheIndex = LoadSheet(compIndex);
394 }
395
396 //---- ロック
397 m_LRUMan.Lock(cacheIndex);
398 return true;
399 }
400
401 bool
UnlockSheet(CharCode c,bool bUnload)402 PackedFont::UnlockSheet(
403 CharCode c,
404 bool bUnload
405 )
406 {
407 int compIndex = GetSheetIndex(c);
408 int cacheIndex = GetCacheIndex(compIndex);
409
410 //---- キャッシュ上に存在しなければならない
411 if (cacheIndex == SHEET_INDEX_NOT_LOADED)
412 {
413 return false;
414 }
415
416 //---- ロック解除
417 m_LRUMan.Unlock(cacheIndex);
418
419 if (bUnload)
420 {
421 //---- キャッシュ破棄
422 UnloadSheet(compIndex);
423 m_LRUMan.Unuse(cacheIndex);
424 }
425
426 return true;
427 }
428
429 void
UnlockSheetAll()430 PackedFont::UnlockSheetAll()
431 {
432 for (int i = 0; i < m_NumSheetCache; ++i)
433 {
434 m_LRUMan.Unlock(i);
435 }
436 }
437
438
439
440 /* =======================================================================
441 PackedFont private
442 ======================================================================== */
443
444 /* ------------------------------------------------------------------------
445 バッファサイズ計算
446 ------------------------------------------------------------------------ */
447
448 u32
CalcCopySize(const FontGlyphGroupsAcs & gg,const char * glyphGroups,int * pNumLoadSheet)449 PackedFont::CalcCopySize(
450 const FontGlyphGroupsAcs& gg,
451 const char* glyphGroups,
452 int* pNumLoadSheet
453 )
454 {
455 NN_POINTER_ASSERT(glyphGroups);
456
457 u32 sizeSumSheet = 0;
458 u32 sizeSumCWDH = 0;
459 u32 sizeSumCMAP = 0;
460 int numLoadSheet = 0;
461
462 // ロードするシートのサイズを計算
463 for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumSheet(); ++flagSetNo)
464 {
465 u32 useSheets = 0x0;
466
467 for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
468 {
469 const char* setName = gg.GetSetName(setNo);
470
471 if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
472 {
473 useSheets |= gg.GetUseSheetFlags(setNo, flagSetNo);
474 }
475 }
476
477 for (int b = 0; b < 32; ++b)
478 {
479 if (((useSheets << b) & (1u << 31)) != 0)
480 {
481 sizeSumSheet += gg.GetSizeCompSheet(flagSetNo * 32 + b);
482 numLoadSheet++;
483 }
484 }
485 }
486
487 // CWDH ブロック用に必要なバッファサイズを計算
488 for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCWDH(); ++flagSetNo)
489 {
490 u32 useCWDH = 0x0;
491
492 for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
493 {
494 const char* setName = gg.GetSetName(setNo);
495
496 if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
497 {
498 useCWDH |= gg.GetUseCWDHFlags(setNo, flagSetNo);
499 }
500 }
501
502 for (int b = 0; b < 32; ++b)
503 {
504 if (((useCWDH << b) & (1u << 31)) != 0)
505 {
506 sizeSumCWDH += gg.GetSizeCWDH(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader);
507 }
508 }
509 }
510
511 // CMAP ブロック用に必要なバッファサイズを計算
512 for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCMAP(); ++flagSetNo)
513 {
514 u32 useCMAP = 0x0;
515
516 for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
517 {
518 const char* setName = gg.GetSetName(setNo);
519
520 if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
521 {
522 useCMAP |= gg.GetUseCMAPFlags(setNo, flagSetNo);
523 }
524 }
525
526 for (int b = 0; b < 32; ++b)
527 {
528 if ( ((useCMAP << b) & (1u << 31)) != 0)
529 {
530 sizeSumCMAP += gg.GetSizeCMAP(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader);
531 }
532 }
533 }
534
535
536 if (pNumLoadSheet != NULL)
537 {
538 *pNumLoadSheet = numLoadSheet;
539 }
540
541 //---- 必要バッファサイズの計算
542 const u32 sizeFINF = math::RoundUp(sizeof(FontInformation), 4);
543 const u32 sizeTGLP = math::RoundUp(sizeof(FontTextureGlyph), 4);
544
545 // GLGR ブロックの処理に必要なテンポラリバッファのサイズ
546 // バッファサイズはこの値以上になるようにする
547 // 通常、このサイズより小さくなる事は無い
548 const u32 glgrSize = (sizeof(ut::BinaryFileHeader) + gg.GetGLGRSize()) * 2;
549
550 // 圧縮されたシートにアライメントは不要だが処理の都合上アライメントを入れる
551 const u32 loadResSize = math::RoundUp(sizeFINF + sizeTGLP, GlyphDataAlignment)
552 + sizeSumSheet + sizeSumCWDH + sizeSumCMAP;
553
554 return math::Max(loadResSize, glgrSize);
555 }
556
557 u32
CalcCacheSize(const FontGlyphGroupsAcs & gg,int numSheetCache)558 PackedFont::CalcCacheSize(
559 const FontGlyphGroupsAcs& gg,
560 int numSheetCache
561 )
562 {
563 const u32 numResSheet = gg.GetNumSheet();
564 numSheetCache = math::Clamp(numSheetCache, 1, static_cast<int>(numResSheet));
565
566 u32 sizeLRUBuffer = LRUManager::GetRequireBufferSize(numSheetCache);
567 u32 sizeCompSheetArray = sizeof(u8*) * numResSheet;
568 u32 sizeResSheetIndexArray = sizeof(u16) * numSheetCache;
569 u32 sizeSheetCached = gg.GetSheetSize() * numSheetCache;
570 u32 sizeTextureNamesArray = sizeof(internal::TextureObject) * numSheetCache;
571
572 u32 offsetLRUBuffer = 0;
573 u32 offsetCompSheetArray = math::RoundUp(offsetLRUBuffer + sizeLRUBuffer, 4);
574 u32 offsetSheetIndexArray = math::RoundUp(offsetCompSheetArray + sizeCompSheetArray, 2);
575 u32 offsetResSheetIndexArray = math::RoundUp(offsetSheetIndexArray + sizeCompSheetArray, 2);
576 u32 offsetSheetCached = math::RoundUp(offsetResSheetIndexArray + sizeResSheetIndexArray, GlyphDataAlignment);
577 u32 size = math::RoundUp(offsetSheetCached + sizeSheetCached, 4);
578 size = math::RoundUp(size + sizeTextureNamesArray, 4);
579
580 return size;
581 }
582
583
584
585 /* ------------------------------------------------------------------------
586 構築/破棄
587 ------------------------------------------------------------------------ */
588
589 u16*
AssignMemory(u8 * buffer,u32 bufferSize,u32 numResSheet,u32 numLoadSheet,u32 sheetSize)590 PackedFont::AssignMemory(
591 u8* buffer,
592 u32 bufferSize,
593 u32 numResSheet,
594 u32 numLoadSheet,
595 u32 sheetSize
596 )
597 {
598 NN_POINTER_ASSERT(buffer);
599 NW_FONT_BUFFERSIZE_ASSERT(bufferSize);
600 NN_ASSERT( numLoadSheet <= numResSheet );
601 u16* pGlyphIndexAdjustArray;
602
603 // シートキャッシュ数計算
604 u32 sizeGlyphIndexAdjustArray = math::RoundUp(sizeof(u16) * numResSheet, 2);
605 u32 sizeCacheIndexArray = math::RoundUp(sizeof(u16) * numLoadSheet, 2);
606 u32 sizeCompSheetArray = math::RoundUp(sizeof(u8*) * numLoadSheet, 4);
607
608 u32 varibaleAreaSize = bufferSize - sizeGlyphIndexAdjustArray
609 - sizeCacheIndexArray
610 - sizeCompSheetArray
611 - sizeof(LRUManager::OrderNode);
612 if (varibaleAreaSize > bufferSize)
613 {
614 // varibaleAreaSize が負になった
615 return NULL;
616 }
617
618 int numSheetCache = static_cast<int>(varibaleAreaSize
619 / (sheetSize + sizeof(LRUManager::OrderNode)
620 + sizeof(u16) + sizeof(internal::TextureObject)
621 )
622 );
623
624 u32 sizeLRUBuffer = LRUManager::GetRequireBufferSize(numSheetCache);
625 u32 sizeCacheUserArray = sizeof(u16) * numSheetCache;
626 u32 sizeSheetCached = sheetSize * numSheetCache;
627
628 // バッファ割り当て計算
629 u32 offsetLRUBuffer = 0;
630 u32 offsetGlyphIndexAdjustArray = math::RoundUp(offsetLRUBuffer + sizeLRUBuffer, 2);
631 u32 offsetCacheIndexArray = math::RoundUp(offsetGlyphIndexAdjustArray + sizeGlyphIndexAdjustArray, 2);
632 u32 offsetCacheUserArray = math::RoundUp(offsetCacheIndexArray + sizeCacheIndexArray, 2);
633 u32 offsetCompSheetArray = math::RoundUp(offsetCacheUserArray + sizeCacheUserArray, 4);
634 u32 offsetSheetCache = math::RoundUp(offsetCompSheetArray + sizeCompSheetArray, GlyphDataAlignment);
635 u32 offsetTextureObjectsArray = math::RoundUp(offsetSheetCache + sizeSheetCached, 4);
636
637
638 // バッファ割り当て
639 m_LRUMan.Init(buffer + offsetLRUBuffer, numSheetCache);
640 m_NumCompSheet = 0; // ConstructContext::PREPAIR_EXPAND_SHEET で設定される
641 m_NumSheetCache = static_cast<u16>(numSheetCache);
642 pGlyphIndexAdjustArray = reinterpret_cast<u16*> (buffer + offsetGlyphIndexAdjustArray);
643 m_pCacheIndexArray = reinterpret_cast<u16*> (buffer + offsetCacheIndexArray);
644 m_pCacheUserArray = reinterpret_cast<u16*> (buffer + offsetCacheUserArray);
645 m_pCompSheetArray = reinterpret_cast<const u8**>(buffer + offsetCompSheetArray);
646 m_pSheetCache = reinterpret_cast<u8*> (buffer + offsetSheetCache);
647 SetTextureObjectsBufferPtr(buffer + offsetTextureObjectsArray);
648
649 return pGlyphIndexAdjustArray;
650 }
651
652
653
654 /* ------------------------------------------------------------------------
655 グリフ取得/シート管理
656 ------------------------------------------------------------------------ */
657
658 void
MakeGlyph(Glyph * glyph,GlyphIndex gindex,int cacheIndex) const659 PackedFont::MakeGlyph(
660 Glyph* glyph,
661 GlyphIndex gindex,
662 int cacheIndex
663 ) const
664 {
665 const FontTextureGlyph& tg = *GetFINF()->pGlyph;
666
667 glyph->pTexture = GetLoadedSheet(cacheIndex);
668 glyph->widths = GetCharWidthsFromIndex(gindex);
669 glyph->pTextureObject = GetTextureObject(cacheIndex);
670 SetGlyphMember(glyph, gindex, tg);
671 }
672
673 int
LoadSheet(int compIndex) const674 PackedFont::LoadSheet(int compIndex) const
675 {
676 int nextCacheIndex = m_LRUMan.GetLastIndex();
677 int oldCacheUser = GetCacheUser(nextCacheIndex);
678
679 u8* pSheetDst = GetLoadedSheet(nextCacheIndex);
680 const u8* pCompSheet = GetCompSheet(compIndex);
681
682 if (oldCacheUser != SHEET_INDEX_NOT_LOADED)
683 {
684 GXDrawDone();
685 UnloadSheet(oldCacheUser);
686 }
687 nn::cx::UncompressHuffman(pCompSheet, pSheetDst);
688 SetCacheUser(compIndex, nextCacheIndex);
689
690 return nextCacheIndex;
691 }
692
693 void
UnloadSheet(int compIndex) const694 PackedFont::UnloadSheet(int compIndex) const
695 {
696 int cacheIndex = GetCacheIndex(compIndex);
697 ResetCacheUser(compIndex, cacheIndex);
698 }
699
700 int
GetSheetIndex(CharCode c) const701 PackedFont::GetSheetIndex(CharCode c) const
702 {
703 NN_POINTER_ASSERT(GetFINF());
704 GlyphIndex index = GetGlyphIndex(c);
705 u16 adjustedIndex = AdjustIndex(index);
706
707 if (adjustedIndex == GLYPH_INDEX_NOT_FOUND)
708 {
709 index = GetFINF()->alterCharIndex;
710 adjustedIndex = AdjustIndex(index);
711 }
712 NN_ASSERT( adjustedIndex != GLYPH_INDEX_NOT_FOUND );
713
714 return CalcSheetIndex(adjustedIndex);
715 }
716
717 int
CalcSheetIndex(GlyphIndex index) const718 PackedFont::CalcSheetIndex(GlyphIndex index) const
719 {
720 const FontTextureGlyph& tg = *GetFINF()->pGlyph;
721 const int cellsInASheet = internal::GetCellsInASheet(tg);
722 return index / cellsInASheet;
723 }
724
725 int
GetCacheIndex(int compIndex) const726 PackedFont::GetCacheIndex(int compIndex) const
727 {
728 NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
729 return m_pCacheIndexArray[compIndex];
730 }
731
732 int
GetCacheUser(int cacheIndex) const733 PackedFont::GetCacheUser(int cacheIndex) const
734 {
735 NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
736 return m_pCacheUserArray[cacheIndex];
737 }
738
739 void
SetCacheUser(int compIndex,int cacheIndex) const740 PackedFont::SetCacheUser(
741 int compIndex,
742 int cacheIndex
743 ) const
744 {
745 NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
746 NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
747 m_pCacheIndexArray[compIndex] = static_cast<u16>(cacheIndex);
748 m_pCacheUserArray[cacheIndex] = static_cast<u16>(compIndex);
749 }
750
751 void
ResetCacheUser(int compIndex,int cacheIndex) const752 PackedFont::ResetCacheUser(
753 int compIndex,
754 int cacheIndex
755 ) const
756 {
757 NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
758 NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
759 NN_ASSERT( m_pCacheIndexArray[compIndex] == cacheIndex );
760 NN_ASSERT( m_pCacheUserArray[cacheIndex] == compIndex );
761 m_pCacheIndexArray[compIndex] = SHEET_INDEX_NOT_LOADED;
762 m_pCacheUserArray[cacheIndex] = SHEET_INDEX_NOT_LOADED;
763 }
764
765
766 u8*
GetLoadedSheet(int cacheIndex) const767 PackedFont::GetLoadedSheet(int cacheIndex) const
768 {
769 NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
770 const u32 offsetBytes = cacheIndex * GetFINF()->pGlyph->sheetSize;
771 return m_pSheetCache + offsetBytes;
772 }
773
774 const u8*
GetCompSheet(int compIndex) const775 PackedFont::GetCompSheet(int compIndex) const
776 {
777 NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
778 return m_pCompSheetArray[compIndex];
779 }
780
781
782
783 /* ------------------------------------------------------------------------
784 構築処理置き換え
785 ------------------------------------------------------------------------ */
786
787 PackedFont::ConstructResult
ConstructOpAnalyzeGLGRPacked(PackedFont::ConstructContext * pContext,PackedFont::CachedStreamReader * pStream)788 PackedFont::ConstructOpAnalyzeGLGRPacked(
789 PackedFont::ConstructContext* pContext,
790 PackedFont::CachedStreamReader* pStream
791 )
792 {
793 NN_POINTER_ASSERT(pContext);
794 NN_POINTER_ASSERT(pStream);
795 u8* pTempFileHead;
796 u8* pTempGLGRTail;
797
798 // GLGR ブロックの確保
799 {
800 const ut::BinaryFileHeader& header = *pContext->GetCurrentPtr<const ut::BinaryFileHeader*>();
801 const u32 requireSize = pContext->header.size - sizeof(ut::BinaryBlockHeader);
802 const u32 infoSize = sizeof(ut::BinaryFileHeader) + pContext->header.size;
803
804 if (header.signature != BINFILE_SIG_FONTA)
805 {
806 // バイナリファイルヘッダがロードされていない or これはフォントリソースではない
807 NN_LOG("invalid font binary file.");
808 return CONSTRUCT_ERROR;
809 }
810 if (pStream->GetRemain() < requireSize)
811 {
812 return RequestData(pContext, pStream, requireSize);
813 }
814 if (pContext->GetRemain() < infoSize)
815 {
816 // 出力先バッファのサイズが足らなかった
817 NN_LOG("buffer size too small");
818 return CONSTRUCT_ERROR;
819 }
820
821 // GLGR ブロックを一時的にコピー
822 // CopyTo(pContext, ...) だとバッファ位置が進んでしまうので CopyTo(void*, ...) を使う
823 pTempFileHead = pContext->GetCurrentPtr<u8*>();
824 u8* blockHeaderPos = pTempFileHead + sizeof(ut::BinaryFileHeader);
825 u8* blockBodyPos = blockHeaderPos + sizeof(ut::BinaryBlockHeader);
826 pTempGLGRTail = blockHeaderPos + pContext->header.size;
827 std::memcpy(blockHeaderPos, &pContext->header, sizeof(ut::BinaryBlockHeader));
828 pStream->CopyTo(blockBodyPos, requireSize);
829
830 //---- 妥当性のチェック
831 if (! IsValidResource(pTempFileHead, infoSize))
832 {
833 return CONSTRUCT_ERROR;
834 }
835 }
836
837 const u32 bufferSize = pContext->GetRemain();
838 u16 numResSheet;
839 u32 numLoadSheet;
840 u16 numGlyphsPerSheet;
841 u32 numBlock;
842 u32 sheetSize;
843 u16* pTempAdjustArray;
844 u32 sizeAdjustTable;
845 u32 sizeResLoadBuffer;
846
847 //---- グリフインデックス調整テーブルの構築
848 {
849 FontGlyphGroupsAcs gg(pTempFileHead);
850
851 numResSheet = gg.GetNumSheet();
852 numLoadSheet = 0;
853 numGlyphsPerSheet = gg.GetNumGlyphsPerSheet();
854 numBlock = gg.GetNumBlock();
855 sheetSize = gg.GetSheetSize();
856
857 sizeAdjustTable = math::RoundUp(numResSheet * sizeof(u16), 4); // 4 バイトアライメント
858 pTempAdjustArray = reinterpret_cast<u16*>(math::RoundDown(
859 reinterpret_cast<uptr>(pTempFileHead + bufferSize - sizeAdjustTable), 2));
860 if (bufferSize < (pTempGLGRTail - pTempFileHead) + sizeAdjustTable)
861 {
862 // 出力先バッファのサイズが足らなかった
863 NN_LOG("buffer size too small");
864 return CONSTRUCT_ERROR;
865 }
866
867 // 以下 AdjustTable を一時的にフラグ配列として使う。
868 // フラグを全て落とす。
869 for (int sheetNo = 0; sheetNo < numResSheet; ++sheetNo)
870 {
871 pTempAdjustArray[sheetNo] = 0;
872 }
873
874 // 使用するシートに対応するフラグを立てていく。
875 for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
876 {
877 const char* setName = gg.GetSetName(setNo);
878
879 if (IsNullString(pContext->GetGlyphGroups()) || IncludeName(pContext->GetGlyphGroups(), setName))
880 {
881 for (int sheetNo = 0; sheetNo < numResSheet; ++sheetNo)
882 {
883 if (gg.IsUseSheet(setNo, sheetNo))
884 {
885 pTempAdjustArray[sheetNo] = 1;
886 }
887 }
888 }
889 }
890
891 // フラグを元に AdjustTable を構築する。
892 u16 adjust = 0;
893 for (int sheetNo = 0; sheetNo < numResSheet; ++sheetNo)
894 {
895 u16 &entry = pTempAdjustArray[sheetNo];
896
897 if (entry == 1)
898 {
899 entry = adjust;
900 numLoadSheet++;
901 }
902 else
903 {
904 entry = 0xFFFF;
905 adjust += gg.GetNumGlyphsPerSheet();
906 }
907 }
908
909 sizeResLoadBuffer = CalcCopySize(gg, pContext->GetGlyphGroups(), NULL);
910 }
911
912 // 以下では一時的にコピーした GLGR ブロックを破壊するので以降アクセスする事はできない。
913
914 // メモリの配分
915 {
916 const u32 sizeValiableBuffer = math::RoundDown(bufferSize - sizeResLoadBuffer, 4);
917 const u32 offsetValiableBuffer = 0;
918 const u32 offsetResLoadBuffer = offsetValiableBuffer + sizeValiableBuffer;
919 if (sizeResLoadBuffer >= bufferSize)
920 {
921 // 出力先バッファのサイズが足らなかった
922 NN_LOG("buffer size too small");
923 return CONSTRUCT_ERROR;
924 }
925
926 u8* const pValiableBuffer = pTempFileHead + offsetValiableBuffer;
927 u16* pTrueAdjustArray = AssignMemory(pValiableBuffer, sizeValiableBuffer, numResSheet, numLoadSheet, sheetSize);
928 if (pTrueAdjustArray == NULL)
929 {
930 // 出力先バッファのサイズが足らなかった
931 NN_LOG("buffer size too small");
932 return CONSTRUCT_ERROR;
933 }
934
935
936 std::copy(pTempAdjustArray, pTempAdjustArray + numResSheet,
937 NW_CHECKED_ARRAY_ITERATOR(pTrueAdjustArray, numResSheet));
938
939 pContext->SetGLGR( pTrueAdjustArray,
940 numResSheet,
941 numGlyphsPerSheet,
942 numBlock );
943
944 pContext->Advance(offsetResLoadBuffer); // 既に確保した分
945 pContext->op = ConstructContext::DISPATCH;
946 }
947
948 return CONSTRUCT_CONTINUE;
949 }
950
951 PackedFont::ConstructResult
ConstructOpPrepairCopyPackedSheet(PackedFont::ConstructContext * pContext,PackedFont::CachedStreamReader * pStream)952 PackedFont::ConstructOpPrepairCopyPackedSheet(
953 PackedFont::ConstructContext* pContext,
954 PackedFont::CachedStreamReader* pStream
955 )
956 {
957 NN_POINTER_ASSERT(pContext);
958 NN_POINTER_ASSERT(pStream);
959 // 全てのシートに対して処理が終わっているか?
960 if (! pContext->HasMoreSheet())
961 {
962 pContext->op = ConstructContext::DISPATCH;
963 return CONSTRUCT_CONTINUE;
964 }
965
966 u32 compSize;
967 const u32 requireSize = sizeof(compSize);
968
969 if (pStream->GetRemain() < requireSize)
970 {
971 return RequestData(pContext, pStream, requireSize);
972 }
973
974 // 圧縮データサイズを読み込む
975 pStream->CopyTo(&compSize, sizeof(compSize));
976
977 const u32 srcSize = compSize;
978
979 // ロードしなければならないシートか?
980 if (pContext->IsRequireSheet())
981 {
982 // ロードする
983
984 if (pContext->GetRemain() < srcSize)
985 {
986 NN_LOG("buffer size too small");
987 return CONSTRUCT_ERROR;
988 }
989
990 // CXヘッダ + CXデータをコピー
991 pContext->SetupCopyTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET);
992 }
993 else
994 {
995 // CXヘッダ + CXデータをスキップ
996 pContext->SetupSkipTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET);
997 }
998
999 // カレントシート番号を更新
1000 pContext->NextSheet();
1001
1002 return CONSTRUCT_CONTINUE;
1003 }
1004
1005
1006
1007
1008
1009 /* =======================================================================
1010 LRUManager
1011 ======================================================================== */
1012
1013 void
Init(void * buffer,int numOrderNode)1014 PackedFont::LRUManager::Init(
1015 void* buffer,
1016 int numOrderNode
1017 )
1018 {
1019 mpOrderNodeArray = reinterpret_cast<OrderNode*>(buffer);
1020 mNumOrderNode = static_cast<u16>(numOrderNode);
1021 mNumLockedNode = 0;
1022
1023 // index = numOrderNode をルートとして双方向循環リストを構成する
1024 // index=0 が LRU となる
1025 int i = 0;
1026 for ( ; i < numOrderNode; ++i)
1027 {
1028 OrderNode& node = GetNode(i);
1029 node.prevIndex = static_cast<u16>(i + 1);
1030 node.nextIndex = static_cast<u16>((i <= 0) ? numOrderNode: i - 1);
1031 }
1032
1033 OrderNode& root = GetRootNode();
1034 root.prevIndex = 0;
1035 root.nextIndex = static_cast<u16>(numOrderNode - 1);
1036 }
1037
1038 void
Use(int index)1039 PackedFont::LRUManager::Use(int index)
1040 {
1041 NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1042 OrderNode& target = GetNode(index);
1043
1044 if (! IsLockedNode(target))
1045 {
1046 // target をリンクリストからはずす
1047 Unlink(target);
1048
1049 // target を先頭に挿入
1050 OrderNode& root = GetRootNode();
1051 OrderNode& first = GetNode(root.nextIndex);
1052 target.nextIndex = root.nextIndex;
1053 target.prevIndex = first.prevIndex;
1054 root.nextIndex = static_cast<u16>(index);
1055 first.prevIndex = static_cast<u16>(index);
1056 }
1057 }
1058
1059 void
Unuse(int index)1060 PackedFont::LRUManager::Unuse(int index)
1061 {
1062 NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1063 OrderNode& target = GetNode(index);
1064
1065 if (! IsLockedNode(target))
1066 {
1067 // target をリンクリストからはずす
1068 Unlink(target);
1069 }
1070
1071 // target を最後に挿入
1072 OrderNode& root = GetRootNode();
1073 OrderNode& last = GetNode(root.prevIndex);
1074 target.prevIndex = root.prevIndex;
1075 target.nextIndex = last.nextIndex;
1076 root.prevIndex = static_cast<u16>(index);
1077 last.nextIndex = static_cast<u16>(index);
1078 }
1079
1080 void
Lock(int index)1081 PackedFont::LRUManager::Lock(int index)
1082 {
1083 NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1084 OrderNode& target = GetNode(index);
1085
1086 if (! IsLockedNode(target))
1087 {
1088 // target をリンクリストからはずす
1089 Unlink(target);
1090
1091 // ロック状態にする
1092 MarkLocked(target);
1093 mNumLockedNode++;
1094 }
1095 }
1096
1097 void
Unlock(int index)1098 PackedFont::LRUManager::Unlock(int index)
1099 {
1100 NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1101 OrderNode& target = GetNode(index);
1102
1103 if (IsLockedNode(target))
1104 {
1105 mNumLockedNode--;
1106
1107 // target を先頭に挿入
1108 OrderNode& root = GetRootNode();
1109 OrderNode& first = GetNode(root.nextIndex);
1110 target.nextIndex = root.nextIndex;
1111 target.prevIndex = first.prevIndex;
1112 root.nextIndex = static_cast<u16>(index);
1113 first.prevIndex = static_cast<u16>(index);
1114 }
1115 }
1116
1117
1118
1119
1120 } // namespace font
1121 } // namespace nw
1122