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