// This code is part of libctru. // https://github.com/devkitPro/libctru #include #include #include "types.h" #include "drivers/gfx.h" #include "arm11/console.h" #include "arm11/fmt.h" #include "util.h" #include "arm11/font_6x10.h" //set up the palette for color printing static u16 colorTable[] = { BGR8_2_565( 0, 0, 0), // black BGR8_2_565(128, 0, 0), // red BGR8_2_565( 0,128, 0), // green BGR8_2_565(128,128, 0), // yellow BGR8_2_565( 0, 0,128), // blue BGR8_2_565(128, 0,128), // magenta BGR8_2_565( 0,128,128), // cyan BGR8_2_565(192,192,192), // white BGR8_2_565(128,128,128), // bright black BGR8_2_565(255, 0, 0), // bright red BGR8_2_565( 0,255, 0), // bright green BGR8_2_565(255,255, 0), // bright yellow BGR8_2_565( 0, 0,255), // bright blue BGR8_2_565(255, 0,255), // bright magenta BGR8_2_565( 0,255,255), // bright cyan BGR8_2_565(255,255,255), // bright white BGR8_2_565( 0, 0, 0), // faint black BGR8_2_565( 64, 0, 0), // faint red BGR8_2_565( 0, 64, 0), // faint green BGR8_2_565( 64, 64, 0), // faint yellow BGR8_2_565( 0, 0, 64), // faint blue BGR8_2_565( 64, 0, 64), // faint magenta BGR8_2_565( 0, 64, 64), // faint cyan BGR8_2_565( 96, 96, 96), // faint white }; static const u8 colorCube[] = { 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff, }; static const u8 grayScale[] = { 0x08, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e, 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee, }; PrintConsole defaultConsole = { //Font: { (u8*)default_font, //font gfx 0, //first ascii character in the set 256 //number of characters in the font set }, (u16*)NULL, 0,0, //cursorX cursorY 0,0, //prevcursorX prevcursorY 53, //console width 24, //console height 0, //window x 0, //window y 53, //window width 24, //window height 3, //tab size 15, // foreground color 0, // background color 0, // flags 0, //print callback false //console initialized }; PrintConsole currentCopy; PrintConsole* currentConsole = ¤tCopy; PrintConsole* consoleGetDefault(void){return &defaultConsole;} void consolePrintChar(int c); void consoleDrawChar(int c); //--------------------------------------------------------------------------------- static void consoleCls(int mode) { //--------------------------------------------------------------------------------- int i = 0; int colTemp,rowTemp; switch (mode) { case 0: { colTemp = currentConsole->cursorX ; rowTemp = currentConsole->cursorY ; while(i++ < ((currentConsole->windowHeight * currentConsole->windowWidth) - (rowTemp * currentConsole->consoleWidth + colTemp))) consolePrintChar(' '); currentConsole->cursorX = colTemp; currentConsole->cursorY = rowTemp; break; } case 1: { colTemp = currentConsole->cursorX ; rowTemp = currentConsole->cursorY ; currentConsole->cursorY = 0; currentConsole->cursorX = 0; while (i++ < (rowTemp * currentConsole->windowWidth + colTemp)) consolePrintChar(' '); currentConsole->cursorX = colTemp; currentConsole->cursorY = rowTemp; break; } case 2: { currentConsole->cursorY = 0; currentConsole->cursorX = 0; while(i++ < currentConsole->windowHeight * currentConsole->windowWidth) consolePrintChar(' '); currentConsole->cursorY = 0; currentConsole->cursorX = 0; break; } } GFX_flushBuffers(); } //--------------------------------------------------------------------------------- static void consoleClearLine(int mode) { //--------------------------------------------------------------------------------- int i = 0; int colTemp; switch (mode) { case 0: { colTemp = currentConsole->cursorX ; while(i++ < (currentConsole->windowWidth - colTemp)) { consolePrintChar(' '); } currentConsole->cursorX = colTemp; break; } case 1: { colTemp = currentConsole->cursorX ; currentConsole->cursorX = 0; while(i++ < ((currentConsole->windowWidth - colTemp)-2)) { consolePrintChar(' '); } currentConsole->cursorX = colTemp; break; } case 2: { colTemp = currentConsole->cursorX ; currentConsole->cursorX = 0; while(i++ < currentConsole->windowWidth) { consolePrintChar(' '); } currentConsole->cursorX = colTemp; break; } } GFX_flushBuffers(); } //--------------------------------------------------------------------------------- static inline void consolePosition(int x, int y) { //--------------------------------------------------------------------------------- // invalid position if(x < 0 || y < 0) return; // 1-based, but we'll take a 0 if(x < 1) x = 1; if(y < 1) y = 1; // clip to console edge if(x > currentConsole->windowWidth) x = currentConsole->windowWidth; if(y > currentConsole->windowHeight) y = currentConsole->windowHeight; // 1-based adjustment currentConsole->cursorX = x - 1; currentConsole->cursorY = y - 1; } static struct { union { struct { int movement; } directional; struct { int y; int x; } absolute; struct { int type; } clear; struct { int args[3]; int flags; u16 fg; u16 bg; } color; int rawBuf[5]; }; int argIdx; bool hasArg[3]; enum ESC_STATE { ESC_NONE, ESC_START, ESC_BUILDING_UNKNOWN, ESC_BUILDING_FORMAT_UNKNOWN, ESC_BUILDING_FORMAT_FG, ESC_BUILDING_FORMAT_BG, ESC_BUILDING_FORMAT_FG_NONRGB, ESC_BUILDING_FORMAT_BG_NONRGB, ESC_BUILDING_FORMAT_FG_RGB, ESC_BUILDING_FORMAT_BG_RGB, } state; } escapeSeq; static void consoleHandleColorEsc(int code) { switch (escapeSeq.state) { case ESC_BUILDING_FORMAT_UNKNOWN: switch (code) { case 0: // reset escapeSeq.color.flags = 0; escapeSeq.color.bg = 0; escapeSeq.color.fg = 15; break; case 1: // bold escapeSeq.color.flags &= ~CONSOLE_COLOR_FAINT; escapeSeq.color.flags |= CONSOLE_COLOR_BOLD; break; case 2: // faint escapeSeq.color.flags &= ~CONSOLE_COLOR_BOLD; escapeSeq.color.flags |= CONSOLE_COLOR_FAINT; break; case 3: // italic escapeSeq.color.flags |= CONSOLE_ITALIC; break; case 4: // underline escapeSeq.color.flags |= CONSOLE_UNDERLINE; break; case 5: // blink slow escapeSeq.color.flags &= ~CONSOLE_BLINK_FAST; escapeSeq.color.flags |= CONSOLE_BLINK_SLOW; break; case 6: // blink fast escapeSeq.color.flags &= ~CONSOLE_BLINK_SLOW; escapeSeq.color.flags |= CONSOLE_BLINK_FAST; break; case 7: // reverse video escapeSeq.color.flags |= CONSOLE_COLOR_REVERSE; break; case 8: // conceal escapeSeq.color.flags |= CONSOLE_CONCEAL; break; case 9: // crossed-out escapeSeq.color.flags |= CONSOLE_CROSSED_OUT; break; case 21: // bold off escapeSeq.color.flags &= ~CONSOLE_COLOR_BOLD; break; case 22: // normal color escapeSeq.color.flags &= ~CONSOLE_COLOR_BOLD; escapeSeq.color.flags &= ~CONSOLE_COLOR_FAINT; break; case 23: // italic off escapeSeq.color.flags &= ~CONSOLE_ITALIC; break; case 24: // underline off escapeSeq.color.flags &= ~CONSOLE_UNDERLINE; break; case 25: // blink off escapeSeq.color.flags &= ~CONSOLE_BLINK_SLOW; escapeSeq.color.flags &= ~CONSOLE_BLINK_FAST; break; case 27: // reverse off escapeSeq.color.flags &= ~CONSOLE_COLOR_REVERSE; break; case 29: // crossed-out off escapeSeq.color.flags &= ~CONSOLE_CROSSED_OUT; break; case 30 ... 37: // writing color escapeSeq.color.flags &= ~CONSOLE_FG_CUSTOM; escapeSeq.color.fg = code - 30; break; case 38: // custom foreground color escapeSeq.state = ESC_BUILDING_FORMAT_FG; break; case 39: // reset foreground color escapeSeq.color.flags &= ~CONSOLE_FG_CUSTOM; escapeSeq.color.fg = 15; break; case 40 ... 47: // screen color escapeSeq.color.flags &= ~CONSOLE_BG_CUSTOM; escapeSeq.color.bg = code - 40; break; case 48: // custom background color escapeSeq.state = ESC_BUILDING_FORMAT_BG; break; case 49: // reset background color escapeSeq.color.flags &= ~CONSOLE_BG_CUSTOM; escapeSeq.color.fg = 0; break; } break; case ESC_BUILDING_FORMAT_FG: if (escapeSeq.color.args[0] == 5) escapeSeq.state = ESC_BUILDING_FORMAT_FG_NONRGB; else if (escapeSeq.color.args[0] == 2) escapeSeq.state = ESC_BUILDING_FORMAT_FG_RGB; else escapeSeq.state = ESC_BUILDING_FORMAT_UNKNOWN; break; case ESC_BUILDING_FORMAT_BG: if (escapeSeq.color.args[0] == 5) escapeSeq.state = ESC_BUILDING_FORMAT_BG_NONRGB; else if (escapeSeq.color.args[0] == 2) escapeSeq.state = ESC_BUILDING_FORMAT_BG_RGB; else escapeSeq.state = ESC_BUILDING_FORMAT_UNKNOWN; break; case ESC_BUILDING_FORMAT_FG_NONRGB: if (code <= 15) { escapeSeq.color.fg = code; escapeSeq.color.flags &= ~CONSOLE_FG_CUSTOM; } else if (code <= 231) { code -= 16; unsigned int r = code / 36; unsigned int g = (code - r * 36) / 6; unsigned int b = code - r * 36 - g * 6; escapeSeq.color.fg = BGR8_2_565(colorCube[r], colorCube[g], colorCube[b]); escapeSeq.color.flags |= CONSOLE_FG_CUSTOM; } else if (code <= 255) { code -= 232; escapeSeq.color.fg = BGR8_2_565(grayScale[code], grayScale[code], grayScale[code]); escapeSeq.color.flags |= CONSOLE_FG_CUSTOM; } escapeSeq.state = ESC_BUILDING_FORMAT_UNKNOWN; break; case ESC_BUILDING_FORMAT_BG_NONRGB: if (code <= 15) { escapeSeq.color.bg = code; escapeSeq.color.flags &= ~CONSOLE_BG_CUSTOM; } else if (code <= 231) { code -= 16; unsigned int r = code / 36; unsigned int g = (code - r * 36) / 6; unsigned int b = code - r * 36 - g * 6; escapeSeq.color.bg = BGR8_2_565(colorCube[r], colorCube[g], colorCube[b]); escapeSeq.color.flags |= CONSOLE_BG_CUSTOM; } else if (code <= 255) { code -= 232; escapeSeq.color.bg = BGR8_2_565(grayScale[code], grayScale[code], grayScale[code]); escapeSeq.color.flags |= CONSOLE_BG_CUSTOM; } escapeSeq.state = ESC_BUILDING_FORMAT_UNKNOWN; break; case ESC_BUILDING_FORMAT_FG_RGB: escapeSeq.color.fg = BGR8_2_565((unsigned int)escapeSeq.color.args[0], (unsigned int)escapeSeq.color.args[1], (unsigned int)escapeSeq.color.args[2]); escapeSeq.color.flags |= CONSOLE_FG_CUSTOM; escapeSeq.state = ESC_BUILDING_FORMAT_UNKNOWN; break; case ESC_BUILDING_FORMAT_BG_RGB: escapeSeq.color.bg = BGR8_2_565((unsigned int)escapeSeq.color.args[0], (unsigned int)escapeSeq.color.args[1], (unsigned int)escapeSeq.color.args[2]); escapeSeq.color.flags |= CONSOLE_BG_CUSTOM; escapeSeq.state = ESC_BUILDING_FORMAT_UNKNOWN; break; default: break; } escapeSeq.argIdx = 0; } static void consoleColorStateShift(void) { switch (escapeSeq.state) { case ESC_BUILDING_UNKNOWN: escapeSeq.state = ESC_BUILDING_FORMAT_UNKNOWN; if (escapeSeq.hasArg[0]) consoleHandleColorEsc(escapeSeq.color.args[0]); if (escapeSeq.hasArg[1]) consoleHandleColorEsc(escapeSeq.color.args[1]); escapeSeq.argIdx = 0; escapeSeq.hasArg[0] = escapeSeq.hasArg[1] = false; break; case ESC_BUILDING_FORMAT_BG: case ESC_BUILDING_FORMAT_FG: case ESC_BUILDING_FORMAT_FG_NONRGB: case ESC_BUILDING_FORMAT_BG_NONRGB: consoleHandleColorEsc(escapeSeq.color.args[0]); escapeSeq.argIdx = 0; escapeSeq.hasArg[0] = escapeSeq.hasArg[1] = false; break; case ESC_BUILDING_FORMAT_FG_RGB: case ESC_BUILDING_FORMAT_BG_RGB: if (escapeSeq.argIdx < 3) escapeSeq.argIdx++; else consoleHandleColorEsc(0); // Nothing passed here because three RGB items break; default: break; } } static void consoleColorApply(void) { currentConsole->bg = escapeSeq.color.bg; currentConsole->fg = escapeSeq.color.fg; currentConsole->flags = escapeSeq.color.flags; } //--------------------------------------------------------------------------------- ssize_t con_write(/*struct _reent *r,void *fd,*/const char *ptr, size_t len) { //--------------------------------------------------------------------------------- char chr; int i, count = 0; char *tmp = (char*)ptr; if(!tmp) return -1; i = 0; while(i<(int)len) { chr = *(tmp++); i++; count++; switch (escapeSeq.state) { case ESC_NONE: if (chr == 0x1b) escapeSeq.state = ESC_START; else consolePrintChar(chr); break; case ESC_START: if (chr == '[') { escapeSeq.state = ESC_BUILDING_UNKNOWN; memset(escapeSeq.rawBuf, 0, sizeof(escapeSeq.rawBuf)); memset(escapeSeq.hasArg, 0, sizeof(escapeSeq.hasArg)); escapeSeq.color.bg = currentConsole->bg; escapeSeq.color.fg = currentConsole->fg; escapeSeq.color.flags = currentConsole->flags; escapeSeq.argIdx = 0; } else { consolePrintChar(0x1b); consolePrintChar(chr); escapeSeq.state = ESC_NONE; } break; case ESC_BUILDING_UNKNOWN: switch (chr) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': escapeSeq.hasArg[escapeSeq.argIdx] = true; escapeSeq.rawBuf[escapeSeq.argIdx] = escapeSeq.rawBuf[escapeSeq.argIdx] * 10 + (chr - '0'); break; case ';': if (escapeSeq.argIdx < 2) escapeSeq.argIdx++; else consoleColorStateShift(); break; //--------------------------------------- // Cursor directional movement //--------------------------------------- case 'A': if (!escapeSeq.hasArg[0]) escapeSeq.directional.movement = 1; currentConsole->cursorY = (currentConsole->cursorY - escapeSeq.directional.movement) < 0 ? 0 : currentConsole->cursorY - escapeSeq.directional.movement; escapeSeq.state = ESC_NONE; break; case 'B': if (!escapeSeq.hasArg[0]) escapeSeq.directional.movement = 1; currentConsole->cursorY = (currentConsole->cursorY + escapeSeq.directional.movement) > currentConsole->windowHeight - 1 ? currentConsole->windowHeight - 1 : currentConsole->cursorY + escapeSeq.directional.movement; escapeSeq.state = ESC_NONE; break; case 'C': if (!escapeSeq.hasArg[0]) escapeSeq.directional.movement = 1; currentConsole->cursorX = (currentConsole->cursorX + escapeSeq.directional.movement) > currentConsole->windowWidth - 1 ? currentConsole->windowWidth - 1 : currentConsole->cursorX + escapeSeq.directional.movement; escapeSeq.state = ESC_NONE; break; case 'D': if (!escapeSeq.hasArg[0]) escapeSeq.directional.movement = 1; currentConsole->cursorX = (currentConsole->cursorX - escapeSeq.directional.movement) < 0 ? 0 : currentConsole->cursorX - escapeSeq.directional.movement; escapeSeq.state = ESC_NONE; break; //--------------------------------------- // Cursor position movement //--------------------------------------- case 'H': case 'f': consolePosition(escapeSeq.hasArg[1] ? escapeSeq.absolute.x : 1, escapeSeq.hasArg[0] ? escapeSeq.absolute.y : 1); escapeSeq.state = ESC_NONE; break; //--------------------------------------- // Screen clear //--------------------------------------- case 'J': consoleCls(escapeSeq.hasArg[0] ? escapeSeq.clear.type : 0); escapeSeq.state = ESC_NONE; break; //--------------------------------------- // Line clear //--------------------------------------- case 'K': consoleClearLine(escapeSeq.hasArg[0] ? escapeSeq.clear.type : 0); escapeSeq.state = ESC_NONE; break; //--------------------------------------- // Save cursor position //--------------------------------------- case 's': currentConsole->prevCursorX = currentConsole->cursorX ; currentConsole->prevCursorY = currentConsole->cursorY ; escapeSeq.state = ESC_NONE; break; //--------------------------------------- // Load cursor position //--------------------------------------- case 'u': currentConsole->cursorX = currentConsole->prevCursorX ; currentConsole->cursorY = currentConsole->prevCursorY ; escapeSeq.state = ESC_NONE; break; //--------------------------------------- // Color scan codes //--------------------------------------- case 'm': consoleColorStateShift(); consoleColorApply(); escapeSeq.state = ESC_NONE; break; default: // some sort of unsupported escape; just gloss over it escapeSeq.state = ESC_NONE; break; } break; default: switch (chr) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': escapeSeq.hasArg[escapeSeq.argIdx] = true; escapeSeq.rawBuf[escapeSeq.argIdx] = escapeSeq.rawBuf[escapeSeq.argIdx] * 10 + (chr - '0'); break; case ';': consoleColorStateShift(); break; case 'm': consoleColorStateShift(); consoleColorApply(); escapeSeq.state = ESC_NONE; break; default: // some sort of unsupported escape; just gloss over it escapeSeq.state = ESC_NONE; break; } } } return count; } //--------------------------------------------------------------------------------- PrintConsole* consoleInit(GfxLcd lcd, PrintConsole* console) { //--------------------------------------------------------------------------------- static bool firstConsoleInit = true; if(firstConsoleInit) { memset(&escapeSeq, 0, sizeof(escapeSeq)); firstConsoleInit = false; } if(console) { currentConsole = console; } else { console = currentConsole; } *currentConsole = defaultConsole; console->consoleInitialised = 1; //gfxSetScreenFormat(lcd,GSP_BGR565_OES); GFX_setDoubleBuffering(lcd, false); console->frameBuffer = (u16*)GFX_getBuffer(lcd, GFX_SIDE_LEFT); if(lcd==GFX_LCD_TOP) { //bool isWide = gfxIsWide(); console->consoleWidth = 66;//isWide ? 100 : 50; console->windowWidth = 66;//isWide ? 100 : 50; } consoleCls(2); return currentConsole; } //--------------------------------------------------------------------------------- PrintConsole *consoleSelect(PrintConsole* console){ //--------------------------------------------------------------------------------- PrintConsole *tmp = currentConsole; currentConsole = console; return tmp; } //--------------------------------------------------------------------------------- PrintConsole *consoleGet(void){ //--------------------------------------------------------------------------------- return currentConsole; } //--------------------------------------------------------------------------------- void consoleSetFont(PrintConsole* console, ConsoleFont* font){ //--------------------------------------------------------------------------------- if(!console) console = currentConsole; console->font = *font; } //--------------------------------------------------------------------------------- static void newRow() { //--------------------------------------------------------------------------------- currentConsole->cursorY ++; if(currentConsole->cursorY >= currentConsole->windowHeight) { currentConsole->cursorY --; u16 *dst = ¤tConsole->frameBuffer[(currentConsole->windowX * 6 * 240) + (239 - (currentConsole->windowY * 10))]; u16 *src = dst - 10; int i,j; for (i=0; iwindowWidth*6; i++) { u32 *from = (u32*)((int)src & ~3); u32 *to = (u32*)((int)dst & ~3); for (j=0;j<(((currentConsole->windowHeight-1)*10)/2);j++) *(to--) = *(from--); dst += 240; src += 240; } consoleClearLine(2); } } //--------------------------------------------------------------------------------- void consoleDrawChar(int c) { //--------------------------------------------------------------------------------- c -= currentConsole->font.asciiOffset; if ( c < 0 || c > currentConsole->font.numChars ) return; u8 *fontdata = currentConsole->font.gfx + (10 * c); u16 fg = currentConsole->fg; u16 bg = currentConsole->bg; if (!(currentConsole->flags & CONSOLE_FG_CUSTOM)) { if (currentConsole->flags & CONSOLE_COLOR_BOLD) { fg = colorTable[fg + 8]; } else if (currentConsole->flags & CONSOLE_COLOR_FAINT) { fg = colorTable[fg + 16]; } else { fg = colorTable[fg]; } } if (!(currentConsole->flags & CONSOLE_BG_CUSTOM)) { bg = colorTable[bg]; } if (currentConsole->flags & CONSOLE_COLOR_REVERSE) { u16 tmp = fg; fg = bg; bg = tmp; } u8 b1 = *(fontdata++); u8 b2 = *(fontdata++); u8 b3 = *(fontdata++); u8 b4 = *(fontdata++); u8 b5 = *(fontdata++); u8 b6 = *(fontdata++); u8 b7 = *(fontdata++); u8 b8 = *(fontdata++); u8 b9 = *(fontdata++); u8 b10 = *(fontdata++); if (currentConsole->flags & CONSOLE_UNDERLINE) b10 = 0xff; if (currentConsole->flags & CONSOLE_CROSSED_OUT) b5 = 0xff; u8 mask = 0x80; int i; int x = (currentConsole->cursorX + currentConsole->windowX) * 6; int y = ((currentConsole->cursorY + currentConsole->windowY) * 10); u16 *screen = ¤tConsole->frameBuffer[(x * 240) + (239 - (y + 9))]; for (i=0;i<6;i++) { if (b10 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b9 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b8 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b7 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b6 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b5 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b4 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b3 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b2 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } if (b1 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } mask >>= 1; screen += 240 - 10; } } //--------------------------------------------------------------------------------- void consolePrintChar(int c) { //--------------------------------------------------------------------------------- if (c==0) return; if(currentConsole->PrintChar) if(currentConsole->PrintChar(currentConsole, c)) return; if(currentConsole->cursorX >= currentConsole->windowWidth) { currentConsole->cursorX = 0; newRow(); } switch(c) { /* The only special characters we will handle are tab (\t), carriage return (\r), line feed (\n) and backspace (\b). Carriage return & line feed will function the same: go to next line and put cursor at the beginning. For everything else, use VT sequences. Reason: VT sequences are more specific to the task of cursor placement. The special escape sequences \b \f & \v are archaic and non-portable. */ case 8: currentConsole->cursorX--; if(currentConsole->cursorX < 0) { if(currentConsole->cursorY > 0) { currentConsole->cursorX = currentConsole->windowX - 1; currentConsole->cursorY--; } else { currentConsole->cursorX = 0; } } consoleDrawChar(' '); break; case 9: currentConsole->cursorX += currentConsole->tabSize - ((currentConsole->cursorX)%(currentConsole->tabSize)); break; case 10: newRow(); // Falls through. case 13: currentConsole->cursorX = 0; GFX_flushBuffers(); break; default: consoleDrawChar(c); ++currentConsole->cursorX ; break; } } //--------------------------------------------------------------------------------- void consoleClear(void) { //--------------------------------------------------------------------------------- consoleCls(2); } //--------------------------------------------------------------------------------- void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height){ //--------------------------------------------------------------------------------- if(!console) console = currentConsole; console->windowWidth = width; console->windowHeight = height; console->windowX = x; console->windowY = y; console->cursorX = 0; console->cursorY = 0; }