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