658 lines
19 KiB
C++
658 lines
19 KiB
C++
#include <pd.hpp>
|
|
|
|
PD::Net::Backend::Ref net_backend;
|
|
PD::LI::Backend::Ref backend;
|
|
PD::Hid::Ref inp;
|
|
|
|
#ifdef __3DS__
|
|
#include <3ds.h>
|
|
|
|
#include <li_backend_c3d.hpp>
|
|
#include <pd_hid_3ds.hpp>
|
|
#include <pd_net_3ds.hpp>
|
|
|
|
const u32 DisplayTransferFlags =
|
|
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) |
|
|
GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) |
|
|
GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) |
|
|
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO));
|
|
#else
|
|
#include <li_backend_gl2.hpp>
|
|
#include <pd_hid_glfw.hpp>
|
|
#include <pd_net_desktop.hpp>
|
|
|
|
bool vs = true;
|
|
|
|
void WindowIcn(GLFWwindow* win, const std::string& path) {
|
|
auto img = PD::Image::New(path);
|
|
if (img->Fmt() == img->RGB) {
|
|
PD::Image::Convert(img, img->RGBA);
|
|
}
|
|
GLFWimage* i = new GLFWimage;
|
|
i->pixels = new unsigned char[img->GetBuffer().size()];
|
|
/** Use std::copy_n instead of memcpy (Weil nicht rot unterstrichen) */
|
|
std::copy_n(img->GetBuffer().data(), img->GetBuffer().size(), i->pixels);
|
|
i->width = img->Width();
|
|
i->height = img->Height();
|
|
glfwSetWindowIcon(win, 1, i);
|
|
}
|
|
|
|
#endif
|
|
|
|
class FileBrowserOderSo {
|
|
public:
|
|
struct Entry {
|
|
std::string Name;
|
|
std::string Path;
|
|
bool Directory;
|
|
std::shared_ptr<std::vector<Entry>> DirContent;
|
|
};
|
|
FileBrowserOderSo() { Listing = ParseDir(CurrentPath); }
|
|
~FileBrowserOderSo() = default;
|
|
|
|
std::vector<Entry> ParseDir(const std::string& path) {
|
|
std::vector<Entry> res;
|
|
try {
|
|
for (auto& it : std::filesystem::directory_iterator(path)) {
|
|
res.push_back({it.path().filename().string(), it.path().string(),
|
|
it.is_directory()});
|
|
}
|
|
} catch (const std::filesystem::filesystem_error& e) {
|
|
// Actually just keeping the App alive
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/** Recursive Continue Tree View Generation */
|
|
void RCTVG(PD::UI7::Menu::Ref m, std::vector<Entry>& listing,
|
|
const std::string& cp) {
|
|
if (m->BeginTreeNode(cp)) {
|
|
for (auto& it : listing) {
|
|
if (it.Directory) {
|
|
if (!it.DirContent) {
|
|
it.DirContent = std::make_shared<std::vector<Entry>>();
|
|
*it.DirContent = ParseDir(it.Path);
|
|
}
|
|
RCTVG(m, *it.DirContent, it.Name);
|
|
} else {
|
|
m->Label(it.Name);
|
|
}
|
|
}
|
|
m->EndTreeNode();
|
|
}
|
|
}
|
|
|
|
void UI_Handle(PD::UI7::Context::Ref ui7) {
|
|
if (ui7->BeginMenu("FileBrowser", UI7MenuFlags_Scrolling)) {
|
|
auto m = ui7->GetCurrentMenu();
|
|
RCTVG(m, Listing, CurrentPath);
|
|
ui7->EndMenu();
|
|
}
|
|
}
|
|
|
|
std::string CurrentPath = "/";
|
|
std::vector<Entry> Listing;
|
|
};
|
|
|
|
#include <mutex>
|
|
#include <thread>
|
|
|
|
const int PORT = 8080;
|
|
const size_t MAX_LOGS = 100;
|
|
|
|
bool skill_thread = false;
|
|
|
|
std::mutex logMutex;
|
|
std::mutex coutCaptureMutex;
|
|
std::deque<std::string> logBuffer;
|
|
|
|
std::ostringstream capturedOutput;
|
|
|
|
class CoutRedirector : public std::streambuf {
|
|
public:
|
|
CoutRedirector(std::streambuf* original) : originalBuf(original) {}
|
|
|
|
protected:
|
|
int overflow(int c) override {
|
|
if (c != EOF) {
|
|
std::lock_guard<std::mutex> lock(coutCaptureMutex); // separate mutex
|
|
capturedOutput.put(c);
|
|
if (c == '\n') {
|
|
logBuffer.push_back(capturedOutput.str());
|
|
capturedOutput.str("");
|
|
capturedOutput.clear();
|
|
}
|
|
}
|
|
return originalBuf->sputc(c); // still forward to original
|
|
}
|
|
|
|
private:
|
|
std::streambuf* originalBuf;
|
|
};
|
|
|
|
CoutRedirector* redirector = nullptr;
|
|
|
|
void startCoutCapture() {
|
|
static std::streambuf* originalCoutBuffer = std::cout.rdbuf();
|
|
redirector = new CoutRedirector(originalCoutBuffer);
|
|
std::cout.rdbuf(redirector);
|
|
}
|
|
|
|
void logMessage(const std::string& msg) {
|
|
std::lock_guard<std::mutex> lock(logMutex);
|
|
if (logBuffer.size() >= MAX_LOGS) logBuffer.pop_front();
|
|
logBuffer.push_back(msg);
|
|
std::cout << msg << std::endl;
|
|
}
|
|
|
|
const char* css_file = R"(
|
|
html, body {
|
|
font-family: 'Montserrat', sans-serif;
|
|
background-color: #1e1e1e;
|
|
color: #e0e0e0;
|
|
margin: 0;
|
|
padding: 0;
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100vh;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
main {
|
|
flex: 1;
|
|
padding: 2rem;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
h2 {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
pre {
|
|
background-color: #2e2e2e;
|
|
padding: 1rem;
|
|
border-radius: 8px;
|
|
overflow-x: auto;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
footer {
|
|
background-color: #333;
|
|
color: #e0e0e0;
|
|
padding: 1rem;
|
|
text-align: center;
|
|
width: 100%;
|
|
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
img {
|
|
border-radius: 50%;
|
|
}
|
|
|
|
a {
|
|
color: #3498db;
|
|
text-decoration: none;
|
|
font-weight: bold;
|
|
}
|
|
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
footer a {
|
|
color: #3498db;
|
|
text-decoration: none;
|
|
font-weight: bold;
|
|
}
|
|
|
|
footer a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
)";
|
|
|
|
const char* html_begin = R"(
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>HTTP Server</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="/style.css">
|
|
</head>
|
|
)";
|
|
|
|
const char* html_404 = R"(
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta http-equiv="refresh" content="5">
|
|
<title>404 Not Found</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="/style.css">
|
|
</head>
|
|
<body>
|
|
<img src="/assets/icon.png" width="100">
|
|
<h2>404 Page not found!</h2>
|
|
<a href="/">Return to main Page</a>
|
|
</body>
|
|
</html>
|
|
)";
|
|
|
|
const char* html_end = "<footer>2025 tobid7</footer></body></html>";
|
|
|
|
std::string getLogs() {
|
|
std::lock_guard<std::mutex> lock(logMutex);
|
|
std::ostringstream oss;
|
|
for (const auto& line : logBuffer) oss << line;
|
|
return oss.str();
|
|
}
|
|
|
|
std::string getIndexHTML() {
|
|
std::lock_guard<std::mutex> lock(logMutex);
|
|
std::ostringstream oss;
|
|
|
|
oss << html_begin;
|
|
oss << "<body><main><h1>Welcome</h1><ul><li><a href=\"/logs\">View "
|
|
"Logs</a></li><li><a href=\"/sysinfo\">System "
|
|
"Info</a></li></ul></main>";
|
|
oss << html_end;
|
|
return oss.str();
|
|
}
|
|
|
|
std::string getSystemInfo() {
|
|
std::ostringstream oss;
|
|
oss << "Compiler -> " << PD::Strings::GetCompilerVersion() << std::endl;
|
|
oss << "Lithium -> " << backend->pName << std::endl;
|
|
oss << "Input Driver -> " << inp->pName << std::endl;
|
|
oss << "Network Driver -> " << net_backend->pName << std::endl;
|
|
oss << "Lithium:" << std::endl;
|
|
oss << " Vertices: " << backend->VertexCounter << std::endl;
|
|
oss << " Indices: " << backend->IndexCounter << std::endl;
|
|
oss << " Triangles: " << backend->IndexCounter / 3 << std::endl;
|
|
#ifdef __3DS__
|
|
oss << "Section 3DS" << std::endl;
|
|
oss << " linear_mem: " << PD::Strings::FormatBytes(linearSpaceFree())
|
|
<< std::endl;
|
|
#endif
|
|
return oss.str();
|
|
}
|
|
|
|
void handleClient(PD::Net::Socket::Ref client) {
|
|
std::string buf;
|
|
int len = client->Receive(buf, 4096);
|
|
if (len > 0) {
|
|
buf[len] = '\0';
|
|
if (buf.find("GET / ") == 0 || buf.find("GET /HTTP") == 0 ||
|
|
buf.find("GET / HTTP") == 0) {
|
|
std::string body = getIndexHTML();
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/html\r\n"
|
|
<< "Content-Length: " << body.size() << "\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body;
|
|
client->Send(response.str());
|
|
} else if (buf.find("GET /logs") == 0) {
|
|
std::ostringstream body;
|
|
body << html_begin;
|
|
body << R"(
|
|
<body>
|
|
<main>
|
|
<h2>Logs</h2>
|
|
<pre id="logs">Fetching logs...</pre>
|
|
<script>
|
|
// Simply fetch a string by using an api endpoint
|
|
async function fetchLogs() {
|
|
const res = await fetch('/logdata');
|
|
const text = await res.text();
|
|
document.getElementById('logs').innerText = text;
|
|
}
|
|
setInterval(fetchLogs, 2000);
|
|
fetchLogs();
|
|
</script>
|
|
</main>
|
|
)";
|
|
body << html_end;
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/html\r\n"
|
|
<< "Content-Length: " << body.str().size() << "\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body.str();
|
|
client->Send(response.str());
|
|
} else if (buf.find("GET /sysinfo ") == 0) {
|
|
std::ostringstream body;
|
|
body << html_begin;
|
|
body << R"(
|
|
<body>
|
|
<main>
|
|
<h2>System Info</h2>
|
|
<pre id="sysinfo">Loading...</pre>
|
|
<script>
|
|
// Simply fetch a string by using an api endpoint
|
|
async function fetchSysInfo() {
|
|
const res = await fetch('/sysinfo/data');
|
|
const text = await res.text();
|
|
document.getElementById('sysinfo').innerText = text;
|
|
}
|
|
setInterval(fetchSysInfo, 2000);
|
|
fetchSysInfo();
|
|
</script>
|
|
</main>
|
|
)";
|
|
body << html_end;
|
|
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/html\r\n"
|
|
<< "Content-Length: " << body.str().size() << "\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body.str();
|
|
client->Send(response.str());
|
|
} else if (buf.find("GET /sysinfo/data") == 0) {
|
|
std::string body = getSystemInfo();
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/plain\r\n"
|
|
<< "Content-Length: " << body.size() << "\r\n"
|
|
<< "Cache-Control: no-cache\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body;
|
|
client->Send(response.str());
|
|
} else if (buf.find("GET /logdata") == 0) {
|
|
std::string body = getLogs();
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/plain\r\n"
|
|
<< "Content-Length: " << body.size() << "\r\n"
|
|
<< "Cache-Control: no-cache\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body;
|
|
client->Send(response.str());
|
|
} else if (buf.find("GET /style.css") == 0) {
|
|
std::string body = css_file;
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/css\r\n"
|
|
<< "Content-Length: " << body.size() << "\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body;
|
|
client->Send(response.str());
|
|
} else if (buf.find("GET /assets/icon.png") == 0) {
|
|
std::ifstream f("test.png", std::ios::binary);
|
|
if (f) {
|
|
std::ostringstream body_stream;
|
|
body_stream << f.rdbuf();
|
|
std::string body = body_stream.str();
|
|
std::ostringstream header;
|
|
header << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: image/png\r\n"
|
|
<< "Content-Length: " << body.size() << "\r\n"
|
|
<< "Connection: close\r\n\r\n";
|
|
client->Send(header.str());
|
|
client->Send(body);
|
|
} else {
|
|
client->Send("HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n");
|
|
}
|
|
std::string body = css_file;
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/css\r\n"
|
|
<< "Content-Length: " << body.size() << "\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body;
|
|
client->Send(response.str());
|
|
} else {
|
|
std::string body = html_404;
|
|
std::ostringstream response;
|
|
response << "HTTP/1.1 200 OK\r\n"
|
|
<< "Content-Type: text/html\r\n"
|
|
<< "Content-Length: " << body.size() << "\r\n"
|
|
<< "Connection: close\r\n\r\n"
|
|
<< body;
|
|
client->Send(response.str());
|
|
}
|
|
}
|
|
client->Close();
|
|
}
|
|
|
|
void startServer() {
|
|
auto server = PD::Net::Socket::New(net_backend, PORT);
|
|
server->Listen();
|
|
|
|
std::cout << "HTTP Logging Console running on http://localhost:" << PORT
|
|
<< "/logs\n";
|
|
|
|
while (!skill_thread) {
|
|
auto client = PD::Net::Socket::New(net_backend);
|
|
server->Accept(client);
|
|
std::thread(handleClient, client).detach();
|
|
}
|
|
}
|
|
|
|
class HttpServer {
|
|
public:
|
|
HttpServer(PD::Net::Backend::Ref backend) {}
|
|
|
|
void StartServer() {
|
|
auto server = PD::Net::Socket::New(pBackend, PORT);
|
|
server->Listen();
|
|
while (true) {
|
|
auto client = PD::Net::Socket::New(pBackend);
|
|
server->Accept(client);
|
|
}
|
|
}
|
|
|
|
PD::Net::Backend::Ref pBackend;
|
|
};
|
|
|
|
int main() {
|
|
bool m__ = false;
|
|
bool a__ = false;
|
|
bool s__ = false;
|
|
#ifdef __3DS__
|
|
net_backend = PD::NetBackend3DS::New();
|
|
net_backend->Init();
|
|
osSetSpeedupEnable(true);
|
|
gfxInitDefault();
|
|
cfguInit();
|
|
cfguExit();
|
|
// consoleInit(GFX_BOTTOM, nullptr);
|
|
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE * 2);
|
|
C3D_RenderTarget* Top =
|
|
C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
|
C3D_RenderTarget* Bottom =
|
|
C3D_RenderTargetCreate(240, 320, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
|
C3D_RenderTargetSetOutput(Top, GFX_TOP, GFX_LEFT, DisplayTransferFlags);
|
|
C3D_RenderTargetSetOutput(Bottom, GFX_BOTTOM, GFX_LEFT, DisplayTransferFlags);
|
|
backend = PD::LI::Backend_C3D::New();
|
|
inp = PD::Hid3DS::New();
|
|
#else
|
|
net_backend = PD::NetBackendDesktop::New();
|
|
net_backend->Init();
|
|
glfwInit();
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
|
|
// glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
|
|
#ifdef __APPLE__
|
|
// Using This as frame buffer would be way too large
|
|
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, 0);
|
|
#endif
|
|
glfwWindowHint(GLFW_SAMPLES, 8); // Anti Aliasing
|
|
auto win = glfwCreateWindow(1280, 720, "Palladium", nullptr, nullptr);
|
|
glfwMakeContextCurrent(win);
|
|
glfwSwapInterval(1);
|
|
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
|
|
std::cout << "OpenGL: " << GLVersion.major << "." << GLVersion.minor
|
|
<< std::endl;
|
|
if (!glCreateShader) {
|
|
std::cout << "glCreateShader wurde nicht gefunden oder so keine ahnung"
|
|
<< std::endl;
|
|
}
|
|
|
|
WindowIcn(win, "test.png");
|
|
backend = PD::LI::Backend_GL2::New();
|
|
inp = PD::HidGLFW::New(win);
|
|
#endif
|
|
startCoutCapture();
|
|
std::thread server_http(startServer);
|
|
server_http.detach();
|
|
#ifdef __3DS__
|
|
std::cout << "System freezed... Press A!" << std::endl;
|
|
while (aptMainLoop()) {
|
|
hidScanInput();
|
|
if (hidKeysDown() & KEY_A) {
|
|
break;
|
|
}
|
|
gspWaitForVBlank();
|
|
gfxSwapBuffers();
|
|
}
|
|
#endif
|
|
backend->Init();
|
|
auto font = PD::LI::Font::New(backend);
|
|
font->LoadTTF("ComicNeue.ttf", 32);
|
|
#ifdef __3DS__
|
|
font->DefaultPixelHeight = 24;
|
|
#else
|
|
font->DefaultPixelHeight = 32;
|
|
#endif
|
|
auto ren = PD::LI::Renderer::New(backend);
|
|
PD::Image img("test.png");
|
|
PD::Image img2("logo.png");
|
|
auto tex = backend->LoadTexture(
|
|
img, img.Width(), img.Height(),
|
|
img.Fmt() == img.RGBA ? PD::LI::Texture::RGBA32 : PD::LI::Texture::RGB24);
|
|
auto tex2 =
|
|
backend->LoadTexture(img2, img2.Width(), img2.Height(),
|
|
img2.Fmt() == img.RGBA ? PD::LI::Texture::RGBA32
|
|
: PD::LI::Texture::RGB24);
|
|
auto r = PD::LI::DrawList::New(ren->WhitePixel);
|
|
r->SetFont(font);
|
|
PD::UI7::Context::Ref ui7 = PD::UI7::Context::New(ren, inp);
|
|
ui7->GetIO()->Font = font;
|
|
FileBrowserOderSo fb;
|
|
#ifdef __3DS__
|
|
ui7->GetIO()->Theme->Set(UI7Color_Background, PD::Color("#222222aa"));
|
|
while (aptMainLoop()) {
|
|
backend->ViewPort = ivec2(320, 240);
|
|
#else
|
|
while (!glfwWindowShouldClose(win)) {
|
|
int wx, wy;
|
|
glfwGetWindowSize(win, &wx, &wy);
|
|
backend->ViewPort = ivec2(wx, wy);
|
|
#endif
|
|
inp->Update();
|
|
r->CurrentTex = ren->WhitePixel;
|
|
ren->CurrentTex = ren->WhitePixel;
|
|
ui7->DoMenuEx("TestInline", UI7MenuFlags_Scrolling,
|
|
[&](PD::UI7::ReMenu::Ref m) {
|
|
m->SeparatorText("Test");
|
|
m->Label("Test oder So");
|
|
static bool v;
|
|
static float v2;
|
|
m->Checkbox("Checkbox", v);
|
|
m->DragData("Test V2", &v2, 1);
|
|
m->Label("Test");
|
|
m->Separator();
|
|
if (m->Button("Hello1")) {
|
|
logMessage("Button Pressed");
|
|
}
|
|
m->Image(tex2);
|
|
});
|
|
/*if (ui7->BeginMenuEx("TestMenu")) {
|
|
auto m = ui7->GetCurrentMenuEx();
|
|
m->SeparatorText("Hello World!");
|
|
m->Separator();
|
|
ui7->EndMenuEx();
|
|
}*/
|
|
if (ui7->BeginMenu("Test")) {
|
|
auto m = ui7->GetCurrentMenu();
|
|
m->Button("Button");
|
|
m->Label("Label");
|
|
if (m->Button("Show Metrics")) {
|
|
m__ = true;
|
|
}
|
|
if (m->Button("Show About")) {
|
|
a__ = true;
|
|
}
|
|
if (m->Button("Show Style")) {
|
|
s__ = true;
|
|
}
|
|
m->PushAlignment(UI7Align_Mid);
|
|
m->SeparatorText("Extra");
|
|
m->PopAlignment();
|
|
m->DragData("FontScale", &font->DefaultPixelHeight);
|
|
#ifndef __3DS__
|
|
if (m->Button("Toggle VSYNC")) {
|
|
vs = !vs;
|
|
glfwSwapInterval(vs);
|
|
}
|
|
#endif
|
|
ui7->EndMenu();
|
|
}
|
|
// fb.UI_Handle(ui7);
|
|
ui7->StyleEditor(&s__);
|
|
ui7->AboutMenu(&a__);
|
|
ui7->MetricsMenu(&m__);
|
|
r->CurrentTex = tex;
|
|
r->DrawCircleFilled(
|
|
100, 24, 0xffffffff,
|
|
3 + int(((std::sin(ui7->GetIO()->Time->GetSeconds()) + 1) / 2) * 50));
|
|
ui7->Update(0);
|
|
// r->CurrentTex = smdhtex;
|
|
// r->DrawRectFilled(0, 48, 0xffffffff);
|
|
ren->RegisterDrawList(r);
|
|
|
|
#ifdef __3DS__
|
|
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
|
|
C3D_FrameDrawOn(Top);
|
|
C3D_RenderTargetClear(Top, C3D_CLEAR_ALL, 0x00000000, 0);
|
|
auto l = PD::LI::DrawList::New(ren->WhitePixel);
|
|
l->DrawText(5, std::format("Tris: {}", ui7->GetIO()->NumIndices / 3),
|
|
0xffffffff);
|
|
ivec2 tvp = backend->ViewPort;
|
|
backend->ViewPort = ivec2(400, 240);
|
|
backend->NewFrame();
|
|
backend->RenderDrawData(l->pDrawList);
|
|
l->pDrawList.Clear();
|
|
backend->ViewPort = tvp;
|
|
C3D_FrameDrawOn(Bottom);
|
|
C3D_RenderTargetClear(Bottom, C3D_CLEAR_ALL, 0x00000000, 0);
|
|
PD::TT::Beg("R");
|
|
// backend->NewFrame();
|
|
backend->RenderDrawData(ui7->GetIO()->pRDL->pDrawList);
|
|
ui7->GetIO()->pRDL->pDrawList.Clear();
|
|
// ren->Render();
|
|
PD::TT::End("R");
|
|
C3D_FrameEnd(0);
|
|
#else
|
|
PD::TT::Beg("R");
|
|
ren->Render();
|
|
PD::TT::End("R");
|
|
glfwPollEvents();
|
|
glfwSwapBuffers(win);
|
|
#endif
|
|
}
|
|
backend->Deinit();
|
|
skill_thread = true;
|
|
if (server_http.joinable()) {
|
|
server_http.join();
|
|
}
|
|
net_backend->Deinit();
|
|
#ifdef __3DS__
|
|
C3D_Fini();
|
|
gfxExit();
|
|
#else
|
|
glfwTerminate();
|
|
#endif
|
|
return 0;
|
|
} |