84 Commits
Author SHA1 Message Date
tobid7 15667c17de reset layers and give menus a base layer to gather perfect ordered rendering 2026-09-06 16:13:41 +02:00
tobid7 23cb94267a Add FontStack to UI7 and uncomment layer lines 2026-09-06 16:13:41 +02:00
tobid7 763d947413 move and fix scrolling to layout
Scrolling was hardcoded to 3ds sCrEeNhEiGhT wTh
2026-09-06 16:13:40 +02:00
tobid7 e6a9604c55 Layers are back 2026-09-06 16:13:40 +02:00
tobid7 619b4d4e93 hotfix 2026-09-06 16:13:39 +02:00
tobid7 597488717f Add Hid3DS 2026-09-06 16:13:39 +02:00
tobid7 5d8ce7f56f 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-06 16:13:38 +02:00
tobid7 8cd292bcc3 Add Drawlist Vertex and Indexcount geteter (for debugging usage only) 2026-09-06 16:13:38 +02:00
tobid7 9ef52bcd05 Fix The rest of UI7 Mem leaks
Throw OneFrame living objs into a pool
2026-09-06 16:13:37 +02:00
tobid7 e8bc35b2fb stop leaking idobj memory (and coloredit layout mem) 2026-09-06 16:13:37 +02:00
tobid7 fa20c743d0 dx9: update device size on window size change 2026-09-06 16:13:36 +02:00
tobid7 79e7682e2d format documents 2026-09-06 16:13:36 +02:00
tobid7 3fd005e8a6 unload debugfont and add Gfx debug menu 2026-09-06 16:13:35 +02:00
tobid7 fa4d32fa5e fix random garbage ptr issues 2026-09-06 16:13:34 +02:00
tobid7 6521bdc711 Fix Indexorder issues and patchfixsomehow dx9 tex filtering 2026-09-06 16:13:34 +02:00
tobid7 457460e7a8 No big update without msvc compiler errors :/ 2026-09-06 16:13:33 +02:00
tobid7 a04efd602a More timings 2026-09-06 16:13:33 +02:00
tobid7 d7188aa140 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-06 16:13:32 +02:00
tobid7 a958222c29 Add missing GetDriverName to Os 2026-09-06 16:13:32 +02:00
tobid7 391221a6a6 Draw the line (oder so) 2026-09-06 16:13:31 +02:00
tobid7 fb04d5ec79 Load the font async for now 2026-09-06 16:13:31 +02:00
tobid7 89e98bbcc2 n3ds-boost 2026-09-06 16:13:30 +02:00
tobid7 83e06e013f SDF & MONOSPACE FONT RENDERING 2026-09-06 16:13:30 +02:00
tobid7 70e5f8859a save 75% of font memory 2026-09-06 16:13:29 +02:00
tobid7 b1cf3840af Upload pools once per Gfx::Draw and FIX DX9 2026-09-06 16:13:29 +02:00
tobid7 ccb5191551 reset pools on newframe 2026-09-06 16:13:28 +02:00
tobid7 affad4febd move global pools into gfx driver
prevents double copy problems
saves memory
(needs to be optimized...)
2026-09-06 16:13:28 +02:00
tobid7 839af66858 faster rect command creation 2026-09-06 16:13:27 +02:00
tobid7 847259cb48 cache ascii chars directly 2026-09-06 16:13:26 +02:00
tobid7 fa7812a51b insane performance boost (on 3ds) 2026-09-06 16:13:26 +02:00
tobid7 e05c915c36 time trace is back 2026-09-06 16:13:25 +02:00
tobid7 2423784ec7 implement Image::Convert and Image::Flip 2026-09-06 16:13:25 +02:00
tobid7 4ee10208c7 pool append move and copy 2026-09-06 16:13:24 +02:00
tobid7 03418f38d5 # small fixes
- Fix Os::GetTimeNano()
- only build tests on non vendored usage
2026-09-06 16:13:24 +02:00
tobid7 8a7a1d7fe8 Fix 2026-09-06 16:13:23 +02:00
tobid7 3d385583f2 Fix 3ds build and update libpicasso 2026-09-06 16:13:23 +02:00
tobid7 4c15f91e88 remove poc func 2026-09-06 16:13:22 +02:00
tobid7 da4baf8fbd Add support for rotated gradients 2026-09-06 16:13:22 +02:00
tobid7 eda4213ffc Add stick and trigger input support 2026-09-06 16:13:21 +02:00
tobid7 9535ec06c0 Fix clang warning 2026-09-06 16:13:21 +02:00
tobid7 979a043034 fix preset names for Selection Views 2026-09-06 16:13:20 +02:00
tobid7 6116f97bba Add NX Hid Driver Template
- Add WIP HidNX Driver (clangd not working with devkitpro for switch on windows)
- Add default-release as default search path for compile_commands.json
- remove mingw preset (casue its exactly the default target)
- Move Mouse pos cycle into HidDriver::Update
- Test around with HidGlfw on Nintendo switch
2026-09-06 16:13:20 +02:00
tobid7 8ac08b15d4 Add proper Gamepad support (WIP) 2026-09-06 16:13:19 +02:00
tobid7 429514ce8b allo wPD::Color in Drawlist 2026-09-06 16:13:19 +02:00
tobid7 69936b1cf0 Add Input functionality to Ultra
- Add point InSpace check to PD::Li::Math
- Add Universal AlignmentCenter flag for Horizontal and and Vertical Alignment
-  Add Fallbackfont to Layout (if you dont want to set font per object)
- Add Button Object WIP
- Rename OnHover to OnFocus and add OnUnfocus
- Move font and FontScale to ElementBase (for fallback logic etc)
- Add UpdateInput func to ElementBase
- Corectly Set fontScale in Text Rendering
- Update ecample
2026-09-06 16:13:18 +02:00
tobid7 f058dfd0b8 Allow implicit usage of "#ffffffff" etc 2026-09-06 16:13:18 +02:00
tobid7 d43ed70ba3 Add HidDriver base and small HidGLFW driver 2026-09-06 16:13:17 +02:00
tobid7 5db9bae9f8 rename PDBackendFlags to PDGfxBackendFlags 2026-09-06 16:13:17 +02:00
tobid7 82d5fa6ae3 Implement VCanvas and Update TextElem
- Text now requires a font and is able to take an individual scale
- Container requires &ref for Elements to make sure they always exist
- SetViewport now sets the canvas as well
- SetBaseViewport Sets the Virtual Canvas Size
- Layout Now requires a Drawlist reference in Render function
- main.cpp: updated the template
2026-09-06 16:13:16 +02:00
tobid7 3805e08b31 Actually implement ultra-rendering 2026-09-06 16:13:16 +02:00
tobid7 350cb752af Rework Project Ultra
- Added container
- Made container the base of Layout
- Set Containers theirself as pParent for Elements on Push
2026-09-06 16:13:15 +02:00
tobid7 23817f1c85 Fix path rects 2026-09-06 16:13:15 +02:00
tobid7 2b6171a7a2 Fixing riunded rects 2026-09-06 16:13:14 +02:00
tobid7 95530e987d Add a default preset (for linux/macos default builds) 2026-09-06 16:13:14 +02:00
tobid7 1ea5ad5e0f Add cmake presets
- MSVC requires cmake for Windows
- mingw only builds when GLSLANG is excluded due to wrong header generation
2026-09-06 16:13:13 +02:00
tobid7 60fcb4f80d build 3dsx and nro in ALL stage 2026-09-06 16:13:12 +02:00
tobid7 6c1c59014e More stuff done at Project Ultra
- Added renderspace
- Revision System (to not always update pRenderspace
- added some test scene
2026-09-06 16:13:12 +02:00
tobid7 d8b19e3993 WIP (Codename Ultra) UI lib 2026-09-06 16:13:11 +02:00
tobid7 17e000a02c implement font deletion 2026-09-06 16:13:11 +02:00
tobid7 8ebee69338 Fix font bugs 2026-09-06 16:13:10 +02:00
tobid7 283583c333 Add debug getters (and somehow text is not rendering :/) 2026-09-06 16:13:10 +02:00
tobid7 a96bb1e874 Fix Vertex Alloc usage at Index Alloc 2026-09-06 16:13:09 +02:00
tobid7 266075fe4b Readd font support (not workign yet) 2026-09-06 16:13:09 +02:00
tobid7 17df854d99 Update lazyvec / vec api as well as rect are mostly constexpr now 2026-09-06 16:13:08 +02:00
tobid7 d5998c317d Always disable glslang build for NintendoSwitch on Windows 2026-09-06 16:13:08 +02:00
tobid7 22d8e74f25 Present DX9 Frames ... 2026-09-06 16:13:07 +02:00
tobid7 bc09667346 Add a PositionTranslate func and add Errors for TextureSize mismatch 2026-09-06 16:13:07 +02:00
tobid7 1b663aa120 Add PD::Image and add a setter for logfilter 2026-09-06 16:13:06 +02:00
tobid7 71a1abed20 Forgot about dx9 (UNTESTED!!!) 2026-09-06 16:13:06 +02:00
tobid7 f02b67043f Add Os Bridge into test framework 2026-09-06 16:13:05 +02:00
tobid7 35ef853c49 Refactor PD::Li Pools system, Upgrade PD::Pool and add better logging
- Add ResetFast to Pool using c++20 concept
- Add Put function to Pool
- Use Pool Index instead of pointers in Command
- Add accessor to Li Pools to prevent wrong command usage
- Add Command Formatter
- Use ResetFast for all Pools
- Add Reset func to Li::Vertex (for ResetFast)
- Add Pool Expandor and Put funcs to Lithium pools
- Add getters for GfxDriverBase to PD::Li Pools
2026-09-06 16:13:05 +02:00
tobid7 0fe3872d08 Add nintendo switch support 2026-09-06 16:13:04 +02:00
tobid7 0d4723bd2b Remove Gfx Driver Vertex and IndexBuffer size config 2026-09-06 16:13:03 +02:00
tobid7 8ece89aa62 Add Drawlist
- Add Pool iterator support
- Add Pool Expandability
- Add Pool::Push
- Add Lithium Maths API
- Remove InitPools
- update spirv-helper
2026-09-06 16:13:03 +02:00
tobid7 d055521c2a Replace spirv-helper stuff with a library that combines everything 2026-09-06 16:13:02 +02:00
tobid7 3fa061e58e Add the shaders 2026-09-06 16:13:02 +02:00
tobid7 842ac99e2a Add pdsg (palladium spirv-generator)
- remove glslang from pd-system
- use spirv blobs instead of glsl 460
- Use Legacy shaders for OpenGL2 backend
- add devnotes
2026-09-06 16:13:01 +02:00
tobid7 d0f780381b Add SpirvHelper (Shader cross compilation)
- Make OpenGL2 and OpenGL3 use the same base shaders (using SpirvHelper)
- Add Transpose func to Mat4
2026-09-06 16:13:01 +02:00
tobid7 290fece35a Add missing sources 2026-09-06 16:13:00 +02:00
tobid7 b6ba5eb64e Full 3ds support and fix dx9 2026-09-06 16:13:00 +02:00
tobid7 0f7223ff18 Work at 3ds support and backend upgrades
- Track textures (not sure if this is done tbh)
- Add lithium formatters and move TextureID, TextureFormat and TextureFilter to lithium
- Only include gl-helper if any glDriver is included
- Add Li::Rect for UV stuff
- Add Li::Texture as Info holder (still thinking of making them to ptrs
- Add Check if textures are still loaded on exit
2026-09-06 16:12:59 +02:00
tobid7 9359167a8e Add backends
- Renamed GfxOpenGL to GfxOPenGL2
- Added GfxOpenGL3 backend for OpenGL 3.3+
- Added WIP DirectX9 backend
- Added structure for Citro3D
- Added linear Allocator
2026-09-06 16:12:59 +02:00
tobid7 1681ec458a More work to drivers
- Add gfx_test
- add texture loading to GfxOpenGL
- add full submit code
- add debug logging
- add construct and destroy functionality to Pool
- add command functionality
- add vertex and index pools to lithium (static and not threadsafe yet)
- Update GfxDriver Matrix with SetViewPort
- Add glfw (only dependency of gfx_test) maybe later required for input driver
2026-09-06 16:12:58 +02:00
tobid7 5ec73d20c3 - Update pool to use template allocator directly instead of std::vector
- Add a GfxDriver config Template to be able to modify settings like allocators / Types for specific Drivers
- Add glad
2026-09-06 16:12:57 +02:00
162 changed files with 35677 additions and 197 deletions
+6
View File
@@ -0,0 +1,6 @@
CompileFlags:
CompilationDatabase: build/default-release
Add: []
Completion:
HeaderInsertion: Never
+1 -2
View File
@@ -1,2 +1 @@
include/pd/external/* linguist-vendored
backends/desktop/glad/* linguist-vendored
vendor/* linguist-vendored
+1
View File
@@ -1,3 +1,4 @@
build*/
.cache
.vscode
.DS_Store
+9
View File
@@ -1,3 +1,12 @@
[submodule "vendor/stb"]
path = vendor/stb
url = https://github.com/nothings/stb.git
[submodule "vendor/glfw"]
path = vendor/glfw
url = https://github.com/glfw/glfw.git
[submodule "vendor/libpicasso"]
path = vendor/libpicasso
url = https://github.com/tobid7/libpicasso
[submodule "vendor/spirv-helper"]
path = vendor/spirv-helper
url = https://github.com/tobid7/spirv-helper.git
+98 -13
View File
@@ -12,30 +12,98 @@ include(cmake/palladium.cmake)
option(PD_BUILD_TESTS "Sets if TestApp and TestBench get build" OFF)
option(PD_BUILD_SHARED "Build Shared Library" OFF)
option(PD_BUILD_TOOLS "Build Palladium Tools" OFF)
option(PD_INCLUDE_STB_IMAGE "Inlude stb image symbols in palladium" ON)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
add_compile_options(-Wno-psabi)
endif()
if(${PD_BUILD_TOOLS})
add_subdirectory(tools)
endif()
add_subdirectory(vendor)
# # Include Library Source
set(PD_SOURCES
# Common
source/common.cpp
# Core
source/core/bits.cpp
source/core/color.cpp
source/core/io.cpp
source/core/mat.cpp
source/core/strings.cpp
source/core/timer.cpp
source/core/timetrace.cpp
# Image
source/image/convert.cpp
source/image/image.cpp
# Drivers
source/drivers/os.cpp
source/drivers/gfx.cpp
source/drivers/hid.cpp
# Lithium
source/lithium/command.cpp
source/lithium/drawlist.cpp
source/lithium/font.cpp
source/lithium/math.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
source/ultra/canvas.cpp
source/ultra/layout.cpp
source/ultra/elems/element.cpp
source/ultra/elems/rect.cpp
source/ultra/elems/text.cpp
source/ultra/elems/image.cpp
source/ultra/elems/button.cpp
)
if(${PD_BUILD_SHARED})
add_library(palladium SHARED ${PD_SOURCES})
target_compile_definitions(palladium PRIVATE -DPD_BUILD_SHARED)
target_compile_definitions(palladium PRIVATE PD_BUILD_SHARED)
else()
add_library(palladium STATIC ${PD_SOURCES})
target_compile_definitions(palladium PUBLIC -DPD_BUILD_STATIC)
target_compile_definitions(palladium PUBLIC PD_BUILD_STATIC)
endif()
target_link_libraries(palladium
PUBLIC stb
)
target_compile_definitions(palladium
PUBLIC
PD_DEBUG
$<$<OR:$<BOOL:${PD_INCLUDE_STB_IMAGE}>,$<BOOL:${PD_BUILD_SHARED}>>:PD_INCLUDE_STB_IMAGE> # Always on in shared build
)
target_compile_options(palladium
PUBLIC $<$<CXX_COMPILER_ID:GNU,Clang>:
-fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/source=source
-fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/include=include
>
)
add_library(palladium::palladium ALIAS palladium)
target_include_directories(palladium
@@ -44,18 +112,24 @@ target_include_directories(palladium
$<INSTALL_INTERFACE:include>
)
target_compile_options(palladium PRIVATE
$<$<CONFIG:Debug>:-O0 -g>
$<$<CONFIG:Release>:-O3>
target_compile_options(palladium
PRIVATE
$<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:GNU,Clang>>:-O0 -g>
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:GNU,Clang>>:-O3>
$<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:MSVC>>:/Od /Zi>
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:MSVC>>:/O2>
)
install(TARGETS palladium
install(
TARGETS palladium
EXPORT palladiumTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(DIRECTORY include/
install(
DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(EXPORT palladiumTargets
@@ -68,27 +142,35 @@ include(CMakePackageConfigHelpers)
configure_package_config_file(
cmake/palladiumConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/palladiumConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/palladium
INSTALL_DESTINATION
${CMAKE_INSTALL_LIBDIR}/cmake/palladium
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/palladiumConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
VERSION
${PROJECT_VERSION}
COMPATIBILITY
SameMajorVersion
)
install(FILES
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/palladiumConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/palladiumConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/palladium
)
find_program(CLANG_FORMAT clang-format)
file(GLOB_RECURSE PD_FMTFILES CONFIGURE_DEPENDS
file(GLOB_RECURSE PD_FMTFILES
CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp
${CMAKE_CURRENT_SOURCE_DIR}/backends/source/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/backends/include/*.hpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/core/source/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/gfx/source/*.cpp
)
add_custom_target(pd-clang-format
@@ -96,4 +178,7 @@ add_custom_target(pd-clang-format
COMMENT "Formatting Project Sources"
)
add_subdirectory(backends)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
endif()
+14
View File
@@ -0,0 +1,14 @@
{
"version": 10,
"cmakeMinimumRequired": {
"major": 3,
"minor": 22,
"patch": 0
},
"include": [
"cmake/presets/default.json",
"cmake/presets/3ds.json",
"cmake/presets/switch.json",
"cmake/presets/msvc.json"
]
}
+90
View File
@@ -0,0 +1,90 @@
cmake_minimum_required(VERSION 3.22)
project(pd-system)
option(PD_ENABLE_OPENGL2 "Enable OpenGL 2.1 (On Supported Hardware)" ON)
option(PD_ENABLE_OPENGL3 "Enable OpenGL 3.3 (On Supported Hardware)" ON)
option(PD_ENABLE_DIRECTX9 "Enable DirectX9 Support" ON)
option(PD_ENABLE_CITRO3D "Enable Citro3D Support (3DS)" OFF)
option(PD_ENABLE_VULKAN "Not implemented yet" OFF)
option(PD_ENABLE_HID_GLFW "Enable GLFW Input Driver" ON)
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...
set(PD_ENABLE_DIRECTX9 OFF)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Nintendo3DS")
set(PD_ENABLE_OPENGL2 OFF)
set(PD_ENABLE_OPENGL3 OFF)
set(PD_ENABLE_VULKAN OFF)
set(PD_ENABLE_CITRO3D ON)
set(PD_ENABLE_HID_GLFW OFF)
set(PD_ENABLE_HID_NX OFF)
set(PD_ENABLE_HID3DS ON)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "NintendoSwitch")
set(PD_ENABLE_OPENGL2 OFF)
set(PD_ENABLE_OPENGL3 ON)
set(PD_ENABLE_VULKAN OFF)
set(PD_ENABLE_CITRO3D OFF)
set(PD_ENABLE_HID_NX ON) # Best case for Nintendo Switch
set(PD_ENABLE_HID_GLFW ON) # Technically supported but not recommended
endif()
add_library(pd-system STATIC
${CMAKE_CURRENT_SOURCE_DIR}/source/gl-helper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_opengl2.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_opengl3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_directx9.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_nx.cpp
)
target_include_directories(pd-system
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
# Why is this not a default include (same problem as with the __SWITCH__ define)
$<$<STREQUAL:${CMAKE_SYSTEM_NAME},NintendoSwitch>:${DEVKITPRO}/portlibs/switch/include>
)
target_compile_options(palladium
PUBLIC $<$<CXX_COMPILER_ID:GNU,Clang>:
-fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/source=source
-fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/include=include
>
)
target_compile_definitions(pd-system
PUBLIC
$<$<BOOL:${PD_ENABLE_OPENGL2}>:PD_ENABLE_OPENGL2>
$<$<BOOL:${PD_ENABLE_OPENGL3}>:PD_ENABLE_OPENGL3>
$<$<BOOL:${PD_ENABLE_VULKAN}>:PD_ENABLE_VULKAN>
$<$<BOOL:${PD_ENABLE_DIRECTX9}>:PD_ENABLE_DIRECTX9>
$<$<BOOL:${PD_ENABLE_CITRO3D}>:PD_ENABLE_CITRO3D>
$<$<BOOL:${PD_ENABLE_HID_GLFW}>:PD_ENABLE_HID_GLFW>
$<$<BOOL:${PD_ENABLE_HID_NX}>:PD_ENABLE_HID_NX>
$<$<BOOL:${PD_ENABLE_HID3DS}>:PD_ENABLE_HID3DS>
)
# Palladium
target_link_libraries(pd-system PUBLIC palladium::palladium)
# Depandant Lib includes (i love this cmake feature)
target_link_libraries(pd-system PUBLIC
$<$<BOOL:${PD_ENABLE_DIRECTX9}>:d3d9 d3dcompiler> # DirectX9
$<$<BOOL:${PD_ENABLE_CITRO3D}>:pica::pica citro3d ctru> # 3ds
$<$<BOOL:${PD_ENABLE_OPENGL3}>:spirv-helper> # OpenGL3
# Include Glad if we have any OpenGL Usage
$<$<OR:$<BOOL:${PD_ENABLE_OPENGL2}>,$<BOOL:${PD_ENABLE_OPENGL3}>>:glad>
$<$<BOOL:${PD_ENABLE_HID_NX}>:nx> # Hid NX requirement
# Hid GLFW requirement
$<$<BOOL:${PD_ENABLE_HID_GLFW}>:
$<$<STREQUAL:${CMAKE_SYSTEM_NAME},NintendoSwitch>:glfw3>
$<$<NOT:$<STREQUAL:${CMAKE_SYSTEM_NAME},NintendoSwitch>>:glfw>>
)
+24
View File
@@ -0,0 +1,24 @@
# Backends
- [Graphics](#graphics)
- [OpenGL2](#opengl2-legacy)
- [OpenGL3](#opengl3-modern-opengl)
- [DirectX9](#directx9-could-potentially-cover-more-then-opengl2)
- [Citro3D](#citro3d-3ds)
## Graphics
### OpenGL2 (Legacy)
> [!NOTE]
> As SPIRV to GLSL 120 translation doesn't work, your'e forced to write separate shaders for this backend
### OpenGL3+ (Modern OpenGL)
### DirectX9 (Could potentially cover more than OpenGL2)
### Citro3D (3DS)
> [!NOTE]
> This backend requires shaders as binary file, directly in the code or as string for libpicasso
> The Fragment Stage is special and is still wip
@@ -0,0 +1,67 @@
#pragma once
#ifdef __3DS__
#include <3ds.h>
#endif
#include <limits>
#include <memory>
#include <stdexcept>
// Custom C++ Allocator class to interface with libctru linear heap memory
// based on this guide:
// https://johnfarrier.com/custom-allocators-in-c-high-performance-memory-management/
namespace PD {
template <typename T>
class LinearAllocator {
public:
using value_type = T;
LinearAllocator() noexcept = default;
template <typename U>
constexpr LinearAllocator(const LinearAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
if (n > max_size()) {
throw std::runtime_error("[PD] LinearAllocator: Bad alloc!");
}
#ifdef __3DS__
return static_cast<T*>(linearAlloc(n * sizeof(T)));
#else
return static_cast<T*>(malloc(n * sizeof(T)));
#endif
}
#ifdef __3DS__
void deallocate(T* p, std::size_t) noexcept { linearFree(p); }
#else
void deallocate(T* p, std::size_t) noexcept { free(p); }
#endif
template <class U, class... Args>
void construct(U* p, Args&&... args) {
::new ((void*)p) U(std::forward<Args>(args)...);
}
template <class U>
void destroy(U* p) {
p->~U();
}
friend bool operator==(const LinearAllocator, const LinearAllocator) {
return true;
}
friend bool operator!=(const LinearAllocator, const LinearAllocator) {
return false;
}
#ifdef __3DS__
// Use linearSpace free as max_size to not allocate out of bounds
// or to b eable to see a crash report screen.
size_t max_size() const noexcept { return linearSpaceFree(); }
#else
size_t max_size() const noexcept {
return std::numeric_limits<size_t>::max();
}
#endif
};
} // namespace PD
@@ -0,0 +1,37 @@
#pragma once
#include <pd/drivers/gfx.hpp>
#include <pd_system/ctr-linear-allocator.hpp>
namespace PD {
struct GfxCitro3DConfig {
// Vertex Allocator
template <typename T>
using VertexAlloc = LinearAllocator<T>;
// Index Allocator
template <typename T>
using IndexAlloc = LinearAllocator<T>;
};
class GfxCitro3D : public GfxDriverBase<GfxCitro3DConfig> {
public:
GfxCitro3D() : GfxDriverBase("Citro3D") {}
~GfxCitro3D() {}
void SysInit() override;
void SysDeinit() override;
void Submit(size_t count, size_t start) override;
void BindTexture(TextureID id) override;
void SysReset() override;
Li::Texture LoadTexture(
const std::vector<PD::u8>& pixels, int w, int h,
TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
private:
struct Impl;
Impl* impl = nullptr;
};
} // namespace PD
@@ -0,0 +1,38 @@
#pragma once
#include <pd/drivers/gfx.hpp>
namespace PD {
struct GfxDirectX9Config {
// Vertex Allocator
template <typename T>
using VertexAlloc = std::allocator<T>;
// Index Allocator
template <typename T>
using IndexAlloc = std::allocator<T>;
};
class GfxDirectX9 : public GfxDriverBase<GfxDirectX9Config> {
public:
GfxDirectX9(void* device = nullptr)
: GfxDriverBase("DirectX9"), pDevice(device) {}
~GfxDirectX9() {}
void SysInit() override;
void SysDeinit() override;
void Submit(size_t count, size_t start) override;
void BindTexture(TextureID id) override;
void SysReset() override;
Li::Texture LoadTexture(
const std::vector<PD::u8>& pixels, int w, int h,
TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
private:
struct Impl;
Impl* impl = nullptr;
void* pDevice = nullptr;
};
} // namespace PD
@@ -0,0 +1,44 @@
#pragma once
#include <pd/drivers/gfx.hpp>
namespace PD {
struct GfxOpenGL2Config {
// Vertex Allocator
template <typename T>
using VertexAlloc = std::allocator<T>;
// Index Allocator
template <typename T>
using IndexAlloc = std::allocator<T>;
};
class GfxOpenGL2 : public GfxDriverBase<GfxOpenGL2Config> {
public:
GfxOpenGL2() : GfxDriverBase("OpenGL2") {}
~GfxOpenGL2() {}
void SysInit() override;
void SysDeinit() override;
void Submit(size_t count, size_t start) override;
void BindTexture(TextureID id) override;
void SysReset() override;
Li::Texture LoadTexture(
const std::vector<PD::u8>& pixels, int w, int h,
TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
private:
void pSetupShaderAttribs(u32 shader);
u32 pShader = 0;
u32 VBO = 0;
u32 IBO = 0;
int pLocTex = 0;
int pLocAlfa = 0;
int pLocIsSDF = 0;
int pLocProjection = 0;
static const char* pVertCode;
static const char* pFragCode;
};
} // namespace PD
@@ -0,0 +1,42 @@
#pragma once
#include <pd/drivers/gfx.hpp>
namespace PD {
struct GfxOpenGL3Config {
// Vertex Allocator
template <typename T>
using VertexAlloc = std::allocator<T>;
// Index Allocator
template <typename T>
using IndexAlloc = std::allocator<T>;
};
class GfxOpenGL3 : public GfxDriverBase<GfxOpenGL3Config> {
public:
GfxOpenGL3() : GfxDriverBase("OpenGL3") {}
~GfxOpenGL3() {}
void SysInit() override;
void SysDeinit() override;
void Submit(size_t count, size_t start) override;
void BindTexture(TextureID id) override;
void SysReset() override;
Li::Texture LoadTexture(
const std::vector<PD::u8>& pixels, int w, int h,
TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) override;
void DeleteTexture(const Li::Texture& tex) override;
void UploadPools() override;
private:
u32 pShader = 0;
u32 VBO = 0;
u32 IBO = 0;
u32 VAO = 0;
int pLocTex = 0;
int pLocAlfa = 0;
int pLocIsSDF = 0;
int pLocProjection = 0;
};
} // namespace PD
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <pd/common.hpp>
namespace PD {
u32 CreateShaderProgram(const char* vert, const char* frag);
}
+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
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <pd/drivers/hid.hpp>
typedef struct GLFWwindow GLFWwindow;
typedef struct GLFWgamepadstate GLFWgamepadstate;
namespace PD {
class HidGlfw : public HidDriver {
public:
HidGlfw(GLFWwindow* window);
~HidGlfw();
void Update() override;
private:
void HandleAxisKey(GLFWgamepadstate s, int iK, int eA, bool negative);
struct Impl;
Impl* impl;
};
} // namespace PD
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <pd/drivers/hid.hpp>
namespace PD {
class HidNX : public HidDriver {
public:
HidNX();
~HidNX();
void Update() override;
private:
struct Impl;
Impl* impl;
};
} // namespace PD
+17
View File
@@ -0,0 +1,17 @@
#pragma once
namespace PD {
/**
* Shader blobs
* Required for OpenGL3, and maybe later for vulkan
* Shaders can be found in /tools/pdsg/shaders
*/
namespace Shaders {
// clang-format off
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 off
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
} // namespace Shaders
} // namespace PD
+11
View File
@@ -0,0 +1,11 @@
#pragma once
// Gfx
#include <pd_system/gfx_citro3d.hpp>
#include <pd_system/gfx_directx9.hpp>
#include <pd_system/gfx_opengl2.hpp>
#include <pd_system/gfx_opengl3.hpp>
// Hid
#include <pd_system/hid_3ds.hpp>
#include <pd_system/hid_glfw.hpp>
+287
View File
@@ -0,0 +1,287 @@
// Well yes, i finally try it
#include <pd/core/core.hpp>
#include <pd/lithium/formatters.hpp>
#include <pd_system/gfx_citro3d.hpp>
#if defined(PD_ENABLE_CITRO3D) && defined(__3DS__)
#include <3ds.h>
#include <citro3d.h>
#include <pd/drivers/drivers.hpp>
#include <pica.hpp>
namespace PD {
const char* LIShaderCTR = R"(
; LI7 Shader
; Constants
.constf myconst(0.0, 1.0, 0.00392156862745, 0.0)
.alias ones myconst.yyyy ; Vector full of ones
; Uniforms
.fvec projection[4]
; Outputs
.out out_position position
.out out_color color
.out out_uv texcoord0
; Inputs
.alias in_xy v0
.alias in_uvc v1
.alias in_col v2
.entry vmain
.proc vmain
mov r0.xy, in_xy.xy
mov r0.w, ones
dp4 out_position.x, projection[0], r0
dp4 out_position.y, projection[1], r0
dp4 out_position.z, projection[2], r0
dp4 out_position.w, projection[3], r0
mov out_uv, in_uvc.xy
mul r1, myconst.zzzz, in_col
mov out_color, r1
end
.end
)";
struct GfxCitro3D::Impl {
C3D_AttrInfo pAttr;
shaderProgram_s pShader;
DVLB_s* pCode;
int uLocProjection = 0;
C3D_Tex* CurrentTex = nullptr;
std::vector<u8> pShaderRaw;
GPU_TEXCOLOR TextureTranslateFormat(TextureFormat fmt) {
switch (fmt) {
case PD::TextureFormat::A8:
return GPU_A8;
case PD::TextureFormat::RGB24:
return GPU_RGB8;
case PD::TextureFormat::RGBA32:
return GPU_RGBA8;
default:
return GPU_RGBA8;
}
}
int TextureFormat2Bpp(TextureFormat fmt) {
switch (fmt) {
case PD::TextureFormat::A8:
return 1;
case PD::TextureFormat::RGB24:
return 3;
case PD::TextureFormat::RGBA32:
return 4;
default:
return 0;
}
}
void SetupPixelStage(bool sdf) {
shaderProgramUse(&pShader);
C3D_BindProgram(&pShader);
C3D_SetAttrInfo(&pAttr);
C3D_DepthTest(false, GPU_GREATER, GPU_WRITE_ALL);
if (!CurrentTex) return;
C3D_TexEnv* env = C3D_GetTexEnv(0);
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) {
case GPU_A4:
case GPU_A8:
case GPU_L4:
case GPU_L8:
C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
break;
case GPU_RGB565:
C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE);
break;
default:
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0);
C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
break;
}
}
}
};
void GfxCitro3D::SysInit() {
if (impl) return;
PDLOG("GfxCitro3D::SysInit();");
impl = new Impl();
Flags |= PDGfxBackendFlags_FlipUV_Y;
impl->pShaderRaw = Pica::AssembleCode(LIShaderCTR);
impl->pCode = DVLB_ParseFile((uint32_t*)impl->pShaderRaw.data(),
impl->pShaderRaw.size());
shaderProgramInit(&impl->pShader);
shaderProgramSetVsh(&impl->pShader, &impl->pCode->DVLE[0]);
impl->uLocProjection = shaderInstanceGetUniformLocation(
impl->pShader.vertexShader, "projection");
AttrInfo_Init(&impl->pAttr);
AttrInfo_AddLoader(&impl->pAttr, 0, GPU_FLOAT, 2);
AttrInfo_AddLoader(&impl->pAttr, 1, GPU_FLOAT, 2);
AttrInfo_AddLoader(&impl->pAttr, 2, GPU_UNSIGNED_BYTE, 4);
}
void GfxCitro3D::SysDeinit() {
if (!impl) return;
shaderProgramFree(&impl->pShader);
DVLB_Free(impl->pCode);
delete impl;
impl = nullptr;
PDLOG("GfxCitro3D::SysDeinit()");
}
void GfxCitro3D::Submit(size_t count, size_t start) {
if (!impl) return;
BindTexture(CurrentTex);
impl->SetupPixelStage(CurrentTexIsSDF); // needs to be called after
C3D_Mtx proj;
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,
// (C3D_Mtx*)&Projection);
C3D_DrawElements(GPU_TRIANGLES, count, C3D_UNSIGNED_SHORT,
GetIndexBufPtr(start));
impl->CurrentTex = nullptr;
}
void GfxCitro3D::BindTexture(TextureID id) {
if (!impl || !id) return;
impl->CurrentTex = (C3D_Tex*)id;
C3D_TexBind(0, (C3D_Tex*)id);
}
void GfxCitro3D::SysReset() {
if (!impl) return;
C3D_CullFace(GPU_CULL_NONE);
}
Li::Texture GfxCitro3D::LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, TextureFormat type,
TextureFilter filter) {
if (!impl || w > 1024 || h > 1024) return Li::Texture();
if (pixels.size() !=
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type))) {
PDERR("Failed to load Texture due to Size mismatch: {} != {}",
pixels.size(),
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type)));
return Li::Texture();
}
// Don't check here as check done before
PD::Li::Texture res;
int bpp = impl->TextureFormat2Bpp(type);
ivec2 tex_size(w, h);
// Pow2
if (!PD::Bits::IsSingleBit(w)) {
tex_size.x = PD::Bits::GetPow2((unsigned int)w);
}
if (!PD::Bits::IsSingleBit(h)) {
tex_size.y = PD::Bits::GetPow2((unsigned int)h);
}
res.SetSize(w, h);
res.SetUV(0.f, 1.f, ((float)w / (float)tex_size.x),
1.0 - ((float)h / (float)tex_size.y));
// Texture Setup
auto fltr = (filter == TextureFilter::Linear ? GPU_NEAREST : GPU_LINEAR);
auto tex_fmt = impl->TextureTranslateFormat(type);
auto tex = new C3D_Tex;
C3D_TexInit(tex, (u16)tex_size.x, (u16)tex_size.y, tex_fmt);
C3D_TexSetFilter(tex, fltr, fltr);
std::memset((PD::u8*)tex->data, 0x0, tex->size);
/// Probably Remove this if statement in future
/// This are the things confirmed as working
if (bpp == 3 || bpp == 4 || bpp == 1) {
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int dst_pos = ((((y >> 3) * ((int)tex_size.x >> 3) + (x >> 3)) << 6) +
((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) |
((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))) *
bpp;
int src_pos = (y * w + x) * bpp;
/// Best idea i had
for (int i = 0; i < bpp; i++) {
((u8*)tex->data)[dst_pos + bpp - 1 - i] = pixels[src_pos + i];
}
}
}
C3D_TexFlush(tex);
}
tex->border = 0x00000000;
C3D_TexSetWrap(tex, GPU_REPEAT, GPU_REPEAT);
res.SetID((TextureID)tex);
RegisterTexture(res);
PDLOG("GfxCitro3D::LoadTexture -> {{ {} }}, [{}, {}]", res, type, filter);
return res;
}
void GfxCitro3D::DeleteTexture(const Li::Texture& tex) {
if (!tex.GetID()) return;
UnregisterTexture(tex);
C3D_Tex* t = reinterpret_cast<C3D_Tex*>(tex.GetID());
C3D_TexDelete(t);
delete t;
}
void GfxCitro3D::UploadPools() {
auto buf = C3D_GetBufInfo();
BufInfo_Init(buf);
BufInfo_Add(buf, GetVertexBufPtr(0), sizeof(Li::Vertex), 3, 0x210);
}
} // namespace PD
#else
namespace PD {
void GfxCitro3D::SysInit() {
PDERR(
"GfxCitro3D::SysInit: Citro3D Driver is not included in "
"palladium-system");
}
void GfxCitro3D::SysDeinit() {}
void GfxCitro3D::Submit(size_t count, size_t start) {}
void GfxCitro3D::BindTexture(TextureID id) {}
void GfxCitro3D::SysReset() {}
Li::Texture GfxCitro3D::LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, TextureFormat type,
TextureFilter filter) {
return Li::Texture();
}
void GfxCitro3D::DeleteTexture(const Li::Texture& tex) {}
void GfxCitro3D::UploadPools() {}
} // namespace PD
#endif
+308
View File
@@ -0,0 +1,308 @@
// Well yes, i finally try it
#include <pd/lithium/formatters.hpp>
#include <pd_system/gfx_directx9.hpp>
// Sicher ist sicher
#if defined(PD_ENABLE_DIRECTX9) && defined(_WIN32)
#include <d3d9.h>
#include <d3dcompiler.h>
#include <pd/drivers/drivers.hpp>
namespace PD {
static const char* g_vsCode = R"(
float4x4 projection;
struct VS_IN {
float2 pos : POSITION0;
float2 uv : TEXCOORD0;
float4 col : COLOR0;
};
struct VS_OUT {
float4 pos : POSITION0;
float2 uv : TEXCOORD0;
float4 col : COLOR0;
};
VS_OUT main(VS_IN input) {
VS_OUT o;
o.pos = mul(projection, float4(input.pos, 0.0, 1.0));
o.uv = input.uv;
o.col = input.col.bgra;
return o;
}
)";
static const char* g_psCode = R"(
sampler2D tex : register(s0);
float alfa : register(c1);
float is_sdf : register(c2);
struct PS_IN {
float2 uv : TEXCOORD0;
float4 col : COLOR0;
};
float4 main(PS_IN input) : COLOR0 {
float4 tc = tex2D(tex, input.uv);
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);
else
return tc * input.col;
}
)";
struct GfxDirectX9::Impl {
IDirect3DDevice9* Device = nullptr;
IDirect3DVertexBuffer9* VBO = nullptr;
IDirect3DIndexBuffer9* IBO = nullptr;
IDirect3DVertexDeclaration9* Decl = nullptr;
IDirect3DVertexShader9* VS = nullptr;
IDirect3DPixelShader9* FS = nullptr;
IDirect3DTexture9* CurrentTex = nullptr;
size_t VertexBufferSize = 0;
size_t IndexBufferSize = 0;
};
void GfxDirectX9::SysInit() {
if (impl) return;
PDLOG("GfxDirectX9::SysInit();");
impl = new Impl();
impl->Device = (IDirect3DDevice9*)pDevice;
if (impl->Device) {
D3DVERTEXELEMENT9 elements[]{
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,
0},
{0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD,
0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,
0},
D3DDECL_END()};
impl->Device->CreateVertexDeclaration(elements, &impl->Decl);
ID3DBlob* vsBlob = nullptr;
ID3DBlob* errBlob = nullptr;
HRESULT hr = D3DCompile(g_vsCode, strlen(g_vsCode), nullptr, nullptr,
nullptr, "main", "vs_2_0", 0, 0, &vsBlob, &errBlob);
if (FAILED(hr)) {
PDERR("Vertex Shader compile error: {}",
errBlob ? (char*)errBlob->GetBufferPointer() : "");
} else {
impl->Device->CreateVertexShader((DWORD*)vsBlob->GetBufferPointer(),
&impl->VS);
}
if (vsBlob) vsBlob->Release();
if (errBlob) errBlob->Release();
ID3DBlob* psBlob = nullptr;
errBlob = nullptr;
hr = D3DCompile(g_psCode, strlen(g_psCode), nullptr, nullptr, nullptr,
"main", "ps_2_0", 0, 0, &psBlob, &errBlob);
if (FAILED(hr)) {
PDLOG("Pixel Shader compile error: {}",
errBlob ? (char*)errBlob->GetBufferPointer() : "");
} else {
impl->Device->CreatePixelShader((DWORD*)psBlob->GetBufferPointer(),
&impl->FS);
}
if (psBlob) psBlob->Release();
if (errBlob) errBlob->Release();
} else {
PDERR(
"GfxDirectX9::SysInit Error: pDevice is not set!\nYOu need to include "
"your D3D9 Device as "
"folowing:\nPD::Gfx::UseDriver<PD::GfxDirectX9>(D3D9Device);");
}
}
void GfxDirectX9::SysDeinit() {
if (!impl || !impl->Device) return;
if (impl->VBO) impl->VBO->Release();
if (impl->IBO) impl->IBO->Release();
if (impl->Decl) impl->Decl->Release();
if (impl->VS) impl->VS->Release();
if (impl->FS) impl->FS->Release();
delete impl;
impl = nullptr;
PDLOG("GfxDirectX9::SysDeinit()");
}
void GfxDirectX9::Submit(size_t count, size_t start) {
if (!impl || !impl->Device || !impl->VBO || !impl->IBO) return;
BindTexture(CurrentTex);
impl->Device->SetVertexShaderConstantF(0, Projection.Ptr(), 4);
impl->Device->SetStreamSource(0, impl->VBO, 0, sizeof(PD::Li::Vertex));
impl->Device->SetIndices(impl->IBO);
impl->Device->SetVertexDeclaration(impl->Decl);
impl->Device->SetVertexShader(impl->VS);
impl->Device->SetPixelShader(impl->FS);
impl->Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0,
GetVertexPoolSize(), start, count / 3);
}
void GfxDirectX9::BindTexture(TextureID id) {
if (!impl || !impl->Device) return;
impl->CurrentTex = (IDirect3DTexture9*)id;
impl->Device->SetTexture(0, impl->CurrentTex);
bool a8 = false;
if (impl->CurrentTex) {
D3DSURFACE_DESC desc;
impl->CurrentTex->GetLevelDesc(0, &desc);
a8 = (desc.Format == D3DFMT_A8);
}
float v = a8 ? 1.0f : 0.0f;
impl->Device->SetPixelShaderConstantF(0, &v, 1);
float sdf = CurrentTexIsSDF ? 1.0f : 0.0f;
impl->Device->SetPixelShaderConstantF(1, &sdf, 1);
}
void GfxDirectX9::SysReset() {
if (!impl || !impl->Device) return;
impl->Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
impl->Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
impl->Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
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,
int h, TextureFormat type,
TextureFilter filter) {
if (!impl || !impl->Device) return Li::Texture();
if (pixels.size() !=
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type))) {
PDERR("Failed to load Texture due to Size mismatch: {} != {}",
pixels.size(),
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type)));
return Li::Texture();
}
IDirect3DTexture9* tex = nullptr;
D3DFORMAT fmt = D3DFMT_A8R8G8B8;
if (type == TextureFormat::RGB24)
fmt = D3DFMT_X8R8G8B8;
else if (type == TextureFormat::A8)
fmt = D3DFMT_A8;
HRESULT hr = impl->Device->CreateTexture(w, h, 1, 0, fmt, D3DPOOL_MANAGED,
&tex, nullptr);
if (FAILED(hr) || !tex) return Li::Texture();
D3DLOCKED_RECT rect;
tex->LockRect(0, &rect, nullptr, 0);
if (type == TextureFormat::RGB24) {
u8* dstRow = reinterpret_cast<u8*>(rect.pBits);
for (int y = 0; y < h; ++y) {
u32* dst = reinterpret_cast<u32*>(dstRow);
for (int x = 0; x < w; ++x) {
u8 r = pixels[(y * w + x) * 3 + 0];
u8 g = pixels[(y * w + x) * 3 + 1];
u8 b = pixels[(y * w + x) * 3 + 2];
dst[x] = (0xFF << 24) | (r << 16) | (g << 8) | b;
}
dstRow += rect.Pitch;
}
} else if (type == TextureFormat::RGBA32) {
u8* dstRow = reinterpret_cast<u8*>(rect.pBits);
for (int y = 0; y < h; ++y) {
u32* dst = reinterpret_cast<u32*>(dstRow);
for (int x = 0; x < w; ++x) {
u8 r = pixels[(y * w + x) * 4 + 0];
u8 g = pixels[(y * w + x) * 4 + 1];
u8 b = pixels[(y * w + x) * 4 + 2];
u8 a = pixels[(y * w + x) * 4 + 3];
dst[x] = (a << 24) | (r << 16) | (g << 8) | b;
}
dstRow += rect.Pitch;
}
} else if (type == TextureFormat::A8) {
u8* dstRow = reinterpret_cast<u8*>(rect.pBits);
for (int y = 0; y < h; ++y) {
memcpy(dstRow, &pixels[y * w], w);
dstRow += rect.Pitch;
}
}
tex->UnlockRect(0);
Li::Texture res;
res.SetID((TextureID)tex);
res.SetSize(w, h);
res.SetUV(0.f, 0.f, 1.f, 1.f);
RegisterTexture(res);
PDLOG("GfxDirectX9::LoadTexture -> {{ {} }}, [{}, {}]", res, type, filter);
return res;
}
void GfxDirectX9::DeleteTexture(const Li::Texture& tex) {
if (!tex.GetID()) return;
UnregisterTexture(tex);
IDirect3DTexture9* t = (IDirect3DTexture9*)tex.GetID();
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();
}
} // namespace PD
#else
namespace PD {
void GfxDirectX9::SysInit() {
PDERR(
"GfxDirectX9::SysInit: DirectX9 Driver is not included in "
"palladium-system");
}
void GfxDirectX9::SysDeinit() {}
void GfxDirectX9::Submit(size_t count, size_t start) {}
void GfxDirectX9::BindTexture(TextureID id) {}
void GfxDirectX9::SysReset() {}
Li::Texture GfxDirectX9::LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, TextureFormat type,
TextureFilter filter) {
return Li::Texture();
}
void GfxDirectX9::DeleteTexture(const Li::Texture& tex) {}
void GfxDirectX9::UploadPools() {}
} // namespace PD
#endif
+207
View File
@@ -0,0 +1,207 @@
#include <pd/lithium/formatters.hpp>
#include <pd_system/gfx_opengl2.hpp>
#if defined(PD_ENABLE_OPENGL2)
#include <glad/glad.h>
#include <pd/drivers/drivers.hpp>
#include <pd_system/gl-helper.hpp>
namespace PD {
const char* GfxOpenGL2::pVertCode = R"(
#version 120
attribute vec2 pos;
attribute vec2 uv;
attribute vec4 color;
varying vec2 oUV;
varying vec4 oColor;
// Probably forgot about this matrix and
// searched hours for why the rendering isn't working :/
uniform mat4 projection;
void main() {
gl_Position = projection*vec4(pos, 0.0, 1.0);
oUV = uv;
oColor = color;
}
)";
const char* GfxOpenGL2::pFragCode = R"(
#version 120
varying vec2 oUV;
varying vec4 oColor;
uniform sampler2D tex;
uniform bool alfa;
uniform bool is_sdf;
void main() {
vec4 tc = texture2D(tex, oUV);
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);
} else {
gl_FragColor = tc * oColor;
}
}
)";
void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {
GLint _pos = glGetAttribLocation(shader, "pos");
GLint _uv = glGetAttribLocation(shader, "uv");
GLint _color = glGetAttribLocation(shader, "color");
glVertexAttribPointer(_pos, 2, GL_FLOAT, GL_FALSE, sizeof(PD::Li::Vertex),
(void*)offsetof(PD::Li::Vertex, pos));
glEnableVertexAttribArray(_pos);
glVertexAttribPointer(_uv, 2, GL_FLOAT, GL_FALSE, sizeof(PD::Li::Vertex),
(void*)offsetof(PD::Li::Vertex, uv));
glEnableVertexAttribArray(_uv);
glVertexAttribPointer(_color, 4, GL_UNSIGNED_BYTE, GL_TRUE,
sizeof(PD::Li::Vertex),
(void*)offsetof(PD::Li::Vertex, color));
glEnableVertexAttribArray(_color);
}
void GfxOpenGL2::SysInit() {
pShader = CreateShaderProgram(pVertCode, pFragCode);
glUseProgram(pShader);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
pSetupShaderAttribs(pShader);
pLocTex = glGetUniformLocation(pShader, "tex");
pLocAlfa = glGetUniformLocation(pShader, "alfa");
pLocIsSDF = glGetUniformLocation(pShader, "is_sdf");
pLocProjection = glGetUniformLocation(pShader, "projection");
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void GfxOpenGL2::SysDeinit() {
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &IBO);
PDLOG("GfxOpenGL2::SysDeinit()");
}
void GfxOpenGL2::Submit(size_t count, size_t start) {
BindTexture(CurrentTex);
glUseProgram(pShader);
glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data());
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
pSetupShaderAttribs(pShader);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT,
reinterpret_cast<void*>(start * sizeof(u16)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
BindTexture(0);
}
void GfxOpenGL2::BindTexture(TextureID id) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, (GLuint)id);
glUniform1i(pLocTex, 0);
GLint fmt = 0;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
glUniform1i(pLocAlfa, fmt == GL_ALPHA);
glUniform1i(pLocIsSDF, CurrentTexIsSDF);
}
void GfxOpenGL2::SysReset() {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
Li::Texture GfxOpenGL2::LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, TextureFormat type,
TextureFilter filter) {
if (pixels.size() !=
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type))) {
PDERR("Failed to load Texture due to Size mismatch: {} != {}",
pixels.size(),
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type)));
return Li::Texture();
}
GLuint texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
// Set base format (Always using RGBA as base)
GLenum fmt = GL_RGBA;
if (type == TextureFormat::RGB24) {
fmt = GL_RGB;
} else if (type == TextureFormat::A8) {
fmt = GL_ALPHA;
}
glTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, fmt, GL_UNSIGNED_BYTE,
pixels.data());
if (filter == TextureFilter::Linear) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else if (filter == TextureFilter::Nearest) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
glBindTexture(GL_TEXTURE_2D, 0);
Li::Texture res;
res.SetID(texID);
res.SetSize(w, h);
res.SetUV(0.f, 0.f, 1.f, 1.f);
RegisterTexture(res);
PDLOG("GfxOpenGL2::LoadTexture -> {{ {} }}, [{}, {}]", res, type, filter);
return res;
}
void GfxOpenGL2::DeleteTexture(const Li::Texture& tex) {
UnregisterTexture(tex);
GLuint tex_ = tex.GetID();
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);
}
} // namespace PD
#else
namespace PD {
void GfxOpenGL2::SysInit() {
PDERR(
"GfxOpenGL2::SysInit: OpenGL2 Driver is not included in "
"palladium-system");
}
void GfxOpenGL2::SysDeinit() {}
void GfxOpenGL2::Submit(size_t count, size_t start) {}
void GfxOpenGL2::BindTexture(TextureID id) {}
void GfxOpenGL2::SysReset() {}
Li::Texture GfxOpenGL2::LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, TextureFormat type,
TextureFilter filter) {
return Li::Texture();
}
void GfxOpenGL2::DeleteTexture(const Li::Texture& tex) {}
void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {}
void GfxOpenGL2::UploadPools() {}
} // namespace PD
#endif
+182
View File
@@ -0,0 +1,182 @@
#include <pd/lithium/formatters.hpp>
#include <pd_system/gfx_opengl3.hpp>
#if defined(PD_ENABLE_OPENGL3)
#include <glad/glad.h>
#include <pd/drivers/drivers.hpp>
#include <pd_system/gl-helper.hpp>
#include <pd_system/shaders.hpp>
#include <spirv-helper.hpp>
namespace PD {
void GfxOpenGL3::SysInit() {
std::string vcode = SpirvHelper::SPV2GLSL(
std::vector<unsigned int>(
Shaders::VertexShader,
Shaders::VertexShader +
(sizeof(Shaders::VertexShader) / sizeof(unsigned int))),
330, false);
std::string fcode = SpirvHelper::SPV2GLSL(
std::vector<unsigned int>(
Shaders::FragmentShader,
Shaders::FragmentShader +
(sizeof(Shaders::FragmentShader) / sizeof(unsigned int))),
330, false);
PDLOG("Vertex: \n{}", vcode);
PDLOG("Fragment: \n{}", fcode);
pShader = CreateShaderProgram(vcode.c_str(), fcode.c_str());
glUseProgram(pShader);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(PD::Li::Vertex),
(void*)offsetof(PD::Li::Vertex, pos));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(PD::Li::Vertex),
(void*)offsetof(PD::Li::Vertex, uv));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(PD::Li::Vertex),
(void*)offsetof(PD::Li::Vertex, color));
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
pLocTex = glGetUniformLocation(pShader, "tex");
pLocAlfa = glGetUniformLocation(pShader, "push.alfa");
pLocIsSDF = glGetUniformLocation(pShader, "push.is_sdf");
pLocProjection = glGetUniformLocation(pShader, "ubo.projection");
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void GfxOpenGL3::SysDeinit() {
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &IBO);
glDeleteVertexArrays(1, &VAO);
PDLOG("GfxOpenGL3::SysDeinit()");
}
void GfxOpenGL3::Submit(size_t count, size_t start) {
BindTexture(CurrentTex);
glUseProgram(pShader);
glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data());
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT,
reinterpret_cast<void*>(start * sizeof(u16)));
glBindVertexArray(0);
BindTexture(0);
}
void GfxOpenGL3::BindTexture(TextureID id) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, (GLuint)id);
glUniform1i(pLocTex, 0);
GLint fmt = 0;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
glUniform1i(pLocAlfa, fmt == GL_R8);
glUniform1i(pLocIsSDF, CurrentTexIsSDF);
}
void GfxOpenGL3::SysReset() {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
Li::Texture GfxOpenGL3::LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, TextureFormat type,
TextureFilter filter) {
if (pixels.size() !=
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type))) {
PDERR("Failed to load Texture due to Size mismatch: {} != {}",
pixels.size(),
static_cast<size_t>(w * h * Li::TextureFormat2Bpp(type)));
return Li::Texture();
}
GLuint texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
// Set base format (Always using RGBA as base)
GLenum fmt = GL_RGBA;
GLenum ifmt = GL_RGBA8;
if (type == TextureFormat::RGB24) {
ifmt = GL_RGB8;
fmt = GL_RGB;
} else if (type == TextureFormat::A8) {
ifmt = GL_R8;
fmt = GL_RED;
}
glTexImage2D(GL_TEXTURE_2D, 0, ifmt, w, h, 0, fmt, GL_UNSIGNED_BYTE,
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) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else if (filter == TextureFilter::Nearest) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
glBindTexture(GL_TEXTURE_2D, 0);
Li::Texture res;
res.SetID(texID);
res.SetSize(w, h);
res.SetUV(0.f, 0.f, 1.f, 1.f);
RegisterTexture(res);
PDLOG("GfxOpenGL3::LoadTexture -> {{ {} }}, [{}, {}]", res, type, filter);
return res;
}
void GfxOpenGL3::DeleteTexture(const Li::Texture& tex) {
UnregisterTexture(tex);
GLuint tex_ = tex.GetID();
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);
}
} // namespace PD
#else
namespace PD {
void GfxOpenGL3::SysInit() {
PDERR(
"GfxOpenGL3::SysInit: OpenGL3 Driver is not included in "
"palladium-system");
}
void GfxOpenGL3::SysDeinit() {}
void GfxOpenGL3::Submit(size_t count, size_t start) {}
void GfxOpenGL3::BindTexture(TextureID id) {}
void GfxOpenGL3::SysReset() {}
Li::Texture GfxOpenGL3::LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h, TextureFormat type,
TextureFilter filter) {
return Li::Texture();
}
void GfxOpenGL3::DeleteTexture(const Li::Texture& tex) {}
void GfxOpenGL3::UploadPools() {}
} // namespace PD
#endif
+48
View File
@@ -0,0 +1,48 @@
#if defined(PD_ENABLE_OPENGL2) || defined(PD_ENABLE_OPENGL3)
#include <glad/glad.h>
#include <iostream>
#include <pd_system/gl-helper.hpp>
namespace PD {
GLuint compileShader(const char* src, GLenum type) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
std::cerr << "Shader Compilation Error: " << infoLog << std::endl;
}
return shader;
}
u32 CreateShaderProgram(const char* vert, const char* frag) {
GLuint vertexShader = compileShader(vert, GL_VERTEX_SHADER);
GLuint fragmentShader = compileShader(frag, GL_FRAGMENT_SHADER);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
GLint success;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
std::cerr << "Shader Program Linking Error: " << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
if (success) PDLOG("Shader [{}] compiled sucessfully", shaderProgram);
return shaderProgram;
}
} // namespace PD
#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
+156
View File
@@ -0,0 +1,156 @@
#include <pd_system/hid_glfw.hpp>
#ifdef PD_ENABLE_HID_GLFW
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
namespace PD {
struct HidGlfw::Impl {
GLFWwindow* Win;
int PrevState;
std::unordered_map<int, int> PrevStates;
std::unordered_map<int, int> GPPrevStates;
GLFWcharfun OldTextCB;
std::string* Text;
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") {
impl = new Impl;
impl->Win = win;
pFlags |= PDHidBackendFlags_HasMouse;
pFlags |= PDHidBackendFlags_HasKeyboard;
if (glfwJoystickPresent(GLFW_JOYSTICK_1)) {
pFlags |= PDHidBackendFlags_HasGamepad;
}
pGamepad[GLFW_GAMEPAD_BUTTON_A] = HidInternal::Gamepad::A;
pGamepad[GLFW_GAMEPAD_BUTTON_B] = HidInternal::Gamepad::B;
pGamepad[GLFW_GAMEPAD_BUTTON_X] = HidInternal::Gamepad::X;
pGamepad[GLFW_GAMEPAD_BUTTON_Y] = HidInternal::Gamepad::Y;
pGamepad[GLFW_GAMEPAD_BUTTON_START] = HidInternal::Gamepad::Start;
pGamepad[GLFW_GAMEPAD_BUTTON_BACK] = HidInternal::Gamepad::Select;
pGamepad[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] = HidInternal::Gamepad::DLeft;
pGamepad[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] = HidInternal::Gamepad::DRight;
pGamepad[GLFW_GAMEPAD_BUTTON_DPAD_UP] = HidInternal::Gamepad::DUp;
pGamepad[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] = HidInternal::Gamepad::DDown;
pGamepad[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] = HidInternal::Gamepad::L;
pGamepad[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = HidInternal::Gamepad::R;
pGamepad[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = HidInternal::Gamepad::LStick;
pGamepad[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = HidInternal::Gamepad::RStick;
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;
}
}
HidGlfw::~HidGlfw() { delete impl; }
void HidGlfw::Update() {
HidDriver::Update(); // clear stats
GLFWgamepadstate gpstate;
int gps = glfwGetGamepadState(GLFW_JOYSTICK_1, &gpstate);
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++) {
if (gpstate.buttons[i] == GLFW_PRESS) {
if (impl->GPPrevStates[i] == GLFW_RELEASE) {
pGamepadEvents[0][Event::Down] |= pGamepad[i];
}
pGamepadEvents[0][Event::Held] |= pGamepad[i];
} else if (gpstate.buttons[i] == GLFW_RELEASE &&
impl->GPPrevStates[i] == GLFW_PRESS) {
pGamepadEvents[0][Event::Up] |= pGamepad[i];
}
impl->GPPrevStates[i] = gpstate.buttons[i];
}
}
int state = glfwGetMouseButton(impl->Win, GLFW_MOUSE_BUTTON_LEFT);
if (state == GLFW_PRESS) {
if (impl->PrevState == GLFW_RELEASE) {
pGamepadEvents[0][Event::Down] |= HidInternal::Touch;
}
pGamepadEvents[0][Event::Held] |= HidInternal::Touch;
} else if (state == GLFW_RELEASE && impl->PrevState == GLFW_PRESS) {
pGamepadEvents[0][Event::Up] |= HidInternal::Touch;
}
impl->PrevState = state;
// if (pLocked) {
// SwapTab();
// }
double x, y;
glfwGetCursorPos(impl->Win, &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
#else
struct GLFWgamepadstate {};
namespace PD {
HidGlfw::HidGlfw(GLFWwindow* win) : HidDriver("HidGlfw") {}
HidGlfw::~HidGlfw() {}
void HidGlfw::Update() {
HidDriver::Update(); // clear stats
}
void HidGlfw::HandleAxisKey(GLFWgamepadstate s, int iK, int eA, bool negative) {
}
} // namespace PD
#endif
+31
View File
@@ -0,0 +1,31 @@
#include <pd_system/hid_nx.hpp>
#ifdef PD_ENABLE_HID_NX
#include <switch.h>
namespace PD {
struct HidNX::Impl {
PadState Pad;
};
HidNX::HidNX() : HidDriver("HidNX") { impl = new Impl; }
HidNX::~HidNX() { delete impl; }
void HidNX::Update() {
HidDriver::Update(); // clear stats
}
} // namespace PD
#else
namespace PD {
HidNX::HidNX() : HidDriver("HidNX") {}
HidNX::~HidNX() {}
void HidNX::Update() {
HidDriver::Update(); // clear stats
}
} // namespace PD
#endif
+35
View File
@@ -0,0 +1,35 @@
{
"version": 10,
"configurePresets": [
{
"name": "3ds-debug",
"generator": "Ninja",
"displayName": "Nintendo 3DS Debug",
"binaryDir": "${sourceDir}/build/3ds-debug",
"toolchainFile": "/opt/devkitPro/cmake/3DS.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "3ds-release",
"generator": "Ninja",
"displayName": "Nintendo 3DS Release",
"binaryDir": "${sourceDir}/build/3ds-release",
"toolchainFile": "/opt/devkitPro/cmake/3DS.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
],
"buildPresets": [
{
"name": "3ds-release",
"configurePreset": "3ds-release"
},
{
"name": "3ds-debug",
"configurePreset": "3ds-debug"
}
]
}
+33
View File
@@ -0,0 +1,33 @@
{
"version": 10,
"configurePresets": [
{
"name": "default-debug",
"generator": "Ninja",
"displayName": "Default Debug",
"binaryDir": "${sourceDir}/build/default-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "default-release",
"generator": "Ninja",
"displayName": "Default Release",
"binaryDir": "${sourceDir}/build/default-release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
],
"buildPresets": [
{
"name": "default-release",
"configurePreset": "default-release"
},
{
"name": "default-debug",
"configurePreset": "default-debug"
}
]
}
+24
View File
@@ -0,0 +1,24 @@
{
"version": 10,
"configurePresets": [
{
"name": "msvc",
"cmakeExecutable": "C:\\Program Files\\CMake\\bin\\cmake.exe",
"displayName": "MSVC",
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build/msvc-build"
}
],
"buildPresets": [
{
"name": "msvc-release",
"configuration": "Release",
"configurePreset": "msvc"
},
{
"name": "msvc-debug",
"configuration": "Debug",
"configurePreset": "msvc"
}
]
}
+37
View File
@@ -0,0 +1,37 @@
{
"version": 10,
"configurePresets": [
{
"name": "switch-debug",
"generator": "Ninja",
"displayName": "Nintendo Switch Debug",
"binaryDir": "${sourceDir}/build/switch-debug",
"toolchainFile": "/opt/devkitPro/cmake/Switch.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"SPV_EXCLUDE_GLSLANG": "ON"
}
},
{
"name": "switch-release",
"generator": "Ninja",
"displayName": "Nintendo Switch Release",
"binaryDir": "${sourceDir}/build/switch-release",
"toolchainFile": "/opt/devkitPro/cmake/Switch.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"SPV_EXCLUDE_GLSLANG": "ON"
}
}
],
"buildPresets": [
{
"name": "switch-release",
"configurePreset": "switch-release"
},
{
"name": "switch-debug",
"configurePreset": "switch-debug"
}
]
}
+3
View File
@@ -25,3 +25,6 @@ SOFTWARE.
#include <pd/core/core.hpp>
#include <pd/drivers/drivers.hpp>
#include <pd/image/image.hpp>
#include <pd/lithium/lithium.hpp>
#include <pd/ui7/ui7.hpp>
+65
View File
@@ -23,16 +23,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#if defined(__GNUG__) && !defined(_MSC_VER)
#include <cxxabi.h>
#endif
#include <array>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <exception>
#include <format>
#include <fstream>
#include <numbers>
#include <pd/pd_p_api.hpp>
#include <string>
#include <unordered_map>
#include <vector>
namespace PD {
enum class LogLevel {
None,
Info,
Warning,
Error,
};
[[noreturn]] inline void Throw(const std::string& msg) {
throw std::runtime_error(msg);
}
@@ -41,4 +57,53 @@ using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;
using ptr = uintptr_t;
PD_API void LogFilter(LogLevel minimum);
PD_API void Log(const std::string& txt, LogLevel lvl = LogLevel::Info);
template <typename... Args>
void Log(std::format_string<Args...> fmt, Args&&... args) {
std::string msg = std::format(fmt, std::forward<Args>(args)...);
Log(msg, LogLevel::Info);
}
template <typename... Args>
void Log(LogLevel lvl, std::format_string<Args...> fmt, Args&&... args) {
std::string msg = std::format(fmt, std::forward<Args>(args)...);
Log(msg, lvl);
}
template <typename T>
std::string TypeName() {
#ifdef __RTTI
#if defined(__GNUG__) && !defined(_MSC_VER)
int res = 0;
std::unique_ptr<char, void (*)(void*)> up{
abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &res), std::free};
return (res == 0) ? up.get() : typeid(T).name();
#else
return typeid(T).name(); // no demangler available :/
#endif
#else
return "";
#endif
}
} // namespace PD
#if defined(__GNUC__) || defined(__clang__)
#define PDPRETTYFUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define PDPRETTYFUNC __FUNCSIG__
#else
#define PDPRETTYFUNC __FUNCTION__
#endif
#ifdef PD_DEBUG
#define PDLOG(fmt, ...) \
PD::Log("[{}:{}]: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
#define PDWARN(fmt, ...) \
PD::Log(PD::LogLevel::Warning, "[{}:{}]: " fmt, __FILE__, __LINE__, \
##__VA_ARGS__)
#define PDERR(fmt, ...) \
PD::Log(PD::LogLevel::Error, "[{}:{}]: " fmt, __FILE__, __LINE__, \
##__VA_ARGS__)
#else
#define PDLOG(fmt, ...)
#define PDWARN(fmt, ...)
#define PDERR(fmt, ...)
#endif
+20
View File
@@ -71,6 +71,12 @@ class PD_API Color {
*/
constexpr Color(const std::string_view& hex) { Hex(hex); }
/**
* Constructor for Hex Input (is abel to run at compile time xD)
* @param hex Hex String in `#ffffff` or `#ffffffff` format
*/
constexpr Color(const char* hex) { Hex(std::string_view{hex}); }
/**
* Create Color Object by Hex String (at compile time btw)
* @param hex Hex String in `#ffffff` or `#ffffffff` format
@@ -115,6 +121,20 @@ class PD_API Color {
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
* @return 32Bit Color Value (ABGR iirc)
+1 -1
View File
@@ -93,6 +93,6 @@ struct std::formatter<PD::Color> : std::formatter<std::string> {
std::format_parse_context::const_iterator end,
size_t len, const char* what) {
return (end - it >= static_cast<std::ptrdiff_t>(len) &&
std::string_view(it, len) == what);
std::string_view(&*it, len) == what); // msvc things...
}
};
+10
View File
@@ -109,6 +109,16 @@ struct PD_API Mat4 {
return ret;
}
constexpr Mat4 Transpose() const {
Mat4 ret;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
ret(i, j) = (*this)(j, i);
}
}
return ret;
}
constexpr static Mat4 Ortho(float l, float r, float b, float t, float n,
float f) {
Mat4 ret;
+132 -17
View File
@@ -1,20 +1,41 @@
#pragma once
#include <memory>
#include <pd/common.hpp>
namespace PD {
// lets take use of c++ 20 concepts
// https://en.cppreference.com/w/cpp/language/constraints.html
template <typename T>
concept Resettable = requires(T& v) { v.Reset(); };
template <typename T, typename Alloc = std::allocator<T>>
class Pool {
public:
using value_type = T;
using iterator = T*;
using const_iterator = const T*;
Pool() = default;
~Pool() = default;
~Pool() {
if (pData) {
for (size_t i = 0; i < pCap; i++) {
std::allocator_traits<Alloc>::destroy(pAlloc, &pData[i]);
}
pAlloc.deallocate(pData, pCap);
pData = nullptr;
}
}
static Pool* Create(size_t size) { return new Pool(size); }
void Init(size_t size) {
pPos = 0;
pCap = size;
pPool.resize(size);
pData = pAlloc.allocate(size);
for (size_t i = 0; i < pCap; i++) {
std::allocator_traits<Alloc>::construct(pAlloc, &pData[i]);
}
PDLOG("Pool::Init({})", size);
}
Pool(const Pool&) = delete;
@@ -23,29 +44,123 @@ class Pool {
Pool& operator=(Pool&&) = delete;
T* Allocate(size_t num = 1) {
if (CheckLimits(num)) return nullptr;
T* ret = &pPool[pPos];
ExpandIf(num);
T* ret = &pData[pPos];
pPos += num;
return ret;
}
bool CheckLimits(size_t num) {
if ((pPos + num) >= pCap) {
throw std::runtime_error(
std::format("[PD::Pool]: Trying to allocate {} elements but this is "
"going out of range ({}/{})",
num, pPos + num, pCap));
return true;
}
return false;
void Push(const T& elem) {
T* e = Allocate(1);
*e = elem;
}
void Reset() { pPos = 0; }
void Put(size_t idx, const T& elem) {
if (idx >= pCap) ExpandIf(idx);
pData[idx] = elem;
}
void ExpandIf(size_t req) {
if ((pPos + req) <= pCap) return;
size_t ncap = std::max(pCap * 2, pPos + req);
T* nu = pAlloc.allocate(ncap);
if (pData) {
for (size_t i = 0; i < pPos; i++) {
std::allocator_traits<Alloc>::construct(
pAlloc, &nu[i], std::move_if_noexcept(pData[i]));
}
for (size_t i = 0; i < pCap; i++) {
std::allocator_traits<Alloc>::destroy(pAlloc, &pData[i]);
}
pAlloc.deallocate(pData, pCap);
}
for (size_t i = pPos; i < ncap; i++) {
std::allocator_traits<Alloc>::construct(pAlloc, &nu[i]);
}
PDLOG("Pool::ExpandIf({}): {} -> {}", req, pCap, ncap);
pData = nu;
pCap = ncap;
}
void Reset() {
for (size_t i = 0; i < pCap; i++) {
std::allocator_traits<Alloc>::destroy(pAlloc, &pData[i]);
}
pPos = 0;
for (size_t i = 0; i < pCap; i++) {
std::allocator_traits<Alloc>::construct(pAlloc, &pData[i]);
}
}
void ResetFast() {
if constexpr (Resettable<T>) {
for (size_t i = 0; i < pPos; i++) {
pData[i].Reset();
}
} else if constexpr (!std::is_trivially_destructible_v<T>) {
PDWARN(
"ResetFast should only be executed with a non destructible type or a "
"class/struct that has a Reset func! {} is not "
"trivially_destructible and has no reset func.",
TypeName<T>());
}
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 capacity() const { return pCap; }
T& at(size_t idx) { return pData[idx]; }
const T& at(size_t idx) const { return pData[idx]; }
iterator begin() { return pData; }
iterator end() { return pData + pPos; }
const_iterator begin() const { return pData; }
const_iterator end() const { return pData + pPos; }
T& operator[](size_t idx) { return at(idx); }
const T& operator[](size_t idx) const { return at(idx); }
private:
Pool(size_t size) : pCap(size), pPos(0) { pPool.resize(size); }
Pool(size_t size) : pCap(size), pPos(0) {
pPos = 0;
pCap = size;
pData = pAlloc.allocate(size);
for (size_t i = 0; i < pCap; i++) {
std::allocator_traits<Alloc>::construct(pAlloc, &pData[i]);
}
PDLOG("Pool::Init({})", size);
}
size_t pCap = 0;
size_t pPos = 0;
std::vector<T, Alloc> pPool;
Alloc pAlloc;
T* pData = nullptr;
};
} // namespace PD
+1 -1
View File
@@ -149,7 +149,7 @@ class U8Iterator {
}
bool PeekNext32(u32& ret) {
// if ((ptr + 1) == 0 || *(ptr + 1) == 0) return false;
if (ptr == nullptr || *(ptr + 1) == 0) return false;
u8 c = *ptr;
if (c < 0x80) {
ret = c;
+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.
*/
#include <map>
#include <pd/common.hpp>
namespace PD {
@@ -202,14 +203,15 @@ class Res {
/** Trace ID */
std::string id;
/** Start time */
u64 start;
u64 start = 0;
/** End Time */
u64 end;
u64 end = 0;
/** Last Diff */
u64 diff;
u64 diff = 0;
/** Protocol */
TimeStats protocol;
};
using TraceMap = std::map<std::string, TT::Res>;
/**
* Begin a 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
*/
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
* when the Scope object goes out of scope
+23 -23
View File
@@ -23,7 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// This file is generated by lazyvec 2.0.0
// This file is generated by lazyvec 2.1.0
#include <pd/common.hpp>
@@ -54,117 +54,117 @@ class vec2 {
// Operations
template <typename T1>
vec2<T>& operator+=(T1 v) {
constexpr vec2<T>& operator+=(T1 v) {
x += (T)v;
y += (T)v;
return *this;
}
template <typename T1>
vec2<T>& operator+=(const vec2<T1>& v) {
constexpr vec2<T>& operator+=(const vec2<T1>& v) {
x += (T)v.x;
y += (T)v.y;
return *this;
}
template <typename T1>
vec2<T> operator+(T1 v) const {
constexpr vec2<T> operator+(T1 v) const {
return vec2<T>(x + (T)v, y + (T)v);
}
template <typename T1>
vec2<T> operator+(const vec2<T1>& v) const {
constexpr vec2<T> operator+(const vec2<T1>& v) const {
return vec2<T>(x + (T)v.x, y + (T)v.y);
}
template <typename T1>
vec2<T>& operator-=(T1 v) {
constexpr vec2<T>& operator-=(T1 v) {
x -= (T)v;
y -= (T)v;
return *this;
}
template <typename T1>
vec2<T>& operator-=(const vec2<T1>& v) {
constexpr vec2<T>& operator-=(const vec2<T1>& v) {
x -= (T)v.x;
y -= (T)v.y;
return *this;
}
template <typename T1>
vec2<T> operator-(T1 v) const {
constexpr vec2<T> operator-(T1 v) const {
return vec2<T>(x - (T)v, y - (T)v);
}
template <typename T1>
vec2<T> operator-(const vec2<T1>& v) const {
constexpr vec2<T> operator-(const vec2<T1>& v) const {
return vec2<T>(x - (T)v.x, y - (T)v.y);
}
template <typename T1>
vec2<T>& operator*=(T1 v) {
constexpr vec2<T>& operator*=(T1 v) {
x *= (T)v;
y *= (T)v;
return *this;
}
template <typename T1>
vec2<T>& operator*=(const vec2<T1>& v) {
constexpr vec2<T>& operator*=(const vec2<T1>& v) {
x *= (T)v.x;
y *= (T)v.y;
return *this;
}
template <typename T1>
vec2<T> operator*(T1 v) const {
constexpr vec2<T> operator*(T1 v) const {
return vec2<T>(x * (T)v, y * (T)v);
}
template <typename T1>
vec2<T> operator*(const vec2<T1>& v) const {
constexpr vec2<T> operator*(const vec2<T1>& v) const {
return vec2<T>(x * (T)v.x, y * (T)v.y);
}
template <typename T1>
vec2<T>& operator/=(T1 v) {
constexpr vec2<T>& operator/=(T1 v) {
x /= (T)v;
y /= (T)v;
return *this;
}
template <typename T1>
vec2<T>& operator/=(const vec2<T1>& v) {
constexpr vec2<T>& operator/=(const vec2<T1>& v) {
x /= (T)v.x;
y /= (T)v.y;
return *this;
}
template <typename T1>
vec2<T> operator/(T1 v) const {
constexpr vec2<T> operator/(T1 v) const {
return vec2<T>(x / (T)v, y / (T)v);
}
template <typename T1>
vec2<T> operator/(const vec2<T1>& v) const {
constexpr vec2<T> operator/(const vec2<T1>& v) const {
return vec2<T>(x / (T)v.x, y / (T)v.y);
}
// Generic Operations
vec2 operator-() const { return vec2(-x, -y); }
constexpr vec2 operator-() const { return vec2(-x, -y); }
template <typename T1>
bool operator==(const vec2<T1>& v) const {
constexpr bool operator==(const vec2<T1>& v) const {
return x == (T)v.x && y == (T)v.y;
}
template <typename T1>
bool operator!=(const vec2<T1>& v) const {
constexpr bool operator!=(const vec2<T1>& v) const {
return !(*this == v);
}
// Functions
double Len() const { return std::sqrt(SqLen()); }
double SqLen() const { return x * x + y * y; }
constexpr double SqLen() const { return x * x + y * y; }
template <typename T1>
double Distance(const vec2<T1>& v) const {
@@ -180,12 +180,12 @@ class vec2 {
}
template <typename T1>
T Dot(const vec2<T1>& v) const {
constexpr T Dot(const vec2<T1>& v) const {
return x * (T)v.x + y * (T)v.y;
}
// Swap Functions
void SwapXY() {
constexpr void SwapXY() {
T t = x;
x = y;
y = t;
+26 -26
View File
@@ -23,7 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// This file is generated by lazyvec 2.0.0
// This file is generated by lazyvec 2.1.0
#include <pd/common.hpp>
// Extended includes (rename if you use other filenames/paths)
@@ -69,7 +69,7 @@ class vec3 {
// Operations
template <typename T1>
vec3<T>& operator+=(T1 v) {
constexpr vec3<T>& operator+=(T1 v) {
x += (T)v;
y += (T)v;
z += (T)v;
@@ -77,7 +77,7 @@ class vec3 {
}
template <typename T1>
vec3<T>& operator+=(const vec3<T1>& v) {
constexpr vec3<T>& operator+=(const vec3<T1>& v) {
x += (T)v.x;
y += (T)v.y;
z += (T)v.z;
@@ -85,17 +85,17 @@ class vec3 {
}
template <typename T1>
vec3<T> operator+(T1 v) const {
constexpr vec3<T> operator+(T1 v) const {
return vec3<T>(x + (T)v, y + (T)v, z + (T)v);
}
template <typename T1>
vec3<T> operator+(const vec3<T1>& v) const {
constexpr vec3<T> operator+(const vec3<T1>& v) const {
return vec3<T>(x + (T)v.x, y + (T)v.y, z + (T)v.z);
}
template <typename T1>
vec3<T>& operator-=(T1 v) {
constexpr vec3<T>& operator-=(T1 v) {
x -= (T)v;
y -= (T)v;
z -= (T)v;
@@ -103,7 +103,7 @@ class vec3 {
}
template <typename T1>
vec3<T>& operator-=(const vec3<T1>& v) {
constexpr vec3<T>& operator-=(const vec3<T1>& v) {
x -= (T)v.x;
y -= (T)v.y;
z -= (T)v.z;
@@ -111,17 +111,17 @@ class vec3 {
}
template <typename T1>
vec3<T> operator-(T1 v) const {
constexpr vec3<T> operator-(T1 v) const {
return vec3<T>(x - (T)v, y - (T)v, z - (T)v);
}
template <typename T1>
vec3<T> operator-(const vec3<T1>& v) const {
constexpr vec3<T> operator-(const vec3<T1>& v) const {
return vec3<T>(x - (T)v.x, y - (T)v.y, z - (T)v.z);
}
template <typename T1>
vec3<T>& operator*=(T1 v) {
constexpr vec3<T>& operator*=(T1 v) {
x *= (T)v;
y *= (T)v;
z *= (T)v;
@@ -129,7 +129,7 @@ class vec3 {
}
template <typename T1>
vec3<T>& operator*=(const vec3<T1>& v) {
constexpr vec3<T>& operator*=(const vec3<T1>& v) {
x *= (T)v.x;
y *= (T)v.y;
z *= (T)v.z;
@@ -137,17 +137,17 @@ class vec3 {
}
template <typename T1>
vec3<T> operator*(T1 v) const {
constexpr vec3<T> operator*(T1 v) const {
return vec3<T>(x * (T)v, y * (T)v, z * (T)v);
}
template <typename T1>
vec3<T> operator*(const vec3<T1>& v) const {
constexpr vec3<T> operator*(const vec3<T1>& v) const {
return vec3<T>(x * (T)v.x, y * (T)v.y, z * (T)v.z);
}
template <typename T1>
vec3<T>& operator/=(T1 v) {
constexpr vec3<T>& operator/=(T1 v) {
x /= (T)v;
y /= (T)v;
z /= (T)v;
@@ -155,7 +155,7 @@ class vec3 {
}
template <typename T1>
vec3<T>& operator/=(const vec3<T1>& v) {
constexpr vec3<T>& operator/=(const vec3<T1>& v) {
x /= (T)v.x;
y /= (T)v.y;
z /= (T)v.z;
@@ -163,31 +163,31 @@ class vec3 {
}
template <typename T1>
vec3<T> operator/(T1 v) const {
constexpr vec3<T> operator/(T1 v) const {
return vec3<T>(x / (T)v, y / (T)v, z / (T)v);
}
template <typename T1>
vec3<T> operator/(const vec3<T1>& v) const {
constexpr vec3<T> operator/(const vec3<T1>& v) const {
return vec3<T>(x / (T)v.x, y / (T)v.y, z / (T)v.z);
}
// Generic Operations
vec3 operator-() const { return vec3(-x, -y, -z); }
constexpr vec3 operator-() const { return vec3(-x, -y, -z); }
template <typename T1>
bool operator==(const vec3<T1>& v) const {
constexpr bool operator==(const vec3<T1>& v) const {
return x == (T)v.x && y == (T)v.y && z == (T)v.z;
}
template <typename T1>
bool operator!=(const vec3<T1>& v) const {
constexpr bool operator!=(const vec3<T1>& v) const {
return !(*this == v);
}
// Functions
double Len() const { return std::sqrt(SqLen()); }
double SqLen() const { return x * x + y * y + z * z; }
constexpr double SqLen() const { return x * x + y * y + z * z; }
template <typename T1>
double Distance(const vec3<T1>& v) const {
@@ -203,27 +203,27 @@ class vec3 {
}
template <typename T1>
T Dot(const vec3<T1>& v) const {
constexpr T Dot(const vec3<T1>& v) const {
return x * (T)v.x + y * (T)v.y + z * (T)v.z;
}
template <typename T1>
vec3<T> Cross(const vec3<T1>& v) const {
constexpr vec3<T> Cross(const vec3<T1>& v) const {
return vec3<T>(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
}
// Swap Functions
void SwapXY() {
constexpr void SwapXY() {
T t = x;
x = y;
y = t;
}
void SwapXZ() {
constexpr void SwapXZ() {
T t = x;
x = z;
z = t;
}
void SwapYZ() {
constexpr void SwapYZ() {
T t = y;
y = z;
z = t;
+28 -28
View File
@@ -23,7 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// This file is generated by lazyvec 2.0.0
// This file is generated by lazyvec 2.1.0
#include <pd/common.hpp>
// Extended includes (rename if you use other filenames/paths)
@@ -84,7 +84,7 @@ class vec4 {
// Operations
template <typename T1>
vec4<T>& operator+=(T1 v) {
constexpr vec4<T>& operator+=(T1 v) {
x += (T)v;
y += (T)v;
z += (T)v;
@@ -93,7 +93,7 @@ class vec4 {
}
template <typename T1>
vec4<T>& operator+=(const vec4<T1>& v) {
constexpr vec4<T>& operator+=(const vec4<T1>& v) {
x += (T)v.x;
y += (T)v.y;
z += (T)v.z;
@@ -102,17 +102,17 @@ class vec4 {
}
template <typename T1>
vec4<T> operator+(T1 v) const {
constexpr vec4<T> operator+(T1 v) const {
return vec4<T>(x + (T)v, y + (T)v, z + (T)v, w + (T)v);
}
template <typename T1>
vec4<T> operator+(const vec4<T1>& v) const {
constexpr vec4<T> operator+(const vec4<T1>& v) const {
return vec4<T>(x + (T)v.x, y + (T)v.y, z + (T)v.z, w + (T)v.w);
}
template <typename T1>
vec4<T>& operator-=(T1 v) {
constexpr vec4<T>& operator-=(T1 v) {
x -= (T)v;
y -= (T)v;
z -= (T)v;
@@ -121,7 +121,7 @@ class vec4 {
}
template <typename T1>
vec4<T>& operator-=(const vec4<T1>& v) {
constexpr vec4<T>& operator-=(const vec4<T1>& v) {
x -= (T)v.x;
y -= (T)v.y;
z -= (T)v.z;
@@ -130,17 +130,17 @@ class vec4 {
}
template <typename T1>
vec4<T> operator-(T1 v) const {
constexpr vec4<T> operator-(T1 v) const {
return vec4<T>(x - (T)v, y - (T)v, z - (T)v, w - (T)v);
}
template <typename T1>
vec4<T> operator-(const vec4<T1>& v) const {
constexpr vec4<T> operator-(const vec4<T1>& v) const {
return vec4<T>(x - (T)v.x, y - (T)v.y, z - (T)v.z, w - (T)v.w);
}
template <typename T1>
vec4<T>& operator*=(T1 v) {
constexpr vec4<T>& operator*=(T1 v) {
x *= (T)v;
y *= (T)v;
z *= (T)v;
@@ -149,7 +149,7 @@ class vec4 {
}
template <typename T1>
vec4<T>& operator*=(const vec4<T1>& v) {
constexpr vec4<T>& operator*=(const vec4<T1>& v) {
x *= (T)v.x;
y *= (T)v.y;
z *= (T)v.z;
@@ -158,17 +158,17 @@ class vec4 {
}
template <typename T1>
vec4<T> operator*(T1 v) const {
constexpr vec4<T> operator*(T1 v) const {
return vec4<T>(x * (T)v, y * (T)v, z * (T)v, w * (T)v);
}
template <typename T1>
vec4<T> operator*(const vec4<T1>& v) const {
constexpr vec4<T> operator*(const vec4<T1>& v) const {
return vec4<T>(x * (T)v.x, y * (T)v.y, z * (T)v.z, w * (T)v.w);
}
template <typename T1>
vec4<T>& operator/=(T1 v) {
constexpr vec4<T>& operator/=(T1 v) {
x /= (T)v;
y /= (T)v;
z /= (T)v;
@@ -177,7 +177,7 @@ class vec4 {
}
template <typename T1>
vec4<T>& operator/=(const vec4<T1>& v) {
constexpr vec4<T>& operator/=(const vec4<T1>& v) {
x /= (T)v.x;
y /= (T)v.y;
z /= (T)v.z;
@@ -186,31 +186,31 @@ class vec4 {
}
template <typename T1>
vec4<T> operator/(T1 v) const {
constexpr vec4<T> operator/(T1 v) const {
return vec4<T>(x / (T)v, y / (T)v, z / (T)v, w / (T)v);
}
template <typename T1>
vec4<T> operator/(const vec4<T1>& v) const {
constexpr vec4<T> operator/(const vec4<T1>& v) const {
return vec4<T>(x / (T)v.x, y / (T)v.y, z / (T)v.z, w / (T)v.w);
}
// Generic Operations
vec4 operator-() const { return vec4(-x, -y, -z, -w); }
constexpr vec4 operator-() const { return vec4(-x, -y, -z, -w); }
template <typename T1>
bool operator==(const vec4<T1>& v) const {
constexpr bool operator==(const vec4<T1>& v) const {
return x == (T)v.x && y == (T)v.y && z == (T)v.z && w == (T)v.w;
}
template <typename T1>
bool operator!=(const vec4<T1>& v) const {
constexpr bool operator!=(const vec4<T1>& v) const {
return !(*this == v);
}
// Functions
double Len() const { return std::sqrt(SqLen()); }
double SqLen() const { return x * x + y * y + z * z + w * w; }
constexpr double SqLen() const { return x * x + y * y + z * z + w * w; }
template <typename T1>
double Distance(const vec4<T1>& v) const {
@@ -226,37 +226,37 @@ class vec4 {
}
template <typename T1>
T Dot(const vec4<T1>& v) const {
constexpr T Dot(const vec4<T1>& v) const {
return x * (T)v.x + y * (T)v.y + z * (T)v.z + w * (T)v.w;
}
// Swap Functions
void SwapXY() {
constexpr void SwapXY() {
T t = x;
x = y;
y = t;
}
void SwapXZ() {
constexpr void SwapXZ() {
T t = x;
x = z;
z = t;
}
void SwapXW() {
constexpr void SwapXW() {
T t = x;
x = w;
w = t;
}
void SwapYZ() {
constexpr void SwapYZ() {
T t = y;
y = z;
z = t;
}
void SwapYW() {
constexpr void SwapYW() {
T t = y;
y = w;
w = t;
}
void SwapZW() {
constexpr void SwapZW() {
T t = z;
z = w;
w = t;
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#include <pd/drivers/gfx.hpp>
#include <pd/drivers/hid.hpp>
#include <pd/drivers/os.hpp>
+275 -44
View File
@@ -2,67 +2,237 @@
#include <pd/core/mat.hpp>
#include <pd/drivers/interface.hpp>
#include <pd/lithium/command.hpp>
#include <pd/lithium/drawlist.hpp>
#include <pd/lithium/pools.hpp>
#include <pd/lithium/texture.hpp>
using LiBackendFlags = PD::u32;
enum LiBackendFlags_ {
LiBackendFlags_None = 0,
LiBackendFlags_FlipUV_Y = 1 << 0, // Essential for font loading
using PDGfxBackendFlags = PD::u32;
enum PDGfxBackendFlags_ {
PDGfxBackendFlags_None = 0,
PDGfxBackendFlags_FlipUV_Y = 1 << 0, // Essential for font loading
PDGfxBackendFlags_WindingCW = 1 << 0, // Use CW instead of CCW winding
};
namespace PD {
using TextureID = ptr;
enum class TextureFilter {
Linear,
Nearest,
};
enum class TextureFormat {
RGBA32,
A8,
};
// Pre interface class
class PD_API GfxDriver : public DriverInterface {
public:
GfxDriver(std::string_view name = "Default") : DriverInterface(name) {}
virtual ~GfxDriver() {}
GfxDriver(std::string_view name);
virtual ~GfxDriver();
virtual void Init() {}
virtual void Deinit() {}
virtual void Submit() {}
virtual void BindTexture(TextureID id) {}
virtual void Reset() {}
virtual TextureID LoadTexture(const std::vector<PD::u8>& pixels, int w, int h,
TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) {}
virtual void DeleteTexture(const TextureID& tex) {}
void Draw(const std::vector<Li::Command>& commands) {
CountCommands += commands.size();
// Bind shader
Projection = Mat4::Ortho(0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f);
// Shader Set Mtx
size_t index = 0;
while (index < commands.size()) {
CurrentTex = commands[index].Tex;
if (!CurrentTex) {
index++;
continue;
}
}
virtual void Deinit() {
DeleteTexture(pWhite);
SysDeinit();
}
private:
size_t CurrentIndex = 0;
size_t CurrentVertex = 0;
TextureID CurrentTex = 0;
Mat4 Projection;
ivec2 ViewPort;
void SetViewPort(const ivec2& size);
void SetViewPort(int x, int y);
virtual void BindTexture(TextureID id) {}
void Reset();
virtual Li::Texture LoadTexture(
const std::vector<PD::u8>& pixels, int w, int h,
TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) {
return Li::Texture();
}
virtual void DeleteTexture(const Li::Texture& tex) {}
virtual void Draw(const Li::Drawlist& commands) {}
Li::Texture::Ptr GetWhiteTexture() { return &pWhite; }
PDGfxBackendFlags GetFlags() { return Flags; }
size_t GetNumVertices() const { return CountVertices; }
size_t GetNumIndices() const { return CountIndices; }
size_t GetNumDrawcalls() const { return CountDrawcalls; }
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:
virtual void SysDeinit() {}
virtual void SysInit() {}
virtual void SysReset() {}
virtual void Submit(size_t count, size_t start) {}
virtual void UploadPools() {} // not every driver requires it
void RegisterTexture(const Li::Texture& tex);
void UnregisterTexture(const Li::Texture& tex);
// Counters
size_t CountDrawcalls = 0;
size_t CountCommands = 0;
size_t CountVertices = 0;
size_t CountIndices = 0;
size_t CurrentIndex = 0;
size_t CurrentVertex = 0;
size_t pCountDrawcalls = 0;
size_t pCountCommands = 0;
// State Variables oder so
TextureID CurrentTex = 0;
bool CurrentTexIsSDF = false;
Mat4 Projection;
ivec2 ViewPort;
std::unordered_map<TextureID, Li::Texture> pTextureRegestry;
Li::Texture pWhite;
PDGfxBackendFlags Flags = 0;
};
struct DefaultGfxConfig {
// Vertex Allocator
template <typename T>
using VertexAlloc = std::allocator<T>;
// Index Allocator
template <typename T>
using IndexAlloc = std::allocator<T>;
};
template <typename Config = DefaultGfxConfig>
class GfxDriverBase : public GfxDriver {
public:
using VtxPool =
Pool<Li::Vertex, typename Config::template VertexAlloc<Li::Vertex>>;
using IdxPool = Pool<u16, typename Config::template VertexAlloc<u16>>;
GfxDriverBase(std::string_view name = "Default") : GfxDriver(name) {}
virtual ~GfxDriverBase() {}
void Init() override {
SysInit();
std::vector<u8> img(16 * 16 * 4, 0xff);
pWhite = LoadTexture(img, 16, 16);
}
void Draw(const Li::Drawlist& dl) override {
const auto& commands = dl.Data();
if (commands.size() == 0) return;
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(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 ioff = start_idx;
while (index < commands.size()) {
CurrentTex = commands[index].Tex;
CurrentTexIsSDF = commands[index].SDF;
if (!CurrentTex) {
CurrentTex = pWhite.GetID();
}
size_t num_indices = 0;
while (index < commands.size() &&
CurrentTexIsSDF == commands[index].SDF &&
(CurrentTex == commands[index].Tex ||
(CurrentTex == pWhite.GetID() && commands[index].Tex == 0))) {
num_indices += commands[index].IndexCount;
index++;
}
if (num_indices > 0) {
Submit(num_indices, ioff);
ioff += num_indices;
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:
u16* GetIndexBufPtr(size_t start) { return &pIdxPool[start]; }
Li::Vertex* GetVertexBufPtr(size_t start) { return &pVtxPool[start]; }
size_t GetVertexPoolSize() const { return pVtxPool.size(); }
size_t GetIndexPoolSize() const { return pIdxPool.size(); }
private:
VtxPool pVtxPool;
IdxPool pIdxPool;
PD::ptr pVertexAccessor = 0;
PD::ptr pIndexAccessor = 0;
};
class PD_API Gfx {
@@ -76,6 +246,67 @@ class PD_API Gfx {
driver = std::make_unique<T>(std::forward<Args>(args)...);
}
static void Init() { driver->Init(); }
static void Deinit() { driver->Deinit(); }
static void SetViewPort(const ivec2& vp) { driver->SetViewPort(vp); }
static void SetViewPort(int w, int h) { driver->SetViewPort(w, h); }
static void Reset() { driver->Reset(); }
static void Draw(const Li::Drawlist& dl) { driver->Draw(dl); }
static Li::Texture LoadTexture(const std::vector<PD::u8>& pixels, int w,
int h,
TextureFormat type = TextureFormat::RGBA32,
TextureFilter filter = TextureFilter::Linear) {
return driver->LoadTexture(pixels, w, h, type, filter);
}
static void DeleteTexture(const Li::Texture& tex) {
driver->DeleteTexture(tex);
}
static Li::Texture::Ptr GetWhiteTexture() {
return driver->GetWhiteTexture();
}
static PDGfxBackendFlags GetFlags() { return driver->GetFlags(); }
static const char* GetDriverName() { return driver->GetName(); }
static size_t GetNumVertices() { return driver->GetNumVertices(); }
static size_t GetNumIndices() { return driver->GetNumIndices(); }
static size_t GetNumDrawcalls() { return driver->GetNumDrawcalls(); }
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:
static std::unique_ptr<GfxDriver> driver;
};
+183
View File
@@ -0,0 +1,183 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/drivers/interface.hpp>
using PDHidBackendFlags = PD::u32;
enum PDHidBackendFlags_ {
PDHidBackendFlags_None = 0,
PDHidBackendFlags_HasTouch = 1 << 1,
PDHidBackendFlags_HasGamepad = 1 << 2,
PDHidBackendFlags_HasMouse = 1 << 3,
PDHidBackendFlags_HasKeyboard = 1 << 4,
};
namespace PD {
namespace HidInternal {
class Keyboard {
public:
Keyboard() = default;
virtual ~Keyboard() = default;
using Key = u128;
constexpr static Key No = 0;
constexpr static Key Escape = Key::Flag(0);
constexpr static Key Q = Key::Flag(1);
constexpr static Key W = Key::Flag(2);
constexpr static Key E = Key::Flag(3);
constexpr static Key R = Key::Flag(4);
constexpr static Key T = Key::Flag(5);
constexpr static Key Z = Key::Flag(6);
constexpr static Key U = Key::Flag(7);
constexpr static Key I = Key::Flag(8);
constexpr static Key O = Key::Flag(9);
constexpr static Key P = Key::Flag(10);
constexpr static Key A = Key::Flag(11);
constexpr static Key S = Key::Flag(12);
constexpr static Key D = Key::Flag(13);
constexpr static Key F = Key::Flag(14);
constexpr static Key G = Key::Flag(15);
constexpr static Key H = Key::Flag(16);
constexpr static Key J = Key::Flag(17);
constexpr static Key K = Key::Flag(18);
constexpr static Key L = Key::Flag(19);
constexpr static Key Y = Key::Flag(20);
constexpr static Key X = Key::Flag(21);
constexpr static Key C = Key::Flag(22);
constexpr static Key V = Key::Flag(23);
constexpr static Key B = Key::Flag(24);
constexpr static Key N = Key::Flag(25);
constexpr static Key M = Key::Flag(26);
constexpr static Key _1 = Key::Flag(27);
constexpr static Key _2 = Key::Flag(28);
constexpr static Key _3 = Key::Flag(29);
constexpr static Key _4 = Key::Flag(30);
constexpr static Key _5 = Key::Flag(31);
constexpr static Key _6 = Key::Flag(32);
constexpr static Key _7 = Key::Flag(33);
constexpr static Key _8 = Key::Flag(34);
constexpr static Key _9 = Key::Flag(35);
constexpr static Key _0 = Key::Flag(36);
constexpr static Key F1 = Key::Flag(37);
constexpr static Key F2 = Key::Flag(38);
constexpr static Key F3 = Key::Flag(39);
constexpr static Key F4 = Key::Flag(40);
constexpr static Key F5 = Key::Flag(41);
constexpr static Key F6 = Key::Flag(42);
constexpr static Key F7 = Key::Flag(43);
constexpr static Key F8 = Key::Flag(44);
constexpr static Key F9 = Key::Flag(45);
constexpr static Key F10 = Key::Flag(46);
constexpr static Key F11 = Key::Flag(47);
constexpr static Key F12 = Key::Flag(48);
constexpr static Key MouseLeft = Key::Flag(120);
};
using GamepadKey = u32;
enum Gamepad : GamepadKey {
None = 0, ///< No Key
A = 1 << 0, ///< A
B = 1 << 1, ///< B
X = 1 << 2, ///< X
Y = 1 << 3, ///< Y
Start = 1 << 4, ///< Start
Select = 1 << 5, ///< Select
L = 1 << 6, ///< L
R = 1 << 7, ///< R
DUp = 1 << 8, ///< Dpad Up
DDown = 1 << 9, ///< Dpad down
DLeft = 1 << 10, ///< Dpad left
DRight = 1 << 11, ///< Dpad right
CPUp = 1 << 12, ///< Cpad up
CPDown = 1 << 13, ///< cpad down
CPLeft = 1 << 14, ///< cpad left
CPRight = 1 << 15, ///< Cpad right
CSUp = 1 << 16, ///< Cstick up
CSDown = 1 << 17, ///< cstick down
CSLeft = 1 << 18, ///< cstick left
CSRight = 1 << 19, ///< cstick right
ZL = 1 << 20, ///< ZL
ZR = 1 << 21, ///< ZR
Touch = 1 << 22, ///< Touch
LStick = 1 << 23, ///< Left Stick
RStick = 1 << 24, ///< Right Stick
Up = DUp | CPUp, ///< DPad or CPad Up
Down = DDown | CPDown, ///< DPad or CPad Down
Left = DLeft | CPLeft, ///< DPad or CPad Left
Right = DRight | CPRight, ///< DPad or CPad Right
};
} // namespace HidInternal
// Pre interface class
class PD_API HidDriver : public DriverInterface {
public:
enum class Event {
Null, ///< Nothing happended
Down, ///< Key Pressed
Held, ///< Key held
Up, ///< Key released
};
HidDriver(std::string_view name = "HidNull");
virtual ~HidDriver();
virtual void Init() {}
virtual void Deinit() {}
virtual const fvec2& MousePos() const { return pMouse[0]; }
virtual const fvec2& MousePosLast() const { return pMouse[1]; }
virtual const fvec2& TouchPos() const { return pMouse[0]; }
virtual const fvec2& TouchPosLast() const { return pMouse[1]; }
virtual void Update();
virtual bool IsEvent(Event e, HidInternal::GamepadKey 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; }
protected:
void SwapTab();
PDHidBackendFlags pFlags = PDHidBackendFlags_None;
fvec2 pMouse[2]; // Current And last pos
fvec2 pLStick[2];
fvec2 pRStick[2];
std::unordered_map<u32, u32> pGamepad;
std::unordered_map<u128, u128> pKeyboard;
std::unordered_map<Event, u32> pGamepadEvents[2];
std::unordered_map<Event, u128> pKeyboardEvents[2];
};
class PD_API Hid {
public:
using Gamepad = HidInternal::Gamepad;
using Keyboard = HidInternal::Keyboard;
using Event = HidDriver::Event;
Hid() = default;
~Hid() = default;
template <typename T, typename... Args>
static void UseDriver(Args&&... args) {
// assert(driver == nullptr && "OS Driver already set");
driver = std::make_unique<T>(std::forward<Args>(args)...);
}
static void Init() { driver->Init(); }
static void Deinit() { driver->Deinit(); }
static const fvec2& MousePos() { return driver->MousePos(); }
static const fvec2& MousePosLast() { return driver->MousePosLast(); }
static const fvec2& TouchPos() { return driver->TouchPos(); }
static const fvec2& TouchPosLast() { return driver->TouchPosLast(); }
static void Update() { driver->Update(); }
static bool IsEvent(Event e, HidInternal::GamepadKey keys) {
return driver->IsEvent(e, keys);
}
static bool IsEvent(Event e, HidInternal::Keyboard::Key keys) {
return driver->IsEvent(e, keys);
}
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(); }
private:
static std::unique_ptr<HidDriver> driver;
};
} // namespace PD
+2
View File
@@ -26,6 +26,8 @@ class PD_API Os {
static u64 GetTime() { return driver->GetTime(); }
static u64 GetTimeNano() { return driver->GetTimeNano(); }
static const char* GetDriverName() { return driver->GetName(); }
private:
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
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include <pd/core/core.hpp>
namespace PD {
class PD_API Image {
public:
enum class Format {
RGBA, // bpp == 4
RGB, // bpp == 3
RGB565, // bpp == 2 (not supported in laoding)
BGR, // bpp == 3
ABGR, // bpp == 4
BGRA, // bpp == 4
};
Image();
Image(const std::string& path);
Image(const std::vector<u8>& buf);
Image(const std::vector<u8>& pixels, int w, int h, int bpp = 4);
~Image();
void Load(const std::string& path);
void Load(const std::vector<u8>& buf);
void Load(const u8* buf, size_t size);
void Copy(const std::vector<u8>& pixels, int w, int h, int bpp = 4);
const int& Width() const { return pSize.x; }
const int& Height() const { return pSize.y; }
const ivec2& Size() const { return pSize; }
const std::vector<u8>& data() const { return pData; }
std::vector<u8>& data() { return pData; }
operator const std::vector<u8>&() const { return pData; }
operator std::vector<u8>&() { return pData; }
operator const ivec2&() const { return pSize; }
operator const Format&() const { return pFormat; }
void Flip(bool horizontal = true, bool vertical = true);
static int Format2Bpp(Format fmt);
static Format GuessFmtFromBpp(int bpp);
void Convert(Format dst);
private:
std::vector<u8> pData;
ivec2 pSize;
Format pFormat = Format::RGBA;
};
} // namespace PD
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/lithium/texture.hpp>
namespace PD {
namespace Li {
enum class AtlasState {
Invalid,
ReqCreate,
ReqUpdate,
ReqDestroy,
};
class Atlas {
public:
Atlas() {}
~Atlas() {}
private:
AtlasState pState = AtlasState::Invalid;
TextureID pID;
};
} // namespace Li
} // namespace PD
+17 -8
View File
@@ -1,5 +1,6 @@
#pragma once
#include <cstddef>
#include <pd/core/pool.hpp>
#include <pd/lithium/vertex.hpp>
@@ -7,18 +8,26 @@ namespace PD {
namespace Li {
class Command {
public:
Command() {}
Command() { Reset(); }
~Command() {}
void Reserve(size_t vtx, size_t idx);
void Reset();
Command& Add(const Vertex& vtx);
Command& Add(u16 idx);
Command& Add(u16 a, u16 b, u16 c);
int Layer = 0;
ptr Tex = 0;
Vertex* FirstVertex = nullptr;
u16* FirstIndex = nullptr;
size_t VertexCount;
size_t IndexCount;
PD::Pool<Vertex>* pVpool;
PD::Pool<u16>* pIpool;
bool SDF = false;
size_t FirstVertex = 0;
size_t FirstIndex = 0;
size_t VertexCount = 0;
size_t IndexCount = 0;
// Todo: implement
size_t VertexCountMax = 0;
size_t IndexCountMax = 0;
};
} // namespace Li
} // namespace PD
+142
View File
@@ -0,0 +1,142 @@
#pragma once
#include <pd/lithium/command.hpp>
#include <pd/lithium/font.hpp>
#include <pd/lithium/texture.hpp>
using LiPathRectFlags = PD::u32;
enum LiPathRectFlags_ : PD::u32 {
LiPathRectFlags_None = 0,
LiPathRectFlags_KeepTopLeft = 1 << 0,
LiPathRectFlags_KeepTopRight = 1 << 1,
LiPathRectFlags_KeepBotRight = 1 << 2,
LiPathRectFlags_KeepBotLeft = 1 << 3,
LiPathRectFlags_KeepTop =
LiPathRectFlags_KeepTopLeft | LiPathRectFlags_KeepTopRight,
LiPathRectFlags_KeepBot =
LiPathRectFlags_KeepBotLeft | LiPathRectFlags_KeepBotRight,
LiPathRectFlags_KeepLeft =
LiPathRectFlags_KeepTopLeft | LiPathRectFlags_KeepBotLeft,
LiPathRectFlags_KeepRight =
LiPathRectFlags_KeepTopRight | LiPathRectFlags_KeepBotRight,
};
using LiDrawFlags = PD::u32;
enum LiDrawFlags_ : PD::u32 {
LiDrawFlags_None = 0,
LiDrawFlags_Close = 1 << 0,
LiDrawFlags_AA = 1 << 1,
};
namespace PD {
namespace Li {
class PD_API Drawlist {
public:
Drawlist();
~Drawlist();
/** Baisc */
void Merge(Drawlist& other);
void Copy(Drawlist& other);
void Optimize();
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& NewCommand();
bool HasCommands() { return pCommands.size() > 0; }
Command& GetLastCommand() { return pCommands[pCommands.size() - 1]; }
/** Path API */
void PathAdd(const fvec2& point) { pPath.Push(point); }
void PathAdd(float x, float y) { pPath.Push(fvec2(x, y)); }
void PathClear() { pPath.Reset(); }
/**
* @brief Reserve memory for the next PathAdd uses
* @note As path will autoexpant and keep the size this func is
* only for special use cases
*/
void PathReserve(size_t num) { pPath.ExpandIf(num); }
void PathStroke(const PD::Color& color, int t = 1,
LiDrawFlags flags = LiDrawFlags_None);
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 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 PathRectEx(const fvec2& tl, const fvec2& br, float r = 0.f,
LiPathRectFlags flags = LiPathRectFlags_None);
/** Texture Handling */
void BindTexture(const Texture& tex);
void UnbindTexture() { pCurrentTexture = Texture(); }
/** Font Handling */
void SetFont(Font* font) { pFont = font; }
void SetFontscale(float fontscale = 1.f) { pFontScale = fontscale; }
const float& GetFontScale() const { return pFontScale; }
/** Data geters */
const Pool<Command>& Data() const { return pCommands; }
operator const Pool<Command>&() const { return pCommands; }
/** Drawing functions */
void DrawRect(const fvec2& pos, const fvec2& size, const PD::Color& color,
int t = 1);
void DrawRectFilled(const fvec2& pos, const fvec2& size,
const PD::Color& color);
void DrawTriangle(const fvec2& a, const fvec2& b, const fvec2& c,
const PD::Color& color, int t = 1);
void DrawTriangleFilled(const fvec2& a, const fvec2& b, const fvec2& c,
const PD::Color& color);
void DrawCircle(const fvec2& center, float rad, const PD::Color& color,
int num_segments, int t = 1);
void DrawCircleFilled(const fvec2& center, float rad, const PD::Color& color,
int num_segments);
void DrawText(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));
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,
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& a,
const PD::Color b, float rad = 0.f);
void PrimQuad(Command& cmd, const Rect& quad, const Rect& uv,
const PD::Color& color);
void PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b,
const fvec2& c, const PD::Color& color);
private:
Texture pCurrentTexture;
int pCurrentLayer = 0;
Pool<Command> pCommands;
Pool<fvec2> pPath;
Pool<Vertex> pVertices;
Pool<u16> pIndices;
Font* pFont = nullptr;
float pFontScale = 1.f;
};
} // namespace Li
} // namespace PD
+125
View File
@@ -0,0 +1,125 @@
#pragma once
#include <pd/lithium/texture.hpp>
using LiTextFlags = PD::u32;
enum LiTextFlags_ : PD::u32 {
LiTextFlags_None = 0, ///< Do nothing
LiTextFlags_AlignRight = 1 << 0, ///< Align Right of position
LiTextFlags_AlignMid = 1 << 1, ///< Align in the middle of pos and box
LiTextFlags_Shaddow = 1 << 2, ///< Draws the text twice to create shaddow
LiTextFlags_Wrap = 1 << 3, ///< Wrap Text: May be runs better with TMS
LiTextFlags_Short = 1 << 4, ///< Short Text: May be runs better with TMS
LiTextFlags_Scroll = 1 << 5, ///< Not implemented [scoll text if to long]
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 Li {
class Drawlist;
class PD_API Font {
public:
struct Codepoint {
u32 pCodepoint = 0;
fvec4 SimpleUV;
size_t Tex = 0;
fvec2 Size;
fvec2 Offset;
// float Offset = 0.f;
float AdvanceX = 0.f;
bool pInvalid = false;
};
Font() {}
~Font() {}
bool IsMonospace() { return pFlags & LiFontFlags_Monospace; }
bool IsSDF() { return pFlags & LiFontFlags_SDF; }
/**
* Load a TTF File
* @param path Path to the TTF file
* @param px_height Pixelheight of the codepoints (limit by 64)
*/
void LoadTTF(const std::string& path, int px_height = 32,
LiFontFlags flags = LiFontFlags_None);
/**
* Load a TTF File from Memory
* @param data File data
* @param px_height Pixelheight of the codepoints (limit by 64)
*/
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
* @return codepoint dataholder reference
*/
Codepoint& GetCodepoint(u32 c);
/**
* Get Text Bounding Box
*/
fvec2 GetTextBounds(const char* text, float scale);
/**
* Extended Draw Text Function that vreates a Command List
*/
void CmdTextEx(Drawlist& dl, const fvec2& pos, u32 color, float scale,
const char* text, LiTextFlags flags = 0, const fvec2& box = 0);
/**
* Cleanup Font and unload Textures
*/
void Delete();
/**
* Garbage collection for TextMapSystem
*/
void CleanupTMS();
/**
* Utility function to create a font atlas
* During TTF loading (Internal and should not be called)
*/
void BakeAndPush(bool final, std::vector<u8>& font_tex, int texszs);
std::string pWrapText(const std::string& txt, float scale,
const PD::fvec2& max, PD::fvec2& dim);
std::string pShortText(const std::string& txt, float scale,
const PD::fvec2& max, PD::fvec2& dim);
/** Data Section */
int PixelHeight = 0;
int DefaultPixelHeight = 32;
std::vector<TextureID> Textures;
/**
* 32Bit Codepoint Dataholder reference map
* **Now using unordered map**
*/
std::unordered_map<u32, Codepoint> CodeMap;
/** need some performance tweaks */
std::array<Codepoint, 128> pAsciiCache;
/** TMS */
struct TMELEM {
PD::u32 ID;
PD::fvec2 Size;
std::string Text;
u64 TimeStamp;
};
std::unordered_map<u32, TMELEM> pTMS;
private:
size_t pCurrentTex = 0;
LiFontFlags pFlags = 0;
};
} // namespace Li
} // namespace PD
+122
View File
@@ -0,0 +1,122 @@
#pragma once
#include <pd/lithium/atlas.hpp>
#include <pd/lithium/command.hpp>
#include <pd/lithium/rect.hpp>
#include <pd/lithium/texture.hpp>
#include <pd/lithium/vertex.hpp>
template <>
struct std::formatter<PD::TextureFilter> {
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PD::TextureFilter& value, FormatContext& ctx) const {
std::string_view ret = "Unknown";
switch (value) {
case PD::TextureFilter::Linear:
ret = "Linear";
break;
case PD::TextureFilter::Nearest:
ret = "Nearest";
break;
}
return std::format_to(ctx.out(), "{}", ret);
}
};
template <>
struct std::formatter<PD::TextureFormat> {
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PD::TextureFormat& value, FormatContext& ctx) const {
std::string_view ret = "Unknown";
switch (value) {
case PD::TextureFormat::RGBA32:
ret = "RGBA32";
break;
case PD::TextureFormat::RGB24:
ret = "RGB24";
break;
case PD::TextureFormat::A8:
ret = "A8";
break;
}
return std::format_to(ctx.out(), "{}", ret);
}
};
template <>
struct std::formatter<PD::Li::Rect> : std::formatter<std::string> {
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PD::Li::Rect& value, FormatContext& ctx) const {
// {l, t, r, t, l, b, r, b}
return std::format_to(ctx.out(), "{}, {}, {}, {}, {}, {}, {}, {}",
value.Top.x, value.Top.y, value.Top.z, value.Top.w,
value.Bot.x, value.Bot.y, value.Bot.z, value.Bot.w);
}
};
template <>
struct std::formatter<PD::Li::Texture> : std::formatter<std::string> {
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PD::Li::Texture& value, FormatContext& ctx) const {
// {ID, [w, h], [l, t, r, t, l, b, r, b]}
return std::format_to(ctx.out(), "{}, [{}], [{}]", value.GetID(),
value.GetSize(), value.GetUV());
}
};
template <>
struct std::formatter<PD::Li::Vertex> : std::formatter<std::string> {
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PD::Li::Vertex& value, FormatContext& ctx) const {
// { [x, y], [u, v], colorhex }
return std::format_to(ctx.out(), "[{}], [{}], #{:08X}", value.pos, value.uv,
value.color);
}
};
template <>
struct std::formatter<PD::Li::AtlasState> : std::formatter<std::string> {
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PD::Li::AtlasState& value, FormatContext& ctx) const {
std::string_view ret = "Unknown";
switch (value) {
case PD::Li::AtlasState::Invalid:
ret = "Invalid";
break;
case PD::Li::AtlasState::ReqCreate:
ret = "RequestCreate";
break;
case PD::Li::AtlasState::ReqUpdate:
ret = "RequestUpdate";
break;
case PD::Li::AtlasState::ReqDestroy:
ret = "RequestDestroy";
break;
}
return std::format_to(ctx.out(), "{}", ret);
}
};
template <>
struct std::formatter<PD::Li::Command> : std::formatter<std::string> {
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PD::Li::Command& value, FormatContext& ctx) const {
return std::format_to(ctx.out(), "[0x{:X}, 0x{:X}] [{}, {}] 0x{:X}",
(PD::ptr)value.FirstVertex, (PD::ptr)value.FirstIndex,
value.VertexCount, value.IndexCount, value.Tex);
}
};
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <pd/lithium/command.hpp>
#include <pd/lithium/drawlist.hpp>
#include <pd/lithium/font.hpp>
#include <pd/lithium/math.hpp>
#include <pd/lithium/pools.hpp>
#include <pd/lithium/vertex.hpp>
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/lithium/rect.hpp>
namespace PD {
namespace Li {
namespace Math {
PD_API bool InBounds(const fvec2& pos, const fvec2& size, const fvec4& rect);
PD_API bool InBounds(const fvec2& pos, const fvec4& rect);
PD_API bool InBounds(const fvec2& a, const fvec2& b, const fvec2& c,
const fvec4& rect);
PD_API bool InSpace(const PD::fvec2& pos, const Rect& rect);
PD_API void RotateCorner(fvec2& pos, float sinus, float cosinus);
PD_API Rect PrimRect(const fvec2& pos, const fvec2& size, float angle = 0.f);
PD_API Rect PrimLine(const fvec2& a, const fvec2& b, int t = 1);
} // namespace Math
} // namespace Li
} // namespace PD
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/lithium/vertex.hpp>
namespace PD {
namespace Li {
PD_API PD::Pool<Vertex>& GetVertexPool();
PD_API PD::Pool<u16>& GetIndexPool();
PD_API void ResetPools();
} // namespace Li
} // namespace PD
+152
View File
@@ -0,0 +1,152 @@
#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 Li {
class Rect {
public:
constexpr Rect() : Top(0), Bot(0) {}
~Rect() = default;
/**
* Constructor that initializes the rectangle using top and bottom positions.
* @param t Top left and right corner positions.
* @param b Bottom left and right corner positions.
*/
constexpr Rect(const fvec4& t, const fvec4& b) {
Top = t;
Bot = b;
}
/**
* Constructor that initializes the rectangle using individual corner
* positions.
* @param tl Top left corner position.
* @param tr Top right corner position.
* @param bl Bottom left corner position.
* @param br Bottom right corner position.
*/
constexpr Rect(const fvec2& tl, const fvec2& tr, const fvec2& bl,
const fvec2& br) {
Top = fvec4(tl, tr);
Bot = fvec4(bl, br);
}
/**
* Constructor that initializes the rectangle using a UV mapping vector.
*
* - The old API used vec4 for UV mapping.
* - Spritesheets have rotated images, so this was updated to use Rect for UV.
*
* @param uv Vec4 UV map.
*/
constexpr Rect(const fvec4& uv) {
Top = vec4(uv.x, uv.y, uv.z, uv.y);
Bot = vec4(uv.x, uv.w, uv.z, uv.w);
}
/**
* Get the top-left corner position.
* @return Top-left position as vec2.
*/
constexpr fvec2 TopLeft() const { return fvec2(Top.x, Top.y); }
/**
* Get the top-right corner position.
* @return Top-right position as vec2.
*/
constexpr fvec2 TopRight() const { return fvec2(Top.z, Top.w); }
/**
* Get the bottom-left corner position.
* @return Bottom-left position as vec2.
*/
constexpr fvec2 BotLeft() const { return fvec2(Bot.x, Bot.y); }
/**
* Get the bottom-right corner position.
* @return Bottom-right position as vec2.
*/
constexpr fvec2 BotRight() const { return fvec2(Bot.z, Bot.w); }
/**
* Set the top-left corner position.
* @param v New top-left position.
* @return Reference to the updated Rect.
*/
constexpr Rect& TopLeft(const fvec2& v) {
Top.x = v.x;
Top.y = v.y;
return *this;
}
/**
* Set the top-right corner position.
* @param v New top-right position.
* @return Reference to the updated Rect.
*/
constexpr Rect& TopRight(const fvec2& v) {
Top.z = v.x;
Top.w = v.y;
return *this;
}
/**
* Set the bottom-left corner position.
* @param v New bottom-left position.
* @return Reference to the updated Rect.
*/
constexpr Rect& BotLeft(const fvec2& v) {
Bot.x = v.x;
Bot.y = v.y;
return *this;
}
/**
* Set the bottom-right corner position.
* @param v New bottom-right position.
* @return Reference to the updated Rect.
*/
constexpr Rect& BotRight(const fvec2& v) {
Bot.z = v.x;
Bot.w = v.y;
return *this;
}
constexpr bool operator==(const Rect& r) const {
return Top == r.Top && Bot == r.Bot;
}
constexpr void SwapVec2XY() {
Top.SwapXY();
Top.SwapZW();
Bot.SwapXY();
Bot.SwapZW();
}
/** Data Section */
fvec4 Top;
fvec4 Bot;
};
} // namespace Li
} // namespace PD
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/lithium/rect.hpp>
namespace PD {
using TextureID = ptr;
enum class TextureFilter {
Linear,
Nearest,
};
enum class TextureFormat {
RGBA32,
RGB24,
A8,
};
namespace Li {
inline int TextureFormat2Bpp(TextureFormat fmt) {
switch (fmt) {
case PD::TextureFormat::A8:
return 1;
case PD::TextureFormat::RGB24:
return 3;
case PD::TextureFormat::RGBA32:
return 4;
default:
return 0;
}
}
class Texture {
public:
using Ptr = Texture*;
Texture() : pID(0), pSize(0, 0), pUV(fvec4(0, 0, 1, 1)) {}
Texture(TextureID id, ivec2 size)
: pID(id), pSize(size), pUV(fvec4(0, 0, 1, 1)) {}
const ivec2& GetSize() const { return pSize; }
TextureID GetID() { return pID; }
const TextureID& GetID() const { return pID; }
const Rect& GetUV() const { return pUV; }
void SetSize(int x, int y) {
pSize.x = x;
pSize.y = y;
}
void SetSize(const ivec2& size) { pSize = size; }
void SetID(TextureID id) { pID = id; }
void SetUV(const Rect& uv) { pUV = uv; }
void SetUV(const fvec4& uv) { pUV = uv; }
void SetUV(float t, float l, float b, float r) { SetUV(fvec4(t, l, b, r)); }
private:
TextureID pID;
ivec2 pSize;
Rect pUV;
};
} // namespace Li
} // namespace PD
+8
View File
@@ -9,8 +9,16 @@ class Vertex {
Vertex() {}
Vertex(const fvec2& pos, const fvec2& uv, u32 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() {}
void Reset() {
pos = fvec2(0.f);
uv = fvec2(0.f);
color = 0x00000000;
}
fvec2 pos;
fvec2 uv;
u32 color = 0x00000000;
+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)) {}
~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>
+102
View File
@@ -0,0 +1,102 @@
#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
};
/**
* 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
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/lithium/lithium.hpp>
#include <pd/ultra/flags.hpp>
namespace PD {
namespace Ultra {
class PD_API Canvas {
public:
Canvas();
Canvas(const PD::fvec2& size);
~Canvas();
void SetVirtualViewport(const PD::fvec2& size);
void SetViewport(const PD::fvec2& size);
PD::fvec2 VTranslatePos(const PD::fvec2& p) const;
PD::fvec2 VTranslateAlignPos(const PD::fvec2& pos, const PD::fvec2& size,
UltraAlignment align) const;
PD::Li::Rect VTranslateObject(const PD::fvec2& pos, const PD::fvec2& size,
UltraAlignment align,
bool size_modified = false) const;
PD::Li::Rect TranslateObject(const PD::fvec2& pos, const PD::fvec2& size,
UltraAlignment align,
bool size_modified = false) const;
PD::fvec2 TranslatePos(const PD::fvec2& p) const;
PD::fvec2 VTranslateSize(const PD::fvec2& s) const;
PD::fvec2 TranslateSize(const PD::fvec2& s) const;
float VTranslateFontscale(float f) const;
float TranslateFontscale(float f) const;
const PD::u32& GetRevision() const;
private:
PD::fvec2 pViewport;
PD::fvec2 pVirtualViewPort;
float pVfactor = 0.f;
PD::fvec2 pVoff;
PD::u32 pRev; // revision
};
} // namespace Ultra
} // namespace PD
+45
View File
@@ -0,0 +1,45 @@
#pragma once
#include <pd/lithium/lithium.hpp>
#include <pd/ultra/canvas.hpp>
#include <pd/ultra/elems/element.hpp>
namespace PD {
namespace Ultra {
class Container {
public:
Container() {}
Container(const PD::Li::Rect& r) : pRect(r) {}
virtual ~Container() {}
void Push(PD::Ultra::ElementBase& elem) {
elem.SetParent(this);
pElems.Push(&elem);
}
void Reset() { pElems.ResetFast(); }
const PD::Li::Rect& GetRenderspace() const { return pRect; }
void SetViewport(const PD::fvec2& vp) {
pCanvas.SetViewport(vp);
pRect = PD::fvec4(PD::fvec2(0), vp);
}
void SetBaseViewport(const PD::ivec2& vp) { pCanvas.SetVirtualViewport(vp); }
const PD::fvec2 GetTopLeft() const { return pRect.TopLeft(); }
const PD::fvec2 GetTopRight() const { return pRect.TopRight(); }
const PD::fvec2 GetBotLeft() const { return pRect.BotLeft(); }
const PD::fvec2 GetBotRight() const { return pRect.BotRight(); }
const PD::fvec2 GetSize() const { return pRect.BotRight() - pRect.TopLeft(); }
const PD::fvec2 GetPosition() const { return pRect.TopLeft(); }
const Canvas& GetCanvas() const { return pCanvas; }
protected:
PD::Pool<PD::Ultra::ElementBase*>& GetElements() { return pElems; }
private:
PD::Li::Rect pRect;
Canvas pCanvas;
PD::Pool<PD::Ultra::ElementBase*> pElems;
};
} // namespace Ultra
} // namespace PD
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/ultra/elems/element.hpp>
namespace PD {
namespace Ultra {
class PD_API Button : public ElementBase {
public:
Button() {}
Button(const PD::fvec2& pos, const PD::fvec2& size, const PD::Color& color,
float rounding = 0.f, UltraAlignment align = 0)
: pColor(color), pRounding(rounding) {
this->pAlignment = align;
this->pPos = pos;
this->pSize = size;
}
Button(float x, float y, float w, float h, const PD::Color& color,
float rounding = 0.f, UltraAlignment align = 0)
: pColor(color), pRounding(rounding) {
this->pAlignment = align;
this->pPos = PD::fvec2(x, y);
this->pSize = PD::fvec2(w, h);
}
~Button() {}
void Draw(PD::Li::Drawlist& l) override;
void Update() override;
void SetColor(const PD::Color& color) { pColor = color; }
void SetFocusedColor(const PD::Color& color) { pHovered = color; }
void SetTextColor(const PD::Color& color) { pTextColor = color; }
void SetRounding(float r) { pRounding = r; }
void SetLined(bool v) { pLined = v; }
void SetThickness(int v) { pThickness = v; }
void SetText(const std::string& text) { pText = text; }
void SetAutoSizePadding(const PD::fvec2& size) { pAsp = size; }
// Discard these funcs
void OnFocus(EventFunc func) override {}
void OnUnFocus(EventFunc func) override {}
private:
std::string pText;
PD::Color pRenderColor;
PD::Color pColor;
PD::Color pHovered;
PD::Color pTextColor;
float pRounding = 0.f;
bool pLined = false;
int pThickness = 1.f;
// Auto-Size-Padding
PD::fvec2 pAsp = PD::fvec2(30, 10);
};
} // namespace Ultra
} // namespace PD
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include <functional>
#include <pd/lithium/lithium.hpp>
#include <pd/ultra/flags.hpp>
namespace PD {
namespace Ultra {
class Canvas;
class Container;
using EventFunc = std::function<void()>;
class PD_API ElementBase {
public:
ElementBase() {}
~ElementBase() {}
virtual void Draw(PD::Li::Drawlist& dl) = 0;
/**
* Reset Function (for PD::Pool::FastReset)
*/
virtual void Reset() {}
virtual void Update();
void SetAlignment(UltraAlignment a) { pAlignment = a; }
void SetPosition(const PD::fvec2& pos) { pPos = pos; }
void SetPosition(float x, float y) { pPos = PD::fvec2(x, y); }
void SetSize(const PD::fvec2& size) { pSize = size; }
void SetSize(float w, float h) { pSize = PD::fvec2(w, h); }
/**
* Executed on Hovering
* Elemnents can override / discard this func
*/
virtual void OnFocus(EventFunc func) { pHover = func; }
/**
* Executed on Mocing out of the space
* Elemnents can override / discard this func
*/
virtual void OnUnFocus(EventFunc func) { pUnHover = func; }
/**
* Executrd on KeyUp event
* Elemnents can override / discard this func
*/
virtual void OnPress(EventFunc func) { pPress = func; }
void SetFontScale(float s = 1.f) { pFontScale = 1.f; }
float GetFontScale() const { return pFontScale; }
void SetFont(PD::Li::Font& font) { pFont = &font; }
void SetFontIfNull(PD::Li::Font& font) {
if (!pFont) pFont = &font;
}
virtual void UpdateInput();
protected:
friend class Container;
void SetParent(Container* c) { pParent = c; }
bool RevisionUpdate(PD::u32 req);
Container* pParent = nullptr;
PD::u32 pCanvasRev = 0;
UltraAlignment pAlignment = 0;
PD::fvec2 pPos;
PD::fvec2 pSize;
PD::Li::Rect pRenderspace;
EventFunc pHover = nullptr;
EventFunc pUnHover = nullptr;
EventFunc pPress = nullptr;
bool pFocued = false;
// Not used by every object btw
PD::Li::Font* pFont = nullptr;
float pFontScale = 1.f;
};
} // namespace Ultra
} // namespace PD
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/ultra/elems/element.hpp>
namespace PD {
namespace Ultra {
class PD_API Image : public ElementBase {
public:
Image() {}
Image(PD::Li::Texture* tex, const PD::fvec2& pos, float rounding = 0.f,
UltraAlignment align = 0)
: pColor(0xffffffff), pRounding(rounding) {
this->pAlignment = align;
this->pPos = pos;
SetTexture(tex);
}
Image(PD::Li::Texture* tex, float x, float y, float rounding = 0.f,
UltraAlignment align = 0)
: pColor(0xffffffff), pRounding(rounding) {
this->pAlignment = align;
this->pPos = PD::fvec2(x, y);
SetTexture(tex);
}
~Image() {}
void Draw(PD::Li::Drawlist& l) override;
void SetColor(const PD::Color& color) { pColor = color; }
void SetRounding(float r) { pRounding = r; }
void SetTexture(PD::Li::Texture* tex) {
pTex = tex;
SetSize(pTex->GetSize());
}
private:
PD::Color pColor = 0xffffffff;
PD::Li::Texture* pTex = nullptr;
float pRounding = 0.f;
};
} // namespace Ultra
} // namespace PD
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/ultra/elems/element.hpp>
namespace PD {
namespace Ultra {
class PD_API Rect : public ElementBase {
public:
Rect() {}
Rect(const PD::fvec2& pos, const PD::fvec2& size, const PD::Color& color,
float rounding = 0.f, UltraAlignment align = 0)
: pColor(color), pRounding(rounding) {
this->pAlignment = align;
this->pPos = pos;
this->pSize = size;
}
Rect(float x, float y, float w, float h, const PD::Color& color,
float rounding = 0.f, UltraAlignment align = 0)
: pColor(color), pRounding(rounding) {
this->pAlignment = align;
this->pPos = PD::fvec2(x, y);
this->pSize = PD::fvec2(w, h);
}
~Rect() {}
void Draw(PD::Li::Drawlist& l) override;
void SetColor(const PD::Color& color) { pColor = color; }
void SetRounding(float r) { pRounding = r; }
void SetLined(bool v) { pLined = v; }
void SetThickness(int v) { pThickness = v; }
private:
PD::Color pColor;
float pRounding = 0.f;
bool pLined = false;
int pThickness = 1.f;
};
} // namespace Ultra
} // namespace PD
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <pd/core/core.hpp>
#include <pd/ultra/elems/element.hpp>
namespace PD {
namespace Ultra {
class PD_API Text : public ElementBase {
public:
Text() {}
~Text() {}
void Draw(PD::Li::Drawlist& l) override;
void Update() override;
void SetColor(const PD::Color& color) { pColor = color; }
void SetText(const std::string& text) { pText = text; }
private:
PD::Color pColor;
std::string pText;
};
} // namespace Ultra
} // namespace PD
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <pd/common.hpp>
using UltraAlignment = PD::u32;
enum UltraAlignment_ {
UltraAlignment_None = 0,
UltraAlignment_Top = 1 << 0,
UltraAlignment_Bot = 1 << 1,
UltraAlignment_Left = 1 << 2,
UltraAlignment_Right = 1 << 3,
UltraAlignment_CenterVertical = 1 << 4,
UltraAlignment_CenterHorizontal = 1 << 5,
UltraAlignment_TopLeft = UltraAlignment_Top | UltraAlignment_Left,
UltraAlignment_TopRight = UltraAlignment_Top | UltraAlignment_Right,
UltraAlignment_BotLeft = UltraAlignment_Bot | UltraAlignment_Left,
UltraAlignment_BotRight = UltraAlignment_Bot | UltraAlignment_Right,
UltraAlignment_Center =
UltraAlignment_CenterVertical | UltraAlignment_CenterHorizontal,
};
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <pd/ultra/canvas.hpp>
#include <pd/ultra/container.hpp>
#include <pd/ultra/elems/element.hpp>
namespace PD {
namespace Ultra {
class PD_API Layout : public Container {
public:
Layout() {}
~Layout() {}
/**
* Set a fallback font if you dont want to explicitly set a font for every
* objectt individually
*/
void SetFont(PD::Li::Font& font) { pFont = &font; }
void Render(PD::Li::Drawlist& list);
private:
PD::Li::Font* pFont = nullptr;
};
} // namespace Ultra
} // namespace PD
+34
View File
@@ -0,0 +1,34 @@
#include <iostream>
#include <pd/common.hpp>
namespace PD {
constexpr const char* pColorNo = "\033[0m";
constexpr const char* pColorYellow = "\033[33m";
constexpr const char* pColorRed = "\033[31m";
static LogLevel pFilter = LogLevel::Info;
PD_API void LogFilter(LogLevel lvl) { pFilter = lvl; }
PD_API void Log(const std::string& txt, LogLevel lvl) {
if ((int)lvl < (int)pFilter) return;
const char* clr = pColorNo;
const char* plvl = "INFO";
switch (lvl) {
case PD::LogLevel::None:
case PD::LogLevel::Info:
clr = pColorNo;
plvl = "INFO";
break;
case PD::LogLevel::Warning:
clr = pColorYellow;
plvl = "WARNING";
break;
case PD::LogLevel::Error:
clr = pColorRed;
plvl = "ERROR";
break;
}
std::cout << clr << "[PD][" << plvl << "] " << txt << pColorNo << std::endl;
}
} // namespace PD
+19 -4
View File
@@ -22,15 +22,30 @@ SOFTWARE.
*/
#include <pd/core/timetrace.hpp>
#include <pd/drivers/os.hpp>
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) {
auto trace = os.GetTraceRef(id);
trace->SetStart(os.GetNanoTime());
auto& trace = GetTraceRef(id);
trace.SetStart(PD::Os::GetTimeNano());
}
PD_API void End(const std::string& id) {
auto trace = os.GetTraceRef(id);
trace->SetEnd(os.GetNanoTime());
auto& trace = GetTraceRef(id);
trace.SetEnd(PD::Os::GetTimeNano());
}
} // namespace PD::TT
+52
View File
@@ -0,0 +1,52 @@
#include <pd/drivers/gfx.hpp>
#include <pd/lithium/formatters.hpp>
namespace PD {
PD_API std::unique_ptr<GfxDriver> Gfx::driver;
PD_API GfxDriver::GfxDriver(std::string_view name) : DriverInterface(name) {}
PD_API GfxDriver::~GfxDriver() {
if (pTextureRegestry.size()) {
PDERR("GfxDriver: {} is still holding {} texture{}!", GetName(),
pTextureRegestry.size(), (pTextureRegestry.size() == 1 ? "" : "s"));
}
}
PD_API void GfxDriver::SetViewPort(const ivec2& size) {
ViewPort = size;
Projection = Mat4::Ortho(0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f);
}
PD_API void GfxDriver::SetViewPort(int x, int y) {
ViewPort.x = x;
ViewPort.y = y;
Projection = Mat4::Ortho(0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f);
}
PD_API void GfxDriver::Reset() {
CountIndices = CurrentIndex;
CountVertices = CurrentVertex;
CurrentVertex = 0;
CurrentIndex = 0;
CountCommands = pCountCommands;
CountDrawcalls = pCountDrawcalls;
pCountCommands = 0;
pCountDrawcalls = 0;
SysReset();
}
PD_API void GfxDriver::RegisterTexture(const Li::Texture& tex) {
pTextureRegestry[tex.GetID()] = tex;
}
PD_API void GfxDriver::UnregisterTexture(const Li::Texture& tex) {
if (pTextureRegestry.count(tex.GetID())) {
pTextureRegestry.erase(pTextureRegestry.find(tex.GetID()));
PDLOG("GfxDriver: Texture {{ {} }} has been deleted!", tex);
} else {
PDWARN("GfxDriver: WARNING Texture {{ {} }} does not exist in regestry!",
tex);
}
}
} // namespace PD
+48
View File
@@ -0,0 +1,48 @@
#include <pd/drivers/hid.hpp>
namespace PD {
PD_API std::unique_ptr<HidDriver> Hid::driver;
PD_API HidDriver::HidDriver(std::string_view name) : DriverInterface(name) {}
PD_API HidDriver::~HidDriver() {}
PD_API bool HidDriver::IsEvent(Event e, HidInternal::GamepadKey keys) {
return pGamepadEvents[0][e] & keys;
}
PD_API bool HidDriver::IsEvent(Event e, HidInternal::Keyboard::Key keys) {
return pKeyboardEvents[0][e].Has(keys);
}
/**
* Todo: Keyboard support
*/
PD_API void HidDriver::SwapTab() {
auto tkd = pGamepadEvents[1][Event::Down];
auto tkh = pGamepadEvents[1][Event::Held];
auto tku = pGamepadEvents[1][Event::Up];
pGamepadEvents[1][Event::Down] = pGamepadEvents[0][Event::Down];
pGamepadEvents[1][Event::Held] = pGamepadEvents[0][Event::Held];
pGamepadEvents[1][Event::Up] = pGamepadEvents[0][Event::Up];
pGamepadEvents[0][Event::Down] = tkd;
pGamepadEvents[0][Event::Held] = tkh;
pGamepadEvents[0][Event::Up] = tku;
}
/**
* If this func has no verride, still clear the stats
* cause if they are empty this leads to a crash
*/
PD_API void HidDriver::Update() {
// Clear States
for (int i = 0; i < 2; i++) {
pGamepadEvents[i][Event::Down] = 0;
pGamepadEvents[i][Event::Held] = 0;
pGamepadEvents[i][Event::Up] = 0;
for (auto& it : pKeyboardEvents[i]) {
it.second = 0; // ? why was this Event_Null
}
}
pMouse[1] = pMouse[0]; // cycle here
}
} // namespace PD
+2 -2
View File
@@ -1,7 +1,7 @@
#include <pd/drivers/os.hpp>
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 {
return std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -10,7 +10,7 @@ PD_API u64 OsDriver::GetTime() 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())
.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
+164
View File
@@ -0,0 +1,164 @@
#include <pd/image/convert.hpp>
#include <pd/image/image.hpp>
#if defined(PD_INCLUDE_STB_IMAGE)
#define STB_IMAGE_IMPLEMENTATION
#endif
#include <stb_image.h>
namespace PD {
PD_API Image::Image() {}
PD_API Image::Image(const std::string& path) { Load(path); }
PD_API Image::Image(const std::vector<u8>& buf) { Load(buf); }
PD_API Image::Image(const std::vector<u8>& pixels, int w, int h, int bpp) {
Copy(pixels, w, h, bpp);
}
PD_API Image::~Image() {}
PD_API void Image::Load(const u8* buf, size_t size) {
int w = 0, h = 0, c = 0;
u8* img = stbi_load_from_memory(buf, size, &w, &h, &c, 4);
if (c == 3) {
stbi_image_free(img);
img = stbi_load_from_memory(buf, size, &w, &h, &c, 3);
pFormat = Format::RGB;
}
pData.assign(img, img + (w * h * c));
pSize = ivec2(w, h);
stbi_image_free(img);
}
PD_API void Image::Load(const std::string& path) {
int w = 0, h = 0, c = 0;
u8* img = stbi_load(path.c_str(), &w, &h, &c, 4);
if (c == 3) {
stbi_image_free(img);
img = stbi_load(path.c_str(), &w, &h, &c, 3);
pFormat = Format::RGB;
}
pData.assign(img, img + (w * h * c));
pSize = ivec2(w, h);
stbi_image_free(img);
}
PD_API void Image::Load(const std::vector<u8>& buf) {
Load(buf.data(), buf.size());
}
PD_API void Image::Copy(const std::vector<u8>& pixels, int w, int h, int bpp) {
pData = pixels;
pSize = ivec2(w, h);
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) {
switch (fmt) {
case Format::RGBA:
case Format::ABGR:
case Format::BGRA:
return 4;
case Format::BGR:
case Format::RGB:
return 3;
case Format::RGB565:
return 2;
}
return 0;
}
PD_API Image::Format Image::GuessFmtFromBpp(int bpp) {
/** Only return defaults here */
switch (bpp) {
case 4:
return Format::RGBA;
case 3:
return Format::RGB;
case 2:
return Format::RGB565;
default:
return Format::RGBA;
}
}
PD_API void Image::Flip(bool hz, bool vt) {
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
+87
View File
@@ -0,0 +1,87 @@
#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;
}
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
+392
View File
@@ -0,0 +1,392 @@
#include <algorithm>
#include <iostream>
#include <pd/drivers/gfx.hpp>
#include <pd/lithium/drawlist.hpp>
#include <pd/lithium/formatters.hpp>
#include <pd/lithium/math.hpp>
namespace PD {
namespace Li {
PD_API Drawlist::Drawlist() { Clear(); }
PD_API Drawlist::~Drawlist() { Clear(); }
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) {
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() {
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() {
UnbindTexture();
pPath.ResetFast();
pCommands.NoReset();
pCurrentLayer = 0;
}
/** Command Allocation */
PD_API Command& Drawlist::NewCommand() {
auto cmd = pCommands.Allocate(1);
cmd->Reset();
cmd->Layer = pCurrentLayer;
cmd->Tex = pCurrentTexture.GetID();
return *cmd;
}
PD_API void Drawlist::BindTexture(const Texture& tex) { pCurrentTexture = tex; }
/** Path API */
PD_API void Drawlist::PathStroke(const PD::Color& color, int t,
LiDrawFlags flags) {
DrawPolyLine(pPath, color, flags, t);
PathClear();
}
PD_API void Drawlist::PathFill(const PD::Color& color) {
DrawConvexPolyFilled(pPath, color);
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,
float amax, int s) {
// Path.push_back(c);
PathReserve(s + 1);
for (int i = 0; i < s; i++) {
float a = amin + ((float)i / (float)s) * (amax - amin);
PathAdd(vec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r));
}
}
PD_API void Drawlist::PathFastArcToN(const fvec2& c, float r, float amin,
float amax, int s) {
/**
* Funcion with less division overhead
* Usefull for stuff where a lot of calculations are required
*/
float d = (amax - amin) / s;
PathReserve(s + 1);
for (int i = 0; i <= s; i++) {
float a = amin + i * d;
PathAdd(fvec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r));
}
}
PD_API void Drawlist::PathRect(const fvec2& tl, const fvec2& br,
float rounding) {
if (rounding == 0.f) {
PathAdd(tl);
PathAdd(vec2(br.x, tl.y));
PathAdd(br);
PathAdd(vec2(tl.x, br.y));
} else {
float r = std::min({rounding, (br.x - tl.x) * 0.5f, (br.y - tl.y) * 0.5f});
/** Calculate Optimal segment count automatically */
float corner = M_PI * 0.5f;
int segments = std::max(3, int(std::ceil(corner / (6.0f * M_PI / 180.0f))));
/**
* To Correctly render filled shapes with Paths API
* The Commands need to be setup clockwise
*/
/** Top Left */
PathAdd(vec2(tl.x + r, tl.y));
PathFastArcToN(vec2(br.x - r, tl.y + r), r, -M_PI / 2.0f, 0.0f, segments);
/** Top Right */
PathAdd(vec2(br.x, br.y - r));
PathFastArcToN(vec2(br.x - r, br.y - r), r, 0.0f, M_PI / 2.0f, segments);
/** Bottom Right */
PathAdd(vec2(tl.x + r, br.y));
PathFastArcToN(vec2(tl.x + r, br.y - r), r, M_PI / 2.0f, M_PI, segments);
/** Bottom Left */
PathAdd(vec2(tl.x, tl.y + r));
PathFastArcToN(vec2(tl.x + r, tl.y + r), r, M_PI, 3.0f * M_PI / 2.0f,
segments);
}
}
PD_API void Drawlist::PathRectEx(const fvec2& tl, const fvec2& br,
float rounding, LiPathRectFlags flags) {
if (rounding == 0.f) {
PathAdd(tl);
PathAdd(vec2(br.x, tl.y));
PathAdd(br);
PathAdd(vec2(tl.x, br.y));
} else {
float r = std::min({rounding, (br.x - tl.x) * 0.5f, (br.y - tl.y) * 0.5f});
/** Calculate Optimal segment count automatically */
float corner = M_PI * 0.5f;
int segments = std::max(3, int(std::ceil(corner / (6.0f * M_PI / 180.0f))));
/**
* To Correctly render filled shapes with Paths API
* The Commands need to be setup clockwise
*/
/** Top Left */
if (flags & LiPathRectFlags_KeepTopLeft) {
PathAdd(tl);
} else {
PathAdd(vec2(tl.x + r, tl.y));
PathFastArcToN(vec2(br.x - r, tl.y + r), r, -M_PI / 2.0f, 0.0f, segments);
}
/** Top Right */
if (flags & LiPathRectFlags_KeepTopRight) {
PathAdd(vec2(br.x, tl.y));
} else {
PathAdd(vec2(br.x, br.y - r));
PathFastArcToN(vec2(br.x - r, br.y - r), r, 0.0f, M_PI / 2.0f, segments);
}
/** Bottom Right */
if (flags & LiPathRectFlags_KeepBotRight) {
PathAdd(br);
} else {
PathAdd(vec2(tl.x + r, br.y));
PathFastArcToN(vec2(tl.x + r, br.y - r), r, M_PI / 2.0f, M_PI, segments);
}
/** Bottom Left */
if (flags & LiPathRectFlags_KeepBotLeft) {
PathAdd(vec2(tl.x, br.y));
} else {
PathAdd(vec2(tl.x, tl.y + r));
PathFastArcToN(vec2(tl.x + r, tl.y + r), r, M_PI, 3.0f * M_PI / 2.0f,
segments);
}
}
}
/** Drawing functions */
PD_API void Drawlist::DrawRect(const fvec2& pos, const fvec2& size,
const PD::Color& color, int t) {
PathRect(pos, pos + size);
PathStroke(color, t, LiDrawFlags_Close);
}
PD_API void Drawlist::DrawRectFilled(const fvec2& pos, const fvec2& size,
const PD::Color& color) {
PathRect(pos, pos + size);
PathFill(color);
}
PD_API void Drawlist::DrawTriangle(const fvec2& a, const fvec2& b,
const fvec2& c, const PD::Color& color,
int t) {
PathAdd(a);
PathAdd(b);
PathAdd(c);
PathStroke(color, t, LiDrawFlags_Close);
}
PD_API void Drawlist::DrawTriangleFilled(const fvec2& a, const fvec2& b,
const fvec2& c,
const PD::Color& color) {
PathAdd(a);
PathAdd(b);
PathAdd(c);
PathFill(color);
}
PD_API void Drawlist::DrawCircle(const fvec2& center, float rad,
const PD::Color& color, int num_segments,
int t) {
if (num_segments <= 0) {
// Auto Segment
} else {
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
PathArcToN(center, rad, 0.f, am, num_segments);
}
UnbindTexture(); // Only Solid Color Supported
PathStroke(color, t, LiDrawFlags_Close);
}
PD_API void Drawlist::DrawCircleFilled(const fvec2& center, float rad,
const PD::Color& color,
int num_segments) {
if (num_segments <= 0) {
// Auto Segment
} else {
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
PathArcToN(center, rad, 0.f, am, num_segments);
}
PathFill(color);
}
PD_API void Drawlist::DrawText(const fvec2& p, const char* text,
const PD::Color& color) {
if (!pFont) return;
pFont->CmdTextEx(*this, p, color, pFontScale, text);
}
PD_API void Drawlist::DrawTextEx(const fvec2& p, const char* text,
const PD::Color& color, LiTextFlags flags,
const fvec2& box) {
if (!pFont) return;
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,
const PD::Color& color, LiDrawFlags flags,
int t) {
if (points.size() < 2) {
return;
}
UnbindTexture();
auto& cmd = NewCommand();
bool close = (flags & LiDrawFlags_Close);
int num_points = close ? (int)points.size() : (int)points.size() - 1;
if (flags & LiDrawFlags_AA) {
// TODO: Find a way to draw less garbage looking lines
} else {
// Non antialiased lines look awful when rendering with thickness != 1
for (int i = 0; i < num_points; i++) {
int j = (i + 1) == (int)points.size() ? 0 : (i + 1);
auto line = Math::PrimLine(points[i], points[j], t);
this->PrimQuad(cmd, line, vec4(0.f, 1.f, 1.f, 0.f), color);
}
}
}
PD_API void Drawlist::DrawConvexPolyFilled(const Pool<fvec2>& points,
const PD::Color& color) {
if (points.size() < 3) {
return; // Need at least three points
}
// Support for Custom Textures (UV calculation)
float minX = points[0].x, minY = points[0].y;
float maxX = minX, maxY = minY;
// Check for the max and min Positions
for (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();
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);
}
for (int i = 0; i < (int)points.size(); i++) {
// Calculate U and V coords
float u =
uv_tl.x + ((points[i].x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x);
float v =
uv_tl.y + ((points[i].y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y);
cmd.Add(Vertex(points[i], fvec2(u, v), color));
}
}
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,
const PD::Color& color) {
cmd.Reserve(4, 6);
cmd.Add(2, 1, 0);
cmd.Add(3, 2, 0);
cmd.Add(Vertex(quad.TopLeft(), uv.TopLeft(), color));
cmd.Add(Vertex(quad.TopRight(), uv.TopRight(), color));
cmd.Add(Vertex(quad.BotRight(), uv.BotRight(), color));
cmd.Add(Vertex(quad.BotLeft(), uv.BotLeft(), color));
}
PD_API void Drawlist::PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b,
const fvec2& c, const PD::Color& color) {
cmd.Reserve(3, 3);
cmd.Add(2, 1, 0);
cmd.Add(Vertex(a, vec2(0.f, 1.f), color));
cmd.Add(Vertex(b, vec2(1.f, 1.f), color));
cmd.Add(Vertex(c, vec2(1.f, 0.f), color));
}
} // namespace Li
} // namespace PD
+349
View File
@@ -0,0 +1,349 @@
#include <pd/core/core.hpp>
#include <pd/drivers/gfx.hpp>
#include <pd/lithium/drawlist.hpp>
#include <pd/lithium/font.hpp>
#include <pd/lithium/math.hpp>
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.h>
#include <map>
#include <utility>
namespace PD {
namespace Li {
PD_API void Font::LoadTTF(const std::string& path, int px_height,
LiFontFlags flags) {
/**
* Just use LoadFile2Mem which looks way cleaner
* and helps not having the font loading code twice
* when adding LoadTTF with mem support
*/
PDLOG("Font: Loading {}...", path);
TT::Scope st("LI_LoadTTF_" + path);
auto font = PD::IO::LoadFile2Mem(path);
PDLOG("Font Size: {}", PD::Strings::FormatBytes(font.size()));
LoadTTF(font, px_height, flags);
}
PD_API void Font::LoadTTF(const std::vector<u8>& data, int px_height,
LiFontFlags flags) {
/**
* Some additional Info:
* Removed the stbtt get bitmapbox as we dont need to place
* the glyps nicely in the tex. next step would be using the free
* space on the y axis to get mor glyphs inside
*/
pFlags = flags;
PixelHeight = px_height;
int texszs = PD::Bits::GetPow2(px_height * 16);
if (texszs > 1024) {
texszs = 1024; // Max size
}
stbtt_fontinfo inf;
if (!stbtt_InitFont(&inf, data.data(), 0)) {
return;
}
float scale = stbtt_ScaleForPixelHeight(&inf, PixelHeight);
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap);
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
std::map<u32, int> buf_cache;
std::vector<u8> font_tex(texszs * texszs, 0);
fvec2 off;
bool empty = true;
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);
if (gi == 0) 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;
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);
}
if (!bitmap || w <= 0 || h <= 0) {
if (bitmap) free(bitmap);
continue;
}
u32 hashed_map =
IO::HashMemory(std::vector<u8>(bitmap, bitmap + (w * h)));
if (buf_cache.find(hashed_map) != buf_cache.end()) {
Codepoint c = GetCodepoint(buf_cache[hashed_map]);
c.pCodepoint = ii;
CodeMap[ii] = c;
free(bitmap);
continue;
} else {
buf_cache[hashed_map] = ii;
}
// Next row
if (off.x + w > texszs) {
off.y += PixelHeight;
off.x = 0.0f;
}
// Bake cause we go out of the tex
if (off.y + PixelHeight > texszs) {
BakeAndPush(false, font_tex, texszs);
off = 0;
std::fill(font_tex.begin(), font_tex.end(), 0);
empty = true;
}
// UVs & Codepoint
Codepoint c;
fvec4 uvs;
// cast the ints to floats and not the floats...
// dont know where my mind was when creating the code
uvs.x = off.x / static_cast<float>(texszs);
uvs.y = off.y / static_cast<float>(texszs);
uvs.z = (off.x + w) / static_cast<float>(texszs);
uvs.w = (off.y + h) / static_cast<float>(texszs);
// Flip if needed
if (PD::Gfx::GetFlags() & PDGfxBackendFlags_FlipUV_Y) {
uvs.y = 1.f - uvs.y;
uvs.w = 1.f - uvs.w;
}
c.SimpleUV = uvs;
c.Tex = pCurrentTex;
c.Size = fvec2(w, h);
c.Offset = fvec2(xo + center_offset, baseline + yo);
c.AdvanceX = final_advance;
c.pCodepoint = ii;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int map_pos = ((static_cast<int>(off.y) + y) * texszs +
(static_cast<int>(off.x) + x));
font_tex[map_pos] = bitmap[x + y * w];
}
}
empty = false;
CodeMap[ii] = c;
free(bitmap);
// offset by 1 (prevents visual glitches i had)
off.x += w + 1;
}
}
if (!empty) {
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) {
if (c < 128) {
// Direct Access (~11% improvement)
return pAsciiCache[c];
}
// Check if codepoijt exist or return a static invalid one
auto res = CodeMap.find(c);
if (res == CodeMap.end()) {
static Codepoint invalid;
invalid.pInvalid = true;
return invalid;
}
return res->second;
}
PD_API fvec2 Font::GetTextBounds(const char* text, float scale) {
// Create a temp position and offset as [0, 0]
fvec2 res;
float x = 0;
// Curent Font Scale
float cfs = (DefaultPixelHeight * scale) / (float)PixelHeight;
float lh = (float)PixelHeight * cfs;
U8Iterator it(text);
u32 c;
while (it.Decode32(c)) {
auto cp = GetCodepoint(c);
if ((cp.pInvalid && c != L'\n' && c != L'\t' && c != L' ') && c != L'\r')
continue;
if (c == L'\n') {
res.y += lh;
res.x = std::max(res.x, x);
x = 0.f;
continue;
}
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.y += lh;
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,
float scale, const char* text, LiTextFlags flags,
const fvec2& box) {
fvec2 off;
float cfs = (DefaultPixelHeight * scale) / (float)PixelHeight;
float lh = (float)PixelHeight * cfs;
fvec2 td;
fvec2 rpos = pos;
fvec2 rbox = box;
if (flags & (LiTextFlags_AlignMid | LiTextFlags_AlignRight)) {
td = GetTextBounds(text, scale);
}
if (flags & LiTextFlags_AlignMid) rpos = rbox * 0.5 - td * 0.5 + pos;
if (flags & LiTextFlags_AlignRight) rpos.x -= td.x;
U8Iterator it(text);
u32 c;
Command* cmd = dl.HasCommands() ? &dl.GetLastCommand() : nullptr;
while (it.Decode32(c)) {
auto cp = GetCodepoint(c);
if ((cp.pInvalid && c != L'\n' && c != L'\t' && c != L' ') && c != L'\r')
continue;
if (c == L'\n') {
off.y += lh;
off.x = 0.f;
continue;
}
if (c == L'\t') {
off.x += (cp.AdvanceX > 0 ? cp.AdvanceX : 16.f) * 4.f * cfs;
continue;
}
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;
cmd = &dl.NewCommand();
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) {
PrimTextQuad(*cmd, cx + 1.f, cy + 1.f, cw, ch, cp.SimpleUV, 0xff111111);
}
PrimTextQuad(*cmd, cx, cy, cw, ch, cp.SimpleUV, color);
}
off.x += cp.AdvanceX * cfs;
}
}
PD_API void Font::CleanupTMS() {}
PD_API void Font::BakeAndPush(bool final, std::vector<u8>& font_tex,
int texszs) {
auto t = PD::Gfx::LoadTexture(font_tex, texszs, texszs, TextureFormat::A8);
PDLOG("Font: Texture backed as 0x{:X} at {}", t.GetID(), pCurrentTex);
Textures.push_back(t.GetID());
pCurrentTex = Textures.size();
}
PD_API std::string Font::pWrapText(const std::string& txt, float scale,
const PD::fvec2& max, PD::fvec2& dim) {
return "";
}
PD_API std::string Font::pShortText(const std::string& txt, float scale,
const PD::fvec2& max, PD::fvec2& dim) {
return "";
}
PD_API void Font::Delete() {
for (auto& it : Textures) {
// Creating a tmp fake Li tex for deletion
PD::Gfx::DeleteTexture(PD::Li::Texture(it, 0));
}
pCurrentTex = 0;
PixelHeight = 0;
pTMS.clear();
CodeMap.clear();
}
} // namespace Li
} // namespace PD
+71
View File
@@ -0,0 +1,71 @@
#include <pd/lithium/math.hpp>
namespace PD {
namespace Li {
namespace Math {
PD_API bool InBounds(const fvec2& pos, const fvec2& size, const fvec4& rect) {
return (pos.x + size.x >= rect.x && pos.y + size.y >= rect.y &&
pos.x <= rect.z && pos.y <= rect.w);
}
PD_API bool InBounds(const fvec2& pos, const fvec4& rect) {
return (pos.x > rect.x && pos.x < rect.x + rect.z && pos.y > rect.y &&
pos.y < rect.y + rect.w);
}
PD_API bool InBounds(const fvec2& a, const fvec2& b, const fvec2& c,
const fvec4& rect) {
return ((a.x < rect.z && b.x < rect.z && c.x < rect.z) ||
(a.y < rect.w && b.y < rect.w && c.y < rect.w) ||
(a.x > 0 && b.x > 0 && c.x > 0) || (a.y > 0 && b.y > 0 && c.y > 0));
}
PD_API bool InSpace(const PD::fvec2& pos, const Rect& rect) {
return (pos.x > rect.Top.x && pos.x < rect.Top.z && pos.y > rect.Top.y &&
pos.y < rect.Bot.y);
}
PD_API void RotateCorner(fvec2& pos, float sinus, float cosinus) {
float x = pos.x * cosinus - pos.y * sinus;
float y = pos.y * cosinus - pos.x * sinus;
pos = fvec2(x, y);
}
PD_API Rect PrimRect(const fvec2& pos, const fvec2& size, float a) {
fvec2 c = size * 0.5f; // Center
fvec2 corner[4] = {
fvec2(-c.x, -c.y),
fvec2(-c.x + size.x, -c.y),
fvec2(-c.x, -c.y + size.y),
fvec2(-c.x + size.x, -c.y + size.y),
};
// Only rotate if required
if (a != 0.f) {
float s = std::sin(a);
float co = std::cos(a);
for (int i = 0; i < 4; i++) {
RotateCorner(corner[i], s, co);
}
}
// Return Result
return Rect(corner[0] + pos + c, corner[1] + pos + c, corner[2] + pos + c,
corner[3] + pos + c);
}
PD_API Rect PrimLine(const fvec2& a, const fvec2& b, int t) {
// Using the vec maths api makes the code as short as it is
vec2 dir = a - b;
float len = dir.Len();
if (len == 0.0f) return Rect();
vec2 unit_dir = dir / len;
vec2 perpendicular(-unit_dir.y, unit_dir.x);
vec2 off = perpendicular * ((float)t * 0.5f);
return Rect(a + off, b + off, a - off, b - off);
}
} // namespace Math
} // namespace Li
} // namespace PD
+16
View File
@@ -0,0 +1,16 @@
#include <pd/lithium/pools.hpp>
namespace PD {
namespace Li {
static PD::Pool<Vertex> gVertexPool;
static PD::Pool<u16> gIndexPool;
PD_API PD::Pool<Vertex>& GetVertexPool() { return gVertexPool; }
PD_API PD::Pool<u16>& GetIndexPool() { return gIndexPool; }
PD_API void ResetPools() {
gVertexPool.NoReset();
gIndexPool.NoReset();
}
} // namespace Li
} // 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

Some files were not shown because too many files have changed in this diff Show More