Add virtual console to menu to show logs/messages from dosbox.

This commit is contained in:
retro100 2021-04-30 19:31:18 +02:00
parent aac6061671
commit 213977f7fc
19 changed files with 986 additions and 0 deletions

View File

@ -32,6 +32,9 @@
#include "regs.h"
#include "debug.h"
#include "debug_inc.h"
#ifdef HW_RVL
#include <stdio_wrapper.h>
#endif
struct _LogGroup {
char const* front;

View File

@ -38,6 +38,9 @@
#include "control.h"
#include "inout.h"
#include "dma.h"
#ifdef HW_RVL
#include <stdio_wrapper.h>
#endif
#if defined(OS2)

View File

@ -34,6 +34,7 @@
#ifdef HW_RVL
#include <wiihardware.h>
#include <menu.h>
#include <wiiio.h>
#endif
#include "cross.h"
@ -53,6 +54,9 @@
#include "cpu.h"
#include "cross.h"
#include "control.h"
#ifdef HW_RVL
#include <stdio_wrapper.h>
#endif
#define MAPPERFILE "mapper-" VERSION ".map"
//#define DISABLE_JOYSTICK
@ -1770,6 +1774,16 @@ static BOOL WINAPI ConsoleEventHandler(DWORD event) {
* Fixes some bugs when -noconsole is used in a read only directory */
static bool no_stdout = false;
void GFX_ShowMsg(char const* format,...) {
#ifdef HW_RVL
if (no_stdout) {
return;
}
va_list msg;
va_start(msg,format);
wiiio_vprintf(format, msg);
va_end(msg);
wiiio_print("\n");
#else
char buf[512];
va_list msg;
@ -1779,6 +1793,7 @@ void GFX_ShowMsg(char const* format,...) {
buf[sizeof(buf) - 1] = '\0';
if (!no_stdout) puts(buf); //Else buf is parsed again. (puts adds end of line)
#endif
}
@ -2052,6 +2067,18 @@ int main(int argc, char* argv[]) {
try {
#ifdef HW_RVL
WiiInit();
if (argc > 0) {
wiiio_print("args:");
for (int i = 0; i < argc; ++i) {
if (argv[i] != NULL) {
wiiio_printf(" %s", argv[i]);
}
else {
wiiio_print(" (null)");
}
}
wiiio_print("\n\n");
}
if(argc > 0 && argv[0] != NULL)
CreateAppPath(argv[0]);
#endif

View File

@ -72,6 +72,12 @@ extern const u32 battery_bar_png_size;
extern const u8 credits_box_png[];
extern const u32 credits_box_png_size;
extern const u8 bg_console_png[];
extern const u32 bg_console_png_size;
extern const u8 font8x8_basic_png[];
extern const u32 font8x8_basic_png_size;
extern const u8 keyboard_textbox_png[];
extern const u32 keyboard_textbox_png_size;
@ -134,6 +140,8 @@ extern const u32 player4_point_png_size;
#include "battery_bar_png.h"
#include "credits_box_png.h"
#include "bg_console_png.h"
#include "font8x8_basic_png.h"
#include "keyboard_textbox_png.h"
#include "keyboard_key_png.h"

View File

@ -0,0 +1,158 @@
// see https://raw.githubusercontent.com/dhepper/font8x8/master/font8x8_basic.h
// changes:
// change type for font8x8_basic from char to unsigned char
// header file only used by the converter program font8x8_to_png.c.txt
/**
* 8x8 monochrome bitmap fonts for rendering
* Author: Daniel Hepper <daniel@hepper.net>
*
* License: Public Domain
*
* Based on:
* // Summary: font8x8.h
* // 8x8 monochrome bitmap fonts for rendering
* //
* // Author:
* // Marcel Sondaar
* // International Business Machines (public domain VGA fonts)
* //
* // License:
* // Public Domain
*
* Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm
**/
// Constant: font8x8_basic
// Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin)
unsigned char font8x8_basic[128][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//)
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F
};

View File

@ -0,0 +1,131 @@
// a simple hack for convert the monospace font from font8x8_basic.h into a png file
// rename font8x8_to_png.c.txt to font8x8_to_png.c and
// compile with gcc -Wall font8x8_to_png.c -lpng -o font8x8_to_png
// to create the png file font8x8_basic.png execute following command:
// ./font8x8_to_png font8x8_basic.png
#include <stdlib.h>
#include <stdio.h>
#include <png.h>
#include "font8x8_basic.h"
// return 1 for error
int writeImage(char* filename, int width, int height, float *buffer, char* title)
{
FILE *fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Could not open file %s for writing\n", filename);
return 1;
}
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
fprintf(stderr, "Could not allocate write struct\n");
fclose(fp);
return 1;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
fprintf(stderr, "Could not allocate info struct\n");
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
fclose(fp);
return 1;
}
if (setjmp(png_jmpbuf(png_ptr))) {
fprintf(stderr, "Error during png creation\n");
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
fclose(fp);
return 1;
}
png_init_io(png_ptr, fp);
// Write header
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
if (title) {
png_text title_text;
title_text.compression = PNG_TEXT_COMPRESSION_NONE;
title_text.key = "Title";
title_text.text = title;
png_set_text(png_ptr, info_ptr, &title_text, 1);
}
png_write_info(png_ptr, info_ptr);
png_bytep row = (png_bytep) malloc(4 * width * sizeof(png_byte));
for (int y = 0 ; y < height ; ++y) {
for (int x = 0 ; x < width ; ++x) {
row[x*4] = buffer[(y*width + x)*4];
row[x*4+1] = buffer[(y*width + x)*4+1];
row[x*4+2] = buffer[(y*width + x)*4+2];
row[x*4+3] = buffer[(y*width + x)*4+3];
}
png_write_row(png_ptr, row);
}
// End write
png_write_end(png_ptr, NULL);
free(row);
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
fclose(fp);
return 0;
}
#define FONT_WIDTH 8
#define FONT_HEIGHT 8
#define SPACE_LEFT 1
#define SPACE_RIGHT 1
#define SPACE_TOP 1
#define SPACE_BOTTOM 1
#define CHARCOUNT_X 16
#define CHARCOUNT_Y 6
#define FIRST_CHAR 32 // space 0x20
int main(int argc, char**argv) {
if (argc < 2) {
printf("no filename for writing a png file\n");
return 1;
}
// 96 chars from 32 to 127
// 16 chars per row
// --> 16x6
int width = (FONT_WIDTH + SPACE_LEFT + SPACE_RIGHT) * CHARCOUNT_X;
int height = (FONT_HEIGHT + SPACE_TOP + SPACE_BOTTOM) * CHARCOUNT_Y;
float *buffer = calloc(sizeof(float), width * height * 4);
for (int ci = FIRST_CHAR; ci < 128; ++ci) {
int cx = (ci - FIRST_CHAR) % CHARCOUNT_X;
int cy = (ci - FIRST_CHAR) / CHARCOUNT_X;
unsigned char* glyph = font8x8_basic[ci];
for (int gy = 0; gy < FONT_HEIGHT; ++gy) {
unsigned char glyph_row = glyph[gy];
for (int gx = 0; gx < FONT_WIDTH; ++gx) {
unsigned char bitflag = 1 << gx;
int is_used = (glyph_row & bitflag);
int x = cx * (FONT_WIDTH + SPACE_LEFT + SPACE_RIGHT) + SPACE_LEFT + gx;
int y = cy * (FONT_HEIGHT + SPACE_TOP + SPACE_BOTTOM) + SPACE_TOP + gy;
int offset = (y*width +x)*4;
//buffer[offset] = is_used ? 255.0f : 0.0f;
buffer[offset] = 255.0f;
buffer[offset + 1] = 255.0f;
buffer[offset + 2] = 255.0f;
buffer[offset + 3] = is_used ? 255.0f : 0.0f;
}
}
}
writeImage(argv[1], width, height, buffer, "font8x8_basic");
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -35,6 +35,7 @@
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <exception>
#include <wchar.h>
@ -636,6 +637,63 @@ class GuiImage : public GuiElement
int stripe; //!< Alpha value (0-255) to apply a stripe effect to the texture
};
typedef struct vconsole vconsole_t;
// by retro100
// The class GuiMonoText is dual licensed for you to choose from.
// public domain. no warranty implied; use at your own risk.
// also licensed under the zlib license.
class GuiMonoText : public GuiImage
{
public:
//! Constructor
//!
//! The full glyph width is glyphMarginLeft + glyphWidth + glyphMarginRight
//! The full glyph height is glyphMarginTop + glyphHeight + glyphMarginBottom
//!
//!\param glyphCountX Count of glyphs in X direction inside the image/tileset
//!\param glyphCountY Count of glyphs in Y direction inside the image/tileset
//!\param firstGlyphAsciiCode e.g. 0 if all 128 glyphs are inside or 32 if the first glyph is a blank
//!\param glyphWidth width of one glyph in pixels WITHOUT extra margin between glyphs
//!\param glyphHeight height of one glyph in pixels without margin
//!\param glyphMarginLeft extra margin at the left side of each glyph (e.g. 0 or 1 px)
//!\param glyphMarginRight extra margin at the right side of each glyph (e.g. 0 or 1 px)
//!\param glyphMarginTop extra margin at the top side of each glyph (e.g. 0 or 1 px)
//!\param glyphMarginBottom extra margin at the bottom side of each glyph (e.g. 0 or 1 px)
GuiMonoText(GuiImageData * img,
unsigned int glyphCountX,
unsigned int glyphCountY,
unsigned int firstGlyphAsciiCode,
unsigned int glyphWidth,
unsigned int glyphHeight,
unsigned int glyphMarginLeft,
unsigned int glyphMarginRight,
unsigned int glyphMarginTop,
unsigned int glyphMarginBottom);
~GuiMonoText();
void SetText(const std::string& text);
void SetVirtualConsole(vconsole_t* vc, float lineSpace);
virtual void Draw();
private:
unsigned int glyphCountX;
unsigned int glyphCountY;
char firstGlyphAsciiCode;
float glyphWidthF;
float glyphHeightF;
float glyphMarginLeftF;
float glyphMarginTopF;
float fullGlyphWidthF;
float fullGlyphHeightF;
float texFullGlyphWidth;
float texFullGlyphHeight;
std::string text;
vconsole_t* vc;
float lineSpace;
void DrawText(float xpos, float ypos, const char* str);
void DrawVirtualConsole(float xpos, float ypos);
};
//!Display, manage, and manipulate text in the GUI
class GuiText : public GuiElement
{

View File

@ -0,0 +1,156 @@
// by retro100
// This file is dual licensed for you to choose from.
// public domain. no warranty implied; use at your own risk.
// also licensed under the zlib license.
#include "gui.h"
#include "../vconsole.h"
GuiMonoText::GuiMonoText(GuiImageData * img,
unsigned int glyphCountX,
unsigned int glyphCountY,
unsigned int firstGlyphAsciiCode,
unsigned int glyphWidth,
unsigned int glyphHeight,
unsigned int glyphMarginLeft,
unsigned int glyphMarginRight,
unsigned int glyphMarginTop,
unsigned int glyphMarginBottom)
:GuiImage(img),
glyphCountX(glyphCountX),
glyphCountY(glyphCountY),
firstGlyphAsciiCode(firstGlyphAsciiCode),
text(),
vc(NULL),
lineSpace(0.0f)
{
unsigned int fullGlyphWidth = glyphMarginLeft + glyphWidth + glyphMarginRight;
unsigned int fullGlyphHeight = glyphMarginTop + glyphHeight + glyphMarginBottom;
unsigned int tilesetWidth = fullGlyphWidth * glyphCountX;
unsigned int tilesetHeight = fullGlyphHeight * glyphCountY;
// Normally tilesetWidth should have the same value as the image width and
// tilesetHeight should have the same value as the image height.
// Only if the tileset image has a extra border (free space) at the right side
// and/or at the bottom then the values are different. (which is also no problem)
float texTilesetWidth = (float)tilesetWidth / (float)width;
float texTilesetHeight = (float)tilesetHeight / (float)height;
texFullGlyphWidth = texTilesetWidth / (float) glyphCountX;
texFullGlyphHeight = texTilesetHeight / (float) glyphCountY;
glyphWidthF = glyphWidth;
glyphHeightF = glyphHeight;
glyphMarginLeftF = glyphMarginLeft;
glyphMarginTopF = glyphMarginTop;
fullGlyphWidthF = fullGlyphWidth;
fullGlyphHeightF = fullGlyphHeight;
}
GuiMonoText::~GuiMonoText()
{
}
void GuiMonoText::SetText(const std::string& text)
{
this->text = text;
}
void GuiMonoText::SetVirtualConsole(vconsole_t* vc, float lineSpace)
{
this->vc = vc;
this->lineSpace = lineSpace;
}
void GuiMonoText::Draw()
{
if(!image || !this->IsVisible() || (text.empty() && !vc))
return;
f32 xpos = this->GetLeft();
f32 ypos = this->GetTop();
u8* data = image;
//u8 alpha = this->GetAlpha();
GXTexObj texObj;
GX_InitTexObj(&texObj, data, width,height, GX_TF_RGBA8,GX_CLAMP, GX_CLAMP,GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_InvalidateTexAll();
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
if (vc) {
DrawVirtualConsole(xpos, ypos);
}
else {
DrawText(xpos, ypos, text.c_str());
}
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);
}
void GuiMonoText::DrawText(float xpos, float ypos, const char* str)
{
size_t count = strlen(str);
xpos -= glyphMarginLeftF;
ypos -= glyphMarginTopF;
GX_Begin(GX_QUADS, GX_VTXFMT0, 4 * count);
for (size_t i = 0; i < count; ++i, xpos += glyphWidthF) {
unsigned char ch = (unsigned char)str[i];
if (ch < firstGlyphAsciiCode || ch >= 128) {
ch = '?';
}
unsigned int glyphIndex = ch - firstGlyphAsciiCode;
unsigned int xi = glyphIndex % glyphCountX;
unsigned int yi = glyphIndex / glyphCountX;
float texX = float(xi) * texFullGlyphWidth;
float texY = float(yi) * texFullGlyphHeight;
// left top
GX_Position3f32(xpos, ypos, 0);
GX_Color4u8(0x00, 0x00, 0x00, alpha);
GX_TexCoord2f32(texX, texY);
// right top
GX_Position3f32(xpos + fullGlyphWidthF, ypos, 0);
GX_Color4u8(0x00, 0x00, 0x00, alpha);
GX_TexCoord2f32(texX + texFullGlyphWidth, texY);
// right bottom
GX_Position3f32(xpos + fullGlyphWidthF, ypos + fullGlyphHeightF, 0);
GX_Color4u8(0x00, 0x00, 0x00, alpha);
GX_TexCoord2f32(texX + texFullGlyphWidth, texY + texFullGlyphHeight);
// left bottom
GX_Position3f32(xpos, ypos + fullGlyphHeightF, 0);
GX_Color4u8(0x00, 0x00, 0x00, alpha);
GX_TexCoord2f32(texX, texY + texFullGlyphHeight);
}
GX_End();
}
void GuiMonoText::DrawVirtualConsole(float xpos, float ypos)
{
int current_line_count = vc->line_count;
int current_line_index = vc->vc_current_line_index;
if (current_line_count < VCONSOLE_HEIGHT) {
for (int i = 0; i <= current_line_index; ++i, ypos += glyphHeightF + lineSpace) {
DrawText(xpos, ypos, vc->vc_text_lines[i]);
}
}
else {
for (int i = current_line_index + 1; i < VCONSOLE_HEIGHT; ++i, ypos += glyphHeightF + lineSpace) {
DrawText(xpos, ypos, vc->vc_text_lines[i]);
}
for (int i = 0; i <= current_line_index; ++i, ypos += glyphHeightF + lineSpace) {
DrawText(xpos, ypos, vc->vc_text_lines[i]);
}
}
}

View File

@ -38,6 +38,7 @@ GuiText::GuiText(const char * t, int s, GXColor c)
color = c;
alpha = c.a;
style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE;
monoPercentage = 100;
maxWidth = 0;
wrap = false;
textDynNum = 0;

View File

@ -21,6 +21,8 @@
#include "wiihardware.h"
#include "menu.h"
#include "cpu.h"
#include "vconsole.h"
#include "wiiio.h"
#define THREAD_SLEEP 100
#define APPVERSION "1.7"
@ -131,6 +133,81 @@ HaltGui()
guithread = LWP_THREAD_NULL;
}
static void OnScreenConsole()
{
vconsole_t& vc = *wiiio_get_vconsole();
GuiWindow terminal(screenwidth, screenheight);
GuiImageData backgroundData(bg_console_png);
GuiImage backgroundImg(&backgroundData);
backgroundImg.SetParent(&terminal);
backgroundImg.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
backgroundImg.SetPosition(23, 38);
terminal.Append(&backgroundImg);
GuiImageData fontData(font8x8_basic_png);
GuiMonoText terminalOutput(&fontData,
16, //glyphCountX
6, //glyphCountY
32, //firstGlyphAsciiCode
8, //glyphWidth
8, //glyphHeight
1, //glyphMarginLeft
1, //glyphMarginRight
1, //glyphMarginTop
1); //glyphMarginBottom
terminalOutput.SetParent(&terminal);
terminalOutput.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
terminalOutput.SetPosition(31, 48);
terminalOutput.SetVirtualConsole(&vc, 2.0f);
terminal.Append(&terminalOutput);
GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
GuiImageData btnOutline(button_png);
GuiImageData btnOutlineOver(button_over_png);
GuiTrigger trigA;
trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
GuiText okBtnTxt("Close", 22, (GXColor){0, 0, 0, 255});
GuiImage okBtnImg(&btnOutline);
GuiImage okBtnImgOver(&btnOutlineOver);
GuiButton okBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
okBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
okBtn.SetPosition(80, -35);
okBtn.SetLabel(&okBtnTxt);
okBtn.SetImage(&okBtnImg);
okBtn.SetImageOver(&okBtnImgOver);
okBtn.SetSoundOver(&btnSoundOver);
okBtn.SetTrigger(&trigA);
okBtn.SetEffectGrow();
terminal.Append(&okBtn);
HaltGui();
mainWindow->SetState(STATE_DISABLED);
mainWindow->Append(&terminal);
mainWindow->ChangeFocus(&terminal);
ResumeGui();
for (;;) {
usleep(THREAD_SLEEP);
if(okBtn.GetState() == STATE_CLICKED) {
break;
// for testing: comment the break and uncomment this.
//okBtn.ResetState();
//vconsole_print(&vc, "012345678901234567890123456789");
}
}
HaltGui();
mainWindow->Remove(&terminal);
mainWindow->SetState(STATE_DEFAULT);
ResumeGui();
}
/****************************************************************************
* OnScreenKeyboard
*
@ -473,6 +550,20 @@ void HomeMenu ()
exitBtn.SetTrigger(&trigA);
exitBtn.SetEffectGrow();
GuiText logBtnTxt("Logging", 24, (GXColor){0, 0, 0, 255});
GuiImage logBtnImg(&btnLargeOutline);
GuiImage logBtnImgOver(&btnLargeOutlineOver);
GuiButton logBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight());
logBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
logBtn.SetPosition(-125, 240);
logBtn.SetLabel(&logBtnTxt);
logBtn.SetImage(&logBtnImg);
logBtn.SetImageOver(&logBtnImgOver);
logBtn.SetSoundOver(&btnSoundOver);
logBtn.SetSoundClick(&btnSoundClick);
logBtn.SetTrigger(&trigA);
logBtn.SetEffectGrow();
GuiText keyboardBtnTxt("Keyboard", 24, (GXColor){0, 0, 0, 255});
GuiImage keyboardBtnImg(&btnLargeOutline);
GuiImage keyboardBtnImgOver(&btnLargeOutlineOver);
@ -556,6 +647,7 @@ void HomeMenu ()
w.Append(logoBtn);
w.Append(&closeBtn);
w.Append(&exitBtn);
w.Append(&logBtn);
w.Append(&cycleText);
w.Append(&fskipText);
w.Append(&cycleDecBtn);
@ -645,6 +737,11 @@ void HomeMenu ()
{
ExitRequested = 1;
}
else if(logBtn.GetState() == STATE_CLICKED)
{
logBtn.ResetState();
OnScreenConsole();
}
else if(keyboardBtn.GetState() == STATE_CLICKED)
{
keyboardBtn.ResetState();

View File

@ -10,6 +10,7 @@
#include <stdio.h>
#include <malloc.h>
#include <gccore.h>
#include <string.h>
#include "pngu.h"
#include <png.h>

View File

@ -0,0 +1,17 @@
// by retro100
// This file is dual licensed for you to choose from.
// public domain. no warranty implied; use at your own risk.
// also licensed under the zlib license.
#ifndef STDIO_WRAPPER_H
#define STDIO_WRAPPER_H
#include "wiiio.h"
#ifdef printf
#undef printf
#endif
#define printf(fmt, ...) wiiio_printf(fmt, ##__VA_ARGS__)
#endif

133
src/platform/wii/vconsole.c Normal file
View File

@ -0,0 +1,133 @@
// by retro100
// This file is dual licensed for you to choose from.
// public domain. no warranty implied; use at your own risk.
// also licensed under the zlib license.
#include "vconsole.h"
#include <gccore.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#define MAX_PRINTF_LEN 512
static void vc_jump_to_next_line(vconsole_t* vc) {
// terminate the current line
vc->vc_current_line[vc->vc_current_xpos_cursor_position] = '\0';
// jump to next line
vc->vc_current_xpos_cursor_position = 0;
vc->explicit_new_line = 0;
// increase vc_current_line_index to a tmp variable and
// only update to the increased value if it is allowed
// --> Avoids a momentary invalid value at vc->vc_current_line_index.
// --> Race conditions not really a problem (no sync is needed).
int next_line_index = vc->vc_current_line_index + 1;
if (next_line_index >= VCONSOLE_HEIGHT) {
vc->vc_current_line_index = 0;
}
else {
vc->vc_current_line_index = next_line_index;
}
vc->vc_current_line = vc->vc_text_lines[vc->vc_current_line_index];
// clear the line content of the new line.
// Using memset instead of simple
// vc_current_line[vc_current_xpos_cursor_position] = '\0';
// because if there are race conditions of different threads
// at the current line then it always has a termination
// at any position.
memset(vc->vc_current_line, 0, VCONSOLE_WIDTH);
++vc->line_count;
}
void vconsole_init(vconsole_t* vc)
{
memset(vc->vc_text_lines, 0, sizeof(vc->vc_text_lines));
//memset(vc->vc_text_lines, 0, VCONSOLE_HEIGHT * VCONSOLE_WIDTH);
vc->vc_current_line_index = 0;
vc->vc_current_xpos_cursor_position = 0;
vc->explicit_new_line = 1;
vc->vc_current_line = vc->vc_text_lines[0];
vc->line_count = 0;
}
void vconsole_destroy(vconsole_t* vc)
{
// currently nothing to to
}
int vconsole_printf(vconsole_t* vc, const char *format, ...)
{
va_list args;
va_start (args, format);
int rv = vconsole_vprintf(vc, format, args);
va_end (args);
return rv;
}
int vconsole_vprintf(vconsole_t* vc, const char *format, va_list ap)
{
char msg[MAX_PRINTF_LEN];
vsnprintf(msg, MAX_PRINTF_LEN, format, ap);
msg[MAX_PRINTF_LEN - 1] = '\0';
return vconsole_print(vc, msg);
}
int vconsole_print(vconsole_t* vc, const char* text)
{
size_t len = strlen(text);
vconsole_write(vc, text, len);
return len;
}
void vconsole_write(vconsole_t* vc, const void* buf, unsigned int len)
{
const char* text = buf;
for (unsigned int i = 0; i < len; ++i) {
char ch = text[i];
if (ch == '\0') {
// ignore it
}
else if (ch == '\n') {
if (vc->vc_current_xpos_cursor_position > 0 || vc->explicit_new_line) {
vc_jump_to_next_line(vc);
vc->explicit_new_line = 1;
}
}
else if (ch == '\r') {
// ignore it.
// --> For a new line \r\n or \n must be used.
// Only \r makes no new line.
}
else if (ch == '\t') {
if (vc->vc_current_xpos_cursor_position >= VCONSOLE_WIDTH - 4) {
vc_jump_to_next_line(vc);
}
vc->vc_current_line[vc->vc_current_xpos_cursor_position] += ' ';
vc->vc_current_line[vc->vc_current_xpos_cursor_position + 1] += ' ';
vc->vc_current_line[vc->vc_current_xpos_cursor_position + 2] += ' ';
vc->vc_current_line[vc->vc_current_xpos_cursor_position + 3] += ' ';
vc->vc_current_xpos_cursor_position += 4;
if (vc->vc_current_xpos_cursor_position >= VCONSOLE_WIDTH - 1) {
vc_jump_to_next_line(vc);
}
}
else {
if (ch < 0x20 || ch >= 0x7f) {
ch = '?';
}
vc->vc_current_line[vc->vc_current_xpos_cursor_position] = ch;
++vc->vc_current_xpos_cursor_position;
if (vc->vc_current_xpos_cursor_position >= VCONSOLE_WIDTH - 1) {
vc_jump_to_next_line(vc);
}
}
}
// terminate the new added content
vc->vc_current_line[vc->vc_current_xpos_cursor_position] = '\0';
}

View File

@ -0,0 +1,67 @@
// by retro100
// This file is dual licensed for you to choose from.
// public domain. no warranty implied; use at your own risk.
// also licensed under the zlib license.
#ifndef VCONSOLE_H
#define VCONSOLE_H
#include <stdio.h>
#define VCONSOLE_WIDTH 73 // usable are 72
#define VCONSOLE_HEIGHT 33
/*
by retro100
If the macro SHOW_DEBUGVC is defined then
a virtual console with a size of 86x40 can
be used to print messages.
The output of the virtual console scrolls
if a new line is added.
\n and also \t are supported.
The font is NOT monospace. The effective length
of the rendered output depends on the used characters.
*/
#ifdef SHOW_DEBUGVC
#define DEBUG_vc_printf(fmt, ...) DEBUG_vc_printf__(fmt, ##__VA_ARGS__)
#define DEBUG_vc_print(text) DEBUG_vc_print__(text)
#define DEBUG_vc_render_console_with_init(r, g, b, a) DEBUG_vc_render_console_with_init__(r, g, b, a)
#define DEBUG_vc_render_console() DEBUG_vc_render_console__()
#else
#define DEBUG_vc_printf(fmt, ...)
#define DEBUG_vc_print(fmt, ...)
#define DEBUG_vc_render_console_with_init(r, g, b, a)
#define DEBUG_vc_render_console()
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct vconsole
{
char vc_text_lines[VCONSOLE_HEIGHT][VCONSOLE_WIDTH];
int vc_current_line_index;
int vc_current_xpos_cursor_position;
int explicit_new_line;
char *vc_current_line;
int line_count;
} vconsole_t;
void vconsole_init(vconsole_t* vc);
void vconsole_destroy(vconsole_t* vc);
int vconsole_printf(vconsole_t* vc, const char *format, ...)
__attribute__ ((format(printf, 2, 3)));
int vconsole_vprintf(vconsole_t* vc, const char *format, va_list ap);
int vconsole_print(vconsole_t* vc, const char* text);
void vconsole_write(vconsole_t* vc, const void* buf, unsigned int len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -21,6 +21,7 @@
#include "input.h"
#include "filelist.h"
#include "SDL_events.h"
#include "wiiio.h"
extern "C" {
extern void __exception_setreload(int t);
@ -205,6 +206,7 @@ void WiiInit()
extern const devoptab_t dotab_stdnull;
devoptab_list[STD_OUT] = &dotab_stdnull;
devoptab_list[STD_ERR] = &dotab_stdnull;
wiiio_init();
//USBGeckoOutput(); // uncomment to enable USB gecko output
__exception_setreload(8);
fatInitDefault();

90
src/platform/wii/wiiio.c Normal file
View File

@ -0,0 +1,90 @@
// by retro100
// This file is dual licensed for you to choose from.
// public domain. no warranty implied; use at your own risk.
// also licensed under the zlib license.
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "wiiio.h"
#include "vconsole.h"
#include <stdarg.h>
#include <stdlib.h>
static vconsole_t* vc = NULL;
static ssize_t vc_memfile_write(void *c, const char *buf, size_t size)
{
vconsole_write(vc, buf, size);
return size;
}
static ssize_t vc_memfile_read(void *c, char *buf, size_t size)
{
return 0;
}
static int vc_memfile_seek(void *c, off_t *offset, int whence)
{
return 0; // or maybe -1 should be returned?
}
static int vc_memfile_close(void *c)
{
return 0;
}
void wiiio_init()
{
if (!vc) {
vc = malloc(sizeof(vconsole_t));
vconsole_init(vc);
}
}
FILE* wiiio_fopen()
{
cookie_io_functions_t vc_memfile_func = {
.read = vc_memfile_read,
.write = vc_memfile_write,
.seek = vc_memfile_seek,
.close = vc_memfile_close
};
FILE* fp = fopencookie(vc, "w+", vc_memfile_func);
if (!fp) {
vconsole_print(vc, "open failed!\n");
}
return fp;
}
vconsole_t* wiiio_get_vconsole()
{
return vc;
}
int wiiio_printf(const char *format, ...)
{
va_list args;
va_start (args, format);
int rv = wiiio_vprintf(format, args);
va_end (args);
return rv;
}
int wiiio_vprintf(const char *format, va_list ap)
{
return vconsole_vprintf(vc, format, ap);
}
int wiiio_print(const char* text)
{
return vconsole_print(vc, text);
}
int wiiio_puts(const char* text)
{
int rv = vconsole_print(vc, text);
rv += vconsole_print(vc, "\n");
return rv;
}

34
src/platform/wii/wiiio.h Normal file
View File

@ -0,0 +1,34 @@
// by retro100
// This file is dual licensed for you to choose from.
// public domain. no warranty implied; use at your own risk.
// also licensed under the zlib license.
#ifndef WIIIO_H
#define WIIIO_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct vconsole vconsole_t;
void wiiio_init();
FILE* wiiio_fopen();
vconsole_t* wiiio_get_vconsole();
int wiiio_printf(const char *format, ...)
__attribute__ ((format(printf, 1, 2)));
int wiiio_vprintf(const char *format, va_list ap);
int wiiio_print(const char* text);
// wiiio_puts() writes the string text and a trailing newline.
int wiiio_puts(const char* text);
#ifdef __cplusplus
}
#endif
#endif