1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: dev_DirectPrint.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 <nw/dev/dev_DirectPrint.h>
19
20 #ifdef NW_DEV_ENABLED
21 #include <cstdio>
22 #include <cstring>
23 #include <nn/gx.h>
24 #include <nn/gx/CTR/gx_CommandAccess.h>
25
26 namespace nw
27 {
28 namespace dev
29 {
30
31 namespace
32 {
33
34 //----------------------------------------------------------------------------
35 // ASCII文字変換テーブル
36 //
37
38 const int FONT_WIDTH = DirectPrint::FONT_WIDTH; // フォントの横幅
39 const int FONT_HEIGHT = DirectPrint::FONT_HEIGHT; // フォントの高さ
40 const int LINE_HEIGHT = DirectPrint::LINE_HEIGHT; // 行の高さ
41 const int FONT_ROW = 5; // フォントデータサイズ
42 const int TAB_WIDTH = DirectPrint::TAB_WIDTH; // タブ幅
43
44 enum {
45 ASCII_w0 = 0,
46 ASCII_w1 = 1,
47 ASCII_w2 = 2,
48 ASCII_w3 = 3,
49 ASCII_w4 = 4,
50 ASCII_w5 = 5,
51 ASCII_w6 = 6,
52 ASCII_w7 = 7,
53 ASCII_w8 = 8,
54 ASCII_w9 = 9,
55
56 ASCII_wA = 10,
57 ASCII_wB = 11,
58 ASCII_wC = 12,
59 ASCII_wD = 13,
60 ASCII_wE = 14,
61 ASCII_wF = 15,
62 ASCII_wG = 16,
63 ASCII_wH = 17,
64 ASCII_wI = 18,
65 ASCII_wJ = 19,
66 ASCII_wK = 20,
67 ASCII_wL = 21,
68 ASCII_wM = 22,
69 ASCII_wN = 23,
70 ASCII_wO = 24,
71 ASCII_wP = 25,
72 ASCII_wQ = 26,
73 ASCII_wR = 27,
74 ASCII_wS = 28,
75 ASCII_wT = 29,
76 ASCII_wU = 30,
77 ASCII_wV = 31,
78 ASCII_wW = 32,
79 ASCII_wX = 33,
80 ASCII_wY = 34,
81 ASCII_wZ = 35,
82
83 ASCII_CN = 36, /* : */
84 ASCII_KS = 37, /* ( */
85 ASCII_KE = 38, /* ) */
86 ASCII_MI = 39, /* - */
87 ASCII_QT = 40, /* ? */
88 ASCII_EM = 41, /* ! */
89 ASCII_PL = 42, /* + */
90 ASCII_PA = 43, /* % */
91 ASCII_DT = 44, /* . */
92
93 ASCII_NO = 0xff,
94 ASCII_SP = 0xff,
95 ASCII_RET = 0xfe,
96 ASCII_TAB = 0xfd,
97
98 ASCII_DQ = 100, /* " */
99 ASCII_SH = 101, /* # */
100 ASCII_DL = 102, /* $ */
101 ASCII_AM = 103, /* & */
102 ASCII_AP = 104, /* ' */
103 ASCII_AS = 105, /* * */
104 ASCII_CO = 106, /* , */
105 ASCII_SL = 107, /* / */
106 ASCII_SM = 108, /* ; */
107 ASCII_LT = 109, /* < */
108 ASCII_EQ = 110, /* = */
109 ASCII_GT = 111, /* > */
110 ASCII_AT = 112, /* @ */
111 ASCII_QP1 = 113, /* [ */
112 ASCII_BS = 114, /* \ */
113 ASCII_QP2 = 115, /* ] */
114 ASCII_HT = 116, /* ^ */
115 ASCII_UB = 117, /* _ */
116 ASCII_WP1 = 118, /* { */
117 ASCII_VL = 119, /* | */
118 ASCII_WP2 = 120, /* } */
119 ASCII_TI = 121, /* ~ */
120 ASCII_FC = 122, /* facemark */
121
122 ASCII_lA = 125, /* a */
123 ASCII_lB = 126, /* b */
124 ASCII_lC = 127, /* c */
125 ASCII_lD = 128, /* d */
126 ASCII_lE = 129, /* e */
127 ASCII_lF = 130, /* f */
128 ASCII_lG = 131, /* g */
129 ASCII_lH = 132, /* h */
130 ASCII_lI = 133, /* i */
131 ASCII_lJ = 134, /* j */
132 ASCII_lK = 135, /* k */
133 ASCII_lL = 136, /* l */
134 ASCII_lM = 137, /* m */
135 ASCII_lN = 138, /* n */
136 ASCII_lO = 139, /* o */
137 ASCII_lP = 140, /* p */
138 ASCII_lQ = 141, /* q */
139 ASCII_lR = 142, /* r */
140 ASCII_lS = 143, /* s */
141 ASCII_lT = 144, /* t */
142 ASCII_lU = 145, /* u */
143 ASCII_lV = 146, /* v */
144 ASCII_lW = 147, /* w */
145 ASCII_lX = 148, /* x */
146 ASCII_lY = 149, /* y */
147 ASCII_lZ = 150, /* z */
148
149 ASCII_dummyEnd = 999
150 };
151
152 const u8 sAsciiTable[128] =
153 {
154 ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, ASCII_TAB,ASCII_RET,ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, ASCII_FC, /* 0x00 */
155 ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, ASCII_NO, /* 0x10 */
156 ASCII_SP, ASCII_EM, ASCII_DQ, ASCII_SH, ASCII_DL, ASCII_PA, ASCII_AM, ASCII_AP, ASCII_KS, ASCII_KE, ASCII_AS, ASCII_PL, ASCII_CO, ASCII_MI, ASCII_DT, ASCII_SL, /* 0x20 */
157 ASCII_w0, ASCII_w1, ASCII_w2, ASCII_w3, ASCII_w4, ASCII_w5, ASCII_w6, ASCII_w7, ASCII_w8, ASCII_w9, ASCII_CN, ASCII_SM, ASCII_LT, ASCII_EQ, ASCII_GT, ASCII_QT, /* 0x30 */
158 ASCII_AT, ASCII_wA, ASCII_wB, ASCII_wC, ASCII_wD, ASCII_wE, ASCII_wF, ASCII_wG, ASCII_wH, ASCII_wI, ASCII_wJ, ASCII_wK, ASCII_wL, ASCII_wM, ASCII_wN, ASCII_wO, /* 0x40 */
159 ASCII_wP, ASCII_wQ, ASCII_wR, ASCII_wS, ASCII_wT, ASCII_wU, ASCII_wV, ASCII_wW, ASCII_wX, ASCII_wY, ASCII_wZ, ASCII_QP1, ASCII_BS,ASCII_QP2,ASCII_HT, ASCII_UB, /* 0x50 */
160 ASCII_NO, ASCII_lA, ASCII_lB, ASCII_lC, ASCII_lD, ASCII_lE, ASCII_lF, ASCII_lG, ASCII_lH, ASCII_lI, ASCII_lJ, ASCII_lK, ASCII_lL, ASCII_lM, ASCII_lN, ASCII_lO, /* 0x60 */
161 ASCII_lP, ASCII_lQ, ASCII_lR, ASCII_lS, ASCII_lT, ASCII_lU, ASCII_lV, ASCII_lW, ASCII_lX, ASCII_lY, ASCII_lZ, ASCII_WP1, ASCII_VL,ASCII_WP2,ASCII_TI, ASCII_FC, /* 0x70 */
162 };
163
164 //----------------------------------------------------------------------------
165 // ASCII文字フォントデータ
166 //
167 // ・FONT_ROW 数のフォントが1行ずつ u32 にパックされています。
168 // ・フォントデータは1ピクセルあたり1ビットです。
169 // ・最上位ビットは最初のフォントの左端のビットです。
170 //
171
172 const u32 sFontData[64] =
173 {
174 0x70871C30, 0x8988A250, 0x88808290, 0x88830C90, 0x888402F8, 0x88882210, 0x71CF9C10, 0xF9CF9C70,
175 0x8208A288, 0xF200A288, 0x0BC11C78, 0x0A222208, 0x8A222208, 0x71C21C70, 0x23C738F8, 0x5228A480,
176 0x8A282280, 0x8BC822F0, 0xFA282280, 0x8A28A480, 0x8BC738F8, 0xF9C89C08, 0x82288808, 0x82088808,
177 0xF2EF8808, 0x82288888, 0x82288888, 0x81C89C70, 0x8A08A270, 0x920DA288, 0xA20AB288, 0xC20AAA88,
178 0xA208A688, 0x9208A288, 0x8BE8A270, 0xF1CF1CF8, 0x8A28A220, 0x8A28A020, 0xF22F1C20, 0x82AA0220,
179 0x82492220, 0x81A89C20, 0x8A28A288, 0x8A28A288, 0x8A289488, 0x8A2A8850, 0x894A9420, 0x894AA220,
180 0x70852220, 0xF8011000, 0x08020800, 0x10840400, 0x20040470, 0x40840400, 0x80020800, 0xF8011000,
181 0x70800000, 0x88822200, 0x08820400, 0x108F8800, 0x20821000, 0x00022200, 0x20800020, 0x00000000,
182 };
183
184 const u32 sFontData2[77] =
185 {
186 0x51421820, 0x53e7a420, 0x014a2c40, 0x01471000, 0x0142aa00, 0x03eaa400, 0x01471a78,
187 0x00000000, 0x50008010, 0x20010820, 0xf8020040, 0x20420820, 0x50441010, 0x00880000,
188 0x00070e00, 0x01088840, 0x78898820, 0x004a8810, 0x788a8810, 0x01098808, 0x00040e04,
189 0x70800620, 0x11400820, 0x12200820, 0x10001020, 0x10000820, 0x100f8820, 0x70000620,
190 0x60070000, 0x110f82a0, 0x12aa8ae0, 0x084f92a0, 0x100fbe1c, 0x10089008, 0x60070808,
191
192 // a-e
193 0x00000000, 0x02000200, 0x7a078270, 0x8bc81e88, 0x8a2822f8, 0x9a282280, 0x6bc79e78,
194
195 // f-j
196 0x30000000, 0x48080810, 0x41e80000, 0x422f1830, 0xfbe88810, 0x40288890, 0x43c89c60,
197
198 // k-o
199 0x81000000, 0x81000000, 0x990f3c70, 0xa10aa288, 0xe10aa288, 0xa10aa288, 0x98caa270,
200
201 // p-t
202 0x00000000, 0x00000020, 0xf1ef1e20, 0x8a28a0f8, 0x8a281c20, 0xf1e80220, 0x80283c38,
203
204 // u-y
205 0x00000000, 0x00000000, 0x8a28b688, 0x8a2a8888, 0x8a2a8878, 0x894a8808, 0x788536f0,
206
207 // z
208 0x00000000, 0x00000000, 0xf8000000, 0x10000000, 0x20000000, 0x40000000, 0xf8000000,
209
210 };
211
212 //!
213 //! @brief 描画コンテキスト。
214 //!
215 struct PixelWriterContext
216 {
217 //! ピクセルのアドレス計算の起点です。
218 u8* m_BufferBase;
219
220 //! X座標にするアドレスの増分
221 int m_StrideX;
222
223 //! Y座標に対するアドレスの増分
224 int m_StrideY;
225
226 //! X座標の上限。
227 int m_LimitX;
228
229 //! Y座標の上限。
230 int m_LimitY;
231
232 //! ピクセルあたりのバイト数。
233 int m_PixelSize;
234
235 //! バッファのフォーマットに変換された描画カラー。
236 u8 m_PixelColor[4];
237
238 //! バッファのフォーマットに変換された背景カラー。
239 u8 m_PixelBgColor[4];
240 };
241
242 //!
243 //! @brief バッファへの描画クラス(抽象基底クラス)。
244 //!
245 //! @details
246 //! バッファのフォーマットに応じた具象クラスを導出します。
247 //! オブジェクトは状態を持ちません。
248 //!
249 class PixelWriter
250 {
251 public:
252 //! @brief 矩形領域を暗くします。
253 //!
254 //! @param buffer フレームバッファ情報です。
255 //! @param direction 描画方向です。
256 //! @param x 矩形領域の位置(X方向成分)です。
257 //! @param y 矩形領域の位置(Y方向成分)です。
258 //! @param width 矩形領域の幅です。
259 //! @param height 矩形領域の高さです。
260 //! @param bgColor 背景色です。
261 //!
Erase(const internal::FrameBufferInfo & buffer,DirectPrint::Direction direction,int x,int y,int width,int height,const ut::Color8 & bgColor)262 void Erase(
263 const internal::FrameBufferInfo& buffer,
264 DirectPrint::Direction direction,
265 int x,
266 int y,
267 int width,
268 int height,
269 const ut::Color8& bgColor)
270 {
271 // コンテキストの初期化
272 PixelWriterContext context;
273 this->InitializeContext(context, buffer, ut::Color8::BLACK, bgColor, direction);
274
275 this->Erase(context, x, y, width, height);
276 }
277
278 //! @brief 文字列を描画します。
279 //!
280 //! @param buffer フレームバッファ情報です。
281 //! @param direction 描画方向です。
282 //! @param color 描画色です。
283 //! @param bgColor 背景色です。
284 //! @param x 描画開始位置(X方向成分)です。
285 //! @param y 描画開始位置(Y方向成分)です。
286 //! @param str 文字列です。
287 //! @param turnOver 行右端で折り返す場合には true を指定します。
288 //! @param backErase 背景を暗くする場合は true を指定します。
289 //!
290 void
DrawString(const internal::FrameBufferInfo & buffer,DirectPrint::Direction direction,ut::Color color,ut::Color bgColor,int x,int y,const char * str,bool turnOver,bool backErase)291 DrawString(
292 const internal::FrameBufferInfo& buffer,
293 DirectPrint::Direction direction,
294 ut::Color color,
295 ut::Color bgColor,
296 int x,
297 int y,
298 const char* str,
299 bool turnOver,
300 bool backErase)
301 {
302 NW_NULL_ASSERT(str);
303
304 // コンテキストの初期化
305 PixelWriterContext context;
306 this->InitializeContext(context, buffer, color, bgColor, direction);
307
308 this->DrawString(context, x, y, str, turnOver, backErase);
309 }
310
311 //! @brief コンテキストを初期化します。
312 //!
313 //! @param context 初期化対象のコンテキストです。
314 //! @param buffer フレームバッファの情報です。
315 //! @param color 描画色です。
316 //!
InitializeContext(PixelWriterContext & context,const internal::FrameBufferInfo & buffer,ut::Color8 color,ut::Color8 bgColor,DirectPrint::Direction direction)317 void InitializeContext(
318 PixelWriterContext& context,
319 const internal::FrameBufferInfo& buffer,
320 ut::Color8 color,
321 ut::Color8 bgColor,
322 DirectPrint::Direction direction)
323 {
324 context.m_PixelSize = this->GetPixelSize();
325 this->MakePixel(context.m_PixelColor, color);
326 this->MakePixel(context.m_PixelBgColor, bgColor);
327
328 switch (direction)
329 {
330 case DirectPrint::DIRECTION_VERTICAL:
331 default:
332 context.m_BufferBase = buffer.m_Address;
333 context.m_StrideX = context.m_PixelSize;
334 context.m_StrideY = context.m_PixelSize * buffer.m_Width;
335 context.m_LimitX = buffer.m_Width;
336 context.m_LimitY = buffer.m_Height;
337 break;
338
339 case DirectPrint::DIRECTION_HORIZONTAL:
340 context.m_BufferBase = buffer.m_Address + context.m_PixelSize * (buffer.m_Width - 1);
341 context.m_StrideX = context.m_PixelSize * buffer.m_Width;
342 context.m_StrideY = -context.m_PixelSize;
343 context.m_LimitX = buffer.m_Height;
344 context.m_LimitY = buffer.m_Width;
345 }
346 }
347
348 //! @brief ピクセルのアドレスを求めます。
349 //!
350 //! @param context コンテキストです。
351 //! @param x X座標の値です。
352 //! @param y Y座標の値です。
353 //!
354 //! @return
355 //! ピクセルのアドレスを返します。
GetPixelAddress(const PixelWriterContext & context,int x,int y)356 u8* GetPixelAddress(const PixelWriterContext& context, int x, int y)
357 {
358 return context.m_BufferBase + context.m_StrideX * x + context.m_StrideY * y;
359 }
360
361 //! @brief 矩形領域を暗くします。
362 //!
363 //! @param context コンテキストです。
364 //! @param x 矩形領域の位置(X方向成分)です。
365 //! @param y 矩形領域の位置(Y方向成分)です。
366 //! @param width 矩形領域の幅です。
367 //! @param height 矩形領域の高さです。
368 //!
Erase(const PixelWriterContext & context,int x,int y,int width,int height)369 void Erase(
370 const PixelWriterContext& context,
371 int x,
372 int y,
373 int width,
374 int height)
375 {
376 // 開始点(X)をバッファ内にクリップする。
377 if (x < 0)
378 {
379 width += x;
380 x = 0;
381 }
382
383 // 開始点(Y)をバッファ内にクリップする。
384 if (y < 0)
385 {
386 height += y;
387 y = 0;
388 }
389
390 // バッファサイズをオーバーしている場合はクリップする(水平方向)
391 int posEndX = ut::Max(0, ut::Min((int)context.m_LimitX, x + width));
392 width = posEndX - x;
393
394 // バッファサイズをオーバーしている場合はクリップする(垂直方向)
395 int posEndY = ut::Max(0, ut::Min((int)context.m_LimitY, y + height));
396 height = posEndY - y;
397
398 // クリップの結果、消去範囲の面積が0になった場合は終了。
399 if (width <= 0 || height <= 0)
400 {
401 return;
402 }
403
404 // ---- 指定矩形を暗く
405 for (int cnty = 0; cnty < height; ++cnty)
406 {
407 for (int cntx = 0; cntx < width; ++cntx)
408 {
409 u8* pixel = this->GetPixelAddress(context, x + cntx, y + cnty);
410 this->ErasePixel(pixel, context.m_PixelBgColor);
411 }
412 }
413 }
414
415 //! @brief 文字列を描画します。
416 //!
417 //! @param context コンテキストです。
418 //! @param x 描画開始位置(X方向成分)です。
419 //! @param y 描画開始位置(Y方向成分)です。
420 //! @param str 文字列です。
421 //! @param turnOver 行右端で折り返す場合には true を指定します。
422 //! @param backErase 背景を暗くする場合は true を指定します。
423 //!
424 void
DrawString(const PixelWriterContext & context,int x,int y,const char * str,bool turnOver,bool backErase)425 DrawString(
426 const PixelWriterContext& context,
427 int x,
428 int y,
429 const char* str,
430 bool turnOver,
431 bool backErase)
432 {
433 int basePosX = x;
434
435 while (*str != '\0')
436 {
437 if (backErase)
438 {
439 int len = this->StrLineWidth(str);
440 const int top = (LINE_HEIGHT - FONT_HEIGHT) / 2;
441 const int left = (FONT_WIDTH + 1) / 2;
442 this->Erase(context, x - left, y - top, (len + 1) * FONT_WIDTH, LINE_HEIGHT);
443 }
444
445 int width = (context.m_LimitX - x) / FONT_WIDTH;
446 // 行末までの文字列を出力する。
447 str = this->DrawLine(context, x, y, str, width);
448 y += LINE_HEIGHT;
449 if (*str == '\n')
450 {
451 // 改行コードで終わった場合には次の行へ
452 ++str;
453 x = basePosX;
454 }
455 else if (*str != '\0')
456 // 行の途中で折り返した場合
457 {
458 ++str;
459 if (! turnOver)
460 {
461 // 右端での折り返しがOFFであれば次の行までジャンプする。
462 if ((str = std::strchr(str, '\n')) == NULL)
463 {
464 return;
465 }
466 ++str;
467 x = basePosX;
468 }
469 else
470 {
471 x = 0;
472 }
473 }
474 }
475 }
476
477 //! @brief 文字列を1行分描画します。
478 //!
479 //! @param context コンテキストです。
480 //! @param x 文字を描画する位置のX座標です。
481 //! @param y 文字を描画する位置のY座標です。
482 //! @param str 文字列へのポインタです。
483 //! @param width 1行あたりの最大文字数です。
484 //!
485 //! @return 最後に出力もしくは判定をおこなった文字へのポインタを返します。
486 //!
487 const char*
DrawLine(const PixelWriterContext & context,int x,int y,const char * str,int width)488 DrawLine(
489 const PixelWriterContext& context,
490 int x,
491 int y,
492 const char* str,
493 int width)
494 {
495 char c; // カレント文字
496 int code; // 内部文字コードへ変換した値
497 int cnt = 0; // 出力文字数のカウンタ
498
499 NW_NULL_ASSERT(str);
500 NW_ASSERT(width > 0);
501
502 while ((c = *str) != '\0')
503 {
504 // 行の終端であれば終了
505 if (c == '\n' || c == '\0')
506 {
507 return str;
508 }
509
510 // ---- 表示コード
511 code = sAsciiTable[c & 0x7f];
512
513 if (code == ASCII_TAB)
514 // ---- タブ
515 {
516 int tab_size = TAB_WIDTH - (cnt & (TAB_WIDTH - 1));
517 x += FONT_WIDTH * tab_size;
518 cnt += tab_size;
519 }
520 else
521 // ---- 1文字出力
522 {
523 // ---- 空白以外
524 if (code != ASCII_SP)
525 {
526 this->DrawChar(context, x, y, code);
527 }
528 x += FONT_WIDTH;
529 ++cnt;
530 }
531
532 if (cnt >= width)
533 {
534 if (*(str + 1) == '\n')
535 {
536 // 終端が改行の場合には次へ
537 ++str;
538 }
539 return str;
540 }
541 ++str;
542 }
543 return str;
544 }
545
546 //! @brief 文字を描画します。
547 //!
548 //! @param context コンテキストです。
549 //! @param x 文字を描画する位置のX座標です。
550 //! @param y 文字を描画する位置のY座標です。
551 //! @param code 描画する文字コードです。
552 //!
553 void
DrawChar(const PixelWriterContext & context,int x,int y,int code)554 DrawChar(const PixelWriterContext& context, int x, int y, int code)
555 {
556 int ncode = (code >= 100) ? (code - 100) : code;
557 int fontx = (ncode % FONT_ROW) * FONT_WIDTH;
558 int fonty = (ncode / FONT_ROW) * FONT_HEIGHT;
559 const u32* fontLine = (code < 100) ? (sFontData + fonty) : (sFontData2 + fonty);
560
561 // バッファ範囲から外れてる場合は出力しない
562 if (x < 0 || context.m_LimitX <= x + FONT_WIDTH)
563 {
564 return;
565 }
566
567 if (y < 0 || context.m_LimitY <= y + FONT_HEIGHT)
568 {
569 return;
570 }
571
572 for (int cnty = 0; cnty < FONT_HEIGHT; cnty++)
573 {
574 u32 fontBits = (*fontLine++) << fontx;
575
576 // フォントデータは左につめられてる。
577 // 左近傍のビットにアクセスできるように、1ビット余白を付加する。
578 fontBits = (fontBits & 0xfc000000) >> 1;
579
580 for (int cntx = 0; cntx < FONT_WIDTH; cntx += 1)
581 {
582 u8* pixel = this->GetPixelAddress(context, x + cntx, y + cnty);
583
584 if (fontBits & 0x40000000)
585 {
586 this->WritePixel(pixel, context.m_PixelColor);
587 }
588
589 fontBits <<= 1;
590 }
591 }
592 }
593
594 //! @brief 改行文字もしくは終端文字までの文字数を取得します。
595 //!
596 //! @details
597 //! タブ文字はスペースに展開されます。
598 //!
599 //! @param str 文字列へのポインタです。
600 //!
601 //! @return 文字数を返します。
602 //!
StrLineWidth(const char * str)603 int StrLineWidth(const char* str)
604 {
605 int len = 0;
606 char c;
607
608 NW_NULL_ASSERT(str);
609
610 while (true)
611 {
612 c = *str++;
613 if (c == '\0' || c == '\n')
614 {
615 return len;
616 }
617 if (c == '\t')
618 {
619 len = (len + TAB_WIDTH) & ~(TAB_WIDTH - 1);
620 }
621 else
622 {
623 ++len;
624 }
625 }
626 }
627
628 virtual int GetPixelSize() const = 0;
629 virtual void ErasePixel(u8* dest, const u8 pixel[4]) const = 0;
630 virtual void MakePixel(u8 pixel[4], ut::Color color) const = 0;
631 virtual void WritePixel(u8* dest, const u8 pixel[4]) const = 0;
632 };
633
634 class PixelWriter_RGBA8 : public PixelWriter
635 {
GetPixelSize() const636 virtual int GetPixelSize() const
637 {
638 return 4;
639 }
640
ErasePixel(u8 * dest,const u8 pixel[4]) const641 virtual void ErasePixel(u8* dest, const u8 pixel[4]) const
642 {
643 // アルファには手をつけない。
644
645 dest[1] = pixel[1]; // B
646 dest[2] = pixel[2]; // G
647 dest[3] = pixel[3]; // R
648 }
649
MakePixel(u8 pixel[4],ut::Color color) const650 virtual void MakePixel(u8 pixel[4], ut::Color color) const
651 {
652 pixel[0] = 255;
653 pixel[1] = color.b;
654 pixel[2] = color.g;
655 pixel[3] = color.r;
656 }
657
WritePixel(u8 * dest,const u8 pixel[4]) const658 virtual void WritePixel(u8* dest, const u8 pixel[4]) const
659 {
660 dest[0] = pixel[0]; // A
661 dest[1] = pixel[1]; // B
662 dest[2] = pixel[2]; // G
663 dest[3] = pixel[3]; // R
664 }
665 };
666
667 class PixelWriter_RGB8 : public PixelWriter
668 {
GetPixelSize() const669 virtual int GetPixelSize() const
670 {
671 return 3;
672 }
673
ErasePixel(u8 * dest,const u8 pixel[4]) const674 virtual void ErasePixel(u8* dest, const u8 pixel[4]) const
675 {
676 dest[0] = pixel[0]; // B
677 dest[1] = pixel[1]; // G
678 dest[2] = pixel[2]; // R
679 }
680
MakePixel(u8 pixel[4],ut::Color color) const681 virtual void MakePixel(u8 pixel[4], ut::Color color) const
682 {
683 pixel[0] = color.b;
684 pixel[1] = color.g;
685 pixel[2] = color.r;
686 }
687
WritePixel(u8 * dest,const u8 pixel[4]) const688 virtual void WritePixel(u8* dest, const u8 pixel[4]) const
689 {
690 dest[0] = pixel[0];
691 dest[1] = pixel[1];
692 dest[2] = pixel[2];
693 }
694 };
695
696 class PixelWriter_RGBA4 : public PixelWriter
697 {
GetPixelSize() const698 virtual int GetPixelSize() const
699 {
700 return 2;
701 }
702
ErasePixel(u8 * dest,const u8 pixel[4]) const703 virtual void ErasePixel(u8* dest, const u8 pixel[4]) const
704 {
705 // アルファには手をつけない。
706
707 dest[0] = (pixel[0] & ~0x0f) | (dest[0] & 0x0f);
708 dest[1] = pixel[1];
709 }
710
MakePixel(u8 pixel[4],ut::Color color) const711 virtual void MakePixel(u8 pixel[4], ut::Color color) const
712 {
713 u16 val = (color.r & 0xf0) << 8 | (color.g & 0xf0) << 4 | (color.b & 0xf0) | 0x0f;
714 pixel[0] = static_cast<u8>((val >> 0) & 0xff);
715 pixel[1] = static_cast<u8>((val >> 8) & 0xff);
716 }
717
WritePixel(u8 * dest,const u8 pixel[4]) const718 virtual void WritePixel(u8* dest, const u8 pixel[4]) const
719 {
720 dest[0] = pixel[0];
721 dest[1] = pixel[1];
722 }
723 };
724
725 class PixelWriter_RGB5A1 : public PixelWriter
726 {
GetPixelSize() const727 virtual int GetPixelSize() const
728 {
729 return 2;
730 }
731
ErasePixel(u8 * dest,const u8 pixel[4]) const732 virtual void ErasePixel(u8* dest, const u8 pixel[4]) const
733 {
734 // アルファには手をつけない。
735
736 dest[0] = (pixel[0] & ~0x01) | (dest[0] & 0x01);
737 dest[1] = pixel[1];
738 }
739
MakePixel(u8 pixel[4],ut::Color color) const740 virtual void MakePixel(u8 pixel[4], ut::Color color) const
741 {
742 u16 val = (color.r & 0xf8) << 8 | (color.g & 0xf8) << 3 | (color.b & 0xf8) >> 2 | 0x01;
743 pixel[0] = static_cast<u8>((val >> 0) & 0xff);
744 pixel[1] = static_cast<u8>((val >> 8) & 0xff);
745 }
746
WritePixel(u8 * dest,const u8 pixel[4]) const747 virtual void WritePixel(u8* dest, const u8 pixel[4]) const
748 {
749 dest[0] = pixel[0];
750 dest[1] = pixel[1];
751 }
752 };
753
754 class PixelWriter_RGB565 : public PixelWriter
755 {
GetPixelSize() const756 virtual int GetPixelSize() const
757 {
758 return 2;
759 }
760
ErasePixel(u8 * dest,const u8 pixel[4]) const761 virtual void ErasePixel(u8* dest, const u8 pixel[4]) const
762 {
763 dest[0] = pixel[0];
764 dest[1] = pixel[1];
765 }
766
MakePixel(u8 pixel[4],ut::Color color) const767 virtual void MakePixel(u8 pixel[4], ut::Color color) const
768 {
769 u16 val = (color.r & 0xf8) << 8 | (color.g & 0xfc) << 3 | (color.b & 0xf8) >> 3;
770 pixel[0] = static_cast<u8>((val >> 0) & 0xff);
771 pixel[1] = static_cast<u8>((val >> 8) & 0xff);
772 }
773
WritePixel(u8 * dest,const u8 pixel[4]) const774 virtual void WritePixel(u8* dest, const u8 pixel[4]) const
775 {
776 dest[0] = pixel[0];
777 dest[1] = pixel[1];
778 }
779 };
780
781
782 //! @brief フォーマットに対応するPixelWriterを取得します。
783 //!
784 //! @param format ピクセルのフォーマットです。
785 //!
786 //! @return PixelWriterへの参照を返します。
787 //!
788 PixelWriter&
GetPixelWriter_(GLuint format)789 GetPixelWriter_(GLuint format)
790 {
791 switch (format)
792 {
793 case GL_RGBA8_OES:
794 {
795 static PixelWriter_RGBA8 pixelWriterRGBA8;
796 return pixelWriterRGBA8;
797 }
798
799 case GL_RGB8_OES:
800 {
801 static PixelWriter_RGB8 pixelWriterRGB8;
802 return pixelWriterRGB8;
803 }
804
805 case GL_RGBA4:
806 {
807 static PixelWriter_RGBA4 pixelWriterRGBA4;
808 return pixelWriterRGBA4;
809 }
810
811 case GL_RGB5_A1:
812 {
813 static PixelWriter_RGB5A1 pixelWriterRGB5A1;
814 return pixelWriterRGB5A1;
815 }
816
817 case GL_RGB565:
818 {
819 static PixelWriter_RGB565 pixelWriterRGB565;
820 return pixelWriterRGB565;
821 }
822
823 default:
824 NW_FATAL_ERROR("unexpected pixel format (0x%x).", format);
825 return *(PixelWriter*)(-1);
826 }
827 }
828
829 } // namespace {anonymous}
830
831
DirectPrint()832 DirectPrint::DirectPrint()
833 : m_Initialized(false)
834 {
835 }
836
~DirectPrint()837 DirectPrint::~DirectPrint()
838 {
839 if (m_Initialized)
840 {
841 this->Finalize();
842 }
843 }
844
845 void
Initialize()846 DirectPrint::Initialize()
847 {
848 if (this->m_Initialized)
849 {
850 return;
851 }
852
853 this->SetTargetBuffer(NULL, 0, 320, 240);
854 this->SetColor(nw::ut::Color8::WHITE);
855 this->SetBackgroundColor(nw::ut::Color8::BLACK);
856 this->SetDirection(DIRECTION_VERTICAL);
857
858 m_Initialized = true;
859 }
860
861 void
Finalize()862 DirectPrint::Finalize()
863 {
864 if (m_Initialized)
865 {
866 m_Initialized = false;
867 }
868 }
869
870 bool
IsActive() const871 DirectPrint::IsActive() const
872 {
873 return m_Initialized && m_Buffer.m_Address != NULL;
874 }
875
876 void
SetTargetBuffer(void * buffer,GLuint format,u16 width,u16 height)877 DirectPrint::SetTargetBuffer(
878 void* buffer,
879 GLuint format,
880 u16 width,
881 u16 height)
882 {
883 m_Buffer.m_Address = static_cast<u8*>(buffer);
884 m_Buffer.m_Format = format;
885 m_Buffer.m_Width = width;
886 m_Buffer.m_Height = height;
887 }
888
889 void
SetTargetBuffer(void * buffer)890 DirectPrint::SetTargetBuffer(void* buffer)
891 {
892 m_Buffer.m_Address = static_cast<u8*>(buffer);
893 }
894
895 void
SetTargetActiveDisplayBuffer()896 DirectPrint::SetTargetActiveDisplayBuffer()
897 {
898 #ifdef NW_PLATFORM_CTR
899 GLint address = 0;
900 nngxGetDisplaybufferParameteri(NN_GX_DISPLAYBUFFER_ADDRESS, &address);
901 NW_ASSERT(address != 0);
902 GLint format = 0;
903 nngxGetDisplaybufferParameteri(NN_GX_DISPLAYBUFFER_FORMAT, &format);
904 GLint width = 0;
905 nngxGetDisplaybufferParameteri(NN_GX_DISPLAYBUFFER_WIDTH, &width);
906 GLint height = 0;
907 nngxGetDisplaybufferParameteri(NN_GX_DISPLAYBUFFER_HEIGHT, &height);
908 this->SetTargetBuffer(
909 reinterpret_cast<void*>(address),
910 format,
911 static_cast<u16>(width),
912 static_cast<u16>(height));
913
914 #else
915 NW_FATAL_ERROR("unavailable.");
916 #endif
917 }
918
919 void
StoreCache()920 DirectPrint::StoreCache()
921 {
922 // ---- 書き換えたフレームバッファをフラッシュ
923 // DCStoreRange(sFrameBufferInfo.frameMemory, sFrameBufferInfo.frameSize);
924 // TODO: キャッシュのストア
925
926 PixelWriter& pixelWriter = GetPixelWriter_(m_Buffer.m_Format);
927 size_t size = pixelWriter.GetPixelSize() * m_Buffer.m_Width * m_Buffer.m_Height;
928 nngxUpdateBuffer(m_Buffer.m_Address, size);
929 }
930
931 void
Erase(int x,int y,int width,int height)932 DirectPrint::Erase(int x, int y, int width, int height)
933 {
934 if (!this->IsActive())
935 {
936 return;
937 }
938
939 PixelWriter& pixelWriter = GetPixelWriter_(m_Buffer.m_Format);
940 pixelWriter.Erase(m_Buffer, m_Direction, x, y, width, height, m_BackgroundColor);
941 }
942
943 void
Printf(int x,int y,const char * format,...)944 DirectPrint::Printf(int x, int y, const char* format, ...)
945 {
946 std::va_list vargs;
947
948 va_start(vargs, format);
949
950 this->VPrintf(x, y, format, vargs, true, true);
951
952 va_end(vargs);
953 }
954
955 void
Printf(int x,int y,bool turnOver,const char * format,...)956 DirectPrint::Printf(int x, int y, bool turnOver, const char* format, ...)
957 {
958 std::va_list vargs;
959
960 va_start(vargs, format);
961
962 this->VPrintf(x, y, format, vargs, turnOver, true);
963
964 va_end(vargs);
965 }
966
967 void
Printf(int x,int y,bool turnOver,bool backErase,const char * format,...)968 DirectPrint::Printf(int x, int y, bool turnOver, bool backErase, const char* format, ...)
969 {
970 std::va_list vargs;
971
972 va_start(vargs, format);
973
974 this->VPrintf(x, y, format, vargs, turnOver, backErase);
975
976 va_end(vargs);
977 }
978
979 void
VPrintf(int x,int y,const char * format,std::va_list vargs,bool turnOver,bool backErase)980 DirectPrint::VPrintf(
981 int x,
982 int y,
983 const char* format,
984 std::va_list vargs,
985 bool turnOver,
986 bool backErase)
987 {
988 static const size_t BUFFER_SIZE = 256;
989 char buffer[BUFFER_SIZE];
990
991 int length = ut::vsnprintf(buffer, BUFFER_SIZE, BUFFER_SIZE-1, format, vargs);
992
993 if (length <= 0)
994 {
995 return;
996 }
997
998 this->DrawString(x, y, buffer, turnOver, backErase);
999 }
1000
1001 void
SetColor(ut::Color8 color)1002 DirectPrint::SetColor(ut::Color8 color)
1003 {
1004 m_Color = color;
1005 }
1006
1007 void
SetColor(u8 r,u8 g,u8 b)1008 DirectPrint::SetColor(u8 r, u8 g, u8 b)
1009 {
1010 m_Color = ut::Color(r, g, b, 255 /* unused */);
1011 }
1012
1013 ut::Color8
GetColor() const1014 DirectPrint::GetColor() const
1015 {
1016 return m_Color;
1017 }
1018
1019 void
SetBackgroundColor(ut::Color8 color)1020 DirectPrint::SetBackgroundColor(ut::Color8 color)
1021 {
1022 m_BackgroundColor = color;
1023 }
1024
1025 void
SetBackgroundColor(u8 r,u8 g,u8 b)1026 DirectPrint::SetBackgroundColor(u8 r, u8 g, u8 b)
1027 {
1028 m_BackgroundColor = ut::Color(r, g, b, 255 /* unused */);
1029 }
1030
1031 ut::Color8
GetBackgroundColor() const1032 DirectPrint::GetBackgroundColor() const
1033 {
1034 return m_BackgroundColor;
1035 }
1036
1037 void
SetDirection(Direction direction)1038 DirectPrint::SetDirection(Direction direction)
1039 {
1040 m_Direction = direction;
1041 }
1042
1043 DirectPrint::Direction
GetDirection() const1044 DirectPrint::GetDirection() const
1045 {
1046 return m_Direction;
1047 }
1048
1049 void
DrawString(int x,int y,const char * str,bool turnOver,bool backErase)1050 DirectPrint::DrawString(
1051 int x,
1052 int y,
1053 const char* str,
1054 bool turnOver,
1055 bool backErase)
1056 {
1057 NW_NULL_ASSERT(str);
1058
1059 if (!this->IsActive())
1060 {
1061 return;
1062 }
1063
1064 PixelWriter& pixelWriter = GetPixelWriter_(m_Buffer.m_Format);
1065 pixelWriter.DrawString(m_Buffer, m_Direction, m_Color, m_BackgroundColor, x, y, str, turnOver, backErase);
1066 }
1067
1068 } // namespace nw::dev
1069 } // namespace nw
1070 #endif
1071