mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
Added gfxSetDoubleBuffering(). Adjusted g_gfxCurrentBuffer updating. Imported console from libctru with adjustments for Switch.
This commit is contained in:
parent
94809a1e15
commit
33c5181237
@ -43,6 +43,7 @@ extern "C" {
|
|||||||
#include <switch/gfx/nvioctl.h>
|
#include <switch/gfx/nvioctl.h>
|
||||||
#include <switch/gfx/nvgfx.h>
|
#include <switch/gfx/nvgfx.h>
|
||||||
|
|
||||||
|
#include <switch/devices/console.h>
|
||||||
#include <switch/devices/usb_comms.h>
|
#include <switch/devices/usb_comms.h>
|
||||||
#include <switch/devices/fs_dev.h>
|
#include <switch/devices/fs_dev.h>
|
||||||
|
|
||||||
|
165
nx/include/switch/devices/console.h
Normal file
165
nx/include/switch/devices/console.h
Normal file
@ -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 <switch.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
@ -5,6 +5,7 @@ void gfxExit(void);
|
|||||||
void gfxWaitForVsync();
|
void gfxWaitForVsync();
|
||||||
void gfxSwapBuffers();
|
void gfxSwapBuffers();
|
||||||
u8* gfxGetFramebuffer(u32* width, u32* height);
|
u8* gfxGetFramebuffer(u32* width, u32* height);
|
||||||
|
void gfxSetDoubleBuffering(bool doubleBuffering);
|
||||||
void gfxFlushBuffers(void);
|
void gfxFlushBuffers(void);
|
||||||
|
|
||||||
u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y);
|
u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y);
|
||||||
|
765
nx/source/devices/console.c
Normal file
765
nx/source/devices/console.c
Normal file
@ -0,0 +1,765 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/iosupport.h>
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#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<len) {
|
||||||
|
|
||||||
|
chr = *(tmp++);
|
||||||
|
i++; count++;
|
||||||
|
|
||||||
|
if ( chr == 0x1b && *tmp == '[' ) {
|
||||||
|
bool escaping = true;
|
||||||
|
char *escapeseq = tmp++;
|
||||||
|
int escapelen = 1;
|
||||||
|
i++; count++;
|
||||||
|
|
||||||
|
do {
|
||||||
|
chr = *(tmp++);
|
||||||
|
i++; count++; escapelen++;
|
||||||
|
int parameter, assigned, consumed;
|
||||||
|
|
||||||
|
// make sure parameters are positive values and delimited by semicolon
|
||||||
|
if((chr >= '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; i<currentConsole->windowWidth*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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -14,6 +14,8 @@ static s32 g_gfxCurrentProducerBuffer = 0;
|
|||||||
static u8 *g_gfxFramebuf;
|
static u8 *g_gfxFramebuf;
|
||||||
static size_t g_gfxFramebufSize;
|
static size_t g_gfxFramebufSize;
|
||||||
|
|
||||||
|
static bool g_gfxDoubleBuf = 1;
|
||||||
|
|
||||||
extern u32 __nx_applet_type;
|
extern u32 __nx_applet_type;
|
||||||
|
|
||||||
extern u32 g_nvgfx_totalframebufs;
|
extern u32 g_nvgfx_totalframebufs;
|
||||||
@ -48,9 +50,14 @@ static Result _gfxGetNativeWindowID(u8 *buf, u64 size, s32 *out_ID) {
|
|||||||
static Result _gfxDequeueBuffer() {
|
static Result _gfxDequeueBuffer() {
|
||||||
Result rc=0;
|
Result rc=0;
|
||||||
|
|
||||||
|
if (!g_gfxDoubleBuf) {
|
||||||
|
g_gfxCurrentProducerBuffer = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
rc = gfxproducerDequeueBuffer(/*1*/0, 1280, 720, 0, 0x300, &g_gfxCurrentProducerBuffer);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -58,6 +65,9 @@ static Result _gfxDequeueBuffer() {
|
|||||||
static Result _gfxQueueBuffer(s32 buf) {
|
static Result _gfxQueueBuffer(s32 buf) {
|
||||||
Result rc=0;
|
Result rc=0;
|
||||||
u64 *ptr64 = (u64*)&g_gfxQueueBufferData;
|
u64 *ptr64 = (u64*)&g_gfxQueueBufferData;
|
||||||
|
|
||||||
|
if (buf == -1) return 0;
|
||||||
|
|
||||||
ptr64[1] = svcGetSystemTick();//Unknown what is actually used for timestamp, but shouldn't(?) matter.
|
ptr64[1] = svcGetSystemTick();//Unknown what is actually used for timestamp, but shouldn't(?) matter.
|
||||||
|
|
||||||
rc = gfxproducerQueueBuffer(buf, (u8*)g_gfxQueueBufferData);
|
rc = gfxproducerQueueBuffer(buf, (u8*)g_gfxQueueBufferData);
|
||||||
@ -84,6 +94,7 @@ static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 L
|
|||||||
g_gfxCurrentProducerBuffer = 0;
|
g_gfxCurrentProducerBuffer = 0;
|
||||||
g_gfxFramebuf = NULL;
|
g_gfxFramebuf = NULL;
|
||||||
g_gfxFramebufSize = 0;
|
g_gfxFramebufSize = 0;
|
||||||
|
g_gfxDoubleBuf = 1;
|
||||||
|
|
||||||
rc = viInitialize(servicetype);
|
rc = viInitialize(servicetype);
|
||||||
if (R_FAILED(rc)) return rc;
|
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];
|
return &g_gfxFramebuf[g_gfxCurrentBuffer*g_nvgfx_singleframebuf_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gfxSetDoubleBuffering(bool doubleBuffering) {
|
||||||
|
g_gfxDoubleBuf = doubleBuffering;
|
||||||
|
}
|
||||||
|
|
||||||
void gfxFlushBuffers(void) {
|
void gfxFlushBuffers(void) {
|
||||||
armDCacheFlush(&g_gfxFramebuf[g_gfxCurrentBuffer*g_nvgfx_singleframebuf_size], g_nvgfx_singleframebuf_size);
|
armDCacheFlush(&g_gfxFramebuf[g_gfxCurrentBuffer*g_nvgfx_singleframebuf_size], g_nvgfx_singleframebuf_size);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user