7 Commits

Author SHA1 Message Date
b3d621a847 Add LayerOptimisation / QoL change 2025-12-19 21:08:32 +01:00
4ad00cd2be pd-3ds: Add sysfont loader
- add support for Alpha only textures in rendering
2025-12-19 21:07:57 +01:00
1e35dbd743 ReAdd text shorting 2025-12-18 21:51:48 +01:00
803fa5cdb5 Remove custom standard lib
Why?? cause it was russian roulette with pointer access stuff etc
2025-12-17 10:02:05 +01:00
66d3825481 bknd-3ds: implement libpicasso to load shader 2025-12-17 09:25:36 +01:00
6c38aa6f21 Adding and fixing stuff
- Fix HexChar2Int
- Remove some devisions in tween engine
- Add PathAdd function for x, y seperated instead of fvec2
- Readd text wrapping (rd7-palladium maybe)
2025-12-15 22:16:19 +01:00
f19c947fc3 Road to 0.6.0
- readd the c++ linear allocator for 3ds
- start switching from PD::Vec to std::vector
- Add Color::Hex as constexpr for compiletime color converts
- Add FNV Hasing functions
- Make UI7 ids be able to be generated at compile time
- Added a Throw Function (for whatever)
- Added HexCHar2Int (replaces the lookup table)
- Made u128 fully constexpr
2025-12-10 19:02:54 +01:00
51 changed files with 602 additions and 1016 deletions

9
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "backends/desktop/glfw"]
path = backends/desktop/glfw
url = https://github.com/glfw/glfw
[submodule "backends/desktop/glfw"]
path = backends/desktop/glfw
url = https://github.com/glfw/glfw
[submodule "backends/3ds/libpicasso"]
path = backends/3ds/libpicasso
url = https://github.com/npid7/libpicasso

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.22)
# Set Project
project(palladium LANGUAGES C CXX VERSION 0.5.1)
project(palladium LANGUAGES C CXX VERSION 0.6.0)
# Required to add this Variable
set(PD_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 - 2025 tobid7
Copyright (c) 2024 - 2025 René Amthor tobid7
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ 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.
SOFTWARE.

View File

@@ -1,13 +1,13 @@
cmake_minimum_required(VERSION 3.22)
project(pd-3ds LANGUAGES CXX VERSION 0.5.0)
project(pd-3ds LANGUAGES CXX VERSION 0.6.0)
set(SRC
source/bknd-gfx.cpp
source/bknd-hid.cpp
source/pd-3ds.cpp
)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libpicasso)
pd_add_lib(pd-3ds SRC_FILES ${SRC})
target_include_directories(pd-3ds PUBLIC include)
target_link_libraries(pd-3ds PUBLIC m palladium ctru citro3d)
target_link_libraries(pd-3ds PUBLIC m palladium ctru citro3d pica::pica)

View File

@@ -28,5 +28,6 @@ SOFTWARE.
#include <pd-3ds/bknd-hid.hpp>
namespace PD {
PD::Li::Font::Ref LoadSystemFont();
void Init(void* data = nullptr);
}
} // namespace PD

View File

@@ -27,19 +27,10 @@ SOFTWARE.
#include <3ds.h>
#include <citro3d.h>
#include <pd-3ds/linearAllocator.hpp>
#include <pd/lithium/lithium.hpp>
namespace PD {
template <typename T>
class LinearAlloc : public Allocator<T> {
public:
LinearAlloc() = default;
~LinearAlloc() = default;
/** Never forget the sizeof(T) again (most painful bug i created) */
T* Allocate(size_t n) override { return (T*)linearAlloc(n * sizeof(T)); }
void Deallocate(T* ptr) { linearFree(ptr); }
};
class GfxC3D : public GfxDriver {
public:
GfxC3D() : GfxDriver("Citro3D") {}
@@ -59,11 +50,12 @@ class GfxC3D : public GfxDriver {
PD::Li::Texture::Filter filter =
PD::Li::Texture::Filter::LINEAR) override;
Vec<Li::Vertex, LinearAlloc<Li::Vertex>> VertexBuffer;
Vec<u16, LinearAlloc<u16>> IndexBuffer;
std::vector<Li::Vertex, LinearAllocator<Li::Vertex>> VertexBuffer;
std::vector<u16, LinearAllocator<u16>> IndexBuffer;
int pLocProjection = 0;
DVLB_s* ShaderCode;
shaderProgram_s Shader;
C3D_AttrInfo ShaderInfo;
std::vector<u8> pRawShader;
};
} // namespace PD

View File

@@ -0,0 +1,49 @@
#pragma once
#include <3ds.h>
#include <pd/core/common.hpp>
// Custom C++ Allocator class to interface with libctru linear heap memory
// based on this guide:
// https://johnfarrier.com/custom-allocators-in-c-high-performance-memory-management/
namespace PD {
template <typename T>
class LinearAllocator {
public:
using value_type = T;
LinearAllocator() noexcept = default;
template <typename U>
constexpr LinearAllocator(const LinearAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
if (n > max_size()) {
throw std::runtime_error("[PD] LinearAllocator: Bad alloc!");
}
return static_cast<T*>(linearAlloc(n * sizeof(T)));
}
void deallocate(T* p, std::size_t) noexcept { linearFree(p); }
template <class U, class... Args>
void construct(U* p, Args&&... args) {
::new ((void*)p) U(std::forward<Args>(args)...);
}
template <class U>
void destroy(U* p) {
p->~U();
}
friend bool operator==(const LinearAllocator, const LinearAllocator) {
return true;
}
friend bool operator!=(const LinearAllocator, const LinearAllocator) {
return false;
}
// Use linearSpace free as max_size to not allocate out of bounds
// or to b eable to see a crash report screen.
size_t max_size() const noexcept { return linearSpaceFree(); }
};
} // namespace PD

View File

@@ -23,11 +23,8 @@ SOFTWARE.
*/
#include <pd-3ds/bknd-gfx.hpp>
#include <pica.hpp>
/// @brief Shader Code (Unused as i dont want to use libpicasso here (yet))
/// Update: Picasso breaks the linearRam or ram for somereason
/// as far as i found out loading anything into linear ram after
/// using libpicasso to compile a shader leads into a system freeze
const char* LIShaderCTR = R"(
; LI7 Shader
; Constants
@@ -65,13 +62,6 @@ const char* LIShaderCTR = R"(
.end
)";
// clang-format off
unsigned char li_shader[] = {
0x44, 0x56, 0x4c, 0x42, 0x1, 0x0, 0x0, 0x0, 0xa4, 0x0, 0x0, 0x0, 0x44, 0x56, 0x4c, 0x50, 0x0, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e, 0x1, 0xf0, 0x7, 0x4e, 0x2, 0x8, 0x2, 0x8, 0x3, 0x18, 0x2, 0x8, 0x4, 0x28, 0x2, 0x8, 0x5, 0x38, 0x2, 0x8, 0x6, 0x10, 0x40, 0x4c, 0x7, 0xf1, 0x27, 0x22, 0x8, 0x10, 0x21, 0x4c, 0x0, 0x0, 0x0, 0x88, 0xac, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x64, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x62, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x61, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xd5, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x56, 0x4c, 0x45, 0x2, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x2, 0x0, 0x5f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x1, 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1, 0x0, 0xf, 0x0, 0x0, 0x0, 0x3, 0x0, 0x2, 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x13, 0x0, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0, 0x0,
};
// clang-format on
size_t li_shader_size = 0x124;
namespace PD {
GPU_TEXCOLOR GetTexFmt(Li::Texture::Type type) {
if (type == Li::Texture::RGBA32)
@@ -92,13 +82,35 @@ int GetBPP(Li::Texture::Type type) {
return 0; // Error
}
void FragCfg(GPU_TEXCOLOR clr) {
C3D_DepthTest(false, GPU_GREATER, GPU_WRITE_ALL);
C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvInit(env);
switch (clr) {
case GPU_A4:
case GPU_A8:
case GPU_L4:
case GPU_L8:
C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
break;
default:
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0);
C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
break;
}
}
void GfxC3D::Init() {
VertexBuffer.Resize(4 * 8192);
IndexBuffer.Resize(6 * 8192);
VertexBuffer.resize(4 * 8192);
IndexBuffer.resize(6 * 8192);
Flags |= LiBackendFlags_FlipUV_Y;
ShaderCode = DVLB_ParseFile((uint32_t*)li_shader, li_shader_size);
pRawShader = Pica::AssembleCode(LIShaderCTR);
ShaderCode = DVLB_ParseFile((uint32_t*)&pRawShader[0], pRawShader.size());
shaderProgramInit(&Shader);
shaderProgramSetVsh(&Shader, &ShaderCode->DVLE[0]);
pLocProjection =
@@ -131,7 +143,6 @@ void GfxC3D::BindTex(PD::Li::TexAddress addr) {
}
void GfxC3D::RenderDrawData(const std::vector<PD::Li::Command::Ref>& Commands) {
// C3D_BindProgram(&Shader);
shaderProgramUse(&Shader);
C3D_SetAttrInfo(&ShaderInfo);
C3D_Mtx proj;
@@ -139,11 +150,6 @@ void GfxC3D::RenderDrawData(const std::vector<PD::Li::Command::Ref>& Commands) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, pLocProjection, &proj);
// Mat4 proj = Mat4::Ortho(0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f);
// C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, pLocProjection, (C3D_Mtx*)&proj);
C3D_DepthTest(false, GPU_GREATER, GPU_WRITE_ALL);
C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvInit(env);
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0);
C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
size_t index = 0;
while (index < Commands.size()) {
PD::Li::Texture::Ref Tex = Commands[index]->Tex;
@@ -159,11 +165,11 @@ void GfxC3D::RenderDrawData(const std::vector<PD::Li::Command::Ref>& Commands) {
Commands[index]->ScissorOn == ScissorEnabled &&
Commands[index]->ScissorRect == ScissorRect) {
auto c = Commands[index].get();
for (size_t i = 0; i < c->IndexBuffer.Size(); i++) {
IndexBuffer[CurrentIndex++] = CurrentVertex + c->IndexBuffer.At(i);
for (size_t i = 0; i < c->IndexBuffer.size(); i++) {
IndexBuffer[CurrentIndex++] = CurrentVertex + c->IndexBuffer.at(i);
}
for (size_t i = 0; i < c->VertexBuffer.Size(); i++) {
VertexBuffer[CurrentVertex++] = c->VertexBuffer.At(i);
for (size_t i = 0; i < c->VertexBuffer.size(); i++) {
VertexBuffer[CurrentVertex++] = c->VertexBuffer.at(i);
}
index++;
}
@@ -176,13 +182,14 @@ void GfxC3D::RenderDrawData(const std::vector<PD::Li::Command::Ref>& Commands) {
} else {
C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0);
}
FragCfg(((C3D_Tex*)Tex->Address)->fmt);
BindTex(Tex->Address);
auto bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, VertexBuffer.Data(), sizeof(Li::Vertex), 3, 0x210);
BufInfo_Add(bufInfo, VertexBuffer.data(), sizeof(Li::Vertex), 3, 0x210);
C3D_DrawElements(GPU_TRIANGLES, CurrentIndex - StartIndex,
C3D_UNSIGNED_SHORT, IndexBuffer.Data() + StartIndex);
C3D_UNSIGNED_SHORT, IndexBuffer.data() + StartIndex);
}
C3D_DepthTest(true, GPU_GREATER, GPU_WRITE_ALL);
}

View File

@@ -22,10 +22,106 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <3ds.h>
#include <palladium>
#include <pd-3ds.hpp>
namespace PD {
PD::Li::Font::Ref LoadSystemFont() {
TT::Scope st("LI_SystemFont"); // Trace loading time
Li::Font::Ref ret = Li::Font::New();
fontEnsureMapped(); // Call this to be sure the font is mapped
// Get some const references for system font loading
const auto fnt = fontGetSystemFont();
const auto fnt_info = fontGetInfo(fnt);
const auto glyph_info = fontGetGlyphInfo(fnt);
// Resize the Texture list by the num of sysfont textures
ret->Textures.resize(glyph_info->nSheets + 1);
/// Modify the Pixel Height by 1.1f to fit the
/// Size og ttf font Rendering
ret->PixelHeight = glyph_info->cellHeight;
// Load the Textures and make sure they don't auto unload
for (size_t i = 0; i < glyph_info->nSheets; i++) {
auto stex = Li::Texture::New();
auto tx = new C3D_Tex;
tx->data = fontGetGlyphSheetTex(fnt, i);
tx->fmt = (GPU_TEXCOLOR)glyph_info->sheetFmt;
tx->size = glyph_info->sheetSize;
tx->width = glyph_info->sheetWidth;
tx->height = glyph_info->sheetHeight;
tx->param = GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) |
GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
GPU_TEXTURE_WRAP_S(GPU_REPEAT) | GPU_TEXTURE_WRAP_T(GPU_REPEAT);
tx->border = 0xffffffff;
tx->lodParam = 0;
stex->Address = (Li::TexAddress)tx;
stex->Size = fvec2(tx->width, tx->height);
stex->UV = fvec4(0, 1, 1, 0);
ret->Textures[i] = stex;
}
std::vector<unsigned int> charSet;
// Write the Charset into a vector
for (auto cmap = fnt_info->cmap; cmap; cmap = cmap->next) {
if (cmap->mappingMethod == CMAP_TYPE_DIRECT) {
if (cmap->codeEnd >= cmap->codeBegin) {
charSet.reserve(charSet.size() + cmap->codeEnd - cmap->codeBegin + 1);
for (auto i = cmap->codeBegin; i <= cmap->codeEnd; ++i) {
if (cmap->indexOffset + (i - cmap->codeBegin) == 0xFFFF) break;
charSet.emplace_back(i);
}
}
} else if (cmap->mappingMethod == CMAP_TYPE_TABLE) {
if (cmap->codeEnd >= cmap->codeBegin) {
charSet.reserve(charSet.size() + cmap->codeEnd - cmap->codeBegin + 1);
for (auto i = cmap->codeBegin; i <= cmap->codeEnd; ++i) {
if (cmap->indexTable[i - cmap->codeBegin] == 0xFFFF) continue;
charSet.emplace_back(i);
}
}
} else if (cmap->mappingMethod == CMAP_TYPE_SCAN) {
charSet.reserve(charSet.size() + cmap->nScanEntries);
for (unsigned i = 0; i < cmap->nScanEntries; ++i) {
if (cmap->scanEntries[i].code >= cmap->codeBegin &&
cmap->scanEntries[i].code <= cmap->codeEnd) {
if (cmap->scanEntries[i].glyphIndex != 0xFFFF) {
charSet.emplace_back(cmap->scanEntries[i].code);
}
}
}
} else {
continue;
}
}
// Sort the charset and make sure all values are unique
std::sort(charSet.begin(), charSet.end());
charSet.erase(std::unique(charSet.begin(), charSet.end()));
// Setup the Codepoint map by the charset
for (auto cp : charSet) {
int gidx = fontGlyphIndexFromCodePoint(fnt, cp);
if (gidx >= 0xFFFF) continue;
Li::Font::Codepoint codepoint;
fontGlyphPos_s dat;
fontCalcGlyphPos(&dat, fnt, gidx, GLYPH_POS_CALC_VTXCOORD, 1.f, 1.f);
codepoint.pCodepoint = cp;
codepoint.SimpleUV = fvec4(dat.texcoord.left, dat.texcoord.top,
dat.texcoord.right, dat.texcoord.bottom);
if (dat.sheetIndex < (int)ret->Textures.size()) {
codepoint.Tex = ret->Textures[dat.sheetIndex];
} else {
codepoint.pInvalid = true;
}
codepoint.Size = fvec2(dat.vtxcoord.right, dat.vtxcoord.bottom);
codepoint.Offset = 0;
ret->CodeMap[cp] = codepoint;
}
return ret;
}
void Init(void* data) {
// Dekstop Init Stage
// First use default OS Driver

View File

@@ -52,8 +52,8 @@ class GfxGL2 : public GfxDriver {
PD::Li::Texture::Filter filter =
PD::Li::Texture::Filter::LINEAR) override;
PD::Vec<Li::Vertex> VertexBuffer;
PD::Vec<PD::u16> IndexBuffer;
std::vector<Li::Vertex> VertexBuffer;
std::vector<PD::u16> IndexBuffer;
GLuint Shader;
GLuint pLocProjection;
GLuint pLocTex;

View File

@@ -123,8 +123,8 @@ void SetupShaderAttribs(GLuint Shader) {
/** Actual Backend */
void GfxGL2::Init() {
VertexBuffer.Resize(4 * 8192);
IndexBuffer.Resize(6 * 8192);
VertexBuffer.resize(4 * 8192);
IndexBuffer.resize(6 * 8192);
Shader = createShaderProgram(vertex_shader, frag_shader);
glUseProgram(Shader);
@@ -190,11 +190,11 @@ void GfxGL2::RenderDrawData(const std::vector<PD::Li::Command::Ref>& Commands) {
Commands[index]->ScissorOn == ScissorOn &&
Commands[index]->ScissorRect == ScissorRect) {
auto c = Commands[index].get();
for (size_t i = 0; i < c->IndexBuffer.Size(); i++) {
IndexBuffer[CurrentIndex++] = CurrentVertex + c->IndexBuffer.At(i);
for (size_t i = 0; i < c->IndexBuffer.size(); i++) {
IndexBuffer[CurrentIndex++] = CurrentVertex + c->IndexBuffer.at(i);
}
for (size_t i = 0; i < c->VertexBuffer.Size(); i++) {
VertexBuffer[CurrentVertex++] = c->VertexBuffer.At(i);
for (size_t i = 0; i < c->VertexBuffer.size(); i++) {
VertexBuffer[CurrentVertex++] = c->VertexBuffer.at(i);
}
index++;
}

View File

@@ -24,6 +24,7 @@ SOFTWARE.
*/
#include <pd/core/common.hpp>
#include <pd/core/strings.hpp>
namespace PD {
class PD_CORE_API Color {
@@ -65,17 +66,34 @@ class PD_CORE_API Color {
b(static_cast<u8>(255.f * b)),
a(static_cast<u8>(255.f * a)) {}
/**
* Constructor for Hex Input
* Constructor for Hex Input (is abel to run at compile time xD)
* @param hex Hex String in `#ffffff` or `#ffffffff` format
*/
Color(const std::string& hex) { Hex(hex); }
constexpr Color(const std::string_view& hex) { Hex(hex); }
/**
* Create Color Object by Hex String
* Create Color Object by Hex String (at compile time btw)
* @param hex Hex String in `#ffffff` or `#ffffffff` format
* @return Color class itself
*/
Color& Hex(const std::string& hex);
constexpr Color& Hex(const std::string_view& hex) {
if (!(hex.length() == 7 || hex.length() == 9)) {
throw "[PD] Color: hex string is not rgb or rgba!";
}
r = PD::Strings::HexChar2Int(hex[1]) * 16 +
PD::Strings::HexChar2Int(hex[2]);
g = PD::Strings::HexChar2Int(hex[3]) * 16 +
PD::Strings::HexChar2Int(hex[4]);
b = PD::Strings::HexChar2Int(hex[5]) * 16 +
PD::Strings::HexChar2Int(hex[6]);
if (hex.length() == 9) {
a = PD::Strings::HexChar2Int(hex[7]) * 16 +
PD::Strings::HexChar2Int(hex[8]);
} else {
a = 255;
}
return *this;
}
/**
* Convert this Color Object to Hex string
* @param rgba [default false] sets if 8 or 6 digit color should be returned
@@ -89,7 +107,7 @@ class PD_CORE_API Color {
* @param p Amount (supports -1.0 to 1.0 for use of sine)
* @return Class Reference
*/
Color& Fade(const Color& color, float p) {
constexpr Color& Fade(const Color& color, float p) {
a = static_cast<u8>((color.a - a) * ((p + 1.f) / 2));
b = static_cast<u8>((color.b - b) * ((p + 1.f) / 2));
g = static_cast<u8>((color.g - g) * ((p + 1.f) / 2));
@@ -101,12 +119,12 @@ class PD_CORE_API Color {
* Get 32Bit Color Value
* @return 32Bit Color Value (ABGR iirc)
*/
u32 Get() const { return (a << 24) | (b << 16) | (g << 8) | r; }
constexpr u32 Get() const { return (a << 24) | (b << 16) | (g << 8) | r; }
/**
* Get The Luminance of the Color
* @return luminance (from 0.0 to 1.0)
*/
float Luminance() const {
constexpr float Luminance() const {
// For Reference https://en.wikipedia.org/wiki/HSL_and_HSV#Lightness
return (0.3 * (r / 255.f) + 0.59 * (g / 255.f) + 0.11 * (b / 255.f));
}
@@ -114,13 +132,13 @@ class PD_CORE_API Color {
* Check if the Color is Light or Dark
* @return true if light
*/
bool IsLight() const { return (Luminance() >= 0.5); }
constexpr bool IsLight() const { return (Luminance() >= 0.5); }
/**
* Operator to cast Color to 32Bit Value
* @return 32Bit Color Value
*/
operator u32() const { return Get(); }
constexpr operator u32() const { return Get(); }
/** Public Access Data section */
u8 r;

View File

@@ -32,6 +32,7 @@ SOFTWARE.
#include <fstream>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <numbers>
@@ -62,6 +63,9 @@ SOFTWARE.
#define PD_BIT(x) (1 << x)
namespace PD {
[[noreturn]] inline void Throw(const std::string& str) {
throw std::runtime_error("[PD] " + str);
}
/** Types */
using u8 = unsigned char;
using u16 = unsigned short;

View File

@@ -25,11 +25,12 @@ SOFTWARE.
#include <pd/core/bit_util.hpp>
#include <pd/core/color.hpp>
#include <pd/core/fnv.hpp>
#include <pd/core/io.hpp>
#include <pd/core/mat.hpp>
#include <pd/core/sl/sl.hpp>
#include <pd/core/strings.hpp>
#include <pd/core/timer.hpp>
#include <pd/core/timetrace.hpp>
#include <pd/core/tween.hpp>
#include <pd/core/u128.hpp>
#include <pd/core/vec.hpp>

View File

@@ -1,43 +1,53 @@
#pragma once
/*
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/core/common.hpp>
namespace PD {
/**
* Function to get Arraysize for any type using modern c++ to
* get the size at compiletime instead of runtime
* @note this function only works for Arrays declared as
* type arr[size] and not for pointer references.
* This function will precalculate the size at compile time
* while keeping the code clean to not hardcode arraysizes
* into functions like std::fill_n
*/
template <typename T, size_t N>
constexpr size_t ArraySize(T (&)[N]) noexcept {
return N;
}
#pragma once
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/core/common.hpp>
namespace PD {
/**
* FNV-1a 32Bit hasing function
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
*/
constexpr u32 FNV1A32(std::string_view str) {
u32 ret = 0x811c9dc5; // Offset basis
for (auto& it : str) {
ret ^= it;
ret *= 0x01000193; // Prime
}
return ret;
}
/**
* FNV-1a 64Bit hasing function
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
*/
constexpr u64 FNV1A64(std::string_view str) {
u64 ret = 0xcbf29ce484222325; // Offset basis
for (auto& it : str) {
ret ^= it;
ret *= 0x00000100000001b3; // Prime
}
return ret;
}
} // namespace PD

View File

@@ -1,51 +0,0 @@
#pragma once
/*
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/core/common.hpp>
namespace PD {
/**
* Custom Allocator for Custom Vec and probably other stuff in future
*/
template <typename T>
class Allocator {
public:
Allocator() = default;
~Allocator() = default;
virtual T* Allocate(size_t n) { return new T[n]; }
virtual T* AllocateRaw(size_t n) {
return reinterpret_cast<T*>(::operator new(sizeof(T) * n));
}
virtual void DeallocateRaw(T* ptr) { operator delete(ptr); }
virtual void Deallocate(T* ptr) { delete[] ptr; }
template <typename... Args>
void Construct(T* ptr, Args&&... args) {
new (ptr) T(std::forward<Args>(args)...);
}
void Destroy(T* ptr) { ptr->~T(); }
};
} // namespace PD

View File

@@ -1,71 +0,0 @@
#pragma once
/*
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/core/common.hpp>
#include <pd/core/sl/list.hpp>
#include <pd/core/sl/pair.hpp>
namespace PD {
template <typename K, typename V, size_t bucket_count = 10>
class HashMap {
public:
HashMap() {}
~HashMap() {}
void Insert(const K& k, const V& v) {
size_t idx = Hash(k);
auto& bukket = pBuckets[idx];
for (auto& it : bukket) {
if (it.First == k) {
it.Second = v;
return;
}
}
bukket.PushBack(Pair(k, v));
}
bool Contains(const K& k) const {
size_t idx = Hash(k);
auto& bukket = pBuckets[idx];
for (auto& it : bukket) {
if (it.First == k) {
return true;
}
}
return false;
}
void Clear() {
for (size_t i = 0; i < bucket_count; i++) {
pBuckets[i].Clear();
}
}
size_t Hash(const K& k) const { return std::hash<K>{}(k) % bucket_count; }
PD::List<PD::Pair<K, V>> pBuckets[bucket_count];
};
} // namespace PD

View File

@@ -1,210 +0,0 @@
#pragma once
/*
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/core/common.hpp>
namespace PD {
template <typename T>
class List {
public:
List() {}
~List() {}
struct Node {
Node(const T& v) : Data(v) {}
T Data;
Node* Prev = nullptr;
Node* Next = nullptr;
};
class Iterator {
public:
Iterator(Node* n) : pNode(n) {}
T& operator*() { return pNode->Data; }
Iterator& operator++() {
pNode = pNode->Next;
return *this;
}
bool operator!=(const Iterator& o) const { return pNode != o.pNode; }
Node* pNode = nullptr;
};
void PushFront(const T& val) {
Node* node = new Node(val);
// node->Data = val;
node->Prev = nullptr;
node->Next = pHead;
if (pHead) {
pHead->Prev = node;
}
pHead = node;
if (!pTail) {
pTail = node;
}
pSize++;
}
void PushBack(const T& val) {
Node* node = new Node(val);
// node->Data = val;
node->Prev = pTail;
node->Next = nullptr;
if (pTail) {
pTail->Next = node;
}
pTail = node;
if (!pHead) {
pHead = node;
}
pSize++;
}
void PopFront() {
if (!pHead) {
return;
}
Node* t = pHead;
pHead = pHead->Next;
if (pHead) {
pHead->Prev = nullptr;
} else {
pTail = nullptr;
}
delete t;
pSize--;
}
void PopBack() {
if (!pTail) {
return;
}
Node* t = pTail;
pTail = pTail->Prev;
if (pTail) {
pTail->Next = nullptr;
} else {
pHead = nullptr;
}
delete t;
pSize--;
}
void Clear() {
while (pHead) {
PopFront();
}
}
void Remove(const T& v) {
Node* s = pHead;
while (s) {
if (s->Data == v) {
if (s->Prev) {
s->Prev->Next = s->Next;
} else {
pHead = s->Next;
}
if (s->Next) {
s->Next->Prev = s->Prev;
} else {
pTail = s->Prev;
}
delete s;
pSize--;
return;
}
s = s->Next;
}
}
void Reverse() {
Node* cur = pHead;
while (cur) {
Node* temp = cur->Prev;
cur->Prev = cur->Next;
cur->Next = temp;
cur = cur->Prev;
}
Node* temp = pHead;
pHead = pTail;
pTail = temp;
}
T& Front() {
if (pHead) {
return pHead->Data;
}
// Need a List Empty Error Here (exceptions are disabled on 3ds)
exit(1);
}
const T& Front() const {
if (pHead) {
return pHead->Data;
}
// Need a List Empty Error Here (exceptions are disabled on 3ds)
exit(1);
}
T& Back() {
if (pTail) {
return pTail->Data;
}
// Need a List Empty Error Here (exceptions are disabled on 3ds)
exit(1);
}
const T& Back() const {
if (pTail) {
return pTail->Data;
}
// Need a List Empty Error Here (exceptions are disabled on 3ds)
exit(1);
}
size_t Size() const { return pSize; }
Iterator begin() { return Iterator(pHead); }
Iterator end() { return Iterator(nullptr); }
private:
Node* Find(const T& v) const {
Node* t = pHead;
while (t) {
if (t->Data == v) {
return t;
}
t = t->Next;
}
return nullptr;
}
Node* pHead = nullptr;
Node* pTail = nullptr;
size_t pSize = 0;
};
} // namespace PD

View File

@@ -1,34 +0,0 @@
#pragma once
/*
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/core/sl/allocator.hpp>
#include <pd/core/sl/hashmap.hpp>
#include <pd/core/sl/list.hpp>
#include <pd/core/sl/pair.hpp>
#include <pd/core/sl/stack.hpp>
#include <pd/core/sl/tools.hpp>
#include <pd/core/sl/u128.hpp>
#include <pd/core/sl/vector.hpp>

View File

@@ -1,70 +0,0 @@
#pragma once
/*
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/core/common.hpp>
#include <pd/core/sl/vector.hpp>
namespace PD {
/**
* Custom Stack class (caus std::stack ofsten lead to memory coruption)
*/
template <typename T, typename Alloc = Allocator<T>>
class Stack {
public:
Stack() = default;
explicit Stack(size_t cap) : pVec(cap) {}
void Push(const T& val) { pVec.Add(val); }
void Pop() {
if (pVec.Size() == 0) {
exit(1);
}
pVec.PopBack();
}
T& Top() {
if (pVec.Size() == 0) {
exit(1);
}
return pVec[pVec.Size() - 1];
}
const T& Top() const {
if (pVec.Size() == 0) {
exit(1);
}
return pVec[pVec.Size() - 1];
}
bool IsEmpty() const { return pVec.Size() == 0; }
size_t Size() const { return pVec.Size(); }
void Clear() { pVec.Clear(); }
private:
Vec<T, Alloc> pVec;
};
} // namespace PD

View File

@@ -1,165 +0,0 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/core/common.hpp>
#include <pd/core/sl/allocator.hpp>
namespace PD {
/**
* Open Access Vector class (Alternative to std::vector)
*/
template <typename T, typename Alloc = Allocator<T>>
class Vec {
public:
Vec() {
pData = pAllocator.Allocate(2);
pCap = 2;
Clear();
pPos = 0;
};
Vec(const size_t& Size) {
pData = pAllocator.Allocate(Size + 2);
pCap = Size + 2;
Clear();
pPos = Size;
}
Vec(const size_t& Size, const T& v) {
pData = pAllocator.Allocate(Size + 2);
pCap = Size + 2;
Clear();
pPos = Size;
std::fill_n(pData, Size, v);
}
Vec(const T* s, const T* e) {
pData = pAllocator.Allocate(2);
pCap = 2;
Clear();
pPos = 0;
Resize(e - s);
std::copy_n(s, e - s, pData);
}
Vec(const Vec& v) {
pCap = v.pCap;
pPos = v.pPos;
pData = pAllocator.Allocate(pCap);
for (size_t i = 0; i < pPos; i++) {
pData[i] = v.pData[i];
}
}
~Vec() { pAllocator.Deallocate(pData); }
void Add(const T& v) {
if (pPos >= pCap) {
Reserve(pCap * 2);
}
pData[pPos++] = v;
}
void PopBack() {
if (pPos == 0) return;
pPos--;
}
T Pop() {
if (pPos == 0) {
// Todo: LOG
exit(1);
}
return pData[pPos--];
}
T& At(const size_t& Idx) {
if (Idx >= pPos) {
// Log
exit(1);
}
return pData[Idx];
}
const T& At(const size_t& Idx) const {
if (Idx >= pPos) {
// Log
exit(1);
}
return pData[Idx];
}
T& operator[](const size_t& Idx) { return At(Idx); }
const T& operator[](const size_t& Idx) const { return At(Idx); }
void operator+=(T v) { Add(v); }
T* Begin() { return pData; }
const T* Begin() const { return pData; }
T* End() { return pData + pPos; }
const T* End() const { return pData + pPos; }
// Support: `for(auto& it : Vec)` //
T* begin() { return pData; }
const T* begin() const { return pData; }
T* end() { return pData + pPos; }
const T* end() const { return pData + pPos; }
T* Data() { return pData; }
T* Data() const { return pData; }
size_t Size() const { return pPos; }
size_t Capacity() const { return pCap; }
void Clear() {
// Avoid memset to support std::string for now
// probably revert this decision based if it lacks performance
// or make it a setting
std::fill(pData, pData + pCap, T());
pPos = 0;
}
void Reserve(const size_t& Size) {
if (Size <= pCap) return;
T* tmp = pAllocator.Allocate(Size);
std::fill(tmp, tmp + Size, T());
std::copy(pData, pData + pCap, tmp);
pAllocator.Deallocate(pData);
pData = tmp;
pCap = Size;
}
void Resize(size_t Size) {
if (Size < pPos) {
pPos = Size;
} else if (Size > pCap) {
Reserve(Size);
}
std::fill(pData + pPos, pData + Size, T());
pPos = Size;
}
// Allocator
Alloc pAllocator;
// Data Reference Pointer
T* pData;
// Capacity
size_t pCap;
// Current Position (Size)
size_t pPos;
};
} // namespace PD

View File

@@ -30,6 +30,13 @@ namespace PD {
* Set of String Utillity Functions
*/
namespace Strings {
constexpr int HexChar2Int(char c) {
/** Imagine man hat ne lookup table dafür verwendet :/ */
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
return -1; // Error
}
/**
* Check if a String ends with a specific extension
* @param str Input string

View File

@@ -30,7 +30,7 @@ namespace PD {
* Class to calculate Maximum/Minimum and Average Timings
*/
class TimeStats {
public:
public:
/**
* Constructor taking a lengh for the List
* @param l Lengh of the data list
@@ -55,7 +55,8 @@ class TimeStats {
* @return Average
*/
u64 GetAverage() {
if (!num_val) return 0.f;
if (!num_val)
return 0.f;
u64 res = 0;
for (int i = 0; i < num_val; i++) {
res += val[smart_idx(i)];
@@ -68,7 +69,8 @@ class TimeStats {
* @return Minimum value
*/
u64 GetMin() {
if (!num_val) return 0.f;
if (!num_val)
return 0.f;
u64 res = std::numeric_limits<u64>::max();
for (int i = 0; i < num_val; i++) {
res = std::min(val[smart_idx(i)], res);
@@ -81,7 +83,8 @@ class TimeStats {
* @return Max Value
*/
u64 GetMax() {
if (!num_val) return 0.f;
if (!num_val)
return 0.f;
u64 res = 0;
for (int i = 0; i < num_val; i++) {
res = std::max(val[smart_idx(i)], res);
@@ -119,7 +122,7 @@ class TimeStats {
*/
const size_t GetNumValues() { return num_val; }
private:
private:
/**
* Get the Next Position to write to
* @param c current position
@@ -149,9 +152,9 @@ namespace TT {
* Data Structure for a TimeTrace Result
*/
class Res {
public:
public:
/** Constructore that Inits a protocol at size of 60 frames */
Res(): start(0), end(0) { protocol = TimeStats::New(60); }
Res() : start(0), end(0) { protocol = TimeStats::New(60); }
~Res() = default;
PD_SHARED(Res);
@@ -201,7 +204,7 @@ class Res {
*/
TimeStats::Ref GetProtocol() { return protocol; }
private:
private:
/** Trace ID */
std::string id;
/** Start time */
@@ -237,7 +240,7 @@ PD_CORE_API void End(const std::string &id);
* ```
*/
class Scope {
public:
public:
/**
* Constructor requiring a Name for the Trace
* @param id Name of the Trace
@@ -251,9 +254,9 @@ class Scope {
*/
~Scope() { End(ID); }
private:
private:
/** Trace Name/ID */
std::string ID;
};
} // namespace TT
} // namespace PD
} // namespace TT
} // namespace PD

View File

@@ -60,7 +60,7 @@ class Tween {
* @param delta deltatime
*/
void Update(float delta) {
time += delta / 1000.f;
time += delta * 0.001f;
if (time > tend) {
finished = true;
time = tend;
@@ -162,10 +162,10 @@ class Tween {
return -(end - start) * t * (t - 2) + start;
break;
case EaseInOutQuad:
t = time / (tend / 2);
if (t < 1) return (end - start) / 2 * t * t + start;
t = time / (tend * 0.5f);
if (t < 1) return (end - start) * 0.5f * t * t + start;
t--;
return -(end - start) / 2 * (t * (t - 2) - 1) + start;
return -(end - start) * 0.5f * (t * (t - 2) - 1) + start;
break;
case EaseInCubic:
t = time / tend;
@@ -177,20 +177,20 @@ class Tween {
return (end - start) * (t * t * t + 1) + start;
break;
// case EaseInOutCubic:
// t = time / (tend / 2);
// if (t < 1) return (end - start) / 2 * t * t * t + start;
// t = time / (tend *0.5f);
// if (t < 1) return (end - start) *0.5f * t * t * t + start;
// t--;
// return (end - start) / 2 * (t * t * t * 2) + start;
// return (end - start) *0.5f * (t * t * t * 2) + start;
// break;
case EaseInSine:
return -(end - start) * cos(time / tend * (M_PI / 2)) + (end - start) +
start;
return -(end - start) * cos(time / tend * (M_PI * 0.5f)) +
(end - start) + start;
break;
case EaseOutSine:
return (end - start) * sin(time / tend * (M_PI / 2)) + start;
return (end - start) * sin(time / tend * (M_PI * 0.5f)) + start;
break;
case EaseInOutSine:
return -(end - start) / 2 * (cos(M_PI * time / tend) - 1) + start;
return -(end - start) * 0.5f * (cos(M_PI * time / tend) - 1) + start;
break;
default: // Linear

View File

@@ -28,18 +28,18 @@ class u128 {
return u128();
}
u128 operator+(const u128& v) const {
constexpr u128 operator+(const u128& v) const {
u128 ret;
ret.pLow = pLow + v.pLow;
ret.pHigh = pHigh + v.pHigh + (ret.pLow < pLow);
return ret;
}
u128 operator&(const u128& v) const {
constexpr u128 operator&(const u128& v) const {
return u128(pLow & v.pLow, pHigh & v.pHigh);
}
u128 operator<<(u32 s) const {
constexpr u128 operator<<(u32 s) const {
if (s == 0) {
return *this;
}
@@ -52,7 +52,7 @@ class u128 {
return u128(pLow << s, (pHigh << s) | (pLow >> (64 - s)));
}
u128 operator>>(u32 s) const {
constexpr u128 operator>>(u32 s) const {
if (s == 0) {
return *this;
}
@@ -65,23 +65,23 @@ class u128 {
return u128((pLow >> s) | (pHigh << (64 - s)), pHigh >> s);
}
u128& operator|=(const u128& v) {
constexpr u128& operator|=(const u128& v) {
pLow |= v.pLow;
pHigh |= v.pHigh;
return *this;
}
u128 operator|(const u128& v) const {
constexpr u128 operator|(const u128& v) const {
return u128(pLow | v.pLow, pHigh | v.pHigh);
}
u128& operator&=(const u128& v) {
constexpr u128& operator&=(const u128& v) {
pLow &= v.pLow;
pHigh &= v.pHigh;
return *this;
}
u128 operator~() const { return u128(~pLow, ~pHigh); }
constexpr u128 operator~() const { return u128(~pLow, ~pHigh); }
/**
* Old why to make if checks possible
@@ -92,7 +92,7 @@ class u128 {
// return pLow & v.pLow || pHigh & v.pHigh;
// }
bool operator==(const u128& v) const {
constexpr bool operator==(const u128& v) const {
return pLow == v.pLow && pHigh == v.pHigh;
}
@@ -100,12 +100,14 @@ class u128 {
* Use explicit here to make sure it is only for checking and not for
* some error leading implicit bool assignments...
*/
explicit operator bool() const { return pLow != 0 || pHigh != 0; }
constexpr explicit operator bool() const { return pLow != 0 || pHigh != 0; }
/** Deprecated way to handle `flag & SomeFlag` */
bool Has(const u128& v) const { return pLow & v.pLow || pHigh & v.pHigh; }
constexpr bool Has(const u128& v) const {
return pLow & v.pLow || pHigh & v.pHigh;
}
bool operator!=(const u128& v) const { return !(*this == v); }
constexpr bool operator!=(const u128& v) const { return !(*this == v); }
};
} // namespace PD

View File

@@ -1,41 +1,45 @@
#pragma once
/*
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/core/common.hpp>
namespace PD {
template <typename T1, typename T2>
class Pair {
public:
Pair() = default;
Pair(const T1& f, const T2& s) : First(f), Second(s) {}
Pair(T1&& f, T2&& s) : First(std::move(f)), Second(std::move(s)) {}
~Pair() = default;
T1 First;
T2 Second;
};
#pragma once
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/core/core.hpp>
namespace PD {
class Snd {
public:
Snd(const std::string& name = "NullSnd") : pName(name) {};
~Snd() = default;
PD_SHARED(Snd);
virtual void Init() {}
virtual void Deinit() {}
virtual bool Done(int buf_idx) {}
virtual void Update(int buf_idx, void* data) {}
virtual bool IsChannelPlaying(int chn) {}
virtual bool IsChannelPaused(int chn) {}
const std::string pName = "NullSnd";
};
} // namespace PD

View File

@@ -55,28 +55,5 @@ void RGB32toRGBA24(std::vector<u8> &out, const std::vector<u8> &in,
*/
PD_IMAGE_API void Reverse32(std::vector<u8> &buf, const int &w, const int &h);
PD_IMAGE_API void ReverseBuf(std::vector<u8> &buf, size_t bpp, int w, int h);
/**
* Convert RGB24 to RGBA32 by adding a 4th alpha value set to 255
* to every pixel
* @param out Result List
* @param in Input Buffer List (rgb24)
* @param w width of the image
* @param h height of the image
*/
PD_IMAGE_API
void RGB24toRGBA32(PD::Vec<u8> &out, const PD::Vec<u8> &in, const int &w,
const int &h);
PD_IMAGE_API
void RGB32toRGBA24(PD::Vec<u8> &out, const PD::Vec<u8> &in, const int &w,
const int &h);
/**
* Reverse 32 (RGBA -> ABGR || ABGR -> RGBA)
* @param buf Buffer to convert
* @param w width
* @param h height
*/
PD_IMAGE_API void Reverse32(PD::Vec<u8> &buf, const int &w, const int &h);
PD_IMAGE_API void ReverseBuf(PD::Vec<u8> &buf, size_t bpp, int w, int h);
} // namespace ImgConvert
} // namespace PD

View File

@@ -37,17 +37,17 @@ class Command {
PD_UNIQUE(Command);
Command& AddIdx(const u16& idx) {
IndexBuffer.Add(VertexBuffer.Size() + idx);
IndexBuffer.push_back(VertexBuffer.size() + idx);
return *this;
}
Command& AddVtx(const Vertex& v) {
VertexBuffer.Add(std::move(v));
VertexBuffer.push_back(std::move(v));
return *this;
}
PD::Vec<Vertex> VertexBuffer;
PD::Vec<u16> IndexBuffer;
std::vector<Vertex> VertexBuffer;
std::vector<u16> IndexBuffer;
ivec4 ScissorRect;
bool ScissorOn = false;
int Layer;

View File

@@ -64,14 +64,22 @@ class PD_LITHIUM_API DrawList {
/**
* Append an input drawlist on top of this one
* This Function will clear the Input list to make sure
* THat the moved memory blocks don't get used
* That the moved memory blocks don't get used
* @param list DrawList to move into current
*/
void Merge(DrawList::Ref list);
/**
* Optimize a Drawlist to a more or less perfect order
* to reduce drawcall overhead... This function also uses
* the Layersystem to keep specific stuff in the correct order
*/
void Optimize();
Command::Ref PreGenerateCmd();
void AddCommand(Command::Ref v);
void Clear();
void Layer(int l) { this->pLayer = l; }
int Layer() { return this->pLayer; }
void SetFont(Font::Ref font) { pCurrentFont = font; }
void SetFontScale(float scale) { pFontScale = scale; }
@@ -97,7 +105,7 @@ class PD_LITHIUM_API DrawList {
* Extended Draw Text Function
*/
void DrawTextEx(const fvec2& p, const std::string& text, u32 color,
LiTextFlags flags, fvec2 box = fvec2(0.f));
LiTextFlags flags, const fvec2& box = fvec2(0.f));
void DrawLine(const fvec2& a, const fvec2& b, u32 color, int t = 1);
/**
* Take list of points and display it as a line on screen
@@ -106,7 +114,7 @@ class PD_LITHIUM_API DrawList {
* @param flags Additional Flags (Close for go back to starting point)
* @param thickness Thickness of the Line
*/
void DrawPolyLine(const Vec<fvec2>& points, u32 clr, u32 flags = 0,
void DrawPolyLine(const std::vector<fvec2>& points, u32 clr, u32 flags = 0,
int thickness = 1);
/**
* Take a List ofpoints and display it as Filled Shape
@@ -114,7 +122,7 @@ class PD_LITHIUM_API DrawList {
* @param points List of Points
* @param clr Color of the shape
*/
void DrawConvexPolyFilled(const Vec<fvec2>& points, u32 clr);
void DrawConvexPolyFilled(const std::vector<fvec2>& points, u32 clr);
// SECTION: PATH API //
@@ -124,20 +132,28 @@ class PD_LITHIUM_API DrawList {
* @param num_points Number of Positions you want to add
*/
void PathReserve(size_t num_points) {
pPath.Reserve(pPath.Size() + num_points);
pPath.reserve(pPath.size() + num_points);
}
/**
* Clear current Path
* @note PathStroke and PathFill will automatically clear
*/
void PathClear() { pPath.Clear(); }
void PathClear() { pPath.clear(); }
/**
* Add a Point to the Path
* @note Keep in mind that this function is used for
* setting the starting point
* @param v Position to add
*/
void PathAdd(const fvec2& v) { pPath.Add(v); }
void PathAdd(const fvec2& v) { pPath.push_back(v); }
/**
* Add a Point to the Path
* @note Keep in mind that this function is used for
* setting the starting point
* @param x X Position to add
* @param y Y Position to add
*/
void PathAdd(float x, float y) { pPath.push_back(fvec2(x, y)); }
/**
* Path Stroke Create Line from point to point
* @note For Primitives like Rect or Triangle mak sure to use
@@ -148,7 +164,7 @@ class PD_LITHIUM_API DrawList {
*/
void PathStroke(u32 clr, int thickness = 1, u32 flags = 0) {
DrawPolyLine(pPath, clr, flags, thickness);
pPath.Clear();
pPath.clear();
}
/**
* Fill a Path with a Color
@@ -158,7 +174,7 @@ class PD_LITHIUM_API DrawList {
*/
void PathFill(u32 clr) {
DrawConvexPolyFilled(pPath, clr);
pPath.Clear();
pPath.clear();
}
void PathArcToN(const fvec2& c, float radius, float a_min, float a_max,
int segments);
@@ -175,25 +191,25 @@ class PD_LITHIUM_API DrawList {
/// @param flags DrawFlags (for special rounding rules)
void PathRectEx(fvec2 a, fvec2 b, float rounding = 0.f, u32 flags = 0);
void PushClipRect(const fvec4& cr) { pClipRects.Push(cr); }
void PushClipRect(const fvec4& cr) { pClipRects.push(cr); }
void PopClipRect() {
if (pClipRects.IsEmpty()) {
if (pClipRects.empty()) {
return;
}
pClipRects.Pop();
pClipRects.pop();
}
/** One linear Clip rect Setup */
void pClipCmd(Command* cmd);
/** Data Section */
Stack<fvec4> pClipRects;
int Layer;
std::stack<fvec4> pClipRects;
int pLayer;
float pFontScale = 0.7f;
Font::Ref pCurrentFont;
Texture::Ref CurrentTex;
std::vector<Command::Ref> pDrawList;
PD::Vec<fvec2> pPath;
std::vector<fvec2> pPath;
u32 pNumIndices = 0;
u32 pNumVertices = 0;
};

View File

@@ -101,6 +101,10 @@ class PD_LITHIUM_API Font {
*/
void pMakeAtlas(bool final, std::vector<u8>& font_tex, int texszs,
PD::Li::Texture::Ref tex);
std::string pWrapText(const std::string& txt, float scale,
const PD::fvec2& max, PD::fvec2& dim);
std::string pShortText(const std::string& txt, float scale,
const PD::fvec2& max, PD::fvec2& dim);
/** Data Section */
int PixelHeight;

View File

@@ -46,10 +46,11 @@ class PD_LITHIUM_API Renderer {
u32 color);
static void CmdTriangle(Command* cmd, const fvec2 a, const fvec2 b,
const fvec2 c, u32 clr);
static void CmdPolyLine(const Vec<fvec2>& points, u32 clr, u32 flags = 0,
int thickness = 1);
static void CmdConvexPolyFilled(Command* cmd, const Vec<fvec2>& points,
u32 clr, Texture::Ref tex);
static void CmdPolyLine(const std::vector<fvec2>& points, u32 clr,
u32 flags = 0, int thickness = 1);
static void CmdConvexPolyFilled(Command* cmd,
const std::vector<fvec2>& points, u32 clr,
Texture::Ref tex);
// SECTION: InBounds Checks

View File

@@ -45,8 +45,8 @@ class ID {
* used when directly placing a string istead of using ID("")
* @param text Input String
*/
ID(const char* text) {
pID = PD::Strings::FastHash(text);
constexpr ID(const char* text) {
pID = PD::FNV1A32(text);
pName = text;
}
/**
@@ -56,16 +56,17 @@ class ID {
~ID() = default;
/** Get The ID Initial Name */
const std::string& GetName() const { return pName; }
constexpr const std::string_view& GetNameView() const { return pName; }
const std::string GetName() const { return std::string(pName); }
/** Getter for the raw 32bit int id */
const u32& RawID() const { return pID; }
constexpr const u32& RawID() const { return pID; }
/** Return the ID when casting to u32 */
operator u32() const { return pID; }
constexpr operator u32() const { return pID; }
u32 pID; ///< Hash of the name
std::string pName; ///< Name
u32 pID; ///< Hash of the name
std::string_view pName; ///< Name
};
} // namespace UI7
} // namespace PD

View File

@@ -79,19 +79,18 @@ class PD_UI7_API IO {
bool ShowFrameBorder = false; // not implemented yet
float OverScrollMod = 0.15f;
u64 DoubleClickTime = 500; // Milliseconds
PD::List<Pair<UI7::ID, Li::DrawList::Ref>> DrawListRegestry;
std::list<std::pair<UI7::ID, Li::DrawList::Ref>> DrawListRegestry;
// Short define for DrawKistRegestryLast
PD::List<Pair<UI7::ID, Li::DrawList::Ref>> pDLRL;
// std::vector<std::pair<UI7::ID, Li::DrawList::Ref>> DrawListRegestry;
std::list<std::pair<UI7::ID, Li::DrawList::Ref>> pDLRL;
Li::DrawList::Ref Back;
Li::DrawList::Ref Front;
u32 NumVertices = 0; ///< Debug Vertices Num
u32 NumIndices = 0; ///< Debug Indices Num
Vec<u32> MenuOrder;
std::vector<u32> MenuOrder;
// DrawListApi
void RegisterDrawList(const UI7::ID& id, Li::DrawList::Ref v) {
DrawListRegestry.PushBack(Pair(id, v));
DrawListRegestry.push_back(std::make_pair(id, v));
}
void AddViewPort(const ID& id, const ivec4& size) {

View File

@@ -52,7 +52,7 @@ class PD_UI7_API Layout {
PD_SHARED(Layout);
const std::string& GetName() const { return ID.GetName(); }
const std::string GetName() const { return ID.GetName(); }
const UI7::ID& GetID() const { return this->ID; }
const fvec2& GetPosition() const { return Pos; }
@@ -135,7 +135,7 @@ class PD_UI7_API Layout {
bool Scrolling[2];
// Objects
PD::List<Container::Ref> Objects;
std::list<Container::Ref> Objects;
std::vector<Container::Ref> IDObjects;
};
} // namespace UI7

View File

@@ -37,7 +37,7 @@ SOFTWARE.
* Major Minor Patch Build
* 0x01010000 -> 1.1.0-0
*/
#define UI7_VERSION 0x00050100
#define UI7_VERSION 0x00060000
namespace PD {
namespace UI7 {
@@ -55,18 +55,18 @@ class PD_UI7_API Context {
PD_SHARED(Context);
void AddViewPort(const ID &id, const ivec4 &vp);
void UseViewPort(const ID &id);
void AddViewPort(const ID& id, const ivec4& vp);
void UseViewPort(const ID& id);
void Update();
bool BeginMenu(const ID &id, UI7MenuFlags flags = 0, bool *pShow = nullptr);
bool BeginMenu(const ID& id, UI7MenuFlags flags = 0, bool* pShow = nullptr);
void EndMenu();
void AboutMenu(bool *show = nullptr);
void MetricsMenu(bool *show = nullptr);
void StyleEditor(bool *show = nullptr);
void AboutMenu(bool* show = nullptr);
void MetricsMenu(bool* show = nullptr);
void StyleEditor(bool* show = nullptr);
Li::DrawList::Ref GetDrawData() { return pIO->FDL; }
Menu::Ref pGetOrCreateMenu(const ID &id) {
Menu::Ref pGetOrCreateMenu(const ID& id) {
auto menu = pMenus.find(id);
if (menu == pMenus.end()) {
pMenus[id] = Menu::New(id, pIO);

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22)
project(pd-core LANGUAGES CXX VERSION 0.5.1)
project(pd-core LANGUAGES CXX VERSION 0.6.0)
set(SRC
source/bit_util.cpp

View File

@@ -25,39 +25,6 @@ SOFTWARE.
#include <pd/core/color.hpp>
namespace PD {
// The Solution of the biggest performance issue
// A Simple Lookup table
static const std::map<char, int> HEX_DEC = {
{'0', 0}, {'1', 1}, {'2', 2}, {'3', 3}, {'4', 4}, {'5', 5},
{'6', 6}, {'7', 7}, {'8', 8}, {'9', 9}, {'a', 10}, {'b', 11},
{'c', 12}, {'d', 13}, {'e', 14}, {'f', 15}, {'A', 10}, {'B', 11},
{'C', 12}, {'D', 13}, {'E', 14}, {'F', 15}};
PD_CORE_API Color& Color::Hex(const std::string& hex) {
#ifdef PD_NO_SAFE_CODE
/// Safetey check (not required if you programm well xd)
if (hex.length() != 7 || hex.length() != 9 || hex.length() != 6 ||
hex.length() != 8 || std::find_if(hex.begin(), hex.end(), [](char c) {
return !std::isxdigit(c);
}) != hex.end()) {
return *this;
}
#endif
int offset = ((hex.length() == 7 || hex.length() == 9) ? 1 : 0);
r = HEX_DEC.at(hex[offset]) * 16 + HEX_DEC.at(hex[offset + 1]);
offset += 2;
g = HEX_DEC.at(hex[offset]) * 16 + HEX_DEC.at(hex[offset + 1]);
offset += 2;
b = HEX_DEC.at(hex[offset]) * 16 + HEX_DEC.at(hex[offset + 1]);
offset += 2;
if (hex.length() == 9) {
a = HEX_DEC.at(hex[offset]) * 16 + HEX_DEC.at(hex[offset + 1]);
} else {
a = 255;
}
return *this;
}
PD_CORE_API std::string Color::Hex(bool rgba) const {
/** Need to int cast (so it is used as num and not char...) */
std::stringstream s;
@@ -65,7 +32,7 @@ PD_CORE_API std::string Color::Hex(bool rgba) const {
s << std::hex << std::setw(2) << std::setfill('0') << (int)r;
s << std::hex << std::setw(2) << std::setfill('0') << (int)g;
s << std::hex << std::setw(2) << std::setfill('0') << (int)b;
if (rgba) {
if (rgba || a != 255) { // QoL change btw
s << std::hex << std::setw(2) << std::setfill('0') << (int)a;
}
return s.str();

View File

@@ -79,59 +79,4 @@ PD_IMAGE_API void ReverseBuf(std::vector<u8> &buf, size_t bpp, int w, int h) {
}
}
}
PD_IMAGE_API void RGB24toRGBA32(PD::Vec<u8> &out, const PD::Vec<u8> &in,
const int &w, const int &h) {
// Converts RGB24 to RGBA32
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int src = (y * w + x) * 3;
int dst = (y * w + x) * 4;
out[dst + 0] = in[src + 0];
out[dst + 1] = in[src + 1];
out[dst + 2] = in[src + 2];
out[dst + 3] = 255;
}
}
}
PD_IMAGE_API void RGB32toRGBA24(PD::Vec<u8> &out, const PD::Vec<u8> &in,
const int &w, const int &h) {
// Converts RGB24 to RGBA32
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int src = (y * w + x) * 4;
int dst = (y * w + x) * 3;
out[dst + 0] = in[src + 0];
out[dst + 1] = in[src + 1];
out[dst + 2] = in[src + 2];
}
}
}
PD_IMAGE_API void Reverse32(PD::Vec<u8> &buf, const int &w, const int &h) {
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int i = y * w + x;
u8 t0 = buf[i + 0];
u8 t1 = buf[i + 1];
buf[i + 0] = buf[i + 3];
buf[i + 1] = buf[i + 2];
buf[i + 3] = t0;
buf[i + 2] = t1;
}
}
}
PD_IMAGE_API void ReverseBuf(PD::Vec<u8> &buf, size_t bpp, int w, int h) {
PD::Vec<u8> cpy = buf;
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int pos = (y * w + x) * bpp;
for (size_t i = 0; i < bpp; i++) {
buf[pos + bpp - 1 - i] = cpy[pos + i];
}
}
}
}
} // namespace PD::ImgConvert

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22)
project(pd-lithium LANGUAGES CXX VERSION 0.5.1)
project(pd-lithium LANGUAGES CXX VERSION 0.6.0)
option(PD_LI_INCLUDE_FONTS "Include Fonts" OFF)

View File

@@ -37,27 +37,47 @@ PD_LITHIUM_API void DrawList::Clear() {
pNumIndices = 0;
pNumVertices = 0;
pDrawList.clear();
pPath.clear();
while (!pClipRects.empty()) {
pClipRects.pop();
}
}
PD_LITHIUM_API void DrawList::AddCommand(Command::Ref v) {
pNumIndices += v->IndexBuffer.Size();
pNumVertices += v->VertexBuffer.Size();
pNumIndices += v->IndexBuffer.size();
pNumVertices += v->VertexBuffer.size();
pDrawList.push_back(std::move(v));
}
PD_LITHIUM_API void DrawList::Merge(DrawList::Ref list) {
for (size_t i = 0; i < list->pDrawList.size(); i++) {
pNumIndices += list->pDrawList[i]->IndexBuffer.Size();
pNumVertices += list->pDrawList[i]->VertexBuffer.Size();
pNumIndices += list->pDrawList[i]->IndexBuffer.size();
pNumVertices += list->pDrawList[i]->VertexBuffer.size();
pDrawList.push_back(std::move(list->pDrawList[i]));
}
/** Make sure The list gets cleared */
list->Clear();
}
PD_LITHIUM_API void DrawList::Optimize() {
#ifndef NDEBUG
PD::TT::Scope s("Optimize");
#endif
std::sort(pDrawList.begin(), pDrawList.end(),
[](const PD::Li::Command::Ref &a, const PD::Li::Command::Ref &b) {
if (a->Layer == b->Layer) { // Same layer
if (a->Tex == b->Tex) { // same tex
return a->Index < b->Index;
}
return a->Tex < b->Tex; // order by address
}
return a->Layer < b->Layer; // Order by layer
});
}
PD_LITHIUM_API Command::Ref DrawList::PreGenerateCmd() {
Command::Ref cmd = Command::New();
cmd->Layer = Layer;
cmd->Layer = pLayer;
cmd->Index = pDrawList.size();
cmd->Tex = CurrentTex;
pClipCmd(cmd.get());
@@ -65,9 +85,9 @@ PD_LITHIUM_API Command::Ref DrawList::PreGenerateCmd() {
}
PD_LITHIUM_API void DrawList::pClipCmd(Command *cmd) {
if (!pClipRects.IsEmpty()) {
if (!pClipRects.empty()) {
cmd->ScissorOn = true;
cmd->ScissorRect = ivec4(pClipRects.Top());
cmd->ScissorRect = ivec4(pClipRects.top());
}
}
@@ -231,21 +251,21 @@ PD_LITHIUM_API void DrawList::DrawCircleFilled(const fvec2 &center, float rad,
}
// 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) {
PD_LITHIUM_API void DrawList::DrawPolyLine(const std::vector<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;
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);
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);
}
@@ -253,9 +273,9 @@ PD_LITHIUM_API void DrawList::DrawPolyLine(const Vec<fvec2> &points, u32 clr,
AddCommand(std::move(cmd));
}
PD_LITHIUM_API void DrawList::DrawConvexPolyFilled(const Vec<fvec2> &points,
u32 clr) {
if (points.Size() < 3) {
PD_LITHIUM_API void DrawList::DrawConvexPolyFilled(
const std::vector<fvec2> &points, u32 clr) {
if (points.size() < 3) {
return; // Need at least three points
}
auto cmd = PreGenerateCmd();
@@ -271,23 +291,23 @@ PD_LITHIUM_API void DrawList::DrawText(const fvec2 &pos,
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;
cmds[i]->Index = pDrawList.size() + i;
cmds[i]->Layer = pLayer;
AddCommand(std::move(cmds[i]));
}
}
PD_LITHIUM_API void DrawList::DrawTextEx(const fvec2 &p,
const std::string &text, u32 color,
LiTextFlags flags, fvec2 box) {
LiTextFlags flags, const 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;
cmds[i]->Index = pDrawList.size() + i;
cmds[i]->Layer = pLayer;
AddCommand(std::move(cmds[i]));
}
}

View File

@@ -250,6 +250,10 @@ PD_LITHIUM_API void Font::CmdTextEx(std::vector<Command::Ref> &cmds,
fvec2 td;
fvec2 rpos = pos;
fvec2 rbox = box;
std::string txt = text;
if (flags & LiTextFlags_Wrap) {
txt = pWrapText(txt, scale, box, td);
}
if (flags & (LiTextFlags_AlignMid | LiTextFlags_AlignRight)) {
td = GetTextBounds(text, scale);
}
@@ -261,17 +265,17 @@ PD_LITHIUM_API void Font::CmdTextEx(std::vector<Command::Ref> &cmds,
}
std::vector<std::string> lines;
std::istringstream iss(text);
std::istringstream iss(txt);
std::string tmp;
while (std::getline(iss, tmp)) {
lines.push_back(tmp);
}
for (auto &it : lines) {
/*if (flags & LITextFlags_Short) {
if (flags & LiTextFlags_Short) {
fvec2 tmp_dim;
it = ShortText(it, box.x() - pos.x(), tmp_dim);
}*/
it = pShortText(it, scale, box - pos, tmp_dim);
}
auto wline = Strings::MakeWstring(it);
auto cmd = Command::New();
auto Tex = GetCodepoint(wline[0]).Tex;
@@ -315,5 +319,62 @@ PD_LITHIUM_API void Font::CmdTextEx(std::vector<Command::Ref> &cmds,
}
}
PD_LITHIUM_API std::string Font::pWrapText(const std::string &txt, float scale,
const PD::fvec2 &max,
PD::fvec2 &dim) {
std::string ret;
std::string line;
int lx = 0;
std::stringstream s(txt);
std::string tmp;
// Simply go over every word
while (s >> tmp) {
auto d = GetTextBounds(tmp, scale);
if (lx + d.x <= max.x) {
line += tmp + ' ';
lx += d.x;
} else {
ret += line + '\n';
line = tmp + ' ';
lx = GetTextBounds(line, scale).x;
}
}
ret += line;
dim = GetTextBounds(ret, scale);
return ret;
}
PD_LITHIUM_API std::string Font::pShortText(const std::string &txt, float scale,
const PD::fvec2 &max,
PD::fvec2 &dim) {
auto test = GetTextBounds(txt, scale);
if (test.x < max.x) {
return txt;
}
std::string ext;
std::string ph = "(...)"; // placeholder
std::string tmp = txt;
std::string ret;
auto maxlen = max.x;
size_t ext_ = tmp.find_last_of('.');
if (ext_ != tmp.npos) {
ext = tmp.substr(ext_);
tmp = tmp.substr(0, ext_);
}
maxlen -= GetTextBounds(ext, scale).x;
maxlen -= GetTextBounds(ph, scale).x;
for (auto &it : tmp) {
if (GetTextBounds(ret, scale).x > maxlen) {
ret += ph;
ret += ext;
dim = GetTextBounds(ret, scale);
return ret;
}
ret += it;
}
return ret;
}
} // namespace Li
} // namespace PD
} // namespace PD

View File

@@ -110,10 +110,9 @@ PD_LITHIUM_API void Renderer::CmdTriangle(Command* cmd, const fvec2 a,
// 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) {
PD_LITHIUM_API void Renderer::CmdConvexPolyFilled(
Command* cmd, const std::vector<fvec2>& points, u32 clr, Texture::Ref tex) {
if (points.size() < 3 || tex == nullptr) {
return; // Need at least three points
}
@@ -121,11 +120,11 @@ PD_LITHIUM_API void Renderer::CmdConvexPolyFilled(Command* cmd,
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;
for (const auto& it : points) {
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)
@@ -134,10 +133,10 @@ PD_LITHIUM_API void Renderer::CmdConvexPolyFilled(Command* cmd,
auto uv_bl = tex->UV.BotLeft();
// Render
for (int i = 2; i < (int)points.Size(); i++) {
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++) {
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);

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22)
project(pd-ui7 LANGUAGES CXX VERSION 0.5.1)
project(pd-ui7 LANGUAGES CXX VERSION 0.6.0)
set(SRC
source/theme.cpp

View File

@@ -50,10 +50,10 @@ PD_UI7_API void Button::Draw() {
// Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
// io->Ren->OnScreen(screen);
list->DrawRectFilled(FinalPos(), size, io->Theme->Get(color));
list->Layer++;
list->pLayer++;
list->DrawText(FinalPos() + size * 0.5 - tdim * 0.5, label,
io->Theme->Get(UI7Color_Text));
list->Layer--;
list->pLayer--;
}
PD_UI7_API void Button::Update() {

View File

@@ -83,11 +83,11 @@ PD_UI7_API void DragData<T>::Draw() {
vec2 td = io->Font->GetTextBounds(p, io->FontScale);
list->DrawRectFilled(FinalPos() + fvec2(off_x, 0), td + io->FramePadding,
io->Theme->Get(UI7Color_Button));
list->Layer++;
list->pLayer++;
list->DrawTextEx(FinalPos() + fvec2(off_x, 0), p,
io->Theme->Get(UI7Color_Text), LiTextFlags_AlignMid,
td + io->FramePadding);
list->Layer--;
list->pLayer--;
off_x += td.x + io->ItemSpace.x + io->FramePadding.x;
}
list->DrawText(FinalPos() + fvec2(off_x, io->FramePadding.y * 0.5), label,

View File

@@ -29,11 +29,11 @@ PD_UI7_API void Image::Draw() {
// Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
// Assert(img.get(), "Image is nullptr!");
// io->Ren->OnScreen(screen);
list->Layer++;
list->pLayer++;
list->DrawTexture(img);
list->DrawRectFilled(FinalPos(), newsize, 0xffffffff);
list->DrawSolid();
list->Layer--;
list->pLayer--;
}
} // namespace UI7
} // namespace PD

View File

@@ -34,9 +34,8 @@ PD_UI7_API void UI7::IO::Update() {
Time->Update();
InputHandler->Update();
Framerate = 1000.f / Delta;
DrawListRegestry.Clear();
DrawListRegestry.PushFront(
Pair<UI7::ID, Li::DrawList::Ref>("CtxBackList", Back));
DrawListRegestry.clear();
DrawListRegestry.push_front(std::make_pair("CtxBackList", Back));
// RegisterDrawList("CtxBackList", Back);
NumIndices = FDL->pNumIndices;
NumVertices = FDL->pNumVertices;

View File

@@ -66,7 +66,7 @@ PD_UI7_API void Layout::AddObject(Container::Ref obj) {
obj->Update();
CursorMove(obj->GetSize());
obj->HandleScrolling(ScrollOffset, WorkRect);
Objects.PushBack(obj);
Objects.push_back(obj);
}
PD_UI7_API void Layout::AddObjectEx(Container::Ref obj, u32 flags) {
@@ -83,9 +83,9 @@ PD_UI7_API void Layout::AddObjectEx(Container::Ref obj, u32 flags) {
obj->HandleScrolling(ScrollOffset, WorkRect);
}
if (flags & UI7LytAdd_Front) {
Objects.PushFront(obj);
Objects.push_front(obj);
} else {
Objects.PushBack(obj);
Objects.push_back(obj);
}
}
@@ -133,7 +133,7 @@ PD_UI7_API void Layout::Update() {
for (auto& it : tbr) {
IDObjects.erase(IDObjects.begin() + it);
}
Objects.Clear();
Objects.clear();
WorkRect = fvec4(fvec2(WorkRect.x, WorkRect.y), Size - IO->MenuPadding);
CursorInit();
}

View File

@@ -27,24 +27,24 @@ SOFTWARE.
namespace PD {
namespace UI7 {
Menu::Menu(const ID &id, IO::Ref io) : pIO(io), pID(id) {
Menu::Menu(const ID& id, IO::Ref io) : pIO(io), pID(id) {
pLayout = Layout::New(id, io);
TitleBarHeight = io->FontScale * 30.f;
pLayout->WorkRect.y += TitleBarHeight;
pLayout->CursorInit();
}
PD_UI7_API void Menu::Label(const std::string &label) {
PD_UI7_API void Menu::Label(const std::string& label) {
// Layout API
auto r = Label::New(label, pIO);
r->SetClipRect(fvec4(pLayout->GetPosition(), pLayout->GetSize()));
pLayout->AddObject(r);
}
PD_UI7_API bool Menu::Button(const std::string &label) {
PD_UI7_API bool Menu::Button(const std::string& label) {
bool ret = false;
u32 id = Strings::FastHash("btn" + label +
std::to_string(pLayout->Objects.Size()));
std::to_string(pLayout->Objects.size()));
Container::Ref r = pLayout->FindObject(id);
if (!r) {
r = Button::New(label, pIO);
@@ -57,9 +57,9 @@ PD_UI7_API bool Menu::Button(const std::string &label) {
return ret;
}
PD_UI7_API void Menu::Checkbox(const std::string &label, bool &v) {
PD_UI7_API void Menu::Checkbox(const std::string& label, bool& v) {
u32 id = Strings::FastHash("cbx" + label +
std::to_string(pLayout->Objects.Size()));
std::to_string(pLayout->Objects.size()));
Container::Ref r = pLayout->FindObject(id);
if (!r) {
r = Checkbox::New(label, v, pIO);
@@ -76,7 +76,7 @@ PD_UI7_API void Menu::Image(Li::Texture::Ref img, fvec2 size, Li::Rect uv) {
PD_UI7_API void Menu::Separator() {
// Dynamic Objects are very simple...
Container::Ref r = DynObj::New(
[=, this](UI7::IO::Ref io, Li::DrawList::Ref l, UI7::Container *self) {
[=, this](UI7::IO::Ref io, Li::DrawList::Ref l, UI7::Container* self) {
l->DrawRectFilled(self->FinalPos(), self->GetSize(),
pIO->Theme->Get(UI7Color_TextDead));
});
@@ -85,10 +85,10 @@ PD_UI7_API void Menu::Separator() {
pLayout->AddObject(r);
}
PD_UI7_API void Menu::SeparatorText(const std::string &label) {
PD_UI7_API void Menu::SeparatorText(const std::string& label) {
// Also note to use [=] instead of [&] to not undefined access label
Container::Ref r = DynObj::New([=, this](UI7::IO::Ref io, Li::DrawList::Ref l,
UI7::Container *self) {
UI7::Container* self) {
fvec2 size = self->GetSize();
fvec2 tdim = io->Font->GetTextBounds(label, io->FontScale);
fvec2 pos = self->FinalPos();
@@ -141,7 +141,7 @@ PD_UI7_API void Menu::HandleScrolling() {
pLayout->ScrollStart = pLayout->ScrollOffset;
}
if (pIO->InputHandler->DragObject(
"sbg" + pID.pName,
"sbg" + pID.GetName(),
fvec4(pLayout->Pos, fvec2(0.f)) + pLayout->WorkRect)) {
if (pIO->InputHandler->DragReleasedAW) {
} else {
@@ -238,8 +238,8 @@ PD_UI7_API void Menu::DrawBaseLayout() {
/** Resize Sym (Render on Top of Everything) */
if (!(Flags & UI7MenuFlags_NoResize)) {
Container::Ref r = DynObj::New(
[](IO::Ref io, Li::DrawList::Ref l, UI7::Container *self) {
l->Layer = 1;
[](IO::Ref io, Li::DrawList::Ref l, UI7::Container* self) {
l->pLayer = 1;
l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(0, 20));
l->PathAdd(self->FinalPos() + self->GetSize());
l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(20, 0));
@@ -254,8 +254,8 @@ PD_UI7_API void Menu::DrawBaseLayout() {
/** Background */
Container::Ref r = DynObj::New([](IO::Ref io, Li::DrawList::Ref l,
UI7::Container *self) {
l->Layer = 0;
UI7::Container* self) {
l->pLayer = 0;
l->PathRectEx(self->FinalPos(), self->FinalPos() + self->GetSize(), 10.f,
LiPathRectFlags_KeepTop | LiPathRectFlags_KeepBot);
l->PathFill(io->Theme->Get(UI7Color_Background));
@@ -271,12 +271,12 @@ PD_UI7_API void Menu::DrawBaseLayout() {
}
if (!(Flags & UI7MenuFlags_NoTitlebar)) {
Container::Ref r = DynObj::New(
[=, this](UI7::IO::Ref io, Li::DrawList::Ref l, UI7::Container *self) {
l->Layer = 20;
[=, this](UI7::IO::Ref io, Li::DrawList::Ref l, UI7::Container* self) {
l->pLayer = 20;
/** Header Bar */
l->DrawRectFilled(self->FinalPos(), self->GetSize(),
io->Theme->Get(UI7Color_Header));
l->Layer = 21;
l->pLayer = 21;
/** Inline if statement to shift the Text if collapse sym is shown */
/** What the hell is this code btw (didn't found a better way) */
l->DrawText(self->FinalPos() + fvec2(Flags & UI7MenuFlags_NoClose
@@ -295,9 +295,9 @@ PD_UI7_API void Menu::DrawBaseLayout() {
/** Collapse Sym */
if (!(Flags & UI7MenuFlags_NoCollapse)) {
r = DynObj::New([=, this](UI7::IO::Ref io, Li::DrawList::Ref l,
UI7::Container *self) {
UI7::Container* self) {
/** This sym actually requires layer 21 (i dont know why) */
l->Layer = 21;
l->pLayer = 21;
/**
* Symbol (Position Swapping set by pIsOpen ? openpos : closepos;)
*/
@@ -351,7 +351,7 @@ PD_UI7_API void Menu::Update() {
pLayout->Update();
}
PD_UI7_API bool Menu::BeginTreeNode(const ID &id) {
PD_UI7_API bool Menu::BeginTreeNode(const ID& id) {
// As of some notes this should work:
auto n = pTreeNodes.find(id);
if (n == pTreeNodes.end()) {
@@ -368,7 +368,7 @@ PD_UI7_API bool Menu::BeginTreeNode(const ID &id) {
// Object
auto r =
DynObj::New([=, this](IO::Ref io, Li::DrawList::Ref l, Container *self) {
DynObj::New([=, this](IO::Ref io, Li::DrawList::Ref l, Container* self) {
fvec2 ts = self->FinalPos() + fvec2(0, 7);
fvec2 pl[2] = {fvec2(10, 5), fvec2(0, 10)};
if (n->second) {
@@ -383,7 +383,7 @@ PD_UI7_API bool Menu::BeginTreeNode(const ID &id) {
id.GetName(), io->Theme->Get(UI7Color_Text));
});
/** Yes this new function handler was created for tree nodes */
r->AddInputHandler([=, this](IO::Ref io, Container *self) {
r->AddInputHandler([=, this](IO::Ref io, Container* self) {
if (io->InputHandler->DragObject(
ID(pID.GetName() + id.GetName()),
fvec4(self->FinalPos(), self->GetSize()))) {

View File

@@ -272,7 +272,7 @@ PD_UI7_API void Context::MetricsMenu(bool *show) {
}
// Well this are Li Drawlists now and they do not count their stats (yet)
/*if (m->BeginTreeNode("DrawLists (" +
std::to_string(pIO->DrawListRegestry.Size()) + ")")) {
std::to_string(pIO->DrawListRegestry.size()) + ")")) {
for (auto &it : pIO->DrawListRegestry) {
if (m->BeginTreeNode(it.First.GetName())) {
m->Label("Vertices: " + std::to_string(it.Second->NumVertices));