57 Commits
Author SHA1 Message Date
tobid7 6547f64d13 fix resize sym 2026-09-18 22:11:08 +02:00
tobid7 2b37204763 remove Font::LoadDefaultFont 2026-09-17 21:35:19 +02:00
tobid7 8c2bcedc93 Testing around 2026-09-16 21:20:45 +02:00
tobid7 01d3eb771e remove the 3ds ifdefs out of the core mat lib
need to find a way to handle mtx stuff in the gfx driver or another way
2026-09-15 07:20:00 +02:00
tobid7 6de3683818 3ds: move ui7 to bottom screne 2026-09-13 14:10:07 +02:00
tobid7 ec49f70c0b Add more gfx backend flags (available features) 2026-09-13 01:24:55 +02:00
tobid7 6284ff885d citro3d: clipping 2026-09-13 01:06:23 +02:00
tobid7 91c245c1a6 dx9 clipping 2026-09-12 17:29:48 +02:00
tobid7 c828166ce4 refactor UI7 clipping 2026-09-10 07:55:37 +02:00
tobid7 c7816ea170 fix close sym 2026-09-09 22:03:19 +02:00
tobid7 0dbf430c0c Implement clipping 2026-09-08 21:15:21 +02:00
tobid7 aec9083ebb small fixes 2026-09-07 22:05:51 +02:00
tobid7 9e6c6fd84d Merge dev-0.7-rewrite into stable 2026-09-06 16:23:08 +02:00
tobid7 7e0f3a6bf6 reset layers and give menus a base layer to gather perfect ordered rendering 2026-09-06 15:10:37 +02:00
tobid7 1ae4d0cd46 Add FontStack to UI7 and uncomment layer lines 2026-09-06 15:03:45 +02:00
tobid7 420edd0677 move and fix scrolling to layout
Scrolling was hardcoded to 3ds sCrEeNhEiGhT wTh
2026-09-06 14:46:22 +02:00
tobid7 e8a9055090 Layers are back 2026-09-06 14:39:28 +02:00
tobid7 9e27dfb0eb hotfix 2026-09-06 14:25:12 +02:00
tobid7 42c669de55 Add Hid3DS 2026-09-06 14:21:30 +02:00
tobid7 4488425a94 Bring back global lithium pools
why?
cause sorting around the global driver pool would basically use more cpu power then just copy data sequences into the right order
And sorting data references costs 0 performance at all
2026-09-05 22:52:59 +02:00
tobid7 eafe5c9be5 Add Drawlist Vertex and Indexcount geteter (for debugging usage only) 2026-09-05 21:28:09 +02:00
tobid7 d18e397eaf Fix The rest of UI7 Mem leaks
Throw OneFrame living objs into a pool
2026-09-05 18:06:59 +02:00
tobid7 fc5a357caa stop leaking idobj memory (and coloredit layout mem) 2026-09-05 18:06:12 +02:00
tobid7 a1cb3bf290 dx9: update device size on window size change 2026-09-05 17:18:21 +02:00
tobid7 8c1063640c format documents 2026-09-05 17:04:28 +02:00
tobid7 85f50df154 unload debugfont and add Gfx debug menu 2026-09-05 17:03:17 +02:00
tobid7 32c94e0776 fix random garbage ptr issues 2026-09-05 17:02:58 +02:00
tobid7 6b5f30b334 Fix Indexorder issues and patchfixsomehow dx9 tex filtering 2026-09-05 17:02:37 +02:00
tobid7 42cb7ce2ed No big update without msvc compiler errors :/ 2026-09-05 16:29:53 +02:00
tobid7 26a8c230c6 More timings 2026-09-05 15:10:48 +02:00
tobid7 0a5a86459b UI7 is BACK!
took me about a full week to get something to render again withour shared_ptrs
as of now this is very unstable, untested and lacking a lot of features due to lithium is lacking the base for that
Added JetBrainsMono font as debug font for the metrics
2026-09-05 14:48:03 +02:00
tobid7 0f25a70901 Add missing GetDriverName to Os 2026-09-05 14:47:41 +02:00
tobid7 6a22b26a3d Draw the line (oder so) 2026-09-05 14:46:51 +02:00
tobid7 245cc0f314 Load the font async for now 2026-09-05 11:56:41 +02:00
tobid7 cb437d41a0 n3ds-boost 2026-09-05 11:56:26 +02:00
tobid7 322ce785b9 SDF & MONOSPACE FONT RENDERING 2026-09-05 11:56:13 +02:00
tobid7 b29e298d55 save 75% of font memory 2026-09-03 09:36:41 +02:00
tobid7 2801b876e6 Upload pools once per Gfx::Draw and FIX DX9 2026-09-03 09:18:49 +02:00
tobid7 f1540f0098 reset pools on newframe 2026-09-03 08:12:34 +02:00
tobid7 54584728c3 move global pools into gfx driver
prevents double copy problems
saves memory
(needs to be optimized...)
2026-09-02 08:04:50 +02:00
tobid7 daaf473af7 faster rect command creation 2026-09-01 21:21:40 +02:00
tobid7 9ed3ed233d cache ascii chars directly 2026-09-01 21:20:52 +02:00
tobid7 dd97aab749 insane performance boost (on 3ds) 2026-09-01 21:16:23 +02:00
tobid7 0746295013 time trace is back 2026-09-01 10:02:54 +02:00
tobid7 2984354884 implement Image::Convert and Image::Flip 2026-09-01 08:15:03 +02:00
tobid7 4d2470b0c6 pool append move and copy 2026-08-31 08:59:41 +02:00
tobid7 cfb6a9b3dd # small fixes
- Fix Os::GetTimeNano()
- only build tests on non vendored usage
2026-07-19 14:27:48 +02:00
tobid7 799e779fe6 Fix 2026-04-30 12:38:35 +02:00
tobid7 7f708a565e Fix 3ds build and update libpicasso 2026-04-25 00:01:06 +02:00
tobid7 280ce524bf remove poc func 2026-04-18 14:34:45 +02:00
tobid7 b99fc39444 Add support for rotated gradients 2026-04-18 14:33:31 +02:00
tobid7 6dbf5a4812 Add stick and trigger input support 2026-04-09 21:51:38 +02:00
tobid7 ff3b241dd2 Fix clang warning 2026-04-05 04:31:50 +02:00
tobid7 7a1751589e fix preset names for Selection Views 2026-04-05 04:31:22 +02:00
tobid7 0501a4f87c Make UI7::IO::CurrentViewPort a Reference (finally) 2026-03-18 21:33:35 +01:00
tobid7 3d8b57ead6 add .gitattributes file 2026-03-16 20:28:30 +01:00
tobid7 ac37ce9e12 Fix test 2026-03-14 21:15:40 +01:00
96 changed files with 5475 additions and 470 deletions
+20
View File
@@ -39,6 +39,7 @@ set(PD_SOURCES
source/core/timetrace.cpp source/core/timetrace.cpp
# Image # Image
source/image/convert.cpp
source/image/image.cpp source/image/image.cpp
# Drivers # Drivers
@@ -47,11 +48,28 @@ set(PD_SOURCES
source/drivers/hid.cpp source/drivers/hid.cpp
# Lithium # Lithium
source/lithium/command.cpp
source/lithium/drawlist.cpp source/lithium/drawlist.cpp
source/lithium/font.cpp source/lithium/font.cpp
source/lithium/math.cpp source/lithium/math.cpp
source/lithium/pools.cpp source/lithium/pools.cpp
# UI7
source/ui7/io.cpp
source/ui7/layout.cpp
source/ui7/menu.cpp
source/ui7/theme.cpp
source/ui7/ui7.cpp
source/ui7/container/button.cpp
source/ui7/container/checkbox.cpp
source/ui7/container/coloredit.cpp
source/ui7/container/container.cpp
source/ui7/container/dragdata.cpp
source/ui7/container/dynobj.cpp
source/ui7/container/image.cpp
source/ui7/container/label.cpp
source/ui7/container/slider.cpp
# Ultra # Ultra
source/ultra/canvas.cpp source/ultra/canvas.cpp
source/ultra/layout.cpp source/ultra/layout.cpp
@@ -161,4 +179,6 @@ add_custom_target(pd-clang-format
) )
add_subdirectory(backends) add_subdirectory(backends)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
endif()
+4
View File
@@ -9,6 +9,7 @@ option(PD_ENABLE_CITRO3D "Enable Citro3D Support (3DS)" OFF)
option(PD_ENABLE_VULKAN "Not implemented yet" OFF) option(PD_ENABLE_VULKAN "Not implemented yet" OFF)
option(PD_ENABLE_HID_GLFW "Enable GLFW Input Driver" ON) option(PD_ENABLE_HID_GLFW "Enable GLFW Input Driver" ON)
option(PD_ENABLE_HID_NX "Enable NX Input Driver" OFF) option(PD_ENABLE_HID_NX "Enable NX Input Driver" OFF)
option(PD_ENABLE_HID3DS "Enable 3ds Input Driver" OFF)
if(NOT WIN32) # cause we are not on windows... if(NOT WIN32) # cause we are not on windows...
set(PD_ENABLE_DIRECTX9 OFF) set(PD_ENABLE_DIRECTX9 OFF)
@@ -21,6 +22,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
set(PD_ENABLE_CITRO3D ON) set(PD_ENABLE_CITRO3D ON)
set(PD_ENABLE_HID_GLFW OFF) set(PD_ENABLE_HID_GLFW OFF)
set(PD_ENABLE_HID_NX OFF) set(PD_ENABLE_HID_NX OFF)
set(PD_ENABLE_HID3DS ON)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "NintendoSwitch") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "NintendoSwitch")
set(PD_ENABLE_OPENGL2 OFF) set(PD_ENABLE_OPENGL2 OFF)
set(PD_ENABLE_OPENGL3 ON) set(PD_ENABLE_OPENGL3 ON)
@@ -36,6 +38,7 @@ add_library(pd-system STATIC
${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_opengl3.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_opengl3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_directx9.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_directx9.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_citro3d.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_citro3d.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/hid_3ds.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/hid_glfw.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/hid_glfw.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/hid_nx.cpp ${CMAKE_CURRENT_SOURCE_DIR}/source/hid_nx.cpp
) )
@@ -64,6 +67,7 @@ target_compile_definitions(pd-system
$<$<BOOL:${PD_ENABLE_CITRO3D}>:PD_ENABLE_CITRO3D> $<$<BOOL:${PD_ENABLE_CITRO3D}>:PD_ENABLE_CITRO3D>
$<$<BOOL:${PD_ENABLE_HID_GLFW}>:PD_ENABLE_HID_GLFW> $<$<BOOL:${PD_ENABLE_HID_GLFW}>:PD_ENABLE_HID_GLFW>
$<$<BOOL:${PD_ENABLE_HID_NX}>:PD_ENABLE_HID_NX> $<$<BOOL:${PD_ENABLE_HID_NX}>:PD_ENABLE_HID_NX>
$<$<BOOL:${PD_ENABLE_HID3DS}>:PD_ENABLE_HID3DS>
) )
# Palladium # Palladium
@@ -28,6 +28,8 @@ class GfxCitro3D : public GfxDriverBase<GfxCitro3DConfig> {
TextureFormat type = TextureFormat::RGBA32, TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
void ClipRect() override;
private: private:
struct Impl; struct Impl;
@@ -28,6 +28,8 @@ class GfxDirectX9 : public GfxDriverBase<GfxDirectX9Config> {
TextureFormat type = TextureFormat::RGBA32, TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
void ClipRect() override;
private: private:
struct Impl; struct Impl;
@@ -27,6 +27,8 @@ class GfxOpenGL2 : public GfxDriverBase<GfxOpenGL2Config> {
TextureFormat type = TextureFormat::RGBA32, TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
void ClipRect() override;
private: private:
void pSetupShaderAttribs(u32 shader); void pSetupShaderAttribs(u32 shader);
@@ -35,6 +37,7 @@ class GfxOpenGL2 : public GfxDriverBase<GfxOpenGL2Config> {
u32 IBO = 0; u32 IBO = 0;
int pLocTex = 0; int pLocTex = 0;
int pLocAlfa = 0; int pLocAlfa = 0;
int pLocIsSDF = 0;
int pLocProjection = 0; int pLocProjection = 0;
static const char* pVertCode; static const char* pVertCode;
static const char* pFragCode; static const char* pFragCode;
@@ -27,6 +27,8 @@ class GfxOpenGL3 : public GfxDriverBase<GfxOpenGL3Config> {
TextureFormat type = TextureFormat::RGBA32, TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override; TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override; void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
void ClipRect() override;
private: private:
u32 pShader = 0; u32 pShader = 0;
@@ -35,6 +37,7 @@ class GfxOpenGL3 : public GfxDriverBase<GfxOpenGL3Config> {
u32 VAO = 0; u32 VAO = 0;
int pLocTex = 0; int pLocTex = 0;
int pLocAlfa = 0; int pLocAlfa = 0;
int pLocIsSDF = 0;
int pLocProjection = 0; int pLocProjection = 0;
}; };
} // namespace PD } // namespace PD
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <pd/drivers/hid.hpp>
namespace PD {
class Hid3DS : public HidDriver {
public:
Hid3DS();
~Hid3DS();
void Update() override;
private:
struct Impl;
Impl* impl;
};
} // namespace PD
+2
View File
@@ -3,6 +3,7 @@
#include <pd/drivers/hid.hpp> #include <pd/drivers/hid.hpp>
typedef struct GLFWwindow GLFWwindow; typedef struct GLFWwindow GLFWwindow;
typedef struct GLFWgamepadstate GLFWgamepadstate;
namespace PD { namespace PD {
class HidGlfw : public HidDriver { class HidGlfw : public HidDriver {
@@ -13,6 +14,7 @@ class HidGlfw : public HidDriver {
void Update() override; void Update() override;
private: private:
void HandleAxisKey(GLFWgamepadstate s, int iK, int eA, bool negative);
struct Impl; struct Impl;
Impl* impl; Impl* impl;
}; };
+1 -1
View File
@@ -11,7 +11,7 @@ namespace Shaders {
const unsigned int VertexShader[] = { 0x7230203, 0x10000, 0x8000B, 0x2B, 0x0, 0x20011, 0x1, 0x6000B, 0x1, 0x4C534C47, 0x6474732E, 0x3035342E, 0x0, 0x3000E, 0x0, 0x1, 0xB000F, 0x0, 0x4, 0x6E69616D, 0x0, 0xD, 0x19, 0x24, 0x25, 0x27, 0x29, 0x30003, 0x2, 0x1CC, 0x40005, 0x4, 0x6E69616D, 0x0, 0x60005, 0xB, 0x505F6C67, 0x65567265, 0x78657472, 0x0, 0x60006, 0xB, 0x0, 0x505F6C67, 0x7469736F, 0x6E6F69, 0x70006, 0xB, 0x1, 0x505F6C67, 0x746E696F, 0x657A6953, 0x0, 0x70006, 0xB, 0x2, 0x435F6C67, 0x4470696C, 0x61747369, 0x65636E, 0x70006, 0xB, 0x3, 0x435F6C67, 0x446C6C75, 0x61747369, 0x65636E, 0x30005, 0xD, 0x0, 0x30005, 0x11, 0x4F4255, 0x60006, 0x11, 0x0, 0x6A6F7270, 0x69746365, 0x6E6F, 0x30005, 0x13, 0x6F6275, 0x30005, 0x19, 0x736F70, 0x30005, 0x24, 0x56556F, 0x30005, 0x25, 0x7675, 0x40005, 0x27, 0x6C6F436F, 0x726F, 0x40005, 0x29, 0x6F6C6F63, 0x72, 0x30047, 0xB, 0x2, 0x50048, 0xB, 0x0, 0xB, 0x0, 0x50048, 0xB, 0x1, 0xB, 0x1, 0x50048, 0xB, 0x2, 0xB, 0x3, 0x50048, 0xB, 0x3, 0xB, 0x4, 0x30047, 0x11, 0x2, 0x40048, 0x11, 0x0, 0x5, 0x50048, 0x11, 0x0, 0x7, 0x10, 0x50048, 0x11, 0x0, 0x23, 0x0, 0x40047, 0x13, 0x21, 0x0, 0x40047, 0x13, 0x22, 0x0, 0x40047, 0x19, 0x1E, 0x0, 0x40047, 0x24, 0x1E, 0x0, 0x40047, 0x25, 0x1E, 0x1, 0x40047, 0x27, 0x1E, 0x1, 0x40047, 0x29, 0x1E, 0x2, 0x20013, 0x2, 0x30021, 0x3, 0x2, 0x30016, 0x6, 0x20, 0x40017, 0x7, 0x6, 0x4, 0x40015, 0x8, 0x20, 0x0, 0x4002B, 0x8, 0x9, 0x1, 0x4001C, 0xA, 0x6, 0x9, 0x6001E, 0xB, 0x7, 0x6, 0xA, 0xA, 0x40020, 0xC, 0x3, 0xB, 0x4003B, 0xC, 0xD, 0x3, 0x40015, 0xE, 0x20, 0x1, 0x4002B, 0xE, 0xF, 0x0, 0x40018, 0x10, 0x7, 0x4, 0x3001E, 0x11, 0x10, 0x40020, 0x12, 0x2, 0x11, 0x4003B, 0x12, 0x13, 0x2, 0x40020, 0x14, 0x2, 0x10, 0x40017, 0x17, 0x6, 0x2, 0x40020, 0x18, 0x1, 0x17, 0x4003B, 0x18, 0x19, 0x1, 0x4002B, 0x6, 0x1B, 0x0, 0x4002B, 0x6, 0x1C, 0x3F800000, 0x40020, 0x21, 0x3, 0x7, 0x40020, 0x23, 0x3, 0x17, 0x4003B, 0x23, 0x24, 0x3, 0x4003B, 0x18, 0x25, 0x1, 0x4003B, 0x21, 0x27, 0x3, 0x40020, 0x28, 0x1, 0x7, 0x4003B, 0x28, 0x29, 0x1, 0x50036, 0x2, 0x4, 0x0, 0x3, 0x200F8, 0x5, 0x50041, 0x14, 0x15, 0x13, 0xF, 0x4003D, 0x10, 0x16, 0x15, 0x4003D, 0x17, 0x1A, 0x19, 0x50051, 0x6, 0x1D, 0x1A, 0x0, 0x50051, 0x6, 0x1E, 0x1A, 0x1, 0x70050, 0x7, 0x1F, 0x1D, 0x1E, 0x1B, 0x1C, 0x50091, 0x7, 0x20, 0x16, 0x1F, 0x50041, 0x21, 0x22, 0xD, 0xF, 0x3003E, 0x22, 0x20, 0x4003D, 0x17, 0x26, 0x25, 0x3003E, 0x24, 0x26, 0x4003D, 0x7, 0x2A, 0x29, 0x3003E, 0x27, 0x2A, 0x100FD, 0x10038, }; const unsigned int VertexShader[] = { 0x7230203, 0x10000, 0x8000B, 0x2B, 0x0, 0x20011, 0x1, 0x6000B, 0x1, 0x4C534C47, 0x6474732E, 0x3035342E, 0x0, 0x3000E, 0x0, 0x1, 0xB000F, 0x0, 0x4, 0x6E69616D, 0x0, 0xD, 0x19, 0x24, 0x25, 0x27, 0x29, 0x30003, 0x2, 0x1CC, 0x40005, 0x4, 0x6E69616D, 0x0, 0x60005, 0xB, 0x505F6C67, 0x65567265, 0x78657472, 0x0, 0x60006, 0xB, 0x0, 0x505F6C67, 0x7469736F, 0x6E6F69, 0x70006, 0xB, 0x1, 0x505F6C67, 0x746E696F, 0x657A6953, 0x0, 0x70006, 0xB, 0x2, 0x435F6C67, 0x4470696C, 0x61747369, 0x65636E, 0x70006, 0xB, 0x3, 0x435F6C67, 0x446C6C75, 0x61747369, 0x65636E, 0x30005, 0xD, 0x0, 0x30005, 0x11, 0x4F4255, 0x60006, 0x11, 0x0, 0x6A6F7270, 0x69746365, 0x6E6F, 0x30005, 0x13, 0x6F6275, 0x30005, 0x19, 0x736F70, 0x30005, 0x24, 0x56556F, 0x30005, 0x25, 0x7675, 0x40005, 0x27, 0x6C6F436F, 0x726F, 0x40005, 0x29, 0x6F6C6F63, 0x72, 0x30047, 0xB, 0x2, 0x50048, 0xB, 0x0, 0xB, 0x0, 0x50048, 0xB, 0x1, 0xB, 0x1, 0x50048, 0xB, 0x2, 0xB, 0x3, 0x50048, 0xB, 0x3, 0xB, 0x4, 0x30047, 0x11, 0x2, 0x40048, 0x11, 0x0, 0x5, 0x50048, 0x11, 0x0, 0x7, 0x10, 0x50048, 0x11, 0x0, 0x23, 0x0, 0x40047, 0x13, 0x21, 0x0, 0x40047, 0x13, 0x22, 0x0, 0x40047, 0x19, 0x1E, 0x0, 0x40047, 0x24, 0x1E, 0x0, 0x40047, 0x25, 0x1E, 0x1, 0x40047, 0x27, 0x1E, 0x1, 0x40047, 0x29, 0x1E, 0x2, 0x20013, 0x2, 0x30021, 0x3, 0x2, 0x30016, 0x6, 0x20, 0x40017, 0x7, 0x6, 0x4, 0x40015, 0x8, 0x20, 0x0, 0x4002B, 0x8, 0x9, 0x1, 0x4001C, 0xA, 0x6, 0x9, 0x6001E, 0xB, 0x7, 0x6, 0xA, 0xA, 0x40020, 0xC, 0x3, 0xB, 0x4003B, 0xC, 0xD, 0x3, 0x40015, 0xE, 0x20, 0x1, 0x4002B, 0xE, 0xF, 0x0, 0x40018, 0x10, 0x7, 0x4, 0x3001E, 0x11, 0x10, 0x40020, 0x12, 0x2, 0x11, 0x4003B, 0x12, 0x13, 0x2, 0x40020, 0x14, 0x2, 0x10, 0x40017, 0x17, 0x6, 0x2, 0x40020, 0x18, 0x1, 0x17, 0x4003B, 0x18, 0x19, 0x1, 0x4002B, 0x6, 0x1B, 0x0, 0x4002B, 0x6, 0x1C, 0x3F800000, 0x40020, 0x21, 0x3, 0x7, 0x40020, 0x23, 0x3, 0x17, 0x4003B, 0x23, 0x24, 0x3, 0x4003B, 0x18, 0x25, 0x1, 0x4003B, 0x21, 0x27, 0x3, 0x40020, 0x28, 0x1, 0x7, 0x4003B, 0x28, 0x29, 0x1, 0x50036, 0x2, 0x4, 0x0, 0x3, 0x200F8, 0x5, 0x50041, 0x14, 0x15, 0x13, 0xF, 0x4003D, 0x10, 0x16, 0x15, 0x4003D, 0x17, 0x1A, 0x19, 0x50051, 0x6, 0x1D, 0x1A, 0x0, 0x50051, 0x6, 0x1E, 0x1A, 0x1, 0x70050, 0x7, 0x1F, 0x1D, 0x1E, 0x1B, 0x1C, 0x50091, 0x7, 0x20, 0x16, 0x1F, 0x50041, 0x21, 0x22, 0xD, 0xF, 0x3003E, 0x22, 0x20, 0x4003D, 0x17, 0x26, 0x25, 0x3003E, 0x24, 0x26, 0x4003D, 0x7, 0x2A, 0x29, 0x3003E, 0x27, 0x2A, 0x100FD, 0x10038, };
// clang-format on // clang-format on
// clang-format off // clang-format off
const unsigned int FragmentShader[] = { 0x7230203, 0x10000, 0x8000B, 0x39, 0x0, 0x20011, 0x1, 0x6000B, 0x1, 0x4C534C47, 0x6474732E, 0x3035342E, 0x0, 0x3000E, 0x0, 0x1, 0x8000F, 0x0, 0x4, 0x6E69616D, 0x0, 0x11, 0x22, 0x24, 0x30003, 0x2, 0x1CC, 0x40005, 0x4, 0x6E69616D, 0x0, 0x30005, 0x9, 0x6374, 0x30005, 0xD, 0x786574, 0x30005, 0x11, 0x56556F, 0x50005, 0x16, 0x68737550, 0x61746144, 0x0, 0x50006, 0x16, 0x0, 0x61666C61, 0x0, 0x40005, 0x18, 0x68737570, 0x0, 0x50005, 0x22, 0x67617246, 0x6F6C6F43, 0x72, 0x40005, 0x24, 0x6C6F436F, 0x726F, 0x40047, 0xD, 0x21, 0x0, 0x40047, 0xD, 0x22, 0x0, 0x40047, 0x11, 0x1E, 0x0, 0x30047, 0x16, 0x2, 0x50048, 0x16, 0x0, 0x23, 0x0, 0x40047, 0x24, 0x1E, 0x1, 0x20013, 0x2, 0x30021, 0x3, 0x2, 0x30016, 0x6, 0x20, 0x40017, 0x7, 0x6, 0x4, 0x40020, 0x8, 0x7, 0x7, 0x90019, 0xA, 0x6, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3001B, 0xB, 0xA, 0x40020, 0xC, 0x0, 0xB, 0x4003B, 0xC, 0xD, 0x0, 0x40017, 0xF, 0x6, 0x2, 0x40020, 0x10, 0x1, 0xF, 0x4003B, 0x10, 0x11, 0x1, 0x4002B, 0x6, 0x13, 0x0, 0x40015, 0x15, 0x20, 0x1, 0x3001E, 0x16, 0x15, 0x40020, 0x17, 0x9, 0x16, 0x4003B, 0x17, 0x18, 0x9, 0x4002B, 0x15, 0x19, 0x0, 0x40020, 0x1A, 0x9, 0x15, 0x20014, 0x1D, 0x40020, 0x21, 0x3, 0x7, 0x4003B, 0x21, 0x22, 0x3, 0x40020, 0x23, 0x1, 0x7, 0x4003B, 0x23, 0x24, 0x1, 0x40017, 0x25, 0x6, 0x3, 0x40015, 0x28, 0x20, 0x0, 0x4002B, 0x28, 0x29, 0x3, 0x40020, 0x2A, 0x7, 0x6, 0x40020, 0x2D, 0x1, 0x6, 0x50036, 0x2, 0x4, 0x0, 0x3, 0x200F8, 0x5, 0x4003B, 0x8, 0x9, 0x7, 0x4003D, 0xB, 0xE, 0xD, 0x4003D, 0xF, 0x12, 0x11, 0x70058, 0x7, 0x14, 0xE, 0x12, 0x2, 0x13, 0x3003E, 0x9, 0x14, 0x50041, 0x1A, 0x1B, 0x18, 0x19, 0x4003D, 0x15, 0x1C, 0x1B, 0x500AB, 0x1D, 0x1E, 0x1C, 0x19, 0x300F7, 0x20, 0x0, 0x400FA, 0x1E, 0x1F, 0x35, 0x200F8, 0x1F, 0x4003D, 0x7, 0x26, 0x24, 0x8004F, 0x25, 0x27, 0x26, 0x26, 0x0, 0x1, 0x2, 0x50041, 0x2A, 0x2B, 0x9, 0x29, 0x4003D, 0x6, 0x2C, 0x2B, 0x50041, 0x2D, 0x2E, 0x24, 0x29, 0x4003D, 0x6, 0x2F, 0x2E, 0x50085, 0x6, 0x30, 0x2C, 0x2F, 0x50051, 0x6, 0x31, 0x27, 0x0, 0x50051, 0x6, 0x32, 0x27, 0x1, 0x50051, 0x6, 0x33, 0x27, 0x2, 0x70050, 0x7, 0x34, 0x31, 0x32, 0x33, 0x30, 0x3003E, 0x22, 0x34, 0x200F9, 0x20, 0x200F8, 0x35, 0x4003D, 0x7, 0x36, 0x9, 0x4003D, 0x7, 0x37, 0x24, 0x50085, 0x7, 0x38, 0x36, 0x37, 0x3003E, 0x22, 0x38, 0x200F9, 0x20, 0x200F8, 0x20, 0x100FD, 0x10038, }; const unsigned int FragmentShader[] = { 0x7230203, 0x10000, 0x8000B, 0x50, 0x0, 0x20011, 0x1, 0x6000B, 0x1, 0x4C534C47, 0x6474732E, 0x3035342E, 0x0, 0x3000E, 0x0, 0x1, 0x8000F, 0x0, 0x4, 0x6E69616D, 0x0, 0x11, 0x2C, 0x2E, 0x30003, 0x2, 0x1CC, 0x40005, 0x4, 0x6E69616D, 0x0, 0x30005, 0x9, 0x6374, 0x30005, 0xD, 0x786574, 0x30005, 0x11, 0x56556F, 0x50005, 0x16, 0x68737550, 0x61746144, 0x0, 0x50006, 0x16, 0x0, 0x61666C61, 0x0, 0x50006, 0x16, 0x1, 0x735F7369, 0x6664, 0x40005, 0x18, 0x68737570, 0x0, 0x40005, 0x23, 0x68706C61, 0x61, 0x50005, 0x2C, 0x67617246, 0x6F6C6F43, 0x72, 0x40005, 0x2E, 0x6C6F436F, 0x726F, 0x40047, 0xD, 0x21, 0x0, 0x40047, 0xD, 0x22, 0x0, 0x40047, 0x11, 0x1E, 0x0, 0x30047, 0x16, 0x2, 0x50048, 0x16, 0x0, 0x23, 0x0, 0x50048, 0x16, 0x1, 0x23, 0x4, 0x40047, 0x2E, 0x1E, 0x1, 0x20013, 0x2, 0x30021, 0x3, 0x2, 0x30016, 0x6, 0x20, 0x40017, 0x7, 0x6, 0x4, 0x40020, 0x8, 0x7, 0x7, 0x90019, 0xA, 0x6, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3001B, 0xB, 0xA, 0x40020, 0xC, 0x0, 0xB, 0x4003B, 0xC, 0xD, 0x0, 0x40017, 0xF, 0x6, 0x2, 0x40020, 0x10, 0x1, 0xF, 0x4003B, 0x10, 0x11, 0x1, 0x4002B, 0x6, 0x13, 0x0, 0x40015, 0x15, 0x20, 0x1, 0x4001E, 0x16, 0x15, 0x15, 0x40020, 0x17, 0x9, 0x16, 0x4003B, 0x17, 0x18, 0x9, 0x4002B, 0x15, 0x19, 0x1, 0x40020, 0x1A, 0x9, 0x15, 0x4002B, 0x15, 0x1D, 0x0, 0x20014, 0x1E, 0x40020, 0x22, 0x7, 0x6, 0x4002B, 0x6, 0x24, 0x3EE66666, 0x4002B, 0x6, 0x25, 0x3F0CCCCD, 0x40015, 0x26, 0x20, 0x0, 0x4002B, 0x26, 0x27, 0x3, 0x40020, 0x2B, 0x3, 0x7, 0x4003B, 0x2B, 0x2C, 0x3, 0x40020, 0x2D, 0x1, 0x7, 0x4003B, 0x2D, 0x2E, 0x1, 0x40017, 0x2F, 0x6, 0x3, 0x40020, 0x33, 0x1, 0x6, 0x50036, 0x2, 0x4, 0x0, 0x3, 0x200F8, 0x5, 0x4003B, 0x8, 0x9, 0x7, 0x4003B, 0x22, 0x23, 0x7, 0x4003D, 0xB, 0xE, 0xD, 0x4003D, 0xF, 0x12, 0x11, 0x70058, 0x7, 0x14, 0xE, 0x12, 0x2, 0x13, 0x3003E, 0x9, 0x14, 0x50041, 0x1A, 0x1B, 0x18, 0x19, 0x4003D, 0x15, 0x1C, 0x1B, 0x500AB, 0x1E, 0x1F, 0x1C, 0x1D, 0x300F7, 0x21, 0x0, 0x400FA, 0x1F, 0x20, 0x3B, 0x200F8, 0x20, 0x50041, 0x22, 0x28, 0x9, 0x27, 0x4003D, 0x6, 0x29, 0x28, 0x8000C, 0x6, 0x2A, 0x1, 0x31, 0x24, 0x25, 0x29, 0x3003E, 0x23, 0x2A, 0x4003D, 0x7, 0x30, 0x2E, 0x8004F, 0x2F, 0x31, 0x30, 0x30, 0x0, 0x1, 0x2, 0x4003D, 0x6, 0x32, 0x23, 0x50041, 0x33, 0x34, 0x2E, 0x27, 0x4003D, 0x6, 0x35, 0x34, 0x50085, 0x6, 0x36, 0x32, 0x35, 0x50051, 0x6, 0x37, 0x31, 0x0, 0x50051, 0x6, 0x38, 0x31, 0x1, 0x50051, 0x6, 0x39, 0x31, 0x2, 0x70050, 0x7, 0x3A, 0x37, 0x38, 0x39, 0x36, 0x3003E, 0x2C, 0x3A, 0x200F9, 0x21, 0x200F8, 0x3B, 0x50041, 0x1A, 0x3C, 0x18, 0x1D, 0x4003D, 0x15, 0x3D, 0x3C, 0x500AB, 0x1E, 0x3E, 0x3D, 0x1D, 0x300F7, 0x40, 0x0, 0x400FA, 0x3E, 0x3F, 0x4C, 0x200F8, 0x3F, 0x4003D, 0x7, 0x41, 0x2E, 0x8004F, 0x2F, 0x42, 0x41, 0x41, 0x0, 0x1, 0x2, 0x50041, 0x22, 0x43, 0x9, 0x27, 0x4003D, 0x6, 0x44, 0x43, 0x50041, 0x33, 0x45, 0x2E, 0x27, 0x4003D, 0x6, 0x46, 0x45, 0x50085, 0x6, 0x47, 0x44, 0x46, 0x50051, 0x6, 0x48, 0x42, 0x0, 0x50051, 0x6, 0x49, 0x42, 0x1, 0x50051, 0x6, 0x4A, 0x42, 0x2, 0x70050, 0x7, 0x4B, 0x48, 0x49, 0x4A, 0x47, 0x3003E, 0x2C, 0x4B, 0x200F9, 0x40, 0x200F8, 0x4C, 0x4003D, 0x7, 0x4D, 0x9, 0x4003D, 0x7, 0x4E, 0x2E, 0x50085, 0x7, 0x4F, 0x4D, 0x4E, 0x3003E, 0x2C, 0x4F, 0x200F9, 0x40, 0x200F8, 0x40, 0x200F9, 0x21, 0x200F8, 0x21, 0x100FD, 0x10038, };
// clang-format on // clang-format on
} // namespace Shaders } // namespace Shaders
} // namespace PD } // namespace PD
+1
View File
@@ -7,4 +7,5 @@
#include <pd_system/gfx_opengl3.hpp> #include <pd_system/gfx_opengl3.hpp>
// Hid // Hid
#include <pd_system/hid_3ds.hpp>
#include <pd_system/hid_glfw.hpp> #include <pd_system/hid_glfw.hpp>
+42 -5
View File
@@ -84,7 +84,7 @@ struct GfxCitro3D::Impl {
} }
} }
void SetupPixelStage() { void SetupPixelStage(bool sdf) {
shaderProgramUse(&pShader); shaderProgramUse(&pShader);
C3D_BindProgram(&pShader); C3D_BindProgram(&pShader);
C3D_SetAttrInfo(&pAttr); C3D_SetAttrInfo(&pAttr);
@@ -92,6 +92,26 @@ struct GfxCitro3D::Impl {
if (!CurrentTex) return; if (!CurrentTex) return;
C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvInit(env); C3D_TexEnvInit(env);
C3D_TexEnv* env1 = C3D_GetTexEnv(1);
C3D_TexEnvInit(env1);
if (sdf) {
C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
C3D_TexEnvColor(env, 0x60606060);
C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, GPU_CONSTANT);
C3D_TexEnvOpAlpha(env, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_SUBTRACT);
C3D_TexEnvScale(env, C3D_Alpha, GPU_TEVSCALE_4);
C3D_TexEnvSrc(env1, C3D_RGB, GPU_PREVIOUS);
C3D_TexEnvFunc(env1, C3D_RGB, GPU_REPLACE);
C3D_TexEnvSrc(env1, C3D_Alpha, GPU_PREVIOUS, GPU_PRIMARY_COLOR);
C3D_TexEnvOpAlpha(env, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA);
C3D_TexEnvFunc(env1, C3D_Alpha, GPU_MODULATE);
} else {
switch (CurrentTex->fmt) { switch (CurrentTex->fmt) {
case GPU_A4: case GPU_A4:
case GPU_A8: case GPU_A8:
@@ -113,6 +133,7 @@ struct GfxCitro3D::Impl {
break; break;
} }
} }
}
}; };
void GfxCitro3D::SysInit() { void GfxCitro3D::SysInit() {
@@ -120,6 +141,9 @@ void GfxCitro3D::SysInit() {
PDLOG("GfxCitro3D::SysInit();"); PDLOG("GfxCitro3D::SysInit();");
impl = new Impl(); impl = new Impl();
Flags |= PDGfxBackendFlags_FlipUV_Y; Flags |= PDGfxBackendFlags_FlipUV_Y;
Flags |= PDGfxBackendFlags_HasClipRect;
Flags |= PDGfxBackendFlags_ReqPow2;
Flags |= PDGfxBackendFlags_ApproxSDF;
impl->pShaderRaw = Pica::AssembleCode(LIShaderCTR); impl->pShaderRaw = Pica::AssembleCode(LIShaderCTR);
impl->pCode = DVLB_ParseFile((uint32_t*)impl->pShaderRaw.data(), impl->pCode = DVLB_ParseFile((uint32_t*)impl->pShaderRaw.data(),
impl->pShaderRaw.size()); impl->pShaderRaw.size());
@@ -146,15 +170,12 @@ void GfxCitro3D::SysDeinit() {
void GfxCitro3D::Submit(size_t count, size_t start) { void GfxCitro3D::Submit(size_t count, size_t start) {
if (!impl) return; if (!impl) return;
BindTexture(CurrentTex); BindTexture(CurrentTex);
impl->SetupPixelStage(); // needs to be called after impl->SetupPixelStage(CurrentTexIsSDF); // needs to be called after
C3D_Mtx proj; C3D_Mtx proj;
Mtx_OrthoTilt(&proj, 0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f, false); Mtx_OrthoTilt(&proj, 0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f, false);
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, impl->uLocProjection, &proj); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, impl->uLocProjection, &proj);
// C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, impl->uLocProjection, // C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, impl->uLocProjection,
// (C3D_Mtx*)&Projection); // (C3D_Mtx*)&Projection);
auto buf = C3D_GetBufInfo();
BufInfo_Init(buf);
BufInfo_Add(buf, GetVertexBufPtr(0), sizeof(Li::Vertex), 3, 0x210);
C3D_DrawElements(GPU_TRIANGLES, count, C3D_UNSIGNED_SHORT, C3D_DrawElements(GPU_TRIANGLES, count, C3D_UNSIGNED_SHORT,
GetIndexBufPtr(start)); GetIndexBufPtr(start));
impl->CurrentTex = nullptr; impl->CurrentTex = nullptr;
@@ -240,6 +261,20 @@ void GfxCitro3D::DeleteTexture(const Li::Texture& tex) {
C3D_TexDelete(t); C3D_TexDelete(t);
delete t; delete t;
} }
void GfxCitro3D::UploadPools() {
auto buf = C3D_GetBufInfo();
BufInfo_Init(buf);
BufInfo_Add(buf, GetVertexBufPtr(0), sizeof(Li::Vertex), 3, 0x210);
}
void GfxCitro3D::ClipRect() {
// This is so cursed but it works
C3D_SetScissor(CurrentHasClip ? GPU_SCISSOR_NORMAL : GPU_SCISSOR_DISABLE,
ViewPort.y - CurrentClip.w - CurrentClip.y,
ViewPort.x - CurrentClip.z - CurrentClip.x,
ViewPort.y - CurrentClip.y, ViewPort.x - CurrentClip.x);
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -258,5 +293,7 @@ Li::Texture GfxCitro3D::LoadTexture(const std::vector<PD::u8>& pixels, int w,
return Li::Texture(); return Li::Texture();
} }
void GfxCitro3D::DeleteTexture(const Li::Texture& tex) {} void GfxCitro3D::DeleteTexture(const Li::Texture& tex) {}
void GfxCitro3D::UploadPools() {}
void GfxCitro3D::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+66 -42
View File
@@ -30,14 +30,15 @@ VS_OUT main(VS_IN input) {
VS_OUT o; VS_OUT o;
o.pos = mul(projection, float4(input.pos, 0.0, 1.0)); o.pos = mul(projection, float4(input.pos, 0.0, 1.0));
o.uv = input.uv; o.uv = input.uv;
o.col = input.col; o.col = input.col.bgra;
return o; return o;
} }
)"; )";
static const char* g_psCode = R"( static const char* g_psCode = R"(
sampler2D tex : register(s0); sampler2D tex : register(s0);
float alfa; float alfa : register(c1);
float is_sdf : register(c2);
struct PS_IN { struct PS_IN {
float2 uv : TEXCOORD0; float2 uv : TEXCOORD0;
@@ -46,7 +47,10 @@ struct PS_IN {
float4 main(PS_IN input) : COLOR0 { float4 main(PS_IN input) : COLOR0 {
float4 tc = tex2D(tex, input.uv); float4 tc = tex2D(tex, input.uv);
if (alfa > 0.5) if (is_sdf > 0.5) {
float alpha = smoothstep(0.45, 0.55, tc.a);
return float4(input.col.rgb, alpha * input.col.a);
} else if (alfa > 0.5)
return float4(input.col.rgb, tc.a * input.col.a); return float4(input.col.rgb, tc.a * input.col.a);
else else
return tc * input.col; return tc * input.col;
@@ -108,6 +112,7 @@ void GfxDirectX9::SysInit() {
} }
if (psBlob) psBlob->Release(); if (psBlob) psBlob->Release();
if (errBlob) errBlob->Release(); if (errBlob) errBlob->Release();
Flags |= PDGfxBackendFlags_HasClipRect;
} else { } else {
PDERR( PDERR(
"GfxDirectX9::SysInit Error: pDevice is not set!\nYOu need to include " "GfxDirectX9::SysInit Error: pDevice is not set!\nYOu need to include "
@@ -132,44 +137,8 @@ void GfxDirectX9::Submit(size_t count, size_t start) {
if (!impl || !impl->Device || !impl->VBO || !impl->IBO) return; if (!impl || !impl->Device || !impl->VBO || !impl->IBO) return;
BindTexture(CurrentTex); BindTexture(CurrentTex);
impl->Device->SetVertexShaderConstantF(
0, reinterpret_cast<const float*>(&Projection), 4);
if (!impl->VBO || impl->VertexBufferSize != GetVertexPoolSize()) { impl->Device->SetVertexShaderConstantF(0, Projection.Ptr(), 4);
if (impl->VBO) {
impl->VBO->Release();
impl->VBO = nullptr;
impl->VertexBufferSize = 0;
}
if (impl->Device->CreateVertexBuffer(
GetVertexPoolSize() * sizeof(Li::Vertex),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT,
&impl->VBO, nullptr) < 0)
return;
impl->VertexBufferSize = GetVertexPoolSize();
}
if (!impl->IBO || impl->IndexBufferSize != GetIndexPoolSize()) {
if (impl->IBO) {
impl->IBO->Release();
impl->IBO = nullptr;
impl->IndexBufferSize = 0;
}
if (impl->Device->CreateIndexBuffer(GetVertexPoolSize() * sizeof(u16),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16, D3DPOOL_DEFAULT,
&impl->IBO, nullptr) < 0)
return;
impl->IndexBufferSize = GetIndexPoolSize();
}
void* vptr;
impl->VBO->Lock(0, 0, &vptr, D3DLOCK_DISCARD);
memcpy(vptr, GetVertexBufPtr(0), CurrentVertex * sizeof(PD::Li::Vertex));
impl->VBO->Unlock();
void* iptr;
impl->IBO->Lock(0, 0, &iptr, D3DLOCK_DISCARD);
memcpy(iptr, GetIndexBufPtr(0), CurrentIndex * sizeof(u16));
impl->IBO->Unlock();
impl->Device->SetStreamSource(0, impl->VBO, 0, sizeof(PD::Li::Vertex)); impl->Device->SetStreamSource(0, impl->VBO, 0, sizeof(PD::Li::Vertex));
impl->Device->SetIndices(impl->IBO); impl->Device->SetIndices(impl->IBO);
@@ -177,8 +146,8 @@ void GfxDirectX9::Submit(size_t count, size_t start) {
impl->Device->SetVertexShader(impl->VS); impl->Device->SetVertexShader(impl->VS);
impl->Device->SetPixelShader(impl->FS); impl->Device->SetPixelShader(impl->FS);
impl->Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, CurrentVertex, impl->Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0,
start, count / 3); GetVertexPoolSize(), start, count / 3);
} }
void GfxDirectX9::BindTexture(TextureID id) { void GfxDirectX9::BindTexture(TextureID id) {
@@ -195,14 +164,22 @@ void GfxDirectX9::BindTexture(TextureID id) {
float v = a8 ? 1.0f : 0.0f; float v = a8 ? 1.0f : 0.0f;
impl->Device->SetPixelShaderConstantF(0, &v, 1); impl->Device->SetPixelShaderConstantF(0, &v, 1);
float sdf = CurrentTexIsSDF ? 1.0f : 0.0f;
impl->Device->SetPixelShaderConstantF(1, &sdf, 1);
} }
void GfxDirectX9::SysReset() { void GfxDirectX9::SysReset() {
if (!impl || !impl->Device) return; if (!impl || !impl->Device) return;
impl->Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
impl->Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); impl->Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
impl->Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); impl->Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
impl->Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); impl->Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
impl->Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
impl->Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
impl->Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
} }
Li::Texture GfxDirectX9::LoadTexture(const std::vector<PD::u8>& pixels, int w, Li::Texture GfxDirectX9::LoadTexture(const std::vector<PD::u8>& pixels, int w,
@@ -279,6 +256,51 @@ void GfxDirectX9::DeleteTexture(const Li::Texture& tex) {
IDirect3DTexture9* t = (IDirect3DTexture9*)tex.GetID(); IDirect3DTexture9* t = (IDirect3DTexture9*)tex.GetID();
t->Release(); t->Release();
} }
void GfxDirectX9::UploadPools() {
if (!impl || !impl->Device) return;
if (!impl->VBO || impl->VertexBufferSize != GetVertexPoolSize()) {
if (impl->VBO) impl->VBO->Release();
impl->Device->CreateVertexBuffer(GetVertexPoolSize() * sizeof(Li::Vertex),
D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED,
&impl->VBO, nullptr);
impl->VertexBufferSize = GetVertexPoolSize();
}
if (!impl->IBO || impl->IndexBufferSize != GetIndexPoolSize()) {
if (impl->IBO) impl->IBO->Release();
impl->Device->CreateIndexBuffer(GetIndexPoolSize() * sizeof(u16),
D3DUSAGE_WRITEONLY, D3DFMT_INDEX16,
D3DPOOL_MANAGED, &impl->IBO, nullptr);
impl->IndexBufferSize = GetIndexPoolSize();
}
void* vptr;
impl->VBO->Lock(0, 0, &vptr, 0);
memcpy(vptr, GetVertexBufPtr(0),
GetVertexPoolSize() * sizeof(PD::Li::Vertex));
impl->VBO->Unlock();
void* iptr;
impl->IBO->Lock(0, 0, &iptr, 0);
memcpy(iptr, GetIndexBufPtr(0), GetIndexPoolSize() * sizeof(u16));
impl->IBO->Unlock();
}
void GfxDirectX9::ClipRect() {
if (CurrentHasClip) {
RECT r;
r.left = CurrentClip.x;
r.top = CurrentClip.y;
r.right = CurrentClip.x + CurrentClip.z;
r.bottom = CurrentClip.y + CurrentClip.w;
impl->Device->SetScissorRect(&r);
impl->Device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
} else {
impl->Device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
}
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -297,5 +319,7 @@ Li::Texture GfxDirectX9::LoadTexture(const std::vector<PD::u8>& pixels, int w,
return Li::Texture(); return Li::Texture();
} }
void GfxDirectX9::DeleteTexture(const Li::Texture& tex) {} void GfxDirectX9::DeleteTexture(const Li::Texture& tex) {}
void GfxDirectX9::UploadPools() {}
void GfxDirectX9::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+34 -9
View File
@@ -38,10 +38,15 @@ const char* GfxOpenGL2::pFragCode = R"(
uniform sampler2D tex; uniform sampler2D tex;
uniform bool alfa; uniform bool alfa;
uniform bool is_sdf;
void main() { void main() {
vec4 tc = texture2D(tex, oUV); vec4 tc = texture2D(tex, oUV);
if (alfa) { if (is_sdf) {
float dist = tc.a;
float alpha = smoothstep(0.45, 0.55, dist);
gl_FragColor = vec4(oColor.rgb, alpha * oColor.a);
} else if (alfa) {
gl_FragColor = vec4(oColor.rgb, tc.a * oColor.a); gl_FragColor = vec4(oColor.rgb, tc.a * oColor.a);
} else { } else {
gl_FragColor = tc * oColor; gl_FragColor = tc * oColor;
@@ -68,6 +73,7 @@ void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {
} }
void GfxOpenGL2::SysInit() { void GfxOpenGL2::SysInit() {
Flags |= PDGfxBackendFlags_HasClipRect;
pShader = CreateShaderProgram(pVertCode, pFragCode); pShader = CreateShaderProgram(pVertCode, pFragCode);
glUseProgram(pShader); glUseProgram(pShader);
glGenBuffers(1, &VBO); glGenBuffers(1, &VBO);
@@ -78,6 +84,7 @@ void GfxOpenGL2::SysInit() {
pSetupShaderAttribs(pShader); pSetupShaderAttribs(pShader);
pLocTex = glGetUniformLocation(pShader, "tex"); pLocTex = glGetUniformLocation(pShader, "tex");
pLocAlfa = glGetUniformLocation(pShader, "alfa"); pLocAlfa = glGetUniformLocation(pShader, "alfa");
pLocIsSDF = glGetUniformLocation(pShader, "is_sdf");
pLocProjection = glGetUniformLocation(pShader, "projection"); pLocProjection = glGetUniformLocation(pShader, "projection");
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -94,19 +101,14 @@ void GfxOpenGL2::Submit(size_t count, size_t start) {
BindTexture(CurrentTex); BindTexture(CurrentTex);
glUseProgram(pShader); glUseProgram(pShader);
glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data()); glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data());
glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, CurrentVertex * sizeof(PD::Li::Vertex),
GetVertexBufPtr(0), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, CurrentIndex * sizeof(PD::u16),
GetIndexBufPtr(0), GL_DYNAMIC_DRAW);
pSetupShaderAttribs(pShader); pSetupShaderAttribs(pShader);
GLint ibo = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &ibo);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT,
reinterpret_cast<void*>(start * sizeof(u16))); reinterpret_cast<void*>(start * sizeof(u16)));
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
BindTexture(0); BindTexture(0);
@@ -119,6 +121,7 @@ void GfxOpenGL2::BindTexture(TextureID id) {
GLint fmt = 0; GLint fmt = 0;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
glUniform1i(pLocAlfa, fmt == GL_ALPHA); glUniform1i(pLocAlfa, fmt == GL_ALPHA);
glUniform1i(pLocIsSDF, CurrentTexIsSDF);
} }
void GfxOpenGL2::SysReset() { void GfxOpenGL2::SysReset() {
@@ -171,6 +174,26 @@ void GfxOpenGL2::DeleteTexture(const Li::Texture& tex) {
GLuint tex_ = tex.GetID(); GLuint tex_ = tex.GetID();
glDeleteTextures(1, &tex_); glDeleteTextures(1, &tex_);
} }
void GfxOpenGL2::UploadPools() {
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, GetVertexPoolSize() * sizeof(PD::Li::Vertex),
GetVertexBufPtr(0), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndexPoolSize() * sizeof(u16),
GetIndexBufPtr(0), GL_DYNAMIC_DRAW);
}
void GfxOpenGL2::ClipRect() {
if (CurrentHasClip) {
glEnable(GL_SCISSOR_TEST);
glScissor(CurrentClip.x, ViewPort.y - (CurrentClip.y + CurrentClip.w),
CurrentClip.z, CurrentClip.w);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -190,5 +213,7 @@ Li::Texture GfxOpenGL2::LoadTexture(const std::vector<PD::u8>& pixels, int w,
} }
void GfxOpenGL2::DeleteTexture(const Li::Texture& tex) {} void GfxOpenGL2::DeleteTexture(const Li::Texture& tex) {}
void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {} void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {}
void GfxOpenGL2::UploadPools() {}
void GfxOpenGL2::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+44 -13
View File
@@ -11,6 +11,7 @@
namespace PD { namespace PD {
void GfxOpenGL3::SysInit() { void GfxOpenGL3::SysInit() {
Flags |= PDGfxBackendFlags_HasClipRect;
std::string vcode = SpirvHelper::SPV2GLSL( std::string vcode = SpirvHelper::SPV2GLSL(
std::vector<unsigned int>( std::vector<unsigned int>(
Shaders::VertexShader, Shaders::VertexShader,
@@ -47,6 +48,7 @@ void GfxOpenGL3::SysInit() {
pLocTex = glGetUniformLocation(pShader, "tex"); pLocTex = glGetUniformLocation(pShader, "tex");
pLocAlfa = glGetUniformLocation(pShader, "push.alfa"); pLocAlfa = glGetUniformLocation(pShader, "push.alfa");
pLocIsSDF = glGetUniformLocation(pShader, "push.is_sdf");
pLocProjection = glGetUniformLocation(pShader, "ubo.projection"); pLocProjection = glGetUniformLocation(pShader, "ubo.projection");
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -65,20 +67,12 @@ void GfxOpenGL3::Submit(size_t count, size_t start) {
BindTexture(CurrentTex); BindTexture(CurrentTex);
glUseProgram(pShader); glUseProgram(pShader);
glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data()); glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data());
glBindVertexArray(VAO); glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, CurrentVertex * sizeof(PD::Li::Vertex),
GetVertexBufPtr(0), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, CurrentIndex * sizeof(u16),
GetIndexBufPtr(0), GL_DYNAMIC_DRAW);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT,
reinterpret_cast<void*>(start * sizeof(u16))); reinterpret_cast<void*>(start * sizeof(u16)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0); glBindVertexArray(0);
BindTexture(0); BindTexture(0);
} }
@@ -88,7 +82,8 @@ void GfxOpenGL3::BindTexture(TextureID id) {
glUniform1i(pLocTex, 0); glUniform1i(pLocTex, 0);
GLint fmt = 0; GLint fmt = 0;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
glUniform1i(pLocAlfa, fmt == GL_ALPHA); glUniform1i(pLocAlfa, fmt == GL_R8);
glUniform1i(pLocIsSDF, CurrentTexIsSDF);
} }
void GfxOpenGL3::SysReset() { void GfxOpenGL3::SysReset() {
@@ -112,13 +107,23 @@ Li::Texture GfxOpenGL3::LoadTexture(const std::vector<PD::u8>& pixels, int w,
// Set base format (Always using RGBA as base) // Set base format (Always using RGBA as base)
GLenum fmt = GL_RGBA; GLenum fmt = GL_RGBA;
GLenum ifmt = GL_RGBA8;
if (type == TextureFormat::RGB24) { if (type == TextureFormat::RGB24) {
ifmt = GL_RGB8;
fmt = GL_RGB; fmt = GL_RGB;
} else if (type == TextureFormat::A8) { } else if (type == TextureFormat::A8) {
fmt = GL_ALPHA; ifmt = GL_R8;
fmt = GL_RED;
} }
glTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, fmt, GL_UNSIGNED_BYTE, glTexImage2D(GL_TEXTURE_2D, 0, ifmt, w, h, 0, fmt, GL_UNSIGNED_BYTE,
pixels.data()); pixels.data());
if (type == TextureFormat::A8) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE);
}
if (filter == TextureFilter::Linear) { if (filter == TextureFilter::Linear) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -141,6 +146,30 @@ void GfxOpenGL3::DeleteTexture(const Li::Texture& tex) {
GLuint tex_ = tex.GetID(); GLuint tex_ = tex.GetID();
glDeleteTextures(1, &tex_); glDeleteTextures(1, &tex_);
} }
void GfxOpenGL3::UploadPools() {
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, GetVertexPoolSize() * sizeof(PD::Li::Vertex),
GetVertexBufPtr(0), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndexPoolSize() * sizeof(u16),
GetIndexBufPtr(0), GL_DYNAMIC_DRAW);
glBindVertexArray(0);
}
void GfxOpenGL3::ClipRect() {
if (CurrentHasClip) {
glEnable(GL_SCISSOR_TEST);
glScissor(CurrentClip.x, ViewPort.y - (CurrentClip.y + CurrentClip.w),
CurrentClip.z, CurrentClip.w);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
} // namespace PD } // namespace PD
#else #else
namespace PD { namespace PD {
@@ -159,5 +188,7 @@ Li::Texture GfxOpenGL3::LoadTexture(const std::vector<PD::u8>& pixels, int w,
return Li::Texture(); return Li::Texture();
} }
void GfxOpenGL3::DeleteTexture(const Li::Texture& tex) {} void GfxOpenGL3::DeleteTexture(const Li::Texture& tex) {}
void GfxOpenGL3::UploadPools() {}
void GfxOpenGL3::ClipRect() {}
} // namespace PD } // namespace PD
#endif #endif
+82
View File
@@ -0,0 +1,82 @@
#include <pd_system/hid_3ds.hpp>
#if defined(PD_ENABLE_HID3DS) && defined(__3DS__)
#include <3ds.h>
namespace PD {
struct Hid3DS::Impl {
std::string* Text;
bool InTextMode = false;
};
Hid3DS::Hid3DS() : HidDriver("Hid3DS") {
impl = new Impl;
pFlags |= PDHidBackendFlags_HasGamepad;
pFlags |= PDHidBackendFlags_HasTouch;
pGamepad[KEY_A] = HidInternal::Gamepad::A;
pGamepad[KEY_B] = HidInternal::Gamepad::B;
pGamepad[KEY_X] = HidInternal::Gamepad::X;
pGamepad[KEY_Y] = HidInternal::Gamepad::Y;
pGamepad[KEY_START] = HidInternal::Gamepad::Start;
pGamepad[KEY_SELECT] = HidInternal::Gamepad::Select;
pGamepad[KEY_L] = HidInternal::Gamepad::L;
pGamepad[KEY_R] = HidInternal::Gamepad::R;
pGamepad[KEY_DUP] = HidInternal::Gamepad::DUp;
pGamepad[KEY_DDOWN] = HidInternal::Gamepad::DDown;
pGamepad[KEY_DLEFT] = HidInternal::Gamepad::DLeft;
pGamepad[KEY_DRIGHT] = HidInternal::Gamepad::DRight;
pGamepad[KEY_CPAD_UP] = HidInternal::Gamepad::CPUp;
pGamepad[KEY_CPAD_DOWN] = HidInternal::Gamepad::CPDown;
pGamepad[KEY_CPAD_LEFT] = HidInternal::Gamepad::CPLeft;
pGamepad[KEY_CPAD_RIGHT] = HidInternal::Gamepad::CPRight;
pGamepad[KEY_CSTICK_UP] = HidInternal::Gamepad::CSUp;
pGamepad[KEY_CSTICK_DOWN] = HidInternal::Gamepad::CSDown;
pGamepad[KEY_CSTICK_LEFT] = HidInternal::Gamepad::CSLeft;
pGamepad[KEY_CSTICK_RIGHT] = HidInternal::Gamepad::CSRight;
pGamepad[KEY_ZL] = HidInternal::Gamepad::ZL;
pGamepad[KEY_ZR] = HidInternal::Gamepad::ZR;
pGamepad[KEY_TOUCH] = HidInternal::Gamepad::Touch;
}
Hid3DS::~Hid3DS() { delete impl; }
void Hid3DS::Update() {
HidDriver::Update(); // clear stats
hidScanInput();
u32 kd = hidKeysDown();
u32 kh = hidKeysHeld();
u32 ku = hidKeysUp();
for (const auto& b : pGamepad) {
if (b.first & kd) {
pGamepadEvents[0][Event::Down] |= b.second;
}
if (b.first & kh) {
pGamepadEvents[0][Event::Held] |= b.second;
}
if (b.first & ku) {
pGamepadEvents[0][Event::Up] |= b.second;
}
}
/*if (pLocked) {
SwapTab();
}*/
touchPosition t;
hidTouchRead(&t);
pMouse[0] = fvec2(t.px, t.py);
}
} // namespace PD
#else
struct GLFWgamepadstate {};
namespace PD {
Hid3DS::Hid3DS() : HidDriver("Hid3DS") {}
Hid3DS::~Hid3DS() {}
void Hid3DS::Update() {
HidDriver::Update(); // clear stats
}
} // namespace PD
#endif
+64 -3
View File
@@ -14,6 +14,19 @@ struct HidGlfw::Impl {
bool InTextMode = false; bool InTextMode = false;
}; };
constexpr int KEY_BASE = GLFW_GAMEPAD_BUTTON_LAST;
constexpr int KEY_LSTICK_LEFT = KEY_BASE + 1;
constexpr int KEY_LSTICK_RIGHT = KEY_BASE + 2;
constexpr int KEY_LSTICK_UP = KEY_BASE + 3;
constexpr int KEY_LSTICK_DOWN = KEY_BASE + 4;
constexpr int KEY_RSTICK_LEFT = KEY_BASE + 5;
constexpr int KEY_RSTICK_RIGHT = KEY_BASE + 6;
constexpr int KEY_RSTICK_UP = KEY_BASE + 7;
constexpr int KEY_RSTICK_DOWN = KEY_BASE + 8;
constexpr int KEY_LEFT_TRIGGER = KEY_BASE + 9;
constexpr int KEY_RIGHT_TRIGGER = KEY_BASE + 10;
constexpr int KEY_LAST = KEY_RIGHT_TRIGGER;
HidGlfw::HidGlfw(GLFWwindow* win) : HidDriver("HidGlfw") { HidGlfw::HidGlfw(GLFWwindow* win) : HidDriver("HidGlfw") {
impl = new Impl; impl = new Impl;
impl->Win = win; impl->Win = win;
@@ -37,21 +50,47 @@ HidGlfw::HidGlfw(GLFWwindow* win) : HidDriver("HidGlfw") {
pGamepad[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = HidInternal::Gamepad::R; pGamepad[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = HidInternal::Gamepad::R;
pGamepad[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = HidInternal::Gamepad::LStick; pGamepad[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = HidInternal::Gamepad::LStick;
pGamepad[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = HidInternal::Gamepad::RStick; pGamepad[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = HidInternal::Gamepad::RStick;
for (int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) { pGamepad[KEY_LEFT_TRIGGER] = HidInternal::Gamepad::ZL;
pGamepad[KEY_RIGHT_TRIGGER] = HidInternal::Gamepad::ZR;
pGamepad[KEY_LSTICK_LEFT] = HidInternal::Gamepad::CPLeft;
pGamepad[KEY_LSTICK_RIGHT] = HidInternal::Gamepad::CPRight;
pGamepad[KEY_LSTICK_UP] = HidInternal::Gamepad::CPUp;
pGamepad[KEY_LSTICK_DOWN] = HidInternal::Gamepad::CPDown;
pGamepad[KEY_RSTICK_LEFT] = HidInternal::Gamepad::CSLeft;
pGamepad[KEY_RSTICK_RIGHT] = HidInternal::Gamepad::CSRight;
pGamepad[KEY_RSTICK_UP] = HidInternal::Gamepad::CSUp;
pGamepad[KEY_RSTICK_DOWN] = HidInternal::Gamepad::CSDown;
for (int i = 0; i <= KEY_LAST; i++) {
impl->GPPrevStates[i] = 0; impl->GPPrevStates[i] = 0;
} }
} }
HidGlfw::~HidGlfw() {} HidGlfw::~HidGlfw() { delete impl; }
void HidGlfw::Update() { void HidGlfw::Update() {
HidDriver::Update(); // clear stats HidDriver::Update(); // clear stats
GLFWgamepadstate gpstate; GLFWgamepadstate gpstate;
int gps = glfwGetGamepadState(GLFW_JOYSTICK_1, &gpstate); int gps = glfwGetGamepadState(GLFW_JOYSTICK_1, &gpstate);
if (gps == GLFW_TRUE) { if (gps == GLFW_TRUE) {
HandleAxisKey(gpstate, KEY_LEFT_TRIGGER, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER,
false);
HandleAxisKey(gpstate, KEY_RIGHT_TRIGGER, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER,
false);
HandleAxisKey(gpstate, KEY_LSTICK_LEFT, GLFW_GAMEPAD_AXIS_LEFT_X, true);
HandleAxisKey(gpstate, KEY_LSTICK_RIGHT, GLFW_GAMEPAD_AXIS_LEFT_X, false);
HandleAxisKey(gpstate, KEY_LSTICK_UP, GLFW_GAMEPAD_AXIS_LEFT_Y, true);
HandleAxisKey(gpstate, KEY_LSTICK_DOWN, GLFW_GAMEPAD_AXIS_LEFT_Y, false);
HandleAxisKey(gpstate, KEY_RSTICK_LEFT, GLFW_GAMEPAD_AXIS_RIGHT_X, true);
HandleAxisKey(gpstate, KEY_RSTICK_RIGHT, GLFW_GAMEPAD_AXIS_RIGHT_X, false);
HandleAxisKey(gpstate, KEY_RSTICK_UP, GLFW_GAMEPAD_AXIS_RIGHT_Y, true);
HandleAxisKey(gpstate, KEY_RSTICK_DOWN, GLFW_GAMEPAD_AXIS_RIGHT_Y, false);
pLStick[0].x = gpstate.axes[GLFW_GAMEPAD_AXIS_LEFT_X];
pLStick[0].y = gpstate.axes[GLFW_GAMEPAD_AXIS_LEFT_Y];
pRStick[0].x = gpstate.axes[GLFW_GAMEPAD_AXIS_RIGHT_X];
pRStick[0].y = gpstate.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y];
for (int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) { for (int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) {
if (gpstate.buttons[i] == GLFW_PRESS) { if (gpstate.buttons[i] == GLFW_PRESS) {
if (impl->PrevStates[i] == GLFW_RELEASE) { if (impl->GPPrevStates[i] == GLFW_RELEASE) {
pGamepadEvents[0][Event::Down] |= pGamepad[i]; pGamepadEvents[0][Event::Down] |= pGamepad[i];
} }
pGamepadEvents[0][Event::Held] |= pGamepad[i]; pGamepadEvents[0][Event::Held] |= pGamepad[i];
@@ -80,8 +119,28 @@ void HidGlfw::Update() {
glfwGetCursorPos(impl->Win, &x, &y); glfwGetCursorPos(impl->Win, &x, &y);
pMouse[0] = fvec2(x, y); pMouse[0] = fvec2(x, y);
} }
void HidGlfw::HandleAxisKey(GLFWgamepadstate s, int iK, int eA, bool negative) {
if (s.axes[eA] <= 1.f && s.axes[eA] >= -1.f) {
if (s.axes[eA] > 0.05f && !negative) {
if (impl->GPPrevStates[iK] == GLFW_RELEASE) {
pGamepadEvents[0][Event::Down] |= pGamepad[iK];
}
pGamepadEvents[0][Event::Held] |= pGamepad[iK];
}
if (s.axes[eA] < -0.05f && negative) {
if (impl->GPPrevStates[iK] == GLFW_RELEASE) {
pGamepadEvents[0][Event::Down] |= pGamepad[iK];
}
pGamepadEvents[0][Event::Held] |= pGamepad[iK];
}
}
impl->GPPrevStates[iK] = (s.axes[eA] <= -0.05 && s.axes[eA] >= 0.05 &&
s.axes[eA] >= -1.f && s.axes[eA] <= 1);
}
} // namespace PD } // namespace PD
#else #else
struct GLFWgamepadstate {};
namespace PD { namespace PD {
HidGlfw::HidGlfw(GLFWwindow* win) : HidDriver("HidGlfw") {} HidGlfw::HidGlfw(GLFWwindow* win) : HidDriver("HidGlfw") {}
@@ -91,5 +150,7 @@ HidGlfw::~HidGlfw() {}
void HidGlfw::Update() { void HidGlfw::Update() {
HidDriver::Update(); // clear stats HidDriver::Update(); // clear stats
} }
void HidGlfw::HandleAxisKey(GLFWgamepadstate s, int iK, int eA, bool negative) {
}
} // namespace PD } // namespace PD
#endif #endif
+1 -1
View File
@@ -11,7 +11,7 @@ struct HidNX::Impl {
HidNX::HidNX() : HidDriver("HidNX") { impl = new Impl; } HidNX::HidNX() : HidDriver("HidNX") { impl = new Impl; }
HidNX::~HidNX() {} HidNX::~HidNX() { delete impl; }
void HidNX::Update() { void HidNX::Update() {
HidDriver::Update(); // clear stats HidDriver::Update(); // clear stats
+2 -2
View File
@@ -4,7 +4,7 @@
{ {
"name": "3ds-debug", "name": "3ds-debug",
"generator": "Ninja", "generator": "Ninja",
"displayName": "Nintendo 3DS", "displayName": "Nintendo 3DS Debug",
"binaryDir": "${sourceDir}/build/3ds-debug", "binaryDir": "${sourceDir}/build/3ds-debug",
"toolchainFile": "/opt/devkitPro/cmake/3DS.cmake", "toolchainFile": "/opt/devkitPro/cmake/3DS.cmake",
"cacheVariables": { "cacheVariables": {
@@ -14,7 +14,7 @@
{ {
"name": "3ds-release", "name": "3ds-release",
"generator": "Ninja", "generator": "Ninja",
"displayName": "Nintendo 3DS", "displayName": "Nintendo 3DS Release",
"binaryDir": "${sourceDir}/build/3ds-release", "binaryDir": "${sourceDir}/build/3ds-release",
"toolchainFile": "/opt/devkitPro/cmake/3DS.cmake", "toolchainFile": "/opt/devkitPro/cmake/3DS.cmake",
"cacheVariables": { "cacheVariables": {
+2 -2
View File
@@ -4,7 +4,7 @@
{ {
"name": "default-debug", "name": "default-debug",
"generator": "Ninja", "generator": "Ninja",
"displayName": "Default", "displayName": "Default Debug",
"binaryDir": "${sourceDir}/build/default-debug", "binaryDir": "${sourceDir}/build/default-debug",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug" "CMAKE_BUILD_TYPE": "Debug"
@@ -13,7 +13,7 @@
{ {
"name": "default-release", "name": "default-release",
"generator": "Ninja", "generator": "Ninja",
"displayName": "Default", "displayName": "Default Release",
"binaryDir": "${sourceDir}/build/default-release", "binaryDir": "${sourceDir}/build/default-release",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release" "CMAKE_BUILD_TYPE": "Release"
+2 -2
View File
@@ -4,7 +4,7 @@
{ {
"name": "switch-debug", "name": "switch-debug",
"generator": "Ninja", "generator": "Ninja",
"displayName": "Nintendo Switch", "displayName": "Nintendo Switch Debug",
"binaryDir": "${sourceDir}/build/switch-debug", "binaryDir": "${sourceDir}/build/switch-debug",
"toolchainFile": "/opt/devkitPro/cmake/Switch.cmake", "toolchainFile": "/opt/devkitPro/cmake/Switch.cmake",
"cacheVariables": { "cacheVariables": {
@@ -15,7 +15,7 @@
{ {
"name": "switch-release", "name": "switch-release",
"generator": "Ninja", "generator": "Ninja",
"displayName": "Nintendo Switch", "displayName": "Nintendo Switch Release",
"binaryDir": "${sourceDir}/build/switch-release", "binaryDir": "${sourceDir}/build/switch-release",
"toolchainFile": "/opt/devkitPro/cmake/Switch.cmake", "toolchainFile": "/opt/devkitPro/cmake/Switch.cmake",
"cacheVariables": { "cacheVariables": {
+1
View File
@@ -27,3 +27,4 @@ SOFTWARE.
#include <pd/drivers/drivers.hpp> #include <pd/drivers/drivers.hpp>
#include <pd/image/image.hpp> #include <pd/image/image.hpp>
#include <pd/lithium/lithium.hpp> #include <pd/lithium/lithium.hpp>
#include <pd/ui7/ui7.hpp>
+4
View File
@@ -71,6 +71,7 @@ void Log(LogLevel lvl, std::format_string<Args...> fmt, Args&&... args) {
} }
template <typename T> template <typename T>
std::string TypeName() { std::string TypeName() {
#ifdef __RTTI
#if defined(__GNUG__) && !defined(_MSC_VER) #if defined(__GNUG__) && !defined(_MSC_VER)
int res = 0; int res = 0;
std::unique_ptr<char, void (*)(void*)> up{ std::unique_ptr<char, void (*)(void*)> up{
@@ -79,6 +80,9 @@ std::string TypeName() {
#else #else
return typeid(T).name(); // no demangler available :/ return typeid(T).name(); // no demangler available :/
#endif #endif
#else
return "";
#endif
} }
} // namespace PD } // namespace PD
+14
View File
@@ -121,6 +121,20 @@ class PD_API Color {
return *this; return *this;
} }
/**
* Lerp
* @param v Target color
* @param t interpolation factor
* @return Class Reference
*/
constexpr Color& Lerp(const Color& v, float t) {
a = static_cast<u8>(a + (v.a - a) * t);
b = static_cast<u8>(b + (v.b - b) * t);
g = static_cast<u8>(g + (v.g - g) * t);
r = static_cast<u8>(r + (v.r - r) * t);
return *this;
}
/** /**
* Get 32Bit Color Value * Get 32Bit Color Value
* @return 32Bit Color Value (ABGR iirc) * @return 32Bit Color Value (ABGR iirc)
+1 -22
View File
@@ -56,21 +56,9 @@ struct PD_API Mat4 {
constexpr float* Ptr() { return m.data(); } constexpr float* Ptr() { return m.data(); }
constexpr const float* Ptr() const { return m.data(); } constexpr const float* Ptr() const { return m.data(); }
constexpr float& operator()(int row, int col) { constexpr float& operator()(int row, int col) { return m[col * 4 + row]; }
#ifdef __3DS__
// 3ds is full reverse order iirc
return m[row * 4 + (3 - col)];
#else
return m[col * 4 + row];
#endif
}
constexpr float operator()(int row, int col) const { constexpr float operator()(int row, int col) const {
#ifdef __3DS__
// 3ds is full reverse order iirc
return m[row * 4 + (3 - col)];
#else
return m[col * 4 + row]; return m[col * 4 + row];
#endif
} }
constexpr Mat4 operator*(const Mat4& v) const { constexpr Mat4 operator*(const Mat4& v) const {
@@ -122,21 +110,12 @@ struct PD_API Mat4 {
constexpr static Mat4 Ortho(float l, float r, float b, float t, float n, constexpr static Mat4 Ortho(float l, float r, float b, float t, float n,
float f) { float f) {
Mat4 ret; Mat4 ret;
#ifdef __3DS__ // Patch to rotate the Matrix correctly
ret(0, 1) = 2.f / (t - b);
ret(0, 3) = (b + t) / (b - t);
ret(1, 0) = 2.f / (l - r);
ret(1, 3) = (l + r) / (r - l);
ret(2, 2) = 1.f / (n - f);
ret(2, 3) = 0.5f * (n + f) / (n - f) - 0.5f;
#else
ret(0, 0) = 2.0f / (r - l); ret(0, 0) = 2.0f / (r - l);
ret(0, 3) = -(r + l) / (r - l); ret(0, 3) = -(r + l) / (r - l);
ret(1, 1) = 2.0f / (t - b); ret(1, 1) = 2.0f / (t - b);
ret(1, 3) = -(t + b) / (t - b); ret(1, 3) = -(t + b) / (t - b);
ret(2, 2) = -2.0f / (f - n); ret(2, 2) = -2.0f / (f - n);
ret(2, 3) = -(f + n) / (f - n); ret(2, 3) = -(f + n) / (f - n);
#endif
ret(3, 3) = 1.f; ret(3, 3) = 1.f;
return ret; return ret;
} }
+28
View File
@@ -107,6 +107,34 @@ class Pool {
pPos = 0; pPos = 0;
} }
/** THE ILLEGAL RESET FUNC */
void NoReset() { pPos = 0; }
/**
* Copy the data of another pool
*/
void AppendCopy(const Pool& v) {
if (!v.size()) return;
ExpandIf(v.size());
for (size_t i = 0; i < v.size(); i++) {
pData[pPos + i] = v.pData[i];
}
pPos += v.size();
}
/**
* Move the data of another pool
*/
void AppendMove(Pool& v) {
if (!v.size()) return;
ExpandIf(v.size());
for (size_t i = 0; i < v.size(); i++) {
pData[pPos + i] = std::move(v.pData[i]);
}
pPos += v.size();
v.ResetFast();
}
size_t size() const { return pPos; } size_t size() const { return pPos; }
size_t capacity() const { return pCap; } size_t capacity() const { return pCap; }
T& at(size_t idx) { return pData[idx]; } T& at(size_t idx) { return pData[idx]; }
+8 -3
View File
@@ -23,6 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include <map>
#include <pd/common.hpp> #include <pd/common.hpp>
namespace PD { namespace PD {
@@ -202,14 +203,15 @@ class Res {
/** Trace ID */ /** Trace ID */
std::string id; std::string id;
/** Start time */ /** Start time */
u64 start; u64 start = 0;
/** End Time */ /** End Time */
u64 end; u64 end = 0;
/** Last Diff */ /** Last Diff */
u64 diff; u64 diff = 0;
/** Protocol */ /** Protocol */
TimeStats protocol; TimeStats protocol;
}; };
using TraceMap = std::map<std::string, TT::Res>;
/** /**
* Begin a Trace * Begin a Trace
* @param id Name of the Trace * @param id Name of the Trace
@@ -220,6 +222,9 @@ PD_API void Beg(const std::string& id);
* @param id Name of the Trace * @param id Name of the Trace
*/ */
PD_API void End(const std::string& id); PD_API void End(const std::string& id);
PD_API TraceMap& GetTraceMap();
PD_API TT::Res& GetTraceRef(const std::string& id);
PD_API bool TraceExist(const std::string& id);
/** /**
* Collect Start end end of the trace by tracking * Collect Start end end of the trace by tracking
* when the Scope object goes out of scope * when the Scope object goes out of scope
+161 -26
View File
@@ -2,7 +2,7 @@
#include <pd/core/mat.hpp> #include <pd/core/mat.hpp>
#include <pd/drivers/interface.hpp> #include <pd/drivers/interface.hpp>
#include <pd/lithium/command.hpp> #include <pd/lithium/drawlist.hpp>
#include <pd/lithium/pools.hpp> #include <pd/lithium/pools.hpp>
#include <pd/lithium/texture.hpp> #include <pd/lithium/texture.hpp>
@@ -10,7 +10,10 @@ using PDGfxBackendFlags = PD::u32;
enum PDGfxBackendFlags_ { enum PDGfxBackendFlags_ {
PDGfxBackendFlags_None = 0, PDGfxBackendFlags_None = 0,
PDGfxBackendFlags_FlipUV_Y = 1 << 0, // Essential for font loading PDGfxBackendFlags_FlipUV_Y = 1 << 0, // Essential for font loading
PDGfxBackendFlags_WindingCW = 1 << 0, // Use CW instead of CCW winding PDGfxBackendFlags_WindingCW = 1 << 1, // Use CW instead of CCW winding
PDGfxBackendFlags_HasClipRect = 1 << 2, // Clip rects supported
PDGfxBackendFlags_ReqPow2 = 1 << 3, // Tex size must be pow of 2
PDGfxBackendFlags_ApproxSDF = 1 << 4, // Fake SDF for non smoothstep systems
}; };
namespace PD { namespace PD {
@@ -38,7 +41,7 @@ class PD_API GfxDriver : public DriverInterface {
return Li::Texture(); return Li::Texture();
} }
virtual void DeleteTexture(const Li::Texture& tex) {} virtual void DeleteTexture(const Li::Texture& tex) {}
virtual void Draw(const Pool<Li::Command>& commands) {} virtual void Draw(const Li::Drawlist& commands) {}
Li::Texture::Ptr GetWhiteTexture() { return &pWhite; } Li::Texture::Ptr GetWhiteTexture() { return &pWhite; }
PDGfxBackendFlags GetFlags() { return Flags; } PDGfxBackendFlags GetFlags() { return Flags; }
@@ -47,12 +50,25 @@ class PD_API GfxDriver : public DriverInterface {
size_t GetNumDrawcalls() const { return CountDrawcalls; } size_t GetNumDrawcalls() const { return CountDrawcalls; }
size_t GetNumCommands() const { return CountCommands; } size_t GetNumCommands() const { return CountCommands; }
// Global Pool Interface
virtual size_t AllocateVertices(size_t count, PD::ptr accessor) = 0;
virtual size_t AllocateIndices(size_t count, PD::ptr accessor) = 0;
virtual bool ExpandVertices(size_t count, PD::ptr accessor) = 0;
virtual bool ExpandIndices(size_t count, PD::ptr accessor) = 0;
virtual void PutVertex(size_t loc, const Li::Vertex& vtx,
PD::ptr accessor) = 0;
virtual void PutIndex(size_t loc, u16 idx, PD::ptr accessor) = 0;
virtual const Li::Vertex& GetVertex(size_t loc) const = 0;
virtual const u16& GetIndex(size_t loc) const = 0;
virtual void ResetPools() = 0;
protected: protected:
virtual void SysDeinit() {} virtual void SysDeinit() {}
virtual void SysInit() {} virtual void SysInit() {}
virtual void SysReset() {} virtual void SysReset() {}
virtual void Submit(size_t count, size_t start) {} virtual void Submit(size_t count, size_t start) {}
virtual void ResetPools() = 0; virtual void UploadPools() {} // not every driver requires it
virtual void ClipRect() {}
void RegisterTexture(const Li::Texture& tex); void RegisterTexture(const Li::Texture& tex);
void UnregisterTexture(const Li::Texture& tex); void UnregisterTexture(const Li::Texture& tex);
@@ -65,7 +81,11 @@ class PD_API GfxDriver : public DriverInterface {
size_t CurrentVertex = 0; size_t CurrentVertex = 0;
size_t pCountDrawcalls = 0; size_t pCountDrawcalls = 0;
size_t pCountCommands = 0; size_t pCountCommands = 0;
// State Variables oder so
TextureID CurrentTex = 0; TextureID CurrentTex = 0;
bool CurrentTexIsSDF = false;
bool CurrentHasClip = false;
fvec4 CurrentClip = 0;
Mat4 Projection; Mat4 Projection;
ivec2 ViewPort; ivec2 ViewPort;
std::unordered_map<TextureID, Li::Texture> pTextureRegestry; std::unordered_map<TextureID, Li::Texture> pTextureRegestry;
@@ -97,49 +117,133 @@ class GfxDriverBase : public GfxDriver {
pWhite = LoadTexture(img, 16, 16); pWhite = LoadTexture(img, 16, 16);
} }
void Draw(const Pool<Li::Command>& commands) override { void Draw(const Li::Drawlist& dl) override {
const auto& commands = dl.Data();
if (commands.size() == 0) return;
pCountCommands += commands.size(); pCountCommands += commands.size();
size_t vtotal = dl.GetNumVertices();
size_t itotal = dl.GetNumIndices();
size_t start_vtx = pVtxPool.size();
pVtxPool.Allocate(vtotal);
CurrentVertex += vtotal;
size_t start_idx = pIdxPool.size();
pIdxPool.Allocate(itotal);
CurrentIndex += itotal;
size_t current_vtx = start_vtx;
size_t current_idx = start_idx;
const auto& vpool = Li::GetVertexPool();
const auto& ipool = Li::GetIndexPool();
/** Build Pools */
for (size_t i = 0; i < commands.size(); i++) {
const auto& cmd = commands[i];
if (cmd.VertexCount > 0) {
std::memcpy(reinterpret_cast<void*>(pVtxPool.begin() + current_vtx),
vpool.begin() + cmd.FirstVertex,
cmd.VertexCount * sizeof(Li::Vertex));
}
for (size_t idx = 0; idx < cmd.IndexCount; idx++) {
u16 local_idx = ipool[cmd.FirstIndex + idx];
pIdxPool[current_idx + idx] = static_cast<u16>(current_vtx + local_idx);
}
current_vtx += cmd.VertexCount;
current_idx += cmd.IndexCount;
}
UploadPools();
size_t index = 0; size_t index = 0;
size_t ioff = start_idx;
while (index < commands.size()) { while (index < commands.size()) {
CurrentTex = commands[index].Tex; CurrentTex = commands[index].Tex;
CurrentTexIsSDF = commands[index].SDF;
CurrentHasClip = commands[index].ClipRectUsed;
CurrentClip = commands[index].ClipRect;
if (!CurrentTex) { if (!CurrentTex) {
CurrentTex = pWhite.GetID(); CurrentTex = pWhite.GetID();
} }
size_t startidx = CurrentIndex; size_t num_indices = 0;
ClipRect();
while (index < commands.size() && while (index < commands.size() &&
CurrentTexIsSDF == commands[index].SDF &&
(CurrentTex == commands[index].Tex || (CurrentTex == commands[index].Tex ||
(CurrentTex == pWhite.GetID() && commands[index].Tex == 0))) { (CurrentTex == pWhite.GetID() && commands[index].Tex == 0)) &&
const auto& c = commands[index]; CurrentClip == commands[index].ClipRect &&
auto pIdx = pIdxPool.Allocate(c.IndexCount); CurrentHasClip == commands[index].ClipRectUsed) {
auto pVtx = pVtxPool.Allocate(c.VertexCount); num_indices += commands[index].IndexCount;
for (size_t i = 0; i < c.IndexCount; i++) {
pIdx[i] = CurrentVertex + Li::GetIndex(c.FirstIndex + i);
}
CurrentIndex += c.IndexCount;
CurrentVertex += c.VertexCount;
for (size_t i = 0; i < c.VertexCount; i++) {
pVtx[i] = Li::GetVertex(c.FirstVertex + i);
}
index++; index++;
} }
Submit(CurrentIndex - startidx, startidx); if (num_indices > 0) {
Submit(num_indices, ioff);
ioff += num_indices;
pCountDrawcalls++; pCountDrawcalls++;
} }
} }
}
size_t AllocateVertices(size_t count, PD::ptr accessor) override {
pVertexAccessor = accessor;
size_t loc = pVtxPool.size();
pVtxPool.Allocate(count);
return loc;
}
size_t AllocateIndices(size_t count, PD::ptr accessor) override {
pIndexAccessor = accessor;
size_t loc = pIdxPool.size();
pIdxPool.Allocate(count);
return loc;
}
bool ExpandVertices(size_t count, PD::ptr accessor) override {
if (pVertexAccessor != accessor) return false;
pVtxPool.Allocate(count);
return true;
}
bool ExpandIndices(size_t count, PD::ptr accessor) override {
if (pIndexAccessor != accessor) return false;
pIdxPool.Allocate(count);
return true;
}
void PutVertex(size_t loc, const Li::Vertex& vtx, PD::ptr accessor) override {
if (pVertexAccessor != accessor) return;
pVtxPool.Put(loc, vtx);
}
void PutIndex(size_t loc, u16 idx, PD::ptr accessor) override {
if (pIndexAccessor != accessor) return;
pIdxPool.Put(loc, idx);
}
const Li::Vertex& GetVertex(size_t loc) const override {
return pVtxPool[loc];
}
const u16& GetIndex(size_t loc) const override { return pIdxPool[loc]; }
void ResetPools() override {
pVtxPool.NoReset();
pIdxPool.NoReset();
}
protected: protected:
u16* GetIndexBufPtr(size_t start) { return &pIdxPool[start]; } u16* GetIndexBufPtr(size_t start) { return &pIdxPool[start]; }
Li::Vertex* GetVertexBufPtr(size_t start) { return &pVtxPool[start]; } Li::Vertex* GetVertexBufPtr(size_t start) { return &pVtxPool[start]; }
size_t GetVertexPoolSize() const { return pVtxPool.size(); } size_t GetVertexPoolSize() const { return pVtxPool.size(); }
size_t GetIndexPoolSize() const { return pIdxPool.size(); } size_t GetIndexPoolSize() const { return pIdxPool.size(); }
void ResetPools() override {
pVtxPool.ResetFast();
pIdxPool.ResetFast();
}
private: private:
VtxPool pVtxPool; VtxPool pVtxPool;
IdxPool pIdxPool; IdxPool pIdxPool;
PD::ptr pVertexAccessor = 0;
PD::ptr pIndexAccessor = 0;
}; };
class PD_API Gfx { class PD_API Gfx {
@@ -158,9 +262,7 @@ class PD_API Gfx {
static void SetViewPort(const ivec2& vp) { driver->SetViewPort(vp); } static void SetViewPort(const ivec2& vp) { driver->SetViewPort(vp); }
static void SetViewPort(int w, int h) { driver->SetViewPort(w, h); } static void SetViewPort(int w, int h) { driver->SetViewPort(w, h); }
static void Reset() { driver->Reset(); } static void Reset() { driver->Reset(); }
static void Draw(const Pool<Li::Command>& commands) { static void Draw(const Li::Drawlist& dl) { driver->Draw(dl); }
driver->Draw(commands);
}
static Li::Texture LoadTexture(const std::vector<PD::u8>& pixels, int w, static Li::Texture LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, int h,
TextureFormat type = TextureFormat::RGBA32, TextureFormat type = TextureFormat::RGBA32,
@@ -183,6 +285,39 @@ class PD_API Gfx {
static size_t GetNumDrawcalls() { return driver->GetNumDrawcalls(); } static size_t GetNumDrawcalls() { return driver->GetNumDrawcalls(); }
static size_t GetNumCommands() { return driver->GetNumCommands(); } static size_t GetNumCommands() { return driver->GetNumCommands(); }
// Gloabal Pool Interface
static size_t AllocateVertices(size_t count, PD::ptr accessor) {
return driver->AllocateVertices(count, accessor);
}
static size_t AllocateIndices(size_t count, PD::ptr accessor) {
return driver->AllocateIndices(count, accessor);
}
static bool ExpandVertices(size_t count, PD::ptr accessor) {
return driver->ExpandVertices(count, accessor);
}
static bool ExpandIndices(size_t count, PD::ptr accessor) {
return driver->ExpandIndices(count, accessor);
}
static void PutVertex(size_t loc, const Li::Vertex& vtx, PD::ptr accessor) {
driver->PutVertex(loc, vtx, accessor);
}
static void PutIndex(size_t loc, u16 idx, PD::ptr accessor) {
driver->PutIndex(loc, idx, accessor);
}
static const Li::Vertex& GetVertex(size_t loc) {
return driver->GetVertex(loc);
}
static const u16& GetIndex(size_t loc) { return driver->GetIndex(loc); }
static void NewFrame() { driver->ResetPools(); }
private: private:
static std::unique_ptr<GfxDriver> driver; static std::unique_ptr<GfxDriver> driver;
}; };
+6
View File
@@ -127,6 +127,8 @@ class PD_API HidDriver : public DriverInterface {
virtual void Update(); virtual void Update();
virtual bool IsEvent(Event e, HidInternal::GamepadKey keys); virtual bool IsEvent(Event e, HidInternal::GamepadKey keys);
virtual bool IsEvent(Event e, HidInternal::Keyboard::Key keys); virtual bool IsEvent(Event e, HidInternal::Keyboard::Key keys);
virtual const fvec2& GetLeftStick() const { return pLStick[0]; }
virtual const fvec2& GetRightStick() const { return pRStick[0]; }
PDHidBackendFlags GetFlags() const { return pFlags; } PDHidBackendFlags GetFlags() const { return pFlags; }
@@ -134,6 +136,8 @@ class PD_API HidDriver : public DriverInterface {
void SwapTab(); void SwapTab();
PDHidBackendFlags pFlags = PDHidBackendFlags_None; PDHidBackendFlags pFlags = PDHidBackendFlags_None;
fvec2 pMouse[2]; // Current And last pos fvec2 pMouse[2]; // Current And last pos
fvec2 pLStick[2];
fvec2 pRStick[2];
std::unordered_map<u32, u32> pGamepad; std::unordered_map<u32, u32> pGamepad;
std::unordered_map<u128, u128> pKeyboard; std::unordered_map<u128, u128> pKeyboard;
std::unordered_map<Event, u32> pGamepadEvents[2]; std::unordered_map<Event, u32> pGamepadEvents[2];
@@ -168,6 +172,8 @@ class PD_API Hid {
return driver->IsEvent(e, keys); return driver->IsEvent(e, keys);
} }
static PDHidBackendFlags GetFlags() { return driver->GetFlags(); } static PDHidBackendFlags GetFlags() { return driver->GetFlags(); }
static const fvec2& GetLeftStick() { return driver->GetLeftStick(); }
static const fvec2& GetRightStick() { return driver->GetRightStick(); }
static const char* GetDriverName() { return driver->GetName(); } static const char* GetDriverName() { return driver->GetName(); }
+2
View File
@@ -26,6 +26,8 @@ class PD_API Os {
static u64 GetTime() { return driver->GetTime(); } static u64 GetTime() { return driver->GetTime(); }
static u64 GetTimeNano() { return driver->GetTimeNano(); } static u64 GetTimeNano() { return driver->GetTimeNano(); }
static const char* GetDriverName() { return driver->GetName(); }
private: private:
static std::unique_ptr<OsDriver> driver; static std::unique_ptr<OsDriver> driver;
}; };
+58
View File
@@ -0,0 +1,58 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/image/image.hpp>
#include <pd/pd_p_api.hpp>
namespace PD {
/**
* Namespace containing function to convert images
*/
namespace ImgConvert {
/**
* 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_API
void RGB24toRGBA32(std::vector<PD::u8>& out, const std::vector<u8>& in,
const int& w, const int& h);
PD_API
void RGB32toRGBA24(std::vector<u8>& out, const std::vector<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_API void Reverse32(std::vector<u8>& buf, const int& w, const int& h);
PD_API void ReverseBuf(std::vector<u8>& buf, size_t bpp, int w, int h);
} // namespace ImgConvert
} // namespace PD
+3 -1
View File
@@ -25,7 +25,7 @@ class PD_API Image {
void Copy(const std::vector<u8>& pixels, int w, int h, int bpp = 4); void Copy(const std::vector<u8>& pixels, int w, int h, int bpp = 4);
const int& Width() const { return pSize.x; } const int& Width() const { return pSize.x; }
const int& Height() const { return pSize.x; } const int& Height() const { return pSize.y; }
const ivec2& Size() const { return pSize; } const ivec2& Size() const { return pSize; }
const std::vector<u8>& data() const { return pData; } const std::vector<u8>& data() const { return pData; }
@@ -40,6 +40,8 @@ class PD_API Image {
static int Format2Bpp(Format fmt); static int Format2Bpp(Format fmt);
static Format GuessFmtFromBpp(int bpp); static Format GuessFmtFromBpp(int bpp);
void Convert(Format dst);
private: private:
std::vector<u8> pData; std::vector<u8> pData;
ivec2 pSize; ivec2 pSize;
+9 -48
View File
@@ -2,7 +2,6 @@
#include <cstddef> #include <cstddef>
#include <pd/core/pool.hpp> #include <pd/core/pool.hpp>
#include <pd/lithium/pools.hpp>
#include <pd/lithium/vertex.hpp> #include <pd/lithium/vertex.hpp>
namespace PD { namespace PD {
@@ -12,57 +11,16 @@ class Command {
Command() { Reset(); } Command() { Reset(); }
~Command() {} ~Command() {}
void Reserve(size_t vtx, size_t idx) { void Reserve(size_t vtx, size_t idx);
if (!FirstVertex) { void Reset();
FirstVertex = AllocateVertices(vtx, (PD::ptr)this);
VertexCountMax = vtx;
} else {
ExpandVertices(vtx, (PD::ptr)this);
VertexCountMax += vtx;
}
if (!FirstIndex) {
FirstIndex = AllocateIndices(idx, (PD::ptr)this);
IndexCountMax = idx;
} else {
ExpandIndices(idx, (PD::ptr)this);
IndexCountMax += idx;
}
}
void Reset() { Command& Add(const Vertex& vtx);
Layer = 0; Command& Add(u16 idx);
Tex = 0; Command& Add(u16 a, u16 b, u16 c);
FirstIndex = 0;
FirstVertex = 0;
IndexCount = 0;
VertexCount = 0;
VertexCountMax = 0;
IndexCountMax = 0;
}
Command& Add(const Vertex& vtx) {
if (VertexCount <= VertexCountMax)
PutVertex(FirstVertex + VertexCount++, vtx, (PD::ptr)this);
return *this;
}
Command& Add(u16 idx) {
if (IndexCount <= IndexCountMax)
PutIndex(FirstIndex + IndexCount++, VertexCount + idx, (PD::ptr)this);
return *this;
}
Command& Add(u16 a, u16 b, u16 c) {
if (IndexCount + 3 <= IndexCountMax) {
size_t idx = FirstIndex + IndexCount;
PutIndex(idx + 0, VertexCount + a, (PD::ptr)this);
PutIndex(idx + 1, VertexCount + b, (PD::ptr)this);
PutIndex(idx + 2, VertexCount + c, (PD::ptr)this);
IndexCount += 3;
}
return *this;
}
int Layer = 0; int Layer = 0;
ptr Tex = 0; ptr Tex = 0;
bool SDF = false;
size_t FirstVertex = 0; size_t FirstVertex = 0;
size_t FirstIndex = 0; size_t FirstIndex = 0;
size_t VertexCount = 0; size_t VertexCount = 0;
@@ -70,6 +28,9 @@ class Command {
// Todo: implement // Todo: implement
size_t VertexCountMax = 0; size_t VertexCountMax = 0;
size_t IndexCountMax = 0; size_t IndexCountMax = 0;
// ClipRect
PD::fvec4 ClipRect;
bool ClipRectUsed = false;
}; };
} // namespace Li } // namespace Li
} // namespace PD } // namespace PD
+33 -2
View File
@@ -26,6 +26,7 @@ using LiDrawFlags = PD::u32;
enum LiDrawFlags_ : PD::u32 { enum LiDrawFlags_ : PD::u32 {
LiDrawFlags_None = 0, LiDrawFlags_None = 0,
LiDrawFlags_Close = 1 << 0, LiDrawFlags_Close = 1 << 0,
LiDrawFlags_AA = 1 << 1,
}; };
namespace PD { namespace PD {
@@ -41,9 +42,27 @@ class PD_API Drawlist {
void Copy(Drawlist& other); void Copy(Drawlist& other);
void Optimize(); void Optimize();
void Clear(); void Clear();
void SetLayer(int layer) { pCurrentLayer = layer; }
void LayerUp() { pCurrentLayer++; }
void LayerDown() { pCurrentLayer--; }
int GetLayer() const { return pCurrentLayer; }
size_t GetNumVertices() const {
size_t count = 0;
for (const auto& cmd : pCommands) count += cmd.VertexCount;
return count;
}
size_t GetNumIndices() const {
size_t count = 0;
for (const auto& cmd : pCommands) count += cmd.IndexCount;
return count;
}
/** Command Allocation */ /** Command Allocation */
Command& NewCommand(); Command& NewCommand();
bool HasCommands() { return pCommands.size() > 0; }
Command& GetLastCommand() { return pCommands[pCommands.size() - 1]; }
/** Path API */ /** Path API */
void PathAdd(const fvec2& point) { pPath.Push(point); } void PathAdd(const fvec2& point) { pPath.Push(point); }
@@ -58,6 +77,8 @@ class PD_API Drawlist {
void PathStroke(const PD::Color& color, int t = 1, void PathStroke(const PD::Color& color, int t = 1,
LiDrawFlags flags = LiDrawFlags_None); LiDrawFlags flags = LiDrawFlags_None);
void PathFill(const PD::Color& color); void PathFill(const PD::Color& color);
void PathFillGradient(const PD::Color& a, const PD::Color& b,
float rad = 0.f);
void PathArcToN(const fvec2& c, float r, float amin, float amax, int s); void PathArcToN(const fvec2& c, float r, float amin, float amax, int s);
void PathFastArcToN(const fvec2& c, float r, float amin, float amax, int s); void PathFastArcToN(const fvec2& c, float r, float amin, float amax, int s);
void PathRect(const fvec2& tl, const fvec2& br, float r = 0.f); void PathRect(const fvec2& tl, const fvec2& br, float r = 0.f);
@@ -93,22 +114,32 @@ class PD_API Drawlist {
void DrawText(const fvec2& p, const char* text, const PD::Color& color); void DrawText(const fvec2& p, const char* text, const PD::Color& color);
void DrawTextEx(const fvec2& p, const char* text, const PD::Color& color, void DrawTextEx(const fvec2& p, const char* text, const PD::Color& color,
LiTextFlags flags, const fvec2& box = fvec2(0.f)); LiTextFlags flags, const fvec2& box = fvec2(0.f));
void DrawLine(const fvec2& a, const fvec2& b, const PD::Color& color,
int thickness = 1);
void DrawPolyLine(const Pool<fvec2>& points, const PD::Color& color, void DrawPolyLine(const Pool<fvec2>& points, const PD::Color& color,
LiDrawFlags flags = LiDrawFlags_None, int t = 1); LiDrawFlags flags = LiDrawFlags_None, int t = 1);
void DrawConvexPolyFilled(const Pool<fvec2>& points, const PD::Color& color); void DrawConvexPolyFilled(const Pool<fvec2>& points, const PD::Color& color);
void DrawConvexPolyFilled(const Pool<fvec2>& points, const PD::Color& a,
const PD::Color b, float rad = 0.f);
void PrimQuad(Command& cmd, const Rect& quad, const Rect& uv, void PrimQuad(Command& cmd, const Rect& quad, const Rect& uv,
const PD::Color& color); const PD::Color& color);
void PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b, void PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b,
const fvec2& c, const PD::Color& color); const fvec2& c, const PD::Color& color);
void PushClipRect(const fvec4& r) { pClipRects.push_back(r); }
void PopClipRect() {
if (!pClipRects.empty()) pClipRects.pop_back();
}
bool HasClipRect() { return !pClipRects.empty(); }
private: private:
Texture pCurrentTexture; Texture pCurrentTexture;
int pCurrentLayer = 0;
Pool<Command> pCommands; Pool<Command> pCommands;
Pool<fvec2> pPath; Pool<fvec2> pPath;
Pool<Vertex> pVertices; std::vector<fvec4> pClipRects;
Pool<u16> pIndices;
Font* pFont = nullptr; Font* pFont = nullptr;
float pFontScale = 1.f; float pFontScale = 1.f;
}; };
+20 -9
View File
@@ -14,6 +14,13 @@ enum LiTextFlags_ : PD::u32 {
LiTextFlags_NoOOS = 1 << 6, ///< No Out of Screen Rendering LiTextFlags_NoOOS = 1 << 6, ///< No Out of Screen Rendering
}; };
using LiFontFlags = PD::u32;
enum LiFontFlags_ : PD::u32 {
LiFontFlags_None = 0, ///< Not special (bitmap font)
LiFontFlags_SDF = 1 << 0, ///< SDF Texture (and mode)
LiFontFlags_Monospace = 1 << 1, ///< Monospace Rendering
};
namespace PD { namespace PD {
namespace Li { namespace Li {
class Drawlist; class Drawlist;
@@ -24,30 +31,31 @@ class PD_API Font {
fvec4 SimpleUV; fvec4 SimpleUV;
size_t Tex = 0; size_t Tex = 0;
fvec2 Size; fvec2 Size;
float Offset = 0.f; fvec2 Offset;
// float Offset = 0.f;
float AdvanceX = 0.f;
bool pInvalid = false; bool pInvalid = false;
}; };
Font() {} Font() {}
~Font() {} ~Font() {}
bool IsMonospace() { return pFlags & LiFontFlags_Monospace; }
bool IsSDF() { return pFlags & LiFontFlags_SDF; }
/** /**
* Load a TTF File * Load a TTF File
* @param path Path to the TTF file * @param path Path to the TTF file
* @param px_height Pixelheight of the codepoints (limit by 64) * @param px_height Pixelheight of the codepoints (limit by 64)
*/ */
void LoadTTF(const std::string& path, int px_height = 32); void LoadTTF(const std::string& path, int px_height = 32,
LiFontFlags flags = LiFontFlags_None);
/** /**
* Load a TTF File from Memory * Load a TTF File from Memory
* @param data File data * @param data File data
* @param px_height Pixelheight of the codepoints (limit by 64) * @param px_height Pixelheight of the codepoints (limit by 64)
*/ */
void LoadTTF(const std::vector<u8>& data, int px_height = 32); void LoadTTF(const std::vector<u8>& data, int px_height = 32,
/** LiFontFlags flags = LiFontFlags_None);
* Function that loads a default integrated font...
* This will only work if PD_LI_INCLUDE_FONTS was set
* on lithium build cause otherwise the font data is not included
*/
void LoadDefaultFont(int id = 0, int pixel_height = 32);
/** /**
* Getter for Codepoint reference * Getter for Codepoint reference
* @return codepoint dataholder reference * @return codepoint dataholder reference
@@ -92,6 +100,8 @@ class PD_API Font {
* **Now using unordered map** * **Now using unordered map**
*/ */
std::unordered_map<u32, Codepoint> CodeMap; std::unordered_map<u32, Codepoint> CodeMap;
/** need some performance tweaks */
std::array<Codepoint, 128> pAsciiCache;
/** TMS */ /** TMS */
struct TMELEM { struct TMELEM {
PD::u32 ID; PD::u32 ID;
@@ -103,6 +113,7 @@ class PD_API Font {
private: private:
size_t pCurrentTex = 0; size_t pCurrentTex = 0;
LiFontFlags pFlags = 0;
}; };
} // namespace Li } // namespace Li
} // namespace PD } // namespace PD
+3 -17
View File
@@ -1,26 +1,12 @@
#pragma once #pragma once
#include <cstddef> #include <pd/core/core.hpp>
#include <pd/lithium/vertex.hpp> #include <pd/lithium/vertex.hpp>
namespace PD { namespace PD {
namespace Li { namespace Li {
/** PD_API PD::Pool<Vertex>& GetVertexPool();
* Allocate an amount of vertices PD_API PD::Pool<u16>& GetIndexPool();
* returns the index of the first vertex
*/
PD_API size_t AllocateVertices(size_t count, PD::ptr accessor);
/**
* Allocate an amount of indices
* returns the index of the first elem
*/
PD_API size_t AllocateIndices(size_t count, PD::ptr accessor);
PD_API bool ExpandVertices(size_t count, PD::ptr accessor);
PD_API bool ExpandIndices(size_t count, PD::ptr accessor);
PD_API void PutVertex(size_t loc, const Vertex& vtx, PD::ptr accessor);
PD_API void PutIndex(size_t loc, u16 idx, PD::ptr accessor);
PD_API const Vertex& GetVertex(size_t loc);
PD_API const u16& GetIndex(size_t loc);
PD_API void ResetPools(); PD_API void ResetPools();
} // namespace Li } // namespace Li
} // namespace PD } // namespace PD
+1 -1
View File
@@ -16,7 +16,7 @@ enum class TextureFormat {
A8, A8,
}; };
namespace Li { namespace Li {
static int TextureFormat2Bpp(TextureFormat fmt) { inline int TextureFormat2Bpp(TextureFormat fmt) {
switch (fmt) { switch (fmt) {
case PD::TextureFormat::A8: case PD::TextureFormat::A8:
return 1; return 1;
+2
View File
@@ -9,6 +9,8 @@ class Vertex {
Vertex() {} Vertex() {}
Vertex(const fvec2& pos, const fvec2& uv, u32 color) Vertex(const fvec2& pos, const fvec2& uv, u32 color)
: pos(pos), uv(uv), color(color) {} : pos(pos), uv(uv), color(color) {}
Vertex(float x, float y, float u, float v, u32 color)
: pos(x, y), uv(u, v), color(color) {}
~Vertex() {} ~Vertex() {}
void Reset() { void Reset() {
+75
View File
@@ -0,0 +1,75 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
namespace UI7 {
/**
* Button Object
* @note Button Press is delayed by 1 frame
* (but the visual reaction is done in the same frame)
* This only means that InPressed is responding the info in
* the next frame
*/
class PD_API Button : public Container {
public:
/**
* Button Object constructor
* @param label Label of the Button
* @param pos Base Position
* @param lr Reference to the Renderer
*/
Button(const std::string& label, UI7::IO& io) {
this->label = label;
this->tdim = io.Font->GetTextBounds(label.c_str(), io.FontScale);
}
~Button() = default;
/** Return true if butten is pressed*/
bool IsPressed() { return pressed; }
/**
* Override for the Input Handler
* @note This function is usally called by Menu::Update
*/
void HandleInput() override;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/** Function to Update Size if framepadding changes */
void Update() override;
private:
fvec2 tdim; ///< Text size
UI7Color color = UI7Color_Button; ///< current button color
std::string label; ///< Label of the Button
bool pressed = false; ///< ispressed value
};
} // namespace UI7
} // namespace PD
+72
View File
@@ -0,0 +1,72 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
namespace PD {
namespace UI7 {
/**
* Checkbox Object
* @note The Updated input is available after
* Context::Update while the visual update is done
* during the Update
*/
class PD_API Checkbox : public Container {
public:
/**
* Constructor for Checkbox Object
* @param label Label of the Checkbox
* @param usr_ref Reference to the bool value to update
* @param io IO Reference
*/
Checkbox(const std::string& label, bool& usr_ref, UI7::IO& io)
: usr_ref(usr_ref) {
this->label = label;
this->tdim = io.Font->GetTextBounds(label.c_str(), io.FontScale);
}
~Checkbox() = default;
/**
* Override for the Input Handler
* @note This function is usally called by Menu::Update
*/
void HandleInput() override;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/** Update Size if framepadding changed */
void Update() override;
private:
fvec2 tdim; ///< Text Size
fvec2 cbs = fvec2(18); ///< Checkbox size
UI7Color color = UI7Color_FrameBackground; ///< Checkbox background Color
std::string label; ///< Checkbox Label
bool& usr_ref; ///< User bool reference
};
} // namespace UI7
} // namespace PD
+77
View File
@@ -0,0 +1,77 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
#include <pd/ui7/io.hpp>
#include <pd/ui7/layout.hpp>
namespace PD {
namespace UI7 {
/**
* Color Editor (Creating a PopUP when clicking)
*/
class PD_API ColorEdit : public Container {
public:
/**
* Constructor
* @param label Label of the Button
* @param pos Base Position
* @param lr Reference to the Renderer
*/
ColorEdit(const std::string& label, u32* color, UI7::IO& io) {
// PD::Assert(color != nullptr, "Input Color Address is null!");
this->label = label;
this->color_ref = color;
this->initial_color = *color;
this->tdim = io.Font->GetTextBounds(label.c_str(), io.FontScale);
}
~ColorEdit() {
if (layout) delete layout;
}
/**
* Override for the Input Handler
* @note This function is usally called by Menu::Update
*/
void HandleInput() override;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/** Function to Update Size if framepadding changes */
void Update() override;
private:
fvec2 tdim; ///< Text size
u32* color_ref = nullptr; ///< Color Reference
u32 initial_color; ///< Initial Color
std::string label; ///< Label of the Button
Layout* layout = nullptr; ///< Layout to open
bool is_shown = false; ///< AHow Layout Editor
};
} // namespace UI7
} // namespace PD
+201
View File
@@ -0,0 +1,201 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/pd_p_api.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
namespace UI7 {
/**
* Container base class all Objects are based on
* @note this class can be used to create custom Objects as well
*/
class PD_API Container {
public:
Container() = default;
/**
* Constructor with pos and Size
* @param pos Container Position
* @param size Container Size
*/
Container(const fvec2& pos, const fvec2& size) : pos(pos), size(size) {}
/**
* Constructor by a vec4 box
* @param box Box containing top left and bottom right coords
*/
Container(const fvec4& box)
: pos(fvec2(box.x, box.y)), size(fvec2(box.z - box.x, box.w - box.y)) {}
virtual ~Container() = default;
/**
* Init Function Required by every Object that uses
* Render or Input functions
* @param io IO Reference
* @param l Drawlist Reference
*/
void Init(UI7::IO* io, Li::Drawlist* l) {
list = l;
this->io = io;
pFont = io->Font;
// this->screen = io->Ren->CurrentScreen();
}
void SetClipRect(fvec4 clip) {
pClipRect = clip;
pCLipRectUsed = true;
}
/** Setter for Position */
void SetPos(const fvec2& pos) { this->pos = pos; }
/** Setter for Size */
void SetSize(const fvec2& size) { this->size = size; }
/** Getter for Position */
fvec2 GetPos() { return pos; }
/** Getter for Size */
fvec2 GetSize() { return size; }
Li::Font* GetFont() { return pFont; }
/**
* Get the Containers Final Position
* for Rendering and Input (if it has a parent Object)
*/
fvec2 FinalPos() {
vec2 res = pos;
if (parent) {
/// Probably should use parant->FinalPos here
res += parent->GetPos();
}
return res;
}
/** Setter for Parent Container */
void SetParent(Container* v) { parent = v; }
/** Getter for Parent Container */
Container* GetParent() { return parent; }
/** Check if Rendering can be skipped */
bool Skippable() const { return skippable; }
/** Check if the Object got a timeout (ID OBJ Relevant) */
bool Removable() const { return rem; }
/**
* Handles Scrolling by scrolling pos as well as
* Time for Remove for ID Objects
* @param scrolling Scrolling Position
* @param viewport Viewport to check if the Object is skippable
*/
void HandleScrolling(fvec2 scrolling, fvec4 viewport);
/** Template function for Input Handling */
virtual void HandleInput() {}
/** Tamplate function for Object rendering */
virtual void Draw() {}
/** Template function to update internal data (if needed) */
virtual void Update() {}
/** Template as well as base func for Pool based Containers */
virtual void Reset() {
pos = 0;
size = 0;
parent = nullptr;
id = 0;
pFlags = 0;
skippable = false;
rem = false;
inp_done = false;
pSelected = false;
pPressed = false;
pPressedTwice = false;
pCLipRectUsed = false;
pClipRect = 0;
io = nullptr;
list = nullptr;
last_use = 0;
}
/** Internal function */
void PreDraw();
/** Internal function */
void PostDraw();
/** Internal Input Handler */
void HandleInternalInput();
/**
* Function to unlock Input after Rendering is done in
* Menu::Update
* @note This is used if the Object got Input Handled directly after creation
* to not check for Inputs twice
*/
void UnlockInput() { inp_done = false; }
/** Get the Objects ID (if it is an ID object)*/
u32 GetID() const { return id; }
/**
* Set ID for ID Objects
* @param id Object ID (hashed prefix+objname+prefixed_counter)
*/
void SetID(u32 id) { this->id = id; }
/** Get a reference to IO */
UI7::IO* GetIO() { return io; }
protected:
/** used to skip Input/Render preocessing ot not*/
bool skippable = false;
/** value to check if an ID Object goes out of lifetime*/
bool rem = false;
/** Time of the last use (set by HandleScrolling)*/
u64 last_use = 0;
/** Input done or not for current frame*/
bool inp_done = false;
/** Reference to the Screen to draw the Object on*/
// Screen::Ref screen;
/** Container Position*/
fvec2 pos;
/** Container Size*/
fvec2 size;
/** Reference to the Drawlist to Draw to*/
Li::Drawlist* list = nullptr;
/** IO Reference for Renderer and Theme */
UI7::IO* io = nullptr;
/** Reference to the parent container*/
Container* parent = nullptr;
/** Object ID (0 if unused)*/
u32 id = 0;
/** Internal Flags */
u32 pFlags = 0;
/** Is Selected? */
bool pSelected = false;
/** Was Pressed */
bool pPressed = false;
/** Was Pressed Twice */
bool pPressedTwice = false;
/** ClipRect */
fvec4 pClipRect;
/** Clip Rect used */
bool pCLipRectUsed = false;
Li::Font* pFont = nullptr;
};
} // namespace UI7
} // namespace PD
+90
View File
@@ -0,0 +1,90 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
namespace UI7 {
/**
* DragData Object can take a datatype or a list
* and modifys these by moving left or right when dragging
*/
template <typename T>
class PD_API DragData : public Container {
public:
/**
* Constructor
* @param label Label of the Button
* @param data Data reference (Supported types can be seen in dragdata.cpp)
* @param num_elms Number of Array elements (for exaple with use ofvec4)
* @param io IO Reference
* @param min minimum number using Minimum limit
* @param max Maximum number set by max limit by default
* @param step To set the modifier for drag movement
* @param precision for float and double to set precision
*/
DragData(const std::string& label, T* data, size_t num_elms, UI7::IO& io,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), T step = 1,
int precision = 1) {
// PD::Assert(data != nullptr, "Input Data Address is null!");
this->label = label;
this->data = data;
this->elm_count = num_elms;
this->min = min;
this->max = max;
this->step = step;
this->precision = precision;
this->tdim = io.Font->GetTextBounds(label.c_str(), io.FontScale);
}
~DragData() = default;
/**
* Override for the Input Handler
* @note This function is usally called by Menu::Update
*/
void HandleInput() override;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/** Function to Update Size if framepadding changes */
void Update() override;
private:
fvec2 tdim; ///< Text size
std::string label; ///< Label of the Button
T* data;
size_t elm_count = 0;
T min;
T max;
T step;
int precision = 1;
};
} // namespace UI7
} // namespace PD
+88
View File
@@ -0,0 +1,88 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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 <functional>
#include <pd/ui7/container/container.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
namespace UI7 {
/**
* Button Object
* @note Button Press is delayed by 1 frame
* (but the visual reaction is done in the same frame)
* This only means that InPressed is responding the info in
* the next frame
*/
class PD_API DynObj : public Container {
public:
DynObj() {}
/**
* Button Object constructor
* @param label Label of the Button
* @param pos Base Position
* @param lr Reference to the Renderer
*/
DynObj(std::function<void(UI7::IO*, Li::Drawlist*, Container*)> RenderFunc) {
pRenFun = RenderFunc;
}
~DynObj() = default;
void AddInputHandler(std::function<void(UI7::IO*, Container*)> inp) {
pInp = inp;
}
/** Return true if butten is pressed*/
bool IsPressed() { return pressed; }
/**
* Override for the Input Handler
* @note This function is usally called by Menu::Update
*/
void HandleInput() override;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/** Function to Update Size if framepadding changes */
void Update() override;
void Reset() override {
Container::Reset();
color = UI7Color_Button;
pressed = false;
pRenFun = nullptr;
pInp = nullptr;
}
private:
UI7Color color = UI7Color_Button; ///< current button color
bool pressed = false; ///< ispressed value
std::function<void(UI7::IO*, Li::Drawlist*, Container*)> pRenFun;
std::function<void(UI7::IO*, Container*)> pInp;
};
} // namespace UI7
} // namespace PD
+74
View File
@@ -0,0 +1,74 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
namespace PD {
namespace UI7 {
/**
* Image Object
*/
class PD_API Image : public Container {
public:
Image() {}
/**
* Constructor for the Image Object
* @param img Image Texture Reference
* @param size Custom Size of the Image
*/
Image(Li::Texture img, fvec2 size = 0.f, Li::Rect uv = fvec4(0.f)) {
this->img = img;
if (size == fvec2(0.f)) {
size = img.GetSize();
}
if (uv == Li::Rect(fvec4(0.f))) {
uv = img.GetUV();
}
this->cuv = uv;
this->newsize = size;
SetSize(size);
}
~Image() = default;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
void Reset() override {
Container::Reset();
img = Li::Texture();
newsize = 0.f;
cuv = Li::Rect();
}
private:
Li::Texture img; ///< Texture
fvec2 newsize = 0.f; ///< New Size
Li::Rect cuv; ///< Custom UV
};
} // namespace UI7
} // namespace PD
+71
View File
@@ -0,0 +1,71 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
namespace PD {
namespace UI7 {
/**
* Label [Text] Object
*/
class PD_API Label : public Container {
public:
Label() {}
/**
* Constructor for Label Object
* @param label Label [Text] to Draw
* @param lr Renderer Reference
*/
Label(const std::string& label, IO& io) {
this->label = label;
this->tdim = io.Font->GetTextBounds(label.c_str(), io.FontScale);
this->SetSize(tdim);
}
~Label() = default;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/**
* Override Update func to support Text modifications
*/
void Update() override;
void Reset() override {
Container::Reset();
tdim = 0;
color = UI7Color_Text;
label.clear();
}
private:
fvec2 tdim; ///< Text Size
UI7Color color = UI7Color_Text; ///< Color
std::string label; ///< Text to Render
};
} // namespace UI7
} // namespace PD
+89
View File
@@ -0,0 +1,89 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
namespace UI7 {
/**
* Slider Object can take a datatype or a list
* and modifys these by moving left or right when dragging
*/
template <typename T>
class PD_API Slider : public Container {
public:
/**
* Constructor
* @param label Label of the Button
* @param data Data reference (Supported types can be seen in Slider.cpp)
* @param num_elms Number of Array elements (for exaple with use ofvec4)
* @param io IO Reference
* @param min minimum number using Minimum limit
* @param max Maximum number set by max limit by default
* @param step To set the modifier for drag movement
* @param precision for float and double to set precision
*/
Slider(const std::string& label, T* data, UI7::IO& io,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), int precision = 1) {
// PD::Assert(data != nullptr, "Input Data Address is null!");
this->label = label;
this->data = data;
this->min = min;
this->max = max;
this->precision = precision;
this->width = io.CurrentViewPort.pSize.z * 0.3f;
this->tdim = io.Font->GetTextBounds(label.c_str(), io.FontScale);
}
~Slider() = default;
/**
* Override for the Input Handler
* @note This function is usally called by Menu::Update
*/
void HandleInput() override;
/**
* Override for the Rendering Handler
* @note This function is usally called by Menu::Update
* */
void Draw() override;
/** Function to Update Size if framepadding changes */
void Update() override;
private:
fvec2 tdim; ///< Text size
float width; ///< Size
std::string label; ///< Label of the Button
T* data;
T min;
T max;
int precision = 1;
float slw = 0.f; // silider drag width (calculated in update)
float slp = 0.f; // silider drag pos (calculated in update)
};
} // namespace UI7
} // namespace PD
+33
View File
@@ -0,0 +1,33 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/button.hpp>
#include <pd/ui7/container/checkbox.hpp>
#include <pd/ui7/container/coloredit.hpp>
#include <pd/ui7/container/dragdata.hpp>
#include <pd/ui7/container/dynobj.hpp>
#include <pd/ui7/container/image.hpp>
#include <pd/ui7/container/label.hpp>
#include <pd/ui7/container/slider.hpp>
+104
View File
@@ -0,0 +1,104 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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.
*/
/** 32Bit Value to Stpre Menu Flags */
using UI7MenuFlags = unsigned int;
/** 32Bit Value to store Alignment Flags */
using UI7Align = unsigned int;
/** 32Bit Value to store Context (IO) flags */
using UI7IOFlags = unsigned int;
/** 32Bit Value for Layout Flags */
using UI7LayoutFlags = unsigned int;
/** Menu Flags */
enum UI7MenuFlags_ {
UI7MenuFlags_None = 0, ///< No Flags (Default)
UI7MenuFlags_NoTitlebar = 1 << 0, ///< Dont Show Titlebar
UI7MenuFlags_CenterTitle = 1 << 1, ///< Center the Menu Title in Titlebar
UI7MenuFlags_HzScrolling = 1 << 2, ///< Enable Horizontal Scrolling
UI7MenuFlags_VtScrolling = 1 << 3, ///< Enable Vertical Scrolling
UI7MenuFlags_NoBackground = 1 << 4, ///< Dont Render Menu Background
UI7MenuFlags_NoClipRect = 1 << 5, ///< Disable clip render area of the Menu
UI7MenuFlags_NoCollapse = 1 << 6, ///< Disable Menu Collapse
UI7MenuFlags_NoMove = 1 << 7, ///< Disable Menu Movement
UI7MenuFlags_NoResize = 1 << 8, ///< Disable Menu Resize
UI7MenuFlags_NoClose = 1 << 9, ///< Disable Close Button
UI7MenuFlags_NoScrollbar = 1 << 10, ///< Hide the Scrollbar
// POC
UI7MenuFlags_Maximize = 1 << 11, ///< Add a Maximize Button
UI7MenuFlags_Minimize = 1 << 12, ///< Add a Minimize Button
UI7MenuFlags_AlwaysAutoSize = 1 << 13, ///< Always Auto Resize Menu
// Enable Horizontal and Vertical Scrolling
UI7MenuFlags_Scrolling = UI7MenuFlags_HzScrolling | UI7MenuFlags_VtScrolling,
};
/** UI7 Layout Flags */
enum UI7LayoutFlags_ {
UI7LayoutFlags_None = 0, ///< No Flags used
UI7LayoutFlags_UseClipRect = 1 << 0, ///< Enable ClipRect
UI7LayoutFlags_HzScrolling = 1 << 1, ///< Scrolling Horizontal
UI7LayoutFlags_VtScrolling = 1 << 2, ///< Scrolling Vertical
};
/** UI7 Context Flags */
enum UI7IOFlags_ {
UI7IOFlags_None = 0, ///< No Additional Config available
UI7IOFlags_HasTouch = 1 << 0, ///< Enable touch support [future]
UI7IOFlags_HasMouseCursor = 1 << 1, ///< Enable Mouse support [future]
};
/** Probably need to update this */
enum UI7Align_ {
UI7Align_Left = 1 << 0, ///< [Hz Op] Align Left (Default)
UI7Align_Center = 1 << 1, ///< [Hz Op] Align Center
UI7Align_Right = 1 << 2, ///< [Hz Op] Align Right
UI7Align_Top = 1 << 3, ///< [Vt Op] Align Top (Default)
UI7Align_Mid = 1 << 4, ///< [Vt Op] Align Mid
UI7Align_Bottom = 1 << 5, ///< [Vt Op] Align Bottom
// Default Horizontal and Vertical Alignment
UI7Align_Default = UI7Align_Left | UI7Align_Top,
};
/** Special flags for Layout::AddObjectEx */
enum UI7LytAdd_ {
UI7LytAdd_None = 0, ///< Also known as default or ->AddObject
UI7LytAdd_NoCursorUpdate = 1 << 0, ///< Add without cursor alignment
UI7LytAdd_NoScrollHandle = 1 << 1, ///< Skip HandleScrolling
UI7LytAdd_Front = 1 << 2, ///< Add in front of the list
UI7LytAdd_NoGlobalClipping = 1 << 3, ///< Dont use global Layout clip rect
UI7LytAdd_NoClipTitlebar = 1 << 4, ///< Dont clip content behind the titlebar
};
/**
* Todo: Look at this
* Maybe proof of concept ???
* Didnt remember that this exists
*/
enum UI7ContainerFlags_ {
UI7ContainerFlags_None = 0,
UI7ContainerFlags_EnableInternalInput = 1 << 0,
UI7ContainerFlags_Selectable = 1 << 1,
UI7ContainerFlags_OutlineSelected = 1 << 2,
};
+74
View File
@@ -0,0 +1,74 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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 {
namespace UI7 {
/**
* ID Class (Generating an ID by String)
*/
class ID {
public:
/**
* Constructor to Generate ID by input string
* @param text Input String
*/
ID(const std::string& text) {
pID = PD::Strings::FastHash(text);
// pStrName = text;
pName = text;
}
/**
* Constructor used for const char* which is automatically
* used when directly placing a string istead of using ID("")
* @param text Input String
*/
constexpr ID(const char* text) {
pID = PD::FNV1A32(text);
pName = text;
}
/**
* Use an ID as Input
*/
ID(u32 id) { pID = id; }
~ID() = default;
/** Get The ID Initial Name */
// 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 */
constexpr const u32& RawID() const { return pID; }
/** Return the ID when casting to u32 */
constexpr operator u32() const { return pID; }
u32 pID; ///< Hash of the name
std::string pName; ///< Name
// std::string pStrName; ///< Keep this stringview alive
};
} // namespace UI7
} // namespace PD
+138
View File
@@ -0,0 +1,138 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/drivers/drivers.hpp>
#include <pd/lithium/lithium.hpp>
#include <pd/pd_p_api.hpp>
#include <pd/ui7/id.hpp>
namespace PD {
namespace UI7 {
class InputHandler {
public:
InputHandler() {}
~InputHandler() = default;
/**
* Function to Check if current Object is dragged
* or set it dragged
* @param id ID to identify this specific Object
* @param area Area where to start dragging
* @return if inputs to this objects are alowed or not
*/
bool DragObject(const UI7::ID& id, fvec4 area) {
if (CurrentMenu != FocusedMenu) {
return false;
}
if (IsObjectDragged()) {
// Only block if the Dragged Object has a difrent id
if (DraggedObject != id) {
return false;
}
}
// Get a Short define for touch pos
fvec2 p = PD::Hid::MousePos();
// Check if Drag starts in the area position
if ((PD::Hid::IsEvent(PD::Hid::Event::Down, PD::Hid::Gamepad::Touch) ||
PD::Hid::IsEvent(PD::Hid::Event::Down,
PD::Hid::Keyboard::MouseLeft)) &&
Li::Math::InBounds(p, area)) {
// Set ID and iniatial Positions
DraggedObject = id;
DragSourcePos = p;
DragPosition = p;
DragLastPosition = p;
DragDestination = area;
// Reset and Start DragTimer
DragTime.Reset();
DragTime.Rseume();
return false; // To make sure the Object is "Dragged"
} else if ((PD::Hid::IsEvent(PD::Hid::Event::Held,
PD::Hid::Gamepad::Touch) ||
PD::Hid::IsEvent(PD::Hid::Event::Held,
PD::Hid::Keyboard::MouseLeft)) &&
IsObjectDragged()) {
// Update DragLast and DragPoisition
DragLastPosition = DragPosition;
DragPosition = p;
} else if ((PD::Hid::IsEvent(PD::Hid::Event::Up, PD::Hid::Gamepad::Touch) ||
PD::Hid::IsEvent(PD::Hid::Event::Up,
PD::Hid::Keyboard::MouseLeft)) &&
IsObjectDragged()) {
// Released... Everything gets reset
DraggedObject = 0;
DragPosition = 0;
DragSourcePos = 0;
DragLastPosition = 0;
DragDestination = fvec4(0);
// Set Drag released to true (only one frame)
// and Only if still in Box
DragReleased = Li::Math::InBounds(PD::Hid::MousePosLast(), area);
DragReleasedAW = true; // Advanced
u64 d_rel = PD::Os::GetTime();
if (d_rel - DragLastReleased < DoubleClickTime) {
DragDoubleRelease = true;
DragLastReleased = 0; // Set 0 to prevent double exec
} else {
DragLastReleased = d_rel;
}
// Ensure timer is paused
DragTime.Pause();
DragTime.Reset();
// Still return The Object is Dragged to ensure
// the DragReleased var can be used
return true;
}
return IsObjectDragged();
}
void Update() {
DragTime.Update();
DragReleased = false;
DragReleasedAW = false;
DragDoubleRelease = false;
}
u64 DoubleClickTime = 500; // Milliseconds
u32 FocusedMenu = 0;
fvec4 FocusedMenuRect;
u32 CurrentMenu = 0;
u32 DraggedObject = 0;
fvec2 DragSourcePos = 0;
fvec2 DragPosition = 0;
fvec2 DragLastPosition = 0;
/** Fvec4 has an constructor problem currently */
fvec4 DragDestination = fvec4(0);
Timer DragTime;
u64 DragLastReleased = 0;
bool DragReleased = false; ///< Drag Releaded in Box
bool DragReleasedAW = false; ///< Drag Released Anywhere
bool DragDoubleRelease = false; ///< Double Click
/** Check if an object is Dragged already */
bool IsObjectDragged() const { return DraggedObject != 0; }
};
} // namespace UI7
} // namespace PD
+126
View File
@@ -0,0 +1,126 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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 <list>
#include <pd/core/core.hpp>
#include <pd/pd_p_api.hpp>
#include <pd/ui7/input_api.hpp>
#include <pd/ui7/theme.hpp>
#include <pd/ui7/viewport.hpp>
namespace PD {
namespace UI7 {
class Label;
class Image;
class DynObj;
class PD_API IO {
public:
IO();
~IO();
/**
* IO Update Internal Variables
*/
void Update();
/**
* Final Draw List for PD::Li::Gfx::RednerDrawData
*
* Possible thanks to the Drawlist::Merge Feature
*/
Li::Drawlist FDL;
ViewPort CurrentViewPort;
// ivec4 CurrentViewPort = ivec4(0, 0, 0, 0);
std::unordered_map<u32, ViewPort> ViewPorts;
float Framerate = 0.f;
float Delta = 0.f;
u64 LastTime = 0;
TimeStats DeltaStats;
Timer Time;
Li::Font* Font = nullptr;
float FontScale = 0.7f;
UI7::Theme Theme;
fvec2 MenuPadding = 5.f;
fvec2 FramePadding = 5.f;
float ItemRowHeight = 0.f;
float FrameRounding = 0.f;
fvec2 ItemSpace = fvec2(5.f, 2.f);
fvec2 MinSliderDragSize = 10.f; // Min height (Vt) and Min Width (Hz)
bool ShowMenuBorder = true;
bool ShowFrameBorder = false; // not implemented yet
bool WrapLabels = false; // Beta state
float OverScrollMod = 0.15f;
u64 DoubleClickTime = 500; // Milliseconds
std::list<std::pair<UI7::ID, Li::Drawlist*>> DrawlistRegestry;
// Short define for DrawKLstRegestryLast
std::list<std::pair<UI7::ID, Li::Drawlist*>> pDLRL;
Li::Drawlist Back;
Li::Drawlist Front;
u32 NumVertices = 0; ///< Debug Vertices Num
u32 NumIndices = 0; ///< Debug Indices Num
std::vector<u32> MenuOrder;
std::vector<Li::Font*> FontStack;
// Pools
PD::Pool<UI7::Label> LabelPool;
PD::Pool<UI7::Image> ImagePool;
PD::Pool<UI7::DynObj> DynObjPool;
// DrawlistApi
void RegisterDrawlist(const UI7::ID& id, Li::Drawlist* v) {
DrawlistRegestry.push_back(std::make_pair(id, v));
}
void AddViewPort(const ID& id, const ivec4& size) {
if (ViewPorts.count(id.RawID())) {
return;
}
ViewPorts[id.RawID()] = ViewPort(id, size);
}
ViewPort& GetViewPort(const ID& id) {
if (!ViewPorts.count(id.RawID())) {
static ViewPort err;
return err;
}
return ViewPorts[id.RawID()];
}
void PushFont(Li::Font* f) {
FontStack.push_back(Font);
Font = f;
}
void PopFont() {
if (!FontStack.empty()) {
Font = FontStack.back();
FontStack.pop_back();
}
}
UI7::InputHandler InputHandler;
};
} // namespace UI7
} // namespace PD
+211
View File
@@ -0,0 +1,211 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/pd_p_api.hpp>
#include <pd/ui7/container/container.hpp>
#include <pd/ui7/container/dragdata.hpp>
#include <pd/ui7/container/slider.hpp>
#include <pd/ui7/flags.hpp>
#include <pd/ui7/input_api.hpp>
#include <pd/ui7/theme.hpp>
namespace PD {
namespace UI7 {
class Context;
class PD_API Layout {
public:
Layout(const ID& id, IO& io) : ID(id), IO(io) {
DrawList.SetFont(IO.Font);
DrawList.SetFontscale(io.FontScale);
Scrolling[0] = false;
Scrolling[1] = false;
CursorInit();
Pos = fvec2(io.CurrentViewPort.pSize.x, io.CurrentViewPort.pSize.y);
Size = 0;
WorkRect = fvec4(IO.MenuPadding, Size - (fvec2(2) * IO.MenuPadding));
}
~Layout();
/** SECTION CONTAINERS */
/**
* Render a Simple Label
* @param label The text to draw
*/
void Label(const std::string& label);
template <typename... Args>
void Label(std::format_string<Args...> s, Args&&... args) {
Label(std::format(s, std::forward<Args>(args)...));
}
/**
* Render a Button
* @param label The buttons text
* @return if the button was pressed
*/
bool Button(const std::string& label);
/**
* Render a Checkbox
* @param label Label of the Checkbox
* @param v A value to update
*/
void Checkbox(const std::string& label, bool& v);
/**
* Render an Image
* @param img Texture reference of the image
* @param size a Custom Size if needed
*/
void Image(Li::Texture img, fvec2 size = 0.f, Li::Rect uv = fvec4(0));
/**
* Render a Drag Object witth any supported type:
* [`int`, `float`, `double`, `u8`, `u16`, `u32`]
* @param label Name of the Drag
* @param data Reference to Data Object (can be multiple as well)
* @param num_elements Defien the number of Elements in the Data addr
* @param precission Difine the Format string len for float/double
*/
template <typename T>
void DragData(const std::string& label, T* data, size_t num_elms = 1,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), T step = 1,
int precision = 1) {
u32 id = Strings::FastHash("drd" + label + std::to_string((uintptr_t)data));
Container* r = FindObject(id);
if (!r) {
r = new UI7::DragData<T>(label, data, num_elms, this->IO, min, max, step,
precision);
r->SetID(id);
}
AddObject(r);
}
template <typename T>
void Slider(const std::string& label, T* data,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), int precision = 1) {
u32 id = Strings::FastHash("drd" + label + std::to_string((uintptr_t)data));
Container* r = FindObject(id);
if (!r) {
r = new UI7::Slider<T>(label, data, this->IO, min, max, precision);
r->SetID(id);
}
AddObject(r);
}
/** SECTION OTHERSTUFF */
const std::string GetName() const { return ID.GetName(); }
const UI7::ID& GetID() const { return this->ID; }
const fvec2& GetPosition() const { return Pos; }
void SetPosition(const fvec2& v) { Pos = v; }
const fvec2& GetSize() const { return Size; }
void SetSize(const fvec2& v) { Size = v; }
Li::Drawlist& GetDrawList() { return DrawList; }
void CursorInit();
void SameLine();
void CursorMove(const fvec2& size);
void PushFont(Li::Font* f) { IO.PushFont(f); }
void PopFont() { IO.PopFont(); }
bool ObjectWorkPos(fvec2& movpos);
/**
* Extended Object Add Func to Add Object in Front or disable
* Position by cursor as well as cursor update...
* Should only be used in special cases as the
* AddObject function is faster
* Using Flags for its features cause dont want to have too much args
*/
void AddObjectEx(Container* obj, u32 Flags);
/**
* Fast Function to Add Object in Layout SPace like
* button Label images etc
*/
void AddObject(Container* obj);
Container* FindObject(u32 id);
void ClearIDObjects() { IDObjects.clear(); }
fvec2 AlignPosition(fvec2 pos, fvec2 size, fvec4 area, UI7Align alignment);
/** Get the Alignment for Current State */
UI7Align GetAlignment() {
/// if temp alignment is used then return it and
/// reset tmpalign
if (TempAlign) {
auto t = TempAlign;
TempAlign = 0;
return t;
}
return Alignment;
}
void SetAlign(UI7Align a) { Alignment = a; }
void NextAlign(UI7Align a) { TempAlign = a; }
void HandleScrolling();
void Update();
fvec2 DbgScrollOffset() { return ScrollOffset; }
private:
friend class Menu;
friend class PD::UI7::Context;
friend class ReMenu;
// Base Components
UI7::ID ID;
UI7::IO& IO;
Li::Drawlist DrawList;
UI7LayoutFlags Flags;
// Positioning
fvec2 Pos;
fvec2 Size;
UI7Align Alignment = UI7Align_Default;
UI7Align TempAlign;
// Cursor
fvec2 Cursor;
fvec2 InitialCursorOffset;
fvec2 BackupCursor;
fvec2 SamelineCursor;
fvec2 BeforeSameLine;
fvec2 LastObjSize;
fvec2 MaxPosition;
fvec4 WorkRect;
// Scrolling (Only theoretical)
// Rendering must be done by the Objective that uses the Lyt
fvec2 ScrollOffset;
fvec2 ScrollStart;
bool Scrolling[2];
// Objects
std::list<Container*> Objects;
std::vector<Container*> IDObjects;
};
} // namespace UI7
} // namespace PD
+146
View File
@@ -0,0 +1,146 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/pd_p_api.hpp>
#include <pd/ui7/containers.hpp>
#include <pd/ui7/io.hpp>
#include <pd/ui7/layout.hpp>
#include "pd/ui7/container/dragdata.hpp"
namespace PD {
namespace UI7 {
class PD_API Menu {
public:
Menu(const UI7::ID& id, UI7::IO& pIO);
~Menu() {}
/**
* Render a Simple Label
* @param label The text to draw
*/
void Label(const std::string& label);
template <typename... Args>
void Label(std::format_string<Args...> s, Args&&... args) {
Label(std::format(s, std::forward<Args>(args)...));
}
/**
* Render a Button
* @param label The buttons text
* @return if the button was pressed
*/
bool Button(const std::string& label);
/**
* Render a Checkbox
* @param label Label of the Checkbox
* @param v A value to update
*/
void Checkbox(const std::string& label, bool& v);
/**
* Render an Image
* @param img Texture reference of the image
* @param size a Custom Size if needed
*/
void Image(Li::Texture img, fvec2 size = 0.f, Li::Rect uv = fvec4(0));
/**
* Render a Drag Object witth any supported type:
* [`int`, `float`, `double`, `u8`, `u16`, `u32`]
* @param label Name of the Drag
* @param data Reference to Data Object (can be multiple as well)
* @param num_elements Defien the number of Elements in the Data addr
* @param precission Difine the Format string len for float/double
*/
template <typename T>
void DragData(const std::string& label, T* data, size_t num_elms = 1,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), T step = 1,
int precision = 1) {
u32 id = Strings::FastHash("drd" + label + std::to_string((uintptr_t)data));
Container* r = pLayout.FindObject(id);
if (!r) {
r = new UI7::DragData<T>(label, data, num_elms, pIO, min, max, step,
precision);
// Isnt This exactly the same line???
// r = UI7::DragData<T>::New(label, data, num_elms, pIO, min, max, step,
// precision);
r->SetID(id);
}
pLayout.AddObject(r);
}
template <typename T>
void Slider(const std::string& label, T* data,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max(), int precision = 1) {
u32 id = Strings::FastHash("drd" + label + std::to_string((uintptr_t)data));
Container* r = pLayout.FindObject(id);
if (!r) {
r = new UI7::Slider<T>(label, data, pIO, min, max, precision);
r->SetID(id);
}
pLayout.AddObject(r);
}
void ColorEdit(const std::string& label, u32& clr);
void SameLine() { pLayout.SameLine(); }
void Separator();
void SeparatorText(const std::string& label);
bool BeginTreeNode(const ID& id);
void EndTreeNode();
void HandleFocus();
void HandleTitlebarActions();
void DrawBaseLayout();
void AddObject(PD::UI7::Container* obj) { pLayout.AddObject(obj); }
void AddObjectEx(PD::UI7::Container* obj, PD::u32 flags) {
pLayout.AddObjectEx(obj, flags);
}
Container* FindObject(u32 id) { return pLayout.FindObject(id); }
void PushFont(Li::Font* f) { pIO.PushFont(f); }
void PopFont() { pIO.PopFont(); }
void Update();
void SetSize(PD::fvec2 size) { pLayout.SetSize(size); }
void SetPosition(PD::fvec2 pos) { pLayout.SetPosition(pos); }
const PD::fvec2& GetSize() const { return pLayout.GetSize(); }
const PD::fvec2& GetPosition() const { return pLayout.GetPosition(); }
/** Data Section */
UI7MenuFlags Flags = 0;
Layout pLayout;
IO& pIO;
ID pID;
bool* pIsShown = nullptr;
bool pIsOpen = true;
std::unordered_map<u32, bool> pTreeNodes;
fvec2 TempScrollXY;
float TitleBarHeight = 0.f;
};
} // namespace UI7
} // namespace PD
+159
View File
@@ -0,0 +1,159 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/pd_p_api.hpp>
/**
* Using this to support 32bit color values as well as
* values from UI7Color_
*/
using UI7Color = PD::u32;
/** Theme Color */
enum UI7Color_ {
UI7Color_Background, ///< UI7 Menu Background
UI7Color_Border, ///< Menu/Frame Border Color
UI7Color_Button, ///< UI7 Button Idle Color
UI7Color_ButtonDead, ///< UI7 Disabled Button Color
UI7Color_ButtonActive, ///< UI7 Pressed Button Color
UI7Color_ButtonHovered, ///< UI7 Hovered Button Color
UI7Color_Text, ///< UI7 Text Color
UI7Color_TextDead, ///< UI7 Dead Text Color
UI7Color_Header, ///< UI7 Menu Header Color
UI7Color_HeaderDead, ///< Inactive Header
UI7Color_Selector, ///< UI7 Selector Color
UI7Color_Checkmark, ///< UI7 Checkmark Color
UI7Color_FrameBackground, ///< UI7 Frame Background
UI7Color_FrameBackgroundHovered, ///< UI7 Hovered Frame Background
UI7Color_Progressbar, ///< UI7 Progressbar Background
UI7Color_ListEven, ///< UI7 List (Even Entry) Background Color
UI7Color_ListOdd, ///< UI7 List (Odd Entry) Background Color
};
namespace PD {
namespace UI7 {
class PD_API Theme {
public:
/**
* Default Constructor Setting up the Default theme
* @note if using Shared Reference you probably need to do
* Theme::Default(*theme.get());
*/
Theme() { Default(*this); }
~Theme() {}
/**
* Simple static Loader for the Default Theme
* @param theme Theme Reference
*/
static void Default(Theme& theme);
/**
* White Mode Theme
* @param Theme theme reference
*/
static void Flashbang(Theme& theme);
/** Revert the last Color Change */
Theme& Pop() {
pTheme[pChanges[pChanges.size() - 1].first] =
pChanges[pChanges.size() - 1].second;
pChanges.pop_back();
return *this;
}
/**
* Revert the last color Change done for a specific color
* @param c Color to revert change from
*/
Theme& Pop(UI7Color c) {
for (size_t i = pChanges.size() - 1; i > 0; i--) {
if (pChanges[i].first == c) {
pTheme[c] = pChanges[i].second;
pChanges.erase(pChanges.begin() + i);
break;
}
}
return *this;
}
/**
* Change a Color
* @param tc Color Identifier
* @param color Color to change to
*/
Theme& Change(UI7Color tc, u32 color) {
if (pTheme.find(tc) == pTheme.end()) {
return *this;
}
pChanges.push_back(std::make_pair(tc, pTheme[tc]));
pTheme[tc] = color;
return *this;
}
/**
* Get the Color of a Color ReferenceID
* @param c ReferenceID
*/
u32 Get(UI7Color c) const {
auto e = pTheme.find(c);
if (e == pTheme.end()) {
return 0x00000000;
}
return e->second;
}
/**
* [UNSAFE] to use
* Get the Color Ref of a Color ReferenceID
* @param c ReferenceID
*/
u32& GetRef(UI7Color c) {
auto e = pTheme.find(c);
if (e == pTheme.end()) {
static u32 noclr = 0x00000000;
return noclr;
}
return e->second;
}
/**
* Operator wrapper for get
* @param c Color ReferenceID
*/
u32 operator[](UI7Color c) const { return Get(c); }
/**
* Change but just sets [can implement completly new ids]
* @param tc Color ID (Can be self creeated ones as well)
* @param clr Color it should be set to
*/
void Set(UI7Color tc, u32 clr) { pTheme[tc] = clr; }
std::unordered_map<u32, u32> pTheme; ///< Theme Data
std::vector<std::pair<UI7Color, u32>> pChanges; ///< List of Changes
};
} // namespace UI7
} // namespace PD
+85
View File
@@ -0,0 +1,85 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/pd_p_api.hpp>
#include <pd/ui7/io.hpp>
#include <pd/ui7/menu.hpp>
#include "pd/ui7/flags.hpp"
/**
* Declare UI7 Version
* Format: 00 00 00 00
* Major Minor Patch Build
* 0x01010000 -> 1.1.0-0
*/
#define UI7_VERSION 0x00070000
namespace PD {
namespace UI7 {
/**
* Get UI7 Version String
* @param show_build Show build num (mostly unused)
* @return Version String (1.0.0-1 for example)
*/
PD_API std::string GetVersion(bool show_build = false);
/** Base Context for UI7 */
class PD_API Context {
public:
Context() {}
~Context() = default;
IO& GetIO() { return pIO; }
void AddViewPort(const ID& id, const ivec4& vp);
void UseViewPort(const ID& id);
void Update();
Menu* BeginMenu(const ID& id, UI7MenuFlags flags = 0, bool* pShow = nullptr);
Menu* CurrentMenu() { return pCurrent; }
void EndMenu();
void AboutMenu(bool* show = nullptr);
void MetricsMenu(bool* show = nullptr);
void StyleEditor(bool* show = nullptr);
Li::Drawlist& GetDrawData() { return pIO.FDL; }
Menu* pGetOrCreateMenu(const ID& id) {
auto menu = pMenus.find(id);
if (menu == pMenus.end()) {
pMenus[id] = new Menu(id, pIO);
menu = pMenus.find(id);
}
return menu->second;
}
IO pIO;
/** Current Menu */
Menu* pCurrent = nullptr;
std::vector<u32> pCurrentMenus;
std::vector<u32> pDFO; /** Debug Final Order */
std::unordered_map<u32, Menu*> pMenus;
};
} // namespace UI7
} // namespace PD
+44
View File
@@ -0,0 +1,44 @@
#pragma once
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/ui7/id.hpp>
namespace PD {
namespace UI7 {
class ViewPort {
public:
ViewPort() : pID(""), pSize(0) {}
ViewPort(const ID& id, const ivec4& size) : pID(id), pSize(size) {}
~ViewPort() {}
ID GetID() const { return pID; }
ivec4& GetSize() { return pSize; }
ID pID;
ivec4 pSize;
};
} // namespace UI7
} // namespace PD
+1
View File
@@ -14,6 +14,7 @@ PD_API void Log(const std::string& txt, LogLevel lvl) {
const char* clr = pColorNo; const char* clr = pColorNo;
const char* plvl = "INFO"; const char* plvl = "INFO";
switch (lvl) { switch (lvl) {
case PD::LogLevel::None:
case PD::LogLevel::Info: case PD::LogLevel::Info:
clr = pColorNo; clr = pColorNo;
plvl = "INFO"; plvl = "INFO";
-5
View File
@@ -85,13 +85,8 @@ PD_API Mat4 Mat4::Perspective(float fov, float aspect, float n, float f) {
Mat4 ret; Mat4 ret;
ret(0, 0) = 1.f / (aspect * _fov); ret(0, 0) = 1.f / (aspect * _fov);
ret(1, 1) = 1.f / _fov; ret(1, 1) = 1.f / _fov;
#ifdef __3DS__
ret(2, 3) = f * n / (n - f);
ret(2, 2) = -(-1.f) * n / (n - f);
#else
ret(2, 2) = -(f + n) / (f - n); ret(2, 2) = -(f + n) / (f - n);
ret(2, 3) = -(2.f * f * n) / (f - n); ret(2, 3) = -(2.f * f * n) / (f - n);
#endif
ret(3, 2) = -1.f; ret(3, 2) = -1.f;
ret(3, 3) = 0.0f; ret(3, 3) = 0.0f;
return ret; return ret;
+19 -4
View File
@@ -22,15 +22,30 @@ SOFTWARE.
*/ */
#include <pd/core/timetrace.hpp> #include <pd/core/timetrace.hpp>
#include <pd/drivers/os.hpp>
namespace PD::TT { namespace PD::TT {
static TraceMap pTraces;
PD_API TraceMap& GetTraceMap() { return pTraces; }
PD_API TT::Res& GetTraceRef(const std::string& id) {
if (!pTraces.count(id)) {
pTraces[id] = TT::Res();
pTraces[id].SetID(id);
}
return pTraces[id];
}
PD_API bool TraceExist(const std::string& id) { return pTraces.count(id); }
PD_API void Beg(const std::string& id) { PD_API void Beg(const std::string& id) {
/*auto trace = os.GetTraceRef(id); auto& trace = GetTraceRef(id);
trace->SetStart(os.GetNanoTime());*/ trace.SetStart(PD::Os::GetTimeNano());
} }
PD_API void End(const std::string& id) { PD_API void End(const std::string& id) {
/*auto trace = os.GetTraceRef(id); auto& trace = GetTraceRef(id);
trace->SetEnd(os.GetNanoTime());*/ trace.SetEnd(PD::Os::GetTimeNano());
} }
} // namespace PD::TT } // namespace PD::TT
-1
View File
@@ -33,7 +33,6 @@ PD_API void GfxDriver::Reset() {
CountDrawcalls = pCountDrawcalls; CountDrawcalls = pCountDrawcalls;
pCountCommands = 0; pCountCommands = 0;
pCountDrawcalls = 0; pCountDrawcalls = 0;
ResetPools();
SysReset(); SysReset();
} }
+2 -2
View File
@@ -1,7 +1,7 @@
#include <pd/drivers/os.hpp> #include <pd/drivers/os.hpp>
namespace PD { namespace PD {
PD_API std::unique_ptr<OsDriver> Os::driver; PD_API std::unique_ptr<OsDriver> Os::driver = std::make_unique<OsDriver>();
PD_API u64 OsDriver::GetTime() const { PD_API u64 OsDriver::GetTime() const {
return std::chrono::duration_cast<std::chrono::milliseconds>( return std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -10,7 +10,7 @@ PD_API u64 OsDriver::GetTime() const {
} }
PD_API u64 OsDriver::GetTimeNano() const { PD_API u64 OsDriver::GetTimeNano() const {
return std::chrono::duration_cast<std::chrono::milliseconds>( return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch()) std::chrono::steady_clock::now().time_since_epoch())
.count(); .count();
} }
+82
View File
@@ -0,0 +1,82 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/image/convert.hpp>
namespace PD::ImgConvert {
PD_API void RGB24toRGBA32(std::vector<u8>& out, const std::vector<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_API void RGB32toRGBA24(std::vector<u8>& out, const std::vector<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_API void Reverse32(std::vector<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_API void ReverseBuf(std::vector<u8>& buf, size_t bpp, int w, int h) {
std::vector<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
+75 -1
View File
@@ -1,3 +1,4 @@
#include <pd/image/convert.hpp>
#include <pd/image/image.hpp> #include <pd/image/image.hpp>
#if defined(PD_INCLUDE_STB_IMAGE) #if defined(PD_INCLUDE_STB_IMAGE)
@@ -54,6 +55,53 @@ PD_API void Image::Copy(const std::vector<u8>& pixels, int w, int h, int bpp) {
pFormat = GuessFmtFromBpp(bpp); pFormat = GuessFmtFromBpp(bpp);
} }
PD_API void Image::Convert(Format dst) {
if (pFormat == dst) {
return;
} else if (pFormat == Format::RGB && dst == Format::BGR) {
ImgConvert::ReverseBuf(pData, 3, pSize.x, pSize.y);
pFormat = Format::BGR;
} else if (pFormat == Format::RGB && dst == Format::RGBA) {
std::vector<PD::u8> cpy = pData;
pData.resize(pSize.x * pSize.y * 4);
ImgConvert::RGB24toRGBA32(pData, cpy, pSize.x, pSize.y);
pFormat = Format::RGBA;
} else if (pFormat == Format::RGBA && dst == Format::RGB) {
std::vector<PD::u8> cpy = pData;
pData.resize(pSize.x * pSize.y * 3);
ImgConvert::RGB32toRGBA24(pData, cpy, pSize.x, pSize.y);
pFormat = Format::RGB;
} else if (pFormat == Format::RGBA && dst == Format::BGRA) {
for (int i = 0; i < (pSize.x * pSize.y * 4); i += 4) {
u8 _tmp = pData[i + 0];
pData[i + 0] = pData[i + 2];
pData[i + 2] = _tmp;
}
} else if (pFormat == Format::RGBA && dst == Format::RGB565) {
Convert(Format::RGB);
Convert(Format::RGB565);
} else if (pFormat == Format::RGB && dst == Format::RGB565) {
auto f = [](u8 r, u8 g, u8 b) -> u16 {
u16 _r = (r >> 3);
u16 _g = (g >> 2);
u16 _b = (b >> 3);
return (_r << 11) | (_g << 5) | _b;
};
std::vector<PD::u8> cpy = pData;
pData.resize(pSize.x * pSize.y * 2);
for (int y = 0; y < pSize.x; y++) {
for (int x = 0; x < pSize.y; x++) {
int src = (y * pSize.x + x) * 3;
int dst = (y * pSize.x + x) * 2;
u16 new_px = f(cpy[src + 0], cpy[src + 1], cpy[src + 2]);
pData[dst + 0] = new_px >> 8;
pData[dst + 1] = new_px & 0xff;
}
}
pFormat = Format::RGB565;
}
}
PD_API int Image::Format2Bpp(Format fmt) { PD_API int Image::Format2Bpp(Format fmt) {
switch (fmt) { switch (fmt) {
case Format::RGBA: case Format::RGBA:
@@ -84,7 +132,33 @@ PD_API Image::Format Image::GuessFmtFromBpp(int bpp) {
} }
PD_API void Image::Flip(bool hz, bool vt) { PD_API void Image::Flip(bool hz, bool vt) {
// TODO auto bpp = Format2Bpp(pFormat);
int rlen = pSize.x * bpp; // calculate as less as possible
if (hz) {
for (int j = 0; j < pSize.y; j++) {
int roff = j * rlen;
for (int i = 0; i < pSize.x / 2; i++) {
int src = roff + (i * bpp);
int dst = roff + (pSize.x - 1 - i) * bpp;
for (int k = 0; k < bpp; k++) {
PD::u8 tmp = pData[dst + k];
pData[dst + k] = pData[src + k];
pData[src + k] = tmp;
}
}
}
}
if (vt) {
for (int j = 0; j < pSize.y / 2; j++) {
int rsrc = j * rlen;
int rdst = (pSize.y - 1 - j) * rlen;
for (int i = 0; i < rlen; i++) { // swap the entire row
PD::u8 tmp = pData[rdst + i];
pData[rdst + i] = pData[rsrc + i];
pData[rsrc + i] = tmp;
}
}
}
} }
} // namespace PD } // namespace PD
+89
View File
@@ -0,0 +1,89 @@
#include <pd/drivers/gfx.hpp>
#include <pd/lithium/command.hpp>
#include <pd/lithium/pools.hpp>
namespace PD {
namespace Li {
void Command::Reserve(size_t vtx, size_t idx) {
auto& vpool = GetVertexPool();
auto& ipool = GetIndexPool();
if (VertexCountMax == 0) {
FirstVertex = vpool.size();
vpool.Allocate(vtx);
VertexCountMax = vtx;
} else {
if (vpool.size() == FirstVertex + VertexCountMax) {
vpool.Allocate(vtx);
VertexCountMax += vtx;
} else {
size_t tmp = FirstVertex;
FirstVertex = vpool.size();
vpool.Allocate(VertexCountMax + vtx);
for (size_t i = 0; i < VertexCount; i++) {
vpool[FirstVertex + i] = vpool[tmp + i];
}
VertexCountMax += vtx;
}
}
if (IndexCountMax == 0) {
FirstIndex = ipool.size();
ipool.Allocate(idx);
IndexCountMax = idx;
} else {
if (ipool.size() == FirstIndex + IndexCountMax) {
ipool.Allocate(idx);
IndexCountMax += idx;
} else {
size_t tmp = FirstIndex;
FirstIndex = ipool.size();
ipool.Allocate(IndexCountMax + idx);
for (size_t i = 0; i < IndexCount; i++) {
ipool[FirstIndex + i] = ipool[tmp + i];
}
IndexCountMax += idx;
}
}
}
void Command::Reset() {
Layer = 0;
Tex = 0;
SDF = false;
FirstIndex = 0;
FirstVertex = 0;
IndexCount = 0;
VertexCount = 0;
VertexCountMax = 0;
IndexCountMax = 0;
ClipRect = 0.f;
ClipRectUsed = false;
}
Command& Command::Add(const Vertex& vtx) {
if (VertexCount < VertexCountMax) {
GetVertexPool()[FirstVertex + VertexCount++] = vtx;
}
return *this;
}
Command& Command::Add(u16 idx) {
if (IndexCount < IndexCountMax) {
GetIndexPool()[FirstIndex + IndexCount++] =
static_cast<u16>(VertexCount + idx);
}
return *this;
}
Command& Command::Add(u16 a, u16 b, u16 c) {
if (IndexCount + 3 <= IndexCountMax) {
auto& ip = GetIndexPool();
size_t idx = FirstIndex + IndexCount;
ip[idx + 0] = static_cast<u16>(VertexCount + a);
ip[idx + 1] = static_cast<u16>(VertexCount + b);
ip[idx + 2] = static_cast<u16>(VertexCount + c);
IndexCount += 3;
}
return *this;
}
} // namespace Li
} // namespace PD
+100 -8
View File
@@ -1,3 +1,4 @@
#include <algorithm>
#include <iostream> #include <iostream>
#include <pd/drivers/gfx.hpp> #include <pd/drivers/gfx.hpp>
#include <pd/lithium/drawlist.hpp> #include <pd/lithium/drawlist.hpp>
@@ -10,24 +11,51 @@ PD_API Drawlist::Drawlist() { Clear(); }
PD_API Drawlist::~Drawlist() { Clear(); } PD_API Drawlist::~Drawlist() { Clear(); }
PD_API void Drawlist::Merge(Drawlist& other) {} PD_API void Drawlist::Merge(Drawlist& other) {
size_t start = pCommands.size();
pCommands.AppendMove(other.pCommands);
for (size_t i = start; i < pCommands.size(); i++) {
pCommands[i].Layer += this->pCurrentLayer;
}
other.Clear();
}
PD_API void Drawlist::Copy(Drawlist& other) {} PD_API void Drawlist::Copy(Drawlist& other) {
int start = pCommands.size();
pCommands.AppendCopy(other.pCommands);
for (size_t i = start; i < pCommands.size(); i++) {
pCommands[i].Layer += this->pCurrentLayer;
}
}
PD_API void Drawlist::Optimize() {} PD_API void Drawlist::Optimize() {
if (pCommands.size() <= 1) return;
std::stable_sort(pCommands.begin(), pCommands.end(),
[](const Command& a, const Command& b) {
if (a.Layer != b.Layer) return a.Layer < b.Layer;
if (a.SDF != b.SDF) return a.SDF < b.SDF;
return a.Tex < b.Tex;
});
}
PD_API void Drawlist::Clear() { PD_API void Drawlist::Clear() {
UnbindTexture(); UnbindTexture();
pPath.ResetFast(); pPath.ResetFast();
pVertices.ResetFast(); pCommands.NoReset();
pIndices.ResetFast(); pCurrentLayer = 0;
pCommands.ResetFast(); pClipRects.clear();
} }
/** Command Allocation */ /** Command Allocation */
PD_API Command& Drawlist::NewCommand() { PD_API Command& Drawlist::NewCommand() {
auto cmd = pCommands.Allocate(1); auto cmd = pCommands.Allocate(1);
cmd->Reset();
cmd->Layer = pCurrentLayer;
cmd->Tex = pCurrentTexture.GetID(); cmd->Tex = pCurrentTexture.GetID();
if (HasClipRect()) {
cmd->ClipRectUsed = HasClipRect();
cmd->ClipRect = pClipRects.back();
}
return *cmd; return *cmd;
} }
@@ -45,6 +73,12 @@ PD_API void Drawlist::PathFill(const PD::Color& color) {
PathClear(); PathClear();
} }
PD_API void Drawlist::PathFillGradient(const PD::Color& a, const PD::Color& b,
float rad) {
DrawConvexPolyFilled(pPath, a, b, rad);
PathClear();
}
PD_API void Drawlist::PathArcToN(const fvec2& c, float r, float amin, PD_API void Drawlist::PathArcToN(const fvec2& c, float r, float amin,
float amax, int s) { float amax, int s) {
// Path.push_back(c); // Path.push_back(c);
@@ -221,6 +255,13 @@ PD_API void Drawlist::DrawTextEx(const fvec2& p, const char* text,
pFont->CmdTextEx(*this, p, color, pFontScale, text, flags, box); pFont->CmdTextEx(*this, p, color, pFontScale, text, flags, box);
} }
PD_API void Drawlist::DrawLine(const fvec2& a, const fvec2& b,
const PD::Color& color, int thickness) {
this->PathAdd(a);
this->PathAdd(b);
this->PathStroke(color, thickness);
}
PD_API void Drawlist::DrawPolyLine(const Pool<fvec2>& points, PD_API void Drawlist::DrawPolyLine(const Pool<fvec2>& points,
const PD::Color& color, LiDrawFlags flags, const PD::Color& color, LiDrawFlags flags,
int t) { int t) {
@@ -229,9 +270,9 @@ PD_API void Drawlist::DrawPolyLine(const Pool<fvec2>& points,
} }
UnbindTexture(); UnbindTexture();
auto& cmd = NewCommand(); auto& cmd = NewCommand();
bool close = (flags & (1 << 0)); bool close = (flags & LiDrawFlags_Close);
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)) { if (flags & LiDrawFlags_AA) {
// TODO: Find a way to draw less garbage looking lines // TODO: Find a way to draw less garbage looking lines
} else { } else {
// Non antialiased lines look awful when rendering with thickness != 1 // Non antialiased lines look awful when rendering with thickness != 1
@@ -282,6 +323,57 @@ PD_API void Drawlist::DrawConvexPolyFilled(const Pool<fvec2>& points,
} }
} }
PD_API void Drawlist::DrawConvexPolyFilled(const Pool<fvec2>& points,
const PD::Color& a,
const PD::Color b, float rad) {
if (points.size() < 3) {
return; // Need at least three points
}
fvec2 dir = fvec2(std::cos(rad), std::sin(rad));
// 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 (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)
auto uv_tl = pCurrentTexture.GetUV().TopLeft();
auto uv_tr = pCurrentTexture.GetUV().TopRight();
auto uv_bl = pCurrentTexture.GetUV().BotLeft();
// Gradient
float tmin = std::numeric_limits<float>::max();
float tmax = std::numeric_limits<float>::lowest();
for (const auto& p : points) {
float t = p.x * dir.x + p.y * dir.y;
if (t < tmin) tmin = t;
if (t > tmax) tmax = t;
}
// potential div0
float irange = (tmax != tmin) ? (1.0f / (tmax - tmin)) : 0.0f;
// Command building (oder so)
auto& cmd = NewCommand();
cmd.Reserve(points.size(), (points.size() - 2) * 3);
// Render
for (int i = 2; i < (int)points.size(); i++) {
cmd.Add(0, i, i - 1);
}
// Why was this for loop not used in normal Convex Poly filled???
for (auto& it : points) {
// Calculate U and V coords
float u = uv_tl.x + ((it.x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x);
float v = uv_tl.y + ((it.y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y);
float t = it.x * dir.x + it.y * dir.y;
cmd.Add(Vertex(it, fvec2(u, v), PD::Color(a).Lerp(b, (t - tmin) * irange)));
}
}
PD_API void Drawlist::PrimQuad(Command& cmd, const Rect& quad, const Rect& uv, PD_API void Drawlist::PrimQuad(Command& cmd, const Rect& quad, const Rect& uv,
const PD::Color& color) { const PD::Color& color) {
cmd.Reserve(4, 6); cmd.Reserve(4, 6);
+115 -53
View File
@@ -8,10 +8,12 @@
#include <stb_truetype.h> #include <stb_truetype.h>
#include <map> #include <map>
#include <utility>
namespace PD { namespace PD {
namespace Li { namespace Li {
PD_API void Font::LoadTTF(const std::string& path, int px_height) { PD_API void Font::LoadTTF(const std::string& path, int px_height,
LiFontFlags flags) {
/** /**
* Just use LoadFile2Mem which looks way cleaner * Just use LoadFile2Mem which looks way cleaner
* and helps not having the font loading code twice * and helps not having the font loading code twice
@@ -21,16 +23,18 @@ PD_API void Font::LoadTTF(const std::string& path, int px_height) {
TT::Scope st("LI_LoadTTF_" + path); TT::Scope st("LI_LoadTTF_" + path);
auto font = PD::IO::LoadFile2Mem(path); auto font = PD::IO::LoadFile2Mem(path);
PDLOG("Font Size: {}", PD::Strings::FormatBytes(font.size())); PDLOG("Font Size: {}", PD::Strings::FormatBytes(font.size()));
LoadTTF(font, px_height); LoadTTF(font, px_height, flags);
} }
PD_API void Font::LoadTTF(const std::vector<u8>& data, int px_height) { PD_API void Font::LoadTTF(const std::vector<u8>& data, int px_height,
LiFontFlags flags) {
/** /**
* Some additional Info: * Some additional Info:
* Removed the stbtt get bitmapbox as we dont need to place * Removed the stbtt get bitmapbox as we dont need to place
* the glyps nicely in the tex. next step would be using the free * the glyps nicely in the tex. next step would be using the free
* space on the y axis to get mor glyphs inside * space on the y axis to get mor glyphs inside
*/ */
pFlags = flags;
PixelHeight = px_height; PixelHeight = px_height;
int texszs = PD::Bits::GetPow2(px_height * 16); int texszs = PD::Bits::GetPow2(px_height * 16);
if (texszs > 1024) { if (texszs > 1024) {
@@ -48,28 +52,72 @@ PD_API void Font::LoadTTF(const std::vector<u8>& data, int px_height) {
stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap);
int baseline = static_cast<int>(ascent * scale); int baseline = static_cast<int>(ascent * scale);
float mono_advance = 0.f;
if (IsMonospace()) {
int a, l;
int rgi = stbtt_FindGlyphIndex(&inf, 'W');
if (rgi == 0) rgi = stbtt_FindGlyphIndex(&inf, '0');
if (rgi != 0) {
stbtt_GetGlyphHMetrics(&inf, rgi, &a, &l);
mono_advance = a * scale;
}
}
// Cache to not render same codepoint tex twice // Cache to not render same codepoint tex twice
std::map<u32, int> buf_cache; std::map<u32, int> buf_cache;
std::vector<u8> font_tex(texszs * texszs * 4, 0); std::vector<u8> font_tex(texszs * texszs, 0);
fvec2 off; fvec2 off;
bool empty = true; bool empty = true;
for (u32 ii = 0x0000; ii <= 0xFFFF; ii++) { std::vector<std::pair<u32, u32>> ranges = {
{0x0020, 0x007E}, // ASCII
{0x00A0, 0x00FF}, // LATIN-1
};
for (auto& it : ranges) {
for (u32 ii = it.first; ii <= it.second; ii++) {
int gi = stbtt_FindGlyphIndex(&inf, ii); int gi = stbtt_FindGlyphIndex(&inf, ii);
if (gi == 0) continue; if (gi == 0) continue;
if (stbtt_IsGlyphEmpty(&inf, gi)) continue;
int advance, lsb;
stbtt_GetGlyphHMetrics(&inf, gi, &advance, &lsb);
float sadvance = advance * scale;
float final_advance = sadvance;
float center_offset = 0.f;
if (IsMonospace() && mono_advance > 0.f) {
final_advance = mono_advance;
center_offset = (mono_advance - sadvance) * 0.5f;
}
if (stbtt_IsGlyphEmpty(&inf, gi)) {
Codepoint c;
c.AdvanceX = final_advance;
c.Size = fvec2(0.f);
c.pCodepoint = ii;
c.pInvalid = false;
CodeMap[ii] = c;
continue;
}
int w = 0, h = 0, xo = 0, yo = 0; int w = 0, h = 0, xo = 0, yo = 0;
unsigned char* bitmap = unsigned char* bitmap = nullptr;
if (IsSDF()) {
bitmap = stbtt_GetCodepointSDF(&inf, scale, ii, 5, 128, 255.f / 5.f, &w,
&h, &xo, &yo);
} else {
bitmap =
stbtt_GetCodepointBitmap(&inf, scale, scale, ii, &w, &h, &xo, &yo); stbtt_GetCodepointBitmap(&inf, scale, scale, ii, &w, &h, &xo, &yo);
}
if (!bitmap || w <= 0 || h <= 0) { if (!bitmap || w <= 0 || h <= 0) {
if (bitmap) free(bitmap); if (bitmap) free(bitmap);
continue; continue;
} }
u32 hashed_map = IO::HashMemory(std::vector<u8>(bitmap, bitmap + (w * h))); u32 hashed_map =
IO::HashMemory(std::vector<u8>(bitmap, bitmap + (w * h)));
if (buf_cache.find(hashed_map) != buf_cache.end()) { if (buf_cache.find(hashed_map) != buf_cache.end()) {
Codepoint c = GetCodepoint(buf_cache[hashed_map]); Codepoint c = GetCodepoint(buf_cache[hashed_map]);
c.pCodepoint = ii; c.pCodepoint = ii;
@@ -110,18 +158,15 @@ PD_API void Font::LoadTTF(const std::vector<u8>& data, int px_height) {
c.SimpleUV = uvs; c.SimpleUV = uvs;
c.Tex = pCurrentTex; c.Tex = pCurrentTex;
c.Size = fvec2(w, h); c.Size = fvec2(w, h);
c.Offset = baseline + yo; c.Offset = fvec2(xo + center_offset, baseline + yo);
c.AdvanceX = final_advance;
c.pCodepoint = ii; c.pCodepoint = ii;
for (int y = 0; y < h; ++y) { for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) { for (int x = 0; x < w; ++x) {
int map_pos = ((static_cast<int>(off.y) + y) * texszs + int map_pos = ((static_cast<int>(off.y) + y) * texszs +
(static_cast<int>(off.x) + x)) * (static_cast<int>(off.x) + x));
4; font_tex[map_pos] = bitmap[x + y * w];
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];
} }
} }
@@ -132,15 +177,29 @@ PD_API void Font::LoadTTF(const std::vector<u8>& data, int px_height) {
// offset by 1 (prevents visual glitches i had) // offset by 1 (prevents visual glitches i had)
off.x += w + 1; off.x += w + 1;
} }
}
if (!empty) { if (!empty) {
BakeAndPush(true, font_tex, texszs); BakeAndPush(true, font_tex, texszs);
} }
for (u32 i = 0; i < 128; i++) {
auto r = CodeMap.find(i);
if (r == CodeMap.end()) {
static Codepoint invalid;
invalid.pInvalid = true;
pAsciiCache[i] = invalid;
} else {
pAsciiCache[i] = CodeMap[i];
}
}
} }
PD_API void Font::LoadDefaultFont(int id, int pixel_height) {}
PD_API Font::Codepoint& Font::GetCodepoint(u32 c) { PD_API Font::Codepoint& Font::GetCodepoint(u32 c) {
if (c < 128) {
// Direct Access (~11% improvement)
return pAsciiCache[c];
}
// Check if codepoijt exist or return a static invalid one // Check if codepoijt exist or return a static invalid one
auto res = CodeMap.find(c); auto res = CodeMap.find(c);
if (res == CodeMap.end()) { if (res == CodeMap.end()) {
@@ -162,36 +221,36 @@ PD_API fvec2 Font::GetTextBounds(const char* text, float scale) {
u32 c; u32 c;
while (it.Decode32(c)) { while (it.Decode32(c)) {
auto cp = GetCodepoint(c); auto cp = GetCodepoint(c);
if (cp.pInvalid && c != '\n' && c != '\t' && c != ' ') { if ((cp.pInvalid && c != L'\n' && c != L'\t' && c != L' ') && c != L'\r')
continue; continue;
} if (c == L'\n') {
switch (c) {
case L'\n':
res.y += lh; res.y += lh;
res.x = std::max(res.x, x); res.x = std::max(res.x, x);
x = 0.f; x = 0.f;
break; continue;
case L'\t':
x += 16 * cfs;
break;
case L' ':
x += 4 * cfs;
// Fall trough here to get the same result as in
// TextCommand if/else Section
default:
x += cp.Size.x * cfs;
// Omly passing c cause i know its not used
if (it.PeekNext32(c)) {
x += 2 * cfs;
} }
break; if (c == L'\t') {
x += (cp.AdvanceX > 0 ? cp.AdvanceX : 16.f) * 4.f * cfs;
continue;
} }
x += cp.AdvanceX * cfs;
} }
res.x = std::max(res.x, x); res.x = std::max(res.x, x);
res.y += lh; res.y += lh;
return res; return res;
} }
PD_API void PrimTextQuad(Command& cmd, float x, float y, float w, float h,
const fvec4& uv, const PD::Color& color) {
cmd.Reserve(4, 6);
cmd.Add(2, 1, 0);
cmd.Add(3, 2, 0);
cmd.Add(Vertex(x, y, uv.x, uv.y, color));
cmd.Add(Vertex(x + w, y, uv.z, uv.y, color));
cmd.Add(Vertex(x + w, y + h, uv.z, uv.w, color));
cmd.Add(Vertex(x, y + h, uv.x, uv.w, color));
}
PD_API void Font::CmdTextEx(Drawlist& dl, const fvec2& pos, u32 color, PD_API void Font::CmdTextEx(Drawlist& dl, const fvec2& pos, u32 color,
float scale, const char* text, LiTextFlags flags, float scale, const char* text, LiTextFlags flags,
const fvec2& box) { const fvec2& box) {
@@ -210,7 +269,7 @@ PD_API void Font::CmdTextEx(Drawlist& dl, const fvec2& pos, u32 color,
U8Iterator it(text); U8Iterator it(text);
u32 c; u32 c;
Command* cmd = nullptr; Command* cmd = dl.HasCommands() ? &dl.GetLastCommand() : nullptr;
while (it.Decode32(c)) { while (it.Decode32(c)) {
auto cp = GetCodepoint(c); auto cp = GetCodepoint(c);
if ((cp.pInvalid && c != L'\n' && c != L'\t' && c != L' ') && c != L'\r') if ((cp.pInvalid && c != L'\n' && c != L'\t' && c != L' ') && c != L'\r')
@@ -221,33 +280,36 @@ PD_API void Font::CmdTextEx(Drawlist& dl, const fvec2& pos, u32 color,
off.x = 0.f; off.x = 0.f;
continue; continue;
} }
if (c == L'\t') { if (c == L'\t') {
off.x += 16 * cfs; off.x += (cp.AdvanceX > 0 ? cp.AdvanceX : 16.f) * 4.f * cfs;
continue;
}
if (c == L' ') {
off.x += 4 * cfs;
continue; continue;
} }
if (cmd == nullptr || cmd->Tex != Textures[cp.Tex]) { if (cp.Size.x > 0 && cp.Size.y > 0) {
if (cmd == nullptr || cmd->Tex != Textures[cp.Tex] ||
cmd->Layer != dl.GetLayer()) {
if (cp.Tex >= Textures.size()) continue; if (cp.Tex >= Textures.size()) continue;
cmd = &dl.NewCommand(); cmd = &dl.NewCommand();
cmd->Tex = Textures[cp.Tex]; cmd->Tex = Textures[cp.Tex];
cmd->SDF = IsSDF();
} }
// calculating once and using PrimTextQuad to directly push
// saves ~42% on raw multiline text draw time 6.3 -> 3.7 ms
// and ~25% on the whole frametime 20.3 -> 15.2 ms
// tested with Craftus-Next 0.8.0 commit:
// 33298ccc276bf996d341710e69ecf05f99c57961
float cx = rpos.x + off.x + (cp.Offset.x * cfs);
float cy = rpos.y + off.y + (cp.Offset.y * cfs);
float cw = cp.Size.x * cfs;
float ch = cp.Size.y * cfs;
if (flags & LiTextFlags_Shaddow) { if (flags & LiTextFlags_Shaddow) {
Rect rec = Math::PrimRect(rpos + off + fvec2(1, cp.Offset * cfs + 1), PrimTextQuad(*cmd, cx + 1.f, cy + 1.f, cw, ch, cp.SimpleUV, 0xff111111);
cp.Size * cfs, 0.f);
dl.PrimQuad(*cmd, rec, cp.SimpleUV, 0xff111111);
} }
PrimTextQuad(*cmd, cx, cy, cw, ch, cp.SimpleUV, color);
Rect rec = Math::PrimRect(rpos + off + fvec2(0, cp.Offset * cfs), }
cp.Size * cfs, 0.f); off.x += cp.AdvanceX * cfs;
dl.PrimQuad(*cmd, rec, cp.SimpleUV, color);
off.x += cp.Size.x * cfs + 2 * cfs;
} }
} }
@@ -255,7 +317,7 @@ PD_API void Font::CleanupTMS() {}
PD_API void Font::BakeAndPush(bool final, std::vector<u8>& font_tex, PD_API void Font::BakeAndPush(bool final, std::vector<u8>& font_tex,
int texszs) { int texszs) {
auto t = PD::Gfx::LoadTexture(font_tex, texszs, texszs); auto t = PD::Gfx::LoadTexture(font_tex, texszs, texszs, TextureFormat::A8);
PDLOG("Font: Texture backed as 0x{:X} at {}", t.GetID(), pCurrentTex); PDLOG("Font: Texture backed as 0x{:X} at {}", t.GetID(), pCurrentTex);
Textures.push_back(t.GetID()); Textures.push_back(t.GetID());
pCurrentTex = Textures.size(); pCurrentTex = Textures.size();
+1
View File
@@ -58,6 +58,7 @@ PD_API Rect PrimLine(const fvec2& a, const fvec2& b, int t) {
// Using the vec maths api makes the code as short as it is // Using the vec maths api makes the code as short as it is
vec2 dir = a - b; vec2 dir = a - b;
float len = dir.Len(); float len = dir.Len();
if (len == 0.0f) return Rect();
vec2 unit_dir = dir / len; vec2 unit_dir = dir / len;
vec2 perpendicular(-unit_dir.y, unit_dir.x); vec2 perpendicular(-unit_dir.y, unit_dir.x);
vec2 off = perpendicular * ((float)t * 0.5f); vec2 off = perpendicular * ((float)t * 0.5f);
+6 -54
View File
@@ -1,64 +1,16 @@
#include <pd/core/core.hpp>
#include <pd/lithium/pools.hpp> #include <pd/lithium/pools.hpp>
namespace PD { namespace PD {
namespace Li { namespace Li {
PD::Pool<Vertex> pVtxPool; static PD::Pool<Vertex> gVertexPool;
PD::Pool<u16> pIdxPool; static PD::Pool<u16> gIndexPool;
PD::ptr pVertexAccessor = 0;
PD::ptr pIndexAccessor = 0;
PD_API size_t AllocateVertices(size_t count, PD::ptr accessor) { PD_API PD::Pool<Vertex>& GetVertexPool() { return gVertexPool; }
pVertexAccessor = accessor; PD_API PD::Pool<u16>& GetIndexPool() { return gIndexPool; }
int loc = pVtxPool.size();
pVtxPool.Allocate(count);
return loc;
}
PD_API size_t AllocateIndices(size_t count, PD::ptr accessor) {
pIndexAccessor = accessor;
int loc = pIdxPool.size();
pIdxPool.Allocate(count);
return loc;
}
PD_API bool ExpandVertices(size_t count, PD::ptr accessor) {
if (pVertexAccessor != accessor) return false;
pVtxPool.Allocate(count);
return true;
}
PD_API bool ExpandIndices(size_t count, PD::ptr accessor) {
if (pIndexAccessor != accessor) return false;
pIdxPool.Allocate(count);
return true;
}
PD_API void PutVertex(size_t loc, const Vertex& vtx, PD::ptr accessor) {
if (pVertexAccessor != accessor) return;
pVtxPool.Put(loc, vtx);
}
PD_API void PutIndex(size_t loc, u16 idx, PD::ptr accessor) {
if (pIndexAccessor != accessor) return;
pIdxPool.Put(loc, idx);
}
PD_API const Vertex& GetVertex(size_t loc) {
if (loc < pVtxPool.size()) return pVtxPool[loc];
static Vertex pErrVtx;
return pErrVtx;
}
PD_API const u16& GetIndex(size_t loc) {
if (loc < pIdxPool.size()) return pIdxPool[loc];
static u16 pErrIdx = 0;
return pErrIdx;
}
PD_API void ResetPools() { PD_API void ResetPools() {
pVtxPool.Reset(); gVertexPool.NoReset();
pIdxPool.Reset(); gIndexPool.NoReset();
} }
} // namespace Li } // namespace Li
} // namespace PD } // namespace PD
+66
View File
@@ -0,0 +1,66 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/button.hpp>
namespace PD {
namespace UI7 {
PD_API void Button::HandleInput() {
/// Ensure to only check input once
if (inp_done) {
return;
}
/// Ensure it gets sed to false and stays if not pressed
pressed = false;
color = UI7Color_Button;
// Assert(screen.get(), "Screen is not set up!");
// if (screen->ScreenType() == Screen::Bottom) {
if (io->InputHandler.DragObject(this->GetID(), fvec4(FinalPos(), size))) {
if (io->InputHandler.DragReleased) {
color = UI7Color_ButtonActive;
pressed = true;
} else {
color = UI7Color_ButtonHovered;
}
}
//}
inp_done = true;
}
PD_API void Button::Draw() {
// Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
// io->Ren->OnScreen(screen);
list->SetFont(GetFont());
list->PathRect(FinalPos(), FinalPos() + size, io->FrameRounding);
list->PathFill(io->Theme.Get(color));
list->LayerUp();
list->DrawText(FinalPos() + size * 0.5 - tdim * 0.5, label.c_str(),
io->Theme.Get(UI7Color_Text));
list->LayerDown();
}
PD_API void Button::Update() {
// Assert(io.get(), "Did you run Container::Init correctly?");
this->SetSize(tdim + io->FramePadding);
}
} // namespace UI7
} // namespace PD
+69
View File
@@ -0,0 +1,69 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/checkbox.hpp>
namespace PD {
namespace UI7 {
PD_API void Checkbox::HandleInput() {
/// Ensure to only check input once
if (inp_done) {
return;
}
color = UI7Color_FrameBackground;
/// Ensure it gets sed to false and stays if not pressed
// Assert(screen.get(), "Screen is not set up!");
// if (screen->ScreenType() == Screen::Bottom) {
if (io->InputHandler.DragObject(this->GetID(), fvec4(FinalPos(), size))) {
if (io->InputHandler.DragReleased) {
color = UI7Color_FrameBackgroundHovered;
usr_ref = !usr_ref;
} else {
color = UI7Color_FrameBackgroundHovered;
}
}
//}
inp_done = true;
}
PD_API void Checkbox::Draw() {
// Assert(list.get() && io.get(), "Did you run Container::Init correctly?");
// io->Ren->OnScreen(screen);
list->SetFont(GetFont());
list->PathRect(FinalPos(), FinalPos() + cbs, io->FrameRounding);
list->PathFill(io->Theme.Get(color));
if (usr_ref) {
list->PathRect(FinalPos() + 2, FinalPos() + cbs - 2, io->FrameRounding);
list->PathFill(io->Theme.Get(UI7Color_Checkmark));
}
list->DrawText(
FinalPos() + fvec2(cbs.x + io->ItemSpace.x, cbs.y * 0.5 - tdim.y * 0.5),
label.c_str(), io->Theme.Get(UI7Color_Text));
}
PD_API void Checkbox::Update() {
// Assert(io.get(), "Did you run Container::Init correctly?");
cbs = io->ItemRowHeight;
this->SetSize(cbs + fvec2(tdim.x + io->ItemSpace.x, 0));
}
} // namespace UI7
} // namespace PD
+104
View File
@@ -0,0 +1,104 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/coloredit.hpp>
#include <pd/ui7/containers.hpp>
namespace PD {
namespace UI7 {
PD_API void ColorEdit::HandleInput() {
/// Ensure to only check input once
if (inp_done) {
return;
}
// Assert(screen.get(), "Screen is not set up!");
// if (screen->ScreenType() == Screen::Bottom) {
if (io->InputHandler.DragObject(this->GetID() + 2, fvec4(FinalPos(), size))) {
if (io->InputHandler.DragReleasedAW) {
is_shown = !is_shown;
}
}
//}
inp_done = true;
}
PD_API void ColorEdit::Draw() {
// Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
// io->Ren->OnScreen(screen);
list->SetFont(GetFont());
list->PathRect(FinalPos(), FinalPos() + io->ItemRowHeight, io->FrameRounding);
list->PathFill(*color_ref);
list->DrawText(FinalPos() + fvec2(io->ItemSpace.x + io->ItemRowHeight, 0),
label.c_str(), io->Theme.Get(UI7Color_Text));
if (is_shown) {
if (!layout) {
layout = new UI7::Layout(GetID(), *io);
}
layout->SetPosition(FinalPos());
DynObj* r = io->DynObjPool.Allocate();
*r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l, Container* thiz) {
list->SetFont(thiz->GetFont());
thiz->SetSize(layout->GetSize());
// l->Layer(30);
l->PathRect(thiz->GetPos(), thiz->GetPos() + thiz->GetSize(),
io->FrameRounding);
l->PathFill(io->Theme.Get(UI7Color_FrameBackground));
l->SetLayer(0);
});
layout->AddObjectEx(r, UI7LytAdd_Front | UI7LytAdd_NoCursorUpdate |
UI7LytAdd_NoScrollHandle);
r = io->DynObjPool.Allocate();
*r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l, Container* thiz) {
list->SetFont(thiz->GetFont());
l->PathRect(thiz->FinalPos(), thiz->FinalPos() + io->ItemRowHeight,
io->FrameRounding);
l->PathFill(*color_ref);
l->DrawText(
thiz->FinalPos() + fvec2(io->ItemSpace.x + io->ItemRowHeight, 0),
label.c_str(), io->Theme.Get(UI7Color_Text));
});
r->SetSize(PD::fvec2(200, io->ItemRowHeight));
layout->AddObject(r);
layout->Label("RGBA: ({}, {}, {}, {})", *((u8*)color_ref),
*(((u8*)color_ref) + 1), *(((u8*)color_ref) + 2),
*(((u8*)color_ref) + 3));
layout->Label("Hex: {}", PD::Color(*color_ref).Hex(true));
layout->Slider<u8>("R", ((u8*)color_ref));
layout->Slider<u8>("G", ((u8*)color_ref) + 1);
layout->Slider<u8>("B", ((u8*)color_ref) + 2);
layout->Slider<u8>("A", ((u8*)color_ref) + 3);
layout->Update();
list->SetLayer(50);
list->Merge(layout->GetDrawList());
list->SetLayer(0);
// io->RegisterDrawList(GetID(), layout->GetDrawList());
}
}
PD_API void ColorEdit::Update() {
// Assert(io.get(), "Did you run Container::Init correctly?");
this->SetSize(
fvec2(tdim.x + io->ItemSpace.x + io->ItemRowHeight, io->ItemRowHeight));
}
} // namespace UI7
} // namespace PD
+57
View File
@@ -0,0 +1,57 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/container.hpp>
namespace PD {
namespace UI7 {
PD_API void Container::HandleScrolling(fvec2 scrolling, fvec4 viewport) {
if (last_use != 0 && PD::Os::GetTime() - last_use > 5000) {
rem = true;
}
last_use = PD::Os::GetTime();
pos -= fvec2(0, scrolling.y);
skippable =
!Li::Math::InBounds(pos, size,
fvec4(viewport.x, viewport.y, viewport.x + viewport.z,
viewport.y + viewport.w));
}
PD_API void Container::HandleInternalInput() {
/** Requires Handle Scrolling First */
}
/** Internal function */
PD_API void Container::PreDraw() {
if (pCLipRectUsed) {
list->PushClipRect(pClipRect);
}
}
/** Internal function */
PD_API void Container::PostDraw() {
if (pCLipRectUsed) {
list->PopClipRect();
}
}
} // namespace UI7
} // namespace PD
+119
View File
@@ -0,0 +1,119 @@
/*
MIT License
Copyright (c) 2024 - 2026 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 <algorithm>
#include <pd/ui7/container/dragdata.hpp>
#include <pd/ui7/container/label.hpp>
#include <type_traits>
namespace PD {
namespace UI7 {
// Setup Supported Datatypes (Probably making this Object
// header only to not care about datatype support)
template class PD_API DragData<float>;
template class PD_API DragData<int>;
template class PD_API DragData<double>;
template class PD_API DragData<u8>;
template class PD_API DragData<u16>;
template class PD_API DragData<u32>;
template class PD_API DragData<u64>;
template <typename T>
PD_API void DragData<T>::HandleInput() {
/// Ensure to only check input once
if (inp_done) {
return;
}
// Assert(screen.get(), "Screen is not set up!");
// if (screen->ScreenType() == Screen::Bottom) {
float off_x = 0;
for (size_t i = 0; i < elm_count; i++) {
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", data[i], precision);
} else {
p = std::format("{}", data[i]);
}
vec2 tdim = io->Font->GetTextBounds(p.c_str(), io->FontScale);
// Unsafe but is the fastest solution
if (io->InputHandler.DragObject(
this->GetID() + i + 1,
fvec4(FinalPos() + fvec2(off_x, 0), tdim + io->FramePadding))) {
data[i] = std::clamp(
T(data[i] + (step * (io->InputHandler.DragPosition.x -
io->InputHandler.DragLastPosition.x))),
this->min, this->max);
}
off_x += tdim.x + io->ItemSpace.x + io->FramePadding.x;
}
//}
inp_done = true;
}
template <typename T>
PD_API void DragData<T>::Draw() {
// Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
// io->Ren->OnScreen(screen);
float off_x = 0.f;
for (size_t i = 0; i < elm_count; i++) {
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", data[i], precision);
} else {
p = std::format("{}", data[i]);
}
vec2 td = io->Font->GetTextBounds(p.c_str(), io->FontScale);
list->PathRect(FinalPos() + fvec2(off_x, 0),
FinalPos() + fvec2(off_x, 0) + td + io->FramePadding,
io->FrameRounding);
list->PathFill(io->Theme.Get(UI7Color_Button));
list->LayerUp();
list->DrawTextEx(FinalPos() + fvec2(off_x, 0), p.c_str(),
io->Theme.Get(UI7Color_Text), LiTextFlags_AlignMid,
td + io->FramePadding);
list->LayerDown();
off_x += td.x + io->ItemSpace.x + io->FramePadding.x;
}
list->DrawText(FinalPos() + fvec2(off_x, io->FramePadding.y * 0.5),
label.c_str(), io->Theme.Get(UI7Color_Text));
}
template <typename T>
PD_API void DragData<T>::Update() {
// Assert(io.get(), "Did you run Container::Init correctly?");
// Probably need to find a faster solution (caching sizes calculated here)
list->SetFont(GetFont());
float off_x = 0;
for (size_t i = 0; i < elm_count; i++) {
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", data[i], precision);
} else {
p = std::format("{}", data[i]);
}
vec2 tdim = io->Font->GetTextBounds(p.c_str(), io->FontScale);
off_x += tdim.x + io->ItemSpace.x + io->FramePadding.x;
}
this->SetSize(vec2(tdim.x + off_x, tdim.y + io->FramePadding.y));
}
} // namespace UI7
} // namespace PD
+38
View File
@@ -0,0 +1,38 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/dynobj.hpp>
namespace PD {
namespace UI7 {
PD_API void DynObj::Draw() { pRenFun(io, list, this); }
PD_API void DynObj::HandleInput() {
if (pInp) {
pInp(io, this);
}
}
PD_API void DynObj::Update() {}
} // namespace UI7
} // namespace PD
+39
View File
@@ -0,0 +1,39 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/image.hpp>
namespace PD {
namespace UI7 {
PD_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->LayerUp();
list->BindTexture(img);
list->DrawRectFilled(FinalPos(), newsize, 0xffffffff);
list->UnbindTexture();
list->LayerDown();
}
} // namespace UI7
} // namespace PD
+53
View File
@@ -0,0 +1,53 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/container/label.hpp>
namespace PD {
namespace UI7 {
PD_API void Label::Draw() {
// Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
// io->Ren->OnScreen(screen);
list->SetFont(GetFont());
list->DrawTextEx(FinalPos(), label.c_str(), io->Theme.Get(UI7Color_Text),
LiTextFlags_NoOOS,
PD::fvec2(0, io->CurrentViewPort.pSize.w));
}
PD_API void Label::Update() {
/**
* Todo: This is a hacky workaround
* Needs proper optimisation
* Needs a max size (to support sligning dynaically by the window size)
*/
if (io->WrapLabels) {
this->label = io->Font->pWrapText(
this->label, io->FontScale,
PD::fvec2(io->CurrentViewPort.pSize.z - FinalPos().x * 4,
io->CurrentViewPort.pSize.w),
this->tdim);
SetSize(tdim);
}
}
} // namespace UI7
} // namespace PD
+109
View File
@@ -0,0 +1,109 @@
/*
MIT License
Copyright (c) 2024 - 2026 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 <algorithm>
#include <pd/ui7/container/label.hpp>
#include <pd/ui7/container/slider.hpp>
#include <type_traits>
namespace PD {
namespace UI7 {
// Setup Supported Datatypes (Probably making this Object
// header only to not care about datatype support)
template class PD_API Slider<float>;
template class PD_API Slider<int>;
template class PD_API Slider<double>;
template class PD_API Slider<u8>;
template class PD_API Slider<u16>;
template class PD_API Slider<u32>;
template class PD_API Slider<u64>;
template <typename T>
PD_API void Slider<T>::HandleInput() {
/// Ensure to only check input once
if (inp_done) {
return;
}
// Assert(screen.get(), "Screen is not set up!");
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", *data, precision);
} else {
p = std::format("{}", *data);
}
// Unsafe but is the fastest solution
float xps = FinalPos().x;
if (io->InputHandler.DragObject(
this->GetID(),
fvec4(FinalPos() + fvec2(2, 0), fvec2(width, GetSize().y)))) {
if (!io->InputHandler.DragReleasedAW) {
*data = std::clamp(
T(max *
(std::clamp(io->InputHandler.DragLastPosition.x - xps, 0.f, width) /
width)),
this->min, this->max);
}
}
inp_done = true;
}
template <typename T>
PD_API void Slider<T>::Draw() {
// Assert(io.get() && list.get(), "Did you run Container::Init correctly?");
// io->Ren->OnScreen(screen);
list->SetFont(GetFont());
std::string p;
if constexpr (std::is_floating_point_v<T>) {
p = std::format("{:.{}f}", *data, precision);
} else {
p = std::format("{}", *data);
}
fvec2 td = io->Font->GetTextBounds(p.c_str(), io->FontScale);
list->PathRect(FinalPos(), FinalPos() + fvec2(width, td.y) + io->FramePadding,
io->FrameRounding);
list->PathFill(io->Theme.Get(UI7Color_Button));
list->PathRect(FinalPos() + 2 + PD::fvec2(slp, 0),
FinalPos() + fvec2(slp + slw - 2, td.y - 2) + io->FramePadding,
io->FrameRounding);
list->PathFill(io->Theme.Get(UI7Color_ButtonActive));
list->LayerUp();
list->DrawTextEx(FinalPos(), p.c_str(), io->Theme.Get(UI7Color_Text),
LiTextFlags_AlignMid, fvec2(width, td.y) + io->FramePadding);
list->LayerDown();
list->DrawText(FinalPos() + fvec2(width + io->FramePadding.x * 2.f,
io->FramePadding.y * 0.5),
label.c_str(), io->Theme.Get(UI7Color_Text));
}
template <typename T>
PD_API void Slider<T>::Update() {
// Assert(io.get(), "Did you run Container::Init correctly?");
// Probably need to find a faster solution (caching sizes calculated here)
slw = std::clamp(static_cast<float>(width / max), 3.f, width);
slp = static_cast<float>((float)*data / (float)max) * (width - slw);
fvec2 tdim = io->Font->GetTextBounds(label.c_str(), io->FontScale);
this->SetSize(
fvec2(width + tdim.x + io->ItemSpace.x * 2, tdim.y + io->FramePadding.y));
}
} // namespace UI7
} // namespace PD
+61
View File
@@ -0,0 +1,61 @@
/*
MIT License
Copyright (c) 2024 - 2026 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>
#include <pd/drivers/drivers.hpp>
#include <pd/ui7/containers.hpp>
#include <pd/ui7/io.hpp>
namespace PD {
PD_API UI7::IO::IO() : CurrentViewPort("", 0), DeltaStats(60) {
/** Probably not the best solution i guess */
// CurrentViewPort =
// ViewPort::New("Default", ivec4(ivec2(0, 0), pCtx.Gfx()->ViewPort));
// Start a little larger on these
LabelPool.Init(512);
DynObjPool.Init(512);
}
PD_API UI7::IO::~IO() {}
PD_API void UI7::IO::Update() {
/** Todo: find out if we even still use the Drawlist regestry */
u64 current = PD::Os::GetTimeNano();
Delta = static_cast<float>(current - LastTime) / 1000000.f;
LastTime = current;
DeltaStats.Add(Delta * 1000);
Time.Update();
InputHandler.Update();
Framerate = 1000.f / Delta;
DrawlistRegestry.clear();
DrawlistRegestry.push_front(std::make_pair("CtxBackList", &Back));
if (Font) ItemRowHeight = FontScale * Font->PixelHeight;
// RegisterDrawList("CtxBackList", Back);
NumIndices = FDL.GetNumIndices();
NumVertices = FDL.GetNumVertices();
LabelPool.ResetFast();
DynObjPool.ResetFast();
ImagePool.ResetFast();
}
} // namespace PD
+250
View File
@@ -0,0 +1,250 @@
/*
MIT License
Copyright (c) 2024 - 2026 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 <algorithm>
#include <pd/ui7/containers.hpp>
#include <pd/ui7/layout.hpp>
namespace PD {
namespace UI7 {
PD_API Layout::~Layout() {
// We all love managing memory i guess
for (Container* obj : IDObjects) {
delete obj;
}
IDObjects.clear();
}
PD_API void Layout::CursorInit() { Cursor = fvec2(WorkRect.x, WorkRect.y); }
PD_API void Layout::SameLine() {
BackupCursor = LastObjSize;
Cursor = SamelineCursor;
}
PD_API void Layout::CursorMove(const fvec2& size) {
LastObjSize = size;
SamelineCursor = Cursor + fvec2(size.x + IO.ItemSpace.x, 0);
if (BeforeSameLine.y) {
Cursor =
fvec2(IO.MenuPadding.x, Cursor.y + BeforeSameLine.y + IO.ItemSpace.y);
BeforeSameLine = 0.f;
} else {
Cursor = fvec2(IO.MenuPadding.x + InitialCursorOffset.x,
Cursor.y + size.y + IO.ItemSpace.y);
}
// Logical Issue here as x should use a max check
MaxPosition = fvec2(std::max(MaxPosition.x, SamelineCursor.x), Cursor.y);
}
PD_API bool Layout::ObjectWorkPos(fvec2& movpos) {
if (Scrolling[1]) {
movpos.y -= ScrollOffset.y;
if (!Li::Math::InBounds(
movpos, LastObjSize,
fvec4(WorkRect.x, WorkRect.y, WorkRect.x + WorkRect.z,
WorkRect.y + WorkRect.w))) {
return true;
}
}
return false;
}
PD_API void Layout::AddObject(Container* obj) {
obj->Init(&IO, &DrawList);
obj->SetPos(AlignPosition(Cursor, obj->GetSize(), WorkRect, GetAlignment()));
obj->Update();
CursorMove(obj->GetSize());
obj->HandleScrolling(ScrollOffset, WorkRect);
if (Flags & UI7LayoutFlags_UseClipRect) {
obj->SetClipRect(
fvec4(Pos.x, Pos.y + WorkRect.y, Size.x, Size.y - WorkRect.y));
}
Objects.push_back(obj);
}
PD_API void Layout::AddObjectEx(Container* obj, u32 flags) {
obj->Init(&IO, &DrawList);
if (!(flags & UI7LytAdd_NoCursorUpdate)) {
obj->SetPos(
AlignPosition(Cursor, obj->GetSize(), WorkRect, GetAlignment()));
}
obj->Update();
if (!(flags & UI7LytAdd_NoCursorUpdate)) {
CursorMove(obj->GetSize());
}
if (!(flags & UI7LytAdd_NoScrollHandle)) {
obj->HandleScrolling(ScrollOffset, WorkRect);
}
if (Flags & UI7LayoutFlags_UseClipRect &&
!(flags & UI7LytAdd_NoGlobalClipping)) {
if (flags & UI7LytAdd_NoClipTitlebar) {
obj->SetClipRect(fvec4(Pos.x, Pos.y, Size.x, Size.y));
} else {
obj->SetClipRect(
fvec4(Pos.x, Pos.y + WorkRect.y, Size.x, Size.y - WorkRect.y));
}
}
if (flags & UI7LytAdd_Front) {
Objects.push_front(obj);
} else {
Objects.push_back(obj);
}
}
PD_API Container* Layout::FindObject(u32 id) {
for (auto& it : IDObjects) {
if (it->GetID() == id) {
return it;
}
}
return nullptr;
}
PD_API fvec2 Layout::AlignPosition(fvec2 pos, fvec2 size, fvec4 area,
UI7Align alignment) {
vec2 p = pos;
if (alignment & UI7Align_Center) {
p.x = (area.x + area.z) * 0.5 - (pos.x - area.x + size.x * 0.5);
} else if (alignment & UI7Align_Right) {
}
if (alignment & UI7Align_Mid) {
p.y = (area.y + area.w) * 0.5 - (pos.y - area.y + size.y * 0.5);
} else if (alignment & UI7Align_Bottom) {
}
return p;
}
PD_API void Layout::HandleScrolling() {
if (Flags & UI7LayoutFlags_VtScrolling) {
bool allowed = MaxPosition.y > WorkRect.w;
if (allowed) {
if (PD::Hid::IsEvent(Hid::Event::Down, PD::Hid::Gamepad::Touch) ||
PD::Hid::IsEvent(Hid::Event::Down, PD::Hid::Keyboard::MouseLeft)) {
ScrollStart = ScrollOffset;
}
if (IO.InputHandler.DragObject(UI7::ID("sbg" + ID.GetName()),
fvec4(Pos, fvec2(0.f)) + WorkRect)) {
if (!IO.InputHandler.DragReleasedAW) {
ScrollOffset.y =
std::clamp(ScrollStart.y + IO.InputHandler.DragSourcePos.y -
IO.InputHandler.DragPosition.y,
-20.f, MaxPosition.y - WorkRect.w + 20.f);
}
}
} else {
ScrollOffset.y = 0.f;
}
if (ScrollOffset.y > MaxPosition.y - WorkRect.w) {
ScrollOffset.y -= 1.5f;
if (ScrollOffset.y < MaxPosition.y - WorkRect.w) {
ScrollOffset.y = MaxPosition.y - WorkRect.w;
}
}
if (ScrollOffset.y < 0) {
ScrollOffset.y += 1.5f;
if (ScrollOffset.y > 0) {
ScrollOffset.y = 0;
}
}
}
}
PD_API void Layout::Update() {
if (Size == fvec2(0.f)) {
Size = fvec2(MaxPosition) + IO.MenuPadding * 2;
}
for (auto& it : Objects) {
if (it->GetID() != 0 && !FindObject(it->GetID())) {
IDObjects.push_back(it);
}
if (!it->Skippable()) {
it->SetPos(it->GetPos() + Pos);
it->HandleInput();
it->UnlockInput();
it->PreDraw();
it->Draw();
it->PostDraw();
}
}
for (auto it = IDObjects.begin(); it != IDObjects.end();) {
if ((*it)->Removable()) {
delete *it;
it = IDObjects.erase(it);
} else {
it++;
}
}
Objects.clear();
WorkRect = fvec4(fvec2(WorkRect.x, WorkRect.y), Size - IO.MenuPadding);
CursorInit();
HandleScrolling();
}
/** SECTION CONTAINERS (STOLEN FROM FORMER MENU) */
PD_API void Layout::Label(const std::string& label) {
// Layout API
auto r = IO.LabelPool.Allocate();
*r = UI7::Label(label, IO);
// r->SetClipRect(fvec4(GetPosition(), GetSize()));
AddObject(r);
}
PD_API bool Layout::Button(const std::string& label) {
bool ret = false;
u32 id = Strings::FastHash("btn" + label + std::to_string(Objects.size()));
Container* r = FindObject(id);
if (!r) {
r = new UI7::Button(label, IO);
r->SetID(id);
}
AddObject(r);
if (!r->Skippable()) {
ret = reinterpret_cast<UI7::Button*>(r)->IsPressed();
}
return ret;
}
PD_API void Layout::Checkbox(const std::string& label, bool& v) {
u32 id = Strings::FastHash("cbx" + label + std::to_string(Objects.size()));
Container* r = FindObject(id);
if (!r) {
r = new UI7::Checkbox(label, v, IO);
r->SetID(id);
}
AddObject(r);
}
PD_API void Layout::Image(Li::Texture img, fvec2 size, Li::Rect uv) {
auto r = IO.ImagePool.Allocate();
*r = UI7::Image(img, size, uv);
AddObject(r);
}
} // namespace UI7
} // namespace PD
+404
View File
@@ -0,0 +1,404 @@
/*
MIT License
Copyright (c) 2024 - 2026 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 <algorithm>
#include <pd/ui7/containers.hpp>
#include <pd/ui7/menu.hpp>
namespace PD {
namespace UI7 {
Menu::Menu(const ID& id, IO& io) : pLayout(id, io), pIO(io), pID(id) {
TitleBarHeight = pIO.FontScale * pIO.Font->PixelHeight + pIO.MenuPadding.y;
pLayout.WorkRect.y += TitleBarHeight;
pLayout.Flags |= UI7LayoutFlags_UseClipRect;
pLayout.CursorInit();
}
PD_API void Menu::Label(const std::string& label) {
// Layout API
auto r = pIO.LabelPool.Allocate();
*r = UI7::Label(label, pIO);
pLayout.AddObject(r);
}
PD_API bool Menu::Button(const std::string& label) {
bool ret = false;
u32 id =
Strings::FastHash("btn" + label + std::to_string(pLayout.Objects.size()));
Container* r = pLayout.FindObject(id);
if (!r) {
r = new UI7::Button(label, pIO);
r->SetID(id);
}
pLayout.AddObject(r);
if (!r->Skippable()) {
ret = reinterpret_cast<UI7::Button*>(r)->IsPressed();
}
return ret;
}
PD_API void Menu::Checkbox(const std::string& label, bool& v) {
u32 id =
Strings::FastHash("cbx" + label + std::to_string(pLayout.Objects.size()));
Container* r = pLayout.FindObject(id);
if (!r) {
r = new UI7::Checkbox(label, v, pIO);
r->SetID(id);
}
pLayout.AddObject(r);
}
PD_API void Menu::Image(Li::Texture img, fvec2 size, Li::Rect uv) {
auto r = pIO.ImagePool.Allocate();
*r = UI7::Image(img, size, uv);
pLayout.AddObject(r);
}
PD_API void Menu::ColorEdit(const std::string& label, u32& clr) {
u32 id = Strings::FastHash("drd" + label);
Container* r = pLayout.FindObject(id);
if (!r) {
r = new UI7::ColorEdit(label, &clr, pIO);
r->SetID(id);
}
pLayout.AddObject(r);
}
PD_API void Menu::Separator() {
// Dynamic Objects are very simple...
DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj(
[=, this](UI7::IO* io, Li::Drawlist* l, UI7::Container* self) {
l->DrawRectFilled(self->FinalPos(), self->GetSize(),
pIO.Theme.Get(UI7Color_TextDead));
});
// Set size before pushing (cause Cursor Move will require it)
r->SetSize(fvec2(
pLayout.Size.x - pIO.MenuPadding.x * 2 - pLayout.InitialCursorOffset.x,
1));
pLayout.AddObject(r);
}
PD_API void Menu::SeparatorText(const std::string& label) {
// Also note to use [=] instead of [&] to not undefined access label
DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l,
UI7::Container* self) {
l->SetFont(self->GetFont());
fvec2 size = self->GetSize();
fvec2 tdim = io->Font->GetTextBounds(label.c_str(), io->FontScale);
fvec2 pos = self->FinalPos();
auto align = pLayout.GetAlignment();
vec2 rpos = pLayout.AlignPosition(pos, tdim,
fvec4(pLayout.Pos, pLayout.Size), align);
if (!(align & UI7Align_Left)) {
l->DrawRectFilled(fvec2(rpos.x + io->FramePadding.x, tdim.y * 0.5),
fvec2(pos.x - rpos.x - io->MenuPadding.x, 1),
io->Theme.Get(UI7Color_TextDead));
}
if (!(align & UI7Align_Right)) {
l->DrawRectFilled(pos + fvec2(tdim.x + io->FramePadding.x, tdim.y * 0.5),
fvec2(size.x - tdim.x - io->MenuPadding.x, 1),
io->Theme.Get(UI7Color_TextDead));
}
l->DrawTextEx(rpos, label.c_str(), io->Theme.Get(UI7Color_Text), 0,
fvec2(pLayout.Size.x, self->GetSize().y));
});
// Set size before pushing (cause Cursor Move will require it)
r->SetSize(fvec2(
pLayout.Size.x - pIO.MenuPadding.x * 2 - pLayout.InitialCursorOffset.x,
pIO.Font->PixelHeight * pIO.FontScale));
pLayout.AddObject(r);
}
PD_API void Menu::HandleFocus() {
// Check if menu can be focused for Selective Menu Input API
vec4 newarea = fvec4(pLayout.Pos, pLayout.Size);
if (!pIsOpen) {
newarea = fvec4(pLayout.Pos, fvec2(pLayout.Size.x, TitleBarHeight));
}
if ((PD::Hid::IsEvent(Hid::Event::Down, Hid::Gamepad::Touch) ||
PD::Hid::IsEvent(Hid::Event::Down, Hid::Keyboard::MouseLeft)) &&
Li::Math::InBounds(PD::Hid::MousePos(), newarea) &&
!Li::Math::InBounds(PD::Hid::MousePos(),
pIO.InputHandler.FocusedMenuRect)) {
pIO.InputHandler.FocusedMenu = pID;
}
if (pIO.InputHandler.FocusedMenu == pID) {
pIO.InputHandler.FocusedMenuRect = newarea;
}
}
PD_API void Menu::HandleTitlebarActions() {
// Collapse
if (!(Flags & UI7MenuFlags_NoCollapse)) {
vec2 cpos = pLayout.Pos + pIO.FramePadding;
// clr_collapse_tri = UI7Color_FrameBackground;
if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "clbse"),
fvec4(cpos, fvec2(18, TitleBarHeight)))) {
if (pIO.InputHandler.DragReleased) {
pIsOpen = !pIsOpen;
}
// clr_collapse_tri = UI7Color_FrameBackgroundHovered;
}
}
// Close Logic
if (!(Flags & UI7MenuFlags_NoClose) && pIsShown != nullptr) {
fvec2 size = TitleBarHeight - pIO.FramePadding.y * 2;
fvec2 cpos =
fvec2(pLayout.Pos.x + pLayout.Size.x - size.x - pIO.FramePadding.x,
pLayout.Pos.y + pIO.FramePadding.y);
// clr_close_btn = UI7Color_FrameBackground;
if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "clse"),
fvec4(cpos, size))) {
if (pIO.InputHandler.DragReleased) {
*pIsShown = !(*pIsShown);
}
// clr_close_btn = UI7Color_FrameBackgroundHovered;
}
}
// Resize logic
if (!(Flags & UI7MenuFlags_NoResize)) {
vec2 cpos = pLayout.Pos + pLayout.Size - fvec2(20);
// clr_close_btn = UI7Color_FrameBackground;
if (pIO.InputHandler.DragObject(UI7::ID(pID.GetName() + "rszs"),
fvec4(cpos, fvec2(20)))) {
fvec2 szs = pLayout.Size + (pIO.InputHandler.DragPosition -
pIO.InputHandler.DragLastPosition);
if (szs.x < 30) szs.x = 30;
if (szs.y < 30) szs.y = 30;
pLayout.Size = szs;
// clr_close_btn = UI7Color_FrameBackgroundHovered;
}
}
// Menu Movement
if (!(Flags & UI7MenuFlags_NoMove)) {
if (pIO.InputHandler.DragObject(
pID.GetName() + "tmv",
fvec4(pLayout.Pos, fvec2(pLayout.Size.x, TitleBarHeight)))) {
if (pIO.InputHandler.DragDoubleRelease) {
pIsOpen = !pIsOpen;
}
pLayout.Pos = pLayout.Pos + (pIO.InputHandler.DragPosition -
pIO.InputHandler.DragLastPosition);
// Keep Window In Viewport
// Maybe i need to add some operators to vec
pLayout.Pos.x = std::clamp<float>(pLayout.Pos.x, -pLayout.Size.x + 10,
pIO.CurrentViewPort.pSize.z - 10);
pLayout.Pos.y =
std::clamp<float>(pLayout.Pos.y, pIO.CurrentViewPort.pSize.y,
pIO.CurrentViewPort.pSize.w - 10);
}
}
}
PD_API void Menu::DrawBaseLayout() {
if (pIsOpen) {
/** Resize Sym (Render on Top of Everything) */
if (!(Flags & UI7MenuFlags_NoResize)) {
DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([](IO* io, Li::Drawlist* l, UI7::Container* self) {
l->SetLayer(21);
l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(0, 20));
l->PathAdd(self->FinalPos() + self->GetSize());
l->PathAdd(self->FinalPos() + self->GetSize() - fvec2(20, 0));
l->PathFill(io->Theme.Get(UI7Color_Button));
l->SetLayer(0);
});
r->SetSize(
fvec2(pLayout.GetSize().x, pLayout.GetSize().y - TitleBarHeight));
r->SetPos(fvec2(0, TitleBarHeight));
pLayout.AddObjectEx(r,
UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle);
}
/** Background */
DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([](IO* io, Li::Drawlist* l, UI7::Container* self) {
l->SetLayer(0);
l->PathRectEx(self->FinalPos(), self->FinalPos() + self->GetSize(), 10.f,
LiPathRectFlags_KeepTop | LiPathRectFlags_KeepBot);
l->PathFill(io->Theme.Get(UI7Color_Background));
/*l->DrawRectFilled(self->FinalPos(), self->GetSize(),
io->Theme.Get(UI7Color_Background));*/
});
// Set size before pushing (cause Cursor Move will require it)
r->SetSize(
fvec2(pLayout.GetSize().x, pLayout.GetSize().y - TitleBarHeight));
r->SetPos(fvec2(0, TitleBarHeight));
pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle |
UI7LytAdd_Front | UI7LytAdd_NoClipTitlebar);
}
if (!(Flags & UI7MenuFlags_NoTitlebar)) {
DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj(
[=, this](UI7::IO* io, Li::Drawlist* l, UI7::Container* self) {
l->SetFont(self->GetFont());
l->SetLayer(20);
/** Header Bar */
l->DrawRectFilled(self->FinalPos(), self->GetSize(),
io->Theme.Get(UI7Color_Header));
l->SetLayer(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_NoCollapse)
? pIO.FramePadding.x
: (TitleBarHeight - pIO.FramePadding.y * 2 +
(io->FramePadding.x * 2)),
2),
pID.GetName().c_str(), io->Theme.Get(UI7Color_Text));
l->SetLayer(0);
});
r->SetSize(fvec2(pLayout.GetSize().x, TitleBarHeight));
r->SetPos(0);
pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate | UI7LytAdd_NoScrollHandle |
UI7LytAdd_NoClipTitlebar);
/** Collapse Sym */
if (!(Flags & UI7MenuFlags_NoCollapse)) {
DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([=, this](UI7::IO* io, Li::Drawlist* l,
UI7::Container* self) {
/** This sym actually requires layer 21 (i dont know why) */
l->SetLayer(21);
/**
* Symbol (Position Swapping set by pIsOpen ? openpos : closepos;)
*/
l->DrawTriangleFilled(
self->FinalPos(),
self->FinalPos() +
fvec2(self->GetSize().x, pIsOpen ? 0 : self->GetSize().y * 0.5),
self->FinalPos() +
fvec2(pIsOpen ? self->GetSize().x * 0.5 : 0, self->GetSize().y),
io->Theme.Get(UI7Color_FrameBackground));
l->SetLayer(0);
});
r->SetSize(TitleBarHeight - pIO.FramePadding.y * 2);
r->SetPos(pIO.FramePadding);
pLayout.AddObjectEx(r, UI7LytAdd_NoCursorUpdate |
UI7LytAdd_NoScrollHandle |
UI7LytAdd_NoClipTitlebar);
}
/** Close Sym (only shown if pIsShown is not nullptr) */
if (!(Flags & UI7MenuFlags_NoClose) && pIsShown) {
fvec2 size = TitleBarHeight - pIO.FramePadding.y * 2; // Fixed quad size
// Need to clamp this way as the math lib lacks a less and greater
// operator in vec2 (don't checked if it would make sense yet)
size.x = std::clamp(size.x, 5.f, std::numeric_limits<float>::max());
size.y = std::clamp(size.y, 5.f, std::numeric_limits<float>::max());
// Probably should fix the minsize to be locked on y
fvec2 cpos =
fvec2(pLayout.Pos.x + pLayout.Size.x - size.x - pIO.FramePadding.x,
pLayout.Pos.y + pIO.FramePadding.y);
pLayout.DrawList.SetLayer(21);
pLayout.DrawList.DrawLine(cpos, cpos + size,
pIO.Theme.Get(UI7Color_FrameBackground), 2);
pLayout.DrawList.DrawLine(cpos + fvec2(0, size.y),
cpos + fvec2(size.x, 0),
pIO.Theme.Get(UI7Color_FrameBackground), 2);
pLayout.DrawList.SetLayer(0);
}
}
}
PD_API void Menu::Update() {
HandleFocus();
if (pLayout.Size == fvec2(0.f) || Flags & UI7MenuFlags_AlwaysAutoSize) {
pLayout.Size = fvec2(pLayout.MaxPosition) + pIO.MenuPadding * 2;
}
if (Flags & UI7MenuFlags_VtScrolling)
pLayout.Flags |= UI7LayoutFlags_VtScrolling;
if (Flags & UI7MenuFlags_HzScrolling)
pLayout.Flags |= UI7LayoutFlags_HzScrolling;
if (!(Flags & UI7MenuFlags_NoTitlebar)) {
TitleBarHeight = pIO.FontScale * pIO.Font->PixelHeight + pIO.MenuPadding.y;
pLayout.WorkRect.y = 5.f + TitleBarHeight;
HandleTitlebarActions();
} else {
TitleBarHeight = 0.f;
pLayout.WorkRect.y = 5.f;
}
DrawBaseLayout();
pLayout.Update();
}
PD_API bool Menu::BeginTreeNode(const ID& id) {
// As of some notes this should work:
auto n = pTreeNodes.find(id);
if (n == pTreeNodes.end()) {
pTreeNodes[id] = false;
n = pTreeNodes.find(id);
}
fvec2 pos = pLayout.Cursor;
fvec2 tdim = pIO.Font->GetTextBounds(id.GetName().c_str(), pIO.FontScale);
fvec2 szs = tdim + fvec2(pIO.ItemSpace.x + 10, 0);
if (n->second) {
pLayout.InitialCursorOffset += 10.f;
}
// Object
DynObj* r = pIO.DynObjPool.Allocate();
*r = UI7::DynObj([=, this](IO* io, Li::Drawlist* l, Container* self) {
l->SetFont(self->GetFont());
fvec2 ts = self->FinalPos() + fvec2(0, 7);
fvec2 pl[2] = {fvec2(10, 5), fvec2(0, 10)};
if (n->second) {
float t = pl[0].y;
pl[0].y = pl[1].x;
pl[1].x = t;
}
l->DrawTriangleFilled(ts, ts + pl[0], ts + pl[1],
io->Theme.Get(UI7Color_FrameBackground));
l->DrawText(self->FinalPos() + fvec2(10 + io->ItemSpace.x, 0),
id.GetName().c_str(), io->Theme.Get(UI7Color_Text));
});
/** Yes this new function handler was created for tree nodes */
r->AddInputHandler([=, this](IO* io, Container* self) {
if (io->InputHandler.DragObject(ID(pID.GetName() + id.GetName()),
fvec4(self->FinalPos(), self->GetSize()))) {
if (io->InputHandler.DragReleased) {
n->second = !n->second;
}
}
});
r->SetPos(pos);
r->SetSize(szs);
/** Use Add Object as it is faster */
pLayout.AddObject(r);
return n->second;
}
PD_API void UI7::Menu::EndTreeNode() {
pLayout.InitialCursorOffset.x -= 10.f;
pLayout.Cursor.x -= 10.f;
if (pLayout.InitialCursorOffset.x < 0.f) {
pLayout.InitialCursorOffset.x = 0.f;
}
}
} // namespace UI7
} // namespace PD
+68
View File
@@ -0,0 +1,68 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/theme.hpp>
namespace PD {
namespace UI7 {
PD_API void Theme::Default(Theme& theme) {
theme.Set(UI7Color_Text, Color("#FFFFFFFF"));
theme.Set(UI7Color_TextDead, Color("#AAAAAAFF"));
theme.Set(UI7Color_Background, Color("#222222aa"));
theme.Set(UI7Color_Border, Color("#999999ff"));
theme.Set(UI7Color_Button, Color("#111111FF"));
theme.Set(UI7Color_ButtonDead, Color("#080808FF"));
theme.Set(UI7Color_ButtonActive, Color("#2A2A2AFF"));
theme.Set(UI7Color_ButtonHovered, Color("#222222FF"));
theme.Set(UI7Color_Header, Color("#111111cc"));
theme.Set(UI7Color_HeaderDead, Color("#080808FF"));
theme.Set(UI7Color_Selector, Color("#222222FF"));
theme.Set(UI7Color_Checkmark, Color("#2A2A2AFF"));
theme.Set(UI7Color_FrameBackground, Color("#555555FF"));
theme.Set(UI7Color_FrameBackgroundHovered, Color("#777777FF"));
theme.Set(UI7Color_Progressbar, Color("#00FF00FF"));
theme.Set(UI7Color_ListEven, Color("#CCCCCCFF"));
theme.Set(UI7Color_ListOdd, Color("#BBBBBBFF"));
}
PD_API void Theme::Flashbang(Theme& theme) {
theme.Set(UI7Color_Text, Color("#000000FF"));
theme.Set(UI7Color_TextDead, Color("#333333FF"));
theme.Set(UI7Color_Background, Color("#eeeeeeFF"));
theme.Set(UI7Color_Border, Color("#777777ff"));
theme.Set(UI7Color_Button, Color("#ccccccFF"));
theme.Set(UI7Color_ButtonDead, Color("#bbbbbbFF"));
theme.Set(UI7Color_ButtonActive, Color("#ccccccFF"));
theme.Set(UI7Color_ButtonHovered, Color("#acacacFF"));
theme.Set(UI7Color_Header, Color("#ddddddFF"));
theme.Set(UI7Color_HeaderDead, Color("#cdcdcdFF"));
theme.Set(UI7Color_Selector, Color("#222222FF"));
theme.Set(UI7Color_Checkmark, Color("#ccccccFF"));
theme.Set(UI7Color_FrameBackground, Color("#aaaaaaFF"));
theme.Set(UI7Color_FrameBackgroundHovered, Color("#909090FF"));
theme.Set(UI7Color_Progressbar, Color("#00FF00FF"));
theme.Set(UI7Color_ListEven, Color("#CCCCCCFF"));
theme.Set(UI7Color_ListOdd, Color("#BBBBBBFF"));
}
} // namespace UI7
} // namespace PD
+359
View File
@@ -0,0 +1,359 @@
/*
MIT License
Copyright (c) 2024 - 2026 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/ui7/ui7.hpp>
#include "pd/pd_p_api.hpp"
#include "pd/ui7/flags.hpp"
#define UI7DHX32(x) std::format("{}: {:#08x}", #x, x)
#define UI7DTF(x) PD::Strings::FormatNanos(x)
namespace PD {
namespace UI7 {
PD_API std::string GetVersion(bool show_build) {
std::stringstream s;
s << ((UI7_VERSION >> 24) & 0xFF) << ".";
s << ((UI7_VERSION >> 16) & 0xFF) << ".";
s << ((UI7_VERSION >> 8) & 0xFF);
if (show_build) s << "-" << ((UI7_VERSION) & 0xFF);
return s.str();
}
PD_API void Context::AddViewPort(const ID& id, const ivec4& vp) {
pIO.AddViewPort(id, vp);
}
PD_API void Context::UseViewPort(const ID& id) {
if (!pIO.ViewPorts.count(id)) {
return;
}
pIO.CurrentViewPort = pIO.ViewPorts[id.RawID()];
}
PD_API Menu* Context::BeginMenu(const ID& id, UI7MenuFlags flags, bool* pShow) {
if (pCurrent) {
PDERR("UI7: You are already in {} Menu!", pCurrent->pID.GetName());
return nullptr;
}
if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(), (u32)id) !=
pCurrentMenus.end()) {
PDERR("UI7: Menu {} already exists!", id.GetName());
return nullptr;
}
pCurrent = pGetOrCreateMenu(id);
this->pCurrent->pIsShown = pShow;
if (pCurrent->pIsShown != nullptr) {
if (!*pCurrent->pIsShown) {
pCurrent = nullptr;
return nullptr;
}
}
/** Probably we dont even need Input Handling in this stage */
// this->pIO.InputHandler.CurrentMenu = id;
pCurrentMenus.push_back(id);
pCurrent->Flags = flags;
if (!pCurrent->pIsOpen) {
pCurrent = nullptr;
}
return pCurrent;
}
PD_API void Context::EndMenu() {
/**
* Currently it would be a better wy to handle menus as follows
*
* The folowing context will generate a new menu as normally but instead
* of true or false we have m is false (nullptr) or true (some ptr returned)
* and after that it should simply out of scope
* (This would probably require some wrapper class to find out if m goes
* out of scope)
* ```cpp
* if(auto m = ui7->BeginMenu("Test")) {
* m->Label("Show some Text");
* }
* ```
*/
if (!pCurrent) {
return;
}
pCurrent = nullptr;
// pIO.InputHandler.CurrentMenu = 0;
}
PD_API void Context::Update() {
/**
* Cause Commenting each line looks carbage...
* This function simply clears the FinalDrawList, Searches for Menu ID's in
* The sorted menu List from last frame to insert them as same order into
* the final list. After that it adds new menus to the begin to 'add' new
* menus on top. As final step the focused menu gets add to begin
* Then the menus update their Input and DraeList Generation in List Order
* and the DrawLists get Merged into the FDL in reverse Order. At end the List
* gets cleanup and io gets updated
*
* Very simple ...
*/
pIO.FDL.Clear();
if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(),
pIO.InputHandler.FocusedMenu) == pCurrentMenus.end()) {
pIO.InputHandler.FocusedMenu = 0;
pIO.InputHandler.FocusedMenuRect = fvec4(0);
}
std::vector<u32> FinalList;
for (auto it : pDFO) {
if (std::find(pCurrentMenus.begin(), pCurrentMenus.end(), it) !=
pCurrentMenus.end() &&
it != pIO.InputHandler.FocusedMenu) {
FinalList.push_back(it);
}
}
for (auto it : pCurrentMenus) {
if (std::find(FinalList.begin(), FinalList.end(), it) == FinalList.end() &&
it != pIO.InputHandler.FocusedMenu) {
FinalList.push_back(it);
}
}
if (pMenus.count(pIO.InputHandler.FocusedMenu)) {
FinalList.insert(FinalList.begin(), pIO.InputHandler.FocusedMenu);
}
pDFO = FinalList;
for (auto& it : FinalList) {
this->pIO.InputHandler.CurrentMenu = it;
pMenus[it]->Update(); /** Render */
this->pIO.InputHandler.CurrentMenu = 0;
}
int base_layer = 0;
for (int i = (int)FinalList.size() - 1; i >= 0; i--) {
pIO.FDL.SetLayer(base_layer);
pIO.FDL.Merge(pMenus[FinalList[i]]->pLayout.GetDrawList());
base_layer += 100;
}
pCurrentMenus.clear();
pIO.Update();
pIO.FDL.Optimize();
}
PD_API void Context::AboutMenu(bool* show) {
if (auto m = BeginMenu("About UI7", UI7MenuFlags_Scrolling, show)) {
m->Label("Palladium UI7 " + GetVersion());
m->Separator();
m->Label("(c) 2023-2026 René Amthor");
m->Label("UI7 is licensed under the MIT License.");
m->Label("See LICENSE for more information.");
static bool show_build;
m->Checkbox("Show Build Info", show_build);
if (show_build) {
m->SeparatorText("Build Info");
m->Label("Full Version -> " + GetVersion(true));
m->Label("sizeof(size_t) -> " + std::to_string(sizeof(size_t)));
m->Label("sizeof(LI::Vertex) -> " + std::to_string(sizeof(Li::Vertex)));
m->Label("__cplusplus -> " + std::to_string(__cplusplus));
m->Label("Compiler -> {}",
Strings::GetCompilerVersion()); // + LibInfo::CompiledWith());
}
EndMenu();
}
}
PD_API void Context::MetricsMenu(bool* show) {
if (auto m = BeginMenu("UI7 Metrics", UI7MenuFlags_Scrolling, show)) {
m->Label("Palladium - UI7 " + GetVersion());
m->Separator();
m->Label(
std::format("Average {:.3f} ms/f ({:.1f} FPS)",
((float)pIO.DeltaStats.GetAverage() / 1000.f),
1000.f / ((float)pIO.DeltaStats.GetAverage() / 1000.f)));
m->Label(std::format("NumVertices: {}", pIO.NumVertices));
m->Label(std::format("NumIndices: {} -> {} Tris", pIO.NumIndices,
pIO.NumIndices / 3));
m->Label("Menus: " + std::to_string(pMenus.size()));
/** Section TimeTrace */
m->SeparatorText("TimeTrace");
if (m->BeginTreeNode("Traces (" +
std::to_string(PD::TT::GetTraceMap().size()) + ")")) {
for (auto& it : PD::TT::GetTraceMap()) {
if (m->BeginTreeNode(it.second.GetID())) {
m->Label("Diff: " + UI7DTF(it.second.GetLastDiff()));
m->Label("Protocol Len: " +
std::to_string(it.second.GetProtocol().GetLen()));
m->Label("Average: " + UI7DTF(it.second.GetProtocol().GetAverage()));
m->Label("Min: " + UI7DTF(it.second.GetProtocol().GetMin()));
m->Label("Max: " + UI7DTF(it.second.GetProtocol().GetMax()));
m->EndTreeNode();
}
}
m->EndTreeNode();
}
m->SeparatorText("Palladium Info");
m->Label("Os Driver: {}", PD::Os::GetDriverName());
if (m->BeginTreeNode(
std::format("Gfx Driver: {}", PD::Gfx::GetDriverName()))) {
m->SeparatorText("Features");
if (PD::Gfx::GetFlags() & PDGfxBackendFlags_HasClipRect)
m->Label("ClipRects");
if (PD::Gfx::GetFlags() & PDGfxBackendFlags_ReqPow2)
m->Label("Texture As Pow of 2");
if (PD::Gfx::GetFlags() & PDGfxBackendFlags_ApproxSDF)
m->Label("SDF Approximation");
m->EndTreeNode();
}
if (m->BeginTreeNode(
std::string(std::string("Input: ") + PD::Hid::GetDriverName()))) {
/* if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasKeyboard) {
m->Label("- Keyboard Supported");
}
if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasMouse) {
m->Label("- Mouse Supported");
}
if (pIO.pCtx.Hid()->Flags & PD::HidDriver::Flags_HasTouch) {
m->Label("- Touch Supported");
}
if (pIO.pCtx.Hid()->Flags & PD::HidDriver::FLags_HasGamepad) {
m->Label("- Gamepad Supported");
}*/
m->EndTreeNode();
}
/** Section IO */
m->SeparatorText("IO");
if (m->BeginTreeNode("Menus (" + std::to_string(pMenus.size()) + ")")) {
for (auto& it : pMenus) {
if (m->BeginTreeNode(it.second->pID.GetName())) {
m->Label("Name: " + it.second->pID.GetName());
m->Label(std::format("Pos: {}", it.second->pLayout.GetPosition()));
m->Label(std::format("Size: {}", it.second->pLayout.GetSize()));
m->Label(std::format("WorkRect: {}", it.second->pLayout.WorkRect));
m->Label(std::format("Cursor: {}", it.second->pLayout.Cursor));
if (m->BeginTreeNode(
"ID Objects (" +
std::to_string(it.second->pLayout.IDObjects.size()) + ")")) {
for (auto& jt : it.second->pLayout.IDObjects) {
m->Label(std::format("{:08X}", jt->GetID()));
}
m->EndTreeNode();
}
m->EndTreeNode();
}
}
m->EndTreeNode();
}
if (m->BeginTreeNode("Active Menus (" +
std::to_string(pCurrentMenus.size()) + ")")) {
for (auto& it : pCurrentMenus) {
if (m->BeginTreeNode(pMenus[it]->pID.GetName())) {
m->Label("Name: " + pMenus[it]->pID.GetName());
m->Label(std::format("Pos: {}", pMenus[it]->pLayout.GetPosition()));
m->Label(std::format("Size: {}", pMenus[it]->pLayout.GetSize()));
m->Label(std::format("WorkRect: {}", pMenus[it]->pLayout.WorkRect));
m->Label(std::format("Cursor: {}", pMenus[it]->pLayout.Cursor));
if (m->BeginTreeNode(
"ID Objects (" +
std::to_string(pMenus[it]->pLayout.IDObjects.size()) + ")")) {
for (auto& jt : pMenus[it]->pLayout.IDObjects) {
m->Label(std::format("{:08X}", jt->GetID()));
}
m->EndTreeNode();
}
m->EndTreeNode();
}
}
m->EndTreeNode();
}
// Well this are Li Drawlists now and they do not count their stats (yet)
/*if (m->BeginTreeNode("DrawLists (" +
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));
m->Label("Indices: " + std::to_string(it.Second->NumIndices));
m->Label("Base Layer: " + std::to_string(it.Second->Base));
m->EndTreeNode();
}
}
m->EndTreeNode();
}*/
m->Label("io->Time: " + Strings::FormatMillis(pIO.Time.Get()));
m->Label(std::format("Delta: {:.3f}", pIO.Delta));
m->Label(std::format("Framerate: {:.2f}", pIO.Framerate));
m->Label(std::format("Focused Menu: {:08X}", pIO.InputHandler.FocusedMenu));
m->Label(
std::format("Dragged Object: {:08X}", pIO.InputHandler.DraggedObject));
m->Label(std::format("DragTime: {:.2f}s",
pIO.InputHandler.DragTime.GetSeconds()));
m->Label(
std::format("DragDestination: [{}]", pIO.InputHandler.DragDestination));
m->Label(std::format("DragSource: [{}]", pIO.InputHandler.DragSourcePos));
m->Label(std::format("DragPos: [{}]", pIO.InputHandler.DragPosition));
m->Label(
std::format("DragLastPos: [{}]", pIO.InputHandler.DragLastPosition));
EndMenu();
}
}
PD_API void UI7::Context::StyleEditor(bool* show) {
if (auto m = BeginMenu("UI7 Style Editor", UI7MenuFlags_Scrolling, show)) {
m->Label("Palladium - UI7 " + GetVersion() + " Style Editor");
m->Separator();
m->DragData("MenuPadding", (float*)&pIO.MenuPadding, 2, 0.f, 100.f);
m->DragData("FramePadding", (float*)&pIO.FramePadding, 2, 0.f, 100.f);
m->DragData("ItemSpace", (float*)&pIO.ItemSpace, 2, 0.f, 100.f);
m->DragData("MinSliderSize", (float*)&pIO.MinSliderDragSize, 2, 1.f, 100.f);
m->DragData("OverScroll Modifier", &pIO.OverScrollMod, 1, 0.01f,
std::numeric_limits<float>::max(), 0.01f, 2);
m->Checkbox("Menu Border", pIO.ShowMenuBorder);
m->Checkbox("Frame Border", pIO.ShowFrameBorder);
m->SeparatorText("Theme");
if (m->Button("Dark")) {
UI7::Theme::Default(pIO.Theme);
}
m->SameLine();
if (m->Button("Flashbang")) {
UI7::Theme::Flashbang(pIO.Theme);
}
/// Small trick to print without prefix
#define ts(x) m->ColorEdit(std::string(#x).substr(9), pIO.Theme.GetRef(x));
#define ts2(x) \
m->DragData(std::string(#x).substr(9), (u8*)&pIO.Theme.GetRef(x), 4, (u8)0, \
(u8)255);
ts(UI7Color_Background);
ts(UI7Color_Border);
ts(UI7Color_Button);
ts(UI7Color_ButtonDead);
ts(UI7Color_ButtonActive);
ts(UI7Color_ButtonHovered);
ts(UI7Color_Text);
ts(UI7Color_TextDead);
ts(UI7Color_Header);
ts(UI7Color_HeaderDead);
ts(UI7Color_Selector);
ts(UI7Color_Checkmark);
ts(UI7Color_FrameBackground);
ts(UI7Color_FrameBackgroundHovered);
ts(UI7Color_Progressbar);
ts(UI7Color_ListEven);
ts(UI7Color_ListOdd);
this->EndMenu();
}
}
} // namespace UI7
} // namespace PD
+55
View File
@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.22)
project(test)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED true)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_EXPORT_COMPILE_COMMANDS true)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
if(${PD_BUILD_SHARED})
message(ERROR "3DS Only supports Static libraries")
endif()
endif()
add_subdirectory(../ palladium)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
add_subdirectory(../backends/3ds pd-3ds)
else()
add_subdirectory(../backends/desktop pd-desktop)
endif()
add_executable(test source/main.cpp
${BKND_SRC})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
target_link_libraries(test PUBLIC pd-3ds palladium)
else()
target_link_libraries(test PUBLIC pd-desktop palladium)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
target_compile_options(palladium PRIVATE
$<$<COMPILE_LANGUAGE:C>:-Wall>
$<$<COMPILE_LANGUAGE:C>:-Wno-psabi>
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Release")
target_compile_options(palladium PRIVATE
$<$<CONFIG:Debug>:-O0 -g>
$<$<CONFIG:Release>:-O3>
)
endif()
# set(RC_FILES
# testassets/ComicNeue.ttf
# testassets/logo.png
# testassets/test.png)
# install(FILES ${RC_FILES} DESTINATION ".")
# else()
# target_link_libraries(test PUBLIC pd-backend-3ds ctru citro3d)
# endif()
Binary file not shown.
+93
View File
@@ -0,0 +1,93 @@
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
+17
View File
@@ -20,9 +20,26 @@ bool ColorTests() {
return true; return true;
} }
bool IDTests() {
std::cout << std::format("HashID32(\"1234\") -> {:016X}",
PD::HashID32("1234").Get())
<< std::endl;
std::cout << std::format("HashID32(\"1235\") -> {:016X}",
PD::HashID32("1235").Get())
<< std::endl;
std::cout << std::format("HashID64(\"1234\") -> {:016X}",
PD::HashID64("1234").Get())
<< std::endl;
std::cout << std::format("HashID64(\"1235\") -> {:016X}",
PD::HashID64("1235").Get())
<< std::endl;
return true;
}
int main() { int main() {
PD::Os::UseDriver<PD::OsDriver>(); PD::Os::UseDriver<PD::OsDriver>();
ColorTests(); ColorTests();
IDTests();
std::cout << PD::Os::GetTime() << std::endl; std::cout << PD::Os::GetTime() << std::endl;
PD::Pool<int> pool; PD::Pool<int> pool;
pool.Init(90); pool.Init(90);
+2
View File
@@ -21,6 +21,8 @@ class OsCtx {
virtual bool Mainloop() { return false; } virtual bool Mainloop() { return false; }
virtual void ClearViewPort() {} virtual void ClearViewPort() {}
virtual void SwapBuffers() {} virtual void SwapBuffers() {}
virtual int GetScreenCount() { return 1; }
virtual void DrawOnScreen(int s = 0) {}
PD::fvec2 PositionTranslate(PD::fvec2 in) { PD::fvec2 PositionTranslate(PD::fvec2 in) {
return fvec2(in.x * pViewPort.x, in.y * pViewPort.y); return fvec2(in.x * pViewPort.x, in.y * pViewPort.y);
} }
+2
View File
@@ -13,6 +13,8 @@ class HorizonCtr : public PD::OsCtx {
bool Mainloop() override; bool Mainloop() override;
void ClearViewPort() override; void ClearViewPort() override;
void SwapBuffers() override; void SwapBuffers() override;
int GetScreenCount() override { return 2; }
void DrawOnScreen(int s) override;
private: private:
struct Impl; struct Impl;
+160 -9
View File
@@ -1,7 +1,9 @@
#include <future>
#include <os/desktopos.hpp> #include <os/desktopos.hpp>
#include <os/horizon-ctr.hpp> #include <os/horizon-ctr.hpp>
#include <os/horizon-nx.hpp> #include <os/horizon-nx.hpp>
#include <palladium> #include <palladium>
#include <thread>
//// ////
#include <pd/ultra/elems/button.hpp> #include <pd/ultra/elems/button.hpp>
@@ -57,6 +59,30 @@ std::string Key2String(PD::Hid::Gamepad gp) {
if (gp & PD::Hid::Gamepad::DRight) { if (gp & PD::Hid::Gamepad::DRight) {
res += "DRight"; res += "DRight";
} }
if (gp & PD::Hid::Gamepad::CPDown) {
res += "CPDown";
}
if (gp & PD::Hid::Gamepad::CPUp) {
res += "CPUp";
}
if (gp & PD::Hid::Gamepad::CPLeft) {
res += "CPLeft";
}
if (gp & PD::Hid::Gamepad::CPRight) {
res += "CPRight";
}
if (gp & PD::Hid::Gamepad::CSDown) {
res += "CSDown";
}
if (gp & PD::Hid::Gamepad::CSUp) {
res += "CSUp";
}
if (gp & PD::Hid::Gamepad::CSLeft) {
res += "CSLeft";
}
if (gp & PD::Hid::Gamepad::CSRight) {
res += "CSRight";
}
if (gp & PD::Hid::Gamepad::L) { if (gp & PD::Hid::Gamepad::L) {
res += "L"; res += "L";
} }
@@ -95,7 +121,7 @@ class MainMenu : public PD::Ultra::Layout {
Push(pBackground); Push(pBackground);
pText.SetColor("#ffffff"); pText.SetColor("#ffffff");
pText.SetText("MousePos: "); pText.SetText("MousePos: ");
pText.SetAlignment(UltraAlignment_TopLeft); pText.SetAlignment(UltraAlignment_TopRight);
Push(pText); Push(pText);
pBtn.SetText("Test"); pBtn.SetText("Test");
pBtn.SetAlignment(UltraAlignment_Center); pBtn.SetAlignment(UltraAlignment_Center);
@@ -133,9 +159,22 @@ class App {
MainMenu main; MainMenu main;
}; };
struct Cursor {
PD::fvec2 pPos = 0;
std::string name;
PD::Color pColor = 0xffff00ff;
void Render(PD::Li::Drawlist& l) {
l.DrawCircleFilled(pPos, 32.f, pColor, 15);
}
};
int main(int argc, char** argv) { int main(int argc, char** argv) {
// PD::LogFilter(PD::LogLevel::Warning); // PD::LogFilter(PD::LogLevel::Warning);
#ifdef __APPLE__
Driver drv = Driver::OpenGL2; // default gl2
#else
Driver drv = Driver::OpenGL3; Driver drv = Driver::OpenGL3;
#endif
if (argc == 2) { if (argc == 2) {
if (std::string(argv[1]) == "gl2") { if (std::string(argv[1]) == "gl2") {
drv = Driver::OpenGL2; drv = Driver::OpenGL2;
@@ -158,21 +197,60 @@ int main(int argc, char** argv) {
PD::Image img(ResourcePath("icon.png")); PD::Image img(ResourcePath("icon.png"));
auto pTex = PD::Gfx::LoadTexture(img, img.Width(), img.Height()); auto pTex = PD::Gfx::LoadTexture(img, img.Width(), img.Height());
PD::Li::Font font; PD::Li::Font font;
font.LoadTTF(ResourcePath("default.ttf"), 64); PD::Li::Font debug_font;
font.LoadTTF(ResourcePath("default.ttf"), 32, LiFontFlags_SDF);
debug_font.LoadTTF(ResourcePath("JetBrainsMono-Medium.ttf"), 32,
LiFontFlags_SDF | LiFontFlags_Monospace);
pList.SetFont(&font); pList.SetFont(&font);
App app(font); App app(font);
Cursor LeftStick;
Cursor RightStick;
RightStick.pColor = "#00ffff";
PD::UI7::Context ui7;
ui7.GetIO().Font = &font;
#ifdef __3DS__
ui7.AddViewPort("Default", PD::ivec4(0, 0, 320, 240));
ui7.GetIO().FontScale = 0.5f;
#else
ui7.AddViewPort("Default", PD::ivec4(0, 0, 1280, 720));
#endif
ui7.UseViewPort("Default");
bool pMetricsWin = true;
while (pOs->Mainloop()) { while (pOs->Mainloop()) {
PD::Hid::Update(); PD::TT::End("OSCTX::MainLoop");
pOs->DrawOnScreen(0);
pOs->ClearViewPort(); pOs->ClearViewPort();
PD::Li::ResetPools(); // Move to other place (or refactor this) PD::TT::Scope __st("MainLoop");
app.Update(pOs->GetViewport(), pList); PD::TT::Beg("MainRaw");
pList.DrawText( PD::Hid::Update();
PD::Gfx::NewFrame();
PD::Li::ResetPools();
// app.Update(pOs->GetViewport(), pList);
pList.SetFontscale(0.7);
if (PD::Hid::IsEvent(PD::Hid::Event::Down, PD::Hid::Gamepad::CPLeft |
PD::Hid::Gamepad::CPRight)) {
LeftStick.pPos.x += PD::Hid::GetLeftStick().x * 15;
}
if (PD::Hid::IsEvent(PD::Hid::Event::Down,
PD::Hid::Gamepad::CPUp | PD::Hid::Gamepad::CPDown)) {
LeftStick.pPos.y += PD::Hid::GetLeftStick().y * 15;
}
if (PD::Hid::IsEvent(PD::Hid::Event::Down, PD::Hid::Gamepad::CSLeft |
PD::Hid::Gamepad::CSRight)) {
RightStick.pPos.x += PD::Hid::GetRightStick().x * 15;
}
if (PD::Hid::IsEvent(PD::Hid::Event::Down,
PD::Hid::Gamepad::CSUp | PD::Hid::Gamepad::CSDown)) {
RightStick.pPos.y += PD::Hid::GetRightStick().y * 15;
}
/*pList.DrawText(
PD::fvec2(5, 37), PD::fvec2(5, 37),
std::format( std::format(
"Input:\n Driver: {}\n Gamepad: {}\n {}\n {}\n " "Input:\n Driver: {}\n Gamepad: {}\n {}\n {}\n "
"{}\n {}\n {}\n {}\n {}\n {}\n {}\n {}\n " "{}\n {}\n {}\n {}\n {}\n {}\n {}\n {}\n "
"{}\n {}\n {}\n {}\n {}\n {}\n {}\n {}\n "
"{}\n {}\n " "{}\n {}\n "
"{}\n {}\n", "{}\n {}\n LS: [{}]\n RS: [{}]\nLSP: {}",
PD::Hid::GetDriverName(), PD::Hid::GetDriverName(),
bool(PD::Hid::GetFlags() & PDHidBackendFlags_HasGamepad), bool(PD::Hid::GetFlags() & PDHidBackendFlags_HasGamepad),
ComboGpOut(PD::Hid::Gamepad::Start), ComboGpOut(PD::Hid::Gamepad::Start),
@@ -184,15 +262,88 @@ int main(int argc, char** argv) {
ComboGpOut(PD::Hid::Gamepad::DLeft), ComboGpOut(PD::Hid::Gamepad::DLeft),
ComboGpOut(PD::Hid::Gamepad::DRight), ComboGpOut(PD::Hid::Gamepad::DRight),
ComboGpOut(PD::Hid::Gamepad::L), ComboGpOut(PD::Hid::Gamepad::R), ComboGpOut(PD::Hid::Gamepad::L), ComboGpOut(PD::Hid::Gamepad::R),
ComboGpOut(PD::Hid::Gamepad::ZL), ComboGpOut(PD::Hid::Gamepad::ZR)) ComboGpOut(PD::Hid::Gamepad::ZL), ComboGpOut(PD::Hid::Gamepad::ZR),
ComboGpOut(PD::Hid::Gamepad::CPLeft),
ComboGpOut(PD::Hid::Gamepad::CPRight),
ComboGpOut(PD::Hid::Gamepad::CPUp),
ComboGpOut(PD::Hid::Gamepad::CPDown),
ComboGpOut(PD::Hid::Gamepad::CSLeft),
ComboGpOut(PD::Hid::Gamepad::CSRight),
ComboGpOut(PD::Hid::Gamepad::CSUp),
ComboGpOut(PD::Hid::Gamepad::CSDown), PD::Hid::GetLeftStick(),
PD::Hid::GetRightStick(), LeftStick.pPos)
.c_str(), .c_str(),
"#ffffff"); "#ffffff");*/
// LeftStick.Render(pList);
// RightStick.Render(pList);
pList.UnbindTexture();
// pList.PathRect(50, PD::fvec2(450, 240));
/*pList.PathFillGradient("#ff0000", "#990000", PD::Radians(135));
pList.PathAdd(PD::fvec2(100, 120));
pList.PathAdd(PD::fvec2(250, 260));
pList.PathAdd(PD::fvec2(420, 180));
pList.PathAdd(PD::fvec2(600, 320));
pList.PathAdd(PD::fvec2(820, 220));
pList.PathAdd(PD::fvec2(1000, 360));
pList.PathStroke("#ff00ff", 10, LiDrawFlags_AA);*/
pList.SetFontscale(std::sin(PD::Os::GetTime() * 0.001f) * 1.85f + 2.15f);
pList.DrawText(PD::fvec2(5, 130), "Some text...", "#fff00fff");
#ifdef __3DS__
pList.SetFontscale(0.4);
#else
pList.SetFontscale(0.6f);
#endif
pList.SetFont(&debug_font);
int __i = 0;
for (auto& it : PD::TT::GetTraceMap()) {
pList.DrawText(
PD::fvec2(2, 2 + (__i++) * 17),
std::format("{}: {}", it.second.GetID(),
PD::Strings::FormatNanos(it.second.GetLastDiff()))
.c_str(),
"#ff00ff");
}
pList.SetFont(&font);
PD::TT::Beg("BuildUI7Menus");
if (auto m = ui7.BeginMenu("Test")) {
m->Label("Hello World!");
m->Image(pTex, 128.f);
ui7.EndMenu();
}
if (auto m = ui7.BeginMenu("LI DBG INFO")) {
m->PushFont(&debug_font);
m->Label("Gfx Driver: {}", PD::Gfx::GetDriverName());
m->Separator();
m->Label("LI Draw Comamnds: {}", PD::Gfx::GetNumCommands());
m->Label("GFX Draw Calls: {}", PD::Gfx::GetNumDrawcalls());
m->Label("GFX Vertices: {}", PD::Gfx::GetNumVertices());
m->Label("GFX Triangles: {}", PD::Gfx::GetNumVertices() / 3);
m->Label("GFX Indices: {}", PD::Gfx::GetNumIndices());
m->PopFont();
ui7.EndMenu();
}
ui7.MetricsMenu(&pMetricsWin);
ui7.StyleEditor();
PD::TT::End("BuildUI7Menus");
PD::TT::Beg("UI7::Context::Update");
ui7.Update();
PD::TT::End("UI7::Context::Update");
PD::Gfx::Reset(); PD::Gfx::Reset();
PD::TT::Beg("PD::Gfx::Draw");
pOs->DrawOnScreen(1);
pOs->ClearViewPort();
PD::Gfx::Draw(ui7.GetDrawData());
pOs->DrawOnScreen(0);
PD::Gfx::Draw(pList); PD::Gfx::Draw(pList);
PD::TT::End("PD::Gfx::Draw");
pList.Clear(); pList.Clear();
PD::TT::End("MainRaw");
pOs->SwapBuffers(); pOs->SwapBuffers();
PD::TT::Beg("OSCTX::MainLoop");
} }
font.Delete(); font.Delete();
debug_font.Delete();
PD::Gfx::DeleteTexture(pTex); PD::Gfx::DeleteTexture(pTex);
PD::Gfx::Deinit(); PD::Gfx::Deinit();
pOs->Deinit(); pOs->Deinit();
+21 -7
View File
@@ -18,6 +18,7 @@ struct DesktopOS::Impl {
#if WIN32 #if WIN32
IDirect3D9* d3d = nullptr; IDirect3D9* d3d = nullptr;
IDirect3DDevice9* dx9_device = nullptr; IDirect3DDevice9* dx9_device = nullptr;
D3DPRESENT_PARAMETERS d3dpp = {};
#endif #endif
}; };
@@ -56,14 +57,18 @@ void DesktopOS::Init() {
if (pDriver == Driver::DirectX9) { if (pDriver == Driver::DirectX9) {
impl->d3d = Direct3DCreate9(D3D_SDK_VERSION); impl->d3d = Direct3DCreate9(D3D_SDK_VERSION);
auto hwnd = glfwGetWin32Window(impl->win); auto hwnd = glfwGetWin32Window(impl->win);
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = TRUE; impl->d3dpp = D3DPRESENT_PARAMETERS{};
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; impl->d3dpp.Windowed = TRUE;
d3dpp.hDeviceWindow = hwnd; impl->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
impl->d3dpp.hDeviceWindow = hwnd;
impl->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
impl->d3dpp.EnableAutoDepthStencil = TRUE;
impl->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
HRESULT hr = impl->d3d->CreateDevice( HRESULT hr = impl->d3d->CreateDevice(
D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &impl->dx9_device); D3DCREATE_HARDWARE_VERTEXPROCESSING, &impl->d3dpp, &impl->dx9_device);
if (FAILED(hr)) { if (FAILED(hr)) {
MessageBoxW(nullptr, L"Failed to create D3D9 device", L"Error", MB_OK); MessageBoxW(nullptr, L"Failed to create D3D9 device", L"Error", MB_OK);
std::abort(); std::abort();
@@ -97,7 +102,15 @@ void DesktopOS::ClearViewPort() {
glViewport(0, 0, pViewPort.x, pViewPort.y); glViewport(0, 0, pViewPort.x, pViewPort.y);
} else if (pDriver == Driver::DirectX9) { } else if (pDriver == Driver::DirectX9) {
#ifdef _WIN32 #ifdef _WIN32
if (impl->dx9_device) { // Resize the swapchain to match the window size
if (impl->dx9_device && pViewPort.x > 0 && pViewPort.y > 0) {
if (impl->d3dpp.BackBufferWidth != (UINT)pViewPort.x ||
impl->d3dpp.BackBufferHeight != (UINT)pViewPort.y) {
impl->d3dpp.BackBufferWidth = pViewPort.x;
impl->d3dpp.BackBufferHeight = pViewPort.y;
impl->dx9_device->Reset(&impl->d3dpp);
}
impl->dx9_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, impl->dx9_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(25, 25, 25), 1.0f, 0); D3DCOLOR_XRGB(25, 25, 25), 1.0f, 0);
impl->dx9_device->BeginScene(); impl->dx9_device->BeginScene();
@@ -109,7 +122,8 @@ void DesktopOS::ClearViewPort() {
void DesktopOS::SwapBuffers() { void DesktopOS::SwapBuffers() {
if (pDriver == Driver::DirectX9) { if (pDriver == Driver::DirectX9) {
#ifdef _WIN32 #ifdef _WIN32
if (impl->dx9_device) { // yes we schould use some safetey checks
if (impl->dx9_device && pViewPort.x > 0 && pViewPort.y > 0) {
impl->dx9_device->EndScene(); impl->dx9_device->EndScene();
impl->dx9_device->Present(nullptr, nullptr, nullptr, nullptr); impl->dx9_device->Present(nullptr, nullptr, nullptr, nullptr);
} }
+19 -6
View File
@@ -16,6 +16,7 @@ struct HorizonCtr::Impl {
C3D_RenderTarget* Top = nullptr; C3D_RenderTarget* Top = nullptr;
C3D_RenderTarget* Bottom = nullptr; C3D_RenderTarget* Bottom = nullptr;
uint32_t* pSocBuf = nullptr; uint32_t* pSocBuf = nullptr;
int CurrentScreen = 0;
}; };
void HorizonCtr::Init() { void HorizonCtr::Init() {
@@ -31,8 +32,9 @@ void HorizonCtr::Init() {
} }
link3dsStdio(); link3dsStdio();
romfsInit(); romfsInit();
osSetSpeedupEnable(true);
gfxInitDefault(); gfxInitDefault();
consoleInit(GFX_BOTTOM, nullptr); // consoleInit(GFX_BOTTOM, nullptr);
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
impl->Top = impl->Top =
C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
@@ -42,7 +44,7 @@ void HorizonCtr::Init() {
C3D_RenderTargetSetOutput(impl->Bottom, GFX_BOTTOM, GFX_LEFT, C3D_RenderTargetSetOutput(impl->Bottom, GFX_BOTTOM, GFX_LEFT,
DisplayTransferFlags); DisplayTransferFlags);
PD::Gfx::UseDriver<PD::GfxCitro3D>(); PD::Gfx::UseDriver<PD::GfxCitro3D>();
PD::Hid::UseDriver<PD::HidDriver>(); PD::Hid::UseDriver<PD::Hid3DS>();
} }
void HorizonCtr::Deinit() { void HorizonCtr::Deinit() {
@@ -60,16 +62,27 @@ void HorizonCtr::Deinit() {
bool HorizonCtr::Mainloop() { bool HorizonCtr::Mainloop() {
pViewPort = ivec2(400, 240); pViewPort = ivec2(400, 240);
hidScanInput();
bool _kill = hidKeysUp() & KEY_START; bool _kill = hidKeysUp() & KEY_START;
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
impl->CurrentScreen = 0;
return aptMainLoop() && !_kill; return aptMainLoop() && !_kill;
} }
void HorizonCtr::ClearViewPort() { void HorizonCtr::ClearViewPort() {
PD::Gfx::SetViewPort(pViewPort); C3D_RenderTargetClear(impl->CurrentScreen ? impl->Bottom : impl->Top,
C3D_FrameBegin(C3D_FRAME_SYNCDRAW); C3D_CLEAR_ALL, PD::Color(25, 25, 25, 25), 0);
}
void HorizonCtr::DrawOnScreen(int s) {
impl->CurrentScreen = s;
if (s == 0) {
C3D_FrameDrawOn(impl->Top); C3D_FrameDrawOn(impl->Top);
C3D_RenderTargetClear(impl->Top, C3D_CLEAR_ALL, PD::Color(25, 25, 25, 25), 0); pViewPort = PD::ivec2(400, 240);
} else if (s == 1) {
C3D_FrameDrawOn(impl->Bottom);
pViewPort = PD::ivec2(320, 240);
}
PD::Gfx::SetViewPort(pViewPort);
} }
void HorizonCtr::SwapBuffers() { C3D_FrameEnd(0); } void HorizonCtr::SwapBuffers() { C3D_FrameEnd(0); }
+5 -1
View File
@@ -6,13 +6,17 @@ layout(location = 1) in vec4 oColor;
uniform sampler2D tex; uniform sampler2D tex;
layout(push_constant) uniform PushData { layout(push_constant) uniform PushData {
int alfa; int alfa;
int is_sdf;
} push; } push;
out vec4 FragColor; out vec4 FragColor;
void main() { void main() {
vec4 tc = texture(tex, oUV); vec4 tc = texture(tex, oUV);
if (push.alfa != 0) { if(push.is_sdf != 0) {
float alpha = smoothstep(0.45, 0.55, tc.a);
FragColor = vec4(oColor.rgb, alpha * oColor.a);
} else if (push.alfa != 0) {
FragColor = vec4(oColor.rgb, tc.a * oColor.a); FragColor = vec4(oColor.rgb, tc.a * oColor.a);
} else { } else {
FragColor = tc * oColor; FragColor = tc * oColor;