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