Compare commits

...

286 Commits

Author SHA1 Message Date
ba80aebfae Merge pull request #181 from orange-cpp/feature/walk-bot
Feature/walk bot
2026-04-14 15:23:49 +03:00
9c1b6d0ba3 added tests improved API 2026-04-12 21:21:23 +03:00
ea07d17dbb improved walkbot 2026-04-12 12:05:40 +03:00
bb974da0e2 improvement 2026-04-12 11:16:39 +03:00
fde764c1fa added code 2026-04-12 11:12:17 +03:00
va_alpatov
28e86fc355 tests hotfix 2026-04-11 20:23:08 +03:00
va_alpatov
93e7a9457a fixed pathfinding bug 2026-04-11 20:06:39 +03:00
8f65183882 fixed tests 2026-04-08 15:34:10 +03:00
327db8d441 updated contributing 2026-04-03 20:59:34 +03:00
d8188de736 keeping 1 AABB type 2026-03-28 14:22:36 +03:00
33cd3f64e4 Merge pull request #180 from orange-cpp/feature/aabb-linetrace
added aabb line trace
2026-03-25 03:37:35 +03:00
67a07eed45 added aabb line trace 2026-03-25 03:14:22 +03:00
0b52b2847b Merge pull request #179 from orange-cpp/feature/aabb_check
added AABB check
2026-03-24 10:45:00 +03:00
d38895e4d7 added AABB check 2026-03-24 10:20:50 +03:00
04203d46ff patch 2026-03-24 06:44:10 +03:00
bcbb5c1a8d fixed index 2026-03-24 06:05:56 +03:00
ba46c86664 simplified method 2026-03-24 06:03:35 +03:00
3b0470cc11 Merge pull request #178 from orange-cpp/feature/imrovements
Feature/imrovements
2026-03-24 05:55:47 +03:00
8562c5d1f2 added more unreachable checks 2026-03-24 05:28:01 +03:00
8daba25c29 added ureachable 2026-03-24 05:21:00 +03:00
29b7ac6450 Merge pull request #177 from orange-cpp/feature/custom_ndc_z_range
Feature/custom ndc z range
2026-03-24 04:20:57 +03:00
89df10b778 specifeid ndc for game engines 2026-03-24 00:08:06 +03:00
8fb96b83db removed dead code 2026-03-23 23:52:41 +03:00
4b6db0c402 updated z range 2026-03-23 23:36:19 +03:00
a9ff7868cf simplified code 2026-03-23 05:52:35 +03:00
be80a5d243 added as_vector3 to view angles 2026-03-23 05:23:53 +03:00
881d3b9a2a added fields 2026-03-22 19:07:38 +03:00
f60e18b6ba replaced with table offset 2026-03-22 18:58:07 +03:00
0769d3d079 replaced with auto 2026-03-22 17:30:25 +03:00
b6755e21f9 fix 2026-03-22 16:32:00 +03:00
2287602fa2 Merge pull request #176 from orange-cpp/feature/vtable_index
added stuff
2026-03-22 16:21:39 +03:00
663890706e test fix 2026-03-22 16:06:57 +03:00
ab103f626b swaped to std::uintptr_t 2026-03-22 16:05:09 +03:00
cc4e01b100 added stuff 2026-03-22 16:00:35 +03:00
308f7ed481 forgot return 2026-03-21 16:43:18 +03:00
8802ad9af1 fix 2026-03-21 16:41:03 +03:00
2ac508d6e8 fixed tests 2026-03-21 16:28:48 +03:00
eb1ca6055b added additional error code 2026-03-21 16:15:48 +03:00
b528e41de3 fixed test names 2026-03-21 15:45:22 +03:00
8615ab2b7c changed name, fixed bug 2026-03-21 15:22:02 +03:00
5a4c042fec replaced enum 2026-03-21 14:53:04 +03:00
8063c1697a improved interface 2026-03-21 14:41:07 +03:00
7567501f00 Merge pull request #175 from orange-cpp/feature/w2s_no_clip
added clip option
2026-03-21 14:12:07 +03:00
46d999f846 added clip option 2026-03-21 13:58:06 +03:00
b54601132b added doc build to release 2026-03-21 06:32:05 +03:00
5c8ce2d163 Merge pull request #174 from orange-cpp/feature/docs-pipelines
added docs pipeline
2026-03-21 06:26:21 +03:00
04a86739b4 added docs pipeline 2026-03-21 06:11:20 +03:00
575b411863 updated install md 2026-03-21 06:05:29 +03:00
5a91151bc0 fix 2026-03-19 20:27:25 +03:00
66d4df0524 fix 2026-03-19 20:17:10 +03:00
54e14760ca fix 2026-03-19 20:09:07 +03:00
ee61c47d7d Merge pull request #173 from orange-cpp/feature/targeting_algorithms
Feature/targeting algorithms
2026-03-19 19:52:22 +03:00
d737aee1c5 added by distance targeting 2026-03-19 19:29:01 +03:00
ef422f0a86 added overload 2026-03-19 19:23:39 +03:00
e99ca0bc2b update 2026-03-19 19:19:42 +03:00
5f94e36965 fix for windows specific suff related to far near macroses 2026-03-19 15:32:05 +03:00
29510cf9e7 Removed from credit by own request 2026-03-19 15:24:35 +03:00
927508a76b Merge pull request #172 from orange-cpp/feaute/methods_calling_improvement
Feaute/methods calling improvement
2026-03-19 01:33:42 +03:00
f390b386d7 fix 2026-03-19 01:06:16 +03:00
012d837e8b fix windows x32 bit 2026-03-19 00:57:54 +03:00
6236c8fd68 added nodiscard 2026-03-18 21:24:35 +03:00
06dc36089f added overload 2026-03-18 21:19:09 +03:00
91136a61c4 improvement 2026-03-18 21:12:18 +03:00
9cdffcbdb1 added tests 2026-03-18 20:12:46 +03:00
a3e93ac259 added nttp 2026-03-18 20:05:32 +03:00
59f6d7a361 added call_method 2026-03-18 19:58:52 +03:00
dcf1ef1ea9 Merge pull request #171 from orange-cpp/feaute/projectile_pred_improvement
Feaute/projectile pred improvement
2026-03-17 21:58:59 +03:00
89bd879187 added tolerance depending on arch 2026-03-17 21:15:39 +03:00
aa08c7cb65 improved projectile prediction 2026-03-17 20:43:26 +03:00
a5c0ca0cbd added stuff 2026-03-17 20:31:46 +03:00
624683aed6 added unreachanble 2026-03-17 19:53:15 +03:00
f46672b2c6 Merge pull request #170 from orange-cpp/feature/projectile_aim_widget
add projectile
2026-03-17 19:51:12 +03:00
b8e61f49fa add projectile 2026-03-17 19:36:35 +03:00
37ea091282 Merge pull request #169 from orange-cpp/feaute/hud_features
Feaute/hud features
2026-03-16 14:39:58 +03:00
29a2743728 renamed args 2026-03-16 13:17:16 +03:00
1117eb37f1 added icon 2026-03-16 13:13:41 +03:00
b6b0d4db13 added aim dot 2026-03-16 03:24:53 +03:00
2e8a74aaaf imroved spacer 2026-03-16 03:06:14 +03:00
d8632dc74c added progress ring 2026-03-16 03:03:23 +03:00
fd531c930c added spacer 2026-03-16 02:21:24 +03:00
a91673216d added const 2026-03-16 02:10:05 +03:00
6487554844 corrected code style 2026-03-16 01:54:45 +03:00
1744172694 updated credits 2026-03-15 20:42:13 +03:00
114b2a6e58 Update README to enhance library description and features 2026-03-15 20:21:08 +03:00
d90a85d8b6 Merge pull request #168 from orange-cpp/feature/hud_declarative
Feature/hud declarative
2026-03-15 20:02:32 +03:00
e0a7179812 fix 2026-03-15 19:43:55 +03:00
a99dd24d6b improvement 2026-03-15 19:39:02 +03:00
d62dec9a8f changed api 2026-03-15 19:10:15 +03:00
1a176d8f09 fix 2026-03-15 18:48:22 +03:00
8e6ed19abf added dashed bar 2026-03-15 18:39:40 +03:00
311ab45722 Merge pull request #167 from orange-cpp/feaute/sig_scan_file_in_mem
added stuff
2026-03-15 17:37:42 +03:00
130277c1ae refactored test 2026-03-15 17:20:28 +03:00
4f1c42d6f6 tests fix 2026-03-15 17:04:21 +03:00
ccea4a0f0d added stuff 2026-03-15 16:54:47 +03:00
3fb98397e4 Merge pull request #166 from orange-cpp/feature/hud_improvement
Feature/hud improvement
2026-03-15 14:01:33 +03:00
56256c40fb cleaned code 2026-03-15 13:47:41 +03:00
46c94ae541 decomposed Run 2026-03-15 13:44:25 +03:00
a45f095b9c added skeleton 2026-03-15 04:59:47 +03:00
e849d23c47 improved dashed box 2026-03-15 04:56:10 +03:00
adad66599a adde dash box 2026-03-15 04:49:01 +03:00
69bdfc3307 improved example 2026-03-15 04:43:19 +03:00
55304c5df1 fixed bug 2026-03-15 04:28:56 +03:00
19d796cd4e improvement 2026-03-15 04:23:07 +03:00
d31ea6ed4d added more stuff 2026-03-15 04:17:30 +03:00
977d772687 fix 2026-03-13 22:20:57 +03:00
746f1b84a8 hot fix 2026-03-13 22:16:42 +03:00
af399a14ed Merge pull request #165 from orange-cpp/feature/hud
Feature/hud
2026-03-13 22:11:26 +03:00
6fb420642b updated props 2026-03-13 21:58:14 +03:00
6a2b4b90b4 fix 2026-03-13 21:49:56 +03:00
371d8154ee fix 2026-03-13 21:40:30 +03:00
d6a2165f83 fix 2026-03-13 21:37:03 +03:00
bb1b5ad14a removed shit 2026-03-13 21:32:44 +03:00
f188257e0f added stuff 2026-03-13 21:28:16 +03:00
87966c82b9 added realization 2026-03-13 21:09:12 +03:00
9da19582b5 added files 2026-03-13 20:51:59 +03:00
29f3e2565d Merge pull request #164 from orange-cpp/feaute/disk_optimization
avoid saving files on disk
2026-03-13 03:55:56 +03:00
e083b15e0b update 2026-03-13 03:42:12 +03:00
ed9da79d08 avoid saving files on disk 2026-03-13 03:33:57 +03:00
2002bcca83 Merge pull request #163 from orange-cpp/feature/serailization
Feature/serailization
2026-03-11 14:47:23 +03:00
ffacba71e2 changed to string view 2026-03-11 14:31:45 +03:00
6081a9c426 added throw test 2026-03-11 14:30:01 +03:00
8bbd504356 added check 2026-03-11 14:23:12 +03:00
1d54039f57 added events 2026-03-11 14:19:58 +03:00
93fc93d4f6 added more tests 2026-03-11 14:16:26 +03:00
b8a578774c improved serialization 2026-03-11 14:12:52 +03:00
bfa6c77776 Merge pull request #162 from orange-cpp/feature/scanner_example
Auto stash before checking out "origin/main"
2026-03-10 21:39:20 +03:00
1341ef9925 Auto stash before checking out "origin/main" 2026-03-10 20:06:00 +03:00
3ccbb0b25b Merge pull request #161 from orange-cpp/feature/lua-bindings
Feature/lua bindings
2026-03-10 19:41:34 +03:00
68993db48a updated read me 2026-03-10 19:22:39 +03:00
337204b3bf fixed missing source 2026-03-10 19:09:29 +03:00
1e601d2d8f android fix 2026-03-10 19:01:54 +03:00
2b4a75d011 added lua status to build logs 2026-03-10 19:00:36 +03:00
99a30e8fdf added pattern scan to lua 2026-03-10 18:55:55 +03:00
0cdd1d021f added triangle to lua 2026-03-10 18:39:20 +03:00
a79ac9743a added badge, added triangle 2026-03-10 18:39:10 +03:00
f26afb703b added bigobj for msvc and mingw 2026-03-10 18:29:13 +03:00
f237ee5f6a removed useless headers 2026-03-10 18:15:54 +03:00
9058ea9b39 refactored to class 2026-03-10 18:14:29 +03:00
f707ac1adb fixed forward decl 2026-03-10 18:04:31 +03:00
cbdabd3fc2 removed useless header 2026-03-10 17:57:11 +03:00
30e3feb4f8 fix 2026-03-10 16:38:00 +03:00
0726fdef32 webasm fix 2026-03-10 16:31:49 +03:00
0ffe0c2bdc potential fix 2026-03-10 16:24:21 +03:00
e9600ad42b splited lua into multiple sources 2026-03-10 16:15:02 +03:00
673835618c restructurized stuff 2026-03-10 15:57:22 +03:00
afb2a13dd6 added color 2026-03-08 23:08:23 +03:00
943472cf64 migrated to sol2
decomposed method

added vector2, vector4

refactored tests

added opengl engine to lua

added other engines

added source tests

removed tons of lua files
2026-03-08 12:55:35 +03:00
9752accb14 Merge pull request #160 from orange-cpp/feaure/gjk-epa-improvement
Feaure/gjk epa improvement
2026-03-03 18:25:37 +03:00
7373e6d3df added std namspace to int64_t type 2026-03-03 10:00:46 +03:00
68f4c8cc72 added nodiscard 2026-03-03 09:38:05 +03:00
2dafc8a49d added additional method 2026-03-03 09:22:11 +03:00
11fe49e801 added const 2026-03-03 08:51:13 +03:00
dee705a391 improvement 2026-03-03 08:43:30 +03:00
bfe147ef80 Merge remote-tracking branch 'orange-cpp/feaure/gjk-epa-improvement' into feaure/gjk-epa-improvement 2026-03-03 08:27:50 +03:00
2c70288a8f added epa tests 2026-03-03 08:27:26 +03:00
529322fe34 decomposed method 2026-03-03 08:14:12 +03:00
414b2af289 added gjk tests 2026-03-02 19:58:31 +03:00
a79ad6948c optimized 2026-03-02 19:40:45 +03:00
ea2c7c3d7f added benchmark 2026-03-02 19:40:37 +03:00
91c2e0d74b Merge pull request #159 from orange-cpp/feature/color_update
Feature/color update
2026-03-01 13:53:18 +03:00
52e9b906ff added const 2026-03-01 13:32:13 +03:00
cc6d625c2d added more formaters 2026-03-01 13:30:32 +03:00
5eaec70846 fixed tests 2026-03-01 13:22:15 +03:00
2063c4d33a updated color 2026-03-01 13:15:09 +03:00
60bf8ca30f moved file 2026-03-01 13:00:24 +03:00
6fca106edc Merge pull request #158 from orange-cpp/feature/quaternions
added files
2026-03-01 09:04:18 +03:00
78cb644920 added files 2026-03-01 08:23:26 +03:00
646a920e4c fixed potential deadlock 2026-02-27 08:47:46 +03:00
52687a70c7 fixed formating 2026-02-27 07:41:05 +03:00
a9eff7d320 Merge pull request #157 from orange-cpp/feature/mesh_improvement
Feature/mesh improvement
2026-02-26 16:39:21 +03:00
211e4c3d9b optimization 2026-02-26 16:19:54 +03:00
74dc2234f7 fixed collider when rotated 2026-02-26 16:17:41 +03:00
7ebbed6763 added funding
edit
2026-02-23 07:18:25 +03:00
e271bccaf5 added codeowners 2026-02-23 06:45:43 +03:00
50765f69c5 removed unused var 2026-02-23 04:36:48 +03:00
1169534133 fix 2026-02-23 04:32:13 +03:00
783501aab9 Enhance installation guide with prebuilt binaries section
Updated vcpkg section and added instructions for using prebuilt binaries from GitHub Releases.
2026-02-21 10:00:19 +03:00
1a79566731 Merge pull request #156 from orange-cpp/copilot/add-automatic-binary-attach
Add release workflow with binary uploads for all CI platforms
2026-02-21 09:31:12 +03:00
copilot-swe-agent[bot]
9183406e7a Add all CI pipeline platforms to release workflow (Linux x86, iOS, FreeBSD, Android, WebAssembly, MinGW)
Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>
2026-02-21 04:55:36 +00:00
copilot-swe-agent[bot]
b592af91a9 Add release workflow to automatically attach binaries to new releases
Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>
2026-02-21 04:45:20 +00:00
copilot-swe-agent[bot]
af9c043e95 Initial plan 2026-02-21 04:41:46 +00:00
2aaa8633b9 updated tag 2026-02-20 09:07:33 +03:00
0d1cc2088f Merge pull request #155 from orange-cpp/feaute/examples-folders
retructurized examples
2026-02-20 08:55:20 +03:00
260b3b97f9 fix 2026-02-20 08:53:03 +03:00
e0904690e6 fixed formating 2026-02-20 08:52:26 +03:00
7021d9d365 fixed formating 2026-02-20 08:46:43 +03:00
862d52593a retructurized examples 2026-02-20 07:48:19 +03:00
97a3111791 fixed code style 2026-02-20 04:02:26 +03:00
a9bec00973 Merge pull request #154 from luadebug/example1
Example with opengl triangle
2026-02-20 03:37:58 +03:00
Saikari
66debb46fa Refactor to use Color class and Triangle structure for better clarity in drawing functions 2026-02-20 03:01:34 +03:00
Saikari
b8323d3bc0 simplify complexity 2026-02-20 02:56:27 +03:00
Saikari
f363fa6f1a Fix text 2026-02-20 02:53:20 +03:00
Saikari
0546272493 Use dot not quad 2026-02-20 02:50:55 +03:00
Saikari
58801bfab3 Add one more example 2026-02-20 02:43:27 +03:00
4567cfa318 updated read me 2026-02-19 12:03:19 +03:00
1db9340dbf updated read me 2026-02-19 08:42:58 +03:00
7b9a181b0e Merge pull request #153 from orange-cpp/feature/cryengine-support
Feature/cryengine support
2026-02-19 08:34:33 +03:00
0876af3c14 added warning back 2026-02-19 08:34:21 +03:00
e46a369ddc added more tests 2026-02-19 08:06:34 +03:00
630ffa69f6 clang format 2026-02-19 08:00:23 +03:00
609970cdfe fix 2026-02-19 07:57:04 +03:00
e935155022 improved tests 2026-02-19 07:47:23 +03:00
800082e4b3 added mesh 2026-02-19 06:35:08 +03:00
02d909f77d added mesh trait 2026-02-19 01:06:08 +03:00
49319a1c7c added more files 2026-02-19 01:05:09 +03:00
d0f3e5059a added formulas 2026-02-19 01:05:09 +03:00
c9874f30d0 add 2026-02-19 01:05:09 +03:00
3080faeaa9 hotfix: projectile prediction 2026-02-19 01:01:38 +03:00
af36c909a4 improved simple game 2026-02-18 07:38:04 +03:00
1041256fac Revert "removed useless include"
This reverts commit 88012e2524.
2026-02-18 06:07:27 +03:00
88012e2524 removed useless include 2026-02-18 05:53:16 +03:00
4561dbe0e7 fix 2026-02-18 05:51:46 +03:00
b50f759675 more template stuff 2026-02-18 05:51:18 +03:00
85b672fdf3 Merge pull request #152 from orange-cpp/feature/camera_improvement
added more methods
2026-02-17 07:57:35 +03:00
360734f252 added more methods 2026-02-17 07:39:45 +03:00
1e215f3ff5 added more lfs file extensions 2026-02-15 16:43:08 +03:00
ca5f8cd328 moved another file to lfs 2026-02-15 15:49:51 +03:00
5e40a09b2e Merge pull request #151 from orange-cpp/feature/lfs
update
2026-02-15 15:38:19 +03:00
87e291d3b9 update 2026-02-15 15:35:58 +03:00
af44c918a2 removed psd file 2026-02-15 15:24:10 +03:00
0774a27d20 added site doc folder to gitignore 2026-02-14 20:55:48 +03:00
e212f66b85 added vscode config 2026-02-12 23:13:37 +03:00
6d0109edbc fix 2026-02-08 20:57:10 +03:00
58f1045e88 Merge pull request #148 from orange-cpp/feature/engine-units-to-metric
Feature/engine units to metric
2026-02-08 03:28:54 +03:00
fbd2543644 added tests 2026-02-08 03:15:21 +03:00
815b42159a added frostbite tests 2026-02-08 03:03:23 +03:00
dfc564b30d added for other engines 2026-02-08 02:58:59 +03:00
58a592a806 improved naming 2026-02-08 02:51:48 +03:00
4c92dbe1ed added for source 2026-02-08 02:43:10 +03:00
0145e0455c Merge pull request #146 from orange-cpp/feature/line_tracer_template
improvement
2026-02-06 00:14:15 +03:00
e91a2d7853 fixed warnings 2026-02-06 00:02:00 +03:00
9dc9b2cca2 added noexcept 2026-02-05 23:45:41 +03:00
268eff0f3f simplified shit 2026-02-05 23:43:17 +03:00
092b23993b added constexpr 2026-02-05 23:38:51 +03:00
1c844fe488 removed uselss c++ file 2026-02-05 23:31:14 +03:00
6490bf13ed improvement 2026-02-05 23:27:31 +03:00
e328f58a8e Merge pull request #145 from orange-cpp/feature/macho_improvement
Feature/macho improvement
2026-02-04 19:27:44 +03:00
41d09c5699 fixed bug 2026-02-04 19:10:06 +03:00
d14e77883a removed nesting 2026-02-04 18:35:04 +03:00
ca39dc20c1 removed nesting 2026-02-04 18:33:05 +03:00
02810fb0f3 fixed codestyle 2026-02-04 18:30:45 +03:00
3aa1e23025 added resharper ignore segment 2026-02-04 18:29:55 +03:00
Copilot
53fdff64e2 Add Mach-O pattern scanner (#144)
* Initial plan

* Add Mach-O pattern scanner implementation and unit tests

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

* Add Mach-O pattern scanner

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

* Remove CodeQL build artifacts from PR

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>
2026-02-04 17:30:20 +03:00
9a1a622dad Merge pull request #143 from luadebug/opengl
fix `pixi run examples` for linux
2026-01-30 16:00:50 +03:00
Saikari
4630bd6dcf do similiar for aarch64 linux 2026-01-30 05:13:27 +03:00
Saikari
7d25101344 add pixi.lock to gitignore 2026-01-30 05:06:14 +03:00
Saikari
e48532bcb9 fix pixi run examples for linux 2026-01-30 05:04:50 +03:00
Saikari
32b3113556 Add initial project configuration and build scripts for omath library
- Created pixi.toml for project metadata and dependencies management.
- Added formatting script (fmt.cmake) to ensure consistent CMake file formatting.
- Implemented benchmark execution script (run.benchmark.cmake) to run benchmark tests.
- Developed example execution script (run.examples.cmake) to run example applications.
- Created unit test execution script (run.unit.tests.cmake) to run unit tests.

removed lock file
2026-01-30 02:36:34 +03:00
7bff17e46c updated tag 2026-01-29 20:09:36 +03:00
e12c6b1824 removed unity build completely 2026-01-29 20:06:18 +03:00
50ceb54eaa Merge pull request #139 from orange-cpp/feature/mesh_line_tracer
Feature/mesh line tracer
2026-01-27 01:42:41 +03:00
734e680c2f fixed naming 2026-01-27 01:25:49 +03:00
2c2d014f7b mesh improvement 2026-01-27 01:25:07 +03:00
a27ea2eedf WIP on feature/rotation_improved 2026-01-27 01:07:37 +03:00
86943cb9f0 Merge pull request #138 from orange-cpp/feature/primitives_improvement
Feature/primitives improvement
2026-01-27 01:07:15 +03:00
2f725bab05 dropped uselss cpp files 2026-01-27 00:51:17 +03:00
dc39f4fdc6 fixed naming 2026-01-27 00:39:34 +03:00
8f428a34bd added primitives to other engine triplets 2026-01-27 00:37:23 +03:00
9a61ce1984 added opengl primitives 2026-01-27 00:33:35 +03:00
3b8a5c09fa fix 2026-01-26 20:59:19 +03:00
108614a3a1 fix 2026-01-26 19:01:39 +03:00
a15e197d99 fix 2026-01-26 18:59:34 +03:00
f9261cb553 ppatch 2026-01-26 17:21:23 +03:00
6631819c75 added stuff 2026-01-26 17:07:38 +03:00
701687c38b added files 2026-01-26 15:44:46 +03:00
2753dfaa30 Merge pull request #137 from luadebug/xm
xmake Add tests
2026-01-22 12:57:19 +03:00
Saikari
ccc5fca804 fixup 2026-01-22 08:53:23 +03:00
Saikari
c77000897f Add tests 2026-01-22 08:52:18 +03:00
ca9faeacec Merge pull request #136 from luadebug/xmake
Add build configuration for omath and examples
2026-01-20 01:27:48 +03:00
Saikari
a9ef405c67 Add rules for CMake and pkg-config imports 2026-01-19 04:45:41 +03:00
Saikari
38dba9f3f7 Add build configuration for omath and examples 2026-01-19 04:43:21 +03:00
2fcd3c60e4 Update copyright year in LICENSE file 2026-01-17 21:35:34 +03:00
8ecda78e79 Merge pull request #135 from orange-cpp/feature/crypto_var
Feature/crypto var
2026-01-04 23:41:24 +03:00
ff4d20a4db added final 2026-01-04 23:24:07 +03:00
ce01671596 improvement 2026-01-04 23:22:25 +03:00
b11385c4e1 added cmake option 2026-01-04 23:02:58 +03:00
03d06d669b forgot to remove 2026-01-04 22:53:57 +03:00
cdf2c29013 removed 128 bit int 2026-01-04 22:46:09 +03:00
5209e85c67 improvement 2026-01-04 22:41:28 +03:00
1a9741fd6f fixed test 2026-01-04 22:23:57 +03:00
f172fe5837 silenced warn 2026-01-04 22:16:40 +03:00
cf71e8f4e5 improved stuff 2026-01-04 22:16:40 +03:00
90e6b4eaaa fix 2026-01-04 22:16:40 +03:00
056e715f04 added check 2026-01-04 22:16:40 +03:00
25690053d1 changed algorithm 2026-01-04 22:16:40 +03:00
84bdcc9dc7 added stuff 2026-01-04 22:16:40 +03:00
215 changed files with 16640 additions and 1307 deletions

View File

@@ -12,6 +12,7 @@ AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignTrailingComments: false
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
BreakTemplateDeclarations: Leave

25
.cmake-format Normal file
View File

@@ -0,0 +1,25 @@
format:
line_width: 100
tab_size: 4
use_tabchars: false
max_subgroups_hwrap: 3
max_pargs_hwrap: 5
separate_ctrl_name_with_space: false
separate_fn_name_with_space: false
dangle_parens: false
dangle_align: child
line_ending: unix
command_case: canonical
keyword_case: upper
enable_sort: true
autosort: true
markup:
bullet_char: "*"
enum_char: .
enable_markup: false
additional_commands:
target_link_libraries:
kwargs:
PUBLIC: "*"
SHARED: "*"
PRIVATE: "*"

97
.gitattributes vendored
View File

@@ -1,5 +1,98 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff
# Images
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.webp filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
*.heic filter=lfs diff=lfs merge=lfs -text
*.heif filter=lfs diff=lfs merge=lfs -text
*.avif filter=lfs diff=lfs merge=lfs -text
*.ico filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.xcf filter=lfs diff=lfs merge=lfs -text
*.kra filter=lfs diff=lfs merge=lfs -text
*.sketch filter=lfs diff=lfs merge=lfs -text
# Video
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.m4v filter=lfs diff=lfs merge=lfs -text
*.mkv filter=lfs diff=lfs merge=lfs -text
*.avi filter=lfs diff=lfs merge=lfs -text
*.wmv filter=lfs diff=lfs merge=lfs -text
*.flv filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text
*.mpeg filter=lfs diff=lfs merge=lfs -text
*.mpg filter=lfs diff=lfs merge=lfs -text
# Audio
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.flac filter=lfs diff=lfs merge=lfs -text
*.aac filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.m4a filter=lfs diff=lfs merge=lfs -text
# 3D / CAD / DCC
*.blend filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.stl filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
*.gltf filter=lfs diff=lfs merge=lfs -text
*.usd filter=lfs diff=lfs merge=lfs -text
*.usdz filter=lfs diff=lfs merge=lfs -text
*.max filter=lfs diff=lfs merge=lfs -text
*.c4d filter=lfs diff=lfs merge=lfs -text
*.dwg filter=lfs diff=lfs merge=lfs -text
*.dxf filter=lfs diff=lfs merge=lfs -text
*.step filter=lfs diff=lfs merge=lfs -text
*.stp filter=lfs diff=lfs merge=lfs -text
*.iges filter=lfs diff=lfs merge=lfs -text
*.igs filter=lfs diff=lfs merge=lfs -text
# Documents / publishing binaries
*.pdf filter=lfs diff=lfs merge=lfs -text
*.indd filter=lfs diff=lfs merge=lfs -text
*.idml filter=lfs diff=lfs merge=lfs -text
*.ppt filter=lfs diff=lfs merge=lfs -text
*.pptx filter=lfs diff=lfs merge=lfs -text
*.key filter=lfs diff=lfs merge=lfs -text
*.doc filter=lfs diff=lfs merge=lfs -text
*.docx filter=lfs diff=lfs merge=lfs -text
# Archives / packaged artifacts
*.zip filter=lfs diff=lfs merge=lfs -text
*.7z filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
# Fonts
*.ttf filter=lfs diff=lfs merge=lfs -text
*.otf filter=lfs diff=lfs merge=lfs -text
*.woff filter=lfs diff=lfs merge=lfs -text
*.woff2 filter=lfs diff=lfs merge=lfs -text
# ML / data artifacts
*.onnx filter=lfs diff=lfs merge=lfs -text
*.pt filter=lfs diff=lfs merge=lfs -text
*.pth filter=lfs diff=lfs merge=lfs -text
*.ckpt filter=lfs diff=lfs merge=lfs -text
*.pb filter=lfs diff=lfs merge=lfs -text
*.tflite filter=lfs diff=lfs merge=lfs -text
*.h5 filter=lfs diff=lfs merge=lfs -text
*.hdf5 filter=lfs diff=lfs merge=lfs -text
*.parquet filter=lfs diff=lfs merge=lfs -text
*.feather filter=lfs diff=lfs merge=lfs -text
*.arrow filter=lfs diff=lfs merge=lfs -text
*.npy filter=lfs diff=lfs merge=lfs -text
*.npz filter=lfs diff=lfs merge=lfs -text
*.pickle filter=lfs diff=lfs merge=lfs -text
*.pkl filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text

4
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
# These are supported funding model platforms
open_collective: libomathorg
github: orange-cpp

BIN
.github/psd/omath.psd LFS vendored

Binary file not shown.

View File

@@ -107,7 +107,7 @@ jobs:
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DOMATH_ENABLE_COVERAGE=${{ matrix.coverage == true && 'ON' || 'OFF' }} \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;lua"
- name: Build
shell: bash
@@ -193,7 +193,7 @@ jobs:
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DOMATH_ENABLE_COVERAGE=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;lua"
- name: Build
shell: bash
@@ -234,7 +234,7 @@ jobs:
-DOMATH_ENABLE_COVERAGE=ON \
-DOMATH_THREAT_WARNING_AS_ERROR=OFF \
-DCMAKE_BUILD_TYPE=Debug \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;lua"
cmake --build cmake-build/build/${{ matrix.preset }} --config Debug --target unit_tests omath
- name: Run Tests (Generates .profraw)
@@ -370,16 +370,19 @@ jobs:
shell: bash
run: |
cmake --preset ${{ matrix.preset }} \
-DCMAKE_C_COMPILER=$(xcrun --find clang) \
-DCMAKE_CXX_COMPILER=$(xcrun --find clang++) \
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DOMATH_ENABLE_COVERAGE=${{ matrix.coverage == true && 'ON' || 'OFF' }} \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;lua"
- name: Build
shell: bash
run: cmake --build cmake-build/build/${{ matrix.preset }} --target unit_tests omath
- name: Run unit_tests
if: ${{ matrix.coverage != true }}
shell: bash
run: ./out/Release/unit_tests
@@ -450,7 +453,7 @@ jobs:
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;tests;lua"
- name: Build
shell: bash
@@ -509,7 +512,7 @@ jobs:
cmake --preset ${{ matrix.preset }} \
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests" \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;lua" \
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported"
cmake --build cmake-build/build/${{ matrix.preset }} --target unit_tests omath
./out/Release/unit_tests
@@ -581,7 +584,7 @@ jobs:
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;tests;lua"
- name: Build
shell: bash
@@ -650,7 +653,7 @@ jobs:
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;tests;lua"
- name: Build
shell: bash
@@ -735,7 +738,7 @@ jobs:
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;tests"
-DVCPKG_MANIFEST_FEATURES="imgui;tests;lua"
- name: Build
run: |
@@ -800,7 +803,7 @@ jobs:
-DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=ON \
-DOMATH_ENABLE_VALGRIND=ON \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;benchmark"
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;lua;tests;benchmark"
- name: Build All Targets
shell: bash

62
.github/workflows/docs.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: Documentation
on:
push:
branches: [ main ]
paths:
- 'docs/**'
- 'mkdocs.yml'
- '.github/workflows/docs.yml'
pull_request:
branches: [ main ]
paths:
- 'docs/**'
- 'mkdocs.yml'
- '.github/workflows/docs.yml'
concurrency:
group: docs-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
name: Build Documentation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install mkdocs and dependencies
run: pip install mkdocs mkdocs-bootswatch
- name: Build documentation
run: mkdocs build --strict
- name: Upload artifact
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
with:
path: site/
deploy:
name: Deploy to GitHub Pages
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

647
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,647 @@
name: Release
on:
release:
types: [published]
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
jobs:
##############################################################################
# 0) Documentation MkDocs
##############################################################################
docs-release:
name: Documentation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install mkdocs and dependencies
run: pip install mkdocs mkdocs-bootswatch
- name: Build documentation
run: mkdocs build --strict
- name: Package
run: tar -czf omath-docs.tar.gz -C site .
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${{ github.event.release.tag_name }}" omath-docs.tar.gz --clobber
##############################################################################
# 1) Linux Clang / Ninja
##############################################################################
linux-release:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- name: Linux (Clang) (x64-linux)
triplet: x64-linux
runner: ubuntu-latest
preset: linux-release-vcpkg
archive: omath-linux-x64
install_cmd: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
sudo add-apt-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main"
sudo apt-get update
sudo apt-get install -y git build-essential cmake ninja-build \
zip unzip curl pkg-config ca-certificates \
clang-21 lld-21 libc++-21-dev libc++abi-21-dev
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-21 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-21 100
sudo update-alternatives --install /usr/bin/lld lld /usr/bin/lld-21 100
- name: Linux (Clang) (x86-linux)
triplet: x86-linux
runner: ubuntu-latest
preset: linux-release-vcpkg-x86
archive: omath-linux-x86
install_cmd: |
# Add LLVM 21 repository
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
sudo add-apt-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main"
# Add GCC Toolchain PPA
sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu plucky main universe"
# Enable i386 architecture
sudo dpkg --add-architecture i386
sudo apt-get update
# Install Clang 21
sudo apt-get install -y git build-essential cmake ninja-build \
zip unzip curl pkg-config ca-certificates \
clang-21 lld-21 libc++-21-dev libc++abi-21-dev
sudo apt-get install -y -t plucky binutils
# Install GCC 15 with multilib support
sudo apt-get install -y gcc-15-multilib g++-15-multilib
# Set up alternatives for Clang
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-21 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-21 100
sudo update-alternatives --install /usr/bin/lld lld /usr/bin/lld-21 100
# Set up alternatives for GCC
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 100
- name: Linux (Clang) (arm64-linux)
triplet: arm64-linux
runner: ubuntu-24.04-arm
preset: linux-release-vcpkg-arm64
archive: omath-linux-arm64
install_cmd: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
sudo add-apt-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main"
sudo apt-get update
sudo apt-get install -y git build-essential cmake ninja-build \
zip unzip curl pkg-config ca-certificates \
clang-21 lld-21 libc++-21-dev libc++abi-21-dev
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-21 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-21 100
sudo update-alternatives --install /usr/bin/lld lld /usr/bin/lld-21 100
fail-fast: false
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps:
- name: Install basic tool-chain
shell: bash
run: ${{ matrix.install_cmd }}
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up vcpkg
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
cd "$VCPKG_ROOT"
./bootstrap-vcpkg.sh
- name: Configure (cmake --preset)
shell: bash
run: |
cmake --preset ${{ matrix.preset }} \
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2"
- name: Build
shell: bash
run: cmake --build cmake-build/build/${{ matrix.preset }} --target omath
- name: Install
shell: bash
run: cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
- name: Package
shell: bash
run: tar -czf ${{ matrix.archive }}.tar.gz -C staging .
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.tar.gz" --clobber
##############################################################################
# 2) Windows MSVC / Ninja
##############################################################################
windows-release:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- name: Windows (MSVC) (x64-windows)
runner: windows-latest
arch: amd64
preset: windows-release-vcpkg
triplet: x64-windows
archive: omath-windows-x64
- name: Windows (MSVC) (x86-windows)
runner: windows-latest
arch: amd64_x86
preset: windows-release-vcpkg-x86
triplet: x86-windows
archive: omath-windows-x86
- name: Windows (MSVC) (arm64-windows)
runner: windows-11-arm
arch: arm64
preset: windows-release-vcpkg-arm64
triplet: arm64-windows
archive: omath-windows-arm64
fail-fast: false
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps:
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@v4
- name: Set up MSVC developer command-prompt
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.arch }}
- name: Configure (cmake --preset)
shell: bash
run: |
cmake --preset ${{ matrix.preset }} \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2"
- name: Build
shell: bash
run: cmake --build cmake-build/build/${{ matrix.preset }} --target omath
- name: Install
shell: bash
run: cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
- name: Package
shell: pwsh
run: Compress-Archive -Path staging\* -DestinationPath "${{ matrix.archive }}.zip"
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.zip" --clobber
##############################################################################
# 3) macOS AppleClang / Ninja
##############################################################################
macos-release:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- name: macOS (AppleClang) (arm64-osx)
runner: macos-latest
preset: darwin-release-vcpkg
triplet: arm64-osx
archive: omath-macos-arm64
- name: macOS (AppleClang) (x64-osx)
runner: macos-15-intel
preset: darwin-release-vcpkg-x64
triplet: x64-osx
archive: omath-macos-x64
fail-fast: false
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps:
- name: Install basic tool-chain with Homebrew
shell: bash
run: |
brew install cmake ninja
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up vcpkg
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
- name: Configure (cmake --preset)
shell: bash
run: |
cmake --preset ${{ matrix.preset }} \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2"
- name: Build
shell: bash
run: cmake --build cmake-build/build/${{ matrix.preset }} --target omath
- name: Install
shell: bash
run: cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
- name: Package
shell: bash
run: tar -czf ${{ matrix.archive }}.tar.gz -C staging .
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.tar.gz" --clobber
##############################################################################
# 4) iOS AppleClang / Xcode / arm64-ios
##############################################################################
ios-release:
name: iOS (AppleClang) (${{ matrix.triplet }})
runs-on: macOS-latest
strategy:
matrix:
include:
- triplet: arm64-ios
preset: ios-release-vcpkg
archive: omath-ios-arm64
fail-fast: false
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps:
- name: Install CMake tooling
shell: bash
run: |
brew install cmake ninja
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up vcpkg
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
cd "$VCPKG_ROOT"
./bootstrap-vcpkg.sh
- name: Configure (cmake --preset)
shell: bash
run: |
cmake --preset ${{ matrix.preset }} \
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui"
- name: Build
shell: bash
run: |
cmake --build cmake-build/build/${{ matrix.preset }} --config Release --target omath
- name: Install
shell: bash
run: cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
- name: Package
shell: bash
run: tar -czf ${{ matrix.archive }}.tar.gz -C staging .
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.tar.gz" --clobber
##############################################################################
# 5) FreeBSD Clang / Ninja
##############################################################################
freebsd-release:
name: FreeBSD (Clang) (${{ matrix.triplet }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- triplet: x64-freebsd
preset: freebsd-release-vcpkg
arch: x86-64
archive: omath-freebsd-x64
fail-fast: false
env:
VCPKG_ROOT: ${{ github.workspace }}/tmp/vcpkg
steps:
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build and Package
uses: cross-platform-actions/action@v0.31.0
with:
operating_system: freebsd
architecture: ${{ matrix.arch }}
version: '15.0'
memory: '12G'
cpu_count: 4
run: |
sudo pkg install -y git curl zip unzip gmake llvm gsed bash perl5 openssl 7-zip coreutils cmake ninja pkgconf patchelf
git config --global --add safe.directory `pwd`
# Build vcpkg in /tmp to avoid sshfs timestamp sync issues
export VCPKG_ROOT=/tmp/vcpkg
rm -rf "$VCPKG_ROOT"
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
cd "$VCPKG_ROOT"
./bootstrap-vcpkg.sh
cd -
export VCPKG_FORCE_SYSTEM_BINARIES=0
cmake --preset ${{ matrix.preset }} \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2" \
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported"
cmake --build cmake-build/build/${{ matrix.preset }} --target omath
cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
tar -czf ${{ matrix.archive }}.tar.gz -C staging .
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.tar.gz" --clobber
##############################################################################
# 6) Android NDK Clang / Ninja
##############################################################################
android-release:
name: Android NDK (${{ matrix.triplet }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- triplet: arm-neon-android
preset: android-arm-neon-release-vcpkg
archive: omath-android-arm-neon
- triplet: arm64-android
preset: android-arm64-release-vcpkg
archive: omath-android-arm64
- triplet: x64-android
preset: android-x64-release-vcpkg
archive: omath-android-x64
- triplet: x86-android
preset: android-x86-release-vcpkg
archive: omath-android-x86
fail-fast: false
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
ANDROID_NDK_HOME: ${{ github.workspace }}/android-ndk
steps:
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Android NDK
shell: bash
run: |
NDK_VERSION="r28b"
NDK_ZIP="android-ndk-${NDK_VERSION}-linux.zip"
wget -q "https://dl.google.com/android/repository/${NDK_ZIP}"
unzip -q "${NDK_ZIP}" -d "${{ github.workspace }}"
mv "${{ github.workspace }}/android-ndk-${NDK_VERSION}" "$ANDROID_NDK_HOME"
rm "${NDK_ZIP}"
echo "ANDROID_NDK_HOME=${ANDROID_NDK_HOME}" >> $GITHUB_ENV
- name: Install basic tool-chain
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y ninja-build cmake
- name: Set up vcpkg
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
cd "$VCPKG_ROOT"
./bootstrap-vcpkg.sh
- name: Configure (cmake --preset)
shell: bash
run: |
cmake --preset ${{ matrix.preset }} \
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui"
- name: Build
shell: bash
run: |
cmake --build cmake-build/build/${{ matrix.preset }} --target omath
- name: Install
shell: bash
run: cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
- name: Package
shell: bash
run: tar -czf ${{ matrix.archive }}.tar.gz -C staging .
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.tar.gz" --clobber
##############################################################################
# 7) WebAssembly (Emscripten) Clang / Ninja / wasm32-emscripten
##############################################################################
wasm-release:
name: WebAssembly (Emscripten) (${{ matrix.triplet }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- triplet: wasm32-emscripten
preset: wasm-release-vcpkg
archive: omath-wasm32
fail-fast: false
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps:
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install basic tool-chain
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y ninja-build
- name: Setup Emscripten
uses: mymindstorm/setup-emsdk@v14
with:
version: 'latest'
- name: Verify Emscripten
shell: bash
run: |
echo "EMSDK=$EMSDK"
emcc --version
ls -la "$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
- name: Set up vcpkg
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
cd "$VCPKG_ROOT"
./bootstrap-vcpkg.sh
- name: Configure (cmake --preset)
shell: bash
run: |
cmake --preset ${{ matrix.preset }} \
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui"
- name: Build
shell: bash
run: |
cmake --build cmake-build/build/${{ matrix.preset }} --target omath
- name: Install
shell: bash
run: cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
- name: Package
shell: bash
run: tar -czf ${{ matrix.archive }}.tar.gz -C staging .
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.tar.gz" --clobber
##############################################################################
# 8) Windows MSYS2 MinGW GCC / Ninja
##############################################################################
mingw-release:
name: ${{ matrix.name }}
runs-on: windows-latest
strategy:
matrix:
include:
- name: MINGW64 (MSYS2) (x64-mingw-dynamic)
msystem: MINGW64
pkg_prefix: mingw-w64-x86_64
preset: mingw-release-vcpkg
archive: omath-mingw64-x64
- name: UCRT64 (MSYS2) (x64-mingw-dynamic)
msystem: UCRT64
pkg_prefix: mingw-w64-ucrt-x86_64
preset: mingw-release-vcpkg
archive: omath-ucrt64-x64
- name: MINGW32 (MSYS2) (x86-mingw-dynamic)
msystem: MINGW32
pkg_prefix: mingw-w64-i686
preset: mingw32-release-vcpkg
archive: omath-mingw32-x86
fail-fast: false
defaults:
run:
shell: msys2 {0}
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps:
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
update: true
install: >-
${{ matrix.pkg_prefix }}-toolchain
${{ matrix.pkg_prefix }}-cmake
${{ matrix.pkg_prefix }}-ninja
${{ matrix.pkg_prefix }}-pkg-config
git
base-devel
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up vcpkg
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
cd "$VCPKG_ROOT"
./bootstrap-vcpkg.sh
- name: Configure (cmake --preset)
run: |
cmake --preset ${{ matrix.preset }} \
-DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \
-DOMATH_BUILD_TESTS=OFF \
-DOMATH_BUILD_BENCHMARK=OFF \
-DVCPKG_MANIFEST_FEATURES="imgui"
- name: Build
run: |
cmake --build cmake-build/build/${{ matrix.preset }} --target omath
- name: Install
run: cmake --install cmake-build/build/${{ matrix.preset }} --prefix staging
- name: Package
shell: pwsh
run: Compress-Archive -Path staging\* -DestinationPath "${{ matrix.archive }}.zip"
- name: Upload release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release upload "${{ github.event.release.tag_name }}" "${{ matrix.archive }}.zip" --clobber

9
.gitignore vendored
View File

@@ -5,4 +5,11 @@
.idea/workspace.xml
/build/
/clang-coverage/
*.gcov
*.gcov
*.bin
# pixi lock
pixi.lock
# pixi environments
.pixi/*
!.pixi/config.toml
/site/

9
.idea/editor.xml generated
View File

@@ -17,7 +17,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
@@ -56,6 +56,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefinitionsOrder/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
@@ -102,7 +103,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
@@ -201,7 +202,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
@@ -215,7 +216,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />

5
.luarc.json Normal file
View File

@@ -0,0 +1,5 @@
{
"diagnostics.globals": [
"omath"
]
}

24
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,24 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": " Unit Tests (Debug)",
"type": "lldb",
"request": "launch",
"program": "${workspaceRoot}/out/Debug/unit_tests",
"args": [],
"cwd": "${workspaceRoot}"
},
{
"name": " Unit Tests (Release)",
"type": "lldb",
"request": "launch",
"program": "${workspaceRoot}/out/Release/unit_tests",
"args": [],
"cwd": "${workspaceRoot}"
}
]
}

View File

@@ -9,49 +9,61 @@ include(CheckCXXCompilerFlag)
include(cmake/Coverage.cmake)
include(cmake/Valgrind.cmake)
if (MSVC)
if(MSVC)
check_cxx_compiler_flag("/arch:AVX2" COMPILER_SUPPORTS_AVX2)
else ()
else()
check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
endif ()
endif()
option(OMATH_BUILD_TESTS "Build unit tests" OFF)
option(OMATH_BUILD_BENCHMARK "Build benchmarks" OFF)
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
option(OMATH_THREAT_WARNING_AS_ERROR
"Set highest level of warnings and force compiler to treat them as errors" ON)
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ${COMPILER_SUPPORTS_AVX2})
option(OMATH_IMGUI_INTEGRATION "Omath will define method to convert omath types to imgui types" OFF)
option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF)
option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF)
option(OMATH_SUPRESS_SAFETY_CHECKS "Supress some safety checks in release build to improve general performance" ON)
option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" OFF)
option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" ON)
option(OMATH_ENABLE_LEGACY
"Will enable legacy classes that MUST be used ONLY for backward compatibility" ON)
option(OMATH_SUPRESS_SAFETY_CHECKS
"Supress some safety checks in release build to improve general performance" ON)
option(OMATH_ENABLE_COVERAGE "Enable coverage" OFF)
option(OMATH_ENABLE_FORCE_INLINE
"Will for compiler to make some functions to be force inlined no matter what" ON)
if (VCPKG_MANIFEST_FEATURES)
foreach (omath_feature IN LISTS VCPKG_MANIFEST_FEATURES)
if (omath_feature STREQUAL "imgui")
option(OMATH_ENABLE_LUA
"omath bindings for lua" OFF)
if(VCPKG_MANIFEST_FEATURES)
foreach(omath_feature IN LISTS VCPKG_MANIFEST_FEATURES)
if(omath_feature STREQUAL "imgui")
set(OMATH_IMGUI_INTEGRATION ON)
elseif (omath_feature STREQUAL "avx2")
elseif(omath_feature STREQUAL "avx2")
set(OMATH_USE_AVX2 ${COMPILER_SUPPORTS_AVX2})
elseif (omath_feature STREQUAL "tests")
elseif(omath_feature STREQUAL "tests")
set(OMATH_BUILD_TESTS ON)
elseif (omath_feature STREQUAL "benchmark")
elseif(omath_feature STREQUAL "benchmark")
set(OMATH_BUILD_BENCHMARK ON)
elseif (omath_feature STREQUAL "examples")
elseif(omath_feature STREQUAL "examples")
set(OMATH_BUILD_EXAMPLES ON)
endif ()
elseif(omath_feature STREQUAL "lua")
set(OMATH_ENABLE_LUA ON)
endif()
endforeach ()
endif ()
endforeach()
endif()
if (OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2)
message(WARNING "OMATH_USE_AVX2 requested, but compiler/target does not support AVX2. Disabling.")
if(OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2)
message(
WARNING "OMATH_USE_AVX2 requested, but compiler/target does not support AVX2. Disabling.")
set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE)
endif ()
endif()
if (${PROJECT_IS_TOP_LEVEL})
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
if(${PROJECT_IS_TOP_LEVEL})
message(
STATUS
"[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}"
)
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
@@ -65,80 +77,90 @@ if (${PROJECT_IS_TOP_LEVEL})
message(STATUS "[${PROJECT_NAME}]: Building using vcpkg ${OMATH_BUILD_VIA_VCPKG}")
message(STATUS "[${PROJECT_NAME}]: Coverage feature status ${OMATH_ENABLE_COVERAGE}")
message(STATUS "[${PROJECT_NAME}]: Valgrind feature status ${OMATH_ENABLE_VALGRIND}")
endif ()
message(STATUS "[${PROJECT_NAME}]: Lua feature status ${OMATH_ENABLE_LUA}")
endif()
file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
if (OMATH_BUILD_AS_SHARED_LIBRARY)
if(OMATH_BUILD_AS_SHARED_LIBRARY)
add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
else ()
else()
add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS})
endif ()
endif()
if (OMATH_ENABLE_LUA)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LUA)
find_package(Lua REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE ${LUA_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE ${LUA_LIBRARIES})
find_path(SOL2_INCLUDE_DIRS "sol/abort.hpp")
target_include_directories(${PROJECT_NAME} PRIVATE ${SOL2_INCLUDE_DIRS})
endif ()
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}")
if (OMATH_IMGUI_INTEGRATION)
if(OMATH_IMGUI_INTEGRATION)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_IMGUI_INTEGRATION)
# IMGUI is being linked as submodule
if (TARGET imgui)
if(TARGET imgui)
target_link_libraries(${PROJECT_NAME} PUBLIC imgui)
install(TARGETS imgui
EXPORT omathTargets
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
else ()
install(
TARGETS imgui
EXPORT omathTargets
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
else()
# Assume that IMGUI linked via VCPKG.
find_package(imgui CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC imgui::imgui)
endif ()
endif()
endif ()
endif()
if (OMATH_USE_AVX2)
if(OMATH_USE_AVX2)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_USE_AVX2)
endif ()
endif()
if (OMATH_SUPRESS_SAFETY_CHECKS)
if(OMATH_SUPRESS_SAFETY_CHECKS)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_SUPRESS_SAFETY_CHECKS)
endif ()
endif()
if (OMATH_ENABLE_LEGACY)
if(OMATH_ENABLE_LEGACY)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY)
endif ()
endif()
set_target_properties(${PROJECT_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
if(OMATH_ENABLE_FORCE_INLINE)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_FORCE_INLINE)
endif()
if (OMATH_USE_UNITY_BUILD)
set_target_properties(${PROJECT_NAME} PROPERTIES
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20)
endif ()
set_target_properties(
${PROJECT_NAME}
PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
set_target_properties(${PROJECT_NAME} PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
)
endif ()
if(OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY
"MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
if (OMATH_USE_AVX2)
if (MSVC)
if(OMATH_USE_AVX2)
if(MSVC)
target_compile_options(${PROJECT_NAME} PUBLIC /arch:AVX2)
elseif (EMSCRIPTEN)
elseif(EMSCRIPTEN)
target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2)
endif ()
endif ()
endif()
endif()
if(EMSCRIPTEN)
target_compile_options(${PROJECT_NAME} PUBLIC -fexceptions)
@@ -147,79 +169,85 @@ endif()
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
if (OMATH_BUILD_TESTS)
if(OMATH_BUILD_TESTS)
add_subdirectory(tests)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)
if(OMATH_ENABLE_COVERAGE)
omath_setup_coverage(${PROJECT_NAME})
endif()
endif ()
endif()
if (OMATH_BUILD_BENCHMARK)
if(OMATH_BUILD_BENCHMARK)
add_subdirectory(benchmark)
endif ()
endif()
if (OMATH_BUILD_EXAMPLES)
if(OMATH_BUILD_EXAMPLES)
add_subdirectory(examples)
endif ()
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR)
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX)
elseif (OMATH_THREAT_WARNING_AS_ERROR)
elseif(OMATH_THREAT_WARNING_AS_ERROR)
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror)
endif ()
endif()
# Windows SDK redefine min/max via preprocessor and break std::min and std::max
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${PROJECT_NAME} PRIVATE /bigobj)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_HOST_SYSTEM_NAME EQUAL "Windows")
target_compile_options(${PROJECT_NAME} PRIVATE -mbig-obj)
endif()
# Windows SDK redefine min/max via preprocessor and break std::min and std::max
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_definitions(${PROJECT_NAME} INTERFACE NOMINMAX)
endif ()
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # Use this path when building the project
$<INSTALL_INTERFACE:include> # Use this path when the project is installed
)
endif()
target_include_directories(
${PROJECT_NAME}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # Use this path
# when building
# the project
$<INSTALL_INTERFACE:include> # Use this path when the project is
# installed
)
# Installation rules
# Install the library
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
ARCHIVE DESTINATION lib COMPONENT ${PROJECT_NAME} # For static libraries
LIBRARY DESTINATION lib COMPONENT ${PROJECT_NAME} # For shared libraries
RUNTIME DESTINATION bin COMPONENT ${PROJECT_NAME} # For executables (on Windows)
)
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
ARCHIVE DESTINATION lib COMPONENT ${PROJECT_NAME} # For static libraries
LIBRARY DESTINATION lib COMPONENT ${PROJECT_NAME} # For shared libraries
RUNTIME DESTINATION bin COMPONENT ${PROJECT_NAME} # For executables (on
# Windows)
)
# Install headers as part of omath_component
install(DIRECTORY include/ DESTINATION include COMPONENT ${PROJECT_NAME})
# Export omath target for CMake find_package support, also under omath_component
install(EXPORT ${PROJECT_NAME}Targets
FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION lib/cmake/${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
)
install(
EXPORT ${PROJECT_NAME}Targets
FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION lib/cmake/${PROJECT_NAME}
COMPONENT ${PROJECT_NAME})
# Generate the omathConfigVersion.cmake file
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake"
VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion)
# Generate the omathConfig.cmake file from the template (which is in the cmake/ folder)
# Generate the omathConfig.cmake file from the template (which is in the cmake/
# folder)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/omathConfig.cmake.in" # Path to the .in file
"${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" # Output path for the generated file
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
)
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/omathConfig.cmake.in" # Path to the .in
# file
"${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" # Output path for the
# generated file
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME})
# Install the generated config files
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake"
DESTINATION lib/cmake/${PROJECT_NAME}
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake"
DESTINATION lib/cmake/${PROJECT_NAME})

View File

@@ -145,7 +145,7 @@
"hidden": true,
"inherits": ["linux-base", "vcpkg-base"],
"cacheVariables": {
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2"
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;lua"
}
},
{
@@ -235,7 +235,7 @@
"hidden": true,
"inherits": ["darwin-base", "vcpkg-base"],
"cacheVariables": {
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples"
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples;lua"
}
},
{

37
CODEOWNERS Normal file
View File

@@ -0,0 +1,37 @@
## List of maintainers for the omath library
## This file purpose is to give newcomers to the project the responsible
## developers when submitting a pull request on GitHub, or opening a bug
## report in issues.
## This file will notably establish who is responsible for a specific
## area of omath. Being a maintainer means the following:
## - that person has good knownledge in the area
## - that person is able to enforce consistency in the area
## - that person may be available for giving help in the area
## - that person has push access on the repository
## Being a maintainer does not mean the following:
## - that person is dedicated to the area
## - that person is working full-time on the area/on omath
## - that person is paid
## - that person is always available
# omath core source code
/source @orange-cpp
/include @orange-cpp
# Tests and becnchmarks
/benchmark @orange-cpp
/tests @orange-cpp @luadebug
# Examples and documentation
/examples @luadebug @orange-cpp
/docs @orange-cpp
# Misc like formating
/scripts @luadebug
/pixi @luadebug
# CI/CD
/.github/workflows @luadbg @orange-cpp

View File

@@ -1,32 +1,36 @@
## 🤝 Contributing to OMath or other Orange's Projects
# Contributing
### ❕ Prerequisites
## Prerequisites
- A working up-to-date OMath installation
- C++ knowledge
- Git knowledge
- Ability to ask for help (Feel free to create empty pull-request or PM a maintainer
in [Telegram](https://t.me/orange_cpp))
- C++ compiler with C++23 support (Clang 18+, GCC 14+, MSVC 19.38+)
- CMake 3.25+
- Git
- Familiarity with the codebase (see `INSTALL.md` for setup)
### ⏬ Setting up OMath
For questions, create a draft PR or reach out via [Telegram](https://t.me/orange_cpp).
Please read INSTALL.md file in repository
## Workflow
### 🔀 Pull requests and Branches
1. [Fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the repository.
2. Create a feature branch from `main`.
3. Make your changes, ensuring tests pass.
4. Open a [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) against `main`.
In order to send code back to the official OMath repository, you must first create a copy of OMath on your github
account ([fork](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)) and
then [create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) back to OMath.
## Code Style
OMath development is performed on multiple branches. Changes are then pull requested into master. By default, changes
merged into master will not roll out to stable build users unless the `stable` tag is updated.
Follow the project `.clang-format`. Run `clang-format` before committing.
### 📜 Code-Style
## Building
The orange code-style can be found in `.clang-format`.
Use one of the CMake presets defined in `CMakePresets.json`:
### 📦 Building
```bash
cmake --preset <preset-name> -DOMATH_BUILD_TESTS=ON
cmake --build --preset <preset-name>
```
OMath has already created the `cmake-build` and `out` directories where cmake/bin files are located. By default, you
can build OMath by running `cmake --build cmake-build/build/windows-release --target omath -j 6` in the source
directory.
Run `cmake --list-presets` to see available configurations.
## Tests
All new functionality must include unit tests. Run the test binary after building to verify nothing is broken.

View File

@@ -3,8 +3,8 @@
Thanks to everyone who made this possible, including:
- Saikari aka luadebug for VCPKG port and awesome new initial logo design.
- AmbushedRaccoon for telegram post about omath to boost repository activity.
- Billy O'Neal aka BillyONeal for fixing compilation issues due to C math library compatibility.
- Alex2772 for reference of AUI declarative interface design for omath::hud
And a big hand to everyone else who has contributed over the past!

View File

@@ -1,6 +1,6 @@
# 📥Installation Guide
## <img width="28px" src="https://vcpkg.io/assets/mark/mark.svg" /> Using vcpkg
## <img width="28px" src="https://vcpkg.io/assets/mark/mark.svg" /> Using vcpkg (recomended)
**Note**: Support vcpkg for package management
1. Install [vcpkg](https://github.com/microsoft/vcpkg)
2. Run the following command to install the orange-math package:
@@ -28,6 +28,69 @@ target("...")
add_packages("omath")
```
## <img width="28px" src="https://conan.io/favicon.png" /> Using Conan
**Note**: Support Conan for package management
1. Install [Conan](https://conan.io/downloads)
2. Run the following command to install the omath package:
```
conan install --requires="omath/[*]" --build=missing
```
conanfile.txt
```ini
[requires]
omath/[*]
[generators]
CMakeDeps
CMakeToolchain
```
CMakeLists.txt
```cmake
find_package(omath CONFIG REQUIRED)
target_link_libraries(main PRIVATE omath::omath)
```
For more details, see the [Conan documentation](https://docs.conan.io/2/).
## <img width="28px" src="https://github.githubassets.com/favicons/favicon.svg" /> Using prebuilt binaries (GitHub Releases)
**Note**: This is the fastest option if you dont want to build from source.
1. **Go to the Releases page**
- Open the projects GitHub **Releases** page and choose the latest version.
2. **Download the correct asset for your platform**
- Pick the archive that matches your OS and architecture (for example: Windows x64 / Linux x64 / macOS arm64).
3. **Extract the archive**
- You should end up with something like:
- `include/` (headers)
- `lib/` or `bin/` (library files / DLLs)
- sometimes `cmake/` (CMake package config)
4. **Use it in your project**
### Option A: CMake package (recommended if the release includes CMake config files)
If the extracted folder contains something like `lib/cmake/omath` or `cmake/omath`, you can point CMake to it:
```cmake
# Example: set this to the extracted prebuilt folder
list(APPEND CMAKE_PREFIX_PATH "path/to/omath-prebuilt")
find_package(omath CONFIG REQUIRED)
target_link_libraries(main PRIVATE omath::omath)
```
### Option B: Manual include + link (works with any layout)
If theres no CMake package config, link it manually:
```cmake
target_include_directories(main PRIVATE "path/to/omath-prebuilt/include")
# Choose ONE depending on what you downloaded:
# - Static library: .lib / .a
# - Shared library: .dll + .lib import (Windows), .so (Linux), .dylib (macOS)
target_link_directories(main PRIVATE "path/to/omath-prebuilt/lib")
target_link_libraries(main PRIVATE omath) # or the actual library filename
```
## <img width="28px" src="https://upload.wikimedia.org/wikipedia/commons/e/ef/CMake_logo.svg?" /> Build from source using CMake
1. **Preparation**

View File

@@ -1,4 +1,4 @@
Copyright (C) 2023-2025 Orange++ orange_github@proton.me
Copyright (C) 2023-2026 Orange++ orange_github@proton.me
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -14,4 +14,4 @@ freely, subject to the following restrictions:
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
3. This notice may not be removed or altered from any source distribution.

View File

@@ -9,11 +9,12 @@
[![CodeFactor](https://www.codefactor.io/repository/github/orange-cpp/omath/badge)](https://www.codefactor.io/repository/github/orange-cpp/omath)
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/orange-cpp/omath/cmake-multi-platform.yml)
[![Vcpkg package](https://repology.org/badge/version-for-repo/vcpkg/orange-math.svg)](https://repology.org/project/orange-math/versions)
![Conan Center](https://img.shields.io/conan/v/omath)
![GitHub forks](https://img.shields.io/github/forks/orange-cpp/omath)
[![discord badge](https://dcbadge.limes.pink/api/server/https://discord.gg/eDgdaWbqwZ?style=flat)](https://discord.gg/eDgdaWbqwZ)
[![telegram badge](https://img.shields.io/badge/Telegram-2CA5E0?style=flat-squeare&logo=telegram&logoColor=white)](https://t.me/orangennotes)
OMath is a 100% independent, constexpr template blazingly fast math library that doesn't have legacy C++ code.
OMath is a 100% independent, constexpr template blazingly fast math/physics/games/mods/cheats development framework that doesn't have legacy C++ code.
It provides the latest features, is highly customizable, has all for cheat development, DirectX/OpenGL/Vulkan support, premade support for different game engines, much more constexpr stuff than in other libraries and more...
<br>
@@ -80,9 +81,12 @@ if (auto screen = camera.world_to_screen(world_position)) {
- **Collision Detection**: Production ready code to handle collision detection by using simple interfaces.
- **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
- **Engine support**: Supports coordinate systems of **Source, Unity, Unreal, Frostbite, IWEngine and canonical OpenGL**.
- **Engine support**: Supports coordinate systems of **Source, Unity, Unreal, Frostbite, IWEngine, CryEngine and canonical OpenGL**.
- **Cross platform**: Supports Windows, MacOS and Linux.
- **Algorithms**: Has ability to scan for byte pattern with wildcards in PE files/modules, binary slices, works even with Wine apps.
- **Algorithms**: Has ability to scan for byte pattern with wildcards in ELF/Mach-O/PE files/modules, binary slices, works even with Wine apps.
- **Scripting**: Supports to make scripts in Lua out of box.
- **Handy**: Allow to design wall hacks in modern jetpack compose like way.
- **Battle tested**: It's already used by some big players on the market like wraith.su and bluedream.ltd
<div align = center>
# Gallery

View File

@@ -1 +1 @@
4.6.0
5.0.0

View File

@@ -1,22 +1,23 @@
project(omath_benchmark)
file(GLOB_RECURSE OMATH_BENCHMARK_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_executable(${PROJECT_NAME} ${OMATH_BENCHMARK_SOURCES})
set_target_properties(${PROJECT_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
set_target_properties(
${PROJECT_NAME}
PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
if (TARGET benchmark::benchmark) # Benchmark is being linked as submodule
if(TARGET benchmark::benchmark) # Benchmark is being linked as submodule
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
else()
find_package(benchmark CONFIG REQUIRED) # Benchmark is being linked as vcpkg package
find_package(benchmark CONFIG REQUIRED) # Benchmark is being linked as vcpkg
# package
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
endif ()
endif()
if(OMATH_ENABLE_VALGRIND)
omath_setup_valgrind(${PROJECT_NAME})

View File

@@ -0,0 +1,161 @@
//
// Created by Vlad on 3/2/2026.
//
#include <benchmark/benchmark.h>
#include <memory_resource>
#include <omath/collision/epa_algorithm.hpp>
#include <omath/collision/gjk_algorithm.hpp>
#include <omath/engines/source_engine/collider.hpp>
#include <omath/engines/source_engine/mesh.hpp>
using Mesh = omath::source_engine::Mesh;
using Collider = omath::source_engine::MeshCollider;
using Gjk = omath::collision::GjkAlgorithm<Collider>;
using Epa = omath::collision::Epa<Collider>;
namespace
{
// Unit cube with half-extent 1 — 8 vertices in [-1,1]^3.
const std::vector<omath::primitives::Vertex<>> k_cube_vbo = {
{ { -1.f, -1.f, -1.f }, {}, {} },
{ { -1.f, -1.f, 1.f }, {}, {} },
{ { -1.f, 1.f, -1.f }, {}, {} },
{ { -1.f, 1.f, 1.f }, {}, {} },
{ { 1.f, 1.f, 1.f }, {}, {} },
{ { 1.f, 1.f, -1.f }, {}, {} },
{ { 1.f, -1.f, 1.f }, {}, {} },
{ { 1.f, -1.f, -1.f }, {}, {} },
};
const std::vector<omath::Vector3<std::uint32_t>> k_empty_vao{};
} // namespace
// ---------------------------------------------------------------------------
// GJK benchmarks
// ---------------------------------------------------------------------------
// Separated cubes — origin distance 2.1, no overlap.
// Exercises the early-exit path and the centroid-based initial direction.
static void BM_Gjk_Separated(benchmark::State& state)
{
const Collider a{Mesh{k_cube_vbo, k_empty_vao}};
Mesh mesh_b{k_cube_vbo, k_empty_vao};
mesh_b.set_origin({0.f, 2.1f, 0.f});
const Collider b{mesh_b};
for ([[maybe_unused]] auto _ : state)
benchmark::DoNotOptimize(Gjk::is_collide(a, b));
}
// Overlapping cubes — B offset by 0.5 along X, ~1.5 units penetration depth.
static void BM_Gjk_Overlapping(benchmark::State& state)
{
const Collider a{Mesh{k_cube_vbo, k_empty_vao}};
Mesh mesh_b{k_cube_vbo, k_empty_vao};
mesh_b.set_origin({0.5f, 0.f, 0.f});
const Collider b{mesh_b};
for ([[maybe_unused]] auto _ : state)
benchmark::DoNotOptimize(Gjk::is_collide(a, b));
}
// Identical cubes at the same origin — deep overlap / worst case for GJK.
static void BM_Gjk_SameOrigin(benchmark::State& state)
{
const Collider a{Mesh{k_cube_vbo, k_empty_vao}};
const Collider b{Mesh{k_cube_vbo, k_empty_vao}};
for ([[maybe_unused]] auto _ : state)
benchmark::DoNotOptimize(Gjk::is_collide(a, b));
}
// ---------------------------------------------------------------------------
// EPA benchmarks
// ---------------------------------------------------------------------------
// EPA with a pre-allocated monotonic buffer (reset each iteration).
// Isolates algorithmic cost from allocator overhead.
static void BM_Epa_MonotonicBuffer(benchmark::State& state)
{
const Collider a{Mesh{k_cube_vbo, k_empty_vao}};
Mesh mesh_b{k_cube_vbo, k_empty_vao};
mesh_b.set_origin({0.5f, 0.f, 0.f});
const Collider b{mesh_b};
const auto [hit, simplex] = Gjk::is_collide_with_simplex_info(a, b);
if (!hit)
return; // shouldn't happen, but guard for safety
constexpr Epa::Params params{.max_iterations = 64, .tolerance = 1e-4f};
// Pre-allocate a 32 KiB stack buffer — enough for typical polytope growth.
constexpr std::size_t k_buf_size = 32768;
alignas(std::max_align_t) char buf[k_buf_size];
std::pmr::monotonic_buffer_resource mr{buf, k_buf_size, std::pmr::null_memory_resource()};
for ([[maybe_unused]] auto _ : state)
{
mr.release(); // reset the buffer without touching the upstream resource
benchmark::DoNotOptimize(Epa::solve(a, b, simplex, params, mr));
}
}
// EPA with the default (malloc-backed) memory resource.
// Shows total cost including allocator pressure.
static void BM_Epa_DefaultResource(benchmark::State& state)
{
const Collider a{Mesh{k_cube_vbo, k_empty_vao}};
Mesh mesh_b{k_cube_vbo, k_empty_vao};
mesh_b.set_origin({0.5f, 0.f, 0.f});
const Collider b{mesh_b};
const auto [hit, simplex] = Gjk::is_collide_with_simplex_info(a, b);
if (!hit)
return;
constexpr Epa::Params params{.max_iterations = 64, .tolerance = 1e-4f};
for ([[maybe_unused]] auto _ : state)
benchmark::DoNotOptimize(Epa::solve(a, b, simplex, params));
}
// ---------------------------------------------------------------------------
// Combined GJK + EPA pipeline
// ---------------------------------------------------------------------------
// Full collision pipeline: GJK detects contact, EPA resolves penetration.
// This is the hot path in a physics engine tick.
static void BM_GjkEpa_Pipeline(benchmark::State& state)
{
const Collider a{Mesh{k_cube_vbo, k_empty_vao}};
Mesh mesh_b{k_cube_vbo, k_empty_vao};
mesh_b.set_origin({0.5f, 0.f, 0.f});
const Collider b{mesh_b};
constexpr Epa::Params params{.max_iterations = 64, .tolerance = 1e-4f};
constexpr std::size_t k_buf_size = 32768;
alignas(std::max_align_t) char buf[k_buf_size];
std::pmr::monotonic_buffer_resource mr{buf, k_buf_size, std::pmr::null_memory_resource()};
for ([[maybe_unused]] auto _ : state)
{
mr.release();
const auto [hit, simplex] = Gjk::is_collide_with_simplex_info(a, b);
if (hit)
benchmark::DoNotOptimize(Epa::solve(a, b, simplex, params, mr));
}
}
BENCHMARK(BM_Gjk_Separated)->Iterations(100'000);
BENCHMARK(BM_Gjk_Overlapping)->Iterations(100'000);
BENCHMARK(BM_Gjk_SameOrigin)->Iterations(100'000);
BENCHMARK(BM_Epa_MonotonicBuffer)->Iterations(100'000);
BENCHMARK(BM_Epa_DefaultResource)->Iterations(100'000);
BENCHMARK(BM_GjkEpa_Pipeline)->Iterations(100'000);

View File

@@ -7,38 +7,23 @@ function(omath_setup_coverage TARGET_NAME)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
target_compile_options(${TARGET_NAME} PRIVATE
-fprofile-instr-generate
-fcoverage-mapping
/Zi
)
target_link_options(${TARGET_NAME} PRIVATE
target_compile_options(${TARGET_NAME} PRIVATE -fprofile-instr-generate -fcoverage-mapping
/Zi)
target_link_options(
${TARGET_NAME}
PRIVATE
-fprofile-instr-generate
-fcoverage-mapping
/DEBUG:FULL
/INCREMENTAL:NO
/PROFILE
)
/PROFILE)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang")
target_compile_options(${TARGET_NAME} PRIVATE
-fprofile-instr-generate
-fcoverage-mapping
-g
-O0
)
target_link_options(${TARGET_NAME} PRIVATE
-fprofile-instr-generate
-fcoverage-mapping
)
target_compile_options(${TARGET_NAME} PRIVATE -fprofile-instr-generate -fcoverage-mapping
-g -O0)
target_link_options(${TARGET_NAME} PRIVATE -fprofile-instr-generate -fcoverage-mapping)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(${TARGET_NAME} PRIVATE
--coverage
-g
-O0
)
target_link_options(${TARGET_NAME} PRIVATE
--coverage
)
target_compile_options(${TARGET_NAME} PRIVATE --coverage -g -O0)
target_link_options(${TARGET_NAME} PRIVATE --coverage)
endif()
if(TARGET coverage)
@@ -47,40 +32,36 @@ function(omath_setup_coverage TARGET_NAME)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
message(STATUS "MSVC detected: Use VS Code Coverage from CI workflow")
add_custom_target(coverage
add_custom_target(
coverage
DEPENDS unit_tests
COMMAND $<TARGET_FILE:unit_tests>
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Running tests for coverage (use VS Code Coverage from CI)"
)
COMMENT "Running tests for coverage (use VS Code Coverage from CI)")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang")
add_custom_target(coverage
add_custom_target(
coverage
DEPENDS unit_tests
COMMAND bash "${CMAKE_SOURCE_DIR}/scripts/coverage-llvm.sh"
"${CMAKE_SOURCE_DIR}"
"${CMAKE_BINARY_DIR}"
"$<TARGET_FILE:unit_tests>"
"${CMAKE_BINARY_DIR}/coverage"
COMMAND bash "${CMAKE_SOURCE_DIR}/scripts/coverage-llvm.sh" "${CMAKE_SOURCE_DIR}"
"${CMAKE_BINARY_DIR}" "$<TARGET_FILE:unit_tests>" "${CMAKE_BINARY_DIR}/coverage"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Running LLVM coverage"
)
COMMENT "Running LLVM coverage")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_custom_target(coverage
add_custom_target(
coverage
DEPENDS unit_tests
COMMAND $<TARGET_FILE:unit_tests> || true
COMMAND lcov --capture --directory "${CMAKE_BINARY_DIR}"
--output-file "${CMAKE_BINARY_DIR}/coverage.info"
--ignore-errors mismatch,gcov
COMMAND lcov --remove "${CMAKE_BINARY_DIR}/coverage.info"
"*/tests/*" "*/gtest/*" "*/googletest/*" "*/_deps/*" "/usr/*"
--output-file "${CMAKE_BINARY_DIR}/coverage.info"
--ignore-errors unused
COMMAND genhtml "${CMAKE_BINARY_DIR}/coverage.info"
--output-directory "${CMAKE_BINARY_DIR}/coverage"
COMMAND lcov --capture --directory "${CMAKE_BINARY_DIR}" --output-file
"${CMAKE_BINARY_DIR}/coverage.info" --ignore-errors mismatch,gcov
COMMAND
lcov --remove "${CMAKE_BINARY_DIR}/coverage.info" "*/tests/*" "*/gtest/*"
"*/googletest/*" "*/_deps/*" "/usr/*" --output-file
"${CMAKE_BINARY_DIR}/coverage.info" --ignore-errors unused
COMMAND genhtml "${CMAKE_BINARY_DIR}/coverage.info" --output-directory
"${CMAKE_BINARY_DIR}/coverage"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Running lcov/genhtml"
)
COMMENT "Running lcov/genhtml")
endif()
endfunction()

View File

@@ -22,23 +22,19 @@ function(omath_setup_valgrind TARGET_NAME)
return()
endif()
set(VALGRIND_FLAGS
--leak-check=full
--show-leak-kinds=all
--track-origins=yes
--error-exitcode=99
)
set(VALGRIND_FLAGS --leak-check=full --show-leak-kinds=all --track-origins=yes
--error-exitcode=99)
set(VALGRIND_TARGET "valgrind_${TARGET_NAME}")
if(NOT TARGET ${VALGRIND_TARGET})
add_custom_target(${VALGRIND_TARGET}
add_custom_target(
${VALGRIND_TARGET}
DEPENDS ${TARGET_NAME}
COMMAND ${VALGRIND_EXECUTABLE} ${VALGRIND_FLAGS} $<TARGET_FILE:${TARGET_NAME}>
WORKING_DIRECTORY $<TARGET_FILE_DIR:${TARGET_NAME}>
COMMENT "Running Valgrind memory check on ${TARGET_NAME}..."
USES_TERMINAL
)
USES_TERMINAL)
add_dependencies(valgrind_all ${VALGRIND_TARGET})
endif()

View File

@@ -1,6 +1,6 @@
# Installation
# Installation Guide
## <img width="28px" src="https://vcpkg.io/assets/mark/mark.svg" /> Using vcpkg
## <img width="28px" src="https://vcpkg.io/assets/mark/mark.svg" /> Using vcpkg (recomended)
**Note**: Support vcpkg for package management
1. Install [vcpkg](https://github.com/microsoft/vcpkg)
2. Run the following command to install the orange-math package:
@@ -28,6 +28,69 @@ target("...")
add_packages("omath")
```
## <img width="28px" src="https://conan.io/favicon.png" /> Using Conan
**Note**: Support Conan for package management
1. Install [Conan](https://conan.io/downloads)
2. Run the following command to install the omath package:
```
conan install --requires="omath/[*]" --build=missing
```
conanfile.txt
```ini
[requires]
omath/[*]
[generators]
CMakeDeps
CMakeToolchain
```
CMakeLists.txt
```cmake
find_package(omath CONFIG REQUIRED)
target_link_libraries(main PRIVATE omath::omath)
```
For more details, see the [Conan documentation](https://docs.conan.io/2/).
## <img width="28px" src="https://github.githubassets.com/favicons/favicon.svg" /> Using prebuilt binaries (GitHub Releases)
**Note**: This is the fastest option if you dont want to build from source.
1. **Go to the Releases page**
- Open the projects GitHub **Releases** page and choose the latest version.
2. **Download the correct asset for your platform**
- Pick the archive that matches your OS and architecture (for example: Windows x64 / Linux x64 / macOS arm64).
3. **Extract the archive**
- You should end up with something like:
- `include/` (headers)
- `lib/` or `bin/` (library files / DLLs)
- sometimes `cmake/` (CMake package config)
4. **Use it in your project**
### Option A: CMake package (recommended if the release includes CMake config files)
If the extracted folder contains something like `lib/cmake/omath` or `cmake/omath`, you can point CMake to it:
```cmake
# Example: set this to the extracted prebuilt folder
list(APPEND CMAKE_PREFIX_PATH "path/to/omath-prebuilt")
find_package(omath CONFIG REQUIRED)
target_link_libraries(main PRIVATE omath::omath)
```
### Option B: Manual include + link (works with any layout)
If theres no CMake package config, link it manually:
```cmake
target_include_directories(main PRIVATE "path/to/omath-prebuilt/include")
# Choose ONE depending on what you downloaded:
# - Static library: .lib / .a
# - Shared library: .dll + .lib import (Windows), .so (Linux), .dylib (macOS)
target_link_directories(main PRIVATE "path/to/omath-prebuilt/lib")
target_link_libraries(main PRIVATE omath) # or the actual library filename
```
## <img width="28px" src="https://upload.wikimedia.org/wikipedia/commons/e/ef/CMake_logo.svg?" /> Build from source using CMake
1. **Preparation**
@@ -62,7 +125,7 @@ target("...")
Use **\<platform\>-\<build configuration\>** preset to build suitable version for yourself. Like **windows-release** or **linux-release**.
| Platform Name | Build Config |
|---------------|---------------|
|---------------|---------------|
| windows | release/debug |
| linux | release/debug |
| darwin | release/debug |

View File

@@ -1,37 +1,11 @@
project(examples)
add_executable(example_projection_matrix_builder example_proj_mat_builder.cpp)
set_target_properties(example_projection_matrix_builder PROPERTIES
CXX_STANDARD 26
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
)
target_link_libraries(example_projection_matrix_builder PRIVATE omath::omath)
add_executable(example_signature_scan example_signature_scan.cpp)
set_target_properties(example_signature_scan PROPERTIES
CXX_STANDARD 26
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
)
target_link_libraries(example_signature_scan PRIVATE omath::omath)
add_executable(example_glfw3 example_glfw3.cpp)
set_target_properties(example_glfw3 PROPERTIES CXX_STANDARD 26
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
)
find_package(GLEW REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
target_link_libraries(example_glfw3 PRIVATE omath::omath GLEW::GLEW glfw)
add_subdirectory(example_barycentric)
add_subdirectory(example_glfw3)
add_subdirectory(example_proj_mat_builder)
add_subdirectory(example_signature_scan)
add_subdirectory(example_hud)
if(OMATH_ENABLE_VALGRIND)
omath_setup_valgrind(example_projection_matrix_builder)
omath_setup_valgrind(example_signature_scan)
omath_setup_valgrind(example_glfw3)
omath_setup_valgrind(example_projection_matrix_builder)
omath_setup_valgrind(example_signature_scan)
omath_setup_valgrind(example_glfw3)
endif()

View File

@@ -0,0 +1,14 @@
project(example_barycentric)
add_executable(${PROJECT_NAME} example_barycentric.cpp)
set_target_properties(
${PROJECT_NAME}
PROPERTIES CXX_STANDARD 23
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
find_package(OpenGL)
find_package(GLEW REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE omath::omath GLEW::GLEW glfw OpenGL::GL)

View File

@@ -0,0 +1,427 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
#include <iostream>
#include <omath/omath.hpp>
#include <vector>
using omath::Color;
using omath::Triangle;
using omath::Vector3;
static const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in float aPointSize;
layout (location = 3) in float aIsLine;
out vec3 vColor;
out float vIsLine;
void main() {
gl_Position = vec4(aPos, 1.0);
vColor = aColor;
gl_PointSize = aPointSize;
vIsLine = aIsLine;
}
)";
static const char* fragmentShaderSource = R"(
#version 330 core
in vec3 vColor;
in float vIsLine;
out vec4 FragColor;
void main() {
if (vIsLine < 0.5) {
// Calculate distance from center of the point
vec2 coord = gl_PointCoord - vec2(0.5);
if(length(coord) > 0.5)
discard;
}
FragColor = vec4(vColor, 1.0);
}
)";
GLuint compileShader(GLenum type, const char* src)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
GLint ok;
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
if (!ok)
{
char log[1024];
glGetShaderInfoLog(shader, sizeof(log), nullptr, log);
std::cerr << "Shader error: " << log << std::endl;
}
return shader;
}
void drawChar(char c, float x, float y, float scale, const Color& color, std::vector<float>& lines)
{
float w = 0.5f * scale;
float h = 1.0f * scale;
auto add = [&](float x1, float y1, float x2, float y2)
{
lines.push_back(x + x1 * w);
lines.push_back(y + y1 * h);
lines.push_back(0.0f);
lines.push_back(color.value().x);
lines.push_back(color.value().y);
lines.push_back(color.value().z);
lines.push_back(1.0f); // size
lines.push_back(1.0f); // isLine
lines.push_back(x + x2 * w);
lines.push_back(y + y2 * h);
lines.push_back(0.0f);
lines.push_back(color.value().x);
lines.push_back(color.value().y);
lines.push_back(color.value().z);
lines.push_back(1.0f); // size
lines.push_back(1.0f); // isLine
};
switch (c)
{
case '0':
add(0, 0, 1, 0);
add(1, 0, 1, 1);
add(1, 1, 0, 1);
add(0, 1, 0, 0);
break;
case '1':
add(0.5f, 0, 0.5f, 1);
add(0.25f, 0.75f, 0.5f, 1);
add(0.25f, 0, 0.75f, 0);
break;
case '2':
add(0, 1, 1, 1);
add(1, 1, 1, 0.5f);
add(1, 0.5f, 0, 0.5f);
add(0, 0.5f, 0, 0);
add(0, 0, 1, 0);
break;
case '3':
add(0, 1, 1, 1);
add(1, 1, 1, 0);
add(1, 0, 0, 0);
add(0, 0.5f, 1, 0.5f);
break;
case '4':
add(0, 1, 0, 0.5f);
add(0, 0.5f, 1, 0.5f);
add(1, 1, 1, 0);
break;
case '5':
add(1, 1, 0, 1);
add(0, 1, 0, 0.5f);
add(0, 0.5f, 1, 0.5f);
add(1, 0.5f, 1, 0);
add(1, 0, 0, 0);
break;
case '6':
add(1, 1, 0, 1);
add(0, 1, 0, 0);
add(0, 0, 1, 0);
add(1, 0, 1, 0.5f);
add(1, 0.5f, 0, 0.5f);
break;
case '7':
add(0, 1, 1, 1);
add(1, 1, 0.5f, 0);
break;
case '8':
add(0, 0, 1, 0);
add(1, 0, 1, 1);
add(1, 1, 0, 1);
add(0, 1, 0, 0);
add(0, 0.5f, 1, 0.5f);
break;
case '9':
add(1, 0.5f, 0, 0.5f);
add(0, 0.5f, 0, 1);
add(0, 1, 1, 1);
add(1, 1, 1, 0);
add(1, 0, 0, 0);
break;
case '.':
add(0.4f, 0, 0.6f, 0);
add(0.6f, 0, 0.6f, 0.2f);
add(0.6f, 0.2f, 0.4f, 0.2f);
add(0.4f, 0.2f, 0.4f, 0);
break;
}
}
void drawText(const std::string& text, float x, float y, float scale, const Color& color, std::vector<float>& lines)
{
float cursor = x;
for (char c : text)
{
drawChar(c, cursor, y, scale, color, lines);
cursor += (c == '.' ? 0.3f : 0.7f) * scale;
}
}
GLFWwindow* initWindow(int width, int height, const char* title)
{
if (!glfwInit())
{
std::cerr << "Failed to initialize GLFW\n";
return nullptr;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL);
if (!window)
{
std::cerr << "Failed to create GLFW window\n";
glfwTerminate();
return nullptr;
}
glfwMakeContextCurrent(window);
// Check if context is valid using standard GL
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
if (renderer && version)
{
std::cout << "Renderer: " << renderer << "\n";
std::cout << "OpenGL version supported: " << version << "\n";
}
else
{
std::cerr << "Failed to get GL_RENDERER or GL_VERSION. Context might be invalid.\n";
}
glewExperimental = GL_TRUE;
GLenum glewErr = glewInit();
if (glewErr != GLEW_OK)
{
// Ignore GLEW_ERROR_NO_GLX_DISPLAY if we have a valid context (e.g. Wayland)
if (glewErr == GLEW_ERROR_NO_GLX_DISPLAY && renderer)
{
std::cerr << "GLEW warning: " << glewGetErrorString(glewErr) << " (Ignored because context seems valid)\n";
}
else
{
std::cerr << "Failed to initialize GLEW: " << glewGetErrorString(glewErr) << "\n";
glfwTerminate();
return nullptr;
}
}
return window;
}
GLuint createShaderProgram()
{
GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glLinkProgram(shaderProgram);
return shaderProgram;
}
void generatePointCloud(std::vector<float>& pointCloud, const Triangle<Vector3<float>>& triangle)
{
const auto& A = triangle.m_vertex1;
const auto& B = triangle.m_vertex2;
const auto& C = triangle.m_vertex3;
// Iterating over barycentric coordinates (u, v, w) from 0.0 to 1.0
for (float u = 0.0f; u <= 1.0f; u += 0.015f)
{
for (float v = 0.0f; v <= 1.0f - u; v += 0.015f)
{
float w = 1.0f - u - v;
if (w >= 0.0f && w <= 1.0f)
{
Vector3<float> P = A * u + B * v + C * w;
pointCloud.push_back(P.x);
pointCloud.push_back(P.y);
pointCloud.push_back(P.z);
pointCloud.push_back(u);
pointCloud.push_back(v);
pointCloud.push_back(w);
pointCloud.push_back(2.0f); // size
pointCloud.push_back(0.0f); // isLine
}
}
}
}
void setupBuffers(GLuint& VAO_cloud, GLuint& VBO_cloud, const std::vector<float>& pointCloud, GLuint& VAO_dyn,
GLuint& VBO_dyn)
{
glGenVertexArrays(1, &VAO_cloud);
glGenBuffers(1, &VBO_cloud);
glBindVertexArray(VAO_cloud);
glBindBuffer(GL_ARRAY_BUFFER, VBO_cloud);
glBufferData(GL_ARRAY_BUFFER, pointCloud.size() * sizeof(float), pointCloud.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(7 * sizeof(float)));
glEnableVertexAttribArray(3);
glGenVertexArrays(1, &VAO_dyn);
glGenBuffers(1, &VBO_dyn);
glBindVertexArray(VAO_dyn);
glBindBuffer(GL_ARRAY_BUFFER, VBO_dyn);
glBufferData(GL_ARRAY_BUFFER, 1000 * 8 * sizeof(float), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(7 * sizeof(float)));
glEnableVertexAttribArray(3);
}
void updateDynamicData(std::vector<float>& dynData, float u, float v, float w, const Vector3<float>& P,
const Triangle<Vector3<float>>& triangle)
{
const auto& A = triangle.m_vertex1;
const auto& B = triangle.m_vertex2;
const auto& C = triangle.m_vertex3;
float sizeA = 10.0f + u * 30.0f;
float sizeB = 10.0f + v * 30.0f;
float sizeC = 10.0f + w * 30.0f;
float sizeP = 12.0f;
dynData = {// Lines from P to A, B, C
P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
// The animated dot itself (White)
P.x, P.y, P.z, 1.0f, 1.0f, 1.0f, sizeP, 0.0f,
// The 3 corner dots
A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, sizeA, 0.0f, B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, sizeB, 0.0f, C.x, C.y,
C.z, 0.0f, 0.0f, 1.0f, sizeC, 0.0f};
char bufA[16], bufB[16], bufC[16];
snprintf(bufA, sizeof(bufA), "%.2f", u);
snprintf(bufB, sizeof(bufB), "%.2f", v);
snprintf(bufC, sizeof(bufC), "%.2f", w);
// Keep text at a fixed distance from the dots
float distA = 0.13f;
float distB = 0.13f;
float distC = 0.13f;
drawText(bufA, A.x - 0.05f, A.y + distA, 0.1f, Color(1, 0, 0, 1), dynData);
drawText(bufB, B.x - 0.15f - distB, B.y - 0.05f - distB, 0.1f, Color(0, 1, 0, 1), dynData);
drawText(bufC, C.x + 0.05f + distC, C.y - 0.05f - distC, 0.1f, Color(0, 0, 1, 1), dynData);
}
int main()
{
GLFWwindow* window = initWindow(800, 800, "Barycentric Coordinates");
if (!window)
return -1;
GLuint shaderProgram = createShaderProgram();
// Triangle vertices as shown in the picture (Red, Green, Blue)
// Scaled down slightly to leave room for text
Triangle<Vector3<float>> triangle(Vector3<float>(0.0f, 0.6f, 0.0f), // Red dot (top)
Vector3<float>(-0.6f, -0.6f, 0.0f), // Green dot (bottom left)
Vector3<float>(0.6f, -0.6f, 0.0f) // Blue dot (bottom right)
);
std::vector<float> pointCloud;
generatePointCloud(pointCloud, triangle);
GLuint VAO_cloud, VBO_cloud, VAO_dyn, VBO_dyn;
setupBuffers(VAO_cloud, VBO_cloud, pointCloud, VAO_dyn, VBO_dyn);
glEnable(GL_PROGRAM_POINT_SIZE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.02f, 0.02f, 0.02f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
// Draw the point cloud (the iterated points)
glBindVertexArray(VAO_cloud);
glDrawArrays(GL_POINTS, 0, pointCloud.size() / 8);
// Animate the white dot to simulate dragging
float t = glfwGetTime();
float u = (std::sin(t * 1.5f) * 0.5f + 0.5f);
float v = (std::cos(t * 1.1f) * 0.5f + 0.5f);
if (u + v > 1.0f)
{
u = 1.0f - u;
v = 1.0f - v;
}
float w = 1.0f - u - v;
if (w > 1.0f)
{
float diff = w - 1.0f;
w = 1.0f;
u += diff / 2.0f;
v += diff / 2.0f;
}
else if (w < 0.0f)
{
float diff = -w;
w = 0.0f;
u -= diff / 2.0f;
v -= diff / 2.0f;
}
Vector3<float> P = triangle.m_vertex1 * u + triangle.m_vertex2 * v + triangle.m_vertex3 * w;
std::vector<float> dynData;
updateDynamicData(dynData, u, v, w, P, triangle);
glBindVertexArray(VAO_dyn);
glBindBuffer(GL_ARRAY_BUFFER, VBO_dyn);
glBufferSubData(GL_ARRAY_BUFFER, 0, dynData.size() * sizeof(float), dynData.data());
// Draw lines
glDrawArrays(GL_LINES, 0, 6);
// Draw text lines
int numTextVertices = (dynData.size() / 8) - 10;
if (numTextVertices > 0)
{
glDrawArrays(GL_LINES, 10, numTextVertices);
}
// Draw dots
glDrawArrays(GL_POINTS, 6, 4);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}

View File

@@ -0,0 +1,14 @@
project(example_glfw3)
add_executable(${PROJECT_NAME} example_glfw3.cpp)
set_target_properties(
${PROJECT_NAME}
PROPERTIES CXX_STANDARD 23
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
find_package(OpenGL)
find_package(GLEW REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE omath::omath GLEW::GLEW glfw OpenGL::GL)

View File

@@ -120,9 +120,14 @@ int main()
return -1;
}
std::cout << "GLFW Version: " << glfwGetVersionString() << "\n";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Force GLX context creation API to ensure compatibility with GLEW
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
@@ -141,15 +146,36 @@ int main()
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// Check if context is valid using standard GL
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
if (renderer && version)
{
std::cout << "Renderer: " << renderer << "\n";
std::cout << "OpenGL version supported: " << version << "\n";
}
else
{
std::cerr << "Failed to get GL_RENDERER or GL_VERSION. Context might be invalid.\n";
}
// ---------- GLEW init ----------
glewExperimental = GL_TRUE;
GLenum glewErr = glewInit();
if (glewErr != GLEW_OK)
{
std::cerr << "Failed to initialize GLEW: " << reinterpret_cast<const char*>(glewGetErrorString(glewErr))
<< "\n";
glfwTerminate();
return -1;
// Ignore NO_GLX_DISPLAY if we have a valid context
if (glewErr == GLEW_ERROR_NO_GLX_DISPLAY && renderer)
{
std::cerr << "GLEW warning: " << glewGetErrorString(glewErr) << " (Ignored because context seems valid)\n";
}
else
{
std::cerr << "Failed to initialize GLEW: " << reinterpret_cast<const char*>(glewGetErrorString(glewErr))
<< "\n";
glfwTerminate();
return -1;
}
}
// ---------- GL state ----------
@@ -280,11 +306,65 @@ int main()
static float old_frame_time = glfwGetTime();
float lastX = 640.0f / 2.0f;
float lastY = 480.0f / 2.0f;
bool firstMouse = true;
bool mouse_capture = false;
float mouseSensitivity = 0.1f;
// ---------- Main loop ----------
static double old_mouse_time = glfwGetTime();
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
omath::Vector3<float> move_dir;
if (glfwGetKey(window, GLFW_KEY_W))
move_dir += camera.get_forward();
if (glfwGetKey(window, GLFW_KEY_A))
move_dir -= camera.get_right();
if (glfwGetKey(window, GLFW_KEY_S))
move_dir -= camera.get_forward();
if (glfwGetKey(window, GLFW_KEY_D))
move_dir += camera.get_right();
if (glfwGetKey(window, GLFW_KEY_SPACE))
move_dir += camera.get_up();
if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL))
move_dir -= camera.get_up();
auto delta = glfwGetTime() - old_mouse_time;
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) && delta > 0.4)
{
old_mouse_time = glfwGetTime();
mouse_capture = !mouse_capture;
glfwSetInputMode(window, GLFW_CURSOR, mouse_capture ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL);
}
if (mouse_capture)
{
int x, y;
glfwGetWindowSize(window, &x, &y);
camera.set_origin(camera.get_origin() + (move_dir.normalized() * 0.4f));
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
float xoffset = (float)xpos - x / 2.f;
float yoffset = y / 2.f - ypos ; // reversed: y-coordinates go bottom->top for pitch
xoffset *= mouseSensitivity;
yoffset *= mouseSensitivity;
auto new_angles = camera.get_view_angles();
new_angles.pitch += decltype(new_angles.pitch)::from_degrees(yoffset);
new_angles.yaw -= decltype(new_angles.yaw)::from_degrees(xoffset);
camera.set_view_angles(new_angles);
glfwSetCursorPos(window, x / 2., y / 2);
}
float currentTime = glfwGetTime();
float deltaTime = currentTime - old_frame_time;
old_frame_time = currentTime;

View File

@@ -0,0 +1,16 @@
project(example_hud)
add_executable(${PROJECT_NAME} main.cpp gui/main_window.cpp gui/main_window.hpp)
set_target_properties(
${PROJECT_NAME}
PROPERTIES CXX_STANDARD 23
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
find_package(OpenGL)
find_package(GLEW REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE glfw imgui::imgui omath::omath OpenGL::GL)

View File

@@ -0,0 +1,263 @@
//
// Created by Orange on 11/11/2024.
//
#include "main_window.hpp"
#include "omath/hud/renderer_realizations/imgui_renderer.hpp"
#include <GLFW/glfw3.h>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <omath/hud/entity_overlay.hpp>
namespace imgui_desktop::gui
{
bool MainWindow::m_canMoveWindow = false;
MainWindow::MainWindow(const std::string_view& caption, int width, int height)
{
if (!glfwInit())
std::exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, true);
m_window = glfwCreateWindow(width, height, caption.data(), nullptr, nullptr);
glfwMakeContextCurrent(m_window);
ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = {0.05f, 0.05f, 0.05f, 0.92f};
ImGui::GetStyle().AntiAliasedLines = false;
ImGui::GetStyle().AntiAliasedFill = false;
ImGui_ImplGlfw_InitForOpenGL(m_window, true);
ImGui_ImplOpenGL3_Init("#version 150");
}
void MainWindow::Run()
{
while (!glfwWindowShouldClose(m_window) && m_opened)
{
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
const auto* vp = ImGui::GetMainViewport();
ImGui::GetBackgroundDrawList()->AddRectFilled({}, vp->Size, ImColor(30, 30, 30, 220));
draw_controls();
draw_overlay();
ImGui::Render();
present();
}
glfwDestroyWindow(m_window);
}
void MainWindow::draw_controls()
{
const auto* vp = ImGui::GetMainViewport();
ImGui::SetNextWindowPos({0.f, 0.f});
ImGui::SetNextWindowSize({280.f, vp->Size.y});
ImGui::Begin("Controls", &m_opened,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
ImGui::PushItemWidth(160.f);
if (ImGui::CollapsingHeader("Entity", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::SliderFloat("X##ent", &m_entity_x, 100.f, vp->Size.x - 100.f);
ImGui::SliderFloat("Top Y", &m_entity_top_y, 20.f, m_entity_bottom_y - 20.f);
ImGui::SliderFloat("Bottom Y", &m_entity_bottom_y, m_entity_top_y + 20.f, vp->Size.y - 20.f);
}
if (ImGui::CollapsingHeader("Box", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Checkbox("Box##chk", &m_show_box);
ImGui::SameLine();
ImGui::Checkbox("Cornered", &m_show_cornered_box);
ImGui::SameLine();
ImGui::Checkbox("Dashed", &m_show_dashed_box);
ImGui::ColorEdit4("Color##box", reinterpret_cast<float*>(&m_box_color), ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("Fill##box", reinterpret_cast<float*>(&m_box_fill), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Thickness", &m_box_thickness, 0.5f, 5.f);
ImGui::SliderFloat("Corner ratio", &m_corner_ratio, 0.05f, 0.5f);
ImGui::Separator();
ImGui::ColorEdit4("Dash color", reinterpret_cast<float*>(&m_dash_color), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Dash length", &m_dash_len, 2.f, 30.f);
ImGui::SliderFloat("Dash gap", &m_dash_gap, 1.f, 20.f);
ImGui::SliderFloat("Dash thick", &m_dash_thickness, 0.5f, 5.f);
}
if (ImGui::CollapsingHeader("Bars", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::ColorEdit4("Color##bar", reinterpret_cast<float*>(&m_bar_color), ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("BG##bar", reinterpret_cast<float*>(&m_bar_bg_color), ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("Outline##bar", reinterpret_cast<float*>(&m_bar_outline_color),
ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Width##bar", &m_bar_width, 1.f, 20.f);
ImGui::SliderFloat("Value##bar", &m_bar_value, 0.f, 1.f);
ImGui::SliderFloat("Offset##bar", &m_bar_offset, 1.f, 20.f);
ImGui::Checkbox("Right##bar", &m_show_right_bar);
ImGui::SameLine();
ImGui::Checkbox("Left##bar", &m_show_left_bar);
ImGui::Checkbox("Top##bar", &m_show_top_bar);
ImGui::SameLine();
ImGui::Checkbox("Bottom##bar", &m_show_bottom_bar);
ImGui::Checkbox("Right dashed##bar", &m_show_right_dashed_bar);
ImGui::SameLine();
ImGui::Checkbox("Left dashed##bar", &m_show_left_dashed_bar);
ImGui::Checkbox("Top dashed##bar", &m_show_top_dashed_bar);
ImGui::SameLine();
ImGui::Checkbox("Bot dashed##bar", &m_show_bottom_dashed_bar);
ImGui::SliderFloat("Dash len##bar", &m_bar_dash_len, 2.f, 20.f);
ImGui::SliderFloat("Dash gap##bar", &m_bar_dash_gap, 1.f, 15.f);
}
if (ImGui::CollapsingHeader("Labels", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Checkbox("Outlined", &m_outlined);
ImGui::SliderFloat("Offset##lbl", &m_label_offset, 0.f, 15.f);
ImGui::Checkbox("Right##lbl", &m_show_right_labels);
ImGui::SameLine();
ImGui::Checkbox("Left##lbl", &m_show_left_labels);
ImGui::Checkbox("Top##lbl", &m_show_top_labels);
ImGui::SameLine();
ImGui::Checkbox("Bottom##lbl", &m_show_bottom_labels);
ImGui::Checkbox("Ctr top##lbl", &m_show_centered_top);
ImGui::SameLine();
ImGui::Checkbox("Ctr bot##lbl", &m_show_centered_bottom);
}
if (ImGui::CollapsingHeader("Skeleton"))
{
ImGui::Checkbox("Show##skel", &m_show_skeleton);
ImGui::ColorEdit4("Color##skel", reinterpret_cast<float*>(&m_skel_color), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Thick##skel", &m_skel_thickness, 0.5f, 5.f);
}
if (ImGui::CollapsingHeader("Progress Ring"))
{
ImGui::Checkbox("Show##ring", &m_show_ring);
ImGui::ColorEdit4("Color##ring", reinterpret_cast<float*>(&m_ring_color), ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("BG##ring", reinterpret_cast<float*>(&m_ring_bg), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Radius##ring", &m_ring_radius, 4.f, 30.f);
ImGui::SliderFloat("Value##ring", &m_ring_ratio, 0.f, 1.f);
ImGui::SliderFloat("Thick##ring", &m_ring_thickness, 0.5f, 6.f);
ImGui::SliderFloat("Offset##ring", &m_ring_offset, 0.f, 15.f);
}
if (ImGui::CollapsingHeader("Scan Marker"))
{
ImGui::Checkbox("Show##scan", &m_show_scan);
ImGui::ColorEdit4("Fill##scan", reinterpret_cast<float*>(&m_scan_color), ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("Outline##scan", reinterpret_cast<float*>(&m_scan_outline), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Thick##scan", &m_scan_outline_thickness, 0.5f, 5.f);
}
if (ImGui::CollapsingHeader("Aim Dot"))
{
ImGui::Checkbox("Show##aim", &m_show_aim);
ImGui::ColorEdit4("Color##aim", reinterpret_cast<float*>(&m_aim_color), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Radius##aim", &m_aim_radius, 1.f, 10.f);
}
if (ImGui::CollapsingHeader("Projectile Aim"))
{
ImGui::Checkbox("Show##proj", &m_show_proj);
ImGui::ColorEdit4("Color##proj", reinterpret_cast<float*>(&m_proj_color), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Size##proj", &m_proj_size, 1.f, 30.f);
ImGui::SliderFloat("Line width##proj", &m_proj_line_width, 0.5f, 5.f);
ImGui::SliderFloat("Pos X##proj", &m_proj_pos_x, 0.f, vp->Size.x);
ImGui::SliderFloat("Pos Y##proj", &m_proj_pos_y, 0.f, vp->Size.y);
ImGui::Combo("Figure##proj", &m_proj_figure, "Circle\0Square\0");
}
if (ImGui::CollapsingHeader("Snap Line"))
{
ImGui::Checkbox("Show##snap", &m_show_snap);
ImGui::ColorEdit4("Color##snap", reinterpret_cast<float*>(&m_snap_color), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Width##snap", &m_snap_width, 0.5f, 5.f);
}
ImGui::PopItemWidth();
ImGui::End();
}
void MainWindow::draw_overlay()
{
using namespace omath::hud::widget;
using omath::hud::when;
const auto* vp = ImGui::GetMainViewport();
const Bar bar{m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width, m_bar_value, m_bar_offset};
const DashedBar dbar{m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width,
m_bar_value, m_bar_dash_len, m_bar_dash_gap, m_bar_offset};
omath::hud::EntityOverlay({m_entity_x, m_entity_top_y}, {m_entity_x, m_entity_bottom_y},
std::make_shared<omath::hud::ImguiHudRenderer>())
.contents(
// ── Boxes ────────────────────────────────────────────────────
when(m_show_box, Box{m_box_color, m_box_fill, m_box_thickness}),
when(m_show_cornered_box, CorneredBox{omath::Color::from_rgba(255, 0, 255, 255), m_box_fill,
m_corner_ratio, m_box_thickness}),
when(m_show_dashed_box, DashedBox{m_dash_color, m_dash_len, m_dash_gap, m_dash_thickness}),
RightSide{
when(m_show_right_bar, bar),
when(m_show_right_dashed_bar, dbar),
when(m_show_right_labels,
Label{{0.f, 1.f, 0.f, 1.f}, m_label_offset, m_outlined, "Health: 100/100"}),
when(m_show_right_labels,
Label{{1.f, 0.f, 0.f, 1.f}, m_label_offset, m_outlined, "Shield: 125/125"}),
when(m_show_right_labels,
Label{{1.f, 0.f, 1.f, 1.f}, m_label_offset, m_outlined, "*LOCKED*"}),
SpaceVertical{10},
when(m_show_ring, ProgressRing{m_ring_color, m_ring_bg, m_ring_radius, m_ring_ratio,
m_ring_thickness, m_ring_offset}),
},
LeftSide{
when(m_show_left_bar, bar),
when(m_show_left_dashed_bar, dbar),
when(m_show_left_labels, Label{omath::Color::from_rgba(255, 128, 0, 255),
m_label_offset, m_outlined, "Armor: 75"}),
when(m_show_left_labels, Label{omath::Color::from_rgba(0, 200, 255, 255),
m_label_offset, m_outlined, "Level: 42"}),
},
TopSide{
when(m_show_top_bar, bar),
when(m_show_top_dashed_bar, dbar),
when(m_show_centered_top, Centered{Label{omath::Color::from_rgba(0, 255, 255, 255),
m_label_offset, m_outlined, "*VISIBLE*"}}),
when(m_show_top_labels, Label{omath::Color::from_rgba(255, 255, 0, 255), m_label_offset,
m_outlined, "*SCOPED*"}),
when(m_show_top_labels, Label{omath::Color::from_rgba(255, 0, 0, 255), m_label_offset,
m_outlined, "*BLEEDING*"}),
},
BottomSide{
when(m_show_bottom_bar, bar),
when(m_show_bottom_dashed_bar, dbar),
when(m_show_centered_bottom, Centered{Label{omath::Color::from_rgba(255, 255, 255, 255),
m_label_offset, m_outlined, "PlayerName"}}),
when(m_show_bottom_labels, Label{omath::Color::from_rgba(200, 200, 0, 255),
m_label_offset, m_outlined, "42m"}),
},
when(m_show_aim, AimDot{{m_entity_x, m_entity_top_y+40.f}, m_aim_color, m_aim_radius}),
when(m_show_scan, ScanMarker{m_scan_color, m_scan_outline, m_scan_outline_thickness}),
when(m_show_skeleton, Skeleton{m_skel_color, m_skel_thickness}),
when(m_show_proj, ProjectileAim{{m_proj_pos_x, m_proj_pos_y}, m_proj_color, m_proj_size, m_proj_line_width, static_cast<ProjectileAim::Figure>(m_proj_figure)}),
when(m_show_snap, SnapLine{{vp->Size.x / 2.f, vp->Size.y}, m_snap_color, m_snap_width}));
}
void MainWindow::present()
{
int w, h;
glfwGetFramebufferSize(m_window, &w, &h);
glViewport(0, 0, w, h);
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(m_window);
}
} // namespace imgui_desktop::gui

View File

@@ -0,0 +1,94 @@
//
// Created by Orange on 11/11/2024.
//
#pragma once
#include <omath/hud/entity_overlay.hpp>
#include <omath/utility/color.hpp>
#include <string_view>
struct GLFWwindow;
namespace imgui_desktop::gui
{
class MainWindow
{
public:
MainWindow(const std::string_view& caption, int width, int height);
void Run();
private:
void draw_controls();
void draw_overlay();
void present();
GLFWwindow* m_window = nullptr;
static bool m_canMoveWindow;
bool m_opened = true;
// Entity
float m_entity_x = 550.f, m_entity_top_y = 150.f, m_entity_bottom_y = 450.f;
// Box
omath::Color m_box_color{1.f, 1.f, 1.f, 1.f};
omath::Color m_box_fill{0.f, 0.f, 0.f, 0.f};
float m_box_thickness = 1.f, m_corner_ratio = 0.2f;
bool m_show_box = true, m_show_cornered_box = true, m_show_dashed_box = false;
// Dashed box
omath::Color m_dash_color = omath::Color::from_rgba(255, 200, 0, 255);
float m_dash_len = 8.f, m_dash_gap = 5.f, m_dash_thickness = 1.f;
// Bars
omath::Color m_bar_color{0.f, 1.f, 0.f, 1.f};
omath::Color m_bar_bg_color{0.f, 0.f, 0.f, 0.5f};
omath::Color m_bar_outline_color{0.f, 0.f, 0.f, 1.f};
float m_bar_width = 4.f, m_bar_value = 0.75f, m_bar_offset = 5.f;
bool m_show_right_bar = true, m_show_left_bar = true;
bool m_show_top_bar = true, m_show_bottom_bar = true;
bool m_show_right_dashed_bar = false, m_show_left_dashed_bar = false;
bool m_show_top_dashed_bar = false, m_show_bottom_dashed_bar = false;
float m_bar_dash_len = 6.f, m_bar_dash_gap = 4.f;
// Labels
float m_label_offset = 3.f;
bool m_outlined = true;
bool m_show_right_labels = true, m_show_left_labels = true;
bool m_show_top_labels = true, m_show_bottom_labels = true;
bool m_show_centered_top = true, m_show_centered_bottom = true;
// Skeleton
omath::Color m_skel_color = omath::Color::from_rgba(255, 255, 255, 200);
float m_skel_thickness = 1.f;
bool m_show_skeleton = false;
// Progress ring
omath::Color m_ring_color = omath::Color::from_rgba(0, 200, 255, 255);
omath::Color m_ring_bg{0.3f, 0.3f, 0.3f, 0.5f};
float m_ring_radius = 10.f, m_ring_ratio = 0.65f, m_ring_thickness = 2.5f, m_ring_offset = 5.f;
bool m_show_ring = false;
// Scan marker
omath::Color m_scan_color = omath::Color::from_rgba(255, 200, 0, 150);
omath::Color m_scan_outline = omath::Color::from_rgba(255, 200, 0, 255);
float m_scan_outline_thickness = 2.f;
bool m_show_scan = false;
// Aim dot
omath::Color m_aim_color = omath::Color::from_rgba(255, 0, 0, 255);
float m_aim_radius = 3.f;
bool m_show_aim = false;
// Snap line
omath::Color m_snap_color = omath::Color::from_rgba(255, 50, 50, 255);
float m_snap_width = 1.5f;
bool m_show_snap = true;
// Projectile aim
omath::Color m_proj_color = omath::Color::from_rgba(255, 50, 50, 255);
float m_proj_size = 10.f;
float m_proj_line_width = 1.5f;
float m_proj_pos_x = 300.f, m_proj_pos_y = 30.f;
int m_proj_figure = 1; // 0=circle, 1=square
bool m_show_proj = true;
};
} // namespace imgui_desktop::gui

View File

@@ -0,0 +1,8 @@
//
// Created by orange on 13.03.2026.
//
#include "gui/main_window.hpp"
int main()
{
imgui_desktop::gui::MainWindow("omath::hud", 800, 600).Run();
}

View File

@@ -0,0 +1,10 @@
project(example_projection_matrix_builder)
add_executable(${PROJECT_NAME} example_proj_mat_builder.cpp)
set_target_properties(
${PROJECT_NAME}
PROPERTIES CXX_STANDARD 23
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
target_link_libraries(${PROJECT_NAME} PRIVATE omath::omath)

View File

@@ -0,0 +1,10 @@
project(example_signature_scan)
add_executable(${PROJECT_NAME} example_signature_scan.cpp)
set_target_properties(
${PROJECT_NAME}
PROPERTIES CXX_STANDARD 23
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
target_link_libraries(${PROJECT_NAME} PRIVATE omath::omath)

View File

@@ -0,0 +1,28 @@
//
// Created by Vladislav on 24.03.2026.
//
#pragma once
#include "omath/linear_algebra/vector3.hpp"
namespace omath::primitives
{
template<class Type>
struct Aabb final
{
Vector3<Type> min;
Vector3<Type> max;
[[nodiscard]]
constexpr Vector3<Type> center() const noexcept
{
return (min + max) / static_cast<Type>(2);
}
[[nodiscard]]
constexpr Vector3<Type> extents() const noexcept
{
return (max - min) / static_cast<Type>(2);
}
};
} // namespace omath::primitives

View File

@@ -3,14 +3,60 @@
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/opengl_engine/camera.hpp"
#include "omath/engines/opengl_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::primitives
{
template<class BoxMeshType>
[[nodiscard]]
std::array<Triangle<Vector3<float>>, 12> create_box(const Vector3<float>& top, const Vector3<float>& bottom,
const Vector3<float>& dir_forward, const Vector3<float>& dir_right,
float ratio = 4.f) noexcept;
}
BoxMeshType create_box(const Vector3<float>& top, const Vector3<float>& bottom, const Vector3<float>& dir_forward,
const Vector3<float>& dir_right, const float ratio = 4.f) noexcept
{
const auto height = top.distance_to(bottom);
const auto side_size = height / ratio;
// corner layout (03 bottom, 47 top)
std::array<Vector3<float>, 8> p;
p[0] = bottom + (dir_forward + dir_right) * side_size; // frontrightbottom
p[1] = bottom + (dir_forward - dir_right) * side_size; // frontleftbottom
p[2] = bottom + (-dir_forward + dir_right) * side_size; // backrightbottom
p[3] = bottom + (-dir_forward - dir_right) * side_size; // backleftbottom
p[4] = top + (dir_forward + dir_right) * side_size; // frontrighttop
p[5] = top + (dir_forward - dir_right) * side_size; // frontlefttop
p[6] = top + (-dir_forward + dir_right) * side_size; // backrighttop
p[7] = top + (-dir_forward - dir_right) * side_size; // backlefttop
std::array<Vector3<std::uint32_t>, 12> poly;
// bottom face (+Y up ⇒ wind CW when viewed from above)
poly[0] = {0, 2, 3};
poly[1] = {0, 3, 1};
// top face
poly[2] = {4, 7, 6};
poly[3] = {4, 5, 7};
// front face
poly[4] = {0, 5, 1};
poly[5] = {0, 4, 5};
// right face
poly[6] = {0, 6, 2};
poly[7] = {0, 4, 6};
// back face
poly[8] = {2, 7, 3};
poly[9] = {2, 6, 7};
// left face
poly[10] = {1, 7, 5};
poly[11] = {1, 3, 7};
return BoxMeshType{std::move(p), std::move(poly)};
}
} // namespace omath::primitives

View File

@@ -25,16 +25,17 @@ namespace omath::primitives
template<typename T> concept HasNormal = requires(T vertex) { vertex.normal; };
template<typename T> concept HasUv = requires(T vertex) { vertex.uv; };
template<class Mat4X4, class RotationAngles, class MeshTypeTrait, class VertType = Vertex<>>
template<class Mat4X4, class RotationAngles, class MeshTypeTrait, class VertType = Vertex<>,
class VboType = std::vector<VertType>, class EboType = std::vector<Vector3<std::uint32_t>>>
class Mesh final
{
public:
using VectorType = VertType::VectorType;
using VertexType = VertType;
using VertexType = VboType::value_type;
private:
using Vbo = std::vector<VertexType>;
using Ebo = std::vector<Vector3<std::uint32_t>>;
using Vbo = VboType;
using Ebo = EboType;
public:
Vbo m_vertex_buffer;
@@ -100,20 +101,26 @@ namespace omath::primitives
[[nodiscard]]
VectorType vertex_position_to_world_space(const Vector3<float>& vertex_position) const
requires HasPosition<VertexType>
{
auto abs_vec = get_to_world_matrix() * mat_column_from_vector<typename Mat4X4::ContainedType, Mat4X4::get_store_ordering()>(vertex_position);
auto abs_vec = get_to_world_matrix()
* mat_column_from_vector<typename Mat4X4::ContainedType, Mat4X4::get_store_ordering()>(
vertex_position);
return {abs_vec.at(0, 0), abs_vec.at(1, 0), abs_vec.at(2, 0)};
}
[[nodiscard]]
Triangle<VectorType> make_face_in_world_space(const Ebo::const_iterator vao_iterator) const
requires HasPosition<VertexType>
{
return {vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->x).position),
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->y).position),
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->z).position)};
if constexpr (HasPosition<VertexType>)
{
return {vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->x).position),
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->y).position),
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->z).position)};
}
return {vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->x)),
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->y)),
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->z))};
}
private:

View File

@@ -3,14 +3,30 @@
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/opengl_engine/camera.hpp"
#include "omath/engines/opengl_engine/mesh.hpp"
#include "omath/engines/opengl_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::primitives
{
template<class PlaneMeshType>
[[nodiscard]]
std::array<Triangle<Vector3<float>>, 2> create_plane(const Vector3<float>& vertex_a,
const Vector3<float>& vertex_b,
const Vector3<float>& direction, float size) noexcept;
}
PlaneMeshType create_plane(const Vector3<float>& vertex_a, const Vector3<float>& vertex_b,
const Vector3<float>& direction, const float size) noexcept
{
const auto second_vertex_a = vertex_a + direction * size;
const auto second_vertex_b = vertex_b + direction * size;
std::array<Vector3<float>, 4> grid = {vertex_a, vertex_b, second_vertex_a, second_vertex_b};
std::array<Vector3<std::uint32_t>, 2> poly;
poly[0] = {1, 1, 2};
poly[1] = {0, 1, 3};
return PlaneMeshType(std::move(grid), std::move(poly));
}
} // namespace omath::primitives

View File

@@ -0,0 +1,98 @@
//
// Created by Vladislav on 19.03.2026.
//
#pragma once
#include "omath/linear_algebra/vector3.hpp"
#include <functional>
#include <iterator>
#include <optional>
#include <ranges>
namespace omath::algorithm
{
template<class CameraType, std::input_or_output_iterator IteratorType, class FilterT>
requires std::is_invocable_r_v<bool, std::function<FilterT>, std::iter_reference_t<IteratorType>>
[[nodiscard]]
IteratorType get_closest_target_by_fov(const IteratorType& begin, const IteratorType& end, const CameraType& camera,
auto get_position,
const std::optional<std::function<FilterT>>& filter_func = std::nullopt)
{
auto best_target = end;
const auto& camera_angles = camera.get_view_angles();
const Vector2<float> camera_angles_vec = {camera_angles.pitch.as_degrees(), camera_angles.yaw.as_degrees()};
for (auto current = begin; current != end; current = std::next(current))
{
if (filter_func && !filter_func.value()(*current))
continue;
if (best_target == end)
{
best_target = current;
continue;
}
const auto current_target_angles = camera.calc_look_at_angles(get_position(*current));
const auto best_target_angles = camera.calc_look_at_angles(get_position(*best_target));
const auto current_target_distance = camera_angles_vec.distance_to(current_target_angles.as_vector3());
const auto best_target_distance = camera_angles.as_vector3().distance_to(best_target_angles.as_vector3());
if (current_target_distance < best_target_distance)
best_target = current;
}
return best_target;
}
template<class CameraType, std::ranges::range RangeType, class FilterT>
requires std::is_invocable_r_v<bool, std::function<FilterT>,
std::ranges::range_reference_t<const RangeType>>
[[nodiscard]]
auto get_closest_target_by_fov(const RangeType& range, const CameraType& camera,
auto get_position,
const std::optional<std::function<FilterT>>& filter_func = std::nullopt)
{
return get_closest_target_by_fov<CameraType, decltype(std::ranges::begin(range)), FilterT>(
std::ranges::begin(range), std::ranges::end(range), camera, get_position, filter_func);
}
// ── By world-space distance ───────────────────────────────────────────────
template<std::input_or_output_iterator IteratorType, class FilterT>
requires std::is_invocable_r_v<bool, std::function<FilterT>, std::iter_reference_t<IteratorType>>
[[nodiscard]]
IteratorType get_closest_target_by_distance(const IteratorType& begin, const IteratorType& end,
const Vector3<float>& origin, auto get_position,
const std::optional<std::function<FilterT>>& filter_func = std::nullopt)
{
auto best_target = end;
for (auto current = begin; current != end; current = std::next(current))
{
if (filter_func && !filter_func.value()(*current))
continue;
if (best_target == end)
{
best_target = current;
continue;
}
if (origin.distance_to(get_position(*current)) < origin.distance_to(get_position(*best_target)))
best_target = current;
}
return best_target;
}
template<std::ranges::range RangeType, class FilterT>
requires std::is_invocable_r_v<bool, std::function<FilterT>,
std::ranges::range_reference_t<const RangeType>>
[[nodiscard]]
auto get_closest_target_by_distance(const RangeType& range, const Vector3<float>& origin,
auto get_position,
const std::optional<std::function<FilterT>>& filter_func = std::nullopt)
{
return get_closest_target_by_distance<decltype(std::ranges::begin(range)), FilterT>(
std::ranges::begin(range), std::ranges::end(range), origin, get_position, filter_func);
}
} // namespace omath::algorithm

View File

@@ -8,16 +8,17 @@
#include <memory>
#include <memory_resource>
#include <queue>
#include <unordered_map>
#include <utility>
#include <vector>
namespace omath::collision
{
template<class V>
concept EpaVector = requires(const V& a, const V& b, float s) {
template<class V, class FloatingType>
concept EpaVector = requires(const V& a, const V& b, FloatingType s) {
{ a - b } -> std::same_as<V>;
{ a.cross(b) } -> std::same_as<V>;
{ a.dot(b) } -> std::same_as<float>;
{ a.dot(b) } -> std::same_as<FloatingType>;
{ -a } -> std::same_as<V>;
{ a * s } -> std::same_as<V>;
{ a / s } -> std::same_as<V>;
@@ -28,13 +29,18 @@ namespace omath::collision
{
public:
using VectorType = ColliderInterfaceType::VectorType;
static_assert(EpaVector<VectorType>, "VertexType must satisfy EpaVector concept");
static_assert(EpaVector<VectorType, typename VectorType::ContainedType>,
"VertexType must satisfy EpaVector concept");
private:
using FloatingType = VectorType::ContainedType;
public:
struct Result final
{
VectorType normal{}; // from A to B
VectorType penetration_vector;
float depth{0.0f};
FloatingType depth{0.0};
int iterations{0};
int num_vertices{0};
int num_faces{0};
@@ -43,7 +49,7 @@ namespace omath::collision
struct Params final
{
int max_iterations{64};
float tolerance{1e-4f}; // absolute tolerance on distance growth
FloatingType tolerance{1e-4}; // absolute tolerance on distance growth
};
// Precondition: simplex.size()==4 and contains the origin.
[[nodiscard]]
@@ -51,83 +57,76 @@ namespace omath::collision
const Simplex<VectorType>& simplex, const Params params = {},
std::pmr::memory_resource& mem_resource = *std::pmr::get_default_resource())
{
// --- Build initial polytope from simplex (4 points) ---
std::pmr::vector<VectorType> vertexes = build_initial_polytope_from_simplex(simplex, mem_resource);
// Initial tetra faces (windings corrected in make_face)
std::pmr::vector<Face> faces = create_initial_tetra_faces(mem_resource, vertexes);
auto heap = rebuild_heap(faces, mem_resource);
// Build initial min-heap by distance.
Heap heap = rebuild_heap(faces, mem_resource);
Result out{};
// Hoisted outside the loop to reuse bucket allocation across iterations.
// Initial bucket count 16 covers a typical horizon without rehashing.
BoundaryMap boundary{16, &mem_resource};
for (int it = 0; it < params.max_iterations; ++it)
{
// If heap might be stale after face edits, rebuild lazily.
if (heap.empty())
break;
// Rebuild when the "closest" face changed (simple cheap guard)
// (We could keep face handles; this is fine for small Ns.)
if (const auto top = heap.top(); faces[top.idx].d != top.d)
heap = rebuild_heap(faces, mem_resource);
// Lazily discard stale (deleted or index-mismatched) heap entries.
discard_stale_heap_entries(faces, heap);
if (heap.empty())
break;
//FIXME: STORE REF VALUE, DO NOT USE
// AFTER IF STATEMENT BLOCK
const Face& face = faces[heap.top().idx];
// Get the furthest point in face normal direction
const VectorType p = support_point(a, b, face.n);
const float p_dist = face.n.dot(p);
const auto p_dist = face.n.dot(p);
// Converged if we cant push the face closer than tolerance
// Converged: new support can't push the face closer than tolerance.
if (p_dist - face.d <= params.tolerance)
{
out.normal = face.n;
out.depth = face.d; // along unit normal
out.depth = face.d;
out.iterations = it + 1;
out.num_vertices = static_cast<int>(vertexes.size());
out.num_faces = static_cast<int>(faces.size());
out.penetration_vector = out.normal * out.depth;
return out;
}
// Add new vertex
const int new_idx = static_cast<int>(vertexes.size());
vertexes.emplace_back(p);
const auto [to_delete, boundary] = mark_visible_and_collect_horizon(faces, p);
// Tombstone visible faces and collect the horizon boundary.
// This avoids copying the faces array (O(n)) each iteration.
tombstone_visible_faces(faces, boundary, p);
erase_marked(faces, to_delete);
// Stitch new faces around the horizon
for (const auto& e : boundary)
// Stitch new faces around the horizon and push them directly onto the
// heap — no full O(n log n) rebuild needed.
for (const auto& [key, e] : boundary)
{
const int fi = static_cast<int>(faces.size());
faces.emplace_back(make_face(vertexes, e.a, e.b, new_idx));
// Rebuild heap after topology change
heap = rebuild_heap(faces, mem_resource);
heap.emplace(faces.back().d, fi);
}
if (!std::isfinite(vertexes.back().dot(vertexes.back())))
break; // safety
out.iterations = it + 1;
}
if (faces.empty())
// Find the best surviving (non-deleted) face.
const Face* best = find_best_surviving_face(faces);
if (!best)
return std::nullopt;
const auto best = *std::ranges::min_element(faces, [](const auto& first, const auto& second)
{ return first.d < second.d; });
out.normal = best.n;
out.depth = best.d;
out.normal = best->n;
out.depth = best->d;
out.num_vertices = static_cast<int>(vertexes.size());
out.num_faces = static_cast<int>(faces.size());
out.penetration_vector = out.normal * out.depth;
return out;
}
@@ -136,7 +135,8 @@ namespace omath::collision
{
int i0, i1, i2;
VectorType n; // unit outward normal
float d; // n · v0 (>=0 ideally because origin is inside)
FloatingType d; // n · v0 (>= 0 ideally because origin is inside)
bool deleted{false}; // tombstone flag — avoids O(n) compaction per iteration
};
struct Edge final
@@ -146,9 +146,10 @@ namespace omath::collision
struct HeapItem final
{
float d;
FloatingType d;
int idx;
};
struct HeapCmp final
{
[[nodiscard]]
@@ -160,35 +161,44 @@ namespace omath::collision
using Heap = std::priority_queue<HeapItem, std::pmr::vector<HeapItem>, HeapCmp>;
// Horizon boundary: maps packed(a,b) → Edge.
// Opposite edges cancel in O(1) via hash lookup instead of O(h) linear scan.
using BoundaryMap = std::pmr::unordered_map<std::int64_t, Edge>;
[[nodiscard]]
static constexpr std::int64_t pack_edge(const int a, const int b) noexcept
{
return (static_cast<std::int64_t>(a) << 32) | static_cast<std::uint32_t>(b);
}
[[nodiscard]]
static Heap rebuild_heap(const std::pmr::vector<Face>& faces, auto& memory_resource)
{
std::pmr::vector<HeapItem> storage{&memory_resource};
storage.reserve(faces.size()); // optional but recommended
storage.reserve(faces.size());
Heap h{HeapCmp{}, std::move(storage)};
for (int i = 0; i < static_cast<int>(faces.size()); ++i)
h.emplace(faces[i].d, i);
return h; // allocator is preserved
if (!faces[i].deleted)
h.emplace(faces[i].d, i);
return h;
}
[[nodiscard]]
static bool visible_from(const Face& f, const VectorType& p)
{
// positive if p is in front of the face
return f.n.dot(p) - f.d > 1e-7f;
return f.n.dot(p) - f.d > static_cast<FloatingType>(1e-7);
}
static void add_edge_boundary(std::pmr::vector<Edge>& boundary, int a, int b)
static void add_edge_boundary(BoundaryMap& boundary, int a, int b)
{
// Keep edges that appear only once; erase if opposite already present
auto itb = std::ranges::find_if(boundary, [&](const Edge& e) { return e.a == b && e.b == a; });
if (itb != boundary.end())
boundary.erase(itb); // internal edge cancels out
// O(1) cancel: if the opposite edge (b→a) is already in the map it is an
// internal edge shared by two visible faces and must be removed.
// Otherwise this is a horizon edge and we insert it.
const std::int64_t rev = pack_edge(b, a);
if (const auto it = boundary.find(rev); it != boundary.end())
boundary.erase(it);
else
boundary.emplace_back(a, b); // horizon edge (directed)
boundary.emplace(pack_edge(a, b), Edge{a, b});
}
[[nodiscard]]
@@ -198,19 +208,18 @@ namespace omath::collision
const VectorType& a1 = vertexes[i1];
const VectorType& a2 = vertexes[i2];
VectorType n = (a1 - a0).cross(a2 - a0);
if (n.dot(n) <= 1e-30f)
{
if (n.dot(n) <= static_cast<FloatingType>(1e-30))
n = any_perp_vec(a1 - a0); // degenerate guard
}
// Ensure normal points outward (away from origin): require n·a0 >= 0
if (n.dot(a0) < 0.0f)
if (n.dot(a0) < static_cast<FloatingType>(0.0))
{
std::swap(i1, i2);
n = -n;
}
const float inv_len = 1.0f / std::sqrt(std::max(n.dot(n), 1e-30f));
const auto inv_len =
static_cast<FloatingType>(1.0) / std::sqrt(std::max(n.dot(n), static_cast<FloatingType>(1e-30)));
n = n * inv_len;
const float d = n.dot(a0);
const auto d = n.dot(a0);
return {i0, i1, i2, n, d};
}
@@ -223,7 +232,7 @@ namespace omath::collision
template<class V>
[[nodiscard]]
static constexpr bool near_zero_vec(const V& v, const float eps = 1e-7f)
static constexpr bool near_zero_vec(const V& v, const FloatingType eps = 1e-7f)
{
return v.dot(v) <= eps * eps;
}
@@ -237,6 +246,7 @@ namespace omath::collision
return d;
return V{1, 0, 0};
}
[[nodiscard]]
static std::pmr::vector<Face> create_initial_tetra_faces(std::pmr::memory_resource& mem_resource,
const std::pmr::vector<VectorType>& vertexes)
@@ -256,48 +266,45 @@ namespace omath::collision
{
std::pmr::vector<VectorType> vertexes{&mem_resource};
vertexes.reserve(simplex.size());
for (std::size_t i = 0; i < simplex.size(); ++i)
vertexes.emplace_back(simplex[i]);
return vertexes;
}
static void erase_marked(std::pmr::vector<Face>& faces, const std::pmr::vector<bool>& to_delete)
static const Face* find_best_surviving_face(const std::pmr::vector<Face>& faces)
{
auto* mr = faces.get_allocator().resource(); // keep same resource
std::pmr::vector<Face> kept{mr};
kept.reserve(faces.size());
for (std::size_t i = 0; i < faces.size(); ++i)
if (!to_delete[i])
kept.emplace_back(faces[i]);
faces.swap(kept);
const Face* best = nullptr;
for (const auto& f : faces)
if (!f.deleted && (best == nullptr || f.d < best->d))
best = &f;
return best;
}
struct Horizon
static void tombstone_visible_faces(std::pmr::vector<Face>& faces, BoundaryMap& boundary,
const VectorType& p)
{
std::pmr::vector<bool> to_delete;
std::pmr::vector<Edge> boundary;
};
static Horizon mark_visible_and_collect_horizon(const std::pmr::vector<Face>& faces, const VectorType& p)
{
auto* mr = faces.get_allocator().resource();
Horizon horizon{std::pmr::vector<bool>(faces.size(), false, mr), std::pmr::vector<Edge>(mr)};
horizon.boundary.reserve(faces.size());
for (std::size_t i = 0; i < faces.size(); ++i)
if (visible_from(faces[i], p))
boundary.clear();
for (auto& f : faces)
{
if (!f.deleted && visible_from(f, p))
{
const auto& rf = faces[i];
horizon.to_delete[i] = true;
add_edge_boundary(horizon.boundary, rf.i0, rf.i1);
add_edge_boundary(horizon.boundary, rf.i1, rf.i2);
add_edge_boundary(horizon.boundary, rf.i2, rf.i0);
f.deleted = true;
add_edge_boundary(boundary, f.i0, f.i1);
add_edge_boundary(boundary, f.i1, f.i2);
add_edge_boundary(boundary, f.i2, f.i0);
}
}
}
return horizon;
static void discard_stale_heap_entries(const std::pmr::vector<Face>& faces,
std::priority_queue<HeapItem, std::pmr::vector<HeapItem>, HeapCmp>& heap)
{
while (!heap.empty())
{
const auto& top = heap.top();
if (!faces[top.idx].deleted && faces[top.idx].d == top.d)
break;
heap.pop();
}
}
};
} // namespace omath::collision

View File

@@ -14,11 +14,15 @@ namespace omath::collision
Simplex<VertexType> simplex; // valid only if hit == true and size==4
};
struct GjkSettings final
{
float epsilon = 1e-6f;
std::size_t max_iterations = 64;
};
template<class ColliderInterfaceType>
class GjkAlgorithm final
{
using VectorType = ColliderInterfaceType::VectorType;
public:
[[nodiscard]]
static VectorType find_support_vertex(const ColliderInterfaceType& collider_a,
@@ -36,20 +40,34 @@ namespace omath::collision
[[nodiscard]]
static GjkHitInfo<VectorType> is_collide_with_simplex_info(const ColliderInterfaceType& collider_a,
const ColliderInterfaceType& collider_b)
const ColliderInterfaceType& collider_b,
const GjkSettings& settings = {})
{
auto support = find_support_vertex(collider_a, collider_b, VectorType{1, 0, 0});
// Use centroid difference as initial direction — greatly reduces iterations for separated shapes.
VectorType initial_dir;
if constexpr (requires { collider_b.get_origin() - collider_a.get_origin(); })
{
initial_dir = collider_b.get_origin() - collider_a.get_origin();
if (initial_dir.dot(initial_dir) < settings.epsilon * settings.epsilon)
initial_dir = VectorType{1, 0, 0};
}
else
{
initial_dir = VectorType{1, 0, 0};
}
auto support = find_support_vertex(collider_a, collider_b, initial_dir);
Simplex<VectorType> simplex;
simplex.push_front(support);
auto direction = -support;
while (true)
for (std::size_t iteration = 0; iteration < settings.max_iterations; ++iteration)
{
support = find_support_vertex(collider_a, collider_b, direction);
if (support.dot(direction) <= 0.f)
if (support.dot(direction) <= settings.epsilon)
return {false, simplex};
simplex.push_front(support);
@@ -57,6 +75,7 @@ namespace omath::collision
if (simplex.handle(direction))
return {true, simplex};
}
return {false, simplex};
}
};
} // namespace omath::collision

View File

@@ -3,35 +3,158 @@
//
#pragma once
#include "omath/3d_primitives/aabb.hpp"
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
namespace omath::collision
{
class Ray
template<class T = Vector3<float>>
class Ray final
{
public:
Vector3<float> start;
Vector3<float> end;
using VectorType = T;
VectorType start;
VectorType end;
bool infinite_length = false;
[[nodiscard]]
Vector3<float> direction_vector() const noexcept;
constexpr VectorType direction_vector() const noexcept
{
return end - start;
}
[[nodiscard]]
Vector3<float> direction_vector_normalized() const noexcept;
constexpr VectorType direction_vector_normalized() const noexcept
{
return direction_vector().normalized();
}
};
class LineTracer
template<class RayType = Ray<>>
class LineTracer final
{
using TriangleType = Triangle<typename RayType::VectorType>;
using AABBType = primitives::Aabb<typename RayType::VectorType::ContainedType>;
public:
LineTracer() = delete;
[[nodiscard]]
static bool can_trace_line(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept;
constexpr static bool can_trace_line(const RayType& ray, const TriangleType& triangle) noexcept
{
return get_ray_hit_point(ray, triangle) == ray.end;
}
// Realization of MöllerTrumbore intersection algorithm
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
[[nodiscard]]
static Vector3<float> get_ray_hit_point(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept;
constexpr static auto get_ray_hit_point(const RayType& ray, const TriangleType& triangle) noexcept
{
constexpr float k_epsilon = std::numeric_limits<float>::epsilon();
const auto side_a = triangle.side_a_vector();
const auto side_b = triangle.side_b_vector();
const auto ray_dir = ray.direction_vector();
const auto p = ray_dir.cross(side_b);
const auto det = side_a.dot(p);
if (std::abs(det) < k_epsilon)
return ray.end;
const auto inv_det = 1 / det;
const auto t = ray.start - triangle.m_vertex2;
const auto u = t.dot(p) * inv_det;
if ((u < 0 && std::abs(u) > k_epsilon) || (u > 1 && std::abs(u - 1) > k_epsilon))
return ray.end;
const auto q = t.cross(side_a);
// ReSharper disable once CppTooWideScopeInitStatement
const auto v = ray_dir.dot(q) * inv_det;
if ((v < 0 && std::abs(v) > k_epsilon) || (u + v > 1 && std::abs(u + v - 1) > k_epsilon))
return ray.end;
const auto t_hit = side_b.dot(q) * inv_det;
if (ray.infinite_length && t_hit <= k_epsilon)
return ray.end;
if (t_hit <= k_epsilon || t_hit > 1 - k_epsilon)
return ray.end;
return ray.start + ray_dir * t_hit;
}
// Slab method ray-AABB intersection
// Returns the hit point on the AABB surface, or ray.end if no intersection
[[nodiscard]]
constexpr static auto get_ray_hit_point(const RayType& ray, const AABBType& aabb) noexcept
{
using T = typename RayType::VectorType::ContainedType;
const auto dir = ray.direction_vector();
auto t_min = -std::numeric_limits<T>::infinity();
auto t_max = std::numeric_limits<T>::infinity();
const auto process_axis = [&](const T& d, const T& origin, const T& box_min,
const T& box_max) -> bool
{
constexpr T k_epsilon = std::numeric_limits<T>::epsilon();
if (std::abs(d) < k_epsilon)
return origin >= box_min && origin <= box_max;
const T inv = T(1) / d;
T t0 = (box_min - origin) * inv;
T t1 = (box_max - origin) * inv;
if (t0 > t1)
std::swap(t0, t1);
t_min = std::max(t_min, t0);
t_max = std::min(t_max, t1);
return t_min <= t_max;
};
if (!process_axis(dir.x, ray.start.x, aabb.min.x, aabb.max.x))
return ray.end;
if (!process_axis(dir.y, ray.start.y, aabb.min.y, aabb.max.y))
return ray.end;
if (!process_axis(dir.z, ray.start.z, aabb.min.z, aabb.max.z))
return ray.end;
// t_hit: use entry point if in front of origin, otherwise 0 (started inside)
const T t_hit = std::max(T(0), t_min);
if (t_max < T(0))
return ray.end; // box entirely behind origin
if (!ray.infinite_length && t_hit > T(1))
return ray.end; // box beyond ray endpoint
return ray.start + dir * t_hit;
}
template<class MeshType>
[[nodiscard]]
constexpr static auto get_ray_hit_point(const RayType& ray, const MeshType& mesh) noexcept
{
auto mesh_hit = ray.end;
const auto begin = mesh.m_element_buffer_object.cbegin();
const auto end = mesh.m_element_buffer_object.cend();
for (auto current = begin; current < end; current = std::next(current))
{
const auto face = mesh.make_face_in_world_space(current);
auto ray_stop_point = get_ray_hit_point(ray, face);
if (ray_stop_point.distance_to(ray.start) < mesh_hit.distance_to(ray.start))
mesh_hit = ray_stop_point;
}
return mesh_hit;
}
};
} // namespace omath::collision

View File

@@ -42,13 +42,40 @@ namespace omath::collision
m_mesh.set_origin(new_origin);
}
[[nodiscard]]
const MeshType& get_mesh() const
{
return m_mesh;
}
[[nodiscard]]
MeshType& get_mesh()
{
return m_mesh;
}
private:
[[nodiscard]]
const VertexType& find_furthest_vertex(const VectorType& direction) const
{
return *std::ranges::max_element(
m_mesh.m_vertex_buffer, [&direction](const auto& first, const auto& second)
{ return first.position.dot(direction) < second.position.dot(direction); });
// The support query arrives in world space, but vertex positions are stored
// in local space. We need argmax_v { world(v) · d }.
//
// world(v) = M·v (ignoring translation, which is constant across vertices)
// world(v) · d = v · Mᵀ·d
//
// So we transform the direction to local space once — O(1) — then compare
// raw local positions, which is far cheaper than calling
// vertex_position_to_world_space (full 4×4 multiply) for every vertex.
//
// d_local = upper-left 3×3 of M, transposed, times d_world:
// d_local[j] = sum_i M.at(i,j) * d[i] (i.e. column j of M dotted with d)
const auto& m = m_mesh.get_to_world_matrix();
const VectorType d_local = {
m[0, 0] * direction.x + m[1, 0] * direction.y + m[2, 0] * direction.z,
m[0, 1] * direction.x + m[1, 1] * direction.y + m[2, 1] * direction.z,
m[0, 2] * direction.x + m[1, 2] * direction.y + m[2, 2] * direction.z,
};
return *std::ranges::max_element(m_mesh.m_vertex_buffer, [&d_local](const auto& first, const auto& second)
{ return first.position.dot(d_local) < second.position.dot(d_local); });
}
MeshType m_mesh;
};

View File

@@ -130,7 +130,7 @@ namespace omath::collision
template<class V>
[[nodiscard]]
static constexpr bool near_zero(const V& v, const float eps = 1e-7f)
static constexpr bool near_zero(const V& v, const float eps = 1e-7f) noexcept
{
return v.dot(v) <= eps * eps;
}
@@ -146,7 +146,7 @@ namespace omath::collision
}
[[nodiscard]]
constexpr bool handle_line(VectorType& direction)
constexpr bool handle_line(VectorType& direction) noexcept
{
const auto& a = m_points[0];
const auto& b = m_points[1];
@@ -158,21 +158,11 @@ namespace omath::collision
{
// ReSharper disable once CppTooWideScopeInitStatement
auto n = ab.cross(ao); // Needed to valid handle collision if colliders placed at same origin pos
if (near_zero(n))
{
// collinear: origin lies on ray AB (often on segment), pick any perp to escape
direction = any_perp(ab);
}
else
{
direction = n.cross(ab);
}
}
else
{
*this = {a};
direction = ao;
direction = near_zero(n) ? any_perp(ab) : n.cross(ab);
return false;
}
*this = {a};
direction = ao;
return false;
}

View File

@@ -0,0 +1,194 @@
//
// Created by Vladislav on 04.01.2026.
//
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <span>
#ifdef OMATH_ENABLE_FORCE_INLINE
#ifdef _MSC_VER
#define OMATH_FORCE_INLINE __forceinline
#else
#define OMATH_FORCE_INLINE __attribute__((always_inline)) inline
#endif
#else
#define OMATH_FORCE_INLINE
#endif
namespace omath::detail
{
[[nodiscard]]
consteval std::uint64_t fnv1a_64(const char* s)
{
std::uint64_t h = 14695981039346656037ull;
while (*s)
{
h ^= static_cast<unsigned char>(*s++);
h *= 1099511628211ull;
}
return h;
}
// SplitMix64 mixer (good quality for seeding / scrambling)
[[nodiscard]]
consteval std::uint64_t splitmix64(std::uint64_t x)
{
x += 0x9E3779B97F4A7C15ull;
x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9ull;
x = (x ^ (x >> 27)) * 0x94D049BB133111EBull;
return x ^ (x >> 31);
}
// Choose your policy:
// - If you want reproducible builds, REMOVE __DATE__/__TIME__.
// - If you want "different each build", keep them.
[[nodiscard]]
consteval std::uint64_t base_seed()
{
std::uint64_t h = 0;
h ^= fnv1a_64(__FILE__);
h ^= splitmix64(fnv1a_64(__DATE__));
h ^= splitmix64(fnv1a_64(__TIME__));
return splitmix64(h);
}
// Produce a "random" 64-bit value for a given stream index (compile-time)
template<std::uint64_t Stream>
[[nodiscard]]
consteval std::uint64_t rand_u64()
{
// Stream is usually __COUNTER__ so each call site differs
return splitmix64(base_seed() + 0xD1B54A32D192ED03ull * (Stream + 1));
}
template<std::int64_t Lo, std::int64_t Hi, std::uint64_t Stream>
[[nodiscard]]
consteval std::int64_t rand_uint8_t()
{
static_assert(Lo <= Hi);
const std::uint64_t r = rand_u64<Stream>();
return static_cast<std::int64_t>(r) + Lo;
}
[[nodiscard]]
consteval std::uint64_t rand_u64(const std::uint64_t seed, const std::uint64_t i)
{
return splitmix64(seed + 0xD1B54A32D192ED03ull * (i + 1ull));
}
// Convert to int (uses low 32 bits; you can also use high bits if you prefer)
[[nodiscard]]
consteval std::uint8_t rand_uint8t(const std::uint64_t seed, const std::uint64_t i)
{
return static_cast<std::uint8_t>(rand_u64(seed, i)); // narrowing is fine/deterministic
}
template<std::size_t N, std::uint64_t Seed, std::size_t... I>
[[nodiscard]]
consteval std::array<std::uint8_t, N> make_array_impl(std::index_sequence<I...>)
{
return {rand_uint8t(Seed, static_cast<std::uint64_t>(I))...};
}
template<std::size_t N, std::uint64_t Seed>
[[nodiscard]]
consteval std::array<std::uint8_t, N> make_array()
{
return make_array_impl<N, Seed>(std::make_index_sequence<N>{});
}
} // namespace omath::detail
namespace omath
{
template<class T>
class VarAnchor;
template<class T, std::size_t key_size, std::array<std::uint8_t, key_size> key>
class EncryptedVariable final
{
using value_type = std::remove_cvref_t<T>;
bool m_is_encrypted{};
value_type m_data{};
OMATH_FORCE_INLINE constexpr void xor_contained_var_by_key()
{
// Safe, keeps const-correctness, and avoids reinterpret_cast issues
auto bytes = std::as_writable_bytes(std::span<value_type, 1>{&m_data, 1});
for (std::size_t i = 0; i < bytes.size(); ++i)
{
const std::uint8_t k = static_cast<std::uint8_t>(key[i % key_size] + (i * key_size));
bytes[i] ^= static_cast<std::byte>(k);
}
}
public:
OMATH_FORCE_INLINE constexpr explicit EncryptedVariable(const value_type& data)
: m_is_encrypted(false), m_data(data)
{
encrypt();
}
[[nodiscard]] constexpr bool is_encrypted() const
{
return m_is_encrypted;
}
OMATH_FORCE_INLINE constexpr void decrypt()
{
if (!m_is_encrypted)
return;
xor_contained_var_by_key();
m_is_encrypted = false;
}
OMATH_FORCE_INLINE constexpr void encrypt()
{
if (m_is_encrypted)
return;
xor_contained_var_by_key();
m_is_encrypted = true;
}
[[nodiscard]] OMATH_FORCE_INLINE constexpr value_type& value()
{
return m_data;
}
[[nodiscard]] OMATH_FORCE_INLINE constexpr const value_type& value() const
{
return m_data;
}
constexpr OMATH_FORCE_INLINE ~EncryptedVariable()
{
decrypt();
}
[[nodiscard]] constexpr OMATH_FORCE_INLINE auto drop_anchor()
{
return VarAnchor{*this};
}
};
template<class EncryptedVarType>
class VarAnchor final
{
public:
// ReSharper disable once CppNonExplicitConvertingConstructor
OMATH_FORCE_INLINE constexpr VarAnchor(EncryptedVarType& var): m_var(var)
{
m_var.decrypt();
}
OMATH_FORCE_INLINE constexpr ~VarAnchor()
{
m_var.encrypt();
}
private:
EncryptedVarType& m_var;
};
} // namespace omath
#define OMATH_CT_RAND_ARRAY_BYTE(N) \
(::omath::detail::make_array<(N), (::omath::detail::base_seed() ^ static_cast<std::uint64_t>(__COUNTER__))>())
#define OMATH_DEF_CRYPT_VAR(TYPE, KEY_SIZE) omath::EncryptedVariable<TYPE, KEY_SIZE, OMATH_CT_RAND_ARRAY_BYTE(KEY_SIZE)>

View File

@@ -0,0 +1,13 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include "omath/engines/cry_engine/constants.hpp"
#include "omath/projection/camera.hpp"
#include "traits/camera_trait.hpp"
namespace omath::cry_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
} // namespace omath::cry_engine

View File

@@ -0,0 +1,25 @@
//
// Created by Vlad on 10/21/2025.
//
#pragma once
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <omath/trigonometry/angle.hpp>
#include <omath/trigonometry/view_angles.hpp>
namespace omath::cry_engine
{
constexpr Vector3<float> k_abs_up = {0, 0, 1};
constexpr Vector3<float> k_abs_right = {1, 0, 0};
constexpr Vector3<float> k_abs_forward = {0, 1, 0};
using Mat4X4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat3X3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat1X3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
using PitchAngle = Angle<float, -90.f, 90.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
} // namespace omath::cry_engine

View File

@@ -0,0 +1,75 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include "omath/engines/cry_engine/constants.hpp"
namespace omath::cry_engine
{
[[nodiscard]]
Vector3<float> forward_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> up_vector(const ViewAngles& angles) noexcept;
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_centimeters(const FloatingType& units)
{
return units / static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_meters(const FloatingType& units)
{
return units;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_kilometers(const FloatingType& units)
{
return units_to_meters(units) / static_cast<FloatingType>(1000);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
{
return centimeters * static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType meters_to_units(const FloatingType& meters)
{
return meters;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
{
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
}
} // namespace omath::cry_engine

View File

@@ -0,0 +1,12 @@
//
// Created by Vladislav on 09.11.2025.
//
#pragma once
#include "constants.hpp"
#include "omath/3d_primitives/mesh.hpp"
#include "traits/mesh_trait.hpp"
namespace omath::cry_engine
{
using Mesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait>;
}

View File

@@ -0,0 +1,24 @@
//
// Created by Vlad on 8/10/2025.
//
#pragma once
#include "omath/engines/cry_engine/formulas.hpp"
#include "omath/projection/camera.hpp"
namespace omath::cry_engine
{
class CameraTrait final
{
public:
[[nodiscard]]
static ViewAngles calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept;
[[nodiscard]]
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};
} // namespace omath::cry_engine

View File

@@ -0,0 +1,19 @@
//
// Created by Vladislav on 09.11.2025.
//
#pragma once
#include <omath/engines/cry_engine/constants.hpp>
#include <omath/engines/cry_engine/formulas.hpp>
namespace omath::cry_engine
{
class MeshTrait final
{
public:
[[nodiscard]]
static Mat4X4 rotation_matrix(const ViewAngles& rotation)
{
return cry_engine::rotation_matrix(rotation);
}
};
} // namespace omath::cry_engine

View File

@@ -0,0 +1,77 @@
//
// Created by Vlad on 8/6/2025.
//
#pragma once
#include "omath/engines/cry_engine/formulas.hpp"
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
#include <optional>
namespace omath::cry_engine
{
class PredEngineTrait final
{
public:
constexpr static Vector3<float> predict_projectile_position(const projectile_prediction::Projectile& projectile,
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
const auto launch_pos = projectile.m_origin + projectile.m_launch_offset;
auto current_pos = launch_pos
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;
current_pos.z -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f;
return current_pos;
}
[[nodiscard]]
static constexpr Vector3<float> predict_target_position(const projectile_prediction::Target& target,
const float time, const float gravity) noexcept
{
auto predicted = target.m_origin + target.m_velocity * time;
if (target.m_is_airborne)
predicted.z -= gravity * (time * time) * 0.5f;
return predicted;
}
[[nodiscard]]
static float calc_vector_2d_distance(const Vector3<float>& delta) noexcept
{
return std::sqrt(delta.x * delta.x + delta.y * delta.y);
}
[[nodiscard]]
constexpr static float get_vector_height_coordinate(const Vector3<float>& vec) noexcept
{
return vec.z;
}
[[nodiscard]]
static Vector3<float> calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
Vector3<float> predicted_target_position,
const std::optional<float> projectile_pitch) noexcept
{
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
return {predicted_target_position.x, predicted_target_position.y, projectile.m_origin.z + height};
}
// Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be:
// 89 look up, -89 look down
[[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::asin(direction.z));
}
[[nodiscard]]
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(-std::atan2(direction.x, direction.y));
};
};
} // namespace omath::cry_engine

View File

@@ -9,5 +9,5 @@
namespace omath::frostbite_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
} // namespace omath::unity_engine

View File

@@ -22,5 +22,54 @@ namespace omath::frostbite_engine
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
} // namespace omath::unity_engine
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_centimeters(const FloatingType& units)
{
return units / static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_meters(const FloatingType& units)
{
return units;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_kilometers(const FloatingType& units)
{
return units_to_meters(units) / static_cast<FloatingType>(1000);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
{
return centimeters * static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType meters_to_units(const FloatingType& meters)
{
return meters;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
{
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
}
} // namespace omath::frostbite_engine

View File

@@ -0,0 +1,17 @@
//
// Created by Vladislav on 27.01.2026.
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/frostbite_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::frostbite_engine
{
using BoxMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>, std::array<Vector3<float>, 8>,
std::array<Vector3<std::uint32_t>, 12>>;
using PlaneMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>,
std::array<Vector3<float>, 4>, std::array<Vector3<std::uint32_t>, 2>>;
} // namespace omath::frostbite_engine

View File

@@ -18,7 +18,7 @@ namespace omath::frostbite_engine
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far) noexcept;
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};
} // namespace omath::unreal_engine

View File

@@ -16,7 +16,8 @@ namespace omath::frostbite_engine
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
auto current_pos = projectile.m_origin
const auto launch_pos = projectile.m_origin + projectile.m_launch_offset;
auto current_pos = launch_pos
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;
@@ -55,7 +56,7 @@ namespace omath::frostbite_engine
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
return {predicted_target_position.x, predicted_target_position.y + height, projectile.m_origin.z};
return {predicted_target_position.x, projectile.m_origin.y + height, predicted_target_position.z};
}
// Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be:
// 89 look up, -89 look down

View File

@@ -9,5 +9,5 @@
namespace omath::iw_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
} // namespace omath::iw_engine

View File

@@ -22,5 +22,56 @@ namespace omath::iw_engine
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_centimeters(const FloatingType& units)
{
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
return units * centimeter_in_unit;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_meters(const FloatingType& units)
{
return units_to_centimeters(units) / static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_kilometers(const FloatingType& units)
{
return units_to_meters(units) / static_cast<FloatingType>(1000);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
{
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
return centimeters / centimeter_in_unit;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType meters_to_units(const FloatingType& meters)
{
return centimeters_to_units(meters * static_cast<FloatingType>(100));
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
{
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
}
} // namespace omath::iw_engine

View File

@@ -0,0 +1,17 @@
//
// Created by Vladislav on 27.01.2026.
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/iw_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::iw_engine
{
using BoxMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>, std::array<Vector3<float>, 8>,
std::array<Vector3<std::uint32_t>, 12>>;
using PlaneMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>,
std::array<Vector3<float>, 4>, std::array<Vector3<std::uint32_t>, 2>>;
} // namespace omath::iw_engine

View File

@@ -18,7 +18,7 @@ namespace omath::iw_engine
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far) noexcept;
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};
} // namespace omath::iw_engine

View File

@@ -17,7 +17,8 @@ namespace omath::iw_engine
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
auto current_pos = projectile.m_origin
const auto launch_pos = projectile.m_origin + projectile.m_launch_offset;
auto current_pos = launch_pos
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;

View File

@@ -8,5 +8,5 @@
namespace omath::opengl_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, true, NDCDepthRange::NEGATIVE_ONE_TO_ONE>;
} // namespace omath::opengl_engine

View File

@@ -4,7 +4,6 @@
#pragma once
#include "omath/engines/opengl_engine/constants.hpp"
namespace omath::opengl_engine
{
[[nodiscard]]
@@ -22,5 +21,54 @@ namespace omath::opengl_engine
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_centimeters(const FloatingType& units)
{
return units / static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_meters(const FloatingType& units)
{
return units;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_kilometers(const FloatingType& units)
{
return units_to_meters(units) / static_cast<FloatingType>(1000);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
{
return centimeters * static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType meters_to_units(const FloatingType& meters)
{
return meters;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
{
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
}
} // namespace omath::opengl_engine

View File

@@ -0,0 +1,17 @@
//
// Created by Vladislav on 27.01.2026.
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/opengl_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::opengl_engine
{
using BoxMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>, std::array<Vector3<float>, 8>,
std::array<Vector3<std::uint32_t>, 12>>;
using PlaneMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>,
std::array<Vector3<float>, 4>, std::array<Vector3<std::uint32_t>, 2>>;
} // namespace omath::opengl_engine

View File

@@ -18,7 +18,7 @@ namespace omath::opengl_engine
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far) noexcept;
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};
} // namespace omath::opengl_engine

View File

@@ -16,7 +16,8 @@ namespace omath::opengl_engine
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
auto current_pos = projectile.m_origin
const auto launch_pos = projectile.m_origin + projectile.m_launch_offset;
auto current_pos = launch_pos
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;
@@ -55,7 +56,7 @@ namespace omath::opengl_engine
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
return {predicted_target_position.x, predicted_target_position.y + height, projectile.m_origin.z};
return {predicted_target_position.x, projectile.m_origin.y + height, predicted_target_position.z};
}
// Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be:
// 89 look up, -89 look down

View File

@@ -7,5 +7,5 @@
#include "traits/camera_trait.hpp"
namespace omath::source_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
} // namespace omath::source_engine

View File

@@ -21,5 +21,56 @@ namespace omath::source_engine
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_centimeters(const FloatingType& units)
{
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
return units * centimeter_in_unit;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_meters(const FloatingType& units)
{
return units_to_centimeters(units) / static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_kilometers(const FloatingType& units)
{
return units_to_meters(units) / static_cast<FloatingType>(1000);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
{
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
return centimeters / centimeter_in_unit;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType meters_to_units(const FloatingType& meters)
{
return centimeters_to_units(meters * static_cast<FloatingType>(100));
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
{
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
}
} // namespace omath::source_engine

View File

@@ -0,0 +1,17 @@
//
// Created by Vladislav on 27.01.2026.
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/source_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::source_engine
{
using BoxMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>, std::array<Vector3<float>, 8>,
std::array<Vector3<std::uint32_t>, 12>>;
using PlaneMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>,
std::array<Vector3<float>, 4>, std::array<Vector3<std::uint32_t>, 2>>;
} // namespace omath::source_engine

View File

@@ -18,7 +18,7 @@ namespace omath::source_engine
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far) noexcept;
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};
} // namespace omath::source_engine

View File

@@ -17,7 +17,8 @@ namespace omath::source_engine
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
auto current_pos = projectile.m_origin
const auto launch_pos = projectile.m_origin + projectile.m_launch_offset;
auto current_pos = launch_pos
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;

View File

@@ -9,5 +9,5 @@
namespace omath::unity_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
} // namespace omath::unity_engine

View File

@@ -22,5 +22,54 @@ namespace omath::unity_engine
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_centimeters(const FloatingType& units)
{
return units / static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_meters(const FloatingType& units)
{
return units;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_kilometers(const FloatingType& units)
{
return units_to_meters(units) / static_cast<FloatingType>(1000);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
{
return centimeters * static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType meters_to_units(const FloatingType& meters)
{
return meters;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
{
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
}
} // namespace omath::unity_engine

View File

@@ -0,0 +1,17 @@
//
// Created by Vladislav on 27.01.2026.
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/unity_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::unity_engine
{
using BoxMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>, std::array<Vector3<float>, 8>,
std::array<Vector3<std::uint32_t>, 12>>;
using PlaneMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>,
std::array<Vector3<float>, 4>, std::array<Vector3<std::uint32_t>, 2>>;
} // namespace omath::unity_engine

View File

@@ -18,7 +18,7 @@ namespace omath::unity_engine
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far) noexcept;
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};
} // namespace omath::unity_engine

View File

@@ -16,7 +16,8 @@ namespace omath::unity_engine
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
auto current_pos = projectile.m_origin
const auto launch_pos = projectile.m_origin + projectile.m_launch_offset;
auto current_pos = launch_pos
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;
@@ -55,7 +56,7 @@ namespace omath::unity_engine
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
return {predicted_target_position.x, predicted_target_position.y + height, projectile.m_origin.z};
return {predicted_target_position.x, projectile.m_origin.y + height, predicted_target_position.z};
}
// Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be:
// 89 look up, -89 look down

View File

@@ -9,5 +9,5 @@
namespace omath::unreal_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
} // namespace omath::unreal_engine

View File

@@ -22,5 +22,54 @@ namespace omath::unreal_engine
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_centimeters(const FloatingType& units)
{
return units;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_meters(const FloatingType& units)
{
return units / static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType units_to_kilometers(const FloatingType& units)
{
return units_to_meters(units) / static_cast<FloatingType>(1000);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
{
return centimeters;
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType meters_to_units(const FloatingType& meters)
{
return meters * static_cast<FloatingType>(100);
}
template<class FloatingType>
requires std::is_floating_point_v<FloatingType>
[[nodiscard]]
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
{
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
}
} // namespace omath::unreal_engine

View File

@@ -0,0 +1,17 @@
//
// Created by Vladislav on 27.01.2026.
//
#pragma once
#include "mesh.hpp"
#include "omath/engines/unreal_engine/traits/mesh_trait.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::unreal_engine
{
using BoxMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>, std::array<Vector3<float>, 8>,
std::array<Vector3<std::uint32_t>, 12>>;
using PlaneMesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, primitives::Vertex<>,
std::array<Vector3<float>, 4>, std::array<Vector3<std::uint32_t>, 2>>;
} // namespace omath::unreal_engine

View File

@@ -18,7 +18,7 @@ namespace omath::unreal_engine
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far) noexcept;
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};
} // namespace omath::unreal_engine

View File

@@ -16,7 +16,8 @@ namespace omath::unreal_engine
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
auto current_pos = projectile.m_origin
const auto launch_pos = projectile.m_origin + projectile.m_launch_offset;
auto current_pos = launch_pos
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;

View File

@@ -0,0 +1,23 @@
//
// Created by orange on 13.03.2026.
//
#pragma once
#include "omath/linear_algebra/vector2.hpp"
#include <array>
namespace omath::hud
{
class CanvasBox final
{
public:
CanvasBox(Vector2<float> top, Vector2<float> bottom, float ratio = 4.f);
[[nodiscard]]
std::array<Vector2<float>, 4> as_array() const;
Vector2<float> top_left_corner;
Vector2<float> top_right_corner;
Vector2<float> bottom_left_corner;
Vector2<float> bottom_right_corner;
};
} // namespace omath::hud

View File

@@ -0,0 +1,202 @@
//
// Created by orange on 13.03.2026.
//
#pragma once
#include "canvas_box.hpp"
#include "entity_overlay_widgets.hpp"
#include "hud_renderer_interface.hpp"
#include "omath/linear_algebra/vector2.hpp"
#include "omath/utility/color.hpp"
#include <memory>
#include <string_view>
namespace omath::hud
{
class EntityOverlay final
{
public:
EntityOverlay(const Vector2<float>& top, const Vector2<float>& bottom,
const std::shared_ptr<HudRendererInterface>& renderer);
// ── Boxes ────────────────────────────────────────────────────────
EntityOverlay& add_2d_box(const Color& box_color, const Color& fill_color = Color{0.f, 0.f, 0.f, 0.f},
float thickness = 1.f);
EntityOverlay& add_cornered_2d_box(const Color& box_color, const Color& fill_color = Color{0.f, 0.f, 0.f, 0.f},
float corner_ratio_len = 0.2f, float thickness = 1.f);
EntityOverlay& add_dashed_box(const Color& color, float dash_len = 8.f, float gap_len = 5.f,
float thickness = 1.f);
// ── Bars ─────────────────────────────────────────────────────────
EntityOverlay& add_right_bar(const Color& color, const Color& outline_color, const Color& bg_color, float width,
float ratio, float offset = 5.f);
EntityOverlay& add_left_bar(const Color& color, const Color& outline_color, const Color& bg_color, float width,
float ratio, float offset = 5.f);
EntityOverlay& add_top_bar(const Color& color, const Color& outline_color, const Color& bg_color, float height,
float ratio, float offset = 5.f);
EntityOverlay& add_bottom_bar(const Color& color, const Color& outline_color, const Color& bg_color,
float height, float ratio, float offset = 5.f);
EntityOverlay& add_right_dashed_bar(const Color& color, const Color& outline_color, const Color& bg_color,
float width, float ratio, float dash_len, float gap_len,
float offset = 5.f);
EntityOverlay& add_left_dashed_bar(const Color& color, const Color& outline_color, const Color& bg_color,
float width, float ratio, float dash_len, float gap_len, float offset = 5.f);
EntityOverlay& add_top_dashed_bar(const Color& color, const Color& outline_color, const Color& bg_color,
float height, float ratio, float dash_len, float gap_len, float offset = 5.f);
EntityOverlay& add_bottom_dashed_bar(const Color& color, const Color& outline_color, const Color& bg_color,
float height, float ratio, float dash_len, float gap_len,
float offset = 5.f);
// ── Labels ───────────────────────────────────────────────────────
EntityOverlay& add_right_label(const Color& color, float offset, bool outlined, const std::string_view& text);
EntityOverlay& add_left_label(const Color& color, float offset, bool outlined, const std::string_view& text);
EntityOverlay& add_top_label(const Color& color, float offset, bool outlined, std::string_view text);
EntityOverlay& add_bottom_label(const Color& color, float offset, bool outlined, std::string_view text);
EntityOverlay& add_centered_top_label(const Color& color, float offset, bool outlined,
const std::string_view& text);
EntityOverlay& add_centered_bottom_label(const Color& color, float offset, bool outlined,
const std::string_view& text);
template<typename... Args>
EntityOverlay& add_right_label(const Color& color, const float offset, const bool outlined, std::format_string<Args...> fmt,
Args&&... args)
{
return add_right_label(color, offset, outlined,
std::string_view{std::vformat(fmt.get(), std::make_format_args(args...))});
}
template<typename... Args>
EntityOverlay& add_left_label(const Color& color, const float offset, const bool outlined, std::format_string<Args...> fmt,
Args&&... args)
{
return add_left_label(color, offset, outlined,
std::string_view{std::vformat(fmt.get(), std::make_format_args(args...))});
}
template<typename... Args>
EntityOverlay& add_top_label(const Color& color, const float offset, const bool outlined, std::format_string<Args...> fmt,
Args&&... args)
{
return add_top_label(color, offset, outlined,
std::string_view{std::vformat(fmt.get(), std::make_format_args(args...))});
}
template<typename... Args>
EntityOverlay& add_bottom_label(const Color& color, const float offset, const bool outlined,
std::format_string<Args...> fmt, Args&&... args)
{
return add_bottom_label(color, offset, outlined,
std::string_view{std::vformat(fmt.get(), std::make_format_args(args...))});
}
template<typename... Args>
EntityOverlay& add_centered_top_label(const Color& color, const float offset, const bool outlined,
std::format_string<Args...> fmt, Args&&... args)
{
return add_centered_top_label(color, offset, outlined,
std::string_view{std::vformat(fmt.get(), std::make_format_args(args...))});
}
template<typename... Args>
EntityOverlay& add_centered_bottom_label(const Color& color, const float offset, const bool outlined,
std::format_string<Args...> fmt, Args&&... args)
{
return add_centered_bottom_label(color, offset, outlined,
std::string_view{std::vformat(fmt.get(), std::make_format_args(args...))});
}
// ── Spacers ─────────────────────────────────────────────────────
EntityOverlay& add_right_space_vertical(float size);
EntityOverlay& add_right_space_horizontal(float size);
EntityOverlay& add_left_space_vertical(float size);
EntityOverlay& add_left_space_horizontal(float size);
EntityOverlay& add_top_space_vertical(float size);
EntityOverlay& add_top_space_horizontal(float size);
EntityOverlay& add_bottom_space_vertical(float size);
EntityOverlay& add_bottom_space_horizontal(float size);
// ── Progress rings ──────────────────────────────────────────────
EntityOverlay& add_right_progress_ring(const Color& color, const Color& bg, float radius, float ratio,
float thickness = 2.f, float offset = 5.f, int segments = 0);
EntityOverlay& add_left_progress_ring(const Color& color, const Color& bg, float radius, float ratio,
float thickness = 2.f, float offset = 5.f, int segments = 0);
EntityOverlay& add_top_progress_ring(const Color& color, const Color& bg, float radius, float ratio,
float thickness = 2.f, float offset = 5.f, int segments = 0);
EntityOverlay& add_bottom_progress_ring(const Color& color, const Color& bg, float radius, float ratio,
float thickness = 2.f, float offset = 5.f, int segments = 0);
// ── Icons ────────────────────────────────────────────────────────
EntityOverlay& add_right_icon(const std::any& texture_id, float width, float height,
const Color& tint = Color{1.f, 1.f, 1.f, 1.f}, float offset = 5.f);
EntityOverlay& add_left_icon(const std::any& texture_id, float width, float height,
const Color& tint = Color{1.f, 1.f, 1.f, 1.f}, float offset = 5.f);
EntityOverlay& add_top_icon(const std::any& texture_id, float width, float height,
const Color& tint = Color{1.f, 1.f, 1.f, 1.f}, float offset = 5.f);
EntityOverlay& add_bottom_icon(const std::any& texture_id, float width, float height,
const Color& tint = Color{1.f, 1.f, 1.f, 1.f}, float offset = 5.f);
// ── Misc ─────────────────────────────────────────────────────────
EntityOverlay& add_snap_line(const Vector2<float>& start_pos, const Color& color, float width);
EntityOverlay& add_skeleton(const Color& color, float thickness = 1.f);
// ── Declarative interface ─────────────────────────────────────────
/// Pass any combination of widget:: descriptor structs (and std::optional<W>
/// from when()) to render them all in declaration order.
template<typename... Widgets>
EntityOverlay& contents(Widgets&&... widgets)
{
(dispatch(std::forward<Widgets>(widgets)), ...);
return *this;
}
private:
// optional<W> dispatch — enables when() conditional widgets
template<typename W>
void dispatch(const std::optional<W>& w)
{
if (w)
dispatch(*w);
}
void dispatch(const widget::Box& box);
void dispatch(const widget::CorneredBox& cornered_box);
void dispatch(const widget::DashedBox& dashed_box);
void dispatch(const widget::RightSide& right_side);
void dispatch(const widget::LeftSide& left_side);
void dispatch(const widget::TopSide& top_side);
void dispatch(const widget::BottomSide& bottom_side);
void dispatch(const widget::Skeleton& skeleton);
void dispatch(const widget::SnapLine& snap_line);
void dispatch(const widget::ScanMarker& scan_marker);
void dispatch(const widget::AimDot& aim_dot);
void dispatch(const widget::ProjectileAim& proj_widget);
void draw_progress_ring(const Vector2<float>& center, const widget::ProgressRing& ring);
void draw_outlined_text(const Vector2<float>& position, const Color& color, const std::string_view& text);
void draw_dashed_line(const Vector2<float>& from, const Vector2<float>& to, const Color& color, float dash_len,
float gap_len, float thickness) const;
void draw_dashed_fill(const Vector2<float>& origin, const Vector2<float>& step_dir,
const Vector2<float>& perp_dir, float full_len, float filled_len, const Color& fill_color,
const Color& split_color, float dash_len, float gap_len) const;
CanvasBox m_canvas;
Vector2<float> m_text_cursor_right;
Vector2<float> m_text_cursor_top;
Vector2<float> m_text_cursor_bottom;
Vector2<float> m_text_cursor_left;
std::shared_ptr<HudRendererInterface> m_renderer;
};
} // namespace omath::hud

View File

@@ -0,0 +1,233 @@
//
// Created by orange on 15.03.2026.
//
#pragma once
#include "omath/linear_algebra/vector2.hpp"
#include "omath/utility/color.hpp"
#include <any>
#include <initializer_list>
#include <optional>
#include <string_view>
#include <variant>
namespace omath::hud::widget
{
// ── Overloaded helper for std::visit ──────────────────────────────────────
template<typename... Ts>
struct Overloaded : Ts...
{
using Ts::operator()...;
};
template<typename... Ts>
Overloaded(Ts...) -> Overloaded<Ts...>;
// ── Standalone widgets ────────────────────────────────────────────────────
struct Box
{
Color color;
Color fill{0.f, 0.f, 0.f, 0.f};
float thickness = 1.f;
};
struct CorneredBox
{
Color color;
Color fill{0.f, 0.f, 0.f, 0.f};
float corner_ratio = 0.2f;
float thickness = 1.f;
};
struct DashedBox
{
Color color;
float dash_len = 8.f;
float gap_len = 5.f;
float thickness = 1.f;
};
struct Skeleton
{
Color color;
float thickness = 1.f;
};
struct SnapLine
{
Vector2<float> start;
Color color;
float width;
};
struct ScanMarker
{
Color color;
Color outline{0.f, 0.f, 0.f, 0.f};
float outline_thickness = 1.f;
};
/// Dot at an absolute screen position.
struct AimDot
{
Vector2<float> position;
Color color;
float radius = 3.f;
};
struct ProjectileAim
{
enum class Figure
{
CIRCLE,
SQUARE,
};
Vector2<float> position;
Color color;
float size = 3.f;
float line_size = 1.f;
Figure figure = Figure::SQUARE;
};
// ── Side-agnostic widgets (used inside XxxSide containers) ────────────────
/// A filled bar. `size` is width for left/right sides, height for top/bottom.
struct Bar
{
Color color;
Color outline;
Color bg;
float size;
float ratio;
float offset = 5.f;
};
/// A dashed bar. Same field semantics as Bar plus dash parameters.
struct DashedBar
{
Color color;
Color outline;
Color bg;
float size;
float ratio;
float dash_len;
float gap_len;
float offset = 5.f;
};
struct Label
{
Color color;
float offset;
bool outlined;
std::string_view text;
};
/// Wraps a Label to request horizontal centering (only applied in TopSide / BottomSide).
template<typename W>
struct Centered
{
W child;
};
template<typename W>
Centered(W) -> Centered<W>;
/// Empty vertical gap that advances the Y cursor without drawing.
struct SpaceVertical
{
float size;
};
/// Empty horizontal gap that advances the X cursor without drawing.
struct SpaceHorizontal
{
float size;
};
struct ProgressRing
{
Color color;
Color bg{0.3f, 0.3f, 0.3f, 0.5f};
float radius = 12.f;
float ratio;
float thickness = 2.f;
float offset = 5.f;
int segments = 32;
};
struct Icon
{
std::any texture_id;
float width;
float height;
Color tint{1.f, 1.f, 1.f, 1.f};
float offset = 5.f;
};
// ── Side widget variant ───────────────────────────────────────────────────
struct None
{
}; ///< No-op placeholder — used by widget::when for disabled elements.
using SideWidget =
std::variant<None, Bar, DashedBar, Label, Centered<Label>, SpaceVertical, SpaceHorizontal, ProgressRing, Icon>;
// ── Side containers ───────────────────────────────────────────────────────
// Storing std::initializer_list<SideWidget> is safe here: the backing array
// is a const SideWidget[] on the caller's stack whose lifetime matches the
// temporary side-container object, which is consumed within the same
// full-expression by EntityOverlay::dispatch. No heap allocation occurs.
struct RightSide
{
std::initializer_list<SideWidget> children;
RightSide(const std::initializer_list<SideWidget> c): children(c)
{
}
};
struct LeftSide
{
std::initializer_list<SideWidget> children;
LeftSide(const std::initializer_list<SideWidget> c): children(c)
{
}
};
struct TopSide
{
std::initializer_list<SideWidget> children;
TopSide(const std::initializer_list<SideWidget> c): children(c)
{
}
};
struct BottomSide
{
std::initializer_list<SideWidget> children;
BottomSide(const std::initializer_list<SideWidget> c): children(c)
{
}
};
} // namespace omath::hud::widget
namespace omath::hud::widget
{
/// Inside XxxSide containers: returns the widget as a SideWidget when condition is true,
/// or None{} otherwise. Preferred over hud::when for types inside the SideWidget variant.
template<typename W>
requires std::constructible_from<SideWidget, W>
SideWidget when(const bool condition, W widget)
{
if (condition)
return SideWidget{std::move(widget)};
return None{};
}
} // namespace omath::hud::widget
namespace omath::hud
{
/// Top-level: returns an engaged optional<W> when condition is true, std::nullopt otherwise.
/// Designed for use with EntityOverlay::contents() for top-level widget types.
template<typename W>
std::optional<W> when(const bool condition, W widget)
{
if (condition)
return std::move(widget);
return std::nullopt;
}
} // namespace omath::hud

View File

@@ -0,0 +1,47 @@
//
// Created by orange on 13.03.2026.
//
#pragma once
#include "omath/linear_algebra/vector2.hpp"
#include "omath/utility/color.hpp"
#include <any>
#include <span>
namespace omath::hud
{
class HudRendererInterface
{
public:
virtual ~HudRendererInterface() = default;
virtual void add_line(const Vector2<float>& line_start, const Vector2<float>& line_end, const Color& color,
float thickness) = 0;
virtual void add_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color,
float thickness) = 0;
virtual void add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color) = 0;
virtual void add_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) = 0;
virtual void add_filled_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) = 0;
virtual void add_circle(const Vector2<float>& center, float radius, const Color& color, float thickness,
int segments = 0) = 0;
virtual void add_filled_circle(const Vector2<float>& center, float radius, const Color& color,
int segments = 0) = 0;
/// Draw an arc (partial circle outline). Angles in radians, 0 = right (+X), counter-clockwise.
virtual void add_arc(const Vector2<float>& center, float radius, float a_min, float a_max, const Color& color,
float thickness, int segments = 0) = 0;
/// Draw a textured quad. texture_id is renderer-specific (e.g. ImTextureID for ImGui).
virtual void add_image(const std::any& texture_id, const Vector2<float>& min, const Vector2<float>& max,
const Color& tint = Color{1.f, 1.f, 1.f, 1.f}) = 0;
virtual void add_text(const Vector2<float>& position, const Color& color, const std::string_view& text) = 0;
[[nodiscard]]
virtual Vector2<float> calc_text_size(const std::string_view& text) = 0;
};
} // namespace omath::hud

View File

@@ -0,0 +1,33 @@
//
// Created by orange on 13.03.2026.
//
#pragma once
#include <omath/hud/hud_renderer_interface.hpp>
#ifdef OMATH_IMGUI_INTEGRATION
namespace omath::hud
{
class ImguiHudRenderer final : public HudRendererInterface
{
public:
~ImguiHudRenderer() override;
void add_line(const Vector2<float>& line_start, const Vector2<float>& line_end, const Color& color,
float thickness) override;
void add_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color, float thickness) override;
void add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color) override;
void add_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) override;
void add_filled_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) override;
void add_circle(const Vector2<float>& center, float radius, const Color& color, float thickness,
int segments = 0) override;
void add_filled_circle(const Vector2<float>& center, float radius, const Color& color,
int segments = 0) override;
void add_arc(const Vector2<float>& center, float radius, float a_min, float a_max, const Color& color,
float thickness, int segments = 0) override;
void add_image(const std::any& texture_id, const Vector2<float>& min, const Vector2<float>& max,
const Color& tint = Color{1.f, 1.f, 1.f, 1.f}) override;
void add_text(const Vector2<float>& position, const Color& color, const std::string_view& text) override;
[[nodiscard]]
virtual Vector2<float> calc_text_size(const std::string_view& text) override;
};
} // namespace omath::hud
#endif // OMATH_IMGUI_INTEGRATION

View File

@@ -37,6 +37,12 @@ namespace omath
COLUMN_MAJOR
};
enum class NDCDepthRange : uint8_t
{
NEGATIVE_ONE_TO_ONE = 0, // OpenGL: [-1.0, 1.0]
ZERO_TO_ONE // DirectX / Vulkan: [0.0, 1.0]
};
template<typename M1, typename M2> concept MatTemplateEqual
= (M1::rows == M2::rows) && (M1::columns == M2::columns)
&& std::is_same_v<typename M1::value_type, typename M2::value_type> && (M1::store_type == M2::store_type);
@@ -658,56 +664,98 @@ namespace omath
} * mat_translation<Type, St>(-camera_origin);
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard]]
Mat<4, 4, Type, St> mat_perspective_left_handed(const float field_of_view, const float aspect_ratio,
const float near, const float far) noexcept
{
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, (far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, 1.f, 0.f}};
if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE)
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, far / (far - near), -(near * far) / (far - near)},
{0.f, 0.f, 1.f, 0.f}};
else if constexpr (DepthRange == NDCDepthRange::NEGATIVE_ONE_TO_ONE)
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, (far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, 1.f, 0.f}};
else
std::unreachable();
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard]]
Mat<4, 4, Type, St> mat_perspective_right_handed(const float field_of_view, const float aspect_ratio,
const float near, const float far) noexcept
{
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, -(far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, -1.f, 0.f}};
if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE)
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, -far / (far - near), -(near * far) / (far - near)},
{0.f, 0.f, -1.f, 0.f}};
else if constexpr (DepthRange == NDCDepthRange::NEGATIVE_ONE_TO_ONE)
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, -(far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, -1.f, 0.f}};
else
std::unreachable();
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard]]
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type near, const Type far) noexcept
{
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE)
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, static_cast<Type>(1) / (far - near), -near / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
else if constexpr (DepthRange == NDCDepthRange::NEGATIVE_ONE_TO_ONE)
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
else
std::unreachable();
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard]]
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type near, const Type far) noexcept
{
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, -static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE)
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, -static_cast<Type>(1) / (far - near), -near / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
else if constexpr (DepthRange == NDCDepthRange::NEGATIVE_ONE_TO_ONE)
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, -static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
else
std::unreachable();
}
template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR>
Mat<4, 4, T, St> mat_look_at_left_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up)

View File

@@ -0,0 +1,219 @@
//
// Created by vlad on 3/1/2026.
//
#pragma once
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
#include <cmath>
#include <format>
namespace omath
{
template<class Type>
requires std::is_arithmetic_v<Type>
class Quaternion
{
public:
using ContainedType = Type;
Type x = static_cast<Type>(0);
Type y = static_cast<Type>(0);
Type z = static_cast<Type>(0);
Type w = static_cast<Type>(1); // identity quaternion
constexpr Quaternion() noexcept = default;
constexpr Quaternion(const Type& x, const Type& y, const Type& z, const Type& w) noexcept
: x(x), y(y), z(z), w(w)
{
}
// Factory: build from a normalized axis and an angle in radians
[[nodiscard]]
static Quaternion from_axis_angle(const Vector3<Type>& axis, const Type& angle_rad) noexcept
{
const Type half = angle_rad / static_cast<Type>(2);
const Type s = std::sin(half);
return {axis.x * s, axis.y * s, axis.z * s, std::cos(half)};
}
[[nodiscard]] constexpr bool operator==(const Quaternion& other) const noexcept
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
[[nodiscard]] constexpr bool operator!=(const Quaternion& other) const noexcept
{
return !(*this == other);
}
// Hamilton product: this * other
[[nodiscard]] constexpr Quaternion operator*(const Quaternion& other) const noexcept
{
return {
w * other.x + x * other.w + y * other.z - z * other.y,
w * other.y - x * other.z + y * other.w + z * other.x,
w * other.z + x * other.y - y * other.x + z * other.w,
w * other.w - x * other.x - y * other.y - z * other.z,
};
}
constexpr Quaternion& operator*=(const Quaternion& other) noexcept
{
return *this = *this * other;
}
[[nodiscard]] constexpr Quaternion operator*(const Type& scalar) const noexcept
{
return {x * scalar, y * scalar, z * scalar, w * scalar};
}
constexpr Quaternion& operator*=(const Type& scalar) noexcept
{
x *= scalar;
y *= scalar;
z *= scalar;
w *= scalar;
return *this;
}
[[nodiscard]] constexpr Quaternion operator+(const Quaternion& other) const noexcept
{
return {x + other.x, y + other.y, z + other.z, w + other.w};
}
constexpr Quaternion& operator+=(const Quaternion& other) noexcept
{
x += other.x;
y += other.y;
z += other.z;
w += other.w;
return *this;
}
[[nodiscard]] constexpr Quaternion operator-() const noexcept
{
return {-x, -y, -z, -w};
}
// Conjugate: negates the vector part (x, y, z)
[[nodiscard]] constexpr Quaternion conjugate() const noexcept
{
return {-x, -y, -z, w};
}
[[nodiscard]] constexpr Type dot(const Quaternion& other) const noexcept
{
return x * other.x + y * other.y + z * other.z + w * other.w;
}
[[nodiscard]] constexpr Type length_sqr() const noexcept
{
return x * x + y * y + z * z + w * w;
}
#ifndef _MSC_VER
[[nodiscard]] constexpr Type length() const noexcept
{
return std::sqrt(length_sqr());
}
[[nodiscard]] constexpr Quaternion normalized() const noexcept
{
const Type len = length();
return len != static_cast<Type>(0) ? *this * (static_cast<Type>(1) / len) : *this;
}
#else
[[nodiscard]] Type length() const noexcept
{
return std::sqrt(length_sqr());
}
[[nodiscard]] Quaternion normalized() const noexcept
{
const Type len = length();
return len != static_cast<Type>(0) ? *this * (static_cast<Type>(1) / len) : *this;
}
#endif
// Inverse: q* / |q|^2 (for unit quaternions inverse == conjugate)
[[nodiscard]] constexpr Quaternion inverse() const noexcept
{
return conjugate() * (static_cast<Type>(1) / length_sqr());
}
// Rotate a 3D vector: v' = q * pure(v) * q^-1
// Computed via Rodrigues' formula to avoid full quaternion product overhead
[[nodiscard]] constexpr Vector3<Type> rotate(const Vector3<Type>& v) const noexcept
{
const Vector3<Type> q_vec{x, y, z};
const Vector3<Type> cross = q_vec.cross(v);
return v + cross * (static_cast<Type>(2) * w) + q_vec.cross(cross) * static_cast<Type>(2);
}
// 3x3 rotation matrix from this (unit) quaternion
[[nodiscard]] constexpr Mat<3, 3, Type> to_rotation_matrix3() const noexcept
{
const Type xx = x * x, yy = y * y, zz = z * z;
const Type xy = x * y, xz = x * z, yz = y * z;
const Type wx = w * x, wy = w * y, wz = w * z;
const Type one = static_cast<Type>(1);
const Type two = static_cast<Type>(2);
return {
{one - two * (yy + zz), two * (xy - wz), two * (xz + wy) },
{two * (xy + wz), one - two * (xx + zz), two * (yz - wx) },
{two * (xz - wy), two * (yz + wx), one - two * (xx + yy)},
};
}
// 4x4 rotation matrix (with homogeneous row/column)
[[nodiscard]] constexpr Mat<4, 4, Type> to_rotation_matrix4() const noexcept
{
const Type xx = x * x, yy = y * y, zz = z * z;
const Type xy = x * y, xz = x * z, yz = y * z;
const Type wx = w * x, wy = w * y, wz = w * z;
const Type one = static_cast<Type>(1);
const Type two = static_cast<Type>(2);
const Type zero = static_cast<Type>(0);
return {
{one - two * (yy + zz), two * (xy - wz), two * (xz + wy), zero},
{two * (xy + wz), one - two * (xx + zz), two * (yz - wx), zero},
{two * (xz - wy), two * (yz + wx), one - two * (xx + yy), zero},
{zero, zero, zero, one },
};
}
[[nodiscard]] constexpr std::array<Type, 4> as_array() const noexcept
{
return {x, y, z, w};
}
};
} // namespace omath
template<class Type>
struct std::formatter<omath::Quaternion<Type>> // NOLINT(*-dcl58-cpp)
{
[[nodiscard]]
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
static auto format(const omath::Quaternion<Type>& q, FormatContext& ctx)
{
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
return std::format_to(ctx.out(), "[{}, {}, {}, {}]", q.x, q.y, q.z, q.w);
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
return std::format_to(ctx.out(), L"[{}, {}, {}, {}]", q.x, q.y, q.z, q.w);
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
return std::format_to(ctx.out(), u8"[{}, {}, {}, {}]", q.x, q.y, q.z, q.w);
}
};

View File

@@ -220,6 +220,12 @@ namespace omath
{
return std::make_tuple(x, y);
}
[[nodiscard]]
constexpr std::array<Type, 2> as_array() const noexcept
{
return {x, y};
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
constexpr ImVec2 to_im_vec2() const noexcept

View File

@@ -4,8 +4,8 @@
#pragma once
#include "omath/trigonometry/angle.hpp"
#include "omath/linear_algebra/vector2.hpp"
#include "omath/trigonometry/angle.hpp"
#include <cstdint>
#include <expected>
#include <functional>
@@ -233,7 +233,8 @@ namespace omath
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(std::acos(dot(other) / bottom));
}
[[nodiscard]] bool is_perpendicular(const Vector3& other, Type epsilon = static_cast<Type>(0.0001)) const noexcept
[[nodiscard]] bool is_perpendicular(const Vector3& other,
Type epsilon = static_cast<Type>(0.0001)) const noexcept
{
if (const auto angle = angle_between(other))
return std::abs(angle->as_degrees() - static_cast<Type>(90)) <= epsilon;
@@ -274,6 +275,12 @@ namespace omath
{
return length() >= other.length();
}
[[nodiscard]]
constexpr std::array<Type, 3> as_array() const noexcept
{
return {this->x, this->y, z};
}
};
} // namespace omath

View File

@@ -3,8 +3,8 @@
//
#pragma once
#include <algorithm>
#include "omath/linear_algebra/vector3.hpp"
#include <algorithm>
namespace omath
{
@@ -183,6 +183,12 @@ namespace omath
return length() >= other.length();
}
[[nodiscard]]
constexpr std::array<Type, 4> as_array() const noexcept
{
return {this->x, this->y, this->z, w};
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
constexpr ImVec4 to_im_vec4() const noexcept
@@ -200,7 +206,7 @@ namespace omath
return {static_cast<Type>(other.x), static_cast<Type>(other.y), static_cast<Type>(other.z)};
}
#endif
};
};
} // namespace omath
template<> struct std::hash<omath::Vector4<float>>

25
include/omath/lua/lua.hpp Normal file
View File

@@ -0,0 +1,25 @@
//
// Created by orange on 07.03.2026.
//
#pragma once
#ifdef OMATH_ENABLE_LUA
#include <sol/forward.hpp>
namespace omath::lua
{
class LuaInterpreter final
{
public:
static void register_lib(lua_State* lua_state);
private:
static void register_vec2(sol::table& omath_table);
static void register_vec3(sol::table& omath_table);
static void register_vec4(sol::table& omath_table);
static void register_color(sol::table& omath_table);
static void register_triangle(sol::table& omath_table);
static void register_shared_types(sol::table& omath_table);
static void register_engines(sol::table& omath_table);
static void register_pattern_scan(sol::table& omath_table);
};
}
#endif

View File

@@ -17,6 +17,9 @@
// Matrix classes
#include "omath/linear_algebra/mat.hpp"
// Quaternion
#include "omath/linear_algebra/quaternion.hpp"
// Color functionality
#include "omath/utility/color.hpp"

View File

@@ -6,7 +6,9 @@
#include "omath/linear_algebra/vector3.hpp"
#include <expected>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
namespace omath::pathfinding
@@ -28,10 +30,20 @@ namespace omath::pathfinding
[[nodiscard]]
bool empty() const;
[[nodiscard]] std::vector<uint8_t> serialize() const noexcept;
// Events -- per-vertex optional tag (e.g. "jump", "teleport")
void set_event(const Vector3<float>& vertex, const std::string_view& event_id);
void clear_event(const Vector3<float>& vertex);
void deserialize(const std::vector<uint8_t>& raw) noexcept;
[[nodiscard]]
std::optional<std::string> get_event(const Vector3<float>& vertex) const noexcept;
[[nodiscard]] std::string serialize() const noexcept;
void deserialize(const std::string& raw);
std::unordered_map<Vector3<float>, std::vector<Vector3<float>>> m_vertex_map;
private:
std::unordered_map<Vector3<float>, std::string> m_vertex_events;
};
} // namespace omath::pathfinding

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