1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     dbg_DirectPrint.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  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   $Rev: 48011 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/nstd.h>
17 #include <nn/nstd/nstd_String.h>
18 #include <nn/dbg/CTR/dbg_DirectPrint.h>
19 #include <gles2/gl2ext.h>
20 #include <nn/gx.h>
21 #include <nn/gx/CTR/gx_CommandAccess.h>
22 #include <nn/os.h>
23 
24 
25 namespace nn { namespace dbg { namespace CTR {
26 
27     namespace
28     {
29         //------------------------------------------------------------------------------
30         const bool FONT_BITMAP[ 96 ][ DirectPrint::FONT_HEIGHT ][ DirectPrint::FONT_WIDTH ] =
31         {
32             #include "dbg_DirectPrintResource.inc"
33         };
34 
GetByteByDot(GLenum format)35         s32 GetByteByDot( GLenum format )
36         {
37             switch( format )
38             {
39             case GL_RGBA8_OES:
40                 return 4;
41             case GL_RGB8_OES:
42                 return 3;
43             case GL_RGBA4:
44                 return 2;
45             case GL_RGB5_A1:
46                 return 2;
47             case GL_RGB565:
48                 return 2;
49             default:
50                 {
51                     NN_TPANIC_("Undefined format.");
52                 }
53                 return 0;
54             }
55         }
56 
57         //------------------------------------------------------------------------------
58     }
59 
60 //------------------------------------------------------------------------------
61 
DirectPrint()62 DirectPrint::DirectPrint()
63     : m_CurBuffer( NULL )
64     , m_BufferFormat( 0 )
65     , m_BufferSize( 0 , 0 )
66     , m_CharColor( 0xff , 0xff , 0xff , 0xff )
67     , m_BgColor  ( 0x00 , 0x00 , 0x00 , 0xff )
68     , m_LastCursorPos( 0 , 0 )
69     , m_FillSpace(true)
70 {
71 }
72 
73 //------------------------------------------------------------------------------
74 
~DirectPrint()75 DirectPrint::~DirectPrint()
76 {
77 }
78 
79 //------------------------------------------------------------------------------
80 
ChangeDisplaybuffer(void * dispbuf,GLenum format,const nn::math::VEC2 & size)81 void DirectPrint::ChangeDisplaybuffer( void* dispbuf, GLenum format, const nn::math::VEC2& size )
82 {
83     ChangeDisplaybuffer( dispbuf );
84     m_BufferFormat = format;
85     m_BufferSize = size;
86 }
87 
88 //------------------------------------------------------------------------------
89 
Flush()90 void DirectPrint::Flush()
91 {
92     s32 byteByDot = GetByteByDot( m_BufferFormat );
93     nn::gx::UpdateBuffer( m_CurBuffer, byteByDot * m_BufferSize.x * m_BufferSize.y );
94 }
95 
96 //------------------------------------------------------------------------------
97 
ChangeDisplaybuffer(void * dispbuf)98 void DirectPrint::ChangeDisplaybuffer( void* dispbuf )
99 {
100     NN_TASSERTMSG_( os::GetDeviceMemoryAddress() <= reinterpret_cast<uptr>(dispbuf)
101         && reinterpret_cast<uptr>(dispbuf) < os::GetDeviceMemoryAddress() + os::GetDeviceMemorySize(),
102         "'dispbuf' must be on DeviceMemory." );
103 
104     m_CurBuffer = reinterpret_cast<bit8*>( dispbuf );
105 }
106 
107 //------------------------------------------------------------------------------
108 
Printf(const nn::math::VEC2 & pos,const char * format,...)109 void DirectPrint::Printf( const nn::math::VEC2& pos, const char* format, ... )
110 {
111     va_list v;
112     va_start( v, format );
113     VPrintf( pos, format, v );
114     va_end( v );
115 }
116 
117 //------------------------------------------------------------------------------
118 
Printf(const nn::math::VEC2 & pos,bool autoLineFeed,bool fillBg,const char * format,...)119 void DirectPrint::Printf( const nn::math::VEC2& pos, bool autoLineFeed, bool fillBg, const char* format, ... )
120 {
121     va_list v;
122     va_start( v, format );
123     VPrintf( pos, autoLineFeed, fillBg, format, v );
124     va_end( v );
125 }
126 
127 //------------------------------------------------------------------------------
128 
VPrintf(const nn::math::VEC2 & pos,const char * format,va_list v)129 void DirectPrint::VPrintf( const nn::math::VEC2& pos, const char* format, va_list v )
130 {
131     VPrintf( pos, true, true, format, v );
132 }
133 
134 //------------------------------------------------------------------------------
135 
VPrintf(const nn::math::VEC2 & pos,bool autoLineFeed,bool fillBg,const char * format,va_list v)136 void DirectPrint::VPrintf( const nn::math::VEC2& pos, bool autoLineFeed, bool fillBg, const char* format, va_list v )
137 {
138     char buf[ 256 ] = {};
139     nn::nstd::TVSNPrintf( buf , sizeof( buf ) , format , v );
140     PutString( pos, autoLineFeed, fillBg, buf );
141 }
142 
143 //------------------------------------------------------------------------------
144 
PutString(const nn::math::VEC2 & pos,const char * str)145 void DirectPrint::PutString( const nn::math::VEC2& pos, const char* str )
146 {
147     PutString( pos, true, true, str );
148 }
149 
150 //------------------------------------------------------------------------------
151 
PutString(const nn::math::VEC2 & pos,bool autoLineFeed,bool fillBg,const char * str)152 void DirectPrint::PutString( const nn::math::VEC2& pos, bool autoLineFeed, bool fillBg, const char* str )
153 {
154     nn::math::VEC2 cursor = pos;
155     const s32 boxWidth = 320; // Assumed to appear only on the lower screen
156     int offset = 0;
157 
158     while ( str[ offset ] != '\0' )
159     {
160         char c = str[ offset ];
161         if ( c == '\0' )
162         {
163             break;
164         }
165         if ( c != '\n' )
166         {
167             // 1 character display.
168             PutChar( cursor, fillBg, c );
169             // Move cursor.
170             cursor.x += FONT_WIDTH;
171         }
172         // Move to next character here to make processing convenient.
173         ++ offset;
174         // Newline
175         if ( c == '\n' || ( autoLineFeed && str[ offset ] != '\n' && cursor.x + FONT_WIDTH >= boxWidth ) )
176         {
177             cursor.x = 0;
178             cursor.y += FONT_HEIGHT;
179         }
180     }
181     m_LastCursorPos = cursor;
182 }
183 
184 //------------------------------------------------------------------------------
185 
PutChar(const nn::math::VEC2 & pos,char c)186 void DirectPrint::PutChar( const nn::math::VEC2& pos, char c )
187 {
188     PutChar( pos, true, c );
189 }
190 
191 //------------------------------------------------------------------------------
192 
PutChar(const nn::math::VEC2 & pos,bool fillBg,char c)193 void DirectPrint::PutChar( const nn::math::VEC2& pos, bool fillBg, char c )
194 {
195     // Convert to data format already in memory.
196     s32 byteByDot = GetByteByDot( m_BufferFormat );
197     bit8 charColorData[ 4 ];
198     bit8 bgColorData[ 4 ];
199     ConvertColorFormat( charColorData, m_CharColor, m_BufferFormat );
200     ConvertColorFormat( bgColorData, m_BgColor, m_BufferFormat );
201     // Recalculate to coordinates in buffer.
202     nn::math::VEC2 bufPos;
203     ConvertPositionUserOriginToDeviceOrigin( &bufPos, pos + nn::math::VEC2( 0, FONT_HEIGHT ) );
204     // Printing possible?
205     bool printable;
206     if ( ( 0 <= c && c <= 0x20 ) || c == 0x7f )
207     {
208         printable = false;
209     }
210     else
211     {
212         printable = true;
213     }
214 
215     // Fill in starting from bottom left
216     for( s32 y = 0; y < FONT_WIDTH; y++ )
217     {
218         // Skip if outside screen
219         if ( bufPos.y + y >= m_BufferSize.x || bufPos.y + y < 0 )
220         {
221             continue;
222         }
223         for( s32 x = 0; x < FONT_HEIGHT; x++ )
224         {
225             // Skip if outside screen
226             if ( bufPos.x + x >= m_BufferSize.y || bufPos.x + x < 0 )
227             {
228                 continue;
229             }
230             if( printable && FONT_BITMAP[ c - ' ' ][ int( FONT_HEIGHT ) - x - 1 ][ y ] )
231             {
232                 PutDot( nn::math::VEC2( bufPos.x + x, bufPos.y + y ), charColorData, byteByDot );
233             }
234             else if( fillBg )
235             {
236                 if( printable || m_FillSpace )
237                 {
238                     PutDot( nn::math::VEC2( bufPos.x + x, bufPos.y + y ), bgColorData, byteByDot );
239                 }
240             }
241         }
242     }
243 }
244 
245 //------------------------------------------------------------------------------
246 
Clear()247 void DirectPrint::Clear()
248 {
249     nn::math::VEC2 pos( 0 , 0 );
250     nn::math::VEC2 size( 320 , 240 );
251 
252     // Convert to data format already in memory
253     s32 byteByDot = GetByteByDot( m_BufferFormat );
254     bit8 bgColorData[ 4 ];
255     ConvertColorFormat( bgColorData, m_BgColor, m_BufferFormat );
256 
257     // Recalculate to coordinates in buffer.
258     nn::math::VEC2 bufPos;
259     ConvertPositionUserOriginToDeviceOrigin( &bufPos, pos + nn::math::VEC2( 0, size.y ) );
260     // Fill in starting from bottom left
261     for( s32 y = 0; y < size.x; y++ )
262     {
263         // Skip if outside screen
264         if ( bufPos.y + y >= m_BufferSize.x || bufPos.y + y < 0 )
265         {
266             continue;
267         }
268         for( s32 x = 0; x < size.y; x++ )
269         {
270             // Skip if outside screen
271             if ( bufPos.x + x >= m_BufferSize.y || bufPos.x + x < 0 )
272             {
273                 continue;
274             }
275             PutDot( nn::math::VEC2( bufPos.x + x, bufPos.y + y ), bgColorData, byteByDot );
276         }
277     }
278 }
279 
280 //------------------------------------------------------------------------------
281 
ConvertColorFormat(bit8 * data,const nn::util::Color8 & src,GLenum format)282 void DirectPrint::ConvertColorFormat( bit8* data, const nn::util::Color8& src, GLenum format )
283 {
284     // Actually, sometimes not all data is filled in because only up to the range returned by GetByteByDot is used.
285     switch( format )
286     {
287     case GL_RGB8_OES:
288         {
289             data[ 0 ] = src.b;
290             data[ 1 ] = src.g;
291             data[ 2 ] = src.r;
292         }
293         break;
294     case GL_RGBA4:
295         {
296             data[ 0 ] = ( src.b & 0xf0 ) | ( src.a >> 4 );
297             data[ 1 ] =( src.r & 0xf0 ) | ( src.g >> 4 );
298         }
299         break;
300     case GL_RGB5_A1:
301         {
302             data[ 0 ] = ( ( src.a & 0x80 ) >> 7 ) | ( ( src.b & 0xf8 ) >> 2 ) | ( ( src.g & 0x3 ) << 6 );
303             data[ 1 ] = ( ( src.g & 0x38 ) >> 3 ) | ( src.r & 0xf8 );
304         }
305         break;
306     case GL_RGB565:
307         {
308             data[ 0 ] = ( ( src.g & 0x1c ) << 5 ) | ( src.b >> 3 );
309             data[ 1 ] = ( ( src.r & 0xf8 ) | ( ( src.g & 0xe0 ) >> 5 ) );
310         }
311         break;
312     default:
313         return;
314     }
315 }
316 
317 //------------------------------------------------------------------------------
318 
ConvertPositionUserOriginToDeviceOrigin(nn::math::VEC2 * dst,const nn::math::VEC2 & src)319 void DirectPrint::ConvertPositionUserOriginToDeviceOrigin( nn::math::VEC2* dst, const nn::math::VEC2& src )
320 {
321     dst->x = m_BufferSize.y - src.y;
322     dst->y = src.x;
323 }
324 
325 //------------------------------------------------------------------------------
326 
PutDot(const nn::math::VEC2 & bufPos,const bit8 * data,s32 byteByDot)327 void DirectPrint::PutDot( const nn::math::VEC2& bufPos, const bit8* data, s32 byteByDot )
328 {
329     s32 linearPos = int( bufPos.y ) * int( m_BufferSize.y ) + int( bufPos.x );
330     bit8* startAddr = m_CurBuffer + linearPos * byteByDot;
331     nn::nstd::MemCpy( startAddr, data, byteByDot );
332 }
333 
334 }}}
335