# Stage 1.7

- Added File to Memory and FastHashMomory
- Add Protection that only one app can exist
- Add a Trace exist Variable as GetTraceRef automatically creates a trace
- Outsource the LI::Rect to its own header
- Add a CurrentScreen func
- Use Rect for uv (to manually set all corners)
- Rect still supports to use vec4 for uv
- Add tex3ds Spritesheet support
- Add T3X Loader to Texture (if single tex)
- Integrate an autounload into Texture as in case of spritesheet the Tex needs to be unloaded manually
- Safe some performance in texture loading by combining the Loops (best thing ive ever found)
- Use the Momory Hash to only render one error icon into the TTF Texture
- Also Try loading the whole 16-Bit range
- Use GPU_A8 format for TTF rendering to save 24Bits per pixel and use the same Rendermode as System Font
- Simplify Quad Command by using modern vec api
- Integrate Text aligning
- Fix FPS displayed twice in Performance overlay
- UI7 DrawList now has its own AST system
  - TODO: do the same layering for the objects as Text uses
- Map Drawcommands with a bool that declares either bottom or top screen was active
- Add first basic Manu functions
- Fix Typos in Theme
- Add a basic UI7 Context Handler

## Extra
- Added JetBrainsMono font in Test app
## Bugs:
- Performance Overlay Freezes 3ds hardware and crashes Citra with Vulkan when System Font is used
- UI7 Menu scrolling is as scruffed as back in RenderD7 0.9.5
This commit is contained in:
tobid7 2025-01-29 03:14:29 +01:00
parent d55f485b8d
commit 2914f2c8e5
33 changed files with 1198 additions and 211 deletions

View File

@ -32,6 +32,7 @@ set(SRC_FILES
source/common/sys.cpp
source/common/lang.cpp
source/common/error.cpp
source/common/io.cpp
# Controls
source/controls/hid.cpp
# Maths
@ -40,6 +41,7 @@ set(SRC_FILES
source/maths/img_convert.cpp
# Graphics
source/graphics/texture.cpp
source/graphics/spritesheet.cpp
source/graphics/li7_shader.cpp
source/graphics/lithium.cpp
# Overlays
@ -51,6 +53,7 @@ set(SRC_FILES
source/tools/gamepad_icons.cpp
# UI7
source/ui7/drawlist.cpp
source/ui7/menu.cpp
source/ui7/theme.cpp
source/ui7/ui7.cpp
# External

View File

@ -32,6 +32,7 @@ SOFTWARE.
#include <pd/common/timetrace.hpp>
// Graphics
#include <pd/graphics/lithium.hpp>
#include <pd/graphics/spritesheet.hpp>
#include <pd/graphics/texture.hpp>
// Maths
#include <pd/maths/bit_util.hpp>
@ -46,4 +47,11 @@ SOFTWARE.
// UI7
#include <pd/ui7/ui7.hpp>
/// Setup these as non Namespaced access by default
#ifndef PD_MATH_NAMESPACED
using vec2 = PD::vec2;
using vec3 = PD::vec3;
using vec4 = PD::vec4;
#endif
// namespace Palladium = PD;

View File

@ -32,9 +32,14 @@ SOFTWARE.
namespace PD {
/// @brief Template Class for User Application
class App : public SmartCtor<App> {
class App {
public:
App() = default;
App() {
if (too) {
Error("Only one App can be created at the same time!");
}
too++;
}
~App() = default;
/// @brief Templete function where the user can Init his stuff
@ -50,8 +55,8 @@ class App : public SmartCtor<App> {
/// @brief Function to run the App
/// (int main() {
/// auto app = PD::New<UserApp>();
/// app->Run();
/// UserApp app;
/// app.Run();
/// return 0;
/// })
void Run();
@ -71,5 +76,8 @@ class App : public SmartCtor<App> {
u64 last_time;
float app_time;
float fps;
/// The Only One
static int too;
};
} // namespace PD

10
include/pd/common/io.hpp Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <pd/common/common.hpp>
namespace PD {
namespace IO {
std::vector<u8> LoadFile2Mem(const std::string& path);
u32 HashMemory(const std::vector<u8>& data);
} // namespace IO
} // namespace PD

View File

@ -32,6 +32,7 @@ using TraceMap = std::map<std::string, TT::Res::Ref>;
u64 GetTime();
u64 GetNanoTime();
TT::Res::Ref& GetTraceRef(const std::string& id);
bool TraceExist(const std::string& id);
TraceMap& GetTraceMap();
} // namespace Sys
} // namespace PD

View File

@ -26,6 +26,7 @@ SOFTWARE.
#include <pd/common/common.hpp>
#include <pd/common/memory.hpp>
#include <pd/graphics/rect.hpp>
#include <pd/graphics/screen.hpp>
#include <pd/graphics/texture.hpp>
#include <pd/maths/vec.hpp>
@ -46,32 +47,6 @@ enum LITextFlags_ {
namespace PD {
namespace LI {
/// @brief Container that holds top and bottom corners of a quad
class Rect {
public:
Rect() = default;
Rect(const vec4& t, const vec4& b) {
top = t;
bot = b;
}
Rect(const vec2& tl, const vec2& tr, const vec2& bl, const 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 {
@ -172,7 +147,7 @@ class Vertex {
/// @brief Required to Set the TexENV
enum RenderMode {
RenderMode_RGBA,
RenderMode_SysFont,
RenderMode_Font,
};
/// @brief Reform the Drawcommand by generating the Vertexbuffer into it
class Command : public SmartCtor<Command> {
@ -362,6 +337,7 @@ class Renderer : public SmartCtor<Renderer> {
void SetColor(u32 col);
void SetPos(const vec2& pos);
void SetLayer(int l);
void SetUnused() { used = false; }
bool Used() const { return used; }
@ -397,6 +373,10 @@ class Renderer : public SmartCtor<Renderer> {
area_size = bottom ? bot->GetSize() : top->GetSize();
}
Screen::Screen_ CurrentScreen() const {
return bottom ? Screen::Bottom : Screen::Top;
}
void Rotation(float v) { rot = v; }
float Rotation() const { return rot; }
void TextScale(float v) { text_size = v; }
@ -404,6 +384,7 @@ class Renderer : public SmartCtor<Renderer> {
float TextScale() const { return text_size; }
void Layer(int v) { current_layer = v; }
int Layer() const { return current_layer; }
RenderFlags& GetFlags() { return flags; }
void Font(Font::Ref v) {
font = v;
font_update = true;
@ -424,7 +405,7 @@ class Renderer : public SmartCtor<Renderer> {
/// @param color Color
/// @param uv UV Map
void DrawRect(const vec2& pos, const vec2& size, u32 color,
const vec4& uv = vec4(0.f, 1.f, 1.f, 0.f));
const Rect& 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
@ -488,7 +469,7 @@ class Renderer : public SmartCtor<Renderer> {
/// @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, const vec4& uv, u32 col);
void QuadCommand(Command::Ref cmd, const Rect& quad, const Rect& uv, u32 col);
/// @brief Create a Default Triangle
void TriangleCommand(Command::Ref cmd, const vec2& a, const vec2& b,
const vec2& c, u32 col);

View File

@ -0,0 +1,82 @@
#pragma once
#include <pd/common/common.hpp>
#include <pd/maths/vec.hpp>
namespace PD {
namespace LI {
/// @brief Container that holds top and bottom corners of a quad
class Rect {
public:
Rect() = default;
Rect(const vec4& t, const vec4& b) {
top = t;
bot = b;
}
Rect(const vec2& tl, const vec2& tr, const vec2& bl, const vec2& br) {
top = vec4(tl, tr);
bot = vec4(bl, br);
}
/// This Constructor Fixes the issue of rewriting some Stuff in the Text
/// Renderer
Rect(const vec4& uv) {
top = vec4(uv.x(), uv.y(), uv.z(), uv.y());
bot = vec4(uv.x(), uv.w(), uv.z(), uv.w());
}
~Rect() = default;
vec4 Top() const { return top; }
vec4 Bot() const { return bot; }
Rect& Top(const vec4& v) {
top = v;
return *this;
}
Rect& Bot(const vec4& v) {
bot = v;
return *this;
}
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]); }
Rect& TopLeft(const vec2& v) {
top[0] = v[0];
top[1] = v[1];
return *this;
}
Rect& TopRight(const vec2& v) {
top[2] = v[0];
top[3] = v[1];
return *this;
}
Rect& BotLeft(const vec2& v) {
bot[0] = v[0];
bot[1] = v[1];
return *this;
}
Rect& BotRight(const vec2& v) {
bot[2] = v[0];
bot[3] = v[1];
return *this;
}
void SwapVec2XY() {
for (int i = 0; i < 4; i += 2) {
float t = top[i];
top[i] = top[i + 1];
top[i + 1] = t;
t = bot[i];
bot[i] = bot[i + 1];
bot[i + 1] = t;
}
}
private:
vec4 top;
vec4 bot;
};
} // namespace LI
} // namespace PD

View File

@ -0,0 +1,26 @@
#pragma once
#include <citro3d.h>
#include <tex3ds.h>
#include <pd/common/common.hpp>
#include <pd/graphics/lithium.hpp>
#include <pd/graphics/texture.hpp>
namespace PD {
class SpriteSheet {
public:
SpriteSheet() {}
SpriteSheet(const std::string& path) { this->LoadFile(path); }
~SpriteSheet();
void LoadFile(const std::string& path);
Texture::Ref Get(int idx);
int NumTextures() const;
Texture::Ref operator[](int idx) { return Get(idx); }
private:
std::vector<Texture::Ref> textures;
};
} // namespace PD

View File

@ -27,6 +27,7 @@ SOFTWARE.
#include <citro3d.h>
#include <pd/common/common.hpp>
#include <pd/graphics/rect.hpp>
#include <pd/maths/vec.hpp>
namespace PD {
@ -46,8 +47,12 @@ class Texture : public SmartCtor<Texture> {
Texture() : uv(0.f, 1.f, 1.f, 0.f) {}
/// @brief Load file Constructor
/// @param path path to file
Texture(const std::string& path) : uv(0.f, 1.f, 1.f, 0.f) {
this->LoadFile(path);
Texture(const std::string& path, bool t3x = false) : uv(0.f, 1.f, 1.f, 0.f) {
if (t3x) {
this->LoadT3X(path);
} else {
this->LoadFile(path);
}
}
/// @brief Load Memory constructor
/// @param data File Data reference
@ -66,7 +71,11 @@ class Texture : public SmartCtor<Texture> {
this->LoadPixels(data, w, h, type, filter);
}
/// @brief Deconstructor (aka auto delete)
~Texture() { Delete(); }
~Texture() {
if (autounload) {
Delete();
}
}
/// @brief Deletes image (if not already unloaded)
void Delete();
@ -86,11 +95,17 @@ class Texture : public SmartCtor<Texture> {
void LoadPixels(const std::vector<u8>& data, int w, int h, Type type = RGBA32,
Filter filter = NEAREST);
/// @brief Load a texture of a T3X File
/// @note This is used for single texture T3X
/// Not for SpriteSheets
/// @param path path to .t3x file
void LoadT3X(const std::string& path);
/// @brief Input a Texture that you had set up on your own
/// @param tex Texture reference (deletes itself)
/// @param rszs The size of the source image
/// @param uvs Your uv Setup
void LoadExternal(C3D_Tex* tex, vec2 rszs, vec4 uvs) {
void LoadExternal(C3D_Tex* tex, vec2 rszs, LI::Rect uvs) {
this->Delete();
this->tex = tex;
this->size = rszs;
@ -105,19 +120,23 @@ class Texture : public SmartCtor<Texture> {
}
vec2 GetSize() const { return size; }
C3D_Tex* GetTex() const { return tex; };
vec4 GetUV() const { return uv; }
LI::Rect GetUV() const { return uv; }
bool IsValid() const { return tex != 0; }
bool AutoUnLoad() const { return autounload; }
void AutoUnLoad(bool v) { autounload = v; }
operator C3D_Tex*() const { return tex; }
operator vec2() const { return size; }
operator vec4() const { return uv; }
operator LI::Rect() const { return uv; }
operator bool() const { return tex != 0; }
private:
void MakeTex(std::vector<u8>& buf, int w, int h, Type type = RGBA32,
Filter filter = NEAREST);
vec2 size;
vec4 uv;
LI::Rect uv;
C3D_Tex* tex = nullptr;
bool autounload = true;
};
} // namespace PD

View File

@ -21,16 +21,16 @@ class MessageMgr : public PD::SmartCtor<MessageMgr> {
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<vec2> 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
PD::Color col_bg; // Background Color
PD::Color col_text; // Text Color
float lifetime = 0.f; // LifeTime
PD::Tween<vec2> 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() {}

View File

@ -38,7 +38,7 @@ class DrawList : public SmartCtor<DrawList> {
void AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, const UI7Color& clr);
void AddText(vec2 pos, const std::string& text, const UI7Color& clr,
LITextFlags flags = 0, vec2 box = vec2());
void AddImage(vec2 pos, Texture::Ref img);
void AddImage(vec2 pos, Texture::Ref img, vec2 size = 0.f);
void Clear();
void Process();
@ -47,9 +47,22 @@ class DrawList : public SmartCtor<DrawList> {
void Layer(int v) { layer = v; }
private:
/// @brief Base Layer offset (Internal Used)
int BaseLayer() const { return base; }
/// @brief Base Layer offset (Internal Used)
void BaseLayer(int v) { base = v; }
/// @brief Exopose Renderer here for Menus [DONT KNOW IF THIUS GETS REMOVED]
LI::Renderer::Ref GetRenderer() { return ren; }
friend class Menu;
friend class Context;
int layer;
int base;
LI::Renderer::Ref ren;
std::vector<LI::Command::Ref> commands;
std::unordered_map<u32, LI::Renderer::StaticText::Ref> static_text;
std::vector<std::pair<bool, LI::Command::Ref>> commands;
};
} // namespace UI7
} // namespace PD

View File

@ -7,13 +7,23 @@ namespace PD {
namespace UI7 {
class ID {
public:
ID(const std::string& text) { id = PD::Strings::FastHash(text); }
ID(const std::string& text) {
id = PD::Strings::FastHash(text);
name = text;
}
ID(const char* text) {
id = PD::Strings::FastHash(text);
name = text;
}
~ID() {}
std::string GetName() const { return name; }
operator u32() const { return id; }
private:
u32 id;
std::string name;
};
} // namespace UI7
} // namespace PD

View File

@ -23,14 +23,20 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/controls/hid.hpp>
#include <pd/ui7/drawlist.hpp>
#include <pd/ui7/flags.hpp>
#include <pd/ui7/id.hpp>
namespace PD {
namespace UI7 {
class Menu : public SmartCtor<Menu> {
public:
Menu(u32 id) {
Menu(ID id, Theme* tl, Hid::Ref h) {
linked_theme = tl;
this->inp = h;
this->id = id;
this->name = id.GetName();
scrolling[0] = false;
scrolling[1] = false;
scrollbar[0] = false;
@ -38,10 +44,75 @@ class Menu : public SmartCtor<Menu> {
scroll_allowed[0] = false;
scroll_allowed[1] = false;
};
~Menu() {};
~Menu() {}
/// Objects
void Label(const std::string& label);
bool Button(const std::string& label);
void Checkbox(const std::string& label, bool& v);
void Image(Texture::Ref img, vec2 size = 0.f);
/// Basic API
void SameLine();
void Separator();
void SeparatorText(const std::string& label);
/// API for Custom Objects
bool HandleScrolling(vec2& pos, const vec2& size);
vec2 Cursor() const { return cursor; }
void Cursor(const vec2& v) {
bcursor = cursor;
cursor = v;
}
void RestoreCursor() {
cursor = bcursor;
bcursor = vec2();
}
/// Draw Lists
DrawList::Ref BackList() { return back; }
void BackList(DrawList::Ref v) { back = v; }
DrawList::Ref MainList() { return main; }
void MainList(DrawList::Ref v) { main = v; }
DrawList::Ref FrontList() { return front; }
void FrontList(DrawList::Ref v) { front = v; }
/// Advanced
void DebugLabels();
/// Uneditable Stuff
std::string GetName() const { return name; }
u32 GetID() const { return id; }
private:
/// Advanced Handlers
void PreHandler(UI7MenuFlags flags);
void PostHandler();
/// Basic Settings
vec2 BackupCursor() const { return bcursor; }
void BackupCursor(const vec2& v) { bcursor = v; }
vec2 SameLineCursor() const { return slcursor; }
void SameLineCursor(const vec2& v) { slcursor = v; }
vec4 ViewArea() const { return view_area; }
void ViewArea(const vec4& v) { view_area = v; }
vec2 ScrollOffset() const { return scrolling_off; }
void ScrollOffset(const vec2& v) { scrolling_off = v; }
vec2 ScrollMod() const { return scroll_mod; }
void ScrollMod(const vec2& v) { scroll_mod = v; }
/// Advanced
void CursorMove(const vec2& szs);
/// Internal Processing
void Update(float delta);
/// This ability is crazy useful
friend class Context;
/// Data
UI7MenuFlags flags = 0;
u32 id;
std::string name;
vec2 cursor;
vec2 bcursor;
vec2 slcursor;
@ -65,6 +136,12 @@ class Menu : public SmartCtor<Menu> {
vec2 mouse;
vec2 bslpos;
vec2 last_size;
// Theme
Theme* linked_theme;
// Input Reference
Hid::Ref inp;
};
} // namespace UI7
} // namespace PD

View File

@ -32,14 +32,14 @@ enum UI7Color_ {
UI7Color_Button,
UI7Color_ButtonDead,
UI7Color_ButtonActive,
UI7Color_ButtonDisabled,
UI7Color_ButtonHovered,
UI7Color_Text,
UI7Color_TextDead,
UI7Color_Header,
UI7Color_Selector,
UI7Color_Checkmark,
UI7Color_FrameBackground,
UI7Color_FragmeBackgroundHovered,
UI7Color_FrameBackgroundHovered,
UI7Color_Progressbar,
UI7Color_ListEven,
UI7Color_ListOdd,
@ -115,20 +115,4 @@ class Theme {
std::vector<std::pair<UI7Color, u32>> 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 {
public:
UI7Color() {
/// No Color
}
UI7Color(unsigned int c) { color = c; }
UI7Color(UI7Color_ c) {}
~UI7Color() {}
operator u32() const { return color; }
private:
u32 color;
};
} // namespace PD

View File

@ -23,23 +23,45 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/controls/hid.hpp> //// WOW A NON UI/ Header
#include <pd/ui7/drawlist.hpp>
#include <pd/ui7/flags.hpp>
#include <pd/ui7/id.hpp>
#include <pd/ui7/menu.hpp>
#include <pd/ui7/theme.hpp>
#include <unordered_map>
namespace PD {
namespace UI7 {
class Context : public SmartCtor<Context> {
public:
Context() {}
Context(LI::Renderer::Ref ren, Hid::Ref hid) {
this->ren = ren;
this->inp = hid;
Theme::Default(theme);
back = DrawList::New(ren);
front = DrawList::New(ren);
}
~Context() {}
bool BeginMenu(const ID& id, UI7MenuFlags flags = 0);
Menu::Ref GetCurrentMenu();
void EndMenu();
/// Theme Management
Theme& GetTheme() { return theme; }
/// @brief Update Context (Render menus)
/// @param delta deltatime
void Update(float delta);
/// Expose DrawLists
DrawList::Ref BackList() { return back; }
DrawList::Ref FrontList() { return front; }
private:
// Linked Renderer / Hid
LI::Renderer::Ref ren;
Hid::Ref inp;
// Timing
float delta;
float time;
@ -50,11 +72,14 @@ class Context : public SmartCtor<Context> {
bool debugging;
// Menu Handlers
std::unordered_map<u32, Menu::Ref> menus;
std::vector<u32> amenus; // Active ones
Menu::Ref current;
// Context DrawList
DrawList::Ref debug;
DrawList::Ref front;
DrawList::Ref back;
// Theme
Theme theme;
// Promt Handler
};
} // namespace UI7

View File

@ -28,6 +28,8 @@ SOFTWARE.
#include <pd/common/sys.hpp>
namespace PD {
int App::too;
void App::Run() {
this->PreInit();
this->Init();
@ -45,7 +47,10 @@ void App::Run() {
}
PD::TT::End("App_MainLoop");
PD::TT::Beg("Ovl_Update");
renderer->Layer(90);
overlay_mgr->Update(dt);
/// Messages have their own special Layer
renderer->Layer(93);
msg_mgr->Update(dt);
PD::TT::End("Ovl_Update");
renderer->Render();

26
source/common/io.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <pd/common/io.hpp>
namespace PD {
namespace IO {
std::vector<u8> LoadFile2Mem(const std::string& path) {
std::ifstream iff(path, std::ios::binary);
if (!iff) {
return std::vector<u8>();
}
iff.seekg(0, std::ios::end);
size_t szs = iff.tellg();
iff.seekg(0, std::ios::beg);
std::vector<u8> res(szs, 0);
iff.read(reinterpret_cast<char*>(res.data()), res.size());
iff.close();
return res;
}
u32 HashMemory(const std::vector<u8>& data) {
u32 hash = 4477;
for (auto& it : data) {
hash = (hash * 33) + it;
}
return hash;
}
} // namespace IO
} // namespace PD

View File

@ -44,5 +44,8 @@ TT::Res::Ref& GetTraceRef(const std::string& id) {
}
return pd_sys_tm[id];
}
bool TraceExist(const std::string& id) {
return pd_sys_tm.find(id) != pd_sys_tm.end();
}
TraceMap& GetTraceMap() { return pd_sys_tm; }
} // namespace PD::Sys

View File

@ -23,6 +23,7 @@ SOFTWARE.
#include <pd/external/stb_truetype.h>
#include <pd/common/io.hpp>
#include <pd/common/strings.hpp>
#include <pd/common/sys.hpp>
#include <pd/graphics/li7_shader.hpp>
@ -45,31 +46,44 @@ void Font::LoadTTF(const std::string& path, int height) {
loader.read(reinterpret_cast<char*>(buffer), len);
loader.close();
stbtt_InitFont(&inf, buffer, 0);
std::vector<unsigned char> font_tex(quad * quad * 4);
std::vector<unsigned char> font_tex(quad * quad);
float scale = stbtt_ScaleForPixelHeight(&inf, pixel_height);
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap);
int baseline = static_cast<int>(ascent * scale);
std::map<u32, int> buf_cache;
auto tex = Texture::New();
vec2 off;
for (int i = 0; i < 255; i++) {
Codepoint c;
for (u32 ii = 0x0000; ii < 0xFFFF; ii++) {
int i = stbtt_FindGlyphIndex(&inf, ii);
if (i == 0) {
continue;
}
if (stbtt_IsGlyphEmpty(&inf, i)) {
c.cp(i);
c.tex(tex);
c.invalid(true);
cpmap[i] = c;
continue;
}
Codepoint c;
int w = 0, h = 0, xo = 0, yo = 0;
unsigned char* bitmap =
stbtt_GetCodepointBitmap(&inf, scale, scale, i, &w, &h, &xo, &yo);
int x0, y0, x1, y1;
stbtt_GetCodepointBitmapBox(&inf, i, scale, scale, &x0, &y0, &x1, &y1);
u32 hashed_map = IO::HashMemory(std::vector<u8>(bitmap, bitmap + (w * h)));
if (buf_cache.find(hashed_map) != buf_cache.end()) {
c = GetCodepoint(buf_cache[hashed_map]);
c.cp(i);
cpmap[i] = c;
free(bitmap);
continue;
} else {
buf_cache[hashed_map] = i;
}
if (off[0] + w > quad) {
off[1] += pixel_height;
off[0] = 0;
@ -88,24 +102,25 @@ void Font::LoadTTF(const std::string& path, int height) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int map_pos = ((off[1] + y) * quad + (off[0] + x)) * 4;
font_tex[map_pos + 0] = 255;
font_tex[map_pos + 1] = 255;
font_tex[map_pos + 2] = 255;
font_tex[map_pos + 3] = bitmap[x + y * w];
int map_pos = ((off[1] + y) * quad + (off[0] + x));
font_tex[map_pos] = bitmap[x + y * w];
}
}
free(bitmap);
cpmap[i] = c;
// Small Patch to avoid some possible artifacts
off[0] += w + 1;
if (off[0] + w > quad) {
off[1] += pixel_height;
if (off[1] + pixel_height > quad) {
break;
}
off[0] = 0;
}
free(bitmap);
cpmap[i] = c;
}
tex->LoadPixels(font_tex, quad, quad, Texture::RGBA32, Texture::LINEAR);
tex->LoadPixels(font_tex, quad, quad, Texture::A8, Texture::LINEAR);
textures.push_back(tex);
}
@ -143,6 +158,7 @@ void Font::LoadSystemFont() {
tx->border = 0xffffffff;
tx->lodParam = 0;
stex->LoadExternal(tx, vec2(tx->width, tx->height), vec4(0, 1, 1, 0));
stex->AutoUnLoad(false);
textures[i] = stex;
}
std::vector<unsigned int> charSet;
@ -192,8 +208,10 @@ void Font::LoadSystemFont() {
codepoint.uv(vec4(dat.texcoord.left, dat.texcoord.top, dat.texcoord.right,
dat.texcoord.bottom));
if (textures.at(dat.sheetIndex) != nullptr) {
if (dat.sheetIndex < (int)textures.size()) {
codepoint.tex(textures[dat.sheetIndex]);
} else {
codepoint.invalid(true);
}
codepoint.size(vec2(dat.vtxcoord.right, dat.vtxcoord.bottom));
codepoint.off(0);
@ -250,7 +268,9 @@ void Renderer::StaticText::Setup(Renderer* ren, const vec2& pos, u32 clr,
this->pos = pos;
this->ren = ren;
this->text = StaticObject::New();
ren->TextCommand(this->text->List(), pos, clr, text, flags, box);
/// Ensure that it also renders Out of Screen i guess
ren->TextCommand(this->text->List(), pos, clr, text,
flags | LITextFlags_RenderOOS, box);
OptiCommandList(this->text->List());
}
@ -267,6 +287,8 @@ void Renderer::StaticText::SetPos(const vec2& pos) {
text->MoveIt(pos - this->pos);
}
void Renderer::StaticText::SetLayer(int layer) { text->ReLayer(layer); }
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]);
@ -341,18 +363,14 @@ 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, const vec4& uv,
void Renderer::QuadCommand(Command::Ref cmd, const Rect& quad, const Rect& uv,
u32 col) {
cmd->PushIndex(0).PushIndex(1).PushIndex(2);
cmd->PushIndex(0).PushIndex(2).PushIndex(3);
cmd->PushVertex(
Vertex(vec2(quad.Bot().z(), quad.Bot().w()), vec2(uv.z(), uv.w()), col));
cmd->PushVertex(
Vertex(vec2(quad.Top().z(), quad.Top().w()), vec2(uv.z(), uv.y()), col));
cmd->PushVertex(
Vertex(vec2(quad.Top().x(), quad.Top().y()), vec2(uv.x(), uv.y()), col));
cmd->PushVertex(
Vertex(vec2(quad.Bot().x(), quad.Bot().y()), vec2(uv.x(), uv.w()), col));
cmd->PushVertex(Vertex(quad.BotRight(), uv.BotRight(), col));
cmd->PushVertex(Vertex(quad.TopRight(), uv.TopRight(), col));
cmd->PushVertex(Vertex(quad.TopLeft(), uv.TopLeft(), col));
cmd->PushVertex(Vertex(quad.BotLeft(), uv.BotLeft(), col));
}
void Renderer::TriangleCommand(Command::Ref cmd, const vec2& a, const vec2& b,
@ -364,7 +382,6 @@ void Renderer::TriangleCommand(Command::Ref cmd, const vec2& a, const vec2& b,
cmd->PushVertex(Vertex(c, vec2(1.f, 0.f), col));
}
/// TO BE REWRITTEN
void Renderer::TextCommand(std::vector<Command::Ref>& cmds, const vec2& pos,
u32 color, const std::string& text,
LITextFlags flags, const vec2& box) {
@ -375,6 +392,23 @@ void Renderer::TextCommand(std::vector<Command::Ref>& cmds, const vec2& pos,
float cfs = (default_font_h * text_size) / (float)font->PixelHeight();
float lh = (float)font->PixelHeight() * cfs;
vec2 td;
vec2 rpos = pos;
vec2 rbox = box;
if (flags & (LITextFlags_AlignMid | LITextFlags_AlignRight)) {
td = GetTextDimensions(text);
if (rbox[0] == 0.f) {
rbox[0] = area_size.x();
}
if (rbox[1] == 0.f) {
rbox[1] = area_size.y();
}
}
if (flags & LITextFlags_AlignMid) {
rpos = rbox * 0.5 - td * 0.5 + pos;
}
if (flags & LITextFlags_AlignRight) {
rpos[0] = rbox[0] - td[0];
}
std::vector<std::string> lines;
std::istringstream iss(text);
@ -384,10 +418,10 @@ void Renderer::TextCommand(std::vector<Command::Ref>& cmds, const vec2& pos,
}
for (auto& it : lines) {
if (pos[1] + off[1] + lh < 0) {
if (rpos[1] + off[1] + lh < 0) {
off[1] += lh;
continue;
} else if (pos[1] + off[1] > GetViewport().w() &&
} else if (rpos[1] + off[1] > GetViewport().w() &&
!(flags & LITextFlags_RenderOOS)) {
// Break cause next lines would be out of screen
break;
@ -396,9 +430,7 @@ void Renderer::TextCommand(std::vector<Command::Ref>& cmds, const vec2& pos,
auto cmd = Command::New();
current_tex = font->GetCodepoint(wline[0]).tex();
SetupCommand(cmd);
if (font->SystemFont()) {
cmd->Rendermode(RenderMode_SysFont);
}
cmd->Rendermode(RenderMode_Font);
for (auto& jt : wline) {
auto cp = font->GetCodepoint(jt);
if (cp.invalid() && jt != '\n' && jt != '\t') {
@ -409,9 +441,7 @@ void Renderer::TextCommand(std::vector<Command::Ref>& cmds, const vec2& pos,
cmd = Command::New();
current_tex = cp.tex();
SetupCommand(cmd);
if (font->SystemFont()) {
cmd->Rendermode(RenderMode_SysFont);
}
cmd->Rendermode(RenderMode_Font);
}
if (jt == '\t') {
off[0] += 16 * cfs;
@ -421,13 +451,13 @@ void Renderer::TextCommand(std::vector<Command::Ref>& cmds, const vec2& pos,
if (flags & LITextFlags_Shaddow) {
// Draw
Rect rec = CreateRect(
pos + vec2(off[0] + 1, off[1] + (cp.off() * cfs)) + 1,
rpos + vec2(off[0] + 1, off[1] + (cp.off() * cfs)) + 1,
cp.size() * cfs, 0.f);
QuadCommand(cmd, rec, cp.uv(), 0xff111111);
current_layer++;
}
// Draw
Rect rec = CreateRect(pos + off + vec2(0, (cp.off() * cfs)),
Rect rec = CreateRect(rpos + off + vec2(0, (cp.off() * cfs)),
cp.size() * cfs, 0.f);
QuadCommand(cmd, rec, cp.uv(), color);
current_layer = lr;
@ -450,7 +480,6 @@ vec4 Renderer::GetViewport() {
return vec4(0, 0, screen[0], screen[1]);
}
/// TO BE REWRITTEN
vec2 Renderer::GetTextDimensions(const std::string& text) {
if (!font) {
// No font no size (oder so)
@ -516,7 +545,8 @@ vec2 Renderer::GetTextDimensions(const std::string& text) {
void Renderer::UpdateRenderMode(const RenderMode& mode) {
C3D_TexEnv* env = C3D_GetTexEnv(0);
switch (mode) {
case RenderMode_SysFont:
case RenderMode_Font:
/// Sets Only Alpha Using the Color and Replase RGB with vertex color
C3D_TexEnvInit(env);
C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
@ -526,6 +556,7 @@ void Renderer::UpdateRenderMode(const RenderMode& mode) {
// Fall trough instead of defining twice
case RenderMode_RGBA:
default:
/// Use Texture for RGBA and vertexcolor for visibility
C3D_TexEnvInit(env);
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0);
C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
@ -536,23 +567,17 @@ void Renderer::UpdateRenderMode(const RenderMode& mode) {
void Renderer::RenderOn(bool bot) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection,
(bot ? &bot_proj : &top_proj));
C3D_DepthTest(false, GPU_GREATER, GPU_WRITE_ALL);
UpdateRenderMode(RenderMode_RGBA);
int total_vertices = 0;
int total_indices = 0;
drawcalls = 0;
auto& cmds = draw_list[bot];
commands = cmds.size();
size_t index = 0;
if (flags & RenderFlags_LRS) {
OptiCommandList(cmds);
}
while (index < cmds.size()) {
C3D_Tex* tex = cmds[index]->Tex()->GetTex();
auto mode = cmds[index]->Rendermode();
@ -572,6 +597,7 @@ void Renderer::RenderOn(bool bot) {
}
index++;
}
C3D_TexBind(0, tex);
auto bufInfo = C3D_GetBufInfo();
@ -580,6 +606,7 @@ void Renderer::RenderOn(bool bot) {
C3D_DrawElements(GPU_TRIANGLES, index_idx - start_idx, C3D_UNSIGNED_SHORT,
index_buf.data() + start_idx);
drawcalls++;
total_vertices += vertex_idx - start_vtx;
total_indices += index_idx - start_idx;
@ -629,6 +656,8 @@ void Renderer::Render() {
if (Sys::GetTime() - it.second.TimeCreated() > 5) rem.push_back(it.first);
}
for (auto it : rem) tms.erase(it);
} else {
tms.clear();
}
if (flags & RenderFlags_AST) {
std::vector<u32> rem;
@ -641,11 +670,13 @@ void Renderer::Render() {
for (auto& it : rem) {
ast.erase(it);
}
} else {
ast.clear();
}
}
void Renderer::DrawRect(const vec2& pos, const vec2& size, u32 color,
const vec4& uv) {
const Rect& uv) {
if (!InBox(pos, size, GetViewport())) {
// Instand abort as it is out of screen
return;
@ -659,7 +690,7 @@ void Renderer::DrawRect(const vec2& pos, const vec2& size, u32 color,
void Renderer::DrawRectSolid(const vec2& pos, const vec2& size, u32 color) {
UseTex();
DrawRect(pos, size, color);
DrawRect(pos, size, color, vec4(0.f, 1.f, 1.f, 0.f));
}
void Renderer::DrawTriangle(const vec2& a, const vec2& b, const vec2& c,

View File

@ -0,0 +1,44 @@
#include <pd/common/io.hpp>
#include <pd/graphics/spritesheet.hpp>
namespace PD {
SpriteSheet::~SpriteSheet() { textures.clear(); }
void SpriteSheet::LoadFile(const std::string& path) {
auto file = IO::LoadFile2Mem(path);
if (file.size() == 0) {
Error("Unable to load file:\n" + path);
}
C3D_Tex* tex = new C3D_Tex;
auto t3x =
Tex3DS_TextureImport(file.data(), file.size(), tex, nullptr, false);
if (!t3x) {
Error("Unable to import:\n" + path);
}
tex->border = 0;
C3D_TexSetWrap(tex, GPU_CLAMP_TO_BORDER, GPU_CLAMP_TO_BORDER);
C3D_TexSetFilter(tex, GPU_LINEAR, GPU_NEAREST);
textures.reserve(Tex3DS_GetNumSubTextures(t3x) + 1);
for (int i = 0; i < (int)Tex3DS_GetNumSubTextures(t3x); i++) {
auto t = Texture::New();
auto st = Tex3DS_GetSubTexture(t3x, i);
LI::Rect uv(vec2(st->left, st->top), vec2(st->right, st->top),
vec2(st->left, st->bottom), vec2(st->right, st->bottom));
if (st->top < st->bottom) {
uv.SwapVec2XY();
}
t->LoadExternal(tex, vec2(st->width, st->height), uv);
textures.push_back(t);
}
}
Texture::Ref SpriteSheet::Get(int idx) {
if (idx >= (int)textures.size()) {
Error("Trying to Access Texture " + std::to_string(idx + 1) + " of " +
std::to_string(NumTextures()));
}
return textures[idx];
}
int SpriteSheet::NumTextures() const { return textures.size(); }
} // namespace PD

View File

@ -24,12 +24,14 @@ SOFTWARE.
#include <3ds.h>
#include <pd/external/stb_image.h>
#include <tex3ds.h>
#include <pd/common/error.hpp>
#include <pd/common/io.hpp>
#include <pd/common/timetrace.hpp>
#include <pd/graphics/texture.hpp>
#include <pd/maths/bit_util.hpp>
#include <pd/maths/img_convert.hpp>
#include <pd/common/error.hpp>
namespace PD {
GPU_TEXCOLOR GetTexFmt(Texture::Type type) {
@ -54,36 +56,6 @@ void Texture::MakeTex(std::vector<u8>& buf, int w, int h, Texture::Type type,
Filter filter) {
// Don't check here as check done before
int bpp = GetBPP(type);
if (bpp == 4) {
// RGBA -> Abgr
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int pos = (x + y * w) * bpp;
auto r = buf[pos + 0];
auto g = buf[pos + 1];
auto b = buf[pos + 2];
auto a = buf[pos + 3];
buf[pos + 0] = a;
buf[pos + 1] = b;
buf[pos + 2] = g;
buf[pos + 3] = r;
}
}
} else if (bpp == 3) {
// RGBA -> Abgr
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int pos = (x + y * w) * bpp;
auto r = buf[pos + 0];
auto g = buf[pos + 1];
auto b = buf[pos + 2];
buf[pos + 0] = b;
buf[pos + 1] = g;
buf[pos + 2] = r;
}
}
}
vec2 tex_size(w, h);
// Pow2
if (!PD::BitUtil::IsSingleBit(w)) {
@ -95,10 +67,8 @@ void Texture::MakeTex(std::vector<u8>& buf, int w, int h, Texture::Type type,
this->size.x() = (u16)w;
this->size.y() = (u16)h;
this->uv.x() = 0.0f;
this->uv.y() = 1.0f;
this->uv.z() = ((float)w / (float)tex_size.x());
this->uv.w() = 1.0 - ((float)h / (float)tex_size.y());
this->uv = vec4(0.f, 1.f, ((float)w / (float)tex_size.x()),
1.0 - ((float)h / (float)tex_size.y()));
// Texture Setup
auto fltr = (filter == NEAREST ? GPU_NEAREST : GPU_LINEAR);
@ -109,7 +79,9 @@ void Texture::MakeTex(std::vector<u8>& buf, int w, int h, Texture::Type type,
memset(tex->data, 0, tex->size);
if (bpp == 3 || bpp == 4) {
/// Probably Remove this if statement in future
/// This are the things confirmed as working
if (bpp == 3 || bpp == 4 || bpp == 1) {
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int dst_pos = ((((y >> 3) * ((int)tex_size.x() >> 3) + (x >> 3)) << 6) +
@ -117,13 +89,13 @@ void Texture::MakeTex(std::vector<u8>& buf, int w, int h, Texture::Type type,
((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))) *
bpp;
int src_pos = (y * w + x) * bpp;
memcpy(&((u8*)tex->data)[dst_pos], &buf[src_pos], bpp);
/// Best idea i had
for (int i = 0; i < bpp; i++) {
((u8*)tex->data)[dst_pos + bpp - 1 - i] = buf[src_pos + i];
}
}
}
C3D_TexFlush(tex);
} else if (bpp == 1) {
C3D_TexLoadImage(tex, buf.data(), GPU_TEXFACE_2D, 0);
}
tex->border = 0x00000000;
@ -200,4 +172,23 @@ void Texture::LoadPixels(const std::vector<u8>& pixels, int w, int h, Type type,
std::vector<u8> cpy(pixels);
MakeTex(cpy, w, h, type, filter);
}
void Texture::LoadT3X(const std::string& path) {
this->Delete();
auto file = IO::LoadFile2Mem(path);
if (file.size() == 0) {
Error("Unable to load file:\n" + path);
}
this->tex = new C3D_Tex;
auto t3x =
Tex3DS_TextureImport(file.data(), file.size(), this->tex, nullptr, false);
if (!t3x) {
Error("Unable to import:\n" + path);
}
auto st = Tex3DS_GetSubTexture(t3x, 0);
this->uv = vec4(st->left, st->top, st->right, st->bottom);
this->size[0] = st->width;
this->size[1] = st->height;
Tex3DS_TextureFree(t3x);
}
} // namespace PD

View File

@ -484,8 +484,6 @@ void Keyboard::Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) {
/// Process Controller Movement
Movement(inp);
/// Declare RenderLayer (10 above the latest)
ren->Layer(ren->Layer() + 10);
/// Update animations
flymgr.Update(delta);
selector.Update(delta);

View File

@ -104,8 +104,6 @@ void MessageMgr::Push(const std::string& title, const std::string& 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

View File

@ -12,8 +12,7 @@ void Performance::Update(float delta, LI::Renderer::Ref ren, Hid::Ref inp) {
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, std::format("{:.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);

View File

@ -21,6 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/common/strings.hpp>
#include <pd/ui7/drawlist.hpp>
namespace PD {
@ -31,11 +32,12 @@ void DrawList::AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr) {
}
auto rect = ren->CreateRect(pos, szs, 0.f);
auto cmd = LI::Command::New();
ren->SetupCommand(cmd);
ren->UseTex();
ren->SetupCommand(cmd);
cmd->Layer(layer);
ren->QuadCommand(cmd, rect, vec4(0.f, 1.f, 1.f, 0.f), clr);
commands.push_back(cmd);
commands.push_back(
std::make_pair(ren->CurrentScreen() == Screen::Bottom, cmd));
}
void DrawList::AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2,
@ -44,41 +46,82 @@ void DrawList::AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2,
return;
}
auto cmd = LI::Command::New();
ren->SetupCommand(cmd);
ren->UseTex();
ren->SetupCommand(cmd);
cmd->Layer(layer);
ren->TriangleCommand(cmd, pos0, pos1, pos2, clr);
commands.push_back(cmd);
commands.push_back(
std::make_pair(ren->CurrentScreen() == Screen::Bottom, cmd));
}
void DrawList::AddText(vec2 pos, const std::string& text, const UI7Color& clr,
LITextFlags flags, vec2 box) {
u32 id = Strings::FastHash(text);
auto e = static_text.find(id);
if (e == static_text.end()) {
static_text[id] = LI::Renderer::StaticText::New();
e = static_text.find(id);
}
if (!e->second->IsSetup()) {
e->second->Setup(&(*ren), pos, clr, text, flags, box);
}
e->second->SetPos(pos);
e->second->SetColor(clr);
e->second->SetLayer(base + layer);
e->second->Draw();
////// STILL LEAVING THE OLD CODE BELOW AS IT IS MAYBE NEEDED //////
////// IF STATIC TEXT SYSTEM SHOULD HAVE AN DISABLE OPTION //////
// 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);
// Oh and Handle Layer management here as well
// int l = ren->Layer();
// ren->Layer(layer);
// std::vector<LI::Command::Ref> cmds;
// ren->TextCommand(cmds, pos, clr, text, flags, box);
// ren->Layer(l);
// for (auto c : cmds) {
// commands.push_back(
// std::make_pair(ren->CurrentScreen() == Screen::Bottom, c));
// }
}
void DrawList::AddImage(vec2 pos, Texture::Ref img) {
if (!ren->InBox(pos, img->GetSize(), ren->GetViewport())) {
void DrawList::AddImage(vec2 pos, Texture::Ref img, vec2 size) {
size = size == 0.f ? img->GetSize() : size;
if (!ren->InBox(pos, size, ren->GetViewport())) {
return;
}
auto rect = ren->CreateRect(pos, img->GetSize(), 0.f);
auto rect = ren->CreateRect(pos, size, 0.f);
auto cmd = LI::Command::New();
ren->SetupCommand(cmd);
ren->UseTex(img);
ren->SetupCommand(cmd);
cmd->Layer(layer);
ren->QuadCommand(cmd, rect, vec4(0.f, 1.f, 1.f, 0.f), 0xffffffff);
commands.push_back(cmd);
ren->QuadCommand(cmd, rect, img->GetUV(), 0xffffffff);
commands.push_back(
std::make_pair(ren->CurrentScreen() == Screen::Bottom, cmd));
}
void DrawList::Clear() { commands.clear(); }
void DrawList::Process() {
// UI7 Commands Use LI7 as default feature
ren->OptiCommandList(commands);
for (auto command : commands) {
ren->PushCommand(command);
command.second->Layer(command.second->Layer() + base);
ren->OnScreen(command.first ? Screen::Bottom : Screen::Top);
ren->PushCommand(command.second);
}
commands.clear();
layer = 0;
std::vector<u32> rem;
for (auto it : static_text) {
if (!it.second->Used()) {
rem.push_back(it.first);
}
it.second->SetUnused();
}
for (auto& it : rem) {
static_text.erase(it);
}
}
} // namespace UI7

331
source/ui7/menu.cpp Normal file
View File

@ -0,0 +1,331 @@
#include <pd/common/sys.hpp>
#include <pd/common/timetrace.hpp>
#include <pd/ui7/menu.hpp>
//////////////////////////////
//////// OBJECT SETUP ////////
////// Setup Variables ///////
///////// Move Cursor ////////
//// Check Scrolling State ///
/////// Handle Controls //////
////////// Render ////////////
//////////////////////////////
namespace PD {
namespace UI7 {
void UI7::Menu::Label(const std::string& label) {
vec2 size = this->back->GetRenderer()->GetTextDimensions(label);
vec2 pos = Cursor();
CursorMove(size - vec2(0, 4)); // Fix to make gap not to large
if (HandleScrolling(pos, size)) {
return;
}
/// To Draw a Label above the head bar you should
/// use the m->GetFrontList() instead
main->AddText(pos, label, linked_theme->Get(UI7Color_Text), 0,
vec2(view_area.z(), 20));
}
bool UI7::Menu::Button(const std::string& label) {
bool ret = false;
auto tszs = this->back->GetRenderer()->GetTextDimensions(label);
vec2 size = tszs + vec2(8, 4);
vec2 pos = Cursor();
UI7Color clr = UI7Color_Button;
CursorMove(size);
/////// SCROLLING HANDLER HERE ////////
if (HandleScrolling(pos, size)) {
return false;
}
/// CONTROLS ///
if (has_touch) {
if (inp->IsHeld(inp->Touch) &&
LI::Renderer::InBox(inp->TouchPos(), vec4(pos, size))) {
clr = UI7Color_ButtonHovered;
}
if (inp->IsUp(inp->Touch) &&
LI::Renderer::InBox(inp->TouchPosLast(), vec4(pos, size))) {
clr = UI7Color_ButtonActive;
ret = true;
}
}
/// Rendering ///
main->AddRectangle(pos, size, linked_theme->Get(clr));
main->AddText(pos + size * 0.5 - tszs * 0.5, label,
linked_theme->Get(UI7Color_Text));
return ret;
}
void UI7::Menu::Checkbox(const std::string& label, bool& v) {
vec2 pos = Cursor();
vec2 tdim = front->ren->GetTextDimensions(label);
vec2 cbs(18);
vec2 size = cbs + vec2(tdim.x() + 5, 0);
CursorMove(size);
if (HandleScrolling(pos, size)) {
return;
}
UI7Color cbbg = UI7Color_FrameBackground;
if (has_touch) {
if (inp->IsHeld(inp->Touch) &&
LI::Renderer::InBox(inp->TouchPos(), vec4(pos, size))) {
cbbg = UI7Color_FrameBackgroundHovered;
}
if (inp->IsUp(inp->Touch) &&
LI::Renderer::InBox(inp->TouchPosLast(), vec4(pos, size))) {
cbbg = UI7Color_FrameBackgroundHovered;
v = !v;
}
}
main->AddRectangle(pos, cbs, linked_theme->Get(cbbg));
if (v) {
main->AddRectangle(pos + 2, cbs - 4, linked_theme->Get(UI7Color_Checkmark));
}
main->AddText(pos + vec2(cbs.x() + 5, cbs.y() * 0.5 - tdim.y() * 0.5), label,
linked_theme->Get(UI7Color_Text));
}
void UI7::Menu::Image(Texture::Ref img, vec2 size) {
/// Variable Setup Stage ///
size = size == 0.f ? img->GetSize() : size;
vec2 pos = Cursor();
CursorMove(size);
/// Scrolling Handler ///
if (HandleScrolling(pos, size)) {
return;
}
/// Rendering Stage ///
main->AddImage(pos, img, size);
}
void UI7::Menu::DebugLabels() {
std::stringstream s;
s << "Name: " << name << " [";
s << std::hex << std::setw(8) << std::setfill('0') << id;
s << std::dec << "]";
this->Label(s.str());
this->Label(
"Pre: " +
Strings::FormatNanos(
Sys::GetTraceRef("MPRE_" + name)->GetProtocol()->GetAverage()));
this->Label(
"Post: " +
Strings::FormatNanos(
Sys::GetTraceRef("MPOS_" + name)->GetProtocol()->GetAverage()));
this->Label(
"Update: " +
Strings::FormatNanos(
Sys::GetTraceRef("MUPT_" + name)->GetProtocol()->GetAverage()));
this->Label(
"MUser: " +
Strings::FormatNanos(
Sys::GetTraceRef("MUSR_" + name)->GetProtocol()->GetAverage()));
}
void UI7::Menu::Update(float delta) {
TT::Scope st("MUPT_" + name);
this->back->BaseLayer(30);
this->back->Process();
this->main->BaseLayer(40);
this->main->Process();
this->front->BaseLayer(50);
this->front->Process();
}
void UI7::Menu::CursorMove(const vec2& size) {
last_size = size;
slcursor = cursor + vec2(size[0] + 5, 0);
if (bslpos[1]) {
cursor = vec2(5, cursor[1] + bslpos[1] + 5);
bslpos = vec2();
} else {
cursor = vec2(5, cursor[1] + size[1] + 5);
}
max = vec2(slcursor[0], cursor[1]);
}
void UI7::Menu::PreHandler(UI7MenuFlags flags) {
TT::Scope st("MPRE_" + name);
TT::Beg("MUSR_" + name);
Cursor(vec2(5, 5));
this->flags = flags;
this->scrolling[0] = flags & UI7MenuFlags_HzScrolling;
this->scrolling[1] = flags & UI7MenuFlags_VtScrolling;
has_touch = main->GetRenderer()->CurrentScreen() == Screen::Bottom;
if (!(flags & UI7MenuFlags_NoBackground)) {
back->AddRectangle(0, view_area.zw(), UI7Color_Background);
}
if (!(flags & UI7MenuFlags_NoTitlebar)) {
tbh = front->GetRenderer()->TextScale() * 30.f;
front->AddRectangle(0, vec2(view_area.z(), tbh),
linked_theme->Get(UI7Color_Header));
vec2 tpos(5, tbh * 0.5 - front->ren->GetTextDimensions(name).y() * 0.5);
LITextFlags tflags = LITextFlags_None;
if (flags & UI7MenuFlags_CenterTitle) {
tpos = 0;
tflags = LITextFlags_AlignMid;
}
front->AddText(tpos, this->name, linked_theme->Get(UI7Color_Text), tflags,
vec2(view_area.z(), tbh));
Cursor(vec2(5, tbh + 5));
}
}
void UI7::Menu::PostHandler() {
TT::Scope st("MPOS_" + name);
if (scrolling[1]) {
scroll_allowed[1] = (max[1] > 235);
scrollbar[1] = scroll_allowed[1];
if (scrollbar[1]) {
/// Setup Some Variables hare [they are self described]
int screen_w = view_area.z();
int tsp = 5 + tbh;
int slider_w = 4;
int szs = view_area.w() - tsp - 5;
/// Actually dont have a Horizontal bar yet
if (scrollbar[0]) szs -= slider_w - 2;
int lslider_h = 20; // Dont go less heigt for the drag
float slider_h = (szs - 4) * (float(szs - 4) / max[1]);
/// Visual Slider Height (How it looks in the end)
int vslider_h = std::clamp(slider_h, float(lslider_h), float(szs - 4));
/// Check if we overscroll to the bottom and Auto scroll back...
/// Probably schould use Tween ENgine here
if (scrolling_off[1] > max[1] - view_area[3] && max[1] != 0.f &&
max[1] >= view_area[3] - 5) {
scrolling_off[1] -= 3.f;
if (scrolling_off[1] < max[1] - view_area[3]) {
scrolling_off[1] = max[1] - view_area[3];
}
}
/// Do the Same as above just for Overscroll back to the top
if (scrolling_off[1] < 0) {
scrolling_off[1] += 3.f;
if (scrolling_off[1] > 0) {
scrolling_off[1] = 0;
}
}
/// Dont overscroll to much
if (scrolling_off[1] < -40 ||
scrolling_off[1] > max[1] - view_area[3] + 40) {
scroll_mod[1] = 0.f;
}
/// The pain :(
if (has_touch) {
vec2 tpos = inp->TouchPos();
if (inp->IsDown(inp->Touch)) {
mouse = tpos;
} else if (inp->IsUp(inp->Touch)) {
mouse = vec2();
}
if (inp->IsHeld(inp->Touch)) {
if (!front->ren->InBox(tpos, vec4(view_area[2] - 13, tbh + 5, 8,
view_area[3] - tbh - 10))) {
if (scrolling_off[1] < max[1] - view_area[3] + 40 &&
scrolling_off[1] > -40) {
/// Cursor Mod
float cm = mouse[1] - tpos[1];
if (scroll_mod[1] <= 4.f && scroll_mod[1] >= -4.f && cm != 0) {
scroll_mod[1] = cm;
}
}
mouse = tpos;
}
}
}
/// Effect
if (scroll_mod[1] != 0) {
scrolling_off[1] += scroll_mod[1];
}
if (scroll_mod[1] < 0.f) {
scroll_mod[1] += 0.4f;
if (scroll_mod[1] > 0.f) {
scroll_mod[1] = 0;
}
}
if (scroll_mod[1] > 0.f) {
scroll_mod[1] -= 0.4f;
if (scroll_mod[1] < 0.f) {
scroll_mod[1] = 0;
}
}
int srpos =
tsp + std::clamp(float(szs - vslider_h - 4) *
(scrolling_off[1] / (max[1] - view_area[3])),
0.f, float(szs - vslider_h - 4));
/// Rendering Stage
front->AddRectangle(vec2(screen_w - 12, tsp), vec2(slider_w * 2, szs),
linked_theme->Get(UI7Color_FrameBackground));
front->AddRectangle(vec2(screen_w - 10, tsp + 2), vec2(slider_w, szs - 4),
linked_theme->Get(UI7Color_FrameBackgroundHovered));
front->AddRectangle(vec2(screen_w - 10, srpos + 2),
vec2(slider_w, vslider_h),
linked_theme->Get(UI7Color_Button));
}
}
TT::End("MUSR_" + name);
}
void UI7::Menu::SameLine() {
bslpos = last_size;
cursor = slcursor;
}
void UI7::Menu::Separator() {
vec2 pos = Cursor();
vec2 size = vec2(view_area.z() - (scrollbar[1] ? 24 : 10), 1);
CursorMove(size);
if (HandleScrolling(pos, size)) {
return;
}
main->AddRectangle(pos, size, linked_theme->Get(UI7Color_TextDead));
}
void UI7::Menu::SeparatorText(const std::string& label) {
vec2 size = vec2(view_area.z() - (scrollbar[1] ? 24 : 10), 1);
vec2 tdim = this->back->GetRenderer()->GetTextDimensions(label);
vec2 pos = Cursor();
CursorMove(vec2(size.x(), tdim.y() - 4)); // Fix to make gap not to large
if (HandleScrolling(pos, size)) {
return;
}
/// Label pos for better overview
vec2 lpos = pos + vec2((view_area.z() - 10) * 0.5 - tdim.x() * 0.5, 0);
main->AddRectangle(pos + vec2(0, tdim.y() * 0.5),
vec2(lpos.x() - pos.x() - 5, size.y()),
linked_theme->Get(UI7Color_TextDead));
main->AddRectangle(pos + vec2(lpos.x() + tdim.x(), tdim.y() * 0.5),
vec2(size.x() - (lpos.x() + tdim.x()), size.y()),
linked_theme->Get(UI7Color_TextDead));
main->AddText(lpos, label, linked_theme->Get(UI7Color_Text), 0,
vec2(view_area.z(), 20));
}
bool UI7::Menu::HandleScrolling(vec2& pos, const vec2& size) {
if (scrolling[1]) {
vec2 p = pos;
pos -= vec2(0, scrolling_off.y());
if (pos.y() > view_area.w() ||
(pos.y() + size.y() < tbh - 5 && p.y() > tbh)) {
return true;
}
}
return false;
}
} // namespace UI7
} // namespace PD

View File

@ -10,12 +10,12 @@ void Theme::Default(Theme& theme) {
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_ButtonHovered, 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_FrameBackgroundHovered, Color("#777777FF"));
theme.Set(UI7Color_Progressbar, Color("#00FF00FF"));
theme.Set(UI7Color_ListEven, Color("#CCCCCCFF"));
theme.Set(UI7Color_ListOdd, Color("#BBBBBBFF"));

View File

@ -0,0 +1,52 @@
#include <pd/common/timetrace.hpp>
#include <pd/ui7/ui7.hpp>
namespace PD {
bool UI7::Context::BeginMenu(const ID& id, UI7MenuFlags flags) {
Assert(!this->current, "You are already in another Menu!");
Assert(std::find(amenus.begin(), amenus.end(), (u32)id) == amenus.end(),
"Menu Name Already used or\nContext::Update not called!");
auto menu = this->menus.find(id);
if (menu == this->menus.end()) {
this->menus[id] = Menu::New(id, &theme, inp);
menu = this->menus.find(id);
}
this->current = menu->second;
if (!this->current->BackList()) {
this->current->BackList(DrawList::New(ren));
}
if (!this->current->MainList()) {
this->current->MainList(DrawList::New(ren));
}
if (!this->current->FrontList()) {
this->current->FrontList(DrawList::New(ren));
}
this->current->ViewArea(this->ren->GetViewport());
this->current->PreHandler(flags);
amenus.push_back(this->current->GetID());
return true;
}
UI7::Menu::Ref UI7::Context::GetCurrentMenu() {
Assert(current != nullptr, "Not in a Menu!");
return current;
}
void UI7::Context::EndMenu() {
this->current->PostHandler();
this->current = nullptr;
}
void UI7::Context::Update(float delta) {
TT::Scope st("UI7_Update");
Assert(current == nullptr, "Still in a Menu!");
this->back->BaseLayer(10);
this->back->Process();
for (auto it : amenus) {
menus[it]->Update(delta);
}
this->front->BaseLayer(60);
this->front->Process();
this->amenus.clear();
}
} // namespace PD

View File

@ -27,54 +27,82 @@ SOFTWARE.
#include <pd.hpp>
#include <pd/maths/tween.hpp>
using vec2 = PD::vec2;
using vec3 = PD::vec3;
using vec4 = PD::vec4;
class Test : public PD::App {
public:
Test() = default;
~Test() = default;
void Init() override {
ren = Renderer();
inp = Input();
test = PD::Texture::New("romfs:/icon.png");
Overlays()->Push(PD::New<PD::Performance>(dbg, dbg_screen));
// Performance Overlay freezes N3DS
// Overlays()->Push(PD::New<PD::Performance>(dbg, dbg_screen));
font = PD::LI::Font::New();
// font->LoadSystemFont();
font->LoadTTF("romfs:/ComicNeue.ttf", 32);
Renderer()->Font(font);
ui7 = PD::UI7::Context::New();
// font->LoadTTF("romfs:/fonts/ComicNeue.ttf", 32);
font->LoadTTF("romfs:/fonts/JetBrainsMono-Medium.ttf", 32);
ren->Font(font);
ui7 = PD::UI7::Context::New(ren, inp);
}
bool MainLoop(float delta, float time) override {
DrawFancyBG(time);
Renderer()->OnScreen(PD::Screen::Bottom);
Renderer()->DrawRectSolid(0, vec2(320, 240), PD::Color("#222222"));
Renderer()->UseTex(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 (Input()->IsDown(PD::Hid::Start)) {
ren->OnScreen(PD::Screen::Bottom);
// ren->DrawRectSolid(0, vec2(320, 240), PD::Color("#222222"));
// ren->Layer(ren->Layer() + 1);
// ren->DrawImage(ren->GetViewport().zw() * 0.5 - test->GetSize() * 0.5,
// test); ren->DrawText(5, 0xffffffff, "Hello World!", LITextFlags_None);
if (ui7->BeginMenu("Test",
UI7MenuFlags_Scrolling | UI7MenuFlags_CenterTitle)) {
auto m = ui7->GetCurrentMenu();
m->SeparatorText("Menu Timings");
m->DebugLabels();
m->SeparatorText("Lithium Settings");
FlagBox(m, "LI AST", PD::LI::RenderFlags_AST);
FlagBox(m, "LI LRS", PD::LI::RenderFlags_LRS);
FlagBox(m, "LI TMS", PD::LI::RenderFlags_TMS);
m->SeparatorText("UI7 Tests");
m->Label("This seems to be a label");
m->Separator();
m->Button("Button?");
m->SeparatorText("SeparatorText");
m->Checkbox("Test", cbtest);
for (int i = 0; i < 10; i++) {
m->Label("Label: " + std::to_string(i));
}
ui7->EndMenu();
}
ui7->Update(delta);
if (inp->IsDown(PD::Hid::Start)) {
return false;
}
if (Input()->IsDown(Input()->A)) {
if (inp->IsDown(inp->A)) {
Overlays()->Push(PD::New<PD::Performance>(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)) {
if (inp->IsUp(inp->B)) {
Overlays()->Push(PD::New<PD::Keyboard>(text, state));
// what.To(vec2(5, 180)).From(vec2(5, 200)).In(0.5).As(what.EaseOutQuad);
}
return true;
}
void Deinit() override {}
void FlagBox(PD::UI7::Menu::Ref m, const std::string& label,
PD::LI::RenderFlags flag) {
bool has_flag = ren->GetFlags() & flag;
m->Checkbox(label, has_flag);
if (has_flag != (ren->GetFlags() & flag)) {
if (has_flag) {
ren->GetFlags() |= flag;
} else {
ren->GetFlags() &= ~flag;
}
}
}
void DrawFancyBG(float time) {
Renderer()->DrawRect(vec2(0, 0), vec2(400, 240), 0xff64c9fd);
ren->DrawRect(vec2(0, 0), vec2(400, 240), 0xff64c9fd);
for (int i = 0; i < 44; i++) Append(i, vec2(0, 0), vec2(400, 240), time);
}
@ -90,7 +118,7 @@ class Test : public PD::App {
sin(offset + time) * 10 + 30;
float color_effect = 1 - exp(-(index / 11) / 3.0f);
Renderer()->DrawTriangle(
ren->DrawTriangle(
vec2(x_position, y_position), vec2(x_position + 300, y_position + (90)),
vec2(x_position - 300, y_position + (90)),
PD::Color(.94f - .17f * color_effect, .61f - .25f * color_effect,
@ -98,8 +126,13 @@ class Test : public PD::App {
}
private:
/// Shorter Acess to Renderer / Input
PD::LI::Renderer::Ref ren;
PD::Hid::Ref inp;
/// Other Data
PD::Texture::Ref test;
bool dbg = false, dbg_screen = false;
bool cbtest = true;
std::string text;
PD::Keyboard::State state;
PD::UI7::Context::Ref ui7;
@ -108,7 +141,7 @@ class Test : public PD::App {
};
int main() {
auto app = PD::New<Test>();
app->Run();
Test app;
app.Run();
return 0;
}

View File

@ -0,0 +1,93 @@
Copyright 2014 The Comic Neue Project Authors (https://github.com/crozynski/comicneue)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View File

@ -0,0 +1,93 @@
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.