CfgUSBLoader/source/console.c
2015-01-17 10:11:08 +00:00

1198 lines
27 KiB
C

// Transparency and fixes by oggzee
#include <stdlib.h>
#include <string.h>
#include <reent.h>
#include <errno.h>
#include <sys/param.h>
#include "ogc/machine/asm.h"
#include "ogc/machine/processor.h"
#include "ogc/color.h"
#include "ogc/cache.h"
#include "ogc/video.h"
#include "ogc/system.h"
#include "console.h"
#include "ogc/consol.h"
#include "ogc/usbgecko.h"
#include <stdio.h>
#include <sys/iosupport.h>
#include "util.h"
#include "version.h"
#include "pngu/pngu.h"
#include "net.h"
extern void *bg_buf_rgba;
extern void *bg_buf_ycbr;
//---------------------------------------------------------------------------------
const devoptab_t dotab_stdout = {
//---------------------------------------------------------------------------------
"stdout", // device name
0, // size of file structure
NULL, // device open
NULL, // device close
__console_write, // device write
NULL, // device read
NULL, // device seek
NULL, // device fstat
NULL, // device stat
NULL, // device link
NULL, // device unlink
NULL, // device chdir
NULL, // device rename
NULL, // device mkdir
0, // dirStateSize
NULL, // device diropen_r
NULL, // device dirreset_r
NULL, // device dirnext_r
NULL, // device dirclose_r
NULL // device statvfs_r
};
//color table YcbYcr
const unsigned int color_table_YcbYcr[] =
{
0x00800080, // 30 normal black
0x246A24BE, // 31 normal red
0x4856484B, // 32 normal green
0x6D416D8A, // 33 normal yellow
0x0DBE0D75, // 34 normal blue
0x32A932B4, // 35 normal magenta
0x56955641, // 36 normal cyan
0xC580C580, // 37 normal white
0x7B807B80, // 30 bright black
0x4C544CFF, // 31 bright red
0x95299512, // 32 bright green
0xE200E294, // 33 bright yellow
0x1CFF1C6B, // 34 bright blue
0x69D669ED, // 35 bright magenta
0xB2ABB200, // 36 bright cyan
0xFF80FF80, // 37 bright white
};
// RGBA
const unsigned int color_table[] =
{
0x000000FF, // 30 normal black
0x800000FF, // 31 normal red
0x008000FF, // 32 normal green
0x808000FF, // 33 normal yellow
0x000080FF, // 34 normal blue
0x800080FF, // 35 normal magenta
0x008080FF, // 36 normal cyan
0xB0B0B0FF, // 37 normal white
0x606060FF, // 30 bright black
0xFF0000FF, // 31 bright red
0x00FF00FF, // 32 bright green
0xFFFF00FF, // 33 bright yellow
0x0000FFFF, // 34 bright blue
0xFF00FFFF, // 35 bright magenta
0x00FFFFFF, // 36 bright cyan
0xFFFFFFFF, // 37 bright white
};
#define RGBA_COLOR_WHITE 0xFFFFFFFF
#define RGBA_COLOR_BLACK 0x000000FF
struct unifont_header *unifont = NULL;
u8 *unifont_glyph = NULL;
inline u32 RGB8x2_TO_YCbYCr(u8 *c1, u8 *c2)
{
return PNGU_RGB8_TO_YCbYCr(c1[0], c1[1], c1[2], c2[0], c2[1], c2[2]);
}
static u32 do_xfb_copy = FALSE;
static struct _console_data_s stdcon;
static struct _console_data_s *curr_con = NULL;
static void *_console_buffer = NULL;
// transparency
struct _c1
{
//char c;
wchar_t c;
int fg, bg;
};
//static void *_bg_buffer = NULL;
//static unsigned int _bg_color = COLOR_BLACK;
static unsigned int _bg_color = RGBA_COLOR_BLACK;
static int _c_buffer_size = 0;
static struct _c1 *_c_buffer = NULL;
static int _tr_enable = 0;
int __console_disable = 0;
int __console_scroll = 0;
static s32 __gecko_status = -1;
static u32 __gecko_safe = 0;
extern u8 console_font_8x16[];
extern u8 console_font_512[];
int fb_change = 0;
int retrace_cnt = 0;
int con_exception_mode = 0;
void __console_vipostcb(u32 retraceCnt)
{
if (retrace_cnt < 5) {
retrace_cnt++;
return;
}
if (!fb_change) return;
do_xfb_copy = TRUE;
__console_flush(0);
do_xfb_copy = FALSE;
}
void __console_flush(int retrace_min)
{
u32 ycnt,xcnt, fb_stride;
u32 *fb,*ptr;
if (!fb_change && retrace_min >= 0) {
if (retrace_min == 0) retrace_cnt = 0;
return;
}
if (retrace_cnt < retrace_min) return;
fb_change = 0;
retrace_cnt = 0;
if (__console_disable) return;
ptr = curr_con->destbuffer;
fb = VIDEO_GetCurrentFramebuffer()+(curr_con->target_y*curr_con->tgt_stride) + curr_con->target_x*VI_DISPLAY_PIX_SZ;
fb_stride = curr_con->tgt_stride/4 - (curr_con->con_xres/VI_DISPLAY_PIX_SZ);
for(ycnt=curr_con->con_yres;ycnt>0;ycnt--)
{
for(xcnt=curr_con->con_xres;xcnt>0;xcnt-=VI_DISPLAY_PIX_SZ)
{
*fb++ = *ptr++;
}
fb += fb_stride;
}
}
void __console_bg_grab(void *x_fb)
{
/*
u32 ycnt,xcnt, fb_stride;
u32 *fb,*ptr;
if (x_fb == NULL) x_fb = VIDEO_GetCurrentFramebuffer();
if (!_bg_buffer) return;
ptr = _bg_buffer;
fb = x_fb + (curr_con->target_y*curr_con->tgt_stride) + curr_con->target_x*VI_DISPLAY_PIX_SZ;
fb_stride = curr_con->tgt_stride/4 - (curr_con->con_xres/VI_DISPLAY_PIX_SZ);
for(ycnt=curr_con->con_yres;ycnt>0;ycnt--)
{
for(xcnt=curr_con->con_xres;xcnt>0;xcnt-=VI_DISPLAY_PIX_SZ)
{
*ptr++ = *fb++;
}
fb += fb_stride;
}
*/
}
int console_set_unifont(void *buf, int size)
{
unifont_header *u = (unifont_header*) buf;
char *end;
unifont = NULL;
unifont_glyph = NULL;
if (!buf) return -1;
if (size < sizeof(unifont_header) + 4) return -1;
/*
printf("head: %.8s\n", u->head_tag);
printf("index: %.4s\n", u->index_tag);
printf("glyph: %.4s\n", u->glyph_tag);
printf("max i: %04x\n", u->max_idx);
printf("siz g: %04x\n", u->glyph_size);
*/
if (memcmp(u->head_tag, "UNIFONT", 8)) return -1;
if (memcmp(u->index_tag, "INDX", 4)) return -1;
if (memcmp(u->glyph_tag, "GLYP", 4)) return -1;
if (u->max_idx != 0xFFFF) return -1;
if (size < sizeof(unifont_header) + u->glyph_size + 4) return -1;
end = buf + sizeof(unifont_header) + u->glyph_size * 16;
//printf("end: %.4s\n", end);
if (memcmp(end, "END", 4)) return -1;
unifont = u;
unifont_glyph = buf + sizeof(unifont_header);
return 0;
}
int console_load_unifont(char *fname)
{
FILE *f = NULL;
void *buf = NULL;
struct stat st;
u32 size;
s32 ret;
//printf("load %s\n", fname); Wpad_WaitButtons();
ret = stat(fname, &st);
if (ret != 0) return -1;
size = st.st_size;
buf = mem1_alloc(size);
if (!buf) return -1;
f = fopen(fname, "rb");
if (!f) goto err;
ret = fread(buf, 1, size, f);
fclose(f);
if (ret != size) goto err;
//printf("unifont: %d\n", size); Wpad_WaitButtons();
if (console_set_unifont(buf, size)) goto err;
/*printf("unifont: OK\n");
printf("機動戦士ガンダム MS戦線\n");
printf("機 動 戦 士 ガ ン ダ ム MS 戦 線\n");
Wpad_WaitButtons();*/
extern void unifont_cache_init();
unifont_cache_init();
return 0;
err:
SAFE_FREE(buf)
return -1;
}
static void _bg_console_draw_glyph(unsigned char *pbits)
{
console_data_s *con;
int ay;
unsigned int *ptr;
//unsigned char bg[8] = {0,0,0,0,0,0,0,0};
unsigned char *bg;
unsigned char bits;
unsigned int color;
unsigned int fgcolor;
//unsigned int bgcolor;
unsigned int nextline;
u8 *c1, *c2;
if(do_xfb_copy==TRUE) return;
if(!curr_con) return;
con = curr_con;
if(!bg_buf_rgba) return;
ptr = (unsigned int*)(con->destbuffer + ( con->con_stride * con->cursor_row * FONT_YSIZE ) + ((con->cursor_col * FONT_XSIZE / 2) * 4));
//bg = (unsigned char*)(bg_buf_rgba + ( con->target_y + con->cursor_row * FONT_YSIZE )*640*4 + (con->target_x + con->cursor_col * FONT_XSIZE) * 4 );
nextline = con->con_stride/4 - 4;
fgcolor = con->foreground;
//bgcolor = con->background;
for (ay = 0; ay < FONT_YSIZE; ay++)
{
/* hard coded loop unrolling ! */
/* this depends on FONT_XSIZE = 8*/
#if FONT_XSIZE == 8
bits = *pbits++;
bg = (unsigned char*)(bg_buf_rgba + ( con->target_y + con->cursor_row * FONT_YSIZE + ay)*640*4 + (con->target_x + con->cursor_col * FONT_XSIZE) * 4 );
/* bits 1 & 2 */
c1 = (bits & 0x80) ? (u8*)&fgcolor : &bg[0];
c2 = (bits & 0x40) ? (u8*)&fgcolor : &bg[4];
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
bg += 8;
/* bits 3 & 4 */
c1 = (bits & 0x20) ? (u8*)&fgcolor : &bg[0];
c2 = (bits & 0x10) ? (u8*)&fgcolor : &bg[4];
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
bg += 8;
/* bits 5 & 6 */
c1 = (bits & 0x08) ? (u8*)&fgcolor : &bg[0];
c2 = (bits & 0x04) ? (u8*)&fgcolor : &bg[4];
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
bg += 8;
/* bits 7 & 8 */
c1 = (bits & 0x02) ? (u8*)&fgcolor : &bg[0];
c2 = (bits & 0x01) ? (u8*)&fgcolor : &bg[4];
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
bg += 8;
/* next line */
ptr += nextline;
#else
#endif
}
}
static void _nc_console_draw_glyph(unsigned char *pbits)
{
console_data_s *con;
int ay;
unsigned int *ptr;
unsigned char bits;
unsigned int color;
unsigned int fgcolor, bgcolor;
unsigned int nextline;
u8 *c1, *c2;
if(do_xfb_copy==TRUE) return;
if(!curr_con) return;
con = curr_con;
ptr = (unsigned int*)(con->destbuffer + ( con->con_stride * con->cursor_row * FONT_YSIZE ) + ((con->cursor_col * FONT_XSIZE / 2) * 4));
nextline = con->con_stride/4 - 4;
fgcolor = con->foreground;
bgcolor = con->background;
for (ay = 0; ay < FONT_YSIZE; ay++)
{
/* hard coded loop unrolling ! */
/* this depends on FONT_XSIZE = 8*/
#if FONT_XSIZE == 8
bits = *pbits++;
/* bits 1 & 2 */
c1 = (bits & 0x80) ? (u8*)&fgcolor : (u8*)&bgcolor;
c2 = (bits & 0x40) ? (u8*)&fgcolor : (u8*)&bgcolor;
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
/* bits 3 & 4 */
c1 = (bits & 0x20) ? (u8*)&fgcolor : (u8*)&bgcolor;
c2 = (bits & 0x10) ? (u8*)&fgcolor : (u8*)&bgcolor;
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
/* bits 5 & 6 */
c1 = (bits & 0x08) ? (u8*)&fgcolor : (u8*)&bgcolor;
c2 = (bits & 0x04) ? (u8*)&fgcolor : (u8*)&bgcolor;
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
/* bits 7 & 8 */
c1 = (bits & 0x02) ? (u8*)&fgcolor : (u8*)&bgcolor;
c2 = (bits & 0x01) ? (u8*)&fgcolor : (u8*)&bgcolor;
color = RGB8x2_TO_YCbYCr(c1, c2);
*ptr++ = color;
/* next line */
ptr += nextline;
#else
#endif
}
}
static void _console_draw_glyph(unsigned char *pbits)
{
if (_tr_enable && curr_con->background == _bg_color) {
_bg_console_draw_glyph(pbits);
} else {
_nc_console_draw_glyph(pbits);
}
}
static void _nc_console_drawc(int c)
{
if (!curr_con) return;
unsigned char *pbits;
if (c <= 512) {
pbits = &curr_con->font[c * FONT_YSIZE];
_console_draw_glyph(pbits);
} else if (unifont && unifont->index[c]) {
u32 off = unifont->index[c] >> 8;
u32 len = unifont->index[c] & 0x0F;
pbits = &unifont_glyph[off * 16];
_console_draw_glyph(pbits);
if (len == 2) {
if (curr_con->cursor_col + 1 >= curr_con->con_cols) return;
curr_con->cursor_col++;
pbits = &unifont_glyph[(off+1) * 16];
_console_draw_glyph(pbits);
}
}
}
#if 0
// YcbYcr
static void _nc_console_drawc(int c)
{
console_data_s *con;
int ay;
unsigned int *ptr;
unsigned char *pbits;
unsigned char bits;
unsigned int color;
unsigned int fgcolor, bgcolor;
unsigned int nextline;
if(do_xfb_copy==TRUE) return;
if(!curr_con) return;
con = curr_con;
if (_tr_enable && _bg_buffer && con->background == _bg_color) {
_bg_console_drawc(c);
return;
}
ptr = (unsigned int*)(con->destbuffer + ( con->con_stride * con->cursor_row * FONT_YSIZE ) + ((con->cursor_col * FONT_XSIZE / 2) * 4));
pbits = &con->font[c * FONT_YSIZE];
nextline = con->con_stride/4 - 4;
fgcolor = con->foreground;
bgcolor = con->background;
for (ay = 0; ay < FONT_YSIZE; ay++)
{
/* hard coded loop unrolling ! */
/* this depends on FONT_XSIZE = 8*/
#if FONT_XSIZE == 8
bits = *pbits++;
/* bits 1 & 2 */
if ( bits & 0x80)
color = fgcolor & 0xFFFF00FF;
else
color = bgcolor & 0xFFFF00FF;
if (bits & 0x40)
color |= fgcolor & 0x0000FF00;
else
color |= bgcolor & 0x0000FF00;
*ptr++ = color;
/* bits 3 & 4 */
if ( bits & 0x20)
color = fgcolor & 0xFFFF00FF;
else
color = bgcolor & 0xFFFF00FF;
if (bits & 0x10)
color |= fgcolor & 0x0000FF00;
else
color |= bgcolor & 0x0000FF00;
*ptr++ = color;
/* bits 5 & 6 */
if ( bits & 0x08)
color = fgcolor & 0xFFFF00FF;
else
color = bgcolor & 0xFFFF00FF;
if (bits & 0x04)
color |= fgcolor & 0x0000FF00;
else
color |= bgcolor & 0x0000FF00;
*ptr++ = color;
/* bits 7 & 8 */
if ( bits & 0x02)
color = fgcolor & 0xFFFF00FF;
else
color = bgcolor & 0xFFFF00FF;
if (bits & 0x01)
color |= fgcolor & 0x0000FF00;
else
color |= bgcolor & 0x0000FF00;
*ptr++ = color;
/* next line */
ptr += nextline;
#else
#endif
}
}
#endif
static void __console_drawc(int c)
{
if(!curr_con) return;
if (_tr_enable && _c_buffer) {
int cidx = curr_con->cursor_row * curr_con->con_cols + curr_con->cursor_col;
_c_buffer[cidx].c = c;
_c_buffer[cidx].fg = curr_con->foreground;
_c_buffer[cidx].bg = curr_con->background;
}
_nc_console_drawc(c);
//fb_change = 1;
}
void _c_repaint();
void _bg_repaint()
{
/*
if (!_bg_buffer) return;
// clear
unsigned int c;
unsigned int *p;
unsigned int *bg;
c = (curr_con->con_xres * curr_con->con_yres)/2;
p = (unsigned int*)curr_con->destbuffer;
bg = _bg_buffer;
while(c--) *p++ = *bg++;
*/
unsigned int y;
unsigned int *p;
unsigned int *bg;
if (!bg_buf_ycbr) return;
p = (unsigned int*)curr_con->destbuffer;
bg = (unsigned int*)(bg_buf_ycbr + curr_con->target_y * 640 * 2 + curr_con->target_x * 2 );
for (y=0; y<curr_con->con_yres; y++) {
memcpy(p, bg, curr_con->con_xres * 2);
p += curr_con->con_xres / 2;
bg += 640/2;
}
}
void _bg_scroll()
{
// clear
_bg_repaint();
// scroll
memmove(_c_buffer, _c_buffer + curr_con->con_cols,
sizeof(struct _c1) * (curr_con->con_rows-1) * curr_con->con_cols);
// clear last
memset(_c_buffer + (curr_con->con_rows-1) * curr_con->con_cols, 0,
sizeof(struct _c1) * curr_con->con_cols);
// redraw characters
_c_repaint();
}
void _c_repaint()
{
// repaint
if (!_c_buffer) return;
int save_row = curr_con->cursor_row;
int save_col = curr_con->cursor_col;
int save_fg = curr_con->foreground;
int save_bg = curr_con->background;
int x, y, i = 0;
for (y=0; y < curr_con->con_rows - 1; y++) {
for (x=0; x < curr_con->con_cols; x++) {
curr_con->cursor_col = x;
curr_con->cursor_row = y;
curr_con->foreground = _c_buffer[i].fg;
curr_con->background = _c_buffer[i].bg;
if (_c_buffer[i].c) _nc_console_drawc(_c_buffer[i].c);
i++;
}
}
curr_con->cursor_row = save_row;
curr_con->cursor_col = save_col;
curr_con->foreground = save_fg;
curr_con->background = save_bg;
}
static void __console_clear(void)
{
console_data_s *con;
unsigned int c;
unsigned int color;
unsigned int *p;
if(!curr_con) return;
con = curr_con;
if (_tr_enable) {
_bg_repaint();
memset(_c_buffer, 0, _c_buffer_size);
} else {
c = (con->con_xres*con->con_yres)/2;
p = (unsigned int*)con->destbuffer;
color = RGB8x2_TO_YCbYCr((u8 *)&(con->background), (u8 *)&(con->background));
while (c--) *p++ = color;
}
con->cursor_row = 0;
con->cursor_col = 0;
con->saved_row = 0;
con->saved_col = 0;
}
void __console_enable(void *fb)
{
if(_tr_enable) {
__console_bg_grab(fb);
_bg_repaint();
_c_repaint();
}
__console_disable = 0;
__console_flush(-1);
}
void __console_init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride)
{
// note: this is called by the CODE DUMP handler (c_default_exceptionhandler)
if (yres > 480) yres = 480;
unsigned int level;
console_data_s *con = &stdcon;
_CPU_ISR_Disable(level);
_tr_enable = 0;
__console_disable = 0;
con->destbuffer = framebuffer;
con->con_xres = xres;
con->con_yres = yres;
con->con_cols = xres / FONT_XSIZE;
con->con_rows = yres / FONT_YSIZE;
con->con_stride = con->tgt_stride = stride;
con->target_x = xstart;
con->target_y = ystart;
con->font = console_font_8x16;
//con->foreground = COLOR_WHITE;
//con->background = COLOR_BLACK;
con->foreground = RGBA_COLOR_WHITE;
con->background = RGBA_COLOR_BLACK;
curr_con = con;
__console_clear();
fb_change = 1;
devoptab_list[STD_OUT] = &dotab_stdout;
devoptab_list[STD_ERR] = &dotab_stdout;
_CPU_ISR_Restore(level);
setvbuf(stdout, NULL , _IONBF, 0);
setvbuf(stderr, NULL , _IONBF, 0);
// print debug log
if (con_exception_mode == 0) {
void Music_PauseVoice(bool pause);
Music_PauseVoice(true);
__console_scroll = 1;
con_exception_mode = 1;
puts(dbg_log_buf);
fputs("cfg", stdout);
puts(CFG_VERSION_STR);
//memcpy((void *)0xC1300000, dbg_log_buf, DBG_LOG_SIZE);
}
con_exception_mode = 2;
}
void __console_init_ex(void *conbuffer,int tgt_xstart,int tgt_ystart,int tgt_stride,int con_xres,int con_yres,int con_stride)
{
unsigned int level;
console_data_s *con = &stdcon;
_CPU_ISR_Disable(level);
con->destbuffer = conbuffer;
con->target_x = tgt_xstart;
con->target_y = tgt_ystart;
con->con_xres = con_xres;
con->con_yres = con_yres;
con->tgt_stride = tgt_stride;
con->con_stride = con_stride;
con->con_cols = con_xres / FONT_XSIZE;
con->con_rows = con_yres / FONT_YSIZE;
con->cursor_row = 0;
con->cursor_col = 0;
con->saved_row = 0;
con->saved_col = 0;
//con->font = console_font_8x16;
con->font = console_font_512;
//con->foreground = COLOR_WHITE;
//con->background = COLOR_BLACK;
con->foreground = RGBA_COLOR_WHITE;
con->background = RGBA_COLOR_BLACK;
curr_con = con;
if(_tr_enable) {
__console_bg_grab(NULL);
con->background = _bg_color;
}
__console_clear();
fb_change = 1;
retrace_cnt = 0;
devoptab_list[STD_OUT] = &dotab_stdout;
devoptab_list[STD_ERR] = &dotab_stdout;
VIDEO_SetPostRetraceCallback(__console_vipostcb);
_CPU_ISR_Restore(level);
setvbuf(stdout, NULL , _IONBF, 0);
setvbuf(stderr, NULL , _IONBF, 0);
}
static int __console_parse_escsequence(char *pchr)
{
char chr;
console_data_s *con;
int i;
int parameters[3];
int para;
if(!curr_con) return -1;
con = curr_con;
/* set default value */
para = 0;
parameters[0] = 0;
parameters[1] = 0;
parameters[2] = 0;
/* scan parameters */
i = 0;
chr = *pchr;
while( (para < 3) && (chr >= '0') && (chr <= '9') )
{
while( (chr >= '0') && (chr <= '9') )
{
/* parse parameter */
parameters[para] *= 10;
parameters[para] += chr - '0';
pchr++;
i++;
chr = *pchr;
}
para++;
if( *pchr == ';' )
{
/* skip parameter delimiter */
pchr++;
i++;
}
chr = *pchr;
}
/* get final character */
chr = *pchr++;
i++;
switch(chr)
{
/////////////////////////////////////////
// Cursor directional movement
/////////////////////////////////////////
case 'A':
{
curr_con->cursor_row -= parameters[0];
if(curr_con->cursor_row < 0) curr_con->cursor_row = 0;
break;
}
case 'B':
{
curr_con->cursor_row += parameters[0];
if(curr_con->cursor_row >= curr_con->con_rows) curr_con->cursor_row = curr_con->con_rows - 1;
break;
}
case 'C':
{
curr_con->cursor_col += parameters[0];
if(curr_con->cursor_col >= curr_con->con_cols) curr_con->cursor_col = curr_con->con_cols - 1;
break;
}
case 'D':
{
curr_con->cursor_col -= parameters[0];
if(curr_con->cursor_col < 0) curr_con->cursor_col = 0;
break;
}
/////////////////////////////////////////
// Cursor position movement
/////////////////////////////////////////
case 'H':
case 'f':
{
curr_con->cursor_col = parameters[1];
curr_con->cursor_row = parameters[0];
if(curr_con->cursor_row >= curr_con->con_rows) curr_con->cursor_row = curr_con->con_rows - 1;
if(curr_con->cursor_col >= curr_con->con_cols) curr_con->cursor_col = curr_con->con_cols - 1;
break;
}
/////////////////////////////////////////
// Screen clear
/////////////////////////////////////////
case 'J':
{
/* different erase modes not yet supported, just clear all */
__console_clear();
break;
}
/////////////////////////////////////////
// Line clear
/////////////////////////////////////////
case 'K':
{
break;
}
/////////////////////////////////////////
// Save cursor position
/////////////////////////////////////////
case 's':
{
con->saved_col = con->cursor_col;
con->saved_row = con->cursor_row;
break;
}
/////////////////////////////////////////
// Load cursor position
/////////////////////////////////////////
case 'u':
con->cursor_col = con->saved_col;
con->cursor_row = con->saved_row;
break;
/////////////////////////////////////////
// SGR Select Graphic Rendition
/////////////////////////////////////////
case 'm':
{
// handle 30-37,39 for foreground color changes
if( (parameters[0] >= 30) && (parameters[0] <= 39) )
{
parameters[0] -= 30;
//39 is the reset code
if(parameters[0] == 9){
parameters[0] = 15;
}
else if(parameters[0] > 7){
parameters[0] = 7;
}
if(parameters[1] == 1)
{
// Intensity: Bold makes color bright
parameters[0] += 8;
}
con->foreground = color_table[parameters[0]];
}
// handle 40-47 for background color changes
else if( (parameters[0] >= 40) && (parameters[0] <= 47) )
{
parameters[0] -= 40;
if(parameters[1] == 1)
{
// Intensity: Bold makes color bright
parameters[0] += 8;
}
con->background = color_table[parameters[0]];
}
break;
}
}
return(i);
}
int __console_write(struct _reent *r,int fd,const char *ptr,size_t len)
{
int i = 0;
char *tmp = (char*)ptr;
console_data_s *con;
//char chr;
wchar_t chr;
if(__gecko_status>=0) {
if(__gecko_safe)
usb_sendbuffer_safe(__gecko_status,ptr,len);
else
usb_sendbuffer(__gecko_status,ptr,len);
}
if(!curr_con) return -1;
con = curr_con;
if(!tmp || len<=0) return -1;
// custom formatting of exception
switch (con_exception_mode) {
default:
case 0:
case 1:
break;
case 2:
if (strcasestr(ptr, "Exception")) {
while (*tmp == '\n') tmp++;
con_exception_mode++;
}
break;
case 3:
if (strcasestr(ptr, "STACK DUMP")) {
con_exception_mode++;
break;
}
return len;
case 4:
if (strcasestr(ptr, "CODE DUMP")) {
con_exception_mode++;
tmp = "\n\n";
len = 2;
}
break;
case 5:
if (strcasestr(ptr, "Reload")) {
con_exception_mode = 1;
//WII_LaunchTitle(TITLE_ID(0x00010001,0xAF1BF516)); // HBC 1.07
break;
}
return len;
}
i = 0;
while(*tmp!='\0' && i<len)
{
int k = 1;
chr = *tmp;
if (chr >= 0x80) {
// UTF-8 decode
k = mbtowc(&chr, tmp, MIN(6,len-i));
// ignore utf8 parse errors
if (k < 1) k = 1;
// font only contains the first 512 chars
if ((unsigned)chr >= 512) {
int map_chr = map_ufont(chr);
if (map_chr == 0 && (unsigned)chr <= 0xFFFF) {
if (unifont && unifont->index[(unsigned)chr]) {
// unifont containst almost all unicode chars
map_chr = chr;
// if len==2 and right border reached: wrap around
int len = unifont->index[(unsigned)chr] & 0x0F;
if (len > 1 && con->cursor_col + len > con->con_cols) {
// insert fake space
chr = ' ';
goto just_print;
}
}
}
chr = map_chr;
}
}
tmp += k;
i += k;
if ( (chr == 0x1b) && (*tmp == '[') )
{
/* escape sequence found */
int k;
tmp++;
i++;
k = __console_parse_escsequence(tmp);
tmp += k;
i += k;
}
else
{
switch(chr)
{
case '\n':
con->cursor_row++;
con->cursor_col = 0;
break;
case '\r':
con->cursor_col = 0;
break;
case '\b':
con->cursor_col--;
if(con->cursor_col < 0)
{
con->cursor_col = 0;
}
break;
case '\f':
con->cursor_row++;
break;
case '\t':
if(con->cursor_col%TAB_SIZE) con->cursor_col += (con->cursor_col%TAB_SIZE);
else con->cursor_col += TAB_SIZE;
break;
default:
just_print:
__console_drawc(chr);
con->cursor_col++;
if( con->cursor_col >= con->con_cols)
{
/* if right border reached wrap around */
con->cursor_row++;
con->cursor_col = 0;
}
}
}
if( con->cursor_row >= con->con_rows)
{
/* if bottom border reached scroll */
if (_tr_enable) {
_bg_scroll();
} else {
memcpy(con->destbuffer,
con->destbuffer+con->con_stride*(FONT_YSIZE*FONT_YFACTOR+FONT_YGAP),
con->con_stride*con->con_yres-FONT_YSIZE);
unsigned int cnt = (con->con_stride * (FONT_YSIZE * FONT_YFACTOR + FONT_YGAP))/4;
unsigned int *bptr = (unsigned int*)(con->destbuffer + con->con_stride * (con->con_yres - FONT_YSIZE));
unsigned int color = RGB8x2_TO_YCbYCr((u8 *)&(con->background), (u8 *)&(con->background));
while(cnt--)
*bptr++ = color;
}
if (__console_scroll)
{
// flush on screen
__console_flush(0);
VIDEO_WaitVSync();
}
con->cursor_row--;
}
}
fb_change = 1;
return i;
}
void CON_Init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride)
{
__console_init(framebuffer,xstart,ystart,xres,yres,stride);
}
/*
void _con_free_bg_buf()
{
if(_bg_buffer) free(_bg_buffer);
_bg_buffer = NULL;
if(_c_buffer) free(_c_buffer);
_c_buffer = NULL;
}
*/
/*
void _con_print_buf()
{
printf("\ncon_buf: %p\n", _console_buffer);
printf("_bg_buf: %p\n", _bg_buffer);
printf("_c_buf: %p\n", _c_buffer);
}
*/
void _con_alloc_buf(s32 *conW, s32 *conH)
{
int w = 640;
int h = 480;
int size;
if (conW && *conW > w) *conW = w;
if (conH && *conH > h) *conH = h;
if (_console_buffer) return;
size = w * h * VI_DISPLAY_PIX_SZ;
_c_buffer_size = sizeof(struct _c1) * (w / FONT_XSIZE) * (h / FONT_YSIZE);
_console_buffer = LARGE_memalign(32, size);
//_bg_buffer = LARGE_memalign(32, size);
_c_buffer = LARGE_memalign(32, _c_buffer_size);
}
s32 CON_InitEx(GXRModeObj *rmode, s32 conXOrigin,s32 conYOrigin,s32 conWidth,s32 conHeight)
{
VIDEO_SetPostRetraceCallback(NULL);
_con_alloc_buf(&conWidth, &conHeight);
/*
if(_console_buffer)
free(_console_buffer);
_console_buffer = malloc(conWidth*conHeight*VI_DISPLAY_PIX_SZ);
if(!_console_buffer) return -1;
_con_free_bg_buf();
*/
_tr_enable = 0;
__console_init_ex(_console_buffer,conXOrigin,conYOrigin,rmode->fbWidth*VI_DISPLAY_PIX_SZ,conWidth,conHeight,conWidth*VI_DISPLAY_PIX_SZ);
return 0;
}
s32 CON_InitTr(GXRModeObj *rmode, s32 conXOrigin,s32 conYOrigin,s32 conWidth,s32 conHeight, s32 bgColor)
{
VIDEO_SetPostRetraceCallback(NULL);
_con_alloc_buf(&conWidth, &conHeight);
/*
if(_console_buffer) free(_console_buffer);
_console_buffer = malloc(conWidth*conHeight*VI_DISPLAY_PIX_SZ);
if(!_console_buffer) return -1;
_con_free_bg_buf();
_bg_buffer = malloc(conWidth*conHeight*VI_DISPLAY_PIX_SZ);
if(!_bg_buffer) return -1;
_c_buffer_size = sizeof(struct _c1) * (conWidth / FONT_XSIZE) * (conHeight/FONT_YSIZE);
_c_buffer = malloc(_c_buffer_size);
if(!_c_buffer) return -1;
*/
memset(_c_buffer, 0, _c_buffer_size);
if (bgColor < 0 || bgColor > 15) bgColor = 0;
_bg_color = color_table[bgColor];
_tr_enable = 1;
__console_init_ex(_console_buffer,conXOrigin,conYOrigin,rmode->fbWidth*VI_DISPLAY_PIX_SZ,conWidth,conHeight,conWidth*VI_DISPLAY_PIX_SZ);
return 0;
}
void CON_GetMetrics(int *cols, int *rows)
{
if(curr_con) {
*cols = curr_con->con_cols;
*rows = curr_con->con_rows;
}
}
void CON_GetPosition(int *col, int *row)
{
if(curr_con) {
*col = curr_con->cursor_col;
*row = curr_con->cursor_row;
}
}
void CON_EnableGecko(int channel,int safe)
{
if(channel && (channel>1 || !usb_isgeckoalive(channel))) channel = -1;
__gecko_status = channel;
__gecko_safe = safe;
if(__gecko_status!=-1) {
devoptab_list[STD_OUT] = &dotab_stdout;
devoptab_list[STD_ERR] = &dotab_stdout;
// line buffered output for threaded apps when only using the usbgecko
if(!curr_con) {
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
}
}
}