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