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
|