mirror of
https://gitlab.com/niansa/llama_nds.git
synced 2025-03-06 20:53:28 +01:00
Implemented initial working GUI
This commit is contained in:
parent
d76d8ced9b
commit
42723347f1
15 changed files with 2987 additions and 375 deletions
170
AsyncManager.cpp
170
AsyncManager.cpp
|
@ -24,91 +24,89 @@ void AsyncManager::cleanFutureMap(SockFutureMap& map) {
|
|||
}
|
||||
|
||||
void AsyncManager::run() {
|
||||
while (!stopping && runtime.cooperate()) {
|
||||
// We should stop once there is nothing left to do
|
||||
if (sockReads.empty() && sockWrites.empty()) [[unlikely]] {
|
||||
break;
|
||||
}
|
||||
|
||||
// We need to keep track of the highest fd for socket()
|
||||
int maxFd = 0;
|
||||
|
||||
// Create except FD set
|
||||
fd_set exceptFds;
|
||||
FD_ZERO(&exceptFds);
|
||||
|
||||
// Create write FD set
|
||||
fd_set writeFds;
|
||||
FD_ZERO(&writeFds);
|
||||
for (const auto& [fd, cb] : sockWrites) {
|
||||
FD_SET(fd, &writeFds);
|
||||
FD_SET(fd, &exceptFds);
|
||||
if (fd > maxFd) {
|
||||
maxFd = fd;
|
||||
}
|
||||
}
|
||||
|
||||
// Create read FD set
|
||||
fd_set readFds;
|
||||
FD_ZERO(&readFds);
|
||||
for (const auto& [fd, cb] : sockReads) {
|
||||
FD_SET(fd, &readFds);
|
||||
FD_SET(fd, &exceptFds);
|
||||
if (fd > maxFd) {
|
||||
maxFd = fd;
|
||||
}
|
||||
}
|
||||
|
||||
// Specify timeout
|
||||
timeval tv{
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 250000
|
||||
};
|
||||
|
||||
// select() until there is data
|
||||
bool error = false;
|
||||
if (select(maxFd+1, &readFds, &writeFds, &exceptFds, &tv) < 0) {
|
||||
FD_ZERO(&readFds);
|
||||
FD_ZERO(&writeFds);
|
||||
error = true;
|
||||
}
|
||||
|
||||
// Execution queue
|
||||
std::vector<std::pair<SockFutureUnique&, bool>> execQueue;
|
||||
|
||||
// Collect all write futures
|
||||
for (auto& [fd, future] : sockWrites) {
|
||||
if (FD_ISSET(fd, &writeFds)) {
|
||||
// Socket is ready for writing
|
||||
execQueue.push_back({future, false});
|
||||
}
|
||||
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
|
||||
// An exception happened in the socket
|
||||
execQueue.push_back({future, true});
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all read futures
|
||||
for (auto& [fd, future] : sockReads) {
|
||||
if (FD_ISSET(fd, &readFds)) {
|
||||
// Socket is ready for reading
|
||||
execQueue.push_back({future, false});
|
||||
}
|
||||
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
|
||||
// An exception happened in the socket
|
||||
execQueue.push_back({future, true});
|
||||
}
|
||||
}
|
||||
|
||||
// Set futures
|
||||
for (auto& [future, value] : execQueue) {
|
||||
future->set(value?AsyncResult::Error:AsyncResult::Success);
|
||||
future = nullptr;
|
||||
}
|
||||
|
||||
// Clean future maps
|
||||
cleanFutureMap(sockWrites);
|
||||
cleanFutureMap(sockReads);
|
||||
// We should stop once there is nothing left to do
|
||||
if (sockReads.empty() && sockWrites.empty()) [[unlikely]] {
|
||||
stopping = true;
|
||||
return;
|
||||
}
|
||||
stopping = false;
|
||||
|
||||
// We need to keep track of the highest fd for socket()
|
||||
int maxFd = 0;
|
||||
|
||||
// Create except FD set
|
||||
fd_set exceptFds;
|
||||
FD_ZERO(&exceptFds);
|
||||
|
||||
// Create write FD set
|
||||
fd_set writeFds;
|
||||
FD_ZERO(&writeFds);
|
||||
for (const auto& [fd, cb] : sockWrites) {
|
||||
FD_SET(fd, &writeFds);
|
||||
FD_SET(fd, &exceptFds);
|
||||
if (fd > maxFd) {
|
||||
maxFd = fd;
|
||||
}
|
||||
}
|
||||
|
||||
// Create read FD set
|
||||
fd_set readFds;
|
||||
FD_ZERO(&readFds);
|
||||
for (const auto& [fd, cb] : sockReads) {
|
||||
FD_SET(fd, &readFds);
|
||||
FD_SET(fd, &exceptFds);
|
||||
if (fd > maxFd) {
|
||||
maxFd = fd;
|
||||
}
|
||||
}
|
||||
|
||||
// Specify timeout
|
||||
timeval tv{
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 250000
|
||||
};
|
||||
|
||||
// select() until there is data
|
||||
bool error = false;
|
||||
if (select(maxFd+1, &readFds, &writeFds, &exceptFds, &tv) < 0) {
|
||||
FD_ZERO(&readFds);
|
||||
FD_ZERO(&writeFds);
|
||||
error = true;
|
||||
}
|
||||
|
||||
// Execution queue
|
||||
std::vector<std::pair<SockFutureUnique&, bool>> execQueue;
|
||||
|
||||
// Collect all write futures
|
||||
for (auto& [fd, future] : sockWrites) {
|
||||
if (FD_ISSET(fd, &writeFds)) {
|
||||
// Socket is ready for writing
|
||||
execQueue.push_back({future, false});
|
||||
}
|
||||
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
|
||||
// An exception happened in the socket
|
||||
execQueue.push_back({future, true});
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all read futures
|
||||
for (auto& [fd, future] : sockReads) {
|
||||
if (FD_ISSET(fd, &readFds)) {
|
||||
// Socket is ready for reading
|
||||
execQueue.push_back({future, false});
|
||||
}
|
||||
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
|
||||
// An exception happened in the socket
|
||||
execQueue.push_back({future, true});
|
||||
}
|
||||
}
|
||||
|
||||
// Set futures
|
||||
for (auto& [future, value] : execQueue) {
|
||||
future->set(value?AsyncResult::Error:AsyncResult::Success);
|
||||
future = nullptr;
|
||||
}
|
||||
|
||||
// Clean future maps
|
||||
cleanFutureMap(sockWrites);
|
||||
cleanFutureMap(sockReads);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@ public:
|
|||
AsyncManager(const AsyncManager&) = delete;
|
||||
AsyncManager(AsyncManager&&) = delete;
|
||||
|
||||
bool shouldRun() const {
|
||||
return !stopping && runtime.cooperate();
|
||||
}
|
||||
void run();
|
||||
void stop() {
|
||||
stopping = true;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(llama.any LANGUAGES CXX)
|
||||
project(llama.nds LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
@ -12,21 +12,16 @@ add_executable(llama
|
|||
Receiver.hpp Receiver.cpp
|
||||
Sender.hpp Sender.cpp
|
||||
AsyncManager.hpp AsyncManager.cpp
|
||||
font.h font.c
|
||||
NDSUI.hpp NDSUI.cpp
|
||||
Runtime.cpp Runtime.hpp
|
||||
basic-coro/AwaitableTask.hpp basic-coro/SingleEvent.hpp basic-coro/SingleEvent.cpp
|
||||
)
|
||||
|
||||
target_compile_definitions(llama PUBLIC PLATFORM="${CMAKE_SYSTEM_NAME}")
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Nintendo3DS)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_3DS)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL NintendoDS)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL NintendoDS)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_DS)
|
||||
target_link_libraries(llama PUBLIC dswifi9 nds9)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_LINUX)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_WINDOWS)
|
||||
target_link_libraries(llama PUBLIC Ws2_32)
|
||||
else()
|
||||
message(SEND_ERROR "${CMAKE_SYSTEM_NAME} is not a supported platform!")
|
||||
endif()
|
||||
|
|
25
Client.cpp
25
Client.cpp
|
@ -17,27 +17,9 @@
|
|||
|
||||
|
||||
void Client::fetchAddr(const std::string& addr, unsigned port) {
|
||||
# ifdef HAS_ADDRINFO
|
||||
// Set up hints
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_INET; //TODO: Care about IPv6
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
|
||||
// Get port as C string
|
||||
char portStr[7];
|
||||
sprintf(portStr, "%u", port);
|
||||
|
||||
// Get addrinfo
|
||||
auto error = getaddrinfo(addr.c_str(), portStr, &hints, &addrInfo);
|
||||
auto bad = addrInfo == nullptr;
|
||||
# else
|
||||
addrInfo = gethostbyname(addr.c_str());
|
||||
auto error = errno;
|
||||
auto bad = addrInfo == nullptr || addrInfo->h_addr_list[0] == nullptr;
|
||||
# endif
|
||||
|
||||
// Check for error
|
||||
if (bad) {
|
||||
|
@ -55,12 +37,6 @@ Client::Client(const std::string& addr, unsigned port, AsyncManager& asyncManage
|
|||
// Fetch address
|
||||
fetchAddr(addr, port);
|
||||
|
||||
# ifdef HAS_ADDRINFO
|
||||
// Connect to server
|
||||
if (connect(*connection, addrInfo->ai_addr, addrInfo->ai_addrlen) != 0) [[unlikely]] {
|
||||
throw Exception("Connection has been refused");
|
||||
}
|
||||
# else
|
||||
// Connect to server
|
||||
struct sockaddr_in sain;
|
||||
sain.sin_family = AF_INET;
|
||||
|
@ -69,7 +45,6 @@ Client::Client(const std::string& addr, unsigned port, AsyncManager& asyncManage
|
|||
if (connect(*connection, reinterpret_cast<sockaddr *>(&sain), sizeof(sain)) != 0) [[unlikely]] {
|
||||
throw Exception("Connection has been declined");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
basiccoro::AwaitableTask<AsyncResult> Client::ask(std::string_view prompt, const std::function<basiccoro::AwaitableTask<void> (unsigned progress)>& on_progress, const std::function<basiccoro::AwaitableTask<void> (std::string_view token)>& on_token) {
|
||||
|
|
|
@ -28,13 +28,8 @@ class Client
|
|||
AsyncManager& aMan;
|
||||
|
||||
int fd = -1;
|
||||
# ifdef HAS_ADDRINFO
|
||||
addrinfo
|
||||
# else
|
||||
bool sent = false;
|
||||
hostent
|
||||
# endif
|
||||
*addrInfo; // Can't be null unless request has already been sent
|
||||
hostent *addrInfo; // Can't be null unless request has already been sent
|
||||
|
||||
std::unique_ptr<SocketConnection<Sender::Simple, Receiver::Simple>> connection;
|
||||
|
||||
|
|
215
NDSUI.cpp
Normal file
215
NDSUI.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
#include "NDSUI.hpp"
|
||||
#include "font.h"
|
||||
|
||||
#include <exception>
|
||||
#include <gl2d.h>
|
||||
#include <nds.h>
|
||||
#include <nds/touch.h>
|
||||
#include <nds/input.h>
|
||||
|
||||
#define SCREEN_BORDER_PADDING 4
|
||||
#define FONT_PADDING 1
|
||||
#define INPUT_LINE_HEIGHT (FONT_HEIGHT+FONT_PADDING)
|
||||
|
||||
|
||||
NDSUI *NDSUI::currentInstance;
|
||||
|
||||
|
||||
|
||||
consteval
|
||||
unsigned NDSUI::calcMaxCharsInLine(unsigned int width) {
|
||||
return width / (FONT_WIDTH + FONT_PADDING);
|
||||
}
|
||||
consteval
|
||||
unsigned NDSUI::calcMaxLinesInRow(unsigned height) {
|
||||
return height / (FONT_HEIGHT + FONT_PADDING);
|
||||
}
|
||||
|
||||
void NDSUI::kbCallback(int key) {
|
||||
if (key > 0) currentInstance->handleInput(static_cast<char>(key));
|
||||
}
|
||||
|
||||
consteval
|
||||
Box2D NDSUI::calcMessageLogDimensions() {
|
||||
return {
|
||||
{SCREEN_BORDER_PADDING, 0},
|
||||
{SCREEN_WIDTH-SCREEN_BORDER_PADDING, SCREEN_HEIGHT-(SCREEN_BORDER_PADDING*2)-INPUT_LINE_HEIGHT}
|
||||
};
|
||||
}
|
||||
void NDSUI::renderMessageLog() {
|
||||
constexpr Box2D boxDims = calcMessageLogDimensions();
|
||||
|
||||
// Draw box
|
||||
glBoxFilled(boxDims.topLeft.x, boxDims.topLeft.y, boxDims.bottomRight.x, boxDims.bottomRight.y, RGB15(6, 2, 14));
|
||||
|
||||
// Log messages renderer
|
||||
auto renderLine = [this, y = int(boxDims.bottomRight.y - FONT_PADDING - FONT_HEIGHT), boxDims] (std::string_view line) mutable {
|
||||
print(line, {boxDims.topLeft.x + FONT_PADDING, unsigned(y)}, RGB15(28, 28, 28));
|
||||
y -= FONT_PADDING + FONT_HEIGHT;
|
||||
if (y < 0) {
|
||||
throw std::exception(); // Stop rendering any more lines
|
||||
}
|
||||
};
|
||||
|
||||
// Display line by line
|
||||
try {
|
||||
for (auto message = messages.rbegin(); message != messages.rend(); message++) {
|
||||
const auto& lines = message->getLines();
|
||||
for (auto line = lines.rbegin(); line != lines.rend(); line++) {
|
||||
renderLine(*line);
|
||||
}
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
consteval
|
||||
Box2D NDSUI::calcInputLineDimensions() {
|
||||
return {
|
||||
{SCREEN_BORDER_PADDING, SCREEN_HEIGHT-SCREEN_BORDER_PADDING-INPUT_LINE_HEIGHT},
|
||||
{SCREEN_WIDTH-SCREEN_BORDER_PADDING, SCREEN_HEIGHT-SCREEN_BORDER_PADDING}
|
||||
};
|
||||
}
|
||||
void NDSUI::renderInputLine() {
|
||||
constexpr Box2D boxDims = calcInputLineDimensions();
|
||||
constexpr Position2D textTopLeft{boxDims.topLeft.x+FONT_PADDING, boxDims.topLeft.y+FONT_PADDING};
|
||||
|
||||
// Draw box
|
||||
glBoxFilled(boxDims.topLeft.x, boxDims.topLeft.y, boxDims.bottomRight.x, boxDims.bottomRight.y, RGB15(13, 8, 3));
|
||||
|
||||
// Measure amount of character that fit in
|
||||
constexpr auto maxChars = calcMaxCharsInLine(boxDims.bottomRight.x - boxDims.topLeft.x);
|
||||
|
||||
// Mease amount of characters that don't fit in
|
||||
unsigned startIdx = 0;
|
||||
if (inputLineBufHead > maxChars) {
|
||||
startIdx = inputLineBufHead - maxChars;
|
||||
}
|
||||
|
||||
// Get that amount of characters
|
||||
print(&inputLineBuf[startIdx], textTopLeft, RGB15(28, 28, 28));
|
||||
}
|
||||
|
||||
bool NDSUI::printChar(const char character, Position2D *topleftpos, const int color) {
|
||||
const bool *fontChar = font_get_character(character);
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
unsigned no = 0;
|
||||
for (const bool *thispixel = fontChar; ; thispixel++) {
|
||||
if (x == FONT_WIDTH) {
|
||||
x = 0;
|
||||
y++;
|
||||
} if (y == FONT_HEIGHT) {
|
||||
break;
|
||||
} if (*thispixel) {
|
||||
// Calculate spareout
|
||||
unsigned spareout = font_pixels / 500;
|
||||
// Skip pixel for spareout
|
||||
if (!(no++ % spareout)) {
|
||||
// Draw pixel with melonDS fallback for debug builds
|
||||
# ifdef NDEBUG
|
||||
glPutPixel(topleftpos->x + x, topleftpos->y + y, color);
|
||||
# else
|
||||
glBoxFilled(topleftpos->x + x, topleftpos->y + y, topleftpos->x + x, topleftpos->y + y, color);
|
||||
# endif
|
||||
font_pixels++;
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return fontChar != fontBitmapUnk;
|
||||
}
|
||||
|
||||
void NDSUI::print(std::string_view str, Position2D topleftpos, const int color) {
|
||||
for (const char c : str) {
|
||||
printChar(c, &topleftpos, color);
|
||||
topleftpos.x += FONT_WIDTH + FONT_PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
void NDSUI::handleInput(char c) {
|
||||
//TODO: Check length
|
||||
switch (c) {
|
||||
case '\b': {
|
||||
// Remove character if not at start
|
||||
if (inputLineBufHead != 0) {
|
||||
inputLineBuf[--inputLineBufHead] = '\0';
|
||||
}
|
||||
} break;
|
||||
case '\n': {
|
||||
if (userInputHandler && inputLineBuf[0]) {
|
||||
auto msg = createLogMessage("User", inputLineBuf.data());
|
||||
addLogMessage(std::move(msg));
|
||||
userInputHandler->set(inputLineBuf.data());
|
||||
resetInputLine();
|
||||
//userInputHandler = nullptr;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
// Add character if not at end
|
||||
if (inputLineBufHead != inputLineBuf.size() - 1) {
|
||||
inputLineBuf[inputLineBufHead] = c;
|
||||
inputLineBuf[++inputLineBufHead] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDSUI::NDSUI() {
|
||||
resetInputLine();
|
||||
glScreen2D();
|
||||
auto swkbd = keyboardDemoInit();
|
||||
swkbd->OnKeyReleased = kbCallback;
|
||||
keyboardShow();
|
||||
}
|
||||
|
||||
void NDSUI::run() {
|
||||
currentInstance = this;
|
||||
font_pixels = 0;
|
||||
// Update keyboard
|
||||
keyboardUpdate();
|
||||
// Draw
|
||||
glBegin2D(); {
|
||||
renderInputLine();
|
||||
renderMessageLog();
|
||||
} glEnd2D();
|
||||
// Apply changes
|
||||
glFlush(0);
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
|
||||
LineWrappedString NDSUI::createLogMessage(const char *username, std::string_view message) {
|
||||
// Do line-wrapping, create and return Message instance
|
||||
return LineWrappedString(" "+std::string(username)+"\n"+std::string(message)+"\n", calcMaxCharsInLine(calcMessageLogDimensions().width()));
|
||||
}
|
||||
|
||||
void LineWrappedString::split(std::string_view str, unsigned maxCharsPerLine) {
|
||||
lines.clear();
|
||||
const char *currStrStart = str.data();
|
||||
const char *strEnd = str.data() + str.size();
|
||||
for (size_t currStrLen = 0; ;) {
|
||||
const char& c = currStrStart[currStrLen];
|
||||
bool brk = false;
|
||||
bool next = false;
|
||||
bool minusOne = false;
|
||||
if (c == '\n') {
|
||||
next = true;
|
||||
minusOne = true;
|
||||
} else if (&c == strEnd) {
|
||||
next = true;
|
||||
brk = true;
|
||||
minusOne = true;
|
||||
} else if (currStrLen > maxCharsPerLine) {
|
||||
next = true;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
lines.push_back({currStrStart, currStrLen});
|
||||
if (brk) break;
|
||||
|
||||
currStrStart += currStrLen + minusOne;
|
||||
currStrLen = 0;
|
||||
} else {
|
||||
currStrLen++;
|
||||
}
|
||||
}
|
||||
}
|
111
NDSUI.hpp
Normal file
111
NDSUI.hpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
#ifndef NDSUI_HPP
|
||||
#define NDSUI_HPP
|
||||
#include "basic-coro/AwaitableTask.hpp"
|
||||
#include "basic-coro/SingleEvent.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class LineWrappedString {
|
||||
unsigned maxCharsPerLine;
|
||||
std::vector<std::string> lines;
|
||||
|
||||
void split(std::string_view, unsigned maxCharsPerLine);
|
||||
|
||||
public:
|
||||
LineWrappedString(std::string_view str, unsigned maxCharsPerLine) : maxCharsPerLine(maxCharsPerLine) {
|
||||
split(str, maxCharsPerLine);
|
||||
}
|
||||
LineWrappedString(const LineWrappedString& o) : maxCharsPerLine(o.maxCharsPerLine), lines(o.lines) {}
|
||||
LineWrappedString(LineWrappedString&& o) : maxCharsPerLine(o.maxCharsPerLine), lines(std::move(o.lines)) {}
|
||||
|
||||
auto& operator=(LineWrappedString&& o) {
|
||||
maxCharsPerLine = o.maxCharsPerLine;
|
||||
lines = std::move(o.lines);
|
||||
return *this;
|
||||
}
|
||||
auto& operator=(const LineWrappedString& o) {
|
||||
maxCharsPerLine = o.maxCharsPerLine;
|
||||
lines = o.lines;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& getLines() const {
|
||||
return lines;
|
||||
}
|
||||
};
|
||||
|
||||
struct Position2D {
|
||||
unsigned x, y;
|
||||
};
|
||||
struct Box2D {
|
||||
Position2D topLeft, bottomRight;
|
||||
|
||||
constexpr
|
||||
unsigned height() const {
|
||||
return bottomRight.y - topLeft.y;
|
||||
}
|
||||
constexpr
|
||||
unsigned width() const {
|
||||
return bottomRight.x - topLeft.x;
|
||||
}
|
||||
};
|
||||
|
||||
class NDSUI {
|
||||
static NDSUI *currentInstance; // Currently updating instance
|
||||
std::array<char, 512> inputLineBuf;
|
||||
unsigned inputLineBufHead = 0;
|
||||
std::vector<LineWrappedString> messages;
|
||||
std::unique_ptr<basiccoro::SingleEvent<std::string>> userInputHandler = nullptr;
|
||||
size_t font_pixels;
|
||||
|
||||
static void kbCallback(int key);
|
||||
|
||||
static consteval
|
||||
Box2D calcInputLineDimensions();
|
||||
static consteval
|
||||
Box2D calcMessageLogDimensions();
|
||||
|
||||
void renderMessageLog();
|
||||
void renderInputLine();
|
||||
|
||||
static consteval
|
||||
unsigned calcMaxCharsInLine(unsigned width);
|
||||
static consteval
|
||||
unsigned calcMaxLinesInRow(unsigned height);
|
||||
|
||||
bool printChar(const char character, Position2D *topleftpos, const int color);
|
||||
void print(std::string_view str, Position2D topleftpos, const int color);
|
||||
|
||||
void handleInput(char);
|
||||
|
||||
void resetInputLine() {
|
||||
inputLineBufHead = 0;
|
||||
inputLineBuf[0] = '\0';
|
||||
}
|
||||
|
||||
public:
|
||||
NDSUI();
|
||||
|
||||
bool shouldRun() const {
|
||||
return userInputHandler != nullptr;
|
||||
}
|
||||
void run();
|
||||
|
||||
auto& addLogMessage(LineWrappedString &&msg) {
|
||||
return messages.emplace_back(std::move(msg));
|
||||
}
|
||||
|
||||
basiccoro::AwaitableTask<std::string> readLine() {
|
||||
userInputHandler = std::make_unique<std::remove_reference<decltype(*userInputHandler)>::type>();
|
||||
co_return co_await *userInputHandler;
|
||||
}
|
||||
|
||||
static
|
||||
LineWrappedString createLogMessage(const char *username, std::string_view message);
|
||||
};
|
||||
#endif // NDSUI_HPP
|
|
@ -3,6 +3,7 @@
|
|||
#include <string_view>
|
||||
#include <array>
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
# include <sys/socket.h>
|
||||
# include <sys/select.h>
|
||||
#else
|
||||
# include <ws2tcpip.h>
|
||||
|
|
47
Runtime.cpp
47
Runtime.cpp
|
@ -1,47 +0,0 @@
|
|||
#include "Runtime.hpp"
|
||||
|
||||
#ifdef PLATFORM_3DS
|
||||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
#include <cerrno>
|
||||
#include <3ds.h>
|
||||
|
||||
|
||||
|
||||
void Runtime::customTerminate() noexcept {
|
||||
// Get error message
|
||||
std::string message;
|
||||
try {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
} catch (const std::exception& e) {
|
||||
message = e.what();
|
||||
} catch (...) {
|
||||
message = "Unknown";
|
||||
}
|
||||
// Display error
|
||||
errorConf conf = {
|
||||
.type = ERROR_TEXT_WORD_WRAP,
|
||||
.errorCode = errno,
|
||||
.upperScreenFlag = ERROR_NORMAL,
|
||||
.useLanguage = CFG_LANGUAGE_EN,
|
||||
.Text = {L'I', L'N', L'V', L'A', L'L', L'I', L'D', L'\0'},
|
||||
.homeButton = true,
|
||||
.softwareReset = false,
|
||||
.appJump = false,
|
||||
.returnCode = ERROR_UNKNOWN,
|
||||
.eulaVersion = 0
|
||||
};
|
||||
errorText(&conf, ("An exception was thrown but never handled:\n\n"+message).c_str());
|
||||
errorDisp(&conf);
|
||||
// Exit
|
||||
aptExit();
|
||||
socExit();
|
||||
gfxExit();
|
||||
exit(-errno);
|
||||
}
|
||||
#elif PLATFORM_DS
|
||||
void Runtime::kbCallback(int key) {
|
||||
if (key > 0) printf("%c", key);
|
||||
}
|
||||
#endif
|
192
Runtime.hpp
192
Runtime.hpp
|
@ -1,77 +1,5 @@
|
|||
#ifndef _RUNTIME_HPP
|
||||
#define _RUNTIME_HPP
|
||||
|
||||
#ifdef PLATFORM_3DS
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include <malloc.h>
|
||||
#include <3ds.h>
|
||||
|
||||
|
||||
class Runtime {
|
||||
u32 *SOC_buffer = NULL;
|
||||
constexpr static auto SOC_ALIGN = 0x1000,
|
||||
SOC_BUFFERSIZE = 0x100000;
|
||||
|
||||
[[noreturn]] static void customTerminate() noexcept;
|
||||
|
||||
public:
|
||||
Runtime() {
|
||||
std::set_terminate(customTerminate);
|
||||
gfxInitDefault();
|
||||
consoleInit(GFX_TOP, NULL);
|
||||
aptInit();
|
||||
SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
|
||||
auto ret = socInit(SOC_buffer, SOC_BUFFERSIZE);
|
||||
if (ret != 0) {
|
||||
throw std::runtime_error("socInit() = "+std::to_string((unsigned int)ret));
|
||||
}
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
~Runtime() {
|
||||
aptSetHomeAllowed(false);
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
std::clog << std::endl << "Runtime destroyed." << std::endl;
|
||||
std::clog << "Press START to exit" << std::flush;
|
||||
for (u32 kDown; !(hidKeysDown() & KEY_START) && cooperate(); hidScanInput()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
aptExit();
|
||||
socExit();
|
||||
gfxExit();
|
||||
}
|
||||
|
||||
static inline
|
||||
bool cooperate() noexcept {
|
||||
return aptMainLoop();
|
||||
}
|
||||
|
||||
static const char *readInput(const char *hint) {
|
||||
static SwkbdState swkbd;
|
||||
static char swkbd_buf[2048];
|
||||
// Read input
|
||||
memset(swkbd_buf, 0, sizeof(swkbd_buf));
|
||||
swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 3, sizeof(swkbd_buf));
|
||||
swkbdSetHintText(&swkbd, hint);
|
||||
swkbdInputText(&swkbd, swkbd_buf, sizeof(swkbd_buf));
|
||||
// Return input as string
|
||||
return swkbd_buf;
|
||||
}
|
||||
|
||||
static void clearScreen() {
|
||||
consoleClear();
|
||||
}
|
||||
};
|
||||
#elif PLATFORM_DS
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
@ -85,12 +13,14 @@ public:
|
|||
|
||||
|
||||
class Runtime {
|
||||
static void kbCallback(int key);
|
||||
|
||||
Keyboard *swkbd;
|
||||
|
||||
public:
|
||||
Runtime() {
|
||||
// Configure displays
|
||||
videoSetMode(MODE_0_3D);
|
||||
lcdMainOnTop();
|
||||
|
||||
// Initialize console
|
||||
consoleDemoInit();
|
||||
|
||||
|
@ -99,10 +29,6 @@ public:
|
|||
if (!Wifi_InitDefault(WFC_CONNECT)) {
|
||||
throw std::runtime_error("Failed to enable WiFi");
|
||||
}
|
||||
|
||||
// Initialize keyboard
|
||||
swkbd = keyboardDemoInit();
|
||||
swkbd->OnKeyPressed = kbCallback;
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
|
@ -126,114 +52,6 @@ public:
|
|||
consoleClear();
|
||||
}
|
||||
};
|
||||
#elif PLATFORM_LINUX
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <mutex>
|
||||
#include <cstring>
|
||||
#include <csignal>
|
||||
#include <cerrno>
|
||||
|
||||
|
||||
|
||||
class Runtime {
|
||||
static inline bool stopping = false;
|
||||
static inline void handler(int signo, siginfo_t *info, void *context) {
|
||||
stopping = true;
|
||||
}
|
||||
|
||||
public:
|
||||
Runtime() {
|
||||
struct sigaction act = { 0 };
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = handler;
|
||||
for (int sig : {SIGTERM, SIGINT, SIGQUIT, SIGHUP}) {
|
||||
if (sigaction(sig, &act, nullptr) < 0) {
|
||||
throw std::runtime_error("sigaction() = "+std::string(strerror(errno)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
~Runtime() {
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
std::clog << std::endl << "Runtime destroyed." << std::endl;
|
||||
}
|
||||
|
||||
static inline bool cooperate() noexcept {
|
||||
// Linux runs threads preemptively, no need to actually cooperate
|
||||
return !stopping;
|
||||
}
|
||||
|
||||
static const char *readInput(const char *hint) {
|
||||
static std::string content;
|
||||
std::cout << hint << ": ";
|
||||
std::getline(std::cin, content);
|
||||
return content.c_str();
|
||||
}
|
||||
|
||||
static void clearScreen() {
|
||||
std::cout << "\033[H\033[2J\033[3J";
|
||||
}
|
||||
};
|
||||
#elif PLATFORM_WINDOWS
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <winsock2.h>
|
||||
|
||||
|
||||
|
||||
class Runtime {
|
||||
public:
|
||||
Runtime() {
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
throw std::runtime_error("Failed to initialize WinSock");
|
||||
}
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
~Runtime() {
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
std::clog << std::endl << "Runtime destroyed." << std::endl;
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
static constexpr bool cooperate() noexcept {
|
||||
// Windows runs threads preemptively, no need to cooperate.
|
||||
// No signals to handle either, Windows doesn't support them.
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *readInput(const char *hint) {
|
||||
static std::string content;
|
||||
std::cout << hint << ": ";
|
||||
std::getline(std::cin, content);
|
||||
return content.c_str();
|
||||
}
|
||||
|
||||
static void clearScreen() {
|
||||
system("cls");
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !(defined(PLATFORM_WINDOWS) || defined(PLATFORM_DS))
|
||||
# define MSG_FLAGS_OR_ZERO(...) __VA_ARGS__
|
||||
#else
|
||||
# define MSG_FLAGS_OR_ZERO(...) 0
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_DS
|
||||
# define IPPROTO_TCP 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_DS
|
||||
# define HAS_ADDRINFO
|
||||
#define IPPROTO_TCP 0
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <string_view>
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
# include <sys/socket.h>
|
||||
# include <sys/select.h>
|
||||
#else
|
||||
# include <ws2tcpip.h>
|
||||
|
@ -25,5 +26,5 @@ basiccoro::AwaitableTask<AsyncResult> Sender::Simple::write(const std::byte *dat
|
|||
}
|
||||
|
||||
// Write
|
||||
co_return (send(fd, reinterpret_cast<const char*>(data), size, MSG_FLAGS_OR_ZERO(MSG_NOSIGNAL | (int(moreData)*MSG_MORE))) < 0)?AsyncResult::Error:AsyncResult::Success;
|
||||
co_return (send(fd, reinterpret_cast<const char*>(data), size, 0) < 0)?AsyncResult::Error:AsyncResult::Success;
|
||||
}
|
||||
|
|
13
font.h
Normal file
13
font.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include <stdbool.h>
|
||||
#define FONT_HEIGHT 16
|
||||
#define FONT_WIDTH 8
|
||||
#define FONT_SIZE FONT_HEIGHT * FONT_WIDTH
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern const bool fontBitmapUnk[FONT_SIZE];
|
||||
const bool *font_get_character(const char character);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
765
font_ugly.h
Normal file
765
font_ugly.h
Normal file
|
@ -0,0 +1,765 @@
|
|||
#include <stdbool.h>
|
||||
#define FONT_HEIGHT 8
|
||||
#define FONT_WIDTH 4
|
||||
#define FONT_SIZE FONT_HEIGHT * FONT_WIDTH
|
||||
|
||||
|
||||
const bool font_space[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
};
|
||||
const bool font_unk[] = {
|
||||
1, 1, 1, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 1, 1, 1,
|
||||
};
|
||||
|
||||
const bool font_digit_1[] = {
|
||||
0, 0, 0, 1,
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
const bool font_digit_2[] = {
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 1, 1,
|
||||
};
|
||||
const bool font_digit_3[] = {
|
||||
1, 1, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
};
|
||||
const bool font_digit_4[] = {
|
||||
0, 0, 0, 1,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
1, 0, 1, 0,
|
||||
1, 1, 1, 1,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 0,
|
||||
};
|
||||
const bool font_digit_5[] = {
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
};
|
||||
const bool font_digit_6[] = {
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_digit_7[] = {
|
||||
1, 1, 1, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
};
|
||||
const bool font_digit_8[] = {
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_digit_9[] = {
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
};
|
||||
const bool font_digit_0[] = {
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
|
||||
const bool font_letter_a[] = {
|
||||
0, 0, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_b[] = {
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_c[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 1, 1,
|
||||
};
|
||||
|
||||
const bool font_letter_d[] = {
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_e[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_f[] = {
|
||||
0, 0, 1, 1,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
};
|
||||
const bool font_letter_g[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_h[] = {
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_i[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
};
|
||||
const bool font_letter_j[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
1, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
};
|
||||
const bool font_letter_k[] = {
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 1, 0,
|
||||
1, 1, 0, 0,
|
||||
1, 0, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_l[] = {
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 1,
|
||||
0, 0, 1, 0,
|
||||
};
|
||||
const bool font_letter_m[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 0, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 0, 1, 1,
|
||||
};
|
||||
const bool font_letter_n[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_o[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_p[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
};
|
||||
const bool font_letter_q[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_r[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
};
|
||||
const bool font_letter_s[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_t[] = {
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 1,
|
||||
};
|
||||
const bool font_letter_u[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_v[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
|
||||
const bool font_letter_w[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_x[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_y[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_z[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
};
|
||||
const bool font_letter_A[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_B[] = {
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_C[] = {
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 1, 1,
|
||||
};
|
||||
const bool font_letter_D[] = {
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_E[] = {
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
};
|
||||
const bool font_letter_F[] = {
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
};
|
||||
const bool font_letter_G[] = {
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_H[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_I[] = {
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
};
|
||||
const bool font_letter_J[] = {
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_K[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 1, 0,
|
||||
1, 1, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 0, 0,
|
||||
1, 0, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_L[] = {
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
};
|
||||
const bool font_letter_M[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_N[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_O[] = {
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_P[] = {
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
};
|
||||
const bool font_letter_Q[] = {
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 0, 1, 1,
|
||||
0, 1, 1, 1,
|
||||
};
|
||||
const bool font_letter_R[] = {
|
||||
1, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
1, 1, 0, 0,
|
||||
1, 0, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_S[] = {
|
||||
0, 1, 1, 1,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
1, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_T[] = {
|
||||
1, 1, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
};
|
||||
const bool font_letter_U[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_V[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_W[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 0,
|
||||
};
|
||||
const bool font_letter_X[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 0,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_Y[] = {
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
const bool font_letter_Z[] = {
|
||||
1, 1, 1, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
1, 1, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
};
|
||||
|
||||
const bool font_special_dot[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
};
|
||||
const bool font_special_colon[] = {
|
||||
0, 1, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
};
|
||||
const bool font_special_exclaimationmark[] = {
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
*/
|
||||
const bool *font_get_character(const char character) {
|
||||
const bool *res = font_unk;
|
||||
switch(character) {
|
||||
case 'a': res = font_letter_a; break;
|
||||
case 'b': res = font_letter_b; break;
|
||||
case 'c': res = font_letter_c; break;
|
||||
case 'd': res = font_letter_d; break;
|
||||
case 'e': res = font_letter_e; break;
|
||||
case 'f': res = font_letter_f; break;
|
||||
case 'g': res = font_letter_g; break;
|
||||
case 'h': res = font_letter_h; break;
|
||||
case 'i': res = font_letter_i; break;
|
||||
case 'j': res = font_letter_j; break;
|
||||
case 'k': res = font_letter_k; break;
|
||||
case 'l': res = font_letter_l; break;
|
||||
case 'm': res = font_letter_m; break;
|
||||
case 'n': res = font_letter_n; break;
|
||||
case 'o': res = font_letter_o; break;
|
||||
case 'p': res = font_letter_p; break;
|
||||
case 'q': res = font_letter_q; break;
|
||||
case 'r': res = font_letter_r; break;
|
||||
case 's': res = font_letter_s; break;
|
||||
case 't': res = font_letter_t; break;
|
||||
case 'u': res = font_letter_u; break;
|
||||
case 'v': res = font_letter_v; break;
|
||||
case 'w': res = font_letter_w; break;
|
||||
case 'x': res = font_letter_x; break;
|
||||
case 'y': res = font_letter_y; break;
|
||||
case 'z': res = font_letter_z; break;
|
||||
case 'A': res = font_letter_A; break;
|
||||
case 'B': res = font_letter_B; break;
|
||||
case 'C': res = font_letter_C; break;
|
||||
case 'D': res = font_letter_D; break;
|
||||
case 'E': res = font_letter_E; break;
|
||||
case 'F': res = font_letter_F; break;
|
||||
case 'G': res = font_letter_G; break;
|
||||
case 'H': res = font_letter_H; break;
|
||||
case 'I': res = font_letter_I; break;
|
||||
case 'J': res = font_letter_J; break;
|
||||
case 'K': res = font_letter_K; break;
|
||||
case 'L': res = font_letter_L; break;
|
||||
case 'M': res = font_letter_M; break;
|
||||
case 'N': res = font_letter_N; break;
|
||||
case 'O': res = font_letter_O; break;
|
||||
case 'P': res = font_letter_P; break;
|
||||
case 'Q': res = font_letter_Q; break;
|
||||
case 'R': res = font_letter_R; break;
|
||||
case 'S': res = font_letter_S; break;
|
||||
case 'T': res = font_letter_T; break;
|
||||
case 'U': res = font_letter_U; break;
|
||||
case 'V': res = font_letter_V; break;
|
||||
case 'W': res = font_letter_W; break;
|
||||
case 'X': res = font_letter_X; break;
|
||||
case 'Y': res = font_letter_Y; break;
|
||||
case 'Z': res = font_letter_Z; break;
|
||||
case ' ': res = font_space; break;
|
||||
case '1': res = font_digit_1; break;
|
||||
case '2': res = font_digit_2; break;
|
||||
case '3': res = font_digit_3; break;
|
||||
case '4': res = font_digit_4; break;
|
||||
case '5': res = font_digit_5; break;
|
||||
case '6': res = font_digit_6; break;
|
||||
case '7': res = font_digit_7; break;
|
||||
case '8': res = font_digit_8; break;
|
||||
case '9': res = font_digit_9; break;
|
||||
case '0': res = font_digit_0; break;
|
||||
case '.': res = font_special_dot; break;
|
||||
case ':': res = font_special_colon; break;
|
||||
case '!': res = font_special_exclaimationmark; break;
|
||||
}
|
||||
return res;
|
||||
}
|
37
main.cpp
37
main.cpp
|
@ -1,3 +1,4 @@
|
|||
#include "NDSUI.hpp"
|
||||
#include "Runtime.hpp"
|
||||
#include "AsyncManager.hpp"
|
||||
#include "Client.hpp"
|
||||
|
@ -13,49 +14,57 @@ void on_progress(float progress) {
|
|||
std::cout << unsigned(progress) << '\r' << std::flush;
|
||||
}
|
||||
|
||||
basiccoro::AwaitableTask<void> async_main(Runtime& rt, AsyncManager &aMan) {
|
||||
basiccoro::AwaitableTask<void> async_main(Runtime& rt, AsyncManager &aMan, NDSUI& ui) {
|
||||
// Ask for server address
|
||||
const std::string addr = rt.readInput("Server address");
|
||||
ui.addLogMessage(ui.createLogMessage("System", "Please type in the address of the server."));
|
||||
const std::string addr = co_await ui.readLine();
|
||||
|
||||
// Create client
|
||||
Client client(addr, 99181, aMan);
|
||||
|
||||
// Greet the user
|
||||
ui.addLogMessage(ui.createLogMessage("Bot", "Hey! How can I help you today?"));
|
||||
|
||||
// Connection loop
|
||||
for (;; rt.cooperate()) {
|
||||
// Read prompt
|
||||
const auto prompt = rt.readInput("Prompt");
|
||||
|
||||
// Clear screen
|
||||
rt.clearScreen();
|
||||
const auto prompt = co_await ui.readLine();
|
||||
|
||||
// Display prompt
|
||||
std::cout << "Prompt: " << prompt << std::endl;
|
||||
auto& msg = ui.addLogMessage(ui.createLogMessage("Bot", "Initializing..."));
|
||||
|
||||
// Run inference
|
||||
co_await client.ask(prompt, [&rt] (float progress) -> basiccoro::AwaitableTask<void> {
|
||||
std::cout << unsigned(progress) << "%\r" << std::flush;
|
||||
std::string result;
|
||||
co_await client.ask(prompt, [&msg, &ui] (unsigned progress) -> basiccoro::AwaitableTask<void> {
|
||||
msg = ui.createLogMessage("Bot", (std::to_string(progress)+"%"));
|
||||
co_return;
|
||||
}, [&rt] (std::string_view token) -> basiccoro::AwaitableTask<void> {
|
||||
std::cout << token << std::flush;
|
||||
}, [&result, &msg, &ui] (std::string_view token) -> basiccoro::AwaitableTask<void> {
|
||||
result.append(token);
|
||||
msg = ui.createLogMessage("Bot", result+"...");
|
||||
co_return;
|
||||
});
|
||||
msg = ui.createLogMessage("Bot", result);
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
Runtime rt;
|
||||
NDSUI ui;
|
||||
AsyncManager aMan(rt);
|
||||
|
||||
// Print header
|
||||
std::cout << "llama.any running on " PLATFORM ".\n"
|
||||
std::cout << "llama.nds running on " PLATFORM ".\n"
|
||||
"\n";
|
||||
|
||||
// Start async main()
|
||||
async_main(rt, aMan);
|
||||
async_main(rt, aMan, ui);
|
||||
|
||||
// Start async manager
|
||||
aMan.run();
|
||||
while (aMan.shouldRun() || ui.shouldRun()) {
|
||||
ui.run();
|
||||
aMan.run();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue