From 33c51812374fb0746de79c6420a05a759187c20d Mon Sep 17 00:00:00 2001 From: yellows8 Date: Tue, 21 Nov 2017 00:26:44 -0500 Subject: [PATCH] Added gfxSetDoubleBuffering(). Adjusted g_gfxCurrentBuffer updating. Imported console from libctru with adjustments for Switch. --- nx/include/switch.h | 1 + nx/include/switch/devices/console.h | 165 ++++++ nx/include/switch/gfx/gfx.h | 1 + nx/source/devices/console.c | 765 ++++++++++++++++++++++++++++ nx/source/gfx/gfx.c | 17 +- 5 files changed, 948 insertions(+), 1 deletion(-) create mode 100644 nx/include/switch/devices/console.h create mode 100644 nx/source/devices/console.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 0bddfc20..a0b82c4f 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -43,6 +43,7 @@ extern "C" { #include #include +#include #include #include diff --git a/nx/include/switch/devices/console.h b/nx/include/switch/devices/console.h new file mode 100644 index 00000000..431945d8 --- /dev/null +++ b/nx/include/switch/devices/console.h @@ -0,0 +1,165 @@ +/** + * @file console.h + * @brief Switch stdio support. + * + * Provides stdio integration for printing to the Switch screen as well as debug print + * functionality provided by stderr. + * + * General usage is to initialize the console by: + * @code + * consoleDemoInit() + * @endcode + * or to customize the console usage by: + * @code + * consoleInit() + * @endcode + */ +#pragma once + +#include + +#define CONSOLE_ESC(x) "\x1b[" #x +#define CONSOLE_RESET CONSOLE_ESC(0m) +#define CONSOLE_BLACK CONSOLE_ESC(30m) +#define CONSOLE_RED CONSOLE_ESC(31;1m) +#define CONSOLE_GREEN CONSOLE_ESC(32;1m) +#define CONSOLE_YELLOW CONSOLE_ESC(33;1m) +#define CONSOLE_BLUE CONSOLE_ESC(34;1m) +#define CONSOLE_MAGENTA CONSOLE_ESC(35;1m) +#define CONSOLE_CYAN CONSOLE_ESC(36;1m) +#define CONSOLE_WHITE CONSOLE_ESC(37;1m) + +/// A callback for printing a character. +typedef bool(*ConsolePrint)(void* con, int c); + +/// A font struct for the console. +typedef struct ConsoleFont +{ + u8* gfx; ///< A pointer to the font graphics + u16 asciiOffset; ///< Offset to the first valid character in the font table + u16 numChars; ///< Number of characters in the font graphics +}ConsoleFont; + +/** + * @brief Console structure used to store the state of a console render context. + * + * Default values from consoleGetDefault(); + * @code + * PrintConsole defaultConsole = + * { + * //Font: + * { + * (u8*)default_font_bin, //font gfx + * 0, //first ascii character in the set + * 128, //number of characters in the font set + * }, + * 0,0, //cursorX cursorY + * 0,0, //prevcursorX prevcursorY + * 160, //console width + * 90, //console height + * 0, //window x + * 0, //window y + * 160, //window width + * 90, //window height + * 3, //tab size + * 0, //font character offset + * 0, //print callback + * false //console initialized + * }; + * @endcode + */ +typedef struct PrintConsole +{ + ConsoleFont font; ///< Font of the console + + u32 *frameBuffer; ///< Framebuffer address + + int cursorX; ///< Current X location of the cursor (as a tile offset by default) + int cursorY; ///< Current Y location of the cursor (as a tile offset by default) + + int prevCursorX; ///< Internal state + int prevCursorY; ///< Internal state + + int consoleWidth; ///< Width of the console hardware layer in characters + int consoleHeight; ///< Height of the console hardware layer in characters + + int windowX; ///< Window X location in characters (not implemented) + int windowY; ///< Window Y location in characters (not implemented) + int windowWidth; ///< Window width in characters (not implemented) + int windowHeight; ///< Window height in characters (not implemented) + + int tabSize; ///< Size of a tab + int fg; ///< Foreground color + int bg; ///< Background color + int flags; ///< Reverse/bright flags + + ConsolePrint PrintChar; ///< Callback for printing a character. Should return true if it has handled rendering the graphics (else the print engine will attempt to render via tiles). + + bool consoleInitialised; ///< True if the console is initialized +}PrintConsole; + +#define CONSOLE_COLOR_BOLD (1<<0) ///< Bold text +#define CONSOLE_COLOR_FAINT (1<<1) ///< Faint text +#define CONSOLE_ITALIC (1<<2) ///< Italic text +#define CONSOLE_UNDERLINE (1<<3) ///< Underlined text +#define CONSOLE_BLINK_SLOW (1<<4) ///< Slow blinking text +#define CONSOLE_BLINK_FAST (1<<5) ///< Fast blinking text +#define CONSOLE_COLOR_REVERSE (1<<6) ///< Reversed color text +#define CONSOLE_CONCEAL (1<<7) ///< Concealed text +#define CONSOLE_CROSSED_OUT (1<<8) ///< Crossed out text + +/// Console debug devices supported by libnx. +typedef enum { + debugDevice_NULL, ///< Swallows prints to stderr + debugDevice_SVC, ///< Outputs stderr debug statements using svcOutputDebugString, which can then be captured by interactive debuggers + debugDevice_CONSOLE, ///< Directs stderr debug statements to Switch console window + debugDevice_3DMOO = debugDevice_SVC, +} debugDevice; + +/** + * @brief Loads the font into the console. + * @param console Pointer to the console to update, if NULL it will update the current console. + * @param font The font to load. + */ +void consoleSetFont(PrintConsole* console, ConsoleFont* font); + +/** + * @brief Sets the print window. + * @param console Console to set, if NULL it will set the current console window. + * @param x X location of the window. + * @param y Y location of the window. + * @param width Width of the window. + * @param height Height of the window. + */ +void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height); + +/** + * @brief Gets a pointer to the console with the default values. + * This should only be used when using a single console or without changing the console that is returned, otherwise use consoleInit(). + * @return A pointer to the console with the default values. + */ +PrintConsole* consoleGetDefault(void); + +/** + * @brief Make the specified console the render target. + * @param console A pointer to the console struct (must have been initialized with consoleInit(PrintConsole* console)). + * @return A pointer to the previous console. + */ +PrintConsole *consoleSelect(PrintConsole* console); + +/** + * @brief Initialise the console. + * @param console A pointer to the console data to initialize (if it's NULL, the default console will be used). + * @return A pointer to the current console. + */ +PrintConsole* consoleInit(PrintConsole* console); + +/** + * @brief Initializes debug console output on stderr to the specified device. + * @param device The debug device (or devices) to output debug print statements to. + */ +void consoleDebugInit(debugDevice device); + +/// Clears the screan by using iprintf("\x1b[2J"); +void consoleClear(void); + diff --git a/nx/include/switch/gfx/gfx.h b/nx/include/switch/gfx/gfx.h index ba9ee17f..7b5bb127 100644 --- a/nx/include/switch/gfx/gfx.h +++ b/nx/include/switch/gfx/gfx.h @@ -5,6 +5,7 @@ void gfxExit(void); void gfxWaitForVsync(); void gfxSwapBuffers(); u8* gfxGetFramebuffer(u32* width, u32* height); +void gfxSetDoubleBuffering(bool doubleBuffering); void gfxFlushBuffers(void); u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y); diff --git a/nx/source/devices/console.c b/nx/source/devices/console.c new file mode 100644 index 00000000..62ab1133 --- /dev/null +++ b/nx/source/devices/console.c @@ -0,0 +1,765 @@ +#include +#include +#include +#include + +#include "default_font_bin.h" + +/// Converts red, green, and blue components to packed RGBA8, with alpha=0xff. +#define RGBA8(r,g,b) (((r)&0xff)|(((g)&0xff)<<8)|(((b)&0xff)<<16)|(0xff<<24)) + +//set up the palette for color printing +static u32 colorTable[] = { + RGBA8( 0, 0, 0), // black + RGBA8(128, 0, 0), // red + RGBA8( 0,128, 0), // green + RGBA8(128,128, 0), // yellow + RGBA8( 0, 0,128), // blue + RGBA8(128, 0,128), // magenta + RGBA8( 0,128,128), // cyan + RGBA8(192,192,192), // white + + RGBA8(128,128,128), // bright black + RGBA8(255, 0, 0), // bright red + RGBA8( 0,255, 0), // bright green + RGBA8(255,255, 0), // bright yellow + RGBA8( 0, 0,255), // bright blue + RGBA8(255, 0,255), // bright magenta + RGBA8( 0,255,255), // bright cyan + RGBA8(255,255,255), // bright white + + RGBA8( 0, 0, 0), // faint black + RGBA8( 64, 0, 0), // faint red + RGBA8( 0, 64, 0), // faint green + RGBA8( 64, 64, 0), // faint yellow + RGBA8( 0, 0, 64), // faint blue + RGBA8( 64, 0, 64), // faint magenta + RGBA8( 0, 64, 64), // faint cyan + RGBA8( 96, 96, 96), // faint white +}; + +//The below width/height is for 720p. +PrintConsole defaultConsole = +{ + //Font: + { + (u8*)default_font_bin, //font gfx + 0, //first ascii character in the set + 256 //number of characters in the font set + }, + (u32*)NULL, + 0,0, //cursorX cursorY + 0,0, //prevcursorX prevcursorY + 160, //console width + 90, //console height + 0, //window x + 0, //window y + 160, //window width + 90, //window height + 3, //tab size + 7, // 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(char mode) { +//--------------------------------------------------------------------------------- + + int i = 0; + int colTemp,rowTemp; + + switch (mode) + { + case '[': + 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; + } + } + gfxFlushBuffers(); +} +//--------------------------------------------------------------------------------- +static void consoleClearLine(char mode) { +//--------------------------------------------------------------------------------- + + int i = 0; + int colTemp; + + switch (mode) + { + case '[': + 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; + } + } + gfxFlushBuffers(); +} + + +//--------------------------------------------------------------------------------- +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; +} + +//--------------------------------------------------------------------------------- +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= '0' && chr <= '9') || chr == ';') + continue; + + switch (chr) { + //--------------------------------------- + // Cursor directional movement + //--------------------------------------- + case 'A': + consumed = 0; + assigned = sscanf(escapeseq,"[%dA%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorY = (currentConsole->cursorY - parameter) < 0 ? 0 : currentConsole->cursorY - parameter; + escaping = false; + break; + case 'B': + consumed = 0; + assigned = sscanf(escapeseq,"[%dB%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorY = (currentConsole->cursorY + parameter) > currentConsole->windowHeight - 1 ? currentConsole->windowHeight - 1 : currentConsole->cursorY + parameter; + escaping = false; + break; + case 'C': + consumed = 0; + assigned = sscanf(escapeseq,"[%dC%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorX = (currentConsole->cursorX + parameter) > currentConsole->windowWidth - 1 ? currentConsole->windowWidth - 1 : currentConsole->cursorX + parameter; + escaping = false; + break; + case 'D': + consumed = 0; + assigned = sscanf(escapeseq,"[%dD%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorX = (currentConsole->cursorX - parameter) < 0 ? 0 : currentConsole->cursorX - parameter; + escaping = false; + break; + //--------------------------------------- + // Cursor position movement + //--------------------------------------- + case 'H': + case 'f': + { + int x, y; + char c; + if(sscanf(escapeseq,"[%d;%d%c", &y, &x, &c) == 3 && (c == 'f' || c == 'H')) { + consolePosition(x, y); + escaping = false; + break; + } + + x = y = 1; + if(sscanf(escapeseq,"[%d;%c", &y, &c) == 2 && (c == 'f' || c == 'H')) { + consolePosition(x, y); + escaping = false; + break; + } + + x = y = 1; + if(sscanf(escapeseq,"[;%d%c", &x, &c) == 2 && (c == 'f' || c == 'H')) { + consolePosition(x, y); + escaping = false; + break; + } + + x = y = 1; + if(sscanf(escapeseq,"[;%c", &c) == 1 && (c == 'f' || c == 'H')) { + consolePosition(x, y); + escaping = false; + break; + } + + // invalid format + escaping = false; + break; + } + //--------------------------------------- + // Screen clear + //--------------------------------------- + case 'J': + if(escapelen <= 3) + consoleCls(escapeseq[escapelen-2]); + escaping = false; + break; + //--------------------------------------- + // Line clear + //--------------------------------------- + case 'K': + if(escapelen <= 3) + consoleClearLine(escapeseq[escapelen-2]); + escaping = false; + break; + //--------------------------------------- + // Save cursor position + //--------------------------------------- + case 's': + if(escapelen == 2) { + currentConsole->prevCursorX = currentConsole->cursorX ; + currentConsole->prevCursorY = currentConsole->cursorY ; + } + escaping = false; + break; + //--------------------------------------- + // Load cursor position + //--------------------------------------- + case 'u': + if(escapelen == 2) { + currentConsole->cursorX = currentConsole->prevCursorX ; + currentConsole->cursorY = currentConsole->prevCursorY ; + } + escaping = false; + break; + //--------------------------------------- + // Color scan codes + //--------------------------------------- + case 'm': + escapeseq++; + escapelen--; + + do { + parameter = 0; + if (escapelen == 1) { + consumed = 1; + } else if (memchr(escapeseq,';',escapelen)) { + sscanf(escapeseq,"%d;%n", ¶meter, &consumed); + } else { + sscanf(escapeseq,"%dm%n", ¶meter, &consumed); + } + + escapeseq += consumed; + escapelen -= consumed; + + switch(parameter) { + case 0: // reset + currentConsole->flags = 0; + currentConsole->bg = 0; + currentConsole->fg = 7; + break; + + case 1: // bold + currentConsole->flags &= ~CONSOLE_COLOR_FAINT; + currentConsole->flags |= CONSOLE_COLOR_BOLD; + break; + + case 2: // faint + currentConsole->flags &= ~CONSOLE_COLOR_BOLD; + currentConsole->flags |= CONSOLE_COLOR_FAINT; + break; + + case 3: // italic + currentConsole->flags |= CONSOLE_ITALIC; + break; + + case 4: // underline + currentConsole->flags |= CONSOLE_UNDERLINE; + break; + + case 5: // blink slow + currentConsole->flags &= ~CONSOLE_BLINK_FAST; + currentConsole->flags |= CONSOLE_BLINK_SLOW; + break; + + case 6: // blink fast + currentConsole->flags &= ~CONSOLE_BLINK_SLOW; + currentConsole->flags |= CONSOLE_BLINK_FAST; + break; + + case 7: // reverse video + currentConsole->flags |= CONSOLE_COLOR_REVERSE; + break; + + case 8: // conceal + currentConsole->flags |= CONSOLE_CONCEAL; + break; + + case 9: // crossed-out + currentConsole->flags |= CONSOLE_CROSSED_OUT; + break; + + case 21: // bold off + currentConsole->flags &= ~CONSOLE_COLOR_BOLD; + break; + + case 22: // normal color + currentConsole->flags &= ~CONSOLE_COLOR_BOLD; + currentConsole->flags &= ~CONSOLE_COLOR_FAINT; + break; + + case 23: // italic off + currentConsole->flags &= ~CONSOLE_ITALIC; + break; + + case 24: // underline off + currentConsole->flags &= ~CONSOLE_UNDERLINE; + break; + + case 25: // blink off + currentConsole->flags &= ~CONSOLE_BLINK_SLOW; + currentConsole->flags &= ~CONSOLE_BLINK_FAST; + break; + + case 27: // reverse off + currentConsole->flags &= ~CONSOLE_COLOR_REVERSE; + break; + + case 29: // crossed-out off + currentConsole->flags &= ~CONSOLE_CROSSED_OUT; + break; + + case 30 ... 37: // writing color + currentConsole->fg = parameter - 30; + break; + + case 39: // reset foreground color + currentConsole->fg = 7; + break; + + case 40 ... 47: // screen color + currentConsole->bg = parameter - 40; + break; + + case 49: // reset background color + currentConsole->fg = 0; + break; + } + } while (escapelen > 0); + + escaping = false; + break; + + default: + // some sort of unsupported escape; just gloss over it + escaping = false; + break; + } + } while (escaping); + continue; + } + + consolePrintChar(chr); + } + + return count; +} + +static const devoptab_t dotab_stdout = { + "con", + 0, + NULL, + NULL, + con_write, + NULL, + NULL, + NULL +}; + +//--------------------------------------------------------------------------------- +static ssize_t debug_write(struct _reent *r, void *fd, const char *ptr, size_t len) { +//--------------------------------------------------------------------------------- + svcOutputDebugString(ptr,len); + return len; +} + +static const devoptab_t dotab_svc = { + "svc", + 0, + NULL, + NULL, + debug_write, + NULL, + NULL, + NULL +}; + + +static const devoptab_t dotab_null = { + "null", + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +//--------------------------------------------------------------------------------- +PrintConsole* consoleInit(PrintConsole* console) { +//--------------------------------------------------------------------------------- + + static bool firstConsoleInit = true; + + if(firstConsoleInit) { + devoptab_list[STD_OUT] = &dotab_stdout; + devoptab_list[STD_ERR] = &dotab_stdout; + + setvbuf(stdout, NULL , _IONBF, 0); + setvbuf(stderr, NULL , _IONBF, 0); + + firstConsoleInit = false; + } + + if(console) { + currentConsole = console; + } else { + console = currentConsole; + } + + *currentConsole = defaultConsole; + + console->consoleInitialised = 1; + + gfxSetDoubleBuffering(false); + gfxFlushBuffers(); + gfxWaitForVsync(); + + console->frameBuffer = (u32*)gfxGetFramebuffer(NULL, NULL); + + + consoleCls('2'); + + return currentConsole; + +} + +//--------------------------------------------------------------------------------- +void consoleDebugInit(debugDevice device){ +//--------------------------------------------------------------------------------- + + int buffertype = _IONBF; + + switch(device) { + + case debugDevice_SVC: + devoptab_list[STD_ERR] = &dotab_svc; + buffertype = _IOLBF; + break; + case debugDevice_CONSOLE: + devoptab_list[STD_ERR] = &dotab_stdout; + break; + case debugDevice_NULL: + devoptab_list[STD_ERR] = &dotab_null; + break; + } + setvbuf(stderr, NULL , buffertype, 0); + +} + +//--------------------------------------------------------------------------------- +PrintConsole *consoleSelect(PrintConsole* console){ +//--------------------------------------------------------------------------------- + PrintConsole *tmp = currentConsole; + currentConsole = console; + return tmp; +} + +//--------------------------------------------------------------------------------- +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 --; + + int i,j; + u32 x, y; + + x = currentConsole->windowX * 8; + y = currentConsole->windowY * 8; + + for (i=0; iwindowWidth*8; i++) { + u32 *from; + u32 *to; + for (j=0;j<(currentConsole->windowHeight-1)*8;j++) { + to = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)]; + from = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + 8 + j)]; + *to = *from; + } + } + + consoleClearLine('2'); + } +} +//--------------------------------------------------------------------------------- +void consoleDrawChar(int c) { +//--------------------------------------------------------------------------------- + c -= currentConsole->font.asciiOffset; + if ( c < 0 || c > currentConsole->font.numChars ) return; + + u8 *fontdata = currentConsole->font.gfx + (8 * c); + + int writingColor = currentConsole->fg; + int screenColor = currentConsole->bg; + + if (currentConsole->flags & CONSOLE_COLOR_BOLD) { + writingColor += 8; + } else if (currentConsole->flags & CONSOLE_COLOR_FAINT) { + writingColor += 16; + } + + if (currentConsole->flags & CONSOLE_COLOR_REVERSE) { + int tmp = writingColor; + writingColor = screenColor; + screenColor = tmp; + } + + u32 bg = colorTable[screenColor]; + u32 fg = colorTable[writingColor]; + + u64 bval = *((u64*)fontdata); + + if (currentConsole->flags & CONSOLE_UNDERLINE) bval |= 0xffUL << 7*8; + + if (currentConsole->flags & CONSOLE_CROSSED_OUT) bval |= 0xff << 3*8; + + u8 mask = 0x80; + + int i, j; + + int x = (currentConsole->cursorX + currentConsole->windowX) * 8; + int y = ((currentConsole->cursorY + currentConsole->windowY) *8 ); + + u32 *screen; + + for (i=0;i<8;i++) { + for (j=0;j<8;j++) { + screen = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)]; + if (bval >> (8*j) & mask) { *screen = fg; }else{ *screen = bg; } + } + mask >>= 1; + } + +} + +//--------------------------------------------------------------------------------- +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(); + case 13: + currentConsole->cursorX = 0; + gfxFlushBuffers(); + break; + default: + consoleDrawChar(c); + ++currentConsole->cursorX ; + break; + } +} + +//--------------------------------------------------------------------------------- +void consoleClear(void) { +//--------------------------------------------------------------------------------- + iprintf("\x1b[2J"); +} + +//--------------------------------------------------------------------------------- +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; + +} + + + diff --git a/nx/source/gfx/gfx.c b/nx/source/gfx/gfx.c index 3b296cfa..e57cade8 100644 --- a/nx/source/gfx/gfx.c +++ b/nx/source/gfx/gfx.c @@ -14,6 +14,8 @@ static s32 g_gfxCurrentProducerBuffer = 0; static u8 *g_gfxFramebuf; static size_t g_gfxFramebufSize; +static bool g_gfxDoubleBuf = 1; + extern u32 __nx_applet_type; extern u32 g_nvgfx_totalframebufs; @@ -48,9 +50,14 @@ static Result _gfxGetNativeWindowID(u8 *buf, u64 size, s32 *out_ID) { static Result _gfxDequeueBuffer() { Result rc=0; + if (!g_gfxDoubleBuf) { + g_gfxCurrentProducerBuffer = -1; + return 0; + } + rc = gfxproducerDequeueBuffer(/*1*/0, 1280, 720, 0, 0x300, &g_gfxCurrentProducerBuffer); - if (R_SUCCEEDED(rc)) g_gfxCurrentBuffer = /*(g_gfxCurrentBuffer+1)*/(g_gfxCurrentProducerBuffer) & (g_nvgfx_totalframebufs-1); + if (R_SUCCEEDED(rc)) g_gfxCurrentBuffer = (g_gfxCurrentBuffer+1) & (g_nvgfx_totalframebufs-1); return rc; } @@ -58,6 +65,9 @@ static Result _gfxDequeueBuffer() { static Result _gfxQueueBuffer(s32 buf) { Result rc=0; u64 *ptr64 = (u64*)&g_gfxQueueBufferData; + + if (buf == -1) return 0; + ptr64[1] = svcGetSystemTick();//Unknown what is actually used for timestamp, but shouldn't(?) matter. rc = gfxproducerQueueBuffer(buf, (u8*)g_gfxQueueBufferData); @@ -84,6 +94,7 @@ static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 L g_gfxCurrentProducerBuffer = 0; g_gfxFramebuf = NULL; g_gfxFramebufSize = 0; + g_gfxDoubleBuf = 1; rc = viInitialize(servicetype); if (R_FAILED(rc)) return rc; @@ -238,6 +249,10 @@ u8* gfxGetFramebuffer(u32* width, u32* height) { return &g_gfxFramebuf[g_gfxCurrentBuffer*g_nvgfx_singleframebuf_size]; } +void gfxSetDoubleBuffering(bool doubleBuffering) { + g_gfxDoubleBuf = doubleBuffering; +} + void gfxFlushBuffers(void) { armDCacheFlush(&g_gfxFramebuf[g_gfxCurrentBuffer*g_nvgfx_singleframebuf_size], g_nvgfx_singleframebuf_size); }