From b4a4b6a4267509620e687d4f3a064766dfd0b16a Mon Sep 17 00:00:00 2001 From: tobid7 Date: Sun, 19 Jan 2025 20:16:43 +0100 Subject: [PATCH] # Rewrite Stage 1.5 - Added Overlays (Performance / Keyboaed) - Keyboard has Gamepad Movement WIP (kinda) - Work on UI7 Started - Added Input Manager - Added Message Boxes (Animated) - Added Signle Header Tween func for animated stuff (Keyboard Messages, etc) - Add FastHash (Maybe useful later) - Using const & for vec in lithium - Add ability to copy a command by a Ref - Make Lists in Commands OpenAccess for Modification (StaticObject) - Add Static Object (System to PreRender Suff that never changes) but can still be recolored or moved - Add Layer and Font change functions - Make Renderer Tools (RotateCorner, CreateRect, CreateLine, InBox, OptiCommandList) static (OpenAccess) - Add ReIndexing to PushCommand - Add Ability to Init vec3 and vec4 with vec2 and add .xy and .zw to vec4 - Fully Animated Keyboard that currently has problem of Top Down GamePad movement - Add Func to Get GamePad Icon Codepoints for TextRenderer - Made deltatime a float - Using filesystem::path().wstring for convertation (works) - Add a New InBox to Renderer that only checks if a point is inside a boundingbox - Disable Font loading on Renderer Init due to 3ds Freezes when using SystemFont - Make SystemFont lineheight 10% larger than it is to be nearly the same size as the ttf fonts - Fix Some SpaceOffsets between TTF and SystemFont Rendering - Cleanup the Update Rendermode Func - Use LayerRenderSystem by default now as it now runs faster even with ttf fonts --- CMakeLists.txt | 13 +- README.md | 2 + include/pd.hpp | 7 + include/pd/common/app.hpp | 13 +- include/pd/common/common.hpp | 1 + include/pd/common/strings.hpp | 1 + include/pd/controls/hid.hpp | 95 +++++ include/pd/graphics/lithium.hpp | 148 ++++++-- include/pd/maths/tween.hpp | 138 +++++++ include/pd/maths/vec.hpp | 26 +- include/pd/overlays/keyboard.hpp | 105 ++++++ include/pd/overlays/message_mgr.hpp | 45 +++ include/pd/overlays/overlay.hpp | 23 ++ include/pd/overlays/overlay_mgr.hpp | 24 ++ include/pd/overlays/performance.hpp | 31 ++ include/pd/overlays/settings.hpp | 38 ++ include/pd/tools/gamepad_icons.hpp | 33 ++ include/pd/ui7/drawlist.hpp | 8 +- include/pd/ui7/flags.hpp | 1 + include/pd/ui7/id.hpp | 19 + include/pd/ui7/menu.hpp | 70 ++++ include/pd/ui7/theme.hpp | 86 ++++- include/pd/ui7/ui7.hpp | 24 +- source/common/app.cpp | 19 +- source/common/strings.cpp | 12 +- source/controls/hid.cpp | 78 ++++ source/graphics/lithium.cpp | 97 +++-- source/overlays/keyboard.cpp | 549 ++++++++++++++++++++++++++++ source/overlays/message_mgr.cpp | 126 +++++++ source/overlays/overlay_mgr.cpp | 14 + source/overlays/performance.cpp | 46 +++ source/tools/gamepad_icons.cpp | 57 +++ source/ui7/drawlist.cpp | 20 +- source/ui7/theme.cpp | 24 ++ test/main.cpp | 57 ++- 35 files changed, 1919 insertions(+), 131 deletions(-) create mode 100644 include/pd/controls/hid.hpp create mode 100644 include/pd/maths/tween.hpp create mode 100644 include/pd/overlays/keyboard.hpp create mode 100644 include/pd/overlays/message_mgr.hpp create mode 100644 include/pd/overlays/overlay.hpp create mode 100644 include/pd/overlays/overlay_mgr.hpp create mode 100644 include/pd/overlays/performance.hpp create mode 100644 include/pd/overlays/settings.hpp create mode 100644 include/pd/tools/gamepad_icons.hpp create mode 100644 include/pd/ui7/id.hpp create mode 100644 include/pd/ui7/menu.hpp create mode 100644 source/controls/hid.cpp create mode 100644 source/overlays/keyboard.cpp create mode 100644 source/overlays/message_mgr.cpp create mode 100644 source/overlays/overlay_mgr.cpp create mode 100644 source/overlays/performance.cpp create mode 100644 source/tools/gamepad_icons.cpp create mode 100644 source/ui7/theme.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f167b50..ba0dffb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,8 @@ set(SRC_FILES source/common/sys.cpp source/common/lang.cpp source/common/error.cpp + # Controls + source/controls/hid.cpp # Maths source/maths/color.cpp source/maths/bit_util.cpp @@ -40,6 +42,15 @@ set(SRC_FILES source/graphics/texture.cpp source/graphics/li7_shader.cpp source/graphics/lithium.cpp + # Overlays + source/overlays/message_mgr.cpp + source/overlays/overlay_mgr.cpp + source/overlays/keyboard.cpp + source/overlays/performance.cpp + # Tools + source/tools/gamepad_icons.cpp + # UI7 + source/ui7/drawlist.cpp # External source/external/stb.cpp ) @@ -61,7 +72,7 @@ target_compile_definitions(${TARGET_NAME} PUBLIC ) add_executable(test test/main.cpp) -target_include_directories(test PUBLIC include) +target_include_directories(test PUBLIC include test) target_link_directories(test PUBLIC ${CMAKE_BINARY_DIR}) target_link_libraries(test PUBLIC palladium citro3d ctru m) # Generate 3DSX diff --git a/README.md b/README.md index a5fa9fa..7d64131 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Palladium +**Framework / Engine to create Homebrew Apps / Games** + ## Build types ```bash diff --git a/include/pd.hpp b/include/pd.hpp index 62dcc29..db68839 100644 --- a/include/pd.hpp +++ b/include/pd.hpp @@ -38,5 +38,12 @@ SOFTWARE. #include #include #include +// Overlays +#include +#include +#include +#include +// UI7 +#include // namespace Palladium = PD; \ No newline at end of file diff --git a/include/pd/common/app.hpp b/include/pd/common/app.hpp index ed92138..f883999 100644 --- a/include/pd/common/app.hpp +++ b/include/pd/common/app.hpp @@ -25,7 +25,10 @@ SOFTWARE. #include #include +#include #include +#include +#include namespace PD { /// @brief Template Class for User Application @@ -43,7 +46,7 @@ class App : public SmartCtor { /// @param delta Deltatime /// @param time App RunTime /// @return false to exit the app - virtual bool MainLoop(u64 delta, float time) { return false; } + virtual bool MainLoop(float delta, float time) { return false; } /// @brief Function to run the App /// (int main() { @@ -52,15 +55,19 @@ class App : public SmartCtor { /// return 0; /// }) void Run(); - LI::Renderer::Ref Renderer() { return renderer; } - + MessageMgr::Ref Messages() { return msg_mgr; } + OverlayMgr::Ref Overlays() { return overlay_mgr; } + Hid::Ref Input() { return input_mgr; } float GetFps() const { return fps; } private: void PreInit(); void PostDeinit(); LI::Renderer::Ref renderer; + MessageMgr::Ref msg_mgr; + OverlayMgr::Ref overlay_mgr; + Hid::Ref input_mgr; u64 last_time; float app_time; float fps; diff --git a/include/pd/common/common.hpp b/include/pd/common/common.hpp index b7c1016..5de161c 100644 --- a/include/pd/common/common.hpp +++ b/include/pd/common/common.hpp @@ -29,6 +29,7 @@ SOFTWARE. #include // Requires C++ 17 or later #include // Requires C++ 20 or later #include +#include #include #include #include diff --git a/include/pd/common/strings.hpp b/include/pd/common/strings.hpp index 00e6a3d..db66d14 100644 --- a/include/pd/common/strings.hpp +++ b/include/pd/common/strings.hpp @@ -38,5 +38,6 @@ const std::string GetFileName(const std::string& path, const std::string PathRemoveExtension(const std::string& path); template const std::string ToHex(const T& v); +u32 FastHash(const std::string& s); } // namespace Strings } // namespace PD \ No newline at end of file diff --git a/include/pd/controls/hid.hpp b/include/pd/controls/hid.hpp new file mode 100644 index 0000000..62aebed --- /dev/null +++ b/include/pd/controls/hid.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include +#include + +namespace PD { +class Hid : public SmartCtor { + public: + enum Key : u32 { + No = 0, + A = 1 << 0, + B = 1 << 1, + X = 1 << 2, + Y = 1 << 3, + Start = 1 << 4, + Select = 1 << 5, + L = 1 << 6, + R = 1 << 7, + DUp = 1 << 8, + DDown = 1 << 9, + DLeft = 1 << 10, + DRight = 1 << 11, + CPUp = 1 << 12, + CPDown = 1 << 13, + CPLeft = 1 << 14, + CPRight = 1 << 15, + CSUp = 1 << 16, + CSDown = 1 << 17, + CSLeft = 1 << 18, + CSRight = 1 << 19, + ZL = 1 << 20, + ZR = 1 << 21, + Touch = 1 << 22, + Up = DUp | CPUp, + Down = DDown | CPDown, + Left = DLeft | CPLeft, + Right = DRight | CPRight, + }; + enum Event { + Event_Down, + Event_Held, + Event_Up, + }; + Hid(); + ~Hid() {} + + vec2 TouchPos() const { return touch[0]; } + vec2 TouchPosLast() const { return touch[1]; } + + bool IsEvent(Event e, Key keys); + bool IsDown(Key keys) const { return key_events[0].at(Event_Down) & keys; } + bool IsHeld(Key keys) const { return key_events[0].at(Event_Held) & keys; } + bool IsUp(Key keys) const { return key_events[0].at(Event_Up) & keys; } + + void Clear() { + for (int i = 0; i < 2; i++) { + key_events[i][Event_Down] = 0; + key_events[i][Event_Up] = 0; + key_events[i][Event_Held] = 0; + } + } + + void Lock(bool v) { + if (v != locked) { + SwappyTable(); + } + locked = v; + } + bool Locked() const { return locked; } + void Lock() { + if (!locked) { + SwappyTable(); + } + locked = true; + } + void Unlock() { + if (locked) { + SwappyTable(); + } + locked = false; + } + + /// @brief Get the New Keystates etc + /// @note WOW not using the deltatime + void Update(); + + private: + void SwappyTable(); + /// Using 2 Touch positions for current and last frame + vec2 touch[2]; + bool locked = false; + std::unordered_map key_events[2]; + std::unordered_map binds; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/graphics/lithium.hpp b/include/pd/graphics/lithium.hpp index 706f089..72f30f2 100644 --- a/include/pd/graphics/lithium.hpp +++ b/include/pd/graphics/lithium.hpp @@ -49,11 +49,11 @@ namespace LI { class Rect { public: Rect() = default; - Rect(vec4 t, vec4 b) { + Rect(const vec4& t, const vec4& b) { top = t; bot = b; } - Rect(vec2 tl, vec2 tr, vec2 bl, vec2 br) { + Rect(const vec2& tl, const vec2& tr, const vec2& bl, const vec2& br) { top = vec4(tl, tr); bot = vec4(bl, br); } @@ -84,7 +84,7 @@ class Font : public SmartCtor { return *this; } vec4 uv() const { return m_uv; } - Codepoint& uv(vec4 v) { + Codepoint& uv(const vec4& v) { m_uv = v; return *this; } @@ -94,7 +94,7 @@ class Font : public SmartCtor { return *this; } vec2 size() const { return m_size; } - Codepoint& size(vec2 v) { + Codepoint& size(const vec2& v) { m_size = v; return *this; } @@ -134,7 +134,7 @@ class Font : public SmartCtor { class Vertex { public: Vertex() {} - Vertex(vec2 p, vec2 u, u32 c) { + Vertex(const vec2& p, const vec2& u, u32 c) { pos[0] = p[0]; pos[1] = p[1]; pos[2] = 0.f; @@ -143,18 +143,18 @@ class Vertex { } ~Vertex() {} - Vertex& Pos(vec3 v) { + Vertex& Pos(const vec3& v) { pos = v; return *this; } // Lets support that as well - Vertex& Pos(vec2 v) { + Vertex& Pos(const vec2& v) { pos[0] = v[0]; pos[1] = v[1]; pos[2] = 0.f; return *this; } - Vertex& Uv(vec2 v) { + Vertex& Uv(const vec2& v) { uv = v; return *this; } @@ -179,6 +179,15 @@ class Command : public SmartCtor { Command() {} ~Command() {} + Command(Command::Ref v) { + this->index = v->index; + this->index_buf = v->index_buf; + this->layer = v->layer; + this->mode = v->mode; + this->tex = v->tex; + this->vertex_buf = v->vertex_buf; + } + Command& Layer(int v) { layer = v; return *this; @@ -200,7 +209,7 @@ class Command : public SmartCtor { Texture::Ref Tex() const { return tex; } - Command& PushVertex(Vertex v) { + Command& PushVertex(const Vertex& v) { vertex_buf.push_back(v); return *this; } @@ -208,6 +217,10 @@ class Command : public SmartCtor { const std::vector& IndexList() const { return index_buf; } const std::vector& VertexList() const { return vertex_buf; } + /// ADVANCED /// + std::vector& IndexList() { return index_buf; } + std::vector& VertexList() { return vertex_buf; } + Command& PushIndex(u16 v) { index_buf.push_back(vertex_buf.size() + v); return *this; @@ -255,11 +268,74 @@ class TextBox { bool optional; std::string text; // TextWrap }; +class StaticObject : public SmartCtor { + public: + StaticObject() {} + ~StaticObject() {} + + void PushCommand(Command::Ref v) { cmds.push_back(v); } + + void ReCopy() { + cpy.clear(); + for (auto it : cmds) { + cpy.push_back(Command::New(it)); + } + } + + void ReColorQuad(int idx, u32 col) { + if (idx > (int)cpy.size()) { + return; + } + for (auto& it : cpy[idx]->VertexList()) { + it.Color(col); + } + } + + void MoveIt(vec2 off) { + for (auto& it : cpy) { + for (auto& jt : it->VertexList()) { + jt.pos += vec3(off, 0); + } + } + } + + void ReColor(u32 col) { + for (auto& it : cpy) { + for (auto& jt : it->VertexList()) { + jt.Color(col); + } + } + } + + void ReLayer(int base_layer) { + for (auto& it : cpy) { + it->Layer(it->Layer() + base_layer); + } + } + + void ReIndex(int start) { + for (int i = 0; i < (int)cpy.size(); i++) { + cpy[i]->Index(start + i); + } + } + + std::vector& List() { + if (cpy.size() != 0) { + return cpy; + } + return cmds; + } + + private: + std::vector cpy; + std::vector cmds; +}; using RenderFlags = u32; enum RenderFlags_ { RenderFlags_None = 0, RenderFlags_TMS = 1 << 0, ///< Text Map System RenderFlags_LRS = 1 << 1, ///< Layer Render System + RenderFlags_AST = 1 << 2, ///< Auto Static Text RenderFlags_Default = RenderFlags_TMS, }; class Renderer : public SmartCtor { @@ -291,6 +367,13 @@ class Renderer : public SmartCtor { void TextScale(float v) { text_size = v; } void DefaultTextScale() { text_size = default_text_size; } float TextScale() const { return text_size; } + void Layer(int v) { current_layer = v; } + int Layer() const { return current_layer; } + void Font(Font::Ref v) { + font = v; + font_update = true; + } + Font::Ref Font() const { return font; } void UseTex(Texture::Ref v = nullptr) { if (v == nullptr) { @@ -305,42 +388,43 @@ class Renderer : public SmartCtor { /// @param size Size /// @param color Color /// @param uv UV Map - void DrawRect(vec2 pos, vec2 size, u32 color, - vec4 uv = vec4(0.f, 1.f, 1.f, 0.f)); + void DrawRect(const vec2& pos, const vec2& size, u32 color, + const vec4& uv = vec4(0.f, 1.f, 1.f, 0.f)); /// @brief Draw a Solid Rect (uses white tex) /// @note acts as a simplified Draw rect Wrapper /// @param pos Position /// @param size Size /// @param color Color - void DrawRectSolid(vec2 pos, vec2 size, u32 color); + void DrawRectSolid(const vec2& pos, const vec2& size, u32 color); /// @brief Render a Triangle /// @param a Position Alpha /// @param b Position Bravo /// @param c Position Delta /// @param color Color /// @note Defaults to Solif Color - void DrawTriangle(vec2 a, vec2 b, vec2 c, u32 color); + void DrawTriangle(const vec2& a, const vec2& b, const vec2& c, u32 color); /// @brief Draw a Circle (Supports Textures) /// @param center_pos Center Position /// @param r Radius /// @param color Color /// @param segments Segments to use /// @note Textures could look a bit janky due to uv mapping - void DrawCircle(vec2 center_pos, float r, u32 color, int segments); + void DrawCircle(const vec2& center_pos, float r, u32 color, int segments); /// @brief Draw a Line between to Positions /// @param a Position Alpha /// @param b Position Bravo /// @param color Color /// @param t Thickness - void DrawLine(vec2 a, vec2 b, u32 color, int t); - void DrawText(vec2 pos, u32 color, const std::string& text, u32 flags = 0, - vec2 ap = vec2()); + void DrawLine(const vec2& a, const vec2& b, u32 color, int t); + void DrawText(const vec2& pos, u32 color, const std::string& text, + u32 flags = 0, const vec2& ap = vec2()); /// @brief Draw a Texture as 2D Image /// @param pos Position /// @param tex Texture reference /// @param scale Scale (cause maybe wants to be resized) /// @note Acts as a Simplified wrapper to DrawRect - void DrawImage(vec2 pos, Texture::Ref tex, vec2 scale = vec2(1.f)); + void DrawImage(const vec2& pos, Texture::Ref tex, + const vec2& scale = vec2(1.f)); /// Debug STUFF u32 Vertices() const { return vertices; } @@ -349,22 +433,28 @@ class Renderer : public SmartCtor { u32 DrawCalls() const { return drawcalls; } /// TOOLS /// - void RotateCorner(vec2& v, float s, float c); - Rect CreateRect(vec2 pos, vec2 size, float angle); - Rect CreateLine(vec2 a, vec2 b, int t); - bool InBox(vec2 pos, vec2 size, vec4 rect); - bool InBox(vec2 alpha, vec2 bravo, vec2 charlie, vec4 rect); - void OptiCommandList(std::vector& list); + static void RotateCorner(vec2& v, float s, float c); + static Rect CreateRect(const vec2& pos, const vec2& size, float angle); + static Rect CreateLine(const vec2& a, const vec2& b, int t); + static bool InBox(const vec2& pos, const vec2& size, const vec4& rect); + static bool InBox(const vec2& pos, const vec4& rect); + static bool InBox(const vec2& alpha, const vec2& bravo, const vec2& charlie, + const vec4& rect); + static void OptiCommandList(std::vector& list); /// @brief Returns Viewport with xy vec4 GetViewport(); /// @brief Push a Self Created command - void PushCommand(Command::Ref cmd) { draw_list[bottom].push_back(cmd); } + void PushCommand(Command::Ref cmd) { + cmd->Index(cmd_idx++); // Indexing + draw_list[bottom].push_back(cmd); + } /// @brief Automatically sets up a command void SetupCommand(Command::Ref cmd); /// @brief Creates a default Quad Render Command - void QuadCommand(Command::Ref cmd, const Rect& quad, vec4 uv, u32 col); + void QuadCommand(Command::Ref cmd, const Rect& quad, const vec4& uv, u32 col); /// @brief Create a Default Triangle - void TriangleCommand(Command::Ref cmd, vec2 a, vec2 b, vec2 c, u32 col); + void TriangleCommand(Command::Ref cmd, const vec2& a, const vec2& b, + const vec2& c, u32 col); /// @brief Create List of a Text Commands /// @param cmds Link to a command List /// @param pos Position @@ -373,8 +463,8 @@ class Renderer : public SmartCtor { /// @param flags Flags /// @param box (Size for wrapping / Offset for Centered Text) /// @note Funktion macht noch faxxen (Text nicht sichtbar) - void TextCommand(std::vector& cmds, vec2 pos, u32 color, - const std::string& text, LITextFlags flags, vec2 box); + void TextCommand(std::vector& cmds, const vec2& pos, u32 color, + const std::string& text, LITextFlags flags, const vec2& box); vec2 GetTextDimensions(const std::string& text); private: diff --git a/include/pd/maths/tween.hpp b/include/pd/maths/tween.hpp new file mode 100644 index 0000000..af1c3d2 --- /dev/null +++ b/include/pd/maths/tween.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include + +namespace PD { +template +class Tween { + public: + enum Effect { + Linear, + EaseInQuad, + EaseOutQuad, + EaseInOutQuad, + EaseInCubic, + EaseOutCubic, + EaseInOutCubic, + EaseInSine, + EaseOutSine, + EaseInOutSine, + }; + Tween() {} + ~Tween() {} + + void Update(float delta) { + time += delta / 1000.f; + if (time > tend) { + finished = true; + time = tend; + } + } + + bool IsFinished() const { return finished; } + + Tween& Finish() { + time = tend; + finished = true; + return *this; + } + + Tween& From(const T& start) { + Reset(); + this->start = start; + return *this; + } + Tween& To(const T& end) { + Reset(); + this->end = end; + return *this; + } + Tween& In(float seconds) { + Reset(); + tend = seconds; + return *this; + } + Tween& As(const Effect& e) { + effect = e; + return *this; + } + Tween& Reset() { + finished = false; + time = 0.f; + return *this; + } + /// @brief Probably usefull for fading colors by animation + /// Used to create this caus dont wanted to create a + /// fade effect fpr keyboard without having to Tween functions + /// @return + float Progress() const { return time / tend; } + + Tween& Swap() { + T temp = start; + start = end; + end = temp; + return *this; + } + + operator T() { + float t = 0.f; + switch (effect) { + case EaseInQuad: + t = time / tend; + return (end - start) * t * t + start; + break; + case EaseOutQuad: + t = time / tend; + return -(end - start) * t * (t - 2) + start; + break; + case EaseInOutQuad: + t = time / (tend / 2); + if (t < 1) return (end - start) / 2 * t * t + start; + t--; + return -(end - start) / 2 * (t * (t - 2) - 1) + start; + break; + case EaseInCubic: + t = time / tend; + return (end - start) * t * t * t + start; + break; + case EaseOutCubic: + t = time / tend; + t--; + return (end - start) * (t * t * t + 1) + start; + break; + // case EaseInOutCubic: + // t = time / (tend / 2); + // if (t < 1) return (end - start) / 2 * t * t * t + start; + // t--; + // return (end - start) / 2 * (t * t * t * 2) + start; + // break; + case EaseInSine: + return -(end - start) * cos(time / tend * (M_PI / 2)) + (end - start) + + start; + break; + case EaseOutSine: + return (end - start) * sin(time / tend * (M_PI / 2)) + start; + break; + case EaseInOutSine: + return -(end - start) / 2 * (cos(M_PI * time / tend) - 1) + start; + break; + + default: // Linear + return (end - start) * (time / tend) + start; + break; + } + } + + private: + Effect effect; + float time = 0.f; + // Defaulting to one to prevent div zero + // without a safetey check + // not implementing one cause if the user is + // Writing a In(0.f) its their fault + float tend = 1.f; + T start; + T end; + bool finished = false; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/maths/vec.hpp b/include/pd/maths/vec.hpp index d6fedc0..96f8262 100644 --- a/include/pd/maths/vec.hpp +++ b/include/pd/maths/vec.hpp @@ -332,6 +332,20 @@ struct vec4 { v[3] = i; } + vec4(const vec3 &xyz, float w) { + v[0] = xyz[0]; + v[1] = xyz[1]; + v[2] = xyz[2]; + v[3] = w; + } + + vec4(float x, const vec3 &yzw) { + v[0] = x; + v[1] = yzw[1]; + v[2] = yzw[2]; + v[3] = yzw[3]; + } + // Operators // Add vec4 &operator+=(const vec4 &i) { @@ -371,7 +385,7 @@ struct vec4 { } // Base - vec3 operator-() const { return vec3(-v[0], -v[1], -v[2]); } + vec4 operator-() const { return vec4(-v[0], -v[1], -v[2], -v[3]); } float operator[](int i) const { return v[i]; } float &operator[](int i) { return v[i]; } @@ -380,7 +394,7 @@ struct vec4 { return v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; } - // Vec2 Acess + // Vec Acess float x() const { return v[0]; } float &x() { return v[0]; } float y() const { return v[1]; } @@ -389,6 +403,10 @@ struct vec4 { float &z() { return v[2]; } float w() const { return v[3]; } float &w() { return v[3]; } + vec2 xy() const { return vec2(v[0], v[1]); } + vec2 zw() const { return vec2(v[2], v[3]); } + vec3 xyz() const { return vec3(v[0], v[1], v[2]); } + vec3 yzw() const { return vec3(v[1], v[2], v[3]); } // Quaternion Acess float r() const { return v[0]; } float &r() { return v[0]; } @@ -398,6 +416,10 @@ struct vec4 { float &j() { return v[2]; } float i() const { return v[3]; } float &i() { return v[3]; } + vec2 rk() const { return vec2(v[0], v[1]); } + vec2 ji() const { return vec2(v[2], v[3]); } + vec3 rkj() const { return vec3(v[0], v[1], v[2]); } + vec3 kji() const { return vec3(v[1], v[2], v[3]); } // Internal Values float v[4]; }; diff --git a/include/pd/overlays/keyboard.hpp b/include/pd/overlays/keyboard.hpp new file mode 100644 index 0000000..7330caf --- /dev/null +++ b/include/pd/overlays/keyboard.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include + +namespace PD { +void DumpLayout(const std::string& path); +/// Keyboard class +/// @brief needs to be pushed with text and State reference as Overlay +/// to communicate with it +/// @note Hardcoded Rendering to get maximum Rendering Performance +class Keyboard : public Overlay { + public: + enum KeyOperation { + AppendSelf = 0, + Shift = 1, + Backspace = 2, + Enter = 3, + OpCancel = 4, + OpConfirm = 5, + Tab = 6, + Caps = 7, + Space = 8, + Op1 = 9, + Op2 = 10, + }; + enum Type { + Default, + Numpad, + Password, + }; + enum State { + None, + Cancel, + Confirm, + }; + using Flags = u32; + enum Flags_ { + Flags_None = 0, + Flags_BlendTop = 1 << 0, + Flags_BlendBottom = 1 << 1, + Flags_LockControls = 1 << 2, + Flags_Default = Flags_BlendBottom | Flags_BlendTop | Flags_LockControls, + }; + Keyboard(std::string& text, State& state, const std::string& hint = "", + Type type = Default, Flags flags = Flags_Default) { + too++; + if (too > 1) { + Kill(); + return; + } + this->text = &text; + this->copy = text; + this->state = &state; + this->hint = hint; + this->type = type; + this->flags = flags; + this->raw_sel = -1; + flymgr.From(vec2(0, 240)).To(vec2(0, 115)).In(0.3f).As(flymgr.EaseInQuad); + chflymgr.From(vec2(-320, 0)).To(vec2(-320, 0)).In(0.1f).As(chflymgr.Linear); + } + ~Keyboard() { too--; } + + void Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) override; + + void Rem() { + rem = true; + flymgr.From(vec2(0, 115)).To(vec2(0, 240)).In(0.2f).As(flymgr.EaseOutQuad); + } + + private: + void LoadTheKeys(LI::Renderer::Ref ren); + void Movement(Hid::Ref inp); + void MoveSelector(); + void DoOperation(KeyOperation op, const std::string& kname); + void RecolorBy(KeyOperation op, u32 color, int cm); + void InputOpBind(Hid::Key k, KeyOperation op, Hid::Ref inp, int cm); + std::string* text; + std::string copy; + std::string hint; + State* state; + Type type; + Flags flags; + int mode = 0; // def, caps, shift + // Stands for The Only One + static int too; + + Tween selector; + Tween sel_szs; + vec2 cselszs; + int raw_sel; + + // Performance Optimisation + LI::StaticObject::Ref keys[3]; + bool keys_loadet = false; + + // Some Animation + bool rem = false; + /// Probably a float would've done the job as well ;) + Tween flymgr; + Tween chflymgr; + bool show_help = true; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/overlays/message_mgr.hpp b/include/pd/overlays/message_mgr.hpp new file mode 100644 index 0000000..de7885e --- /dev/null +++ b/include/pd/overlays/message_mgr.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +namespace PD { +class MessageMgr : public PD::SmartCtor { + public: + class Container : public PD::SmartCtor { + public: + Container(const std::string& title, const std::string& msg); + ~Container() {} + + void Render(PD::LI::Renderer::Ref ren); + void Update(int slot, float delta); + void FlyIn(); + void ToBeMoved(int slot); + void ToBeRemoved(); + + bool ShouldBeRemoved() const { return (tbr && pos.IsFinished()) || kill; } + + private: + PD::Color col_bg; // Background Color + PD::Color col_text; // Text Color + float lifetime = 0.f; // LifeTime + PD::Tween pos; // Position effect + std::string title; // Title + std::string msg; // Message + vec2 size; // Size of the Background + bool tbr = false; // To be Removed ? + bool kill = false; // Instant Kill + int s = 0; // Slot + }; + MessageMgr(PD::LI::Renderer::Ref r) { ren = r; } + ~MessageMgr() {} + + void Push(const std::string& title, const std::string& text); + void Update(float delta); + + private: + std::vector msgs; + PD::LI::Renderer::Ref ren; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/overlays/overlay.hpp b/include/pd/overlays/overlay.hpp new file mode 100644 index 0000000..bf11a25 --- /dev/null +++ b/include/pd/overlays/overlay.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +namespace PD { +class Overlay : public SmartCtor { + public: + Overlay() {} + virtual ~Overlay() {} + + virtual void Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) = 0; + + bool IsKilled() const { return kill; } + + protected: + void Kill() { kill = true; } + + private: + bool kill = false; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/overlays/overlay_mgr.hpp b/include/pd/overlays/overlay_mgr.hpp new file mode 100644 index 0000000..76fc7ec --- /dev/null +++ b/include/pd/overlays/overlay_mgr.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +namespace PD { +class OverlayMgr : public SmartCtor { + public: + OverlayMgr(LI::Renderer::Ref ren, Hid::Ref inp) { + this->ren = ren; + this->inp = inp; + } + ~OverlayMgr() { overlays.clear(); } + + void Push(Overlay::Ref overlay); + void Update(float delta); + + private: + std::vector overlays; + LI::Renderer::Ref ren; + Hid::Ref inp; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/overlays/performance.hpp b/include/pd/overlays/performance.hpp new file mode 100644 index 0000000..b62982a --- /dev/null +++ b/include/pd/overlays/performance.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +namespace PD { +class Performance : public Overlay { + public: + Performance(bool& skill, bool& screen) { + too++; + if (too > 1) { + Kill(); + return; + } + this->skill = &skill; + *this->skill = false; // Make sure its false + this->screen = &screen; + } + ~Performance() { too--; } + + void Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) override; + + private: + void Line(vec2& pos, const std::string& text, LI::Renderer::Ref ren); + // Trace String Average + std::string TSA(const std::string& id); + // Described in Keyboard + static int too; + bool *skill, *screen; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/overlays/settings.hpp b/include/pd/overlays/settings.hpp new file mode 100644 index 0000000..fd786d1 --- /dev/null +++ b/include/pd/overlays/settings.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +namespace PD { +class SettingsMenu : public Overlay { + public: + SettingsMenu() { + too++; + if (too > 1) { + Kill(); + return; + } + flymgr.From(vec2(0, 240)).To(vec2(0, 115)).In(0.3f).As(flymgr.EaseInQuad); + } + ~SettingsMenu() { too--; } + + void Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) override; + + void Rem() { + rem = true; + flymgr.From(vec2(0, 115)).To(vec2(0, 240)).In(0.2f).As(flymgr.EaseOutQuad); + } + + private: + /// Section is used to determinate what + /// should be displayed on the top screen + int section = 0; + // Stands for The Only One + static int too; + + // Some Animation + bool rem = false; + Tween flymgr; +}; +} // namespace PD \ No newline at end of file diff --git a/include/pd/tools/gamepad_icons.hpp b/include/pd/tools/gamepad_icons.hpp new file mode 100644 index 0000000..816ab6f --- /dev/null +++ b/include/pd/tools/gamepad_icons.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace PD { +namespace GamePadIcons { +enum ID { + A, + B, + X, + Y, + L, + R, + Dpad, + Start, + Select, + Home, + Steps, + PlayCoin, + AnalogStick, + Power3DS, + DpadUp, + DpadDown, + DpadLeft, + DpadRight, + DpadHorizontal, + DpadVertical, +}; +std::string GetIcon(ID id); +std::string GetIcon(Hid::Key key); +} // namespace GamePadIcons +} // namespace PD \ No newline at end of file diff --git a/include/pd/ui7/drawlist.hpp b/include/pd/ui7/drawlist.hpp index 6022b55..3ad4ec7 100644 --- a/include/pd/ui7/drawlist.hpp +++ b/include/pd/ui7/drawlist.hpp @@ -28,10 +28,11 @@ SOFTWARE. #include namespace PD { -class UI7DrawList : SmartCtor { +namespace UI7 { +class DrawList : public SmartCtor { public: - UI7DrawList(LI::Renderer::Ref r) { ren = r; } - ~UI7DrawList() = default; + DrawList(LI::Renderer::Ref r) { ren = r; } + ~DrawList() = default; void AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr); void AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, const UI7Color& clr); @@ -50,4 +51,5 @@ class UI7DrawList : SmartCtor { LI::Renderer::Ref ren; std::vector commands; }; +} // namespace UI7 } // namespace PD \ No newline at end of file diff --git a/include/pd/ui7/flags.hpp b/include/pd/ui7/flags.hpp index ba1ae1f..6df9855 100644 --- a/include/pd/ui7/flags.hpp +++ b/include/pd/ui7/flags.hpp @@ -31,5 +31,6 @@ enum UI7MenuFlags_ { UI7MenuFlags_CenterTitle = 1 << 1, UI7MenuFlags_HzScrolling = 1 << 2, UI7MenuFlags_VtScrolling = 1 << 3, + UI7MenuFlags_NoBackground = 1 << 4, UI7MenuFlags_Scrolling = UI7MenuFlags_HzScrolling | UI7MenuFlags_VtScrolling, }; \ No newline at end of file diff --git a/include/pd/ui7/id.hpp b/include/pd/ui7/id.hpp new file mode 100644 index 0000000..cbc9559 --- /dev/null +++ b/include/pd/ui7/id.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace PD { +namespace UI7 { +class ID { + public: + ID(const std::string& text) { id = PD::Strings::FastHash(text); } + ~ID() {} + + operator u32() const { return id; } + + private: + u32 id; +}; +} // namespace UI7 +} // namespace PD \ No newline at end of file diff --git a/include/pd/ui7/menu.hpp b/include/pd/ui7/menu.hpp new file mode 100644 index 0000000..1d86fd7 --- /dev/null +++ b/include/pd/ui7/menu.hpp @@ -0,0 +1,70 @@ +#pragma once + +/* +MIT License +Copyright (c) 2024 René Amthor (tobid7) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +#include + +namespace PD { +namespace UI7 { +class Menu : public SmartCtor { + public: + Menu(u32 id) { + this->id = id; + scrolling[0] = false; + scrolling[1] = false; + scrollbar[0] = false; + scrollbar[1] = false; + scroll_allowed[0] = false; + scroll_allowed[1] = false; + }; + ~Menu() {}; + + private: + u32 id; + vec2 cursor; + vec2 bcursor; + vec2 slcursor; + vec4 view_area; + vec2 scrolling_off; + bool scrolling[2]; + vec2 scroll_mod; + float tbh; + bool scrollbar[2]; + bool scroll_allowed[2]; + bool has_touch; + + Menu::Ref submenu; + + // DrawLists + DrawList::Ref back; + DrawList::Ref main; + DrawList::Ref front; + + vec2 max; + vec2 mouse; + vec2 bslpos; + vec2 last_size; +}; +} // namespace UI7 +} // namespace PD \ No newline at end of file diff --git a/include/pd/ui7/theme.hpp b/include/pd/ui7/theme.hpp index 61ffab3..7148599 100644 --- a/include/pd/ui7/theme.hpp +++ b/include/pd/ui7/theme.hpp @@ -25,14 +25,96 @@ SOFTWARE. #include -using UI7Color = unsigned int; +using UI7Color = u32; enum UI7Color_ { UI7Color_Background, - + UI7Color_Button, + UI7Color_ButtonDead, + UI7Color_ButtonActive, + UI7Color_ButtonDisabled, + UI7Color_Text, + UI7Color_TextDead, + UI7Color_Header, + UI7Color_Selector, + UI7Color_Checkmark, + UI7Color_FrameBackground, + UI7Color_FragmeBackgroundHovered, + UI7Color_Progressbar, + UI7Color_ListEven, + UI7Color_ListOdd, }; namespace PD { +namespace UI7 { +/// @brief Theme Class +class Theme { + public: + public: + Theme() { Default(*this); } + ~Theme() {} + + /// @brief Simple static Loader for the Default Theme + /// @param theme Theme Reference + static void Default(Theme& theme); + + /// @brief Revert the last Color Change + Theme& Pop() { + theme[changes[changes.size() - 1].first] = + changes[changes.size() - 1].second; + changes.pop_back(); + return *this; + } + + /// @brief Revert the last color Change done for a specific color + /// @param c Color to revert change from + Theme& Pop(UI7Color c) { + for (size_t i = changes.size() - 1; i > 0; i--) { + if (changes[i].first == c) { + theme[c] = changes[i].second; + changes.erase(changes.begin() + i); + break; + } + } + return *this; + } + + /// @brief Change a Color + /// @param tc Color Identifier + /// @param color Color to change to + Theme& Change(UI7Color tc, u32 color) { + if (theme.find(tc) == theme.end()) { + return *this; + } + changes.push_back(std::make_pair(tc, theme[tc])); + theme[tc] = color; + return *this; + } + + /// @brief Get the Color of a Color ReferenceID + /// @param c ReferenceID + u32 Get(UI7Color c) const { + auto e = theme.find(c); + if (e == theme.end()) { + return 0x00000000; + } + return e->second; + } + + /// @brief Operator wrapper for get + /// @param c Color ReferenceID + u32 operator[](UI7Color c) const { return Get(c); } + + /// @brief Change but just sets [can implement completly new ids] + /// @param tc Color ID (Can be self creeated ones as well) + /// @param clr Color it should be set to + void Set(UI7Color tc, u32 clr) { theme[tc] = clr; } + + private: + std::unordered_map theme; + std::vector> changes; +}; +} // namespace UI7 /// Using UI7Color as a Class to be able to /// define it as struct as well as using it as enum class UI7Color { diff --git a/include/pd/ui7/ui7.hpp b/include/pd/ui7/ui7.hpp index e9d5857..b2d7338 100644 --- a/include/pd/ui7/ui7.hpp +++ b/include/pd/ui7/ui7.hpp @@ -25,13 +25,19 @@ SOFTWARE. #include #include +#include +#include #include +#include namespace PD { -class UI7Context : SmartCtor { +namespace UI7 { +class Context : public SmartCtor { public: - UI7Context() {} - ~UI7Context() {} + Context() {} + ~Context() {} + + void Update(float delta); private: // Timing @@ -41,13 +47,15 @@ class UI7Context : SmartCtor { // Context bool in_menu; // Debug - bool debug; + bool debugging; // Menu Handlers - + std::unordered_map menus; + Menu::Ref current; // Context DrawList - UI7DrawList::Ref debug; - UI7DrawList::Ref front; - UI7DrawList::Ref back; + DrawList::Ref debug; + DrawList::Ref front; + DrawList::Ref back; // Promt Handler }; +} // namespace UI7 } // namespace PD \ No newline at end of file diff --git a/source/common/app.cpp b/source/common/app.cpp index 2e9ebc3..3f1024c 100644 --- a/source/common/app.cpp +++ b/source/common/app.cpp @@ -33,16 +33,21 @@ void App::Run() { this->Init(); last_time = Sys::GetTime(); while (aptMainLoop()) { - u64 current = Sys::GetTime(); - u64 dt = current - last_time; - app_time += float(dt / 1000.f); + input_mgr->Update(); + u64 current = Sys::GetNanoTime(); + float dt = static_cast(current - last_time) / 1000000.f; + app_time += dt / 1000.f; last_time = current; - fps = 1000.f / (float)dt; + fps = 1000.f / dt; PD::TT::Beg("App_MainLoop"); if (!this->MainLoop(dt, app_time)) { break; } PD::TT::End("App_MainLoop"); + PD::TT::Beg("Ovl_Update"); + overlay_mgr->Update(dt); + msg_mgr->Update(dt); + PD::TT::End("Ovl_Update"); renderer->Render(); } this->Deinit(); @@ -54,11 +59,17 @@ void App::PreInit() { gfxInitDefault(); cfguInit(); romfsInit(); + input_mgr = Hid::New(); renderer = LI::Renderer::New(); + msg_mgr = MessageMgr::New(renderer); + overlay_mgr = OverlayMgr::New(renderer, input_mgr); } void App::PostDeinit() { renderer = nullptr; + msg_mgr = nullptr; + overlay_mgr = nullptr; + input_mgr = nullptr; gfxExit(); cfguExit(); romfsExit(); diff --git a/source/common/strings.cpp b/source/common/strings.cpp index b659cbd..7af85bb 100644 --- a/source/common/strings.cpp +++ b/source/common/strings.cpp @@ -45,7 +45,9 @@ bool StringEndsWith(const std::string& str, } std::wstring MakeWstring(const std::string& s) { - return std::wstring(s.begin(), s.end()); + // As std::wstring(s.begin(), s.end()); doesn't convert it + // Normally this should not be done like this but it works + return std::filesystem::path(s).wstring(); } const std::string FormatNanos(unsigned long long nanos) { @@ -125,4 +127,12 @@ const std::string ToHex(const T& v) { s << "0x" << std::setfill('0') << std::setw(sizeof(v) * 2) << std::hex << v; return s.str(); } + +u32 FastHash(const std::string& s) { + u32 hash = 5381; + for (auto& it : s) { + hash = (hash * 33) + static_cast(it); + } + return hash; +} } // namespace PD::Strings \ No newline at end of file diff --git a/source/controls/hid.cpp b/source/controls/hid.cpp new file mode 100644 index 0000000..db869e0 --- /dev/null +++ b/source/controls/hid.cpp @@ -0,0 +1,78 @@ +#include <3ds.h> + +#include + +/// Reform of the RenderD7 095 Hid Api +/// Using Custom Keybindings for future +/// Porting of the library + +namespace PD { +Hid::Hid() { + binds[KEY_A] = A; + binds[KEY_B] = B; + binds[KEY_X] = X; + binds[KEY_Y] = Y; + binds[KEY_START] = Start; + binds[KEY_SELECT] = Select; + binds[KEY_L] = L; + binds[KEY_R] = R; + binds[KEY_DUP] = DUp; + binds[KEY_DDOWN] = DDown; + binds[KEY_DLEFT] = DLeft; + binds[KEY_DRIGHT] = DRight; + binds[KEY_CPAD_UP] = CPUp; + binds[KEY_CPAD_DOWN] = CPDown; + binds[KEY_CPAD_LEFT] = CPLeft; + binds[KEY_CPAD_RIGHT] = CPRight; + binds[KEY_CSTICK_UP] = CSUp; + binds[KEY_CSTICK_DOWN] = CSDown; + binds[KEY_CSTICK_LEFT] = CSLeft; + binds[KEY_CSTICK_RIGHT] = CSRight; + binds[KEY_ZL] = ZL; + binds[KEY_ZR] = ZR; + binds[KEY_TOUCH] = Touch; +} +void Hid::Update() { + hidScanInput(); + for (int i = 0; i < 2; i++) { + key_events[i][Event_Down] = 0; + key_events[i][Event_Held] = 0; + key_events[i][Event_Up] = 0; + } + u32 kd = hidKeysDown(); + u32 kh = hidKeysHeld(); + u32 ku = hidKeysUp(); + for (auto &b : binds) { + if (b.first & kd) { + key_events[0][Event_Down] |= b.second; + } + if (b.first & kh) { + key_events[0][Event_Held] |= b.second; + } + if (b.first & ku) { + key_events[0][Event_Up] |= b.second; + } + } + if (locked) { + SwappyTable(); + } + touchPosition t; + hidTouchRead(&t); + touch[1] = touch[0]; // Cycle touch pos + touch[0] = vec2(t.px, t.py); +} + +bool Hid::IsEvent(Event e, Key keys) { return key_events[0][e] & keys; } + +void Hid::SwappyTable() { + auto tkd = key_events[1][Event_Down]; + auto tkh = key_events[1][Event_Held]; + auto tku = key_events[1][Event_Up]; + key_events[1][Event_Down] = key_events[0][Event_Down]; + key_events[1][Event_Held] = key_events[0][Event_Held]; + key_events[1][Event_Up] = key_events[0][Event_Up]; + key_events[0][Event_Down] = tkd; + key_events[0][Event_Held] = tkh; + key_events[0][Event_Up] = tku; +} +} // namespace PD \ No newline at end of file diff --git a/source/graphics/lithium.cpp b/source/graphics/lithium.cpp index 7aaa221..3e03fef 100644 --- a/source/graphics/lithium.cpp +++ b/source/graphics/lithium.cpp @@ -75,10 +75,12 @@ void Font::LoadTTF(const std::string& path, int height) { off[0] = 0; } - c.uv(vec4(static_cast(off.x() / (float)quad), - static_cast(1.f - (off.y() / (float)quad)), - static_cast((float)(off.x() + w) / (float)quad), - static_cast((float)(off.y() + h) / (float)quad))); + vec4 uvs; + uvs[0] = static_cast(off.x() / (float)quad); + uvs[1] = static_cast(1.f - (off.y() / (float)quad)); + uvs[2] = static_cast((float)(off.x() + w) / (float)quad); + uvs[3] = static_cast(1.f - (float)(off.y() + h) / (float)quad); + c.uv(uvs); c.tex(tex); c.size(vec2(w, h)); @@ -94,7 +96,8 @@ void Font::LoadTTF(const std::string& path, int height) { font_tex[map_pos + 3] = bitmap[x + y * w]; } } - off[0] += w; + // Small Patch to avoid some possible artifacts + off[0] += w + 1; if (off[0] + w > quad) { off[1] += pixel_height; off[0] = 0; @@ -123,7 +126,9 @@ void Font::LoadSystemFont() { const auto fnt_info = fontGetInfo(fnt); const auto glyph_info = fontGetGlyphInfo(fnt); this->textures.resize(glyph_info->nSheets + 1); - pixel_height = glyph_info->cellHeight; + /// Modify the Pixel Height by 1.1f to fit the + /// Size og ttf font Rendering + pixel_height = glyph_info->cellHeight * 1.1f; for (size_t i = 0; i < glyph_info->nSheets; i++) { auto stex = Texture::New(); auto tx = new C3D_Tex; @@ -226,9 +231,9 @@ Renderer::Renderer(RenderFlags flags) { white = Texture::New(pixels, 16, 16); UseTex(white); - font = Font::New(); - font->LoadSystemFont(); - // font->LoadTTF("romfs:/ComicNeue.ttf", 32); + // Not Loading as Systemfont is freezing + // font = Font::New(); + // font->LoadSystemFont(); area_size = top->GetSize(); } @@ -238,12 +243,18 @@ Renderer::~Renderer() { C3D_Fini(); } -bool Renderer::InBox(vec2 pos, vec2 szs, vec4 rect) { +bool Renderer::InBox(const vec2& pos, const vec2& szs, const vec4& rect) { return (pos[0] < rect[2] || pos[1] < rect[3] || pos[0] + szs[0] > rect[0] || pos[1] + szs[1] > rect[1]); } -bool Renderer::InBox(vec2 alpha, vec2 bravo, vec2 charlie, vec4 rect) { +bool Renderer::InBox(const vec2& pos, const vec4& rect) { + return (pos.x() > rect.x() && pos.x() < rect.x() + rect.z() && + pos.y() > rect.y() && pos.y() < rect.y() + rect.w()); +} + +bool Renderer::InBox(const vec2& alpha, const vec2& bravo, const vec2& charlie, + const vec4& rect) { return ((alpha[0] < rect[2] && bravo[0] < rect[2] && charlie[0] < rect[2]) || (alpha[1] < rect[3] && bravo[1] < rect[3] && charlie[1] < rect[3]) || (alpha[0] > 0 && bravo[0] > 0 && charlie[0] > 0) || @@ -256,7 +267,7 @@ void Renderer::RotateCorner(vec2& v, float s, float c) { v = vec2(x, y); } -Rect Renderer::CreateRect(vec2 pos, vec2 size, float angle) { +Rect Renderer::CreateRect(const vec2& pos, const vec2& size, float angle) { vec2 c = size * 0.5f; // Center vec2 corner[4] = { vec2(-c[0], -c[1]), @@ -279,7 +290,7 @@ Rect Renderer::CreateRect(vec2 pos, vec2 size, float angle) { corner[3] + pos + c); } -Rect Renderer::CreateLine(vec2 a, vec2 b, int t) { +Rect Renderer::CreateLine(const vec2& a, const vec2& b, int t) { // Usin g th evec maths api makes the code as short as it is vec2 dir = a - b; float len = dir.len(); @@ -306,7 +317,7 @@ void Renderer::SetupCommand(Command::Ref cmd) { cmd->Index(cmd_idx++).Layer(current_layer).Tex(current_tex); } -void Renderer::QuadCommand(Command::Ref cmd, const Rect& quad, vec4 uv, +void Renderer::QuadCommand(Command::Ref cmd, const Rect& quad, const vec4& uv, u32 col) { cmd->PushIndex(0).PushIndex(1).PushIndex(2); cmd->PushIndex(0).PushIndex(2).PushIndex(3); @@ -320,8 +331,8 @@ void Renderer::QuadCommand(Command::Ref cmd, const Rect& quad, vec4 uv, Vertex(vec2(quad.Bot().x(), quad.Bot().y()), vec2(uv.x(), uv.w()), col)); } -void Renderer::TriangleCommand(Command::Ref cmd, vec2 a, vec2 b, vec2 c, - u32 col) { +void Renderer::TriangleCommand(Command::Ref cmd, const vec2& a, const vec2& b, + const vec2& c, u32 col) { cmd->Index(cmd_idx++).Layer(current_layer).Tex(current_tex); cmd->PushIndex(2).PushIndex(1).PushIndex(0); cmd->PushVertex(Vertex(a, vec2(0.f, 1.f), col)); @@ -330,9 +341,9 @@ void Renderer::TriangleCommand(Command::Ref cmd, vec2 a, vec2 b, vec2 c, } /// TO BE REWRITTEN -void Renderer::TextCommand(std::vector& cmds, vec2 pos, u32 color, - const std::string& text, LITextFlags flags, - vec2 box) { +void Renderer::TextCommand(std::vector& cmds, const vec2& pos, + u32 color, const std::string& text, + LITextFlags flags, const vec2& box) { if (!font) { return; } @@ -378,7 +389,7 @@ void Renderer::TextCommand(std::vector& cmds, vec2 pos, u32 color, } } if (jt == '\t') { - off[0] += 4 * cfs; + off[0] += 16 * cfs; } else { if (jt != ' ') { int lr = current_layer; @@ -395,6 +406,10 @@ void Renderer::TextCommand(std::vector& cmds, vec2 pos, u32 color, cp.size() * cfs, 0.f); QuadCommand(cmd, rec, cp.uv(), color); current_layer = lr; + } else { + if (!font->SystemFont()) { + off[0] += 2 * cfs; + } } off[0] += cp.size().x() * cfs + 2 * cfs; } @@ -449,8 +464,14 @@ vec2 Renderer::GetTextDimensions(const std::string& text) { x = 0.f; break; case '\t': - x += 8 * cfs; + x += 16 * cfs; break; + case ' ': + if (!font->SystemFont()) { + x += 2 * cfs; + } + // Fall trough here to get the same result as in + // TextCommand if/else Section default: x += cp.size().x() * cfs; if (index != wtext.size()) { @@ -472,19 +493,16 @@ void Renderer::UpdateRenderMode(const RenderMode& mode) { switch (mode) { case RenderMode_SysFont: C3D_TexEnvInit(env); - C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR, (GPU_TEVSRC)0, - (GPU_TEVSRC)0); + C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR); C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE); - C3D_TexEnvSrc(env, C3D_Alpha, GPU_PRIMARY_COLOR, GPU_TEXTURE0, - (GPU_TEVSRC)0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0); C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE); break; // Fall trough instead of defining twice case RenderMode_RGBA: default: C3D_TexEnvInit(env); - C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, - (GPU_TEVSRC)0); + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0); C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); break; } @@ -506,9 +524,9 @@ void Renderer::RenderOn(bool bot) { commands = cmds.size(); size_t index = 0; - if (flags & RenderFlags_LRS) { - OptiCommandList(cmds); - } + // if (flags & RenderFlags_LRS) { + OptiCommandList(cmds); + //} while (index < cmds.size()) { C3D_Tex* tex = cmds[index]->Tex()->GetTex(); @@ -589,7 +607,8 @@ void Renderer::Render() { } } -void Renderer::DrawRect(vec2 pos, vec2 size, u32 color, vec4 uv) { +void Renderer::DrawRect(const vec2& pos, const vec2& size, u32 color, + const vec4& uv) { if (!InBox(pos, size, GetViewport())) { // Instand abort as it is out of screen return; @@ -601,12 +620,13 @@ void Renderer::DrawRect(vec2 pos, vec2 size, u32 color, vec4 uv) { draw_list[bottom].push_back(cmd); } -void Renderer::DrawRectSolid(vec2 pos, vec2 size, u32 color) { +void Renderer::DrawRectSolid(const vec2& pos, const vec2& size, u32 color) { UseTex(); DrawRect(pos, size, color); } -void Renderer::DrawTriangle(vec2 a, vec2 b, vec2 c, u32 color) { +void Renderer::DrawTriangle(const vec2& a, const vec2& b, const vec2& c, + u32 color) { if (!InBox(a, b, c, GetViewport())) { return; } @@ -617,7 +637,8 @@ void Renderer::DrawTriangle(vec2 a, vec2 b, vec2 c, u32 color) { draw_list[bottom].push_back(cmd); } -void Renderer::DrawCircle(vec2 center_pos, float r, u32 color, int segments) { +void Renderer::DrawCircle(const vec2& center_pos, float r, u32 color, + int segments) { if (segments < 3) { return; } @@ -639,7 +660,7 @@ void Renderer::DrawCircle(vec2 center_pos, float r, u32 color, int segments) { draw_list[bottom].push_back(cmd); } -void Renderer::DrawLine(vec2 a, vec2 b, u32 color, int t) { +void Renderer::DrawLine(const vec2& a, const vec2& b, u32 color, int t) { UseTex(); Rect line = CreateLine(a, b, t); @@ -649,13 +670,13 @@ void Renderer::DrawLine(vec2 a, vec2 b, u32 color, int t) { draw_list[bottom].push_back(cmd); } -void Renderer::DrawImage(vec2 pos, Texture::Ref tex, vec2 scale) { +void Renderer::DrawImage(const vec2& pos, Texture::Ref tex, const vec2& scale) { UseTex(tex); DrawRect(pos, tex->GetSize() * scale, 0xffffffff, tex->GetUV()); } -void Renderer::DrawText(vec2 pos, u32 color, const std::string& text, u32 flags, - vec2 ap) { +void Renderer::DrawText(const vec2& pos, u32 color, const std::string& text, + u32 flags, const vec2& ap) { TextCommand(draw_list[bottom], pos, color, text, flags, ap); } diff --git a/source/overlays/keyboard.cpp b/source/overlays/keyboard.cpp new file mode 100644 index 0000000..d19e71a --- /dev/null +++ b/source/overlays/keyboard.cpp @@ -0,0 +1,549 @@ +#include +#include +#include +#include + +namespace PD { +struct Key { + Key(const std::string& key, const vec2& p, const vec2& s, + Keyboard::KeyOperation o) { + k = key; + pos = p; + size = s; + op = o; + } + std::string k; + vec2 pos; + vec2 size; + Keyboard::KeyOperation op; +}; + +using Layout = std::vector; +Layout layouts[3] = { + { + // 1st row + Key("`", vec2(5, 0), 18, Keyboard::AppendSelf), + Key("1", vec2(25, 0), 18, Keyboard::AppendSelf), + Key("2", vec2(45, 0), 18, Keyboard::AppendSelf), + Key("3", vec2(65, 0), 18, Keyboard::AppendSelf), + Key("4", vec2(85, 0), 18, Keyboard::AppendSelf), + Key("5", vec2(105, 0), 18, Keyboard::AppendSelf), + Key("6", vec2(125, 0), 18, Keyboard::AppendSelf), + Key("7", vec2(145, 0), 18, Keyboard::AppendSelf), + Key("8", vec2(165, 0), 18, Keyboard::AppendSelf), + Key("9", vec2(185, 0), 18, Keyboard::AppendSelf), + Key("0", vec2(205, 0), 18, Keyboard::AppendSelf), + Key("-", vec2(225, 0), 18, Keyboard::AppendSelf), + Key("=", vec2(245, 0), 18, Keyboard::AppendSelf), + Key("<---", vec2(265, 0), vec2(50, 18), Keyboard::Backspace), + // 2nd row + Key("Tab", vec2(5, 20), vec2(40, 18), Keyboard::Tab), + Key("q", vec2(47, 20), 18, Keyboard::AppendSelf), + Key("w", vec2(67, 20), 18, Keyboard::AppendSelf), + Key("e", vec2(87, 20), 18, Keyboard::AppendSelf), + Key("r", vec2(107, 20), 18, Keyboard::AppendSelf), + Key("t", vec2(127, 20), 18, Keyboard::AppendSelf), + Key("y", vec2(147, 20), 18, Keyboard::AppendSelf), + Key("u", vec2(167, 20), 18, Keyboard::AppendSelf), + Key("i", vec2(187, 20), 18, Keyboard::AppendSelf), + Key("o", vec2(207, 20), 18, Keyboard::AppendSelf), + Key("p", vec2(227, 20), 18, Keyboard::AppendSelf), + Key("[", vec2(247, 20), 18, Keyboard::AppendSelf), + Key("]", vec2(267, 20), 18, Keyboard::AppendSelf), + Key("\\", vec2(287, 20), vec2(28, 18), Keyboard::AppendSelf), + // 3rd row + Key("Caps", vec2(5, 40), vec2(50, 18), Keyboard::Caps), + Key("a", vec2(57, 40), 18, Keyboard::AppendSelf), + Key("s", vec2(77, 40), 18, Keyboard::AppendSelf), + Key("d", vec2(97, 40), 18, Keyboard::AppendSelf), + Key("f", vec2(117, 40), 18, Keyboard::AppendSelf), + Key("g", vec2(137, 40), 18, Keyboard::AppendSelf), + Key("h", vec2(157, 40), 18, Keyboard::AppendSelf), + Key("j", vec2(177, 40), 18, Keyboard::AppendSelf), + Key("k", vec2(197, 40), 18, Keyboard::AppendSelf), + Key("l", vec2(217, 40), 18, Keyboard::AppendSelf), + Key(";", vec2(237, 40), 18, Keyboard::AppendSelf), + Key("'", vec2(257, 40), 18, Keyboard::AppendSelf), + Key("Enter", vec2(277, 40), vec2(38, 18), Keyboard::Enter), + // 4th row + Key("Shift", vec2(5, 60), vec2(60, 18), Keyboard::Shift), + Key("z", vec2(67, 60), 18, Keyboard::AppendSelf), + Key("x", vec2(87, 60), 18, Keyboard::AppendSelf), + Key("c", vec2(107, 60), 18, Keyboard::AppendSelf), + Key("v", vec2(127, 60), 18, Keyboard::AppendSelf), + Key("b", vec2(147, 60), 18, Keyboard::AppendSelf), + Key("n", vec2(167, 60), 18, Keyboard::AppendSelf), + Key("m", vec2(187, 60), 18, Keyboard::AppendSelf), + Key(",", vec2(207, 60), 18, Keyboard::AppendSelf), + Key(".", vec2(227, 60), 18, Keyboard::AppendSelf), + Key("/", vec2(247, 60), 18, Keyboard::AppendSelf), + Key("Shift", vec2(267, 60), vec2(48, 18), Keyboard::Shift), + // 5th row + Key("Cancel", vec2(5, 80), vec2(70, 18), Keyboard::OpCancel), + Key("(X)", vec2(77, 80), vec2(23, 18), Keyboard::Op1), + Key("Space", vec2(102, 80), vec2(108, 18), Keyboard::Space), + Key("(!)", vec2(212, 80), vec2(23, 18), Keyboard::Op2), + Key("Confirm", vec2(237, 80), vec2(78, 18), Keyboard::OpConfirm), + }, + { + // 1st row + Key("`", vec2(5, 0), 18, Keyboard::AppendSelf), + Key("1", vec2(25, 0), 18, Keyboard::AppendSelf), + Key("2", vec2(45, 0), 18, Keyboard::AppendSelf), + Key("3", vec2(65, 0), 18, Keyboard::AppendSelf), + Key("4", vec2(85, 0), 18, Keyboard::AppendSelf), + Key("5", vec2(105, 0), 18, Keyboard::AppendSelf), + Key("6", vec2(125, 0), 18, Keyboard::AppendSelf), + Key("7", vec2(145, 0), 18, Keyboard::AppendSelf), + Key("8", vec2(165, 0), 18, Keyboard::AppendSelf), + Key("9", vec2(185, 0), 18, Keyboard::AppendSelf), + Key("0", vec2(205, 0), 18, Keyboard::AppendSelf), + Key("-", vec2(225, 0), 18, Keyboard::AppendSelf), + Key("=", vec2(245, 0), 18, Keyboard::AppendSelf), + Key("<---", vec2(265, 0), vec2(50, 18), Keyboard::Backspace), + // 2nd row + Key("Tab", vec2(5, 20), vec2(40, 18), Keyboard::Tab), + Key("Q", vec2(47, 20), 18, Keyboard::AppendSelf), + Key("W", vec2(67, 20), 18, Keyboard::AppendSelf), + Key("E", vec2(87, 20), 18, Keyboard::AppendSelf), + Key("R", vec2(107, 20), 18, Keyboard::AppendSelf), + Key("T", vec2(127, 20), 18, Keyboard::AppendSelf), + Key("Y", vec2(147, 20), 18, Keyboard::AppendSelf), + Key("U", vec2(167, 20), 18, Keyboard::AppendSelf), + Key("I", vec2(187, 20), 18, Keyboard::AppendSelf), + Key("O", vec2(207, 20), 18, Keyboard::AppendSelf), + Key("P", vec2(227, 20), 18, Keyboard::AppendSelf), + Key("[", vec2(247, 20), 18, Keyboard::AppendSelf), + Key("]", vec2(267, 20), 18, Keyboard::AppendSelf), + Key("\\", vec2(287, 20), vec2(28, 18), Keyboard::AppendSelf), + // 3rd row + Key("Caps", vec2(5, 40), vec2(50, 18), Keyboard::Caps), + Key("A", vec2(57, 40), 18, Keyboard::AppendSelf), + Key("S", vec2(77, 40), 18, Keyboard::AppendSelf), + Key("D", vec2(97, 40), 18, Keyboard::AppendSelf), + Key("F", vec2(117, 40), 18, Keyboard::AppendSelf), + Key("G", vec2(137, 40), 18, Keyboard::AppendSelf), + Key("H", vec2(157, 40), 18, Keyboard::AppendSelf), + Key("J", vec2(177, 40), 18, Keyboard::AppendSelf), + Key("K", vec2(197, 40), 18, Keyboard::AppendSelf), + Key("L", vec2(217, 40), 18, Keyboard::AppendSelf), + Key(";", vec2(237, 40), 18, Keyboard::AppendSelf), + Key("'", vec2(257, 40), 18, Keyboard::AppendSelf), + Key("Enter", vec2(277, 40), vec2(38, 18), Keyboard::Enter), + // 4th row + Key("Shift", vec2(5, 60), vec2(60, 18), Keyboard::Shift), + Key("Z", vec2(67, 60), 18, Keyboard::AppendSelf), + Key("X", vec2(87, 60), 18, Keyboard::AppendSelf), + Key("C", vec2(107, 60), 18, Keyboard::AppendSelf), + Key("V", vec2(127, 60), 18, Keyboard::AppendSelf), + Key("B", vec2(147, 60), 18, Keyboard::AppendSelf), + Key("N", vec2(167, 60), 18, Keyboard::AppendSelf), + Key("M", vec2(187, 60), 18, Keyboard::AppendSelf), + Key(",", vec2(207, 60), 18, Keyboard::AppendSelf), + Key(".", vec2(227, 60), 18, Keyboard::AppendSelf), + Key("/", vec2(247, 60), 18, Keyboard::AppendSelf), + Key("Shift", vec2(267, 60), vec2(48, 18), Keyboard::Shift), + // 5th row + Key("Cancel", vec2(5, 80), vec2(70, 18), Keyboard::OpCancel), + Key("(X)", vec2(77, 80), vec2(23, 18), Keyboard::Op1), + Key("Space", vec2(102, 80), vec2(108, 18), Keyboard::Space), + Key("(!)", vec2(212, 80), vec2(23, 18), Keyboard::Op2), + Key("Confirm", vec2(237, 80), vec2(78, 18), Keyboard::OpConfirm), + }, + { + // 1st row + Key("~", vec2(5, 0), 18, Keyboard::AppendSelf), + Key("!", vec2(25, 0), 18, Keyboard::AppendSelf), + Key("@", vec2(45, 0), 18, Keyboard::AppendSelf), + Key("#", vec2(65, 0), 18, Keyboard::AppendSelf), + Key("$", vec2(85, 0), 18, Keyboard::AppendSelf), + Key("%", vec2(105, 0), 18, Keyboard::AppendSelf), + Key("^", vec2(125, 0), 18, Keyboard::AppendSelf), + Key("&", vec2(145, 0), 18, Keyboard::AppendSelf), + Key("*", vec2(165, 0), 18, Keyboard::AppendSelf), + Key("(", vec2(185, 0), 18, Keyboard::AppendSelf), + Key(")", vec2(205, 0), 18, Keyboard::AppendSelf), + Key("_", vec2(225, 0), 18, Keyboard::AppendSelf), + Key("+", vec2(245, 0), 18, Keyboard::AppendSelf), + Key("<---", vec2(265, 0), vec2(50, 18), Keyboard::Backspace), + // 2nd row + Key("Tab", vec2(5, 20), vec2(40, 18), Keyboard::Tab), + Key("Q", vec2(47, 20), 18, Keyboard::AppendSelf), + Key("W", vec2(67, 20), 18, Keyboard::AppendSelf), + Key("E", vec2(87, 20), 18, Keyboard::AppendSelf), + Key("R", vec2(107, 20), 18, Keyboard::AppendSelf), + Key("T", vec2(127, 20), 18, Keyboard::AppendSelf), + Key("Y", vec2(147, 20), 18, Keyboard::AppendSelf), + Key("U", vec2(167, 20), 18, Keyboard::AppendSelf), + Key("I", vec2(187, 20), 18, Keyboard::AppendSelf), + Key("O", vec2(207, 20), 18, Keyboard::AppendSelf), + Key("P", vec2(227, 20), 18, Keyboard::AppendSelf), + Key("{", vec2(247, 20), 18, Keyboard::AppendSelf), + Key("}", vec2(267, 20), 18, Keyboard::AppendSelf), + Key("|", vec2(287, 20), vec2(28, 18), Keyboard::AppendSelf), + // 3rd row + Key("Caps", vec2(5, 40), vec2(50, 18), Keyboard::Caps), + Key("A", vec2(57, 40), 18, Keyboard::AppendSelf), + Key("S", vec2(77, 40), 18, Keyboard::AppendSelf), + Key("D", vec2(97, 40), 18, Keyboard::AppendSelf), + Key("F", vec2(117, 40), 18, Keyboard::AppendSelf), + Key("G", vec2(137, 40), 18, Keyboard::AppendSelf), + Key("H", vec2(157, 40), 18, Keyboard::AppendSelf), + Key("J", vec2(177, 40), 18, Keyboard::AppendSelf), + Key("K", vec2(197, 40), 18, Keyboard::AppendSelf), + Key("L", vec2(217, 40), 18, Keyboard::AppendSelf), + Key(":", vec2(237, 40), 18, Keyboard::AppendSelf), + Key("\"", vec2(257, 40), 18, Keyboard::AppendSelf), + Key("Enter", vec2(277, 40), vec2(38, 18), Keyboard::Enter), + // 4th row + Key("Shift", vec2(5, 60), vec2(60, 18), Keyboard::Shift), + Key("Z", vec2(67, 60), 18, Keyboard::AppendSelf), + Key("X", vec2(87, 60), 18, Keyboard::AppendSelf), + Key("C", vec2(107, 60), 18, Keyboard::AppendSelf), + Key("V", vec2(127, 60), 18, Keyboard::AppendSelf), + Key("B", vec2(147, 60), 18, Keyboard::AppendSelf), + Key("N", vec2(167, 60), 18, Keyboard::AppendSelf), + Key("M", vec2(187, 60), 18, Keyboard::AppendSelf), + Key("<", vec2(207, 60), 18, Keyboard::AppendSelf), + Key(">", vec2(227, 60), 18, Keyboard::AppendSelf), + Key("?", vec2(247, 60), 18, Keyboard::AppendSelf), + Key("Shift", vec2(267, 60), vec2(48, 18), Keyboard::Shift), + // 5th row + Key("Cancel", vec2(5, 80), vec2(70, 18), Keyboard::OpCancel), + Key("(X)", vec2(77, 80), vec2(23, 18), Keyboard::Op1), + Key("Space", vec2(102, 80), vec2(108, 18), Keyboard::Space), + Key("(!)", vec2(212, 80), vec2(23, 18), Keyboard::Op2), + Key("Confirm", vec2(237, 80), vec2(78, 18), Keyboard::OpConfirm), + }, +}; + +void DumpLayout(const std::string& path) { + nlohmann::json l0; + l0["name"] = "Default US"; + for (int i = 0; i < 3; i++) { + nlohmann::json l1; + for (size_t j = 0; j < layouts[0].size(); j++) { + nlohmann::json key; + key["display_char"] = layouts[i][j].k; + key["pos_x"] = layouts[i][j].pos[0]; + key["pos_y"] = layouts[i][j].pos[1]; + key["size_x"] = layouts[i][j].size[0]; + key["size_y"] = layouts[i][j].size[1]; + key["op"] = layouts[i][j].op; + l1.push_back(key); + } + l0[std::to_string(i)] = l1; + } + std::ofstream off(path); + off << l0.dump(3); + off.close(); +} + +/// The Only One (too) is a static var to make sur +/// THe Keyboard can only exist once in the overlay mgr +int Keyboard::too = 0; + +void Keyboard::MoveSelector() { + /// Move from Current position to New Position + selector.From(selector).To(layouts[0][raw_sel].pos).In(0.2f); + /// If Button Size Changed, animate to the new size + if (cselszs != layouts[0][raw_sel].size) { + cselszs = layouts[0][raw_sel].size; + sel_szs.Swap(); + sel_szs.To(cselszs).In(0.2); + } +} + +void Keyboard::LoadTheKeys(LI::Renderer::Ref ren) { + for (int i = 0; i < 3; i++) { + keys[i] = LI::StaticObject::New(); + for (auto it : layouts[i]) { + vec2 pos = it.pos + it.size * 0.5 - ren->GetTextDimensions(it.k) * 0.5; + auto c = LI::Command::New(); + auto r = ren->CreateRect(it.pos, it.size, 0.f); + int l = ren->Layer(); + ren->UseTex(); + ren->Layer(1); + ren->SetupCommand(c); + ren->QuadCommand(c, r, vec4(0.f, 1.f, 1.f, 0.f), 0xff444444); + keys[i]->PushCommand(c); + ren->Layer(2); + ren->TextCommand(keys[i]->List(), pos, 0xffffffff, it.k, 0, 0); + ren->Layer(l); + } + ren->OptiCommandList(keys[i]->List()); + } + keys_loadet = true; +} + +void Keyboard::Movement(Hid::Ref inp) { + /// Any Key if no selector + if (raw_sel < 0) { + /// Initial Selector PopUp + if (inp->IsUp((Hid::Key)(inp->Up | inp->Down | inp->Left | inp->Right))) { + raw_sel = 0; + vec2 dst = layouts[0][0].pos; + cselszs = layouts[0][0].size; + selector.As(selector.Linear).From(dst + (cselszs * 0.5)).To(dst).In(0.1f); + sel_szs.As(sel_szs.Linear).From(0).To(cselszs).In(0.1f); + } + } else { + /// Go Up Movement + if (inp->IsUp(inp->Up)) { + // beginning pos of the keyboard + vec2 sp = flymgr; + // Keys are offset by 22 + sp.y() += 22; + // temp pos to save selector tween to + vec2 tp = selector; + // set its offset to startpos to + // create a box over all rows + tp.y() = sp.y(); + // Get the selector tween size + vec2 tszs = sel_szs; + // Get the last keys pos and size + // to calculate the size of temp szs + auto const& lok = layouts[0][layouts[0].size() - 1]; + tszs.y() = lok.pos.y() + lok.size.y(); + // Backwards loop + for (int i = raw_sel; i >= 0; i--) { + if (LI::Renderer::InBox( + sp + layouts[0][i].pos - vec2(0, layouts[0][i].size.y()), + layouts[0][i].size, vec4(tp, tszs))) { + raw_sel = i; + break; + } + } + MoveSelector(); + } + /// Go Down Movement + if (inp->IsUp(inp->Down)) { + vec2 fly = flymgr; + vec2 sel = selector; + vec2 selszs = sel_szs; + vec4 box(fly + sel, selszs); + // clang-format off + int start = layouts[0][raw_sel].pos.y() == + layouts[0][layouts[0].size() - 1].pos.y() + ? 0 : raw_sel + 3; + // clang-format on + for (int i = start; i < (int)layouts[0].size(); i++) { + if (LI::Renderer::InBox(fly + layouts[0][i].pos, sel_szs, box)) { + raw_sel = i; + break; + } + } + MoveSelector(); + } + if (inp->IsUp(inp->Right)) { + if ((raw_sel + 1 >= (int)layouts[0].size()) || + layouts[0][raw_sel].pos.y() != layouts[0][raw_sel + 1].pos.y()) { + for (int i = raw_sel - 1; i > 0; i--) { + if (i - 1 <= 0) { + raw_sel = 0; + break; + } + if (layouts[0][i].pos.y() != layouts[0][i - 1].pos.y()) { + raw_sel = i; + break; + } + } + } else { + raw_sel++; + } + MoveSelector(); + } + if (inp->IsUp(inp->Left)) { + if (raw_sel - 1 < 0 || + layouts[0][raw_sel].pos.y() != layouts[0][raw_sel - 1].pos.y()) { + for (int i = raw_sel; i < (int)layouts[0].size(); i++) { + if (i >= (int)layouts[0].size()) { + raw_sel = (int)layouts[0].size(); + } + if (layouts[0][i].pos.y() != layouts[0][i + 1].pos.y()) { + raw_sel = i; + break; + } + } + } else { + raw_sel--; + } + MoveSelector(); + } + } +} + +void Keyboard::DoOperation(KeyOperation op, const std::string& kname) { + switch (op) { + case AppendSelf: + *text += kname; + if (mode == 2) { + mode = 0; + } + break; + case OpCancel: + Rem(); + *text = copy; + break; + case OpConfirm: + Rem(); + break; + case Shift: + mode = mode == 2 ? 0 : 2; + break; + case Caps: + mode = mode == 1 ? 0 : 1; + break; + case Backspace: { + std::string c = *text; + *text = c.substr(0, c.size() - 1); + } break; + case Space: + *text += ' '; + break; + case Tab: + *text += '\t'; + break; + + default: + break; + } +} + +void Keyboard::RecolorBy(KeyOperation op, u32 color, int cm) { + int i = 0; + /// Not the fastest but the best for custom layouts + for (auto& it : layouts[cm]) { + if (it.op == op) { + keys[cm]->ReColorQuad(i, PD::Color(0xff222222)); + break; + } + i++; + } +} +void Keyboard::InputOpBind(Hid::Key k, KeyOperation op, Hid::Ref inp, int cm) { + if (inp->IsUp(k)) { + RecolorBy(op, PD::Color(0xff222222), cm); + DoOperation(op, ""); + } else if (inp->IsHeld(k)) { + RecolorBy(op, PD::Color(0xff333333), cm); + } +} + +void Keyboard::Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) { + /// Load Keys if not present + if (!keys_loadet) { + inp->Clear(); + LoadTheKeys(ren); + } + /// Unlock Input + inp->Unlock(); + /// Kill Overlay if rem was toggeled and + /// Animation is finished + if (rem && flymgr.IsFinished()) { + // Should be already unlocked ... + // ist mit aber egal + inp->Unlock(); + Kill(); + return; // Break to not lock again + } + /// Process Controller Movement + Movement(inp); + + /// Declare RenderLayer (10 above the latest) + ren->Layer(ren->Layer() + 10); + /// Update animations + flymgr.Update(delta); + selector.Update(delta); + sel_szs.Update(delta); + /// Blend Top or|and Bottom Screen + if (flags & Flags_BlendBottom || flags & Flags_BlendTop) { + Color fade(0.3f, 0.3f, 0.3f); + if (rem) { + fade.a(fade.a() * (1.f - flymgr.Progress())); + } else { + fade.a(fade.a() * flymgr.Progress()); + } + if (flags & Flags_BlendTop) { + ren->OnScreen(Screen::Top); + ren->DrawRectSolid(0, vec2(400, 240), fade); + } + if (flags & Flags_BlendBottom) { + ren->OnScreen(Screen::Bottom); + ren->DrawRectSolid(0, vec2(320, 240), fade); + } + } + /// Get the current start possition + vec2 start = flymgr; + // Draw head and Keyboard background + ren->DrawRectSolid(vec2(0, start.y()), vec2(320, 17), 0xaa000000); + ren->DrawRectSolid(vec2(0, start.y()), vec2(320, 125), 0xaa222222); + /// Grab the base layer and go one up for texts + int l = ren->Layer(); + ren->Layer(l + 2); + // if (ren->Font()->SystemFont()) { + // std::stringstream s; + // s << GamePadIcons::GetIcon(GamePadIcons::B) << " Backspace "; + // s << GamePadIcons::GetIcon(GamePadIcons::Y) << " Space\n"; + // s << GamePadIcons::GetIcon(GamePadIcons::X) << " Cancel "; + // s << GamePadIcons::GetIcon(GamePadIcons::Start) << " Confirm\n"; + // s << GamePadIcons::GetIcon(GamePadIcons::L) << " Shift "; + // s << GamePadIcons::GetIcon(GamePadIcons::R) << " CAPS\n"; + // s << GamePadIcons::GetIcon(GamePadIcons::Dpad) << " Move "; + // s << GamePadIcons::GetIcon(GamePadIcons::A) << " Select\n"; + // ren->DrawText(vec2(5, start.y() - + // ren->GetTextDimensions(s.str()).y()+16), + // 0xffffffff, s.str()); + // } + ren->DrawText(vec2(5, start.y()), 0xffffffff, "> " + *text); + ren->Layer(l + 1); + /// Offset Keys start height by 22 + start[1] += 22; + /// Cache Mode to not render on 0, 0 + int cm = mode; + keys[cm]->ReCopy(); + int ii = 0; + for (auto& it : layouts[mode]) { + PD::Color bgc(0xff444444); + if (((ren->InBox(inp->TouchPosLast(), vec4(start + it.pos, it.size)) && + inp->IsHeld(inp->Touch)) || + (inp->IsHeld(inp->A) && ii == raw_sel)) && + flymgr.IsFinished()) { + bgc = PD::Color(0xff333333); + } + if (((ren->InBox(inp->TouchPosLast(), vec4(start + it.pos, it.size)) && + inp->IsUp(inp->Touch)) || + (inp->IsUp(inp->A) && ii == raw_sel)) && + flymgr.IsFinished()) { + bgc = PD::Color(0xff222222); + DoOperation(it.op, it.k); + } + /// This is hardcoded shit guessing that the + /// Buttons are in the beginning of the list + /// (Should be the case as OptiCmdList sorts by layer) + keys[cm]->ReColorQuad(ii, bgc); + ii++; + } + + // Bind Key Operations + InputOpBind(inp->B, Backspace, inp, cm); + InputOpBind(inp->Y, Space, inp, cm); + InputOpBind(inp->Start, OpConfirm, inp, cm); + InputOpBind(inp->X, OpCancel, inp, cm); + InputOpBind(inp->L, Shift, inp, cm); + InputOpBind(inp->R, Caps, inp, cm); + + if (raw_sel != -1) { + ren->Layer(l); + ren->DrawRectSolid(start + selector - vec2(1), vec2(sel_szs) + vec2(2), + 0xffffffff); + ren->Layer(l); + } + keys[cm]->ReLayer(l); + keys[cm]->MoveIt(start); + for (auto it : keys[cm]->List()) { + ren->PushCommand(it); + } + inp->Lock(); +} +} // namespace PD \ No newline at end of file diff --git a/source/overlays/message_mgr.cpp b/source/overlays/message_mgr.cpp new file mode 100644 index 0000000..7e33958 --- /dev/null +++ b/source/overlays/message_mgr.cpp @@ -0,0 +1,126 @@ +#include + +namespace PD { +MessageMgr::Container::Container(const std::string& title, + const std::string& msg) { + this->title = title; + this->msg = msg; + size = vec2(150, 50); + // Precalculate colors + col_bg = PD::Color("#111111aa"); + col_text = PD::Color("#ffffff"); + // Setup Flyin Animation + FlyIn(); +} +void MessageMgr::Container::Render(PD::LI::Renderer::Ref ren) { + // Create a Temp var to not recalculate + // the position everytime we use it + // even if the calculation would always + // result in the same we would waste a lot + // of cpu performance which is a big issue + // espeacilly on the Old3ds... + vec2 tpos = pos; + // Check if it goes out of screen + // Instant kills cause it will never be on + // Screen agains + if (tpos[1] + size[1] < 0) { + kill = true; + } + // If should be removed modify the color by fade + // Use a temp var as well to not call it twice + if (tbr) { + float f = 1.f - pos.Progress(); + col_bg.a(col_bg.a() * f); + col_text.a(col_text.a() * f); + } + // Create a backup Layer to Render + // Text onto the next layer + int l = ren->Layer(); + ren->DrawRectSolid(tpos, size, col_bg); + ren->Layer(l + 1); + ren->DrawText(tpos + vec2(4, 2), col_text, title); + ren->DrawText(tpos + vec2(4, 16), col_text, msg); + ren->Layer(l); +} +void MessageMgr::Container::Update(int slot, float delta) { + // Increase lifetime + lifetime += delta / 1000.f; + // Trigger move up Animation if + // the slot got changed + if (s != slot) { + ToBeMoved(slot); + s = slot; + } + // Update the animations + pos.Update(delta); + // Trigger the remove Event if lifetime + // goes beyond 4 secods + if (lifetime > 4 && !tbr) { + ToBeRemoved(); + } +} +void MessageMgr::Container::FlyIn() { + // Come from out of the screen to 5, 185 into + // The screen as EaseInSine in 0.5 seconds + pos.From(vec2(-size[0], 240 - size[1] - 5)) + .To(vec2(5, 240 - size[1] - 5)) + .In(0.5) + .As(pos.EaseInSine); +} +void MessageMgr::Container::ToBeMoved(int slot) { + // Bit more special + // Get the current pos as temp one + vec2 tpos = pos; + // Calculate a temp Startpos which + // is the endpos of Flyin if + // it is fully playd (see next comment) + float spos = 240 - size[1] - 5; + // Now from the Current Position Move up by + // The Number of slot * the size.y + 5 + // and make sure it flys diagonal if the + // Flyin hasn't ended yet. This animation uses EaseInSine + // And does it's move in 0.4 seconds to not have + // The new one and this one in collision for to much time + pos.From(tpos) + .To(vec2(5, spos - slot * (size[1] + 5))) + .As(pos.EaseInSine) + .In(0.4); +} + +void MessageMgr::Container::ToBeRemoved() { + // This effect uses EaseOutSine and as well uses the fade anim + tbr = true; + // We Force set the Position to Finished to avoid collision + // to the ToBeMoved Animation And then set an EaseOutSine in 0.5 + // seconds to move the Message 30 pixels up while fading out + pos.Finish(); + vec2 tpos = pos; + pos.From(tpos).To(tpos - vec2(0, 30)).As(pos.EaseOutSine).In(0.5); +} + +void MessageMgr::Push(const std::string& title, const std::string& text) { + // Simply Add a New Message Container + msgs.push_back(Container::New(title, text)); +} + +void MessageMgr::Update(float delta) { + // Go two layers up and Render on Top + ren->Layer(ren->Layer() + 2); + ren->OnScreen(Screen::Top); + for (size_t i = 0; i < msgs.size(); i++) { + // Update the Animation Handlers and Move older + // Messages up if a new one got pushed + msgs[i]->Update(msgs.size() - i - 1, delta); + msgs[i]->Render(ren); + } + /// OMG HE LOOPS TWICE OVER THE OBJECTS TO + /// CHECK IF THEY CAN BE REMOVED WOW....... + /// Just my Stupid fix for the flickering + /// Of the other messages if one get's removed + for (size_t i = 0; i < msgs.size(); i++) { + if (msgs[i]->ShouldBeRemoved()) { + msgs.erase(msgs.begin() + i); + } + } +} +} // namespace PD \ No newline at end of file diff --git a/source/overlays/overlay_mgr.cpp b/source/overlays/overlay_mgr.cpp new file mode 100644 index 0000000..58e2469 --- /dev/null +++ b/source/overlays/overlay_mgr.cpp @@ -0,0 +1,14 @@ +#include + +namespace PD { +void OverlayMgr::Push(Overlay::Ref overlay) { overlays.push_back(overlay); } +void OverlayMgr::Update(float delta) { + for (size_t i = 0; i < overlays.size(); i++) { + if (overlays[i]->IsKilled()) { + overlays.erase(overlays.begin() + i); + continue; + } + overlays[i]->Update(delta, ren, inp); + } +} +} // namespace PD \ No newline at end of file diff --git a/source/overlays/performance.cpp b/source/overlays/performance.cpp new file mode 100644 index 0000000..930f0a2 --- /dev/null +++ b/source/overlays/performance.cpp @@ -0,0 +1,46 @@ +#include +#include +#include + +namespace PD { +int Performance::too = 0; + +void Performance::Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) { + if (*skill) { + Kill(); + } + ren->OnScreen(Screen::Top); + ren->TextScale(0.6); + vec2 pos; + Line(pos, std::format("FPS {:.1f} FPS | {:.2f}ms", 1000.f / delta, delta), + ren); + Line(pos, "Ren [AVG]: " + TSA("LI_RenderAll"), ren); + Line(pos, "App [AVG]: " + TSA("App_MainLoop"), ren); + Line(pos, "Ovl [AVG]: " + TSA("Ovl_Update"), ren); + Line(pos, + "VI: [" + std::to_string(ren->Vertices()) + ", " + + std::to_string(ren->Indices()) + "]", + ren); + Line(pos, + "DC: [" + std::to_string(ren->DrawCalls()) + ", " + + std::to_string(ren->Commands()) + "]", + ren); + ren->DefaultTextScale(); +} + +void Performance::Line(vec2& pos, const std::string& text, + LI::Renderer::Ref ren) { + auto tbs = ren->GetTextDimensions(text); + int l = ren->Layer(); + ren->DrawRectSolid(pos, tbs, 0xaa000000); + ren->Layer(l + 1); + ren->DrawText(pos, 0xffff00ff, text); + ren->Layer(l); + pos[1] += tbs[1]; // Auto set new pos +} + +std::string Performance::TSA(const std::string& id) { + return PD::Strings::FormatNanos( + PD::Sys::GetTraceRef(id)->GetProtocol()->GetAverage()); +} +} // namespace PD \ No newline at end of file diff --git a/source/tools/gamepad_icons.cpp b/source/tools/gamepad_icons.cpp new file mode 100644 index 0000000..f682472 --- /dev/null +++ b/source/tools/gamepad_icons.cpp @@ -0,0 +1,57 @@ +#include + +namespace PD { +namespace GamePadIcons { +/// For Reference see docs at 3DBrew +std::unordered_map gp_icons{ + {A, "\uE000"}, + {B, "\uE001"}, + {X, "\uE002"}, + {Y, "\uE003"}, + {L, "\uE004"}, + {R, "\uE005"}, + {Dpad, "\uE006"}, + {Start, "\uE045"}, + {Select, "\uE046"}, + {Home, "\uE073"}, + {Steps, "\uE074"}, + {PlayCoin, "\uE075"}, + {AnalogStick, "\uE077"}, + {Power3DS, "\uE078"}, + {DpadUp, "\uE079"}, + {DpadDown, "\uE07A"}, + {DpadLeft, "\uE07B"}, + {DpadRight, "\uE07C"}, + {DpadHorizontal, "\uE07D"}, + {DpadVertical, "\uE07E"}, +}; +std::unordered_map gp_link{ + {Hid::A, ID::A}, + {Hid::B, ID::B}, + {Hid::X, ID::X}, + {Hid::Y, ID::Y}, + {Hid::L, ID::L}, + {Hid::R, ID::R}, + {Hid::Start, ID::Start}, + {Hid::Select, ID::Select}, + {Hid::DUp, ID::DpadUp}, + {Hid::DDown, ID::DpadDown}, + {Hid::DLeft, ID::DpadLeft}, + {Hid::DRight, ID::DpadRight}, +}; +std::string GetIcon(ID id) { + auto e = gp_icons.find(id); + if (e == gp_icons.end()) { + return ""; + } + return e->second; +} +std::string GetIcon(Hid::Key key) { + auto e = gp_link.find(key); + if (e == gp_link.end()) { + return ""; + } + return gp_icons[gp_link[key]]; +} +} // namespace GamePadIcons +} // namespace PD diff --git a/source/ui7/drawlist.cpp b/source/ui7/drawlist.cpp index f7315a4..bcc6175 100644 --- a/source/ui7/drawlist.cpp +++ b/source/ui7/drawlist.cpp @@ -24,7 +24,8 @@ SOFTWARE. #include namespace PD { -void UI7DrawList::AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr) { +namespace UI7 { +void DrawList::AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr) { if (!ren->InBox(pos, szs, ren->GetViewport())) { return; } @@ -37,8 +38,8 @@ void UI7DrawList::AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr) { commands.push_back(cmd); } -void UI7DrawList::AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, - const UI7Color& clr) { +void DrawList::AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, + const UI7Color& clr) { if (!ren->InBox(pos0, pos1, pos2, ren->GetViewport())) { return; } @@ -50,16 +51,15 @@ void UI7DrawList::AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, commands.push_back(cmd); } -void UI7DrawList::AddText(vec2 pos, const std::string& text, - const UI7Color& clr, LITextFlags flags = 0, - vec2 box = vec2()) { +void DrawList::AddText(vec2 pos, const std::string& text, const UI7Color& clr, + LITextFlags flags, vec2 box) { // Dont create a Command here as TextCommand has autosetup // cause it needs to generate multiple commands if // Font uses multiple textures ren->TextCommand(commands, pos, clr, text, flags, box); } -void UI7DrawList::AddImage(vec2 pos, Texture::Ref img) { +void DrawList::AddImage(vec2 pos, Texture::Ref img) { if (!ren->InBox(pos, img->GetSize(), ren->GetViewport())) { return; } @@ -72,14 +72,14 @@ void UI7DrawList::AddImage(vec2 pos, Texture::Ref img) { commands.push_back(cmd); } -void UI7DrawList::Clear() { commands.clear(); } +void DrawList::Clear() { commands.clear(); } -void UI7DrawList::Process() { +void DrawList::Process() { // UI7 Commands Use LI7 as default feature ren->OptiCommandList(commands); for (auto command : commands) { ren->PushCommand(command); } } - +} // namespace UI7 } // namespace PD \ No newline at end of file diff --git a/source/ui7/theme.cpp b/source/ui7/theme.cpp new file mode 100644 index 0000000..ac18e6e --- /dev/null +++ b/source/ui7/theme.cpp @@ -0,0 +1,24 @@ +#include +#include + +namespace PD { +namespace UI7 { +void Theme::Default(Theme& theme) { + theme.Set(UI7Color_Text, Color("#FFFFFFFF")); + theme.Set(UI7Color_TextDead, Color("#AAAAAAFF")); + theme.Set(UI7Color_Background, Color("#EEEEEEFF")); + theme.Set(UI7Color_Button, Color("#111111FF")); + theme.Set(UI7Color_ButtonDead, Color("#080808FF")); + theme.Set(UI7Color_ButtonActive, Color("#2A2A2AFF")); + theme.Set(UI7Color_ButtonDisabled, Color("#222222FF")); + theme.Set(UI7Color_Header, Color("#111111FF")); + theme.Set(UI7Color_Selector, Color("#222222FF")); + theme.Set(UI7Color_Checkmark, Color("#2A2A2AFF")); + theme.Set(UI7Color_FrameBackground, Color("#555555FF")); + theme.Set(UI7Color_FragmeBackgroundHovered, Color("#777777FF")); + theme.Set(UI7Color_Progressbar, Color("#00FF00FF")); + theme.Set(UI7Color_ListEven, Color("#CCCCCCFF")); + theme.Set(UI7Color_ListOdd, Color("#BBBBBBFF")); +} +} // namespace UI7 +} // namespace PD \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp index 87305f5..806c1cd 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -25,6 +25,7 @@ SOFTWARE. #include #include +#include using vec2 = PD::vec2; using vec3 = PD::vec3; @@ -37,37 +38,36 @@ class Test : public PD::App { void Init() override { test = PD::Texture::New("romfs:/icon.png"); - cpu = PD::TimeStats::New(100); + Overlays()->Push(PD::New(dbg, dbg_screen)); + font = PD::LI::Font::New(); + // font->LoadSystemFont(); + font->LoadTTF("romfs:/ComicNeue.ttf", 32); + Renderer()->Font(font); + ui7 = PD::UI7::Context::New(); } - bool MainLoop(unsigned long long delta, float time) override { - cpu->Add(C3D_GetProcessingTime()); - hidScanInput(); + bool MainLoop(float delta, float time) override { DrawFancyBG(time); - Renderer()->TextScale(0.6f); - vec2 start(5, 100); - DebugText(start, "FPS: " + std::to_string((int)GetFps())); - DebugText(start, "DrawCalls: " + std::to_string(Renderer()->DrawCalls())); - DebugText(start, "DrawCommands: " + std::to_string(Renderer()->Commands())); - DebugText(start, "Vertices: " + std::to_string(Renderer()->Vertices())); - DebugText(start, "Indices: " + std::to_string(Renderer()->Indices())); - DebugText(start, "Ren [AVG]: " + PD::Strings::FormatNanos( - PD::Sys::GetTraceRef("LI_RenderAll") - ->GetProtocol() - ->GetAverage())); - DebugText(start, "App [AVG]: " + PD::Strings::FormatNanos( - PD::Sys::GetTraceRef("App_MainLoop") - ->GetProtocol() - ->GetAverage())); - Renderer()->DefaultTextScale(); Renderer()->OnScreen(PD::Screen::Bottom); Renderer()->DrawRectSolid(0, vec2(320, 240), PD::Color("#222222")); Renderer()->UseTex(test); - Renderer()->DrawImage(vec2(130, 90), test); + Renderer()->Layer(Renderer()->Layer() + 1); + Renderer()->DrawImage( + Renderer()->GetViewport().zw() * 0.5 - test->GetSize() * 0.5, test); Renderer()->DrawText(5, 0xffffffff, "Hello World!", LITextFlags_None); - if (hidKeysDown() & KEY_START) { + if (Input()->IsDown(PD::Hid::Start)) { return false; } + if (Input()->IsDown(Input()->A)) { + Overlays()->Push(PD::New(dbg, dbg_screen)); + Messages()->Push("Test", "Oder SO"); + // what.To(vec2(5, 200)).From(vec2(-100, + // 200)).In(0.5).As(what.EaseInQuad); + } + if (Input()->IsUp(Input()->B)) { + Overlays()->Push(PD::New(text, state)); + // what.To(vec2(5, 180)).From(vec2(5, 200)).In(0.5).As(what.EaseOutQuad); + } return true; } @@ -97,16 +97,13 @@ class Test : public PD::App { .36f + .38f * color_effect)); } - void DebugText(vec2& pos, const std::string& text) { - auto tbs = Renderer()->GetTextDimensions(text); - Renderer()->DrawRectSolid(pos, tbs, 0xaa000000); - Renderer()->DrawText(pos, 0xffff00ff, text); - pos[1] += tbs[1]; // Auto set new pos - } - private: PD::Texture::Ref test; - PD::TimeStats::Ref cpu; + bool dbg = false, dbg_screen = false; + std::string text; + PD::Keyboard::State state; + PD::UI7::Context::Ref ui7; + PD::LI::Font::Ref font; }; int main() {