#include PD::Net::Backend::Ref net_backend; PD::LI::Backend::Ref backend; PD::Hid::Ref inp; #ifdef __3DS__ #include <3ds.h> #include #include #include 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 #include #include 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> DirContent; }; FileBrowserOderSo() { Listing = ParseDir(CurrentPath); } ~FileBrowserOderSo() = default; std::vector ParseDir(const std::string& path) { std::vector 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& listing, const std::string& cp) { if (m->BeginTreeNode(cp)) { for (auto& it : listing) { if (it.Directory) { if (!it.DirContent) { it.DirContent = std::make_shared>(); *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 Listing; }; #include #include const int PORT = 8080; const size_t MAX_LOGS = 100; bool skill_thread = false; std::mutex logMutex; std::mutex coutCaptureMutex; std::deque 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 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 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"( HTTP Server )"; const char* html_404 = R"( 404 Not Found

404 Page not found!

Return to main Page )"; const char* html_end = "
2025 tobid7
"; std::string getLogs() { std::lock_guard lock(logMutex); std::ostringstream oss; for (const auto& line : logBuffer) oss << line; return oss.str(); } std::string getIndexHTML() { std::lock_guard lock(logMutex); std::ostringstream oss; oss << html_begin; oss << "

Welcome

"; 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"(

Logs

Fetching logs...
)"; 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"(

System Info

Loading...
)"; 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; }