433 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			433 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | #pragma once
 | ||
|  | 
 | ||
|  | /*
 | ||
|  | MIT License | ||
|  | 
 | ||
|  | Copyright (c) 2024 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 <pd/common/common.hpp>
 | ||
|  | #include <pd/common/memory.hpp>
 | ||
|  | #include <pd/graphics/screen.hpp>
 | ||
|  | #include <pd/graphics/texture.hpp>
 | ||
|  | #include <pd/maths/vec.hpp>
 | ||
|  | #include <pd/tools/markdown.hpp>
 | ||
|  | 
 | ||
|  | using LITextFlags = u32; | ||
|  | 
 | ||
|  | enum LITextFlags_ { | ||
|  |   LITextFlags_None = 0, | ||
|  |   LITextFlags_AlignRight = 1 << 0, | ||
|  |   LITextFlags_AlignMid = 1 << 1, | ||
|  |   LITextFlags_Shaddow = 1 << 2,  // Draws the text twice
 | ||
|  |   LITextFlags_Wrap = 1 << 3,     // May be runs better with TMS
 | ||
|  |   LITextFlags_Short = 1 << 4,    // May be runs better with TMS
 | ||
|  |   LITextFlags_Scroll = 1 << 5,   // Not implemented
 | ||
|  | }; | ||
|  | 
 | ||
|  | namespace PD { | ||
|  | namespace LI { | ||
|  | /// @brief Container that holds top and bottom corners of a quad
 | ||
|  | class Rect { | ||
|  |  public: | ||
|  |   Rect() = default; | ||
|  |   Rect(vec4 t, vec4 b) { | ||
|  |     top = t; | ||
|  |     bot = b; | ||
|  |   } | ||
|  |   Rect(vec2 tl, vec2 tr, vec2 bl, vec2 br) { | ||
|  |     top = vec4(tl, tr); | ||
|  |     bot = vec4(bl, br); | ||
|  |   } | ||
|  |   ~Rect() = default; | ||
|  | 
 | ||
|  |   vec4 Top() const { return top; } | ||
|  |   vec4 Bot() const { return bot; } | ||
|  | 
 | ||
|  |   vec2 TopLeft() const { return vec2(top[0], top[1]); } | ||
|  |   vec2 TopRight() const { return vec2(top[2], top[3]); } | ||
|  |   vec2 BotLeft() const { return vec2(bot[0], bot[1]); } | ||
|  |   vec2 BotRight() const { return vec2(bot[2], bot[3]); } | ||
|  | 
 | ||
|  |  private: | ||
|  |   vec4 top; | ||
|  |   vec4 bot; | ||
|  | }; | ||
|  | class Font : public SmartCtor<Font> { | ||
|  |  public: | ||
|  |   class Codepoint { | ||
|  |    public: | ||
|  |     Codepoint() {} | ||
|  |     ~Codepoint() {} | ||
|  | 
 | ||
|  |     u32 cp() const { return m_cp; } | ||
|  |     Codepoint& cp(u32 v) { | ||
|  |       m_cp = v; | ||
|  |       return *this; | ||
|  |     } | ||
|  |     vec4 uv() const { return m_uv; } | ||
|  |     Codepoint& uv(vec4 v) { | ||
|  |       m_uv = v; | ||
|  |       return *this; | ||
|  |     } | ||
|  |     Texture::Ref tex() const { return m_tex; } | ||
|  |     Codepoint& tex(Texture::Ref v) { | ||
|  |       m_tex = v; | ||
|  |       return *this; | ||
|  |     } | ||
|  |     vec2 size() const { return m_size; } | ||
|  |     Codepoint& size(vec2 v) { | ||
|  |       m_size = v; | ||
|  |       return *this; | ||
|  |     } | ||
|  |     float off() const { return m_off; } | ||
|  |     Codepoint& off(float v) { | ||
|  |       m_off = v; | ||
|  |       return *this; | ||
|  |     } | ||
|  |     bool invalid() const { return m_invalid; } | ||
|  |     Codepoint& invalid(bool v) { | ||
|  |       m_invalid = v; | ||
|  |       return *this; | ||
|  |     } | ||
|  | 
 | ||
|  |    private: | ||
|  |     u32 m_cp = 0; | ||
|  |     vec4 m_uv; | ||
|  |     Texture::Ref m_tex = nullptr; | ||
|  |     vec2 m_size; | ||
|  |     float m_off = 0; | ||
|  |     bool m_invalid = false; | ||
|  |   }; | ||
|  |   Font() {} | ||
|  |   ~Font() {} | ||
|  |   void LoadTTF(const std::string& path, int px_height = 32); | ||
|  |   void LoadSystemFont(); | ||
|  |   int PixelHeight() const { return pixel_height; } | ||
|  |   Codepoint& GetCodepoint(u32 c); | ||
|  |   bool SystemFont() const { return sysfont; } | ||
|  | 
 | ||
|  |  private: | ||
|  |   bool sysfont; | ||
|  |   int pixel_height; | ||
|  |   std::vector<Texture::Ref> textures; | ||
|  |   std::map<u32, Codepoint> cpmap; | ||
|  | }; | ||
|  | class Vertex { | ||
|  |  public: | ||
|  |   Vertex() {} | ||
|  |   Vertex(vec2 p, vec2 u, u32 c) { | ||
|  |     pos[0] = p[0]; | ||
|  |     pos[1] = p[1]; | ||
|  |     pos[2] = 0.f; | ||
|  |     uv = u; | ||
|  |     color = c; | ||
|  |   } | ||
|  |   ~Vertex() {} | ||
|  | 
 | ||
|  |   Vertex& Pos(vec3 v) { | ||
|  |     pos = v; | ||
|  |     return *this; | ||
|  |   } | ||
|  |   // Lets support that as well
 | ||
|  |   Vertex& Pos(vec2 v) { | ||
|  |     pos[0] = v[0]; | ||
|  |     pos[1] = v[1]; | ||
|  |     pos[2] = 0.f; | ||
|  |     return *this; | ||
|  |   } | ||
|  |   Vertex& Uv(vec2 v) { | ||
|  |     uv = v; | ||
|  |     return *this; | ||
|  |   } | ||
|  |   Vertex& Color(u32 v) { | ||
|  |     color = v; | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   // private:
 | ||
|  |   vec3 pos; | ||
|  |   vec2 uv; | ||
|  |   u32 color; | ||
|  | }; | ||
|  | /// @brief Required to Set the TexENV
 | ||
|  | enum RenderMode { | ||
|  |   RenderMode_RGBA, | ||
|  |   RenderMode_SysFont, | ||
|  | }; | ||
|  | /// @brief Reform the Drawcommand by generating the Vertexbuffer into it
 | ||
|  | class Command : public SmartCtor<Command> { | ||
|  |  public: | ||
|  |   Command() {} | ||
|  |   ~Command() {} | ||
|  | 
 | ||
|  |   Command& Layer(int v) { | ||
|  |     layer = v; | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   int Layer() const { return layer; } | ||
|  | 
 | ||
|  |   Command& Index(int v) { | ||
|  |     index = v; | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   int Index() const { return index; } | ||
|  | 
 | ||
|  |   Command& Tex(Texture::Ref v) { | ||
|  |     tex = v; | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   Texture::Ref Tex() const { return tex; } | ||
|  | 
 | ||
|  |   Command& PushVertex(Vertex v) { | ||
|  |     vertex_buf.push_back(v); | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   const std::vector<u16>& IndexList() const { return index_buf; } | ||
|  |   const std::vector<Vertex>& VertexList() const { return vertex_buf; } | ||
|  | 
 | ||
|  |   Command& PushIndex(u16 v) { | ||
|  |     index_buf.push_back(vertex_buf.size() + v); | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   Command& Rendermode(const RenderMode& v) { | ||
|  |     mode = v; | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   RenderMode Rendermode() const { return mode; } | ||
|  | 
 | ||
|  |  private: | ||
|  |   /// Using Default std::vector here
 | ||
|  |   std::vector<Vertex> vertex_buf; | ||
|  |   std::vector<u16> index_buf; | ||
|  |   int layer; | ||
|  |   Texture::Ref tex; | ||
|  |   int index; | ||
|  |   RenderMode mode = RenderMode_RGBA; | ||
|  | }; | ||
|  | class TextBox { | ||
|  |  public: | ||
|  |   TextBox() {} | ||
|  |   TextBox(const vec2& s, float time) { | ||
|  |     size = s; | ||
|  |     time_created = time; | ||
|  |     optional = false; | ||
|  |   } | ||
|  |   ~TextBox() {} | ||
|  | 
 | ||
|  |   void TimeCreated(float v) { time_created = v; } | ||
|  |   void Size(const vec2& v) { size = v; } | ||
|  |   void Optional(bool v) { optional = v; } | ||
|  |   void Text(const std::string& v) { text = v; } | ||
|  | 
 | ||
|  |   vec2 Size() const { return size; } | ||
|  |   float TimeCreated() const { return time_created; } | ||
|  |   bool Optional() const { return optional; } | ||
|  |   std::string Text() const { return text; } | ||
|  | 
 | ||
|  |  private: | ||
|  |   vec2 size; | ||
|  |   float time_created; | ||
|  |   bool optional; | ||
|  |   std::string text;  // TextWrap
 | ||
|  | }; | ||
|  | using RenderFlags = u32; | ||
|  | enum RenderFlags_ { | ||
|  |   RenderFlags_None = 0, | ||
|  |   RenderFlags_TMS = 1 << 0,  ///< Text Map System
 | ||
|  |   RenderFlags_LRS = 1 << 1,  ///< Layer Render System
 | ||
|  |   RenderFlags_Default = RenderFlags_TMS, | ||
|  | }; | ||
|  | class Renderer : public SmartCtor<Renderer> { | ||
|  |  public: | ||
|  |   Renderer(RenderFlags flags = RenderFlags_Default); | ||
|  |   ~Renderer(); | ||
|  | 
 | ||
|  |   void Render(); | ||
|  | 
 | ||
|  |   void OnScreen(Screen::Screen_ screen) { | ||
|  |     if (screen == Screen::Top) { | ||
|  |       bottom = false; | ||
|  |       area_size = top->GetSize(); | ||
|  |     } else if (screen == Screen::Bottom) { | ||
|  |       bottom = true; | ||
|  |       area_size = bot->GetSize(); | ||
|  |     } else { | ||
|  |       return; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   void OnScreen(bool bottom) { | ||
|  |     bottom = bottom; | ||
|  |     area_size = bottom ? bot->GetSize() : top->GetSize(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void Rotation(float v) { rot = v; } | ||
|  |   float Rotation() const { return rot; } | ||
|  |   void TextScale(float v) { text_size = v; } | ||
|  |   void DefaultTextScale() { text_size = default_text_size; } | ||
|  |   float TextScale() const { return text_size; } | ||
|  | 
 | ||
|  |   void UseTex(Texture::Ref v = nullptr) { | ||
|  |     if (v == nullptr) { | ||
|  |       current_tex = white; | ||
|  |       return; | ||
|  |     } | ||
|  |     current_tex = v; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// @brief Draws a Rect based on current Texture
 | ||
|  |   /// @param pos Pos
 | ||
|  |   /// @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)); | ||
|  |   /// @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); | ||
|  |   /// @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); | ||
|  |   /// @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); | ||
|  |   /// @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()); | ||
|  |   /// @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)); | ||
|  | 
 | ||
|  |   /// Debug STUFF
 | ||
|  |   u32 Vertices() const { return vertices; } | ||
|  |   u32 Indices() const { return indices; } | ||
|  |   u32 Commands() const { return commands; } | ||
|  |   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<Command::Ref>& 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); } | ||
|  |   /// @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); | ||
|  |   /// @brief Create a Default Triangle
 | ||
|  |   void TriangleCommand(Command::Ref cmd, vec2 a, vec2 b, vec2 c, u32 col); | ||
|  |   /// @brief Create List of a Text Commands
 | ||
|  |   /// @param cmds Link to a command List
 | ||
|  |   /// @param pos Position
 | ||
|  |   /// @param color Color
 | ||
|  |   /// @param text Text
 | ||
|  |   /// @param flags Flags
 | ||
|  |   /// @param box (Size for wrapping / Offset for Centered Text)
 | ||
|  |   /// @note Funktion macht noch faxxen (Text nicht sichtbar)
 | ||
|  |   void TextCommand(std::vector<Command::Ref>& cmds, vec2 pos, u32 color, | ||
|  |                    const std::string& text, LITextFlags flags, vec2 box); | ||
|  |   vec2 GetTextDimensions(const std::string& text); | ||
|  | 
 | ||
|  |  private: | ||
|  |   /// Helper Funcitons ///
 | ||
|  |   void RenderOn(bool bottom); | ||
|  |   void UpdateRenderMode(const RenderMode& mode); | ||
|  | 
 | ||
|  |   /// @brief  Screens ///
 | ||
|  |   Screen::Ref top; | ||
|  |   Screen::Ref bot; | ||
|  | 
 | ||
|  |   /// Context Related ///
 | ||
|  |   RenderFlags flags = RenderFlags_Default; | ||
|  |   vec2 area_size; | ||
|  |   bool bottom = false; | ||
|  |   int current_layer = 0; | ||
|  |   Texture::Ref current_tex = nullptr; | ||
|  |   Texture::Ref white = nullptr;  // Single color
 | ||
|  |   Font::Ref font = nullptr; | ||
|  |   bool font_update; | ||
|  |   RenderMode mode = RenderMode_RGBA; | ||
|  |   // Text Map System
 | ||
|  |   std::map<std::string, TextBox> tms; | ||
|  |   /// Text Rendering ///
 | ||
|  |   const float default_font_h = 24.f; | ||
|  |   const float default_text_size = 0.7f; | ||
|  |   float text_size = 0.7f; | ||
|  |   /// Special ///
 | ||
|  |   float rot = 0.f; | ||
|  |   /// Rendering ///
 | ||
|  |   // Use dual drawlist
 | ||
|  |   std::vector<Command::Ref> draw_list[2]; | ||
|  |   std::vector<Vertex, LinearAllocator<Vertex>> vertex_buf; | ||
|  |   std::vector<u16, LinearAllocator<u16>> index_buf; | ||
|  |   u32 vertex_idx = 0; | ||
|  |   u32 index_idx = 0; | ||
|  |   u32 cmd_idx = 0; | ||
|  | 
 | ||
|  |   /// Debug ///
 | ||
|  |   u32 vertices = 0; | ||
|  |   u32 indices = 0; | ||
|  |   u32 commands = 0; | ||
|  |   u32 drawcalls = 0; | ||
|  | 
 | ||
|  |   /// Shader
 | ||
|  |   DVLB_s* dvlb = nullptr; | ||
|  |   shaderProgram_s shader; | ||
|  |   C3D_AttrInfo attr; | ||
|  |   int uLoc_projection = 0; | ||
|  | 
 | ||
|  |   /// Matrix
 | ||
|  |   C3D_Mtx top_proj; | ||
|  |   C3D_Mtx bot_proj; | ||
|  | }; | ||
|  | }  // namespace LI
 | ||
|  | }  // namespace PD
 |