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