# Rewrite 5
- Move Libraries Source into pd directory and give them all their own CMakeLists.txt - Partial rewrite core (color, autogenerated vec), lithium (now uses UNIQUE PTR for Commands), UI7 - Use MenuV2 as new standart in UI7 - Implementz ViewPort Pre alpha to UI7 - Add Line Drawing to DrawList (not Working) - Implement a Complete new drievrs API (static Drivers) - NO SUPPORT FOR SHARED LIBRARY BUILDS IN VERSION 5 YET - Add Tools to Autogenerate Headers and Stuff
This commit is contained in:
17
pd/lithium/CMakeLists.txt
Executable file
17
pd/lithium/CMakeLists.txt
Executable file
@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(pd-lithium LANGUAGES CXX VERSION 0.5.0)
|
||||
|
||||
set(SRC
|
||||
source/drawlist.cpp
|
||||
source/font.cpp
|
||||
source/renderer.cpp
|
||||
)
|
||||
|
||||
if(PD_BUILD_SHARED)
|
||||
pd_add_lib(pd-lithium BUILD_SHARED TRUE SRC_FILES ${SRC})
|
||||
else()
|
||||
pd_add_lib(pd-lithium SRC_FILES ${SRC})
|
||||
endif()
|
||||
|
||||
target_link_libraries(pd-lithium PUBLIC pd-core)
|
280
pd/lithium/source/drawlist.cpp
Executable file
280
pd/lithium/source/drawlist.cpp
Executable file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 - 2025 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/lithium/drawlist.hpp>
|
||||
#include <pd/lithium/renderer.hpp>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
namespace PD {
|
||||
namespace Li {
|
||||
PD_LITHIUM_API void DrawList::DrawSolid() { CurrentTex = Gfx::GetSolidTex(); }
|
||||
|
||||
PD_LITHIUM_API Command::Ref DrawList::PreGenerateCmd() {
|
||||
Command::Ref cmd = Command::New();
|
||||
cmd->Layer = Layer;
|
||||
cmd->Index = pDrawList.size();
|
||||
cmd->Tex = CurrentTex;
|
||||
pClipCmd(cmd.get());
|
||||
return std::move(cmd);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::pClipCmd(Command *cmd) {
|
||||
if (!pClipRects.IsEmpty()) {
|
||||
cmd->ScissorOn = true;
|
||||
cmd->ScissorRect = ivec4(pClipRects.Top());
|
||||
}
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::PathArcToN(const fvec2 &c, float radius,
|
||||
float a_min, float a_max,
|
||||
int segments) {
|
||||
// Path.push_back(c);
|
||||
PathReserve(segments + 1);
|
||||
for (int i = 0; i < segments; i++) {
|
||||
float a = a_min + ((float)i / (float)segments) * (a_max - a_min);
|
||||
PathAdd(vec2(c.x + std::cos(a) * radius, c.y + std::sin(a) * radius));
|
||||
}
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::PathFastArcToN(const fvec2 &c, float r,
|
||||
float amin, float amax, int s) {
|
||||
/**
|
||||
* Funcion with less division overhead
|
||||
* Usefull for stuff where a lot of calculations are required
|
||||
*/
|
||||
float d = (amax - amin) / s;
|
||||
PathReserve(s + 1);
|
||||
for (int i = 0; i <= s; i++) {
|
||||
float a = amin + i * d;
|
||||
PathAdd(fvec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r));
|
||||
}
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::PathRect(fvec2 a, fvec2 b, float rounding) {
|
||||
if (rounding == 0.f) {
|
||||
PathAdd(a);
|
||||
PathAdd(vec2(b.x, a.y));
|
||||
PathAdd(b);
|
||||
PathAdd(vec2(a.x, b.y));
|
||||
} else {
|
||||
float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f});
|
||||
/** Calculate Optimal segment count automatically */
|
||||
float corner = M_PI * 0.5f;
|
||||
int segments = std::max(3, int(std::ceil(corner / (6.0f * M_PI / 180.0f))));
|
||||
|
||||
/**
|
||||
* To Correctly render filled shapes with Paths API
|
||||
* The Commands need to be setup clockwise
|
||||
*/
|
||||
/** Top Left */
|
||||
PathAdd(vec2(a.x + r, a.y));
|
||||
PathFastArcToN(vec2(b.x - r, a.y + r), r, -M_PI / 2.0f, 0.0f, segments);
|
||||
/** Top Right */
|
||||
PathAdd(vec2(b.x, b.y - r));
|
||||
PathFastArcToN(vec2(b.x - r, b.y - r), r, 0.0f, M_PI / 2.0f, segments);
|
||||
/** Bottom Right */
|
||||
PathAdd(vec2(a.x + r, b.y));
|
||||
PathFastArcToN(vec2(a.x + r, b.y - r), r, M_PI / 2.0f, M_PI, segments);
|
||||
/** Bottom Left */
|
||||
PathAdd(vec2(a.x, a.y + r));
|
||||
PathFastArcToN(vec2(a.x + r, a.y + r), r, M_PI, 3.0f * M_PI / 2.0f,
|
||||
segments);
|
||||
}
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::PathRectEx(fvec2 a, fvec2 b, float rounding,
|
||||
u32 flags) {
|
||||
if (rounding == 0.f) {
|
||||
PathAdd(a);
|
||||
PathAdd(vec2(b.x, a.y));
|
||||
PathAdd(b);
|
||||
PathAdd(vec2(a.x, b.y));
|
||||
} else {
|
||||
float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f});
|
||||
/** Calculate Optimal segment count automatically */
|
||||
float corner = M_PI * 0.5f;
|
||||
int segments = std::max(3, int(std::ceil(corner / (6.0f * M_PI / 180.0f))));
|
||||
|
||||
/**
|
||||
* To Correctly render filled shapes with Paths API
|
||||
* The Commands need to be setup clockwise
|
||||
*/
|
||||
/** Top Left */
|
||||
if (flags & LiPathRectFlags_KeepTopLeft) {
|
||||
PathAdd(a);
|
||||
} else {
|
||||
PathAdd(vec2(a.x + r, a.y));
|
||||
PathFastArcToN(vec2(b.x - r, a.y + r), r, -M_PI / 2.0f, 0.0f, segments);
|
||||
}
|
||||
|
||||
/** Top Right */
|
||||
if (flags & LiPathRectFlags_KeepTopRight) {
|
||||
PathAdd(vec2(b.x, a.y));
|
||||
} else {
|
||||
PathAdd(vec2(b.x, b.y - r));
|
||||
PathFastArcToN(vec2(b.x - r, b.y - r), r, 0.0f, M_PI / 2.0f, segments);
|
||||
}
|
||||
/** Bottom Right */
|
||||
if (flags & LiPathRectFlags_KeepBotRight) {
|
||||
PathAdd(b);
|
||||
} else {
|
||||
PathAdd(vec2(a.x + r, b.y));
|
||||
PathFastArcToN(vec2(a.x + r, b.y - r), r, M_PI / 2.0f, M_PI, segments);
|
||||
}
|
||||
/** Bottom Left */
|
||||
if (flags & LiPathRectFlags_KeepBotLeft) {
|
||||
PathAdd(vec2(a.x, b.y));
|
||||
} else {
|
||||
PathAdd(vec2(a.x, a.y + r));
|
||||
PathFastArcToN(vec2(a.x + r, a.y + r), r, M_PI, 3.0f * M_PI / 2.0f,
|
||||
segments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawRect(const fvec2 &pos, const fvec2 &size,
|
||||
u32 color, int thickness) {
|
||||
PathRect(pos, pos + size);
|
||||
// Flags is currently hardcoded (1 = close)
|
||||
PathStroke(color, thickness, 1);
|
||||
}
|
||||
void DrawList::DrawRectFilled(const fvec2 &pos, const fvec2 &size, u32 color) {
|
||||
PathRect(pos, pos + size);
|
||||
PathFill(color);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawTriangle(const fvec2 &a, const fvec2 &b,
|
||||
const fvec2 &c, u32 color,
|
||||
int thickness) {
|
||||
PathAdd(a);
|
||||
PathAdd(b);
|
||||
PathAdd(c);
|
||||
PathStroke(color, thickness, 1);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawTriangleFilled(const fvec2 &a, const fvec2 &b,
|
||||
const fvec2 &c, u32 color) {
|
||||
PathAdd(a);
|
||||
PathAdd(b);
|
||||
PathAdd(c);
|
||||
PathFill(color);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawCircle(const fvec2 ¢er, float rad,
|
||||
u32 color, int num_segments,
|
||||
int thickness) {
|
||||
if (num_segments <= 0) {
|
||||
// Auto Segment
|
||||
} else {
|
||||
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
|
||||
PathArcToN(center, rad, 0.f, am, num_segments);
|
||||
}
|
||||
DrawSolid(); // Only Solid Color Supported
|
||||
PathStroke(color, thickness, (1 << 0));
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawCircleFilled(const fvec2 ¢er, float rad,
|
||||
u32 color, int num_segments) {
|
||||
if (num_segments <= 0) {
|
||||
// Auto Segment
|
||||
} else {
|
||||
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
|
||||
PathArcToN(center, rad, 0.f, am, num_segments);
|
||||
}
|
||||
PathFill(color);
|
||||
}
|
||||
|
||||
// TODO: Don't render OOS
|
||||
PD_LITHIUM_API void DrawList::DrawPolyLine(const Vec<fvec2> &points, u32 clr,
|
||||
u32 flags, int thickness) {
|
||||
if (points.Size() < 2) {
|
||||
return;
|
||||
}
|
||||
DrawSolid();
|
||||
auto cmd = PreGenerateCmd();
|
||||
bool close = (flags & (1 << 0));
|
||||
int num_points = close ? (int)points.Size() : (int)points.Size() - 1;
|
||||
if (flags & (1 << 1)) {
|
||||
// TODO: Find a way to draw less garbage looking lines
|
||||
} else {
|
||||
// Non antialiased lines look awful when rendering with thickness != 1
|
||||
for (int i = 0; i < num_points; i++) {
|
||||
int j = (i + 1) == (int)points.Size() ? 0 : (i + 1);
|
||||
auto line = Renderer::PrimLine(points[i], points[j], thickness);
|
||||
Renderer::CmdQuad(cmd.get(), line, vec4(0.f, 1.f, 1.f, 0.f), clr);
|
||||
}
|
||||
}
|
||||
AddCommand(std::move(cmd));
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawConvexPolyFilled(const Vec<fvec2> &points,
|
||||
u32 clr) {
|
||||
if (points.Size() < 3) {
|
||||
return; // Need at least three points
|
||||
}
|
||||
auto cmd = PreGenerateCmd();
|
||||
Renderer::CmdConvexPolyFilled(cmd.get(), points, clr, CurrentTex);
|
||||
AddCommand(std::move(cmd));
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawText(const fvec2 &pos,
|
||||
const std::string &text, u32 color) {
|
||||
if (!pCurrentFont) {
|
||||
return;
|
||||
}
|
||||
std::vector<Command::Ref> cmds;
|
||||
pCurrentFont->CmdTextEx(cmds, pos, color, pFontScale, text);
|
||||
for (size_t i = 0; i < cmds.size(); i++) {
|
||||
cmds[i]->Index = pDrawList.size();
|
||||
cmds[i]->Layer = Layer;
|
||||
AddCommand(std::move(cmds[i]));
|
||||
}
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawTextEx(const fvec2 &p,
|
||||
const std::string &text, u32 color,
|
||||
LiTextFlags flags, fvec2 box) {
|
||||
if (!pCurrentFont) {
|
||||
return;
|
||||
}
|
||||
std::vector<Command::Ref> cmds;
|
||||
pCurrentFont->CmdTextEx(cmds, p, color, pFontScale, text, flags, box);
|
||||
for (size_t i = 0; i < cmds.size(); i++) {
|
||||
cmds[i]->Index = pDrawList.size();
|
||||
cmds[i]->Layer = Layer;
|
||||
AddCommand(std::move(cmds[i]));
|
||||
}
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void DrawList::DrawLine(const fvec2 &a, const fvec2 &b,
|
||||
u32 color, int t) {
|
||||
PathAdd(a);
|
||||
PathAdd(b);
|
||||
PathStroke(color, t);
|
||||
}
|
||||
} // namespace Li
|
||||
} // namespace PD
|
282
pd/lithium/source/font.cpp
Executable file
282
pd/lithium/source/font.cpp
Executable file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 - 2025 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/lithium/font.hpp>
|
||||
|
||||
/** Due to Limitations of Shared Lib Stuff */
|
||||
#ifdef PD_LITHIUM_BUILD_SHARED
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#endif
|
||||
#include <pd/external/stb_truetype.h>
|
||||
|
||||
#include <pd/lithium/renderer.hpp>
|
||||
|
||||
namespace PD {
|
||||
namespace Li {
|
||||
PD_LITHIUM_API void Font::LoadTTF(const std::string &path, int height) {
|
||||
TT::Scope st("LI_LoadTTF_" + path);
|
||||
PixelHeight = height; // Set internel pixel height
|
||||
// Use NextPow2 to be able to use sizes between for example 16 and 32
|
||||
// before it only was possible to use 8, 16, 32, 64 as size
|
||||
int texszs = BitUtil::GetPow2(height * 16);
|
||||
// Load stbtt
|
||||
stbtt_fontinfo inf;
|
||||
std::ifstream loader(path, std::ios::binary);
|
||||
if (!loader.is_open()) return;
|
||||
loader.seekg(0, std::ios::end);
|
||||
size_t len = loader.tellg();
|
||||
loader.seekg(0, std::ios::beg);
|
||||
unsigned char *buffer = new unsigned char[len];
|
||||
loader.read(reinterpret_cast<char *>(buffer), len);
|
||||
loader.close();
|
||||
stbtt_InitFont(&inf, buffer, 0);
|
||||
// clang-format off
|
||||
// Disable clang here cause dont want a garbage looking line
|
||||
std::vector<PD::u8> font_tex(texszs * texszs * 4); // Create font Texture
|
||||
// clang-format on
|
||||
float scale = stbtt_ScaleForPixelHeight(&inf, PixelHeight);
|
||||
|
||||
int ascent, descent, lineGap;
|
||||
stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap);
|
||||
int baseline = static_cast<int>(ascent * scale);
|
||||
|
||||
std::map<u32, int> buf_cache; // Cache to not render same codepoint tex twice
|
||||
|
||||
/// Load Codepoints
|
||||
auto tex = Texture::New();
|
||||
fvec2 off;
|
||||
for (u32 ii = 0x0000; ii < 0xFFFF; ii++) {
|
||||
int i = stbtt_FindGlyphIndex(&inf, ii);
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
if (stbtt_IsGlyphEmpty(&inf, i)) {
|
||||
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);
|
||||
|
||||
// Check if Codepoint exists as hash and if it is use its already written
|
||||
// data
|
||||
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.pCodepoint = i;
|
||||
CodeMap[i] = c;
|
||||
free(bitmap);
|
||||
continue;
|
||||
} else {
|
||||
buf_cache[hashed_map] = i;
|
||||
}
|
||||
|
||||
if (off.x + w > texszs) {
|
||||
off.y += PixelHeight;
|
||||
off.x = 0;
|
||||
}
|
||||
|
||||
// Set UV Data
|
||||
fvec4 uvs;
|
||||
uvs.x = static_cast<float>(off.x) / texszs;
|
||||
uvs.y = static_cast<float>(off.y) / texszs;
|
||||
uvs.z = static_cast<float>((off.x + w) / texszs);
|
||||
uvs.w = static_cast<float>((off.y + h) / texszs);
|
||||
if (Gfx::Flags() & LiBackendFlags_FlipUV_Y) {
|
||||
uvs.y = 1.f - uvs.y;
|
||||
uvs.w = 1.f - uvs.w;
|
||||
}
|
||||
c.SimpleUV = uvs;
|
||||
c.Tex = tex;
|
||||
c.Size = fvec2(w, h);
|
||||
c.Offset = baseline + yo;
|
||||
|
||||
// Render glyph
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; ++x) {
|
||||
int map_pos = (((off.y + y) * texszs + (off.x + 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];
|
||||
}
|
||||
}
|
||||
|
||||
free(bitmap);
|
||||
CodeMap[i] = c;
|
||||
|
||||
// Small Patch to avoid some possible artifacts
|
||||
off.x += w + 1;
|
||||
if (off.x + w > texszs) {
|
||||
off.y += PixelHeight;
|
||||
if (off.y + PixelHeight > texszs) {
|
||||
break;
|
||||
}
|
||||
off.x = 0;
|
||||
}
|
||||
}
|
||||
// Load the Texture and append to list
|
||||
{
|
||||
auto t = Gfx::LoadTex(font_tex, texszs, texszs, Texture::RGBA32,
|
||||
Texture::LINEAR);
|
||||
tex->CopyFrom(t);
|
||||
}
|
||||
Textures.push_back(tex);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API Font::Codepoint &Font::GetCodepoint(u32 cp) {
|
||||
// Check if codepoijt exist or return a static invalid one
|
||||
auto res = CodeMap.find(cp);
|
||||
if (res == CodeMap.end()) {
|
||||
static Codepoint invalid;
|
||||
invalid.pInvalid = true;
|
||||
return invalid;
|
||||
}
|
||||
return res->second;
|
||||
}
|
||||
|
||||
PD_LITHIUM_API fvec2 Font::GetTextBounds(const std::string &text, float scale) {
|
||||
// Use wstring for exemple for german äöü
|
||||
auto wtext = Strings::MakeWstring(text);
|
||||
// Create a temp position and offset as [0, 0]
|
||||
fvec2 res;
|
||||
float x = 0;
|
||||
// Curent Font Scale
|
||||
float cfs = (DefaultPixelHeight * scale) / (float)PixelHeight;
|
||||
float lh = (float)PixelHeight * cfs;
|
||||
size_t index = 0;
|
||||
for (auto &it : wtext) {
|
||||
if (it == '\0') {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
auto cp = GetCodepoint(it);
|
||||
if (cp.pInvalid && it != '\n' && it != '\t' && it != ' ') {
|
||||
continue;
|
||||
}
|
||||
switch (it) {
|
||||
case '\n':
|
||||
res.y += lh;
|
||||
res.x = std::max(res.x, x);
|
||||
x = 0.f;
|
||||
break;
|
||||
case '\t':
|
||||
x += 16 * cfs;
|
||||
break;
|
||||
case ' ':
|
||||
x += 2 * cfs;
|
||||
// Fall trough here to get the same result as in
|
||||
// TextCommand if/else Section
|
||||
default:
|
||||
x += cp.Size.x * cfs;
|
||||
if (index != wtext.size()) {
|
||||
x += 2 * cfs;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
res.x = std::max(res.x, x);
|
||||
res.y += lh;
|
||||
return res;
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void Font::CmdTextEx(std::vector<Command::Ref> &cmds,
|
||||
const fvec2 &pos, u32 color, float scale,
|
||||
const std::string &text, LiTextFlags flags,
|
||||
const fvec2 &box) {
|
||||
fvec2 off;
|
||||
float cfs = (DefaultPixelHeight * scale) / (float)PixelHeight;
|
||||
float lh = (float)PixelHeight * cfs;
|
||||
fvec2 td;
|
||||
fvec2 rpos = pos;
|
||||
fvec2 rbox = box;
|
||||
if (flags & (LiTextFlags_AlignMid | LiTextFlags_AlignRight)) {
|
||||
td = GetTextBounds(text, scale);
|
||||
}
|
||||
if (flags & LiTextFlags_AlignMid) {
|
||||
rpos = rbox * 0.5 - td * 0.5 + pos;
|
||||
}
|
||||
if (flags & LiTextFlags_AlignRight) {
|
||||
rpos.x = rpos.x - td.x;
|
||||
}
|
||||
|
||||
std::vector<std::string> lines;
|
||||
std::istringstream iss(text);
|
||||
std::string tmp;
|
||||
while (std::getline(iss, tmp)) {
|
||||
lines.push_back(tmp);
|
||||
}
|
||||
|
||||
for (auto &it : lines) {
|
||||
/*if (flags & LITextFlags_Short) {
|
||||
fvec2 tmp_dim;
|
||||
it = ShortText(it, box.x() - pos.x(), tmp_dim);
|
||||
}*/
|
||||
auto wline = Strings::MakeWstring(it);
|
||||
auto cmd = Command::New();
|
||||
auto Tex = GetCodepoint(wline[0]).Tex;
|
||||
cmd->Tex = Tex;
|
||||
for (auto &jt : wline) {
|
||||
auto cp = GetCodepoint(jt);
|
||||
if ((cp.pInvalid && jt != '\n' && jt != '\t') && jt != '\r') {
|
||||
continue;
|
||||
}
|
||||
if (Tex != cp.Tex) {
|
||||
cmds.push_back(std::move(cmd));
|
||||
cmd = Command::New();
|
||||
Tex = cp.Tex;
|
||||
cmd->Tex = Tex;
|
||||
}
|
||||
if (jt == '\t') {
|
||||
off.x += 16 * cfs;
|
||||
} else {
|
||||
if (jt != ' ') {
|
||||
if (flags & LiTextFlags_Shaddow) {
|
||||
// Draw
|
||||
Rect rec = Renderer::PrimRect(
|
||||
rpos + vec2(off.x + 1, off.x + (cp.Offset * cfs)) + 1,
|
||||
cp.Size * cfs, 0.f);
|
||||
Renderer::CmdQuad(cmd.get(), rec, cp.SimpleUV, 0xff111111);
|
||||
}
|
||||
// Draw
|
||||
Rect rec = Renderer::PrimRect(
|
||||
rpos + off + fvec2(0, (cp.Offset * cfs)), cp.Size * cfs, 0.f);
|
||||
Renderer::CmdQuad(cmd.get(), rec, cp.SimpleUV, color);
|
||||
} else {
|
||||
off.x += 2 * cfs;
|
||||
}
|
||||
off.x += cp.Size.x * cfs + 2 * cfs;
|
||||
}
|
||||
}
|
||||
cmds.push_back(std::move(cmd));
|
||||
off.y += lh;
|
||||
off.x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Li
|
||||
} // namespace PD
|
150
pd/lithium/source/renderer.cpp
Executable file
150
pd/lithium/source/renderer.cpp
Executable file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 - 2025 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/lithium/renderer.hpp>
|
||||
|
||||
namespace PD {
|
||||
namespace Li {
|
||||
PD_LITHIUM_API bool Renderer::InBox(const fvec2& pos, const fvec2& szs,
|
||||
const fvec4& rect) {
|
||||
return (pos.x + szs.x >= rect.x && pos.y + szs.y >= rect.y &&
|
||||
pos.x <= rect.z && pos.y <= rect.w);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API bool Renderer::InBox(const fvec2& pos, const fvec4& rect) {
|
||||
return (pos.x > rect.x && pos.x < rect.x + rect.z && pos.y > rect.y &&
|
||||
pos.y < rect.y + rect.w);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API bool Renderer::InBox(const fvec2& alpha, const fvec2& bravo,
|
||||
const fvec2& charlie, const fvec4& rect) {
|
||||
return ((alpha.x < rect.z && bravo.x < rect.z && charlie.x < rect.z) ||
|
||||
(alpha.y < rect.w && bravo.y < rect.w && charlie.y < rect.w) ||
|
||||
(alpha.x > 0 && bravo.x > 0 && charlie.x > 0) ||
|
||||
(alpha.y > 0 && bravo.y > 0 && charlie.y > 0));
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void Renderer::RotateCorner(fvec2& pos, float sinus,
|
||||
float cosinus) {
|
||||
float x = pos.x * cosinus - pos.y * sinus;
|
||||
float y = pos.y * cosinus - pos.x * sinus;
|
||||
pos = fvec2(x, y);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API Rect Renderer::PrimRect(const fvec2& pos, const fvec2& size,
|
||||
float angle) {
|
||||
fvec2 c = size * 0.5f; // Center
|
||||
fvec2 corner[4] = {
|
||||
fvec2(-c.x, -c.y),
|
||||
fvec2(-c.x + size.x, -c.y),
|
||||
fvec2(-c.x, -c.y + size.y),
|
||||
fvec2(-c.x + size.x, -c.y + size.y),
|
||||
};
|
||||
|
||||
// Only rotate if required
|
||||
if (angle != 0.f) {
|
||||
float s = std::sin(angle);
|
||||
float co = std::cos(angle);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
RotateCorner(corner[i], s, co);
|
||||
}
|
||||
}
|
||||
|
||||
// Return Result
|
||||
return Rect(corner[0] + pos + c, corner[1] + pos + c, corner[2] + pos + c,
|
||||
corner[3] + pos + c);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API Rect Renderer::PrimLine(const fvec2& a, const fvec2& b,
|
||||
int thickness) {
|
||||
// Using the vec maths api makes the code as short as it is
|
||||
vec2 dir = a - b;
|
||||
float len = dir.Len();
|
||||
vec2 unit_dir = dir / len;
|
||||
vec2 perpendicular(-unit_dir.y, unit_dir.x);
|
||||
vec2 off = perpendicular * ((float)thickness * 0.5f);
|
||||
|
||||
return Rect(a + off, b + off, a - off, b - off);
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void Renderer::CmdQuad(Command* cmd, const Rect& quad,
|
||||
const Rect& uv, u32 color) {
|
||||
cmd->AddIdx(0).AddIdx(1).AddIdx(2);
|
||||
cmd->AddIdx(0).AddIdx(2).AddIdx(3);
|
||||
cmd->AddVtx(Vertex(quad.BotRight(), uv.BotRight(), color));
|
||||
cmd->AddVtx(Vertex(quad.TopRight(), uv.TopRight(), color));
|
||||
cmd->AddVtx(Vertex(quad.TopLeft(), uv.TopLeft(), color));
|
||||
cmd->AddVtx(Vertex(quad.BotLeft(), uv.BotLeft(), color));
|
||||
}
|
||||
|
||||
PD_LITHIUM_API void Renderer::CmdTriangle(Command* cmd, const fvec2 a,
|
||||
const fvec2 b, const fvec2 c,
|
||||
u32 clr) {
|
||||
cmd->AddIdx(2).AddIdx(1).AddIdx(0);
|
||||
cmd->AddVtx(Vertex(a, vec2(0.f, 1.f), clr));
|
||||
cmd->AddVtx(Vertex(b, vec2(1.f, 1.f), clr));
|
||||
cmd->AddVtx(Vertex(c, vec2(1.f, 0.f), clr));
|
||||
}
|
||||
|
||||
// TODO: Don't render OOS (Probably make it with a define as it
|
||||
// would probably be faster to render out of screen than checking if
|
||||
// it could be skipped)
|
||||
PD_LITHIUM_API void Renderer::CmdConvexPolyFilled(Command* cmd,
|
||||
const Vec<fvec2>& points,
|
||||
u32 clr, Texture::Ref tex) {
|
||||
if (points.Size() < 3 || tex == nullptr) {
|
||||
return; // Need at least three points
|
||||
}
|
||||
|
||||
// Support for Custom Textures (UV calculation)
|
||||
float minX = points[0].x, minY = points[0].y;
|
||||
float maxX = minX, maxY = minY;
|
||||
// Check for the max and min Positions
|
||||
for (auto it = points.Begin(); it != points.End(); it++) {
|
||||
if ((*it).x < minX) minX = (*it).x;
|
||||
if ((*it).y < minY) minY = (*it).y;
|
||||
if ((*it).x > maxX) maxX = (*it).x;
|
||||
if ((*it).y > maxY) maxY = (*it).y;
|
||||
}
|
||||
// Get Short defines for UV
|
||||
// (Bottom Right is not required)
|
||||
auto uv_tl = tex->UV.TopLeft();
|
||||
auto uv_tr = tex->UV.TopRight();
|
||||
auto uv_bl = tex->UV.BotLeft();
|
||||
|
||||
// Render
|
||||
for (int i = 2; i < (int)points.Size(); i++) {
|
||||
cmd->AddIdx(0).AddIdx(i).AddIdx(i - 1);
|
||||
}
|
||||
for (int i = 0; i < (int)points.Size(); i++) {
|
||||
// Calculate U and V coords
|
||||
float u =
|
||||
uv_tl.x + ((points[i].x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x);
|
||||
float v =
|
||||
uv_tl.y + ((points[i].y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y);
|
||||
cmd->AddVtx(Vertex(points[i], fvec2(u, v), clr));
|
||||
}
|
||||
}
|
||||
} // namespace Li
|
||||
} // namespace PD
|
Reference in New Issue
Block a user