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