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