1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     font_ResFont.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: 14747 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nn/assert.h>
19 #include <nw/ut/ut_Inlines.h>
20 #include <nw/font/font_ResFont.h>
21 
22 namespace nw {
23 namespace font {
24 
25 namespace {
26 
27 /*!--------------------------------------------------------------------------*
28   @brief        オフセットで格納されているポインタを解決します。
29 
30   @param[in,out]  ptr   解決するポインタ。
31   @param[in]      base  オフセットの基準となるアドレス。
32  *---------------------------------------------------------------------------*/
33 template <typename T>
34 inline void
ResolveOffset(T * & ptr,void * base)35 ResolveOffset(T*& ptr, void* base)
36 {
37     ptr = reinterpret_cast<T*>(
38             reinterpret_cast<u8*>(base) + reinterpret_cast<u32>(ptr)
39     );
40 }
41 
42 }   // namespace
43 
44 
45 /* ------------------------------------------------------------------------
46         コンストラクタ/デストラクタ
47    ------------------------------------------------------------------------ */
48 
ResFont()49 ResFont::ResFont()
50 {
51 }
52 
~ResFont()53 ResFont::~ResFont()
54 {
55     if (!IsManaging(NULL))
56 	{
57     	RemoveResource();
58 	}
59 }
60 
61 
62 
63 /* ------------------------------------------------------------------------
64         構築
65    ------------------------------------------------------------------------ */
66 
67 u32
GetDrawBufferSize(const void * bfnt)68 ResFont::GetDrawBufferSize(const void* bfnt)
69 {
70     NN_POINTER_ASSERT(bfnt);
71     NN_ALIGN_ASSERT(bfnt, GlyphDataAlignment);
72 
73     const FontTextureGlyph* pGlyph = NULL;
74     const ut::BinaryFileHeader* fileHeader =
75         reinterpret_cast<const ut::BinaryFileHeader*>(bfnt);
76 
77     //---- オフセット解決済みのフォントか?
78     if (fileHeader->signature == BINFILE_SIG_FONT_RESOLEVED)
79     {
80     }
81     else
82     {
83         //---- 正しいファイルヘッダを持っているか
84 
85         // サポートしてるバージョンかチェック
86         if (! IsValidBinaryFile(fileHeader, BINFILE_SIG_FONT, FONT_FILE_VERSION, 2))
87         {
88             // サポートしていない形式
89             NN_LOG("Invalid font resource.");
90             return 0;
91         }
92     }
93 
94     // FontInfomation を探す
95 
96     const ut::BinaryBlockHeader* blockHeader = reinterpret_cast<const ut::BinaryBlockHeader*>(
97         reinterpret_cast<const u8*>(fileHeader) + fileHeader->headerSize
98     );
99 
100     int nBlocks = 0;
101     while (nBlocks < fileHeader->dataBlocks)
102     {
103         NN_POINTER_ASSERT( blockHeader );
104         if (blockHeader->kind == BINBLOCK_SIG_TGLP)
105         {
106             pGlyph = reinterpret_cast<const FontTextureGlyph*>(
107                 reinterpret_cast<const u8*>(blockHeader) + sizeof(*blockHeader)
108             );
109             break;
110         }
111 
112         blockHeader = reinterpret_cast<const ut::BinaryBlockHeader*>(
113             reinterpret_cast<const u8*>(blockHeader) + blockHeader->size
114         );
115         nBlocks++;
116     }
117 
118     if (pGlyph == NULL)
119     {
120         return 0;
121     }
122 
123     return sizeof(internal::TextureObject) * pGlyph->sheetNum;
124 }
125 
126 void*
SetDrawBuffer(void * buffer)127 ResFont::SetDrawBuffer(void* buffer)
128 {
129     void *const prevBuffer = GetTextureObjectsBufferPtr();
130     if (prevBuffer == buffer)
131     {
132         return buffer;
133     }
134 
135     if (NULL != prevBuffer)
136     {
137         DeleteTextureNames();
138     }
139 
140     SetTextureObjectsBufferPtr(buffer);
141 
142     if (NULL != buffer)
143     {
144         GenTextureNames();
145     }
146 
147     return prevBuffer;
148 }
149 
150 bool
SetResource(void * bfnt)151 ResFont::SetResource(void* bfnt)
152 {
153     NN_POINTER_ASSERT(bfnt);
154     NN_ALIGN_ASSERT(bfnt, GlyphDataAlignment);
155 
156     FontInformation* pFontInfo = NULL;
157     ut::BinaryFileHeader* fileHeader =
158         reinterpret_cast<ut::BinaryFileHeader*>(bfnt);
159 
160     //---- 既にリソースがセットされていないか
161     if (! IsManaging(NULL))
162     {
163         NN_LOG("Font resource already atached.");
164         return false;
165     }
166 
167     //---- オフセット解決済みのフォントか?
168     if (fileHeader->signature == BINFILE_SIG_FONT_RESOLEVED)
169     {
170         // FontInfomation を探す
171         ut::BinaryBlockHeader* blockHeader;
172         int nBlocks = 0;
173 
174         blockHeader = reinterpret_cast<ut::BinaryBlockHeader*>(
175             reinterpret_cast<u8*>(fileHeader) + fileHeader->headerSize
176         );
177 
178         while (nBlocks < fileHeader->dataBlocks)
179         {
180             NN_POINTER_ASSERT( blockHeader );
181             if (blockHeader->kind == BINBLOCK_SIG_FINF)
182             {
183                 pFontInfo = reinterpret_cast<FontInformation*>(
184                     reinterpret_cast<u8*>(blockHeader) + sizeof(*blockHeader)
185                 );
186                 break;
187             }
188 
189             blockHeader = reinterpret_cast<ut::BinaryBlockHeader*>(
190                 reinterpret_cast<u8*>(blockHeader) + blockHeader->size
191             );
192             nBlocks++;
193         }
194     }
195     else
196     {
197         //---- 正しいファイルヘッダを持っているか
198 
199         // サポートしてるバージョンかチェック
200         if (! IsValidBinaryFile(fileHeader, BINFILE_SIG_FONT, FONT_FILE_VERSION, 2))
201         {
202             // サポートしていない形式
203             NN_LOG("Invalid font resource.");
204             return false;
205         }
206 
207         // 再構築する
208         pFontInfo = Rebuild(fileHeader);
209     }
210 
211     if (pFontInfo == NULL)
212     {
213         return false;
214     }
215 
216     SetResourceBuffer(bfnt, pFontInfo);
217 
218     return true;
219 }
220 
221 void*
RemoveResource()222 ResFont::RemoveResource()
223 {
224     if (IsManaging(NULL))
225     {
226         NN_LOG("ResFont::RemoveResource(): Res font is not loaded.\n");
227         return 0;
228     }
229 
230     return RemoveResourceBuffer();
231 }
232 
233 FontInformation*
Rebuild(ut::BinaryFileHeader * fileHeader)234 ResFont::Rebuild(ut::BinaryFileHeader* fileHeader)
235 {
236     NN_POINTER_ASSERT(fileHeader);
237     NN_ALIGN_ASSERT(fileHeader, GlyphDataAlignment);
238 
239     ut::BinaryBlockHeader* blockHeader;
240     FontInformation* info = NULL;
241     int nBlocks = 0;
242 
243     blockHeader = reinterpret_cast<ut::BinaryBlockHeader*>(
244         reinterpret_cast<u8*>(fileHeader) + fileHeader->headerSize
245     );
246 
247     while (nBlocks < fileHeader->dataBlocks)
248     {
249         NN_POINTER_ASSERT(blockHeader);
250         switch (blockHeader->kind)
251         {
252         //--------------------------------------------------
253         // INFO ブロック
254         case BINBLOCK_SIG_FINF:
255             // INFOブロックは1つでなければならない
256             NN_ASSERT(info == NULL);
257             {
258                 info = reinterpret_cast<FontInformation*>(
259                     reinterpret_cast<u8*>(blockHeader) + sizeof(*blockHeader)
260                 );
261 
262                 NN_ASSERT(info->fontType == FONT_TYPE_TEXTURE);
263                 NN_ASSERT(info->alterCharIndex != GLYPH_INDEX_NOT_FOUND);
264 
265                 // pGlyph は必須
266                 NN_NULL_ASSERT(info->pGlyph);
267                 ResolveOffset(info->pGlyph, fileHeader);
268                 NN_POINTER_ASSERT(info->pGlyph);
269 
270                 // pWidth と pMap はなくても良い
271                 if (info->pWidth != NULL)
272                 {
273                     ResolveOffset(info->pWidth, fileHeader);
274                     NN_POINTER_ASSERT(info->pWidth);
275                 }
276                 if (info->pMap != NULL)
277                 {
278                     ResolveOffset(info->pMap, fileHeader);
279                     NN_POINTER_ASSERT(info->pMap);
280                 }
281             }
282             break;
283 
284         //--------------------------------------------------
285         // TGLP ブロック
286         case BINBLOCK_SIG_TGLP:
287             // TGLP ブロックも1つでなければならないが複数存在しても致命的ではない
288             {
289                 FontTextureGlyph* glyph = reinterpret_cast<FontTextureGlyph*>(
290                     reinterpret_cast<u8*>(blockHeader) + sizeof(*blockHeader)
291                 );
292 
293                 NN_NULL_ASSERT(glyph->sheetImage);
294                 ResolveOffset(glyph->sheetImage, fileHeader);
295                 NN_POINTER_ASSERT(glyph->sheetImage);
296 
297                 //---- 32x32 の I4 が最小、1024x1024 の RGBA8 が最大
298                 NW_FONT_MIN_ASSERT       ( glyph->cellWidth,     1 );
299                 NW_FONT_MIN_ASSERT       ( glyph->cellHeight,    1 );
300                 NW_FONT_MINMAX_ASSERT    ( glyph->sheetSize,     32 * 32 / 2,    1024 * 1024 * 4 );
301                 NW_FONT_MIN_ASSERT       ( glyph->sheetNum,      1 );
302                 NW_FONT_MIN_ASSERT       ( glyph->sheetRow,      1 );
303                 NW_FONT_MIN_ASSERT       ( glyph->sheetLine,     1 );
304                 NW_FONT_MINMAX_ASSERT    ( glyph->sheetWidth,    32,             1024 );
305                 NW_FONT_MINMAX_ASSERT    ( glyph->sheetHeight,   32,             1024 );
306             }
307             break;
308 
309         //--------------------------------------------------
310         // CWDHブロック
311         case BINBLOCK_SIG_CWDH:
312             {
313                 FontWidth* width = reinterpret_cast<FontWidth*>(
314                     reinterpret_cast<u8*>(blockHeader) + sizeof(*blockHeader)
315                 );
316 
317                 NN_ASSERT( width->indexBegin <= width->indexEnd );
318 
319                 if (width->pNext != NULL)
320                 {
321                     ResolveOffset(width->pNext, fileHeader);
322                     NN_POINTER_ASSERT( width->pNext );
323                 }
324             }
325             break;
326 
327         //--------------------------------------------------
328         // CMAPブロック
329         case BINBLOCK_SIG_CMAP:
330             {
331                 FontCodeMap* map = reinterpret_cast<FontCodeMap*>(
332                     reinterpret_cast<u8*>(blockHeader) + sizeof(*blockHeader)
333                 );
334 
335                 NN_ASSERT( map->ccodeBegin <= map->ccodeEnd );
336                 NN_ASSERT( (map->mappingMethod == FONT_MAPMETHOD_DIRECT)
337                                 || (map->mappingMethod == FONT_MAPMETHOD_TABLE)
338                                 || (map->mappingMethod == FONT_MAPMETHOD_SCAN) );
339 
340                 if (map->pNext != NULL)
341                 {
342                     ResolveOffset(map->pNext, fileHeader);
343                     NN_POINTER_ASSERT(map->pNext);
344                 }
345             }
346             break;
347 
348         //--------------------------------------------------
349         // GLGR ブロック
350         case BINBLOCK_SIG_GLGR:
351             {
352                 // ResFont では GLGR ブロックは参照しないので何もする必要はない
353             }
354             break;
355 
356         //--------------------------------------------------
357         // unknown
358         default:
359             NN_ASSERTMSG(false, "The font has unknown block('%c%c%c%c').",
360                 (blockHeader->kind >> 24) & 0xFF,
361                 (blockHeader->kind >> 16) & 0xFF,
362                 (blockHeader->kind >>  8) & 0xFF,
363                 (blockHeader->kind >>  0) & 0xFF
364                 );
365             return NULL;
366         }
367 
368         blockHeader = reinterpret_cast<ut::BinaryBlockHeader*>(
369             reinterpret_cast<u8*>(blockHeader) + blockHeader->size
370         );
371         nBlocks++;
372     }
373 
374 
375     //---- シグネチャを変更してオフセット解決済みにマークする
376     fileHeader->signature = BINFILE_SIG_FONT_RESOLEVED;
377 
378     return info;
379 }
380 
381 }   // namespace font
382 }   // namespace nw
383