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